How to write a Prolog rule to define a predicate? - prolog

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) .

Related

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.

How do I go through a database in prolog

I have a database composed of symptoms of a disease and the disease to which these symptoms belongs as follows.
disease([dordecabeca,febre,dormuscular,dorgarganta,cansaco],gripe).
disease([febre,dordecabeca,dorolhos,manchas,nauseas],dengue).
disease([febre,coceira,dordecabeca,dordebarriga,perdadeapetite],catapora).
disease([febre,dordecabeca,fadiga,perdadeapetite,inchacorosto],caxumba).
disease([congestaonasal,gargantairritada,espirros,febre,tosse],resfriado).
treatment([evitarmedicamentosdeaspirina,respouso],dengue).
treatment([evitarmedicamentosdeaspirina,repouso,paracetamol],dengue).
treatment([repouso,evitarpessoas,semmedicamento],catapora).
treatment([repouso,evitarpessoas,medicamento],catapora).
treatment([repouso,evitarpessoas],caxumba).
treatment([repouso,boaalimentacao],gripe).
treatment([repouso,boalimentacao,medicamentos],gripe).
treatment([repouso,boaalimentacao,semmedicamentos],refriado).
treatment([repouso,boaalimentacao,medicamento],resfriado).
symptoms(L1,X):-disease(L1,X).
treatdisease(L1,L2,Y):-symptoms(L1,Y),treatment(L2,Y).
With the symptons predicate, I can visualize all the symptoms and the corresponding disease. And with the predicate treatdisease, I can see the treatment based on the disease common to the two bases.
symptoms(L1,X):-disease(L1,X).
treatdisease(L1,L2,Y):-symptoms(L1,Y),treatment(L2,Y).
But what if I were to compare an entry list with the underlying disease like I would?
If it was just a list I already have the predicate, but on a multidimensional basis I have no idea how to go.
For example if I came in with:
?searchdisease([dordecabeca,febre,dormuscular,dorgarganta],Disease).
How do I go through the bases using this list with the database?
So I have predicates to pick up the different elements between two lists and a predicate to get the equal elements between two lists, but I do not know how to use them when the list is in a subset. Follow the predicates.
%---------------------------------------------------------
%Predicate to pick up equal elements between two lists.
equalelements([],[]).
equalelements([X|Xs0],Ys0) :-
tpartition(=(X),Xs0,Es,Xs),
if_(Es=[], Ys0=Ys, Ys0=[X|Ys]),
equalelements(Xs,Ys).
tpartition(P_2,List,Ts,Fs) :-
tpartition_ts_fs_(List,Ts,Fs,P_2).
tpartition_ts_fs_([],[],[],_).
tpartition_ts_fs_([X|Xs0],Ts,Fs,P_2) :-
if_(call(P_2,X), (Ts = [X|Ts0], Fs = Fs0),
(Ts = Ts0, Fs = [X|Fs0])),
tpartition_ts_fs_(Xs0,Ts0,Fs0,P_2).
if_(If_1, Then_0, Else_0) :-
call(If_1, T),
( T == true -> call(Then_0)
; T == false -> call(Else_0)
; nonvar(T) -> throw(error(type_error(boolean,T),_))
; /* var(T) */ throw(error(instantiation_error,_))
).
=(X, Y, T) :-
( X == Y -> T = true
; X \= Y -> T = false
; T = true, X = Y
; T = false,
dif(X, Y) % ISO extension
% throw(error(instantiation_error,_)) % ISO strict
).
equal_t(X, Y, T):-
=(X, Y, T).
%------------------------------------------------------------
%Predicate to pick up different elements between two lists.
displaydifference([],[],[]).
displaydifference(L1,L2,L4):-concatenate(L1,L2,L3), remove_dups(L3,L4).
concatenate(L1, L2, NL) :-
append(L1, L2, L12),
msort(L12, NL).
remove_dups([], []).
remove_dups([X], [X]).
remove_dups([X,Y|T], [X|R]) :-
X \= Y,
remove_dups([Y|T], R).
remove_dups([X,X|T], R) :-
skip(X, T, WithoutX),
remove_dups(WithoutX, R).
skip(_,[],[]).
skip(X, [X|T], T).
skip(X, [Y|T], [Y|T]) :- X \= Y.
Not sure to understand what do you exactly want obtain with searchdisease/2.
I suppose that you want a predicate that, given a list of symptoms, unifies the second parameter with one or more diseases with symptoms that are a superset of the first parameter.
In that case, I propose
subList([], _).
subList([H | T], S) :-
member(H, S),
subList(T, S).
searchdisease(Symptoms, Disease) :-
disease(Ls, Disease),
subList(Symptoms, Ls).
If you call searchdisease([dordecabeca,febre,dormuscular,dorgarganta],Disease), you unify Disease with gripe because [dordecabeca,febre,dormuscular,dorgarganta] is a subset of the symptoms of gripe.
If you call searchdisease([febre],D), you unify D with gripe and, trying again with backtracking, dengue, catapora, caxumba and resfriado, because febre is a symptom of all of this five diseases.
En passant: I don't understand the usefulness of symptoms/2; why don't you simply use disease/2?

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.

Adding a predicate based on the relationship between people

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

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.

Resources