Jess

Anuncio
Lenguaje de programación Jess
Java
Expert
System
Shell
Ejemplo introductorio
Problema de tipo puzzle en el cual hay cinco
casas, de diferente color, habitadas por
hombres de diferentes nacionalidades, con
diferentes mascotas, bebidas preferidas y
fumadores de ciertas marcas de cigarrillos.
Con ciertos datos, determinar:
–
–
¿Quién bebe agua?
¿De quién es la cebra?
Ejemplo introductorio
El inglés vive en la casa roja. El español tiene un perro.
La casa color marfil está inmediatamente a la izquierda
de la verde, donde vive el que bebe café.
El que bebe leche vive en la casa del medio. El que fuma
Old Golds también cría caracoles.
El ucraniano bebe té. El noruego reside en la primer casa
de la izquierda. El que fuma Chesterfields vive al lado del
que tiene el zorro.
El que fuma Lucky Strike bebe jugo de naranja. El
japonés fuma Parliaments. El que tiene un caballo vive al
lado del que fuma Kools, cuya casa es amarilla.
El noruego vive al lado de la casa azul.
Instalar JessDE
Plugings para Eclipse versión 3.1 o posterior.
Descargar Jess de http://www.jessrules.com/jess/download.shtml
En usuario ya registrado insertar el email
[email protected] y cliquear en:
Stable version Jess 7.1p2 source, docs and samples, zip format
Username: user1714
Password: noybgoc6
Licencia para uso académico.
Luego descomprimir el archivo en una carpeta.
Instalar JessDE
Salir de Eclipse.
Descomprimir todos los archivos de
Jess71p2/eclipse dentro del directorio (de
nivel más alto) de instalación de Eclipse.
Confirmar que existe una carpeta llamada
“eclipse/plugins/gov.sandia.jess_7.1.0"
Reiniciar Eclipse.
Verificar la instalación
Bajo el menú "Help" elegir "about Eclipse SDK"
Debe haber un ícono de Jess.
Cliquear y presionar en "Plug-in Details".
Se encuentra una lista de tres plugins.
Crear un nuevo proyecto Java.
Crear un nuevo archivo en ese proyecto y
nombrarlo "hola.clp".
(printout t "Hola mundo" crlf)
Ejecución en línea de comandos
C:\Jess71p2> bin\jess.bat
Jess, the Rule Engine for the Java Platform
Copyright (C) 2008 Sandia Corporation
Jess Version 7.1p1 8/6/2008
Jess> (+ 2 2)
4
Jess> (batch "..\\examples\\jess\\sticks.clp"
C:\Jess71p2> bin\jess.bat
examples\jess\sticks.clp
Jess el motor de reglas para la
plataforma Java
Para utilizarlo se deben especificar 'reglas'.
Es necesario proveer 'datos' de acuerdo al
problema.
Cuando se ejecuta el motor, las reglas pueden
ser disparadas.
Las reglas pueden crear nuevos datos, o
pueden realizar cualquier tarea que se pueda
realizar con Java.
Elementos Básicos
Símbolos
–
–
–
Números
–
Letras, dígitos, $*=+/.<>_?#.
Diferencia entre mayúscula y minúscula.
nil, TRUE, FALSE son símbolos especiales.
3
4.
5.643
5654L
6.0E4
1D son números válidos
Strings
–
–
–
Se denotan utilizando comillas dobles: "Hola".
\ es carácter de escape.
"\n" no es válido como nueva línea.
Elementos Básicos
Listas
–
Pares de paréntesis con cero o más símbolos.
(+ 3 2) (a b c) ("Hola mundo") ()
(bind ?x 2) son todas listas válidas.
–
Llamamos head al primer elemento de las listas.
–
Comentarios
–
–
; línea comentada
/* comentario
de bloque */
Elementos Básicos
Todo el código en Jess tiene la forma de
llamada a función.
No hay operadores. Algunas funciones tienen
nombres al estilo de los operadores de java.
Las llamadas a función en Jess son
simplemente listas.
Se pueden anidar llamadas a funciones.
Elementos Básicos
Ejemplos de llamadas a funciones:
–
–
(+ (+ 2 3) (* 3 3))
(batch "examples/jess/hello.clp")
Definición de funciones:
Jess> (deffunction max (?a ?b)
(if (> ?a ?b) then
?a
else ?b))
TRUE
Elementos Básicos
Variables
–
–
–
–
Identificadores que comienzan con '?'.
Los nombres pueden contener los siguientes
caracteres: '-',' _', ':' o '*'. No pueden contener '.'.
No se declaran previamente.
Jess> (bind ?a 123)
123
Jess> ?a
123
Elementos Básicos
Control de flujo
Jess> (bind ?i 3)
3
Jess> (while (> ?i 0)
(printout t ?i crlf)
(-- ?i))
3
2
1
FALSE
Memoria de Trabajo (Working
Memory)
Jess mantiene una base de conocimiento.
Las unidades de conocimiento son hechos
(facts).
Existen tres tipos de hechos: no ordenados,
oscuros y ordenados.
Las reglas sólo pueden reaccionar ante
agregado, eliminación o cambios en la
memoria de trabajo.
Cada hecho tiene una plantilla (template).
Memoria de Trabajo (Working
Memory)
Cada plantilla tiene un nombre y un conjunto
de slots (como una clase Java o una tabla de
una BD relacional).
Con el comando facts es posible ver una
lista de todos los hechos de la memoria de
trabajo.
Los hechos se pueden agregar mediante las
funciones assert, add y definstance.
Memoria de Trabajo (Working
Memory)
Una declaración deftemplate incluye:
–
–
–
–
–
–
un nombre,
una string de documentación (opcional),
una cláusula extends (opcional)
una lista de declaraciones (opcional) y
una lista de cero o más slots.
cada slot puede tener una lista de calificadores.
Hechos no ordenados
Tienen campos (slots) con nombre.
(auto (marca Ford) (modelo Explorer))
Se deben definir los slots previamente
mediante deftemplate.
(deftemplate auto "un auto específico"
(slot marca) (slot modelo) (slot color
(default blanco)))
Hechos no ordenados
Jess> (reset)
Jess> (assert (auto (modelo Megane)
(marca Renault)))
<Fact-1>
Jess> (facts)
f-0 (MAIN::initial-fact)
f-1 (MAIN::auto (marca Renault) (modelo
Megane) (color blanco))
For a total of 2 facts in module MAIN.
Hechos no ordenados
Un slot puede contener múltiples valores
Jess> (deftemplate caja (slot
ubicacion) (multislot contenido))
TRUE
Jess> (bind ?id (assert (caja
(ubicacion cocina) (contenido
espatula esponja sarten))))
<Fact-2>
Hechos no ordenados
Se puede modificar un hecho.
Jess> (modify ?id (ubicacion
comedor))
<Fact-2>
Se puede extender un hecho.
Jess> (deftemplate auto-usado
extends auto (slot kilometraje))
TRUE
Reglas
Una regla es similar a una sentencia if…then…
Las reglas se ejecutan cuando se satisface la
parte del if siempre y cuando el motor de
reglas se esté ejecutando (comando run).
Ejemplo:
Jess> (deftemplate persona (slot
nombre) (slot apellido) (slot
edad))
Reglas
Ejemplo:
Jess> (defrule personaMaria
(persona (nombre “María”) (apellido “Pérez”)
(edad 22))
=>
(printout t “María encontrada” crlf))
Jess> (run)
María encontrada
1
Jess>
Reglas
Ejemplo:
Jess> (defrule personaMaria2
(persona (nombre “María”))
=>
(printout t “María encontrada nuevamente”
crlf))
Jess> (run)
María encontrada
María encontrada nuevamente
2
Reglas
Ejemplo:
Jess> (defrule personaMaria3
(persona (nombre “María”) (edad ?e))
=>
(printout t “María tiene ” ?e “ años” crlf))
Jess> (run)
María encontrada
María encontrada nuevamente
María tiene 22 años
3
Patrones simples
Se pueden declarar variables para referirse al
contenido de un slot.
(persona (edad ?a) (nombre ?m)
(apellido ?p))
Este patrón matchea cualquier hecho
persona.
Se asigna a ?a, ?m y ?p el contenido de edad,
nombre y apellido de esa instancia
respectivamente.
Patrones simples
Jess> (reset)
Jess> (deftemplate auto (slot marca) (slot modelo))
Jess> (assert (auto (marca “Ford”) (modelo 1999)))
Jess> (assert (auto (marca “Ford”) (modelo 2002)))
Jess> (defrule modeloFord (auto (marca “Ford”) (modelo
?m)) => (printout t “El Ford es modelo ” ?m “.”
crlf))
Jess> (run)
El Ford es modelo 2002.
El Ford es modelo 1999.
2
Jess> (run)
0
Reglas
El lado derecho de las reglas debe contener
solamente patrones con posibilidad de
matchear con hechos del espacio de trabajo.
El lado derecho no puede contener llamadas a
función.
Siempre se debe ejecutar el comando reset
que dispara el hecho inicial (initial-fact).
Reglas
Las reglas se definen mediante el constructor
defrule.
Jess> (defrule bienvenido-menor
"Saludo para niños"
(persona {edad < 3})
=>
(printout t "Hola niño!"
crlf))
Reglas
Jess> (deftemplate persona (slot nombre) (slot
apellido) (slot edad))
TRUE
Jess> (watch all)
TRUE
Jess> (reset)
==> f-0 (MAIN::initial-fact)
TRUE
Jess> (defrule bienvenido-menor "Saludo para niños"
(persona {edad < 3})
=>
(printout t "Hola niño!" crlf))
Reglas
bienvenido-menor: +1+1+1+t
TRUE
Jess> (assert (persona (edad 2)))
==> f-1 (MAIN::persona (nombre nil) (apellido nil)
(edad 2))
==> Activation: MAIN::bienvenido-menor : f-1
<Fact-1>
Jess> (run)
FIRE 1 MAIN::bienvenido-menor f-1
Hola niño!
<== Focus MAIN
1
Hechos Oscuros
Son hechos no ordenados, definidos a partir
de objetos Java.
Se puede introducir un objeto Java en la
memoria de trabajo.
Jess> (deftemplate Cuenta (declare
(from-class Cuenta)(includevariables TRUE)))
Jess> (defclass Cuenta Cuenta)
Hechos Ordenados
En la mayoría de las oportunidades se utilizan
hechos no ordenados.
En algunos casos no tiene sentido dar
nombres a los slots (numero (value 6)).
Hechos ordenados son simplemente listas.
(padre-de pedro juan)
Jess> (deftemplate padre-de
(declare (ordered TRUE)))
Asignación patrones
Jess>
(defrule teenager
?p <- (person {age > 12 && age <
20} (firstName ?name))
=>
(printout t ?name " is " ?p.age "
years old." crlf))
Patrones simples
Puede haber reglas con más de un patrón.
Jess> (defrule misma-edad-diferente-nombre
?person1 <- (person)
?person2 <- (person {age == person1.age
&&lastName != person1.lastName})
=>
(printout t "Se encontraron personas de "
?person1.age "años." crlf))
Patrones en profundidad
Jess> (deftemplate coordenadas (slot x)
(slot y))
Jess> (defrule ejemplo-1 (coordenadas (x
?x) (y ?y))
=>
(printout t "Coordenadas (" ?x ", " ?y
")" crlf))
Patrones en profundidad - Tests
Los patrones pueden ser:
–
Un valor literal:
(coordenada (x 1.0))
–
Una variable que fue asignada previamente:
(coordenada (x ?x))
–
Una expresión regular de java entre '/':
(person (name /A.*/))
Patrones en profundidad - Tests
–
Restricción de predicados: El caracter ':' seguido
de una llamada a función. En este caso el test se
satisface si la función retorna TRUE.
(coordenada (x ?x&:(> ?x 10)))
–
Restricción de valor de retorno: Un signo '='
seguido de un llamado a función.
(coordenada (x ?x) (y =(+ ?x 1)))
Patrones en profundidad - Tests
Una expresión regular de Java encerrada
entre '/':
(person (name /A.*/))
Cualquiera de los patrones anteriores
precedido por el caracter '~' (negación).
(coordinate (x ?x) (y ~?x))
Matching en slots múltiples
Jess> (defrule match-tres-items
(lista-almacen ? ? ?)
=>
(printout t "Hay una lista de tres items." crlf))
TRUE
Jess> (assert (lista-almacen huevos leche manteca))
<Fact-0>
Jess> (run)
Hay una lista de tres items.
1
Matching en slots múltiples
Jess> (defrule match-lista-completa
(lista-almacen $?list)
=>
(printout t "Necesito comprar " ?list crlf))
TRUE
Jess> (assert (lista-almacen huevos leche manteca))
<Fact-0>
Jess> (run)
Necesito comprar (huevos leche manteca)
1
El algoritmo Rete
Se deben aplicar continuamente sentencias ifthen (reglas) a un conjunto de datos (working
memory).
Para mejorar eficiencia.
Se implementa mediante la construcción de
una red de nodos.
Cada nodo representa uno o más tests
encontrados en el lado izquierdo de alguna regla.
El algoritmo Rete
Cada nodo inferior
(terminal) representa una
regla.
Un conjunto de tests que
atraviesa toda la red hacia
abajo activa y dispara la
regla.
Nodos de una entrada y
nodos de dos entradas.
El algoritmo Rete
Optimización
compartiendo nodos.
Aparecen nuevos nodos
que se pueden
compartir.
El algoritmo Rete
Se pueden observar los
nodos creados y compartidos
mediante el comando watch
compilations:
+1
– +2
– =1
– =2
– +t
Jess genera otros nodos.
–
Elementos condicionales
'and', 'or', 'not', 'exists', 'test', 'forall'.
Jess> (defrule no-impares
(not (numero ?n&:(oddp ?n)))
=>
(printout t "No hay números
impares." crlf))
Código Java dentro de Jess
El código Java:
Vector v = new Vector();
v.add("Hola");
System.out.println(v.lastElement());
Se puede insertar así:
(bind ?v (new Vector))
(call ?v add "Hola")
((get-member System out) println (?v lastElement))
Código Jess dentro de Java
La clase jess.Rete es el motor de inferencia.
Contiene los métodos run(), reset(), etc.
Para ejecutar otros comandos: eval(String)
Rete r = new Rete();
r.eval("(deffunction cuadrado (?n) (return
(* ?n ?n)))");
Value v = r.eval("(cuadrado 3)");
System.out.println(v.intValue(r.getGloba
lContext()));
Resolución de conflictos
Cada regla posee una propiedad llamada
salience, que es una especie de prioridad.
Las reglas activas con mayor número de
prioridad se disparan antes que las de menor
'saliencia'.
El valor por defecto es cero.
Ejemplo: (defrule uno (declare (salience 2)
(persona (nombre "Juan")) => )
Resolución de conflictos
Ante la misma prioridad, el orden de disparo
de las reglas está determinado por una
estrategia para resolución de conflictos.
Jess opera con dos estrategias:
–
–
depth (por defecto): se dispara antes la regla de
activación más reciente.
breadth: las reglas se disparan en el orden en que
fueron activadas.
Se puede configurar la estrategia mediante el
comando set-strategy.
Resolución de conflictos
La utilización de prioridades posee algunas
desventajas:
–
–
Un buen estilo de programación basada en reglas,
no debe forzar el orden de disparo de las mismas.
La utilización de prioridades impacta en la
performance.
Se puede observar la lista de reglas activadas
pero aún no disparadas mediante el comando
agenda.
Módulos
Un sistema típico basado en reglas incluye cientos
de reglas, a veces miles.
Se puede modularizar la base de reglas y la base
de hechos.
En cada instante se trabaja en determinado
módulo, el módulo actual. Por defecto es MAIN.
Además, se provee un mecanismo de control
sobre el disparo de reglas: sólo se disparan las del
módulo que posee el foco (uno por vez).
Módulos y definiciones
Se define un nuevo módulo utilizando defmodule:
Jess> (defmodule TRABAJO)
Se pueden ubicar plantillas, reglas y hechos
dentro de un módulo específico:
Jess> (deftemplate TRABAJO::empleo (slot
salario))
Jess> (list-deftemplates TRABAJO)
TRABAJO::empleo
For a total of 1 deftemplates in module
TRABAJO.
Módulos y definiciones
Una vez definido un módulo, éste pasa a ser el
módulo actual.
Si no se especifica un módulo al crear
plantillas, hechos o reglas, automáticamente
son parte del módulo actua.
Se puede setear el módulo actual mediante
set-current-module.
Módulos, alcance y resolución de
nombres
Un módulo define un espacio de nombres para
plantillas y reglas.
¿A qué plantilla se refiere la definición de una regla?
Cuando Jess compila una regla o hecho busca
plantillas en tres lugares en el siguiente orden:
1.
2.
3.
Si un patrón nombra un módulo explícitamente, se busca
sólo en ese módulo.
Si no, se busca primero en el módulo donde está definida la
regla.
Si allí no se encuentra la plantilla, se busca en MAIN.
Módulos y foco
Los módulos también pueden ser usados para
controlar la ejecución.
Se pueden activar reglas en cualquier módulo.
Se pueden disparar solamente las reglas que
están en el módulo que posee el foco.
El módulo que posee el foco es independiente
del módulo actual.
Al inicio el módulo MAIN tiene el foco.
Módulos y foco
Jess> (defmodule CONDUCCION)
TRUE
Jess> (defrule en-el-auto
=>
(printout t "Listo para partir!" crlf))
TRUE
Jess> (reset)
TRUE
Jess> (run)
0
Módulos y foco
Se puede mover el foco a otro módulo
mediante el comando focus.
focus retorna el módulo que dejó el foco.
Jess> (focus CONDUCCION)
MAIN
Jess> (run)
Listo para partir!
1
Módulos y foco
Se puede invocar el comando focus desde el lado
derecho de una regla.
Jess mantiene una pila de módulos.
El módulo del tope tiene el foco.
Cuando no quedan reglas activas en ese módulo, se lo
quita de la pila y se pasa el foco al siguiente.
Una regla se puede declarar con la propiedad autofocus.
Cuando ésta se activa, el módulo que la contiene se
agrega a la pila.
Descargar