/*
TEACH PRBZOO                                       Aaron Sloman Nov 1995
                                          Updated for new ruleset syntax
                                                              April 1996
                          Based on lib animals, produced by Louise Pryor
                                                        in October 1993

For a general, elementary, introduction to Poprulebase, see

    TEACH * RULEBASE

-- Introduction -------------------------------------------------------

This file shows how to use Poprulebase to create a simple question
and answer program for identifying animals: a discrimination tree.

All the non-program text in this file is `commented out'. So you can
load the program by doing
    ENTER l1

This defines:

(a) a set of rules for identifying animals

(b) a set of possible initial working memories, one for each
    of four animals, called stretch, swifty, splashy, and sandy.

(c) A procedure to run the rules with a given initial working
    memory. It then attempts to identify the animal.

Note, some of the rules produce intermediate inferred results in the
database. Others produce a final answer, by adding an assertion of the
form

    [answer X is a Y]
or
    [answer X is an Y]

At that point the answer is printed out and the program stops.

-- Running the program ------------------------------------------------

Load the program by doing: ENTER l1

The program is (under some conditions) able to identify an animal as
falling into one of these categories:

    albatross cheetah giraffe ostrich penguin tiger zebra

You will get four alternative working memories to try out held in the
variables:

    stretch_wm  swifty_wm  splashy_wm  sandy_wm

You can print them out to see their contents, e.g.

    stretch_wm ==>

You can print them all out. See if you can identify the animals.

To identify one of the animals, give its working memory to the procedure
run_zookeeper. E.g.

    run_zookeeper(stretch_wm);

Try running it with the other initial working memories.

-- Running the program with more trace printing. ----------------------

You can make it tell you more about what's going on if you assign a
number to prb_chatty, coded to give more information (as described in
detail in HELP * POPRULEBASE/prb_chatty ).

    13 * 17 -> prb_chatty;

    run_zookeeper(swifty_wm);

Doing this will make it print out the state of the database more often.

    5 * 13 * 17 -> prb_chatty;

    run_zookeeper(swifty_wm);

Doing this will make it pause repeatedly. On each pause, it prints the
prompt
    Walking>
then waits for you to press RETURN:

    true -> prb_walk;
    13 * 17 -> prb_chatty;
    run_zookeeper(sandy_wm);

-- Exercises ----------------------------------------------------------

1. Try out the different working memories.

2. Study the rules given below. May a copy of them in a file of your own
   called:  prbzoo.p

   Try adding different rules to identify more types of animals, and
   produce more working memories on which to test the program.

3. Would it be possible to make the program infer additional properties,
   after it has discovered something about the test animal?

-- Further reading ----------------------------------------------------

For another tutorial example of the use of rule based programming see
TEACH * PRBWINE. This introduces an expert system for choosing a wine.

For a more general overview see: TEACH * RULEBASE

That file gives pointers to additional online information, demonstration
programs, and some relevant literature.

=======================================================================


         CONTENTS - (Use ENTER g to access required sections)

 -- Introduction
 -- Running the program
 -- Running the program with more trace printing.
 -- Exercises
 -- Further reading
 -- The zoo rules
 -- The initial databases of information about objects
 -- Now define a procedure to run the system

*/


;;; Make sure that poprulebase is compiled

uses poprulebase

;;; Turn off tracing, and pausing:

false -> prb_chatty;
false -> prb_walk;

/*
-- The zoo rules
*/
;;; First define the rule set. the rules are all added to a list called
;;; zoo_rules.


vars animal, type;

define :ruleset zoo_rules;

RULE answer_found  ;;; in zoo_rules
    [answer ?animal is = ?type]
    ==>
    ;;; print out the whole database
    [POP11 prb_print_database()]
    [STOP ANSWER the category of ?animal is ?type]

RULE Z1  ;;; in zoo_rules
    [?animal has hair]
    ==>
    [?animal is a mammal]

RULE Z2  ;;; in zoo_rules
    [?animal gives milk]
    ==>
    [?animal is a mammal]

RULE Z3  ;;; in zoo_rules
    [?animal has feathers]
    ==>
    [?animal is a bird]

RULE Z4  ;;; in zoo_rules
    [?animal flies]
    [?animal lays eggs]
    ==>
    [?animal is a bird]

RULE Z5  ;;; in zoo_rules
    [?animal is a mammal]
    [?animal eats meat]
    ==>
    [?animal is a carnivore]

RULE Z6  ;;; in zoo_rules
    [?animal is a mammal]
    [?animal has pointed teeth]
    [?animal has claws]
    [?animal has forward-pointing eyes]
    ==>
    [?animal is a carnivore]

RULE Z7  ;;; in zoo_rules
    [?animal is a mammal]
    [?animal has hooves]
    ==>
    [?animal is an ungulate]

RULE Z8  ;;; in zoo_rules
    [?animal is a mammal]
    [?animal chews cud]
    ==>
    [?animal is an ungulate]

RULE Z9  ;;; in zoo_rules
    [?animal is a carnivore]
    [?animal has tawny colour]
    [?animal has dark spots]
    ==>
    [answer ?animal is a cheetah]

RULE Z10  ;;; in zoo_rules
    [?animal is a carnivore]
    [?animal has tawny colour]
    [?animal has black stripes]
    ==>
    [answer ?animal is a tiger]

RULE Z11  ;;; in zoo_rules
    [?animal is an ungulate]
    [?animal has long legs]
    [?animal has a long neck]
    [?animal has tawny colour]
    [?animal has dark spots]
    ==>
    [answer ?animal is a giraffe]

RULE Z12  ;;; in zoo_rules
    [?animal is an ungulate]
    [?animal has white colour]
    [?animal has black stripes]
    ==>
    [answer ?animal is a zebra]

RULE Z13  ;;; in zoo_rules
    [?animal is a bird]
    [?animal does not fly]
    [?animal has long legs]
    [?animal has a long neck]
    [?animal is black and white]
    ==>
    [answer ?animal is an ostrich]

RULE Z14  ;;; in zoo_rules
    [?animal is a bird]
    [?animal does not fly]
    [?animal swims]
    [?animal is black and white]
    ==>
    [answer ?animal is a penguin]

RULE Z15  ;;; in zoo_rules
    [?animal is a bird]
    [?animal is a good flyer]
    ==>
    [answer ?animal is an albatross]
enddefine;

/*
-- The initial databases of information about objects

The objects are called stretch, swifty, splashy, and sandy.
*/

;;; Set up working memory for each animal. It is a list of assertions.
;;; We define several different initial working memories,
;;; for different animals

global vars stretch_wm, swifty_wm, splashy_wm, sandy_wm;

[[stretch has hair]
 [stretch chews cud]
 [stretch has long legs]
 [stretch has a long neck]
 [stretch has tawny colour]
 [stretch has dark spots]] -> stretch_wm;

[[swifty has hair]
 [swifty has pointed teeth]
 [swifty has claws]
 [swifty has forward-pointing eyes]
 [swifty has tawny colour]
 [swifty has dark spots]] -> swifty_wm;

[[splashy has feathers]
 [splashy lays eggs]
 [splashy does not fly]
 [splashy is black and white]
 [splashy swims]] -> splashy_wm;

[[sandy has long legs]
 [sandy has a long neck]
 [sandy has feathers]
 [sandy lays eggs]
 [sandy does not fly]
 [sandy is black and white]] -> sandy_wm;

/*
-- Now define a procedure to run the system
*/

;;; You can identify an animal using the procedure run_zookeeper with
;;; an initial working memory. For example,
;;;     run_zookeeper(sandy_wm)

define global procedure run_zookeeper(zoo_database);
    lvars zoo_database;
    ;;; Make sure it does not run the same rule twice for the same
    ;;; reason.
    false -> prb_repeating;
    ;;; Let it run all runnable rules on each cycle
    true -> prb_allrules;

    'INITIAL DATABASE' =>
    zoo_database ==>
    pr(newline);

    prb_run(zoo_rules, zoo_database)
enddefine;
/*

;;; Test it
run_zookeeper(zoo_database);

    run_zookeeper(stretch_wm);
    run_zookeeper(swifty_wm);
    run_zookeeper(splashy_wm);
    run_zookeeper(sandy_wm);
*/

/*
--- $poplocal/local/prb/teach/prbzoo
--- The University of Birmingham 1995.  --------------------------------
*/
