We demonstrate a more modern implementation of this system in Clojure here.
“An expert system is a program capable of pairing up a set of facts with a set of rules to those facts, and execute some actions based on the matching rules. ”
At 180 centimeters, Emily Williams stands tall. She carries a “rectangular” body shape. She wants to select a purse.
We consider two fashion rules related to the selection of purses for individuals with rectangular body shapes , and reason upon them using an expert system:
- If you have a rectangular body shape and are tall, select a large purse.
- If you have a rectangular body shape and are petite, select a small purse.
Moreover, we will demonstrate “cascading effects”, where the conclusion of one rule in an expert system automatically prompts the firing of additional rules based on the conclusions of the first rule.
Notice first that variable values such as “rectangular”, “tall”, “petite”, “large”, and “small” are rather imprecise, whereas specifying Emily’s exact height in centimeters is precise. In a later post we’ll demonstrate the addition of fuzzy logic and fuzzy reasoning to our expert system to account for, say for example, differences in expert opinion about what “tall” means.
We’ll implement our example expert system in CLIPS .
Setting Up the Data Model
We define two data structures, one to hold information about the person whom a purse recommendation is to be made for, and one to contain the purse recommendation itself. The latter is really unnecessary; just something we are supplying to demonstrate a cascade effect.
The first data structure:
(deftemplate person (slot name (type SYMBOL)) (slot height (type SYMBOL)) (slot favorite-color (type SYMBOL)) (slot body-shape (type SYMBOL)) )
Basically we create a record of a person’s features such as their name and height. We’ll use the height and body-shape features to match to the fashion rules detailed above, use the name feature for output, and the favorite-color feature to demonstrate a cascade effect.
The second data structure:
(deftemplate purse-recommendation (slot purse-size (type SYMBOL)) (slot for-whom (type SYMBOL)) )
In this we store a recommended purse size and, for clarity, a reference to whom the recommendation applies to.
The Fact Repository
The rules of an expert system operate on a universe of facts presented to it, which we call the “fact repository”. These facts may be simple, as in:
(assert (pi 3.14159))
or they may employ a data structure such as the ones we defined above:
(assert (person (name Emily) (height tall) (favorite-color pink) (body-shape rectangular))) (assert (person (name Sally) (height petite) (favorite-color blue) (body-shape rectangular)))
Defining the Recommendation Rules
We define two almost identical rules to match body shape and height to a purse recommendation, one for tall individuals and one for petite individuals. Note that we could combine these into one rule with IF-THEN-ELSE logic (we are not yet sure which design pattern proves most effective for expert system construction):
(defrule make-a-purse-recommendation-for-rectangular-body-shape-tall-body-height (person (name ?n) (height tall) (body-shape rectangular) ) => (printout t ?n " should carry a large purse." crlf) (assert (purse-recommendation (purse-size large) (for-whom ?n))) )
(defrule make-a-purse-recommendation-for-rectangular-body-shape-petite-body-height (person (name ?n) (height petite) (body-shape rectangular) ) => (printout t ?n " should carry a small purse." crlf) (assert (purse-recommendation (purse-size small) (for-whom ?n))) )
The first rule fires for each person existing in the fact repository having a rectangular body shape and tall stance. The second rule works similarly for those with rectangular body shapes and petite stance. Each creates a new fact asserting a purse size recommendation tied to the name of the individual the recommendation is for. Notice the use of the variable ?n for name; this provides the means to transfer information from the pattern-matching section of the rule to the activity section of the rule.
Defining a Rule that Demonstrates a Cascade Effect
The “assert” command in each rule above adds a new fact to the fact repository. Immediately upon generation, if the fact is a purse recommendation, the following rule responds:
(defrule show-a-cascade-effect (purse-recommendation (purse-size ?q) (for-whom ?n)) (person (name ?n) (favorite-color ?c)) => (printout t "CASCADE EFFECT: " ?n " should sport a " ?q ", " ?c " purse!" crlf) )
This matches any purse recommendation, saving the recommended size as ?q and the individual for whom the recommendation was made as ?n. It then matches individuals of name ?n to determine their favorite color ?c. Finally, it outputs customized text using these variables.
The Expert System In Action
Suppose we have entered all the data structures, facts, and rules specified above. We first examine the fact repository to clarify our starting point before running the system:
CLIPS> (facts) f-1 (pi 3.14159) f-2 (person (name Emily) (height tall) (favorite-color pink) (body-shape rectangular)) f-3 (person (name Sally) (height petite) (favorite-color blue) (body-shape rectangular)) For a total of 3 facts.
We then run the system and observe the following output:
CLIPS> (run) Sally should carry a small purse. CASCADE EFFECT: Sally should sport a small, blue purse! Emily should carry a large purse. CASCADE EFFECT: Emily should sport a large, pink purse!
We can see that new facts have been defined corresponding to each individual’s purse recommendations:
CLIPS> (facts) f-1 (pi 3.14159) f-2 (person (name Emily) (height tall) (favorite-color pink) (body-shape rectangular)) f-3 (person (name Sally) (height petite) (favorite-color blue) (body-shape rectangular)) f-4 (purse-recommendation (purse-size small) (for-whom Sally)) f-5 (purse-recommendation (purse-size large) (for-whom Emily)) For a total of 5 facts.
This example demonstrates a simple expert system in action. Importantly, we observed how the fulfillment of one rule automatically enables the triggering of another rule based on the first rule’s conclusions—we do not have to explicitly program this behavior.
What we don’t know (yet) is how easy it is to mix a system like CLIPS with external input given through a web form or app. CLIPS is written in C, so we can interact with it via Python (and therefore Django) using SWIG. However, other expert system platforms exist which might be easier to build a customer-facing solution out of.
As alluded to above, we did not discuss fuzzy reasoning in this post, despite the fact that the variable values we encountered in this demonstration prove inherently imprecise. We’ll address that in a forthcoming article.