Prolog - Constraint Library - Variable Scope - prolog

I'm working on trying to solve an LSAT logic problem with Prolog. I'm trying to get Prolog to tell me whether possible values for actors in a line are valid.
I wrote the following:
:- use_module(library(clpfd)).
actor("Jeff",A) :-
A #>= 0,
A #<5.
actor("Rich",C) :-
C #>= 0,
C #<5,
actor("Jeff",A),
A #< C.
When I query:
?- actor("Rich",0).
false.
Which is right since Jeff is < than Rich and Jeff is => 0 so Rich cannot be 0.
But, when I query:
?- actor("Jeff",1), actor("Rich",1).
true
I also get true, which is impossible because Rich > Jeff.
I feel the problem is because of something going on with my variable. I don't understand how
actor("Jeff",A),
A #< C.
is evaluating. It seems to me that actor("Jeff",A) should be set to actor("Jeff",1) and then 1 #< 1 should fail.

Variables within a clause or local to that clause.
In your case, to understand the issue, consider first the following query:
?- actor("Rich", C),
C = 1.
C = 1.
This does not tell us a lot, so we apply the following purely algebraic reasoning: For the goal actor("Rich", C), we substitute the body of the single matching clause:
?- C #>= 0,
C #< 5,
actor("Jeff",A),
A #< C,
C = 1.
The answer is:
C = 1,
A = 0.
This shows that when C is 1, then A is 0. However, on the toplevel, you did not see this because this variable only occurs within the clause for "Rich". Making this explicit shows that there is a solution that satisfies the constraint within that clause, but it is not linked to the variable we want.
There are several ways out. One of them is to make A available as an argument so that you can explicitly refer to it from the toplevel. In general, to link the relevant entities together, you will have to introduce arguments for each of your clauses, so that you can refer to the variables you need to reason about, instead of introducing new ones within each clause.
For example, in your case, this could look as follows:
actor("Jeff", A, _) :-
A #>= 0,
A #< 5.
actor("Rich", A, C) :-
C #>= 0,
C #< 5,
actor("Jeff", A, C),
A #< C.
I have used A to refer to Jeff, and C to refer to Rich.
While we are at at, let us tidy up the code, and use the following essentially equivalent version:
actor(jeff, A, _) :- A in 0..4.
actor(rich, A, C) :- C in 0..4, actor(jeff, A, C), A #< C.
Make sure you understand the following answer:
?- actor(jeff, 1, C), actor(rich, C, 1).
C = 0.
Your original example now yields false, exactly as expected:
?- actor(rich, 1, 1).
false.
Thus, you should be able to solve your task in principle.
However, there is a much simpler way to solve all this, which avoids the reification overload.
Instead of painstakingly keeping track of connections between names and corresponding variables, let us use the variables directly with the intended names. For example, what do you say about this:
?- Jeff in 0..4,
Rich in 0..4,
Jeff #< Rich.
This uses Prolog variables to denote the people, and makes the work a lot simpler. In this representation, your query becomes:
?- Jeff in 0..4,
Rich in 0..4,
Jeff #< Rich,
Jeff = 1,
Rich = 1.
And this obviously results in false.

Related

Why does returning false? [duplicate]

I implemented the following power program in Prolog:
puissance(_,0,1).
puissance(X,N,P) :- N>0,A is N-1, puissance(X,A,Z), P is Z*X.
The code does what is supposed to do, but after the right answer it prints "false.". I don't understand why. I am using swi-prolog.
Can do like this instead:
puissance(X,N,P) :-
( N > 0 ->
A is N-1,
puissance(X,A,Z),
P is Z*X
; P = 1 ).
Then it will just print one answer.
(Your code leaves a `choice point' at every recursive call, because you have two disjuncts and no cut. Using if-then-else or a cut somewhere removes those. Then it depends on the interpreter what happens. Sicstus still asks if you want ((to try to find)) more answers.)
Semantic differences
Currently, there are 3 different versions of puissance/3, and I would like to show a significant semantic difference between some of them.
As a test case, I consider the query:
?- puissance(X, Y, Z), false.
What does this query mean? Declaratively, it is clearly equivalent to false. This query is very interesting nevertheless, because it terminates iff puissance/3 terminates universally.
Now, let us try the query on the different variants of the program:
Original definition (from the question):
?- puissance(X, Y, Z), false.
ERROR: puissance/3: Arguments are not sufficiently instantiated
Accepted answer:
?- puissance(X, Y, Z), false.
false.
Other answer:
?- puissance(X, Y, Z), false.
ERROR: puissance/3: Arguments are not sufficiently instantiated
Obviously, the solution shown in the accepted answer yields a different result, and is worth considering further.
Here is the program again:
puissance(_,0,1) :- !.
puissance(X,N,P) :- N>0,A is N-1, puissance(X,A,Z), P is Z*X.
Let us ask something simple first: Which solutions are there at all? This is called the most general query, because its arguments are all fresh variables:
?- puissance(X, Y, Z).
Y = 0,
Z = 1.
The program answers: There is only a single solution: Y=0, Z=1.
That's incorrect (to see this, try the query ?- puissance(0, 1, _) which succeeds, contrary to the same program claiming that Y can only be 0), and a significant difference from the program shown in the question. For comparison, the original program yields:
?- puissance(X, Y, Z).
Y = 0,
Z = 1 ;
ERROR: puissance/3: Arguments are not sufficiently instantiated
That's OK: On backtracking, the program throws an instantiation error to indicate that no further reasoning is possible at this point. Critically though, it does not simply fail!
Improving determinism
So, let us stick to the original program, and consider the query:
?- puissance(1, 1, Z).
Z = 1 ;
false.
We would like to get rid of false, which occurs because the program is not deterministic.
One way to solve this is to use zcompare/3 from library(clpfd). This lets you reify the comparison, and makes the result available for indexing while retaining the predicate's generality.
Here is one possible solution:
puissance(X, N, P) :-
zcompare(C, 0, N),
puissance_(C, X, N, P).
puissance_(=, _, 0, 1).
puissance_(<, X, N, P) :-
A #= N-1,
puissance(X, A, Z),
P #= Z*X.
With this version, we get:
?- puissance(1, 1, Z).
Z = 1.
This is now deterministic, as intended.
Now, let us consider the test case from above with this version:
?- puissance(X, Y, Z), false.
nontermination
Aha! So this query neither throws an instantiation error nor terminates, and is therefore different from all the versions that have hitherto been posted.
Let us consider the most general query with this program:
?- puissance(X, Y, Z).
Y = 0,
Z = 1 ;
X = Z,
Y = 1,
Z in inf..sup ;
Y = 2,
X^2#=Z,
Z in 0..sup ;
Y = 3,
_G3136*X#=Z,
X^2#=_G3136,
_G3136 in 0..sup ;
etc.
Aha! So we get a symbolic representation of all integers that satisfy this relation.
That's pretty cool, and I therefore recommend you use CLP(FD) constraints when reasoning over integers in Prolog. This will make your programs more general and also lets you improve their efficiency more easily.
You can add a cut operator (i.e. !) to your solution, meaning prolog should not attempt to backtrack and find any more solutions after the first successful unification that has reached that point. (i.e. you're pruning the solution tree).
puissance(_,0,1) :- !.
puissance(X,N,P) :- N>0,A is N-1, puissance(X,A,Z), P is Z*X.
Layman's Explanation:
The reason prolog attempts to see if there are any more solutions, is this:
At the last call to puissance in your recursion, the first puissance clause succeeds since P=1, and you travel all the way back to the top call to perform unification with P with the eventual value that results from that choice.
However, for that last call to puissance, Prolog didn't have a chance to check whether the second puissance clause would also be satisfiable and potentially lead to a different solution, therefore unless you tell it not to check for further solutions (by using a cut on the first clause after it has been successful), it is obligated to go back to that point, and check the second clause too.
Once it does, it sees that the second clause cannot be satisfied because N = 0, and therefore that particular attempt fails.
So the "false" effectively means that prolog checked for other choice points too and couldn't unify P in any other way that would satisfy them, i.e. there are no more valid unifications for P.
And the fact that you're given the choice to look for other solutions in the first place, exactly means that there are still other routes with potentially satisfiable clauses remaining that have not been explored yet.

SWI Prolog Clpfd Library - Reification

I have an upcoming Logic exam and have been studying some past papers from my course. I've come across a question regarding reification and have posted it below;
Illustrate reification by using it to express the property that a variable B can
either take the value of 1 or 8.
After reading some resources and looking at the SWI Prolog manual, I still find the concept of reification quite confusing (primarily studying Java so the switch to learning Prolog has been difficult). It's quite confusing having to use boolean logic within the prolog query.
Without reification, I would have to write the following code (which I know is far too long to be the correct answer);
B in 1..8, B #\= 2,B #\= 3,B #\= 4,B #\= 5,B #\= 6,B #\= 7.
Would really appreciate if someone could show me the above query, but using reification.
From the documentation:
The constraints in/2, #=/2, #\=/2, #/2, #==/2 can be reified, which means reflecting their truth values into Boolean values represented by the integers 0 and 1. Let P and Q denote reifiable constraints or Boolean variables, then:
...
P #\/ Q True iff either P or Q
...
For you, it seems P is B #= 1 and Q is B #= 8, so you end up with:
?- B #= 1 #\/ B #= 8.
B in 1\/8.
As you see, you are not really using the reified values. You are just using reification as a round-about way of declaring the domain of your variable. The answer to your query, B in 1 \/ 8, is what you would probably use directly if you wanted to say that "B is either 1 or 8". If you look carefully at the documentation of in/2, you should see that the domain can be either an integer, a range Lower .. Upper, or the union of Domain1 \/ Domain2. In your case both domains are a single integer, 1 and 8.
PS: Once you go down that road, why not:
?- B in 1..8 #/\ #\ B in 2..7.
B in 1\/8.
B is in [1,8] AND B is not in [2,7].
The possibilities are endless :)
First, try out your query:
?- B in 1..8, B #\= 2,B #\= 3,B #\= 4,B #\= 5,B #\= 6,B #\= 7.
B in 1\/8.
This tells you that your query is equivalent to the single goal B in 1\/8.
From this, you see that you don't need reification to express that a finite domain variable is either equal to 1 or 8.
Reification allows you to reify the truth value of the constraint. For example, you can say:
?- T #<==> B in 1\/8.
T in 0..1,
B in 1\/8#<==>T.
?- T #<==> B in 1\/8, B = 3.
T = 0,
B = 3.
From the second query, you see that if B = 3, then T = 0, because the constraint B in 1\/8 doesn't hold in that case.
Reifying a constraint can be useful if you want to reason about constraints themselves. For example, this allows you to express that a certain number of list elements must be equal to a given integer. I leave solving this as a more meaningful exercise to understand reification.
Initially I was thinking along the same lines as #Boris and #mat. But after pondering the question for a while, another possible interpretation of the task occured to me. However, keep in mind that I am not familiar with your course material, so this is highly speculative. That being said, maybe the task description is asking to write a predicate that evaluates to true if the above property holds or to false otherwise. A predicate like that could be defined as:
val_either_or_t(X,Y,Z,true) :-
( X#=Y ; X#=Z).
val_either_or_t(X,Y,Z,false) :-
X #\= Y,
X #\= Z.
I admit the name is a little clumsy but I couldn't really come up with a better one. Anyway, it does the job according to the task interpretation I described above:
?- val_either_or_t(X,1,8,T).
T = true,
X = 1 ? ;
T = true,
X = 8 ? ;
T = false,
X in inf..0\/2..7\/9..sup
?- val_either_or_t(X,Y,Z,T).
T = true,
X = Y,
X in inf..sup ? ;
T = true,
X = Z,
X in inf..sup ? ;
T = false,
X#\=Z,
X#\=Y
I came up with this idea because lately I was playing around with some reifying predicates that I found on Stackoverflow, and it popped into my mind that the task might be aimed in a direction where the described property could be used as a condition with such predicates. For example with if_/3 that I used a lot with (=)/3 in the condition, but why not use it with something like val_either_or_t/4. Consider the following minimal example:
a(condition_was_true).
b(condition_was_false).
somepredicate(X,Y) :-
if_(val_either_or_t(X,1,8),a(Y),b(Y)).
With the respective query:
?- somepredicate(X,Y).
X = 1,
Y = condition_was_true ? ;
X = 8,
Y = condition_was_true ? ;
Y = condition_was_false,
X in inf..0\/2..7\/9..sup
This example is of course not very meaningful and only intended to illustrate how reification of the given property might be used. Also, I am using the atoms true and false to reify the thruth values with regard to using them with if_/3. However, you can also use 1 and 0 to reify truth values like in #mat's example. Just replace the 4th argument in the definition of val_either_or_t/4 by 1 and 0 respectively. Furthermore you might find the refinement of this idea that was suggested by #repeat in the comments interesting as well.

SWI-Prolog Creating/Printing lists, Recursion etc

I'm trying to teach myself some Prolog, however right now i'm really struggling just adapting to the declarative style having never done declarative programming before.
I'm attempting to get my program to come up with a two positive integer numbers, A & B, where A + B =< 50 and B > A. Obviously there are lots of solutions (e.g. A = 5 & B = 12 or A = 15 & B = 17) and i want my program to print all the different solutions.
I honestly don't really know where to begin and would appreciate some guidance or some example code of how to do something as explained above.
Cheers!
Looks like a good problem to use constraint logic programming:
:- use_module(library(clpfd)).
model(A, B) :-
A #> 0, B #> 0,
A + B #=< 50,
B #> A.
(I assume you want only positive integer solutions, otherwise there will be infinite number of them). Look how the model code directly reflects the problem statement.
After you have the model you can use it to find all solutions:
?- findall(_, (model(A, B), label([A, B]), writeln([A, B])), _).
[1,2]
[1,3]
[1,4]
[1,5]
[1,6]
... skipped many lines ...
[24,25]
[24,26]
true.
A more traditional Prolog solution without constraint programming (with the same results):
model2(A, B) :-
between(1, 50, A),
between(1, 50, B),
A + B =< 50,
B > A.
?- findall(_, (model2(A, B), writeln([A, B])), _).
You could do something like this:
combos(A,B) :-
between(1,50,A) ,
between(1,50,B) ,
S is A+B ,
S =< 50
.
This, on backtracking, will successively find all the solutions.
Use findall/3 to collect the results into a list:
findall(A+B,combos(A,B),X).

Relying on rule order

To calculate the hamming distance between two lists of the same length, I use foldl(hamm, A, B, 0, R). with this definition of hamm/4:
hamm(A, A, V, V) :- !.
hamm(A, B, V0, V1) :- A \= B, V1 is V0 + 1.
The cut in the first rule prevents the unnecessary backtracking. The second rule, however, could have been written differently:
hamm2(A, A, V, V) :- !.
hamm2(_, _, V0, V1) :- V1 is V0 + 1.
and hamm2/4 will still be correct together with foldl/5 or for queries where both A and B are ground.
So is there a really good reason to prefer the one over the other? Or is there a reason to keep the rules in that order or switch them around?
I know that the query
hamm(a, B, 0, 1).
is false, while
hamm2(a, B, 0, 1).
is true, but I can't quite decide which one makes more sense . . .
The OP implemented two accumulator-style predicates for calculating the Hamming distance (hamm/4 and hamm2/4), but wasn't sure which one made more sense.
Let's read the query that puzzled the OP: "Is there an X such that distance(a,X) is 1?". Here are the "answers" Prolog gives:
?- hamm(a,X,0,1).
false. % wrong: should succeed conditionally
?- hamm2(a,X,0,1). % wrong: should succeed, but not unconditionally
true.
From a logical perspective, both implementations misbehave in above test. Let's do a few tests for steadfastness:
?- hamm(a,X,0,1),X=a. % right
false.
?- hamm(a,X,0,1),X=b. % wrong: should succeed as distance(a,b) is 1
false.
?- hamm2(a,X,0,1),X=a. % wrong: should fail as distance(a,a) is 0
X = a.
?- hamm2(a,X,0,1),X=b. % right
X = b.
Note that in previous queries hamm/4 rightly fails when hamm2/4 wrongly succeeded, and vice-versa.
So both are half-right/half-wrong, and neither one
is steadfast.
What can be done?
Based on if_/3 and (=)/3 presented by #false in this answer, I implemented the following pure code for predicate hamm3/4:
:- use_module(library(clpfd)).
hamm3(A,B,V0,V) :-
if_(A = B, V0 = V, V #= V0+1).
Now let's repeat above queries using hamm3/4:
?- hamm3(a,X,0,1).
dif(X,a).
?- hamm3(a,X,0,1),X=a.
false.
?- hamm3(a,X,0,1),X=b.
X = b.
It works! Finally, let's ask the most general query to see the entire solution set of hamm3/4:
?- hamm3(A,B,N0,N).
A = B, N0 = N ;
dif(A,B), N0+1 #= N.
You already spotted the differences between those definitions: efficiency apart, you should decide about your requirements. Are you going to accept variables in your data structures? Such programming style introduces some of advanced Prolog features (incomplete data structures).
Anyway, I think the first form is more accurate (not really sure about, I would say steadfast on 4° argument)
?- hamm(a, B, 0, 1).
false.
?- hamm(a, B, 0, 0).
B = a.
while hamm2 is
?- hamm2(a, B, 0, 1).
true.
?- hamm2(a, B, 0, 0).
B = a.

existential qualifier in prolog, using setof / bagof

I had a quick question re. existential qualifier using setof in prolog (i.e. ^).
using SICStus it seems that (despite what a number of websites claim), S does indeed appear to be quantified in the code below (using the bog standard, mother of / child of facts, which i havent included here):
child(M,F,C) :- setof(X,(mother(S,X)),C).
i check the unification using:
child(M,F,C) :- setof(X-S,(mother(S,X)),C).
so the following code, with the existential operator seem to make no difference:
child(M,F,C) :- setof(X,S^(mother(S,X)),C).
Any ideas why this is? What would be a situation where you would need the unifier then?
thanks!
Ok, I'm not sure I can explain it perfectly, but let me try.
It has to do with the fact that you are querying over a 2-ary relation, mother/2. In that case using X-S as the template has a similar effect on the result set C as using S^ in front of the goal. In X-S you are using both variables in the template, and therefore each possible binding of X and S is included in C. You get the same effect using S^ in front of the goal, as this is saying "ignore bindings of S when constructing the result".
But the difference between the two becomes clearer when you query over a 3-ary relation. The SWI manual has this example:
foo(a, b, c).
foo(a, b, d).
foo(b, c, e).
foo(b, c, f).
foo(c, c, g).
Now do similar queries as in your example
setof(X-Z, foo(X,Y,Z), C).
and
setof(Z, X^foo(X,Y,Z), C).
and you get different results.
It's not just checking unification, X-Z effectively changes your result set.
Hope that helps.
Edit: Maybe it clarifies things when I include the results of the two queries above. The first one goes like this:
?- setof(X-Z, foo(X,Y,Z), C).
Y = b
C = [a-c, a-d] ;
Y = c
C = [b-e, b-f, c-g] ;
No
The second one yields:
?- setof(Z, X^foo(X,Y,Z), C).
Y = b
C = [c, d] ;
Y = c
C = [e, f, g] ;
No

Resources