Esercizio - Prolog - fatti, regole e alberi SLD (laboratorio 4)
In questa pagina 4
Testo (laboratorio 4, Prolog, corso di Intelligenza Artificiale, Ing. dell'Informazione UniPD). Il laboratorio è una guida con query da provare su SWISH; le soluzioni del corso non sono disponibili, quindi qui ogni punto è risolto e tracciato a mano e verificato con un interprete Prolog scritto in Python. Teoria in Prolog - fatti, regole, ricorsione, liste e cutProlog come logica del primo ordine ristretta alle clausole di Horn: fatti, regole, query, motore di inferenza (backward chaining in profondità con backtracking, ordine delle clausole), termini, unificazione e occur check, aritmetica con is, ricorsione, liste e operatore barra, length e append, cut verde e rosso, cut e fail, negazione come fallimento.Prolog - fatti, regole, ricorsione, liste e cut →.
Programma 1:
colleague(X,Y) :- work(X,Z), work(Y,Z).
work(emp1, deepmind).
work(emp2, deepmind).
work(emp3, ibm).
work(emp4, ibm).Programma 2:
likes(mary, pizza).
likes(antonio, Thing).
likes(john, icecream).
food(pizza).
food(icecream).
eats(Person, Thing) :- likes(Person, Thing), food(Thing).Programma 3:
parent(tommaso,francesca).
parent(tommaso,vittorio).
parent(francesca,linda).
parent(vittorio,bianca).
grampa(X,Y) :- parent(X,Z), parent(Z,Y).Programma 4: likes(mary,food). (clausola 1), likes(mary,wine). (2), likes(john,beer). (3), likes(john,wine). (4).
- (Programma 1)
?- colleague(emp1, emp2).e?- colleague(emp1, emp3).Poi trovare tutte le coppiecolleague(X,Y)e correggere il programma perché non restituisca una persona collega di se stessa. - (Programma 2)
?- likes(john, pizza).,?- eats(john, X).,?- eats(antonio, X).Spiegare il fattolikes(antonio, Thing). - (Programma 3) Tracciare
?- grampa(tommaso, bianca).e?- grampa(tommaso, Who).con l'albero di ricerca. Aggiungeresibling/2ecousin/2. - (Programma 4) Tracciare
?- likes(mary,X), likes(john,X).
Punto 1: colleghi
colleague(emp1, emp2): il goal si unifica con la testa (, ); il corpo diventa work(emp1,Z), work(emp2,Z). work(emp1,Z) dà (clausola 1); work(emp2,deepmind) è un fatto: true.
colleague(emp1, emp3): work(emp1,Z) dà ; work(emp3,deepmind) non esiste (work(emp3, ibm) ha un'azienda diversa): fallimento. work(emp1,Z) non ha altre soluzioni: false.
Tutte le coppie colleague(X,Y): per ogni fatto work(X,Z) si cercano tutti gli work(Y,Z) con la stessa azienda. Output (verificato):
X = emp1, Y = emp1 ; X = emp1, Y = emp2 ;
X = emp2, Y = emp1 ; X = emp2, Y = emp2 ;
X = emp3, Y = emp3 ; X = emp3, Y = emp4 ;
X = emp4, Y = emp3 ; X = emp4, Y = emp4Otto risposte: i per deepmind e i per ibm. Quattro sono le coppie banali (): la regola dice solo "stessa azienda", e ogni persona lavora per la propria azienda. Correzione con \= (non unificano):
colleague(X,Y) :- work(X,Z), work(Y,Z), X \= Y.Ora colleague(X,Y) dà risposte: (emp1,emp2), (emp2,emp1), (emp3,emp4), (emp4,emp3). X \= Y va dopo work(...): con le variabili ancora libere e unificherebbero e il controllo fallirebbe sempre.
Punto 2: mangiare
?- likes(john, pizza).Nessuna clausola dilikesha e insieme:false.?- eats(john, X).Corpo:likes(john, X), food(X).likes(john, X)si unifica conlikes(john, icecream), (la clausolalikes(antonio, Thing)non si unifica: );food(icecream)è un fatto:X = icecream. Nessun'altra soluzione.?- eats(antonio, X).likes(antonio, X)si unifica conlikes(antonio, Thing): è una variabile del fatto, quindiXresta libera (le due variabili sono identificate). Poifood(X)è il goal rimasto: provafood(pizza)(, risposta) e al ritornofood(icecream)(, altra risposta):X = pizza ; X = icecream.likes(antonio, Thing).è un fatto con variabile: significa , Antonio ama qualsiasi cosa. Per questoeats(antonio, X)restituisce tutti i cibi.
Query aperta eats(P, T) (verificata): P = mary, T = pizza ; P = antonio, T = pizza ; P = antonio, T = icecream ; P = john, T = icecream.
Punto 3: grampa
?- grampa(tommaso, bianca). Unificazione con la testa: , . Corpo: parent(tommaso,Z), parent(Z,bianca).
parent(tommaso,Z): clausola 1, .parent(francesca,bianca): non c'è nessuna clausola diparentcon e : fallisce. Backtracking: si disfa .parent(tommaso,Z): clausola 2, .parent(vittorio,bianca): clausola 4, riesce. Rispostatrue.
?- grampa(tommaso, Who). Albero di ricerca (la variabile Who finisce unificata con Y):
grampa(tommaso, Who)
| regola: {X = tommaso, Y = Who}
parent(tommaso, Z), parent(Z, Who)
|- Z = francesca -> parent(francesca, Who) -> Who = linda (successo 1)
|- Z = vittorio -> parent(vittorio, Who) -> Who = bianca (successo 2)La ricerca è in profondità: prima il ramo fino al successo Who = linda; con ; si ritorna indietro e si prova : Who = bianca. Il goal parent(francesca, Who) ha una sola soluzione (), quindi niente altri rami. La query grampa(X,Y) aperta dà (tommaso, linda) e (tommaso, bianca).
sibling e cousin (aggiunte nostre, nello stesso stile):
sibling(X,Y) :- parent(P,X), parent(P,Y), X \= Y.
cousin(X,Y) :- parent(A,X), parent(B,Y), sibling(A,B).sibling(X,Y): due persone con lo stesso genitore e diverse. Risposte: (francesca, vittorio) e (vittorio, francesca).cousin(X,Y): figli di due fratelli. Risposte: (linda, bianca) e (bianca, linda), perchésibling(francesca, vittorio)eparent(francesca, linda),parent(vittorio, bianca).
Punto 4: backtracking con due sotto-obiettivi
?- likes(mary,X), likes(john,X). (si cerca ciò che piace a entrambi).
likes(mary,X): clausola 1, .likes(john,food): nessuna clausola (le clausole 3 e 4 hanno e ): fallisce. Ritorno indietro, si disfa .likes(mary,X): clausola 2, .likes(john,wine): clausola 4, riesce. RispostaX = wine.
Dopo la risposta, con ;, Prolog ritorna ancora: likes(mary,X) non ha altre clausole, la ricerca finisce: false. L'unica soluzione è .
Versione ripasso
- Colleghi:
colleague(X,Y) :- work(X,Z), work(Y,Z).colleague(emp1,emp2)true ();colleague(emp1,emp3)false.colleague(X,Y)dà risposte, di cui con ; si corregge conX \= Ydopo iwork(4 risposte: emp1-emp2, emp2-emp1, emp3-emp4, emp4-emp3). - Mangiare:
likes(john,pizza)false;eats(john,X)dàicecream;eats(antonio,X)dàpizza ; icecreamperchélikes(antonio, Thing).vale (Antonio ama tutto) efood(X)enumera i cibi. - grampa:
grampa(tommaso,bianca): fallisce suparent(francesca,bianca), backtracking, riesce.grampa(tommaso,Who): dàlinda, dàbianca. Ricerca in profondità, clausole dall'alto, sotto-obiettivi da sinistra. - sibling/cousin:
sibling(X,Y) :- parent(P,X), parent(P,Y), X \= Y.(francesca-vittorio);cousin(X,Y) :- parent(A,X), parent(B,Y), sibling(A,B).(linda-bianca e simmetrica). - Backtracking:
likes(mary,X), likes(john,X): fallisce sulikes(john,food), riesce. Unica soluzione. - Albero di
grampa(tommaso,Who): corpoparent(tommaso,Z), parent(Z,Who); ramo conparent(francesca,Who)dà ; ramo conparent(vittorio,Who)dà . Con;si passa da un successo al successivo tornando all'ultima scelta aperta. - Programmi:
eats(Person,Thing) :- likes(Person,Thing), food(Thing).conlikes(antonio, Thing).e cibipizza,icecream.eats(P,T)dà (mary, pizza), (antonio, pizza), (antonio, icecream), (john, icecream). - Errore tipico: mettere
X \= Yprima dei goal che legano le variabili; dimenticare che una variabile in un fatto vale per ogni valore.