SISTEMI A RETI SEMANTICHE Cronologia delle notazioni: 1889: 1896: Logica del Primo Ordine (Peano) Grafi Esistenziali (Peirce) – “la logica del futuro” ~1961: Reti Semantiche introdotte in AI Quale formalismo è migliore? Fin dall’inizio si è avuto un dibattito fra i vari sostenitori… ma: ogni rete semantica o sistema a frame è facilmente esprimibile tramite formule della logica del prim’ordine (gestendo opportunamente le eccezioni con qualche accortezza) ogni formula della logica del prim’ordine si può esprimere tramite reti semantiche Motivi del successo delle reti semantiche: formalismo grafico (usano diagrammi) modello esecutivo molto semplice (cf. Prolog vs. dimostratori di teoremi in logica del prim’ordine) Pur programmando una rete molto vasta, è facile capire quali interrogazioni saranno efficienti: facilità di visualizzazione dei passi attraversati dalla procedura di inferenza semplicità del linguaggio di interrogazione, che non consente interrogazioni troppo complesse Per questo motivo, le reti semantiche furono usate dai primi ricercatori sull’ontologia del buon senso per sviluppare le loro teorie. SINTASSI E SEMANTICA I linguaggi di rappresentazione hanno 2 componenti: sintassi - marginale Utile dal punto di vista della chiarezza e comprensibilità per un lettore umano: alcune cose sono più semplici da comprendere in notazione grafica, altre come stringhe di caratteri. Traduzione semplice ed automatizzabile semantica (& teoria della dimostrazione) - fondamentale Qualunque sia il formalismo usato dal linguaggio (stringhe o nodi) e il suo nome (rete semantica o logica), il suo significato o la sua implementazione non variano. Le reti semantiche si concentrano su categorie di oggetti relazioni fra di loro Esempio. Esprimiamo nei due formalismi il fatto che “I gatti sono mammiferi”: Gatti →sottoinsieme Mammiferi Gatti ⊂ Mammiferi o, più formalmente, ∀x gatto(x) ⇒ mammifero(x) L’idea comune è che una formula logica non ammetta eccezioni e che una rete semantica abbia un significato più blando Alcuni sistemi usavano frecce “IsA” per indicare sia l’essere sottoinsieme (“un gatto è un mammifero”) che l’appartenenza (“Tom è un gatto”), il che può portare ad incoerenze. (McDermott, 1976: “Artificial Intelligence Meets Natural Stupidity”) Alcuni sistemi falliscono nella distinzione fra proprietà dei membri di una categoria e della categoria nel suo insieme. RETI SEMANTICHE & LOGICA Esempio. Una rete semantica con la corrispondente traduzione in logica del prim’ordine. Animali Vivo: T Vola: F rel(vivo, animali, true). rel(vola, animali, false). uccelli ⊂ animali mammiferi ⊂ animali rel(vola, uccelli, true). rel(zampe, uccelli, 2). rel(zampe, mammiferi, 4). pinguini ⊂ uccelli gatti ⊂ mammiferi pipistrelli ⊂ mammiferi rel(vola, pinguini, false). rel(zampe, pipistrelli, 2). rel(vola, pipistrelli, true). opus ∈ pinguini tom ∈ gatti pat ∈ pipistrelli nome(opus, ‘Opus’). nome(tom, ‘Tom’). amico(opus, tom). amico(tom, opus). nome(pat, ‘Pat’). Sottoinsieme Sottoinsieme Uccelli Zampe: 2 Vola: T Mammiferi Zampe: 4 Sottoinsieme Pinguini Vola: F Membro Opus Nome: Opus Amico: Sottoinsieme Gatti Membro Tom Nome: Tom Amico: Sottoinsieme Pipistrelli Zampe: 2 Vola: T Membro Pat Nome: Pat Per rispondere alla domanda: “quante zampe ha Opus?” bisogna seguire la catena di legami Membro e Sottoinsieme da Opus ai pinguini fino agli uccelli, che hanno 2 zampe (Ereditarietà). E se ci sono più catene che portano a quantità differenti di zampe? EREDITARIETA’ L’ereditarietà consente di risalire alle proprietà di un oggetto senza doverle esplicitamente elencare tutte per ogni singolo oggetto, ma facendo in modo che: ogni oggetto assuma implicitamente tutte le proprietà della classe a cui appartiene immediatamente; ogni classe a sua volta assuma implicitamente tutte le proprietà delle classi più ampie di cui fa parte. Questo meccanismo, sebbene comodo, non assicura di per sé che, qualora un oggetto o una classe appartenga a sovraclassi diverse, queste non gli attribuiscano valori differenti per una stessa proprietà. La semantica del linguaggio, ossia cosa succede in caso di proprietà con valori diversi a seconda del percorso di ereditarietà seguito, non è chiara: bisogna indurla basandosi sul comportamento del programma che lo implementa. Questo ha fatto sì che gli utenti delle reti semantiche pensino ad esse al livello implementativo piuttosto che a quello logico o di conoscenza. La semantica di semplici reti semantiche si può definire tramite gli equivalenti in logica del primo ordine per le asserzioni nel linguaggio della rete Iniziamo con una versione in cui le eccezioni non sono ammesse EREDITARIETA’ Sono necessari 5 tipi di legami (ossia di relazioni): 1. Sottoinsieme A →Sottoinsieme B Esempio. Gatti ⊂ Mammiferi 2. Membro A →Membro B Esempio. A⊂B A∈B Tom ∈ Gatti 3. R vale fra due oggetti A e B R(A,B) A →R B Esempio. Tom →Età 12 Età(Tom,12) 4. R vale fra ogni elemento della classe A e un oggetto B ∀x x ∈ A ⇒ R(x,B) A →R B Essendo questo tipo molto comune, conveniamo di indicarlo con rel(R,A,B) Esempio. Uccelli →Zampe 2 rel(Zampe, Uccelli, 2) 5. R vale per ogni elemento di A e qualche elemento di B ∀x ∃y x ∈ A ⇒ y ∈ B ∧ R(x,y) A →R B Esempio. Uccelli →Genitore Uccelli N.B.: Un linguaggio di programmazione logica può usare la normale inferenza logica per implementare l’ereditarietà a partire dalle traduzioni logiche dei legami. Un sistema a rete semantica usa algoritmi dedicati per i legami e quindi può risultare più veloce dell’inferenza logica (che è generale). EREDITARIETA’ CON ECCEZIONI I tipi naturali sono ricchi di eccezioni. Esempio. I mammiferi hanno 4 zampe, ma i pipistrelli (che sono mammiferi) solo 2. Gli uccelli volano, ma i pinguini (che sono uccelli) no. Secondo la semantica logica diretta, queste sono contraddizioni. E’ necessario cambiare la traduzione semantica dei legami R da A a B, per indicare che “ogni membro di A deve avere una relazione R verso B a meno che non vi sia qualche A’ per cui rel(R,A’,B’)”. In tal modo, nell’esempio degli animali, non c’è più ambiguità sul fatto che i pipistrelli hanno solo 2 zampe. rel(R,A,B) non significa più che ogni A è legata da R a B, ma che B è un valore di default della relazione R per i membri di A, e che quindi può essere sovrascritto da altra informazione. Sebbene sia intuitivo pensare di gestire l’ereditarietà con eccezioni seguendo le frecce nel diagramma, è anche possibile definire la semantica in logica del primo ordine. 1. Reificare le relazioni (che diventano oggetti invece che predicati). Quindi rel(R,A,B) è una frase atomica, non un’abbreviazione di una formula. Poiché R ora è un oggetto, non possiamo più usare R(x,B). Usiamo: vale(R,x,B) per indicare che l’equivalente di una relazione R(x,B) è asserito esplicitamente nella rete semantica; valido(R,x,B) per indicare che R(x,B) può essere inferito. EREDITARIETA’ CON ECCEZIONI 2. Dobbiamo quindi definire questi nuovi predicati: ∀r, x, b valido(r,x,b) ⇔ vale(r,x,b) ∨ (∃p x ∈ p ∧ rel(r,p,b) ∧ ¬rel_intermedia(x,p,r)) ∀x, p, r rel_intermedia(x,p,r) ⇔ ∃i intermedia(x,i,p) ∧ ∃b’ rel(r,i,b’) ∀a, i, p intermedia(x,i,p) ⇔ (x ∈ i) ∧ (i ⊂ p) cioè valido è definito dicendo che una relazione r vale fra x e b se vi è un predicato esplicito vale, o se vi è una r su qualche classe genitrice p di cui x è un elemento, e non vi è una r in nessuna classe intermedia i (ossia un sottoinsieme di p di cui x è un elemento). N.B.: il simbolo ⊂ indica un sottoinsieme proprio, ossia diverso da p stesso. 3. Infine, oltre a sapere quando valgono, vogliamo sapere anche quando le relazioni rel e vale non valgono. Se la base di conoscenza contiene solo atomi positivi rel, possiamo usare l’Ipotesi del Mondo Chiuso. A tal fine, la traduzione di una rete semantica deve esprimere il fatto che solo le relazioni rel e vale esplicitamente asserite sono vere: ∀r, a, b rel(r,a,b) ⇔ [r,a,b] ∈ {[⋅,⋅,⋅],[⋅,⋅,⋅], …} ∀r, a, b vale(r,a,b) ⇔ [r,a,b] ∈ {[⋅,⋅,⋅],[⋅,⋅,⋅], …} Esempio. Cerchiamo un n che soddisfi valido(Zampe, Opus, n). Sappiamo che rel(Zampe,Uccelli,2) e che Opus ∈ uccelli, ma la definizione di valido non ci consente di inferire nulla a meno che dimostriamo che non esista rel(Zampe,i,b) per i = Pinguini o per alcuna categoria intermedia. La base di conoscenza contiene solo atomi positivi rel(Zampe, uccelli, 2) ∧ rel(Vola, uccelli, true) per cui senza queste ultime regole saremmo bloccati. EREDITARIETA’ MULTIPLA L’ereditarietà multipla, supportata da alcuni sistemi a reti semantiche, consente che un oggetto possa appartenere a più di una categoria e che quindi erediti proprietà lungo percorsi differenti. Spesso questo non causa problemi, in quanto le proprietà ereditate lungo percorsi differenti non sono in conflitto. Esempio. Se una persona appartiene sia alla categoria dei miliardari che a quella dei tassisti, si può inferire che è ricca e sa guidare un’automobile. Ci sono tuttavia casi in cui le risposte date da due cammini di ereditarietà differenti sono in conflitto. Esempio. (Diamante di Nixon) Richard Nixon era un quacchero, dunque un pacifista, ma era anche un repubblicano, dunque non pacifista. Sfruttando le traduzioni logiche date in precedenza si possono quindi inferire entrambe le conclusioni, che disponendo di una sufficiente conoscenza di fondo si rivelerebbero in contraddizione. Essere Umano Sottoinsieme Sottoinsieme Non Pacifista Repubblicano Quacchero Ideale Membro Ideale Pacifista Membro Richard Nixon Tali conflitti non possono essere risolti se non sfruttando informazione aggiuntiva che espliciti un criterio di preferenza per uno dei percorsi in conflitto. EREDITARIETA’ E CAMBIAMENTO L’utilità fondamentale di una base di conoscenza consiste nella possibilità di essere espansa aggiungendo nuova informazione. Nei sistemi basati sulla logica del prim’ordine, si usa la funzione assert(KB,A) per indicare che la base di conoscenza KB viene aumentata con l’affermazione A. La proprietà di monotonicità assicura che, se una conclusione C segue logicamente da KB, allora continuerà a seguire anche dopo aver aumentato KB con la nuova informazione A: if KB C then (KB ∧ A) C L’ereditarietà con eccezioni è non monotona. Esempio. Se aggiungessimo l’affermazione che i gatti hanno 3 zampe: rel(Zampe, Gatti, 3) seguirebbe che Tom ha 3 zampe, e non più 4 come in precedenza. EREDITARIETA’ E CAMBIAMENTO Ci sono 2 modi per risolvere questo problema 1. passare dalla logica del prim’ordine ad una logica non monotona che tratta esplicitamente i valori di default. Le logiche non monotone permettono di dire che una proposizione P dovrebbe essere considerata vera fino a quando qualche informazione aggiuntiva non consenta di dimostrare che P è falsa. C’è stato un grande lavoro teorico su questo punto, ma con un impatto minore sulle applicazioni. 2. trattare l’aggiunta di enunciati facendo precedere la assert da una retract, il che è possibile per come abbiamo definito rel. Invece di fare molte affermazioni della forma assert(KB,rel(R,A,B)), facciamo una grossa enunciazione di equivalenza della forma assert(KB, ∀r,a,b rel(r,a,b) ⇔ …) dove … indicano tutte le possibili rel. Dunque, per aggiungere rel(Zampe, Gatti, 3) dovremmo prima rimuovere il vecchio enunciato di equivalenza sostituendolo con uno nuovo. Una volta alterata la base di conoscenza eliminando da essa una frase (oltre che aggiungendone una nuova) la non monotonicità dovrebbe essere facilmente comprensibile. IMPLEMENTAZIONE DELLE RETI SEMANTICHE Definita la semantica, si può pensare a come realizzare effettivamente la rete: dimostratore di teoremi linguaggio di programmazione logica (spesso scelta migliore) struttura dati (più diretta, per reti di piccole dimensioni) Un nodo si può rappresentare come una struttura dati con campi per le connessioni tassonomiche di base: categorie di cui è membro: appartenenza elementi che ne fanno parte: elementi sovrainsiemi e sottoinsiemi diretti: sovrains, sottoins e altri campi per altre relazioni in cui partecipa: riferimenti ordinari (R): rel_in, rel_out riferimenti R e R: tutte_rel_in e tutte_rel_out Risulta la seguente definizione del tipo di dati per i nodi: TipoDato nodo_rete_sem Componenti nome, appartenenza, elementi, sovrains, sottoins, rel_in, rel_out, tutte_rel_in, tutte_rel_out Ciascun campo ‘rel’ è organizzato come una tavola indicizzata dalla relazione. Una funzione lookup(chiave, tabella) consente di trovare il valore associato ad una chiave in una tavola. Esempio. Dati due riferimenti Opus →Amico Tom e Opus →Amico Steve, lookup(Amico, rel_out(Opus)) = {Tom, Steve}. IMPLEMENTAZIONE DELLE RETI SEMANTICHE L’interrogazione (ask) ad una rete circa quale relazione (Sottoinsieme, Membro, …) vale fra due oggetti è realizzata dal seguente codice: function Membro?(elemento, categoria) returns boolean for each c in appartenenza(elemento) do if Sottoinsieme?(c, categoria) then return T return F function Sottoinsieme?(sotto, sovra) returns boolean if sotto = sovra then return T for each c in sovrains(sotto) do if Sottoinsieme?(c, sovra) then return T return F function Legate?(sorgente, relazione, destinazione) returns boolean if relazione appare in rel_out(sorgente) then return Membro([relazione, destinazione], rel_out(sorgente)) else for each c in appartenenza(sorgente) do if Tutte_legate?(c, relazione, destinazione) then return T end return F function Tutte_legate?(sorgente, relazione, destinazione) returns boolean if relazione appare in tutte_rel_out(sorgente) then return Membro([relazione, destinazione], tutte_rel_out(sorgente)) else for each c in sovrains(categoria) do if Tutte_legate?(c, relazione, destinazione) then return T end return F N.B.: Membro? è una funzione che opera sui nodi della rete semantica; Membro è un’utilità che opera su insiemi. IMPLEMENTAZIONE DELLE RETI SEMANTICHE Ciascuna funzione segue semplicemente i riferimenti appropriati fino a trovare la risposta o fino alla fine dei riferimenti. Il codice non gestisce i riferimenti R, né le eccezioni. Inoltre il codice che asserisce (assert) nuove informazioni nella rete è omesso, in quanto immediato. Si possono aggiungere funzioni per rispondere ad altre domande. Un problema di questo approccio è che è facile venire distratti dalle strutture di dati e dimenticare la semantica alla base. Esempio. Definiamo una funzione numero_sottotipi che restituisce la lunghezza della lista contenuta nel campo sottoins. In base alla definizione precedente, numero_sottotipi(Animale) = 2. Questa potrebbe essere la risposta che voleva l’utente, ma la sua situazione logica è dubbia: è probabile che vi siano specie di animali che non sono rappresentate nella base di conoscenza può accadere che alcuni nodi denotino lo stesso oggetto. Magari Cane e Dog sono due nodi con un riferimento di uguaglianza fra di loro. Questi contano come uno o due? gatto_dalla_coda_nera o gatto_alla_stazione_stamattina sono tipi di animale? E’ facile rispondere a queste domande basandosi su ciò che è presente nella base di conoscenza, ma è meglio avere una semantica chiara in modo tale da poter dare una risposta che sia generale e non dipenda dallo stato corrente della rappresentazione interna. ESPRESSIVITA’ DELLE RETI SEMANTICHE Le reti viste finora hanno un’espressività estremamente limitata, non essendo in grado di esprimere costrutti che sono essenziali in qualunque dominio, quali: negazione disgiunzioni quantificazione Come viene risolta questa limitazione? Alcune reti semantiche estendono la notazione per consentire l’utilizzo di tutti i costrutti della logica del prim’ordine (è il caso dei grafi esistenziali originali). Un approccio più comune riempie i buchi tramite aggiunte procedurali, una tecnica per cui una funzione scritta in un linguaggio di programmazione può essere immagazzinata come valore di una qualche relazione ed utilizzata per rispondere a chiamate ask sulla relazione (e talvolta anche a chiamate assert). Qual è il vantaggio con cui le reti semantiche controbilanciano questi compromessi? possono catturare l’informazione di eredità in maniera modulare sono facili da comprendere grazie alla loro semplicità sono efficienti: poiché l’inferenza viene fatta seguendo riferimenti, piuttosto che recuperando frasi da una base di conoscenza tramite unificazioni, sono sufficienti pochi cicli di macchina per ogni passo In realtà, tuttavia, non vi è molta differenza col tipo di computazioni eseguite dai programmi Prolog. Un programma Prolog compilato per un insieme di relazioni di sottoinsieme e di appartenenza, combinate con proprietà generali di categoria, fa un numero di calcoli praticamente pari a quello di una rete semantica.