Prolog: X is the grandfather of Y - prolog

Assume that the following facts are already entered into the Prolog database:
father(X, Y) // X is the father of Y
mother(X, Y) // X is the mother of Y
male(X) // X is a male
female(X) // X is a female
parent(X, Y) // X is a parent of Y
diff(X, Y) // X and Y are different
(1) Now add a Prolog rule for grandpa_of(X, Y) where "X is the grandfather of Y"
(2) Add another rule for sibling(X, Y) where "X is the sibling of Y"
My thoughts:
Question 1:
I am confused on how I can find the parents of the parents, all I have so far is
grandpa_of(X,Y) :- male(X), ...
Question 2:
sibling(X, Y) :- parent(P, X), parent(P, Y), diff(X, Y)

I think Jason means grandpa_of(X,Y) :- father(X,P), parent(P,Y).

It has been a long time... The first one is something like this:
grandpa_of(X, Y) :- father(X, P), father(P, Y).
Been too long... :-P

Hamad is the parent of Bilal, Laiba, and Marium.
Ali and Mona are Hamad's parents.
Musarat is also the parent of Bilal, Laiba, and Marium.
Kamran and Javeria are her parents.
Kamran and Javeria are also the parents of Salma, and Umar.
Parents are ancestors as are ancestors of parents.
Siblings share a parent.
mother
brother
grandfather
uncle
aunt
male(hamad).
male(bilal).
male(ali).
male(kamran).
male(umar).
female(laiba).
female(marium).
female(mona).
female(musarat).
female(javeria).
female(salma).
parents(ali, hamad).
parents(mona, hamad).
parents(kamran, musarat).
parents(javeria, musarat).
parents(kamran, salma).
parents(kamran, umar).
parents(javeria, salma).
parents(javeria, umar).
parents(hamad, bilal).
parents(hamad, laiba).
parents(hamad, marium).
parents(musarat, bilal).
parents(musarat, laiba).
parents(musarat, marium).
mother(X, Y) :-
parents(X, Y),
female(X),
write(X),
write(' is a mother of '),
write(Y),
nl.
brother(X, Y) :-
male(X),
x \= y,
parents(Z, X),
parents(Z, Y),
write(X),
write(' is a brother of '),
write(Y),
nl.
sister(X, Y) :-
female(X),
x \= y,
parents(Z, X),
parents(Z, Y),
write(X),
write(' is a sister of '),
write(Y),
nl.
grandfather(X, Y) :-
parents(X, P),
parents(P, Y),
male(X),
write(X),
write(' is grandfather of '),
write(Y),
nl.
uncle(X, Z) :-
brother(X, P),
parents(P, Z),
male(X),
write(X),
write(' is an uncle of '),
write(Z),
nl.
aunt(X, Z) :-
sister(X, P),
parents(P, Z),
female(X),
write(X),
write(' is an aunt of '),
write(Z),
nl.

%Sample program of X is a Grandfather of Y
%knowledgebase or database
female(amrita).
female(aroti).
female(manusi).
female(parboti).
male(susanta).
male(prasanta).
male(haran).
male(ratan).
male(srijit).
%clause
parent(manusi,susanta).
parent(ratan,amrita).
parent(aroti,amrita).
parent(haran,prasanta).
parent(haran,susanta).
parent(manusi,prasanta).
parent(susanta,srijit).
%rules
mother(X,Y):-parent(X,Y),female(X).
father(X,Y):-parent(X,Y),male(X).
sister(X,Y):-female(X),x==y,parent(Z,X),parent(Z,Y).
brother(X,Y):-male(X),x==y,parent(Z,X),parent(Z,Y).
grandparent(X,Y):-parent(X,Y),parent(Y,Z).
grandmother(X,Y):-mother(X,Y),parent(Y,Z).
grandfather(X,Y):-father(X,Y),parent(Y,Z).

Related

Given values x and y return rule name if it is true

This is my prolog file.
male(bob).
male(john).
female(betty).
female(dana).
father(bob, john).
father(bob, dana).
mother(betty, john).
mother(betty, dana).
husband(X, Y) :- male(X), mother(Y, Z), father(X, Z).
wife(X, Y) :- female(X), father(Y, Z), mother(X, Z).
son(X, Y) :- male(X), mother(Y, X);female(X), father(Y, X).
daughter(X, Y) :- female(X), mother(Y, X);female(X), father(Y, X).
sister(X, Y) :- female(X), mother(Z, X), mother(Z, Y), X \= Y.
brother(X, Y) :- male(X), mother(Z, X), mother(Z, Y), X \= Y.
I want a name of rule if it returns true for any value x or y.
Let's say x = betty and y = john.
mother(betty, john). <- this will meet so my rule should return 'mother'.
Similarly if any other rule or fact meets true for some value x, y it should return that rule name.
How can I achieve something like that?
could be easy as
query_family(P1, P2, P) :-
% current_predicate(P/2),
member(P, [father, mother, husband, wife, son, daughter, sister, brother]),
call(P, P1, P2).
that gives
?- query_family(betty, john, R).
R = mother ;
false.
?- query_family(betty, X, R).
X = john,
R = mother ;
X = dana,
R = mother ;
X = bob,
R = wife ;
X = bob,
R = wife ;
false.
the semicolon after the answer means 'gimme next'
$ swipl
?- ['facts'].
?- setof( Functor,
Term^(member(Functor, [father, mother, husband, wife, son, daughter, sister, brother]),
Term =.. [Functor, betty, john],
once(Term)),
Answer).
Answer = [mother].
?-
If you want to avoid having to specify the list of functors of interest, you could use current_predicate(F/2).

How to find if somebody is somebodies second cousin once removed in prolog?

I am writing a program to return true if a person is another persons second cousin once removed. The only information that is known is who is the parent of who else. I am using the family tree from here http://en.wikipedia.org/wiki/Cousin#Second_cousins_once_removed. Overall I got everything working but i cant make it find the second cousin once removed. The first cousin and the once removed ones work, just looking to get some help on how to find a second cousin that is also once removed.
parent(adam, betty).
parent(agatha, betty).
parent(adam, charles).
parent(agatha, charles).
parent(bill, david).
parent(betty, david).
parent(charles, emma).
parent(corinda, emma).
parent(dawn, frank).
parent(david, frank).
parent(emma, gwen).
parent(eric, gwen).
parent(frank, harry).
parent(felicity, harry).
child(X, Y) :-
parent(Y, X).
grandparent(X, Y) :-
parent(X, Z),
parent(Z, Y).
greatgrandparent(X, Y) :-
parent(P, Y),
grandparent(X, P).
cousin(X, Y) :-
grandparent(Z, X),
grandparent(Z, Y),
\+sibling(X, Y),
X \= Y.
sibling(X, Y) :-
parent(Z, X),
parent(Z, Y),
X \= Y.
cousinonceremoved(X, Y) :-
cousin(Z, Y),
child(X, Z).
secondcousin(X, Y) :-
greatgrandparent(Z, X),
greatgrandparent(Z, Y),
\+sibling(X, Y),
\+cousin(X, Y),
X \= Y.
Just as stated in the article: "The child of one's second cousin".
secondCousinOnceRemoved(H, G) :- child(H, F), secondcousin(F, G).

How can I refractor the display functions?

I have these display functions:
display_siblings(X,Y):-
setof(X-Y, (siblings(X,Y), ordered(X-Y)), Sibs),
write('The siblings of'),
write(X),
write('are'),nl,
foreach(member(Pair, Sibs),
writeln(Pair)),nl,
write('% end'), nl.
display_sisters(X,Y):-
setof(X-Y, (sisters(X,Y), ordered(X-Y)), Sibs),
write('The sisters of'),
write(X),
write('are'),nl,
foreach(member(Pair, Sibs),
writeln(Pair)),nl,
write('% end'), nl.
As you can see only the second argument of setof is changing.
Could I make one display function of both and if it can how can I do this?
Roelof
One way would be:
display_siblings(X, Y):-
setof(X-Y, (siblings(X, Y), ordered(X-Y)), Sibs),
write('The siblings of'),
write_sibs(X, Sibs).
display_sisters(X, Y) :=
setof(X-Y, (sisters(X, Y), ordered(X-Y)), Sibs),
write('The sisters of'),
write_sibs(X, Sibs).
write_sibs(X, Sibs):-
write(X),
write('are'), nl,
foreach(member(Pair, Sibs),
writeln(Pair)),nl,
write('% end'), nl.
Another way would be:
display_siblings(X, Y) :-
display('siblings', X, Y).
display_sisters(X, Y) :-
display('sisters', X, Y).
display(Type, X, Y) :-
setof(X-Y, (call(Type, X, Y), ordered(X-Y)), Sibs),
write('The '), write(Type), write(' of'),
write(X),
write('are'),nl,
foreach(member(Pair, Sibs),
writeln(Pair)),nl,
write('% end'), nl.

Prolog grandfather(i,i)

A (very) strange story:
I married a widow(W) who has a daughter(D). My father(F) married my stepdaughter (D). My wife gave birth to a son(s1). The wife of my father (the stepdaughter) also had a son (s2).
The goal of this project is to input:
grandfather(i,i).
and return yes in prolog.
Here is what I have so far:
%facts
father(f,i).
husband(i,w).
husband(f,d).
mother(w,d).
mother(w,s1).
father(i,s1).
mother(d,s2).
father(f,s2).
%rules
father(X,Y) :- f_in_law(X,Y).
father(X,Y) :- husband(X,Z),mother(Z,Y).
f_in_law(X,Y) :- husband(Z,Y),father(X,Z).
b_in_law(X,Y) :- husband(Z,Y),brother(X,Z).
%brother(X,Y) :- b_in_law(X,Y).
uncle(X,Y) :- father(Z,Y),brother(X,Z).
grandfather(X,Y) :- father(Z,Y),father(X,Z).
I traced through it to see what went wrong. father(f,i) is true so that's good! But father(i,f) is thought of as false. Any suggestions/ideas on how to correct this? I appreciate any input as I am rather new to prolog.
Should the predicate be
f_in_law(X,Y) :- husband(Y,Z),father(X,Z).
instead of
f_in_law(X,Y) :- husband(Z,Y),father(X,Z).
I have reformulated the riddle
father(i, s1).
father(f, i).
father(f, s2).
fatlaw(X, Y) :- husband(X, Z), mother(Z, Y).
mother(w, d).
mother(w, s1).
mother(d, s2).
motlaw(X, Y) :- husband(Z, X), father(Z, Y).
husband(i, w).
husband(f, d).
grandfather(X, Y) :-
( father(X, Z) ; fatlaw(X, Z) )
, ( father(Z, Y) ; fatlaw(Z, Y) ; mother(Z, Y) ; motlaw(Z, Y) )
.
the point seems to be that grandfather must accept fake biological offsprings (I hope this is reasonable English).
with that
?- grandfather(X,X).
X = i ;
false.

Prolog and ancestor relationship

I have to write a small prolog program which checks if a given person is a ancestor of a second one.
These are the facts and rules:
mother(tim, anna).
mother(anna, fanny).
mother(daniel, fanny).
mother(celine, gertrude).
father(tim, bernd).
father(anna, ephraim).
father(daniel, ephraim).
father(celine, daniel).
parent(X,Y) :- mother(X,Y).
parent(X,Y) :- father(X,Y).
The test if a person is an ancestor of another person is easy:
ancestor(X, Y) :- parent(X, Y).
ancestor(X, Y) :- parent(X, Z), ancestor(Z, Y).
But now I have to write a method ancestor(X,Y,Z) which also prints out the relationship between two persons. It should look like this
?- ancestor(ephraim, tim, X).
false.
?- ancestor(tim, ephraim, X).
X = father(mother(tim)).
And that is the problem: I have no clue how do to this.
You can use an accumulator to adapt #Scott Hunter's solution :
mother(anna, fanny).
mother(daniel, fanny).
mother(celine, gertrude).
father(tim, bernd).
father(anna, ephraim).
father(daniel, ephraim).
father(celine, daniel).
ancestor(X, Y, Z) :- ancestor(X, Y, X, Z).
ancestor(X, Y, Acc, father(Acc)) :- father(X, Y).
ancestor(X, Y, Acc, mother(Acc)) :- mother(X, Y).
ancestor(X, Y, Acc, Result) :-
father(X, Z),
ancestor(Z, Y, father(Acc), Result).
ancestor(X, Y, Acc, Result) :-
mother(X, Z),
ancestor(Z, Y, mother(Acc), Result).
edit : as Scott Hunter showed in his edit, there's no need for an explicit accumulator here, since we can left the inner part of the term unbound easily at each iteration. His solution is therefore better !
A term manipulation alternative to the accumulator tecnique by #Mog:
parent(X, Y, mother(X)) :- mother(X, Y).
parent(X, Y, father(X)) :- father(X, Y).
ancestor(X, Y, R) :-
parent(X, Y, R).
ancestor(X, Y, R) :-
parent(X, Z, P),
ancestor(Z, Y, A),
eldest(A, P, R).
eldest(A, P, R) :-
A =.. [Af, Aa],
( atom(Aa)
-> T = P
; eldest(Aa, P, T)
),
R =.. [Af, T].
To test, I made tim a father: father(ugo, tim).
?- ancestor(tim, ephraim, X).
X = father(mother(tim)) .
?- ancestor(ugo, ephraim, X).
X = father(mother(father(ugo))) .
Simply add a term which tracts what kind of parent is used at each step (edited to get result in proper order):
ancestor(X,Y,father(X)) :- father(X,Y).
ancestor(X,Y,mother(X)) :- mother(X,Y).
ancestor(X,Y,father(Z2)) :- father(Z,Y), ancestor(X,Z,Z2).
ancestor(X,Y,mother(Z2)) :- mother(Z,Y), ancestor(X,Z,Z2).

Resources