Prolog How to skip a fact - prolog

As the title says how can I accomplish this?
I have this knowledge base
person(alice).
person(mark).
person(sally).
likes(alice,coke).
likes(alice,fanta).
likes(alice,sprite).
likes(mark,water).
likes(mark,coffee).
likes(sally,pepsi).
And I want to output every drink that alice likes that is not fanta.Can someone explain how to achieve it and why it's done that way?

If you input the query likes(alice, X) you get all drinks that alice likes including fanta:
?- likes(alice, X).
X = coke ;
X = fanta ;
X = sprite.
If you add the goal X \= fanta in conjunction to that (note: must come after), then when X is bound to fanta, it will fail the goal X \= fanta, and it will backtrack to find other choices:
?- likes(alice, X), X \= fanta.
X = coke ;
X = sprite.
(note: pressing ; to get the next choice)
Suggested reading: Proof search

Related

Retrieve elements from facts in Prolog

I am currently learning Prolog for a class right now. I am using GNU Prolog to define a rule for example class_info(X,Y) and a similar rule, where X is the name of the professor and Y will be the output of the info. For example:
?- class_info(steve, Y).
Y = math ;
false.
But I only know how to return algebraic expressions in rules, but not the one above.
Suppose I have the following facts.
/*facts */
job(steve, professor).
job(john, professor).
teaches(steve, math).
teaches(john, chemistry).
class(math, calculus).
class(chemistry, organic).
class(math, algebra).
class(chemistry, basic).
%rule
class_info(X, Y) :-
%absolutely have no idea what do here, 'is' does not work, since it's only for algebraic expressions
.
exact_class(X, Y) :-
%exact_class(steve, Y). returns Y = calculus? and Y = algebra upon pressing ';'
.
Any help would be appreciated. I am not looking for code, but something to point me in the right direction. The Prolog GNU manual is kind of hard to follow.
class_info(X, Y) :-
teaches(X, Y).
?- class_info(steve,Y).
Y = math ;
false.
Ok, sorry for putting one solution right on top but Prolog is hard to grasp without examples. So I just put the first solution, the second you have to figure out with a bit of explanation.
So you are asking which lecturer X holds which class Y. You already have this info within teaches/2, so you just forward the values from this predicate. So it says something like if a teacher X teaches the lecture Y, the classinfo from X is Y. You can add addional information, for example the teacher has to be a professor. You do this "and" (conjunction) by putting a , between the predicates:
class_info(X, Y) :-
teaches(X, Y),
job(X, professor).
?- class_info(steve,Y).
Y = math ;
false.
Please note that variables start with a capital letter. Questions are asked by starting with ?-, the answers are separeted by a semicolon ; until there are no solutions left (false.).
You can even be more specific about this by using a predicate which also forwards the lecturers job:
class_info_job(X, Y, Z) :-
teaches(X, Y),
job(X, Z).
?- class_info_job (steve, Y, Z).
Y = math,
Z = professor ;
false.
?- class_info_job (steve, Y, professor).
Y = math;
false.
?- class_info_job(X, math, Z).
X = steve,
Z = professor ;
false.
?- class_info_job(X, Y, Z).
X = steve,
Y = math,
Z = professor ;
X = john,
Y = chemistry,
Z = professor ;
false.
Ok, so these were some examples how to play around. I hope this enough to help you with the second rule.

How to formulate an exception for findall/3 correctly?

I have startet to learn Prolog and I want to get a list of opponents of players with findall/3. In the Generalization I just want to add only the opponents to the list who are actually players, except the player I am asking for itself. How can I formulate this exception? I know about the negation as failure concept but I am not sure if and how I need it here.
player(irina).
player(anton).
player(michael).
opponent(irina, anton).
opponent(irina, maria).
opponent(irina, michael).
% Only opponents who are also players should be added to the list,
% except the player of interest itself
opponent(X, Y) :- X \= Y, player(Y).
% the query
?- findall(O, opponent(irina,O) , OpponentList).
% the result
% only the first three results from the facts,
% the results from the rule, a second entry of
% anton and michael are missing.
OpponentList = [anton, maria, michael].
I actually expected, that the resolution would work as follows:
opponent(irina, irina) :- irina \= irina, player(irina).
% false true
% false
% false, hence not added to the list
opponent(irina, anton) :- irina \= anton, player(anton).
% true true
% true
% true, hence added to the list
What am I missing?
Many thanks in advance!
Code:
player(irina).
player(anton).
player(michael).
opponent(irina, anton).
opponent(irina, maria).
opponent(irina, michael).
opponent(X, Y) :-
format("Called with X = ~q, Y = ~q\n",[X,Y]),
X \= Y, % this will fail if Y is still fresh because X and Y can be unified!
player(Y).
opponent_mod(X, Y) :-
format("Called with X = ~q, Y = ~q\n",[X,Y]),
player(Y), % this will set Y to various players
X \= Y. % the test for un-unifiability of two set vars may or may not succeed
% query helpfully as code:
q(Who,OpponentList) :- findall(O, opponent(Who,O) , OpponentList).
q_mod(Who,OpponentList) :- findall(O, opponent_mod(Who,O) , OpponentList).
% even better
q_mod_set(Who,OpponentList) :- setof(O, opponent_mod(Who,O) , OpponentList).
Run it:
Not expected:
?- q(irina,X).
Called with X = irina, Y = _19654
X = [anton, maria, michael].
Expected:
?- q_mod(irina,X).
Called with X = irina, Y = _20568
X = [anton, michael].
So what happens in the "not expected" case with Who = irina:
findall/3 tries to collect all values Y such that opponent(Who,O)
It finds anton, maria, michal through the facts
opponent(irina, anton).
opponent(irina, maria).
opponent(irina, michael).
It also tries the rule opponent(X, Y) :- ... with X = irina (once only). But the test X \= Y fails because X has been constrained to be irina but Y is still fresh (completely unconstrained). This means that a unification of X and Y could succeed if it were attempted (which is what is being tested, = does not as such mean "is not equal"). So X \= Y is false at this point of computation. If you move X \= Y after player(Y), then Y will have been constrained to whatever was grabbed from the player/1 facts, and this would reduce to an actual comparison of the values of X and Y.

Prolog Family Tree Issues

I've been having a novice issue with setting up a family tree in Prolog. For some reason, I can't seem to get 'sibling' to return true.
% male(+Person)
% Specifies the Person is a male.
%
male(abraham).
male(homer).
male(bartholomew).
% female(+Person)
% Specifies the Person is a female.
%
female(mona).
female(marjorie).
female(lisa).
female(margaret).
% mother(+Parent,+Child)
% Specifies Parent is a mother of Child.
%
mother(mona,homer).
mother(marjorie,bartholomew).
mother(marjorie,lisa).
mother(marjorie,margaret).
% father(+Parent,+Child)
% Specifies Parent is a father of Child.
%
father(abraham,homer).
father(homer,bartholomew).
father(homer,lisa).
father(homer,margaret).
% sibling(+Person1,+Person2)
% Specifies Person1 is a sibling of Person2
%
sibling(X,Y) :-
father(X,Z),
mother(Y,Z).
Thanks very much in advance, this issue has been driving me nuts!
as an initial step, use an established relation (mother/2 will do, as well):
sibling(X, Y) :- father(F, X), father(F, Y), X #< Y.
yields
?- sibling(X,Y).
X = bartholomew,
Y = lisa ;
X = bartholomew,
Y = margaret ;
X = lisa,
Y = margaret ;
false.

Rule and query Help in prolog

There are facts like :
student(ram, cs). // ram is student of cs branch
student(kiri,it).
student(akshay,cs).
student(sanjay,me).
I want to write a rule to find out the classmates in any branch AND a query to list out students in a branch say cs. Please help.
what query I had to run if i had to find classmates of akshay?
Two students are classmates if they are participating the same course.
classmates(X, Y) :- student(X, A), student(Y, A), X #< Y.
#</2 here is for suppressing duplicates. I.e it is enough to have only (A,B) without (B,A), (A,A) and (B,B).
?- classmates(X, Y).
X = akshay,
Y = ram ;
false.
To list out all students in a branch cs:
?- student(X, cs).
X = ram ;
X = akshay.
this being a follow up of this previous question, let's keep on the same mood...
classmates(Classmates) :-
aggregate(set(P), B^Q^(student(P,B), student(Q,B), P\=Q), Classmates).
yields
?- classmates(L).
L = [akshay, ram].

Prolog Family Tree query issues

% facts
mother(john, dana).
father(john, david).
mother(chelsea, dana).
father(chelsea, david).
mother(jared, dana).
father(jared, david).
% queries
father(X,Y) :- father(X,Y), write(Y).
mother(X,Y) :- mother(X,Y), write(Y).
parent(X,Y) :- father(X,Y);mother(X,Y).
sibling(X,Y) :- parent(X,Z), parent(Y,Z), write(Y).
I am having trouble getting these queries to work. when I type in the father command, it will tell me yes or no correctly, but won't do the write command (same with mother). "parent" doesn't work at all for me (therefor sibling doesn't either). Also, if I type in sibling(X,Y). I need to get all siblings...for example, sibling(john, chelsea). I need to output all the possible siblings (jared as well). Let me know where I am going wrong, I really don't see an issue with my logic here. Thanks!
Basically you can remove your mother and father predicates that are not facts. They are infinite loops. Since parent use them and sibling use parent, all your predicates are infinite loops.
To see what happens, you can do that :
?- trace, father(john, X).
and observe how prolog handles the query. You'll soon observe than to resolve father, he needs to solve father, and that to solve father, he needs to solve father, and that it never stops...
When the two problematic are removed, I obtain a correct behaviour :
?- father(john, X).
X = david.
?- parent(john, X).
X = david ;
X = dana.
?- sibling(john, X).
john
X = john ;
chelsea
X = chelsea ;
jared
X = jared ;
john
X = john ;
chelsea
X = chelsea ;
jared
X = jared.
Now, to make your sibling predicate better, you could say that someone is not its own sibling and that if you have one common parent it's enough (it will remove the duplicates) :
sibling(X,Y) :- father(Y,Z), father(X, Z), X =\= Y.

Resources