How to find blood relatives only in prolog - prolog

Using recursion i need to find all blood relatives of any person in the family tree.
My attempt so far has failed.
Here is my code, with my attempt at the bottom
female(helen).
female(debbie).
female(louise).
female(yvonne).
female(belinda).
female(heather).
male(john).
male(andrew).
male(barry).
male(daniel).
male(charles).
parent(helen, debbie).
parent(helen, barry).
parent(helen, louise).
parent(john, debbie).
parent(john, barry).
parent(andrew, louise).
parent(debbie, yvonne).
parent(debbie, daniel).
parent(barry, charles).
parent(barry, belinda).
parent(louise, heather).
mother(X, Y) :-
female(X),
parent(X, Y).
father(X, Y) :-
male(X),
parent(X,Y).
child(X, Y) :-
parent(Y, X).
daughter(X, Y) :-
parent(Y, X),
female(X).
son(X, Y) :-
parent(Y,X),
male(X).
sister(X, Y) :-
female(X),
parent(Q,X),
parent(Q,Y).
brother(X, Y) :-
male(X),
parent(Q,X),
parent(Q,Y).
sibling(X, Y) :-
parent(Q,X),
parent(Q,Y),
X\=Y.
uncle(X, Y) :-
parent(P,Y),
brother(X,P).
aunt(X, Y) :-
parent(P,Y),
sister(X,P).
cousin(C, Cousin):-
parent(Parent,C),
sibling(Parent,AU),
child(Cousin,AU).
%Here is Relative
relative(An, Re):-
An\=Re,
parent(An, Re);
sibling(An, Re).
relative(An, Rela):-
parent(An, Child);
sibling(An, Rela),
relative(Child, Rela),
An\=Rela, C\=Rela.
Sort of works, but gets stuck in an infinite loop at the end.
Thanks.

not sure about 'relatives' (any person bound reachable in a parent/child relation ?), but your definition seems more complex than needed ( do you know what ; does ?).
I tried
relative(An, Re):-
parent(An, Re).
relative(An, Rela):-
parent(An, C),
relative(C, Rela).
that yields
16 ?- forall(relative(X,Y),writeln(X:Y)).
helen:debbie
helen:barry
helen:louise
john:debbie
john:barry
andrew:louise
debbie:yvonne
debbie:daniel
barry:charles
barry:belinda
louise:heather
helen:yvonne
helen:daniel
helen:charles
helen:belinda
helen:heather
john:yvonne
john:daniel
john:charles
john:belinda
andrew:heather
true.
edit I tried another relation, using a generalized parent/2, but still too permissive.
relative(Pers, Re):-
ancestor(Re, Pers) ; sibling(Pers, Re) ; cousin(Pers, Re) ; uncle(Re, Pers) ; aunt(Re, Pers).
ancestor(Anc, Pers) :- parent(Anc, Pers).
ancestor(Anc, Pers) :- parent(Anc, P), ancestor(P, Pers).
Maybe cousin/2 is too permissive also. Here is the graph
I guess that heather should have only luise,helen,andrew as relatives. It's this true ?
edit given latest comment, seems that the definition could be right. I get
24 ?- setln(X,relative(heather,X)).
andrew
barry
belinda
charles
daniel
debbie
helen
louise
yvonne
true.
that is everyone is related to heather apart john.

Here's one way that works, but it will sometimes produce duplicates. Using setof will give the unique collection. I avoided the miscellaneous relations and stuck with descendent or parent.
descendent(A, B) :-
parent(B, A).
descendent(A, B) :-
parent(C, A),
descendent(C, B).
relative(A, B) :-
descendent(B, A).
relative(A, B) :-
descendent(A, B).
relative(A, B) :-
descendent(A, C),
descendent(B, C),
A \= B.
setof(A, relative(heather, A), Relatives).
Relatives = [andrew,barry,belinda,charles,daniel,debbie,helen,louise,yvonne]
If you don't have setof, you can use the findall/3 and sort/2 ISO predicates:
findall(A, relative(heather, A), R), sort(R, Relatives).
Note that the solutions presented so far assume that all of the relatives have unique names. A general case of dealing with relatives with the same first name (and possibly the same last name) you would need to track and compare lineages for differences.

Related

Family tree in Prolog

When I try to see who is brother to who and same for sister it gives me the sons and daughter, I cannot find the mistake...
father(pedro-i,fernando-i).
father(pedro-i,beatriz(1347)).
father(pedro-i,joão(1349)).
father(pedro-i,dinis(1354)).
father(pedro-i,joão_grão_mestre_da_ordem_de_avis).
mother(constança(1320),luis).
mother(constança(1320),maria(1342)).
mother(constança(1320),fernando-i).
mother(inês_de_castro,beatriz(1347)).
Any other opinion I appreciate that
ancestor(X,Y) :- mother(X,Y).
ancestor(X,Y) :- father(X,Y).
if_then_else(X,Y,male) :- father(X,Y).
if_then_else(X,Y,female) :- mother(X,Y).
son(X,Y) :- father(X,Y).
sister(X,Y) :- ancestor(Z,Y),X\==Y,if_then_else(X,Y,female).
brother(X,Y) :- ancestor(Z,Y),X\==Y,if_then_else(X,Y,male).
descendent (X,Y) :- filho(X,Y).
descendent (X,Y) :- filho(X,Z),descendent (Z,Y).
grandfather(X,Y) :- ancestor(X,Z),ancestor(Z,Y).
grandmother(X,Y) :- ancestor(X,Z),ancestor(Z,Y).
grandchildren(X,Y) :- ancestor(Z,X),ancestor(Y,Z).
uncle(X,Y) :- brother(X,Z),ancestor(Z,Y).
Your clause brother(X,Y) :- ancestor(Z,Y),X\==Y,if_then_else(X,Y,male). requires Y to have an ancestor, but X also needs to have an ancestor -- the same ancestor:
brother(X,Y) :- ancestor(Z,Y),ancestor(Z,X), X\==Y,if_then_else(X,Y,male).
You also need to eliminate the requirement at the end that X be the father of Y.
brother(X,Y) :- ancestor(Z,Y),ancestor(Z,X), X\==Y,male(X).
male needs to depend simply on the individual (you don't need to be a father to be a male.) male (fernando-i)., etc.

prolog finding first cousins in family

Trying to do a prolog question to find first cousins!
/* first person is parent of second person */
parent(a, b).
parent(b, f).
parent(a, d).
parent(f, g).
parent(a, k).
parent(f, h).
parent(k, l).
parent(f, i).
parent(k, m).
parent(l, t).
parent(b, e).
sibling(X,Y) :- parent(Z,X), parent(Z,Y), not(X=Y).
grandparent(X, Z) :-
parent(X, Y),
parent(Y, Z).
cousin1(Child1,Child2) :-
grandparent(Y1,Child1),
grandparent(Y2,Child2),
not(sibling(Child1,Child2)),
Y1=Y2 .
Seems to be working, but is there a way to stop it from returning true if the same child is input?
EDIT: final answer
cousin1(Child1,Child2) :-
parent(Y1,Child1),
parent(Y2,Child2),
sibling(Y1,Y2).
Final answer!
cousin1(Child1,Child2) :-
parent(Y1,Child1),
parent(Y2,Child2),
sibling(Y1,Y2).
Write a .not-self predicate, which returns false if the children are equal. Add that to your cousin predicate.

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

Simple prolog program returns false too early

It's been a while since I've programmed in Prolog. Today, I tried to make a simple program. It lists some facts of who belongs to the same family. If two people belong to the same family, they cannot give eachother gifts. I want to get all the people (or at least one person) to whom someone is allowed to give a gift.
family(john, jack).
family(matt, ann).
family(ann, jack).
family(jordan, michael).
family(michael, liz).
sameFamily(X, Y) :-
family(X, Y).
sameFamily(X, X) :-
false.
sameFamilySym(X, Y) :-
sameFamily(X, Y).
sameFamilySym(X, Y) :-
sameFamily(Y, X).
sameFamilyTrans(X, Z) :-
sameFamilySym(X, Y),
sameFamilySym(Y, Z).
gift(X, Y) :-
not(sameFamilyTrans(X, Y)).
Some queries if sameFamilyTrans/2 return false when they should in fact return true.
sameFamilyTrans/2 is obviously wrong. I think I need to keep a list of intermediate transitivities. Something like this:
sameFamilyTrans(X, Z, [Y|Ys]) :-
sameFamilySym(X, Y, []),
sameFamilyTrans(Y, Z, Ys).
But then I don't know how to call this.
P.S. I am using SWI-Prolog, if that makes any difference.
Yes, you were on the right track. The trick is to call the transitive closure with an empty accumulator, and check in each step whether a cycle is found (i.e., whether we have seen this member of the family before. As "false" has pointed out, the persons need to be instantiated already before going into the not, though.
So in sum, this works:
family(john, jack).
family(matt, ann).
family(ann, jack).
family(jordan, michael).
family(michael, liz).
sameFamily(X, Y) :-
family(X, Y).
sameFamilySym(X, Y) :-
sameFamily(X, Y).
sameFamilySym(X, Y) :-
sameFamily(Y, X).
sameFamilyTrans(X, Y, Acc) :-
sameFamilySym(X, Y),
not(member(Y,Acc)).
sameFamilyTrans(X, Z, Acc) :-
sameFamilySym(X, Y),
not(member(Y,Acc)),
sameFamilyTrans(Y, Z, [X|Acc]).
person(X) :- family(X, _).
person(X) :- family(_, X).
gift(X, Y) :-
person(X),
person(Y),
X \= Y,
not(sameFamilyTrans(X, Y, [])).
A bit of background: Transitive closure is not actually first-order definable (cf. https://en.wikipedia.org/wiki/Transitive_closure#In_logic_and_computational_complexity). So it can be expected that this would be a little tricky.
Negation is implemented in Prolog in a very rudimentary manner. You can essentially get a useful answer only if a negated query is sufficiently instantiated. To do this, define a relation person/1 that describes all persons you are considering. Then you can write:
gift(X,Y) :-
person(X),
person(Y),
\+ sameFamily(X,Y).
There is another issue with the definition of sameFamily/2.

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