A gentle introduction to CLIPS for CogSci Students

(see also Clips Blurb)

Last modified:  3/11/06

CLIPS is an industrial strength expert system shell.  That is, one can use CLIPS to generate powerful industrial-strength expert systems.  In this class we will examine only a few of the basic elements of the system.

Templates, facts, and rules

Recall that an expert system contains a database which in turn contains a series of facts and rules (productions).

Facts come in two varieties:  structured facts (templates) and ad-hoc facts.  The templates for structured tasks are specified by the deftemplate command:

    (deftemplate aTemplate "some documentation"

        (slot slot1)

        (slot slot2)

            (etc.)

    )

For example, suppose that we want to establish a structure for a student at Puget Sound.  We might want to store the student's student number, name, major, and name of advisor.  A template for doing this is given by

    (deftemplate student "A student template"

        (slot sno)

        (slot sname)

        (slot major)

        (slot advisor)

    )

 

Asserting facts

There are two ways of introducing facts into the CLIPS database.  One way is to include them in a set of initial facts

    (deffacts initial-facts

        (student (sno 123) (sname maigret) (major pre-med)

            (advisor simenon)) ... )

 

deffacts are asserted after the CLIPS file containing them has been loaded into CLIPS (see below) and then after the (reset) command.

Another way to assert a fact is to assert it "on the fly", generally as an action in a rule:

    (assert (student (sno 123) (sname maigret)

        (major pre-med) (advisor simenon)))

Notice that, just as in LISP, parenthesis are important.  Although CLIPS was written in C (the letters CLI in CLIPS stand for "C Language Implementation"), the syntax for using CLIPS is very much LISP-like.

Note:  While running clips, keep your eye on the facts window, and you will see the facts you have written being added to the database.

Non-structured facts

It is sometimes convenient to have a series of ad-hoc facts in the database, as well as the structured ones.  These are simply lists of words between parenthesis, such as:

    (alarm on)

    (alarm off)

    (temperature high)

    (valve a3572 open)

Rules

The basis for a production system, of course, is the collection of condition-action rules.  The syntax for defining a rule is

(defrule rule-name "some documentation"

    (if-condition)

    (if-condition)

    (etc.)

=>

    (action 1)

    (action 2)

    (etc.)

)

For example:

(defrule useful-rule "a useful rule"
                    (animal fierce)
                    (animal big)
                    (animal hungry)
                =>
                    (assert (run away))
                )
 

What this means is that if we have the following (unstructured) facts in our database

                    (animal fierce)
                    (animal big)
                    (animal hungry)
 

then all of the preconditions have been met to fire useful-rule, and we assert (run away) into the database.

 

We will see some more examples in a moment.  First, let's talk about running CLIPS.

 

Running CLIPS

You need to have two programs to run clips

    clipsedt - edit clips files

    clipswin - the CLIPS program for windows

Copies of these are available in my handouts folder under CLIPS.

Example 1:  There is a file in the handouts folder called example1.clp

  1. Copy this into your workspace
  2. Double-click clipsedt to start the program
  3. In clipsedt, open the example1.clp file.  Look it over.
  4. Open clipswin (double-click)
  5. In the file menu, select load (cntrl-L) and load example1.clp
  6. Select the facts and agenda windows (or all of them if you would prefer)
  7. Type (reset) or select it from the execution menu.  Note the facts defined in deffacts appearing in the facts window.  Notice also that our only rule appears in the agenda window.
  8. Step through the program, watching what happens to the facts window.

Congratulations!  You have run your first CLIPS program!

 

Some other features in rules:

Pattern matching

Suppose that we have a fact such as

    (deftemplate student "a student template"
        (slot sname)
        (slot major)
        (slot interest))

(deffacts inital-facts "some initial facts"
    (student (sname dee) (major law))
)

And we would like to look through our database and collect students majoring in law and add to our database the fact that these students are interested in law.  The following rule would do this (this is in example2.clp).:

(defrule rule-1 "a first rule"
    (student (sname ?name) (major law))
=>
    (assert (law-interest ?name))
)

This rule says that if there is anything in our database asserting that a student with some name is majoring in law (major law), then we want to add to our database the fact that this student is interested in law.  The use of ?name is important.  Putting a question mark before a name says that if we find in our database a student with a name and with a law major, we put the name of that student into ?name and then use the same name in further pattern matching in the if-part and then-part of the rule.  If we use the same variable in different parts of the if-part, the same values must be used.  For example (this from student.clp) if we have a rule with

(defrule suggest-math-rule
    (interest ?sno math)
    (ability ?sno math)
    (student (sno ?sno) (sname ?sname))
=>
    (assert (suggest ?sno take-math))
    (printout t "We suggest that " ?sname "take some more math")
)

the ?sno matched in the first rule must be the same in the rest of the rule.

Note the printout statement.  This is as far as we need take that statement for this course.

Exercise:  Try playing with example2.clp.  Important Note:  before loading the new file into CLIPS, it is necessary to clear CLIPS memory.  We do this with the (clear) command (or use the menus).

One final bit, and we will have all we need for CLIPS for this course.  There are, of course, many more details which can be found in the powerpoint slides and in various books on expert systems (Giatanno is one excellent source).  In the above, we added a new fact to our database to express the fact that our student was interested in law.  But why add a rule when there is already a slot in the template for student to store the student's interest?  We would like to add this fact to our existing student record.  To do this we need to modify an existing fact.  The following rule does this:


(defrule rule-2 "a second rule"
    ?f1 <- (student (sname ?name) (major law) (interest nil))
=>
    (modify ?f1 (interest law))
)

The "(interest nil) says that this rule should fire only if we don't have a value for interest yet.  The ?f1 does two things (although any variable name will do, that is ?anyname, CLIPS programmers generally use ?f1, ?f2, and so forth).  In the first occurrence of ?f1,  ?f1 <- (student (sname ?name) (major law)), we bind the fact number of the fact into the variable ?f1.  We can then use that stored value to modify the rule by changing the value of the existing (slot interest) with the value (interest law).  There must be a slot with this name, otherwise nothing works.

Exercise:  Try this out.  This is also in example2.clp.  When you run rule-2, note that the original fact about Dee has been replaced by a new fact.  Modify works by throwing the old fact away and asserting a new fact (behind the scenes, of course).

That's it!  You have enough for the current CLIPS exercise.  Any questions, please ask!

 

A few more examples.

 

The following examples can be found on the lab server \\hedwig under Matthews Handouts:

 

Example2.clp

;
; This example illustrates three ideas:
; 1. The use of a structured frame (deftemplate)
; 2. The use of variables (?name)
; 3. A way to modify an existing frame
;

(deftemplate student "a student template" 
(slot sname) 
(slot major) 
(slot interest)) 
;
; This defines a frame with three slots (sname, major, interest)
; 
(deffacts initial-facts "some initial facts" 
(student (sname dee) (major law)) 
) 
;
; Remember that initial-facts will be loaded into the
; CLIPS database when a (reset) command is issued.
; 
(defrule rule-1 "a first rule" 
(student (sname ?name) (major law)) 
=> 
(assert (law-interest ?name)) 
) 
;
; This first rule says that if we find a student frame
; in the database, we will grab the value in the 'sname' slot
; and place the value we find there into the variable ?name. All
; variables in CLIPS begin with an initial question mark.
; After doing this, we then assert into the database a fact 
; (law-interest ?name)
; The ?name picked up from the student frame is inserted. Since we
; know that Dee (Judge Dee, middle Tang dynasty) is majoring in law,
; the result will be to add a fact that (law-interest dee)
; 
(defrule rule-2 "a second rule" 
?f1 <- (student (sname ?name) (major law) (interest nil)) 
=> 
(modify ?f1 (interest law)) 
) 
;
; In this rule we modify the student frame for students whose major 
; is law. (major law) in a student frame indicates that the student's
; major is law. (interest nil) means that we do not yet have any
; interest value for this student. The use of ?f1 says that if we find
; such a record (Dee again, in this case) we store an identifier to that
; frame in the variable ?f1. In the "then-part" of the rule, we modify
; that rule to add that the student (Dee again) is interested in law.
; This is actually a deletion of the first frame and an insertion of the
; modified frame) 

Example 3.clp

;
; This example illustrates a basic use of the printout command:
;

(deftemplate student "a student template" 
(slot sname) 
(slot major) 
(slot interest)) 
;
; This defines a frame with three slots (sname, major, interest)
; 
(deffacts initial-facts "some initial facts" 
(student (sname dee) (major law)) 
) 
;
; Remember that initial-facts will be loaded into the
; CLIPS database when a (reset) command is issued.
; 
(defrule rule-1 "a first rule" 
(student (sname ?name) (major law)) 
=> 
(assert (law-interest ?name))
(printout t ?name " would be interested in Law" crlf) 
) 
;
; Notice the format of the printout command. The 't' is
; there to say that the output should go to the terminal
; (stdout). Variables can be mixed with text (in double-
; quotes). crlf means produce a carriage return at the 
; end of the text. 

Example 4.clp

;
; This example illustrates a basic use of read and test:
;

(deftemplate student "a student template"
(slot sname)
(slot major)
(slot interest))
;
; This defines a frame with three slots (sname, major, interest)
;
(deftemplate enroll "enrollment records"
(slot sname)
(slot cname)
(slot grade))
(deffacts initial-facts "some initial facts"
(student (sname dee) (major law))
(enroll (sname dee) (cname STS350) (grade nil))
)
;
; Remember that initial-facts will be loaded into the
; CLIPS database when a (reset) command is issued.
;

(defrule ask-grade-rule
(student (sname ?name))
?f1 <- (enroll (sname ?name) (cname ?cnme) (grade nil))
=>
(printout t "Please enter the grade in " ?cnme " for " ?name "-->")
(bind ?score (read))
(modify ?f1 (grade ?score))
)
;
(defrule check-grade-rule
(student (sname ?name))
(enroll (sname ?name) (cname ?cnme) (grade ?sgrade))
(test (numberp ?sgrade))
(test (>= ?sgrade 3.0))
=>
(printout t "Student " ?name " did well in " ?cnme crlf)
)

SCXTAdvise.clp

(deftemplate student "A student frame"
(slot sno)
(slot sname)
(slot major)
(multislot interests))
(deftemplate enroll "students enrolled in classes"
(slot sno)
(slot cno)
(slot grade (type NUMBER)))
(deftemplate class "classes students take"
(slot cno)
(slot cname)
(slot dept))
(defrule cogsci-rule-1
(student (sno ?sno) (sname ?sname) (major ?major)
(interests $? psych $?))
=>
(printout t ?sname "would be interested in SCXT 350" crlf)
)
;
(deffacts Initial-facts
(student (sno s01) (sname Poirot) (major csci)
(interests music go psych ceramics))
)

A slightly more complicated example:  student.clp

(deftemplate student "A student record"
(slot sno)
(slot sname)
(slot major)
(slot wcomm)
(slot scxt)
(slot units) ; Number of units passed
(slot satm)
(slot satv))
;
(deftemplate enroll
(slot sno)
(slot cno))
;
(deftemplate class
(slot cno)
(slot cname)
(slot dept))
;
(defrule suggest-math-rule
(interest ?sno math)
(ability ?sno math)
=>
(assert (suggest ?sno take-math))
)
;
(defrule find-math-interest
(student (sno ?snumb))
(enroll (sno ?snumb) (cno ?cnumb))
(class (cno ?cnumb) (dept math))
=>
(assert (interest ?snumb math))
)
;
(defrule find-math-ability
(student (sno ?snumb) (satm ?score))
(test (and (numberp ?score)
(> ?score 600)))
=>
(assert (ability ?snumb math))
)
;
(deffacts initial-facts
(student (sno 123) (sname "Marple"))
(enroll (sno 123) (cno 321))
(class (cno 321) (cname "Naive Quantum Mechanics") (dept math))
)
;
(defrule ask-satm-rule
?f1 <- (student (sno ?snumb) (sname ?name) (satm nil))
=>
(printout t "Please enter the sat math score for " ?name " ")
(bind ?score (read))
(modify ?f1 (satm ?score))
)

Finally, two (or three) examples of "Fuzzy Clips"  You can edit these files using CLIPSEdt, but you must run  them using FZClips (in the handouts folder)

 

FZStudent.clp

(deftemplate FZscore
0 800 pts
((high (400 0) (800 1))))
;
; This template tells us that if a "fuzzy score" 
; is 400 or less, we do not consider it a high score.
; If the score is 800 or greater we consider it a
; high score with 100% confidence. Between 400 points
; and 800 points, our confidence in calling the score 
; a high score increases (linearly) as the score moves
; between 400 and 800.
;
(deftemplate student "A student record"
(slot sno)
(slot sname)
(slot major)
(slot wcomm)
(slot scxt)
(slot units) ; Number of units passed
(slot satm (type FUZZY-VALUE FZscore))
(slot satv))
;
(deftemplate enroll 
(slot sno)
(slot cno))
;
(deftemplate class
(slot cno)
(slot cname) 
(slot dept))
;
(defrule suggest-math-rule 
(interest ?sno math)
(ability ?sno math)
=>
(assert (suggest ?sno take-math))
)
;
(defrule find-math-interest
(declare (CF 0.9))
;
; CF is a "confidence factor".
;
(student (sno ?snumb))
(enroll (sno ?snumb) (cno ?cnumb))
(class (cno ?cnumb) (dept math))
=> 
(assert (interest ?snumb math))
;
; The assertation will come with a confidence factor
;
)
;
(defrule find-math-ability
(student (sno ?snumb) (satm high))
=> 
(assert (ability ?snumb math))
)
;

(deffacts initial-facts
(student (sno 123) (sname "Marple") 
(satm (699 0) (700 1) (701 0)))
;
; This is a way of saying that the sat math score is 700,
; but presenting it as a distribution.
;
(enroll (sno 123) (cno 321))
(class (cno 321) (cname "Naive Quantum Mechanics") (dept math))
)
;

Several more examples:

FZ-1.clp

;
; Example from page 351 of Durkin written in Fuzzy Clips
;
(deffacts initial-list "initial facts"
(I-believe-in-rain) CF 0.95
(Weatherman-believes-in-rain) CF 0.85
)
;
(defrule Rule1a
(declare (CF 0.9))
(weather lousy)
=>
(assert (no-ballgame))
)
;
(defrule Rule1b
(declare (CF 0.9))
(mood lousy)
=>
(assert (no-ballgame))
)
;
(defrule Rule2
(declare (CF 0.8))
(I-believe-in-rain)
=>
(assert (weather lousy))
)
;
(defrule Rule3
(declare (CF 0.9))
(I-believe-in-rain)
(Weatherman-believes-in-rain)
=>
(assert (mood lousy))
)
;
(defrule Rule4
(declare (CF 0.7))
(Weatherman-believes-in-rain)
=>
(assert (weather lousy))
)
;
(defrule Rule5
(declare (CF 0.95))
(weather lousy)
=>
(assert (mood lousy))
)

FZ-2.clp:

; An example of a fuzzy fact
;
; (from the Fuzzy Clips documentation, page 5.2)
;
(deftemplate temperature
0 100 C
( (cold (0 1) (25 0))
(hot (20 0) (100 1))
))
;
(defrule rule1
(temperature hot)
=>
(printout t "it's hot" crlf)
(assert (fact1))
)
;
(defrule rule2
(temperature cold)
=>
(printout t "it's cold" crlf)
(assert (fact 2))
)
;
(deffacts initial-facts (temperature (67 0) (68 1) (69 0)))
;(deffacts initial-facts (temperature (22 0) (23 1) (24 0)))