Controlling Search (Cont)
Minimisation and Search Control
Recall that we are handling minimisation (so far) by assuming that our underlying system has a predicate
minimise(G,E) which minimises the value of E over all valuations which satisfy ESince we are relying on a built-in
minimise predicate, there is not a great deal we can do to make its search more efficientBut we can ensure that our goal G is efficiently implemented
We can use the tricks we have already discussed to make G more efficient in the required mode
But what is the required mode?
The important point is that in most implementations,
minimise will call G in the formE < m, G.
(where m is a fixed number) - that is, G is rather more constrained than in the context in which
minimise was calledExample
%leaflevel(BTree,Leaf,Depth) if Leaf is a leaf
%at depth Depth in binary tree BTree
leavlevel(node(null,X,null),X,0).
leaflevel(node(TL,_,_),X,D+1) :-
leaflevel(TL,X,D).
leaflevel(node(_,_,TR),X,D+1) :-
leaflevel(TR,X,D).

given the above tree and the goal
minimise(leaflevel(ta,X,D),D) (ie return the node of minimum depth)the goal
leaflevel(ta,X,D) will be executed in a mode where D is subject ot the constraint D<n for some fixed nHowever the implementation of
leaflevel can not make use of this constraint, and the goal will only fail when the search reaches a leafAdding the redundant constraint D>=0 will stop search once the minimum depth already discovered has been passed:
%leaflevel(BTree,Leaf,Depth) if Leaf is a leaf
%at depth Depth in binary tree BTree
leavlevel(node(null,X,null),X,0).
leaflevel(node(TL,_,_),X,D+1) :-
D >= 0,
leaflevel(TL,X,D).
leaflevel(node(_,_,TR),X,D+1) :-
D >= 0,
leaflevel(TR,X,D).
Specifying Deterministic Search
There are sometimes situations where there is potential backtracking in a constraint, where we as the model builders are sure that the backtracking will not be productive (note that if we are wrong, the model may well produce incorrect answers)
If-then-else
The first case is closely analogous to a construct which occurs almost everywhere in traditional programming languages:
(Gtest -> Gthen
; Gelse)
If Gtest succeeds, then Gthen is evaluated; backtracking may occur in Gthen
If Gtest fails then Gelse is evaluated; backtracking may occur in Gelse
But in neither case is there any backtracking in Gtest; if backtracking reaches Gtest, it fails
Examples
abs(X,Y) :-
(X >= 0 -> Y = X
; Y = -X).
gives no backtracking in modes where X is fixed, compared with
abs(X,X) :-
X >= 0.
abs(X,-X) :-
X < 0.
which may give rise to backtracking
But note that the first form may not give correct answers in other modes; for example, the query
abs(X, 2), X < 0.
will incorrectly return the answer 'no', whereas
X < 0, abs(X, 2).
will return the answer X = -2
far_or_equal(X,Y) :-
(apart(X,Y,4) -> true
; X = Y).
apart(X,Y,D) :-
X >= Y + D.
apart(X,Y,D) :-
Y >= X + D.
again
far_or_equal(1,6).
succeeds, and
far_or_equal(1,3).
fails, but
far_or_equal(1,Y), Y = 6.
also fails
Once
The other main restriction constraint specifies that only one solution to the goal is of interest
It is usually used where (the model designer believes that) any one solution is equivalent to any other
Again, if this is wrong, or if the goal is called in unexpected modes, the model may give incorrect answers
Example
intersect(L1, L2) :-
member(X,L1),
member(X, L2).
Given the goal
intersect([a,b,e,g,h], [b,e,f,g,i]).
The predicate will return a first success answer having used X = b
If some later part of the program fails and causes backtracking, the goal will re-evaluate, and after some searching, produce two further success answers using X = e and X = g
Since X is not available outside intersect, it follows that the rest of the program will behave exactly the same, and simply cause two further failures
This can be avoided by
intersect(L1, L2) :-
once ( member(X,L1),
member(X, L2)).
But note that the behaviour of this new version may be incorrect if L1 and L2 are not full instantiated
intersect([a,b], [X1,X2]), X1 = b.
will fail because the first solution has X1 = a
Extended Example
Omitted
Design
Omitted
Finite Constraint Domains
(Chapter 3)
Examples
Map Colouring Problem
Colour a map of Australia using only the colours red, yellow, blue given the constraint that no two adjacent states have the same colour
N Queens Problem
Place N queens on an N*N chessboard in such a way that no queen is attacking another
Matching Problems
As discussed in the graph theory part of the course
Backtracking Solver
Essentially the solver we have discussed in chapters 5 & 7
Node & Arc Consistency
Node Consistency
A primitive constraint c is node consistent with domain D if either it has more than one variable, or if every element of D is a solution of c (and a general constraint is node consistent if all its primitive constraints are)
Node Consistency Algorithm
For each single-variable primitive constraint p in turn
restrict the values in the current domain to those which provide solutions to p
Example
consider the constraint
X < Y, Y < Z, Z <= 2
and domain {1,2,3}
This is not node-consistent, since Z = 3 is inconsistent with the third primitive constraint
Applying the algorithm we get
D(X) = {1,2,3}, D(Y) = {1,2,3}, D(Z) = {1,2}
Arc Consistency
A primitive constraint c is arc consistent with domain D unless it has exactly two variables X and Y, and for some value of X in D, there is no value of Y in D which satisfies the constraint (and a general constraint is arc consistent if all its primitive constraints are)
Arc Consistency Algorithm
For each two-variable primitive constraint p in turn
restrict the values in the current domain to those which provide solutions to p
Example
consider the constraint
X < Y, Y < Z, Z <= 2
and domain {1,2,3}
This is not arc-consistent, since X = 3 is inconsistent with the first primitive constraint
Applying the algorithm we get
D(X) = {1, 2}, D(Y) = {1,2,3}, D(Z)={1,2,3}
Applying it to variable Y, we get
D(X) = {1, 2}, D(Y) = {2}, D(Z)={1,2,3}
Finally, applying it to variable Z, we get
D(X) = {1, 2}, D(Y) = {2}, D(Z)={3}
Node-Arc Solver
Applying the node and arc consistency algorithms together allows us to solve problems which cannot be solved by either separately
Node-Arc Algorithm
Apply the node and arc consistency algorithms indeterminately until the constraints are both node and arc consistent
Example
consider the constraint
X < Y, Y < Z, Z <= 2
and domain {1,2,3}
Applying arc consistency as before, we get
D(X) = {1, 2}, D(Y) = {2}, D(Z)={3}
Applying node consistency, we get
D(X) = {1, 2}, D(Y) = {2}, D(Z)=f
A further application of arc consistency (checking X before Y) gives
D(X) = {1}, D(Y) = f , D(Z)=f
Applying node consistency again gives no further simplification, but a further application of arc consistency gives
D(X) = f , D(Y) = f , D(Z)=f
Bounds Consistency
Hyper-Arc Consistency
One obvious extension of arc consistency (hpyer-arc consistency) is to extend it to primitive constraints with more than two variables
For example, consider the constraint
X = 3Y + 5Z
with D(X) = {2,3,4,5,6,7}, D(Y) = {0,1,2}, D(Z) = {-1,0,1,2}
The first check we would perform would substitute 2 for X and test for solutions (in the domain) for
2 = 3Y + 5Z
In general, this problem (diophantine equations) is too expensive to be built into a constraint solver
A better approach takes into account the fact that the domains of X, Y and Z are in fact continuous domains of integers
An arithmetic primitive constraint c is bounds consistent with integer domain D unless there is a variable x in c for which either c(x® minD(x)) or c(x® maxD(x)) is unsatisfiable for real values
(note that checking for real values is much simpler than for integer values, but if there are no real values, then there are no integer values as a consequence)
Depending on the form of the constraints, we may be able to devise propagation rules, which given a current set of ranges for the variables, generate a new set of ranges which are bounds consistent
Monotonic Bounds Consistency Algorithm
(eg for linear inequalities)
Until constraint c is bounds consistent with domain D
Choose a variable x in a primitive constraint c' of
c giving rise to a bounds inconsistency
If there is no real value minD(x) < x < maxD(x)
for which c' can be satisfied
return "unsatisfiable"
else
If x is minimum bound inconsistent
increase minD(x) until bounds
consistency is restored
else
decrease maxD(x) until bounds
consistency is restored
Example: Smuggler's Knapsack
Smuggler's knapsack has a capacity of 9 units
Size and profit of smuggle-able items are:
|
item |
size |
profit |
|
whiskey |
4 |
15 |
|
perfume |
3 |
10 |
|
cigarettes |
2 |
7 |
The minimum profit (ie risk premium) for a trip is 30; what are acceptable cargoes?
Capacity: 4W + 3P + 2C <= 9
Profit: 15W + 10P + 7C >= 30
Domain is initially [0..¥ ] for each variable
Applying bounds consistency for capacity to W, P and C in turn gives
D(W) = [0..2], D(P) = [0..3], D(C)=[0..4]
The profit constraint is bounds-consistent with this domain
Propagation rules for particular classes of constraint can be quite difficult to find; most solvers have built-in linear inequalities and a limited range of other classes
The applicability of a particular propagation rule will depend directly on the particular primitive form the solver rewrites the initial constraint to
Thus it can be hard to predict which bounds reductions will be achieved by the solver
Some Special Consistency Predicates
If you have looked at the eclipse libraries, you may have wondered why each library has so many special predicates
It relates to the point above, namely that each particular primitive constraint may have specific bounds consistency propagation rules
In many cases, complex constraints may have stronger propagation rules than the rules which could have been derived from more primitive constraints in terms of which they could have been defined
Example: alldifferent
alldifferent([V1,...,Vn])
asserts that the elements of the list are all distinct
It could be modeled by a conjunction of pairwise inequalities
Apart from the efficiency issue that n2 inequalities are required, there is also a constraint propagation issue
A propagation rule for
alldifferent can require that a valid domain for currently free variables has at least as many values as the number of variables remaining freeOn the other hand, if the problem is specified in terms of pairwise inequalities, there is no equivalent constraint which can be specified in terms of any particular primitive constraint
Example: cumulative
cumulative([S1,...,Sm],[D1,...,Dm],[R1,...Rm],L)
specifies that there are m tasks
The ith task starts at time Si, and requires Ri resources for duration Di; at any instant, only L resources are available
Cumulative could be defined more simply as a set of multiplicative equalities and inequalities, but propagation rules for cumulative could not be derived from those for the primitive constraints
Example: element
element(i,[V1,...,Vm],X)
specifies that X is the ith element of [V1,...,Vm] (it may also be required that the Vi are ordered)
The obvious propagation rules then permit the domains for i and for X to be closely linked, in ways which would not be possible if the constraint were re-rewritten in terms of primitive constraints
Optimisation for Arithmetic CSPs
Omitted