Resolving constraints in Prolog - prolog

I am looking resources for learning resolving of constraints in Prolog. For example,
List=[X, Y, Z], List ins 1..4, X - Y #= Z.

What I understand, your want to get concrete solutions (and not the domains). For this, use label/1 or labeling/2, which will give all the explicit solutions (via backtracking). In SWI-Prolog, these predicates are documented here: labeling/2 .
label(List) is equivalent to labeling([],List).
For this simple example, label(List) would suffice:
?- List=[X, Y, Z], List ins 1..4, X - Y #= Z,label(List).
In general, you would benefit by reading the full documentation of clpfd (here for SWI-Prolog).

Related

Proper subsumes_term/2 in SWI-Prolog?

Lets assume SICStus Prolog is the benchmark for the
implementation of certain predicates, even ISO core standard
predicates. Especially in connection with attributed variables.
I then find these examples here. It's from SICStus 4 and not only SICStus 3:
?- when(nonvar(X), X=a), subsumes_term(X, b), X = a.
X = a ?
yes
?- when(nonvar(X), X=a), subsumes_term(X, b), X = b.
no
When doing the same in SWI-Prolog I get different results:
?- when(nonvar(X), X=a), subsumes_term(X, b), X = a.
false.
?- when(nonvar(X), X=a), subsumes_term(X, b), X = b.
false.
How would one implement a workaround in SWI-Prolog? ROKs METUTL.PL probably doesn't help, since it uses normal unification.
Here is a suggestion (not actually tested in SWI-prolog):
subsumes_term_sicstus(X, Y):-
copy_term(X-Y, XC-YC, _),
subsumes_term(XC, YC).
The idea is simply to copy the two structures then use the original predicate on the copies, which do not have attributes or frozen goals attached.
According to the documentation, it appears that copy_term/2 copies the attributes of attributed variables in SWI-prolog (but not in SICStus), so I am using copy_term/3 instead here. I see that there is also a copy_term_nat/2, which might be used instead.

Seeking a pure Prolog implementation of (\=)/2

Negation as failure is usually considered impure. The Prolog interpreter needed for negation as failure must realize SLDNF which is an extension of SLD.
The predicate (\=)/2 is for example used in the library(reif). It can be bootstrapped via negation as failure as follows, but is often a built-in:
X \= Y :- \+ X = Y.
Would it be possible to implement (\=)/2 as a pure predicate? Using only pure Prolog, i.e. only first order horn clauses?
Would it be possible to implement (=)/2 as a pure predicate? Using only pure Prolog, i.e. only first order horn clauses?
You can't implement (\=)/2 in pure Prolog.
Proof:
In logic, conjunction is commutative, and pure Prolog queries, if they terminate, must be logical.
However, with (\=)/2, the order of the terms matters, so it is not logical:
?- X \= Y, X=0, Y=1.
false.
?- X=0, Y=1, X \= Y.
X = 0,
Y = 1.

Duplicate constraints in CLP(FD) and with dif/2

In SWI-Prolog, the following query gives this result:
?- X mod 2 #= 0, X mod 2 #= 0.
X mod 2#=0,
X mod 2#=0.
While correct, there is obviously no need for the second constraint
Similarly:
?- dif(X,0), dif(X,0).
dif(X, 0),
dif(X, 0).
Is there no way to avoid such duplicate constraints? (Obviously the most correct way would be to not write code that leads to that situation, but it is not always that easy).
You can either avoid posting redundant constraints, or remove them with a setof/3-like construct. Both are very implementation specific. The best interface for such purpose is offered by SICStus. Other implementations like YAP or SWI more or less copied that interface, by leaving out some essential parts. A recent attempt to overcome SWI's deficiencies was rejected.
Avoid posting constraints
In SICStus, you can use frozen/2 for this purpose:
| ?- dif(X,0), frozen(X,Goal).
Goal = prolog:dif(X,0),
prolog:dif(X,0) ? ;
no
| ?- X mod 2#=0, frozen(X, Goal).
Goal = clpfd:(X in inf..sup,X mod 2#=0),
X mod 2#=0,
X in inf..sup ? ;
no
Otherwise, copy_term/3 might be good enough, provided the constraints are not too much interconnected with each other.
Eliminate redundant constraints
Here, a setof-like construct together with call_residue_vars/1 and copy_term/3 is probably the best approach. Again, the original implementation is in SICStus....
For dif/2 alone, entailment can be tested without resorting to any internals:
difp(X,Y) :-
( X \= Y -> true
; dif(X, Y)
).
Few constraint programming systems implement contraction also related to factoring in resolution theorem proving, since CLP labeling is not SMT. Contraction is a structural rule, and it reads as follows, assuming constraints are stored before the (|-)/2 in negated form.
G, A, A |- B
------------ (Left-Contraction)
G, A |- B
We might also extend it to the case where the two A's are derivably equivalent. Mostlikely this is not implemented, since it is costly. For example Jekejeke Minlog already implements contraction for CLP(FD), i.e. finite domains. We find for queries similar to the first query from the OP:
?- use_module(library(finite/clpfd)).
% 19 consults and 0 unloads in 829 ms.
Yes
?- Y+X*3 #= 2, 2-Y #= 3*X.
3*X #= -Y+2
?- X #< Y, Y-X #> 0.
X #=< Y-1
Basically we normalize to A1*X1+..+An*Xn #= B respectively A1*X1+..+An*Xn #=< B where gcd(A1,..,An)=1 and X1,..,Xn are lexically ordered, and then we check whether there is already the same constraint in the constraint store. But for CLP(H), i.e. Herbrand domain terms, we have not yet implemented contraction. We are still deliberating an efficient algorithm:
?- use_module(library(term/herbrand)).
% 2 consults and 0 unloads in 35 ms.
Yes
?- neq(X,0), neq(X,0).
neq(X, 0),
neq(X, 0)
Contraction for dif/2 would mean to implement a kind of (==)/2 via the instantiation defined in the dif/2 constraint. i.e. we would need to apply a recursive test following the pairing of variables and terms defined in the dif/2 constraint against all other dif/2 constraints already in the constraint store. Testing subsumption instead of contraction would also make more sense.
It probably is only feasible to implement contraction or subsumption for dif/2 with the help of some appropriate indexing technique. In Jekejeke Minlog for example for CLP(FD) we index on X1, but we did not yet realize some indexing for CLP(H). What we first might need to figure out is a normal form for the dif/2 constraints, see also this problem here.

prolog doesn't give me a solution when one exists

I am working through Seven Languages in Seven Weeks, but there is something I don't understand about prolog. I have the following program (based on their wallace and grommit program):
/* teams.pl */
onTeam(a, aTeam).
onTeam(b, aTeam).
onTeam(b, superTeam).
onTeam(c, superTeam).
teamMate(X, Y) :- \+(X = Y), onTeam(X, Z), onTeam(Y, Z).
and load it like this
?- ['teams.pl'].
true.
but it doesn't give me any solutions to the following
?- teamMate(a, X).
false.
it can solve simpler stuff (which is shown in the book):
?- onTeam(b, X).
X = aTeam ;
X = superTeam.
and there are solutions:
?- teamMate(a, b).
true ;
false.
What am I missing? I have tried with both gnu prolog and swipl.
...AND THERE IS MORE...
when you move the "can't be your own teammate" restriction to then end:
/* teams.pl */
onTeam(a, aTeam).
onTeam(b, aTeam).
onTeam(b, superTeam).
onTeam(c, superTeam).
teamMate(X, Y) :- onTeam(X, Z), onTeam(Y, Z), \+(X = Y).
it gives me the solutions I would expect:
?- ['teams.pl'].
true.
?- teamMate(a, X).
X = b.
?- teamMate(b, X).
X = a ;
X = c.
What gives?
You have made a very good observation! In fact, the situation is even worse, because even the most general query fails:
?- teamMate(X, Y).
false.
Declaratively, this means "there are no solutions whatsoever", which is obviously wrong and not how we expect relations to behave: If there are solutions, then more general queries must not fail.
The reason you get this strange and logically incorrect behaviour is that (\+)/1 is only sound if its arguments are sufficiently instantiated.
To express disequality of terms in a more general way, which works correctly no matter if the arguments are instantiated or not, use dif/2, or, if your Prolog system does not provide it, the safe approximation iso_dif/2 which you can find in the prolog-dif tag.
For example, in your case (note_that_I_am_using_underscores_for_readability instead of tuckingTheNamesTogetherWhichMakesThemHarderToRead):
team_mate(X, Y) :- dif(X, Y), on_team(X, Z), on_team(Y, Z).
Your query now works exactly as expected:
?- team_mate(a, X).
X = b.
The most general query of course also works correctly:
?- team_mate(X, Y).
X = a,
Y = b ;
X = b,
Y = a ;
X = b,
Y = c ;
etc.
Thus, using dif/2 to express disequality preserves logical-purity of your relations: The system now no longer simply says false even though there are solutions. Instead, you get the answer you expect! Note that, in contrast to before, this also works no matter where you place the call!
The answer by mat gives you some high-level considerations and a solution. My answer is a more about the underlying reasons, which might or might not be interesting to you.
(By the way, while learning Prolog, I asked pretty much the same question and got a very similar answer by the same user. Great.)
The proof tree
You have a question:
Are two players team mates?
To get an answer from Prolog, you formulate a query:
?- team_mate(X, Y).
where both X and Y can be free variables or bound.
Based on your database of predicates (facts and rules), Prolog tries to find a proof and gives you solutions. Prolog searches for a proof by doing a depth-first traversal of a proof tree.
In your first implementation, \+ (X = Y) comes before anything else, so it at the root node of the tree, and will be evaluated before the following goals. And if either X or Y is a free variable, X = Y must succeed, which means that \+ (X = Y) must fail. So the query must fail.
On the other hand, if either X or Y is a free variable, dif(X, Y) will succeed, but a later attempt to unify them with each other must fail. At that point, Prolog will have to look for a proof down another branch of the proof tree, if there are any left.
(With the proof tree in mind, try to figure out a way of implementing dif/2: do you think it is possible without either a) adding some kind of state to the arguments of dif/2 or b) changing the resolution strategy?)
And finally, if you put \+ (X = Y) at the very end, and take care that both X and Y are ground by the time it is evaluated, then the unification becomes more like a simple comparison, and it can fail, so that the negation can succeed.

Are HiLog terms still useful in modern Prolog?

Are Hilog terms (i.e. compounds having as functors arbitrary terms) still regarded as a powerful feature in XSB Prolog (or any other Prolog) ?
Are there many XSB projects currently using this feature ? which of them for example ?
I ask since as far as I understand higher order programming is equally possible using the ISO built-in call/N.
Specifically, I would like to understand if XSB is using Hilog terms just for historical reasons or if Hilog terms have considerable advantages in comparison to the current ISO standard.
Within XSB, Hilog terms are very strongly connected to the module system which is unique to XSB. XSB has a functor based module system. That is, within the same scope length(X) might belong to one module, whereas length(L, N) might belong to another. As a consequence, call(length(L), N) might refer to one module and call(length(L, N)) to another:
[Patch date: 2013/02/20 06:17:59]
| ?- use_module(basics,length/2).
yes
| ?- length(Xs,2).
Xs = [_h201,_h203]
yes
| ?- call(length(Xs),2).
Xs = [_h217,_h219]
yes
| ?- use_module(inex,length/1).
yes
| ?- length(Xs,2).
Xs = [_h201,_h203]
yes
| ?- call(length(Xs),2).
++Error[XSB/Runtime/P]: [Existence (No module inex exists)] in arg 1 of predicate load
| ?- call(call(length,Xs),2).
Xs = [_h228,_h230];
It might be that in such a context there are differences between call/N and Hilog terms. I have, however, so far not found one.
Historically, Hilog terms have been introduced 1987-1989. At that point in time, call/N already existed as built-ins in NU and as library(call) in Quintus Prolog with only cursory documentation. It has been proposed 1984 by Richard O'Keefe. On the other hand, call/N was clearly unknown to the authors of Hilog, as is exemplified on p.1101 of Weidong Chen, Michael Kifer, David Scott Warren: HiLog: A First-Order
Semantics for Higher-Order Logic Programming Constructs. NACLP
1989. 1090-1114. MIT-Press.
... Generic transitive closure can also be defined in Prolog:
closure(R, X, Y) :- C =.. [R, X, Y], call(C).
closure(R, X, Y) :- C =.. [R, X, Z], call(C), closure(R, Z, Y).
However, this is obviously inelegant compared to HiLog (see Section 2.1), since this involves both constructing a term out of a list and reflecting this term into an atomic formula using "call". The point of this example is that the lack of theoretical foundations for higher-order constructs in Prolog resulted in an obscure syntax, which partially explains why Prolog programs involving such constructs are notoriously hard to understand.
Now, this can be done with call/N like so:
closure(R, X, Y) :- call(R, X, Y).
closure(R, X, Y) :- call(R, X, Z), closure(R, Z, Y).
Which is even more general than the (=..)/2-version because R is no longer restricted to being an atom. As an aside, I'd rather prefer to write:
closure(R_2, X0,X) :- call(R_2, X0,X1), closure0(R_2, X1,X).
closure0(_R_2, X,X).
closure0(R_2, X0,X) :- call(R_2, X0,X1), closure0(R_2, X1,X).
HiLog allows goals such as
foo(X(a, Y(b))).
and ISO Prolog does not. In ISO Prolog, you'd have to write
foo(T), T=..[X, a, R], R=..[Y, b].
which is less convenient and might be slower.

Resources