Upload
peyton
View
43
Download
0
Embed Size (px)
DESCRIPTION
(Finite domain) constraint logic programming. Andy King [email protected] http://www.cs.kent.ac.uk/~amk/ With thanks to the Mark Wallace, Joachim Schimpf, Warwick Harvey, Andrew Cheadle, Andrew Sadler for use of their ECLiPSe material. Slides originally adapted from notes of Micha Meier - PowerPoint PPT Presentation
Citation preview
(Finite domain) constraint logic programmingAndy [email protected]://www.cs.kent.ac.uk/~amk/
With thanks to the Mark Wallace, Joachim Schimpf, Warwick Harvey, Andrew Cheadle, Andrew Sadler for use of their ECLiPSe material. Slides originally adapted from notes of Micha Meier
http://www.cs.kent.ac.uk/systems/LOCAL-ONLY/ software/eclipse/win32/
http://www.cs.kent.ac.uk/systems/LOCAL-ONLY/ software/eclipse/linux-i386/
Logical course structure
This overviewConstraint satisfaction problems
(CSPs)Bounds propagation, search and
optimisation techniquesModeling problems with reified
constraints
CLP applications Fleet assignment – the assignment of a set of aircraft
of different types to a predefined schedule of flights Job-shop scheduling – a set of jobs and set of
machines are given, each job consisting on a partially ordered set of tasks
Nurse scheduling – specify which days on and which days off given constraints on personnel policy, nurses’ qualifications and individual requests
Interpreting sloppy stick figures – recognizing drawings with missing model parts and noisy data
See at PACT, CP, Constraints and the applications page http://www-icparc.doc.ic.ac.uk/eclipse/appl/
Do not be deceived: constraint solving is usually hidden beneath interface coded in Java.
Growth of constraint programmingResults – 64 submissions to ICLP in 2001; 66
submissions to the ICFP in 2001 compared with 135 submissions to CP in 2001
Systems – AKL, Amulet and Garnet, B-Prolog, Bertrand, CHIP, CPLEX, Cassowary, Cooldraw, Thinglab, ECLiPSe, GNU-Prolog, IF/Prolog, ILOG Solver, Interval Solver for Microsoft Excel, Jsolver, Numerica, Oz, Prolog IV, RISC-CLP(Real), SICStus
Laboratories and startups – CCC, IC-Parc, IF/Computer, ILOG, PrologIA, Vine Solutions, etc
Paper and on-line resources For ECLiPSe see the “ECLiPSe Constraint
Library Manual” in the on-line documentation
Krzysztof Apt, “Principles of Constraint Programming”, Cambridge, 1993
Kim Marriott and Stuckey, “Programming with Constraints”, MIT Press, 1998
Roman Barták, “On-line Guide to Constraint Programming”, see http://kti.ms.mff.cuni.cz/~bartak/constraints/
Commerce versus science
“Were you to ask me which programming paradigm is likely to gain most in commercial significance over the next 5 years I’d have to pick Constrained Logic Programming (CLP), even though it’s perhaps currently one of the least known and understood”
Dick Pountain
BYTE, February 1995
“Constraint programming represents one of the closest approaches computer science has yet made to the Holy Grail of programming: the user states the problem, the computer solves it”
Eugene C. FreuderCONSTRAINTS, April
1997
Constraint satisfaction problems
Chapter 1: the declarative nature of constraint logic programming
Constraint satisfaction problems (CSPs)
A CSP consists of:
a finite set of variables X = {x1, …, xn}a domain D that is a mapping {x1 S1,…, xn Sn} where each Si is a finite set a constraint C that is a finite set of primitive constraints C = {c1, …, cm}
where var(ci) X
The CSP is interpreted as the problem of decidingwhether C x1 D(x1) … xn D(xn) issatisfiable – whether it possesses a solution
What is an example CSP?
The set of variables is X = {WA, NT, Q, NS, SA, V, T}
The domain is D = {WA {red}, NT S, …, T S} where S = {red, yellow, blue}
The set of constraints is C = {WA NT, WA SA, NT SA, NT Q, SA Q, SA NS, SA V, Q NS, NS V}
Colour the regions of a map with a limited number of colours, subject to the condition that no two adjacent regions share the same colour.
For instance, consider the CSP which encodes the problem of colouring Australia so that Western Australia is red:
Coding the colouring CSP in ECLiPSe
:- use_module(library(fd)).
colour(Regions) :- Regions = [NT, Q, NS, SA, V, _T], Regions :: 1..3, [WA] :: 1..1, WA #\= NT, WA #\= SA, NT #\= SA, NT #\= Q, SA #\= Q, SA #\= NS, SA #\= V, Q #\= NS, NS #\= V,
labeling(Regions).
[eclipse 2]: colour(R).
R = [2, 1, 2, 3, 1, 1]More (0.00s cpu) ? ;
R = [2, 1, 2, 3, 1, 2]More (0.00s cpu) ? ;
R = [2, 1, 2, 3, 1, 3]More (0.00s cpu) ? ;
R = [3, 1, 3, 2, 1, 1]More (0.00s cpu) ? ;
R = [3, 1, 3, 2, 1, 2]More (0.00s cpu) ? ;
R = [3, 1, 3, 2, 1, 3]Yes (0.00s cpu)
What is another example of a CSP? Crypto-arithmetic problems – puzzles in which digits are replaced with distinct letters of the alphabet or other symbols.
Consider the classic SEND, MORE, MONEY puzzle that is due to Dudeney [Strand Magazine, July, 1924]
The set of variables is X = {S, E, N, D, M, O, R, Y, C1, C2, C3}
The domain is D = {S {0,…,9}, …, R {0,…,9}, C1 {0,1}, C2 {0,1}, C3 {0,1}}
The set of constraints is C = CP CA where
CP = {S E, S N, S D, S M, S O, S R, E N, E D, E M, E O, E R, N D, N M, N O, N R, D M, D O, D R, M O, M R, O R}
CA = {D + E = Y + 10C1, N + R + C1 = E + 10C2,
E + O + C2 = N + 10C3, S + M + C3 = O + 10M}
SEND
+ MORE
MONEY
Coding the crypto-arithmetic CSP in ECliPSe
:- use_module(library(fd)).
crypto(Digits) :- Digits = [S,E,N,D,M,O,R,Y], Digits :: 0..9, Carrys = [C1, C2, C3], Carrys :: 0..1, alldifferent(Digits), D + E #= Y + 10 * C1, N + R + C1 #= E + 10 * C2, E + O + C2 #= N + 10 * C3, S + M + C3 #= O + 10 * M, labeling(Digits).
[eclipse 2]: crypto(D).
D = [2, 8, 1, 7, 0, 3, 6, 5]More (0.00s cpu) ? ;
D = [2, 8, 1, 9, 0, 3, 6, 7]More (0.00s cpu) ? ;
D = [3, 7, 1, 2, 0, 4, 6, 9]More (0.00s cpu) ? ;
D = [3, 7, 1, 9, 0, 4, 5, 6]More (0.00s cpu) ? ;
…
2817
+ 0368
03185
What is the n-queens problem?
Place n queens on an n by n chessboard so that none of them can take each other
Solutions and non-solutions for, say, n = 6 are
There are n2!/(n!(n2-n)!) possible ways of placing n queens on an n by n board, that is, 1947792 for n = 6
Expressing 6-queens as a CSP
The set of variables is X = {X1, …, X6} where Xi is the column number for the queen in row i
The assignment X1 = 2, X2 = 4 …, X6 = 5 represents the safe configuration:
This representation assumes that exactly one queen occurs in each row:
if two queens occurred in the same row then the configuration is a non-solution (take horizontally)
if zero queens occurred in one row, then at least two queens must occur in another row (take horizontally)
Expressing 6-queens as a CSP (cont’)
The domain is D = {X1 {1,…,6}, …, X6 {1,…,6}}
The set of constraints is C = CP CD where
CP = {X1 X2, X1 X3, X1 X4, X1 X5, X1 X6, X2 X3, X2 X4, X2 X5, X2 X6, …, X4 X5, X5 X6}
This ensures that queens cannot take vertically
CD = {1 abs(X1 – X2), 2 abs(X1 – X3), 3 abs(X1 – X4), 4 abs(X1 – X5), 5 abs(X1 – X6), 1 abs(X2 – X3), 2 abs(X2 – X4), 3 abs(X2 – X5), 4 abs(X2 – X6), …, 1 abs(X5 – X6)}
This ensures that queens cannot take diagonally
Taking diagonally revisited
Suppose the X1 = 2Consider those X2 which
are unsafe relative to X1:
In either case 1 = abs(X1 – X2), hence
require 1 abs(X1 – X2)
Suppose the X5 = 3Consider those X3 which
are unsafe relative to X5:
In either case 2 = abs(X5 – X3), hence
require 2 abs(X5 – X3)
Coding the n-queens CSP in ECliPSe:- use_module(library(fd)).
nqueens(N, Soln):- length(Soln, N), Soln :: 1..N, safe(Soln), alldifferent(Soln),
labeling(Soln).
safe([]).safe([CN | CNs]) :-
no_attack(CNs, CN, 1), safe(CNs).
no_attack([], _, _).no_attack([CN|CNs], First_CN, Diff) :-% Diff #\= abs(First_CN - CN),
Diff #\= First_CN - CN,Diff #\= CN - First_CN,
Next_Diff is Diff + 1, no_attack(CNs, First_CN, Next_Diff).
Running the n-queens program[eclipse 26]: nqueens(6, S).
S = [2, 4, 6, 1, 3, 5]More (0.00s cpu) ? ;
S = [3, 6, 2, 5, 1, 4]More (0.00s cpu) ? ;
S = [4, 1, 5, 2, 6, 3]More (0.00s cpu) ? ;
S = [5, 3, 1, 6, 4, 2]More (0.00s cpu) ? ;
No (0.00s cpu)
Bounds propagation, search and optimisation
Chapter 2: how constraint solving is realised
With and without labelling:- use_module(library(fd)).
bounds(X, Y, Z):- [X] :: 1..5,
[Y] :: 1..2,[Z] :: 3..5,X #= Y + Z.
% labeling([X, Y, Z]).
[eclipse 8]: bounds(X, Y, Z).
X = X{[4, 5]}Y = Y{[1, 2]}Z = Z{[3, 4]}
Yes (0.00s cpu)
:- use_module(library(fd)).
bounds(X, Y, Z):- [X] :: 1..5,
[Y] :: 1..2,[Z] :: 3..5,X #= Y + Z,labeling([X, Y, Z]).
[eclipse 8]: bounds(X, Y, Z).
X = 4, Y = 1, Z = 3Yes (0.00s cpu) ? ;
X = 5, Y = 1, Z = 4Yes (0.00s cpu) ? ;
X = 5, Y = 2, Z = 3Yes (0.00s cpu)
Unravelling (understanding) bounds propagation
Initially 1X5, 1Y2 and 3Z5Consider X = Y + Z
Thus 4=min(Y)+min(Z)Xmax(Y)+max(Z)=7 Tighten by 4X, hence 4X5, 1Y2 and
3Z5Consider Y = X - Z
Thus -1=min(X)-max(Z)Ymax(X)-min(Z)=2 Cannot tighten Y
Consider Z = X - Y Thus 2=min(X)-max(Y)Zmax(X)-min(Y)=4 Tighten by Z4, hence 4X5, 1Y2 and
3Z4
Unravelling (unwinding) labelling[eclipse 8]: [X] :: 1..5, [Y] :: 1..2, [Z] :: 3..5, labeling([X, Y,
Z]).
X = 1, Y = 1, Z = 3Yes (0.00s cpu) ? ;
X = 1, Y = 1, Z = 4Yes (0.00s cpu) ? ;
X = 1, Y = 1, Z = 5Yes (0.00s cpu) ? ;
X = 1, Y = 2, Z = 3Yes (0.00s cpu) ? ;
X = 1, Y = 2, Z = 4Yes (0.00s cpu) ? ;
X = 1, Y = 2, Z = 5Yes (0.00s cpu) ? ;
bounds(X, Y, Z):- [X] :: 1..5,
[Y] :: 1..2,[Z] :: 3..5,labeling([X, Y, Z]).
[eclipse 9]: bounds(X, Y, Z).
X = 1, Y = 1, Z = 3Yes (0.00s cpu) ? ;
X = 1, Y = 1, Z = 4Yes (0.00s cpu) ? ;
X = 1, Y = 1, Z = 5Yes (0.00s cpu) ? ;
Search without bounds propagation (is inefficient)
Without bounds propagation, maximum of 5×2×3 = 30 cases need to be checked for consistency with X #= Y + Z
Bounds propagation infers 4X5, 1Y2 and 3Z4, hence maximum of 2×2×2 = 8 cases need to be checked for consistency
bounds(X, Y, Z):- [X] :: 1..5,
[Y] :: 1..2,[Z] :: 3..5,X #= Y + Z,labeling([X, Y, Z]).
Bounds propagation without search ()
Initially -4X4 and -4Y4 Consider Y = 2(X-1), so X = (Y/2)+1
Thus -1= min(Y)/2+1Xmax(Y)/2+1=3 Tighten -1X3, hence -1X3 and -4Y4
Consider Y = X Thus -1=min(X)Ymax(X)=3 Tighten -1Y3, hence -1X3 and -1Y3
Consider Y = 2(X-1), so X = (Y/2)+1 Thus 1/2= min(Y)/2+1Xmax(Y)/2+1=5/2 Tighten 0X2, hence 0X2 and -1Y3
Consider Y = X Thus 0=min(X)Ymax(X)=2 Tighten -1Y3, hence 0X2 and 0Y2
cross(X, Y) :-[X, Y] :: -4..4,Y #= 2*(X - 1),Y #= X.
[eclipse 8]: cross(X, Y).
X = 2Y = 2Yes (0.00s cpu)
Bounds propagation without search ()
The story so far 0X2 and 0Y2 Consider Y = 2(X-1), so X = (Y/2)+1
Thus 1= min(Y)/2+1Xmax(Y)/2+1=2 Tighten 1X2, hence 1X2 and
0Y2
Consider Y = X Thus 1=min(X)Ymax(X)=2 Tighten 1Y, hence 1X2 and 1Y2
Consider Y = 2(X-1), so X = (Y/2)+1 Thus 3/2=
min(Y)/2+1Xmax(Y)/2+1=2 Tighten 2X, hence 2X2 and 1Y2
Consider Y = X Thus 2=min(X)Ymax(X)=2 Tighten 2Y, hence 2X2 and 2Y2
cross(X, Y) :-[X, Y] :: -4..4,Y #= 2*(X - 1),Y #= X.
[eclipse 8]: cross(X, Y).
X = 2Y = 2Yes (0.00s cpu)
Bounds propagation without search ()
Initially 0X1 and 0Y1 Consider X = 1 – Y, thus
Thus 0=1-max(Y)X1-min(Y)=1 Cannot tighten X
Consider X = 1 – Y, thus Y = 1 - X Thus 0=1-max(Y)X1-min(Y)=1 Cannot tighten Y
Consider Y = X, thus Thus 0=min(X)Ymax(X)=1 Cannot tighten Y
Consider Y = X, thus X = Y Thus 0=min(Y)Xmax(Y)=1 Cannot tighten X
non_bit(X, Y):- [X, Y] :: 0..1,
X #= 1 – Y,X #= Y.
[eclipse 8]: non_bit(X, Y).
X = X{[0, 1]}Y = Y{[0, 1]}
Yes (0.00s cpu)
Bounds propagation versus search Bounds propagation is incomplete; it does not
always perform optimal interval pruning
It may not have the intelligence to infer that no solutions exist (in non_bit there are 4 cases to consider)
It may not have the intelligence to infer that only 3 solutions exist (in bounds there are 8 cases to consider)
When intelligence fails, resort to brute force
Follow bounds propagation with labelling to systematically enumerate the space to either:
Find a solution (bounds example)
Detect that no solutions exist (non_bit example)
Brute force versus divide-and-conquer
Consider a binary CSP where X = {A, …, H}, D = {A S, …, H S} and S = {0,1,2}
Now label E (see the next slide). E fixed so no propagation occurs from G
to E. Once E propagates to G, no more propagation can occur over the E-G constraint so it is as if it is not there.
Thus one CSP over {A,B,C,D} and another CSP over {F,G,H,J}.
The total number of configurations is 3(34 + 34) = 3(81 + 81) = 486 « 19683 = 39
Thus labelling can decompose a CSP into independent sub-CSPs that are cheaper to solve than the whole
A C
D E
F
G
H
J
A B C
D 0
F
G
H
J
A B C
D 2
F
G
H
J
A B C
D 1
F
G
H
J
Brute force versus divide-and-conquer
What is optimisation?Optimisation is the problem of satisfying a
CSP so as to minimise or maximise a solution with respect to a cost function.
A classic optimisation problem is the smuggler’s knapsack problem:
A smuggler has a knapsack of limited capacity, say 19 units. He can smuggle in bottles of whiskey of size 4 units, bottles of scent of size 3 units and boxes of cigarettes of size 2 units. The profits from a bottle of whiskey, scent and a box of cigarettes are 15 pounds, 10 pounds and 7 pounds respectively. The smuggler will only make a trip if he can make 30 pounds or more, so what does he take?
What is optimisation?
Solve the following CSP: The set of variables is X = {W, S, C, P} for
number of bottles of whisky, bottles of scent, boxes of cigarettes and the profits
The domain is D = {W {0,..,9}, S {0,…,9}, C {0,…,9}, P {0,…,10000}}
The set of constraints is C = {4W + 3S + 2C 19, P = 15W + 10S + 7C, 30 P}.
So as to maximise the value assigned to PA more realistic profit limit is 15.2 + 10.3 +
7.4 = 30 + 30 + 28 = 88
“Di-cho-tomic” search(for minimising a cost)
Dichotomic search is essentially bisection search built on top of a binary decision procedure for a CSP
Consider minimising a cost function represented by a variable x X
Note that the maximum number of iterations is log2(|D(x)|)
Note that top is not assigned to mid within the while loop
function dichotomic(CSP X, D, C, x X)begin bot := min(D(x)) top := max(D(x)) if X, D, C unsatisfiable then error while (bot < top) mid := (bot + top) / 2 if X, D, C {bot x mid} satisfiable top := D(x) else bot := (bot + top) / 2 + 1 return botend
Example minimisation
Solve the following CSP: The set of variables is X = {x, y} The domain is D = {x {-10,…,80}, y {-3,
…,14}} The set of constraints is C = {x = (y-4)2}.
So as to minimise the value assigned to xbot top mid := (bot + top) /
2X,D,C{botxmid} satisfiable?
-10 80 35 yes with {x 9, y 7}
-10 9 -1 no
0 9 4 yes with {x 1, y 5}
0 1 0 yes with {x 0, y 4}
0 0
What about maximisation?
The knapsack CSP revisited: The set of variables is X = {W, S, C, P, Q} for
number of bottles of whisky, bottles of scent, boxes of cigarettes and the profits
The domain is D = {W {0,..,9}, S {0,…,9}, C {0,…,9}, P {0,…,88}, Q {-88,…,0}}
The set of constraints is C = {4W + 3S + 2C 19, P = 15W + 10S + 7C, 30 P, P = -Q}.
So as to minimise the value assigned to QThe act of minimising Q maximises P
Maximisation in ECLiPSe
:- use_module(library(fd)).:- use_module(library(branch_and_bound)).
main(Profit, Goods) :-Goods = [Whisky, Scent, Ciggys],Goods :: 0..9,[Profit] :: 0..88,[NegProfit] :: -88..0,
4*Whisky + 3*Scent + 2*Ciggys #<= 19, Profit #= 15*Whisky + 10*Scent + 7*Ciggys, 30 #<= Profit,NegProfit #= -Profit,bb_min(labeling(Goods),
NegProfit, bb_options with [strategy:dichotomic]).
Dichotomic optimisation in ECLiPSe
[eclipse 28]: main(Profit, Goods).Found a solution with cost –35Found a solution with cost –63Found no solution with cost –88.0 .. –75.5Found a solution with cost –70Found no solution with cost –75.5 .. –72.75Found no solution with cost –72.75 .. –71.375Found no solution with cost –71.375 .. –70.375
Profit = 70Goods = [4, 1, 0]Yes (0.01s cpu)
Modeling and reification
Chapter 3: how to coerce a problem into a CSP (CLP)
How to organise your day
:- use_module(library(fd)).
main(Begins) :-Begins = [Beg_Work, Beg_Mail, Beg_Shop, Beg_Bank],Ends = [End_Work, End_Mail, End_Shop, End_Bank],Begins :: 9..17, Ends :: 9..17,End_Work #= Beg_Work + 4,End_Mail #= Beg_Mail + 1,End_Shop #= Beg_Shop + 2,End_Bank #= Beg_Bank + 1,End_Bank #=< Beg_Shop,End_Mail #=< Beg_Work,11 #=< Beg_Work,one_thing_at_a_time(Begins, Ends),labeling(Begins).
Can only perform one task at any given moment in time
In disjunctive scheduling, certain jobs, say tasks 1 and 2, cannot simultaneously use a resource
Modelling disjunctive scheduling with ECLiPSe
one_thing_at_a_time([], []).one_thing_at_a_time([Begin | Begins], [End | Ends]) :-
one_thing_at_a_time(Begins, Ends, Begin, End),one_thing_at_a_time(Begins, Ends).
one_thing_at_a_time([], [], _, _).one_thing_at_a_time([Begin1 | Begins], [End1 | Ends], Begin2, End2) :-
non_overlap(Begin1, End1, Begin2, End2),one_thing_at_a_time(Begins, Ends, Begin2, End2).
non_overlap(Begin1, End1, Begin2, End2) :-(Begin1 #>= End2) #\/ (Begin2 #>= End1).
How to organise your day
[eclipse 10]: main(Begins).
Begins = [13,12,10,9]More (0.00s cpu) ? ;
Begins = [13,10,11,9] ? ;More (0.00s cpu) ? ;
Begins = [13,9,11,10] ? ;More (0.00s cpu) ? ;
Begins = [11,10,15,9] ? ;More (0.00s cpu) ? ;
Begins = [11,9,15,10] More (0.00s cpu)
9 10 11 12 13 14 15 16
B S S M W W W W
B M S S W W W W
M B S S W W W W
B M W W W W S S
M B W W W W S S
Reified constraints
[eclipse 1]: [X, Y, B] :: 0..1,X #< Y #<=> B, X #= 0, Y #= 1.
B #= 1 is posted because X < Y is entailed (it is implied from now on)
[eclipse 2]: [X, Y, B] :: 0..1,X #< Y #<=> B, X #= 1, Y #= 0.
B #= 0 is posted because X < Y is disentailed (it can never be implied from now on)
[eclipse 3]: [X, Y, B] :: 0..1,X #< Y #<=> B, B #= 1.
X #< Y is posted to the store which, in turn, ensures X = 0, Y = 1.
[eclipse 4]: [X, Y, B] :: 0..1,X #=< Y #<=> B, B #= 0.
The negation of X #=< Y is posted to the store, that is, X #> Y, which, in turn, ensures X = 1, Y = 0.
[eclipse 5]: [X, Y, B] :: 0..1,X #< Y #<=> B, X #= 0.
Neither B #= 0 nor B #= 1 is posted because X < Y is entailed nor disentailed.
Instead of merely adding a constraint to the store, like X #< Y say, it is often useful to attach a flag, say B, to the constraint to test and set its truth or falsity
Reification for implementing disjunction
non_overlap(Begin1, End1, Begin2, End2) :-
[B1, B2] :: 0..1, Begin1 #>= End2 #<=> B1, Begin2 #>= End1 #<=> B2, B1 + B2 #> 1.
‘XgreaterthanYimpliesXlessthanZ’(X, Y, Z) :-
[B1, B2] :: 0..1,X #> Y #<=> B1,X #< Z #<=> B2,B1 #<= B2.
Reification for counting
:- use_module(library(fd)).
atmost(Ts, C) :- atmost_aux(Ts, 0, C).
atmost_aux([], Acc, C) :-Acc #=< C.
atmost_aux([T | Ts], Acc, C) :-[B] :: 0..1,Acc1 #= Acc + B,0 #< T #<=> B, atmost_aux(Ts, Acc1, C).
main(Ts, N) :-Ts = [T, _],Ts :: -1 .. 1,atmost(Ts, N),T #= 1.
[eclipse 24]: main(Ts, 2).Ts = [1, _211{[-1..1]}]Yes (0.00s cpu)
[eclipse 25]: main(Ts, 1).Ts = [1, _211{[-1..0]}]Yes (0.00s cpu)
[eclipse 26]: main(Ts, 0).No (0.00s cpu)
Consider the problem of writing a predicate atmost(Ts, C) which ensures that at most C elements of the list Ts are positive
The tennis tournament problem The problem is to schedule the matches
of a tennis tournament so as to minimise the total length of the tournament
Each of n competitors plays each of the other n - 1 competitors giving n(n - 1)/2 matches in all
Each match takes an equal amount of time and at most c matches can be contested simultaneously since there are c courts
No competitor can play two or more others at the same time
No competitor has back-to-back matches, that is, each competitor has at least one match's worth of rest between each match
How can the tennis tournament be modelled? The problem can be modelled by
upper triangular matrix which represents “who plays who and when”
A matrix for the n = 5 and c = 2 is
1 2 3 4 5
1 1 3 5 7
2 1 5 7 9
3 3 5 9 1
4 5 7 9 3
5 7 9 1 3
For n = 6 (our instance) the problem reduces to labelling a list Ts = [T12, T13, T14, T15, T16, T23, T24, T25, T26, …, T56] where Ts is constrained by Ts :: 1..Max_T
A predicate one_game_apart([T12, T13, T14, T15, T16]) will ensure that each of these time slots is separated by at least one game
How can we write one_game_apart?
one_game_apart([]).one_game_apart([H | T]) :-
one_game_apart(T, H),one_game_apart(T).
one_game_apart([], _).one_game_apart([H | T], D) :-% abs(H - D) #> 1,
(H - D #> 1) #\/ (D - H #> 1)one_game_apart(T, D).
Schedule at most c matches simultaneously
We need a predicate atmost(Ts, Time, C), say, which constrains Ts so that no more than C matches are played in a given time slot Time
my_atmost(Ts, Time, C) :- atmost_aux(Ts, 0, Time, C).
atmost_aux([], Acc, _, C) :-Acc #=< C.
atmost_aux([T | Ts], Acc, Time, C) :-
[B] :: 0..1,Acc1 #= Acc + B,Time #= T #<=> B, atmost_aux(Ts, Acc1, Time,
C).
Schedule at most c matches simultaneously
We need to call my_atmost multiply like my_atmost(Ts, 1, C), my_atmost(Ts, 2, C), …, my_atmost(Ts, HighestT, C) to cover all the time slots 1, 2, …, HighestT
courts(0, _, _).courts(Time, Ts, C) :-
Time > 0,my_atmost(Ts, Time, C),Time1 is Time - 1, courts(Time1, Ts, C).
bound_time([], _).bound_time([T | Ts], BoundT) :-
T #=< BoundT, bound_time(Ts, BoundT).
To perform minimisation, we need to find the maximum time slot occurring in Ts
It is sufficient to find an upper bound on the time slots in Ts
How does it all fit together?
main(Ts, C, BoundT) :- HighestT = 29, % 15 games on one court Ts = [T12, T13, T14, T15, T16, T23, T24, T25, T26, T34, T35, T36, T45, T46, T56], Ts :: 1..HighestT, [BoundT] :: 1..HighestT, one_game_apart([T12, T13, T14, T15, T16]), one_game_apart([T12, T23, T24, T25, T26]), one_game_apart([T13, T23, T34, T35, T36]), one_game_apart([T14, T24, T34, T45, T46]), one_game_apart([T15, T25, T35, T45, T56]), one_game_apart([T16, T26, T36, T46, T56]), courts(HighestT, Ts, C),
bound_time(Ts, BoundT),append(Ts, [BoundT], AllTs),
bb_min(labeling(AllTs), BoundT, bb_options with [strategy:dichotomic]).
Games schedules for 2 and 3 courts (4 is not better)[eclipse 28]: main(Ts, 2, BoundT).Found a solution with cost 13Found no solution with cost 1.0 .. 7.0Found no solution with cost 7.0 .. 10.0Found a solution with cost 11Ts = [1, 3, 5, 7, 10, 6, 9, 11, 3, 11, 9, 1, 2, 7, 5]BoundT = 11More (9.43s cpu) ?
[eclipse 28]: main(Ts, 3, BoundT).Found a solution with cost 13Found no solution with cost 1.0 .. 7.0Found a solution with cost 9Found no solution with cost 7.0 .. 8.0Ts = [1, 3, 5, 7, 9, 5, 7, 9, 3, 9, 1, 7, 3, 1, 5]BoundT = 9More (0.15s cpu) ?
1 2 3 4 5 6
1 1 3 5 7 10
2 1 6 9 11
3
3 3 6 11
9 1
4 5 9 11
2 7
5 7 11
9 2 5
6 10
3 1 7 5