Why does my predicate not work, when a similar predicate does? - prolog

I have the following facts:
loves(andy, julia).
loves(andrew, maria).
loves(bob, sofia).
loved(juila).
loved(maria).
loved(sofia).
and I want to have two predicates:
do_love(X, Y) :- ...
is_loved(X, Y) :- ...
which returns Y as the name of the person, and X as the fact itself. For the loved fact, I wrote:
is_loved(X, Y) :- X = loved(Y), X.
which as expected, returns:
is_loved(X,Y).
X = loved(juila),
Y = juila ;
X = loved(maria),
Y = maria ;
X = loved(sofia),
Y = sofia.
However, when I write the predicate for the loves fact in a similar way:
do_love(X, Y) :- X = loves(X, Y), X.
it returns false for the query:
do_love(X,Y).
false.
I'm new to prolog, and can't really see why this is the case. Why does the query for is_loved work, while the one for do_love doesn't?

The problem is you're trying to unify X with two different values:
X = loves(...) and
loves(X, ...)
(I truncate using ... because those parts are irrelevant to what I'm saying).
In other words, your do_love predicate is saying "X must unify with a loves predicate" and also "X must unify with the first argument in a loves predicate". With the data set you've set up, no single value fulfills both requirements.
Depending on what you're trying to do, this might be what you want:
do_love(X, Y) :- loves(X, Y).
Sidenote 1: Predicates don't "return" values like they do in other languages with functions. You don't need the , X in your predicates for them to work.
Sidenote 2: The = is a "unify" operator, rather than an "assignment" like other languages. See this page for more info.

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.

Can't show the second answer in Prolog

sisters(mary,catherine).
sisters(catherine,mary).
brothers(john,simone).
brothers(simone,john).
marriage(john,mary,2010).
marriage(mary,john,2010).
marriage(kate,simone,2009).
marriage(simone,kate,2009).
marriage(catherine,josh,2011).
marriage(josh,catherine,2011).
birth(mary,johnny).
birth(mary,peter).
birth(catherine,william).
birth(kate,betty).
givebirthyear(mary,peter,2015).
givebirthyear(mary,johnny,2012).
givebirthyear(catherine,william,2012).
givebirthyear(kate,betty,2011).
siblings(X,Y) :-
birth(Parent,X),
birth(Parent,Y).
cousins(X,Y) :-
birth(Xparent,X),
birth(Yparent,Y),
sisters(Xparent,Yparent).
cousins(X,Y) :-
X \= Y,
birth(Xmom,X),
birth(Ymom,Y),
marriage(Xmom,Xdad,_),
marriage(Ymom,Ydad,_),
brothers(Xdad,Ydad).
I don' know what's happening in my code. When I input
cousins(betty,johnny).
and
cousins(william,johnny).
The prolog says true. But when I entered
cousins(S,johnny).
THe prolog says S = william but didn't show me that S = betty. I don't really know what's happening. Need help.
Here is the prolog result I got.
?- cousins(S,johnny).
S = william ;
false.
?- cousins(betty,johnny).
true.
?- cousins(william,johnny).
true .
The problem
The reason this happens is because
X \= Y,
actually means:
\+(X = Y).
now \+ or not in Prolog has some weird behaviour compared to the logical not. \+ means negation as finite failure. This means that \+(G) is considered to be true in case Prolog queries G, and can not find a way to satisfy G, and that G is finite (eventually the quest to satisfy G ends).
Now if we query \+(X = Y), Prolog will thus aim to unify X and Y. In case X and Y are (ungrounded) variables, then X can be equal to Y. As a result X \= Y fails in case X and Y are free variables.
So basically we can either use another predicate that for instance puts a constraint on the two variables that is triggered when the variables are grounded, or we can reorder the body of the clause, such that X and Y are already grounded before we call X \= Y.
If we can make for instance the assumption that X and Y will be grounded after calling birth/2, we can reorder the clause to:
cousins(X,Y) :-
birth(Xmom,X),
birth(Ymom,Y),
X \= Y,
marriage(Xmom,Xdad,_),
marriage(Ymom,Ydad,_),
brothers(Xdad,Ydad).
Prolog has however a predicate dif/2 that puts a constraint on the two variables, and from the moment the two are grounded, it will fail if the two are equal. So we can use it like:
cousins(X,Y) :-
dif(X,Y),
birth(Xmom,X),
birth(Ymom,Y),
marriage(Xmom,Xdad,_),
marriage(Ymom,Ydad,_),
brothers(Xdad,Ydad).
Making things simpler
That being said, I think you make the program too complex. We can start with a few definitions:
two people are slibings/2 if they are brothers/2 or sisters/2.
slibings(X,Y) :-
brothers(X,Y).
slibings(X,Y) :-
sisters(X,Y).
It is however possible that brothers/2 and sisters/2 do not provide all information. Two people are also slibings if they have the same mother (we will assume that people do not divorce here, or at least not give birth to other children after they remarry).
slibings(X,Y) :-
dif(X,Y),
birth(Mother,X),
birth(Mother,Y).
a parent/2 of a person is the mother of the person or the father (the person that married the mother).
So we can write:
parent(Mother,X) :-
birth(Mother,X).
parent(Father,X) :-
birth(Mother,X),
marriage(Father,Mother,_).
based on your example, the marriage/3 predicate is bidirectional: in case marriage(X,Y,Z)., then there is also a fact marriage(Y,X,Z)..
And now we can define:
two people are cousins if there parents are slibings:
cousins(X,Y) :-
parent(MF1,X),
parent(MF2,Y),
slibings(MF1,MF2).
and that's it.

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?

Why does this query unify with this clause in Prolog?

I think I have a fundamental misunderstanding about unification. Here are my two clauses:
test(func(X), X, 1) :- X == X.
test(func(X), Y, 0) :- X \== Y.
So- If I query test(func(X), Y, D), I would expect it to only be provable with the second clause, and D will be 0. This is because (I think\I am trying to) ensure that X must be equal to X, in the first clause. So my query shouldn't unify because X is not the same as Y. I thought == tests that the two operands are the same variables. And X and Y clearly aren't.
But the output:
| ?- test(func(X), Y, D).
D = 1
Y = X ? ;
D = 0
So it is saying that it unifies with the first clause if Y = X. But, Y is not equal to X. What am I misunderstanding here?
Your first answer, D = 1, Y = X accords with your first definition. I think you're expecting that when you query ?- test(func(X), Y, D). it should fail for the first definition, because the X and Y are different variables, but the first definition should only succeed if the two variables are identical.
However, in the head of your clause, you have the same variable appearing twice: test(func(X), X, 1) :- X == X. (As #CapelliC pointed out, X == X is superfluous here.) When you query ?- func(func(X), Y, D)., Prolog tries to unify this clause with the head of your first rule. It unifies func(X) with func(X) and Y with X and 1 with 1. Once this pattern-matching unification has succeeded, it then tests the body of the rule to see if the criteria are met. Since Y has been unified with X, the two variables will match the strict equality condition---during the pattern matching, you've unified Y with the same variable as X.
Note the following two queries:
?- X == Y.
false.
?- Y = X, X == Y.
X = Y.
The second is similar to what's happening with the query that's confusing you. If you rewrite your first rule in accordance with #CapelliC's suggestion,
test(func(X), Y, 1) :- X == Y.
Then it will function as expected, because, in this case, a free variable in the second argument will be unified with a different variable than that within the func/1 term, and then the two variables won't satisfy strict equality (but if the two variables are unified with a ground term, they will pass).
X == X it's a sort of tautology (always true), and clearly your first clause could equivalently be
test(func(X), X, 1).
I think you should write it like the second one
test(func(X), Y, 1) :- X == Y.

Prolog - Make two Instantiations Equal

I'm very new to Prolog so please bear with me.
Lets say I have the following:
foo(bar(a,b)).
foo(bar(b,a)).
Then I enter foo(X) as a query:
?- foo(X).
X = bar(a, b) ;
X = bar(b, a).
Prolog returns two instantiations of X to satisfy the query: bar(a, b) and bar(b,a).
Is there away I can make these two instantiations equivalent? Once Prolog instantiates X to bar(a,b), it won't instantiate it to bar(b,a).
So when I enter foo(X) as a query:
?- foo(X).
X = bar(a, b).
X was no instantiated as bar(b,a), because it's equivalent to bar(a,b). Is this possible to do with Prolog, or does it go against the fundamental principals of Prolog?
The first clause of symmetry/2 deals with cases in which both foo(bar(a,b)) and foo(bar(b,a)) occur. I use the standard order of terms in order to return only the former. Notice that the use of #< would have falsely excluded results like foo(bar(e,e)).
The second clause treats cases in which either foo(bar(c,d)) or foo(bar(d,c)) occur.
foo(bar(a, b)).
foo(bar(b, a)).
foo(bar(c, d)).
foo(bar(e, e)).
symmetry(X, Y):-
foo(bar(X, Y)),
foo(bar(Y, X)),
X #=< Y.
symmetry(X, Y):-
foo(bar(X, Y)),
\+ foo(bar(Y, X)).
Example of usage:
?- symmetry(X, Y).
X = a,
Y = b ;
X = Y, Y = e ;
X = c,
Y = d ;
false
Hope this helps!
Identity of literals it's the core of unification - the fundamental operation of Prolog algorithm - and then the answer to your question it's no, it's not possible to handle bar(a,b) as bar(b,a).

Resources