<< Prev | - Up - | Next >> |
The functional procedure MakePredicate
inputs a dominance constraint and computes a solution predicate for it which in turn can be explored by encapsulated search, e. g. Search.all
or Explorer.all
.
The input dominance constraint - the graph - comes as a record which contains the number of nodes N
, i.e. the number of variables in the input constraint, and a procedure P
which represents the dominance constraint itself. Recall that such a procedure takes a list of node representations of length N
and imposes the set constraints encoding the dominance constraint.
A search predicate always has the same form: it is a unary predicate whose argument denotes a solution. First it posts all constraints on the solution, then it specifies a search/distribution strategy:
fun {MakePredicate 'unit'(domCon:DomCon vars:N)}
proc {$ Nodes}
<DC: create nodes>
<DC: translation to set constraints>
<DC: impose treeness>
in
<DC: distribute>
end
end
The solution Nodes
must be a list of N
nodes. Each variable is represented by a distinct integer between 1 and N
. Thus sets of variables can be represented by sets of integers. (We store the specification of the finite domain from 1 to N
in the variable VDom
.) For each variable, MakeNode
creates a term representing the node that is the interpretation of this variable.
VDom = [1#N]
{List.make N Nodes} % constrains Nodes to a list
% [_ ... _] of length N
for Node in Nodes I in 1..N do {MakeNode I VDom Node} end
Then we constrain these nodes using the procedure DomCon
that implements the dominance constraint. After this we execute choice skip end
whose only effect is to wait for stability; i. e. until constraint propagation has inferred as much as it could. Typically the dominance constraint DomCon
provides very strong constraints and it is a good idea to impose them first and wait until they have achieved full effect before going on with the quadratic number of expensive treeness constraints.
{DomCon Nodes}
% waits for stability
{Space.waitStable}
Now we impose the treeness constraint between every pair of nodes Ni
and Nj
. For every such pair we impose a choice which is controlled by its own choice variables with domain [1..4]. We collect the quadratic number of choice variables within the list ChoiceVariables
.
ChoiceVariables =
{List.foldRTail Nodes
fun {$ Ni|Ns Cs}
{List.foldR Ns
fun {$ Nj Cs}
<DC: treeness condition between Ni and Nj>
C|Cs
end Cs}
end nil}
Finally, we specify the distribution strategy: here we use First Fail on the choice variables. Each choice variable is a finite domain variable in [1..4]. First fail is a strategy which attempts to minimize the branching factor in the search tree: it picks a (non-determined) variable with the minimum number of remaining possible assignments.
{FD.distribute ff ChoiceVariables}
<< Prev | - Up - | Next >> |