Adding a predicate based on the relationship between people - prolog

Add the predicate related(X,Y) such that x is related to y if x and y have any ancestor in common but are not the same person
For my homework i need to add the predicate to the .PL i have to prove if 2 people are related. i have worked it out so it will say if they are related if they are brother and sister but i just cant figure out the code for cousins and so on. any help would be much appreciated.
% File FAMILY.PL% Part of a family tree expressed in Prolog
% In father/2, mother/2, and parent/2,
% first arg. is parent and second arg. is child.
father(michael,cathy).
father(michael,sharon).
father(charles_gordon,michael).
father(charles_gordon,julie).
father(charles,charles_gordon).
father(jim,melody).
father(jim,crystal).
father(elmo,jim).
father(greg,stephanie).
father(greg,danielle).
mother(melody,cathy).
mother(melody,sharon).
mother(hazel,michael).
mother(hazel,julie).
mother(eleanor,melody).
mother(eleanor,crystal).
mother(crystal,stephanie).
mother(crystal,danielle).
parent(X,Y) :- father(X,Y).
parent(X,Y) :- mother(X,Y).
sibling(X,Y) :- mother(M,X), mother(M,Y), \+ X == Y.
ancestor(X,Y) :- parent(X,Z), ancestor(Z,Y).
related(X,Y) :- sibling(X,Y), \+ X == Y.
I was trying to add something like this but no luck.
related(X,Y) :- ancestor(Z,X),ancestor(Z,Y).
so i added
related(X,Y) :- parent(Z,X),parent(P,Y),parent(Q,Z),parent(Q,P), \+ X == Y.
and that is working in all my tests. anything wrong with that? or a better way to write it?

Among other problems, your ancestor rule cannot complete, being a recursive rule and missing the base case. Try
ancestor(X,Y) :- parent(X,Y). % base case
ancestor(X,Y) :- parent(X,Z), ancestor(Z,Y). % recursive case
Note: I'm unsure about the linguistic sense of sibling/2, but should be independent of gender, I think
sibling(X,Y) :- parent(P,X), parent(P,Y), X \= Y.
And related/2 could be
related(X,Y) :- ancestor(A,X), ancestor(A,Y), X \= Y.

Complementary to ancestor = The next generation …
nextgen(X,Y) :- parent(Y,X).
nextgen(X,Y) :- parent(Y,Z), nextgen(Z,X).

In order to propose something more refined than ancestor/2 which is talked about tons of times, you can also add depth with something like ancestor/3 :
ancestor(X,Y,0) :-
% Base : X ancestor of Y and N=0 if
parent(X,Y). % X parent of Y
ancestor(X,Y,N) :-
% Recursive : X ancestor of Y if
N>0,
parent(X,Z), % X parent of Z and
M is N-1,
ancestor(Z,Y,M). % Z also ancestor of Y

Related

How to write a Prolog rule to define a predicate?

here's the assignment: In a Prolog program, predicates are defined:
mother(M,Y) — M is the mother of Y
father(F,X) — F is the father of X
Write Prolog code to implement the predicate:
cousins(X,Y) — X and Y are cousins
brother_or_sister(X,Y) — X and Y are brother or sister of each other.
My attempts:
mother(m1, nicolas).
father(f1,nicolas).
mother(m2, mark).
father(f2, mark).
father(f3, f1).
mother(m3, f1).
father(f3, f2).
mother(m3, f2).
brother_or_sister(X, Y) :-
father(f3, X),
father(f3, Y),
mother(m3, X),
mother(m3, Y).
cousins(X, Y) :-
(
mother(m1, X),
father(f1, X),
mother(m2, Y),
father(f2, Y)
)
(
(
brother_or_sister(m1, m2) ;
brother_or_sister(f1, f2)
)
;
(
brother_or_sister(f1, m2) ;
brother_or_sister(m1, f2)
).
Program output:
true
false
Although it's supposed to be true
Please help!
Brothers and sisters are siblings. Two people are siblings if they have common parentage (and half-siblings if they share just one common parent). So we can say things like:
parents(F:M,X) :- mother(M,X), father(F,X) .
sibling(X,Y) :- parents(F:M,X), parents(F:M,Y) .
Similarly, two people are cousins if they have parents who are siblings of each other. That leads to:
parent(P,X) :- father(P,X) .
parent(P,X) :- mother(P,X) .
cousin(X,Y) :- parent(Px,X), parent(Py,Y), sibling(Px,Py) .

Rule in prolog to define whether an atom (which in this case a name) is the oldest son or not?

Here's the code in prolog:
son(blake, john).
son(blake, katey).
son(toney, john).
son(toney, katey).
son(flory, john).
son(flory, katey).
son(charlie, stark).
son(charlie, shrek).
son(valenti, stark).
son(valenti, shrek).
age(blake, 13).
age(toney, 15).
age(flory, 19).
age(charlie, 48).
age(valenti, 49).
The definition of predicate and rules are:
son(X, Y) means X is the son of Y
age(M, N) means age of M is N
siblings(P, Q) means P and Q are siblings
My question is how to make a rule, let it be named oldestSon(X) that true if X is the oldestSon of a family?
When the query is oldestSon(flory) and oldestSon(valenti) it returns true or yes, and when the query is oldest(toney) it returns false or no.
I give it a try by writing these lines of code:
oldestSon(X) :-
son(X, _),
son(Y, _),
siblings(X, Y),
age(X, ageX),
age(Y, ageY),
ageX >= ageY.
But, when I try to input a query, in any of the case, when the query is oldestSon(blake). It returns like this:
false ? ;
false ? ;
false ? ;
...
How to make it only make only one output without using any external library or making another rule?
Your code is not working because:
it doesn't correctly describe the conditions for someone to be the oldest son in a family, and
it uses constants (ageX and ageY) where it should be using variables (AgeX and AgeY).
Assuming that "the oldest son in a family is the one who has no older sibling", you can code:
oldestSon(X) :-
age(X, AgeX),
not( ( siblings(X, Y),
age(Y, AgeY),
AgeY > AgeX ) ).
I am also assuming that the predicate siblings/2 is already defined as:
siblings(X, Y) :-
son(X, Z),
son(Y, Z),
X \= Y.

Creating a Niece Rule in Prolog

Using a family database, I need to create a niece rule (niece(X,Y))in swi-prolog which is defined as "X is a niece of Y if X is a daughter of Y's brother or sister." This is the given database with my already designed rules:
% family DB
grandfather(don,who).
father(don,ted).
father(don,barb).
father(don,paula).
father(greg,erin).
father(greg,austin).
father(wes,alyssa).
father(ted,jessica).
father(ted,david).
%mother(ted, john).
mother(audrey,ted).
mother(audrey,barb).
mother(audrey,paula).
mother(paula,erin).
mother(paula,austin).
mother(barb,alyssa).
married(don,audrey).
married(wes,barb).
married(greg,paula).
male(don).
male(ted).
male(wes).
male(greg).
male(austin).
male(david).
female(audrey).
female(barb).
female(paula).
female(alyssa).
female(jessica).
female(erin).
parent(X,Y) :-
father(X,Y)
; mother(X,Y).
grandfather(X,Y) :-
father(X,Z),
( father(Z,Y)
; mother(Z,Y)
).
samefather(X,Y) :-
father(F,X),
father(F,Y).
samemother(X,Y) :-
mother(M,X),
mother(M,Y).
sameparent(X,Y) :-
samefather(X,Y).
sameparent(X,Y) :-
samemother(X,Y),
not(samefather(X,Y)).
couple(X,Y) :-
married(X,Y),
married(X,Y).
Here is my initial try at the niece rule:
niece(X,Y) :-
parent(F,X),
sameparent(Y,F).
My idea is to use the sameparent rule to check if Y and F are siblings and then check if F is the parent of X. This rule currently doesn't work. I'm still struggling to understand the syntax of combining multiple rules. If anyone could help me by using this same logic, it would be greatly appreciated.
Removing unnecessary rules :
parent(don,ted).
parent(don,barb).
parent(don,paula).
parent(greg,erin).
parent(greg,austin).
parent(wes,alyssa).
parent(ted,jessica).
parent(ted,david).
parent(audrey,ted).
parent(audrey,barb).
parent(audrey,paula).
parent(paula,erin).
parent(paula,austin).
parent(barb,alyssa).
male(don).
male(ted).
male(wes).
male(greg).
male(austin).
male(david).
female(audrey).
female(barb).
female(paula).
female(alyssa).
female(jessica).
female(erin).
father(X,Y) :-
male(X),
parent(X,Y).
mother(X,Y) :-
female(X),
parent(X,Y).
sameparent(X,Y) :-
parent(A,X),
parent(A,Y).
Gives you :
niece(X,Y) :-
female(X),
parent(Z,X),
sameparent(Z,Y),
Z \= Y.
Meaning line by line :
X is a niece of Y if
X is a female and
one parent of X
has a parent in common with Y
who isn't himself/herself.
This gives you :
| ?- niece(X,Y).
X = alyssa
Y = ted;
X = alyssa
Y = paula;
X = jessica
Y = barb;
X = jessica
Y = paula;
X = erin
Y = ted;
X = erin
Y = barb
Twice because in the case of your database every brothers/sisters share the same two parents.
For example, if A is the daughter of B and B is the half-brother of C, A is still the niece of C.
If you want that rule to be false and A to be the niece of C only if B and C are brothers/sisters (and not only half), you can change the niece rule to the following :
sameFather(X,Y) :-
father(A,X),
father(A,Y).
sameMother(X,Y) :-
mother(A,X),
mother(A,Y).
niece(X,Y) :-
female(X),
parent(Z,X),
sameFather(Z,Y),
sameMother(Z,Y),
Z \= Y.
Then you won't get duplicate results whith niece(X,Y).
For me it worked well.
sameparent(X,Y):- parent(A,X),parent(A,Y).
niece(X,Y) :- female(X),parent(Z,X),sameparent(Z,Y),Z=Y.

Prolog ancestor clause using lists

I am struggling to get my head around this basic Prolog concept.
I understand that the basic clause for determining the ancestor of a person is as follows:
ancestor(X, Y) :- parent(X, Y).
ancestor(X, Y) :- parent(X, Z), ancestor(Z, Y).
However, I am trying to get my head around how this works for a prolog program that implements lists to determine children of a parent, i.e:
parent_of(simon, [matthew, andrea, joanne]).
To determine wether or not somebody is the father of somebody, I am using this which works perfectly:
father_of(X, Y) :- parent_of(X, List), my_member(Y, List), male(X).
However, I cant seem to figure out how to get this to work for the ancestor clause above.
member/2 it's the simpler relation between an element and a list:
ancestor_of(X, Y) :- parent_of(X, Ys), member(Y, Ys).
ancestor_of(X, Y) :- parent_of(X, Zs), member(Z, Zs), ancestor_of(Z, Y).
I've added a relation to test the transitive rule
parent_of(simon, [matthew, andrea, joanne]).
parent_of(andrea, [bill, joan]).
yields
?- ancestor_of(andrea,A).
A = bill ;
A = joan ;
false.
?- ancestor_of(simon,A).
A = matthew ;
A = andrea ;
A = joanne ;
A = bill ;
A = joan ;
false.
?- ancestor_of(X,bill).
X = andrea ;
X = simon ;
false.

Prolog Family Tree query issues

% facts
mother(john, dana).
father(john, david).
mother(chelsea, dana).
father(chelsea, david).
mother(jared, dana).
father(jared, david).
% queries
father(X,Y) :- father(X,Y), write(Y).
mother(X,Y) :- mother(X,Y), write(Y).
parent(X,Y) :- father(X,Y);mother(X,Y).
sibling(X,Y) :- parent(X,Z), parent(Y,Z), write(Y).
I am having trouble getting these queries to work. when I type in the father command, it will tell me yes or no correctly, but won't do the write command (same with mother). "parent" doesn't work at all for me (therefor sibling doesn't either). Also, if I type in sibling(X,Y). I need to get all siblings...for example, sibling(john, chelsea). I need to output all the possible siblings (jared as well). Let me know where I am going wrong, I really don't see an issue with my logic here. Thanks!
Basically you can remove your mother and father predicates that are not facts. They are infinite loops. Since parent use them and sibling use parent, all your predicates are infinite loops.
To see what happens, you can do that :
?- trace, father(john, X).
and observe how prolog handles the query. You'll soon observe than to resolve father, he needs to solve father, and that to solve father, he needs to solve father, and that it never stops...
When the two problematic are removed, I obtain a correct behaviour :
?- father(john, X).
X = david.
?- parent(john, X).
X = david ;
X = dana.
?- sibling(john, X).
john
X = john ;
chelsea
X = chelsea ;
jared
X = jared ;
john
X = john ;
chelsea
X = chelsea ;
jared
X = jared.
Now, to make your sibling predicate better, you could say that someone is not its own sibling and that if you have one common parent it's enough (it will remove the duplicates) :
sibling(X,Y) :- father(Y,Z), father(X, Z), X =\= Y.

Resources