Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <h1>Preface</h1> <p>In Prolog, <strong>CLP(FD) constraints</strong> are the right choice for solving such scheduling tasks.</p> <p>See&nbsp;<strong><a href="/questions/tagged/clpfd" class="post-tag" title="show questions tagged &#39;clpfd&#39;" rel="tag">clpfd</a></strong> for more information.</p> <p>In this case, I suggest using the powerful <a href="https://sicstus.sics.se/sicstus/docs/latest4/html/sicstus.html/Arithmetic_002dLogical-Constraints.html#Arithmetic_002dLogical-Constraints" rel="noreferrer"><code>global_cardinality/2</code></a> constraint to restrict the number of <strong>occurrences</strong> of each round, depending on the number of available&nbsp;courts. We can use <em>iterative deepening</em> to find the minimal number of admissible rounds.</p> <p>Freely available Prolog systems suffice to solve the task satisfactorily. Commercial-grade systems will run dozens of times faster.</p> <h1>Variant 1: Solution with SWI-Prolog</h1> <pre><code>:- use_module(library(clpfd)). tennis(N, Courts, Rows) :- length(Rows, N), maplist(same_length(Rows), Rows), transpose(Rows, Rows), Rows = [[_|First]|_], chain(First, #&lt;), 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) #&gt; 1. </code></pre> <p>Sample query: 5 players on 2 courts:</p> <pre><code>?- 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,-] </code></pre> <p>The specified task, <strong>6 players on 2 courts</strong>, solved well within the time limit of 1 minute:</p> <pre> ?- 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"), Rows). % 6,675,665 inferences, 0.970 CPU in 0.977 seconds (99% CPU, 6884940 Lips) - 1 3 5 7 10 1 - 6 9 11 3 3 6 - 11 9 1 5 9 11 - 2 7 7 11 9 2 - 5 10 3 1 7 5 - </pre> <p>Further example: 7 players on 5 courts:</p> <pre> ?- 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"), Rows). % 125,581,090 inferences, 17.476 CPU in 18.208 seconds (96% CPU, 7185927 Lips) - 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 3 1 - </pre> <h1>Variant 2: Solution with SICStus Prolog</h1> <p>With the following additional definitions for compatibility, the <em>same</em> program also runs in SICStus&nbsp;Prolog:</p> <pre> :- use_module(library(lists)). :- use_module(library(between)). :- op(700, xfx, ins). Vs ins D :- maplist(in_(D), Vs). in_(D, V) :- V in D. chain([], _). chain([L|Ls], Pred) :- chain_(Ls, L, Pred). chain_([], _, _). chain_([L|Ls], Prev, Pred) :- call(Pred, Prev, L), chain_(Ls, L, Pred). pairs_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). time(Goal) :- statistics(runtime, [T0|_]), call(Goal), statistics(runtime, [T1|_]), T #= T1 - T0, format("% Runtime: ~Dms\n", [T]). </pre> <p>Major difference: SICStus, being a commercial-grade Prolog that ships with a serious CLP(FD)&nbsp;system, is <strong>much faster</strong> than SWI-Prolog in this use&nbsp;case and others like&nbsp;it.</p> <p>The specified task, 6 players on 2&nbsp;courts:</p> <pre> ?- 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"), Rows). % <b>Runtime: 34ms (!)</b> - 1 3 5 7 10 1 - 6 11 9 3 3 6 - 9 11 1 5 11 9 - 2 7 7 9 11 2 - 5 10 3 1 7 5 - </pre> <p>The larger example:</p> <pre> | ?- 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"), Rows). % <b>Runtime: 884ms</b> - 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 11 3 - 5 11 13 7 9 1 5 - </pre> <h1>Closing remarks</h1> <p>In both systems, <code>global_cardinality/3</code> allows you to specify options that alter the propagation strength of the global cardinality constraint, enabling weaker and potentially more efficient filtering. Choosing the right options for a specific example may have an even larger impact than the choice of Prolog&nbsp;system.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload