Salta al contenuto
Note per Studenti Esercizio - Prolog - fatti, regole e alberi SLD (laboratorio 4)

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:

prolog
colleague(X,Y) :- work(X,Z), work(Y,Z).
work(emp1, deepmind).
work(emp2, deepmind).
work(emp3, ibm).
work(emp4, ibm).

Programma 2:

prolog
likes(mary, pizza).
likes(antonio, Thing).
likes(john, icecream).
food(pizza).
food(icecream).
eats(Person, Thing) :- likes(Person, Thing), food(Thing).

Programma 3:

prolog
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).

  1. (Programma 1) ?- colleague(emp1, emp2). e ?- colleague(emp1, emp3). Poi trovare tutte le coppie colleague(X,Y) e correggere il programma perché non restituisca una persona collega di se stessa.
  2. (Programma 2) ?- likes(john, pizza)., ?- eats(john, X)., ?- eats(antonio, X). Spiegare il fatto likes(antonio, Thing).
  3. (Programma 3) Tracciare ?- grampa(tommaso, bianca). e ?- grampa(tommaso, Who). con l'albero di ricerca. Aggiungere sibling/2 e cousin/2.
  4. (Programma 4) Tracciare ?- likes(mary,X), likes(john,X).

Punto 1: colleghi

colleague(emp1, emp2): il goal si unifica con la testa (X=emp1X = emp1, Y=emp2Y = emp2); il corpo diventa work(emp1,Z), work(emp2,Z). work(emp1,Z) dà Z=deepmindZ = deepmind (clausola 1); work(emp2,deepmind) è un fatto: true.

colleague(emp1, emp3): work(emp1,Z) dà Z=deepmindZ = deepmind; 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 = emp4

Otto risposte: i 2⋅22 \cdot 2 per deepmind e i 2⋅22 \cdot 2 per ibm. Quattro sono le coppie banali (X=YX = Y): la regola dice solo "stessa azienda", e ogni persona lavora per la propria azienda. Correzione con \= (non unificano):

prolog
colleague(X,Y) :- work(X,Z), work(Y,Z), X \= Y.

Ora colleague(X,Y) dà 44 risposte: (emp1,emp2), (emp2,emp1), (emp3,emp4), (emp4,emp3). X \= Y va dopo work(...): con le variabili ancora libere XX e YY unificherebbero e il controllo fallirebbe sempre.

Punto 2: mangiare

  • ?- likes(john, pizza). Nessuna clausola di likes ha johnjohn e pizzapizza insieme: false.
  • ?- eats(john, X). Corpo: likes(john, X), food(X). likes(john, X) si unifica con likes(john, icecream), X=icecreamX = icecream (la clausola likes(antonio, Thing) non si unifica: john≠antoniojohn \neq antonio); food(icecream) è un fatto: X = icecream. Nessun'altra soluzione.
  • ?- eats(antonio, X). likes(antonio, X) si unifica con likes(antonio, Thing): ThingThing è una variabile del fatto, quindi X resta libera (le due variabili sono identificate). Poi food(X) è il goal rimasto: prova food(pizza) (X=pizzaX = pizza, risposta) e al ritorno food(icecream) (X=icecreamX = icecream, altra risposta): X = pizza ; X = icecream.
  • likes(antonio, Thing). è un fatto con variabile: significa ∀Thing likes(antonio,Thing)\forall Thing\ likes(antonio, Thing), Antonio ama qualsiasi cosa. Per questo eats(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: X=tommasoX = tommaso, Y=biancaY = bianca. Corpo: parent(tommaso,Z), parent(Z,bianca).

  1. parent(tommaso,Z): clausola 1, Z=francescaZ = francesca.
  2. parent(francesca,bianca): non c'è nessuna clausola di parent con francescafrancesca e biancabianca: fallisce. Backtracking: si disfa Z=francescaZ = francesca.
  3. parent(tommaso,Z): clausola 2, Z=vittorioZ = vittorio.
  4. parent(vittorio,bianca): clausola 4, riesce. Risposta true.

?- 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 Z=francescaZ = francesca fino al successo Who = linda; con ; si ritorna indietro e si prova Z=vittorioZ = vittorio: Who = bianca. Il goal parent(francesca, Who) ha una sola soluzione (lindalinda), quindi niente altri rami. La query grampa(X,Y) aperta dà (tommaso, linda) e (tommaso, bianca).

sibling e cousin (aggiunte nostre, nello stesso stile):

prolog
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) e parent(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).

  1. likes(mary,X): clausola 1, X=foodX = food.
  2. likes(john,food): nessuna clausola (le clausole 3 e 4 hanno beerbeer e winewine): fallisce. Ritorno indietro, si disfa X=foodX = food.
  3. likes(mary,X): clausola 2, X=wineX = wine.
  4. likes(john,wine): clausola 4, riesce. Risposta X = wine.

Dopo la risposta, con ;, Prolog ritorna ancora: likes(mary,X) non ha altre clausole, la ricerca finisce: false. L'unica soluzione è X=wineX = wine.

Versione ripasso

  • Colleghi: colleague(X,Y) :- work(X,Z), work(Y,Z). colleague(emp1,emp2) true (Z=deepmindZ = deepmind); colleague(emp1,emp3) false. colleague(X,Y) dà 88 risposte, di cui 44 con X=YX = Y; si corregge con X \= Y dopo i work (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 ; icecream perché likes(antonio, Thing). vale ∀Thing\forall Thing (Antonio ama tutto) e food(X) enumera i cibi.
  • grampa: grampa(tommaso,bianca): Z=francescaZ = francesca fallisce su parent(francesca,bianca), backtracking, Z=vittorioZ = vittorio riesce. grampa(tommaso,Who): Z=francescaZ = francesca dà linda, Z=vittorioZ = vittorio 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): X=foodX = food fallisce su likes(john,food), X=wineX = wine riesce. Unica soluzione.
  • Albero di grampa(tommaso,Who): corpo parent(tommaso,Z), parent(Z,Who); ramo Z=francescaZ = francesca con parent(francesca,Who) dà Who=lindaWho = linda; ramo Z=vittorioZ = vittorio con parent(vittorio,Who) dà Who=biancaWho = bianca. Con ; si passa da un successo al successivo tornando all'ultima scelta aperta.
  • Programmi: eats(Person,Thing) :- likes(Person,Thing), food(Thing). con likes(antonio, Thing). e cibi pizza, icecream. eats(P,T) dà (mary, pizza), (antonio, pizza), (antonio, icecream), (john, icecream).
  • Errore tipico: mettere X \= Y prima dei goal che legano le variabili; dimenticare che una variabile in un fatto vale per ogni valore.

Teoria collegata