CLIPS - first contact

CLIPS(C Language Integrated Production System) is an expert system tool. It is designed to facilitate the development of software to model human knowledge or expertise.

There are three ways to represent knowledge in CLIPS:

  • rules - primarily intended for heuristic knowledge based on experience
  • deffunctions and generic functions - primarily intended for procedural knowledge
  • object-oriented programming - intended for procedural knowledge. It supports classes, message-handlers, abstraction, encapsulation, inheritance and polymorphism

You can develop software using only rules, only objects or both. CLIPS can be used as a standalone tool or called from other languages such as C, C++ or Java.

Let's start

To start CLIPS type in clips in console. You'll get a window with command prompt CLIPS>. This is where you type in your commands and programs.

References

CLIPS:Wikipedia:en CLIPS - a tool for building Expert Systems NASA CLIPS rule-based language Expert system tool

Some important commands:

  • (load “prog.clp”) load prog.clp file to environment
  • (run) execute a CLIPS program
  • (clear) removes all rules and facts from memory
  • (reset) removes all facts from memory but not rules
  • (exit) exits CLIPS

You can create an empty file with *.clp extension and there write all your rules. It is better solution than typing them in each time You start CLIPS. Remember that You can't put facts into *.clp file in the same way as you can from the command prompt, so for now you’ll still enter them from command prompt. To save rules written in CLIPS command line write (save “my-work.clp”). It will save rules from memory in my-work.clp file.

Facts & rules

CLIPS operates by maintaining a list of facts and a set of rules operating on them. Fact is a basic informations created by asserting them onto the fact database:

CLIPS> (assert (colour blue))
<Fact-0>
CLIPS> (assert (colour red))
<Fact-1>

CLIPS provide basic arithmetical and math functions +, -, *, /, div, max, min, abs, float and integer:

CLIPS> (assert (number (sqrt (* (* 2 3) (+ 1 5)))))
<Fact-0>
CLIPS> (facts)
f-0     (number 6.0)
For a total of 1 fact.

It is possible to assert more facts at once:

(assert (colour red) (colour green) (colour white))
<Fact-3>
CLIPS> (facts)
f-0     (initial-fact)
f-1     (colour red)
f-2     (colour green)
f-3     (colour white)
For a total of 4 facts.

Other example:

CLIPS> (assert (name-of-dog "\"Beethoven\""))
<Fact-0>
CLIPS> (facts)
f-0     (name-of-dog ""Beethoven"")
For a total of 1 fact.

Note, that if You try to assert fact that is already in fact database you'll get the false. You can your fact database typing in (facts):

CLIPS> (facts)
f-0     (colour blue)
f-1     (colour red)
For a total of 2 facts.

Fact may be removed from the fact database using the retract command. To retract fact you must specify the fact-index(not the fact itself). Fact-indices are not reused.

CLIPS> (retract 0)
CLIPS> (facts)
f-1     (colour red)
For a total of 1 fact.

Two useful commands allow You to save and load facts using a file. There are (save-facts “my-facts-file”) and (load-facts “my-facts-file”)

Exercise
  1. What is a difference between two facts: (black) and (black nil)? Symbol nil means nothing(just like null in C).

Facts only keeps information. To develop a program capable of some useful functions you need a set of rules. A rule is expressed in the form IF something is true THEN do some actions. General syntax of rule looks like:

(defrule rule-name "optional comment"
  (pattern 1)
  (pattern 2)
  ...
  (pattern N)
  =>
  (action 1)
  (action 2)
  ...
  (action M))

If all patterns of a rule match facts, the rule is activated and put on the agenda. The agenda is a collection of activations which are those rules which match patters entities.

(defrule dog
  (animal-is dog)
  =>
    (assert (dog_sound-is bark)))

The rule consists of three parts. In the sample rule, the first part (defrule dog gives the rule a unique name, the second part (animal-is dog) is a pattern of the rule (IF) and the part (assert (sound-is bark)) is the actions of the rule(THEN). This rule means if there is a fact animal-is dog on the facts database then assert another fact (sound-is bark)) onto the fact database.

Execute the sample rule:

CLIPS> (defrule dog
  (animal-is dog)
  =>
    (assert (dog_sound-is bark)))
CLIPS> (rules)
dog
For a total of 1 defrule.
CLIPS> (facts)
f-0     (initial-fact)
For a total of 1 fact.
CLIPS> (assert (animal-is dog))
<Fact-1>
CLIPS> (facts)
f-0     (initial-fact)
f-1     (animal-is dog)
For a total of 2 facts.
CLIPS> (run)
CLIPS> (facts)
f-0     (initial-fact)
f-1     (animal-is dog)
f-2     (dog_sound-is bark)
For a total of 3 facts.

To get list of rules present in the system type rules. At the beginning there are no facts present. After asserting animal-is duck fact there is one fact in facts database. To trigger the rule type (run). Then check the fact list again and you'll see that there is a new fact inferred by the rule. This is the power of rule-based programming.

Rules may have more than one pattern but then all must be satisfied for the action to be taken. The action part of rule can also have multiple actions.

Check another sample:

CLIPS> (defrule duck
  (animal-is duck)
  =>
  (assert (sound-is quack)) 
  (printout t "Asserted sound-is quack" crlf))
CLIPS> (defrule is-it-a-duck
  (animal-has webbed-feet)
  (animal-has feathers)
  =>
  (assert (animal-is duck))
  (printout t "Asserted animal-is duck" crlf))
CLIPS> (assert(animal-has webbed-feet))
<Fact-0>
CLIPS> (assert (animal-has feathers))
<Fact-1>
CLIPS> (run)
Asserted animal-is duck
Asserted sound-is quack

Firstly, rule is-it-a-duck has asserted the fact (animal-is duck). This fact has then triggered rule duck, which has asserted the fact (sound-is quack). Very powerful systems can be built using this ability to chain rules.

Now try to develop more powerful program, for example an expert system to determine how a mobile robot should respond to a traffic light.

"Stop and go" example

Example rules for the red and green lights can be written as follows:

(defrule stop "if light is red wait for green"
  (light red)
  (not (light green))
  =>
    (printout t "Red Light, don't go!" crlf))
 
(defrule go "if there is green light go"
  (light green)
  (not (light red))
  =>
    (printout t "Green light, go!" crlf))

Now assert new fact (light red) or (light green) and run the program. There is used (not) function; it is predefined logical function of negation. The patterns

  (light green)
  (not (light red)

means that in fact database must exists (light green) fact and must NOT exists (light red) fact to fire the rule.

Think about other possibilities of beside the simple lights. Rewrite the program…

Alternative way to enter facts

It is possible to load facts from a file using keyword deffacts, for example:

(deffacts walk "some facts about \"stop and go \" sample"
  (light green)
  (status walking)
  (walk-sign walk))

Now, after loading file to CLIPS it is needed to (reset) - causes facts from deffacts to be asserted.

The undeffacts command removes deffacts from the memory. To restore a deffacts statement after an (undeffacts) command, You must enter the statement again. In additional to facts it is possible to eliminate rules selectivity by using the (undefrule). Other useful command are list-deffacts - lists the names of currently loaded deffacts, and ppdeffacts - print the facts stored in a deffacts.

CLIPS> (list-deffacts)
initial-fact
walk
For a total of 2 deffacts.
CLIPS> (ppdeffacts walk)
(deffacts MAIN::walk "some facts about \"stop and go \" sample"
   (light green)
   (status walking)
   (walk-sign walk))

Debugging CLIPS programs

Basic tool for debugging programs is to watch asserting and retracting facts using (watch facts):

CLIPS> (watch facts)
CLIPS> (assert (colour red))
==> f-1     (colour red)
<Fact-1>
CLIPS> (retract 1)
<== f-1     (colour red)

=⇒ means that new fact is entering the memory, while ⇐= means the fact is leaving memory.

Other helpful commands in debugging:

  • (watch facts)
  • (watch instances)
  • (watch slots) *
  • (watch rules)
  • (watch activations)
  • (watch messages) *
  • (watch message-handlers) *
  • (watch generic-functions)
  • (watch methods) *
  • (watch deffunctions)
  • (watch compilation) ;on by default
  • (watch statistics)
  • (watch globals)
  • (watch focus)
  • (watch all) ;watch everything

* - used with objects

To turn off watch command use unwatch.

© Antoni Ligeza 2009 Driven by DokuWiki