Deprecated: The each() function is deprecated. This message will be suppressed on further calls in /home/zhenxiangba/zhenxiangba.com/public_html/phproxy-improved-master/index.php on line 456
Luca Zappa Web Corner » Jess
[go: Go Back, main page]

Monday, February 7, 2005

Jess

Blogged under Altro by Luca Zappa on Monday 7 February 2005 at 9:29 am

Jess (Java Expert System Shell) è una shell per sistemi esperti e un linguaggio di scripting scritto interamente in Java, permette quindi di richiamare funzioni Java direttamente dal Jess o di incapsulare il Jess all’interno di un programma scritto in Java.

Si tratta di un sistema molto simile al CLIPS (C Language Integrated Production System) uno strumento per la realizzazione di sistemi esperti sviluppato negli anni 80, presso il laboratorio Lyndon B. Johnson Space Center della NASA negli Stati Uniti.

In Jess, come in CLIPS, è possibile definire regole di produzione (dette anche più semplicemente regole), costituite essenzialmente da un insieme di condizioni e da una sequenza di azioni. Se le condizioni di una regola sono soddisfatte essa può essere eseguita, e in questo caso verranno eseguite in sequenza le azioni in essa specificate.

I componenti principali sono:

  • i fatti (fact);
  • le regole (rule);
  • il motore inferenziale (rules engine) o interprete.

L’insieme dei fatti e delle regole forma la Base di conoscenza (Knowledge Base) del sistema esperto.

1. I fatti

I fatti sono uno dei modi per rappresentare informazione (conoscenza), ogni fatto rappresenta un pezzo di informazione che risiede nella lista dei fatti (fact-list).

Un fatto è un elenco di stringhe racchiuso tra parentesi e viene inserito nella fact-list con il comando assert:

(assert (fatto da asserire))

Ecco alcuni esempi di inserimento di fatti:


(assert (padre giovanni marco))
(assert (è uomo mario))
(assert (un uomo ha due gambe))

Quando un fatto viene inserito nella fact-list il sistema gli assegna un numero in modo da poterlo identificare univocamente (fact address):

Per eliminare un fatto si usa il comando retract indicando il suo identificatore numerico:

(retract 2)

In fatti possono essere di due tipi:

  • ordinati (ordered): sono quelli che abbiamo visto precedentemente, consistono in un simbolo seguito da una sequenza di zero o più campi separati da spazi e racchiusi tra parentesi tonde.In questi tipi di fatti l’ordine è fondamentale, infatti il fatto (Mario Rossi) è diverso dal fatto (Rossi Mario)
  • non ordinati (unordered): non conta l’ordine, sono simili ai record dei linguaggi C e Pascal. Prima di poterli usare bisogna definire la propria struttura con il comando deftemplate:

    (deftemplate persona ;nome del template
    (slot nome ;nome del campo
    (type SYMBOL)) ;tipo del campo
    (slot cognome ;nome del campo
    (type SYMBOL)) ;tipo del campo
    (slot annoNascita ;nome del campo
    (type INTEGER)) ;tipo del campo
    (slot professione ;nome del campo
    (type SYMBOL) ;tipo del campo
    (default studente)) ;valore di default

Per inserire un fatto non ordinato si usa il comando assert nel seguente modo:

(assert persona (annoNascita 50) (nome Mario) (cognome Rossi))

Una cosa importante da notare è che i fatti sono case-sensitive e quindi il fatto (padre giovanni marco) è diverso da (padre Giovanni Marco).

2. Le regole

Affinché un sistema si possa definire esperto, è necessario fornirlo di regole che possano produrre conoscenza a partire dai fatti. Esse specificano un insieme di azioni che devono essere eseguite in una data situazione.

Una regola è definita con il comando:


(defrule NomeDellaRegola “commento”
(pattern_1)
(pattern_2)
. . .
(pattern_N)
=>
(action_1)
. . .
(action_M)
)

La parte precedente allo speciale simbolo => (uguale maggiore) si chiama antecedente (LHS: Left Hand Side), mentre quella che viene dopo si chiama conseguente (RHS: Right Hand Side). L’antecedente è un insieme di condizioni (pattern) che devono essere tutte soddisfatte (AND) perché la regola sia applicabile, mentre il conseguente è composto da un insieme di azioni che vengono svolte. È compito del motore inferenziale verificare le condizioni ed eseguire le opportune azioni.

Un esempio di regola è quella che trova i nonni a partire da una lista dei fatti nel quale sono indicati i padri delle varie persone. Decidiamo di indicare che “Mario è il padre di Luca” con il fatto ordinato (padre mario luca).

Chi è nostro nonno? Nostro nonno è il padre di nostro padre, quindi se x è il padre di y e y è il padre di z allora x è il nonno di y, in Jess definiamo questa regola:


(defrule R_nonno “regola che trova i nonni”
(padre ?x ?y)
(padre ?y ?z)
=>
(assert (nonno ?x ?z))
)

Quindi se nella fact-list sono presenti i seguenti fatti:

(padre mario luca)
(padre luca alberto)

la regola R_nonno scatterà con l’assegnazione: ?x = mario ?y = luca ?z = alberto

l’esecuzione della regola, che avviene quando viene dato il comando (run), provoca l’inserzione nella fact-list del fatto:

(nonno mario alberto)

3. L’interprete

Il funzionamento dell’interprete segue il ciclo riconoscimento-azione tipico dei sistemi a regole di produzione. A grandi linee il ciclo è strutturato come segue:

  1. riconoscimento: si confrontano le condizioni di tutte le regole di produzione con tutti i fatti contenuti nella base dei fatti; per ogni regola le cui condizioni sono soddisfatte, si inserisce la corrispondente attivazione nell’agenda (una regola può dar luogo anche a più attivazioni);
  2. azione: se l’agenda è vuota, l’esecuzione termina; altrimenti si preleva l’attivazione in testa all’agenda e la si esegue (eseguendo in sequenza le azioni specificate dalla regola corrispondente);
  3. si ritorna al passo 1.

L’inserimento delle attivazioni nell’agenda avviene secondo una strategia ben definita (depth, breadth, lex, mea, simplicity, complexity e random), inoltre il programmatore può influire direttamente sull’inserimento definendo la priorità (salience) di una regola. Il ciclo riconoscimento-azione ha inizio quando si sottopone all’interprete Jess il comando (run).

4. Utilizzare il Jess all’interno di un programma Java

La classe fondamentale è jess.Rete che implementa il motore inferenziale. Ogni oggetto jess.Rete ha la propria basa di conoscenza, l’agenda, le regole, …; per incapsulare il Jess all’interno di Java basta semplicemente creare uno oggetto jess.Rete e manipolarlo.


Rete r = new Rete();
r.excuteCommand(”(assert (padre mario luca))”);
r.run();

2 Comments »

  1. Comment by Alessandro bigliotto — Wednesday, October 19, 2005 @ 1:17 pm

    ciao, vorrei porti una domanda: le azioni elencate nel conseguente di una regola sono eseguite da jess nell’ordine in cui sono scritte o casuale??
    ovvero, jess fa un ciclo while su ogni azione del conseguente finchè è verificato l’antecedente, OPPURE per ogni antecedente esegue in ordine tutte le azioni e poi verifica nuovamente l’antecedente??

    ad esempio, ipotizzando che esistano 1 regola con tre azioni come RHS:

    LHS se esiste un fatto (nodo-da-sviluppare x) e contemporaneamente esiste un secondo fatto (relazione-disponibile x b)
    RHS: 1)esegui l’azione di asserimento del nuovo fatto (nodo-da-sviluppare b)
    2)esegui l’azione di rimozione del fatto (nodo-da-sviluppare x)

    ipotizziamo che nella KB esistano 10 fatti del tipo (relazione-disponibile x b) ed 1 fatto del tipo (nodo-da-sviluppare x).
    Domanda:
    i 10 nuovi fatti del tipo (nodo-da-sviluppare b) saranno tutti asseriti e POI sarà rimosso il fatto (nodo-da-sviluppare x)?
    OPPUREUNO SOLO dei fatti (nodo-da-sviluppare b) sarà asserito e (nodo-da-sviluppare x) sarà rimosso subito dopo: quindi, dato che la seconda volta non è più verificato l’antecedente, sarà asserito solo 1 dei 10 ?
    GRAZIE!

  2. Comment by Luca Zappa — Wednesday, October 19, 2005 @ 11:53 pm

    Ciao Alessandro,
    non so darti una risposta precisa ed affidabile, è molto tempo che non uso Jess (gli ultimi lavori risalgano ai tempi della tesi, ahimé sono lontani).

    In linea teorica, se mi ricordo bene, l’attivazione delle varie regole può essere impostata, sia attraverso una strategia globale utilizzata dall’algoritmo di pattern matching per smaltire l’agenda (depth, breadth, lex, mea, simplicity, complexity e random) che impostando manualmente la salience nelle singole regole.
    In questo modo le regole con salience (priorità) maggiore vengono eseguite per prima.

    (defrule NomeDellaRegola “commento”
    (declare (salience 10))
    (pattern_1)
    (pattern_2)
    . . .
    (pattern_N)
    =>
    (action_1)
    . . .
    (action_M)
    )

    Tornando invece al discorso sul pattern matching, cioè la strategia di risoluzione dei conflitti, in Jess non si potevano utilizzare tutte le strategie sopra indicate (a differenza di CLISP), ma solo un sottoinsieme:
    - depth: la strategia di default, le regole attività più recentemente vengono eseguite per prima
    - breadth: le regole sono eseguite nell’ordine in cui vengono attivate, quindi prima le più vecchie

    Venendo al tuo caso, senza definire nessuna salience sulle tue regole e utilizzando la strategia di default (depth) non so dirti cosa succeda nella pratica, qual è il tuo obiettivo?
    Se vuoi che prima vengano asseriti tutti i fatti di tipo (nodo-da-sviluppare b) imposta una salience maggiore a quella regola.
    Ti ricordo anche che con il comando agenda puoi vedere l’ordine in cui le regole scatteranno prima che il motore venga effettivamente avviato.

    Spero che quanto scritto ti possa aiutare.

RSS feed for comments on this post. TrackBack URI

Leave a comment

Comment Preview:

Luca Zappa Web Corner is proudly powered by WordPress
Entries (RSS) and Comments (RSS).