Prolog infinite loop - prolog

This is a program that should find out who is compatible with john.
I am new to Prolog. In order to let Prolog know eg. met(X,Y) = met (Y,X)
lots of code has been written.
Now when I start the query
?- compatible(john, X)
it goes into infinite looping...
Source code:
compatible(X,Y) :- reading(X), reading(Y).
compatible(X,Y) :- football(X), football(Y).
compatible(X,Y) :- friends(X,Y).
compatible(X,Y) :- mutual(X,Y).
friends(X,Y) :- havemet(X,Y), compatible(X,Y).
havemet(X,Y) :- met(X,Y).
havemet(X,Y) :- met(Y,X).
mutual(X,Y) :- friends(X,Temp), friends(Y,Temp).
mutual(X,Y) :- friends(Temp,X), friends(Y,Temp).
mutual(X,Y) :- friends(X,Temp), friends(Temp,Y).
mutual(X,Y) :- friends(Temp,X), friends(Temp,Y).
football(john).
football(james).
friends(john, carl).
friends(carl, john).
reading(carl).
reading(fred).
reading(emily).
met(carl, emily).
met(fred, james).
met(fred, emily).
I have been researching so much but I still do not understand what is the problem and how to fix that. It would be great for me to help me.

I am not surprised you got an infinite loop. compatible depends on friends while friends depends on compatible. Are you sure this is what you want?
Please note that if you really wanted your rules to be recursive, you would need a stopping condition. But I don't see why you would need recursion for such a simple problem as affinity matching.

What Prolog system are you using? Are you required to use a particular system?
Your program as it is will not terminate in a standard Prolog, but will in a Prolog with tabling support, such as XSB-Prolog http://xsb.sourceforge.net/ or B-Prolog http://www.probp.com/ - just add :- auto_table. as a first line of your program.
| ?- compatible(john, X).
compatible(john, X).
X = john ?;
X = james ?;
X = carl ?;
X = emily ?;
no

So what is the problem with your program? Here is a way to localize the problems you have. By inserting goals false we obtain a failure slice. This is a fragment that shares still a lot of properties with the original program. In particular: if the failure-slice loops, also the original program loops. So the failure-slice shows us a part of the program that has to be modified to overcome the original problem. For your query I get the following fragment that still does not terminate:
?- compatible(john, X), false.
compatible(X,Y) :- false, reading(X), reading(Y).
compatible(X,Y) :- false, football(X), football(Y).
compatible(X,Y) :- false, friends(X,Y).
compatible(X,Y) :- mutual(X,Y), false.
friends(X,Y) :- havemet(X,Y), compatible(X,Y).
friends(john, carl) :- false.
friends(carl, john).
havemet(X,Y) :- false, met(X,Y).
havemet(X,Y) :- met(Y,X).
mutual(X,Y) :- false, friends(X,Temp), friends(Y,Temp).
mutual(X,Y) :- friends(Temp,X), friends(Y,Temp), false.
mutual(X,Y) :- friends(X,Temp), false, friends(Temp,Y).
mutual(X,Y) :- false, friends(Temp,X), friends(Temp,Y).
met(carl, emily).
met(fred, james) :- false.
met(fred, emily) :- false.
But shouldn't just any query for compatible/2 terminate? For the most general query, the failure slice can be reduced even further:
?- compatible(X, Y), false.
compatible(X,Y) :- false, reading(X), reading(Y).
compatible(X,Y) :- false, football(X), football(Y).
compatible(X,Y) :- false, friends(X,Y).
compatible(X,Y) :- mutual(X,Y), false.
friends(X,Y) :- havemet(X,Y), compatible(X,Y).
friends(john, carl) :- false.
friends(carl, john) :- false.
havemet(X,Y) :- false, met(X,Y).
havemet(X,Y) :- met(Y,X).
mutual(X,Y) :- false, friends(X,Temp), friends(Y,Temp).
mutual(X,Y) :- false, friends(Temp,X), friends(Y,Temp).
mutual(X,Y) :- friends(X,Temp), false, friends(Temp,Y).
mutual(X,Y) :- false, friends(Temp,X), friends(Temp,Y).
met(carl, emily).
met(fred, james) :- false.
met(fred, emily) :- false.
It is in the remaining part here where you have to fix the problem somehow. There might be further reasons for non-termination. But you have to fix this one in any case.
And if this is still not good enough, you might add goals V = const into the program. But I think this should suffice...

Related

Prolog combinatoric of two lists ignoring the last items

I'm trying to get the combinatorics of two lists ignoring the last element of both.
the code:
isady(_, [_]) :-
write('stop here'),
nl,
false.
isady(E, [H|T]) :-
write(E),
write('-'),
write(H),
nl,
isady(E, T).
ady([_], _) :-
write('stop here'),
nl,
false.
ady([H|T], L2) :-
isady(H, L2);
ady(T, L2).
output:
?- ady([a,b,c], [d,e,f]).
a-d
a-e
stop here
a-f
b-d
b-e
stop here
b-f
stop here
c-d
c-e
stop here
c-f
expected output:
?- ady([a,b,c], [d,e,f]).
a-d
a-e
b-d
b-e
As you can see, it doesn't stop when it has to, does anyone knows why?
Try this:
isady(_, [_]) :-
write('stop here'),
nl,
false.
isady(E, [H|T]) :-
T\=[],
write(E),
write('-'),
write(H),
nl,
isady(E, T).
ady([_], _) :-
write('stop here'),
nl,
false.
ady([H|T], L2) :-
T\=[],
isady(H, L2);
ady(T, L2).
The new condition T \= [] will prevent the use of the last elements of both lists.
[EDIT] You can also explicitly use the pattern for a list of length at least 2, to avoid the execution of the "step case" clause with lists of length 1:
isady(_, [_]).
isady(E, [X,Y|T]) :-
writeln(E-X),
isady(E,[Y|T]).
ady([_], _).
ady([X,Y|T], L) :-
isady(X, L),
ady([Y|T], L).
Result:
?- ady([a,b,c], [d,e,f]).
a-d
a-e
b-d
b-e
true ;
false.

Create a list in prolog from facts

I want to create a list from facts like:
table(mickel).
table(harris).
table(wolfgang).
table(yanis).
table(antti).
table(peter).
table(jeroen).
table(johan).
table(luis).
table(eric).
But i don't want to use built-in rules or predicates,
unless i define them by myself.
The result almost is like that:
?- seats(Seats).
Seats = [yanis,antti,peter,jeroen,johan,luis,eric,michel,
harris,wolfgang]
I don't know what to do,please help.
You must create your own findall predicate, this post may help:
seats(L) :- find([], L), !.
find(Acc, Loa) :- table(Y), uList(Y, Acc, AccNew), find(AccNew, Loa).
find(Acc, Acc).
uList(X, [], [X]) :- !.
uList(H, [H|_], _) :- !, fail.
uList(X, [H|T], [H|Rtn]) :- uList(X, T, Rtn).
Consult:
?- seats(L).
L = [mickel, harris, wolfgang, yanis, antti, peter, jeroen, johan, luis|...].

Predicate must be true of all elements in a list

I have a set of facts:
likes(john,mary).
likes(mary,robert).
likes(robert,kate).
likes(alan,george).
likes(alan,mary).
likes(george,mary).
likes(harry,mary).
likes(john,alan).
Now I want to write a relation which will check for all element X of an input list if likes(X,A) is true. my relation should return true once if likes(X,A) is true for all element X in my list L.
If I try this this:
relat(X) :- member(A,[john,alan,george,harry]), likes(A,X).
but the output is
?- relat(mary).
true ;
true ;
true ;
true.
I want to write it such that it returns one true once it found that likes(john,mary),likes(alan,mary),likes(george,mary),likes(harry,mary) all are true.
How to approach this problem?
In SWI-Prolog, you can use forall/2:
?- forall(member(A, [john, alan, george, harry]), likes(A, mary)).
true.
?- forall(member(A, [john,alan,george,harry,marys_ex]), likes(A, mary)).
false.
With standard list processing you can do the following:
helper(X, []). % No one left to check
helper(X, [H|L]) :- likes(H, X), helper(X, L). % Check head, then rest
relat(X) :- helper(X, [john,alan,george,harry]).
Demo:
| ?- relat(harry).
no
| ?- relat(mary).
true ? ;
no
| ?-
Using library(lambda):
liked_byall(X, Ps) :-
maplist(X+\P^likes(P,X), Ps).
Equally without lambdas:
liked_byall(X, Ps) :-
maplist(liked(X), Ps).
liked(X, P) :-
likes(P, X).
Equally:
liked_byall(_X, []).
liked_byall(X, [P|Ps]) :-
likes(P, X),
liked_byall(X, Ps).
With above definitions you can ask even more general questions like "Who is liked by certain persons?"
?- liked_byall(N,[john, alan, george, harry]).
N = mary
; false.
With the following definition these general questions are no longer possible.
liked_byall(X, Ps) :-
\+ ( member(P, Ps), \+ likes(P, X) ).
This second definition only makes sense if X is ground and Ps is a ground list. We can ensure this as follows:
liked_byall(X, Ps) :-
( ground(X+Ps) -> true ; throw(error(instantiation_error,_)) ),
length(Ps,_),
\+ ( member(P, Ps), \+ likes(P, X) ).
These extra checks ensure that absurd cases as the following do not succeed:
?- liked_byall(mary, nonlist).
And that otherwise legitimate cases do not produce an incorrect answer:
?- liked_byall(N,[john, alan, george, harry]), N = the_grinch.
N = the_grinch.

Prolog query exercise

Here are my given clauses
beats(rock, scissors).
beats(scissors, paper).
beats(paper, rock).
better(battleaxe, scissors).
better(lightsabre, battleaxe).
better(boulder, rock).
better(adamantium, boulder).
better(palisade, paper).
better(nanomesh, palisade).
uses(wolverine, adamantium).
uses(vader, lightsabre).
uses(conan, battleaxe).
uses(richard, rock).
win(X,Y) :- beats(X,Y).
win(X,Y) :- better(X,Y).
win(X,Y) :- better(X,'underscore here'), beats('underscore here',Y).
win(X,Y) :- better(X,A), better(Y,B), win(A,B).
win(X,Y) :- uses(X,A), uses(Y,B), !, win(A,B).
play(X,Y,X) :- win(X,Y).
play(X,Y,Y) :- win(Y,X).
the question is asking what result i would get from
?- win(X, nanomesh).
the answer is supposed to be X = lightsabre. However I really do not get why.
Could anyone explain this please?
There are several ways how you can try to understand this particular query. One way, is to add goals false into your program, such that you still get the same answer. By adding false the program is specialized. If it then still gets the same answer, we know that a responsible part is in the visible area. The strike-through parts indicate clauses you now can ignore completely.
beats(rock, scissors) :- false.
beats(scissors, paper).
beats(paper, rock) :- false.
better(battleaxe, scissors).
better(lightsabre, battleaxe).
better(boulder, rock) :- false.
better(adamantium, boulder) :- false.
better(palisade, paper).
better(nanomesh, palisade).
win(X,Y) :- beats(X,Y).
win(X,Y) :- false, better(X,Y).
win(X,Y) :- false, better(X,'underscore here'), beats('underscore here',Y).
win(X,Y) :- better(X,A), better(Y,B), win(A,B).
?- win(lightsabre, nanomesh).
So you have two chains:
nanomesh -> palisade -> paper`
lightsabre -> battleaxe -> scissors
And finally scissors beat paper.
Not sure I agree with this kind of reasoning, though.

grandfather predicate in Prolog

I have written the following program in SWI-Prolog:
male(reza).
male(aliakbar).
male(behrooz).
male(said).
male(aliasghar).
male(taghi).
male(gholamreza).
male(hadi).
female(fatema).
female(tahere).
female(olya).
female(fatema).
mother(fateme,reza).
mother(olya,hasan).
mother(x,y) :-
wife(x,z),
father(z,y).
brother(said,reza).
brother(x,y) :-
father(z,x),
father(z,y),
x\==y,
male(x).
sister(tahere,fateme).
sister(x,y) :-
father(z,x),
father(z,y),
x\==y,
female(x).
sister(olya,aliakbar).
wife(tahere,gholamreza).
father(gholamreza,hadi).
father(gholamreza, nastaran).
father(abdollah,hasan).
father(aliakbar,reza).
father(taghi,olya).
father(taghi,aliakbar).
father(taghi,aliasghar).
father(aliakbar,said).
grandfather(x,z) :-
father(x,y),
father(y,z).
grandfather(x,z) :-
father(x,y),
mother(y,z).
uncle(y,x) :-
father(z,x),
brother(z,y),
male(y).
aunt(y,x) :-
mother(z,x),
sister(z,y),
female(y).
cousin(y,x) :-
aunt(z,x),
mother(z,y),
female(y).
cousin(y,x) :-
aunt(z,x),
mother(z,y),
male(y).
When I consult "father(X,Y),father(Y,Z)." it returns the correct answer (names are in persian), i.e. it returns
X = taghi,
Y = aliakbar,
Z = reza ;
X = taghi,
Y = aliakbar,
Z = said ;
false.
But I could not find the correct answer of grandfather(X,Y). Please help me why.
Thanks.
Be careful: case is crucial in Prolog. Your rules cannot be interpreted right because you didn't use capitals for variables.

Resources