In this final tutorial chapter, we present some small example programs intended to stimulate your own ideas and to further illustrate the topics covered in the earlier tutorial chapters. Nearly all of the examples offer plenty of room for expansion; your own ideas can grow into full-blown programs using one of these programs as a starting point.
In this first example, we show you how to construct a small expert system expert system, sample that figures out which of seven animals (if any) the system's user has in mind. The expert system will figure out the animal by asking questions then making deductions from the replies given. This example demonstrates backtracking--using facts--and how to use not effectively.
A typical user dialogue with this expert system might be:
has it hair?
yes
does it eat meat?
yes
has it a fawn color?
yes
has it dark spots?
yes
Your animal may be a cheetah!
Visual Prolog's ability to check facts and rules will provide your program with the reasoning capabilities germane to an expert system. The first step is to provide the knowledge with which the system can reason; this is known as the inference engine and is shown in ch16e01.pro.
/* Program ch16e01.pro */
DATABASE
xpositive(symbol,symbol)
xnegative(symbol,symbol)
PREDICATES
nondeterm animal_is(symbol)
nondeterm it_is(symbol)
ask(symbol,symbol,symbol)
remember(symbol,symbol,symbol)
positive(symbol,symbol)
negative(symbol,symbol)
clear_facts
run
CLAUSES
animal_is(cheetah):-
it_is(mammal),
it_is(carnivore),
positive(has,tawny_color),
positive(has,dark_spots).
animal_is(tiger):-
it_is(mammal),
it_is(carnivore),
positive(has, tawny_color),
positive(has, black_stripes).
animal_is(giraffe):-
it_is(ungulate),
positive(has,long_neck),
positive(has,long_legs),
positive(has, dark_spots).
animal_is(zebra):-
it_is(ungulate),
positive(has,black_stripes).
animal_is(ostrich):-
it_is(bird),
negative(does,fly),
positive(has,long_neck),
positive(has,long_legs),
positive(has, black_and_white_color).
animal_is(penguin):-
it_is(bird),
negative(does,fly),
positive(does,swim),
positive(has,black_and_white_color).
animal_is(albatross):-
it_is(bird),positive(does,fly_well).
it_is(mammal):-
positive(has,hair).
it_is(mammal):-
positive(does,give_milk).
it_is(bird):-
positive(has,feathers).
it_is(bird):-
positive(does,fly),
positive(does,lay_eggs).
it_is(carnivore):-
positive(does,eat_meat).
it_is(carnivore):-
positive(has,pointed_teeth),
positive(has, claws),
positive(has,forward_eyes).
it_is(ungulate):-
it_is(mammal),
positive(has,hooves).
it_is(ungulate):-
it_is(mammal),
positive(does,chew_cud).
positive(X,Y):-
xpositive(X,Y),!.
positive(X,Y):-
not(xnegative(X,Y)),
ask(X,Y,yes).
negative(X,Y):-
xnegative(X,Y),!.
negative(X,Y):-
not(xpositive(X,Y)),
ask(X,Y,no).
ask(X,Y,yes):-
!,
write(X," it ",Y,'¡¬n'),
readln(Reply),nl,
frontchar(Reply,'y',_),
remember(X,Y,yes).
ask(X,Y,no):-
!,
write(X," it ",Y,'¡¬n'),
readln(Reply),nl,
frontchar(Reply,'n',_),
remember(X,Y,no).
remember(X,Y,yes):-
assertz(xpositive(X,Y)).
remember(X,Y,no):-
assertz(xnegative(X,Y)).
clear_facts:-
write("¡¬n¡¬nPlease press the space bar to exit¡¬n"),
retractall(_,dbasedom),readchar(_).
run:-
animal_is(X),!,
write("¡¬nYour animal may be a (an) ",X),
nl,nl,clear_facts.
run :-
write("¡¬nUnable to determine what"),
write("your animal is.¡¬n¡¬n"),
clear_facts.
GOAL
run.
Each animal is described by a number of attributes that it has (or has not). Those questions that the user is to reply to are the positive(X,Y) and negative(X,Y) ones. The system, therefore, might ask something like this:
Does it have hair?
Having received a reply to such a question, you want to be able to add the answer to the database, so the system will be able to use the previously gathered information when reasoning.*
For simplicity, this example program will only consider positive and negative replies, so it uses a database containing two predicates:
DATABASE
xpositive(symbol, symbol)
xnegative(symbol, symbol)
The fact that the animal doesn't have hair is represented by
xnegative(has,hair).
The rules of positive and negative then check to see if the answer is already known, before asking the user. askable
positive(X,Y) :-
xpositive(X,Y), !.
positive(X,Y) :-
not(xnegative(X,Y)),
ask(X,Y,yes).
negative(X,Y) :-
xnegative(X,Y), !.
negative(X,Y) :-
not(xpositive(X,Y)),
ask(X,Y,no).
Notice that the second rule for both positive and negative ensures that a contradiction won't arise before asking the user.
The ask predicate asks the questions and organizes the remembered replies. If a reply begins with the letter y, the system assumes the answer is Yes; if it begins with n, the answer is No.
/* Asking Questions and Remembering Answers */
ask(X, Y, yes) :- !, write(X, " it ", Y, '¡¬n'),
readln(Reply),
frontchar(Reply, 'y', _),
remember(X, Y, yes).
ask(X, Y, no) :- !, write(X, " it ", Y, '¡¬n'),
readln(Reply),
frontchar(Reply, 'n', _),
remember(X, Y, no).
remember(X, Y, yes) :- assertz(xpositive(X, Y)).
remember(X, Y, no) :- assertz(xnegative(X, Y)).
/* Clearing Out Old Facts */
clear_facts :- write("¡¬n¡¬nPlease press the space bar to exit¡¬n"),
retractall(_,dbasedom), readchar(_).
For practice, type in the preceding inference engine and knowledge clauses. Add appropriate declarations to make a complete program, and then try out the result. The completed animal expert system is provided as ch16e01.pro.
An example expert systems shell (GENI.PRO) is also provided with Visual Prolog in the PROGRAMS directory; this shell is based on the same techniques introduced in this example, with the added feature that it allows you to dynamically change the rules.