SWI-Prolog family tree parent_of/2 - prolog

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).
I was given the facts above and I need to define a rule using the predicate parent_of. Yes, it is the same predicate as the above facts defined by parent_of.
Assume I have a sibling(X, Y) rule that will return all the correct sibling pairs.
I write my parent_of(X, Y) rule as parent_of(X, Y) :- parent_of(X, A), sibling(A, Y).
However, this implementation will lead me to an infinity loop.
Is there a way to define the rule parent_of(X, Y) such that it will return
(warren, jerry),
(warren, stuart),
(warren, kather),
(maryalice, jerry),
(maryalice, stuart),
(maryalice, kather)
I also tried
parent_of(X, Y) :-
parent_of(X, jerry),
brother(jerry, Y).
I can get the correct answers by this way but it ended up in "Out of local stack" error. Besides that, I don't think the rule is fine as I hard coded it.
I have seen suggestions like change the rule name to something else such as another_parent_of(X, Y). It does solve the problem, but it is a requirement for me to define it using the same predicate.
Any help is greatly appreciated.
EDITED
The intention of this exercise is to write rules such that you can complete this family tree, though only minimal facts are given. As you can see, it only states that Warren is the father of Jerry, and from brother and sister facts, we know Jerry is the brother of Stuart and Kather. So I will have a rule, parent_of(X, Y) to deduce Warren is also the father of Stuart and Kather, though this was not stated in the facts above.
The main concern is how can I write my parent_of(X, Y) rule to avoid it getting into infinite loop.

I do not understand why you need to use parent_of in the definition of sibling. Why you no just write:
sibling(X, Y) :-
parent_of(Parent, X),
parent_of(Parent, Y).
I also don't understand the logic of the facts that you are given. You have male and female, but you also have brother and sister; why not define brother and sister in terms of "brother is a male sibling" and "sister is a female sibling"? I already show above how to define "siblings have same parent".
Anyway, this is really old tired question, it is very amazing how many times "Prolog family tree" has been regurgitated.
the cow the old cow she is dead
it sleeps well the horned head
we poor lads tis our turn now
to hear such tunes as killed the cow

I cannot see a way to directly solve your problem. But if your Prolog offers tabling, here is an easy way:
:- use_module(library(tabling)).
...
:- table parent_of/2.
parent_of(warren,jerry).
parent_of(maryalice,jerry).
parent_of(X, Y) :- parent_of(X, A), sibling(A, Y).
...
?- parent_of(X,Y).
X = warren,
Y = stuart ;
X = warren,
Y = jerry ;
X = warren,
Y = kather ;
X = maryalice,
Y = stuart ;
X = maryalice,
Y = jerry ;
X = maryalice,
Y = kather.

Related

Sibling relation that just doesn't seem to cover all cases

I've been tasked with creating a sister relation in prolog, among other basic relations. The issue is that my assertions dont cover all angles for reasons that I just dont get. Currently I have
female(X)).
male(X).
parent(X,Y).
sibling(X,Y) :- female(X), parent(Z,X), parent(Z,Y).
female(mom).
female(mary).
male(tim).
parent(mom,tim).
parent(mom,mary).
With that, my code works fine when testing it with something like sister(mary,tim) (equals true) or sister(father,tim) (equals false) but i'm currently having issues with it defining sister(mom,tim) as true. While that may very well be a true statement somewhere on this world of ours, it's not something I feel is correct given the assignment im working on.
Do not start your programs with things like this:
female(X)).
male(X).
parent(X,Y).
You may think that these are "declarations" of the relations you will be using, but they are not. They are definitions of rules saying "anyone is female", "anyone is male", and "any object whatsoever is a parent of any object whatsoever". Delete these.
Then, let's decompose your problem a bit. A sister is a female sibling. The sibling relation is useful in itself, so let's define that first without worrying about sisters in particular:
siblings(X, Y) :-
parent_of(Parent, X),
parent_of(Parent, Y).
parent_of(mom, tim).
parent_of(mom, mary).
Observe how I renamed your parent relation to parent_of. This is not a symmetric relation, and for a term like parent(X, Y) we might not know which argument is the parent and which one is the child. Naming it parent_of is more suggestive: parent_of(X, Y) means (reading left to right): X is the parent of Y.
We can now test this:
?- siblings(X, Y).
X = Y, Y = tim ;
X = tim,
Y = mary ;
X = mary,
Y = tim ;
X = Y, Y = mary.
Note that this is not correct yet! It says that Tim is his own sibling, and that Mary is her own sibling. You need to fix that. I'll keep using it for the moment.
Now, as we said, a sister is a female sibling. That's easy to express now:
sister_of(Sister, Sibling) :-
female(Sister),
siblings(Sister, Sibling).
female(mom).
female(mary).
male(tim).
Sister is the sister of some Sibling if Sister is female and they are siblings. That is all. Note that these variable names are more informative than X and Y!
Let's test:
?- sister_of(Sister, Sibling).
Sister = mary,
Sibling = tim ;
Sister = Sibling, Sibling = mary.
Only Mary is anybody's sister, which is what we want. She is also her own sister, which we do not want, but that is the same problem noted above in the definition of siblings/2.

Mutually referential Prolog rules in family tree

I've seen various implementations of family trees in Prolog, but I haven't found one that does what I would like to do, which is to define child and parent by referring to each other.
I want to do this because sometimes I have a fact that someone is a child of someone, at other times I have the fact that someone is the parent of someone. From either of these kinds of facts, I'd like to be able to ask who are parents and who are children.
My attempt at coding this is :-
parent(mary, fred).
child(john, peter).
child(paul, peter).
parent(P, C).
parent(P, C) :- child(C, P).
child (C, P).
child(C, P) :- parent(P, C).
This seems to work ok except that it will continue to give me the same results duplicated over and over. Eg :-
[3] ?- parent(peter, X).
true ;
X = john ;
X = paul ;
true ;
X = john ;
X = paul ;
true
Is there a way I can get it to stop after it has given me the full set of results once ?
More generally, is this kind of definition a weird thing to want to do (because of the mutual recursion) ? I want to be able to have facts of either parent or child, as reported, but also to infer the "opposite" relationship from these.
Thanks !
The issue with your program is that you are merging predicates.
parent/2 and child/2 are facts, you should not name a rule like a fact that is already defined in your program.
Rename the rules and all will work. Also, the base clause in your rules should add a condition, that match the fact, something like this:
parent(mary, fred).
child(john, peter).
child(paul, peter).
isparent(P, C):- parent(P, C).
isparent(P, C):- child(C, P).
ischild(C, P):- child(C, P).
ischild(C, P) :- parent(P, C).
Now the query:
?- isparent(peter, X).
X = john
X = paul
Also, don't use the complement rule in your condition, that's not necessary and will avoid you the recursion

Knowledge Based System of a family tree in SWI-Prolog

I have these family facts:
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).
And using the base predicates male, female and parent_of I want to define father, mother, son, daughter, sibling, spouse and parent_of.
This is what I have done:
father(P,C) :- male(P), parent_of(P,C).
mother(P,C) :- female(P), parent_of(P,C).
son(C,P) :- male(C), parent_of(P,C).
daughter(C,P) :- female(C), parent_of(P,C).
sibling(C,OC) :- parent_of(P,C), parent_of(P,OC).
spouse(H,W) :- parent_of(H,C), parent_of(W,C).
parent_of(P,C) :-
( ( sister(C,OC) ; sister(OC,C))
; ( brother(C,OC) ; brother(OC,C))).
By querying parent_of(P,C) it should return that warren is a parent of jerry,stuart and kather and that maryalice is a parent of jerry, stuart and kather also. But this is what I get:
?- parent_of(X,Y).
X = warren,
Y = jerry ;
X = maryalice,
Y = jerry ;
Y = ann ;
Y = kather ;
Y = maryalice ;
Y = jerry ;
Y = jerry ;
Y = jerry ;
Y = peter ;
Y = stuart ;
Y = kather ;
Y = warren.
It does not make any sense! Any help is much appreciated!
Kind regards,
Richard
I fully agree with the answer by danielp, but I hope to attract your attention on another problem, that maybe has gone unnoticed: why X appears only on the first two results ? That's because your last predicate is effectively
parent_of(P,C) :- sister(C,OC).
parent_of(P,C) :- sister(OC,C).
parent_of(P,C) :- brother(C,OC).
parent_of(P,C) :- brother(OC,C).
and P is never bound by such rules. So, you're right
It does not make any sense!
You mixed up facts and predicates which is basically possible but not a recommended approach (at least in this case).
You wrote that you want to define male, female and parent_of as basic facts but in your first source code above you define also sister and brother. That you can easily define by a rule like "S is a sister of X when S is female and has a parent C and X has the same parent C and is not equal to S".
There is no need for re-defining parent_of by sister and brother.
Now let's have a look at the result of your query:
The first two results are the facts you defined (warren and jerry, marryalice and jerry).
The next results are produced by your predicate. Since you did not specify anything about the variable P it remains unbound and is not printed in the result (thus only Y = ... is shown).
And the variable C in the predicate fulfills one of the four conditions you specified (C is a sister of somebody (ann, kather), somebody is a sister of C (maryalice,jerry), C is a brother of somebody (two times jerry, peter) or somebody is a brother of C (stuart, kather, warren).
Summary: Replace the definitions of brother and sister by rules and drop the parent_of predicate.

Prolog - Chain rule for Step Siblings

I am a newbie to Prolog, and have a question regarding programming a "chain rule" for step-siblings that share a "common parent".
In my program, I am assuming that the existence of the parent(X,Y) fact that asserts that X is a parent of Y.
I need a rule chain(X,Y,L): if X is an ancestor of Y, then L is the list containing X, Y and all ancestors of Y who are also descendants of X, listed in descending order of age (oldest first). In other words, my list should contain all the people that link a person with an ancestor.
Eg: If chain(peter,mary,[peter,paul,sue,mary]), then peter is the parent of paul, paul is the parent of sue, and sue is the parent of mary.
Note: I am familiar with the stepSibling(a,b) relationship where their relationship is qualified via their parents partner(X,Y); where siblings a and b are children of their respective parents via the relationship child(a,X) and child(b,Y). Hence; I am only confused with the relationship where both stepsiblings share a common parent. ie. A child relationship that may look like this: child(a,X) and child(b,X).
This is kind of an interesting twist on the usual genealogy problems we discuss in early Prolog courses. Let's consider a simplification first, ancestor(X,Y) is true if X is an ancestor of Y.
So you have a predicate parent(X,Y) which says X is a parent of Y. You can write ancestor/2 like this:
% base case: your parent is an ancestor
ancestor(X, Y) :- parent(X, Y).
ancestor(X, Z) :- parent(X, Y), ancestor(Y, Z).
With a sample database like this it should work fine:
parent(peter, paul).
parent(paul, sue).
parent(sue, mary).
This will work for a query like ancestor(peter, mary), which is close to what you want. The next step would be to retain the chain, which would look something like this:
chain(X, Y, [X,Y]) :- parent(X, Y).
chain(X, Z, [X|Chain]) :- parent(X, Y), chain(Y, Z, Chain).
This appears to work:
?- chain(peter, mary, X).
X = [peter, paul, sue, mary] ;
false.
I worry though, because your question mentions step siblings and that the chain should include other people. Is that just chaff or do you have additional requirements? If so, they're not reflected in your example, so I may need you to augment your question with additional details.

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