Salta al contenuto
Note per Studenti Esercizio - Prolog - cut e negazione come fallimento (laboratorio 4)

Esercizio - Prolog - cut e negazione come fallimento (laboratorio 4)

In questa pagina 4

Testo (laboratorio 4, Prolog, corso di Intelligenza Artificiale, Ing. dell'Informazione UniPD). Le soluzioni del corso non sono disponibili: i punti sono risolti a mano e verificati 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 A (senza cut):

prolog
antibodies_owner(maria).
dance(linda).
sing(linda).
sing(gianni).
noproblems(vittorio).

healthy(X) :- happy(X).
healthy(X) :- antibodies_owner(X).
happy(X) :- sing(X), dance(X).
happy(X) :- noproblems(X).

Programma B: come A ma con la clausola happy(X) :- sing(X), !, dance(X).

Programma C (uccelli): bird(nightingale)., bird(blackbird)., penguin(king_penguin)., ostrich(camelus_ostrich)., e fly(X) :- penguin(X), !, fail., fly(X) :- ostrich(X), !, fail., fly(X) :- bird(X).

Programma D: fly(X) :- bird(X), not(penguin(X)), not(ostrich(X)). con gli stessi fatti.

  1. Elencare le risposte di ?- healthy(X). nel programma A e nel B. Perché Vittorio non è sano nel B? Cosa risponde ?- healthy(vittorio). nel B?
  2. Dire se il cut è verde o rosso in: min(X,Y,X) :- X=<Y, !. e min(X,Y,Y) :- Y<X, !.; poi in min2(X,Y,X) :- X=<Y, !. e min2(X,Y,Y). Provare min2(3,5,5).
  3. Programma C: valutare fly(blackbird), fly(king_penguin), fly(camelus_ostrich), fly(X) e spiegare l'ultima. Cosa cambia se si tolgono i cut?
  4. Programma D: stesse query. Dire perché not va dopo bird(X).

Punto 1: Vittorio e il cut

Programma A (verificato): X = linda ; X = vittorio ; X = maria. Ordine di esecuzione di healthy(X):

  1. Clausola 1: happy(X). Clausola 1 di happy: sing(X), dance(X). sing(X) dà X=lindaX = linda, dance(linda) riesce: linda.
  2. Ritorno: sing(X) dà X=gianniX = gianni, dance(gianni) fallisce.
  3. Clausola 2 di happy: noproblems(X) dà X=vittorioX = vittorio: vittorio.
  4. Clausola 2 di healthy: antibodies_owner(X) dà X=mariaX = maria: maria.

Programma B, con happy(X) :- sing(X), !, dance(X).: risposte X = linda ; X = maria. Esecuzione:

  1. healthy clausola 1, happy clausola 1: sing(X) dà X=lindaX = linda; si esegue !; dance(linda) riesce: linda.
  2. Al ritorno il cut ha eliminato le alternative: non si prova sing(gianni) e non si prova la clausola 2 di happy (noproblems(vittorio)). happy(X) è esaurito.
  3. Clausola 2 di healthy: antibodies_owner(X) dà maria.

Vittorio non compare perché la sua unica via per essere sano, happy(vittorio) :- noproblems(vittorio), è la clausola 2 di happy, scartata dal cut quando X=lindaX = linda ha superato sing.

?- healthy(vittorio). nel B risponde true: con X=vittorioX = vittorio già legata, sing(vittorio) fallisce prima di raggiungere il cut, quindi non si impegna nulla e si prova la clausola 2 di happy, che riesce. È un cut rosso: cambia il significato, e i risultati dipendono da come si interroga il programma (healthy(X) e healthy(vittorio) non sono coerenti), cioè il programma non è reversibile.

Punto 2: cut verde o rosso

min con due cut. Le condizioni X=<Y e Y<X si escludono a vicenda. Senza i cut le soluzioni sono le stesse: il cut serve solo a non provare la seconda clausola dopo il successo della prima. Cut verde. Verifiche: min(3,5,M) dà M=3M = 3; min(5,3,M) dà M=3M = 3; min(4,4,M) dà M=4M = 4 (solo la prima clausola, perché 4<44 < 4 è falso).

min2: min2(X,Y,X) :- X=<Y, !. e min2(X,Y,Y). La seconda clausola non ha condizione e conta sul cut per essere raggiunta solo quando X>YX > Y. Cut rosso: togliendo il cut min2(3,5,M) darebbe M=3M = 3 e anche M=5M = 5 (sbagliato). Anche con il cut:

  • min2(3,5,M) dà M=3M = 3, min2(5,3,M) dà M=3M = 3: giusto;
  • min2(3,5,5) risponde true, sbagliato. Con il terzo argomento già istanziato a 55 la testa della clausola 1 (min2(X,Y,X)) non si unifica (X=3X = 3 e X=5X = 5 in contrasto), il cut non viene raggiunto e la clausola 2, senza condizioni, riesce.

Si corregge scrivendo la condizione nella seconda clausola (Y<X, come in min) oppure unificando l'uscita dopo il cut: min3(X,Y,Z) :- X=<Y, !, Z = X. e min3(_,Y,Y). Ora il cut viene raggiunto anche con Z istanziato: min3(3,5,5) e min3(5,3,5) sono false, min3(3,5,M) e min3(5,3,M) danno M=3M = 3 (verificato).

Punto 3: cut e fail

Programma C (verificato):

Query Risposta Spiegazione
fly(blackbird) true penguin(blackbird) e ostrich(blackbird) falliscono, la clausola 3 riesce con bird(blackbird)
fly(king_penguin) false clausola 1: penguin(king_penguin) riesce, il cut impegna, fail fa fallire fly, senza provare le clausole 2 e 3
fly(camelus_ostrich) false clausola 1 fallisce (non è un pinguino), clausola 2: ostrich riesce, cut, fail
fly(X) false X=kingpenguinX = king_penguin (primo fatto di penguin), cut, fail: le clausole 2 e 3 non si provano, quindi si perde nightingale

L'ultimo caso è l'attenzione delle slide: con la variabile libera il primo legame è il pinguino e il cut-fail chiude tutto, quindi fly(X) risponde false benché volino nightingale e blackbird. Il predicato funziona solo con l'argomento istanziato.

Nota sul programma delle slide: king_penguin e camelus_ostrich non sono dichiarati bird: fly(king_penguin) sarebbe false comunque. Con anche bird(king_penguin). e bird(camelus_ostrich). le risposte della tabella restano le stesse (verificato) e a bloccare i pinguini sono davvero cut e fail; senza i cut fly(king_penguin) darebbe true, perché fail fallirebbe sulla clausola 1 ma poi si proverebbe la 3.

Punto 4: negazione come fallimento

Programma D (verificato, anche con bird per i pinguini):

Query Risposta Spiegazione
fly(blackbird) true bird riesce; not(penguin(blackbird)) e not(ostrich(blackbird)) riescono perché penguin(blackbird) e ostrich(blackbird) non sono dimostrabili
fly(king_penguin) false penguin(king_penguin) è un fatto: not(...) fallisce
fly(camelus_ostrich) false not(ostrich(...)) fallisce
fly(X) X = nightingale ; X = blackbird bird(X) lega XX a ogni uccello, e il not filtra: i pinguini e gli struzzi sono scartati

La query aperta ora funziona, a differenza del programma C: il filtro non impegna con il cut.

Perché not dopo bird(X). Con fly(X) :- not(penguin(X)), bird(X). e i fatti bird(nightingale). bird(king_penguin). penguin(king_penguin). la query fly(X) risponde false: not(penguin(X)) con X libera prova penguin(X), che riesce (X=kingpenguinX = king_penguin), quindi il not fallisce prima che bird(X) assegni un valore. Con bird(X), not(penguin(X)) (verificato) la risposta è X = nightingale. Regola: i goal che generano valori vanno prima, quelli che filtrano (not, confronti, \=) dopo.

not non è la negazione logica: dice "non riesco a dimostrare", sotto l'ipotesi del mondo chiuso (ciò che non è nel programma è falso). Per fly(opus), con opus mai nominato, bird(opus) fallisce e fly(opus) è false anche se in realtà non si sa nulla di lui.

Versione ripasso

  • Vittorio: programma A (senza cut) dà linda ; vittorio ; maria. Programma B (happy(X) :- sing(X), !, dance(X).) dà linda ; maria: il cut dopo X=lindaX = linda elimina sing(gianni) e la clausola 2 di happy (noproblems(vittorio)). healthy(vittorio) nel B è però true (sing(vittorio) fallisce prima del cut). Cut rosso, programma non reversibile.
  • min: min(X,Y,X) :- X=<Y, !. e min(X,Y,Y) :- Y<X, !. cut verde (condizioni già esclusive). min2(X,Y,X) :- X=<Y, !. e min2(X,Y,Y). cut rosso: min2(3,5,5) risponde true (sbagliato). Si corregge con Y<X oppure con min3(X,Y,Z) :- X=<Y, !, Z = X. e min3(_,Y,Y). (uscita dopo il cut).
  • Cut e fail (programma C): fly(blackbird) true, fly(king_penguin) e fly(camelus_ostrich) false, fly(X) false (primo legame king_penguin, cut, fail: nightingale mai provato). Funziona solo con l'argomento istanziato. Nelle slide i pinguini non sono bird: aggiungendoli le risposte non cambiano. Senza i cut fly(king_penguin) diventerebbe true.
  • Negazione (programma D): fly(X) :- bird(X), not(penguin(X)), not(ostrich(X)). dà fly(X): nightingale ; blackbird. not(G) riesce se G non è dimostrabile (mondo chiuso). not dopo il generatore: not(penguin(X)), bird(X) dà false con X libera.
  • Passi del programma B per healthy(X): sing(X) dà lindalinda, !, dance(linda) riesce: linda. Il cut ha tolto sing(gianni) e happy(X) :- noproblems(X).; resta antibodies_owner(maria): maria.
  • Tabella di min2: min2(3,5,M) dà 33; min2(5,3,M) dà 33; min2(3,5,5) true (sbagliato: la testa non si unifica, il cut non si raggiunge, la seconda clausola non ha condizione). Senza cut min2(3,5,M) darebbe anche M=5M = 5.
  • Perché fly(X) fallisce con cut-fail e funziona con not: il cut-fail impegna sul primo pinguino; bird(X) genera uccelli e not li filtra senza impegnare.
  • Errori tipici: cut rosso involontario; fly(X) con cut-fail su variabile libera; not su variabile libera; scambiare not con la negazione logica.

Esercizi su questo argomento

Teoria collegata