First steps to a CAS - prolog

I tried to run this code:
eq(mul(a,b),mul(c,b)).
eq(X,Y) :- eq(mul(X,Z),mul(Y,Z))
with the query: eq (X, Y)
I expected the results:
X=mul(a,b),Y=(mul(c,b)) and X=a,Y=c
But I just got the first one.

I think you want:
eq(mul(a, b), mul(c, b)).
equal(X,Y) :-
eq(mul(X, Z), mul(Y, Z)).
Note that I have used different predicate names, to prevent a common mistake of infinite recursion/looping if a predicate (e.g. "eq") is calling itself.
Result in swi-prolog:
?- equal(X, Y).
X = a,
Y = c.
This rule would be wrong:
eq(X,Y) :- eq(mul(X,Z),mul(Y,Z)).
because X cannot be simultaneously mul(something) and part of the same something inside the mul(). Also, it falls into the trap of infinite recursion/looping.

Related

Prolog query not terminating

This is a very basic query, but I'm new to prolog and have trouble finding why this query does not terminate:
% fact
progeny(dexter, mark).
progeny(mark, bill).
progeny(bill, lisa).
% rule
progeny(X, Y) :- progeny(X, Z), progeny(Z, Y).
The query, progeny(dexter, X), gives mark, bill and lisa, but does not terminate.
Whereas the query, progeny(Y, lisa), gives bill and dexter and does not terminate (this query answer also misses mentioning mark).
It should be noted that I am using the same name for fact and rule to test for some values.
Any help or clarification for this problem would be much appreciated.
You need to define another predicate that will act as transitive relation. The code below works just as fine (notice the predicate progenyt that is the actual transitive relation).
progeny(dexter, mark).
progeny(mark, bill).
progeny(bill, lisa).
progenyt(X, Y) :- progeny(X, Y).
progenyt(X, Y) :- progeny(X, Z), progenyt(Z, Y).
Clarification
When you write progeny(X, Y) :- progeny(X, Z), progeny(Z, Y)., you will, at some point, have prolog trying to match progeny(dexter, Y) :- progeny(dexter, lisa), progeny(lisa, Y)., which is the moment where prolog gets 'confused'.
Namely, it will try to match progeny(lisa, Y) with some fact, which will fail for all entries. Then, prolog will try rule progeny(lisa, Y) :- progeny(lisa, Z), progeny(Z, Y)., which calls for evaluating progeny(lisa, Z). Here you are met with stack overflow, because for progeny(lisa, Y) to succeed, progeny(lisa, Z) has to succeed as well, which induces sort of infinite loop, and that is why your query never terminates.
In the solution I've posted, that can never happen, because for progenyt(lisa, Y) to succeed, progeny(lisa, Z) has to, and that never happens (it fails for all facts). Therefore, it will produce only those three results and will terminate immediately afterwards.
Note that, if progeny and progenyt were to be swapped in the last line, the query will also run into the same problem as before (for progenyt(lisa, Y) to succeed, progenyt(lisa, Z) has to succeed as well first, will causes the infinite loop).
You can also use tabling. Read the docs I linked for background, explanations, details.
To fix your program, you just add a table directive for your predicate progeny/2.
:- table progeny/2.
% fact
progeny(dexter, mark).
progeny(mark, bill).
progeny(bill, lisa).
% rule
progeny(X, Y) :- progeny(X, Z), progeny(Z, Y).
You should now get:
?- [progeny].
true.
?- progeny(dexter, X).
X = bill ;
X = mark ;
X = lisa. % query terminates
?- progeny(Y, lisa).
Y = bill ;
Y = dexter ;
Y = mark. % no missing solutions, query terminates.

Prolog - Find second and second last elements in list

I am new to prolog and currently stuck trying to understand how to implement this.
I need a predicate to find the second and the second last elements of a list using recursion, so for example:
second_secondLast([1,2], X, Y). must return X=2, Y=1.
second_secondLast([1,2,3], X, Y). must return X=2, Y=2.
second_secondLast([1], X, Y). must print 'Error' and return false.
First, I have the error-checking clauses:
second_secondLast([], X, Y) :- print("Error"), !, fail.
second_secondLast([_], X, Y) :- print("Error"), !, fail.
Next, I tried something like this:
second_secondLast([Y,X],X,Y) :- !.
second_secondLast(L, X, Y) :-
second(L,X),
secondLast(L,Y).
second([_,S|_], X) :- X = S.
secondLast([P,_], Y) :- Y = P.
secondLast([F|R], Y) :- secondLast(R, Y).
However, the output using [1,2,3] is X=Y, Y=2.
I'm not sure if it is possible to force the output to be X=2 instead, or if there is a better method to do this.
First of all, the output X=Y, Y=2. has nothing to do with your program, it is an idiosyncracy of swipl (and maybe other interactive environments for Prolog implementations).
I think, your program looks fine, but you are asking for possible improvements.
second([_,S|_], S). is a more elegant version of your second([_,S|_], X) :- X = S..
Likewise, secondLast([P,_], P). is more elegant than your secondLast([P,_], Y) :- Y = P..
I would also prefer secondLast([_|R], Y) :- secondLast(R, Y). to your
secondLast([F|R], Y) :- secondLast(R, Y)..
Your error-checking clauses look fine to me.
You could also get rid of the predicate second and alter the definition of second_secondLast by using
second_secondLast([H,X|T], X, Y):-
secondLast([H,X|T], Y).
instead of your
second_secondLast(L, X, Y) :-
second(L,X),
secondLast(L,Y).
That change would also make it a bit more efficient.
Another possibility is to use
second_secondLast(L, X, Y):-
L= [_,X|_],
secondLast(L, Y).
Then you could also get rid of the predicate secondLast and alter the above clause to
second_secondLast(L, X, Y):-
L= [_,X|_],
append(_, [Y,_], L).
.
There is always a ton of possibilities...

Why do i get a stack limit exceeded error when defining a predicate that convert the relation of two atoms?

I want to know why does the program goes in an infinite recursion in those cases:
?- love(kay, amanda).
and
?- love(rob, amanda).
And here is the code:
love(amanda, kay).
love(kay, geo).
love(geo, rob).
love(X, Y) :-
love(X, Z),
love(Z, Y).
love(X, Y) :-
love(Y, X).
First, your program always goes into an infinite loop. No matter what names you are using. Even ?- loves(amanda, kay). loops. To better see this rather ask ?- loves(amanda, kay), false. Why am I so sure that your program always loops?
To see this, we need some falsework. By adding goals false into your program, we get a new program requiring less (or equal) inferences.
love(amanda, kay) :- false.
love(kay, geo) :- false.
love(geo, rob) :- false.
love(X, Y) :-
love(X, Z), false,
love(Z, Y).
love(X, Y) :- false,
love(Y, X).
Because this fragment (called a failure-slice) does not terminate, your original program will not terminate. As you can see, all the persons have been removed. And thus actual names cannot influence the outcome.
If you want to fix commutativity, rather introduce a further predicate:
love2(X, Y) :- love1(X, Y).
love2(X, Y) :- love1(Y, X).
And to include the transitive closure, use closure/3:
love3(X, Y) :-
closure(love2, X, Y).

Fact formation with ceiling in prolog

Can I define a fact of the following form,
test(X, ceiling(sqrt(X))).
Where, X is related to ceiling(sqrt(X)).
I think , I could have done the following to receive the desired output,
test(X, Y) :- Y is ceiling(sqrt(X)).
You can define:test(X, ceiling(sqrt(X))).
This means that you have as fact atoms in the above form so if you query:
?- test(X, ceiling(sqrt(X))).
true.
because you defined this clause.
But note that if you query:
?- test(1.5, 2).
false.
It returns false because 2 is ceiling(sqrt(1.5)) but the predicate is waiting a syntax like ceiling(sqrt(1.5)) and not the result 2.
Another example:
?- test(1.5, Y).
Y = ceiling(sqrt(1.5)).
and
?- test(X,ceiling(sqrt(1.5))).
X = 1.5.
Also notice that :
test(X) :- X is ceiling(sqrt(X)).
is always failing for any input X (because there is no such X that equals to ceiling(sqrt(X)). )and querying test(X) will have instantiation problems due to is/2.
Maybe what you meant to write is:
test(X,X1) :- X1 is ceiling(sqrt(X)).
Sorry but I don't understand your clause
test(X) :- X is ceiling(sqrt(X)).
You're imposing the equation (not assignment: equation) " X = ceiling(sqrt(X)) ".
I think you're intention was
test(X, Y) :- Y is ceiling(sqrt(X)).
Is this what do you want?

PROLOG - clause returns true for constants, but won't find solution for variable?

After many years of abstinence of the PROLOG programming language, I'm trying to get into it again.
And promptly there, something confused me.
(I am using SWI prolog 6.4.1. on windows)
Consider the following defined:
father(jack, clara).
father(jack, sophie).
mother(angela,clara).
mother(angela,sophie).
parent(A, B) :- father(A, B).
parent(A, B) :- mother(A, B).
sibling( A, B ) :-
A \= B,
parent(P, A),
parent(P, B).
Now, if I "ask" the interpreter:
sibling(clara, sophie).
true is the answer.
But if I try to get the siblings of e.g. clara:
sibling(clara, X).
The answer is just false.
Just as
findall( X, sibling(clara, X ), L ).
returns an empty list.
Why?
To prove sibling(clara, X), you first need to prove clara \= x. But that doesn't work because it reduces to \+ clara = X, were \+ is the infamous negation as failure: Prolog tries to prove clara = X, which succeeds, and concludes that clara \= X must therefore be false.
You should either reorder your program to do the \= check last instead of first, or use dif(clara, X).

Resources