Family tree in Prolog - 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.

Related

Error in Family Tree using Prolog

I have some issues in my family tree. As required, I need to create predicates on father, mother, son, daughter, grandfather, sibling, aunt, uncle, cousin, spouse, parent_of based on the facts of Male, Female, parent_of.
male(jerry).
male(stuart).
male(warren).
male(peter).
female(kather).
female(maryalice).
female(ann).
brother(jerry,stuart).
brother(jerry,kather).
brother(peter, warren).
sister(ann, maryalice).
sister(kather,jerry).
parent_of(warren,jerry).
parent_of(maryalice,jerry).
father(X,Y) :- male(X), parent_of(X,Y).
mother(X,Y) :- female(X), parent_of(X,Y).
son(X,Y) :- male(X), parent_of(Y,X).
daughter(X,Y) :- female(X), parent_of(Y,X).
grandfather(X,Y) :- father(X,P), parent_of(P,Y).
sibling(X,Y):- parent_of(P,X), parent_of(P,Y), X\=Y.
aunt(X,Y) :- sister(X,P), parent_of(P,Y).
uncle(X,Y) :- brother(X,P), parent_of(P,Y).
cousin(X,Y):- sibling(P,Q), parent_of(P,X), parent_of(Q,Y).
spouse(X,Y) :- parent_of(X,P), parent_of(Y,P).
parent_of(X,Y) :- male(X), father(X,Y); female(X), mother(X,Y).
The parent_of predicate gives me an error. Clasues of parent_of/2 are not together in the source file. When I ignore the error and run a query ?- sibling(jerry, stuart), it gives me an error out of local stack. Anyone know how to solve this problem. Your help will be appreicated. Thanks.
Problem 1
The parent_of predicate gives me an error. Clasues of parent_of/2 are not together in the source file.
Simply place definitions of the predicate right next to eachother
Change
parent_of(warren,jerry).
parent_of(maryalice,jerry).
...
spouse(X,Y) :- parent_of(X,P), parent_of(Y,P).
parent_of(X,Y) :- male(X), father(X,Y); female(X), mother(X,Y).
to
parent_of(warren,jerry).
parent_of(maryalice,jerry).
parent_of(X,Y) :- male(X), father(X,Y); female(X), mother(X,Y).
...
spouse(X,Y) :- parent_of(X,P), parent_of(Y,P).
Problem 2
?- sibling(jerry, stuart), it gives me an error out of local stack.
You have a circular logic error. You define parent_of\2 in terms of father\2 and father\2 in terms of parent_of\2. This will cause each to circle off into Prolog never-never-land.

why does this not display the right answer

I have these facts and rules :
male(roelof).
male(mans).
male(ronald).
male(jan).
female(chantal).
female(marie).
female(gerda).
female(dagmar).
female(denise).
female(kimberly).
parent(mans,gerda).
parent(mans,roelof).
parent(marie,gerda).
parent(marie,roelof).
parent(dagmar,denise).
parent(dagmar,kimberly).
parent(ronald,denise).
parent(ronald,kimberly).
parent(chantal,tamara).
parent(roelof,tamara).
parent(jan,chantal).
parent(jan,dagmar).
father_child(Father, Child) :-
parent(Father, Child),
male(Father).
mother_child(Mother, Child) :-
parent(Mother, Child),
female(Mother).
child_father_mother(Child, Father, Mother) :-
father_child(Father, Child),
mother-child(Mother, Child).
same_father(Child, Sibling) :-
father_child(Father, Child),
father_child(Father, Sibling).
same_mother(Child, Sibling) :-
mother_child(Mother, Child),
mother_child(Mother, Sibling).
siblings(Child, Sibling) :-
same_father(Child, Sibling),
Child \= Sibling.
siblings(Child, Sibling) :-
same_mother(Child, Sibling),
Child \= Sibling.
display_siblings(X,Y) :-
setof(X-Y, (siblings(X,Y), \+X=Y), Sibs),
member((X-Y,Y), Sibs),
\+ (Y#<X, member((Y,X), Sibs)).
But when I do display_siblings I expected to see roelof-gerda.
But the output is only x=roelof
What did I do wrong.
Im a beginner at Prolog and try to understand how this works.
Roelof
Edit 1: Could this be a solution: How can I prevent duplicates in prolog
Edit 2: I will do but I still do not understand why 'setof(X-Y, (siblings(X,Y), X #< Y), Sibs),write(Sibs).' is wrong. It works in both cases display_'siblings(gerda,X)' and 'display_siblings(X,Y)'
Most of your problem lies in your display_siblings predicate:
display_siblings(X,Y) :-
setof(X-Y, (siblings(X,Y), \+X=Y), Sibs),
member((X-Y,Y), Sibs),
\+ (Y#<X, member((Y,X), Sibs)).
In the second line, the \+X=Y is superfluous since siblings already enforces that they are different. So that can be:
setof(X-Y, siblings(X,Y), Sibs),
The next line is querying whether (X-Y,Y) is a member of Sibs. However, Sibs consists of X-Y terms which will never match an (X-Y,Y) term. So this call to member will always fail. It should probably be:
member(X-Y, Sibs),
And then the last line is overly complex if all you want to do is eliminate symmetrical duplicates. You can simply use X #< Y and for efficiency, make this part of the setof check:
display_siblings(Sibs) :-
setof(X-Y, (siblings(X,Y), X #< Y), Sibs).
This will yield:
?- display_siblings(Sibs).
Sibs = [chantal-dagmar, denise-kimberly, gerda-roelof].
If you want to select all of the siblings for a given person and still avoid the symmetry redundancies, you may need to process out those redundancies after the setof:
display_siblings(X, Sibs) :-
setof(A-B, ((X = A ; X = B), siblings(A,B)), SibPairs),
pack(SibPairs, Sibs).
pack([X-Y|T], Sibs) :-
pack(T, SibList),
( member(Y-X, SibList)
-> SibList = Sibs
; Sibs = [X-Y|SibList]
).
pack([], []).
?- display_siblings(gerda, Sibs).
Sibs = [roelof-gerda].

how to avoid duplicates here?

I have these predicates:
male(roelof).
male(mans).
male(ronald).
male(jan).
female(chantal).
female(marie).
female(gerda).
female(dagmar).
female(denise).
female(kimberly).
parent(mans,gerda).
parent(mans,roelof).
parent(marie,gerda).
parent(marie,roelof).
parent(dagmar,denise).
parent(dagmar,kimberly).
parent(ronald,denise).
parent(ronald,kimberly).
parent(chantal,tamara).
parent(roelof,tamara).
parent(jan,chantal).
parent(jan,dagmar).
father_child(Father, Child) :-
parent(Father, Child),
male(Father).
mother_child(Mother, Child) :-
parent(Mother, Child),
female(Mother).
child_father_mother(Child, Father, Mother) :-
father_child(Father, Child),
mother_child(Mother, Child).
same_father(Child, Sibling) :-
father_child(Father, Child),
father_child(Father, Sibling).
same_mother(Child, Sibling) :-
mother_child(Mother, Child),
mother_child(Mother, Sibling).
siblings(X,Y) :-
( same_father(X, Y),
X \= Y
; same_mother(X, Y),
\+ same_father(X, Y)
).
display_siblings(Person) :-
findall(Person-Y, siblings(Person,Y), Sibs),
display_the_siblings(Sibs).
display_the_siblings([]) :-
write('Er zijn geen zussen/broers bekend').
display_the_siblings([X-Y]) :-
write('The enigste broer of zuster is '),
write(Y).
display_the_siblings([XY0,XY1|XYs2]) :-
XYs0=[XY0,XY1|XYs2],
write('Alle zusterparen zijn : \n '),
forall(( member(X - Y,XYs0)
),( format('~w en ~w. \n',[X,Y])
)).
It works fine but if you do display_siblings(X) you will see duplicates like this
Person 1 - Person 2
Person 2 - Person 1
How can I change this so the duplicates will not show up.
I know I can change findall to setof but then I see no output at all.
Roelof
Edit 1: #< works but it also means that display(kimberly) fails because Kimberly is further on the alphabet then denise. Can I not use the same trick as this topic : How can I prevent duplicates in prolog.
the simplest way should be to break the symmetry, for instance
...
findall(Person-Y, (siblings(Person,Y), Person #< Y), Sibs),
...

How to find blood relatives only in 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.

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