To try the following examples, use the directive:
:- use_module(library(clpfd)).
to import the CLP(FD) library in SWI Prolog >= 5.6.50.
Basics
Consider a logical variable V that we want to use as a
placeholder for an integer between 0 and 2. We can express this on
the toplevel:
?- V in 0..2.
The system answers:
V in 0..2.
If we place additional goals on the toplevel, the system will
automatically take into account the range we specified for V, which
we call its associated
domain. In particular, the system will prevent us from
binding any values to V that are not part of its domain:
?- V in 0..2, V = 3.
false.
In contrast, the following query succeeds:
?- V in 0..2, V = 1.
V = 1 .
We can successively bind the variable to all values of its
associated domain via backtracking:
?- V in 0..2, indomain(V).
V = 0 ;
V = 1 ;
V = 2.
Now two variables X and Y, both constrained to the interval 0..2:
?- X in 0..2, Y in 0..2.
X in 0..2,
Y in 0..2.
Or, equivalently:
?- [X,Y] ins 0..2.
To enumerate values for X and Y:
?- [X,Y] ins 0..2, indomain(X), indomain(Y).
X = 0
Y = 0 ;
X = 0
Y = 1
... (7 other solutions omitted)
Assigning concrete values to constrained variables is called
labeling, and we can equivalently use the label/1 predicate:
?- [X,Y] ins 0..2, label([X,Y]).
Constraints
An n-ary constraint is a relation between n
variables and values that is taken into account when the
variables that are part of the constraint are instantiated. If
the constraint is not satisfied, or can be seen to be
unsatisfiable, the binding is revoked. For example, we can
constrain Z to be the sum of X and Y:
?- [X,Y] ins 0..2, Z #= X + Y.
X in 0..2,
X+Y#=Z,
Y in 0..2,
Z in 0..4.
The domain of Z could be deduced from the posted domains and
constraints without being stated explicitly. Narrowing domains based
on posted constraints is called (constraint) propagation. If
we bind Z to 0, the system can deduce that both X and Y must also
equal 0:
?- [X,Y] ins 0..2, Z #= X + Y, Z = 0.
X = 0,
Y = 0,
Z = 0.
In this case, propagation yields ground instances for all
variables. In other cases, constraint propagation can detect
unsatisfiability of a set of constraints without any labeling:
?- X in 0..1, X #> 2.
false.
In yet other cases, domain boundaries can be adjusted:
?- [X,Y] ins 0..2, Z #= X + Y, Z = 1.
Z = 1,
X in 0..1,
X+Y#=1,
Y in 0..1.
A set of constraints and variables with associated domains is
called (globally) consistent if all variables can be
simultaneously bound to (at least) one value of their respective
domains such that all constraints are satisfied. It is typically
too expensive for a constraint solver to guarantee global
consistency, so all variables must be labeled to detect
inconsistencies. However, there exist weaker forms of
consistency that are less expensive to guarantee.
The all_different/1 constraint can not detect unsatisfiability
of the following:
?- [X,Y,Z] ins 0..1, all_different([X,Y,Z]).
X in 0..1,
all_different([X, Y, Z]),
Y in 0..1,
Z in 0..1.
The all_distinct/1 constraint, in contrast, can detect the inconsistency
without labeling any variables:
?- [X,Y,Z] ins 0..1, all_distinct([X,Y,Z]).
false.
To guarantee that stronger form of consistency, the
all_distinct/1 constraint must do extra work for propagation. It
therefore depends on the problem at hand whether it pays off to
use it instead of all_different/1.
Labeling strategies
The predicate label/1 can be defined like this:
label([]).
label([V|Vs]) :-
indomain(V),
label(Vs).
In practice, the order in which variables are bound to concrete
values of their domains matters. A simple and often very effective
heuristics is to always label that variable next whose domain
contains the smallest number of elements. This strategy is called
"first-fail", since these variables are often most likely to cause
failure of the labeling process, and trying them early can prune
huge portions of the search tree. It is available
via labeling([ff], Vars).
For other problems, a static reordering of variables may
suffice. With N-queens for example, it is worth trying to order the
variables so that labeling starts from the board's center and
gradually moves to the borders.
Date: November 1st 2005
Main page