Jess, The Rule Engine for the Java Platform Seminario per il Corso di laboratorio di Sistemi Intelligenti a cura di A. Gilitus Sito ufficiale: http://herzberg.ca.sandia.gov/jess/ Jess, The Rule Engine for the Java Platform Come usare il Jess: • Interfaccia a riga di comando • Comando batch Interfaccia a riga di comando Per lanciare l’interfaccia a riga di comando è sufficiente digitare: java jess.Main A questo punto compare il prompt: Jess> in cui digitare i comandi come in CLIPS. Es. Jess> (assert (pippo)) Comando batch Per caricare un programma scritto in Jess si utilizza il comando batch: Jess> (batch nomefile.clp) Oppure specificare il file CLIPS sulla riga di comando quando si carica l’ambiente di Jess. java jess.Main nomefile.clp Jess, The Rule Engine for the Java Platform • Parallelo Jess/CLIPS • Implementazione di Jess con Java Parallelo Jess/CLIPS • Differenze nell’utilizzo dei moduli • Allowed-value • Interfaccia Grafica Differenze nell’utilizzo dei moduli 1. 2. 3. 4. Non si dichiara il modulo MAIN. Regole, fatti, template, ecc. che compaiono nel modulo MAIN devono avere la dicitura MAIN:: davanti. Non si usano import e export, a differenza del CLIPS ogni modulo importa da tutti e esporta a tutti. Ogni fatto dichiarato in un determinato modulo (per es. nel modulo PIPPO) sarà distinto dal nome del modulo stesso in working memory, per es. nel caso di una assert(ciao) nel modulo PIPPO, si avrà il fatto: f1 PIPPO::ciao Per riferirsi a fatti asseriti da altri moduli, è necessario esplicitare il nome del modulo che li ha asseriti. Non si dichiara il modulo MAIN. JESS (deftemplate MAIN::solution (slot value (default no))) (deffacts MAIN::param (solution (value no)) (maxdepth 0)) (deffacts MAIN::S0 (status 0 clear a NA) (status 0 on a b ) (status 0 on b c ) (status 0 ontable c NA) (status 0 ontable d NA) (status 0 clear d NA) (status 0 handempty NA NA)) (deffacts MAIN::final (goal on a b) (goal on c d) (goal ontable d NA) (goal on b c)) CLIPS (defmodule MAIN (export ?ALL)) (deftemplate solution (slot value (default no))) (deffacts param (solution (value no)) (maxdepth 0)) (deffacts S0 (status 0 clear a NA) (status 0 on a b ) (status 0 on b c ) (status 0 ontable c NA) (status 0 ontable d NA) (status 0 clear d NA) (status 0 handempty NA NA)) (deffacts final (goal on a b) (goal on c d) (goal ontable d NA) (goal on b c)) Non si usano import e export JESS (defmodule MAIN2) (defrule got-solution (declare (salience 100)) (solution (value yes)) => (assert (risolto)) (pop-focus) ) (defrule pick (status ?s on ?x ?y) (status ?s clear ?x ?) (status ?s handempty ? ?) (maxdepth ?d) (test (< ?s ?d)) (not (exec ?s pick ?x ?y)) => (assert (apply ?s pick ?x ?y))) CLIPS (defmodule MAIN2 (import MAIN ?ALL)(export ?ALL)) (defrule got-solution (declare (salience 100)) (solution (value yes)) => (assert (risolto)) (pop-focus) ) (defrule pick (status ?s on ?x ?y) (status ?s clear ?x ?) (status ?s handempty ? ?) (maxdepth ?d) (test (< ?s ?d)) (not (exec ?s pick ?x ?y)) => (assert (apply ?s pick ?x ?y))) Ogni fatto dichiarato in determinato modulo sarà distinto dal nome del modulo stesso in working memory Es. le asserzioni nel modulo PIPPO, compariranno in working memory nel seguente modo: f-1 PIPPO::ciao … f-2 PIPPO::sono … f-3 PIPPO::Pippo … Per riferirsi a fatti asseriti da altri moduli, è necessario esplicitare il nome del modulo che li ha asseriti es: (defmodule NEW ) (defrule check-ancestor (declare (salience 50)) ?f1 <- (MAIN2::ancestor ?a) (or (test (> ?a 0)) (test (= ?a 0))) (MAIN2::news ?s) (status ?s ?op ?x ?y) (not (status ?a ?op ?x ?y)) => (assert (MAIN2::ancestor (- ?a 1))) (retract ?f1) (assert (diff ?a))) Allowed-value All’interno di un deftemplate si possono dichiarare diversi slot, in CLIPS si possono assegnare diversi valori a questi slot sotto forma di valori permessi: allowed-value. In Jess non sono ammessi. Load-facts In Jess è possibile caricare un intero blocco di fatti memorizzati su file. (load-facts nomefile) Es. caricare la dichiarazione della mappa del supermercato. Interfaccia Grafica Il Jess non ha un’interfaccia grafica come il CLIPS. E’ stato pensato per essere utilizzato tramite Java. L’interfaccia grafica di CLIPS rende le operazioni di debug molto semplici, in Jess il debug è complicato, a meno che… JessGUI Implementazione di Jess con Java Prima distinzione: scegliere chi sarà l'applicazione pilota, cioè, colei che deterrà il controllo sull'altra. Il Jess consente di effettuare questa scelta: - Java applicherà il controllo sul Jess (consigliato, facile utilizzo) - Jess applicherà il controllo su Java (Writing GUI in Jess, Cap 7., Help di Jess, sconsigliato, difficile utilizzo) Java controlla il Jess • Istanziazione di uno o più motori Jess. • Il motore inferenziale Jess è basato sulla classe Rete. – – – – – knowledge base, agenda, lista dei fatti, stack dei moduli, ecc. • La classe Rete controlla tutto, o quasi, il motore inferenziale Utilizzo della classe Rete Es. 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)"); // Prints '9' System.out.println(v.intValue(r.getGlobalContext())); } catch (JessException ex) { System.err.println(ex); } } } Livello di interazione 1. Si inizializza Jess e si costruisce il programma Jess sfruttando i metodi della classe Rete (tutto eseguito da Java), il codice Jess risulta spezzato e annegato in quello Java. Pro e contro: Difficile correzione del programma Jess, caldamente sconsigliato. Livello di interazione 2. Si inizializza Jess gli si fa caricare il programma Jess e lo si esegue (possibilmente utilizzando thread separati). Questo metodo consente di mantenere una separazione netta, o quasi, tra Java e Jess. Pro e contro: Mantenendo slegate le due esecuzioni è possibile ottenere più che buoni risultati, cambiare il codice Jess non comporta la modifica del codice Java. Livello di interazione 3. Evoluzione del punto 2., si possono applicare “correzioni” al programma Jess prima o durante l’esecuzione (inserendo, per esempio, un fatto in knowledge base). Pro e contro: Si può utilizzare per un eventuale debug, bisogna ricordarsi tutti i punti in cui si è interagito con il Jess per eventuali modifiche. Metodi di utilizzo più frequente 1. 2. 3. 4. 5. 6. 7. 8. caricamento di un programma Jess, reset del motore inferenziale, comando di run, comando di step, metodo per controllare i fatti in knoledge base, metodo per controllare lo stack dei focus, metodo per controllare l’agenda, utilizzo dei watch. Caricamento di un programma Jess Utilizzo della classe JESP: • carica il programma • esegue il parse controlla se ci sono errori nel codice Jesp, un esempio public void caricaImpostazioni(){ try{ FileInputStream fis = new FileInputStream("superLarge.jess"); Jesp j = new Jesp(new InputStreamReader(fis), rete); do{ try{ j.parse(false); }catch(JessException re){ re.printStackTrace(); } }while (fis.available() > 0); }catch(IOException e){ e.printStackTrace(); } } Reset, Run e Step • reset() esegue il reset del motore inferenziale (come in CLIPS) • run() … • run(1) questo metodo run consente di eseguire un certo numero step prima di fermarsi. Fatti, Focus e Agenda • listFacts() restituisce un iteratore, i cui elementi sono di tipo Fact. • listFocusStack() non funziona bene, si consiglia di usare il metodo getFocus() che ritorna il nome del modulo in cima allo stack. • listActivations(String nomeModulo) restituisce un iteratore contenente le regole di possibile attivazione. nomeModulo riduce l’elenco delle regole attivabili al solo modulo interessato Watch • • • • watchAll() unWatchAll() watch(int i) unWatch(int i) Jess controlla Java • Previsione futuristica: creare le classi Java che il Jess dovrà controllare. • Istanziare le classi create tramite il Jess. Un esempio Jess> ;; Create the widgets (defglobal ?*f* = (new java.awt.Frame "Button Demo")) Jess> (defglobal ?*b* = (new java.awt.Button "Hello")) Jess> ;; Define the deffunction (deffunction say-hello "Unconditionally print a message" (?evt) (printout t "Hello, World!" crlf)) Jess> ;; Connect the deffunction to the button (?*b* addActionListener (new jess.awt.ActionListener say-hello (engine))) Jess> ;; Assemble and display the GUI (?*f* add ?*b*) Jess> (?*f* pack) Jess> (set ?*f* visible TRUE) WINDOW_CLOSING Event Jess> ;; If the event is a WINDOW_CLOSING event, exit the program (deffunction frame-handler (?evt) (if (= (?evt getID) (get-member ?evt WINDOW_CLOSING))then (call (get ?evt source) dispose) (exit))) Jess> ;; Connect this deffunction to the frame (?*f* addWindowListener (new jess.awt.WindowListener frame-handler (engine))) Documentazione • Consultabile online sul sito ufficiale: http://herzberg.ca.sandia.gov/jess/ • Tutti i riferimenti alle classi del package Jess sono consultabili attraverso le API della documentazione.