Computer Representations of Anthropological Knowledge

Computer Representations of Anthropological Knowledge

Michael Fischer

University of Kent

BICA Issue No. 5: February 1987

Abstract:

    Knowledge is the anthropologist's stock-in-trade. Malcolm Crick [.Crick knowledge.] argues against the formation of an anthropology of knowledge on the grounds that it would be impossible to isolate such an integral aspect of anthropology to one sub-discipline. It could be said that anthropology is the description and representation of knowledge possessed by human groups. Unfortunately, such knowledge appears to be a very difficult thing to describe or represent. It is even more difficult to describe the knowledge of other societies, as the internal context that allows interpretation of partial systems of representation such as language or ritual is lacking, except, perhaps, to some degree within the ethnographer. The addition of computer-based methods to the anthropologist's repertoire suggests a new requirement: methods of representation of knowledge in a new medium.
  1. One of the barriers anthropologists face in representing problems using a computer is the lack of suitable tools for representation. It is suggested that Prolog, a programming language, is suitable for many such problems. A simple example of creating and using genealogical knowledge bases with Prolog is presented.

Knowledge Representation

I. Rossi [(.Logic Culture training.)] observes that anthropology is distinct from the physical and biological sciences in two ways. First, anthropologists can directly and intimately interact with their subject matter, and second, while both the physical sciences and anthropology use models based on symbolic systems, symbols in the physical sciences are related to things, while those in anthropology are related to other symbols. Although it is not possible at this time to define exactly what knowledge is, the latter observation is perhaps the basis for a working definition of knowledge, or more specifically, what a representation of knowledge is. One way to look at knowledge is to say it is the result of an active process of connecting systems of symbols together; knowledge is not a static collection of facts, but the situationally specific outcome of relating facts and other knowledge. This is, of course, a gross simplification of whatever knowledge is, but it is sufficient for an initial examination of methods of representation, as a representation does not necessarily claim to be a model of what knowledge is, but only a model of what knowledge does in a particular context. {(.Barr Feigenbaum .)} [Vol. 1, Chapter III] present a good review of representation techniques used in artificial intelligence (AI), a discipline which has developed a number of methods to simulate intelligence (by defined criteria). They offer this operational definition: `... a representation of knowledge is a combination of data structures and interpretive procedures that ... will lead to "knowledgeable" behavior.' This definitions is not entirely satisfactory from an anthropological perspective due to the emphasis on behavior rather than the system of knowledge. But it captures the central idea that data plus rules (or processes) results in knowledge. In some sense the anthropologist working in the field is attempting to acquire and analyse an alien representation of knowledge. The goals of AI and Anthropology are not identical...most anthropologists are not interested in writing programs that have knowledgeable behavior for that purpose; they are interested in representing knowledge. However, AI researchers do represent the knowledge of lawyers and doctors; are these techniques useful to represent the knowledge of the Nualu, Zuwaya, or Punjabi? The computer as a representational medium offers some exciting possibilities. The purpose of a representation is twofold. It acts as a means of recording and testing ones ideas about some domain, and it is a means of communicating ones ideas to others who might have an interest in the domain. Traditional representations in anthropology rely on substantial amounts of text and a high level of training and expertise to interpret the text. A computer representation has the potential to represent some of the interpretation as well, relying less on the combined judgement of the researcher and their audience: the computer representation of the knowledge structure is more explicit, less abstract1. The representation can be tested and probed. This allows discussion and criticism to focus directly on the interpretative aspect of the representation, rather than interpretations of the interpretation as so often happens.

Prolog

One of the general problems with representation using a computer are the tools available for that purpose. Programming languages are expressions of the language designer's ideas of how a computer should be instructed to solve the kinds of problems the designer thinks are important. Hence languages such as FORTRAN are good for programming numerical problems, but not very efficient for solving problems involving non-numeric symbols.2 Prolog3 is a programming language that originated in the theoretical work of Colmerauer at the University of Marseilles in the early 1970's. The name stands for PROgramming in LOGic4, and is an attempt to allow problem statement be descriptive and the solution process to be non-deterministic, rather than prescriptive and deterministic like FORTRAN and most other programming languages. A procedural (`prescriptive') language requires an explicit list of operations required to arrive at a solution. This requires the programmer first to model the domain of objects in some abstract way, to define what the set of operations will be, and to describe a method of sequencing the operations; an algorithm, or procedure. A declarative (`descriptive') language requires the programmer to state the relations between objects, define a set of operations (rules), but not the sequencing of the operations. The aspects of process are implicit rather than explicit. The solution is non-deterministic in the sense that the programmer does not explicitly determine the method of solution out of a number that might be provided, and that the problem may have several solutions, each of which may be formed using different derivations5. Although Prolog is not entirely successful as a logic language, it facilitates the statement of many problems that would be very difficult to state in mainstream procedural programming languages. Programming languages have typical introductory examples that are given as a brief description. For FORTRAN the example is converting Fahrenheit to Centigrade, for BASIC inputing and printing the users name, for LISP computing n-factorial, and for Prolog it is building and interrogating genealogical databases. Prolog requires little `setup' or preparation to get a result printed on the terminal; it is an interactive language6. It is capable of handling very complex, arbitrary, data types, such as lists of items, trees, or graphs. It is practically limited to certain problem domains, but many of these are ideal for anthropologically interesting problems. The language is widely available for mainframes and micros, especially in the UK, where much of the development of the language has taken place. The particular dialect used in this paper is C-Prolog 1.4d [(.C-Prolog.)] from the University of Edinburgh, but the examples should run as is on Dec-10/20 Prolog, and Emas 2900 Prolog. A couple of excellent books on Prolog are given in the bibliography7. To maintain continuity in the text, a few of the steps required to actually run the examples will be omitted. Appendix A contains an exact transcript of all steps required to run the examples given in C-Prolog. In the text bold face will represent what the user types, and italics will represent the computer's response.

A case study: Representing Genealogical Relations

The remainder of this paper will focus on developing a representation of one particular example of knowledge structure, a genealogy. This will involve first a representation of the data, a set of relationships between individuals, and an interpretive framework for extending that data into knowledge. The actual relations used correspond to simplified English kinship terminology8 and

Data Structures

Data structures are simply the materials available to the programmer to represent data with. Although the formal definitions vary somewhat, Prolog has in essence three types of data structure; atoms, which can consist of most alphabetic and numerical characters, but must start with a lowercase letter or numeric digit, numbers, which are a special case of atoms to which arithmetic operations can be applied, and lists of atoms (or lists of lists). Atoms can serve as subjects, objects, or predicates, while lists are usually only subjects or objects.9 To clarify this consider the following:

male(john).

In this example male (read `is male') is the predicate, and john is the subject. The English interpretation of this statment (a Prolog `fact') is john is male or the set of males includes john . Prolog will interpret this statement in different ways depending the context of its entry by the user. There are two basic contexts in Prolog, consult context and query context.10 will be taken as an asserted fact by the user, and Prolog will record this fact in its database. In query context Prolog will test the fact against its database (a collection of previously asserted facts). In these examples query context will be denoted by the presence of the characters `?-' preceding the clause:

?- male(john).

yes

Note that Prolog responds yes if the clause is proven (true) relative to its database. The terms male and john are spelled beginning with lowercase letters. This is required in Prolog, as words beginning with capital letters are reserved for an important function. If the following is typed:

?- male(X).

X = john

The use of capital ` X ' in the assertion indicates an unnamed subject, and is called a variable. Any word beginning with a capital letter would have done. A term beginning with a capital letter has a function similar to a pronoun, and Prolog responds to such an assertion by giving values for that term that makes the assertion male(X) true. If there is more than one such value, Prolog will give each of them on request. This request is made by typing a `;' after the reply from Prolog. If the following facts are added to Prolog's database:

male(tom).

male(mike).

and Prolog is given the query:

?- \fBmale(X).

\fIX = john
;

X = tom ;

X = mike ;

no

The no indicates that there are no more solutions to the assertion male(X) . Prolog works on a principle of accepting `facts' from the user, and testing assertions by evaluation based either on the presence of the fact in the database if a fact is specified, or by finding a fact in the database if a fact is not specified. Prolog also handles more complex facts:

child(mike,tom)

child(john,tom).

These facts inform Prolog that mike and tom have the relation child between them. Prolog does not know (and does not care!) who is child of whom, so it is important to be consistent with respect to the order the arguments are given. In this paper these relationships will conventionally be read `the first argument has the relation to the second argument', thus mike is the child of tom, and john is the child of tom. The new facts are tested in the following queries:

?- \fBchild(mike,tom).

\fIyes

?- \fBchild(tom,mike).

\fIno

?- \fBchild(Kid,tom).

\fIKid = mike
;

Kid = john ;

no

?- child(Kid,Pater).

Pater = tom

Kid = mike ;

Pater = tom

Kid = john ;

no

Although the above might have some value as a computer based tool for the anthropologist, the property of Prolog that makes it potentially a very powerful research tool is its ability to understand and evaluate rules that are supplied by the user:

parent(X, Y) :- child(Y, X).

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

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

The preceding rules indicate that X is the parent of Y when Y is the child of X, X is father of Y when X is parent of Y and X is male, and X is mother of Y when X is parent of Y and X is female. A rule is a way of generating new facts based on previous facts and rules. The father-rule or mother-rule can be used just like facts in further rules, and will, in general, act just as if it were a fact:

?- father(tom,john).

yes

?- father(tom,Kid).

Kid = mike ;

Kid = john ;

no

The facility to build complex relationships in Prolog using rules allows experimentation with constructing relationships based on prior relationships. For example the following fact and rule can be added to the database:

child(tom,carl).

grandfather(X,Y) :- father(X,Q) , father(Q,Y).

The basic information that tom is child of carl is added, and then the rule that states that X is grandfather of Y if X is the father of Q, and Q is the father of Y. This new rule can be interrogated:

?- \fBgrandfather(Gf,john).

\fIX = carl
;

no

Note that no value for Q in the grandfather rule was printed. Prolog only prints values for pronominal objects (or variables in Prologese) that appear at the top level, the level of the query. Variables used only inside rules are only for internal use of that rule. Note also that the variable used in the rule definition need not be the same as the one used in the query. The only requirement is that each variable used in a query has a unique form, unless it is intended that the same value be used, as in the case of the Q in the grandfather rule. In terms of extending the genealogical database, rules could be constructed for each relationship of interest:

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

(X is (half-)sibling of Y if the parent of X (Q) is the parent of Y, and X is not the same person as Y!. This could be restricted to X and Y sharing two parents by the rule...sib(X,Y):-father(Q,X),father(Q,Y),mother(R,X),mother(R,Y),X\=Y.)

brother(X,Y) :- sibling(X,Y) , male(X).

(X is brother of Y if X is sibling of Y and X is male.)

grand-parent(X,Y) :- parent(X,Q) , parent(Q,Y).

(X is the grand-parent of Y if X is parent of parent of Y)

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

cousin(X,Y) :- grand-parent(Q,Y) , sibling(Z,Q) , child(X,Z).

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

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

(Four rules for cousin (out of others)... Prolog will try each until one is true relative to the database).

This process continues until suitable definitions were produced for each kin category desired. Note that although the present definitions all hinge on the primitive relation child-of , the primitive criteria could be some other relationship. Less naive rules could also be implemented, or rules for categories which are dependent on the sex of the linking relative. Affinal relations can be added by including a spouse-of relation or rule (as deemed appropriate). By filling out the rule set, a simple program for printing the immediate relationships for some ego can be created:

uncle(X,Y) :- parent(Q,Y) , brother(X,Q).

aunt(X,Y) :- parent(Q,Y) , sister(X,Q).

nephew(X,Y) :- uncle(Y,X) , male(X).

nephew(X,Y) :- aunt(Y,X) , male(X).

niece(X,Y) :- uncle(Y,X) , female(X).

niece(X,Y) :- aunt(Y,X) , female(X).

son(X,Y) :- child(X,Y) , male(X).

daughter(X,Y) :- child(X,Y) , female(X).

grandmother(X,Y) :- grandparent(X,Y) , female(X).

relate(X,Y) :- mother(X,Y) , write('mother').

relate(X,Y) :- father(X,Y) , write('father').

relate(X,Y) :- brother(X,Y) , write('brother').

relate(X,Y) :- sister(X,Y) , write('sister').

relate(X,Y) :- son(X,Y) , write('son').

relate(X,Y) :- daughter(X,Y) , write('daughter').

relate(X,Y) :- uncle(X,Y) , write('uncle').

relate(X,Y) :- aunt(X,Y) , write('aunt').

relate(X,Y) :- grandmother(X,Y) , write('grandmother').

relate(X,Y) :- grandfather(X,Y) , write('grandfather').

relate(X,Y) :- niece(X,Y) , write('niece').

relate(X,Y) :- nephew(X,Y) , write('nephew').

relate(X,Y) :- first-cousin(X,Y) , write('first-cousin').

relate(X,Y) :- second-cousin(X,Y) , write('second-cousin').



(The predicate `write' simply puts the term in the parenthesis on the display terminal. Since there are many relate rules, we need to know which one applied. We could continue to extend relate indefinitely depending on the relationships we wanted to be able to determine.)

The rule \fBrelate
ill behave in different ways, depending on how it is used. If it is invoked as:

?- \fBrelate(tom,john).

\fIfather yes

If invoked as:

?- \fBrelate(X,john).

Prolog would respond with the name of each person that had one of the above lationships to john, and the relationship, ie father, X = tom, brother, X = mike. If invoked as:

\fBrelate(john,X).

Prolog would respond with the name of each person who john had a relationship to, and the name of the relationship. And finally if invoked as:

\fBrelate(X,Y).

Prolog would print the name of each person, the name of the person they held a relationship to, and the relationship. Although the previous treatment is quite primitive (from a Prolog programmers point of view), it is quite suitable if the primary interest is in the actual relationships between individuals, or the number of relationships. As will be shown briefly in the next section it is possible to program such problems more elegantly (from various points of view), but if there is no direct interest in the means of determining the relationship, the method presented above is adequate, and usually much faster in development. For instance the above method took about 5 minutes to type in and 5 minutes to check for typing mistakes and test against data. The method presented in appendix II took about four hours to develop, and although more general, requires a substantially better knowledge of Prolog. One of the advantages of prolog to anthropologists with limited acquaintance with computers is that it can do very useful work with a minimum amount of programming skill.

More complex operations

The above treatment can be useful for examining the coincidence of certain specified relationship terms, but sometimes there is a need for more general operations. Consider the problem of determining if two people are members of the same patrilineage. It is possible, following the model above, to list all possible combinations that would define such a relationship: but in a large database, with thousands of members, this could be tedious at best: as relations such as F, FF, FFF, FFFF... , S, SS, SSS, SSSS , B, FBS, FBSS, FBSSS, and a host of others would have to be defined. This can be simplified by defining a new term, ancestor:

ncestor(X,Y) :- father(X,Y).

ancestor(X,Y) :- father(X,Q) , father(Q,Y).

ancestor(X,Y) :- father(X,Q) , father(Q,W) , father(W,Y).

ancestor(X,Y) :- father(X,Q) , father(Q,W) , father(W,M) , father(M,Y).

in-lineage(X,Y) :- ancestor(X,Y).

in-lineage(X,Y) :- ancestor(Y,X).

in-lineage(X,Y) :- ancestor(Q,X) , ancestor(Q,Y) , X \= Y.

These rules assert that X and Y are in the same lineage if

This definition of \fBin-lineage ill work correctly for four ascending generations (regardless of the number of individuals in the database), and can be extended by increasing the scope of the \fBancestor ule. Prolog includes a facility that can be useful for defining some problems of this sort in a more general way, called recursion. Recursion refers to a method of rule specifications where a rule is defined partially in terms of itself. Consider the following definition of ancestor:

ncestor(X,Y) :- father(X,Y).

ancestor(X,Y) :- father(Q,Y) , ancestor(X,Q).

The first rule for ancestor simply states that if X is father of Y, X is an ancestor of Y. If Prolog finds this to be the case, a solution is found, and Prolog will stop trying to find a solution. If this rule fails, then the second rule will apply, which attempts to find the father of Y, and if there is one applies the rule ancestor to the newly found father and X. Prolog will continue, first seeing if X is the father of the father of Y, and if not will proceed to the second rule, taking the father of the father of Y, and so on. If X is an ancestor to Y, eventually the first ancestor rule will apply, and Prolog will have found a solution. The first ancestor rule is essential, as it marks the boundary condition so that Prolog will not continue forever. This leads then to a general solution to the lineage problem, using the same definitions of \fBin-lineage

n-lineage(X,Y) :- ancestor(X,Y).

in-lineage(X,Y) :- ancestor(Y,X).

in-lineage(X,Y) :- ancestor(Q,Y) , ancestor(Q,X).
For a more complex example of recursion refer to appendix II, which includes a short Prolog program to find all the relationships between any two people in an endogamous population.

Conclusion

Although the previous examples were rather naive formulations of simple anthropological problems, these problems are not simple to represent in more familiar programming languages. This is a representation of knowledge, because from one primitive relationship, a complex structure can be constructed and interrogated on the basis of rules. What could be constructed by collecting data, all the relationships of each member, is constructed by a single relationship, and the application of rules defined in terms of that relationship, and other rule-derived relationships. This construction has descriptive adequacy relative to its ability to reflect the observed situation, and explanatory adequacy relative to the researcher's ability to support and defend the rules that are evaluated. As can be seen in the examples, Prolog is non-deterministic; two objects can have several alternative relationships, and different expressions of rules can co-exist. With the help of informants, a system of native classes can be defined, and Prolog can be used to test the consistency of the definitions formed by the researcher, at least within the set of models Prolog is able to represent. Prolog is best suited to a particular range of representations and models. It is best where the problem domain can be represented as a structure, formed by objects and relations between objects. Prolog's advantage in this domain is the ability to represent the structure, without having to generate it entirely in advance, and its capacity for handling multiple structures superimposed over each other. Prolog's limitations derive from a weakness in representing certain kinds of processes, and a weakness in representing global context. The first limitation is more a matter of ease of representation than possibility. Simulations and other representations of process are often easier to represent in procedural programming languages such as C or BASIC. Still, with a good knowledge of Prolog it is possible to represent process. Prolog works best and easiest when most of the context is local to each rule, that is, Prolog's notion of variables are essentially local. Prolog has powerful facilities for building global structures, but they are not as straight-forward or efficient to use as in some other languages. Prolog's orientation is based on rules `firing' or activating other rules... the sequence of rules that apply in a case must be laid out in advance. Hence its compatibility with structural descriptions. Production rules, such as those used in expert systems [(.Fischer Expert.)], are based on data `firing' rules... as the state of the global information changes, rules are applied to the data. This latter approach is better suited to situations where the structure is not clear.11 The case of Prolog's weaknesses can be overstated, they are simply less convenient than those things Prolog does well. Prolog offers substantial power for the representation of research materials in a flexible way, with a minimum of assumptions built into the language that the casual user cannot control. It matters not to Prolog whether the child definition is a biological one or a social one. It is the researcher's responsibility to select the facts to use, account for the meanings, and to justify each of the rules used in the knowledge base. Prolog simply provides facilities to relate data, information, and knowledge together [(.barr all, fischer expert 1986.)]. Appendix I: Prolog Session Example

In the appendices \fBbold epresents what the user types into the computer, \fIitalics he responses by Prolog, and \s-6(small text)\s+6 represents comments on the dialogue, which do not appear in an actual session. The following (excepting the comments) is a record of a Prolog session. The examples given in the text are an edited version of this record.

\fIC-Prolog version 1.5

\fI[ Restoring file startup ]


\fI| ?-
[user].

| male(john).

| **EOF**

(The first two lines are System messages printed on initialization.)

([user] is a way to get Prolog to take new rules from the keyboard, referred to as `consult' mode in the text.)

(***EOF*** is a key used to indicate end of data. For UNIX (tm) EOF is [CTRL] D. In this context it will return the user to `query' mode.)

user consulted 68 bytes 0.0500003 sec.

yes

(`yes' indicates that Prolog was able to do what was asked; e.g. `success')

| ?- male(john).

yes

| ?- male(X).

X = john

yes

| ?- [user].

| male(tom).

| male(mike).

| **EOF**

user consulted 100 bytes 0.0333334 sec.

yes

| ?- male(X).

X = john ;

X = tom ;

X = mike ;

no

(`no' indicates failure. In this kind of query, it means that there are no more cases that can satisfy male(X).)

| ?- [user].

| child(mike,tom).

| child(john,tom).

| **EOF**

user consulted 144 bytes 0.0166671 sec.

yes

| ?- child(mike,tom).

yes

| ?- child(tom,mike).

no

| ?- child(Kid,tom).

Kid = mike ;

Kid = john ;

no

| ?- child(Kid,Pater).

Kid = mike

Pater = tom ;

Kid = john

Pater = tom ;

no

| ?- [user].

| parent(X,Y) :- child(Y,X).

| father(X,Y) :- parent(X,Y) , male(X).

| **EOF**

user consulted 196 bytes 0.0500003 sec.

yes

| ?- father(tom,john).

yes

| ?- father(tom,Kid).

Kid = mike ;

Kid = john ;

no

| ?- [user].

| child(tom,carl).

| grandfather(X,Y) :- father(X,Q) , father(Q,Y).

| **EOF**

user consulted 148 bytes 0.0333342 sec.

yes

| ?- grandfather(Gf,john).

no

| ?- [user].

| male(carl).

| **EOF**

user consulted 32 bytes 2.77556e-17 sec.

yes

| ?- grandfather(Gf,john).

Gf = carl ;

no

| ?- [kinex].

(A prepared file can be included also, in this case kinex, which is listed at the end of this appendix. This file contains definitions for rules and facts needed for the following dialogue.)



kinex reconsulted 4072 bytes 1.7 sec.

yes

| ?- relate(mike,X).

father

X = demeter ;

father

X = demeter ;

father

X = stephen ;

father

X = stephen ;

brother

X = john ;

brother

X = john ;

brother

X = paul ;

brother

X = paul ;

brother

X = jack ;

brother

X = jack ;

brother

X = nancy ;

brother

X = nancy ;

brother

X = jimmi ;

brother

X = jimmi ;

brother

X = nancy ;

brother

X = nancy ;

brother

X = jimmi ;

brother

X = jimmi ;

son

X = tom ;

son

X = tom ;

son

X = george ;

son

X = george ;

son

X = jean ;

son

X = jean ;

uncle

X = albert ;

uncle

X = simon ;

nephew

X = jim ;

nephew

X = jim ;

nephew

X = jim ;

nephew

X = jim ;

cousin

X = vikki ;

cousin

X = vikki ;

cousin

X = albert ;

cousin

X = albert ;

no

| ?- in-lineage(carl,mike).

yes

| ?- in-lineage(carl,X).

X = tom ;

X = tom ;

X = mike ;

X = mike ;

X = john ;

X = john ;

X = paul ;

X = paul ;

X = jack ;

X = jack ;

X = mike ;

X = mike ;

X = john ;

X = john ;

X = paul ;

X = paul ;

X = jack ;

X = jack ;

X = demeter ;

X = demeter ;

X = stephen ;

X = stephen ;

X = demeter ;

X = demeter ;

X = stephen ;

X = stephen ;

X = albert ;

X = albert ;

X = simon ;

X = simon ;

X = demeter ;

X = demeter ;

X = stephen ;

X = stephen ;

X = demeter ;

X = demeter ;

X = stephen ;

X = stephen ;

X = albert ;

X = albert ;

X = simon ;

X = simon ;

X = carl ;

X = carl

yes

| ?- **EOF**

[ Prolog execution halted ]

Contents of file kinex

male(john).

male(tom).

male(mike).

child(mike,tom).

child(john,tom).

parent(X, Y) :- child(Y, X).

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

child(tom,carl).

grandfather(X,Y) :- father(X,Q) , father(Q,Y).

male(carl).

sibling(X,Y) :- parent(Q,X) ,

parent(Q,Y), not(X = Y).

brother(X,Y) :- sibling(X,Y) , male(X).

grand-parent(X,Y) :- parent(X,Q) , parent(Q,Y).

grandmother(X,Y) :- grandparent(X,Y) , female(X).

cousin(X,Y) :- parent(Q,Y) ,

sibling(Z,Q) , child(X,Z).

cousin(X,Y) :- grand-parent(Q,Y) ,

sibling(Z,Q) , child(X,Z).

cousin(X,Y) :- grand-parent(Q,Y) ,

sibling(Z,Q) , grand-parent(Z,X).

cousin(X,Y) :- parent(Q,Y) ,

sibling(Z,Q) , grand-parent(Z,Y).

uncle(X,Y) :- parent(Q,Y) , brother(X,Q).

aunt(X,Y) :- parent(Q,Y) , sister(X,Q).

nephew(X,Y) :- uncle(Y,X) , male(X).

nephew(X,Y) :- aunt(Y,X) , male(X).

niece(X,Y) :- uncle(Y,X) , female(X).

niece(X,Y) :- aunt(Y,X) , female(X).

son(X,Y) :- child(X,Y) , male(X).

daughter(X,Y) :- child(X,Y) , female(X).

relate(X,Y) :- mother(X,Y) , write('mother').

relate(X,Y) :- father(X,Y) , write('father').

relate(X,Y) :- brother(X,Y) , write('brother').

relate(X,Y) :- sister(X,Y) , write('sister').

relate(X,Y) :- son(X,Y) , write('son').

relate(X,Y) :- daughter(X,Y) ,

write('daughter').

relate(X,Y) :- uncle(X,Y) , write('uncle').

relate(X,Y) :- aunt(X,Y) , write('aunt').

relate(X,Y) :- grandmother(X,Y) ,

write('grandmother').

relate(X,Y) :- grandfather(X,Y) ,

write('grandfather').

relate(X,Y) :- niece(X,Y) , write('niece').

relate(X,Y) :- nephew(X,Y) , write('nephew').

relate(X,Y) :- cousin(X,Y) , write('cousin').

ancestor(X,Y) :- father(X,Y).

ancestor(X,Y) :- father(X,Q) , father(Q,Y).

ancestor(X,Y) :- father(X,Q) , father(Q,W) ,

father(W,Y).

ancestor(X,Y) :- father(X,Q) , father(Q,W) ,

father(W,M) , father(M,Y).

in-lineage(X,Y) :- ancestor(X,Y).

in-lineage(X,Y) :- ancestor(Y,X).

in-lineage(X,Y) :- ancestor(Q,X) ,

ancestor(Q,Y) , not(X = Y).

ancestor(X,Y) :- father(X,Y).

ancestor(X,Y) :- father(Q,Y) , ancestor(X,Q).

male(john).

male(tom).

male(jack).

male(mike).

male(paul).

male(george).

male(earl).

male(jim).

male(albert).

male(stephen).

male(simon).

male(carl).



female(janet).

female(mary).

female(carla).

female(sally).

female(jimmi).

female(nancy).

female(jean).

female(noddy).

female(vikki).

female(demeter).

female(wenonah).



child(mike,george).

child(nancy,george).

child(jimmi,george).

child(mike,jean).

child(nancy,jean).

child(jimmi,jean).

child(george,earl).

child(jim,earl).

child(george,noddy).

child(jim,noddy).

child(vikki,jim).

child(vikki,elizabeth).

child(albert,vikki).

child(albert,paul).

child(demeter,wenonah).

child(demeter,mike).

child(stephen,mike).

child(paul,mary).

child(paul,tom).

child(john,mary).

child(jack,tom).

child(simon,jack).

child(simon,carla).

child(carl,demeter).

child(carl,albert). Appendix II: More Advanced Relate

The basic purpose of this example is to print on the display screen all relationships that can be calculated from the rules and facts given, in terms of a set of primitive or primary kin links; M F B Z S D H W. This is presented as an example of a slightly more complex Prolog program. It will be difficult to fully understand the program in kinrules (listed at the end) without one of the introductions to Prolog given in the bibliography. Also note that it is not as declarative as the prior example...it was found necessary to translate a procedure for determining relationships between people into semi-descriptive rules.

1} Prolog startup

C-Prolog version 1.5

[ Restoring file startup ]

| ?- [kinfacts].

kinfacts consulted 1748 bytes 0.6 sec.

yes

| ?- [kinrules].

kinrules consulted 4456 bytes 1.05 sec.

yes

(The above read two prepared sets of information into prolog, the contents of which are included at the end of this text. The first is the asserted relationships between individuals, and the second contains rules for deriving relationships. As demonstrated in Appendix 1, a prolog statement can be used to find different information, depending on which terms are specified and which are left to prolog to find. The following examples use a statement relate(Relative,Ego,Links) which is designed to find all links between individuals in a given group. The first example specifies Relative and Ego, and leaves prolog to find Links; the relationship and intervening individuals in the relationship.)

| ?- relate(jimmi,mike,Links).

Z

Links = [jimmi] ;

Z

Links = [jimmi] ;

F B D S W F Z

Links = [george,jim,vikki,albert,demeter,mike,jimmi] ;

F B D S W F Z

Links = [george,jim,vikki,albert,demeter,mike,jimmi] ;

F B D S W F Z

Links = [george,jim,vikki,albert,demeter,mike,jimmi] ;

F B D S W F Z

Links = [george,jim,vikki,albert,demeter,mike,jimmi] ;

D H M F B D

Links = [demeter,albert,vikki,jim,george,jimmi] ;

D H M F B D

Links = [demeter,albert,vikki,jim,george,jimmi] ;

no



(There are no more Links.)

| ?- relate (carla,carl,Links).

M F F B D H B W

Links = [demeter,mike,george,jim,vikki,paul,jack,carla] ;

M F F B D H B W

Links = [demeter,mike,george,jim,vikki,paul,jack,carla] ;

F F B W

Links = [albert,paul,jack,carla] ;

no

| ?- relate(vikki,mike,Links).

F B D

Links = [george,jim,vikki] ;

F B D

Links = [george,jim,vikki] ;

D H M

Links = [demeter,albert,vikki] ;

no

| ?- relate(earl,nancy,Links).

F F

Links = [george,earl] ;

B D H M F F

Links = [mike,demeter,albert,vikki,jim,earl] ;

B D H M F F

Links = [mike,demeter,albert,vikki,jim,earl] ;

no



(The next example specifies Ego, but leaves prolog to find all Relatives and the Links for those Relatives.)

| ?- relate(Who,demeter,Links).

S

Who = carl

Links = [carl] ;

B

Who = stephen

Links = [stephen] ;

F Z

Who = nancy

Links = [mike,nancy] ;

F Z

Who = jimmi

Links = [mike,jimmi] ;

F Z

Who = nancy

Links = [mike,nancy] ;

F Z

Who = jimmi

Links = [mike,jimmi] ;

F F B

Who = jim

Links = [mike,george,jim] ;

H M F B

Who = george

Links = [albert,vikki,jim,george] ;

F F B

Who = jim

Links = [mike,george,jim]

yes



(Here yes means that there are more, but I choose not to see them by not typing a semi-colon at the end of the line.)

| ?- **EOF*

[ Prolog execution halted ] Contents of file kinfacts

male(john).

male(tom).

male(jack).

male(mike).

male(paul).

male(george).

male(earl).

male(jim).

male(albert).

male(stephen).

male(simon).

male(carl).

female(janet).

female(mary).

female(carla).

female(sally).

female(jimmi).

female(nancy).

female(jean).

female(noddy).

female(vikki).

female(demeter).

female(wenonah).

child(mike,george).

child(nancy,george).

child(jimmi,george).

child(mike,jean).

child(nancy,jean).

child(jimmi,jean).

child(george,earl).

child(jim,earl).

child(george,noddy).

child(jim,noddy).

child(vikki,jim).

child(vikki,elizabeth).

child(albert,vikki).

child(albert,paul).

child(demeter,wenonah).

child(demeter,mike).

child(stephen,mike).

child(paul,mary).

child(paul,tom).

child(john,mary).

child(jack,tom).

child(simon,jack).

child(simon,carla).

child(carl,demeter).

child(carl,albert). Contents of file kinrules

parent(X,Y) :- child(Y,X).

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

(This definition for mate is a bit weak, since only people who share a child in the database can be considered mates by Prolog. Also mate is extended to be used as husband and wife in later rules. This could be made more accurate by including a spouse relationship in the fact base.)

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

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

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

brother(X,Y) :- sibling(X,Y) , male(X).

sister(X,Y) :- sibling(X,Y) , female(X).

son(X,Y) :- child(X,Y) , male(X).

daughter(X,Y) :- child(X,Y) , female(X).



(The primary kin definitions.)

par(X) :- male(X), write('F ').

par(X) :- female(X), write('M ').

sib(X) :- male(X) , write('B ').

sib(X) :- female(X) , write('Z ').

kid(X) :- female(X) , write('D ').

kid(X) :- male(X) , write('S ').

spo(X) :- male(X) , write('H ').

spo(X) :- female(X) , write('W ').



(These definitions simply write on the terminal a letter corresponding to a primary kin link. They should properly place the term in a list, but that would make the program even less clear.)

member(X,[X|_]).

member(X,[_|Y]) :- member(X,Y).

ident(X,Y) :- not(member(X,Y)).



(member determines if X is in the list Y. ident uses member, and succeeds if X is not in the list. This is necessary to avoid looping in the kin network ie finding relationships that contain a linking person more than once.)

relateA(X,Y,[Z|R],R) :- child(X,Y) , kid(X).

relateA(X,Y,[Z|R],R) :- sibling(X,Y) , sib(X).

relateA(X,Y,[P|Z],R) :- sibling(Q,X),ident(Q,Z),

relateB(Q,Y,[P|[Q|Z]],R),sib(X).

relateA(X,Y,[P|Z],R) :- parent(Q,X),ident(Q,Z),

relateA(Q,Y,[P|[Q|Z]],R), kid(X).



(relateA is true if X is child or sibling of Y, and writes the appropriate primary kin type on the terminal. If neither is true, then the we find a sibling Q, of X, check to see if this sibling Q is in the list of linking relatives so far, and if not in the list use the relateB rule to relate Q to Y instead, and if a relation is found write the appropriate sib link on the terminal. Otherwise we find a parent Q, of X, look Q up on the list, and then apply relateA to Q and Y instead of X and Y. This is a recursive rule, which can be thought of as using the rule to solve a little of the problem at a time. The bracketed notation ie [P|Z] is a Prolog method of representing lists (where P is the first thing in a list, and Z is the remainder of the list), and is used here to maintain the list of linking relatives. The definitions for relateB, following are similar. relateA and relateB represent a kin-system dependant method of tracing relationships between people, and would require some alteration for other systems if we wanted terminological definitions rather than fictive biological relations. If we were to keep the fictive biological links in a list, rather than print them on a terminal, then it would be possible to relate them to terminological rules.)

relateB(X,Y,[Z|R],R) :- parent(X,Y) , par(X).

relateB(X,Y,[Z|R],R) :- mate(X,Y) , spo(X).

relateB(X,Y,[P|Z],R) :- mate(Q,X),ident(Q,Z),

relateA(Q,Y,[P|[Q|Z]],R), spo(X).

relateB(X,Y,[P|Z],R) :- child(Q,X),ident(Q,Z),

relateB(Q,Y,[P|[Q|Z]],R), par(X).

relate(X,Y,R) :- relateA(X,Y,[Y,X],R).

relate(X,Y,R) :- relateB(X,Y,[Y,X],R).

Return to Contents page