CLP(D) is a language framework, parameterized by the domain of the constraints.
Example CLP languages:
There is also an analogous framework HCLP(D), which allows both required and preferential constraints. It is again parameterized by the domain of the constraints. (See Molly Wilson's PhD dissertation.)
We'll be looking at CLP(R), constraint logic programming for the reals.
Data is either real numbers (approximated by floating point numbers), or trees ("elements in the Herbrand universe"). Also called "terms".
Trees are constructed from atoms (written as a symbol beginning with a lower case letter) and "uninterpreted functors" (function symbols). Examples:
x fred point(3,4) [a,b,c,d] /* a list with four elements */ line(point(3,4),point(10,20))
There is no assignment statement; rather, the value of a variable is refined as the computation progresses and constraints are accumulated on the value of a variable. Important: we can have variables embedded in trees (terms).
Scope rules are simple: variables locally scoped within a fact, rule, or query.
Syntax: variables begin with a capital letter.
Anonymous variable: _ (underscore)
For trees, the only kind of constraint is equality. These equality constraints are solved by unification (two-way pattern matching), as we used in type checking in ML and Haskell.
Examples:
a=a succeeds a=b fails a=X succeeds with X=a X=Y succeeds with X=Y (or Y=X) point(X,X)=point(10,Y) succeeds with X=Y=10 [X,Y] = [1,2] succeeds with X=1, Y=2 [X|Xs] = [1,2,3,4,5] succeeds with X=1, Xs=[2,3,4,5] [X|Xs] = [1] succeeds with X=1, Xs=[] [X|Xs] = [] fails
For lists, the vertical bar divides the elements at the front of the list from the rest of the list.
For real numbers, the relational operators are +, <=, <, >= and >. The function symbols are + - * / sin cos pow max min abs.
Examples:
X=1+4*5 succeeds with X=21 2*X+Y=7, X+Y=5 succeeds with X=2, Y=3 X<=10, X<=5, X>=2 succeeds with 2<=X<=5 pow(sin(X),2) + pow(cos(X),2) = 1 says "maybe" X*X + 3*X + 5 = 9 says "maybe"
A CLP(R) program consists of a collection of rules.
P :- Q1, ... Qn, C1, ... Cm This says that P holds if Q1, ... Qn, C1, ... Cm hold, for subgoals Q1, ... Qn and constraints C1, ... Cm.
To run clpr on orcas:
/cse/courses/misc_lang/axp/clpr/bin/clpr (or put /cse/courses/misc_lang/axp/clpr/bin/ in your search path)
For example programs see ~borning/clpr/myprogs/* and ~borning/clpr/progs/* )
You can load a file using the file name as a command line argument:
clpr resistors
Once you are in clpr, you can load a file using consult(myfile).
To reload a changed file: reconsult(myfile).
/**********************************************/ /* centigrade-fahrenheit converter* cf(C,F) :- F = 1.8*C + 32. /**********************************************/ /* length relation */ length([],0). length([H|T],N) :- N > 0, length(T,N-1). /**********************************************/ /* recursive factorial */ fact(0, 1). fact(N, N * F) :- N > 0 , fact(N - 1, F). /**********************************************/ /* list of numbers between Start and Stop */ range(Start,Stop,[]) :- Start > Stop. range(Start,Stop,[Start|More]) :- Start <= Stop, range(Start+1,Stop,More). /**********************************************/ /* sorting */ quicksort([],[]). quicksort([X|Xs],Sorted) :- partition(X,Xs,Smalls,Bigs), quicksort(Smalls,SortedSmalls), quicksort(Bigs,SortedBigs), append(SortedSmalls,[X|SortedBigs],Sorted). partition(Pivot,[],[],[]). partition(Pivot,[X|Xs],[X|Ys],Zs) :- X <= Pivot, partition(Pivot,Xs,Ys,Zs). partition(Pivot,[X|Xs],Ys,[X|Zs]) :- X > Pivot, partition(Pivot,Xs,Ys,Zs). /* auxiliary function - list append */ append([],X,X). append([X|Xs],Ys,[X|Zs]) :- append(Xs,Ys,Zs). Some sample programs on orcas:
A state is a pair <G | C> where G is the current goal and C is the current set of collected constraints. C is held in solved form. Initially G consists of the goals entered by the user and C is empty.
A derivation step from <G | C> to <G' | C'> is written
<G | C> => <G' | C'>
It is defined as follows.
Let G = L1 and ... and Li-1 and Li and ... Li+1 ... and Lm. Li is the selected literal.
Two cases:
1. If Li is a primitive constraint then
C' = C and Li (collect Li)
G' = empty if solver(C') = false;L1 and ... and Li-1 and
Li+1 and .. and Lm otherwise.
2. If Li is an atom
C' = C
G' is a rewriting of G at Li by some rule R in the program.
To rewrite Li, we find a rule with a head that matches Li.
We rename the variables in the rule if necessary so that they are distinct
from any variables in the current derivation. We then set up equality constraints
between the corresponding terms in Li and those head of the
rule, and add the goals in the body of the rule.
A derivation from state <G0 | C0> is a sequence of derivation steps <G0 | C0> => <G1 | C1> => ...
A derivation from a goal G is a derivation from state <G | true>.
A derivation <G0 | C0> => .. => <Gn | Cn>is successful if Gn is empty and solver(Cn) /= false.
It is failed if Gn = empty and solver (Cn)=false.
A derivation for G = append([1,2],[3,4,5],M)
R1: append([],X,X).
R2: append([X|Xs],Ys,[X|Zs]) :- append(Xs,Ys,Zs).
<append([1,2],[3,4,5],M) | true>
<[X|Xs]=[1,2], Ys=[3,4,5], [X|Zs]=M, append(Xs,Ys,Zs) | true> (using R2)
<Ys=[3,4,5], [X|Zs]=M, append(Xs,Ys,Zs) | X=1, Xs=[2]>
<[X|Zs]=M, append(Xs,Ys,Zs) | X=1, Xs=[2] Ys=[3,4,5]>
<append(Xs,Ys,Zs) | X=1, Xs=[2] Ys=[3,4,5], M=[1|Zs]>
<[X'|Xs']=Xs, Ys'=Ys, [X'|Zs']=Zs], append(Xs',Ys',Zs') | X=1, Xs=[2] Ys=[3,4,5], M=[1|Zs]> (using R2)
<Ys'=Ys, [X'|Zs']=Zs], append(Xs',Ys',Zs') | X=1, Xs=[2] Ys=[3,4,5], M=[1|Zs] X'=2, Xs'=[ ]>
<[X'|Zs']=Zs], append(Xs',Ys',Zs') | X=1, Xs=[2] Ys=[3,4,5], M=[1|Zs] X'=2, Xs'=[ ], Ys'=[3,4,5]>
<append(Xs',Ys',Zs') | X=1, Xs=[2] Ys=[3,4,5], M=[1,2|Zs'] X'=2, Xs'=[ ] Ys'=[3,4,5], Zs=[2|Zs']>
<Xs'=[ ],Ys'=Zs' | X=1, Xs=[2] Ys=[3,4,5], M=[1,2|Zs'] X'=2, Xs'=[ ] Ys'=[3,4,5], Zs=[2|Zs']>
<Ys'=Zs' | X=1, Xs=[2] Ys=[3,4,5], M=[1,2|Zs'] X'=2, Xs'=[ ] Ys'=[3,4,5], Zs=[2|Zs']>
<X=1, Xs=[2] Ys=[3,4,5], M=[1,2,3,4,5] X'=2, Xs'=[ ] Ys'=Zs'=[3,4,5], Zs=[2,3,4,5]>
returning just the binding for M we get: M = [1,2,3,4,5]
A derivation tree for goal G is a tree with states as its nodes. Root node: <G | true>. Children of a given node: states produced by each possible rule choice.
Choices: which literal to choose, which rule to choose for a given literal. CLP(R) uses a left-to-right literal selection strategy, and selects the first matching rule in the program (where "first" depends on which rule is first in the program source).
example - see hand-drawn slides
an instance of the CLP scheme: explores efficient implementation; used for a variety of applications
benefits of CLP scheme (pointed out in paper)
some efficiency issues:
loop(X) :- loop(X). test1(A) :- A=4, loop(A), A=3. test2(A) :- A=4, A=3, loop(A). test1 goes into an infinite depth-first search, but test2 fails.
X*X = 4. not as smart as one might like (but making it smarter would probably slow it down a lot!)
X*X = 4, X>0. /* gives a 'maybe' answer */ X*X = 4, X=2. /* gives a 'yes' answer with X=2 */ 4=abs(W).
X = point(3,4). A = f( X , 0.5 , g(Z) ), B = f( sin(Y) , Y , WW ), A=B. In the above example, point and g are uninterpreted function symbols; sin is interpreted.
Constraint Logic Abstract Machine (CLAM) -- derived from Warren Abstract Machine (WAM)
The engine is a structure sharing Prolog interpreter (see Figure 2, page 360)
Distinguish between constraints that can be handled in the engine (e.g. nonsolver variable = number) and those that must be passed to the interface. Constraints that can be handled in the engine are shown in figure 3, page 361.
Simplify input constraint by evaluating arithmetic expressions. If constraint is ground, test it
If there is one non-solver variable, set up a binding. Otherwise put constraint into a canonical form and invoke solver.
solver modules:
Equality Solver: variant of Gaussian elimination.
Represent nonparametric variables in terms of parametric variables and constants. Central data structure: a tableau (2d array). Each row represents some nonparametric variable as a linear combination of parametric variables.
Equality solver is invoked by the interface with a new equality, from the inequality solver with an implicit equality, or with a delayed constraint from the nonlinear handler. Inequality Solver: adapted from first phase of two-phase Simplex algorithm
augmentations of basic Simplex algorithm:
detection of implicit equalities (could scrap equality solver and just do it all with Simplex ...)
Nonlinear handler: delay nonlinear constraints until they become linear