| Computational Logic |
| Constraint Programming: Finite Domains |
- Constraint domains in which the possible values that a variable
can take are restricted to a finite set.
- Examples: Boolean constraints, or integer constraints in which
each variable is constrained to lie in within a finite range of
integers.
- Widely used in constraint programming.
- Many real problems can be easily represented using constraint
domains, e.g.: scheduling, routing and timetabling.
- They involve choosing amongst a finite number of possibilities.
- Commercial importance to many businesses: e.g. deciding how air
crews should be allocated to aircraft flights.
- Developed methods by different research communities:
- Arc and
node consistency techniques (artificial intelligence).
- Bounds propagation techniques (constraint programming).
- Integer programming (operations research).
- In the artificial intelligence community, satisfaction of
constraint problems over finite domains has been studied under the
name of ``constraint satisfaction problems''.
- A constraint satisfaction problem (CSP) consists on:
- The CSP is understood to represent the constraint
.
- Examples of CSPs: map coloring and N-queens problem.
- Binary CSPs: the primitive constraints have at most two
variables (e.g. map coloring).
- It is always possible to determine the satisfiability of a CSP
by ``brute force search'': trying all combinations of different
values (finite number).
- However, this can be prohibitively expensive.
- Simplest techniques for determining satisfiability of an
arbitrary CSP is chronological backtracking:
- choosing a variable, and then, for each value in its
domain, determining satisfiability of the constraint which results
by replacing the variable with that value.
- This is done by calling the backtracking algorithm recursively.
- It uses the parametric function satisfiable(c), which takes
the primitive constraint c which involve no variables and returns
true or false indicating whether c is satisfiable
or not.
INPUT: a CSP with constraint
and domain
.
OUTPUT: Returns
if
is satisfiable (has one or more
solutions), otherwise
.
METHOD:
back_solve(
)
if
then return partial_satisfiable(
)
else choose
for each values
do
let
be obtained from
by replacing
by
if partial_satisfiable(
) then
if back_solve(
) then return
endif
endif
endfor
return
endif
partial_satisfiable(
)
let
be of the form
(each
is aprimitive constraint)
for
:= 1 to
do
if
then
if satisfiable(
)
then return
endif
endif
endfor
return
Exercise: apply the algorithm to the CSP with constraint
and domain
, such that
.
- There are solvers for CSPs which have polynomial worst case
complexity, but are incomplete.
- These solvers are based in the observation that if the domain
for any variable in the CSP is empty, then the CSP is unsatisfiable.
- Idea: transform the CSP into an ``equivalent'' CSP but one in which
the domains of the variables are decreased.
- ``Equivalent'' means that the constraints represented by the CSPs
have the same set of solutions.
- If any of the domains become empty, then this CSP, and also the
original, are unsatisfiable.
- These solvers work by considering each primitive constraint in
turn, and using information about the domain of each variable in the
constraint to eliminate values from the domains of the other variables.
- The solvers are said to be ``consistency'' based since they
propagate information about allowable domain values from one
variable to another until the domains are ``consistent'' with the
constraint.
- Two special domains may result after application of a
consistency based solver:
- False domain: if some variable in the domain is
mapped to the empty set.
- Valuation domain: if every variable is mapped to a
singleton set.
- The function
takes a constraint
and a valuation domain
and returns true or false,
indicating whether
is satisfiable or not under this valuation
(i.e. whether the constraint evaluates to true or false). Examples:
INPUT: a CSP with constraint
and domain
.
OUTPUT: a domain
such that the CSP with constraint
and
domain
is node consistent and is equivalent to the input CSP.
METHOD:
:= node_consistent(
).
node_consistent(
) (
is a constraint and
a domain)
let
be of the form
(each
is aprimitive constraint)
for
:= 1 to
do
:= node_consistent_primitive(
)
endfor
return
node_consistent_primitive(
)
if
then
let
(
is a variable)
:=
is a solution of
(
is a domain value).
endif
return
INPUT: a CSP with constraint
and domain
.
OUTPUT: a domain
such that the CSP with constraint
and
domain
is arc consistent and is equivalent to the input CSP.
METHOD:
:= arc_consistent(
).
arc_consistent(
) (
is a constraint and
a domain)
let
be of the form
(each
is aprimitive constraint)
repeat
:=
for
:= 1 to
do
:= arc_consistent_primitive(
) endfor
until
return
arc_consistent_primitive(
)
if
then
let
(
and
are variables)
:=
for some
,
is a solution of
:=
for some
,
is a solution of
endif
return
INPUT: a CSP with constraint
and domain
.
OUTPUT: Returns true, false or unknown. true
if the CSP is satisfiable (has one or more solutions); false if
the CSP is unsatisfiable (has no solutions); and
unknown if the algorithm is not able of determining the satisfaction of the CSP.
METHOD:
arc_solv(
)
:= node_arc_consistent(
)
if
is a false domain then return false
elseif
is a valuation domain then return
else return unknown
endif
node_arc_consistent(
)
:= node_consistent(
)
:= arc_consistent(
)
return
INPUT: a CSP with constraint
and domain
.
OUTPUT: Returns
if the CSP is satisfiable (has one or more
solutions), otherwise return
.
METHOD: if back_arc_solv(
) returns
, then return
, otherwise return
.
back_arc_solv(
)
:= node_arc_consistent(
)
if
is a false domain then return
elseif
is a valuation domain then
if
then return
else return
endif
endif
Choose a variable
such that
for each value
do
:= back_arc_solv(
)
if
then return
endif
endfor
return
- The restriction to integer and arithmetic constraints allows us
to define a new type of consistency: bounds consistency.
- A CSP is arithmetic if each variable in the CSP ranges over a
finite domain of integers and the primitive constraints are
arithmetic constraints.
- The most important class of CSPs (most problems of commercial
interest).
- Two ideas behind bounds consistency.
- Approximate the domain of a variable using a lower and upper
bound.
- Use real number consistency of primitive constraints rather
than integer consistency.
- A range
represents the set of values
if
, otherwise it represents the empty set.
- If
is a domain over integers,
and
are the minimum and maximum elements in
respectively.
- An arithmetic primitive constraint
is bounds consistent with
domain
if for each variable
there is:
- an assignment of real numbers, say
,
to the remaining variables in
, say
,
such that:
is a solution of
, and
for each
.
- another assignment of real numbers, say
,
to the remaining variables in
, say
,
such that:
is a solution of
, and
for each
.
- An arithmetic CSP with constraint
and domain
is bounds consistent if each primitive constraint
is bounds consistent with
for
.
- Since bounds consistency only depends on the upper and lower
bounds of the domains of the variables, when testing bounds
consistency, we need only consider domains that assign ranges to
each variable.
- Propagation rules methods: are efficient methods so that given a
current range for each of the variables in a primitive constraint,
they calculate a new range for each variable in the constraint,
which makes the constraint to be bounds consistent with the new
domain.
- Example: consider the simple constraint:
.
- It can be written in three forms:
and
- We can see that:
,
,
,
- It is easy to implement an algorithm for the propagation rules
for the constraint
.
INPUT: a domain
.
OUTPUT: a domain which is bounds consistent with the constraint
.
METHOD:
bounds_consistency_addition(
)
:=
:=
:=
:=
:=
:=
:=
:=
:=
return
INPUT: a domain
.
OUTPUT: a domain which is bounds consistent with the constraint
.
METHOD:
bounds_consistency_addition(
)
:=
:=
:=
:=
:=
:=
return
- Example:
- Propagation rules follow directly from:
bounds_consistent(
) (
is a constraint and
a domain)
let
be of the form
(each
is aprimitive constraint)
:=
while
do
choose
:=
:= bounds_consistent_primitive(
)
if
is a false domain then return
endif
for
:= 1 to
do
if there exists
such that
then
:=
endif
endfor
:=
endwhile
return
bounds_consistent_primitive(
)
- Applies the propagation rules for primitive constraint
to
the domain
and returns the new domain.
- We assume that the original CSP has been transformed into a CSP
containing only legitimate primitive constraints.
- The call to the function bounds_consistent_primitive(
)
removes the value
from the range of
giving the updated
domain:
,
,
.
- The constraint
is added to
, since the
range of variable
has changed.
- Another primitive constraint, say
, is removed from
, and its propagation rules are applied yielding the
domain:
,
,
.
- Since the range of variable
has changed, the constraint
is added to
.
- Further processing of the of the constraints,
and
, in
does not change the domain so the function
terminates returning this domain which is bounds consistent with
the constraint.
INPUT: an arithmetic CSP with constraint
and domain
.
OUTPUT: Returns true, false or unknown. true
if the CSP is satisfiable (has one or more solutions); false if
the CSP is unsatisfiable (has no solutions); and
unknown if the algorithm is not able of determining the
satisfaction of the CSP.
METHOD:
bounds_solv(
)
:= bounds_consistent(
)
if
is a false domain then return false
elseif
is a valuation domain then return
else return unknown
endif
INPUT: an arithmetic CSP with constraint
and domain
.
OUTPUT: Returns
if the CSP is satisfiable (has one or more
solutions), otherwise return
.
METHOD: if back_bounds_solv(
) returns
, then return
, otherwise return
.
back_bounds_solv(
)
:= bounds_consistent(
)
if
is a false domain then return
elseif
is a valuation domain then
if
then return
else return
endif
endif
Choose a variable
such that
for each value
do
:= back_bounds_solv(
)
if
then return
endif
endfor
return
- Consider the previous CSP (with constraint
and
domain
, such that
).
- The call to bounds_consistent(
) returns:
,
,
.
- The (complete) solver selects a variable, say
, and tries
different values in its domain.
- First, the (complete) solver calls itself recursively with the
constraint:
and the domain:
,
,
.
- The function bounds_consistent is evaluated with this new
constraint and domain.
- Constraint:
- Domain:
- Using the complete bounds propagation solver, we begin by
calling the bounds_consistent function with this constraint and
domain. This gives the domain:
- Then, choosing a branch on
, we first try adding
.
- Applying bounds_consistent returns:
- Now, choosing to branch on
, we add the constraint
. Applying bounds_consistent we get:
- So, we have found a solution:
,
,
.
- Note: this is not the optimal solution!
- We have seen three consistency based approaches to solving CSPs:
arc, node and bounds consistency.
- These can be combined with each other and also with specialized
consistency methods for ``complex'' primitive constraints:
- For constraints involving only two variables, we can use
the stronger arc consistency tests to remove values from the
domain.
- For constraints involving more than two variables, we can use
the weaker, but more efficiently computable, bounds
consistency approach.
- One of the weaknesses of the consistency based approaches is that
primitive constraints are examined in isolation from each other.
- Sometimes, knowledge about other primitive constraints can
dramatically improve domain pruning.
- For this reason, it is common to provide ``complex'' primitive
constraints which are understood as conjunction of simpler primitive
constraints but which have specialized propagation rules.
alldifferent_consistent_primitive(
) (
is a single alldifferent primitive constraint)
let
be of the form alldifferent(
)
while exists
with
for some
:=
for each
do
:=
endfor
endwhile
:=
:=
for each
do
:=
endfor
if
then return false endif
return
- For many problems, the aim is not simply to find any solution,
but rather, to find the optimal solution.
- The simplest approach to finding an optimal solution to an
arithmetic CSP is to make use of a complete solver for these
problems, and use it iteratively to find better and better solutions
to the problems:
- Use the solver to find any solution to the CSP.
- Add a constraint to the problem which excludes solutions
that are not better than this solution.
- The new constraint is solved recursively, giving rise to a
better solution.
INPUT: an arithmetic CSP with constraint
and domain
and an
arithmetic expression
which is the objective function.
OUTPUT: an optimal solution
or false if the CSP is
unsatisfiable.
METHOD: The answer is the result of evaluating
retry_int_opt(
).
retry_int_opt(
) (
is either asolution or false)
:= int_solv(
) (
is a valuation domain or false)
if
then
return
else
let
be the solution corresponding to
return retry_int_opt(
)
endif
INPUT: an arithmetic CSP with constraint
and domain
and an
arithmetic expression
which is the objective function.
OUTPUT: an optimal solution
or false if the CSP is
unsatisfiable.
METHOD: The answer is the result of evaluating
back_int_opt(
).
back_int_opt(
) (
is either asolution or false)
:= int_consistent(
,
)
if
is a false domain then return
elseif
is a valuation domain then return the solutioncorresponding to
endif
choose a variable
for which
:=
for each
do
if
then
:=
else
:= true endif
:= back_int_opt(
)
endfor
return
Last modification: Wed Nov 22 23:44:17 CET 2006 <webmaster@clip.dia.fi.upm.es>