In the following, each CLP(FD) predicate is described in more detail.
We recommend the following link to refer to this manual:
http://eu.swi-prolog.org/man/clpfd.html
Arithmetic constraints are the most basic use of CLP(FD).
Every time you use (is)/2
or one of the low-level
arithmetic comparisons ((<)/2
, (>)/2
etc.) over integers, consider using CLP(FD) constraints instead.
This can at most increase the generality of your programs. See
declarative integer arithmetic (section
A.9.3).
(is)/2
and (=:=)/2
over integers. See declarative integer arithmetic (section
A.9.3).(=\=)/2
by #\=/2 to obtain more
general relations. See declarative integer arithmetic (section
A.9.3).#=<
X. When reasoning
over integers, replace (>=)/2
by
#>=/2 to obtain more
general relations. See declarative integer arithmetic (section
A.9.3).(=<)/2
by #=</2
to obtain more general relations. See declarative integer arithmetic (section
A.9.3).#<
X. When reasoning
over integers, replace (>)/2
by
#>/2 to obtain more
general relations See declarative integer arithmetic (section
A.9.3).(<)/2
by #</2
to obtain more general relations. See declarative integer arithmetic (section
A.9.3).
In addition to its regular use in tasks that require it, this constraint can also be useful to eliminate uninteresting symmetries from a problem. For example, all possible matches between pairs built from four players in total:
?- Vs = [A,B,C,D], Vs ins 1..4, all_different(Vs), A #< B, C #< D, A #< C, findall(pair(A,B)-pair(C,D), label(Vs), Ms). Ms = [ pair(1, 2)-pair(3, 4), pair(1, 3)-pair(2, 4), pair(1, 4)-pair(2, 3)].
If you are using CLP(FD) to model and solve combinatorial tasks, then you typically need to specify the admissible domains of variables. The membership constraints in/2 and ins/2 are useful in such cases.
=<
I =<
Upper.
Lower must be an integer or the atom inf, which
denotes negative infinity. Upper must be an integer or
the atom sup, which denotes positive infinity.\/
Domain2
When modeling combinatorial tasks, the actual search for solutions is typically performed by enumeration predicates like labeling/2. See the the section about core relations and search for more information.
labeling([], Vars)
. See labeling/2.The variable selection strategy lets you specify which variable of Vars is labeled next and is one of:
The value order is one of:
The branching strategy is one of:
#\=
V, where V is determined by the value ordering options. This is the
default.#=<
M
and X #>
M, where M is the midpoint of the domain of X.At most one option of each category can be specified, and an option must not occur repeatedly.
The order of solutions can be influenced with:
min(Expr)
max(Expr)
This generates solutions in ascending/descending order with respect to the evaluation of the arithmetic expression Expr. Labeling Vars must make Expr ground. If several such options are specified, they are interpreted from left to right, e.g.:
?- [X,Y] ins 10..20, labeling([max(X),min(Y)],[X,Y]).
This generates solutions in descending order of X, and for each
binding of X, solutions are generated in ascending order of Y. To obtain
the incomplete behaviour that other systems exhibit with "maximize(Expr)
"
and "minimize(Expr)
", use once/1,
e.g.:
once(labeling([max(Expr)], Vars))
Labeling is always complete, always terminates, and yields no redundant solutions. See core relations and search (section A.9.9) for usage advice.
A global constraint expresses a relation that involves many variables at once. The most frequently used global constraints of this library are the combinatorial constraints all_distinct/1, global_cardinality/2 and cumulative/2.
?- maplist(in, Vs, [1\/3..4, 1..2\/4, 1..2\/4, 1..3, 1..3, 1..6]), all_distinct(Vs). false.
\
=, #<, #>, #=<
or #>=. For example:
?- [A,B,C] ins 0..sup, sum([A,B,C], #=, 100). A in 0..100, A+B+C#=100, B in 0..100, C in 0..100.
\
=, #<, #>, #=<
or #>=.?- tuples_in([[X,Y]], [[1,2],[1,5],[4,0],[4,3]]), X = 4. X = 4, Y in 0\/3.
As another example, consider a train schedule represented as a list of quadruples, denoting departure and arrival places and times for each train. In the following program, Ps is a feasible journey of length 3 from A to D via trains that are part of the given schedule.
trains([[1,2,0,1], [2,3,4,5], [2,3,0,1], [3,4,5,6], [3,4,2,3], [3,4,8,9]]). threepath(A, D, Ps) :- Ps = [[A,B,_T0,T1],[B,C,T2,T3],[C,D,T4,_T5]], T2 #> T1, T4 #> T3, trains(Ts), tuples_in(Ps, Ts).
In this example, the unique solution is found without labeling:
?- threepath(1, 4, Ps). Ps = [[1, 2, 0, 1], [2, 3, 4, 5], [3, 4, 8, 9]].
=<
S_j or S_j +
D_j =<
S_i for all 1 =<
i <
j =<
n. Example:
?- length(Vs, 3), Vs ins 0..3, serialized(Vs, [1,2,3]), label(Vs). Vs = [0, 1, 3] ; Vs = [2, 0, 3] ; false.
global_cardinality(Vs, Pairs, [])
. See global_cardinality/3.
Example:
?- Vs = [_,_,_], global_cardinality(Vs, [1-2,3-_]), label(Vs). Vs = [1, 1, 3] ; Vs = [1, 3, 1] ; Vs = [3, 1, 1].
?- length(Vs, _), circuit(Vs), label(Vs). Vs = [] ; Vs = [1] ; Vs = [2, 1] ; Vs = [2, 3, 1] ; Vs = [3, 1, 2] ; Vs = [2, 3, 4, 1] .
cumulative(Tasks, [limit(1)])
. See cumulative/2.task(S_i, D_i, E_i, C_i, T_i)
. S_i denotes
the start time, D_i the positive duration, E_i the end time, C_i the
non-negative resource consumption, and T_i the task identifier. Each of
these arguments must be a finite domain variable with bounded domain, or
an integer. The constraint holds iff at each time slot during the start
and end of each task, the total resource consumption of all tasks
running at that time does not exceed the global resource limit. Options
is a list of options. Currently, the only supported option is:
For example, given the following predicate that relates three tasks of durations 2 and 3 to a list containing their starting times:
tasks_starts(Tasks, [S1,S2,S3]) :- Tasks = [task(S1,3,_,1,_), task(S2,2,_,1,_), task(S3,2,_,1,_)].
We can use cumulative/2 as follows, and obtain a schedule:
?- tasks_starts(Tasks, Starts), Starts ins 0..10, cumulative(Tasks, [limit(2)]), label(Starts). Tasks = [task(0, 3, 3, 1, _G36), task(0, 2, 2, 1, _G45), ...], Starts = [0, 0, 2] .
automaton(Vs, _, Vs, Nodes, Arcs, [], [], _)
,
a common use case of automaton/8.
In the following example, a list of binary finite domain variables is
constrained to contain at least two consecutive ones:
two_consecutive_ones(Vs) :- automaton(Vs, [source(a),sink(c)], [arc(a,0,a), arc(a,1,b), arc(b,0,a), arc(b,1,c), arc(c,0,c), arc(c,1,c)]).
Example query:
?- length(Vs, 3), two_consecutive_ones(Vs), label(Vs). Vs = [0, 1, 1] ; Vs = [1, 1, 0] ; Vs = [1, 1, 1].
source(Node)
and sink(Node)
terms. Arcs
is a list of
arc(Node,Integer,Node)
and arc(Node,Integer,Node,Exprs)
terms that denote the automaton's transitions. Each node is represented
by an arbitrary term. Transitions that are not mentioned go to an
implicit failure node. Exprs is a list of arithmetic
expressions, of the same length as Counters. In each
expression, variables occurring in Counters symbolically
refer to previous counter values, and variables occurring in Template
refer to the current element of Sequence. When a transition
containing arithmetic expressions is taken, each counter is updated
according to the result of the corresponding expression. When a
transition without arithmetic expressions is taken, all counters remain
unchanged.
Counters is a list of variables. Initials is a
list of finite domain variables or integers denoting, in the same order,
the initial value of each counter. These values are related to Finals
according to the arithmetic expressions of the taken transitions.
The following example is taken from Beldiceanu, Carlsson, Debruyne and Petit: "Reformulation of Global Constraints Based on Constraints Checkers", Constraints 10(4), pp 339-362 (2005). It relates a sequence of integers and finite domain variables to its number of inflexions, which are switches between strictly ascending and strictly descending subsequences:
sequence_inflexions(Vs, N) :- variables_signature(Vs, Sigs), automaton(Sigs, _, Sigs, [source(s),sink(i),sink(j),sink(s)], [arc(s,0,s), arc(s,1,j), arc(s,2,i), arc(i,0,i), arc(i,1,j,[C+1]), arc(i,2,i), arc(j,0,j), arc(j,1,j), arc(j,2,i,[C+1])], [C], [0], [N]). variables_signature([], []). variables_signature([V|Vs], Sigs) :- variables_signature_(Vs, V, Sigs). variables_signature_([], _, []). variables_signature_([V|Vs], Prev, [S|Sigs]) :- V #= Prev #<==> S #= 0, Prev #< V #<==> S #= 1, Prev #> V #<==> S #= 2, variables_signature_(Vs, V, Sigs).
Example queries:
?- sequence_inflexions([1,2,3,3,2,1,3,0], N). N = 3. ?- length(Ls, 5), Ls ins 0..1, sequence_inflexions(Ls, 3), label(Ls). Ls = [0, 1, 0, 1, 0] ; Ls = [1, 0, 1, 0, 1].
#<
or #>.
For example:
?- chain([X,Y,Z], #>=). X#>=Y, Y#>=Z.
Many CLP(FD) constraints can be reified. This means that their truth value is itself turned into a CLP(FD) variable, so that we can explicitly reason about whether a constraint holds or not. See reification (section A.9.12).
For example, to obtain the complement of a domain:
?- #\ X in -3..0\/10..80. X in inf.. -4\/1..9\/81..sup.
For example:
?- X #= 4 #<==> B, X #\= 4. B = 0, X in inf..3\/5..sup.
The following example uses reified constraints to relate a list of finite domain variables to the number of occurrences of a given value:
vs_n_num(Vs, N, Num) :- maplist(eq_b(N), Vs, Bs), sum(Bs, #=, Num). eq_b(X, Y, B) :- X #= Y #<==> B.
Sample queries and their results:
?- Vs = [X,Y,Z], Vs ins 0..1, vs_n_num(Vs, 4, Num). Vs = [X, Y, Z], Num = 0, X in 0..1, Y in 0..1, Z in 0..1. ?- vs_n_num([X,Y,Z], 2, 3). X = 2, Y = 2, Z = 2.
For example, the sum of natural numbers below 1000 that are multiples of 3 or 5:
?- findall(N, (N mod 3 #= 0 #\/ N mod 5 #= 0, N in 0..999, indomain(N)), Ns), sum(Ns, #=, Sum). Ns = [0, 3, 5, 6, 9, 10, 12, 15, 18|...], Sum = 233168.
Think of zcompare/3
as reifying an arithmetic comparison of two integers. This means
that we can explicitly reason about the different cases within
our programs. As in compare/3,
the atoms
<
, >
and =
denote the
different cases of the trichotomy. In contrast to compare/3
though, zcompare/3
works correctly for all modes, also if only a subset of the
arguments is instantiated. This allows you to make several predicates
over integers deterministic while preserving their generality and
completeness. For example:
n_factorial(N, F) :- zcompare(C, N, 0), n_factorial_(C, N, F). n_factorial_(=, _, 1). n_factorial_(>, N, F) :- F #= F0*N, N1 #= N - 1, n_factorial(N1, F0).
This version of n_factorial/2 is deterministic if the first argument is instantiated, because argument indexing can distinguish the different clauses that reflect the possible and admissible outcomes of a comparison of N against 0. Example:
?- n_factorial(30, F). F = 265252859812191058636308480000000.
Since there is no clause for <
, the predicate
automatically
fails if N is less than 0. The predicate can still be
used in all directions, including the most general query:
?- n_factorial(N, F). N = 0, F = 1 ; N = F, F = 1 ; N = F, F = 2 .
In this case, all clauses are tried on backtracking, and zcompare/3 ensures that the respective ordering between N and 0 holds in each case.
The truth value of a comparison can also be reified with (#<==>
)/2
in combination with one of the arithmetic constraints (section
A.9.2). See reification (section
A.9.12). However, zcompare/3
lets you more conveniently distinguish the cases.
Reflection predicates let us obtain, in a well-defined way, information that is normally internal to this library. In addition to the predicates explained below, also take a look at call_residue_vars/2 and copy_term/3 to reason about CLP(FD) constraints that arise in programs. This can be useful in program analyzers and declarative debuggers.
For example, to implement a custom labeling strategy, you may need to inspect the current domain of a finite domain variable. With the following code, you can convert a finite domain to a list of integers:
dom_integers(D, Is) :- phrase(dom_integers_(D), Is). dom_integers_(I) --> { integer(I) }, [I]. dom_integers_(L..U) --> { numlist(L, U, Is) }, Is. dom_integers_(D1\/D2) --> dom_integers_(D1), dom_integers_(D2).
Example:
?- X in 1..5, X #\= 4, fd_dom(X, D), dom_integers(D, Is). D = 1..3\/5, Is = [1,2,3,5], X in 1..3\/5.
These predicates allow operating directly on the internal representation of CLP(FD) domains. In this context, such an internal domain representation is called an FD set.
Note that the exact term representation of FD sets is unspecified and will vary across CLP(FD) implementations or even different versions of the same implementation. FD set terms should be manipulated only using the predicates in this section. The behavior of other operations on FD set terms is undefined. In particular, you should not construct or deconstruct FD sets by unification, and you cannot reliably compare FD sets using unification or generic term equality/comparison predicates.
\/
Rest,
where Min..Max is a non-empty interval (see fdset_interval/3)
and Rest is another FD set (possibly empty).
If Max is sup, then Rest is the empty FD set. Otherwise, if Rest is non-empty, all elements of Rest are greater than Max+1.
This predicate should only be called with either Set or all other arguments being ground.
Either Interval or Min and Max must be ground.
Either Set or Elt must be ground.
fdset_subtract(inf..sup, Set, Complement)
.
The predicates in this section are not clp(fd)
predicates. They ended up in this library for historical reasons and may
be moved to other libraries in the future.
?- transpose([[1,2,3],[4,5,6],[7,8,9]], Ts). Ts = [[1, 4, 7], [2, 5, 8], [3, 6, 9]].
This predicate is useful in many constraint programs. Consider for instance Sudoku:
sudoku(Rows) :- length(Rows, 9), maplist(same_length(Rows), Rows), append(Rows, Vs), Vs ins 1..9, maplist(all_distinct, Rows), transpose(Rows, Columns), maplist(all_distinct, Columns), Rows = [As,Bs,Cs,Ds,Es,Fs,Gs,Hs,Is], blocks(As, Bs, Cs), blocks(Ds, Es, Fs), blocks(Gs, Hs, Is). blocks([], [], []). blocks([N1,N2,N3|Ns1], [N4,N5,N6|Ns2], [N7,N8,N9|Ns3]) :- all_distinct([N1,N2,N3,N4,N5,N6,N7,N8,N9]), blocks(Ns1, Ns2, Ns3). problem(1, [[_,_,_,_,_,_,_,_,_], [_,_,_,_,_,3,_,8,5], [_,_,1,_,2,_,_,_,_], [_,_,_,5,_,7,_,_,_], [_,_,4,_,_,_,1,_,_], [_,9,_,_,_,_,_,_,_], [5,_,_,_,_,_,_,7,3], [_,_,2,_,1,_,_,_,_], [_,_,_,_,4,_,_,_,9]]).
Sample query:
?- problem(1, Rows), sudoku(Rows), maplist(portray_clause, Rows). [9, 8, 7, 6, 5, 4, 3, 2, 1]. [2, 4, 6, 1, 7, 3, 9, 8, 5]. [3, 5, 1, 9, 2, 8, 7, 4, 6]. [1, 2, 8, 5, 3, 7, 6, 9, 4]. [6, 3, 4, 8, 9, 2, 1, 5, 7]. [7, 9, 5, 4, 6, 1, 8, 3, 2]. [5, 1, 9, 2, 8, 6, 4, 7, 3]. [4, 7, 2, 3, 1, 9, 5, 6, 8]. [8, 6, 3, 7, 4, 5, 2, 1, 9]. Rows = [[9, 8, 7, 6, 5, 4, 3, 2|...], ... , [...|...]].