JESS
1. Introduccin
Jess es un shell para construir sistemas expertos escrito en Java. Jess da soporte para desarrollar sistemas expertos basados en reglas que estn totalmente integrados con aplicaciones escritas en el lenguaje Java. Jess es una biblioteca escrita en Java que sirve como un intrprete para el lenguaje Jess que es muy similar al lenguaje CLIPS que ya conocemos. La pgina oficial del sistema Jess es: http://herzberg.ca.sandia.gov/jess/ Desde all se puede descargar la biblioteca y documentacin que se puede usar para completar esta breve descripcin de las caractersticas principales de Jess y cmo intercambiar informacin con programas Java. Para usar jess necesitamos al menos la versin compilada de la biblioteca que se encuentra en el archivo jess.jar. Adems se incluye y se recomienda consultar la documentacin (/docs/index.html) o manual.pdf y los ejemplos (/examples). En el laboratorio usaremos la versin 6.2 que es para la que tenemos licencia. Actualmente est disponible la versin 7 por lo que la actualizaremos cuando tengamos la nueva licencia. No hay cambios que nos afecten entre las dos versiones.
2.
Para tener una interfaz de lnea de rdenes parecida (pero mucho ms simple) a la que manejbamos en CLIPS hay que ejecutar la clase jess.Main o jess.Console (lo ejecuta en una ventana aparte). La clase jess.Main proporciona una interfaz de lnea de comandos a Jess, pero adems es el ncleo de las interfaces grficas (jess.Console y jess.ConsoleApplet).
Ejemplos:
java jess.Main java jess.Console examples/fullmab.clp
con la distribucin binaria: java cp jess.jar jess.Main examples/fullmab.clp en una ventana aparte: java cp jess.jar jess.Console examples/fullmab.clp Tambin se puede invocar el intrprete y despus cargar los ficheros con batch: java cp jess.jar jess.Console (batch Jess60/examples/fullmab.clp) El archivo de ejemplo fullmab.clp incluye cdigo CLIPS que termina con las instrucciones: (reset) (run) La clase jess.Main lleva a cabo varias acciones: Lee un archivo de cdigo Jess (opcional, slo si se pasa como argumento en la llamada. Para ello usa la clase parser jess.Jesp. Lee y ejecuta la entrada del usuario de forma cclica.
3.
Jess puede ser utilizado de varias formas incluyendo aplicaciones de lnea de comandos, aplicaciones con interfaz grfica, servlets y applets. Se pueden desarrollar distintos tipos de aplicaciones que dependen de dnde quiera escribir el cdigo. Es decir, decidir una arquitectura en la que se escribe principalmente cdigo Java o cdigo Jess. Una forma de utilizar Jess en la que el control estar principalmente en el cdigo Java consiste en manejar objetos de la clase RETE de la biblioteca. Cada objeto rete representa un motor de razonamiento independiente, de forma que un mismo programa puede incluir varios motores independientes (cada uno con su memoria de trabajo, base de reglas, ..). Para utilizar Jess de forma incrustada en una aplicacin Java simplemente ser necesario crear uno (o ms) objetos rete y manipularlo a travs de los mtodos adecuados. Jess -1
El siguiente ejemplo muestra una forma sencilla de utilizar Jess mediante un objeto RETE
Jess -2
public static void reset() { try { m_rete.reset(); } catch(JessException je2) { System.out.println("Error: no puedo resetear "); if (je2.getNextException() != null) { System.out.println(je2); System.out.println("Nested exception is:\n"); System.out.println(je2.getNextException().getMessage()); je2.getNextException().printStackTrace(); } else je2.printStackTrace(); } } public static void run() { try { m_rete.run(); } catch(JessException je4) { System.out.println("Error: no puedo ejecutar "); if (je4.getNextException() != null) { System.out.println(je4); System.out.println("Nested exception is:\n"); System.out.println(je4.getNextException().getMessage()); je4.getNextException().printStackTrace(); } else je4.printStackTrace(); } } }
4.
Class Rete
public Value executeCommand(java.lang.String cmd) throws JessException
Call a Jess function in this engine's global context. Parameters: cmd - A string containing a value Jess function Returns: The function's result. Throws: JessException - If anything goes wrong En el cdigo se hace una llamada a la funcin batch, pero se pueden consultar otras funciones que se pueden llamar en el Apndice A de la documentacin (archivo function_index.html) Ejemplos: m_rete.executeCommand("(batch \"" + nombre + "\")"); m_rete.executeCommand("(batch jess/examples/pumps/pumps-fromjava.clp)"); m_rete.executeCommand("(reset)"); m_rete.executeCommand("(run)");
Ejemplo 2:
El siguiente ejemplo muestra cmo se puede utilizar el mtodo executeCommand para ejecutar desde Java cualquier llamada a una funcin Jess. Realmente en el ejemplo todo se hace en Jess pero controlado desde un programa Java. import jess.*; public class ExSquare { public static void main(String[] unused) { try { Rete r = new Rete(); r.executeCommand("(deffunction square (?n) (return (* ?n ?n)))"); Value v = r.executeCommand("(square 3)"); System.out.println(v.intValue(r.getGlobalContext())); // Prints '9' // La funcin intValue devuelve el contenido de v como un entero. Recibe // como parmetro el contexto actual del objeto rete. } catch (JessException ex) { System.err.println(ex); } } } C:\> java ExSquare 9 Comentarios: La clase RU (Rete Utilities) contiene utilidades generales para Jess. Es una clase sin constructor y todos sus atributos y mtodos son estticos. Funcall es una clase (subclase de ValueVector) para parsear e interpretar las llamadas a funcin. Sus instancias representan llamadas a una funcin. o Constructor de la clase Jess -4
jess.Rete.executeFunction().
Ejemplo:
Rete r = new Rete(); Context c = r.getGlobalContext(); Value dimension = new Value("dimension", RU.ATOM); Funcall f = new Funcall("defclass", r); f.arg(dimension).arg(new Value("java.awt.Dimension", RU.ATOM)); f.execute(c); new Funcall("facts", r).execute(c);
La clase Value representa los valores tipados de Jess. El mtodo type() devuelve la constante de tipo que representa el valor. Constructores: Value(boolean b) Construct a boolean value object (one of the RU.ATOMs TRUE or FALSE. Value(double d, int type) Construct a value of floating-point type. Value(int value, int type)Construct a value of integral type. Value(java.lang.Object o) Construct a value of external address type. Value(java.lang.String s, int type) Construct a value of String type. Value(Value v) Construct a value that is a copy of another Value. Value(ValueVector f, int type) Construct a value of list type.
5.
Quiz la manera ms fcil para definir templates, hechos y otros elementos es usar el lenguaje Jess y hacer que desde java (a travs de las funciones de la biblioteca) se parseen y carguen los archivos correspondientes. An as muchos de los elementos de Jess estn presentes como clases en la biblioteca Jess y se pueden utilizar para construir instancias en Java y despus aadirlas al motor de reglas explcitamente. Los siguientes mtodos de la clase Rete permiten aadir elementos a un motor de reglas (un objeto Rete):
Los siguientes mtodos de la clase Rete devuelven (dado un nombre) los elementos existentes en un motor de reglas.
Los siguientes mtodos de la clase Rete devuelven elementos java.util.Iterators para las distintas estructuras de datos de un motor de reglas: public Iterator listActivations() public Iterator listDeffacts() public Iterator listDefglobals() public Iterator listDefrules() public Iterator listDeftemplates() public Iterator listFacts() public Iterator listFunctions()
Jess -5
6.
Desde el cdigo JESS (archivos clp) se puede hacer llamadas a funciones Java usando call. Por ejemplo, observar cmo se usa para detener la ejecucin del programa: (deffacts idle-fact (idle)) (defrule sleep-if-bored (declare (salience -100)) ?idle <- (idle) => (retract ?idle) (call java.lang.Thread sleep 100) (assert (idle)))
7.
Se pueden utilizar los siguientes mtodos de la clase jess.Rete. public Value store(String name, Value val); public Value store(String name, Object val); public Value fetch(String name); public void clearStorage(); Que se corresponden con las siguientes funciones que estn disponibles en Jess: (store <name> <value>) (fetch <name>) (clear-storage) Para almacenar un valor con store se utiliza un nombre y un valor (que en Jess puede ser cualquier valor y en Java puede ser cualquier objeto jess.Value o cualquier objeto Java) Para recuperar un valor con fetch se utiliza un nombre y se devuelve cualquier valor almacenado con ese nombre (o null en Java y nil en Jess si dicho objeto no existe). Como se puede observar el mecanismo de comunicacin es realmente sencillo mediante el uso de estas dos funciones pues son complementarias. Se establece un pipeline de forma que si desde Java enviamos un objeto mediante un store, lo recogemos des de JESS con la funcin fetch, y de la misma forma si la comunicacin se realiza en el sentido inverso. Conociendo estas dos funciones vemos como seria la interaccin habitual entre Java y JESS. Slo se permite el intercambio de informacin de tipos simples pero es suficiente para las prcticas que haremos. Existen mecanismos de intercambio de informacin estructurada en forma de objetos java que se asertan como objetos o hechos CLIPS. Estas caractersticas se pueden consultar en la documentacin pero el siguiente ejemplo muestra cmo se crea un objeto en Java y se pasa a Jess que lo utiliza como argumento para definir una instancia (definstance en Jess). import jess.*; public class ExFetch { public static void main(String[] unused) throws JessException { Rete r = new Rete(); r.store("DIMENSION", new java.awt.Dimension(10, 10)); r.executeCommand("(defclass dimension java.awt.Dimension)"); r.executeCommand("(definstance dimension (fetch DIMENSION) static)"); r.executeCommand("(facts)"); } } C:\> java ExFetch f-0 (MAIN::dimension (class <External-Address:java.lang.Class>) (height 10.0) (size <External-Address:java.awt.Dimension>) (width 10.0) (OBJECT <ExternalAddress:java.awt.Dimension>)) For a total of 1 facts. Las funciones clearStorage() y clear-storage eliminan todos los valores de la tabla (se almacenan como una tabla hash).. Las funciones clear y Java clear() llamarn a clearStorage(), pero reset y reset() no lo harn. Es decir, que los datos almacenados estn disponibles tras las llamadas a reset().
Jess -6
// //
public static void reset() { try { m_rete.reset(); } catch(JessException je2) { System.out.println("Error: no puedo resetear "); if (je2.getNextException() != null) { System.out.println(je2); System.out.println("Nested exception is:\n"); System.out.println(je2.getNextException().getMessage()); je2.getNextException().printStackTrace(); } else je2.printStackTrace(); } } public static void run() { try { m_rete.run(); } catch(JessException je4) { System.out.println("Error: no puedo ejecutar "); if (je4.getNextException() != null) { System.out.println(je4); System.out.println("Nested exception is:\n"); System.out.println(je4.getNextException().getMessage()); je4.getNextException().printStackTrace(); } else je4.printStackTrace(); } } }
8.
La clase jess.Fact
La clase jess.Fact (subclase de ValueVector) se usa para representar los hechos. Cada hecho se guarda como una lista en la que las entradas se corresponden con los slots. El nombre del hecho se guarda en una variable separada (que se puede obtener a travs del mtodo getName()). Una vez que un objeto jess.Fact se aserta pasa a formar parte de las estructuras de datos internas del objeto Rete (por lo que se deja de tener el control sobre l y no se deben hacer cambios sobre sus slots ya que no se reflejan en el hecho de la parte jess). Al hacer retract del hecho, se devuelve el control sobre el objeto Fact.
Breve tutorial sobre Jess r.executeCommand("(facts)"); } } C:\> java ExPoint f-0 (MAIN::point (x 37) (y 49)) For a total of 1 facts.
Ejemplo 5: en el que el template tiene un multislot En Java, un multislot se representa mediante un objeto Value de tipo RU.LIST; el objeto Value contiene un ValueVector con los campos del multislot. import jess.*; public class ExMulti { public static void main(String[] unused) throws JessException { Rete r = new Rete(); r.executeCommand("(deftemplate vector \"A named vector\"" + " (slot name) (multislot list))"); Fact f = new Fact("vector", r); f.setSlotValue("name", new Value("Groceries", RU.ATOM)); ValueVector vv = new ValueVector(); vv.add(new Value("String Beans", RU.STRING)); vv.add(new Value("Milk", RU.STRING)); vv.add(new Value("Bread", RU.STRING)); f.setSlotValue("list", new Value(vv, RU.LIST)); r.assertFact(f); r.executeCommand("(facts)"); } } C:\> java ExMulti f-0 (MAIN::vector (name Groceries) (list "String Beans" "Milk" "Bread")) For a total of 1 facts.
9.
La clase jess.Deftemplate
Ejemplo alternativo al uso de deftemplate dentro de executeCommand que hemos usado en el ejemplo anterior. import jess.*; public class ExBuildDeftemplate { public static void main(String[] unused) throws JessException { Rete r = new Rete(); Deftemplate dt = new Deftemplate("point", "A 2D point", r); Jess -9
Breve tutorial sobre Jess Value zero = new Value(0, RU.INTEGER); dt.addSlot("x", zero, "NUMBER"); dt.addSlot("y", zero, "NUMBER"); r.addDeftemplate(dt); // Now create and assert Fact } } C:\> java ExBuildDeftemplate
PrettyPrinter
La clase jess.PrettyPrinter puede producir una salida formateada de muchos objetos Jess, por ejemplo de las clases jess.Defrule, jess.Deffunction, jess.Defquery, etc. En general de cualquier cosa que implemente la interfaz jess.Visitable. jess.PrettyPrinter se usa de forma muy simple: definir una instancia, pasar el objeto que se quiere mostrar como argumento del constructor, y llamar al mtodo toString para obtener el resultado formateado. import jess.*; public class ExPretty { public static void main(String[] unused) throws JessException { Rete r = new Rete(); r.executeCommand("(defrule myrule (A) => (printout t \"A\" crlf))"); Defrule dr = (Defrule) r.findDefrule("myrule"); System.out.println(new PrettyPrinter(dr)); } } C:\> java ExPretty (defrule MAIN::myrule (MAIN::A) => (printout t "A" crlf))
11. Aadir funciones java para que puedan ser llamadas desde jess. addUserpackage
La funcin addUserpackage de la clase Rete hace accesible cierta parte del cdigo Java para que pueda ser llamado desde el archivo jess. Por ejemplo:
rete.addUserpackage(new minesweeper.jesspackage.BoardFunctions(tablero)); hace accesible que podamos hacer desde jess las llamadas a ciertas funciones del objeto tablero. La clase aadida (en este ejemplo BoardFunctions) debe implementar jess.Userpackage
public class BoardFunctions implements jess.Userpackage { public void add(Rete engine) { engine.addUserfunction(new LevantaFunction(tablero)); /* permite la llamada tablero.levanta */ engine.addUserfunction(new MarcaFunction(tablero)); engine.addUserfunction(new DesmarcaFunction(tablero)); engine.addUserfunction(new ContenidoFunction(tablero)); engine.addUserfunction(new RandomFunction(tablero)); engine.addUserfunction(new TotalMinesFunction(tablero)); } Para cada una de las funciones se define una clase que implementa jess.Userfunction
Jess -10