Prolog and ancestor relationship - prolog

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).

Related

Prolog OR operator, to stop checking after first predicate returns true?

border(de, fr).
neighbor(X, Y) :- border(X, Y); border(Y, X).
I want it to not check border(Y, X). if border(X, Y). returns true. I originally tried border(X, Y) :- border(Y, X). but that obviously ended up in an infinite loop.
Instead of using once/1, you can define neighbor/2 as:
border(de, fr).
border(fr, es).
border(fr, it).
neighbor(X, Y) :-
bagof(t, (border(X, Y) ; border(Y, X)), _).
Then you can still reason with neighbor/2:
?- neighbor(fr, Y).
Another without bagof/3 but with call_nth/2:
neighbor(X, Y) :-
\+ call_nth((border(X, Y) ; border(Y, X)), 2), !,
(border(X, Y) ; border(Y, X)), !.
neighbor(X, Y) :-
border(X, Y) ; border(Y, X).

Prolog cousin once removed and half sister/brother rules

Am working on a prolog genealogy project and cannot figure out how to make the rules for cousin once removed and half sister/brother rules. Below is what I have and cannot get it to work. Any help or suggestions would be appreciated. I have placed in bold what I have tried. I'm sure its something simple in the way I'm trying to code it.I just cannot figure it out.
person(marc,male).
person(faith,female).
person(alan,male).
person(kim,female).
person(missy,female).
person(eric,male).
person(charles,male).
person(eleanor,female).
person(roland,male).
person(corey,male).
person(amy,female).
person(tyler,male).
person(matty,male).
person(kaydi,female).
person(jenna,female).
person(allison,female).
person(emma,female).
person(hayley,female).
person(jaylin,female).
person(lukus,male).
person(brendon,male).
person(bradley,male).
person(tylerh,male).
person(dayna,female).
person(victor,male).
person(jacoby,male).
person(javi,male).
person(jordan,male).
person(jaxson,male).
person(kenzie,female).
person(richard,male).
person(reggie,male).
person(reggiejr,male).
person(beverly,female).
person(floyd,male).
person(marjorie,female).
person(kevin,male).
parent(marc,alan).
parent(faith,alan).
parent(charles,marc).
parent(charles,kim).
parent(charles,missy).
parent(charles,eric).
parent(eleanor,marc).
parent(eleanor,kim).
parent(eleanor,missy).
parent(eleanor,eric).
parent(eric,matty).
parent(eric,tyler).
parent(eric,kaydi).
parent(amy,matty).
parent(amy,tyler).
parent(amy,kaydi).
parent(missy,jordan).
parent(missy,jaxson).
parent(missy,kenzie).
parent(richard,jordan).
parent(corey,kenzie).
parent(corey,jaxson).
parent(kim,allison).
parent(kim,jenna).
parent(kim,emma).
parent(kim,jaylin).
parent(kim,hayley).
parent(kim,dayna).
parent(roland,allison).
parent(roland,jenna).
parent(roland,emma).
parent(roland,jaylin).
parent(roland,hayley).
parent(roland,dayna).
parent(dayna,javi).
parent(dayna,jacoby).
parent(victor,javi).
parent(victor,jacoby).
parent(jenna,bradley).
parent(brendon,bradley).
parent(tylerh,lukus).
parent(allison,lukus).
parent(reggie,reggiejr).
parent(beverly,reggiejr).
parent(floyd,beverly).
parent(marjorie,beverly).
parent(reggiejr,kevin).
parent(floyd,eleanor).
parent(marjorie,eleanor).
married(marc,faith).
married(charles,eleanor).
married(kim,roland).
married(eric,amy).
married(missy,corey).
married(dayna,victor).
married(allison,tylerh).
married(marjorie,floyd).
married(beverly,reggie).
father(X, Y) :- parent(X, Y), person(X,male).
mother(X, Y) :- parent(X, Y), person(female,Y).
son(X, Y) :- parent(Y,X), person(X,male).
daughter(X, Y) :- parent(X,Y), person(Y,female).
grandparent(X, Z) :- parent(X, Y), parent(Y, Z).
grandfather(X, Z) :- grandparent(X, Z), person(X,male).
grandmother(X, Z) :- grandparent(X, Z), person(female,Y).
grandson(X, Z) :- grandchild(X, Z), person(X,male).
granddaughter(Y, Z) :- grandchild(Y, Z), person(Y,female).
grandchild(X, Z) :- grandparent(Z, X).
sibling(X,Y) :- parent(Z,X), parent(Z,Y).
brother(Y, X) :- sibling(Y,X), person(X,male), not(X=Y).
sister(X, Y) :- sibling(X, Y), person(Y,female).
auntoruncle(X, W) :- sibling(X, Y), parent(Y, W).
auntoruncle(X, Z) :- married(X,Y), sibling(Y,W), parent(W,Z).
uncle(X, W) :- auntoruncle(X, W), person(X,male).
aunt(X, W) :- auntoruncle(X, W), person(female,Y).
cousin(X, Y) :- parent(Z, X), auntoruncle(Z, Y), Y\=X.
nieceornephew(X, Y) :- parent(Z, X), sibling(Z, Y).
nephew(X, Y) :- nieceornephew(X, Y), person(X,male).
niece(X, Y) :- nieceornephew(Y, X), person(Y,female).
greatgrandparent(X, Z) :- parent(X, Y), grandparent(Y, Z).
greatgrandfather(X, Z) :- greatgrandparent(X, Z), person(X,male).
greatgrandmother(X, Z) :- greatgrandparent(X, Z), person(female,Y).
greatgrandchild(X, Z) :- child(X, Y), grandchild(X, Z).
greatgrandson(X, Z) :- greatgrandchild(X, Z), person(X,male).
greatgranddaughter(X, Z) :- greatgrandchild(X, Z), person(female,Y).
married_to(X,Y) :- married(X,Y), not divorced(X,Y).
whatgender(X,Y) :- person(X,Y).
**child(X, Y) :- parent(Y, X).
cousinonceremoved(X, Y) :- cousin(Z, Y), child(X, Z).
halfsibling(X,Y) :- parent(Z,X), parent(Z,Y), parent(P,X), \+parent(P,Y).
halfbrother(X,Y) :- halfsibling(X,Y), male(X).
halfsister(X,Y) :- halfsibling(X,Y), female(X).**
strong text

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).

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.

Resources