Prolog: Out of local stack error - prolog

Consider the following code (taken from Introduction to Prolog by RP Suri):
/* A set of father-child pairs declared */
father("Motilal", "Jawaharlal").
father("Motilal", "Vijayalakshmi").
father("Motilal", "Krishna").
father("Jawaharlal", "Indira").
father("Ranjit", "Tara").
father("Ranjit", "Lekha").
father("Ranjit", "Rita").
father("Feroz", "Sanjay").
father("Feroz", "Rajiv").
father("Sanjay", "Varun").
father("Rajiv", "Rahul").
father("Rajiv", "Priyanka").
/* Mothers declared */
wife_of("Swaruprani", "Motilal").
wife_of("Kamla", "Jawaharlal").
wife_of("Vijayalakshmi", "Ranjit").
wife_of("Indira", "Feroz").
wife_of("Maneka", "Sanjay").
wife_of("Sonia", "Rajiv").
wife_of("Priyanka", "Robert").
/* Predicates declared */
mother(M, C) :- wife_of(M, Hus) , father(Hus, C).
parent(P, C) :- mother(P, C) ; father(P, C).
ancestor(X, Y) :- parent(X, Y).
ancestor(X, Y) :- ancestor(X, Z) , parent(Z, Y).
Now if I query
ancestor("Motilal", X)
I get output as:
?- ancestor("Motilal", X).
X = "Jawaharlal" ;
X = "Vijayalakshmi" ;
.
.
.
X = "Priyanka" ;
(which is the correct output), after which the program stops and a few seconds later I get the message:
ERROR: Out of local stack
A similar thing happens when I query
ancestor(X, "Motilal").
This should return nothing, but the prompt again disappears for a few seconds followed by the same error message. What is the problem in the code?

To understand the problem in your code there is no need to look at your entire program. Instead it suffices to look at a tiny fraction that is responsible for non-termination:
?- ancestor(X, 'Motilal'), false.
ancestor(X, Y) :- false, parent(X, Y).
ancestor(X, Y) :- ancestor(X, Z) , false, parent(Z, Y).
This fragment already does not terminate, and thus the entire program does not terminate. No matter what you wrote in the other parts! So you need to change something in the remaining part. Otherwise, the error will persist.
For more see failure-slice.
Do you see what you need to change?
Put the goal parent(Z, Y) in front!
BTW, it is common in Prolog to use single-quoted atoms in such a situation, since this is much more efficient!

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).

How to return a single value for a Prolog "or" operation?

I have the following rules in my code:
in(rome, lacio).
in(lacio, italy).
in(salvador, bahia).
in(bahia, brazil).
is_in(X, Z) :- (in(X, Y), in(Y, Z)) ; in(X, Z).
So if I ask is_in(rome, lacio). it will return true, which is expected, but if I ask is_in(rome, italy). it will return true and then false, probably because of the second term in is_in/2.
What should I do to prevent it for returning the two results and instead return only true, like in a normal "or" operation? I though the ";" would take care of it but it didn't worked as I expected.
It would be best in parts:
is_in(X, Z) :- in(X, Z), !, true.
is_in(X, Z) :- in(X, Y), in(Y, Z).
But you could also do it with or:
is_in(X, Z) :- in(X, Z), !, true; in(X, Y), in (Y, Z).
The extra I've added prevents Prolog from branching from that choice-point and returns true, because in this case it is. Do be careful doing this kind of thing though, it can cause problems in larger programs.

Function not in prolog

sibling(X, Y):- father(Z, X), father(Z, Y), not (X=Y).
sister(X, Y):- father(Z, X), father(Z, Y), female(X).
brother(X, Y):- father(Z, X), father(Z, Y), male(X).
i'm having a bit problem with using the not function. i've tried not X=Y. but to no avail, the sibling rule still produce error.
if i were to delete the not x=y, the output will be a bit kind of "ugly".
how should i write the not function?
The ISO predicate implementing not provable is called (\+)/1.
However, as #coder explains in the comments, it is much better to use dif/2 to express that two terms are different.
dif/2 is a pure predicate that works correctly in all directions, also if its arguments are not yet instantiated.
For example, with (\+)/1, we get:
?- \+ (X = Y ).
false.
No X and Y exist that satisfy this goal, right? Wrong:
?- X = a, Y = b, \+ (X = Y ).
X = a,
Y = b.
In contrast, with dif/2:
?- dif(X, Y).
dif(X, Y).
and in particular:
?- X = a, Y = b, dif(X, Y).
X = a,
Y = b.
See prolog-dif for more information. dif/2 is with us since the very first Prolog system. I strongly recommend you use it.
SWI Prolog has no notoperator. it can be used as a regular compound term, e.i. not(X).
It must be no space between functor and open parenthesis:
foo( argument list ).
This is the cause of the error.
SWI Prolog suggests ISO-standard replacement for not/1: (\+)/1

Resources