Logic gate AND in swi-prolog - prolog

How do I get for the following Prolog program
and(1,1,1).
and(1,0,0).
and(0,1,0).
and(0,0,0).
respective the following answer
?- and(A,B,C).
A=1, B=1, C=1;
A=1, B=0, C=0;
A=0, B=1, C=0;
A=0, B=0, C=0.
When I try to run the program above I get the following result
?- and(A,B,C).
A = B, B = C, C = 0 ;
A = C, C = 0,
B = 1 ;
A = 1,
B = C, C = 0 ;
A = B, B = C, C = 1.
It seems to be correct, but I don´t want to have variables in my answer, which abbreviates my expected answer.
If I run the example for GNU Prolog, I get only atom´s as a answer for a Variable and not a reference to a Variable itself. That´s what I want for swi-prolog too:
GNU Prolog 1.4.5 (64 bits)
Compiled Feb 5 2017, 10:30:08 with gcc
By Daniel Diaz
Copyright (C) 1999-2016 Daniel Diaz
| ?- und(A,B,C).
A = 1
B = 1
C = 1 ? ;
A = 1
B = 0
C = 0 ? ;
A = 0
B = 1
C = 0 ? ;
A = 0
B = 0
C = 0
This example is also in this PDF file on page 10.
I´m running SWI-Prolog version 7.4.2 for amd64 on Ubuntu 17.10
Thanks!
//edit: corrected result for logical-AND.
//edit2: Added example from GNU Prolog, how results should be.

Firstly, as already mentioned in the comments, your predicate and/3 does not describe logical AND as in the PDF you referenced. The definition on page 10 is:
and(0,0,0).
and(0,1,0).
and(1,0,0).
and(1,1,1).
Secondly, if it's only about the output of the most general query, you can write a wrapper-predicate of arity 1 that displays the two arguments and the result as a triplet:
and(A-B-C) :-
and(A,B,C).
If you query and/1 with a single variable, you get an output that looks similar to the one in your post:
?- and(X).
X = 0-0-0 ;
X = 0-1-0 ;
X = 1-0-0 ;
X = 1-1-1.
If you query and/1 with three variables, you get the same answer as with the most general query for and/3:
?- and(A-B-C).
A = B, B = C, C = 0 ;
A = C, C = 0,
B = 1 ;
A = 1,
B = C, C = 0 ;
A = B, B = C, C = 1.
?- and(A,B,C).
A = B, B = C, C = 0 ;
A = C, C = 0,
B = 1 ;
A = 1,
B = C, C = 0 ;
A = B, B = C, C = 1.
EDIT
In the above examples you can observe how every answer, that Prolog provides, consists of a substitution for every variable that occurs in the query, such that those substitutions satisfy the relation. This is the property used in the "trick" above when querying and/1 with the argument X: there's only one variable to provide answer-substitutions for. You can take this one step further by defining an output predicate of arity 0. Then Prolog can only answer true in the case of success because there are no variables in the query to provide substitutions for and you can use predicates like format/2 to create an output to your liking. For example:
andoutput :-
and(A,B,C),
format('A = ~d, B = ~d, C = ~d~n', [A,B,C]).
Querying this predicate yields the desired output:
?- andoutput.
A = 0, B = 0, C = 0 % <- output by format/2
true ; % <- Prolog's answer
A = 0, B = 1, C = 0 % <- output by format/2
true ; % <- Prolog's answer
A = 1, B = 0, C = 0 % <- output by format/2
true ; % <- Prolog's answer
A = 1, B = 1, C = 1 % <- output by format/2
true. % <- Prolog's answer
Note the difference between the output generated by your predicate and the answers provided by Prolog. If you prefer an output more similar to GNU-Prolog's answers you could define something like this:
andoutput2 :-
and(A,B,C),
format('~nA = ~d~nB = ~d~nC = ~d~n', [A,B,C]).
?- andoutput2.
% <- output by format/2
A = 0 % <- output by format/2
B = 0 % <- output by format/2
C = 0 % <- output by format/2
true ; % <- Prolog's answer
% <- output by format/2
A = 0 % <- output by format/2
B = 1 % <- output by format/2
C = 0 % <- output by format/2
true ; % <- Prolog's answer
% <- output by format/2
A = 1 % <- output by format/2
B = 0 % <- output by format/2
C = 0 % <- output by format/2
true ; % <- Prolog's answer
% <- output by format/2
A = 1 % <- output by format/2
B = 1 % <- output by format/2
C = 1 % <- output by format/2
true. % <- Prolog's answer
However, keep in mind that this is just formatted output and does in no way change Prolog's way to provide answers. So for every predicate that you'd like to answer in an individualized way, you have to provide an output-predicate. To see more options for generating output check the documentation on formatted write.

Related

How do I understand the logic behind this Prolog problem?

I am trying to understand how to solve the following problem in Prolog. Given the following Prolog code, list all solutions in order for the query c(X,Y,Z).
a(1).
a(2).
b(a).
c(A,B,C) :- a(A),d(B,C).
c(A,B,C) :- b(A),d(B,C).
d(B,C) :- a(B),!,a(C).
d(B,_) :- b(B).
I loaded up SWI Prolog to try it out myself, but I am unsure how it reaches the conclusion:
X = Y, Y = Z, Z = 1 ;
X = Y, Y = 1,
Z = 2 ;
X = 2,
Y = Z, Z = 1 ;
X = Z, Z = 2,
Y = 1 ;
X = a,
Y = Z, Z = 1 ;
X = a,
Y = 1,
Z = 2.
Starting small, I tried to query just d(B,C). with the same code, leading to the following conclusion:
Y = Z, Z = 1 ;
Y = 1,
Z = 2.
I understand how to get the Y=1 and Z=1,2, but I am unsure how the code leads to Y=Z. If anyone could help me with the logic to reach these conclusions, that would be well appreciated!
Let's start by looking at the predicates a/1 and b/1: We expect them to produce two and one answer(s) respectively and indeed that is the case:
?- a(X).
X = 1 ? ;
X = 2
?- b(X).
X = a
Next let's look at the predicate d/2 but without the cut, that is:
d(B,C) :- a(B),a(C).
d(B,_) :- b(B).
If we query this predicate:
?- d(B,C).
Prolog will start with the first rule of the predicate d/2, that is d(B,C) :- a(B),a(C). and tries to prove the first goal a(B). That succeeds with the substitution B = 1. So Prolog goes on to prove the goal a(C). Again that succeeds with the substitution C = 1. Prolog then reports the first solution to the query:
?- d(B,C).
B = C = 1 ?
So we ask if there are any more solutions by pressing ;:
?- d(B,C).
B = C = 1 ?;
Now Prolog tries to find another solution for a(C) and finds the substitution C = 2:
?- d(B,C).
B = C = 1 ?;
B = 1,
C = 2 ?
Again we ask if there's more:
?- d(B,C).
B = C = 1 ?;
B = 1,
C = 2 ? ;
Now Prolog fails to find another solution for a(C), so it backtracks to the first goal and tries to find an alternative solution for a(B) and succeeds with the substitution B = 2. So it goes on to prove the second goal a(C) to which again the substitution C = 1 is found. So Prolog reports this new solution.
?- d(B,C).
B = C = 1 ?;
B = 1,
C = 2 ? ;
B = 2,
C = 1 ?
We ask for yet more solutions:
?- d(B,C).
B = C = 1 ?;
B = 1,
C = 2 ? ;
B = 2,
C = 1 ? ;
So Prolog looks for another solution for a(C) and finds C = 2. So it answers:
?- d(B,C).
B = C = 1 ?;
B = 1,
C = 2 ? ;
B = 2,
C = 1 ? ;
B = C = 2 ?
We press ; again
?- d(B,C).
B = C = 1 ?;
B = 1,
C = 2 ? ;
B = 2,
C = 1 ? ;
B = C = 2 ? ;
And Prolog looks for other solutions for a(C) but can't find any. So it backtracks to the goal a(B) and again fails to produce new answers here. So those are all solutions for the first rule of d/2. Prolog now goes on and tries to find a solution for the second rule d(B,_) :- b(B).. This rule only contains one goal: b(B) and Prolog finds a substitution: B = a, so it answers:
?- d(B,C).
B = C = 1 ?;
B = 1,
C = 2 ? ;
B = 2,
C = 1 ? ;
B = C = 2 ? ;
B = a
?-
And there are no more solutions. Let's observe that while Prolog traverses the proof tree as seen above, every time alternative substitutions can't be ruled out a choice point is created and in the course of the search for answers Prolog can backtrack to these choicepoints to look for alternative solutions. Every time an answer in the above query ended with ? Prolog still had some choice points left to explore and by pressing ; we asked it to explore them.
Now let's move our attention back to your posted version of d/2 with the cut in the first rule:
d(B,C) :- a(B),!,a(C).
d(B,_) :- b(B).
What a cut does is to prune away choice points back to where it was when the predicate that contains it was called. So it is essentially throwing away untried alternatives, thereby committing Prolog to the first substitution(s) it finds. So if we issue the query again with this version:
?- d(B,C).
Prolog again starts with the first rule, looking for a solution for a(B), successfully substituting B = 1 encountering the cut, therefore committing to this solution and then searching for a proof for a(C), again successfully substituting C = 1. Prolog then answers:
?- d(B,C).
B = C = 1 ?
indicating that there are open choice points. Again we want more:
?- d(B,C).
B = C = 1 ? ;
Prolog finds another substitution C=2 for the goal a(C) and reports:
?- d(B,C).
B = C = 1 ? ;
B = 1,
C = 2
?-
But this time the query terminates. That is because the choicepoint for an alternative solution for the goal a(B) was pruned away thereby leaving us without the solutions B = 2, C = 1 and B = C = 2. Furthermore the choicepoint that would have led to the second rule being explored was also pruned away thereby robbing us of the solution B = a. Cuts that prune away correct solutions as seen above are often referred to as red cuts in the literature.
Note that by cutting away actual solutions this program is not logically correct anymore. With the above query you asked for all solutions of the predicate d/2 but got only two of them. However, if you ask for the other solutions specifically, the respective queries still succeed:
?- d(2,1).
yes
?- d(2,2).
yes
?- d(a,_).
yes
?-
Returning to your original question, let's compare the query ?- c(X,Y,Z). with both versions of d/2. To make comparisons easier, the variables X, Y and Z are replaced with A, B and C just like they occur in the predicate definitions:
% cut-free version % version with the cut:
?- c(A,B,C). ?- c(A,B,C).
A = B = C = 1 ? ; A = B = C = 1 ? ;
A = B = 1, A = B = 1,
C = 2 ? ; C = 2 ? ;
A = C = 1,
B = 2 ? ;
A = 1,
B = C = 2 ? ;
A = 1,
B = a ? ;
A = 2, A = 2,
B = C = 1 ? ; B = C = 1 ? ;
A = C = 2, A = C = 2,
B = 1 ? ; B = 1 ? ;
A = B = 2,
C = 1 ? ;
A = B = C = 2 ? ;
A = 2,
B = a ? ;
A = a, A = a,
B = C = 1 ? ; B = C = 1 ? ;
A = a, A = a,
B = 1, B = 1,
C = 2 ? ; C = 2
A = a,
B = 2,
C = 1 ? ;
A = a,
B = C = 2 ? ;
A = B = a
For the sake of brevity I'm not going to iterate through the steps of the proof, but let's observe a few key things: Firstly, in both rules of c/3 the predicate d/2 is called by the same goal d(B,C) and we have already looked at that goal in detail for both versions. Secondly, we can observe that both rules of c/3 are taken into regard in the search for answers with both versions of the predicate by seeing all three substitutions, A = 1, A = 2 and A = a appearing in both answer-sets. So the cut doesn't prune away the choice point here. Thirdly, the three solutions of d/2 that are pruned away by the cut: B = 2, C = 1, B = 2, C = 2 and B = a are missing in the answers for all three substitutions of A in the version with the cut. And finally, the version of c/3 with the cut is also not logically correct, as the most general query does not give you all the answers but you can query for the thrown away solutions directly and Prolog will find them, e.g.:
?- c(1,2,1).
yes
?- % etc.
Try the query trace, c(X,Y,Z).

Prolog does not terminate on query with 2 arguments

I'm new to Prolog and have a question to a programming exercise:
I have a program, that is for my opinion working most of the time, but with a specific query, I do not get an answer
is_number(0).
is_number(s(N)) :-
is_number(N).
numberpair(pair(X,Y)) :-
is_number(X),
is_number(Y).
?- numberpair(pair(A,B)), A=s(s(0)), B=s(s(s(0))).
So I understand, that Prolog now tries every possible number for A and B -> [0,s(0),s(s(0)),s(s(s(0))), ...] but if it founds an answer for A (namely s(s(0))) it fails at B and in the next call, it tries the next answer for A (namely s(s(s(0)))) and so on.
Now the thing is, that I want Prolog to stop, if it founds an answer for A, and only searches now for an answer for B.
Can anybody give me a hint, how to solve this?
Edit: As false pointed out:
The reason you won't find an answer is that your rule numberpair/1 won't terminate. The reason you won't find an answer is that Prolog enumerates your answer in a way that it first lists all possibilities for A and then the possibilities for B (note that both have infinite possibilities). What Prolog tries is to find an answer first for the clause numberpair(pair(A,B)) but and then for the following clauses A=s(s(0)) and B=s(s(s(0))). But since numberpair already won't terminate, it won't "come" so far.
If you change the order of your clauses goals and simply call A=s(s(0)) before numberpair(pair(A,B)), it will give list you all answers for the possibilities of B (note that this still won't terminate!).
?- A=s(s(0)), numberpair(pair(A,B)).
A = s(s(0)),
B = 0 ;
A = s(s(0)),
B = s(0) ;
A = B, B = s(s(0)) ;
A = s(s(0)),
B = s(s(s(0))) .
Edit 2, to provide also a version, which will enumerates in a "fair" way!
is_number(0).
is_number(s(N)) :-
is_number(N).
number_number_sum(0,A,A).
number_number_sum(s(A),B,s(C)) :-
number_number_sum(A,B,C).
numberpair(pair(X,Y)) :-
is_number(Z),
number_number_sum(X,Y,Z).
Which will provide us with
?- numberpair(pair(A,B)).
A = B, B = 0 ;
A = 0,
B = s(0) ;
A = s(0),
B = 0 ;
A = 0,
B = s(s(0)) ;
A = B, B = s(0) ;
A = s(s(0)),
B = 0 ;
A = 0,
B = s(s(s(0))) ;
A = s(0),
B = s(s(0)) ;
A = s(s(0)),
B = s(0) ;
A = s(s(s(0))),
B = 0 .

How to solve this puzzle in Prolog? (robbery)

Three suspects are involved in a robbery, Alice, Bob, Carl. At least one of them are guilty.
Here are the conditions:
If A is guilty, he has exactly 1 accomplice.
If B is guilty, he has exactly 2 accomplices.
Who are guilty?
How can I write a Prolog script to solve this problem which guilty(X) gives the gangs?
Here is a solution using clpb :
:- use_module(library(clpb)).
solve(A,B,C) :-
% there is a least one guilty
sat(A + B + C),
% If A is guilty, he has exactly 1 accomplice.
sat(A =< B # C),
% if B is guilty, he has exactly 2 accomplices.
sat(B =< A * C),
% Assigns truth values to the variables such that all constraints are satisfied.
labeling([A,B,C]).
Now we get :
?- solve(A,B,C).
A = B, B = 0,
C = 1 ;
A = C, C = 1,
B = 0.
The answer A = B, B = 0, C = 1 means that C is guilty the other one that A and C are guilties.
Let's encode the state of our world as three numbers, A, B, and C.
Each number will be either 1 (guilty) or 0 (innocent).
The conditions are:
at_least_one(A,B,C):- 0 < A+B+C.
one_accomplice(A,B,C):- A == 1 -> 1 is ....... ; true.
two_accomplices(A,B,C):- B == 1 -> ....... ; true.
The three rules holding together is
ok(A,B,C):- at_least_one(A,B,C),
one_accomplice(A,B,C),
...... .
Now we can find out the gangs, as
the_guilty([A,B,C]):-
( A = 0 ; A = 1 ),
....
....
ok( ..... ).
The last thing is to report the three given numbers as names of people. We know that the first number is for "Alice", the second is for "Bob", etc.
Prolog is easy.

something like pattern matching list in prolog

[A,B,C|_] = [1,2,3,4,5,6,7]
A = 1
B = 2
C = 3.
I expected this result. However, when I have:
L = [A,B,C,D]
how to do:
L = [1,2,3,4,5,6,7]
A = 1
B = 2
C = 3
D = 4
?
The problem is that I don't know how long is L. Only thing that I know: L is shorter than rightside list and L contains only variables.
We just "insert the free variable" at the variables list's tail, append(Vars, _, ExtendedList), and then pattern match, ExtendedList = Data. Contracting, we get:
match_vars(Vars, Data):-
append(Vars, _, Data).
Testing:
2 ?- match_vars([A,B],[1,2,3,4,5]).
A = 1,
B = 2.
3 ?- match_vars([A,B,C,D],[1,2,3,4,5]).
A = 1,
B = 2,
C = 3,
D = 4.
4 ?-
(using append/3 was already mentioned in the comments).

ERROR: Out of local stack in my Prolog code

I cannot figure out why the following query from the given Prolog code generates the error Out of local stack.
Prolog code:
likes(g,c).
likes(c,a).
likes(c,b).
likes(b,a).
likes(b,d).
likes(X,Z) :- likes(X,Y), likes(Y,Z).
the query
?- likes(g,X).
results in
X = c ;
X = a ;
X = b ;
ERROR: Out of local stack
Edit 1 This is the way I think that Prolog should deal with this query,
likes(g,c) is a fact, so X={c}
likes(g,b) <= likes(g,c) and likes(c,b), so X={c,b}
likes(g,a) <= likes(g,b) and likes(b,a), so X={c,b,a}
likes(g,d) <= likes(g,b) and likes(b,d), so X={c,b,a,d}
likes(g,a) and false, so nothing to add to X
likes(g,d) and false, so nothing to add to X
end of backtracking search.
Edit 2 I managed to get what I was looking for by the following modification of the code:
likes(g,c).
likes(c,a).
likes(c,b).
likes(b,a).
likes(b,d).
indirect_likes(A,B):- likes(A,B).
indirect_likes(A,C):- likes(B,C), indirect_likes(A,B).
the query
?- indirect_likes(g,Which).
results in
Which = c ;
Which = a ;
Which = b ;
Which = a ;
Which = d ;
false.
However, there is still something which I cannot figure out the rationale behind. If I change the last rule to be
indirect_likes(A,C):- indirect_likes(A,B), likes(B,C).
Then I get ERROR: Out of local stack! As far as I know, logical conjunction is commutative.
To get the transitive-closure of binary relation R_2, use meta-predicate closure/3 like so:
?- closure(R_2,From,To).
Let's run a sample query of closure/3 together with likes/2!
?- closure(likes,X,Y).
X = g, Y = c
; X = g, Y = a
; X = g, Y = b
; X = g, Y = a % redundant
; X = g, Y = d
; X = c, Y = a
; X = c, Y = b
; X = c, Y = a % redundant
; X = c, Y = d
; X = b, Y = a
; X = b, Y = d
; false. % query terminates universally
We get the same answers when we use indirect_likes/2, but in a different order:
?- indirect_likes(X,Y).
X = g, Y = c
; X = c, Y = a
; X = c, Y = b
; X = b, Y = a
; X = b, Y = d
; X = g, Y = a
; X = g, Y = b
; X = c, Y = a % redundant
; X = g, Y = a % redundant
; X = c, Y = d
; X = g, Y = d
; false. % query terminates universally
As you stated in your comments to #C.B.'s answer, binary relations are not necessarily reflexive and/or symmetric. With the definition you gave, likes/2 is neither:
?- likes(X,X).
false. % not reflexive (not even close)
?- likes(X,Y), likes(Y,X).
false. % not symmetric (not even close)
So far, so good!
Let's tentatively add the following additional fact to your database:
likes(b,b).
With this expanded definition, indirect_likes/2 behaves erratically:
?- indirect_likes(b,b).
true
; true
; true
... % does not terminate universally
?- indirect_likes(X,Y), false. % do we get finite failure?
... % no! query does not terminate universally
What can we do? Let's use meta-predicate closure/3 with the expanded version of likes/2!
?- closure(likes,b,b).
true % succeeds non-deterministically
; false. % query terminates universally
?- closure(likes,X,Y), false. % do we get finite failure?
false. % yes! query terminates universally
The bottom line?
In pure Prolog, conjunction is commutative, as far as the logical meaning is concerned.
Due to Prolog's SLD resolution, the goal false,repeat finitely fails, but repeat,false does not.
The programmer needs to take care of termination, but usually this is a small price to pay for the raw performance and control that Prolog offers.
In this answer I passed "termination worries" on to the implementor of meta-predicate closure/3 :)
You spin off into infinite recursion.
Once you get to likes(b,a), you call likes(a,_G4382), which has no fact defined so it switches to the rule likes(X,Z) :- likes(X,Y), likes(Y,Z). So it calls likes(a,_G4383) which calls likes(X,Z) :- likes(X,Y), likes(Y,Z). over and over and over.
You might want to define and auxillary predicate aux_likes/2 that hosts all your facts. This will only work if there are no circular relationships, i.e. aux_likes(b,c) and aux_likes(c,b). You would also need to define likes(X,X). This is essentially a graph problem and in graph theory a node has to be connected to itself. If you use it as a generator, it will go off into into infinite recursion (if you have cycles) unless you add cuts which are not ideal.
If using swi-prolog, feel free to enter the debug or spy query to see what's going on.
Code:
aux_likes(g,c).
aux_likes(c,a).
aux_likes(c,b).
aux_likes(b,a).
aux_likes(b,d).
likes(X,Z) :- aux_likes(X,Y), likes(Y,Z).
likes(X,X).
Output with new predicate:
?- likes(g,X),print(X),nl,fail.
a
a
d
b
c
g
false.
This says g can like a through c or through b. It likes d through b, it likes b through c and it likes c directly. It also must like itself inorder to query like this. If you would rather have the usage mode (+,+) meaning you supply it with both terms and no variables (as a checker) you can do
?- likes(g,c).
true .

Resources