Sistemi Esperti in Prolog

27
STEFANO FERILLI Monografia su SISTEMI ESPERTI IN PROLOG Università degli Studi di Bari Facoltà di Scienze Matematiche, Fisiche e Naturali Corso di Laurea in Informatica Corso di Ingegneria della Conoscenza e Sistemi Esperti

description

Monografia su Sistemi Esperti in Prolog

Transcript of Sistemi Esperti in Prolog

  • STEFANO FERILLI

    Monografia su

    SISTEMI ESPERTI IN

    PROLOG

    Universit degli Studi di Bari Facolt di Scienze Matematiche, Fisiche e Naturali

    Corso di Laurea in Informatica

    Corso di Ingegneria della Conoscenza e Sistemi Esperti

  • 2

    SISTEMI ESPERTI

    Un sistema esperto un programma che si comporta come un esperto per un determinato

    problema.

    Esso in grado non solo di sfruttare una base di conoscenza sullo specifico dominio per

    la risoluzione di problemi ad esso correlati, ma anche di esplicitare e spiegare le

    decisioni prese ed il ragionamento sottostante.

    I sistemi esperti possono essere usati per l'analisi (ossia per la classificazione) o per la

    sintesi (ossia per la deduzione di nuova conoscenza a partire da quella gi posseduta).

    Il loro schema generale il seguente:

    Utente

    Shell

    Interfaccia

    Utente

    Motore

    Inferenziale

    Base di

    Conoscenza

  • 3

    Tools per lo sviluppo

    - Tipo Skeleton

    Motore inferenziale e interfaccia presi da un sistema esperto gi esistente, cui stata

    tolta la conoscenza specifica.

    Pi immediati, meno flessibili.

    - Tipo Environment

    Ambienti general-purpose che consentono di creare l'interfaccia ed il meccanismo di

    ragionamento.

    Pi flessibili, ma anche pi complessi.

    FASI NELLA COSTRUZIONE

    DI UN SISTEMA ESPERTO

    Rappresentazione della conoscenza

    - Scegliere e definire i dettagli del formalismo

    - Progettare i dettagli di un motore inferenziale che li sfrutti

    - Aggiungere meccanismi per l'interazione con l'utente

    - Aggiungere meccanismi per la gestione dell'incertezza

  • 4

    Motore inferenziale

    - Definire il comportamento voluto

    - Delineare il processo di ragionamento

    - Rispondere a domande di tipo perch

    - Rispondere a domande di tipo come

    Implementazione

    - Gestore (main):

    expert

    - Procedure principali:

    explore (Goal, Trace, Answer)

    useranswer (Goal, Trace, Answer)

    present (Answer)

    PROCESSO DI RAGIONAMENTO

    Per trovare una risposta R ad una domanda D (che per semplicit supponiamo

    ammettere come risposte Vero o Falso), usare il primo dei seguenti principi che risulti

    applicabile:

  • 5

    - Se D si trova come fatto nella base di conoscenza, allora R "D vero".

    - Se nella base di conoscenza c' una regola del tipo

    se condizione allora D

    allora controllare condizione e usare il risultato per costruire la risposta R alla

    domanda D.

    - Se D una domanda che si pu rivolgere all'utente, allora interrogare l'utente

    riguardo a D.

    - Se D della forma D1 e D2, allora esplorare D1 e quindi:

    - se D1 falsa, allora R "D falsa",

    - altrimenti esplorare D2 e combinare appropriatamente le risposte a D1 e D2 in R.

    - Se D della forma D1 o D2, allora esplorare D1 e quindi:

    - se D1 vera, allora R "D vera",

    - altrimenti esplorare D2 e combinare appropriatamente le risposte a D1 e D2 in R.

    - Se la domanda della forma non D, bisogna fare attenzione a come tale negazione

    viene interpretata dal sistema, per evitare di ottenere risposte errate.

    INTERAZIONE CON L'UTENTE

    Il sistema deve interagire con l'utente sia per chiedere informazioni che non siano

  • 6

    ottenibili dalla base di conoscenza, sia per fornirgli spiegazioni sul proprio operato.

    Richiesta di informazioni

    Le richieste di informazioni dovrebbero essere fatte in modo tale da prevedere come

    risposta un semplice si o no.

    Esse dovrebbero anche essere strutturate in maniera che una risposta si faccia

    continuare il sistema ad esaminare l'ipotesi corrente, mentre una risposta no causi

    l'esplorazione di strade alternative.

    E' possibile, all'inizio (ma non solo), presentare all'utente un questionario/menu

    contenente un gruppo di domande di base o strettamente correlate fra loro, che possano

    gi indirizzare il sistema verso un insieme di ipotesi piuttosto che verso un altro.

    Domande di tipo perch

    L'utente dovrebbe avere anche la possibilit, oltre a rispondere si o no, di chiedere al

    sistema il perch di una certa domanda. Questo utile sia quando non chiaro il legame

    che essa ha con il problema, sia quando rispondere comporterebbe un certo sforzo.

    Minimalmente, il sistema dovrebbe prevedere una spiegazione ad hoc per ogni singola

    domanda.

    Questa soluzione, pi pratica per chi sviluppa il sistema, consente per solo spiegazioni

  • 7

    molto generiche quando una stessa domanda potrebbe essere fatta in momenti (e, quindi,

    con scopi) diversi.

    Una possibilit pi raffinata tenere traccia di tutto il processo di ragionamento che lega

    la domanda attuale all'obiettivo originale, in modo da presentarlo come spiegazione

    all'utente.

    In tal caso, il sistema deve farsi carico di mantenere memoria di tutti i singoli passi di

    ragionamento man mano che li esegue.

    Domande di tipo come

    Un altro tipo di spiegazione che il sistema dovrebbe essere in grado di dare , dopo aver

    trovato una risposta al problema, spiegare il modo in cui vi giunto, affinch l'utente

    possa controllarne la validit.

    In tal caso va memorizzato non solo il legame di una singola domanda col problema

    originale, ma tutto l'insieme di strade "confluenti" che hanno portato a quella

    conclusione.

    PROCEDURE DEL SISTEMA

    Il main expert ha la funzione di leggere la domanda dell'utente, innescare il meccanismo

    di ragionamento che trovi una risposta (positiva o negativa) a tale domanda e chiedere

  • 8

    all'utente se vuole conoscere altre possibili risposte, qualora ne esistano.

    La procedura explore ha il compito di sfruttare la base di conoscenza alla ricerca di una

    risposta alla domanda.

    - Goal la domanda, rappresentata come combinazione di congiunzioni e/o

    disgiunzioni di affermazioni semplici.

    - Trace la catena di obiettivi e regole fra l'obiettivo attuale Goal e quello

    iniziale, che consente di rispondere all'eventuale domanda dell'utente sul

    perch si stia investigando l'obiettivo corrente.

    - Answer la risposta all'obiettivo attuale Goal, sotto forma di albero di

    dimostrazione, in modo da poterla giustificare ad un'eventuale domanda

    dell'utente sul come il sistema vi sia giunto.

    La procedura useranswer si incarica, qualora nella base di conoscenza del sistema non

    esistano informazioni sufficienti per ottenere la risposta all'obiettivo attuale Goal, di

    richiedere la risposta Answer direttamente all'utente, qualora ci sia possibile.

    Essa (tramite l'argomento Trace) in grado di rispondere ad un'eventuale domanda

    dell'utente sul perch della richiesta; cerca inoltre, per quanto possibile, di astrarre dalla

    particolare espressione usata dall'utente.

    Avendo gli stessi scopi della procedura explore, alla quale eseguita in alternativa, ha

    anche gli stessi argomenti.

    La procedura present, infine, si occupa di mostrare all'utente la risposta Answer alla sua

    domanda iniziale, mostrandogli eventualmente anche come vi giunto.

  • 9

    INCERTEZZA

    Il Prolog ha una natura categorica, nel senso che ogni elemento del ragionamento per

    lui vero o falso, senza altra possibilit.

    Ci sono, per, ambiti in cui non sempre possibile fare affermazioni categoriche, ma si

    pu soltanto assegnare un certo grado di probabilit ad ogni fatto o regola che sia noto.

    Tale concetto di probabilit, molto spesso, non va inteso nel senso matematico del

    termine, ma piuttosto, in maniera intuitiva, come "fiducia soggettiva" che si ha nella

    verit di un'affermazione o nel fatto che una regola di inferenza si riveli applicabile.

    Per questo, nei sistemi esperti che trattano l'incertezza, non detto che il modello

    implementato sia proprio quello matematico, ed anzi ancora oggetto di disputa il fatto

    che sia pi opportuno usare la teoria delle probabilit "rigorosa" o una sua versione pi

    informale e semplificata.

    La teoria matematica ha dalla sua una maggiore fondatezza teorica, mentre i metodi

    intuitivi poggiano sulla maggiore semplicit implementativa e computazionale oltre che

    sulla somiglianza a quelli effettivamente usati dall'uomo.

    E' possibile "cablare" nel Prolog il trattamento dell'incertezza, assegnando ad ogni

    elemento di conoscenza un grado di probabilit e definendo le modalit con cui tali

  • 10

    probabilit si evolvono nel momento in cui vengono sfruttate dal processo di

    ragionamento.

    Per quanto riguarda i fatti, la relativa probabilit pu essere memorizzata sotto forma di

    argomento aggiuntivo, mentre nelle regole si pu pensare di sfruttare un predicato

    apposito, avente tale valore come argomento.

    La probabilit degli elementi di conoscenza pu essere espressa tramite un numero finito

    di descrittori, oppure numericamente entro una intervallo di valori prefissato, che pu

    anche coincidere con il classico [0, 1].

    Per quanto riguarda i meccanismi di combinazione delle probabilit fra fatti e regole, un

    meccanismo molto semplice ma efficace potrebbe essere il seguente.

    Denotiamo con c(X) la probabilit di una proposizione X, e supponiamo che sia un

    numero reale compreso fra 0 e 1.

    - Se P1 e P2 sono due fatti, con probabilit (rispettivamente) C1 e C2, allora:

    c(P1 e P2) = min(c(P1),c(P2)) (significato intuitivo: se devono essere veri entrambi i fatti, allora la probabilit del risultato risentir

    del pi debole)

    c(P1 o P2) = max(c(P1),c(P2)) (significato intuitivo: se sufficiente che sia vero uno qualunque dei fatti, allora possiamo considerarli

    interscambiabili e quindi associare al risultato la probabilit del pi forte)

    c(non P1) = (1 - c(P1)) (significato intuitivo analogo a quello della teoria matematica: la probabilit dellopposto di un fatto

    il complemento della probabilit del fatto stesso)

  • 11

    - Se c' una regola Se P1 allora P2 con probabilit C, allora:

    c(P2) = c(P1) * C (significato intuitivo: dopo aver assegnato una probabilit alla condizione in base alle sue singole

    componenti, bisogna pesarla con quella della regola stessa per ottenere la probabilit della

    conseguenza)

    Questo schema , ovviamente, semplificato al massimo, perch sarebbe necessario

    almeno prendere in considerazione anche le relazioni fra gli elementi di conoscenza, che

    generalmente non sono indipendenti l'uno dall'altro.

    Esiste un altro metodo per trattare l'incertezza, che, data un'ipotesi da verificare H e

    dell'evidenza E raccolta per confermarla, modella la possibilit che E modifichi la

    speranza in H tramite due parametri (invece che con un singolo valore di probabilit):

    N = Fattore di Necessit

    S = Fattore di Sufficienza

    S ci dice quanto E sia sufficiente per H. Se E vero, tanto maggiore S tanto pi

    probabile sar H.

    N ci dice quanto E sia necessario per H. Se E falso, tanto pi basso N tanto meno

    probabile sar H.

    Se la probabilit di E a met strada fra la certezza e l'impossibilit, la probabilit di H

    sar determinata per interpolazione fra i seguenti casi estremi:

  • 12

    - si sa che E falso

    - si sa che E vero

    - non si sa nulla di E.

    Ogni evento H avr una probabilit a priori, che verr modificata man mano che nuova

    conoscenza verr acquisita.

    MODIFICA DELLE STRUTTURE DI

    CONTROLLO DEL PROLOG

    CICLO IBRIDO

    Essendo un linguaggio general-purpose, il Prolog in grado di implementare anche

    strutture di controllo differenti da quella standard (il backward chaining).

    N.B.: Per semplicit, si supporr che le regole non contengano letterali negati.

  • 13

    Un primo tipo di controllo quello del ciclo di regole ibrido di backward e forward

    chaining, pi semplice da implementare del forward puro.

    Esso si ottiene trasformando ogni regola del programma nel seguente modo:

    - aggiungere alla fine del corpo un letterale asserta() avente per argomento la

    testa della regola stessa;

    - aggiungere all'inizio del corpo un letterale not() con lo stesso argomento;

    - sostituire la testa della regola con un nuovo predicato fittizio che non sia gi

    stato usato dal programma (ad es., dummy).

    Esempio.

    Le regole a :- b. e c :- d, e, f.

    diventano, rispettivamente,

    dummy :- not(a), b, asserta(a). e dummy :- not(c), d, e, f, asserta(c).

    Poich tali regole non si richiamano mai a vicenda (nonostante l'esistenza di predicati

    intermedi), necessario un main che le valuti tutte in sequenza, e ripeta tale operazione

    fino al raggiungimento di una prefissata condizione di terminazione (tipicamente, la

    soluzione del problema).

    FORWARD CHAINING

    Un altro meccanismo il forward chaining puro.

  • 14

    Poich esso lavora cercando ed eliminando progressivamente i letterali dei lati sinistri

    delle regole che risultino veri come fatti della base di conoscenza, opportuno

    trasformare testa e corpo di ogni regola in argomenti di un predicato fittizio rule (il

    corpo, ovviamente, sar tradotto in una lista), ed esprimere ogni fatto sotto forma di

    argomento di un predicato fittizio fact.

    Questo consente di sfruttare le procedure Prolog member e delete.

    Esempio.

    Le regole a :- b,c. e g(X) :- h(X,Y), not(f(Y)).

    diventano, rispettivamente,

    rule(a, [b, c]). e rule(g(X), [h(X,Y), not(f(Y))]).

    Il main dovr quindi, ciclicamente: leggere un fatto, cancellarlo dal corpo di tutte le

    regole che lo contengono e:

    - qualora tutti i letterali del corpo siano stati cancellati

    sostituire la regola con un nuovo fatto uguale alla sua testa

    - o, altrimenti,

    sostituire la nuova regola cos ottenuta alla precedente

    fino a quando ci sia possibile.

    Per evitare che un fatto usato venga ripreso in considerazione, verr eliminato non

    appena usato e riasserito tramite un predicato fittizio usedfact.

    Alla fine, tutte le conclusioni ottenute dalla base di conoscenze saranno sotto forma di

    facts o di usedfacts.

  • 15

    EFFICIENZA

    Un punto importante per il successo del sistema potrebbe rivelarsi l'efficienza, che pu

    essere valutata da vari punti di vista, in corrispondenza dei quali richiede vari tipi di

    soluzioni per essere raggiunta.

    Indicizzazione dei predicati

    Il Prolog indicizza automaticamente le clausole in base al predicato che compare nella

    testa; a volte, per, potrebbe rivelarsi pi utile una suddivisione differente (ad es., nel

    forward chaining, in base ai predicati che sono presenti nel corpo).

    Si pu pensare ad un predicato fittizio rules, avente come primo argomento il valore

    dell'indice e come secondo argomento la lista delle regole che condividono tale valore.

    Lo svantaggio, in tal caso, la ridondanza derivante dal fatto che una stessa regola

    potrebbe essere associata contemporaneamente a pi indici.

    Meta-regole

    Il Prolog usa le regole candidate in ordine di presentazione da parte del programmatore;

    a volte, tuttavia, pi opportuno, sebbene ci comporti maggior perdita di tempo,

    scegliere l'ordine con cui prendere in considerazione le regole in maniera pi ragionata.

    Tale effetto pu essere ottenuto tramite un predicato prefer con quattro argomenti (la

  • 16

    testa ed il corpo di ciascuna delle due clausole da confrontare) che implementi la

    funzione di valutazione scelta.

    COMMENTI E SVILUPPI

    - Mancanza di chiarezza dichiarativa

    - Obiettivi negati

    - Miglioramento:

    - Obiettivi ciclici

    - Navigazione nell'albero di dimostrazione

    - Esplicitazione delle regole usate

    - Miglioramento del dialogo con l'utente

    - Ottimizzazione della ricerca (richieste-lunghezza)

    UN ESEMPIO

    Vediamo l'esecuzione di un sistema esperto che cerca di capire la specie cui appartiene

    un animale.

  • 17

    Le risposte dell'utente sono in grassetto, l'output del sistema in corsivo.

    Domanda, prego:

    peter una tigre.

    E' vero: peter ha il pelo?

    si.

    E' vero: peter mangia carne?

    no.

    E' vero: peter ha denti appuntiti?

    si.

    E' vero: peter ha artigli?

    perch.

    Per capire, tramite la regola 3, se peter un carnivoro

    Per capire, tramite la regola 5, se peter una tigre

    Questa era la tua domanda.

    E' vero: peter ha artigli?

    si.

    E' vero: peter ha gli occhi frontali?

    si.

    E' vero: peter ha un colore fulvo?

    si.

    E' vero: peter ha strisce nere?

    si.

  • 18

    (peter una tigre) vero

    Vuoi vedere come l'ho dedotto?

    si.

    peter una tigre

    stato dedotto tramite la regola 5 da

    peter un carnivoro

    stato dedotto tramite la regola 3 da

    peter un mammifero

    stato dedotto tramite la regola 1 da

    peter ha il pelo

    stato detto

    e

    peter ha denti appuntiti

    stato detto

    e

    peter ha artigli

    stato detto

    e

    peter ha occhi frontali

    stato detto

    peter ha un colore fulvo

    stato detto

    e

    peter ha strisce nere

    stato detto

  • 19

    UN SISTEMA ESPERTO PER LA DIAGNOSI DI MALATTIE DA ITTERO

    Ittero presente

    Ittero franco Ittero Sclerale Febbre? Febbre? si no no Paziente giovane? Paziente giovane? Stress o digiuno (1) nell'ultimo periodo? no si Storia di abuso di alcool? Sindrome di Gibert si Aumento di volume del fegato? si Aumento di volume della milza? si Cirrosi alcolica

  • 20

    Paziente giovane? (1)

    si no

    Stanchezza(Astenia)? Dolori ricorrenti a livello del quadrante superiore destro prima dell'ittero? si si Disturbi dispeptici? Dolore a livello della coleciste? si si Aumento di volume Colecistite del fegato? (Colangite) si Epatite acuta virale

  • 21

    /* Regole di alto livello per la diagnosi */

    diagnosi('Sindrome di Gibert') :- ittero_sclerale, chiedi_se_non(ha(febbre)), stress_digiuno.

    diagnosi('Epatite acuta virale') :- ittero_franco, chiedi_se(ha(febbre)), chiedi_se(giovane), chiedi_se(stanchezza), chiedi_se(dispepsia), chiedi_se(aumento_fegato).

    diagnosi('Colecistite') :- ittero_franco, chiedi_se(ha(febbre)), chiedi_se_non(giovane), chiedi_se(dolori_ricorrenti), chiedi_se(dolore_coleciste).

    diagnosi('Cirrosi alcolica') :- ittero_franco, chiedi_se_non(ha(febbre)), chiedi_se_non(giovane), chiedi_se(alcool), chiedi_se(aumento_fegato), chiedi_se(aumento_milza).

    diagnosi('Il paziente non presenta nessuna delle malattie contemplate dal sistema').

    /* Regole intermedie per la diagnosi */

    ittero_sclerale :- chiedi_se(occhi_gialli), chiedi_se_non(colorito_giallo).

    ittero_franco :- chiedi_se(occhi_gialli), chiedi_se(colorito_giallo).

    stress_digiuno :- chiedi_se(stress). stress_digiuno :- chiedi_se(digiuno).

    eta_medio_avanzata :- chiedi_se_non(giovane).

  • 22

    /* Decodifica domande e relative spiegazioni */

    cod_domanda(occhi_gialli,'Il paziente ha gli occhi giallastri'). spiega(occhi_gialli) :- write('Mi serve per verificare la presenza di

    ittero'), nl.

    cod_domanda(colorito_giallo,'Il paziente ha anche un colorito giallastro').

    spiega(colorito_giallo) :- write('Mi serve per distinguere l''ittero sclerale da quello franco'), nl.

    cod_domanda(stress,'Il paziente ha accusato stress in questo periodo').

    spiega(stress) :- write('La presenza di stress o digiuno fa propendere per la Sindrome di Gibert'), nl.

    cod_domanda(digiuno,'Il paziente ha digiunato in questo periodo'). spiega(digiuno) :- write('La presenza di stress o digiuno fa

    propendere per la Sindrome di Gibert'), nl.

    cod_domanda(giovane,'Il paziente e'' giovane'). spiega(giovane) :- write('Il fatto che il paziente sia giovane o di

    eta'' medio-avanzata porta ad esaminare diagnosi

    diverse'), nl.

    cod_domanda(stanchezza,'Il paziente ha accusato astenia'). spiega(stanchezza) :- write('La presenza di stanchezza nel paziente

    potrebbe essere indice di epatite acuta virale'), nl.

    cod_domanda(dispepsia,'Il paziente ha avuto disturbi dispeptici'). spiega(dispepsia) :- write('La presenza di disturbi dispeptici

    potrebbe essere indice di epatite acuta virale'), nl.

  • 23

    cod_domanda(aumento_fegato,'Si e'' riscontrato un aumento di volume del fegato nel paziente').

    spiega(aumento_fegato) :- write('In base alle risposte precedenti, questa informazione potrebbe aiutare a distinguere

    epatite e cirrosi dalle altre malattie'), nl.

    cod_domanda(dolori_ricorrenti,'Prima dell''ittero il paziente accusava dolori ricorrenti al quadrante superiore

    destro'). spiega(dolori_ricorrenti) :- write('Ittero franco, febbre ed eta''

    medio-avanzata fanno supporre una colecistite, che in

    questo modo potrebbe essere confermata'), nl.

    cod_domanda(dolore_coleciste,'Il paziente accusa dolore a livello della coleciste').

    spiega(dolore_coleciste) :- write('In base ai sintomi precedenti, confermerebbe la presenza di colecistite'), nl.

    cod_domanda(alcool,'E'' noto che il paziente ha abusato di alcool'). spiega(alcool) :- write('Sarebbe un indizio a favore della cirrosi'),

    nl.

    cod_domanda(aumento_milza,'Si e'' riscontrato un aumento di volume della milza nel paziente').

    spiega(aumento_milza) :- write('E'' un sintomo tipico della cirrosi, insieme all''aumento di volume del fegato, nelle storie

    di abuso di alcool'), nl.

    cod_domanda(ha(X),X) :- write('Il paziente ha '). spiega(ha(febbre)) :- write('Nota la presenza dell''ittero franco,

    consente di prendere in considerazione alcune diagnosi

    piuttosto che altre'), nl.

  • 24

    /* Motore inferenziale */

    chiedi_se(Q) :- domanda(Q,A), risposta_positiva(Q,A).

    risposta_positiva(Q,A) :- affermativa(A). risposta_positiva(Qcode,A) :- not(negativa(A)), not(affermativa(A)),

    write('Rispondere si o no.'), read(A2), retract(gia_chiesto(Qcode,A)), asserta(gia_chiesto(Qcode,A2)), affermativa(A2).

    chiedi_se_non(Q) :- not(chiedi_se(Q)).

    domanda(Qcode,A) :- gia_chiesto(Qcode,A). domanda(Qcode,A) :- not(gia_chiesto(Qcode,A)), cod_domanda(Qcode,Q),

    write(Q), write('? '), read(A2), domanda2(Q,Qcode,A2,A).

    domanda2(Q,Qcode,'spiega',A) :- spiega(Qcode), domanda(Qcode,A). domanda2(Q,Qcode,A,A) :- not(A = 'spiega'),

    asserta(gia_chiesto(Qcode,A)).

    affermativa(si). affermativa(s). affermativa(giusto). affermativa(ok). affermativa(certo).

    negativa(no). negativa(n). negativa(non). negativa(mai). negativa(impossibile).

  • 25

    UN SISTEMA ESPERTO PER LA DIAGNOSI DEI GUASTI

    DI UN DISPOSITIVO ELETTRICO

    /* Top-level diagnosis rules */

    diagnosis('Fuse blown') :- power_problem, askif(lights_out). diagnosis('Fuse blown') :- power_problem, askif(hear(pop)). diagnosis('Break in cord') :- power_problem, askif(cord_frayed). diagnosis('Short in cord') :- diagnosis('Fuse blown'), askif(cord_frayed). diagnosis('Device not turned on') :- power_problem, klutz_user, askif(has('an on-

    off switch or control')), askifnot(device_on). diagnosis('Cord not in socket properly') :- power_problem, klutz_user,

    askif(just_plugged), askifnot(in_socket). diagnosis('Foreign matter caught on heating element') :- heating_element,

    not(power_problem), askif(smell_smoke). diagnosis('Appliance wet(emdry it out and try again') :- power_poblem, klutz_user,

    askif(liquids). diagnosis('Controls adjusted improperly') :- klutz_user, askif(has('knobs or

    switches')). diagnosis('Kick it, then try it again') :- mechanical_problem. diagnosis('Throw it out and get a new one').

    /* Definitions of intermediate predicates */

    power_problem :- askif(device_dead). power_problem :- askif(has('knobs or switches')), askifnot(knobs_do_something). power_problem :- askif(smell_smoke), not(heating_element).

    klutz_user :- askifnot(handyperson). klutz_user :- askifnot(familiar_appliance).

    mechanical_problem :- askif(hear('weird noise')), askif(has('moving parts')).

    heating_element :- askif(heats). heating_element :- askif(powerful).

  • 26

    /* Question decoding */

    questioncode(device_dead,'Does the device refuse to do anything'). questioncode(knobs_do_something,'Does changing the switch positions or tuning the

    knobs change anything'). questioncode(lights_out,'Do all the lights in the house seem to be off'). questioncode(cord_frayed,'Does the outer covering of the cord appear to be coming

    apart'). questioncode(handyperson,'Are you good at fixing things'). questioncode(familiar_appliance,'Are you familiar with how this appliance works'). questioncode(device_on,'Is the ON/OFF switch set to ON'). questioncode(just_plugged,'Did you just plug the appliance in'). questioncode(in_socket,'Is the cord firmly plugged into the socket'). questioncode(smell_smoke,'Do you smell smoke'). questioncode(liquids,'Have any liquids spilled on the appliance just now'). questioncode(heats,'Does the appliance heat things'). questioncode(powerful,'Does the appliance require a lot of power'). questioncode(has(X),X) :- write('Does the appliance have '). questioncode(hear(X),X) :- write('Did you hear a ').

    /* Inferential engine */

    askif(Q) :- ask(Q,A), positive_answer(Q,A).

    positive_answer(Q,A) :- affirmative(A). positive_answer(Qcode,A) :- not(negative(A)), not(affirmative(A)), write('Please

    answer yes or no.'), read(A2), retract(asked(Qcode,A)), asserta(asked(Qcode,A2)), affirmative(A2).

    askifnot(Q) :- not(askif(Q)).

    ask(Qcode,A) :- asked(Qcode,A). ask(Qcode,A) :- not(asked(Qcode,A)), questioncode(Qcode,Q), write(Q), write('?'),

    read(A2), ask2(Q,Qcode,A2,A).

    ask2(Q,Qcode,'?',A) :- explain(Qcode), ask(Qcode,A). ask2(Q,Qcode,A,A) :- not(A = '?'), asserta(asked(Qcode,A)).

  • 27

    affirmative(yes). affirmative(y). affirmative(ye). affirmative(right). affirmative(ok). affirmative(uhhuh).

    negative(no). negative(n). negative(not). negative(never). negative(impossible). negative(haha).