Created by Pete Barnum <pbarnum@cs.rochester.edu>
Edited by Frank Ferraro <francis.ferraro@rochester.edu>
Intro to Jess:
JESS, which stands for Java Expert System Shell, is a powerful system that allows the solution of rule-based problems. Jess is written entirely in Java and as a result, it is possible to run any Java code inside of it, with the exception of defining new classes. Jess uses a Common LISP (CLISP) type syntax and familiarity with CLISP is recommended. This tutorial will cover basic commands and usage. For a complete reference, view the Jess manual at http://herzberg.ca.sandia.gov/jess/docs/manual.pdf.
To run the Jess shell, go to the Jess root directory and run
java jess.Main
Currently, log on to the CSUG network and type
> cd /u/cs242/jess
> /usr/staff/bin/java jess.Main
Jess will display information about itself, then gives the
prompt Jess>.
From the prompt, a program can be entered in line-by-line, or else pre-made program file can be
run.
To run the JESS with a file attached, run JESS with the file name passed as an argument. A JESS file has the extension .clp. For the file myJessProgram.clp located in your working directory:
> setenv CLASSPATH ${PWD}:/u/cs242/jess
> /usr/staff/bin/java jess.Main myJessProgram.clp
If you change directories, you should run the setenv command again because ${PWD} is resolved before CLASSPATH is set.
Running with quagents is simple; just load the Quake environment before loading JESS.
Important Jess System Commands:
(batch myJessProgram.clp) Runs Jess program myJessProgram.clp
(exit) Exits the Jess Shell
(facts) Displays current facts
(rules) Displays current rules
(run) Runs the current Jess program
(reset) Resets runtime memory
Variables:
There are two types of variables in Jess, local and global. Local variables are created when first referenced and are destroyed by (reset), while globals must be declared in advance and are not destroyed by (reset).
Local Variables:
To create a new variable or to change an old one, type
Jess> (bind ?x 5) ;assigns 5 to ?x
Jess> (bind ?myList (create$ 1 2 3)) ;assigns the list (1 2 3) to myList
Jess> (bind ?ht (new java.util.Hashtable)) ;creates new hashtable ?ht
;note that Java libraries must be imported
A Jess variable can hold any type of value, including integers, strings, and external Java objects.
Global Variables:
Global variables have the form ?*variable*, and must be declared with (defglobal).
Jess> (defglobal ?*x* = 5) ;assigns 5 to ?*x*
Functions:
Jess has a number of built in functions and has the ability to let users design their own. The simplest are the arithmetic functions, +, - , *, and /:
Jess> (+ 2 3)
5
Jess> (/ 4 8)
0.5
Jess also has comparison functions, such as =, >, and >=:
Jess> (> 3 4)
Jess> (<= 3 4)
A full list of built-in Jess functions can be found in the manual.
To design a custom function in Jess, use (deffunction). The following code calculates ?a / ?b + ?c
Jess> (deffunction myMath (?a ?b ?c)
(return (+ (/ ?a ?b) ?c))
Jess> (myMath 1 2 3)
3.5
Facts:
As said in the Jess Manual in section 2.7,
"A rule-based system maintains a collection of knowledge nuggets called facts. This collection is known as the knowledge base."It is somewhat akin to a relational database, especially in that the facts must have a specific structure.
The two most useful kinds of facts are ordered and unordered. An ordered fact is simply a list, while an unordered fact is a collection of fields with values.
Ordered facts:
Ordered facts are declared using (assert).
Jess> (reset)
Jess> (assert (dog_breeds Terrier Sporting Herding))
<Fact-1>
Jess> (assert (breed_of Fido Sporting))
<Fact-2>
View all facts with (facts) and retract a single fact with (retract):
Jess> (retract (fact-id 1))
All facts can be retracted at once with (reset).
Unordered facts:
Unordered facts in Jess are similar to structs in C. Templates for unordered facts are defined using (deftemplate). Each field can hold either one or several pieces of data, using either the slot or multislot option, respectively.
Jess> (deftemplate course
"A college course"
(slot course_name)
(slot course_number)
(multislot textbooks))
Jess> (assert (course (course_name AI) (course_number 242) (textbooks AI_A_Modern_Approach Common_Lispcraft)))
<Fact-1>
Rules:
Rules are the methods that read and alter the knowledge base. Rules have two parts, the first is the circumstance that the rule can be used, and the second is the result. As an example, a hungry agent can set up a goal to eat.
Jess> (reset)
Jess> (defrule eat-lunch
(hungry)
=>
(assert (plan-to-eat)))
Jess> (assert (hungry))
<Fact-1>
Jess> (run)
1
Jess> (facts)
f-0 (MAIN::initial-fact)
f-1 (MAIN::hungry)
f-2 (MAIN::plan-to-eat)
If it is necessary to keep track of specifics, then temporary variables can be used.
Jess> (reset)
Jess> (deftemplate hungry-agent
(slot name)
(slot hungry))
Jess> (defrule eat-lunch2
?agent <- (hungry-agent (name ?name) (hungry TRUE))
(food-available)
=>
(modify ?agent (hungry FALSE))
(printout t ?name has lunch. crlf))
TRUE
Jess> (assert (food-available))
<Fact-1>
Jess> (assert (hungry-agent (name Wilbur) (hungry TRUE)))
<Fact-2>
Jess> (run)
Wilbur has lunch.
1
Jess> (facts)
f-0 (MAIN::initial-fact)
f-1 (MAIN::food-available)
f-2 (MAIN::hungry-agent (name Wilbur) (hungry FALSE))
Several things happen in the rule. A pointer to the entire agent is held in ?agent, while the agent's name is stored in ?name. There are two prerequisites, one that there is a hungry agent, and one that food is available. To change the hungry attribute, (modify) is used on the pointer to the agent.
Important Rule commands:
The boolean relations and, or, and not can be used in rules, such as (and (a) (not (b)).
Test can perform numeric comparisons, such as (test (= ?a ?b)), which will compare the temporary variables ?a and ?b and return TRUE if they are equal. Be careful not to use just (= ?a ?b) as this will simply search the facts for something like (= 1 4).
Interfacing
with Java:
Although it is possible to do almost anything to do with Java within Jess, it is often easier to write a separate Java class and interface with it. The following example calculates the nth fibonacci number with a Java method.
easy_java.clp
(defglobal ?*external-class*
= 0)
(deffunction initialize ()
(bind ?*external-class* (new easy_java)))
(initialize)
(printout
t "The 6th fibonacci number is: " (?*external-class* fibonacci 6)
crlf)
easy_java.java
public class easy_java{
public int fibonacci(int n){
if(n < 3) return 1;
else return fibonacci(n-1) + fibonacci(n-2);
}
}
To run, compile easy_java.java, then run easy_java.clp with Jess.
Jess> (batch easy_java.clp)
The 6th Fibonacci number is: 8
Just as in standard Java, an instance of the class must be declared. The first (bind) acts the same as the Java code easy_java external_class = new easy_java();. Jess doesn't require periods or parenthesis to call methods, so the call (?*external-class* fibonacci 6) is the same as external_class.fibonacci(6);.