Constraint Satisfaction with an ObjectOriented Knowledge Representation Language Yves Caseau Bellcore, 445 South Street, Morristown NJ 07962, USA. e-mail:
[email protected]
Abstract This paper gives a detailed presentation of constraint satisfaction in the hybrid LAURE language. LAURE is an object-oriented language for Artificial Intelligence (AI) applications which allows the user to combine rules, constraints and methods that cooperate on the same objects in the same program. We illustrate why this extensibility is necessary to solve some large and difficult problems by presenting a real-life application of LAURE. We describe the syntax and the various modes in which constraints may be used, as well as the tools that are proposed by LAURE to extend constraint resolution. The resolution strategy as well as some implementation details are given to explain how we obtain good performances.
1.
Introduction
LAURE is an object-oriented language developed for "advanced" applications (AI in particular) where some form of reasoning is embedded in the software, such as expert systems, scheduling or travel optimization programs or "intelligent" computed-aided design. For such applications, the object-oriented approach, from design to programming, has shown to have many advantages mainly because it helps in the organization of the data domain. However, if object-oriented languages like C++[Str86] or SMALLTALK[GR83] offer a real improvement over traditional languages like C because of their modelling abilities, they still rely on the same computing paradigms, namely procedural or functional (e.g., CLOS [B&al88]). Thus, previously mentioned applications that imply complex processing cannot be implemented easily with available object-oriented languages and have required the development of more (computationally) expressive languages. Our first step towards solving this problem was to make LAURE a deductive language. LAURE incorporates deductive rules, which can be processed in a top-down manner (recursive query processing [Vi86]) or in a bottom-up manner (production rules). Such rules occur naturally and frequently in the specification of "advanced" application and their translation into a procedural language is tedious and error-prone [Ca89]. We developed a logical language for LAURE that allows a declarative style of programming
- 2 -
which is closer to the specifications and which is compiled efficiently through a relational algebra. This first step in the development of LAURE has been covered in detail in [Ca91a] where both motivations and implementation strategies are discussed. However, many "advanced" applications deal with incomplete information and the process of completion according to specification. This yields two problems, one of data representation and one of computing paradigm. A failure to capture such incomplete information in the data model means that the user must represent it with special values for which the interpretation is buried in the details of the program. Our experience is that such a strategy applied to a large problem leads to chaos, such as the SAM database described in [INV91]. Similarly important is the definition of a computation paradigm well suited to efficient problem solving. Rules are not adequate to describe how the search of a valid completion should be performed, unless the search space is really small. We have also experienced at Bellcore a lot of difficulties trying to use ART (an expert system shell) for such applications. Many interesting data models have been proposed to incorporate incomplete information, but automated constraint satisfaction is actually a much harder issue. In addition to the AND/OR model [INV90], one can think of the numerous disjunctive deductive database models that have been proposed (e.g., [AKG87]). However, few of them offer a convincing resolution strategy and almost none have been implemented and tested over a sample of real-life problems. On the other hand, the integration of constraint and logic has produced many families of implemented systems, such as CHIP [VH89] or CLP(R) [JL87]. Those systems combine the elegance and the expressive power of logic programming with an efficient search technique (improved arc-consistency on finite domains [VH91] for CHIP or linear programming tools for CLP(R) [CLP]). Our approach with LAURE is similar in the sense that we have incorporated some efficient search techniques into a high-level object-oriented deductive language. Because of our target problems, we are dealing with finite order-sorted domains [Ca91b], which explains why these techniques have been derived from those developed in CHIP. LAURE is a true hybrid language, which means that constraints, rules, and methods (procedural code) can be combined in the same program and cooperate. In the same way that we had developed inference techniques suited for the object-oriented approach we also propose a notion of constraint on objects and associated resolution techniques that are relevant to the object-oriented approach and significantly differs from CLP. This makes LAURE an extensible constraint solver since rules and methods can be used to guide constraint resolution. We believe that this is an essential feature of LAURE because many of the application problems that we have tried were too difficult to be solved by a pure (generic) constraint solver and required domain-dependent techniques. We shall present such a problem and show how LAURE supports the extension of the constraint solver through rules and methods. In this paper we give a complete description of constraint satisfaction in LAURE, and we put our emphasis on applications and practical use. LAURE is
- 3 -
a large implemented system (100,000 lines of C code) which has be used for many applications. LAURE was designed with large applications in mind (up to 100,000 objects), and is usually coupled with a database (object-riented or relational) containing the description of the problem. On the other hand, LAURE relies on the virtual memory of UNIX® 1 to store all the objects that are necessary for constraint resolution at run-time. Its semantics and other theoretical aspects have been covered in [Ca91a] (algebra and deduction), [Ca91b] (domain reduction) and [Ca91c] (constraint semantics). This paper is organized as follows. Section 2 motivates our approach with two real-life examples that we have implemented with LAURE. The first example is simple and illustrate the link between objects and constraints. It shows that constraints arise naturally and that introducing logic variables is not always desired. It also motivates the notion of reactive resolution. The second example is more complex and justifies the need for an extensible constraint solver. Section3 describes constraints in LAURE from a practical perspective. We show how to attach constraints to objects through sets and abstract objects. We introduce many complementary notions such as dependencies or integrity constraints which are useful to specify problems in a more natural manner. Section4 deals with constraint resolution. We first give an overview of the semantics and present the strategy that we use for resolution, including the various modes that we have implemented. We then discuss the notion of solution querying, where each solution is seen as a database state [KKR90]. We also present some techniques that we have developed for reactive resolution. Section5 presents some interesting aspects of the implementation. We first describe the data structures used for the world mechanism and for logic relations. We then give some insights on the use of the relational algebra for pre-solving equations and compiling into low-level code. The last section concludes with a comparison of other similar approaches to constraint satisfaction: finite domain constraint solvers and languages that mix objects and constraints.
2. Motivating Examples 2.1. Automatic Graphical Layout 2.1.1. Description of the
Problem
Our first example is a graphical layout for a user interface management system. This system is itself a part of a network monitoring system [GGN90] where data is collected from a telephone network and displayed to the user in a format that is specified as a set of constraints. Those constraints are 1
UNIX is a registered trademark of UNIX Systems Laboratories, Inc.
- 4 -
made of a set of generic constraints proposed by the system and a set of additional constraints proposed by the user to suit his domain (what kind of network and what type of application). For instance, constraints are used to specify the relative position of two graphical objects (e.g., they must not not overlap, one must be on top of another, they must stay at a given distance from one another, they must touch one another, etc.). Other constraints relate their attributes such as size or color (e.g., relation between the text and the background window, automatic scaling of dependent windows). Two interesting points can be made. First, the use of constraints to implement UIMS is a very common and practical idea. The specification of such a system is usually a set of constraints, so it seems natural to use them in the implementation, in order to improve extensibility and maintenance. The work on Thinklab [BMM89] and Kaleidoscope [Fre90] is a good example of such systems. Although performance is often an issue, propagation techniques work fine for simple problems and the previous advantages translate in user-friendliness. Secondly, the kind of constraints that occur in a truly declarative system are hard to solve. Although the previously mentioned systems have dealt with constraint classes that can be reactively solved with propagation, many graphical relations, such as non-overlapping, involve disjunctions. When we add disjunctions, such a constraint problem becomes NP (actually NP-hard since we can reduce an integer cutting problem into it). This clearly means that we need search techniques to deal with such problems. Most of the original network monitoring system was developed with Objective-C. There is no need to recall why an object-oriented representation is well suited to graphical applications (which is the domain of object-oriented programming by excellence). More interestingly, it also follows that the constraints through which the UIMS is specified applies to objects, as we shall now see. 2.1.2. Description of the Objects Here we describe some of the objects involved in this problem and their associated constraints. There are two sorts of objects: the d o m a i n objects which represent graphical items such as windows, scroll-bars, etc. and the d i s c o u r s e objects which represent relationship or constraints over the graphical items. Here is some LAURE code that defines some graphical objects, which is self-explanatory. More detailed explanations about LAURE and its syntax will be given in Section 3. The first line defines a common root in the hierarchy. [define GRAPHICAL_OBJECT union superclass {object}] [define RECTANGLE class superclass {GRAPHICAL_OBJECT}] [define WINDOW class superclass {GRAPHICAL_OBJECT}, with slot( TitleBar -> RECTANGLE), slot( Title -> string), slot( Frame -> RECTANGLE)] ...
- 5 -
[define Xul attribute domain RECTANGLE, -> {0 -- MaxX}, comment "x-coordinate of the upper left corner"] [define Yul attribute domain RECTANGLE, -> {0 -- MaxY}, comment "Y-coordinate of the upper left corner"] ...
Note that we use an integer coordinate-based representation as was used in the real system. Two other possibilities, which we shall discuss later, are to use real numbers or points (complex numbers, number pairs or any isomorphic structure). This choice is important since it changes the constraints' domains and the resolution techniques that we may use. Let us illustrate how the objects would be defined if we wanted to build a new domain (points) since we will develop this solution further in the paper. [define POINT class superclass {value}, with slot( x -> integer), slot( y -> integer)] [define UL attribute domain RECTANGLE, -> POINT, comment "upper left corner"] [define DR attribute domain RECTANGLE, -> POINT, comment "down right corner"]
Let us now consider the graphical specifications and see why it is natural to introduce other objects to represent them. We could either use relations or explicit constraints to represent the previously mentioned graphical dependencies between objects. However, extensional relations in LAURE are only binary (as in any object-oriented language) and we very often need extra parameters such as with a distance constraint where the distance between two objects is either a number or an interval. In this case, it is traditional with an object-oriented approach to represent each tuple of a nary relation [Ca91a] by an object of a class. On the other hand, writing a constraint for each desired dependency is tedious and not readable with too many objects. Creating new classes of objects yields a much more compact representation, which is more user-friendly and actually more efficient to process. We define a new class for each type of relationship between graphical objects, for example: [define ABOVE :: class superclass {object}, with slot( r1 -> RECTANGLE), slot( r2 -> RECTANGLE)]
[define DISJOINT class superclass {object}, with slot( r1 -> RECTANGLE), slot( r2 -> RECTANGLE)]
- 6 -
[define DISTANCE class superclass {object}, with slot( r1 -> RECTANGLE), slot( r2 -> RECTANGLE), slot( d -> INTEGER)]
We then instantiate these classes as many times as we want. ABOVE[ r1 A r2 B] will produce a new instance of the class ABOVE, which we mean to represent the fact that rectangle A is above rectangle B. The meaning associated with each class is described formally by a generic constraint. For instance, here is the constraint that defines the DISJOINT class: [define disjoint_spec constraint for_all (D DISJOINT), if xul1 = Xul(r1(D)), xdr1 = Xdr(r1(D)), yul1 = Yul(r1(D)), ydr1 = Ydr(r1(D), xul2 = Xul(r2(D)), xdr2 = Xdr(r2(D)), yul2 = Yul(r2(D)), ydr2 = Ydr(r2(D)), then [or ydr2 > yul1, ydr1 > yul2, xdr1 < xul2, xdr2 < xul1]]
This constraint states that the condition [or ....] must hold for any two rectangles r1(D) and r2(D) which are bound by an object D from the class DISJOINT.
2.1.3. Expected behavior As we shall see in the next sections where we give the syntax and semantics for constraints in LAURE, each constraint is a formula that limits the values that some relations (such as Xul) can take. What we expect from the specification as a set of constraints is the conjunction of three behaviors: • integrity checking: whenever an update is made on the object relations, we expect the system to check that the constraints are still satisfied. We call an integrity constraint (cf. Section 3.3.1) a constraint for which this is the only task we expect from the system. • problem solving: if some graphical objects are partially specified (i.e., some of their logic attribute are unknown yet), constraints can be seen as laws about their possible completions. We expect the system to find the completion when it is unique or propose a valid one when there are many solutions. • reactive solving: in a reactive environment such as a user interface, static solving is used only once (initial setting). The goal is to follow the evolution of monitored objects and dynamically find a new solution to the set of constraints each time an update is made. This new solution is both to be found more efficiently than by a complete search because the new update is used as a propagation pattern, but also to be close to the original solution, since we do not want a local perturbation to cause a major change unless it is absolutely necessary.
- 7 -
Note that although automatic layout is a common and easy-tounderstand problem, there is no available system to our knowledge that solves complex disjunctive problems and solves them reactively. Reactive resolution is performed by propagation in systems like Thinklab and cannot handle complex search strategies. Efficient finite domain solvers such as CHIP do not usually work in a a reactive mode. As a matter of fact, a reactive resolution is more than a simple recomputation of a new solution, since the notion of distance from the old solution implies that the user may specify how perturbation should be processed. The partial solution that we have implemented in LAURE will be described in Section 3.3.3.
2.2
Time-Constrained Traveling Salesman
2.2.1 An Optimization Problem Our second problem is extracted from a large optimization/assignment problem. In this problem we try to assign a set of tasks (many thousands) to a set of technicians (some hundreds) so as to minimize travel time (each task has to be performed at a given location), satisfy time constraints (each task must be performed within a given time window) and other matching constraints (based on skills, preference, etc.). This problem is described in [CK92], where we also show that we need to efficiently solve the subproblem with only one technician. In this paper we will present this sub-problem to illustrate some of our claims. This is a Time-Constrained Traveling Salesman Problem (TCTSP, Fig. 1), which is defined as a graph of tasks (each node) that is a distance graph (the weight of each edge is the sum of the duration of the task and the actual distance between its two nodes), with a time window for each node. A time window is made of two times (atleast and a t m o s t ) between which the task must start. A solution to such a problem is a hamiltonian circuit (the starting location is given) where the cumulated travel time satisfies all the time windows. Here we look for an optimal solution, which is a solution with the smallest travel time and end time (in a lexicographic order). 50
14:00 - 16:00 50
10
10
10 30 8:00 - 16:00
10:00 - 16:00 10
20
10:00 - 11:00
10:00 - 14:00 10 10
20 10:00 - 18:00
Figure 1: A Time-Constrained Traveling Salesman Problem
There are many ways to approach such a problem, which we call strategies. A strategy is defined by the set of logic relation that we want to build (for instance a circuit may be represented by a N e x t relation which links each task to its follower), by the set of constraints that we need to satisfy and by the set of heuristics that we want to use to help the search. A
- 8 -
discussion of various strategies for this problem may be found in [CK92]; here we present a simplified version of the strategy that we are actually using. Here is a first naive version of this approach. We build the hamiltonian circuit with the Next relation and we use the relation Start to represent the starting time for each task. We use two distinguished objects TS and TE to represent the start and end of the tour respectively: [define Next attribute domain {{TS} + TASK}, -> {{TE} + TASK}] [define Start attribute domain {{TS,TE} + TASK}, -> integer]
We can now state some constraints, using the variable *goal* to represent the maximum amount of time we allow for the tour: ;; Next is an injective relation dependency( from Next, on {{TS} + TASK} ) ;; we do not allow useless delays [define tight constraint for_all T:TASK, if x = Start(T), y = Start(Next(T)), then y = ((x + (T distance Next(T))) min atleast(Next(T)))] ;; we must not be late [define respect constraint for_all T:TASK, if x = Start(T), then x < (atmost(T) min *goal*)]
Note that the t i g h t constraint will prevent the formation of cycles (assuming non-zero distance). This program will find a solution in less than *goal* units of time (minutes) and we may find the optimal solution by iteration. To ask for a solution we would write: (Start(TS) is 0) [for x in {{TS} + TASK}, (Next(x) to_solve)] ;; we want to build the circuit [for x in {{TE} + TASK}, (Start(x) to_solve)] ;; we need a schedule search(solver) ;; calls the search
2.2.2 Knowledge and Heuristic If we run the previous LAURE program, we will get the right solution, but poor performances. For instance, it will be slower than an optimized dynamic programming algorithm which exists for this problem. To improve the performance we must add extra knowledge about this domain to the program. In this case, this knowledge comes from our previous experience with scheduling and graph problems. For instance, if there are many time constraints, it is important to detect precedence (ordering among tasks). This ordering information will reduce the possible choices for the constraint solver. From the ordering we can update the atleast/atmost as we would do in a scheduling problem. Here is a
- 9 -
sketch of the LAURE code for this. We first define an additional relation and then we write some rules to deduce ordering. [define Before multi_attribute domain {{TS} + TASK}, -> {{TE} + TASK}] [define order axiom for_all x:TASK, y:TASK, if (atmost(x) + (x distance y)) < atleast(y), then Before(x,y)] [define obvious axiom for_all x:TASK, y:TASK, if Next(x) = y, then Before(x,y)] [define propagate_up axiom for_all x:TASK, y:integer, if [ exists z:TASK, Before(z,x), y = (Atleast(z) + (z distance x)), y < Atleast(x)], then atleast(x,y)] [define propagate_down ....
We can now verify that there are no impossible tasks prune the search tree otherwise.
at any time and
[define nononsense constraint for_all x:integer, y:integer, if [exists z, atleast(z) = x, atmost(z) = y], check x T, T -> P, V -> T, then (P * V) = (n(x) * R * T) )
A relaxation path is a list of ordered pairs of goals (defined previously by the if keyword) and written (x -> y). The informal semantics is that when the value of the goal x is changed, the solver should try first to solve the constraint by changing the value of y. We shall see in Section 4.3.1 how this information is used by the constraint solver but we should already notice that sometimes a small change may lead to a complete re-computation of the whole solution, especially when disjunctive constraints are used.
3.4
Hypothetical
Reasoning
Most of the time the control over the search strategy is left to the constraint solver. We simply interact with the solver through rules and methods (which represent heuristics that guide the search). However, we may also want to have direct control over the search. For instance, we may want to implement a meta-search strategy when we have an optimization
- 17 -
problem. This is why we have implemented in LAURE a notion of worlds, taken from AI works, but simplified in order to make it more efficient. A world can be seen as a temporary copy of the database: creating a new world ( w o r l d + ( ) ) means to store the current state of the database, associate it with the current world index (n = world?() ) and then create a new world with index n+1. Then it is later possible to come back to a previous world ( w o r l d + ( ) or resume(n)). In the LAURE model, the set of logic relations is organized into a set of layers, designated by numbers. A world i is made of all the information contained in layers less than i. To avoid contradictions, successive layers are constrained by some monotonicity rules [Ca91a], which imposes that multi_attributes can only grow and incomplete attribute can only shrink (thus the world i+1 contains more information than the world i). This structure is somewhat simpler than other constructions of multiple worlds in AI languages, but can be implemented very efficiently [Ca91a], which is the main reason why LAURE is an efficient constraint resolution language and has been used for large applications. It must be emphasized that the world mechanism is actually used by the constraint solver to perform its own search. For instance, here is a simple loop that performs end-time optimization in the TCTSP example, using worlds for the exploration and the variable *goal* to represent the current target for the ending time). [let *goal* as 480, ;; some initial value n as world?(), [while [do world+(), find_a_solution(*goal*)], *goal* integer), slot( y -> integer)].
There is an implicit bijection between the class of points and the product integer × integer, which yields that [POINT of x y] = [POINT of a b] if and only if x = a and y = b. [POINT of x y] is also a special instantiation pattern for value classes that is allowed in the logic syntax (next section). This allows the dynamic creation of objects inside rule (object invention [HS89]) and has proven useful for many problems [Ca91a]. 4.1.2 A Logic language and its Relational Algebra Rules and constraints are defined using the LAURE logic language (L 3 ) , which is a first-order logic sub-language with equational extensions, fitted for our object model. This language is used to express conditions among
- 19 -
objects, and will be illustrated by some examples. The interest of this language is the existence of an equivalent relational algebra [Ca91a], which describes the possible operations that one can perform in the object database. Here is an informal description of L 3 ; a more detailed description may be found in [Ca91a]. We use four subsets of the set of features F named F 1 , Fc , Fo and F p , which contain features such that (respectively) their arity is 1 (O → O); they represent a comparison (O × O → Boolean); they represent an operation (O × O → O); or they represent a bijection (this is useful to represent values, as we explained previously). The L 3 language contains assertions and expressions. Assertions are one of the following: < R* > ( ) | : relation as a binary predicate possible(,, )] : choice relation as a predicate ( ) : comparison (() : set grouping from a relation [group , *] : set grouping from an expression (*)
: parameterized object invention
A relational algebra has been formed from some classical operations on binary relations [McL81], using such operations as composition (written o) , which is the binary case of the relational join, intersection (written ∩), u n i o n (written ∪ ) , inversion (written -1 ), and cartesian product (A × B is the graph of a binary relation). Additional operations have been added to handle the logical extensions in our language. An important property is that each operation can be evaluated on a "set-at-a-time" basis, which matches the internal representation of the object-oriented database. Moreover, efficient compilation techniques relieve us from physically computing the sets involved in intermediate computations [Ca89]. The algebra A (R) is made from the set of variables R and those relational operations. Each term t of the algebra represents a binary relation on O for any given database instance, written d(t). A logic assertion and an algebraic term are equivalent if they represent the same relation for every database instance. We have shown
- 20 -
that each assertion could be translated into an equivalent algebraic term, and reciprocally [Ca91a].
4.2 Constraint Satisfaction and Resolution 4.2.1
Constraint Semantic [Ca91c]
A LAURE constraint is a syntactical object that restricts the possible completion of the database instance. It is also a generic constraint since it applies to possibly many LAURE objects. A constraint is defined as previously: D e f i n i t i o n : A constraint is a tuple (s ∈ S, l = ((R 1 ƒ 1 ) , … , ( R m ƒ m ) ) , a(x,v 1 ,...,v m )) where s is a class of S, l is a list such that ∀ i, Ri ∈ R1 and fi is a slot on s (instance variable) or the identity function, and a(x,v1 ,…,v m ) is a L 3 assertion with free variables {x,v1 ,…, vm }. We can now take each such constraint c =(s,((R 1 ƒ1 ), ...,(R m ƒm )),a(x,v 1 , ..., v m )) and translate them into m algebraic constraints {R i Ê Ti } [Ca91a], where T i = t o ƒ i - 1 , and t is equivalent to the assertion a ( x , R 1 ( ƒ 1 (x)), ..., R i - 1 ( ƒ i 1 (x)),y,R i+1 (ƒ i+1 (x)), ..., R n (ƒ n (x))). We say that the algebraic constraint {R i Ê T i } is d e r i v e d from the initial constraint set C. A technique for compiling efficiently the computation {y, (x,y) ∈ d(T)} was developed for rule resolution [Ca91a] which can be reused here. We implicitly have a set of goals Ê R1 × O, on which the completion will operate. For each goal (R i ,x), we have a possible domain, which is d ( R i )(x), and a value y if |d(R i )(x)| = 1 and d(R i )(x) = {y} (also written d(R i )(x) = y). A database instance is complete if it contains no disjunctive information. Here, we suppose that the set of goals is finite, and we write |d| = |{(R i ,x) ∈ R1 × O, |d(R i )(x)| > 1}| (thus d is complete if |d | = 0). A solution to a constraint is a complete database instance such that all assertions are satisfied: Definition: A constraint (s, ((R1 ƒ 1 ), ... ,(Rm ƒ m )), a(x,v1 , ..., vm )) is satisfied by a complete database instance if and only if : ∀ o ∈ O, o ∈ c ⇒ |a(o, R1 (f1 (o)), ..., Rm (fm (o)))|d = true The satisfaction of an algebraic constraint derived from an object constraint is straightforward: Definition: An algebraic constraint is a formula (R i Ê Ti ) where Ti ∈ A ( R ) and Ri ∈ R1 . A database instance d satisfies a constraint (Ri Ê Ti) if and only if d(Ri) Ê d(Ti). A constraint satisfaction problem is made of an initial domain valuation d 0 and a set C of constraints. A solution is a completed database instance v that satisfies all the constraints in C such that for all x in O, d(R i )(x) ∈ d 0 (R i )(x). A given constraint problem can have many or no solutions. The semantics we have given is general in the sense that it applies to any form of constraint assertions [Ca91b]. However, there usually is (partially) a way to go from the possible values (d 0 ) to a solution by using constraint propagation (an a r c consistency function [Ma77]).
- 21 -
4.2.2
Resolution Algorithm
Constraint resolution uses a depth-first search algorithm with backtrack, which is very common for finite domain constraint solvers (e.g., CHIP). A complete description of this algorithm may be found in [Ca91c]. A more original aspect is the domain reduction technique that we use in LAURE, which is based on abstract interpretation [CC77] and is more general than previously known approaches. This aspect is covered in detail in [Ca91b]. Here we give an overview of the algorithm and some of the original features. The resolution algorithm operates on a list of goals (pairs of attribute and objects) that must be completed, i.e., a single value must be assigned to each goal so that all constraint are satisfied (cf previous section). The resolution process is a two-stage algorithm. •
S t a g e 1 : associate a set of possible values to each goal ( R i ,x), starting from its domain d ( R i ) ( x ) and reducing it with abstract interpretation of the algebraic constraints. The idea is very simple. If we have a constraint R i Ê Ti , we know that we may apply the reduction step d(R i )(x) → d(R i )(x) ∩ d(T i )(x) . Such a reduction can be iterated until a fixpoint is found and this will reduce the search space dramatically. However, the complexity of this computation can be worse that the resolution itself! This is why we compute an approximation of the fixpoint using an abstract interpretation technique [Ca91b].
• Stage2.a: choose a goal R i (x i ), choose a possible value y that doesn't violate any constraint, and assert R i (x i ) = y. The choice of the goal is provided by a heuristic function that can be given by the system (e.g., the first-fail principle tells to try goals with smallest domain first) or by the user. In our second problem, we already mentioned that we have a domain-dependent heuristic which is a variation over the first-fail principles and gives (much) better results. Each possible value will be asserted by creating a new world and adding the new fact R i (x) = y. This update may trigger both the (relevant) production rules and the domain reduction algorithm. • Stage2.b: repeat until all goals are assigned and backtrack on failure (go back to a previous world). The important point here is that each choice of the solver is a real update on the database, which may trigger any rule and cause new computation. This is the first condition for building cooperative programs using constraints, rules and methods (the second is that backtracking, using the world mechanism, must be able to undo the effect of such sidecomputations). 4.2.3
Maintenance of Production Rules and
Integrity Constraints
[Ca89]
We mentioned that the assertion of a new choice R i (x) = y can trigger a production rule or an integrity constraint; we shall now briefly explain how
- 22 -
and why. Integrity constraint and production rules are managed in the same way because they are both made of a logical condition, represented as a term of the relational algebra, and a conclusion, which is a piece of LAURE code for a production rule and a LAURE condition to be checked for an integrity constraint. LAURE uses a technique called formal differentiation [Ca91a] to pre-compute how the introduction of a new fact R i (x) = y can modify the condition of a production rule. Formal differentiation rules allow us to compute ∂T/∂R i , which is an algebraic term that tells us what new object pairs satisfy the condition represented by the term T when an update is made on the relation R i . This technique can be thought as a generalization of the RETE algorithm, with an immediate application to rule compiling. We will see in Section 5.4 that differentiation is used to represent a production rule by a family of demons stored on each attribute involved in the logical condition. Production rules have access to the domains d(R i )(x) for each goal of the resolution and can use them to either reduce them explicitly or build additional information. In both cases, LAURE will provide automatic backtrack support (i.e., will undo any modification caused by a choice of the constraint solver through the propagation rules if the constraint solver retracts this choice). Because the domains can only be reduced, the resolution process is guaranteed to terminate whichever set of heuristics is applied. On the other hand, heuristics that explicitly modify the domains can cause the resolution to miss some valid solutions if wrong heuristics are used. Although these heuristics are rarely needed, we found that we could not forbid them without loosing a great deal of expressive power. The interaction between production rules and constraints is especially dealt with in [Ca91c].
4.3 Solution Querying 4.3.1 Reactive Resolution When an update is made over a constrained attribute, the system usually produces an error if the constraints are violated. However, we have implemented a variation of the previous algorithm which uses the relaxation paths defined previously. We now suppose that we have a solution, which is a set of fully described objects that satisfy all the constraints. The goal of reactive resolution is to find a new solution when the value of one relation for one object is changed. The algorithm that we use can be described briefly as follows: • Find the chain of affected goals. Starting from the initial perturbation, we derive a chain of goals (R i , xi ) by propagating the existence of a perturbation. We get the list of all values that may change because of the modification (if we are lucky it is a small list, but it may contain the whole problem space). • Perform a classic finite domain resolution (cf. previously) by using two specific features: (1) use the order of the chain of goals and (2) try the old value of each goal first (when it is still admissible). Because
- 23 -
of (1) and the inverted functions derived from relaxation statements, most common problems will be solved by simple propagation. The new value of each goal will be functionally derived from the previous ones. Enforcing (1) and (2) insures that solutions which leave as many goals unchanged as possible will be tried first. This means that the metric we are using is simply based on discrete distance weighted by the relaxation path. Soundness and completeness can be defined as usual: completeness will be the certitude to get a solution if one exists. For instance, we can demonstrate that the previous algorithm is complete by showing that for any solution any goal with a modified value must be in the chain computed by the algorithm. On the other hand we cannot demonstrate the optimality of our algorithm, even with the implicit distance that we are using (unless we come up with a strange distance that fits our algorithm!) However, this naive approach has given good practical results for our automatic-layout problem. 4.3.2 Querying About Solutions The most common query is to find one possible solution to a set of constraints. In this case, the system will produce one possible completion (a new database value obtained as a new world). This is done by using the search method of the solver object as we have seen previously ( search(solver ) ). On the other hand, it is also very common to need all the solutions or to check that they all satisfy a given property. In this case, the system tries the t e s t predicate in each possible completed database, and returns with a combination of the results (AND/OR) to the initial state. This is done by passing the predicate as an argument to the previous search method. Hypothetical querying is possible if we combine one of the constraint resolution modes with the ability of creating temporary worlds. To test if a condition would necessarily imply a given property, we create a new world in which we assert the condition, we check the property in all possible completions (as described previously) and we return to the initial database. Thus, one can use a combination of world creations and parameterized searches to process complex search queries. However, this falls short of being declarative and user-friendly; it requires a lot of skills from the user. Following the suggestions of [INV90], we are developing a modal query language for constraint resolution, using the world/search tools. We have defined two extensions [possible {(r1 x 1 ), ..., (rix i)}, e] and [sure {(r1 x1 ), ..., (ri xi)}, e] , where e is a LAURE closed expression. [possible {(r 1 x 1 ), ..., (ri x i )}, e] returns t if there is one possible completion of the database value, which only refines the goals r 1 (x 1 ), ..., ri (x i ) and satisfies the constraints in which e is evaluated to true. [sure {(r 1 x1 ), ..., (ri xi )}, e] returns t if e is evaluated to true in all such completions. Note that these statements may be embedded to create complex hypothetical queries. For instance, here is the graph coloring problem, using a constraint. constraint[
for_all x:region, if [exists z, adjacent(x,z), y = color(z)], then no(color,x,y)] [possible [collect x in region, (color, x)], true]
- 24 -
We could have used a direct query without a constraint, but it would be evaluated less efficiently. We can declaratively write hypothetical queries. Here is a more complex example where we use an embedded query to see if we can color two nodes (A and B) such that all possible coloring yields to giving the color yellow to another node C: [possible {(color, A),(color, B)}, [sure [collect x in {Region - {A,B}}, (color, x)], color(C) = yellow]]
5. Modes, Extensions and their Implementation In this section we want to investigate some issues related to the implementation of the constraint solver and its extensibility. More precisely, we want to show how the implementation of some salient features (translation, abstract interpretation) is aimed towards extendibility. A more general presentation of the implementation strategy may be found in [Ca91a] (database), [Ca89] (compilation) and [Ca91c] (constraint resolution).
5.1 Logic Relations and Object Worlds The logic relations and the associated resolution modules are built on top of the object-oriented language. We believe that a similar system could be built on top of most object-oriented languages. Each logic relation associates a unit of information called a bucket to each object in the graph of the relation. The LAURE system actually implements a stack of ordered database instances d 1 , d2, ... di . Instead of representing only one database instance d i , LAURE is able to memorize some intermediate levels, which represent worlds. The monotonicity of this sequence is taken into account so that memory allocation could be shared. Creating or deleting a new level of database instance is a very fast operation due to a complex sharing of memory structures. The association between the objects of the domain and their associated buckets is done in one of the following ways. • Structure allocation: when the domain is a class or a union of classes which have not been instantiated yet (the most common case), LAURE allocates a place in the object structure to store the bucket. This allows very fast access (one machine instruction) to the bucket from the object similar to the way slots (or instance variables in C++) are implemented. • Direct access: when the domain of the relation is an interval of integers, we may use an array to store this association. This provides efficient access in a case that is very common in constraint-satisfaction problems. • Hashing: in any other case we use a hashing table and the object identifier as the seed for the hashing. This has proven to be actually quite efficient, although not as good as the two other solutions. On the other hand the availability of this technique allows us to define a new relation on any domain, including heterogeneous domains ! For instance, we may define a relation on {string + {float + class}}. This has proven to be a very
- 25 -
useful feature when prototyping, and is not allowed with traditional object-oriented languages, The bucket associated with a goal (R i ,x) contains pieces of valuable information such as the domain of possible values, the current value if a choice has been made and the cardinal of the domain otherwise, some state information which is necessary to track loops in the resolution and some history pointers. The use of buckets for deductive resolution is also described in [Ca91a]. Buckets are organized into a chronological stack. Creating a new world is done by moving a pointer that defines the current top of the stack; adding new information will create a new bucket in this new part of the stack. When LAURE resumes to a previous state, each bucket in the newer part replaces itself by its predecessor in the hash table through the use of a direct index. LAURE supports the following modes of domain representations (in a fully extensible way). • A b s t r a c t is the default mode: each domain is represented by an object from the abstract lattice (see next section). This allows full domain reduction using abstract interpretation techniques. • List/Set is a mode where the domain is stored as a list/set. This is used sometimes when there is no possible prediction techniques to be used and we simply need a brute-force enumeration. • Infinite means that the domain is not represented physically. We simply store a type for type consistency checking and perform no finite domain resolution. In this case the only resolution which occurs is deterministic propagation and integrity checking. This mode is used when the domains are infinite (such as real numbers for instance). The default mode of representation is usually deduced by the system from the range of the relation. However, it can be forced through a m o d e declaration when the attribute is instantiated. For instance we may define the a t m o s t attribute in our second example to be in the infinite mode. This tells that only naive constraint resolution is allowed here (actually none is used) and allows for some small optimizations in code generation. [define atleast attribute domain task, ->
{0 -- Max},
mode infinite]
5.2 Translation and Object Operators Translation from the logic language L 3 into the algebraic form is based on rewriting and involves a lot of knowledge about basic mathematics and object operations [Ca91a]. The principle is to solve the equation assertion(x,y) while considering that x is known and that y is searched. The result of the resolution is a relational algorithm that explains how to get y from x and is represented as a term in our relational algebra. LAURE uses a set of guarded re-writing rules that are derived from the mathematical properties of the object operations. For instance, if we know that + induces an Abelian group structure, we may use the following rules:
- 26 -
X + 0 → X, X + (Y + Z) → (X + Y) + Z, X + Y → Y + X, X + Y = Z → X = Z - Y.
Monoid operations and quotient operations are also very common and described by a nice set of rewriting rules. Multiplication on integers, for instance, fits in the commutative monoid category; therefore, associativity and commutativity rewriting rules can be used. There are more sophisticated rewriting rules involving the quotient operation (and the divisibility operator |), such as: X * Y = Z → ( Y | Z ) ∧ (X = Z / Y) .
LAURE also holds some knowledge comparisons and operations with rules like:
about
compatibility
between
X + Y < Z ∧ compatible(+, matrix …), method( *(x:matrix) …), method( inversible? -> boolean …), …]
We then describe the mathematical properties of our new operators. [description(+) is group] [commutative(+) is t] … [description(*) is monoid] [neutral([* @ matrix]) is Identity(n)]
And LAURE is now able to solve some simple constraints over integer matrices.
5.3 Domain Reduction and Abstract Interpretation
- 27 -
As we mentioned earlier, we use first-class objects to represent domains as set abstraction of the powerdomain [Ca91b]. We have created a class ABSTRACT _ SET with four subclasses ABSTRACT _ SMALL (sets with cardinal less than h = 5), ABSTRACT_INTERVAL, ABSTRACT_UNION, and ABSTRACT_CLASS. Each of these classes is defined by some attributes (for instance, a union abstract set is defined by its two attributes set1 and set2 such that x represents the union of set1(x) and set2(x)) and by some methods. Each abstract operation ∩ # , ∪ # ... is implemented as a method on A B S T R A C T _ SET (for instance, the abstraction of intersection ∩ # is represented by the LAURE method ~intersection). For each object, we store its cardinal as an attribute, so that the cardinal of an abstract set is computed only once, since cardinality comparisons play an important role in the fixpoint computation. We heavily rely on the fast allocation of new objects in LAURE since the abstract computation produces a huge number of such small objects. On the other hand, this object-oriented implementation has a tremendous advantage over more compact representations because it is extensible. For instance, if we only had integer constraints, we could use the CHIP strategy and incorporate two min-max slots in the bucket structure. We can then use the same abstraction rules and get (faster) the same results. However, with more complex domains (see [Ca91b] for a detailed example), it is less clear that we know today what the right level of abstraction is. Therefore, it is very desirable to be allowed to experiment with new abstraction schemas. For instance, let us consider our graphical layout problem. We have indicated that we use an integer-based resolution approach, which translates into a lot of inefficiency (the solver does not detect simple contradiction based on the total area of the objects that are used). It would seem more elegant (and maybe more object-oriented) to use points instead of integers as a general domain and rectangles instead of intervals as a domain abstraction. This can be done in LAURE because the class ABSTRACT _ SET can be extended. We first define the class of rectangle and then add a new subclass of abstract sets. [define rectangle class superclass {value}, with slot( UL -> point), slot( DR -> point), method( area -> integer …), method( intersection(x:rectangle) -> {rectangle + {}} …), …] [define abstract_reclangle class superclass {abstract_set}, with slot( representation -> rectangle), method( close ;; this method is called by LAURE at instantiation => (~cardinal(oself) is area(representation(oself))), (jump_to(oself) is point)…) …]
- 28 -
Now that we have extended the abstract representation of the powerdomain lattice, we must extend the operations that are defined on this lattice and which are necessary to perform the abstract interpretation of the constraints [Ca91b]. For instance, we must give the abstract interpretation of set union or set intersection for those new sets. [define ~intersection (self:abstract_rectangle, x:abstract_rectangle) method abstract_set, => [let i as (representation(self) intersection representation(x)), [if (i = {}) {} else abstract_rectangle( representation i) ]]
->
[define ~intersection (self:abstract_rectangle,x:abstract_set) method -> abstract_set, => [case x abstract_list … ;; create a new abstract list abstract_class [if (x = point) self else {}], …]]
With this extension, the constraint solver will be able to reason with domains as rectangles or unions of rectangles and we can incorporate some naive geometrical knowledge to ease the pruning, which is particularly useful for tiling problems. This extensibility allows us to play with various scheme of abstraction and use the full power of object-oriented representation. Our findings will be reported in a future paper, as well as the use of a technique called modal differentiation to compile domain reduction based on abstract interpretation.
5.4
Resolution
An interesting property of the relational algebra that we use is the ability of efficient compilation [Ca89] . Each relational computation can be mapped into a procedural instruction from the object-oriented language such that each intermediate set produced in the computation is built virtually. Since all operations on the algebraic rules or constraints involved in the resolution algorithm consist of applying a given procedure to all members of a relation denoted by an algebraic term, we compile these iterations into small functions that we attach directly to the concerned logic relation (thus called demons) . A general view of the LAURE deductive system is given in Figure 2. Constraints and rules are entered with the syntax presented in Section 3 using the L 3 language. These constraints and rules are translated (cf previous section) into equivalent algebraic representation. Differentiation is applied to production rules [Ca91a] to produce fast bottom-up evaluation. Then each algebraic rule is compiled into one or many demons according to its use in the resolution system. For instance a constraint will be compiled with the value-based compiler to produce lazy demons that are used when we need to remove forbidden values from a domain at the last minute. On the other hand, abstract compilation is applied to produce demons used in the domain prediction stage. In a similar way, we produce a family of demons to efficiently handle the propagation part in reactive resolution. The result is a family of demons, one for each use of the constraints. The code produced is very compact and not each constraint needs all kinds of demons, so the
- 29 -
expansion factor (L 3 code to LAURE code) is on average around 5. Some optimizations, such as constant recognition or re-ordering, are applied both during the translation and the compilation process, and the function is eventually compiled into machine code. The resolution algorithm follows the design proposed in the previous section, and simply calls the right demons associated to the concerned relation for each step of its computation. This avoids most overheads and has proven to be efficient (cf. next section). Some modes may also be attached to the constraint solver, which are similar to the modes attached for logic relation. For instance, the domain prediction can be done using either a true abstract fixpoint [Ca91b] (abstract mode), or a simpler approximation (l a z y mode) which is usually enough for most problems.
production rules object constraints
algebraic rules translation
algebraic constraints
dependencies compilation differentiation
LAURE object database
RESOLUTION if_read demons
logic relations
relaxation demons
abstract demons
lazy demons
if_write demons
domain propagation
Figure 2: The LAURE Constraint Solver
6. Comparison with Related Work 6.1 Finite Domain Constraint Solvers If we look at the LAURE constraint solver from an application point of view, it is a finite domain solver close to other solvers such as CHIP and its various look-alike. Actually, our work on constraint resolution has been greatly inspired by papers on CHIP [VD86] [DSVH87] and there are by consequence many similarities. Besides the use of a relational algebra as a support for efficient compilation, there are two significant differences in our work: • Object-oriented representation: LAURE's constraints are both on ordersorted object domains, and attached to objects directly. The former makes the problem richer and allows for new techniques such as those developed for domain reduction. It also allows to attack large problems more easily because of the expressive power of the object-oriented paradigm. The later makes a large difference when it comes to interface the constraint solver with other programs. Attaching constraints to sets of objects simplifies the modelling work, especially at the prototyping
- 30 -
stage. It also supports an implicit factorization of constraints, which produce shorter and more readable code. • Extensibility through production rules: producing an extensible constraint solver has been a hot topic in the CHIP community for the last two years. After the first successes of the black box approach, it has become clear that large problems require a more open architecture. Many solutions have been proposed, from the very elegant formalism in [VHD91] where the user may define new constraint schemas and how propagation should be performed, to the very efficient approach proposed in PECOS (see next section) where the constraint solver is built as a library of LISP functions, including a more traditional solution for some CHIP look-alikes which is to allow for direct calls to C function inside the constraint solver. We believe that our approach with production rules combines a certain form of elegance (readability and almost declarative semantics [Ca91c]) with efficiency and expressive power. Comparing constraint resolution languages is difficult. Significant problems are hard to find and the performances are so dependent on the way to formulate the problem that we would need to make sure that exactly the same strategies were used. Here we give some examples taken from [VH89] and compare with some of the best systems that are available today (when comparing with the original CHIP we have divided the quoted results by 10 to reflect the average current improvement of the technology). The results should be taken with caution since the systems are too different to guarantee our previous condition (for instance, the magic series is written in LAURE in a way that contains more knowledge than the CHIP program; thus, we get better performance). Last, we have written two hybrid programs for the bridge and for the magic series problem that combine operational research techniques with constraints and this delivers much better performances (but using them in the LAURE column would be unfair).
Problem
LAURE
other
64 queens (one solution)
200 ms
250 ms CHIP* [AB91]
SEND+MORE=MONEY (one solution)
6 ms
6 ms
8th magic series (one solution)
170 ms
1.3 s
House problem (all solution)
50 ms
120 ms CHIP/10 [VH89]
Bridge (solution+ optimality)
2s
3.5 s
CHIP/10 [VH89] cc(fd) [VHD91] CHIP* [AB91]
Figure 3: some results (SUN SPARC1 Workstation)
Our conclusion from these problems is that LAURE is an efficient constraint solver, in the same range (at least) of the newer and faster implementation of the CHIP system. This is obtained with a more general system, which supports constraints on object hierarchy and can be extended with production rules. When production rules are used to help the constraint resolution (such as for the magic series), performance can be increased by an order of magnitude.
- 31 -
Some interesting work has also been done on incremental resolution in the framework of a CHIP system [VH91], which has similar motivations to our work on reactive resolution. We plan to do a more detailed comparison and see how the RECORD/PLAY scheme proposed in [VH91] could be used for such problems as a graphical user interface. A major difference in the two approaches is that we need to require incremental resolution by deterministic propagation whenever it is possible, which is a less salient requirement with the optimization problems studied in [VH91].
6.2 Performance Analysis Although we insisted on the fact that the previous figures are not really representative of a real performance comparison, we want to make the following three performance claims. • LAURE is an object-oriented knowledge representation language that is as fast as the best object-oriented programming languages (e.g., C++) when compared on traditional applications (defining classes, creating objects, reading slots and executing methods …). • LAURE is at least as fast as the best finite-domain constraint solver (e.g., PECOS, CHIP) for traditional constraint solving applications. •
LAURE allows the user to write hybrid programs by using constraints, rules and methods that are as fast as hand-tailored C code for hard optimization problems.
The justification of the first claim is totally beyond the scope of this paper. The reasons behind the efficiency of LAURE as a programming language are the use of strong typing, compilation technology (the implemented system includes both an interpreter and a compiler), optimization techniques for representing large set of objects (e.g., techniques for representing large hierarchies [Ca93]) … etc. As a programming language, LAURE is the result of 10 years of research and development aimed at obtaining as much performance as possible from the language. The second claim is more or less justified by the previous performance figures. The main reason for the efficiency of constraint resolution in LAURE is the use of algebraic representation and manipulation as a backbone for constraint compilation (similar to its use for rule compilation presented in [Ca89]). This means that each constraint is transformed into a set of functions that perform domain reduction, value propagation or abstract propagation for all the possible situation that may occur. Although there is a clear phenomenon of code expansion here (a complex constraint can generate as much as 50 functions), we have not found this to be a problem in practice. The second reason for getting good performances is the use of a good resolution algorithm, similar to those used for CHIP or PECOS and the use of an efficient architecture for backtracking [Ca91a]. This last point is especially important since the backtracking in open in LAURE (i.e., it extends to all the modifications caused by the constraint solver through the user’s production rules).
- 32 -
The really interesting claim is the last, which was justified by our experience reported, for instance, in [CK92] or [CGL93]. In both cases, we have obtained similar or better performance than ad-hoc code that has been written using dynamic programming or other traditional techniques, while retaining the flexibility of a constraint-based system. We have identified four reasons that explain these surprisingly good results. • The use of differentiation for the production rule compiler. Heuristics written as production rules were not made any more efficient when we replaced them with ad-hoc methods. This confirms a previous finding that LAURE’s processing of production rules is very close to using ad-hoc code and actually much faster than the other inference engines that were available to us. • The use of a smart backtracking architecture [Ca91a]. For most applications, LAURE automatic backtrack is as fast as the “undo” code that one could write for each production rule. • The use of optimized data structures. As mentioned in Section 5.1, LAURE offers many choices for the underlying data structures representing the relations and the domains. Although we had spent many years optimizing “generic” data structures, we have found that this level of customization (which is recent in LAURE) provides a big improvement in performance (especially when trying to catch up with C). •
The use of object-oriented representation of data. Throughout our experience with large sets of data, we have found that the objectorientation offers good robustness and scalability. This does not mean that we can apply exponential algorithm to large sets of data, but simply that the performances of a component of the system are not affected by its integration into a much larger system with large amounts of data.
6.3 Objects, Logic and Constraints PECOS [PA91] is a CHIP-like constraint solver that also operates on objects in a LISP environment. Because PECOS also allows constraints to be attached to objects, it has striking similarities with LAURE, especially as far as performances are concerned. It seems that the benchmarks on which LAURE is especially good are the same as those on which PECOS is good (with similar result). We believe that this shows that object-oriented representation has some strong influence on constraint resolution and we will report our findings in a future common paper. On the other hand, PECOS is built as a LISP library which has some tremendous advantages and drawbacks. On the positive side, this allows us to build one's own specialized constraint solver for each new problem. Using LISP as a background, it provides a lot of flexibility and allows for new heuristics to be added in a similar way as we did in our example with LAURE. On the negative side, it is a low level language and programs are hard to write and read. They are harder to write than LAURE programs because the user must perform most of the work that is automated by the algebraic translator/compiler of LAURE. Propagation or
- 33 -
domain reduction must often be defined as a LISP function, as opposed to a more declarative logic representation. If we consider LAURE as an object-oriented language that combines logic and functions, we must compare it with LIFE [AK90]. This comparison is even more interesting since LIFE allows some form of constraint resolution through a clever residuation technique. Motivations for LAURE and LIFE are extremely similar, and so is the underlying object-implementation techniques (such as the use of a full type lattice or the lattice encoding techniques). On the other hand, the philosophies to achieve these goals are very different. LAURE is a bottom-up project which tries to incorporate various new technologies together that we know to implement efficiently and it uses theoretical work to build a common framework for those pieces. LIFE is a top-down approach which starts with an ambitious specification and where theory is used to go progressively from the idea to the realization. As a consequence, LAURE is currently more efficient and LIFE is more elegant. There is a strong hope for cross-fertilization that would make LAURE more elegant, and vice-versa. As far as mixing objects and constraints for graphical applications is concerned, we must compare what we have proposed here with the pioneering work on THINKLAB. THINKLAB [BMM89] and one of its descendents KALEIDOSCOPE [Fre90] are languages designed to perform reactive resolution of simple constraints through propagation [GR92]. In such systems, the main concern has been reactive resolution and many interesting ideas were proposed. The notion of constraint hierarchy [BMM89] is one nice way to define a distance between solutions. Here the nondeterminism only comes from the choice of relaxation directions (in equations with more than three variables) since there are no explicit disjunctions and the mode of resolution is a data flow of propagations. The hierarchical distance model has proven to be well fitted to graphical applications, such as the one we were interested in. However, because we want to handle more complex constraints such as disjunctive constraints, their resolution techniques cannot be applied here. We actually believe that this is an important subject since such constraints have occurred naturally in our problems. Although much more work is needed to extend LAURE’s reactive resolution, it must be noticed that our approach subsumes resolution by propagation, which is supported in LAURE even for infinite domains such as real numbers. There are many other hybrid systems that claim to mix objects, logic and constraints. ECHNYDA [H&al90] is a significant example of a hybrid language, which incorporates object-oriented knowledge representation, logic programming, production rules and constraints over integer, finite and real number domains. ECHNYDA has been used for serious applications and has some original features such as incremental intelligent backtracking or a theory of resolution for real number constraint that subsumes the one used in CLP(R). On the other hand, no hard evidence is given about efficiency or the resolution of a well-known hard problem. The only difficulty in building a hybrid system is to ensure a tight integration which from our experience requires more theoretical than practical work. The only way to measure
- 34 -
success is by comparing the hybrid system to some well-known stand-alone reference systems, so that the cost (or the absence) of overhead can be evaluated.
6.4 Application to Knowledge Bases Although we focused mostly on hard optimization problems, there are many other applications of constraints, inside the framework of a knowledge base, for which a hybrid system like LAURE is well suited. The emphasis on constraints and constraint resolution is motivated by the desire to retain the flexibility that one obtains in data modeling with a knowledge representation language. It is our experience that, if the constraint satisfaction aspects that are almost always present in a knowledge base (at least in the weaker form of checking integrity constraints) are left to more traditional style programming, although decent performances can be obtained by using the appropriate techniques and algorithms, the flexibility to change/ add a new constraint is lost. The first important difference between LAURE and other constraint satisfaction languages that is significant for the applicability towards knowledge bases, is the orientation towards large amount of data. Because of the object-orientation, the use of sets and various mechanisms for their implementation, the emphasis on complete compilation without overhead at run-time, LAURE can be used for complex problems with few generic constraints and many objects of different types. Although LAURE can handle very large collections of objects (over 100,000) using virtual memory if needed (which is extremely rare nowadays because of the availability of workstations with more than 100M of local memory), LAURE does not handle persistence yet. In most applications where a persistent storage of the objects is needed, an interface to an appropriate database has been developed (the type of the database is usually dictated by external consideration). LAURE is a knowledge representation language, which means that it is much easier to represent complex data than with conventional languages (such as linear programming tool kits for instance). This implies that LAURE is not used as a deductive tool for a knowledge base but rather is a complete knowledge representation system that uses an external database for persistence.
7.
Conclusion
We have shown how constraints are used and implemented in the LAURE language and how constraint resolution can be improved by adding domaindependent knowledge through rules and methods. LAURE has been used for many applications, both inside and outside Bellcore. From this experience we may draw several conclusions. First, objects and constraints mix well from a data modeling perspective. Constraints occur naturally and representing them in an object-oriented way is convenient and faster than having to link the object-oriented program to an external solver. There is a big payoff in
- 35 -
representing constraints as such instead of writing procedural code in terms of productivity, maintenance and extensibility. Explicit constraint representation seems to solve one of the worst nightmares when building a large automated system, which is the addition of a new requirement from the end-user at the last minute. Our second point is that a hybrid approach is good for a large class of problems that has been left unresolved. Such problems can be characterized by their complex domains and the absence of a good resolution strategy. In the opposite case, either a CLP solver like CHIP or an off-the-shelves integer programming package is better suited. For instance, we would not think about using LAURE for a pure Traveling Salesman Problem when there are so many dedicated libraries available. On the other hand, when we have such a situation, the flexibility provided by a hybrid language allows the user to explore various designs and algorithms quickly. Because of problem complexity, traditional software engineering techniques based on using formal specifications offer little help since the algorithm proposed in the specification often turns to be a poor performer. Last, we believe that a high-level language is the right way to integrate all these technologies, at least for the prototyping stage. There is a belief in our work community that C++ should be used as a common language and such facilities as set manipulation or constraint resolution should be offered as libraries. We do not agree with this vision based on our experience with some difficult problems. Trying to follow one's intuition using C++ is hard and one gets buried in too much detail. Although the final strategy that we have discovered could usually be implemented with a set of C++ libraries, its finding requires a lot of flexibility and the ability to describe ideas at a high level of abstraction.
Acknowledgments This work has benefited from fruitful discussions with Hassan Aït-Kaci, Peter Koppstein and Pascal Van Hentenryck. I would like to thank Drew Adams, Francois Monnet and Diane Hoffoss for their support and encouragement. I am grateful to Fred Eichelman, Paul Matthews and members of the WFA team at Bellcore for sharing their insights on the task allocation problem that is described in this paper. I am also grateful to members of our research group at Bellcore, including Sam Epstein, Madhur Kohli, François Laburthe and Shamim Naqvi.
References [AKG87] S. Abiteboul, P. Kanellakis, G. Grahne: On the Representation and Querying of Sets of Possible Worlds. Proc. of ACM SIGMOD, 1987. [AK89] S. Abiteboul, P. Kanellakis: Object Identity as a Query Language Primitive. Proc. ACM SIGMOD Conf. on Management of Data, 1989.
- 36 -
[AB91] [AKP90] [B&al88]
[BBM89]
[BMM89]
[Ca89]
[Ca91a]
[Ca91b]
[Ca91c]
[Ca93]
[CK92]
[CGL93]
[CLP] [CC77]
[CP91]
A. Agoun, N. Beldiceanu: Overview of the CHIP Compiler. Proc. of the 8th Int. Conf. on Logic Programming, Paris, 1991. H. Aït-Kaci, A. Podelski: The Meaning of Life. PRL Research Report, DEC, 1990. D. Bobrow, L. DeMichiel, R. Gabriel, S. Keene, G. Kiczales, D. Moon. Common Lisp Object System Specification. Sigplan Notices, 23, September 1988. A. Borgida, R. Brachman, D. McGuinness, L.A. Resnick. CLASSIC: A Structural Data Model for Objects. ACM SIGMOD International Conference on the Management of Data, Portland, June 1989. A. Borning, M. Maher, A. Martindale , M. Wilson: C o n s t r a i n t Hierarchies and Logic Programming. Proc. of the Sixth International Logic Programming Conference, Lisbon, June 1989. Y. Caseau: A Formal System for Producing Demons from Rules. Proc. of the fisrt int. conference of Deductive and Object-Oriented Databases, Kyoto, 1989. Y. Caseau: A Deductive Object-Oriented Language. Annals of Mathematics and Artificial Intelligence, Special Issue on Deductive Databases, March 1991. Y. Caseau: Abstract Interpretation of Constraints over an OrderSorted Domain. Proc. of the Int. Logic Programming Symposium, San Diego, October 1991. Y. Caseau: Constraints in an Object-Oriented Deductive Database. Proc. of the second int. conference of Deductive and ObjectOriented Databases, Munich, 1991. Y. Caseau: Efficient Handling of Multiple Inheritance Hierarchies. Proc. of the int. conf. on Object-Oriented Programming Systems, Languages and Applications, Washington, September1993. Y. Caseau, P. Koppstein: A Rule-Based Approach to a TimeConstrained Traveling Salesman Problem. Presented at the Second International Symposium on Artificial Intelligence and Mathematics, January 1992, to appear. Y. Caseau, P.-Y. Guillo, E. Levenez: A Deductive and Object-Oriented Approach to a Complex Scheduling Problem. Proc. of the third int. conference of Deductive and Object-Oriented Databases, Phoenix, December 1993. N. Heintze & al.: Constraint Logic Programming: A Reader. Proc. 4th IEEE Symposium on Logic Programming, San Francisco, 1987. P. Cousot, R. Cousot: Abstract Interpretation: A Unified Lattice Model for Static Analysis of Programs by Constructions or Approximation of Fixpoints. Proc. Fourth ACM Symposium of Principles of Programming Languages, 1977. Y. Caseau, L. Perron: A type System for Object-Oriented Database Programming and Querying Languages. Proc. of International Workshop on DataBase Programming Languages, 1991.
- 37 -
[Do90]
C. Dony: Exception Handling and Object-Oriented Programming: Towards a Synthesis. Proc. of the int. conf. on Object-Oriented Programming Systems, Languages and Applications, Ottawa, 1990. [DSVH87] M. Dincbas, H. Simonis, P. Van Hentenryck: Extending Equation Solving and Constraint Handling in Logic Programming. Colloquium on Resolution of Equation in Algebraic Structures, Austin, May 1987. [DVH91] Y. Deville, P. Van Hentenryck: An Efficient Arc Consistency Algorithm for a class of CSP Problems. Proc. of 13th Int. Joint Conf. on Artificial Intelligence, Sidney, August 1991. [Fre90] B. Freeman-Benson: Kaleidoscope: Mixing Objects, Constraints, and Imperative Programming. Proc. of the int. conf. on Object-Oriented Programming Systems, Languages and Applications,Ottawa, October 1990. [Fo82] C.L. Forgy. RETE: A Fast Algorithm for the Many Pattern/Many Object Pattern Matching Problem. Artificial Intelligence, no 19, 1982. [GGN90] M. Ganti, P. Goyal, R. Nassif, P. Sunil: An Object-Oriented Development Environment. COMPCON, February 1990. [GR83] A. Goldberg, D. Robson: Smalltalk-80: The language and its implementation. Addison-Wesley, 1983. [GR92] M. Gangnet, B. Rosenberg: Constraint Programming and Graph Algorithms. Presented at the Second International Symposium on Artificial Intelligence and Mathematics, January 1992. [H&al90] W. Havens, S. Sidebottom, G. Sidebottom, J. Jones, M Cuperman, R. Davison: Echnida Constraint Reasoning System: Next-generation Expert System Technology. Technical Report CSS-IS TR 90-09, Simon Fraser University, Burnaby (Canada), December 1990. [HS89] R. Hull, J. Su. Untyped Sets, Invention, and Computable Queries. Proceeding of PODS-89, Philadelphia, 1989. [INV90] T. Imielinski, S. Naqvi, K. Vadaparty: A Query Language for Databases with Incomplete Objects. Proc. ACM SIGMOD Int. Conference on Management of Data, Atlantic City, May 1991. [INV91] T. Imielinski, S. Naqvi, K. Vadaparty: Querying Designs and Planing D a t a b a s e s . Proc. of the second int. conference of Deductive and Object-Oriented Databases,, Munich, 1991. [JL87] J. Jaffar, J.L. Lassez: Constraint Logic Programming. Proc. ACM Symp. Principles of Programming Languages, San Francisco, 1987. [KKR90] P. Kanellakis, G. Kuper, P. Revesz: Constraint Query Languages. Proc. of 9th ACM PODS, 1990. [KW89] M. Kifer, J. Wu: A logic for Object-Oriented Logic Programming (Maier's O-Logic Revisited). Proceeding of PODS-89, Philadelphia, 1989. [LR89] C. Lecluse, P. Richard: Modelling Complex Structures in ObjectOriented Databases. Proc. of ACM PODS, 1989.
- 38 -
[McL81]
B.J. MacLennan: Programming With A Relational Calculus. Rep n° NPS52-81-013, Naval Postgraduate School, September 1981. [Ma77] A. Mackworth: Consistency in Networks of Relations. Artificial Intelligence vol.8, 1977. [MBJK90] J. Mylopoulos, A. Borgida, M. Jarke, M. Koubarakis: Telos: a language for representing knowledge about information systems. A C M Trans. Information Systems 8(4), 1990. [PA91] J.F. Puget, P. Albert: PECOS: programmation par contraintes orientée objets. Génie Logiciel et Systèmes Experts, vol. 23, 1991. [Str86] B. Stroustrup: The C++ Programming Language. Addison-Wesley, 1986. [Ull91] J. Ullman: A Comparison of Deductive and Object-Oriented Database S y s t e m s . Proc. of the second int. conference of Deductive and Object-Oriented Databases,, Munich, 1991. [VD86] P. Van Hentenryck, M. Dincbas: Domains in Logic Programming. Proc. of AAAI-86, Philadelphia, August 1986. [VH89] P. Van Hentenryck: Constraint Satisfaction in Logic Programming. The MIT press, Cambridge, 1989. [VH91] P. Van Hentenryck: Incremental Constraint Satisfaction in Logic P r o g r a m m i n g. Proc. of the 7th Int. Conf. on Logic Programming, Jerusalem, 1990. [VHD91] P. Van Hentenryck, Y. Deville: The Cardinality Operator: A New Logical Connective for Constraint Logic Programming. Proc. of the 8th Int. Conf. on Logic Programming, Paris, 1991. [Vi86] L. Vieille: Recursive Axioms in Deductive Databases: The Query/Subquery Approach. Proc. First Intl. Conference on Expert Database Systems, Charleston, 1986.