 |
 |
Constraint
Programming
within
CLIPS |
|
 |
|
Michel
Futtersack
|
|
Jean-Marc
Labat
|
CRIP5
Paris Descartes University
Paris FRANCE
|
|
LIP6
Pierre et Marie Curie University
Paris FRANCE
|
CCP is a generic knowledge base
which enables CLIPS to solve CSPs (Constraint Satisfaction Problems).
CCP is composed of three modules. The MAIN module contains the
top level loop including the I/O rules. The SEARCH module implements
a classical Chronological Backtrack algorithm. The PROPAGATION
module implements the Forward Checking algorithm.
CCP has been extensively tested with well known puzzles as N-queens,
graph colouring, crosswords, etc.
To implement any particular problem, the users only need to declare
each variable with its domain and they have to define specific
domain description and rules of propagation. So that all specific
knowledge is encapsulated in the PROPAGATION module.
CCP is a generic tool that can be embedded in a knowledge based
system like a work horse for local CSPs solving. CCP is compact,
since it contains only a dozen rules. Moreover, CCP can be seen
as a pedagogical tool illustrating many advanced features of CLIPS
(logical dependencies, forall, exists conditional elements, the
built function and a control strategy based on the focus stack)
1. Introduction
2. Basic Algorithms for Solving CSPs
2.1 Chronological Backtracking
2.2 Improving Backtracking with Heuristics and
with Forward Checking
2.3 Example : the 4-queens Problem
3. Presentation of CCP
3.1 the MAIN Module
3.2 the SEARCH Module
3.3 the PROPAG Module
4. Concluding
Remarks
5. References
CLIPS Sources
Appendix A Solving
5-queens with only one rule
Appendix B CCP's
Code
Appendix C Examples of Problems Solved by CCP
Download CCP's Code & Documentation
in RTF format
Download CCP's code and Documentation in Postscript format
An interesting discussion about CCP by Johan Lindberg
JESS Sources
CCP's Code
The Seat problem
| 1. Introduction |
 |
A wide variety of problems can
be described as Constraint Satisfaction Problems (CSPs) : time
table, cross-words, graph colouring, job shop scheduling, SAT
problems. Combinatorial optimization such as the assignment problem,
the Vehicle Routing Problem or the Knapsack Problem can be also
considered as CSP problems by transforming Max f(x) (respectively
Min) into f(x) > B (resp f(x) < B) where B is a given value,
high (resp low) enough to produce a good solution.
The CSP framework also offers a sound basis for representing and
solving decision problems without uncertainty [Schiex et al, 95].
All of these problems are at least NP-complete (see [Reeves, 93])
and huge instances require a large amount of computational resources.
This is the reason why all these problems are very important in
the field of Artificial Intelligence, with much research centered
on the discovery of new algorithms for CSPs .
But, the algorithms for solving CSPs are more often than not black
boxes. They do not enable you to solve problems needing Human
Computer Interaction. The most typical example is time-table for
schools. At least in France, there is no commercial software available
to satisfy teachers: in most cases, time tables are still hand-made.
It appears that, for some CSPs, it seems better to use knowledge
based systems.
The resolution of CSPs needs a mechanism of hypothesis generation
with backtracking when an impasse occurs (to be described later
in details). Our project stems from a knowledge base proposed
by [Laurière, 86] using an inference engine called SNARK
in which a function "REVENIR-SUR" directly implements
the backtrack mecanism. We do not have such a feature within CLIPS
(which is very costly since all the firings must be registered)
but we used instead the logical conditional element.
Of course, one can object that an inference engine using variables
realizes this mecanism before firing a rule. Such is the case
of the RETE algorithm [Forgy, 82] which implements the instantiation
of variables with backtrack when an impasse occurs. For example,
consider the well known puzzle in which there are five houses,
each of a different color, inhabited by men of different nationalities,
with different pets, drinks, and cigarettes. Given the initial
set of conditions, it must be determined which attributes are
assigned to each man. It can be solved with only one rule in which
each variable is represented by a conditional element (see the
Zebra knowledge base proposed within CLIPS 6.0). However, this
approach is very costly in terms of memory and solving N-queens
with twenty or more queens is impossible on a PC with 32 Mo using
the same way (see the rule in Appendix A) So, the aim of this
paper is to present the knowledge base we have designed using
CLIPS to go beyond this limit.
In the next section, we present the classical Chronological Backtrack
algorithm with a heuristic method to choose the next variable
to instantiate [Laurière, 78] and with Forward Checking
algorithm since [Haralick et al, 80] has proved that it is the
most efficient algorithm, at least for binary CSPs. Then, in Section
3, we present CCP (CCP stand for CLIPS Constraint Programming)
our generic knowledge base and the PROPAG module which is specific
to each problem. In Section 4, we conclude by introducing future
work using CCP.
2. Basic algorithms for solving
CSPs
| 2.1 Chronological
Backtracking |
 |
The basic algorithm used tosolve
CSPs is called Chronological Backtracking (CB). CB is a constructive
algorithm [Minton et al, 92], since it builds up a solution variable
by variable. The iterative process is decomposed into two steps.
First CB chooses a variable (called the current-hypothesis) and
instantiates it to the first possible value from its domain. Then
CB checks the constraints whose all variables are instantiated.
If one constraint fails, the algorithm backtracks. The previous
instantiation of the current-hypothesis is undone and, if it is
possible, replaced with another value (backtrack on the value).
If all the values of the current-hypothesis have been tested,
the algorithm backtracks to the previous instantiated variable
(backtrack on the variable). If the set of possible values is
empty for this variable, the algorithm backtracks again until
an instantiated variable with a non empty set of possible values
is found. This process continues until all the variables have
been successfully instantiated, which means a solution has been
found, or until all possible combinations of instantiations have
been tried out without success.
| 2.2 Improving
backtracking with heuristics and with Forward Checking algorithm |
 |
The drawbacks of the simple CB approach are obvious and well-known
and many improvements are possible. In our knowledge-based approach,
we have introduced two classical improvements. First, we use a
standard heuristic to choose the next variable to instantiate.
The heuristic consists to choose the variable with the smallest
remaining domain at each iteration of the algorithm. This is known
as "first fail principle". The second improvement adds
to the chronological backtrack a look-ahead scheme which attempts
to detect impasses as early as possible in the search. The aim
is to eliminate, in the domains of variables yet to be instantiated,
the values that are not consistent with the current instantiation.
This is called the propagation phase, since the new instantiation
gives new information on the current solution being constructed.
At least, three algorithms exist doing this kind of job: Forward
Checking, Partial Look-Ahead, Full Look-Ahead. We have retained
Forward Checking, known to be the best compromise between the
time spended on filtering the domains and the speed-up achieved
by avoiding useless instantiations. Forward checking filters the
domains of not instantiated variables which are directly linked
to the current-hypothesis by a constraint. Of course, when a backtrack
occurs, the inferences made during the propagation must be retracted.
| 2.3 Example:
4-queens problem. |
 |
Consider the classical 4-queens problem which consists to set
4 queens on a 4x4 in such a way that no one queen can capture
another. It is obvious that you have to set only one queen per
row (and per column). So, it is possible defining the problem
as setting a queen on each row where the place is defined by the
number of the column.
We obtain the following formulation:
Four variables Q1, Q2, Q3, Q4 where the number indicates the number
of the row
The starting domain of each variable is D = {1, 2, 3, 4}
The constraints between Qi and Qj are [if v(Di) is the value of
the variable Di]:
i-j # v(Di) -v(Dj) (no two queens on the same positive diagonal)
i-j # v(Dj) -v(Di) (no two queens on the same negative diagonal)
v(Di) # v(Dj) (no two queens on the same column).
The search tree (see Figure 1) shows the process until the first
solution is found. At the beginning (state 0), the board is empty.
At state 1, Q1 is the first current-hypothesis with 1 as value.
The Forward-Checking algorithm eliminates for Q2, Q3, Q4 the marked
squares. At state 3, it is worth noticing two points: As there
is no choice for Q3, since its domain only contains one value,
Q3 is not marked as a hypothesis. After the propagation of Q3
value, the domain of Q4 becomes empty. This denotes an impasse
and the search algorithm backtracks to the current hypothesis
which is Q2. Since there exists another value for Q2, it is a
backtrack on the value. At state 5, there is another impasse.
But this time, there is no another value possible for Q2, so it
is a backtrack on the previous instantiated variable, Q1. And
so on, until the first solution is found. One can notice that
on the hypothesis made at the state 6, there is no more hypothesis
until the solution is found.
In this example, the number of generated states is only 8. A simple
enumerative algorithm would have generated 77 states and Chronological
Backtracking without Forward-Checking, 31 states. More generally,
the number of nodes is dramatically reduced using Chronological
Backtracking with the "first fail" heuristic and Forward
Checking.
In Figure 1, a cross indicates a value retracted by the Forward
Checking algorithm. A gray square indicates a value which has
previously produced an impasse. Note that in the state 4, Q4 is
instantiated but it could have been Q3. The agenda contains two
activations of the rule forced-instantiation (see Section 3.2)
one with Q3 and one with Q4. No strategy exists for deciding which
one must fire first, so CLIPS chooses.
3. Presentation of CCP
CCP is composed of three modules: the MAIN module, the SEARCH
module and the PROPAGATION module. We will see that the MAIN module
and the SEARCH module are completely independent of the particular
problem. So, we put them into CCP.clp, a file that the users should
not change. They should just load it before the file containing
the PROPAG module which contains templates, facts and rules specific
to the users problem.
| 3.1 The MAIN
module |
 |
Three deftemplates are defined
into this module. The first one, called pb, describes the current
state of the problem and has three slots. The slot state describes
the state of the problem with the six following possible values
: start, in-progress, new-depth, choice-var, solved and blocked.
The slot level represents the number of recursive calls made by
the chronological backtrack during the search. At each new hypothesis,
a fact issued from pb template is duplicated with the slot level
incremented by one. This slot level allows us to backtrack on
the variable when it is necessary. The last slot is current-hypothesis
whose value is the variable chosen as an hypothesis at the current
level of the search.
The second template, called var, describes every variable of the
problem. The users must generate with this template all the variables
describing their problem. Since these facts are the only ones
which depend on the particular problem, we have decided that it
is better for the users to define their variables in the PROPAG
module, although the template is defined in the MAIN module. The
advantage we see is the users have nothing to introduce in the
MAIN module nor in the SEARCH module. The template contains four
slots which are name for the name of the variable, level for the
level in the stack (so, it has the same value that level in pb),
possible-values for the list of possible values remaining in the
domain at each level and value giving the value for an instantiated
variable. For example, you can see in Figure 2 the facts corresponding
to the templates pb and var at level 0 and 1 corresponding to
the state 0 and state 1 in Figure 1.
The third template solution is useful to count the number of solutions
and to register each solution into a mulislot var-val which is
a list containing each variable and its value (we tried initially
to construct a list of lists into the multislot var-val but it
does not seem possible with CLIPS).
The MAIN module contains five rules which are all independent
of the particular problem.
In the first rule, the users are asked if they want all the solutions
or if they prefer be asked after each found solution. We use the
build function to add the rule corresponding to the users choice.
Of course, using the build function is not necessary but it spares
one rule and it is a very simple but not trivial illustration
of the build function.
The second rule is a metarule which constructs the focus stack
when the problem is in progress. This value means that all the
propagations are made and that the problem is not solved, nor
blocked. So, it is necessary to make a new hypothesis. The rule
changes the value from in-progress to new-depth.
The third rule registers a new solution when it occurs.

Figure 1: The tree developped until the first solution is found
(using Chronological Backtracking with Forward-Checking)
The fourth rule stops the search
(no another solution or even no solution at all). This is the
case when the value of the slot state is blocked and the value
of the slot level is zero into the fact pb because no more backtrack
is possible (there is no another value in the domain of the first
variable chosen as current-hypothesis).
The final rule of this module prints the solution (default printing
method). If the users desire a customized printing we propose
them to define it in the PROPAG module.
|
(level-search 0)
- (pb (state start) (level 0) (current-hypothesis
no))
(var (name x4) (level 0) (possible-values 1 2 3 4) (value nil))
(var (name x3) (level 0) (possible-values 1 2 3 4) (value nil))
(var (name x2) (level 0) (possible-values 1 2 3 4) (value nil))
(var (name x1) (level 0) (possible-values 1 2 3 4) (value nil))
(level-search 1)
(pb (state in-progress) (level 1) (current-hypothesis x1))
(var (name x1) (level 1) (possible-values 2 3 4) (value 1))
(var (name x4) (level 1) (possible-values 2 3) (value nil))
(var (name x3) (level 1) (possible-values 2 4) (value nil))
(var (name x2) (level 1) (possible-values 3 4) (value nil))
|
Figure 2 : Facts corresponding
to the templates pb and var
| 3.2 The SEARCH
module |
 |
This module contains only rules
but it imports templates defined in MAIN. These six rules implement
the Chronological Backtrack with the "first fail" heuristic.
When the slot state of the fact pb at the current level is new-depth,
a new hypothesis must be made.
The first rule creates a new level of search. This means two new
facts: if the current level is ?n, a new ordered fact (level-search
(+ ?n 1)) is asserted and a fact pb is duplicated with the value
(+ ?n 1) for the slot level and the value choice-var for the slot
state.
This value activates the rule named choice-var-val which chooses
as current-hypothesis the most constrained variable (i.e. one
among those whose domain is the most reduced) and chooses as value
the first available in the domain. We will improve this choice
in the future, mainly by interacting with the users who can indicate
a good choice, using human properties as experience, social knowledge
or physical perception. After the instantiation of the current-hypothesis,
the propagation of this new information must be made immediately.
So the rule ends by focusing on the PROPAG module, which will
be described after the SEARCH module.
The three following rules of the SEARCH module analyse the result
of the PROPAG module according to the number of values remaining
in the domain of not yet instantiated variables. If the domain
of a not yet instantiated variable contains only one element,
there is no choice and the rule named forced-instantiation fires.
Notice that a forced instantiation does not generate a new level
in the stack but it is necessary to return immediately to the
PROPAG module. Even this rule must not be fired twice before returning
into the PROPAG module, since it can produce an erroneous instantiation.
For example, one can see in the state 2 of the Figure 1 that the
rule forced-instantiation can fire twice, once with Q3, once with
Q4. Of course, this does not produce a solution. When the domain
of at least one variable is empty, backtracking is necessary,
since the partial instantiation cannot produce a solution. Two
cases are possible. If there is another possible value into the
domain of the current-hypothesis, the current instantiation is
undone and the following value is chosen by the rule named backtrack-on-value.
To be consistent with this change of value, it is necessary to
retract all the inferences made by the PROPAG module. This is
made by means of the CLIPSís logical conditional element
feature which provides a truth maintenance capability. We obtain
the deletion of the facts var at the current level by retracting
the ordered fact (level-search ?n) (and reasserting it in the
same rule). In addition, the value of the slot state is changed
from blocked to in-progress and, as there is a new value for the
current hypothesis, it is necessary to return immediately in the
PROPAG module.The last case arrives when there is no further possible
value into the domain of the current-hypothesis. In such a case,
the rule named backtrack-on-variable fires. All the facts of the
current level must be deleted and the current level becomes the
previous one. One can notice that the value of the slot state
at the previous level must be blocked because the value of the
variable instantiated at this level must be changed. Moreover,
it is possible that several backtracks on variable must be made
consecutively. And, in all cases, after the rule backtrack-on-variable
fires, the rule backtrack-on-value must fire. For example, it
is the case in Figure 1 after the state 5. The current hypothesis
is Q2, (Q4 has a forced instantiation), the problem is blocked
and there is no more value for Q2. So the rule backtrack-on-variable
fires and just after the rule backtrack-on-value fires with Q1
(see Figure 3).
f-18 (level-search 1)
f-20 (variable (name x1) (level 1) (possible-values 2 3 4) (value
1))
f-27 (pb (state new-depth) (level 1) (current-hypothesis x1))
f-36 (level-search 2)
f-37 (variable (name x2) (level 2) (possible-values) (value 4))
f-41 (variable (name x4) (level 2) (possible-values) (value 3))
; x4 has a forced instantiation
f-42 (variable (name x3) (level 2) (possible-values) (value
nil))
f-43 (pb (state blocked) (level 2) (current-hypothesis x2))
; the rule "backtrack-on-variable" fires
f-18 (level-search 1)
f-20 (variable (name x1) (level 1) (possible-values 2 3 4) (value
1))
f-24 (variable (name x4) (level 1) (possible-values 2 3) (value
nil))
f-25 (variable (name x3) (level 1) (possible-values 2 4) (value
nil))
f-26 (variable (name x2) (level 1) (possible-values 3 4) (value
nil))
f-44 (pb (state blocked) (level 1) (current-hypothesis x1))
; the rule "backtrack-on-value" fires
f-45 (level-search 1)
f-46 (variable (name x1) (level 1) (possible-values 3 4) (value
2))
f-47 (pb (state in-progress) (level 1) (current-hypothesis x1)) |
Figure 3 : Some facts
showing the backtracking mecanism
The fourth rule stops the search (no another solution or even
no solution at all). This is the case when the value of the slot
state is blocked and the value of the slot level is zero into
the fact pb because no more backtrack is possible (there is no
another value in the domain of the first variable chosen as current-hypothesis).
The final rule of this module prints the solution (default printing
method). If the users desire a customized printing we propose
them to define it in the PROPAG module.
| 3.3 The PROPAG
module |
 |
As we remarked above this module
contains all the specific templates, facts and rules necessary
for a particular problem. First the users must create within the
template var the facts list containing all the variables describing
the problem. Two slots must be fill in: the slot name and the
multislot possible-values. After this necessary declaration, the
users have to define all the constraints they want to deal with.
We have noted that in all the problems we have treated, we have
to define some new templates in order to describe how the variables
interact. For example, in the N-queens problem we define a template
queen with the slot name (in order to make the link with the facts
issued from var) and the slot row because the number which suffixes
the value of the slot name indicates the number of the row (see
Figure 4)
(deffacts chessboard
(queen (name x1) (row 1))
(queen (name x2) (row 2))
(queen (name x3) (row 3))
(queen (name x4) (row 4))) |
Figure 4 : Facts issued
from the template queen
(defrule PROPAG::propagation-2
; if the queen ?x is placed in the ?n1 row and the ?v column
then remove
; from the list of possible values of the queen ?y all the values
; corresponding to the same diagonal
(logical (level-search ?n))
(not (level-search ?n1&:(> ?n1 ?n)))
(variable (name ?x) (value ?v&~nil) (level ?n))
(queen (name ?x) (row ?n1))
(queen (name ?y) (row ?n2))
?f <- (variable (name ?y) (value nil) (level ?m)
(possible-values $?liste&:(member$ (- ?v (- ?n1 ?n2)) ?liste)))
(not (variable (name ?y) (level ?m1&:(> ?m1 ?m))))
=>
(bind ?var (member$ (- ?v (- ?n1 ?n2)) ?liste))
(if (= ?m ?n) then (modify ?f (possible-values (delete$ ?liste
?var ?var)))
else (duplicate ?f (level ?n) (possible-values (delete$ ?liste
?var ?var)))))
?var ?var))))) |
Figure 5 : A rule of the PROPAG module for the N-queens
Of course, the propagation rules are very particular. But only
the LHS are specific, because the conditional elements describes
the constraints. The RHS of these rules are all the same, since
there is always one single action which deletes a value into the
domain of a not yet instantiated variable. In order to limit the
size of the fact-list, one can note that, when a new level is
created in the stack of hypothesis, we do not duplicate the variables.
We duplicate them only when a change occurs, i.e. the variable
is the current-hypothesis or the variable is concerned by the
propagation. This appears in our rules in the PROPAG module since
in the RHS we need an "if then else" function. If it
is the first reduction of its domain at the current level, then
we need to duplicate the variable, otherwise we have just to modify
it. (see Figure 5).
| 4 Concluding
remarks |
 |
Of course, the performance of
this knowledge base cannot be compared with the specialized CSPs
algorithms in terms of time efficiency. However, we had two ideas
in mind while developping this knowledge base.
First, from a pedagogical point of view, one can use CCP to explain
the mecanism of Chronological Backtracking with Forward Checking
and the "first fail" heuristic. Another pedagogical
point of view is the use of many advanced features of CLIPS: the
build function, a control strategy based on the management of
the focus stack, the forall, exists and overall the logical conditional
element.
Secondly, and this is the most important point, we would embed
CCP into a larger knowledge base, since we have noted that, in
some cases, solving a problem needs exploring hypotheses locally.
Moreover, even with pure CSPs, the use of a knowledge based system
must be very efficient, particulary in order to introduce interaction
between the human and the computer during the solving process.
| References |
 |
[Forgy, 82] C. L. Forgy: "Rete: a Fast Algorithm for the
Many Pattern/Many Object Pattern Match Problem", AI 19-1,
17-37, 1982
[Haralick et al, 80] R. M. Haralick, G. L. Elliott : "Increasing
Tree Search Efficiency for Constraint Satisfaction Problems",
Artificial Intelligence (14) 263-313, 1980
[Laurière, 78] J.-L. Laurière: "A Language
and a Program for Stating and Solving Combinatorial Problems",
Artificial Intelligence (10) 29-117, 1978
[Laurière, 86] J.-L. Laurière: "Un langage
déclaratif: SNARK", Revue Technique et Science informatiques,
vol 5, n°3, 141-171, 1986
[Minton et al, 92] S. Minton, M. Johnston, A. Philips and P. Laird:
"Minimizing Conflicts: a Heuristic Repair Method for Constraint
Satisfaction and Scheduling Problems", Artificial Intelligence
(58) 161-205, 1992
[Reeves, 93] C. Reeves: Modern Heuristic Techniques for Combinatorial
Problems, Blackwell, 1993
[Schiex et al, 95] T. Shiex, H. Fargier, G. Verfaillie: "Valued
Constraint Satisfaction Problems: Hard and Easy Problems",
Proceedings of IJCAI 95, 631-637, 1995