1. A parent who has exactly two children. In other word, If 'Rand' is a son of 'X', 'Rand' must be either 'A' or 'B'
I have tried this:
parent2Children(Prt) :-
son(A, Prt),
son(B, Prt),
A \= B,
(son(Z, Prt) -> (Z == A;Z == B)).
but doesn't give the expected result.
2. A child who is the second child of any family
The idea is if he has an older sibling called 'X', then 'X' doesn't have any older siblings. But I am confused to convert it to prolog
Let this rule called:
secondChild(X). /*Which will return true/yes if X is a second child of any family. Else, will return false/no*/
3. A man who has children less than 2 (either have no/0 child or have only one child)
less2Child(Prt) :-
((son(A, Prt), son(Z, Prt)) -> (A == Z));
/* ... or he has no child (I am confused how to convert it to prolog)*/
Here are some rules that can be used:
male(X). /*X is a male*/
female(X). /*X is a emale*/
age(X, AgeX). /*AgeX is age of X*/
married(X, Y). /*X is married with Y, vice versa*/
son(X, Y). /*X is a son of Y (applied on both male or female)*/
siblings(X, Y). /*X is one of a sibling of Y, vice versa*/
elder(X,Y) /*X is older sibling of Y (applied on both male or female)*/
husband(X,Y) /*X is a male, and X is married with Y*/
eldest1(X) /*X is the oldest child in any family)*/
youngest1(X) /*X is the youngest child in any family*/
Your solution for the first part is close. The problem is that while Prolog has a -> built-in predicate, it doesn't do what you want. In fact, -> alone has a very specific and very rarely useful meaning. It is mostly useful in a combination like (Condition -> ThenPart ; ElsePart) which is composed of -> and ; but different from both.
What you're trying to say is something like "if Z is a child of the parent, then Z is the same as A or B". More precisely, this is "any child of the parent must be equal to A or B". Here the word "any" is a quantifier: for all children Z something should hold. -> is not a quantifier. Standard Prolog doesn't have quantifiers, but there is a widely supported forall predicate that can help:
two_children_2(Parent) :-
son(A, Parent),
son(B, Parent),
A \= B,
forall(son(C, Parent), (C = A ; C = B)).
Alternatively, you could turn the statement around and say "there is no child Z that is different from A and B":
two_children(Parent) :-
son(A, Parent),
son(B, Parent),
A \= B,
\+ ( son(C, Parent), C \= A, C \= B ).
The answer to part 2 depends on how exactly the database is to be interpreted. I think the only simple way to implement this if the "elder" predicate is interpreted as "older than and neighboring" sibling. For example, if Bart, Lisa, and Maggie are siblings, and Bart is older than Lisa, who is older than Maggie, then the database should be:
elder(bart, lisa).
elder(lisa, maggie).
But the database should not contain a transitive fact
elder(bart, maggie).
In this case, "second oldest child" would be "there is a next older child who is the oldest in the family".
For the third question, define two auxiliary predicates no_children and exactly_one_child describing people who have no children or exactly one child. Less than two children then just means one or the other:
less_than_two_children(Parent) :-
no_children(Parent).
less_than_two_children(Parent) :-
exactly_one_child(Parent).
Related
I have the provided definition of descendent as below:
"a person who is in direct line to an ancestor. Eg: child,
grandchild, great-grandchild, and forever"
and also other rules like:
...
childof(X, Y).
parent(X, Y).
grandchild(X, Y).
ancestor(X, Y).
...
So can I just simply write a rule as below,
descendant(X, Y):- ancestorof(Y, X).
or is there a better way of doing it?
This is a problem of tree traversal or graph traversal.
I would generalize an ancestor_of/3 predicate:
ancestor(Ancestor,Generations,Descendant)
Assuming you have, say, a set of facts like
parents( mother, father, child ).
On can say that a parent is either the mother or father of a child:
% P is a parent of C if P is either the mother or father of C.
parent(P,C) :- parents(P,_,C).
parent(P,C) :- parents(_,P,C).
And given the above, the solution might look like this:
ancestor(Ancestor, Generations, Descendant) :-
ancestor( Ancestor, 0, Generations, Descendant )
.
ancestor( A, N, G, D ) :- % A is an ancestor of D...
parent(A,D), % * if A is the immediate parent of D
G is N+1 % * in which case, tick the generation count
. % Easy!
ancestor( A, N, G, D ) :- % otherwise, A is an ancestor of D...
parent(A,X), % * if A is the immediate parent of somebody
X \= D, % * other than D
N1 is N+1, % * [ tick the generation count]
ancestor( X, N1, G, D ) % and that somebody is the ancestor of D
. % Also easy!
That allows us to say things like:
grandparent(A,C) :- ancestor(A,2,C).
great-grandparent(A,C) :- ancestor(A,3,C).
etc.
This will work for biological parentage, but if you are allowing
non-biological parentage (e.g., step-parents and the like, then
"I'm my own grandpa" is a possibility, and you will need to carry
a list of visited nodes around so you can detect any cycles in the
graph.
Try to figure out how to determine different degrees of kinship from this
(what does a second cousin thrice removed look like?). You'll need to determine sibling status for starters.
I have recently discovered the language Prolog and have been doing exercises on its basics. I am currently creating a database on animal classes like mammals, birds and reptiles, I want to expand the database by having a size comparison within the animals but not sure how.
Here is my database.
warm_blooded(bat).
warm_blooded(penguin).
cold_blooded(crocodile).
has_fur(bat).
has_feathers(penguin).
has_scales(crocodile).
gives_birth_live(bat).
lays_eggs(penguin).
lays_eggs(crocodile).
produces_milk(bat).
has_lungs(crocodile).
has_lungs(bat).
has_lungs(penguin).
%% if the being belongs to the mammalai class ,mammalia being the scientific word for mammal
mammalia(X) :-
warm_blooded(X),
produces_milk(X),
(
has_fur(X)
;
gives_birth_live(X)
),
format('~w ~s mammal ~n', [X, "is a"]).
%% if the being belongs to the aves class aves being the scientific word for bird
aves(X) :-
warm_blooded(X),
has_feathers(X),
lays_eggs(X),
has_lungs(X),
format('~w ~s bird ~n', [X, "is a"]).
%% if the being belongs to the reptillia class(reptillia being the scientific word for reptile
reptillia(X) :-
cold_blooded(X),
lays_eggs(X),
has_scales(X),
has_lungs(X),
format('~w ~s reptile ~n', [X, "is a"]).
I've tried adding sizes within the parameters but I keep getting compilation errors. I want to have an output wherein the user is able to determine which animal is bigger when compared with each other.
A simple an effective way is to just associate a size fact with each animal.
size(bat,1).
size(penguin,2).
size(crocodile,3).
Then add one predicate with two clauses to chose the larger of the two animals.
larger(A,B,A) :-
size(A,S1),
size(B,S2),
S1 > S2.
larger(A,B,B) :-
size(A,S1),
size(B,S2),
S2 >= S1.
Examples:
?- larger(penguin,crocodile,X).
X = crocodile.
?- larger(penguin,bat,X).
X = penguin ;
false.
?- larger(bat,bat,X).
X = bat.
Note that for examples where the the second animal is smaller, it tries the first clause and succeeds, but then has a choice point and so tries the second clause and fails. This is the pure solution.
If you want to use a cut to avoid the choice point, which is impure, you can do the following
larger_2(A,B,A) :-
size(A,S1),
size(B,S2),
S1 > S2,
!.
larger_2(A,B,B) :-
size(A,S1),
size(B,S2),
S2 >= S1,
!.
Examples:
?- larger_2(penguin,crocodile,X).
X = crocodile.
?- larger_2(penguin,bat,X).
X = penguin.
?- larger_2(bat,bat,X).
X = bat.
Another way as noted by Daniel Lyons is to use ->/2
larger_3(A,B,Larger) :-
size(A,SA),
size(B,SB),
(
SA > SB
->
Larger = A
;
Larger = B
).
This variation is not one operator of just ->/2 but a combination of both ->/2 and ;2.
This also does not leave a choice point and is impure because it too uses a cut (!). Using listing/1 we can see the implementation in Prolog.
?- listing('->'/2).
:- meta_predicate 0->0.
system:A->B :-
call(( A
-> B
)).
true.
?- listing(;/2).
:- meta_predicate 0;0.
system:A:B;A:C :- !,
call(A:(B;C)).
system:A:B;C:D :-
call(A:(B;C:D)).
true.
Notice the cut !.
How the two operators work together is noted in the SWI-Prolog documentation.
The combination ;/2 and ->/2 acts as if defined as:
If -> Then; _Else :- If, !, Then.
If -> _Then; Else :- !, Else.
If -> Then :- If, !, Then.
One other point to note about the use of ->/2 with ;/2 is that the syntactic layout among many Prolog programmers is to use () with the combination and offset the operators ->/2 and ;2 so that the ; stands out.
(
% condition
->
% true
;
% false
)
When a ; is used as an OR operator and not offset the ; is often overlooked in doing a quick scan of the source code as it is seen as a comma , instead of a ;.
Also note the absence of . or , after
SA > SB
and
Larger = A
and
Larger = B
but at the end an operator is needed,
).
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.
sisters(mary,catherine).
sisters(catherine,mary).
brothers(john,simone).
brothers(simone,john).
marriage(john,mary,2010).
marriage(mary,john,2010).
marriage(kate,simone,2009).
marriage(simone,kate,2009).
marriage(catherine,josh,2011).
marriage(josh,catherine,2011).
birth(mary,johnny).
birth(mary,peter).
birth(catherine,william).
birth(kate,betty).
givebirthyear(mary,peter,2015).
givebirthyear(mary,johnny,2012).
givebirthyear(catherine,william,2012).
givebirthyear(kate,betty,2011).
siblings(X,Y) :-
birth(Parent,X),
birth(Parent,Y).
cousins(X,Y) :-
birth(Xparent,X),
birth(Yparent,Y),
sisters(Xparent,Yparent).
cousins(X,Y) :-
X \= Y,
birth(Xmom,X),
birth(Ymom,Y),
marriage(Xmom,Xdad,_),
marriage(Ymom,Ydad,_),
brothers(Xdad,Ydad).
I don' know what's happening in my code. When I input
cousins(betty,johnny).
and
cousins(william,johnny).
The prolog says true. But when I entered
cousins(S,johnny).
THe prolog says S = william but didn't show me that S = betty. I don't really know what's happening. Need help.
Here is the prolog result I got.
?- cousins(S,johnny).
S = william ;
false.
?- cousins(betty,johnny).
true.
?- cousins(william,johnny).
true .
The problem
The reason this happens is because
X \= Y,
actually means:
\+(X = Y).
now \+ or not in Prolog has some weird behaviour compared to the logical not. \+ means negation as finite failure. This means that \+(G) is considered to be true in case Prolog queries G, and can not find a way to satisfy G, and that G is finite (eventually the quest to satisfy G ends).
Now if we query \+(X = Y), Prolog will thus aim to unify X and Y. In case X and Y are (ungrounded) variables, then X can be equal to Y. As a result X \= Y fails in case X and Y are free variables.
So basically we can either use another predicate that for instance puts a constraint on the two variables that is triggered when the variables are grounded, or we can reorder the body of the clause, such that X and Y are already grounded before we call X \= Y.
If we can make for instance the assumption that X and Y will be grounded after calling birth/2, we can reorder the clause to:
cousins(X,Y) :-
birth(Xmom,X),
birth(Ymom,Y),
X \= Y,
marriage(Xmom,Xdad,_),
marriage(Ymom,Ydad,_),
brothers(Xdad,Ydad).
Prolog has however a predicate dif/2 that puts a constraint on the two variables, and from the moment the two are grounded, it will fail if the two are equal. So we can use it like:
cousins(X,Y) :-
dif(X,Y),
birth(Xmom,X),
birth(Ymom,Y),
marriage(Xmom,Xdad,_),
marriage(Ymom,Ydad,_),
brothers(Xdad,Ydad).
Making things simpler
That being said, I think you make the program too complex. We can start with a few definitions:
two people are slibings/2 if they are brothers/2 or sisters/2.
slibings(X,Y) :-
brothers(X,Y).
slibings(X,Y) :-
sisters(X,Y).
It is however possible that brothers/2 and sisters/2 do not provide all information. Two people are also slibings if they have the same mother (we will assume that people do not divorce here, or at least not give birth to other children after they remarry).
slibings(X,Y) :-
dif(X,Y),
birth(Mother,X),
birth(Mother,Y).
a parent/2 of a person is the mother of the person or the father (the person that married the mother).
So we can write:
parent(Mother,X) :-
birth(Mother,X).
parent(Father,X) :-
birth(Mother,X),
marriage(Father,Mother,_).
based on your example, the marriage/3 predicate is bidirectional: in case marriage(X,Y,Z)., then there is also a fact marriage(Y,X,Z)..
And now we can define:
two people are cousins if there parents are slibings:
cousins(X,Y) :-
parent(MF1,X),
parent(MF2,Y),
slibings(MF1,MF2).
and that's it.
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.