Sei sulla pagina 1di 47

Intelligenza artificiale∗

Appunti NON UFFICIALI del corso del prof. Francesco Amigoni†

Politecnico di Milano

Marcello Pogliani
marcello.pogliani - at - gmail - dot - com

A.A. 2012 – 2013


Questo documento raccoglie gli appunti da me raccolti durante le lezioni del corso. Non sono stati
rivisti attentamente: possono contenere errori oppure imprecisioni dovute sia alla fretta con la
quale sono stati redatti che alla mia scarsa conoscenza della materia - del resto, sono appunti
scritti durante lo studio. Per quanto mi riguarda, è possibile distribuire, modificare, etc, etc que-
sto documento, purché venga citata la fonte. Spero di non aver violato il copyright di nessuno :)
Nota: Alcuni esempi e figure citati durante le lezioni e qui riportati sono tratti da [3]. In
particolare, alcune figure sono tratte dai file resi disponibili su [2].

Il programma completo del corso è disponibile sul sito ufficiale [1]
Indice

1 Introduzione 5
1.1 Concetti fondamentali . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.2 Agenti intelligenti . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.2.1 Tipologie di ambiente . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.2.2 Tipologie di agente . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.2.3 Rappresentazione dello stato . . . . . . . . . . . . . . . . . . . . . . . 8

2 Risoluzione dei problemi tramite ricerca 9


2.1 Formulazione del problema . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.2 Ricerca delle soluzioni di un problema . . . . . . . . . . . . . . . . . . . . . . 11
2.3 Strategie di ricerca . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
2.3.1 Ricerca non informata . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
2.3.2 Strategie di ricerca informate . . . . . . . . . . . . . . . . . . . . . . . 14

3 Ricerca con avversari 17


3.1 Giochi come un problema di ricerca . . . . . . . . . . . . . . . . . . . . . . . . 17
3.2 Algoritmo Minimax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
3.2.1 Potatura alfa-beta . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
3.3 Giochi con casualità: expectiminimax . . . . . . . . . . . . . . . . . . . . . . 21

4 Problemi di soddisfacimento di vincoli 23


4.1 CSP come problemi di ricerca . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
4.2 Euristiche . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
4.2.1 Scelta della variabile . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
4.2.2 Scelta del valore . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
4.3 Propagazione dei vincoli . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27

5 Agenti basati sulla conoscenza 31


5.1 Procedure di inferenza per la logica proposizionale . . . . . . . . . . . . . . . 32
5.1.1 Concatenazione in avanti (FC) . . . . . . . . . . . . . . . . . . . . . . 32
5.1.2 Concatenazione all’indietro (BC) . . . . . . . . . . . . . . . . . . . . . 33
5.1.3 Risoluzione (R) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
5.2 Procedure di inferenza per la logica del primo ordine . . . . . . . . . . . . . . 35
5.2.1 Concetti preliminari . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
5.2.2 Concatenazione in avanti e all’indietro . . . . . . . . . . . . . . . . . . 36
5.2.3 Risoluzione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37

6 Pianificazione 41
6.1 STRIPS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
6.2 Pianificazione in avanti . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
6.3 Pianificazione all’indietro . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
6.4 Pianificatori nello spazio dei piani . . . . . . . . . . . . . . . . . . . . . . . . . 44
1 Introduzione

1.1 Concetti fondamentali


Il termine “Intelligenza Artificiale” è stato coniato nel 1956 da John McCarthy, all’interno
di una proposta per organizzare un gruppo di lavoro al Dartmouth College1 . All’idea di
intelligenza artificiale si è comunque arrivati da tante direzioni diverse, che prendono in
considerazione punti di vista differenti gli uni dagli altri, e che hanno portato a una ricchezza
di background su cui è nata la disciplina. I principali approcci alla definizione di intelligenza
artificiale sono:
Agire umanamente Questo è l’approccio del test di Turing (1950, Computer Machinery and
Intelligence): la domanda “possono le macchine pensare?” è troppo difficile, perché
implica una definizione del termine ‘pensare’. Questo approccio cerca di dare come
risposta una definizione operativa sotto forma dell’imitation game: ci sono tre stanze,
A, B e una stanza centrale, separate le une dalle altre e collegate da telescriventi, con
cui gli occupanti di una stanza possono comunicare con quelli delle altre. Nella stanza
A viene messo un uomo, nella stanza B una donna, nella stanza centrale un interro-
gante (di qualsiasi sesso). Lo scopo dell’uomo è di farsi riconoscere come donna, lo
scopo della donna è di farsi riconoscere come donna, lo scopo dell’interrogante è quello
di riconoscere chi è l’uomo e chi è la donna. In seguito, al posto dell’uomo nella stanza
A viene messa una macchina, e si ripete lo stesso gioco. Secondo questo approccio, se
in questa seconda configurazione la macchina riesce a ingannare l’interrogante con la
stessa frequenza con cui l’interrogante era stato ingannato dall’uomo, allora possiamo
concludere che la macchina è intelligente, ossia che la macchina pensa. Astraendo
molto, il test di Turing valuta se una macchina si comporta come un essere umano,
ossia se agisce umanamente.
Pensare umanamente Un secondo approccio è quello di cercare non una macchina che
agisce come un essere umano, ma una macchina che pensa come un essere umano. Dal
punto di vista ingegneristico, il problema di questo approccio è che, allo stato attuale,
non è disponibile un buon modello del funzionamento della mente di un essere umano.
Dal punto di vista scientifico, una strada di questo tipo ha dato vita a una serie di
branche importanti della scienza, quali le scienze cognitive, che cercano di descrivere
con una serie di modelli computazionali il comportamento umano.
Pensare razionalmente Un terzo approccio è astrarre dal pensiero dell’essere umano, e cer-
care di costruire macchine che pensano razionalmente, dove la razionalità è una de-
scrizione idealizzata del pensiero dell’essere umano, di come l’essere umano dovrebbe
pensare: ad esempio, non tutti i comportamenti dell’essere umano sono facilmente
modellabili, ma il pensiero deduttivo lo è.
Agire razionalmente Nell’approccio del pensare razionalmente, in qualche modo, viene for-
nita alla macchina una specifica del metodo di ragionamento, ossia dell’algoritmo che
deve seguire (ad es. il modus ponens). Invece, nell’approccio dell’agire razionalmente
si guarda solo all’output: vengono considerate intelligenti quelle macchine che fan-
no qualcosa (indipendentemente dalla strada che seguono), il cui output è corretto
1 J.McCarthy, M. L. Minsky, N. Rochester, C.E. Shannon, A Proposal for the Dartmouth Summer Research
Project on Artificial Intelligence, 31 agosto 1955
6 INTRODUZIONE

azione
a

Agente Ambiente
p
percezione

Figura 1.1: L’agente e l’ambiente

ed è razionale, dove per razionale si intende fare la cosa giusta con le informazioni
a disposizione. Nel seguito faremo riferimento a quest’ultima definizione: macchine
“intelligenti” sono quelle capaci di agire razionalmente secondo qualche definizione di
razionalità.
Il corso è centrato attorno alla visione di una entità (agente razionale). Un agente è
una macchina che interagisce con un ambiente: è capace di percepire parte dello stato
dell’ambiente con i sensori e di intervenire sull’ambiente tramite i suoi attuatori. In questo
corso, cercheremo di realizzare un agente che sia intelligente, ossia che reagisca razionalmente
nel proprio ambiente.
Discipline che hanno forti relazioni con l’IA sono la filosofia (le macchine possono pensa-
re? cosa vuol dire il pensiero nelle macchine? ...), oltre alla matematica (logica matemati-
ca), psicologia, economia, linguistica (comprensione del linguaggio naturale, ...), scienza del
controllo, informatica.

1.2 Agenti intelligenti


In figura 1.1 è rappresentato il ciclo base di un sistema intelligente. In maniera astratta, le
decisioni dell’agente fanno riferimento a una funzione agente

f : P∗ → A

che ha come dominio l’insieme di tutte le possibili sequenze di percezioni P ∗ , dove P è


l’insieme di tutte le possibili percezioni dell’agente (che sono in numero finito per qualsiasi
agente artificiale che si considera), e ha come codominio l’insieme A di tutte le possibili
azioni. La funzione agente è una specifica di altissimo livello del funzionamento dell’agente.
In questo approccio, il tempo viene considerato come discreto. L’implementazione, in un
programma software, della funzione agente, è detta programma agente.
Esempio 1.1 (Il mondo dell’aspirapolvere): Siano A e B due stanze in cui si può muovere un agente
(aspirapolvere), e sia presente nell’ambiente dello sporco. L’agente è dotato di due sensori, uno che

A B

indica in che stanza si trova l’agente stesso, e l’altro che indica se la stanza è pulita oppure sporca.
Le azioni che può effettuare sono: muoversi a destra (r), muoversi a sinistra (l), aspirare (s), non fare
niente (n). Questo può essere formalizzato come

A = {l, r, s, n} P = {[A, pulita], [A, sporca], [B, pulita], [B, sporca]}

Una possibile specifica tabellare della funzione agente è la seguente:


AGENTI INTELLIGENTI 7

P∗ A
[A, pulita] r
[A, sporca] s
[B, pulita] l
[B, sporca] s
[A, pulita][A, pulita] r
[A, pulita][A, sporca] s
... ...

Gli agenti a cui verrà fatto riferimento devono essere razionali. Una possibile definizione di
razionalità che può essere applicata in questo contesto è:
Definizione (Razionalità). Per ogni possibile sequenza di percezioni, un agente è detto
razionale se sceglie l’azione che massimizza il valore atteso della misura di performance date
le percezioni fino a quel momento e la conoscenza dell’agente
La misura di prestazioni è definita dal progettista e rappresenta lo scopo dell’agente. In
generale, questa misura va sempre definita sugli stati del mondo, e non sulle azioni dell’a-
gente. Secondo la definizione appena data, dunque, essere razionali non vuol dire né essere
onniscenti (“data la conoscenza dell’agente”) né avere conoscenza del futuro (l’obiettivo è
massimizzare il valore atteso della misura di prestazioni).
Per costruire la funzione agente è necessario conoscere, oltre all’insieme delle percezioni P
(i sensori), e l’insieme delle azioni A (gli attuatori), la misura di performance da adottare
e il tipo di ambiente in cui l’agente si trova ad operare. In alcune applicazioni, l’imsieme
delle percezioni e delle azioni sono dati (ad esempio nel caso di un agente giocatore di
scacchi), mentre altre volte sono da progettare (ad esempio nel caso di un robot utilizzato
per l’esplorazione di Marte).

1.2.1 Tipologie di ambiente


Un ambiente può essere classificato secondo vari aspetti:
• completamente osservabile (i sensori dell’agente hanno accesso allo stato completo
dell’ambiente) oppure parzialmente osservabile
• a singolo agente oppure multi-agente
• deterministico (lo stato prossimo dell’ambiente è completamente determinato dallo
stato corrente e dall’azione che l’agente esegue nell’ambiente) oppure stocastico (è
definita una distribuzione di probabilità sullo stato prossimo)
• episodico (nell’ambiente si susseguono episodi indipendenti gli uni dagli altri, ad esem-
pio nel caso di un controllo qualità di pezzi meccanici che si susseguono su un nastro)
oppure sequenziale
• statico (l’ambiente non cambia mentre l’agente pensa) oppure dinamico
• discreto oppure continuo
• noto (l’agente conosce le leggi che governano il funzionamento dell’ambiente) oppure
ignoto

1.2.2 Tipologie di agente


Per implementare un programma agente è possibile utilizzare una delle seguenti architetture
di base. schematizzate in figura 1.2:
• agenti reattivi semplici, che sono utilizzabili, ad esempio, in ambienti completamente
osservabili
8 INTRODUZIONE

• agenti reattivi basati su modello, utilizzabili anche in ambienti parzialmente osservabili


• agenti basati su obiettivi, detti anche agenti risolutori di problemi
• agenti basati sull’utilità. A differenza degli agenti basati su obiettivi, che sono binari
(uno stato del mondo è un obiettivo oppure non lo è), questo tipo di agente attribuisce
ad ogni stato del mondo un valore di utilità
Tutte queste tipologie di agente possono essere estese, aggiungendo un processo di appren-
dimento.

p(t) p(t)
Agente
Agente
aspetto stato aspetto
corrente corrente
del mondo del mondo
Ambiente come evolve

Ambiente
il mondo

cosa fanno
le azioni

regole azione regole azione


condizione/azione da eseguire condizione/azione da eseguire

s(t) s(t)
(a) agente reattivo semplice (b) agente reattivo basato su modello

p(t) p(t)
Agente Agente

stato aspetto stato aspetto


corrente corrente
del mondo del mondo
come evolve come evolve
Ambiente

Ambiente
il mondo il mondo
come cambia come cambia
cosa fanno il mondo se cosa fanno il mondo se
le azioni eseguo a le azioni eseguo a

utilità soddisfazione
azione di essere in s
obiettivi
da eseguire
azione

s(t) s(t)
(c) agente basato su obiettivi (d) agente basato sull’utilità

Figura 1.2: Architetture per l’implementazione di programmi agente

1.2.3 Rappresentazione dello stato


La rappresentazione dello stato del mondo all’interno di un agente può avere varie caratte-
ristiche, e in particolare può essere classificata come una
• rappresentazione atomica: la sola cosa che si può dire riguardo a due stati è stabilire
se sono uguali oppure diversi
• rappresentazione fattorizzata: lo stato è caratterizzato da un insieme di coppie hvariabile,
valorei
• rappresentazione strutturata: vengono considerati esplicitamente gli oggetti che rap-
presentano lo stato e anche le loro relazioni
2 Risoluzione dei problemi tramite ricerca

In questo capitolo si considereranno gli agenti risolutori di problemi, un caso particolare


degli agenti basati su obiettivo. La risoluzione di un problema si articola in tre passi:

1. Formulazione del problema

2. Ricerca di una soluzione

3. Esecuzione della soluzione

Dato un problema formulato opportunamente, un agente risolutore di problemi è in grado


di trovarne autonomamente la soluzione, e quindi di eseguirla.
Esempio 2.1 (Un agente che gioca a scacchi (o a dama)): La formulazione del problema è una specifica
all’agente delle regole del gioco. Il secondo e il terzo passo sono eseguiti dalla macchina stessa: la
macchina, autonomamente, cerca una soluzione del problema formulato (ad es. una sequenza di mosse
che porta allo scacco matto) ed esegue la soluzione (nel caso della dama e degli scacchi questi passi
sono poi reiterati a causa delle mosse dell’avversario).

Secondo questo schema, l’algoritmo che viene utilizzato per risolvere il problema non è scritto
dal progettista, ma viene trovato automaticamente dall’agente. In questo senso, si può
affermare che l’intelligenza artificiale si occupa di meta-algoritmi (algoritmi che generano
altri algoritmi). Ha senso applicare questo approccio quando l’algoritmo per risolvere il
problema non è ovvio. Se non diversamente specificato, si considereranno ambienti statici,
discreti, deterministici, completamente osservabili e noti.

2.1 Formulazione del problema


Il primo passo per la risoluzione di un problema consiste nella formulazione, da parte del
progettista, delle indicazioni necessarie alla macchina per trovare una soluzione al problema
in modo autonomo.
Per illustrare i diversi elementi della formulazione del problema, si considererà l’esempio
del gioco del 15, nella sua versione semplificata detta gioco dell’otto. Si tratta di un rompi-
capo costituito da una griglia 4 × 4 con 15 tesserine numerate che si possono muovere. Lo
scopo del gioco è metterle in fila, lasciando la casella bianca in un estremo della griglia.
La formulazione di un problema si compone di cinque elementi:

lo stato iniziale È la configurazione iniziale del problema. Ad esempio, nel gioco dell’otto,
è la configurazione iniziale delle tessere nella griglia, come la seguente:

1 5 4
8 2 6
3 7

la funzione azioni È una funzione che prende come argomento uno stato e restituisce un
insieme di azioni possibili applicabili a quello stato:

Azioni(s) = { a1 , a2 , . . . }
10 RISOLUZIONE DEI PROBLEMI TRAMITE RICERCA

Nell’esempio, le azioni possibili a partire dallo stato iniziale s0 descritto al punto


precedente sono (6, ↓) e (7, →) che corrispondono rispettivamente a muovere la casella
vuota in alto e a sinistra. In termini della funzione azioni, Azioni(s0 ) = { ↑, ← }.

il modello di transizioni Prende la forma della funzione

Risultato(s, a) = s0

che, preso in ingresso uno stato s e un’azione a applicabile a s, restituisce un nuovo


stato s0 (detto successore di s) che risulta dall’avere applicato l’azione a allo stato s.
Nell’esempio, Risultato(s0 , ↑) = s1 dove lo stato s1 è

1 5 4
8 2
3 7 6

Si può osservare che, in questa definizione della funzione risultato, si è considerato


l’ambiente come deterministico.

Spazio degli stati L’insieme di stato iniziale, funzione azioni e funzione risultato
definisce lo spazio degli stati, ossia un grafo i cui nodi corrispondono agli stati e i cui
archi corrispondono alle azioni.
É importante osservare che alla macchina non viene fornita una rappresentazione espli-
cita dell’intero grafo, ma soltanto le regole per costruirlo, ossia lo spazio degli stati
viene fornito implicitamente. La macchina opererà esplorando il grafo: a un certo
punto, verrà generato uno stato che contiene la soluzione cercata. La soluzione al
problema è il cammino che nello spazio degli stati porta dallo stato iniziale a questo
stato, ovvero le mosse che devono essere compiute per raggiungere l’obiettivo a partire
dalla configurazione iniziale. Il problema sta nel riuscire a trovare questo cammino
senza espandere completamente lo spazio degli stati, che può essere molto ampio1 : è
quindi importante avere una rappresentazione implicita dello spazio degli stati.

il test obiettivo Distingue gli stati terminali dagli stati non terminali. Questo test può
essere implementato elencando esplicitamente gli stati finali (questo tipo di implemen-
tazione risulta semplice, ad esempio, nel gioco dell’otto in cui vi è un solo stato finale),
oppure specificando una proprietà che gli stati finali devono soddisfare.

il costo di cammino Si tratta del costo per ogni cammino presente nello spazio degli stati.
In pratica, viene definito come la somma del costo di ogni passo che lo compone.

Definizione (Soluzione). Una soluzione di un problema è un cammino nello spazio degli


stati che porta dallo stato iniziale a uno degli stati che soddisfano il test obiettivo. Una
soluzione ottima è una soluzione a costo di cammino minimo.
Esempio 2.2 (Problema delle otto regine):
• stato iniziale: scacchiera vuota
• azioni possibili: mettere una regina in una casella vuota2
• funzione risultato: lo stato di prima più la regina nella casella in cui è stata inserita
• test obiettivo: ci devono essere otto regine e non ce ne devono essere due sulla stessa riga, due
sulla stessa colonna, o due sulla stessa diagonale
1 nel problema del gioco degli scacchi è circa 10120 , pari al numero di atomi stimato presente nell’universo
visibile
2 non ci sono azioni applicabili se ci sono già 8 regine
RICERCA DELLE SOLUZIONI DI UN PROBLEMA 11

• costo di passo: unitario


Lo spazio degli stati è composto da 1 + 64 × 63 × 62 × · · · × 57 = 1.8 · 1014 stati. Il problema di questa
formulazione è che tutta la conoscenza è descritta dal test obiettivo. Una formulazione alternativa più
furba è la seguente
• stato iniziale: scacchiera vuota
• funzione azioni: dato uno stato, metti una regina nella colonna più a sinistra libera in modo tale
che non sia attaccata da alcuna altra regina presente sulla scacchiera
• ...
Formulando il problema in questo modo, si è passati a soli 2057 stati. In generale, per ridurre lo spazio
degli stati, la conoscenza del dominio va messa il più possibile nella funzione azione. In questo problema,
per entrambe le formulazioni, la lunghezza della soluzione ottima è 8.

2.2 Ricerca delle soluzioni di un problema


Nel modello presentato in questo capitolo, la rappresentazione dello stato è atomica (è noto
solo che uno stato è diverso da un altro, ma non sono note altre informazioni sugli stati).
Per esplorare una porzione dello spazio degli stati si fa uso di un albero di ricerca, in cui vi
è un unico cammino che porta da un nodo alla radice. Per costruire l’albero di ricerca, si
procede secondo questo algoritmo:
1. Viene generata la radice dell’albero (ossia un nodo che corrisponde allo stato iniziale)
2. Finché l’algoritmo non termina, si ripetono i passi seguenti:
• Si seleziona il prossimo nodo da considerare (secondo qualche strategia)
• Si applica il test obiettivo al nodo considerato. L’algoritmo termina se il test
viene soddisfatto, altrimenti prosegue
• Se il test obiettivo è fallito, si espande il nodo considerato: si costruiscono tutti i
suoi successori, applicando dapprima la funzione Azioni al nodo selezionato per
trovare gli archi, e poi la funzione Risultato per trovare i nodi successivi.
Si dice frontiera, o lista aperta, l’insieme dei nodi che sono nell’albero di ricerca ma devono
essere ancora espansi. Per selezionare un nodo da espandere dalla frontiera, si può ipotizzare
di ordinare secondo qualche criterio i nodi e poi scegliere il primo della lista. Nei paragrafi
successivi verranno descritte le diverse strategie per selezionare il nodo da espandere.
Un nodo nell’albero di ricerca corrisponde a un cammino nello spazio degli stati: infatti,
nell’albero di ricerca è possibile avere più nodi relativi allo stesso stato, che corrispondono
a diversi cammini che portano dallo stato iniziale allo stesso stato. Ogni nodo dell’albero
viene rappresentato da una struttura dati che contiene:
• lo stato a cui il nodo si riferisce
• il nodo padre (serve per risalire l’albero nel caso venga trovata una soluzione)
• l’azione che ha portato al nodo (serve per dare in output la serie di azioni che ha
portato alla soluzione)
• il costo di cammino g(n), somma dei costi delle azioni che portano a nodo n. Se il
costo di ogni passo è unitario, questo corrisponde alla profondità.
Una variante all’algoritmo presentato in questo paragrafo (Ricerca-Albero) prevede
di mantenere, oltre alla frontiera (lista aperta), la cosiddetta lista chiusa, che contiene gli
stati per cui si è già espanso un nodo. Questa struttura consente di evitare di espandere
nuovamente uno stato già considerato (eliminare gli stati ripetuti): se viene selezionato un
nodo già presente nella lista chiusa, questo non viene espanso. L’algoritmo che prevede
l’utilizzo della lista chiusa è detto Ricerca-Grafo.
12 RISOLUZIONE DEI PROBLEMI TRAMITE RICERCA

2.3 Strategie di ricerca


Lo strumento che viene utilizzato per esplorare una parte dei possibili cammini dello spazio
degli stati è l’albero di ricerca. Una strategia di ricerca è un criterio per scegliere i nodi
dalla frontiera ad ogni iterazione. Esistono diverse strategie di ricerca, che si differenziano
per completezza (se esiste una soluzione, la strategia la trova), ottimalità (la strategia trova
sempre la soluzione ottima, se esiste) e complessità, che può essere temporale (calcolata in
genere come il numero di nodi generati nell’albero di ricerca) oppure spaziale (misurata in
base al numero di nodi che devono essere mantenuti in memoria). Nel seguito, verranno
utilizzati alcuni parametri per descrivere le diverse strategie di ricerca:

• b (fattore di ramificazione oppure branching factor): il massimo numero dei successori


di un nodo

• d: profondità della soluzione più vicina alla radice

• m: massima lunghezza di un cammino nello spazio degli stati

• c∗ : costo della soluzione ottima. Se tutti i passi hanno costo unitario, d = c∗ .

2.3.1 Ricerca non informata


Le strategie di ricerca non informate non fanno uso di alcuna altra informazione oltre a quelle
contenute nella definizione del problema. In tutti gli esempi che seguono verrà utilizzato
l’algoritmo di ricerca Ricerca-Albero (senza eliminazione degli stati ripetuti), tranne
quando diversamente indicato.
Esempio 2.3: La figura 2.1 presenta un esempio di spazio degli stati con cinque stati (A, B, C, D, E),
avente A come stato iniziale ed E come unico stato che soddisfa il test obiettivo.

5 B
5

A
E stato iniziale: A
1 stato finale: E
1

C D
1

Figura 2.1: Esempio di spazio degli stati

Ricerca in ampiezza La strategia di ricerca in ampiezza estrae sempre, tra tutti i nodi
presenti nella frontiera, quello meno profondo. Per la regola con cui sono scelti i nodi, prima
di espandere i nodi di livello n + 1 vengono espansi tutti i nodi di livello n, utilizzando una
coda FIFO per la frontiera.
La strategia di ricerca in ampiezza è completa (se il numero di successori di un nodo è
finito, ossia se il branching factor b è un numero finito) e non è ottima3 . La complessità
temporale, calcolata come numero di nodi generati nel caso di Ricerca-albero è data da

1 + b + b2 + ... + bd + b(bd − 1) = O(bd+1 )


3 La ricerca in ampiezza trova la soluzione più vicina alla radice, fornisce la soluzione con il minore numero
di passi. Trova la soluzione ottima quando il costo di cammino è una funzione monotona non decrescente
della profondità del nodo
STRATEGIE DI RICERCA 13

mentre la complessità spaziale (nodi da tenere in memoria nel caso pessimo) è pari alla
complessità temporale (finché non si trova la soluzione, vanno tenuti in memoria tutti i
nodi). Se al posto dell’algoritmo generale si applica il test obiettivo appena viene generato
un nodo (prima di inserirlo nella frontiera), la complessità si riduce a O(bd )
Esempio 2.4: Per lo spazio di stati della figura 2.1, la strategia di ricerca in ampiezza produce il seguente
albero:
A Andamento della frontiera (nodo, profondità):
• (A, 0)
B C • (B, 1) (C, 1)
• (C, 1) (A, 2) (E, 2)
A E A D • (A, 2) (E, 2) (D, 2) (A, 2)
• (E, 2) (D, 2) (A, 2) (B, 3) (C, 3)
B C B C C E • (E, 2) (D, 2) (B, 3) (C, 3) (B, 3) (C, 3)
• (E, 2) (B, 3) (C, 3) (B, 3) (C, 3) (C, 3) (E, 3)

All’ultima iterazione viene considerato il nodo E di profondità 2, il test obiettivo ha successo e l’algorit-
mo termina. Nell’esempio, per risolvere l’ambiguità che si presenta nel caso più nodi abbiano la stessa
profondità, i nodi sono stati estratti in ordine lessicografico. Utilizzando l’algoritmo Ricerca-Grafo
invece di Ricerca-Albero, il nodo A non si sarebbe espanso due volte oltre alla radice.

Costo uniforme La strategia a costo uniforme sceglie dalla frontiera il nodo che ha costo
di cammino più basso. Questa strategia è completa solo se tutti i costi sono strettamente

positivi e ottima. Sia la complessità temporale che quella spaziale è data da O(bdc /εe ), dove
ε è un lower bound positivo sul costo di passo4 .

Ricerca in profondità La ricerca in profondità sceglie dalla frontiera il nodo più lontano
dalla radice (a profondità maggiore). Per la frontiera, questa strategia utilizza una coda
LIFO.

A (continua all’infinito)

B C

A E

A E

B C

...

Figura 2.2: Albero prodotto dalla ricerca in profondità per lo spazio degli stati di figura 2.1

La ricerca in profondità non è completa (diventa completa se i nodi non sono infiniti
utilizzando l’eliminazione degli stati ripetuti, quindi Ricerca-grafo invece che Ricerca-
albero) e non è ottima. In generale, la complessità temporale è O(bm ) (nell’esempio,
m = ∞) e la complessità spaziale è O(b · m) (in generale è necessario mantenere attivo
soltanto il nodo corrente dell’albero, quindi m livelli con b nodi per livello nel caso peggiore).
4 c∗ /ε è il costo della soluzione nel caso peggiore dunque rappresenta la profondità della soluzione
14 RISOLUZIONE DEI PROBLEMI TRAMITE RICERCA

Questa strategia ammette una variante, denominata backtracking, in cui invece di generare
tutti i b successori di un nodo ne viene generato uno alla volta. Il vantaggio è che la sua
complessità spaziale è O(m), non considerando la struttura dati supplementare per tener
traccia del prossimo successore da generare per ogni nodo.

Profondità limitata Questa strategia di ricerca è uguale alla ricerca in profondità, con
la differenza che è definito un limite l per cui, prima di espandere un nodo dopo avere
applicato il test obiettivo, se questo nodo si trova a profondità l non viene espanso. Per
applicare questa strategia è necessario modificare la struttura dati del nodo aggiungendo
l’informazione sulla profondità. La ricerca a profondità limitata è completa se l ≥ d, non è
ottima, ha complessità temporale di O(bl ) e complessità spaziale di O(b · l).

Ricerca ad approfondimento iterativo Il maggiore problema della ricerca a profondità


limitata è che non è noto il minimo valore di l necessario a trovare una soluzione se non
si conosce il valore di d. Questa strategia ripete iterativamente una ricerca a profondità
limitata aumentando di 1 ogni volta il valore di l. Questo permette, rispetto alla ricerca in
ampiezza, di ridurre notevolmente la complessità spaziale: è completa (nel caso in cui b non
sia ∞), non è ottima5 , ha complessità temporale pari a
1(d + 1) + bd + b2 (d − 1) + · · · + bd · 1 = O(bd )
che è la stessa della ricerca in ampiezza quando viene applicato il test obiettivo al momento
della generazione del nodo, ma ha complessità spaziale di O(b · d).

2.3.2 Strategie di ricerca informate


Le strategie di ricerca informate fanno uso di informazione supplementare rispetto a quella
contenuta nella definizione del problema, per scegliere il prossimo nodo da espandere della
frontiera. L’idea di base è quella di definire una funzione f (n), detta funzione di valutazione,
che valuta in qualche modo i nodi che sono presenti nella frontiera. Tutte le volte che un
algoritmo di ricerca (grafo o albero) deve scegliere un nodo dalla frontiera, sceglie quello con
valore di f (n) più alto.

Ricerca greedy Un primo modo per definire la funzione di valutazione è definirla come la
funzione euristica f (n) = h(n), h(n) ≥ 0, che rappresenta una stima del costo per andare
dal nodo n al nodo di goal più vicino. In questo caso la strategia di ricerca è detta greedy
best first. Si noti che, formalmente, la funzione euristica è definita sui nodi. Tuttavia, nei
problemi pratici è più semplice definire la funzione euristica sugli stati: questo significa che
tutti i nodi che corrispondono allo stesso stato hanno lo stesso valore della funzione euristica.
Viene costruito come al solito l’albero di ricerca. Nella frontiera si utilizza un ordinamento
basato sulla funzione f .
Esempio 2.5: Albero generato dallo spazio degli stati della figura 2.3 utilizzando la ricerca greedy best
first.

A Andamento della frontiera (nodo, valore di f (n)):


• (A, 3)
B C • (B, 2) (C, 3)
• (C, 3) (A, 3) (E, 0)
A E

L’ultimo nodo ad essere espanso è E in quanto ha il valore minore della funzione di valutazione (0). Il
test obiettivo fornisce esito positivo, e l’algoritmo termina restituendo la soluzione A − B − E.
5 come nel caso della ricerca in ampiezza, trova sempre la soluzione più vicina alla radice
STRATEGIE DI RICERCA 15

h(B) = 2

2 B 6

h(A) = 3 A E h(E) = 0 stato iniziale: A


stato finale: E

2 2
C D
h(C) = 3 2 h(D) = 2

Figura 2.3: Uno spazio degli stati in cui sono indicati i valori della funzione euristica.

Questa strategia non è completa (si può ciclare all’infinito tra gli stessi stati se le euristiche
sono definite in modo opportuno) e quindi non è nemmeno ottima. È invece completa ma
non ottima utilizzando Ricerca-grafo. La sua complessità è O(bn ) (sia temporale che
spaziale).

Ricerca A* Si può definire un’altra funzione di valutazione come f (n) = g(n) + h(n),
somma del costo del cammino per arrivare al nodo n e della stima del costo per arrivare da
n al nodo di goal (funzione euristica). Questa funzione rappresenta la stima del costo di una
soluzione che passa per n. La strategia di ricerca che utilizza questa funzione è detta A∗ .
Esempio 2.6: Albero generato dallo spazio degli stati della figura 2.3 utilizzando la ricerca A*.

A Andamento della frontiera (nodo, valore di f (n)):


• (A, 3)
B C • (B, 4) (C, 5)
• (C, 5) (A, 7) (E, 8)
A E A D • (A, 7) (E, 8) (A, 7) (D, 6)
• (A, 7) (E, 8) (A, 7) (C, 9) (E, 6)
C E

L’ultimo nodo ad essere espanso è E in quanto ha il valore minore della funzione di valutazione (6). Il
test obiettivo fornisce esito positivo, e l’algoritmo termina restituendo la soluzione A − C − D − E di
costo pari a 6.

Con la ricerca A∗ viene scelto quello che globalmente è il nodo più promettente, secondo
la combinazione del costo sostenuto per arrivare a quel nodo più il costo stimato per arrivare
al goal.

Definizione (Euristica ammissibile). Una funzione euristica è ammissibile quando, per ogni
nodo n
h(n) ≤ h∗ (n)
dove h∗ (n) è il costo reale per arrivare da n allo stato obiettivo

Una funzione euristica è ammissibile, dunque, quando non sovrastima mai il costo per
arrivare al goal. Ci sono diverse tecniche per calcolare funzioni euristiche ammissibili, senza
conoscere il valore di h∗ (n) (ad esempio, per problemi geografici, un’euristica ammissibile
per problemi in cui il costo è il calcolo della distanza tra luoghi - con ostacoli - può essere
la distanza in linea d’aria tra due luoghi). Per qualsiasi tipo di problema, un’euristica
16 RISOLUZIONE DEI PROBLEMI TRAMITE RICERCA

sicuramente ammissibile è 0 per tutti gli stati: in questo caso, la ricerca A∗ si riduce alla
ricerca a costo uniforme. In un nodo di goal, h(n) = 0. Si può dimostrare la proprietà
seguente: A∗ è ottimo se viene utilizzato l’algoritmo Ricerca-albero e h è una euristica
ammissibile.
Idea della dimostrazione: Siano n e G2 due nodi della frontiera, tali che G2 sia un nodo
di goal subottimo e n un nodo che sta sul percorso ottimo per arrivare al goal (nota: questo
nodo esiste sempre se nella frontiera è presente un nodo di goal subottimo). f (G2 ) =
g(G2 ) > c∗ essendo G2 un nodo di goal subottimo, ed essendo c∗ è il costo del cammino
ottimo. f (n) = g(n) + h(n) ≤ c∗ essendo g(n) + h(n) una funzione che non sovrastima il
costo ottimo per arrivare al goal. Allora

f (n) ≤ c∗ < f (G2 )

Questo significa che non verrà mai scelto dall’algoritmo di ricerca A∗ un nodo di goal
subottimo.
Definizione (Euristica consistente). Una funzione euristica è consistente quando per ogni
coppia di nodi n e n0 tali che n0 sia successore di n,

h(n) ≤ c(n, n0 ) + h(n0 )

dove c(n, n0 ) è il costo di passo per andare da n a n0 .


La condizione di consistenza è più stringente dell’ammissibilità. Vale infatti l’implicazione
seguente: se una euristica h è consistente, allora è anche ammissibile. Il viceversa non vale
in generale, anche se in realtà è molto difficile trovare un’euristica ammissibile ma non
consistente.
Teorema. A∗ è ottimo se viene utilizzata Ricerca-grafo e h è consistente.
Idea della dimostrazione: per poter garantire l’ottimaltà su ricerca grafo, devo dimostrare
che tutte le volte che estraggo un nodo dalla frontiera, ho già trovato un cammino ottimo
che passa da quel nodo. Se l’euristica è consistente,

f (n0 ) = g(n0 ) + h(n0 ) = g(n) + c(n, n0 ) + h(n0 ) ≥ g(n) + h(n) = f (n)

pertanto
f (n0 ) ≥ f (n)
per qualsiasi coppia n, n0 t.c. n0 successore di n. Se l’euristica è consistente, la funzione di
valutazione del successore non è mai più piccola della funzione di valutazione del padre: la
funzione di valutazione in un path dell’albero di ricerca è sempre non decrescente. Inoltre, si
può dimostrare che se l’euristica è consistente, A∗ espande i nodi in ordine non decrescente di
f (n). Questo implica che tutte le volte che viene espanso un nodo, si è trovato un cammino
ottimo fino allo stato corrispondente a quel nodo. In particolare, la prima volta che viene
espanso un nodo di goal, si è trovato un cammino ottimo per quel nodo.
Sul funzionamento di A∗ si può dimostrare che l’algoritmo espande
• tutti i nodi con f (n) < c∗
• qualche nodo con f (n) = c∗
• nessun nodo con f (n) > c∗
Si dice che A∗ è ottimamente efficiente: a parità di euristica, non esiste alcun altro algo-
ritmo che espanda meno nodi di A∗ e che garantisca di trovare la soluzione ottima. Sia la

complessità temporale che quella spaziale di A∗ ha la forma O((h −h)×l ). Esistono delle
versioni che utilizzano un quantitativo di memoria limitato (fissato) a spese della complessità
temporale.
3 Ricerca con avversari

Il problema della ricerca con avversari si riscontra tipicamente in giochi come la dama o gli
scacchi. È l’unica tipologia di ambiente multiagente (in particolare, si tratta di un ambiente
in cui operano due soli agenti) che verrà considerato. In questo contesto non è più definito il
concetto di soluzione del problema di ricerca, che viene sostituito dal concetto di strategia:
una strategia indica che cosa il giocatore deve fare rispetto a tutte le possibili azioni che può
compiere l’avversario.
È possibile classificare i giochi, caso tipico della ricerca con avversari, secondo vari aspetti:

• una prima classificazione distingue in giochi deterministici (che quindi non coinvolgono
elementi come il lancio di dadi, carte da estrarre, . . . ) e giochi con casualità.

• un secondo aspetto distingue i giochi a informazione perfetta da quelli a informazione


imperfetta. Un gioco è a informazione perfetta se i due giocatori conoscono ad ogni
istante lo stato completo del gioco, ed è a informazione imperfetta se vi sono elementi
dello stato del gioco che non sono conosciuti da uno dei giocatori (un esempio è il
poker, in cui il giocatore non conosce le carte in mano agli avversari)

Inizialmente l’attenzione sarà rivolta ai giochi deterministici a informazione perfetta. In


seguito, si vedrà come queste tecniche possono essere estese a giochi a informazione perfetta
ma con casualità.

3.1 Giochi come un problema di ricerca


Assumendo che il gioco si svolga a turni e che coinvolga due soli giocatori (detti max e min,
dove max è il primo giocatore che deve effettuare una mossa), si può formalizzare un gioco
come un problema di ricerca costituito dai seguenti elementi:

• lo stato iniziale del gioco

• una funzione Giocatore(s) che, dato uno stato s, restituisce un valore tra min e max,
corrispondente al giocatore che deve effettuare una mossa in s.

• una funzione Azioni(s) che restituisce l’insieme di mosse legali nello stato s

• una funzione Risultato(s, a) = s0 , che fornisce lo stato s0 risultante dall’esecuzione


dell’azione a nello stato s

• il test di terminazione che, dato uno stato, indica se è uno stato finale del gioco. Il
test di terminazione sostituisce quello che nella formulazione del problema di ricerca
era il test obiettivo. A differenza di come era stato definito il test obiettivo (che non
impedisce di effettuare ulteriori azioni), se viene soddisfatto il test di terminazione non
è possibile effettuare ulteriori azioni

• una funzione Utilità(s, p) che ha come parametri uno stato terminale s e uno dei
due giocatori p, e indica qual è l’utilità del giocatore p per lo stato s. Un esempio di
funzione utilità potrebbe ritornare +1 per il giocatore che vince, −1 per il giocatore
che perde, 0 in caso di pareggi).
18 RICERCA CON AVVERSARI

Figura 3.1: Porzione dell’albero di gioco per il tris

Questa formalizzazione definisce implicitamente lo spazio degli stati, che è necessario esplo-
rare con l’artificio dell’albero di ricerca, detto in questo contesto albero di gioco. Ad esempio,
nella figura 3.1 è rappresentata una porzione dell’albero di gioco per il tris. Si può notare,
come prima differenza con i problemi di ricerca classici definiti nelle sezioni precedenti, che
per poter definire una formalizzazione di un gioco è necessario entrare più profondamente
nella struttura dello stato: non è quindi in generale sufficiente avere degli stati identificati
semplicemente da una lettera.
Definizione (Gioco a somma zero). Un gioco si definisce a somma zero se la somma delle
utilità dei giocatori è pari a 0 per ogni stato terminale.
Considerando soltanto giochi a somma zero, si può definire soltanto un valore della fun-
zione utilità (che quindi non dipende dal giocatore), corrispondente all’utilità di max, e
assumere che il giocatore max vuole massimizzare l’utilità, mentre min vuole minimizzarla.
Per questo motivo, nell’esempio di figura 3.1 è rappresentata soltanto l’utilità di max.

3.2 Algoritmo Minimax


Per determinare la mossa migliore per il giocatore max in un gioco, si può sfruttare il calcolo
del valore minimax, associato ad ogni nodo dell’albero di gioco. Il valore minimax è definito
come l’utilità per max di stare in quel nodo, se da quel punto in poi entrambi i giocatori
giocano la partita perfetta. L’idea di base dell’algoritmo minimax risiede nel massimizzare
il minimo valore di utilità che max può ottenere se min gioca la partita perfetta, ovvero di
massimizzare il peggior risultato.
Se è stato generato tutto l’albero di gioco, i valori minimax dei nodi possono essere calcolati
propagandoli verso la radice a partire dai nodi terminali:
ALGORITMO MINIMAX 19

• il valore minimax di un nodo terminale è pari alla sua utilità per max
• il valore minimax di un nodo min è il più piccolo tra i valori minimax dei suoi figli
• il valore minimax di un nodo max è il più grande tra i valori minimax dei suoi figli
Se non è stato ancora generato l’albero di gioco, invece, è possibile calcolare il valore minimax
direttamente durante la visita (o la costruzione) dell’albero in profondità. La figura 3.2
rappresenta un albero per un gioco fittizio, in cui si è indicato per ogni nodo il valore
minimax. Per convenzione, in figura sono rappresentati i nodi corrispondenti a stati in cui
deve giocare max (nodi max) con un triangolo la cui punta è rivolta verso l’alto, mentre i
nodi min sono rappresentati da triangoli con la punta rivolta verso il basso. I nodi terminali
sono rappresentati da un quadrato.

nodo max
3
valore minimax
3 2 2

3 12 8 2 4 6 11 5 2

Figura 3.2: Albero di gioco con valori minimax

In giochi di dimensioni reali risulta computazionalmente impossibile costruire tutto l’al-


bero di gioco. In questi casi, gli algoritmi che vengono utilizzati generano l’albero a partire
dalla radice, senza arrivare agli stati terminali. In altri termini, questi algoritmi tagliano
l’albero in corrispondenza di determinati nodi. È definito un test di taglio che, applicato a
un nodo, decide in base ad alcune caratteristiche (ad esempio la profondità del nodo), se
espandere o meno il sottoalbero a partire da quel nodo. Altre tecniche che vengono utilizzate
consistono nell’espandere, in base a qualche caratteristica, solo un successore di alcuni nodi
e non tutti (estensione singola), oppure scegliere le due o tre mosse che potrebbero essere
migliori (potatura in avanti). Il risultato finale dell’applicazione di queste ottimizzazioni è
un albero le cui foglie non sono terminali. Per calcolare il valore di questi nodi, non essendo
definita la funzione di utilità, viene introdotta la funzione di valutazione che, dato uno stato
non terminale, restituisce un valore associato a quello stato per il giocatore max: questa
funzione è concettualmente simile all’euristica h definita per gli algoritmi di ricerca infor-
mata (A∗ ). Ad esempio, una funzione di valutazione per il gioco degli scacchi può valutare
elementi come il numero di pezzi rimasti, il tipo di pezzi rimasti, la disposizione dei pezzi
sulla scacchiera e altri ancora. Una volta costruito l’albero, viene infine utilizzato l’algoritmo
minimax per propagare fino alla radice i valori ottenuti dalla funzione di valutazione.

3.2.1 Potatura alfa-beta


Per migliorare l’efficienza della tecnica minimax, si può affiancare la tecnica della potatura
alfa-beta (α − β pruning). Per ricavare l’albero a partire dalla definizione del gioco come
problema di ricerca, si può procedere costruendolo in profondità. Appena viene raggiunto un
nodo terminale, si può osservare che è possibile ricavare informazioni sui valori minimax di
altri nodi, pur non conoscendo esattamente quali siano questi valori. Ad esempio, visitando
un nodo terminale il cui valore di utilità è pari a 3, si può ricavare che il padre di questo nodo,
se è un nodo min, avrà un valore minimax ≤ 3. A partire da considerazioni di questo tipo,
si può evitare di generare e visitare intere parti dell’albero, pur mantenendo un risultato
finale esattamente identico a quello generato da minimax (viene trovata la soluzione esatta,
non una approssimata), in quanto si potano rami che vengono sicuramente scartati.
20 RICERCA CON AVVERSARI

3 ≤2 2

3 12 8 2 11 5 2

Figura 3.3: Albero ottenuto con potatura alfa-beta relativo al gioco di figura 3.2

L’entità della potatura (il numero di nodi che non vengono generati) dipende dall’ordine
di valutazione dei nodi. Si può dimostrare che, se il numero di nodi generato da minimax
quando esplora tutto l’albero di gioco è O(bm ) dove b è il branching factor (il massimo
numero di successori di un nodo) e m è la profondità dell’albero, nel caso migliore, ossia
con l’ordinamento dei nodi migliore possibile, la potatura alfa-beta permette di avere una
complessità di O(bm/2 ).

Algorithm 1 Potatura alfa-beta


function Vmax(stato, α, β) . Per lo stato iniziale s0 : Vmax(s0 , −∞, +∞)
if TestTerminale(stato) then
return Utilita(stato)
end if
v ← −∞
for all Successori(stato) as s do
v ← max(v, Vmin(s, α, β))
if v ≥ β then
return v
end if
α ← max(α, v)
end for
return v
end function

function Vmin(stato, α, β)
if TestTerminale(stato) then
return Utilita(stato)
end if
v ← +∞
for all Successori(stato) as s do
v ← min(v, Vmax(s, α, β))
if v ≤ α then
return v
end if
β ← min(β, v)
end for
return v
end function

L’implementazione classica per calcolare il valore minimax di un nodo max e di un nodo


min (algoritmo 1) fa uso di due parametri, detti α e β, dove α è il valore della scelta migliore
per max trovata fino a questo momento, mentre β è il valore della scelta migliore per min
trovata fino a questo momento. In generale, si ha una situazione - presentata in figura 3.4 -
GIOCHI CON CASUALITÀ: EXPECTIMINIMAX 21

in cui nell’albero di gioco è presenta un nodo max in cui c’è una scelta che porta ad avere
un certo valore α di utilità. A un certo punto, un’altra scelta per max porta a un altro
nodo max. Se il valore di un nodo min figlio di quest’ultimo nodo è minore o uguale a un
certo valore v, con v ≤ α, si possono evitare di generare i nodi sotto questo nodo min (si
può effettuare un taglio alfa). Lo stesso ragionamento può essere fatto dal punto di vista di
min (taglio beta): si può tagliare quando c’è un’opzione che è sicuramente più grande del
suo valore β.
...

α ...

... valore ≤ v ≤ α
posso tagliare
...

Figura 3.4: Taglio alfa

3.3 Giochi con casualità: expectiminimax


Le tecniche presentate finora si applicano alla creazione di agenti per giochi deterministici,
privi quindi di elementi di casualità quali il lancio di dadi. Queste tecniche possono essere
generalizzate a giochi con casualità. Ovviamente, le funzioni definite per la formulazione
di un problema, vanno modificate in maniera opportuna per tenere conto della presenza
degli elementi di casualità: il modo più semplice per farlo è considerare un terzo giocatore
(“natura”) che sceglie una mossa secondo una certa distribuzione di probabilità. Nella rap-
presentazione dell’albero di gioco quest’estensione equivale all’aggiunta di nodi di casualità,
i cui rami uscenti sono etichettati con la probabilità con cui la scelta si verifica. L’algoritmo
expectiminimax è un’estensione delle tecniche viste sinora a questo caso. Ad ogni nodo
dell’albero viene assegnato un valore valore expectiminimax in questo modo:

• per i nodi terminali, è il valore di utilità corrispondente

• per un nodo min, è pari al minimo dei valori expectiminimax dei suoi figli

• per un un nodo di casualità è il valore atteso dei valori expectiminimax dei suoi figli

• per un nodo max è il massimo dei valori dei suoi figli.

La figura 3.5 presenta un esempio di albero di gioco e di calcolo dei valori expectimi-
nimax. Nell’esempio sono presenti dei nodi di casualità, rappresentati con dei cerchi, che
corrispondono ai momenti del gioco in cui interviene l’elemento della casualità (in questo
caso, il lancio di una moneta). In questo gioco, max sceglie una mossa, poi viene lanciata
una moneta, min effettua una mossa e il gioco finisce.
È possibile applicare l’algoritmo di potatura alfa-beta visto nel paragrafo precedente anche
nel caso di giochi con casualità. L’algoritmo di potatura alfa-beta, nel modo in cui è stato
presentato, assume che i valori che può assumere la funzione di utilità non siano noti: si
aspetta che i prossimi valori della funzione di utilità possano essere qualsiasi. In realtà, è
22 RICERCA CON AVVERSARI

5.5
5.5 4

0.5 0.5 0.5 0.5

3 8 2 6

5 3 12 8 2 4 6 11

Figura 3.5: Gioco con casualità con valori expectiminimax

spesso possibile fornire dei limiti superiori e inferiori sui possibili valori della funzione di
utilità, ad esempio è possibile supporre che i valori della funzione di utilità per il gioco
di figura 3.5 siano compresi nell’intervallo [−2, +2]. A fronte di queste considerazioni, si
possono migliorare le prestazioni dell’algoritmo.

Nota Essendo la funzione di valutazione una stima della funzione di utilità, possono sor-
gere problemi quando viene utilizzata la tecnica del taglio e dell’utilizzo della funzione di
valutazione con l’algoritmo expectiminimax. Perché l’approccio minimax dia una soluzione
ottima, è necessario che i valori alle foglie dell’albero siano i più precisi possibili: non è suf-
ficiente che mantengano l’ordinamento delle preferenze nelle situazioni per max, ma devono
mantenerne anche la scala, altrimenti la scelta della mossa migliore viene modificata.
4 Problemi di soddisfacimento di vincoli

I problemi di soddisfacimento di vincoli (CSP, constraint satisfaction problem) sono una


specializzazione del problema di ricerca in cui la rappresentazione dello stato è di tipo
fattorizzato (non è atomica come negli algoritmi di ricerca informata e non informata visti
precedentemente). In particolare, uno stato è un insieme di variabili che possono assumere
dei valori che spaziano in determinati domini. Formalmente, un problema di soddisfacimento
di vincoli è definito da:

• un insieme di variabili x1 , x2 , . . . , xn

• un insieme di domini D1 , D2 , . . . , Dn dove Di è il dominio dei valori della variabile xi

• un insieme C1 , C2 , ..., Cm di vincoli. I vincoli specificano le combinazioni di valori per


le variabili ammissibili per il problema (ad esempio, un possibile vincolo è x1 6= x2 ).
Dati i valori delle variabili coinvolte, un vincolo può essere vero o falso: un vincolo
può essere rappresentato come una relazione, ossia da un sottoinsieme del prodotto
cartesiano dei domini delle variabili coinvolte nel vincolo

Lo scopo di un problema di soddisfacimento di vincoli è trovare un assegnamento di valori


alle variabili che sia completo e consistente. Un assegnamento è consistente quando non
viene violato alcun vincolo; è completo quando assegna un valore ad ognuna delle variabili.
I problemi CSP possono essere classificati in problemi a domini continui (problemi tipici
della ricerca operativa) e problemi a domini discreti. A loro volta, i domini discreti possono
essere finiti o infiniti. Nel seguito ci si concentrerà su CSP a domini discreti e finiti.
Esempio 4.1 (colorazione di una mappa geografica): Data una mappa geografica dell’Australia, rappre-
sentata in figura 4.1, si vogliono colorare i territori in modo tale che non ci siano due territori adiacenti
che abbiano lo stesso colore, avendo a disposizione tre colori (rosso, verde, blu). Il problema può essere

Northern
Territory
Queensland
Western
Australia
South
Australia New
South
Wales
Victoria

Tasmania

Figura 4.1: Mappa relativa all’esempio della colorazione degli Stati

formalizzato come segue:


• variabili: WA, NT, SA, Q, NSW, V, T (i territori)
• domini: Di = r, g, b (i tre colori: red, green, blue)
24 PROBLEMI DI SODDISFACIMENTO DI VINCOLI

• vincoli: ad esempio WA 6= NT, WA 6= SA, NT 6= SA, WA 6= SA, . . .

Se tutti i vincoli di un CSP sono binari, se ne può tracciare il grafo dei vincoli, ossia un
grafo i cui nodi rappresentano le variabili e i cui archi rappresentano i vincoli tra le variabili:
due nodi sono collegati da un arco se le variabili che rappresentano sono legate tra loro da
un vincolo. Qualsiasi CSP che coinvolga vincoli che non sono binari può essere ricondotto a
un CSP equivalente che ha solo vincoli binari.

NT Q NSW

WA V

SA

Figura 4.2: Grafo dei vincoli per il problema dell’esempio 4.1

Esempio 4.2 (problema delle otto regine): Il problema delle otto regine può essere formalizzato come
un problema di soddisfacimento di vincoli in vari modi. Una prima formulazione è la seguente:
• si definiscono 64 variabili xij , 1 ≤ i, j ≤ 8, una per ogni casella
• Dij = 0, 1 (ogni variabile vale 1 se la casella contiene una regina, 0 altrimenti)
• vincoli:
– xij = 1 =⇒ xik = 0 1 ≤ k ≤ 8, k 6= j
– xij = 1 =⇒ xkj = 0 1 ≤ k ≤ 8, k 6= i
P8−k
– i=1
xi,i+k ≤ 1 0≤k<8
P8−k
– i=1
xi+k,i ≤ 1 1≤k<8
P8−k
– i=1
xi,8+1−(i+k) ≤ 1 0≤k<8
P8−k
– xi+k,8+1−i ≤ 1 1≤k<8
Pi=1
– i≤i,j≤8
xi,j = 8
Poiché su ogni colonna ci deve essere una e una sola regina, è possibile derivare un’altra formulazione,
più compatta, del problema come CSP:
• variabili: xj 1 ≤ j ≤ 8 (colonne)
• domini: Dj = 1, 2, . . . , 8 (riga su cui sta la regina per la colonna considerata)
• vincoli:
– xj = k =⇒ xi 6= k 1 ≤ i ≤ 8, i 6= j
– xj = k =⇒ |k − xj | 6= |j − i| 1 ≤ i ≤ 8, i 6= j
In questa seconda formulazione non è necessario formalizzare il vincolo per cui devono esserci otto regine,
in quanto viene garantito dal fatto che si cerca un assegnamento completo.

Altri esempi di problemi formalizzabili come CSP sono i problemi di assegnamento (e.g.
assegnamento di task a esecutori), di scheduling (programmare le partenze di attività lungo
l’asse temporale). Nel caso di un problema di scheduling conviene avere come variabili gli
istanti di inizio delle attività, e come vincoli i vincoli di precedenza. Ad esempio, il vincolo
x2 > x1 formalizza che l’istante di inizio dell’attività 2 deve iniziare dopo l’inizio dell’attività
1, mentre, se T è la durata dell’attività 1, x2 > x1 +T formalizza che l’attività 2 deve iniziare
dopo la fine dell’attività 1.
CSP COME PROBLEMI DI RICERCA 25

4.1 CSP come problemi di ricerca


Un problema di soddisfacimento di vincoli può essere formulato come un problema di ricerca
definendone i cinque elementi caratterizzanti in questo modo:
• stato iniziale: l’assegnamento vuoto {}
• funzione Azioni(s): dato uno stato s, questa funzione restituisce tutti gli assegnamenti
di valori consistenti a una delle variabili non assegnate in s
• funzione Risultato(s, a) = s0 : lo stato s0 è costituito dallo stato s unito al nuovo
assegnamento. Per come è stata definita la funzione Azioni, tutti gli assegnamenti
presenti in s0 sono consistenti.
• test obiettivo: verifica se lo stato s è completo1
• costo di passo: viene considerato pari a 1
Per i problemi di soddisfacimento di vincoli, la ricerca in profondità è efficiente: si dirige
subito verso il livello - noto a priori - in cui si può trovare una soluzione.

{}

WA = r WA = g ... T =G

W A = r, N T = g W A = r, N T = b . . .

...

Figura 4.3: Porzione di albero generato dalla ricerca in profondità per il problema dell’esempio 4.1

Poiché lo stato viene rappresentato in modo fattorizzato, e quindi ne è nota la struttura,


è possibile migliorare notevolmente lo schema di base della ricerca in profondità. Una
prima ottimizzazione risiede nella considerazione che, per i problemi di soddisfacimento
di vincoli, l’ordine con cui si effettuano gli assegnamenti non è importante ai fini della
ricerca di una soluzione (vale la proprietà commutativa). Questo permette di fissare l’ordine
con il quale assegnare le variabili, e definire la funzione Azioni in modo che, stabilito un
ordine delle variabili, al primo livello generi tutti gli assegnamenti consistenti per la prima
variabile, al secondo livello tutti gli assegnamenti consistenti per la seconda variabile, e cosı̀
via. Utilizzando una ricerca in profondità standard, per un problema in cui sono presenti n
variabili su un dominio di d valori, vengono generati nel caso pessimo n!dn nodi. Utilizzando
la funzione Azioni modificata tenendo in considerazione che l’ordine con cui si assegnano
variabili non è importante ai fini del trovare una soluzione, nel caso pessimo vengono generati
dn nodi.

4.2 Euristiche
Pur non influenzando la possibilità di trovare o meno una soluzione, cambiando l’ordine con
cui le variabili vengono assegnate, può variare l’efficienza della ricerca. Ad esempio, nel pro-
blema della colorazione della carta geografica dell’Australia, per aumentare l’efficienza della
soluzione lo stato SA, coinvolto nel maggior numero di vincoli, dovrebbe essere assegnato
all’inizio. Un altro aspetto critico, oltre all’ordinamento delle variabili, risiede nella scelta
di un ordinamento dei valori del dominio da assegnare alle variabili.
1 la consistenza è assicurata da come è definita la funzione Azioni
26 PROBLEMI DI SODDISFACIMENTO DI VINCOLI

{}

WA = r WA = g WA = b

W A = r, N T = g W A = r, N T = b ... ...

W A = r, N T = g, SA = b . . . ...

...

Figura 4.4: Porzione di albero generato per l’esempio 4.1 sfruttando la commutatività

È possibile definire tutte le euristiche che verranno descritte in seguito esclusivamente


perché gli stati del problema di ricerca non sono rappresentate in modo atomico, ma come
insiemi di variabili con associati dei valori. Facendo uso delle euristiche, si riescono a risolvere
problemi di grandi dimensioni (ad esempio il problema delle 1000 regine).

4.2.1 Scelta della variabile


Per scegliere le variabili da assegnare, si può utilizzare l’euristica MRV (minimum remai-
ning value). In base a questa euristica, viene scelta sempre la variabile con il minimo
numero di valori legali rimasti nel proprio dominio. Considerando il problema dell’esempio
4.1, utilizzando l’euristica MRV l’inizio della ricerca in profondità prosegue secondo quanto
rappresentato in figura 4.5(a).

{} {}

WA = b SA = b

W A = b, N T = g SA = b, N T = g

W A = b, N T = g, SA = r SA = b, N T = g, N SW = r

(a) MRV (b) euristica di grado

Figura 4.5: Porzione di albero di ricerca ricavato utilizzando MRV e l’euristica di grado

L’euristica MRV aumenta l’efficienza della ricerca poiché permette di individuare i fal-
limenti il prima possibile, scegliendo - se esiste - per prima una variabile che ha dominio
vuoto. Tuttavia, MRV non permette di dire alcunché sulla prima variabile a cui assegnare il
valore: inizialmente, se i domini hanno tutti la stessa cardinalità, tutte le variabili hanno lo
stesso numero di valori legali rimasti nel proprio dominio. Per rimediare a questo problema,
si può usare l’euristica di grado, che sceglie la variabile che è coinvolta nel maggior numero di
vincoli con altre variabili non ancora assegnate. Applicando l’euristica di grado all’esempio
4.1, si ottiene quanto rappresentato in figura 4.5(b), dove sono riportati solo i primi passi. A
differenza di MRV, l’euristica di grado cerca di assegnare per prime le variabili più critiche,
dove per variabili più critiche si intendono quelle coinvolte nel maggior numero di vincoli.
PROPAGAZIONE DEI VINCOLI 27

Nell’esempio riportato, infatti, viene assegnato per primo un valore alla variabile SA. Se
tutte le variabili non sono assegnate, il numero di vincoli coinvolti in una variabile è il grado
del nodo nel grafo dei vincoli, da cui il nome di euristica di grado. È stato dimostrato che si
può ottenere una soluzione migliore combinando sia MRV che l’euristica di grado: di base si
utilizza MRV, ricorrendo all’euristica di grado quando MRV non è in grado di determinare
una variabile (fornisce una parità tra più variabili).

4.2.2 Scelta del valore


Una volta scelta una variabile a cui assegnare un valore a un dato livello dell’albero, rimane
il problema di scegliere quale valore assegnare a quella variabile. A questo scopo, si può
utilizzare l’euristica del valore meno vincolante: si sceglie il valore che lascia più libertà alle
altre variabili ancora da assegnare che sono adiacenti sul grafo dei vincoli alla variabile che
si sta assegnando.
Esempio 4.3 (rif. esempio 4.1): Generando una prima porzione dell’albero senza utilizzare una partico-
lare euristica, si può arrivare a questo punto:

{}

WA = r

W A = r, N T = g ...

W A = r, N T = g, Q =??? . . .

...

Al terzo passo ci sono due valori possibili da assegnare alla variabile Q, b e r. Scegliendo b la vaiabile
SA avrebbe 0 valori legali rimasti, mentre scegliendo r la variabile SA avrebbe 1 valore legale rimasto.
L’euristica del valore meno vincolante sceglie questa seconda possibilità, ponendo Q=r.

L’idea di questa euristica è favorire il più possibile il trovare una soluzione, poiché bisogna
selezionare il valore da assegnare a una variabile il cui nodo è già stato generato. Questa
considerazione è opposta a quella che viene fatta nella scelta della variabile: quando bisogna
scegliere una variabile da assegnare, poiché si deve generare un nodo, se ci sono elementi per
determinare che un ramo è già destinato al fallimento, conviene scoprirlo subito (euristica
MRV).

4.3 Propagazione dei vincoli


Sfruttando la rappresentazione dello stato fattorizzata di un problema di soddisfacimento
di vincoli, si possono definire delle tecniche di per propagare i vincoli parallelamente alla
costruzione dell’albero di ricerca. L’utilizzo di queste tecniche permette di semplificare il
problema e agevolare la ricerca della soluzione: mentre nella formulazione come problema
di ricerca il controllo del rispetto dei vincoli è contenuto nella funzione Azioni, le tecniche
di propagazione dei vincoli controllano i vincoli anche in altri momenti della ricerca.

Verifica in avanti La tecnica della verifica in avanti, o forward checking, permette di


controllare i vincoli tutte le volte che si assegna un valore a una variabile. A seguito del-
l’assegnamento di un valore a una variabile x, vengono controllate tutte le variabili non
assegnate legate a x da un vincolo, e si eliminano dai domini di queste variabili i valori
28 PROBLEMI DI SODDISFACIMENTO DI VINCOLI

che sono inconsistenti con il valore di x. L’informazione che è contenuta nei vincoli viene
propagata nei domini delle variabili, in un processo parallelo alla costruzione dell’albero di
ricerca. La tecnica della verifica in avanti si applica molto spesso come supporto all’euristica
MRV, per aggiornare ad ogni iterazione i domini delle variabili.
Esempio 4.4 (rif. esempio 4.1): Nella tabella sottostante sono rappresentati, per ogni assegnamento
che viene effettuato nell’esplorazione di parte di un ramo dell’albero di ricerca, i domini delle variabili
per come vengono modificati dalla verifica in avanti. I valori in grassetto sono le variabili già assegnate.

WA NT Q NSW SA V T
{r, g, b} {r, g, b} {r, g, b} {r, g, b} {r, g, b} {r, g, b} {r, g, b}
r {g, b} {r, g, b} {r, g, b} {g, b} {r, g, b} {r, g, b}
r {b} g {r, b} {b} {r, g, b} {r, g, b}
r {b} g {r} {} b {r, g, b}
(a) domini

{}

WA = r

W A = r, Q = g

W A = r, Q = g, V = b

...
(b) albero

A questo punto della costruzione dell’albero, il dominio della variabile SA è vuoto: questo significa che
questo ramo è destinato al fallimento. Utilizzando l’euristica MRV, SA sarebbe la prossima variabile
da generare. Applicando questa tecnica, si è scoperto che il dominio di SA è vuoto appena dopo avere
assegnato il valore b allo stato V, e non quando si è cercato di generare il successore (come nell’euristica
MRV). In realtà, ci si poteva accorgere che il ramo è destinato al fallimento già dopo l’assegnamento
Q=g: NT e SA non possono contemporaneamente essere blu, unico valore consentito, ma questo tipo
di inconsistenza non viene rilevato dalla verifica in avanti.

Consistenza d’arco Un’euristica migliore per la propagazione dei vincoli è data dalla con-
sistenza d’arco. In particolare, in questo paragrafo viene descritto l’algoritmo AC-3. Questo
algoritmo controlla il grafo dei vincoli e considera ogni lato come bidirezionale2 .

Definizione (Arco consistente). Si dice che un arco x → y è consistente quando, per ogni
valore del dominio di x esiste qualche valore consistente nel dominio di y.

Applicare la consistenza d’arco significa rendere consistenti gli archi x → y cancellando


valori dal dominio di x. L’idea dell’algoritmo AC-3 è la seguente:

• Si crea una coda contenente tutti gli archi

• Per ogni arco x → y presente in coda, si verifica la consistenza con gli altri archi

• Quando viene aggiornato il dominio di una variabile x per rendere consistente un arco,
è necessario rimettere in coda tutti gli archi della forma z → x, perché potrebbero non
essere più consistenti a seguito della variazione del dominio di x
2 ad esempio, il lato tra SA e NSW viene scomposto in due archi SA → NSW e NSW → SA
PROPAGAZIONE DEI VINCOLI 29

La consistenza d’arco può essere applicata sia come pre-processing prima di iniziare la ricerca,
per semplificare i domini (e quindi avere un minore branching factor per l’albero), che
applicandola tutte le volte che viene assegnato un valore a una variabile.
Ci sono tecniche più potenti della consistenza d’arco per semplificare il problema di ricerca:
la consistenza d’arco (2-consistenza) verifica solo la consistenza tra coppie di variabili; altre
tecniche come la 3-consistenza verificano la consistenza tra triple di variabili, e cosı̀ via
generalizzando, al costo di aumentarne la complessità: verificare la n-consistenza di un
problema con n variabili equivale a risolvere il problema di ricerca.
Esistono problemi, anche non banali, che possono essere completamente risolti senza
costruire l’albero ed effettuare la ricerca, ma semplicemente applicando tecniche come la
consistenza d’arco e le sue generalizzazioni.
5 Agenti basati sulla conoscenza

Come per tutte le tipologie di agente analizzate finora, anche gli agenti basati sulla conoscen-
za risolvono problemi costruendo un albero di ricerca, terminando quando viene generato un
nodo che corrisponde a uno stato finale nello spazio degli stati. Quello che li differenzia dalle
altre tipologie di agente è il contenuto dei singoli nodi. A differenza delle rappresentazioni
atomiche tipiche degli algoritmi di ricerca informata e non informata, e delle rappresenta-
zioni di tipo fattorizzato tipiche dei problemi di soddisfacimento di vincoli, gli agenti basati
sulla conoscenza utilizzano infatti una rappresentazione dello stato del mondo strutturata.
In particolare, lo stato è rappresentato attraverso una KB (knowledge base), che contiene
della conoscenza (informazione espressa formalmente).
Nel caso che verrà considerato, le informazioni presenti nella knowledge base sono espresse
attraverso il linguaggio formale della logica (logica proposizionale oppure logica del primo
ordine). Una KB contiene un insieme di formule in and logico tra di loro. Dal punto di vista
dell’implementazione, servono due meccanismi per poter operare su una KB di questo tipo:

• un meccanismo per asserire fatti, ossia aggiungere formule alla base di conoscenza

• una procedura di interrogazione, con la quale si può chiedere se una formula α è con-
seguenza logica delle formule presenti (KB |= α), ossia se α è vero in tutti i modelli
che rendono vere le formule della KB.

Procedure di inferenza
Si dice che KB `i α quando a partire dalla KB si riesce a derivare α (meccanicamente,
ovvero guardando solo la sintassi e non la semantica) applicando la procedura di inferenza i.
Rispetto alla relazione tra l’inferenza e il concetto di conseguenza logica, si possono definire
le proprietà di completezza e correttezza.

Definizione (Completezza). Una procedura di inferenza i è completa se tutte le formule


che sono conseguenza logica della KB possono essere derivate dalla procedura i:

KB |= α =⇒ KB `i α

Definizione (Correttezza). Una procedura di inferenza i si dice corretta (sound) se, quando
deriva una formula α, allora α è conseguenza logica della KB:

KB `i α =⇒ KB |= α

Naturalmente, una procedura di inferenza “ideale” deve essere corretta e completa. In ogni
caso, è importante garantire la correttezza rispetto alla completezza.
Il vantaggio di utilizzare formule logiche per rappresentare lo stato sta nel poter utilizzare
un insieme piccole di formule per la rappresentazione di uno stato del mondo, senza avere la
necessità di esplicitarne tutte le conseguenze. Queste conseguenze possono essere derivate
all’occorrenza, direttamente dall’agente, attraverso una procedura di inferenza. Per questo
motivo gli agenti basati sulla conoscenza possono lavorare anche in ambienti parzialmen-
te osservabili: dagli assiomi e dalla parte del mondo osservabile l’agente può dedurre la
struttura delle parti dell’ambiente non direttamente osservabili.
32 AGENTI BASATI SULLA CONOSCENZA

Nota Quando l’agente applica una procedura di inferenza per derivare nuova conoscenza,
lo sta facendo in un singolo stato del mondo (che è rappresentato da una singola KB), per
derivare proprietà di quello stato implicitamente contenute nella KB.

5.1 Procedure di inferenza per la logica proposizionale


5.1.1 Concatenazione in avanti (FC)
La concatenazione in avanti è una procedura di inferenza che si applica a basi di conoscenza
che contengono esclusivamente clausole definite.
Definizione (Clausola definita). Una clausola definita è una formula costituita da un solo
simbolo proposizionale oppure da una congiunzione di simboli proposizionali che implica un
singolo simbolo proposizionale.
Esempi di clausole definite sono A, A ∧ B =⇒ C, A =⇒ C. Esempi di formule che non
sono clausole definite sono A∧B =⇒ C ∨D (non implica un singolo simbolo proposizionale)
e A ∨ B =⇒ C (l’antecedente non è una congiunzione).
Nelle applicazioni pratiche, la restrizione a KB costituite esclusivamente da clausole de-
finite non è troppo limitante, in quanto moltissimi domini possono essere adeguatamente
descritti da formule di questo tipo (ad esempio il funzionamento degli artefatti).
La concatenazione in avanti applica una singola regola di inferenza: il modus ponens (MP),
che nel caso della logica proposizionale assume la seguente forma1 :
α1 α2 α1 ∧ α2 ∧ · · · ∧ αn =⇒ β
... αn
MP
β
dove α e β sono generici simboli proposizionali. La concatenazione in avanti, data una
base di conoscenza, estrae ripetutamente da essa n + 1 formule che soddisfano la condizione
espressa dal modus ponens, e aggiunge la formula risultante dall’applicazione della regola di
inferenza.
Esempio 5.1: Dalla seguente KB
1. P =⇒ Q
2. L ∧ M =⇒ P
3. B ∧ L =⇒ M
4. A ∧ P =⇒ L
5. A ∧ B =⇒ L
6. A
7. B
le formule che vengono aggiunte alla KB dall’algoritmo sono:
8 L MP(5,6,7)
9 M MP(7,8,3)
10 P MP(8,9,2)
11 Q MP(10,1)
A questo punto l’algoritmo ha raggiunto un punto fisso, e non può derivare più nulla.
La concatenazione in avanti può derivare solo simboli proposizionali (fatti), ma non deriva
mai nuove implicazioni (regole). Per questo motivo, un limite superiore al numero di ap-
plicazioni del modus ponens effettuate dalla concatenazione in avanti è dato dal numero di
regole. Per questo motivo - che si può sfruttare per ricavarne una implementazione efficiente
- la complessità temporale dell’algoritmo è lineare nel numero di formule presenti nella KB.
1 nelle rappresentazioni di una regola di inferenza, vengono indicate sopra la linea orizzontale tutte le formule
che devono essere presenti nella base di conoscenza per potere applicare la regola, mentre sotto la linea
sono indicate le formule che possono essere aggiunte alla KB applicando la regola di inferenza
PROCEDURE DI INFERENZA PER LA LOGICA PROPOSIZIONALE 33

Proprietà Per le sole KB contenenti solo formule definite, la procedura di inferenza della
concatenazione in avanti è corretta e completa.

5.1.2 Concatenazione all’indietro (BC)


La concatenazione all’indietro è una procedura di inferenza che parte dalla dalla formula Q
di cui si vuole dimostrare se è o meno conseguenza della base di conoscenza:

KB `?BC Q

Questa formula, a differenza del caso della concatenazione in avanti, va indicata esplicita-
mente, in quanto la procedura di inferenza parte dall’obiettivo (la query) e cerca di risalire
alle premesse, di di dimostrare se è conseguenza delle formule presenti nella KB.
La struttura dati che viene utilizzata è detta stack degli obiettivi. Inizialmente, lo stack
contiene l’obiettivo finale Q che si vuole dimostrare. Ogni volta che l’algoritmo estrae da
questa struttura dati un obiettivo, controlla se è presente come fatto nella base di conoscenza.
Se Q non è presente, cerca di applicare “al contrario” una regola presente nella KB, ossia
cerca una regola di cui Q è implicazione.
Ad esempio, riprendendo la base di conoscenza dell’esempio 5.1 e considerando come
obiettivo Q, l’algoritmo trova la regola

P =⇒ Q (1)

quindi si riduce a dimostrare il sotto-obiettivo P , che è una premessa dell’obiettivo. L’algo-


ritmo quindi inserisce nello stack il nuovo obiettivo P . Anche P non è presente come fatto
nella KB, ma si trova la regola
L ∧ M =⇒ P
e l’algoritmo procede considerando come obiettivi L e M . A questo punto, l’algoritmo
considera il sotto-obiettivo L. Nella KB esistono queste due formule:

A ∧ P =⇒ P

A ∧ B =⇒ P
Questo significa che, per dimostrare vero L bisogna dimostrare vero A ∧ P oppure A ∧ B. In
questo caso, vengono inseriti tutti nello stack degli obiettivi. Si procede quindi considerando
M . Si trova la regola B∧L =⇒ M , che vengono aggiunti alla struttura dati. Si estrae quindi
A che è presente nella KB come fatto, e quindi viene aggiunto nella struttura dati dimostrati.
Si estrae P : questo obiettivo non è dimostrabile, perché è proprio quello che si sta cercando
di dimostrare, quindi viene eliminato dallo stack degli obiettivi, e la strada di dimostrare
A e P per dimostrare L fallisce. A questo punto si considera A, che è già dimostrato. Si
estrae B, che risulta presente nella KB come fatto, e quindi anch’esso dimostrato. Avendo
dimostrato A e B, si è dimostrato anche L, che quindi viene aggiunto ai dimostrati. Si
estraggono B e L dallo stack degli obiettivi, entrambi già dimostrati: a questo punto si può
dimostrare M , P , Q e l’algoritmo termina. Il funzionamento dell’algoritmo nel complesso
può essere rappresentato dall’albero and-or di figura 5.1.
A differenza della concatenazione in avanti, che è guidata dai dati in quanto procede
dai fatti presenti nella KB, la concatenazione all’indietro è guidata dagli obiettivi. Si può
dimostrare che anche la concatenazione all’indietro è corretta e completa per KB composte
da clausole definite.

5.1.3 Risoluzione (R)


La risoluzione si applica a basi di conoscenza rappresentate in forma normale congiuntiva
(CNF). Una KB di questo tipo è un insieme di clausole, dove una clausola è una disgiunzione
34 AGENTI BASATI SULLA CONOSCENZA

L M

A P A B B L

Figura 5.1: Albero and-or relativo alla concatenazione all’indietro

di letterali2 . Un letterale è un simbolo proposizionale oppure un simbolo proposizionale


negato. Esempi di clausole sono

A ∨ ¬B B ∨ ¬C ∨ ¬D

Una base di conoscenza che contiene qualsiasi formula della logica proposizionale è esprimi-
bile in forma normale congiuntiva: il fatto che la risoluzione sia applicabile soltanto a KB in
questa forma, pertanto, non è limitante. Rispetto alla definizione data in precedenza, si può
notare che una clausola definita è una clausola che contiene esattamente un singolo letterale
positivo. Si definisce invece clausola di Horn una clausola che contiene al più un letterale
positivo.
La procedura di inferenza detta “risoluzione” applica ripetutamente la regola di inferenza
della risoluzione:
`1 ∨ · · · ∨ `i ∨ · · · ∨ `k , m1 ∨ · · · ∨ mj ∨ · · · ∨ mn
R
`1 ∨ · · · ∨ `i−1 ∨ `i+1 ∨ · · · ∨ `k ∨ m1 ∨ · · · ∨ mj−1 ∨ mj+1 ∨ · · · ∨ mn

dove li e mi sono letterali, e li e mj sono letterali complementari, ossia sono lo stesso simbolo
proposizionale, l’uno negato e l’altro no. La risoluzione parte da due clausole e deriva una
nuova clausola che contiene tutti i letterali di partenza tranne i due complementari.

Esempio 5.2:
A ∨ ¬B B ∨ ¬C ∨ ¬D
R
A ∨ ¬C ∨ ¬D

Anche per la risoluzione è necessario fornire l’obiettivo, ossia la formula α che si vuole
dimostrare3 :
KB `?R α

La risoluzione funziona per refutazione: si chiede se, aggiungendo alla base di conoscenza la
negazione della formula che si vuole dimostrare, si giunge a un assurdo (la clausola vuota
⊥):
KB ∪ {¬α} `?R ⊥

Si può dimostrare che la procedura di inferenza della risoluzione è corretta e completa per
la logica proposizionale.
2 all’interno della KB le singole formule, quindi le clausole, sono in congiunzione tra loro
3a differenza delle procedure di inferenza citate precedentemente, con la risoluzione l’obiettivo non è un
singolo simbolo proposizionale ma è una generica formula
PROCEDURE DI INFERENZA PER LA LOGICA DEL PRIMO ORDINE 35

Nota Per poter applicare la risoluzione, è necessario che ¬α (la negazione della formula da
dimostrare) sia in forma normale congiuntiva.
Esempio 5.3: Data la seguente KB
1. ¬B ∨ A
2. B
si vuole trovare se KB `?R A. Questo equivale a chiedere se KB ∪ {¬A} `?R ⊥. A quest’ultima
formulazione si può applicare la risoluzione. Ad esempio, da ¬B ∨ A e B si genera per risoluzione la
formula A. Applicando la risoluzione alle due clausole unitarie ¬A e A, che sono complementari, si
ottiene la clausola vuota ⊥.

Alcune strategie per applicare la risoluzione in modo efficiente sono:

• Risoluzione unitaria (o risoluzione con preferenze per le clausole unitarie). Questa


strategia cerca di applicare la regola della risoluzione a due clausole di cui una è
costituita da un singolo letterale

• Risoluzione con insieme di supporto. Questa strategia impone che ogni passo della
risoluzione coinvolga almeno una clausola da quello che si è definito come insieme di
supporto. Le clausole risolventi vengono a loro volta aggiunte all’insieme di supporto.
La criticità di questa strategia risiede nella scelta dell’insieme: una scelta errata può
rendere l’algoritmo incompleto

• Risoluzione di input. in ogni passaggio della risoluzione combina una formula di input
con un’altra formula. Tranne che in casi specifici, questa strategia non è in generale
completa.

5.2 Procedure di inferenza per la logica del primo ordine


5.2.1 Concetti preliminari
Si definisce unificatore di due formule del primo ordine α, β la sostituzione

Unify(α, β) = θ

tale che
αθ = βθ
dove una sostituzione {variabile/termineground} sostituisce (sintatticamente) le occorrenze
della variabile con il termine ground specificato.

α β θ
Knows(John, α) Knows(John, Jane) {x/Jane}
Knows(John, x) Knows(y, M other(y)) {y/John, x/M other(John)}
Knows(John, x) Knows(x, OJ) le formule non possono essere unificate
Knows(John, x) Knows(y, x) {y/John}

Tabella 5.1: Alcuni esempi di unificatori

La tabella 5.1 riporta alcuni esempi di unificatori. Nell’ultima riga, l’unificatore riportato
non è l’unico, ma è l’unificatore più generale (MGU, most general unifier). Altri unificatori
- che non sono i più generali - si possono trovare legando x a una costante. In generale,
è possibile determinare algoritmicamente l’unificatore più generale per due formule della
logica del primo ordine.
36 AGENTI BASATI SULLA CONOSCENZA

5.2.2 Concatenazione in avanti e all’indietro


In questo paragrafo siamo interessati a determinare se una formula del prim’ordine α è o
meno conseguenza logica di una KB mediante una procedura di inferenza. Se la procedura
di inferenza i è corretta, chiedere se
KB |=? α
equivale a chiedere se
KB `?i α
Le procedure di inferenza che si utilizzano in logica del primo ordine sono le stesse viste
nel caso della logica proposizionale. A differenza del caso proposizionale, la procedura
di inferenza fornisce, se determina che la formula α è conseguenza della KB - anche una
sostituzione θ tale per cui la formula ottenuta applicando ad α la sostituzione θ è una
conseguenza logica della KB (sempre se la procedura di inferenza è corretta).
Nelle basi di conoscenza che verranno utilizzate per fare inferenza non si utilizzano i
quantificatori, e si assume che, in ogni formula della KB, tutte le variabili sono quantificate
universalmente.
La concatenazione in avanti si applica a KB che contengono solo clausole definite (predicati
singoli, o fatti, e congiunzioni di predicati singoli che implicano un solo predicato, o regole).
La concatenazione in avanti applica ripetutamente il modus ponens in questa forma:

p1 0 , p2 0 , . . . , pn 0 , (p1 ∧ p2 ∧ . . . ∧ pn ⇒ q)
MP

dove p01 , p02 , . . . , p0n , p1 , . . . , pn , q sono formule atomiche della logica del primo ordine (predi-
cati singoli) e rispetto alla sostituzione θ:

∀i pi 0 θ = p i θ

Esempio 5.4: Data la seguente base di conoscenza


1. King(John)
2. Greedy(y)
3. King(x) ∧ Greedy(x) =⇒ Evil(x)
la sostituzione θ che unifica la (1) a King(x) e la (2) a Greedy(x) è

θ = {x/John, y/John}

per cui si può applicare il Modus Ponens, ottenendo - applicando alla formula risultante la sostituzione
θ:
4. Evil(John)

Esempio 5.5 (dal linguaggio naturale alla logica): Dato il seguente testo
La legge dice che è un crimine per un americano vendere armi alle nazioni ostili. La nazione
di Nono, un nemico dell’America, possiede dei missili, e tutti i suoi missili sono stati venduti
dal colonnello West, che è un americano. Il colonnello West è un criminale?
una KB che rappresenta la situazione è:
1. American(x) ∧ Weapon(y) ∧ Hostile(z) ∧ Sells(x, y, z) =⇒ Criminal(x)
2. Missile(M)
3. Owns(Nono, M)
4. Missile(x) ∧ Owns(Nono, x) =⇒ Sells(West, x, Nono)
5. Missile(x) =⇒ Weapon(x)
6. Enemy(x, America) =⇒ Hostile(x)
7. Enemy(Nono, America)
PROCEDURE DI INFERENZA PER LA LOGICA DEL PRIMO ORDINE 37

8. American(West)
dove la (2) e la (3) rappresentano la formula
(∃x)(M issile(x) ∧ Owns(N ono, x))
che non può essere inserita direttamente nella KB perché x è quantificata esistenzialmente. Per inserirla
nella KB, la variabile viene sostituita da un nuovo simbolo di costante, M (questo è un caso particolare
del procedimento di Skolemizzazione spiegato in seguito).
La domanda “Il colonnello West è un criminale?” si traduce - volendo utilizzare la concatenazione in
avanti (forward checking, FC), nel chiedersi se
?
KB `F C α
dove α = Criminal(West). Applicando la concatenazione in avanti, si ottiene la situazione rappresentata
dall’albero di figura 5.2, che viene costruito a partire dalle foglie, ossia dai fatti della base di conoscenza.

Criminal(West)

Weapon(M1) Sells(West,M1,Nono) Hostile(Nono)

American(West) Missile(M1) Owns(Nono,M1) Enemy(Nono,America)

Figura 5.2: Albero risultante dall’applicazione della FC all’esempio 5.5

Si può dimostrare che la concatenazione in avanti è corretta e completa per KB composte


da sole clausole definite. Il problema sta nella semidecidibilità della logica del primo ordine:
se la formula α non è conseguenza logica della KB, la procedura potrebbe non terminare,
e questo vale anche per il sottoinsieme della logica del primo ordine costituito dalle sole
clausole definite. È invece garantita la terminazione per l’algoritmo di concatenazione in
avanti per il sottoinsieme della logica del primo ordine che non utilizza le funzioni.
Come nel caso della concatenazione in avanti, anche la concatenazione all’indietro si ap-
plica a KB composte da sole clausole definite. La procedura della concatenazione all’indietro
parte dall’obiettivo ed è simile al caso proposizionale, effettuando una ricerca in profondità.
Un esempio è dato dall’albero di figura 5.3, riferito sempre all’esempio 5.5. La concatena-
zione all’indietro è una procedura di inferenza corretta, ma non completa (se si considera la
presenza di funzioni, la ricerca in profondità potrebbe non terminare). Sulla concatenazione
all’indietro è basato il funzionamento del linguaggio di programmazione prolog, mentre la
concatenazione in avanti trova applicazione in database deduttivi (Datalog).

5.2.3 Risoluzione
Come nel caso proposizionale, la risoluzione si applica a una KB che contiene solamente delle
formule in CNF (tutte le formule della logica del primo ordine sono esprimibili in CNF). I
passi per portare una formula generica in CNF sono una generalizzazione della procedura
utilizzata per la logca proposizionale.
Esempio 5.6: La frase “chiunque ami tutti gli animali è amato da qualcuno” può essere espressa in
logica del primo ordine come
∀x[(∀y Animal(y) =⇒ Loves(x, y)) =⇒ (∃y Loves(y, x))]
38 AGENTI BASATI SULLA CONOSCENZA

Criminal(West) {x/West, y/M1, z/Nono}

American(West) Weapon(y) Sells(West,M1,z) Hostile(Nono)


{} { z/Nono }

Missile(y) Missile(M1) Owns(Nono,M1) Enemy(Nono,America)


{ y/M1 } {} {} {}

Figura 5.3: Applicazione della BC all’esempio 5.5

per portarla in forma normale congiuntiva, si seguono i seguenti passi:


• Eliminazione delle implicazioni: α =⇒ β ≡ ¬α ∨ β. Questo si applica anche alle doppie
implicazioni, essendo α ⇔ β ≡ (α =⇒ β) ∧ (β =⇒ α). Applicando questo passo all’esempio:

∀x[¬[∀yAnimal(y) =⇒ Loves(x, y)] ∨ [∃yLoves(y, x)]]

∀x[¬[∀y(¬Animal(y) ∨ Loves(x, y))] ∨ [∃yLoves(y, x)]]


• Spostamento delle negazioni all’interno. Alla fine di questo passo, la formula deve contenere
simboli di negazione solamente davanti ai simboli di predicato, utilizzando regole come

¬∀xα ≡ ∃x¬α

oppure
¬∃xα ≡ ∀x¬α
Nell’esempio:
∀x[(∃y¬(¬Animal(y) ∨ Loves(x, y))) ∨ (∃yLoves(y, x))]
da cui applicando la legge di De Morgan si ottiene

∀x[(∃y(Animal(y) ∧ ¬Loves(x, y))) ∨ (∃yLoves(y, x))]

• Standardizzazione delle variabili: ogni quantificatore deve quantificare su una variabile diversa.
Nell’esempio, la formula contiene due quantificatori che operano su due variabili che hanno lo
stesso nome (y), quindi si cambia nome a una delle due variabili:

∀x[(∃y(Animal(y) ∧ ¬Loves(x, y))) ∨ (∃zLoves(z, x))]

• Skolemizzazione: si eliminano le variabili quantificate esistenzialmente, sostituendole con una


funzione (detta funzione di Skolem) delle variabili quantificate universalmente nel cui scope ricade
la variabile che si sta sostituendo4 . Applicando il procedimento all’esempio:

∀x[(Animal(F (x)) ∧ ¬Loves(x, F (x))) ∨ (Loves(G(x), x))]

• Eliminazione dei ∀

[Animal(F (x)) ∧ ¬Loves(x, F (x))] ∨ Loves(G(x), x)

• Distribuzione degli ∧ sugli ∨

[Animal(F (x)) ∨ Loves(G(x), z)] ∧ [¬Loves(x, F (x)) ∨ Loves(G(x), x)]

che è formula di partenza in forma CNF, ed è una congiunzione di disgiunzioni composta da due
clausole.
4 non è sufficiente sostituirle con costanti, altrimenti si stravolgerebbe il significato della formula di partenza
PROCEDURE DI INFERENZA PER LA LOGICA DEL PRIMO ORDINE 39

Il procedimento (automatizzabile) è in grado di trasformare in CNF qualsiasi formula della


logica del primo ordine. La formula che si ottiene è inferenzialmente equivalente alla formula
di partenza.
La procedura di inferenza applica la regola della risoluzione, che per la logica del primo
ordine assume la forma
`1 ∨ `2 ∨ · · · ∨ `k , m1 ∨ m2 ∨ · · · ∨ mn
(`1 ∨ · · · ∨ `i−1 ∨ `i+1 ∨ · · · ∨ `k ∨ m1 ∨ · · · ∨ mj−1 ∨ mj+1 ∨ · · · ∨ mn )θ
dove Unify(`i , ¬mj ) = θ
Esempio 5.7: Date le formule
• ¬Rich(x) ∨ U nhappy(x)
• Rich(Ken)
si può applicare la risoluzione utilizzando la sostituzione
θ = {x/Ken}
ottenendo la clausola U nhappy(Ken), che può essere aggiunta alla KB.

La procedura di inferenza della risoluzione applica ripetutamente la regola di inferenza a


una KB composta dalle formule di partenza e dalla negazione della formula a cui si vuole
arrivare, cercando di inferire la clausola vuota, ovvero per dimostrare se
?
KB |= α
applica l’inferenza
?
KB ∪ {¬α} `R ⊥
La procedura è corretta ed è completa per refutazione, ossia se α è effettivamente conse-
guenza logica della KB prima o poi la risoluzione troverà la clausola vuota. Se α non è
conseguenza logica della KB la risoluzione potrebbe fermarsi fornendo la risposta corretta
oppure andare avanti all’infinito.
Esempio 5.8: Data la KB relativa all’esempio 5.5, si vuole dimostrare se
?
KB |= Criminal(West)
utilizzando la risoluzione, ossia
?
KB ∪ {¬Criminal(West)} `R ⊥
Per prima cosa si aggiunge alla KB la formula
9. ¬Criminal(West)
Applicando la risoluzione, si trovano le seguenti clausole:
10. ¬American(West) ∨ ¬Weapon(y) ∨ ¬Sells(West, y, z) ∨ ¬Hostile(z) R(1, 9), {x/West}
11. ¬Weapon(y) ∨ ¬Sells(West, y, z) ∨ ¬Hostile(z) R(10, 2)
12. ¬Missile(y) ∨ ¬Sells(West, y, z) ∨ ¬Hostile(z) R(3, 11)
13. ¬Sells(West, M, z) ∨ ¬Hostile(z) R(4, 12), = {y/M}
14. ¬Missile(M) ∨ ¬Owns(Nono, M) ∨ ¬Hostile(Nono) R(5, 13), {x/M, z/Nono}
15. ¬Owns(Nono, M) ∨ ¬Hostile(Nono) R(4, 14)
16. ¬Hostile(Nono) R(6, 15)
17. ¬Enemy(Nono, America) R(7, 16), {x/Nono}
18. ⊥ R(8, 17)
La strategia di risoluzione eseguita è una risoluzione di input (tutte le volte si è risolta una formula
generica con una formula appartenente alla KB iniziale o a ¬α), e si è inoltre cercato di eliminare ad
ogni passo il letterale più a sinistra della clausola risultante.
6 Pianificazione

Le tecniche di pianificazione mettono insieme la costruzione di un albero per trovare la solu-


zione a un problema di ricerca e l’utilizzo della logica per rappresentare gli stati come insiemi
di formule, il che ha un forte impatto sull’efficienza e sull’espressività della rappresentazione.
Nella pianificazione, uno stato è un insieme di formule logiche. La rappresentazione degli
stati è basata sullo standard PDDL (planning domain definition language). Nel seguito verrà
utilizzato un sottoinsieme di questo linguaggio, il linguaggio STRIPS (Stanford Research
Institute Problem Solver), che storicamente è antecedente a PDDL ed è meno espressivo.

6.1 STRIPS
Uno stato è formato da una congiunzione di formule della logica del primo ordine. Le formule
che costituiscono uno stato devono essere letterali positivi, senza funzioni, e ground (senza
variabili). Le formule di uno stato sono implicitamente in and tra loro.
Esempio 6.1 (Mondo dei blocchi): In questo esempio, c’è un tavolo su cui sono posati dei blocchi (A,
B e C). Un robot li può afferrare e spostare. Un possibile stato di questo mondo è il seguente:

A B

che in STRIPS può essere rappresentato come:


BLOCK(A), BLOCK(B), BLOCK(C),
ON(A, TABLE), ON(B, TABLE), ON(C,A),
CLEAR(B), CLEAR(C), HANDEMPTY
Nella rappresentazione in STRIPS dell’esempio, ci sono ridondanze e informazioni rap-
presentate: ad esempio, i letterali CLEAR(B) e CLEAR(C), che indicano che B e C sono liberi,
potrebbero essere dedotti dal fatto che non c’è alcun blocco sopra B e C. Per poter effettuare
questo tipo di deduzioni, non valide in logica, spesso in questo ambito si introduce l’ipotesi
del mondo chiuso: si ipotizza che tutte le formule scritte sono vere, e tutte le formule che
non vengono menzionate sono false. Facendo questa ipotesi, i letterali CLEAR(B) e CLEAR(C)
sono effettivamente ridondanti.
In STRIPS, le azioni si indicano attraverso gli schemi di azione, che rappresentano un
insieme di azioni possibili a seconda di come vengono istanziate le variabili. Un possibile
schema di azioni per il mondo dei blocchi è il seguente:
UnStack(x, y)
P: HANDEMPTY, BLOCK(x), BLOCK(y),
CLEAR(x), ON(x, y)
E: ¬HANDEMPTY, ¬CLEAR(x), HOLDING(x), ¬ON(x, y),
CLEAR(y)
42 PIANIFICAZIONE

Uno schema d’azioni è costituito da due liste di formule. La lista P, detta lista delle precon-
dizioni, che contiene un insieme di formule della logica del primo ordine analoghe a quelle
utilizzate per la rappresentazione dello stato (letterali positivi ground privi di funzioni). La
lista delle precondizioni indica ciò che deve essere vero in uno stato per poter eseguire l’a-
zione. La lista E, detta lista degli effetti, contiene letterali positivi oppure negativi. È a sua
volta costituita dalla lista delle aggiunte (add list), che comprende i letterali positivi e indica
quali fatti devono essere veri successivamente all’applicazione dell’azione, e dalla delete list,
composta dai letterali negativi, che indica i fatti che erano veri prima di applicare l’azione
e non sono più veri in seguito. Come per la rappresentazione dello stato, precondizioni ed
effetti si intendono in and logico tra loro.
Un’azione si ottiene istanziando uno schema di azione, ossia assegnando dei valori alle
variabili. A partire dallo stato dell’esempio 6.1, un’azione che può essere eseguita è
UnStack(C, A)
In generale, un’azione A è applicabile in uno stato S quando tutte le precondizioni di A
compaiono nella descrizione di S. Il risultato dell’applicazione di un’azione a uno stato è un
nuovo stato ottenuto
• copiando la descrizione del vecchio stato nel nuovo
• aggiungendo alla descrizione gli elementi della lista delle aggiunte dell’azione applicata
• cancellando gli elementi presenti nella lista delle cancellazioni

Osservazione Un classico problema della pianificazione è il cosiddetto frame problem: da


un frame all’altro, moltissimi elementi rimangono identici e vengono modificati solo alcuni
elementi. Non è banale a questo proposito inserire in logica il concetto di tempo, il che rende
complicato risolvere questo problema in logica. STRIPS risolve questo problema copiando le
formule e modificando solo ciò che le azioni modificano. Un altro problema è il qualification
problem, che riguarda le precondizioni. Si assume che le precondizioni elencate in P siano
tutte e sole le precondizioni necessarie perché l’azione abbia successo. Questo, nel mondo
reale, porta rapidamente ad elencare un numero infinito di precondizioni.
Per completare la definizione di un problema di ricerca, manca la definizione di un obiettivo
(goal), che in STRIPS è una congiunzione di formule della logica del primo ordine che siano
letterali positivi ground e privi di funzioni. Si noti che un obiettivo non è uno stato, ma è un
insieme di letterali che devono essere veri in uno stato affinché quello stato sia considerato
terminale. Ad esempio, il goal ON(B,A) è verificato in tanti stati del mondo dei blocchi:
dipende da dove sta il blocco C.
La soluzione che viene restituita (piano) è la sequenza di azioni che porta da uno stato
iniziale a uno stato che soddisfa l’obiettivo.
In PDDL, a differenza di STRIPS, precondizioni e obiettivi possono contenere letterali
negativi. Un letterale negativo in una precondizione oppure in un obiettivo è soddisfatto se
non compare nella descrizione dello stato.
Esempio 6.2: Completiamo la definizione del mondo dei blocchi aggiungendo gli schemi di azioni, oltre
ad UnStack(x, y), che ne completano la definizione. Lo schema di azione Stack(x, y) posa il blocco
x, contenuto nel braccio robotico, sopra il blocco y.
Stack(x, y)
P: HOLDING(x), BLOCK(x), BLOCK(y),
CLEAR(y)
E: ON(x, y), ¬CLEAR(y), ¬HOLDING(x),
HANDEMPTY, CLEAR(x)
I due schemi di azione analizzati finora non permettono di mettere oppure togliere un blocco dal
tavolo. È quindi necessario definire un’altra coppia di schemi di azione per posare e togliere un blocco
dal tavolo.
PIANIFICAZIONE IN AVANTI 43

PickUp(x)
P: HANDEMPTY, BLOCK(x), CLEAR(x),
ON(x, TABLE)
E: ¬HANDEMPTY, ¬CLEAR(x), HOLDING(x),
¬ON(x, TABLE)
PullDown(x)
P: HOLDING(x)
E: ON(x, TABLE), ¬HOLDING(x), CLEAR(x),
HANDEMPTY

6.2 Pianificazione in avanti


Esistono vari approcci algoritmici per risolvere i problemi di pianificazione. Un primo ap-
proccio è quello della pianificazione in avanti, che considera il problema come un problema
di ricerca. I cinque elementi che lo caratterizzano sono:

stato iniziale la configurazione iniziale del mondo

funzione azioni le azioni applicabili in uno stato s sono tutte le istanze degli schemi di
azione applicabili a partire dallo stato s. Un’azione è applicabile a uno stato quando
tutte le precondizioni sono presenti nella descrizione dello stato

funzione risultato il risultato dell’applicazione di un’azione a a uno stato s è uno stato


descritto dallo stesso insieme di formule di s, a cui si tolgono gli effetti negativi di a e
si aggiungono gli effetti positivi

test obiettivo verifica se nell’insieme di formule che descrivono uno stato sono presenti le
formule che descrivono il goal

costo di passo può essere definito in vari modi, con un costo unitario oppure tenendo conto
di vari aspetti rilevanti per il dominio applicativo (ad esempio, sollevare un blocco
costa di più che abbassarlo)

Definito il problema in questo modo, si può impiegare una qualsiasi delle strategie di ricerca,
informata o non informata, per risolvere il problema di pianificazione. Il problema di questo
approccio è che i problemi reali sono di grandi dimensioni, e risultano intrattabili con questo
approccio: in un dominio di dimensione realistica il branching factor è troppo elevato per
essere gestito.

6.3 Pianificazione all’indietro


L’approccio della pianificazione all’indietro sfrutta l’idea di partire dall’obiettivo, cercando
di applicare gli schemi d’azione al contrario fino a risalire allo stato iniziale. Sono necessarie
alcune definizioni preliminari:

Definizione (Azione rilevante). Si dice che un’azione A è rilevante per un goal G se tra gli
effetti positivi dell’azione A compare un letterale di G.

Definizione (Azione consistente). Un’azione A si dice consistente per un goal G se tra i


suoi effetti negativi non compare alcun letterale di G.

Ad esempio, nel mondo dei blocchi, Stack(B,A) è rilevante e consistente per l’obiettivo

G: ON(B, A), ON(C, B)

mentre è rilevante, ma non consistente, per l’obiettivo


44 PIANIFICAZIONE

G’: CLEAR(B), CLEAR(A)


Definizione (Regressione). Si dice regressione di un goal g attraverso un’azione a (rilevante
e consistente per g) un nuovo goal
R[g, a]
che si ottiene in questo modo:
• si cancellano da g gli effetti positivi di a
• si aggiungono a g le precondizioni di a, se non sono già presenti
Dato un obiettivo g e un certo numero di stati che lo soddisfano, effettuando la regressione
di g si ottiene un nuovo goal R[g, a] che ha le seguenti proprietà:
• dato uno stato s0 che soddisfa R[g, a], le precondizioni di a sono soddisfatte in s0
• applicando l’azione a a s0 , si ottiene un nuovo stato s che soddisfa g
Il tutto può essere rappresentato da un diagramma commutativo:

soddisfa
g s

regressione si applica a

R[g, a] soddisfa
s0

Anche nell’approccio della pianificazione all’indietro viene formulato un problema di ri-


cerca, in questo modo:
stato iniziale il goal iniziale
funzione azioni le azioni applicabili allo stato s sono tutte le azioni rilevanti e consistenti
per il goal contenuto in s
funzione risultato il risultato dell’applicazione di un’azione a a uno stato s è la regressione
del goal corrispondente a s attraverso l’azione a
test obiettivo è verificato se il goal generato è soddisfatto dallo stato iniziale
costo di passo anche in questo caso, può essere unitario oppure dipendente dall’applicazione
Il vantaggio di questo approccio rispetto alla pianificazione in avanti è un ridotto branching
factor. Inoltre, mentre la pianificazione in avanti ragiona passando da uno stato a un altro
stato (spazio degli stati), la pianificazione all’indietro passa da un obiettivo a un altro (spazio
dei goal): i due metodi esplorano spazi concettuali diversi

6.4 Pianificatori nello spazio dei piani


Nella realtà si utilizza l’approccio della pianificazione nello spazio dei piani. Questo tipo di
pianificatore cerca un piano (sequenza di azioni), tra tutti i possibili piani generabili. A par-
tire da un piano vuoto, aggiunge un’azione per ogni livello dell’albero. Inoltre, solitamente
si fa uso di tecniche gerarchiche: si definiscono delle macro-azioni e si cerca un piano basato
su queste, poi si trova un piano per le azioni che corrispondono a una singola macro-azione.
Nell’approccio che è stato considerato (agenti risolutori di problemi), si cerca di costruire
offline un albero di ricerca, e quindi eseguire il piano trovato. Perché l’agente sia sicuro di
raggiungere l’obiettivo, l’ambiente dev’essere statico e deterministico. Per tener conto di
PIANIFICATORI NELLO SPAZIO DEI PIANI 45

un ambiente reale, che non è né statico né deterministico, una delle tecniche utilizzate è la
pianificazione (replanning): dopo avere eseguito ogni azione del piano, l’agente percepisce
l’ambiente per controllare se l’azione è andata a buon fine. Se non è andata a buon fine,
viene eseguita una ripianificazione.
Bibliografia

[1] Francesco Amigoni. Sito del corso di intelligenza artificiale. http://home.deib.polimi.


it/amigoni/IntelligenzaArtificiale.html.
[2] S. Russell and P. Norvig. Artificial intelligence: A modern approach (sito di riferimento).
http://aima.cs.berkeley.edu.

[3] S. Russell and P. Norvig. Artificial Intelligence: A Modern Approach. Pearson – Prentice
Hall, third edition, 2010.
[4] S. Russell and P. Norvig. Intelligenza Artificiale: Un approccio moderno, volume 1.
Pearson Italia, third edition, 2010.