Sunday, May 16, 2010

Family rules

A specialty of Prolog are genealogical databases aka family trees.

For the sake of simplicity we assume that do not need to represent couples without children. Therefore we can choose these three fundamental relations to build our tree: 'male', 'female' and 'parent'.

Here's an example from the Bible:

                      amram
                     jochebed
             ___________|________
            /           |        \
         moses        aaron    miriam
        zipporah     elisheba
        /      \        |
     gershom eliezer  nadab

male(amram).
male(aaron).
male(moses).
male(gershom).
male(eliezer).
male(nadab).

female(jochebed).
female(miriam).
female(zipporah).
female(elisheba).

parent(amram,moses).
parent(jochebed,moses).
parent(amram,aaron).
parent(jochebed,aaron).
parent(amram,miriam).
parent(jochebed,miriam).

parent(moses,gershom).
parent(zipporah,gershom).
parent(moses,eliezer).
parent(zipporah,eliezer).

parent(aaron,nadab).
parent(elisheba,nadab).

All the other family relationships can be defined in terms of these three fundamental predicates. The following definitions are all optmized for the first argument being a constant and the second being a variable:

% profile -,+

father(X,Y) :- parent(X,Y), male(X).
mother(X,Y) :- parent(X,Y), female(X).

% The inverse of parent
child(X,Y) :- parent(Y,X).

son(X,Y) :- parent(Y,X), male(X). 
% just the same
%son(X,Y) :- child(X,Y), male(X).
daughter(X,Y) :- parent(Y,X), female(X).

% Siblings have the same parents.
sibling(X,Y) :- father(Z,Y), mother(W,Y), parent(Z,X), parent(W,X), X \== Y.
% unoptmized version:
%sibling(X,Y) :- father(Z,Y), mother(W,Y), father(Z,X), mother(W,X), X \== Y.

% A brother is a male sibling.
brother(X,Y) :- sibling(X,Y), male(X).
% A sister is a female sibling.
sister(X,Y) :- sibling(X,Y), female(X).

% Here we assume that one only marries once.
husband(X,Y) :- mother(Y,Z), father(X,Z), !.
wife(X,Y) :- father(Y,Z), mother(X,Z), !.

grandparent(X,Y) :- parent(Z,Y), parent(X,Z).
grandmother(X,Y) :- parent(Z,Y), mother(X,Z).
% just the same
%grandmother(X,Y) :- grandparent(X,Y), female(X).
grandfather(X,Y) :- parent(Z,Y), father(X,Z).

cousin(X,Y) :- parent(Z,Y), sibling(W,Z), parent(W,X).

% An aunt is a parent's sister.
aunt(X,Y) :- parent(Z,Y), sister(X,Z).
% An uncle is a parent's brother.
uncle(X,Y) :- parent(Z,Y), brother(X,Z).

Note that if we define siblings as:

sibling(X,Y) :- parent(Z,X), parent(Z,Y), X \== Y.

we have a problem. We get each sibling twice:

?- sibling(X,moses).
X = aaron ;
X = aaron ;
X = miriam ;
X = miriam ;
false.

Can you see why? If not, a little bit of debug output will help you:

sibling(X,Y) :- parent(Z,X), parent(Z,Y), X \== Y, write(Z).

Example queries:

?- father(X,miriam).
X = amram ;
false.

?- sibling(X,moses).
X = aaron ;
X = miriam ;
false.

?- wife(X,moses).
X = zipporah.

?- grandparent(X,gershom).
X = amram ;
X = jochebed ;
false.

?- grandmother(X,eliezer).
X = jochebed ;
false.

?- cousin(X,nadab).
X = gershom ;
X = eliezer ;
false.

?- aunt(X,eliezer).
X = miriam ;
false.

Exercises

Make that of your own family! If you want to use full names the syntax is 'Name Surname'. Add rules for nephew (sibling's son), niece (sibling's daughter), descendant (a child or a descendant's child) and ancestor (the inverse of descendant). The definition of aunt given before is incomplete: "an aunt is a person who is the sister or sister-in-law of a parent". Similarly, mark uncle.

No comments: