BIS 2040 Home Page The Next Page The Next Page
Middlesex Logo

Workshop 2 Building a simple forward-chaining system

The purpose of this workshop is to :
· Show you how the objects to be found in a Kappa knowledgebase can be combined to produce a simple, working expert system containing some real knowledge.
· Introduce you to forward-chaining rule-based reasoning.

Load Kappa in the usual way.
1. Classes & slots. If we want to build a simple system, based on shallow knowledge, we only need to deal with a few objects. In this case, three class objects will do (together with some rules and a function), and they can all be subclasses of the 'Root' object. The idea is simply that we have somewhere to store the pieces of information that we are using to reach our diagnosis.
· We need somewhere to store evidence gathered from the user. In the object browser window, click on the class 'Root' and then select 'Add Subclass' from the Edit menu. Call this new class user_data. Make sure you use lower case: Kappa is case-sensitive. Double-click on this new class to edit it: this will put the class editor on screen.. Select 'New' from the 'Slots' menu. When you are asked for a name, call this new slot tank_empty. Similarly, add slots to this class called petrol_in_carburettor, engine_turns_over, and lights_turn_on. Then choose Update.Save to save the class with its slots, and Update.Close to get the editor off screen.
· We also need to store an intermediate conclusion about whether petrol is reaching the engine. Click on the class 'root' again, select 'Add Subclass' from the Edit menu, and call this new class engine. Double-click on this new class to edit it. Select 'New' from the 'Slots' menu. When you are asked for a name, call this new slot condition. Save the class as before, and close the editor.
· Add another subclass to Root, called car_problem. Double-click on this new class to edit it. Select 'New' from the 'Slots' menu. When you are asked for a name, call this new slot diagnosis. Save the class but don't close the editor.
· We must also add a monitor to the slot 'diagnosis' that we have just created, so that it provides some output when it has reached a conclusion. Choose the 'Methods' menu on the class editor, and 'New' from this menu, and make a method called report. In the 'Body' section of the method editor, type this:
PostMessage("The problem with the car is: ", car_problem:diagnosis);
[You should be quite clear what this means. It means that if the class object called 'car_problem' is asked to do something called 'report', it will put a message box on screen containing the words "The problem with the car is: ", followed by whatever it can find in the slot called 'diagnosis.'] Click on the 'Close' option on the 'Update' menu. The 'car_problem' class is now capable of reporting what it knows about the diagnosis, under the right conditions. We want it to do so whenever something new turns up in the 'diagnosis' slot. Go to the 'Slots' window in the class editor and double click on 'diagnosis'. Find the 'Monitors' section in the middle of the slot editor, and find the 'After change' subsection at the end of it. Use the 6button to get 'Report' on screen and click on it. Then click on 'OK' . Then choose the 'Save' option, and the 'Close' option, from the 'Update' menu of the class editor.

2. Rules. The and/or chart that we saw in Workshop 1 shows us that we will need six rules [refer back to it now]. Each will look for a pattern of data in the slots of the classes/instances we have just created and, if it finds it, will fire and put a piece of data in another slot somewhere. In the 'Edit Tools' window, click on the 'Rule' button and select 'New' to create a new rule. Call this rule empty_tank. In the 'If:' part of the rule editor, type:
user_data:tank_empty #= TRUE;
And in the 'Then:' part type:
{ (car_problem:diagnosis = "run out of petrol");
(engine:condition = no_petrol_reaching_engine) };
You should be very clear what this means. The first part means "Have a look at the class called 'user_data'. Have a look at the slot in it called 'tank_empty'. Make sure that what you find there is the word 'TRUE'." The second part, which will only happen if the first part is successful, says "Have a look at the class called 'car_problem'. Have a look at the slot in it called 'diagnosis'. Change whatever you find there to the words "run out of petrol". Next, have a look at the class called 'engine'. Have a look at the slot in it called 'condition'. Change whatever you find there to the word no_petrol_reaching_engine".
Notice that "#=" does not mean the same as "=". The first, "#=", means "check that the slot contains the following value", and it is used in the conditions of a rule. The second, "=", means "make the value in the slot the following", and it is used in the conclusions of rules.
Having written the rule, choose the 'Save' option, and the 'Close' option, from the 'Update' menu of the rule editor.
The next five rules are made in the same way:
· Make a rule called petrol_blocked whose 'If:' part looks like this:
(user_data:tank_empty #= FALSE) And
(user_data:petrol_in_carburettor #= FALSE);
and whose 'Then:' part looks like this:
{ (car_problem:diagnosis = "blocked feed pipe leading to carburettor");
(engine:condition = no_petrol_reaching_engine) };
· Make a rule called petrol_reaching_engine whose 'If:' part looks like this:
(user_data:petrol_in_carburettor #= TRUE;
and whose 'Then:' part looks like this:
engine:condition = petrol_reaching_engine;
· Make a rule called bad_battery whose 'If:' part looks like this:
(user_data:engine_turns_over #= FALSE) And
(user_data:lights_turn_on #= FALSE) And
(engine:condition #= petrol_reaching_engine);
and whose 'Then:' part looks like this:
car_problem:diagnosis = "battery is defective, or battery cables are defective.";
· Make a rule called bad_spark_plugs whose 'If:' part looks like this:
(user_data:engine_turns_over #= TRUE) And
(engine:condition #= petrol_reaching_engine);
and whose 'Then:' part looks like this:
(car_problem:diagnosis = "bad spark plugs";
· Make a rule called bad_starter_motor whose 'If:' part looks like this:
(user_data:engine_turns_over #= FALSE) And
(user_data:lights_turn_on #= TRUE) And
(engine:condition #= petrol_reaching_engine);
and whose 'Then:' part looks like this:
car_problem:diagnosis = "starter motor is defective";

Notice the syntax that you have to use when writing a rule. Think of something like car_problem:diagnosis = "broken down" - that is, a slot name + some sort of testing of value or allocation of value + the value in question - as an "expression". If there is just one expression to be put into the 'if-part' of a rule, you just write it, with a ";" at the end. Similarly if there's just one expression to be put into the 'then-part': you just write it, with a ";" at the end. If there is more than one expression to be put into the 'if-part', you put round brackets around each expression, and "And" or "Or" between the expressions (according to what's appropriate), and a ";" after the last one. If there is more than one expression to be put into the 'then-part', you put round brackets around each expression, and ";" between the expressions, and you also put "{" at the beginning of the whole group of expressions and "};" at the end.

3. Functions. In due course, we will want the system to use the rules to come to a conclusion. So we will make a function called 'proceed' that will start rule-based reasoning. In the 'Edit Tools' window, click on the 'Functions' button and select 'New' to create a new function. Call this function proceed. In the body of the function, type
ForwardChain([NOASSERT]);

4. Now we need to construct the user interface.
a) Click on the 'Session' button in the main KAPPA window. This will bring up a session window, and it is here that we will build the user interface to the program. Click on the window then type L to go into layout mode (alternatively, choose Options.Layout Mode). When you are more experienced, you will want to use the yellow palette of user interface images that has just appeared but, for the time being, find 'Image' on the 'Select' menu, and choose 'Check Box' from the sub-menu. A cross appears in the session window. Move this to a suitable place - I suggest about a centimetre below the 'Control' menu - and click once. Now make sure the cursor is inside the purple-cornered box that has appeared and double-click. In the CheckBox Options editor, make the following entries: set its title to No petrol in tank?, its Owner to user_data and its OwnerSlot to tank_empty. Press the OK button to save it.
b) Now make another check box in exactly the same way: position it about a centimetre below the first. Give it the following attributes: set its title to Petrol reaching the carburettor?, its Owner to user_data and its OwnerSlot to petrol_in_carburettor. Press the OK button to save it.
c) Now make another, about a centimetre below that one. Set its title to Engine turns over?, its Owner to user_data and its OwnerSlot to engine_turns_over. Press the OK button to save it.
d) Now make another, about a centimetre below that one. Set its title to Lights turn on?, its Owner to user_data and its OwnerSlot to lights_turn_on. Press the OK button to save it.
e) Now we need a button that the user can click on, in order to get a diagnosis, once they have used the check boxes to tell the system everything they know about the four symptoms. As before, find 'Image' on the 'Select' menu, but this time choose 'Button' from the sub-menu. Position it about a centimetre below the check boxes, and give it the following attributes: set its title to Proceed with diagnosis, and, in the 'Action' box, use the 6button to get 'Proceed' on screen and click on it. Click on the OK button to save it.
f) Move your cursor so that it is on a part of the session window that isn't a check box or button or the yellow palette, and double-click. In the Window Attributes editor, make the title Car trouble shooter. Press the OK button to save it.
g) Then press L to leave layout mode. The session window should now look something like this:
o No petrol in the tank?
o Petrol reaching the carburettor?
o Engine turns over?
o Lights turn on?

h) The user interface is now complete and, if you have followed all the instructions correctly, the expert system should be in good working order.

5. Testing the system. Click on the check boxes to switch on or off the various symptoms. Then click on the 'Proceed with diagnosis' button. This should produce a correct diagnosis: for instance, if only the o No petrol in the tank? box is ticked, a window should appear on screen, saying
Try out all the combinations of symptoms you can think of, and decide whether the diagnoses they produce are sensible. If anything doesn't work, see if you can find out what's gone wrong.

6. Saving. Save the program by going to the file menu in the topmost window on screen and choosing "Save As…". Call it CAR_DIAG.KAL. Save it in your own account, in a suitable folder - 'H:\work', for instance.