序文
Prologでは、CLP(FD)制約はそのようなスケジューリングタスクを解決するための正しい選択です。
詳細については 、 clpfdを参照してください。
この場合、利用可能なコートの数に応じて、強力なglobal_cardinality/2
制約を使用して各ラウンドの発生数を制限することをお勧めします。反復深化を使用して、許容可能なラウンドの最小数を見つけることができます。
自由に利用できるPrologシステムは、タスクを十分に解決するのに十分です。商用グレードのシステムは、数十倍高速に実行されます。
バリエーション1:SWI-Prologを使用したソリューション
:- use_module(library(clpfd)).
tennis(N, Courts, Rows) :-
length(Rows, N),
maplist(same_length(Rows), Rows),
transpose(Rows, Rows),
Rows = [[_|First]|_],
chain(First, #<),
length(_, MaxRounds),
numlist(1, MaxRounds, Rounds),
pairs_keys_values(Pairs, Rounds, Counts),
Counts ins 0..Courts,
foldl(triangle, Rows, Vss, Dss, 0, _),
append(Vss, Vs),
global_cardinality(Vs, Pairs),
maplist(breaks, Dss),
labeling([ff], Vs).
triangle(Row, Vs, Ds, N0, N) :-
length(Prefix, N0),
append(Prefix, [-|Vs], Row),
append(Prefix, Vs, Ds),
N #= N0 + 1.
breaks([]).
breaks([P|Ps]) :- maplist(breaks_(P), Ps), breaks(Ps).
breaks_(P0, P) :- abs(P0-P) #> 1.
サンプルクエリ:2コートの5人のプレーヤー:
?- time(tennis(5, 2, Rows)), maplist(writeln, Rows).
% 827,838 inferences, 0.257 CPU in 0.270 seconds (95% CPU, 3223518 Lips)
[-,1,3,5,7]
[1,-,5,7,9]
[3,5,-,9,1]
[5,7,9,-,3]
[7,9,1,3,-]
指定されたタスク、2つのコートの6人のプレーヤーは、1分の制限時間内にうまく解決しました:
?-time(tennis(6、2、Rows))、
maplist(format( "〜t〜w〜3 +〜t〜w〜3 +〜t〜w〜3 +〜t〜w〜3 +〜t〜w〜3 +〜t〜w〜3 + \ n" )、行)。
%6,675,665推論、0.977秒で0.970 CPU(99%CPU、6884940リップ)
--1 3 5 7 10
1-6 9 11 3
3 6-11 9 1
5 9 11-2 7
7 11 92-5
10 3 1 75-
さらなる例:5コートの7人のプレーヤー:
?-time(tennis(7、5、Rows))、
maplist(format( "〜t〜w〜3 +〜t〜w〜3 +〜t〜w〜3 +〜t〜w〜3 +〜t〜w〜3 +〜t〜w〜3 +〜t〜 w〜3 + \ n ")、行)。
%125,581,090推論、18.208秒で17.476 CPU(96%CPU、7185927リップ)
--1 3 5 7 9 11
1-5 3 11 13 9
3 5-9 1 7 13
5 3 9-13 11 7
7 11 1 13-5 3
9 13 7 11 5-1
11 9 13 7 31-
バリエーション2:SICStusPrologを使用したソリューション
互換性のために次の追加の定義を使用すると、同じプログラムがSICStusPrologでも実行されます。
:-use_module(library(lists))。
:-use_module(library(between))。
:-op(700、xfx、ins)。
Vs ins D:-maplist(in_(D)、Vs)。
in_(D、V):-VinD。
鎖([]、 _)。
チェーン([L | Ls]、Pred):-
chain_(Ls、L、Pred)。
鎖_([]、 _、 _)。
chain _([L | Ls]、Prev、Pred):-
call(Pred、Prev、L)、
chain_(Ls、L、Pred)。
pair_keys_values(Ps、Ks、Vs):-keys_and_values(Ps、Ks、Vs)。
foldl(Pred、Ls1、Ls2、Ls3、S0、S):-
foldl_(Ls1、Ls2、Ls3、Pred、S0、S)。
foldl _([]、[]、[]、_、S、S)。
foldl _([L1 | Ls1]、[L2 | Ls2]、[L3 | Ls3]、Pred、S0、S):-
call(Pred、L1、L2、L3、S0、S1)、
foldl_(Ls1、Ls2、Ls3、Pred、S1、S)。
時間(目標):-
統計(ランタイム、[T0 | _])、
呼び出し(目標)、
統計(ランタイム、[T1 | _])、
T#= T1-T0、
format( "%Runtime:〜Dms \ n"、[T])。
主な違い:SICStusは、本格的なCLP(FD)システムを搭載した商用グレードのPrologであり、このユースケースやその他のユースケースではSWI-Prologよりもはるかに高速です。
指定されたタスク、2つのコートで6人のプレーヤー:
?-time(tennis(6、2、Rows))、
maplist(format( "〜t〜w〜3 +〜t〜w〜3 +〜t〜w〜3 +〜t〜w〜3 +〜t〜w〜3 +〜t〜w〜3 + \ n" )、行)。
%ランタイム:34ms(!)
--1 3 5 7 10
1-6 11 9 3
3 6-9 11 1
5 11 9-2 7
7 9 112-5
10 3 1 75-
より大きな例:
| ?-time(tennis(7、5、Rows))、
maplist(format( "〜t〜w〜3 +〜t〜w〜3 +〜t〜w〜3 +〜t〜w〜3 +〜t〜w〜3 +〜t〜w〜3 +〜t〜 w〜3 + \ n ")、行)。
%ランタイム:884ms
--1 3 5 7 9 11
1-5 3 9 7 13
3 5-1 11 13 7
5 3 1-13 11 9
7 9 11 13-3 1
9 7 13 113-5
11 13 7 9 15-
閉会の辞
どちらのシステムでglobal_cardinality/3
も、グローバルカーディナリティ制約の伝播強度を変更するオプションを指定できるため、より弱く、より効率的なフィルタリングが可能になります。特定の例に適切なオプションを選択すると、Prologシステムの選択よりもさらに大きな影響を与える可能性があります。