Prolog Chaining winners? - prolog

I'm trying to compare two people and from those 2 people if the person had played someone before and won then lost to the newer person then that person technically is above from everyone else.
For example, It's set up like this:
Example of how it's set up: winner(won, lost).
winner(john, jacob).
winner(mike, john).
winner(scott, mike).
winner(matt, scott).
winner(X, Z) :- winner(X, Y), winner(Y, Z).
If I call: winner(matt, mike). It'll return true since matt beat scott which means he also beats mike since mike lost to scott.
Essentially I want to be able to call winner(matt, jacob). and it'll return true.
I have it only querying on tier down with that current rule, how would I go about querying through unlimited tiers? I'm confused on how to approach this.

You need two predicates. One for the basic facts, winner/2, and another for the transitive relation. For example:
transitive_winner(X, Y) :-
winner(X, Y).
transitive_winner(X, Z) :-
winner(X, Y),
transitive_winner(Y, Z).
With this definition and your winner/2 facts, you can ask e.g.
?- transitive_winner(mike, Y).
Y = john ;
Y = jacob ;
false.
You need to be careful when defining this transitive relations, however, to avoid left-recursion as in:
transitive_winner(X, Z) :-
transitive_winner(Y, Z),
winner(X, Y).
In Prolog systems that don't support tabling, a call to transitive_winner/2 would result in a stack overflow error.

Related

Use a rule if a fact doesn't exist in prolog?

I'm new to prolog.
The idea of my project is to say "The room X is free if none is a guest of X, while X is taken if a family lives in X".
I use a predicate
guest(FamilySurname,RoomTaken)
So this mean that a family has taken that room.
taken(X) :- guest(_,X).
So if a family lives in room X, then X is taken.
My problem is how could i say that the room X is free? I should use a kind of NOT, like:
free(X) :- "NOT EXIST" guest(_,X).
How could i translate that "NOT EXIST" in prolog?
I have tried with ! but it doesn't work properly... maybe I'm placing it in the wrong way.
Sorry for my english.
Check the following code:
taken(X, Y) :- guest(Y,X).
free(X) :- \+ guest(_,X).
I made the a little change to taken, now it shows you who is on that room.
guest(albert, 123).
?- taken(123, R).
R = albert.
And the free() predicate it's pretty straightforward, I used the negation operator, you can check How to negate in Prolog
The code in the first answer does not seem to be a solution, i.e. the query ?- free(X) will not give an answer, where as the query ?- free(foo) will be successful. One needs to consider query floundering in Prolog into account, i.e. all variables
Consider the following code in which two alternatives for presenting the free predicate.
room(123).
room(124).
guest(albert, 123).
taken(Room) :- guest(_, Room).
free2(Room) :- room(Room),
\+ taken(Room).
free(Room) :- room(Room),
forall(guest(_, RoomTaken),
RoomTaken \= Room).

Sorting program for SWI Prolog

Why this program answers False in SWI-PROLOG?
sor(x, y):- sorted(y), perm(x, y).
sorted([]).
sorted([x, []]).
sorted([x, y, z]):- mi(x, y), sorted([y, z]).
perm([], []).
perm([x,y],[u,v]):- delete(u,[x,u],z), perm(z,v).
delete(x,[x,y],y].
delete(x, [y, z], [y, w]):- delete(x,z,w).
mi(0, x).
mi(s(x), s(y)):- mi(x, y).
for the query ?-
sor([s(s(s(s(s(0))))), s(s(s(s(s(s(0)))))), s(s(s(0))), s(s(0)), []], y).
This is an adaptation to SWIProlog of an inefficient sorting-program used as example in the book Foundations of Logic Programming, by Loyd (you can find the original SLOWSORT program example in this pdf, on page 9)
SWI Prolog is a standard Prolog, isn't it?
Edit
Now I have tried to correct the program (looking a little to the lists syntax in Prolog)
sor(X, Y):- perm(X, Y), sorted(Y).
sorted([]).
sorted([X|[]]).
sorted([X|[Y|Z]]):- mi(X, Y), sorted([Y|Z]).
perm([], []).
perm([X|Y],[U|V]):- delete(U,[X|Y],Z), perm(Z, V).
delete(X,[X|Y],Y).
delete(X, [Y|Z], [Y|W]):- delete(X, Z, W).
mi(0, X).
mi(s(X), s(Y)):- mi(X, Y).
and changing the query in
sor([s(s(s(s(s(0)))))|[ s(s(s(s(s(s(0))))))|[s(s(s(0)))|[ s(s(0))|[]]]]], Y).
Well, Prolog now gives success, but it gives this substitution
Y = [s(s(0)), s(s(s(0))), s(s(s(s(s(0))))), s(s(s(s(s(s(...))))))]
and I don't understand the meaning of (...): Why not (0)?
Edit2
I notice that after giving the command swipl -s slowsort.pl I obtain this error message
Warning: /home/navigazione/Scrivania/slowsort.pl:3:
Singleton variables: [X]
Warning: /home/navigazione/Scrivania/slowsort.pl:9:
Singleton variables: [X]
It seems to refer to 3th and 9th rows of the program, but I don't understand what it means.
Great, you managed to translate it to correct Prolog :)
What you see is the top level trying to make things readable by omitting stuff (the ... means there is stuff there that is not shown). See this question and answers for different ways you can tell the top level to show the complete term instead of hiding parts of it.
As for the singleton variable warnings, it just tells you that you have logical variables (on lines 3 and 9) that you have only mentioned once in their syntactical scope. You can write _X instead of X to make it explicit that you are not using the value of the variable in that scope.

Prolog predicate

Hello I am a newbie to Prolog with basic question. I would like to know why these Prolog predicates daughter_of/2 and son_of/2 do not work as I want them to. For example, if I ask
16 ?- daughter_of(alice, X).
true.
(Why true? What predicate would I need to get Victoria and Albert?)
Thank you.
male(albert).
male(edward).
female(alice).
female(victoria).
parents(edward, victoria, albert).
parents(alice, victoria, albert).
sister_of(X,Y):-
female(X),
parents(X,M,F),
parents(Y,M,F).
brother_of(X,Y):-
male(X),
parents(X,M,F),
parents(Y,M,F).
daughter_of(X,Y):-
female(X),
parents(X,M,F).
son_of(X,_Y):-
male(X),
parents(X,M,F).
The problem is the definition of your doughter_of predicate.
daughter_of(X,Y):-
female(X),
parents(X,M,F).
It should be
daughter_of(X,Y):-
female(X),
parents(X,Y,_).
daughter_of(X,Y):-
female(X),
parents(X,_,Y).
So that the Y parameter is passed on to the parents predicate. Otherwise it would not be used (and even gives me a warning when loading the file). Then prolog could only tell you that X is female and X has parents, but the actual parents would be discarded because M and F are no output parameters of your predicate.
Notice that i have defined the daughter_of predicate twice to work with the father as well as with the mother.
The same applies to son_of.

Why does Prolog crash in this simple example?

likes(tom,jerry).
likes(mary,john).
likes(mary,mary).
likes(tom,mouse).
likes(jerry,jerry).
likes(jerry,cheese).
likes(mary,fruit).
likes(john,book).
likes(mary,book).
likes(tom,john).
likes(john,X):-likes(X,john), X\=john.
Hi there, above is a very simple prolog file, with some facts and only one rule: John likes anyone who likes him.
But after loading this file and ask Prolog the following query:
likes(john,X).
The program crashes. The reason is somehow prolog gets stuck at likes(john,john) even though the rule states that X\=john.
Any advice?
Ironically, given the site we're on, you're getting a stack overflow.
It does this because of the order of execution that prolog uses, it's going to go into an infinite recursion at likes(X,john) in your rule, it activates the rule again - not a fact - never getting to the X\=john bit.
One way to fix this is to have your rule named differently from your fact like this:
kindoflikes(tom,jerry).
kindoflikes(mary,john).
kindoflikes(mary,mary).
kindoflikes(tom,mouse).
kindoflikes(jerry,jerry).
kindoflikes(jerry,cheese).
kindoflikes(mary,fruit).
kindoflikes(john,book).
kindoflikes(mary,book).
kindoflikes(tom,john).
likes(Y,X):- kindoflikes(X,Y), X\=Y.
likex(Y,X):- kindoflikes(Y,X), X\=Y.
Note the reversal of X and Y in the kindoflikes in the two rule definitions.
So you get:
?- likes(john,X).
X = mary ;
X = tom ;
X = book.
But you're not locked into finding what john likes, and you can do:
?- likes(jerry,X).
X = tom ;
X = cheese.
Your first question was why your program crashes. I am not sure what kind of Prolog system you are using, but many systems produce a clean "resource error" which can be handled from within Prolog.
Your actual problem is that your program does not terminate for the query likes(john, X). It gives you the expected answers and only then it loops.
?- likes(john,X).
X = book
; X = mary
; X = tom
; resource_error(local_stack). % ERROR: Out of local stack
You have been pretty lucky that you detected that problem so rapidly. Imagine more answers, and it would have not been that evident that you have the patience to go through all answers. But there is a shortcut for that. Ask instead:
?- likes(john, X), false.
This false goal is never true. So it readily prevents any answer. At best, a query with false at the end terminates. Currently this is not the case. The reason for this non-termination is best seen when considering the following failure-slice (look up other answers for more details):
?- likes(john,X), false.
loops.
likes(tom,jerry) :- false.
likes(mary,john) :- false.
likes(mary,mary) :- false.
likes(tom,mouse) :- false.
likes(jerry,jerry) :- false.
likes(jerry,cheese) :- false.
likes(mary,fruit) :- false.
likes(john,book) :- false.
likes(mary,book) :- false.
likes(tom,john) :- false.
likes(john,X) :-
likes(X,john), false,
X\=john.
So it is this tiny little part of your program that is responsible for the stack overflow. To fix the problem we have to do something in that tiny little part. Here is one: add a goal dif(X, john) such that the rule now reads:
likes(john,X) :-
dif(X, john),
likes(X,john).
dif/2 is available in many Prolog systems like: SICStus, SWI, YAP, B, IF.

Problem with `\+` in Prolog queries with variables

I'm reading "Seven languages in seven weeks" atm, and I'm stumped over some Prolog query that I don't understand the 'no' response to.
The friends.pl file looks like this:
likes(wallace, cheese).
likes(grommit, cheese).
likes(wendolene, sheep).
friend(X, Y) :- \+(X = Y), likes(X, Z), likes(Y, Z).
I can do some trivial queries on it, such as:
| ?- ['friends'].
compiling /home/marc/btlang-code/code/prolog/friends.pl for byte code...
/home/marc/btlang-code/code/prolog/friends.pl compiled, 12 lines read - 994 bytes written, 8 ms
yes
| ?- friend(wallace,grommit).
yes
| ?- friend(wallace,wendolene).
no
This is all as expected. Now, I want to introduce a variable in the query. My intent being that Prolog will give me a list of all of Wallace's friends. I'm expecting X = grommit, but I'm getting no:
| ?- trace.
The debugger will first creep -- showing everything (trace)
yes
{trace}
| ?- friend(wallace,X).
1 1 Call: friend(wallace,_16) ?
2 2 Call: \+wallace=_16 ?
3 3 Call: wallace=_16 ?
3 3 Exit: wallace=wallace ?
2 2 Fail: \+wallace=_16 ?
1 1 Fail: friend(wallace,_16) ?
no
{trace}
It doesn't even try to unify X (_16) with grommit. Why?
It is the definition of friend:
friend(X, Y) :- \+(X = Y), likes(X, Z), likes(Y, Z).
The important thing here is that you start with \+(X = Y) which is normally defined as:
\+ Goal :- Goal,!,fail
Note that this means that if goal succeeds, you are sure to fail. Free variables (ones that havent been assigned) will always unify, and thus be equal, so you will always fail with a free variable. It will thus never assign a value to X or Y if it doesn't already have one.
Instead
friend(X, Y) :- likes(X, Z), likes(Y, Z), \+(X = Y)
will behave more as you expect.
The problem here is that prolog gives you powerful ways to control the flow of programs, but those dont really fit nicely with its more logic oriented design. It should be possible to express "negation as failure" type constraints in a way that does not produce these problems. I'm not a huge prolog fan for this reason.
Regarding Philip JF's comment above:
It should be possible to express
"negation as failure" type constraints
in a way that does not produce these
problems.
This is possible: The modern solution for such problems are constraints. In this case, use for example dif/2, available in all serious Prolog systems.
The first subgoal of friend/2 is \+(X = Y). This is executed by first trying to find a solution for X = Y, then negating that result. The predicate =/2 is roughly the equivalent of unify/2, that is it tries to unify the left operand with the right operand. Now, when you are asking queries using e.g. friend(wallace, gromit), the two atoms wallace and gromit do not unify; but when a free variable is thrown into the mix, it always unifies with whatever term is given, so X = Y is always successful, therefore \+(X = Y) always fails, and the execution never gets past that first subgoal.
Another issue with having the inequality constraint first is: It is uncapable to find a binding for the unbound X (excluding the trivial case of unifying it with grommit for the moment). Prolog finds bindings by running through its database, trying to unify the unbound variable. That is why likes(grommit, Z) will find some binding for Z which can then be further processed, because there are likes clauses in the database. But there are no such clauses for the inequality of grommit with something, so Prolog cannot produce any bindings. As things stand, the friend predicate has to make sure that all variables are bound before the inequality can be tested.

Resources