Tutorial Breve Jess Con Java

Breve tutorial sobre Jess Belén Díaz Agudo JESS 1. Introducción Jess es un shell para construir sistemas expertos es

Views 120 Downloads 51 File size 277KB

Report DMCA / Copyright

DOWNLOAD FILE

Recommend stories

Citation preview

Breve tutorial sobre Jess

Belén Díaz Agudo

JESS 1.

Introducción

Jess es un shell para construir sistemas expertos escrito en Java. Jess da soporte para desarrollar sistemas expertos basados en reglas que estén totalmente integrados con aplicaciones escritas en el lenguaje Java. Jess es una biblioteca escrita en Java que sirve como un intérprete para el lenguaje Jess que es muy similar al lenguaje CLIPS que ya conocemos. La página oficial del sistema Jess es: http://herzberg.ca.sandia.gov/jess/ Desde allí se puede descargar la biblioteca y documentación que se puede usar para completar esta breve descripción de las características principales de Jess y cómo intercambiar información con programas Java. Para usar jess necesitamos al menos la versión compilada de la biblioteca que se encuentra en el archivo jess.jar. Además se incluye y se recomienda consultar la documentación (/docs/index.html) o manual.pdf y los ejemplos (/examples). En el laboratorio usaremos la versión 6.2 que es para la que tenemos licencia. Actualmente está disponible la versión 7 por lo que la actualizaremos cuando tengamos la nueva licencia. No hay cambios que nos afecten entre las dos versiones.

2.

Interfaz de línea de órdenes

Para tener una interfaz de línea de órdenes parecida (pero mucho más simple) a la que manejábamos 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 línea de comandos a Jess, pero además es el núcleo de las interfaces gráficas (jess.Console y jess.ConsoleApplet).

Ejemplos: java jess.Main java jess.Console

examples/fullmab.clp

ó con la distribución binaria: java –cp jess.jar jess.Main examples/fullmab.clp ó en una ventana aparte: java –cp jess.jar jess.Console examples/fullmab.clp También se puede invocar el intérprete y después cargar los ficheros con batch: java –cp jess.jar jess.Console (batch “Jess60/examples/fullmab.clp”) El archivo de ejemplo fullmab.clp incluye código CLIPS que termina con las instrucciones: (reset) (run) La clase jess.Main lleva a cabo varias acciones:  Lee un archivo de código Jess (opcional, sólo 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 cíclica.

3.

Formas de uso de Jess

Jess puede ser utilizado de varias formas incluyendo aplicaciones de línea de comandos, aplicaciones con interfaz gráfica, servlets y applets. Se pueden desarrollar distintos tipos de aplicaciones que dependen de dónde quiera escribir el código. Es decir, decidir una arquitectura en la que se escribe principalmente código Java o código Jess. Una forma de utilizar Jess en la que el control estará principalmente en el código 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 aplicación Java simplemente será necesario crear uno (o más) objetos rete y manipularlo a través de los métodos adecuados. Jess -1

Breve tutorial sobre Jess

Belén Díaz Agudo

El siguiente ejemplo muestra una forma sencilla de utilizar Jess mediante un objeto RETE

Ejemplo 1 (este código está en el CV) import jess.*; import java.io.*; public class Jesster { // The inference engine private static Rete m_rete; // Fichero que almacena el fuente del programa clips que vamos a cargar private static String programaFuente; // Constructor public Jesster() { m_rete = new Rete(); programaFuente = "wordgame.clp"; cargaPrograma(programaFuente); System.out.println("Cargando programa " + programaFuente + " "); } public static void main(String[] args) { int choice; int i; Jesster jesso; jesso = new Jesster(); jesso.reset(); jesso.run(); jesso.listaHechos(); jesso.halt(); } // obtiene e imprime la lista de hechos public static void listaHechos() { java.util.Iterator iterador; // java.util.Iterator iterador= m_rete.listFacts(); while (iterador.hasNext()) { System.out.println(iterador.next()); } } public static void halt() { try { m_rete.halt(); } catch (JessException je3) { System.out.println("Error: no puedo detener programa "); } } public static void cargaPrograma(String nombre) { try { m_rete.executeCommand("(batch \"" + nombre + "\")"); } catch(JessException je0) { System.out.println("Error: no puedo leer programa " + nombre); if (je0.getNextException() != null) { System.out.println(je0); System.out.println("Nested exception is:\n"); System.out.println(je0.getNextException().getMessage()); je0.getNextException().printStackTrace(); } else je0.printStackTrace(); } }

Jess -2

Breve tutorial sobre Jess

Belén Díaz Agudo

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.

Métodos de la clase Rete que aparecen en el ejemplo (extraidos de la documentación):

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 código se hace una llamada a la función batch, pero se pueden consultar otras funciones que se pueden llamar en el Apéndice A de la documentación (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)");

public void halt() throws JessException Stop the engine from firing rules.

public void reset()throws JessException Reset the Rete engine. Remove all facts, activations, etc. Clear all non-globals from the global scope. Assert (initial-fact). Broadcasts a JessEvent of type RESET. Jess -3

Breve tutorial sobre Jess

Belén Díaz Agudo

Throws:

JessException - If anything goes wrong. Es equivalente a:

m_rete.executeCommand("(reset)");

public int run()throws JessException Run the actual engine. Returns: The number of rules fired Throws: JessException - If anything goes wrong. Es equivalente a:

m_rete.executeCommand("(run)");

public java.util.Iterator listFacts() Return an Iterator over all the facts currently on the fact-list Otras funciones que pueden ser útiles:

public Fact assertFact(Fact f)throws JessException Assert a fact Parameters: f - A Fact object. This fact becomes the property of Jess after calling assertFact() -- don't change any of its fields until the fact is retracted! Returns: The fact ID on success, or -1. Throws: JessException - If anything goes wrong

public Fact retract(Fact f) throws JessException Retract a fact. Parameters: f - A Fact object. Doesn't need to be the actual object that appears on the fact-list; can just be a Fact that could compare equal to one. Throws: JessException - If anything goes wrong.

Ejemplo 2: El siguiente ejemplo muestra cómo se puede utilizar el método executeCommand para ejecutar desde Java cualquier llamada a una función 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 función intValue devuelve el contenido de v como un entero. Recibe // como parámetro 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 métodos son estáticos.  Funcall es una clase (subclase de ValueVector) para parsear e interpretar las llamadas a función. Sus instancias representan llamadas a una función. o Constructor de la clase Jess -4

Breve tutorial sobre Jess

Belén Díaz Agudo

Funcall(java.lang.String name, Rete engine), siendo name el nombre de la llamada a función que vamos a llamar en el objeto Rete indicado por engine. o El método add lo hereda de la clase ValueVector y añade un nuevo elemento al final. o El método execute se encarga de ejecutar la función en un cierto contexto. o El método arg se usa para darle los argumentos a la función. Hace lo mismo que add pero permite encadenar las llamadas porque devuelve objetos Funcall en vez de ValueVector (como add). Se puede llamar a funciones Jess utilizando jess.Funcall en vez de utilizar

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 método 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.

Métodos para definir y listar distintos elementos de Jess

Quizá la manera más fácil para definir templates, hechos y otros elementos es usar el lenguaje Jess y hacer que desde java (a través de las funciones de la biblioteca) se parseen y carguen los archivos correspondientes. Aún así muchos de los elementos de Jess están presentes como clases en la biblioteca Jess y se pueden utilizar para construir instancias en Java y después añadirlas al motor de reglas explícitamente. Los siguientes métodos de la clase Rete permiten añadir elementos a un motor de reglas (un objeto Rete):

     

public public public public public public

void void void void void void

addDeffacts(Deffacts) addDefglobal(Defglobal) addDefrule(Defrule) addDeftemplate(Deftemplate) addUserfunction(Userfunction) addUserpackage(Userpackage)

Los siguientes métodos de la clase Rete devuelven (dado un nombre) los elementos existentes en un motor de reglas.

   

public public public public

Defglobal findDefglobal(String) Defrule findDefrule(String) Deftemplate findDeftemplate(String) Userfunction findUserfunction(String)

Los siguientes métodos 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

Breve tutorial sobre Jess

6.

Belén Díaz Agudo

Llamadas a funciones Java desde Jess

Desde el código JESS (archivos clp) se puede hacer llamadas a funciones Java usando call. Por ejemplo, observar cómo se usa para detener la ejecución del programa: (deffacts idle-fact (idle)) (defrule sleep-if-bored (declare (salience -100)) ?idle (retract ?idle) (call java.lang.Thread sleep 100) (assert (idle)))

7.

Transferencia de valores entre código Jess y Java

Se pueden utilizar los siguientes métodos 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 están disponibles en Jess: (store ) (fetch ) (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 comunicación 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 función fetch, y de la misma forma si la comunicación se realiza en el sentido inverso. Conociendo estas dos funciones vemos como seria la interacción habitual entre Java y JESS. Sólo se permite el intercambio de información de tipos “simples” pero es suficiente para las prácticas que haremos. Existen mecanismos de intercambio de información estructurada en forma de objetos java que se asertan como objetos o hechos CLIPS. Estas características se pueden consultar en la documentación pero el siguiente ejemplo muestra cómo 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 ) (height 10.0) (size ) (width 10.0) (OBJECT )) 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() llamarán a clearStorage(), pero reset y reset() no lo harán. Es decir, que los datos almacenados están disponibles tras las llamadas a reset().

Jess -6

Breve tutorial sobre Jess

Belén Díaz Agudo

Ejemplo 3 (este código está en el CV) import jess.*; import java.io.*; import javax.swing.*; public class Jesster { // The inference engine public static Rete m_rete; // Fichero que almacena el fuente del programa clips que vamos a cargar private static String programaFuente; // Constructor public Jesster() { m_rete = new Rete(); programaFuente = "cadenas.clp"; cargaPrograma(programaFuente); System.out.println("Cargando programa " + programaFuente + " "); } public static void main(String[] args) { int choice; int i; Jesster jesso; jesso = new Jesster(); jesso.reset(); for(int i=1;i 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.

Ejemplo 6: creación de un hecho ordenado desde Java Un hecho ordenado se representa como un hecho no ordenado con un único multislot llamado __data. NO es necesario crear un template para un hecho ordenado: se creará automaticamente si no existe. import jess.*; public class ExOrdered { public static void main(String[] unused) throws JessException { Rete r = new Rete(); Fact f = new Fact("letters", r); ValueVector vv = new ValueVector(); vv.add(new Value("a", RU.ATOM)); vv.add(new Value("b", RU.ATOM)); vv.add(new Value("c", RU.ATOM)); f.setSlotValue("__data", new Value(vv, RU.LIST)); r.assertFact(f); r.executeCommand("(facts)"); } } C:\> java ExOrdered f-0 (MAIN::letters a b c) 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

Belén Díaz Agudo

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

10. Formatear la salida. Clase

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 método 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. Añadir funciones java para que puedan ser llamadas desde jess. addUserpackage La función addUserpackage de la clase Rete hace accesible cierta parte del código 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 añadida (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

public class LevantaFunction implements Userfunction. Se recomienda consultar la documentación.

Jess -10