I am trying to query who has a brother that is a grandad but cannot figure it out, I know its simple but its confusing me a little.
I have some basic facts here:
parent(queenmother,elisabeth). parent(elisabeth,charles).
parent(elisabeth,andrew). parent(elisabeth,anne).
parent(elisabeth,edward). parent(diana,william).
parent(diana,harry). parent(sarah,beatrice).
parent(anne,peter). parent(anne,zara).
parent(george,elisabeth). parent(philip,charles).
parent(philip,andrew). parent(philip,edward)...
I have some predicates that determins male from female:
the_royal_males(charles). the_royal_males(andrew).
the_royal_males(edward). the_royal_males(william).
the_royal_males(philip). the_royal_males(phillip).
the_royal_males(georgejun). the_royal_males(harry).
and to determin ancestors, brothers, siblings.
ancestor(X,Y):- parent(X,Y).
ancestor(X,Y):- parent(X,Z), ancestor(Z,Y).
sibling(X,Y):- parent(Z,X), parent(Z,Y), X \= Y.
brother(X,Y):- sibling(X,Y), sibling(Y,X), the_royal_males(Y), X \= Y.
The queries i've been trying such as
brother(X,_), ancestor(X,_)
Isn't giving the desired results. Any help/guidance would be great. Thanks!
Related
I am currently writing a PROLOG program that represents Family Relationships.
Right now I have implemented the following functions that work.
male(X). Returns true if X is male.
female(X). Returns true if X is female.
mother_of(X,Y). Returns true if X is the mother of Y.
father_of(X,Y). Returns true if X is the father of Y.
sister_of(X,Y). Returns true if X is the sister of Y.
brother_of(X,Y). Returns true if X is the brother of Y.
Now I want to implement a function to check if someone is a single child/has no sister/brother.
I have tried the following functions but none of them is working:
single_child(X) :- (\+ sister_of(X,Y)),(\+ brother_of(X,Y)).
single_child(X) :- not(sister_of(X,Y)), not(brother_of(X,Y)).
single_child(X) :- \+ (sister_of(X,Y),\+ brother_of(X,Y)).
single_child(X) :- not(sister_of(X,Y),brother_of(X,Y)).
Does anyone know how I could implement such a function correctly?
Kind Regards
David J.
I found a Solution myself:
single_child(X) :- \+ has_sibling(X),(parent(P,X)).
parent(X,Y) :- father_of(X,Y);mother_of(X,Y).
sibling(X,Y):- parent(Z,X), parent(Z,Y), X\=Y.
has_sibling(X) :- sibling(X,_).
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.
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.
I am working on creating a family tree in prolog. Where I am running into trouble is when I call on sister or brother. The results I get are correct, where julie is the sister of mike, julie is the sister of amanda, amanda is the sister of mike and amanda is the sister of julie. But what happens rather than ending there, if i keep hitting the 'n' key it will loop back through the results again. Why is this happening?
parent(pete,mike).
parent(pete,julie).
parent(pete,amanda).
parent(mary,mike).
parent(mary,julie).
parent(mary,amanda).
female(mary).
female(julie).
female(amanda).
male(mike).
male(pete).
mother(X,Y):-
parent(X,Y),
female(X).
father(X,Y):-
parent(X,Y),
male(X).
sibling(X,Y):-
parent(Z,X),
parent(Z,Y),
X\=Y.
sister(X,Y):-
sibling(X,Y),
female(X).
brother(X,Y):-
sibling(X,Y),
male(X).
Every pair of siblings will have both the same father and the same mother (in the more conservative societies, at least, and in your program at the moment). This is where you get the double answers from. You could maybe say that siblings always share both parents?
As stated, you get double answers because you're checking if they have the same parent, and they have two of those. Moreover, you're getting even more solutions because e.g. mike is sibling of amanda, but also amanda is sibling of mike, and you do nothing to prevent both solutions to appear.
So instead of:
sibling(X, Y):-
parent(Z, X),
parent(Z, Y),
X\=Y.
to solve problem of two parents, you could say they always share both parents:
sibling(X, Y):-
mother(Z, X),
mother(Z, Y),
father(W, X),
father(W, Y),
X\=Y.
You could stop second problem (X=mike, Y=amanda; X=amanda, Y=mike) by introducing #<:
sibling(X, Y):-
mother(Z, X),
mother(Z, Y),
father(W, X),
father(W, Y),
X#<Y.
This way, only one set of solutions is appearing, but you have to be careful with it, as it might not get you want you want, depending on what you want to achieve (X=julie, Y=amanda would not be true in this case).
Depending on the need, perhaps more elegant and general solution (not requiring both parents to be same) would be to use setof (http://www.swi-prolog.org/pldoc/doc_for?object=setof/3) with your original sibling clause, but you would rework your brother/sister clauses, e.g.:
sibling(X, Y):-
parent(Z, X),
parent(Z, Y),
X\=Y.
sister(X,Y,L):-
female(X),
setof([X, Y], (sibling(X, Y)), L).
brother(X,Y,L):-
male(X),
setof([X, Y], (sibling(X, Y)), L).
This would get you a list of unique pairs in list L, e.g. for sister(X, Y, L) you get:
X = julie
L = [[julie, amanda], [julie, mike]]
X = amanda
L = [[amanda, julie], [amanda, mike]]
Play with it a little to get exactly what you need.
% 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.