You are on page 1of 52

Note per il Corso

Fondamenti dellInformatica
Laurea in Informatica
a.a. 2013/14

Giorgio Delzanno, Elena Zucca


8 giugno 2014
(versione preliminare incompleta)

Indice
1

Definizioni base [richiami da LPO]

Linguaggi regolari
4
2.1 Automi a stati finiti . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
2.2 Espressioni regolari [approfondimenti da LPO] . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.3 Propriet`a dei linguaggi regolari . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10

Linguaggi context-free
3.1 Grammatiche context-free [richiami da LPO] . . . .
3.2 Alberi di derivazione e ambiguit`a [richiami da LPO]
3.3 Grammatiche come definizioni induttive . . . . . .
3.4 Automi a pila . . . . . . . . . . . . . . . . . . . .
3.5 Propriet`a dei linguaggi context-free . . . . . . . .

Linguaggi context-sensitive e gerarchia di Chomsky

Macchine di Turing
5.1 Definizione delle macchine di Turing . . . . . . . .
5.2 Semantica operazionale . . . . . . . . . . . . . . .
5.2.1 Descrizioni istantanee . . . . . . . . . . .
5.2.2 Computazioni . . . . . . . . . . . . . . . .
5.3 Riconoscere linguaggi e calcolare funzioni . . . . .
5.4 Programmazione nelle MT . . . . . . . . . . . . .
5.4.1 Riconoscere 0n 1n . . . . . . . . . . . . .
5.4.2 Funzione somma di numeri in unario . . .
5.4.3 Ordinamento di stringhe . . . . . . . . . .
5.4.4 Conteggio simboli . . . . . . . . . . . . .
5.5 Varianti al Modello di Base . . . . . . . . . . . . .
5.5.1 Multitape MT . . . . . . . . . . . . . . . .
5.5.2 MT non deterministica . . . . . . . . . . .
5.5.3 Simulazione di una MT non deterministica
5.6 Macchine con nastro semi-infinito . . . . . . . . .
5.7 Macchine multistack . . . . . . . . . . . . . . . .
5.7.1 Osservazioni . . . . . . . . . . . . . . . .

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

12
12
13
15
17
19
21

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

24
25
26
26
27
27
28
29
29
30
31
31
32
33
34
35
36
37

Altri Modelli
38
6.1 Macchine di Turing e Computer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39

Linguaggi Ricorsivi e Ricorsivamente Enumerabili


7.1 Macchine come Stringhe . . . . . . . . . . . .
7.2 Linguaggio di Diagonalizzazione . . . . . . . .
7.3 Macchina e Linguaggio Universale . . . . . . .
7.4 Riduzioni tra Problemi . . . . . . . . . . . . .
7.4.1 LU LH . . . . . . . . . . . . . . .
7.4.2 LU LE . . . . . . . . . . . . . . .
7.4.3 LU LN E . . . . . . . . . . . . . .
7.4.4 LU LR . . . . . . . . . . . . . . .
7.4.5 LU Lk . . . . . . . . . . . . . . .
7.5 Teorema di Rice . . . . . . . . . . . . . . . . .
7.6 Altri esempi . . . . . . . . . . . . . . . . . . .

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

39
40
41
41
42
42
43
43
43
44
44
45

Post Correspondence Problem


45
8.1 PCP e Context-Free Languages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46

Automi come Modelli di Sistemi: LTS

47

A Appendice
A.1 Relazioni, funzioni e famiglie . . . . . . . . . . . . .
A.2 Definizioni induttive, prove per induzione e punti fissi
A.2.1 Definizioni induttive . . . . . . . . . . . . .
A.2.2 Principio di induzione . . . . . . . . . . . .
A.2.3 Definizioni induttive multiple . . . . . . . .
A.2.4 Punti fissi e definizioni conduttive . . . . . .

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

49
49
49
49
50
51
51

Definizioni base [richiami da LPO]

Def. 1.1 [Alfabeto] Un alfabeto e` un insieme finito non vuoto di oggetti detti simboli.
Def. 1.2 [Stringa] Una stringa u su un alfabeto e` una funzione totale1 da [1, n] in , per qualche n N; n si dice lunghezza
di u e si indica con |u|.
Nel seguito useremo per indicare generici simboli e u, v , w per indicare generiche stringhe.
Lunica stringa u di lunghezza 0 si chiama stringa vuota e si indica con oppure con ; linsieme delle stringhe su si indica
con ? e linsieme delle stringhe non vuote su si indica con + .
Def. 1.3 [Linguaggio] Un linguaggio formale o semplicemente linguaggio su un alfabeto e` un insieme di stringhe su , ossia
un sottoinsieme di ? .
Nel seguito useremo L per indicare generici linguaggi. Notiamo che ? e` sempre un insieme infinito2 . Linsieme vuoto e
linsieme costituito solo dalla stringa vuota {} (attenzione alla differenza!) sono linguaggi su qualunque alfabeto.
In genere, scriviamo le stringhe utilizzando la rappresentazione per giustapposizione, cio`e semplicemente scrivendo i simboli
uno dopo laltro da sinistra a destra.3
Consideriamo nel seguito un alfabeto fissato .
Def. 1.4 [Operazioni su stringhe] Se u e v sono stringhe di lunghezza n ed m rispettivamente, allora u v e` la stringa di lunghezza
n + m, definita da

u(k)
se 1 k n
(u v )(k) =
v (k n) se n < k n + m
E` facile vedere che loperazione di concatenazione di stringhe e` associativa, quindi possiamo utilizzare la notazione u1 . . . un ,
e ha come identit`a la stringa vuota4 .
Inoltre u n , per n 0, e` definita induttivamente da u 0 = , u n+1 = u u n .
La stringa u v viene anche scritta semplicemente uv .
Def. 1.5 [Operazioni su linguaggi] Se L e L0 sono linguaggi, L L0 = {u v | u L, v L0 }. Scriveremo anche semplicemente
LL0 . Inoltre Ln , per n 0, e` definito induttivamente da L0 = {}, Ln+1 = L Ln . Infine, la chiusura di Kleene L? di un
linguaggio L e` definita da L? = n0 Ln , e la chiusura positiva L+ da L+ = n>0 Ln .
E` facile vedere che anche loperazione di concatenazione di linguaggi e` associativa, quindi possiamo utilizzare la notazione
L1 . . . Ln , e ha come identit`a linsieme {}, mentre linsieme vuoto costituisce uno zero delloperazione, ossia L = L = .
Si noti la coerenza con le precedenti definizioni di ? e + , infatti possiamo vedere L? come linsieme delle stringhe sullalfabeto
L, ossia i cui simboli sono a loro volta stringhe.
Si chiama anche linguaggio, con abuso di terminologia, una famiglia di insiemi di stringhe, vedi la Definizione A.5. Per esempio,
nel caso dei linguaggi di programmazione, vi sono diversi insiemi di oggetti sintattici, come programmi, comandi, dichiarazioni,
espressioni ecc., e si usa linguaggio in questa accezione quando si sia interessati a tutti questi insiemi e non solamente a un
insieme principale.
1 Vedi

la Definizione A.1.
precisamente e` un insieme numerabile, ossia in corrispondenza biunivoca con linsieme N dei numeri naturali. Perche?
3 Tuttavia questa rappresentazione e
` arbitraria e pu`o risultare ambigua, mentre la Definizione 1.2 e` rigorosa e indipendente dalla rappresentazione, per
cui e` conveniente richiamarsi a questa definizione se sorge qualche problema di ambiguit`a. Nella pratica, si pu`o invece utilizzare in ogni caso concreto una
rappresentazione non ambigua.
4 Si tratta quindi di un monoide.
2 Pi`
u

Linguaggi regolari

2.1

Automi a stati finiti

Def. 2.1 Un automa a stati finiti deterministico (DFA) e` una quintupla M = hQ, , , q0 , F i dove:
Q e` un insieme finito di stati
e` un alfabeto (alfabeto di input)
: Q Q e` una funzione totale detta funzione di transizione
q0 Q e` lo stato iniziale
F Q e` linsieme degli stati finali.
Un DFA pu`o essere immaginato come una testina (in un certo stato) che legge, spostandosi sempre nella stessa direzione, un
nastro di lunghezza illimitata contenente dei simboli. A seconda dello stato del simbolo letto la testina si porta in un altro stato
(o rimane nello stesso) e si sposta a destra. Quando la lettura dei simboli termina, a seconda dello stato della testina, lautoma
fornisce un risultato di accettazione o rifiuto. Un DFA accetta una stringa in input u se e solo se esiste un cammino i cui archi
sono etichettati con i simboli della stringa nellordine dallo stato iniziale a uno stato finale. Formalmente, definiamo la funzione
: Q ? Q nel modo seguente:
) = q
(q,

u), )
(q, u) = ((q,
0 , u) F . Il linguaggio L(M) accettato (riconosciuto) da M e` linsieme delle
e diciamo che una stringa u e` accettata se (q
stringhe accettate, ossia
0 , u) F }.
L(M) = {u | (q
I linguaggi regolari sono quelli accettati da qualche DFA.
Esercizio 2.2 Proviamo che , {} e ? sono insieme regolari. Infatti, e` immediato vedere che:
e` il linguaggio accettato da un qualunque automa con insieme di stati finali vuoto
{} e` il linguaggio accettato da un automa con stato iniziale e finale q0 , un altro stato q1 non finale, e (q0 , ) = q1 ,
(q1 , ) = q1 per ogni simbolo dellalfabeto
? e` il linguaggio accettato da un automa con stato iniziale e finale q0 , e (q0 , ) = q0 per ogni simbolo dellalfabeto .
Un DFA pu`o essere rappresentato come un grafo orientato etichettato detto grafo di transizione, oppure dando una matrice di
transizione, come illustrato dai seguenti esempi.
Esempio 2.3 Determiniamo il linguaggio accettato dal seguente DFA, rappresentato come matrice di transizione, con stato finale
q1 :
q0
q1
q2

0
q1
q1
q1

1
q2
q1
q0

La rappresentazione come grafo di transizione e` la seguente (gli stati finali sono evidenziati con un doppio cerchio):
0,1
0

q2
1

q1
0

q0

Dimostriamo che il linguaggio accettato consiste delle stringhe con almeno uno zero. A tale scopo, proviamo per induzione
aritmetica, vedi Proposizione A.9, sulla lunghezza della stringa che:
0 , u) = q1 se e solo se u contiene almeno uno zero.
(q
0 , ) = q0 .
Base La tesi vale per la stringa vuota in quanto si ha (q
0 , u) = q1 se e solo se u contiene
Passo induttivo Consideriamo una stringa della forma u. Per ipotesi induttiva, si ha che (q

almeno uno zero. Si hanno due casi: se u contiene almeno uno zero, allora (q0 , u) = q1 , e a questo punto qualunque sia
0 , u) 6= q1 , quindi (q
0 , u) = q0
si resta in q1 quindi si ha la tesi. Se invece u non contiene almeno uno zero, allora (q
0 , u) = q2 . In entrambi i casi leggendo si va in q1 se e solo se = 0, quindi si ha la tesi.
oppure (q
Nel seguito, quando la funzione di transizione e` chiara dal contesto, utilizzeremo talvolta per maggiore leggibilit`a la notazione
u
u) = q 0 .
q q 0 per (q,
Esempio 2.4 Sia = {0, 1}. Proviamo che il linguaggio formato da tutte le stringhe in cui il penultimo simbolo e` uno zero e`
regolare.
Per provare che un linguaggio e` regolare e` sufficiente dare un DFA che accetti il linguaggio. Possiamo costruire questo DFA
ragionando nel modo seguente:
nello stato iniziale q0 non ho ancora letto uno 0, quindi questo stato non deve essere finale
se dallo stato iniziale leggo un 1, resto nello stato q0 (non ho ancora letto uno 0 che sia possibile penultimo)
se dallo stato iniziale leggo uno 0, passo nello stato q1 (se leggo ancora solo un simbolo ok)
se da q1 leggo un 1, passo nello stato q2 , che dovr`a essere finale (ho letto uno 0 e un 1, se non leggo pi`u simboli ok)
se da q1 leggo uno 0, passo nello stato q3 , che dovr`a essere finale (ho letto due zeri, se non leggo pi`u simboli ok)
se da q2 leggo uno 0, passo nello stato q1 , in quanto avendo letto un 1 e uno 0 se leggo ancora solo un simbolo ok
se da q2 leggo un 1, torno nello stato q0 , in quanto avendo letto due 1 non ho ancora letto uno 0 che sia possibile penultimo
se da q3 leggo uno 0, resto nello stato q3 , in quanto ho letto due zeri
se da q3 leggo un 1, passo nello stato q2 , in quanto ho letto uno 0 e un 1.
Otteniamo quindi il seguente automa dove q2 e q3 sono finali [andrebbero marcati anche nel disegno]:
1

q0
1

q1

0
0

q2

q3

Dimostriamo ora formalmente che lautoma cos` costruito effettivamente riconosce il linguaggio dato. Anzitutto notiamo che
0
1
le stringhe di lunghezza minore di due non sono accettate (correttamente), in quanto q0 non e` finale e q0 q1 , q0 q0 .
Consideriamo ora le stringhe di lunghezza almeno due, ossia della forma u0 oppure u1. Notiamo che si ha, qualunque sia lo
00
01
10
11
u00
u01
stato q, che q q3 , q q2 , q q1 , q q0 . Di conseguenza si ha anche, qualunque sia lo stato q, che q q3 , q q2 ,
00
u10
u11
u00
u
q q1 , q q0 (si noti che in questo caso non serve ragionare per induzione in quanto q q3 se q q 0 e q 0 q3 , e
analogamente per gli altri casi).
Si noti che un DFA, essendo la funzione di transizione totale, non si blocca mai, nel senso che in qualunque stato ci si trovi e`
sempre possibile transire in qualche altro stato, qualunque sia il simbolo dellalfabeto letto. Si potrebbe dare una definizione
pi`u generale in cui la funzione di transizione pu`o essere parziale, interpretando questa come unabbreviazione per un DFA
equivalente con funzione di transizione totale 0 e uno stato morto in pi`u qdead , con 0 definita come in tutti i casi in cui e`
definita, e inoltre 0 (q, ) = qdead se (q, ) indefinita e 0 (qdead , ) = qdead per ogni .

Def. 2.5 Un automa a stati finiti non deterministico (NFA) e` una quintupla M = hQ, , , q0 , F i dove Q, , q0 , F sono come
per i DFA, mentre la funzione di transizione ha forma : Q (Q), dove (Q) denota linsieme delle parti di Q, ossia
linsieme i cui elementi sono i sottoinsiemi di Q.
In questo caso definiamo : Q ? (Q) nel modo seguente:
) = {q}
(q,
0
u) = S 0
(q,
q (q,u) (q , )
0 , u) F 6= . Il linguaggio L(M) accettato da M e` linsieme delle stringhe
e diciamo che una stringa u e` accettata se (q
accettate, ossia
0 , u) F 6= }
L(M) = {u | (q
La rappresentazione a tabella deve ora prevedere in ogni casella un insieme di stati, mentre la rappresentazione a grafo rimane
immutata. Si osservi che in questo caso e` possibile che per un certo stato e simbolo non vi sia transizione possibile.
Esempio 2.6 Sia = {0, 1}. Diamo un NFA per il linguaggio formato da tutte le stringhe in cui il penultimo simbolo e` uno
zero.
Possiamo costruire questo NFA ragionando in modo pi`u semplice, e ottenendo un automa pi`u compatto, di quanto visto prima
nel caso deterministico: partendo dallo stato iniziale q0 , finche leggo degli 1 resto sicuramente in q0 , mentre quando leggo uno 0
posso non deterministicamente restare in q0 (lo 0 che ho letto non e` il penultimo simbolo), oppure passare in q1 e poi qualunque
sia il simbolo letto nello stato finale q2 , nel quale non e` pi`u possibile leggere ulteriori simboli. Otteniamo quindi:
0|1

q0

q1

0|1

q2

Proviamo ora che i linguaggi accettati dai DFA e dagli NFA coincidono. Uninclusione e` ovvia in quanto un DFA e` un caso
particolare di NFA. Per linclusione inversa, si pu`o convertire un NFA in un DFA con lidea seguente:
gli stati del DFA sono insiemi di stati del NFA
per ogni stato qD del DFA, che quindi e` un insieme di stati del NFA, per ogni simbolo si ha una transizione nellinsieme
degli stati ottenuti con transizioni da stati in qD nel NFA .
Formalmente si ha il seguente teorema.
Teorema 2.7 [Rabin-Scott, 1959] Sia MN = hQ, , N , q0 , FN i un NFA. Allora esiste un DFA MD tale che L(MD ) =
L(MN ).
Prova Costruiamo MD come la quintupla h(Q), , D , {q0 }, FD i dove:
S
D (qD , ) = qqD N (q, ) per qD (Q)
FD = {qD Q | qD FN 6= }
Proviamo per induzione aritmetica sulla lunghezza della stringa che, per ogni u ? , D ({q0 }, u) = N (q0 , u). Si noti che in
entrambi i casi il risultato e` un elemento di (Q), ossia un insieme di stati.
Base Per la stringa vuota si ha D ({q0 }, ) = {q0 } per definizione di D (caso deterministico), e N (q0 , ) = {q0 } per
definizione di N (caso non deterministico).
Passo induttivo Consideriamo una stringa u. Per ipotesi induttiva, si ha che D ({q0 }, u) = N (q0 , u), e vogliamo provare
che si ha anche D ({q0 }, u) = N (q0 , u). Infatti si ha:
D ({q0 }, u) =
D (D ({q0 }, u), ) per definizione di D (caso deterministico) =
SD (N (q0 , u), ) per ipotesi induttiva (si noti che N (q0 , u) e` un insieme di stati) =
qN (q0 ,u) N (q, ) per definizione di D =
N (q0 , u) per definizione di N (caso non deterministico).
6

Avendo provato che, per ogni u ? , D ({q0 }, u) = N (q0 , u), e` facile vedere che u e` accettata da MD se e solo se e`
accettata da MN . Infatti u e` accettata da MD se e solo se D ({q0 }, u) FD , ossia, per definizione, se e solo se D ({q0 }, u) =
N (q0 , u) FN 6= , ossia se e solo se u e` accettata da MN .
Esempio 2.8 Applichiamo la costruzione del precedente teorema al seguente NFA dove q2 e` finale:
q0
q1
q2

0
q0
q1
q1 , q2

1
q0 , q1
q0 , q2
q0 , q1 , q2

Per semplicit`a, consideriamo solo gli insiemi di stati che sono raggiungibili a partire dallo stato iniziale {q0 }, infatti e` chiaro che
un automa pu`o sempre essere trasformato in uno equivalente eliminando tutti gli stati non raggiungibili. Otteniamo:
{q0 }
{q0 , q1 }
{q0 , q1 , q2 }

0
{q0 }
{q0 , q1 }
{q0 , q1 , q2 }

1
{q0 , q1 }
{q0 , q1 , q2 }
{q0 , q1 , q2 }

ossia:
1

{q 0}

{q0, q1 }

{q , q 1, q 2}
0

0|1

dove {q0 , q1 , q2 } e` finale [andrebbe marcato anche nel disegno]. Il linguaggio accettato e` linsieme delle stringhe che contengono
almeno due 1 (lo si provi formalmente per esercizio).
Esercizio 2.9 Sia = {0, 1}. Si consideri lautoma non deterministico che accetta il linguaggio formato da tutte le stringhe in
cui il penultimo simbolo e` uno zero visto sopra. Si applichi a questo NFA la costruzione del teorema precedente e lo si confronti
con quello dellesempio 2.4.
Def. 2.10 Un NFA con transizioni  e` una quintupla M = hQ, , , q0 , F i dove Q, , q0 , F sono come per gli NFA, mentre la
funzione di transizione ha forma : Q ( {}) (Q).
Intuitivamente, e` permesso passare da uno stato a un altro anche senza leggere simboli di input. In questo caso la costruzione
della funzione che restituisce linsieme degli stati raggiungibili da uno stato dato risulta pi`u complessa. Anzitutto, dato uno
stato q, possiamo definire induttivamente linsieme -closure(q) di tutti gli stati raggiungibili da q con transizioni silenti:
q -closure(q)
se q 0 (q, ), allora q 0 -closure(q)
se q 0 -closure(q) e q 00 -closure(q 0 ) allora q 00 -closure(q)
Possiamo ora estendere alle stringhe nel modo seguente:
) = -closure(q)
(q,
0
u) = S 0
(q,
q (q,u) -closure((q , ))
1 . . . n ) e` linsieme degli stati che possiamo ottenere a partire da q con una sequenza di transizioni 1 , . . . , n
ossia, (q,
0 , w) F 6= }.
intervallata da eventuali transizioni silenti, e definire il linguaggio accettato come {w | (q
), e che in questa classe di automi e` chiaramente
Si osservi che in questo caso (q, ) non coincide necessariamente con (q,
sempre possibile ridursi ad avere un unico stato finale.
I linguaggi accettati dagli NFA e dagli -NFA coincidono. Uninclusione e` ovvia in quanto un NFA e` un caso particolare di
-NFA. Per linclusione inversa, dato un -NFA M = hQ, ,  , q0 , F i, costruiamo il NFA M = hQ, , , q0 , F i nel modo
seguente:

F = F {q0 } se -closure(q0 ) F 6= , F altrimenti.


(q, ) =  (q, ).
S
S
Si noti che, per definizione,  (q, ) = q 0 (q,)
-closure((q 0 , )) = q 0 -closure(q) -closure((q 0 , )). In altri termini

(q, ) e` definita come linsieme degli stati raggiungibili da q con una sequenza (anche vuota) di transizioni silenti, seguita da
una transizione , seguita ancora da una sequenza (anche vuota) di transizioni silenti. Non diamo la prova della correttezza della
costruzione. Vediamo un esempio:
q1

q0

q2

q3

q1

q5

q0

q5

q4

q2

q3

q4

Applicando poi a sua volta allautoma non deterministico cos` costruito la trasformazione vista precedentemente si ottiene il
seguente automa deterministico:
{q2, q }

0
0

{q0}

{q4, q }
5

Il linguaggio accettato e` {, 00}. Si noti che  viene accetta in quanto q0 e` finale, e lo stato non finale morto corrispondente
allinsieme vuoto [nel disegno manca la transizione da in se stesso leggendo 0].
Le due trasformazioni possono anche essere effettuate in un unico passo, in sostanza si applica la trasformazione da non deterministico a deterministico considerando per`o per ogni transizione anche gli stati raggiungibili con transizioni silenti aggiuntive
(si precisi per esercizio, e si applichi la trasformazione in un unico passo al precedente esempio).
Concludiamo la sezione illustrando una tecnica per minimizzare i DFA, ossia dato un DFA M = hQ, , , q0 , F i trovarne uno
equivalente, ossia che accetti lo stesso linguaggio, con un numero minimo di stati.
Anzitutto, come gi`a accennato, e` chiaramente possibile eliminare tutti gli stati che non sono raggiungibili a partire da quello
iniziale. Inoltre, e` possibile far collassare pi`u stati in un solo, come illustrato nel seguito.
La nozione di linguaggio accettato pu`o essere estesa a qualunque stato q di un automa. Diciamo che due stati q e q 0 sono
u) e` finale se e
indistinguibili, e scriviamo qq 0 , se il loro linguaggio accettato e` lo stesso, ossia, per qualunque stringa u, (q,
0
, u) e` finale. Chiaramente si tratta di una relazione di equivalenza, vedi Definizione A.3. Indichiamo con [q] la classe
solo se (q
di equivalenza di q e con Q/ il quoziente di Q rispetto alla relazione di indistinguibilit`a. Due stati sono quindi distinguibili,
scriviamo q 6 q 0 , se esiste almeno una stringa che viene accettata partendo da uno stato ma non dallaltro. Per esempio, uno
stato finale e` sempre distinguibile da uno non finale mediante la stringa vuota.
Due stati indistinguibili possono intuitivamente essere trasformati in un unico stato. In altri termini, possiamo costruire lautoma
M0 = hQ/, , 0 , [q0 ] , F 0 i che ha:
come stati le classi di equivalenza rispetto a
come stato iniziale la classe di equivalenza dello stato iniziale di M
come stati finali le classi di equivalenza degli stati finali di M, ossia [q] F 0 se e solo se q F
funzione di transizione definita da 0 ([q] , ) = [(q, )] .
E` facile vedere che la funzione di transizione e` ben definita (infatti se qq 0 non pu`o essere (q, )
6 (q 0 , )) e che il linguaggio
0
0
0 , u)] ).
accettato da M coincide con quello accettato da M (in quanto ([q0 ] , u) = [(q
Si pu`o provare (non lo vediamo) che lautoma definito in questo modo risulta essere minimale, nel senso che non e` possibile
trovare un automa con un numero strettamente inferiore di stati che generi lo stesso linguaggio.
Inoltre, la relazione di indistinguibilit`a (e quindi lautoma minimale) pu`o essere costruita per approssimazioni successive utilizzando il seguente algoritmo. Inizialmente suddividiamo gli stati in due classi di equivalenza, quelli finali e quelli non finali. Poi,
a ogni passo consideriamo le classi di equivalenza ottenute al passo precedente, e per ognuna di esse, sia C, per ogni simbolo
dellalfabeto , si controlla se con una transizione si arriva, per ognuno degli stati in C, nella stessa classe di equivalenza C 0 .
In caso contrario si scompone ulteriormente C in pi`u classi di equivalenza. Lalgoritmo termina quando si arriva a una situazione
stabile in cui non si effettuano pi`u modifiche. Una semplice descrizione in pseudocodice dellalgoritmo e` la seguente:
8

= {hq, q 0 i | q F q 0 F }
repeat
old =
=
for each hq, q 0 i in old
if ((q, )old (q 0 , ) ) = {hq, q 0 i}
until = old

Esempio 2.11 Consideriamo il seguente NFA dove q0 e` iniziale e q3 e` finale:


q0
q1
q2
q3

a
q0
q1
q2
q3

b
q1
q2
q3
q3

Inizialmente si ha: = {{q3 }, {q0 , q1 , q2 }}. Alla prima iterazione, q0 e q1 risultano distinguibili da q2 leggendo b, quindi
si ha = {{q3 }, {q0 , q1 }, {q2 }}. Infine, alla seconda iterazione q0 risulta distinguibile da q1 leggendo b, quindi si ha =
{{q3 }, {q0 }, {q1 }, {q2 }} (ossia il DFA era gi`a minimo).

2.2

Espressioni regolari [approfondimenti da LPO]

Def. 2.12 Linsieme delle espressioni regolari (abbreviate RE) (su ) e i linguaggi (su ) da esse denotati sono definiti induttivamente nel modo seguente:
e` una RE che denota il linguaggio vuoto
 e` una RE che denota {}
per ogni , e` unespressione regolare che denota {}
se r1 e` unespressione regolare che denota L1 , ed r2 e` unespressione regolare che denota L2 , allora r1 r2 e` unespressione
regolare che denota L1 L2 , ed r1 + r2 (alternativamente si usa anche la sintassi r1 | r2 ) e` unespressione regolare che
denota L1 L2
se r e` unespressione regolare che denota L, r ? e` unespressione regolare che denota L? .
Unespressione regolare e` una stringa che descrive schematicamente un insieme di stringhe. Le espressioni regolari sono
utilizzate in moltissimi campi dellinformatica, dovendo la loro popolarit`a principalmente a due fattori:
permettono di descrivere in modo estremamente sintetico stringhe di varia natura;
a partire da esse e` possibile generare automaticamente dei riconoscitori (ossia, programmi che stabiliscono se una stringa
appartiene al linguaggio oppure no) estremamente efficienti per i linguaggi regolari.
A seconda del campo di applicazione, la sintassi concreta con cui vengono rappresentate le espressioni regolari pu`o cambiare, e
vengono in genere aggiunti agli operatori base visti nella definizione precedente molti altri derivati da questi. In questa maniera,
si riescono a descrivere insiemi di stringhe in modo molto compatto e flessibile.
Esercizio 2.13 Per ognuna delle seguenti identit`a tra espressioni regolari si dica se e` vera, giustificando la risposta.
1. r + s = s + r
2. r + (s + t) = (r + s) + t
3. r (st) = (rs)t
4. ? = 
5. (r + s)? = r ? + s ?
6. r ? (r + s)? = (r + s)?
7. (r ? + s ? ) = (rs)?
9

Possiamo provare che i linguaggi denotati da espressioni regolari coincidono con quelli riconosciuti dagli automi a stati finiti.
A tale scopo, si mostra che, data unespressione regolare r , e` possibile costruire un un NFA con transizioni  che riconosce il
linguaggio da essa denotato. Tale automa, con un unico stato finale, e` definito per induzione, vedi Sezione A.2, sullespressione
regolare r , nel modo seguente.
Il linguaggio e` riconosciuto dallautoma
q0

q1

Il linguaggio {} e` riconosciuto dallautoma


q0

Il linguaggio {} e` riconosciuto dallautoma

q0

q1

Se, per i = 1, 2, Mi con stato iniziale q0i e finale qfi riconosce il linguaggio denotato da ri , allora il linguaggio denotato
da r1 + r2 e` riconosciuto dallautoma
M1
q1f

q10

q0

qf

M2

q 2f

q20

Se, per i = 1, 2, Mi con stato iniziale q0i e finale qfi riconosce il linguaggio denotato da ri , allora il linguaggio denotato
da r1 r2 e` riconosciuto dallautoma
M2

M1
q0

q1f

q10

q20

q 2f

qf

Se M con stato iniziale q0 e finale qf riconosce il linguaggio denotato da r, allora il linguaggio denotato da r? e` riconosciuto
dallautoma

M
q'0

qf

q0

q'0

E` possibile (non lo vediamo) dare anche la costruzione inversa, che a partire da un automa M prova lesistenza di unespressione
regolare che denota il linguaggio riconosciuto da M.

2.3

Propriet`a dei linguaggi regolari

Per dimostrare che un linguaggio non e` regolare si usa in genere il pumping lemma. Diamo prima unidea informale.
Intuitivamente, un automa a stati finiti ha solo una memoria finita, data dai suoi diversi stati, e non e` quindi in grado di contare o
comunque di memorizzare un numero di informazioni non limitato a priori. Dato che e` accettato da un automa a stati finiti, un
linguaggio regolare e` finito oppure contiene sottoinsiemi infiniti non arbitrari, ma formati da stringhe che seguono tutte un certo
pattern (unespressione regolare, corrispondente a un ciclo nellautoma). Per esempio, possiamo convincerci che il linguaggio
{0n 1n } non e` regolare ragionando nel modo seguente.
Supponiamo (per assurdo) che esista un automa che riconosce questo linguaggio, e sia n il numero di stati dellautoma.
10

Supponiamo di fornire in input allautoma una stringa formata di tutti zeri e di lunghezza maggiore di n. Lautoma
attraverser`a una sequenza di stati:
0
0
0
0
q0 q1 . . . qn . . .
Dato per`o che lautoma ha solo n stati, necessariamente dovr`a passare due volte attraverso lo stesso stato, sia qi = qj = q.
0i

0...0

Si avr`a quindi: q0 qi = q q, con la seconda stringa di 0 non vuota.


A questo punto, per accettare la stringa 0i 1i , che appartiene al linguaggio, lautoma dovrebbe, a partire dallo stato q,
arrivare a uno stato finale leggendo 1i . Ma allora accetterebbe anche la stringa 0i 0...01i che non appartiene al linguaggio.
Questo ragionamento pu`o essere generalizzato nel modo seguente.
Lemma 2.14 [Pumping lemma per i linguaggi regolari (Bar-Hillel, Perles, Shamir, 1961] Sia L un linguaggio regolare. Allora
esiste una costante n N tale che, per ogni z L con |z| n, possiamo decomporre z come uvw in modo che:
1. |uv | n,
2. |v | > 0,
3. per ogni i 0 si ha che uv i w L.
Prova Se L e` regolare, esiste un DFA che lo riconosce. Scegliamo allora come n il numero degli stati di questo automa. Sia
u
u) = q 0 . Dato che la stringa e`
z = 1 . . . m , con m n. Utilizziamo, per maggior chiarezza, la notazione q q 0 per (q,
1
2
m
accettata dallautoma, si ha q0 q1 . . . qm = qF , con q0 , . . . , qm stati dellautoma, q0 stato iniziale e qF stato finale.
Dato che gli stati dellautoma sono solo n, necessariamente si ha che almeno uno stato, sia q, viene attraversato due volte nei
primi n passi, ossia q = qi = qj per qualche 0 i < j n. Allora, ponendo:
u = 1 . . . i
v = i+1 . . . j
w = j+1 . . . m
u

vi

vi

si ha che q0 q q qF . Dato che q q, e` facile vedere che, per ogni i 0, si ha q q, e quindi q0 q q qF . Si


noti che |uv | n e |v | > 0 per costruzione.
Il pumping lemma viene tipicamente utilizzato per provare che un linguaggio L non e` regolare. A tale scopo, occorre mostrare
che, fissato un n arbitrario, esiste una stringa z, con |z| n, che appartiene al linguaggio, ma tale che, per ogni sua possibile
decomposizione come uvw , con |uv | n e |v | > 0, uv i w 6 L per qualche i 0. I seguenti esempi illustrano la tecnica.
Esempio 2.15 Possiamo dimostrare, utilizzando il pumping lemma, che il linguaggio {0n 1n } non e` regolare. Infatti, preso n
arbitrario, consideriamo la stringa 0n 1n . Decomponendo tale stringa in tre parti u, v , w tali che la lunghezza delle prime due sia
n e la seconda sia non vuota, si ha chiaramente u = 0a , v = 0b e w = 0c 1n con a + b + c = n, b > 0. Allora, per esempio
per i = 0, si ha che uv 0 w = 0a 0c 1n non appartiene al linguaggio in quanto a + c < n.
Esempio 2.16 Il linguaggio delle stringhe formate da un numero uguale di 0 e di 1 non e` regolare. Infatti, preso n arbitrario,
consideriamo la stringa 0n 1n . Decomponendo tale stringa in tre parti u, v , w tali che la lunghezza delle prime due sia n e la
seconda sia non vuota, si ha chiaramente u = 0a , v = 0b e w = 0c 1n con a + b + c = n, b > 0. Allora, per esempio per i = 0,
si ha che uv 0 w = 0a 0c 1n non ha un numero uguale di 0 e di 1.
Esempio 2.17 Il linguaggio delle stringhe 1p con p numero primo non e` regolare. Infatti, preso n arbitrario, scegliamo un
numero primo p n + 2. Decomponiamo la stringa 1p in tre parti u, v , w tali che la lunghezza delle prime due sia n e la
seconda sia non vuota, e sia m la lunghezza di questa seconda parte. Si ha che uv pm w non appartiene al linguaggio, ossia la
sua lunghezza non e` un numero primo. Infatti:
|uv pm w | = |uw | + (p m)|v | = (p m) + m(p m) = (1 + m)(p m)
che non e` primo, a meno che uno dei fattori non sia 1, ma:
1 + m e` maggiore di 1 poiche m > 0
p m e` maggiore di 1 poiche p supera n (e quindi m) di almeno due.

11

Propriet`a di chiusura: i linguaggi regolari sono chiusi rispetto alle operazioni di unione, concatenazione e chiusura di Kleene
(ovvie per definizione), complementazione e intersezione, ossia se L, L0 sono linguaggi regolari, allora lo sono anche:
L = ? \ L,
L L0 .
Infatti, dato M un DFA che riconosce L, possiamo ottenere da questo un DFA che riconosce L semplicemente scambiando
linsieme degli stati finali con quello dei non finali. A questo punto, anche la chiusura rispetto allintersezione si vede facilmente
in quanto L L0 = L L0 .

3
3.1

Linguaggi context-free
Grammatiche context-free [richiami da LPO]

Def. 3.1 [Grammatica CF] Una grammatica context-free (CF) o libera da contesto e` una quadrupla hT, N, P, Si dove:
T e` lalfabeto dei terminali,
N e` lalfabeto dei non terminali, con T N = ,
P e` un insieme finito di coppie A ::= dette produzioni dove A N e (T N )? ,
S N e` il simbolo iniziale o assioma o start.
In questa sezione useremo talvolta semplicemente il termine grammatica, tuttavia vedremo in seguito (Sezione 4) che esistono
altri tipi di grammatiche per cui la precisazione context-free diventer`a rilevante. Riserveremo u, v , w a indicare generiche
stringhe di terminali, mentre utilizzeremo , , per indicare generiche stringhe di terminali e non terminali.
Per esempio, la seguente grammatica, che chiameremo GExp:
Exp
Num
Id

::= (Exp + Exp) | (Exp Exp) | Num


::= 0 | 1 | . . . | 9
::= a | b | . . . | z

definisce le espressioni aritmetiche costruite, mediante gli operatori + e *, a partire da numeri, formati per semplicit`a da una
sola cifra decimale, e da identificatori formati per semplicit`a da una sola lettera minuscola. Abbiamo utilizzato, come usuale,
labbreviazione A ::= 1 | . . . | n per indicare le produzioni A ::= 1 , . . . , A ::= n .
Per capire in che senso una grammatica definisca un linguaggio introduciamo il concetto di derivazione.
Def. 3.2 [Derivazione in un passo] Sia data una grammatica G = hT, N, P, Si e siano , (T N )? . Diremo che e`
derivabile da in un passo se e` della forma 1 A2 , e` della forma 1 2 , ed esiste una produzione A ::= in P , con
1 , 2 (T N )? . Diremo anche che e` una derivazione (in un passo).
E` chiaro che e` una relazione (Definizione A.1) su (T N )? . Indicheremo con ? la sua chiusura riflessiva e transitiva
(Definizione A.4), e diremo che e` derivabile da se vale ? . Diremo anche che ? e` una derivazione.
Per esempio, con riferimento a GExp, si hanno le seguenti derivazioni a un passo e derivazioni:
Exp (Exp + Exp)
Exp ? (5 + (Exp Exp))
Exp ? (5 + (4 2))
(( + Exp) (( + (Exp Exp))
Lultimo esempio illustra il fatto che esistono derivazioni a partire da una certa stringa a prescindere dal fatto che da questa si
possano derivare stringhe appartenenti al linguaggio generato dalla grammatica, vedi sotto.
Il linguaggio generato da una grammatica e` linsieme delle stringhe composte solo di terminali che si possono derivare dal
simbolo iniziale. Formalmente:
Def. 3.3 [Linguaggio generato da una grammatica] Sia data una grammatica G = hT, N, P, Si. Il linguaggio generato da G e`
linsieme L(G) = {u T ? | S ? u}.

12

Un linguaggio L e` context-free (CF) o libero da contesto se esiste una grammatica libera da contesto G che lo genera, ossia tale
che L(G) = L.
Talvolta siamo interessati non solo al linguaggio generato a partire dallassioma, come nella definizione precedente, ma alla
famiglia di insiemi di stringhe, vedi la Definizione A.5, generati a partire da ogni non terminale della grammatica, ossia LA (G) =
{u T ? | A ? u}. In questo caso non e` quindi significativo scegliere un assioma.
Concludiamo questa sezione con qualche altro semplice esempio con alfabeto dei terminali = {a, b}. Ricordiamo che una
stringa e` palindroma se rimane uguale letta a rovescio.
S ::= a S | bS | 
S ::= S
S ::= a S | S b | 
S ::= a S b | 
S ::= a S b | a b
S ::= a S a | b S b |  | a | b

genera ?
genera
genera {an bm | n, m 0}
genera {an bn | n 0},
genera {an bn | n 1},
genera {u | u {a, b}? , u palindroma}.

Esercizio 3.4 Proviamo che il linguaggio {am bn am+n | m, n 0} e` context-free. Per dimostrarlo occorre dare una grammatica
context-free che lo generi. Dato che il linguaggio pu`o essere equivalentemente descritto come {am bn an am | m, n 0}, e` facile
convincersi che una grammatica che lo genera e` la seguente:
S ::= a S a | X
X ::= b X a | 
Vedremo nel seguito (Sezione 3.3) come provare in modo rigoroso che una grammatica genera esattamente un linguaggio dato.

3.2

Alberi di derivazione e ambiguit`a [richiami da LPO]

Data una stringa nel linguaggio generato da una grammatica, questa pu`o essere in genere ottenuta tramite molte derivazioni diverse, che corrispondono a diverse possibili scelte a ogni passo del non terminale da espandere, cio`e cui applicare una produzione.
Consideriamo la stringa (5+(4*2)) del linguaggio generato da GExp. Questa stringa pu`o essere ottenuta, per esempio, con le
seguenti derivazioni, dove abbiamo sottolineato a ogni passo il non terminale cui viene applicata una produzione:
Exp (Exp + Exp) (Num + Exp) (5 + Exp) (5 + (Exp Exp)) . . .
Exp (Exp + Exp) (Exp + (Exp Exp)) (Exp + (Num Exp)) . . .
Possiamo eliminare questo non determinismo fissando una derivazione canonica, per esempio la leftmost o la rightmost, in cui
il non terminale espanso e` sempre quello p`u a sinistra o, rispettivamente, a destra. Si pu`o provare che una stringa appartenente al
linguaggio generato pu`o sempre essere generata con una derivazione canonica.
Un modo per astrarre rispetto a queste diverse derivazioni e` quello di considerare gli alberi di derivazione o parse tree. La
nozione di albero di derivazione corrisponde infatti a espandere in parallelo tutti i non terminali. Per esempio un albero di
derivazione per la stringa (5+(4*2)) e` illustrato nella Figura 1.
Def. 3.5 [Albero di derivazione] Sia data una grammatica G = hT, N, P, Si; un albero di derivazione per la stringa di terminali
u (in G) e` un albero (ordinato) etichettato in T N tale che:
la radice e` etichettata con S
se un nodo e` etichettato con un terminale, allora e` una foglia
se un nodo e` etichettato con un non terminale B e e` la stringa formata dalle etichette dei figli da sinistra a destra, allora
B ::= e` una produzione in G
u e` la stringa formata dalle etichette terminali delle foglie da sinistra a destra.
Notiamo che e` possibile avere foglie etichettate con non terminali, nel caso vi siano produzioni con parte destra . Una definizione
alternativa e` quella in cui  e` ammessa come etichetta; in questo caso le foglie risultano essere esattamente i nodi etichettati con
un terminale o con .
Si prova che il linguaggio generato da una grammatica G = hT, N, P, Si pu`o essere definito equivalentemente in termini di
alberi di derivazione, ossia che u appartiene a L(G) se e solo se esiste un albero di derivazione per u in G.
Quindi, per provare che una stringa u appartiene al linguaggio L(G), basta, indifferentemente, esibire una derivazione o un
albero di derivazione per u in G. Per provare invece che u 6 L(G), occorre provare che non esiste un albero di derivazione per
13

Exp
(

Exp

Num

( Exp * Exp )

Exp

Num

Num

Figura 1: Un albero di derivazione per la stringa (5+(4*2))

u in G, e in genere questo non e` banale. Nei casi semplici si pu`o fare unanalisi per casi delle produzioni applicabili e mostrare
che si arriva sempre a una situazione in cui non e` pi`u possibile ottenere u; oppure, si pu`o provare per induzione strutturale (vedi
Proposizione 3.7) che tutte le stringhe in L(G) verificano una certa propriet`a che u non soddisfa.
Lalbero di derivazione mette in evidenza la struttura della stringa, ossia il modo in cui la stringa pu`o essere decomposta.
Introduciamo ora il concetto di ambiguit`a per le grammatiche context-free. Intuitivamente, una stringa e` ambigua se pu`o essere
decomposta in due modi diversi, quindi interpretata semanticamente in due modi.
Consideriamo la seguente grammatica GExp amb per le espressioni aritmetiche, in cui non utilizziamo parentesi.
Exp
Num
Id

::= Exp + Exp | Exp Exp | Num


::= 0 | 1 | . . . | 9
::= a | b | . . . | z

Per esempio, la stringa 5+4*2, che appartiene al linguaggio generato, intuitivamente pu`o essere interpretata sia come 5+h4*2i,
cio`e la somma di 5 e 4*2, sia come h5+4i*2, cio`e il prodotto di 5+4 e 2. E` possibile quindi attribuire pi`u di un significato alla
stringa. Formalmente, ci`o corrisponde al fatto che esiste pi`u di un albero di derivazione per la stringa.
Def. 3.6 [Grammatica ambigua] Sia G = hT, N, P, Si una grammatica CF e u L(G). Diciamo che u e` ambigua (in G) se vi
sono due alberi di derivazione diversi per u. Si dice che G e` ambigua se vi e` almeno una stringa ambigua in G.
La grammatica GExp amb e` ambigua, infatti, per esempio, vi sono due alberi di derivazione per la stringa 5+4*2, illustrati nella Figura 2. In generale vorremmo evitare i casi di ambiguit`a semanticamente rilevante, ossia quando le diverse decomposizioni
danno luogo a interpretazioni semantiche diverse. Si pongono quindi i seguenti problemi:
riconoscere le grammatiche ambigue, cio`e dare un algoritmo che dica se una grammatica e` ambigua o no
eliminare lambiguit`a, cio`e dare un algoritmo che data G ambigua fornisca G0 non ambigua e tale che L(G) = L(G0 ).
Entrambi questi problemi non sono per`o risolvibili; si hanno infatti i seguenti risultati:
il primo problema non e` decidibile, ossia non esiste un algoritmo che presa in ingresso una grammatica qualunque produca
in uscita s` o no a seconda se la grammatica e` o non e` ambigua
esistono linguaggi inerentemente ambigui, cio`e tali che ogni grammatica che li genera e` ambigua.
Un esempio di linguaggio inerentemente ambiguo e` {an bm cp | n, m, p 0, n = m oppure m = p}; le stringhe ambigue sono
tutte quelle del tipo an bn cn . Una grammatica che genera questo linguaggio e` la seguente:
S
A
X
Y
C

::=
::=
::=
::=
::=

AX | YC
aA | 
bXc | 
aYb | 
cC | 
14

Exp
Exp

Num

Exp

Exp

Exp

Exp * Exp

Exp + Exp

Num

Num

Num

Num

Exp

Num

Figura 2: Due diversi alberi di derivazione per la stringa 5+4*2.

Ovviamente, questo non vuol dire che, data una particolare grammatica che genera un linguaggio L, non si possa determinare
se e` ambigua o no e, nel caso, costruire una grammatica non ambigua che generi L.

3.3

Grammatiche come definizioni induttive

Notiamo che una grammatica CF pu`o essere vista come una definizione induttiva, in genere multipla, vedi la Sezione A.2, in
quanto ogni produzione
A ::= u0 B1 u1 . . . Bn un ,
con n 0, A, B1 , . . . , Bn non terminali e u1 , . . . , un stringhe di terminali, pu`o essere letta come:
se la stringa v1 appartiene al linguaggio di tipo B1 , . . . , e la stringa vn appartiene al linguaggio di tipo Bn , allora la
stringa u0 v1 u1 . . . vn un appartiene al linguaggio di tipo A.
Tuttavia, le definizioni induttive sono molto pi`u generali; per esempio, e` possibile esprimere il fatto che due sottocomponenti
della stringa debbano essere uguali. Questo e` un esempio di vincolo contestuale, non esprimibile invece con una grammatica
libera dal contesto, vedi Sezione 3.5.
Il fatto che le grammatiche CF siano particolari definizioni induttive ci fornisce un modo semplice per provare che il linguaggio
generato soddisfa certe propriet`a, utilizzando cio`e il principio di induzione, vedi Proposizione A.8, nel caso particolare in cui la
definizione induttiva sia una grammatica CF. Parleremo in questo caso di induzione strutturale o sulla sintassi.
Prop. 3.7 [Principio di induzione strutturale] Sia hT, N, P, Si una grammatica CF e P una famiglia (indiciata su N ) di predicati
su T ? .
(PBi (u) = T per ogni u LBi (G), per ogni i 1..n) implica PA (u) = T
Se: per ogni produzione A ::= u0 B1 u1 . . . Bn un ,
allora: PB (u) = T per ogni u LB (G), per ogni B T .
Vediamo qualche esempio.
Esempio 3.8 Proviamo che il linguaggio generato da S ::= a S a | b S b |  | a | b e` linsieme delle stringhe palindrome. In
questo caso la definizione induttiva non e` multipla. Dobbiamo provare le due inclusioni, ossia che la grammatica genera:
solo stringhe palindrome
tutte le stringhe palindrome.
La prima inclusione pu`o essere provata per induzione strutturale, ossia facendo vedere che linsieme delle stringhe palindrome e`
chiuso rispetto alla grammatica vista come definizione induttiva, ossia rispetto a ogni produzione, quindi controllando le seguenti
condizioni:
se u e` palindroma allora anche aua e` palindroma
15

se u e` palindroma allora anche bub e` palindroma


 e` palindroma
a e` palindroma
b e` palindroma
che valgono tutte ovviamente. Questa tecnica e` applicabile canonicamente per provare che il linguaggio generato da una
grammatica gode di una certa propriet`a, ossia e` contenuto in un linguaggio dato.
Per provare la seconda inclusione, occorre invece un ragionamento ad hoc che provi che tutte le stringhe del linguaggio dato sono
generabili, tipicamente ancora utilizzando una qualche forma del principio di induzione. In questo esempio, possiamo provare
per induzione aritmetica che, per ogni n 0, le stringhe palindrome di lunghezza 2n e 2n + 1 sono generabili. Infatti:
per n = 0, le stringhe palindrome di lunghezza zero o uno sono generate (applicando una delle ultime tre produzioni)
assumendo vera la tesi per n, le stringhe palindrome di lunghezza 2(n + 1) = 2n + 2 oppure 2(n + 1) + 1 = 2n + 3
sono della forma aua oppure bub con u stringa palindroma di lunghezza 2n oppure 2n + 1, quindi si ha la tesi applicando
lipotesi induttiva e una delle prime due produzioni.
Per esercizio si riformuli la prova utilizzando invece linduzione forte, vedi Proposizione A.10.
Esempio 3.9 Vediamo ora un esempio di grammatica con pi`u non terminali, che corrisponde quindi a una definizione induttiva
multipla. Consideriamo la seguente grammatica:
S ::=  | aB | bA
A ::= aS | bAA
B ::= bS | aBB
Questa grammatica e` una definizione mutuamente induttiva di tre sottoinsiemi delle stringhe su {a, b}: linsieme delle stringhe
con un numero uguale di a e di b, linsieme delle stringhe con una a in pi`u, e linsieme delle stringhe con una b in pi`u. Proviamolo
procedendo come nellesempio precedente ma per induzione multipla. Per provare che la grammatica genera solo stringhe che
soddisfano il vincolo dato, basta controllare le seguenti condizioni, che valgono tutte ovviamente:
 e` una stringa con numero di a uguale al numero di b
se u e` una stringa con una b in pi`u, allora au e` una stringa con numero di a uguale al numero di b; analogamente se u e`
una stringa con una a in pi`u, allora bu e` una stringa con numero di a uguale al numero di b
se u e` una stringa con numero di a uguale al numero di b, allora au e` una stringa con una a in pi`u, e analogamente bu e`
una stringa con una b in pi`u;
se u, v sono due stringhe con una a in pi`u, allora buv e` una stringa con una a in pi`u, e analogamente se u, v sono due
stringhe con una b in pi`u, allora auv e` una stringa con una b in pi`u.
Per provare il viceversa, possiamo provare per induzione forte che per ogni n 0 le stringhe di lunghezza n con un numero
uguale di a e di b, una a in pi`u e una b in pi`u sono generate a partire da S, A o B, rispettivamente. Infatti:
Per n = 0, la stringa vuota e` generata a partire da S applicando la prima produzione.
Per n > 0, distinguiamo i tre casi.
Se la stringa ha un numero uguale di a e di b, allora: se inizia per a, sar`a della forma au con u stringa con una b in
pi`u, e quindi e` generata a partire da S applicando lipotesi induttiva e la seconda produzione; analogamente se inizia
per b.
Se la stringa ha una a in pi`u, allora: se inizia per a, sar`a della forma au con u stringa con numero uguale di a e di
b, e quindi e` generata a partire da A applicando lipotesi induttiva e la quarta produzione; se invece inizia per b, sar`a
della forma bu con u con due a in pi`u. Ma una stringa con due a in pi`u pu`o chiaramente essere decomposta come
u1 u2 dove in u1 , u2 vi e` una a in pi`u. Quindi, au1 u2 e` generata applicando lipotesi induttiva e la quinta produzione.
Si noti che e` necessaria linduzione forte in quanto sappiamo solo che le lunghezze di u1 , u2 sono minori di quella di
au1 u2 .
Analogamente se la stringa ha una b in pi`u.

16

3.4

Automi a pila

Il fatto che certi linguaggi, per esempio {an bn } o {ww R } (w R denota la stringa ottenuta rovesciando w ) non possano essere
riconosciuti con un automa a stati finiti dipende intuitivamente dallimpossibilit`a, in questi automi, di contare o memorizzare
simboli in un numero non limitato a priori. Questo diventa invece possibile utilizzando una pila.
Def. 3.10 [Automa a pila] Un automa a pila (non deterministico) (non deterministic pushdown automaton o PDA) e` una tupla
M = hQ, , , , q0 , Z0 , F i
dove Q, , q0 e F sono come per gli automi a stati finiti, e` lalfabeto della pila, Z0 e` il simbolo iniziale nella pila, e : Q
( {}) (Q ? ) e` la funzione di transizione.
In termini informali, un automa a pila che si trova nello stato q, legge il simbolo , e toglie dalla pila il simbolo in cima (pop)
Z, pu`o passare in un nuovo stato q 0 e mettere in cima alla pila (push) una sequenza anche vuota di nuovi simboli (il caso = Z
corrisponde a leggere il simbolo in cima senza toglierlo, il caso =  corrisponde a leggere solamente). Inoltre, lautoma pu`o
anche passare in un nuovo stato e mettere in cima alla pila una sequenza di simboli senza leggere alcun simbolo, ossia con una
transizione silente. Si noti che si tratta di automi non deterministici, in quanto per lo stesso simbolo corrente e simbolo in cima
alla pila si possono avere transizioni diverse (incluse quelle silenti).
Per definire il linguaggio riconosciuto da un PDA introduciamo la nozione di descrizione istantanea.
Def. 3.11 [Linguaggio riconosciuto da un PDA] Sia M = hQ, , , , q0 , Z0 , F i un PDA. Una descrizione istantanea e` una
tripla hq, u, i dove q Q e` lo stato corrente, u ? e` la stringa ancora da leggere e ? e` il contenuto corrente della pila.
La relazione di derivazione (diretta) M e` definita da:
hq, u, Zi M hq 0 , u, i se hq 0 , i hq, , Zi
hq, u, Zi M hq 0 , u, i se hq 0 , i hq, , Zi
Il linguaggio L(M) riconosciuto da M si pu`o definire in due modi diversi:
per pila vuota, ossia L(M) = {u ? | hq0 , u, Z0 i ?M h , , i}
per stati finali, ossia L(M) = {u ? | hq0 , u, Z0 i ?M hq, , i, q F }
Ometteremo lindice M quando chiaro dal contesto.
Si pu`o provare che le due definizioni sono equivalenti, ossia, se il linguaggio L e` riconosciuto da un qualche PDA secondo la
prima definizione, allora esiste anche un PDA che lo riconosce secondo laltra, e viceversa. Quindi nel seguito, senza perdere in
generalit`a, considereremo la prima definizione, e dato che con questa gli stati finali non sono rilevanti assumeremo F = .
Esempio 3.12 Diamo un PDA che riconosce w cw R . Un modo sintetico per descrivere un PDA e` dare una matrice di transizione
per ogni stato, come illustrato sotto per lesempio.
q0
Z
A
B

a
q0 , ZA

b
q0 , ZB

c
q1 , 

q1
Z
A
B

q1 , 
q1 , 

Le caselle vuote sono unabbrevazione per linsieme vuoto (o qualunque altro insieme che conduca sicuramente a una refutazione).
Anche per gli automi a pila e` possibile dare una rappresentazione alternativa come grafo di transizione. Nel caso dellesempio
sopra, il grafo e` il seguente:
a,Z / ZA
b,Z / ZB
q0

c,Z /

q1
b,B /
a,A /

Per provare che un PDA riconosce un certo linguaggio L dobbiamo, come nel caso degli automi a stati finiti, provare che ogni
stringa in L viene accettata (ossia, avendo scelto la prima definizione, dopo aver letto la stringa la pila e` vuota) e ogni stringa
non in L non viene accettata (ossia dopo aver letto la stringa la pila non e` vuota). Nellesempio, possiamo ragionare nel modo
seguente:
17

Se la stringa e` della forma 1 . . . n c n . . . 1 , con 1 , . . . , n {a, b}, n 0, e` facile vedere (identificando per comodit`a
a con A e b con B) che si ha
hq0 , 1 . . . n c n . . . 1 , Zi ? [questo passaggio potrebbe essere formalizzato per induzione aritmetica]
hq0 , c n . . . 1 , Zn . . . 1 i
hq1 , n . . . 1 , n . . . 1 i ? [questo passaggio potrebbe essere formalizzato per induzione aritmetica]
hq1 , , i
Viceversa, proviamo che ogni stringa accettata e` della forma sopra. Anzitutto, se la stringa non contiene c e` immediato
vedere che non si svuota mai la pila. Quindi la stringa contiene una (prima) c, ossia e` della forma 1 . . . n c u, e lunica
sequenza di derivazione possibile e` quella vista sopra:
hq0 , 1 . . . n c u, Zi + [questo passaggio potrebbe essere formalizzato per induzione aritmetica]
hq1 , u, n . . . 1 i
A questo punto, e` facile vedere (nuovamente questo potrebbe essere formalizzato per induzione aritmetica) che per svuotare
la pila u deve necessariamente essere n . . . 1 , e si ha lunica sequenza di derivazione vista sopra.
Come evidenziato dalla precedente prova semi-formale, questo automa e` in realt`a deterministico, nel senso che per ogni configurazione istantanea vi e` al pi`u una transizione possibile. Si noti che, per avere un automa deterministico, occorre non solo che per
ogni simbolo corrente vi sia al pi`u una transizione possibile, ma anche che non sia contemporaneamente possibile leggere il simbolo corrente o non leggerlo, ossia che le transizioni silenti corrispondano al caso in cui linput e` esaurito. Questo e` formalizzato
dalla seguente definizione.
Def. 3.13 Un automa a pila deterministico (DPDA) e` un automa a pila M = hQ, , , , q0 , Z0 , F i tale che, per ogni hq, , Zi
Q :
|hq, , Zi| + |hq, , Zi| 1
Contrariamente a quanto visto per gli automi finiti, gli automi a pila non deterministici sono strettamente pi`u potenti di quelli
deterministici. Per esempio, lautoma che riconosce w cw R dato sopra pu`o essere deterministico grazie alla presenza del simbolo
c che separa la prima porzione della stringa dalla seconda5 . In mancanza di tale separatore, intuitivamente un automa a pila
non sa quando deve iniziare a riconoscere la seconda porzione, e quindi il riconoscimento e` possibile solo in modo non
deterministico.
Esempio 3.14 Diamo un PDA (non deterministico) che riconosce ww R .
q0
Z
A
B


q1 , Z
q1 , A
q1 , B

a
q0 , AZ
q0 , AA
q0 , AB

b
q0 , BZ
q0 , BA
q0 , BB

q1
Z
A
B


q1 , 

q1 , 
q1 , 

Informalmente, lautoma pu`o restare in q0 continuando a mettere sulla pila i simboli che via via incontra, lasciando Z in fondo,
oppure in qualunque momento pu`o decidere di passare in q1 lasciando input e stack immutati, assumendo cio`e che la parte
restante di input sia la stringa rovesciata. Possiamo convincerci della correttezza dellautoma con un ragionamento simile a
quello usato per il PDA deterministico: diamo una traccia che pu`o essere dettagliata per esercizio.
Se la stringa e` della forma 1 . . . n n . . . 1 , n 0, e` facile vedere che viene accettata.
Viceversa, proviamo che ogni stringa accettata e` della forma sopra. Anzitutto, e` immediato vedere che per riuscire a vuotare
la pila e` necessario preliminarmente passare allo stato q1 , ossia effettuare una delle transizioni della prima colonna. Quindi
la prima parte della derivazione che accetta la stringa e` della forma:
hq0 , 1 . . . n u, Zi ? hq0 , u, n . . . 1 Zi hq1 , u, n . . . 1 Zi
A questo punto, e` facile vedere che per svuotare la pila u deve necessariamente essere n . . . 1 .
Esercizio 3.15 Si dia un PDA per an bn .
5 Invece

mantenere Z in cima alla pila nella prima fase serve a rendere lautoma, e la prova, pi`u semplici, ma non e` necessario. Per esercizio, si dia una
variante di automa che rimuove subito Z, e si adatti la prova di conseguenza.

18

E` possibile mostrare che i linguaggi generati da grammatiche CF coincidono con quelli riconosciuti da automi a pila (non
deterministici). Vediamo una traccia della prova.
Per dimostrare che, dato un automa a pila, e` sempre possibile costruire una grammatica CF equivalente, si procede nel modo
seguente. Anzitutto, si pu`o provare che (aumentando i simboli nella pila) ci si pu`o sempre ridurre ad automi a pila con un unico
stato, ossia che, dato un automa a pila M, esiste un automa M0 con un unico stato tale che L(M) = L(M0 ). A questo punto,
e` sufficiente descrivere la costruzione per il caso di un automa a pila con un unico stato6 , sia M = h{q}, , , , q, Z0 , i. La
grammatica che genera il linguaggio riconosciuto da M e` definita nel modo seguente:
lalfabeto dei terminali e`
lalfabeto dei non terminali e`
il simbolo iniziale e` Z0
vi e` una produzione Z ::= se e solo se hq, i hq, , Zi
vi e` una produzione Z ::= se e solo se hq, i hq, , Zi
Si pu`o dimostrare per induzione (farlo per esercizio) che per ogni stringa u ? :
hq, u, Z0 i ?M hq, , i se e solo se Z0 ? u
da cui segue la tesi.
La costruzione inversa, da una grammatica CF a un automa a pila equivalente, procede analogamente. Anzitutto, si pu`o provare
che7 ci si pu`o sempre ridurre a grammatiche in forma normale di Greibach, ossia dove le produzioni sono tutte della forma
A ::= B1 . . . Bn con terminale, B1 , . . . , Bn non terminali, n 0. A questo punto, e` sufficiente descrivere la costruzione per
il caso di una grammatica di Greibach, sia G = hT, N, P, Si. Lautoma che riconosce il linguaggio generato dalla grammatica e`
definito nel modo seguente:
linsieme degli stati e` {q}
lalfabeto e` T
lalfabeto della pila e` N
il simbolo iniziale nella pila e` S
hq, i hq, , Zi se e solo se Z ::= e` una produzione
Si pu`o dimostrare per induzione (farlo per esercizio) che per ogni stringa u ? :
S ? u se e solo se hq, u, Si ?M hq, , i
da cui segue la tesi.
Esercizio 3.16 Si consideri la seguente grammatica (in forma normale di Greibach):
S ::= aB | bA
A ::= aS | bAA | a
B ::= bS | aBB | b
che genera il linguaggio formato dalle stringhe con lo stesso numero (maggiore di zero) di a e di b. Si costruisca il PDA
equivalente.

3.5

Propriet`a dei linguaggi context-free

Anche per i linguaggi CF vale un pumping lemma che pu`o essere utilizzato per provare che un linguaggio non e` CF. Lidea
intuitiva e` la seguente: in ogni stringa sufficientemente lunga di un linguaggio CF si possono trovare due sottostringhe vicine che
e` possibile eliminare o ripetere un numero arbitrario di volte, ottenendo sempre stringhe del linguaggio.
Lemma 3.17 [Pumping lemma per i linguaggi CF (Bar-Hillel, Perles, Shamir, 1961)] Sia L un linguaggio CF. Allora esiste una
costante n N tale che, per ogni z L con |z| n, possiamo decomporre z come z = uvwxy in modo che:
6 Ricordiamo
7 Assumendo

che, avendo scelto il riconoscimento per pila vuota ci si pu`o anche sempre ricondurre ad automi con insieme di stati finali vuoto.
per semplicit`a che il linguaggio non contenga la stringa vuota. In caso contrario la costruzione risulta leggermente pi`u complicata.

19

1. |vwx | n,
2. |vx | > 0,
3. per ogni i 0 si ha che uv i wx i y L.
Prova Se L e` regolare, esiste una grammatica CF che lo genera. Si pu`o provare (non lo vediamo) che, in particolare, esiste8 una
grammatica che lo genera in forma normale di Chomsky, ossia, dove tutte le produzioni sono della forma A ::= BC, con B e C
non terminali, oppure A ::= con terminale.
E` facile vedere che, per una grammatica in forma normale di Chomsky, se un albero di derivazione ha altezza m, la sua frontiera
(quindi la stringa generata) e` lunga al pi`u 2m1 . Infatti:
Base Un albero di derivazione di altezza 1 ha necessariamente forma
S

quindi genera una stringa di lunghezza 211 .


Passo induttivo Un albero di derivazione di altezza m + 1 ha necessariamente forma
S
B

t1

t2

con t1 , t2 alberi di altezza al pi`u m, le cui frontiere quindi per ipotesi induttiva sono lunghe al pi`u 2m1 . Dato che la
frontiera dellalbero completo e` la concatenazione delle due, sar`a lunga al pi`u 2 2m1 = 2m .
Sia allora m il numero di non terminali della grammatica in forma normale di Chomsky che genera L, e prendiamo n = 2m .
Data una stringa z L con |z| n, per il risultato provato sopra laltezza di un albero di derivazione per z deve essere almeno
m + 1. Allora, deve esserci necessariamente un non terminale, sia A, che compare due volte in un cammino dalla radice alle
foglie. Indichiamo con A(1) la prima occorrenza e con A(2) la seconda. Allora z pu`o essere decomposta come uvwxy dove w
e` la stringa ottenuta espandendo loccorrenza A(2) e vwx e` la stringa ottenuta espandendo loccorrenza A(1) . Ma dato che si
tratta di due occorrenze dello stesso non terminale A, e` chiaro che se sostituiamo il sottoalbero con radice A(1) con quello con
radice A(2) otteniamo ancora un albero di derivazione valido, per la stringa uwy. Viceversa, sostituendo il sottoalbero con radice
A(2) con quello con radice A(1) , otteniamo un albero di derivazione per la stringa uv 2 wx 2 y, e iterando la sostituzione otteniamo
alberi di derivazione per tutte le stringhe uv i wx i y con i > 2.
La situazione e` schematizzata nella seguente figura:
S

(1)

A
A(2)

Dobbiamo ancora controllare che:


|vwx | n; per ottenere questo, basta scegliere le due occorrenze dello stesso non terminale in modo che A(1) sia la prima
ripetizione a partire dal basso, ossia che non ci siano altre ripetizioni di non terminali nel sottoalbero di radice A(1) . Allora
laltezza di questo albero e` al pi`u m + 1, quindi la lunghezza di vwx e` al pi`u n = 2m .
8 Sempre

assumendo per semplicit`a  6 L, caso comunque non rilevante qui.

20

|vx | > 0; questo si vede facilmente in quanto i figli di A(1) sono necessariamente (etichettati con) due non terminali,
quindi v e x non possono essere entrambe vuote.
Come nel caso dei regolari, il pumping lemma viene utilizzato per provare che un linguaggio L non e` CF. A tale scopo, occorre
mostrare che, fissato un n arbitrario, esiste una stringa z, con |z| n, che appartiene al linguaggio, ma tale che, per ogni sua
possibile decomposizione come uvwxy, con |vwx | n e |vx | > 0, uv i wx i y 6 L per qualche i 0. Il seguente esempio illustra
la tecnica.
Esempio 3.18 Possiamo dimostrare, utilizzando il pumping lemma, che il linguaggio {an bn cn } non e` CF. Infatti, preso n arbitrario, consideriamo la stringa an bn cn . Vi sono molti diversi casi di decomposizione di questa stringa come uvwxy. Tuttavia,
dato che la lunghezza di vwx deve essere n, e` facile capire che tale sottostringa non pu`o contenere sia a che c, perche in tal
caso dovrebbe contenere tutti i b. Quindi, prendendo uv 0 wx 0 y, si ottiene una stringa in cui il numero di uno o due simboli e`
diminuito strettamente, quindi la stringa non appartiene al linguaggio.
In modo analogo possiamo provare che non sono CF i linguaggi {an bm cn dm } (dato n basta considerare an bn cn dn ) e {ww }
(dato n basta considerare an bn an bn ). Questi due esempi possono essere considerati come la versione astratta di situazioni che
si verificano usualmente nei linguaggi di programmazione: nel primo caso, due diverse chiamate di funzione devono rispettare
ognuna il numero di parametri della corrispondente dichiarazione; nel secondo caso, un identificatore pu`o essere utilizzato solo se
e` stato precedentemente dichiarato. Questi esempi forniscono quindi una motivazione del fatto che i linguaggi di programmazione
non sono CF, ma sono descritti, oltre che attraverso una grammatica CF che genera un soprainsieme del linguaggio, anche
specificando dei vincoli contestuali.
Per quanto riguarda le propriet`a di chiusura, i linguaggi CF risultano chiusi rispetto allunione, alla concatenazione e alla chiusura
di Kleene (questo si pu`o vedere molto semplicemente costruendo le rispettive grammatiche a partire da quelle date). Invece, i
linguaggi CF non sono chiusi rispetto allintersezione: questo pu`o essere visto osservando che i linguaggi an bn cm e an bm cm
sono CF (`e banale dare le grammatiche che li generano), mentre la loro intersezione an bn cn non lo e` , come osservato sopra. Di
conseguenza i linguaggi CF non sono neanche chiusi rispetto alla complementazione.
Per i linguaggi CF il problema dellappartenenza risulta decidibile. Infatti, dato un linguaggio CF, esiste9 una grammatica in
forma normale di Greibach che lo genera. Allora, data una stringa u, se questa e` generata lo e` in esattamente |u| passi, quindi per
vedere se appartiene al linguaggio basta generare esaustivamente tutte le derivazioni di |u| passi. Questo algoritmo ha complessit`a
3
2.8
esponenziale, esistono algoritmi pi`u efficienti di complessit`a O(|u| ) (o anche O(|u| )). Tali algoritmi hanno comunque un
valore puramente teorico, in quanto nella pratica il parsing e` effettuato per particolari classi di grammatiche CF per cui e` fattibile
in modo pi`u efficiente. Si osservi anche che nel caso dei linguaggi regolari il problema e` decidibile in tempo lineare.

Linguaggi context-sensitive e gerarchia di Chomsky

Def. 4.1 [Grammatica] Una grammatica (a struttura di frase) e` una quadrupla hT, N, P, Si dove:
T e` lalfabeto dei terminali,
N e` lalfabeto dei non terminali o meta-simboli, con T N = ,
S N e` il simbolo iniziale o start o assioma,
P e` un insieme finito di coppie ::= dette produzioni dove , (T N )? , 6= .
La gerarchia di Chomsky classifica le grammatiche in quattro classi a seconda della forma delle produzioni:
in una grammatica di tipo 0 non vi e` nessuna restrizione
in una grammatica di tipo 1 (o monotona o context-sensitive) le produzioni sono non decrescenti, ossia si ha || ||
in una grammatica di tipo 2 (o context-free) le produzioni sono, come abbiamo visto nella Definizione 3.1, della forma
A ::= con (T N )?
in una grammatica di tipo 3 (o regolare o lineare) le produzioni sono tutte della forma A ::= B oppure A ::= (lineare
destra), o alternativamente tutte della forma A ::= B oppure A ::= (lineare sinistra), con T e A, B N .
9 Assumendo

per semplicit`a  6 L.

21

Le definizioni di derivazione e linguaggio generato sono esattamente quelle viste per le grammatiche CF.
Una formulazione equivalente per il tipo 0 e` che le produzioni siano della forma 1 A2 ::= , con 1 , 2 , (T N )? ,
A N.
Una formulazione equivalente per il tipo 1 e` che le produzioni siano della forma 1 A2 ::= 1 2 , con 6= . Questa
formulazione mette in evidenza la differenza con le grammatiche context-free: il non terminale A si deriva in , ma solo nel
contesto costituito dalle due stringhe 1 (contesto sinistro) e 2 (contesto destro).
Un esempio classico di grammatica context-sensitive e` la seguente che genera {an bn cn }:
S
CB
bB
bC
cC
aB

::=
::=
::=
::=
::=
::=

aSBC | aBC
BC
bb
bc
cc
ab

Vediamo che in effetti la grammatica genera tutte le stringhe an bn cn . Si ha:


n

S an (BC)n
? an B n C n applicando la terza produzione
? an bn cn applicando le ultime quattro produzioni.
Un linguaggio si dice di tipo i, per i = 0, 1, 2, 3, se esiste una grammatica di tipo i che lo genera. Indichiamo con Li la classe
dei linguaggi di tipo i.
Si ha, per definizione, che ogni classe di grammatiche e` inclusa strettamente nella precedente.10 Inoltre, unanaloga inclusione
stretta vale per le corrispondenti classi di linguaggi (in questo caso il fatto che linclusione sia stretta non e` ovvio). In particolare
si ha:
L0 coincide (vedremo solo ) con la classe degli insiemi ricorsivamente enumerabili, vedi Definizione 7.3
L1 e` contenuta strettamente (vedremo solo ) nella classe degli insiemi ricorsivi, vedi Definizione 7.1, quindi e` anche
contenuta strettamente in L0
L2 ( L1 si vede dimostrando che an bn cn e` in L1 ma non in L2
L3 ( L2 si vede dimostrando che an bn e` in L2 ma non in L3
Teorema 4.2 Ogni linguaggio di tipo 0 (ossia, generato da una grammatica di tipo 0) e` ricorsivamente enumerabile.
Prova In breve: per semi-decidere se una stringa u appartiene al linguaggio, basta generare esaustivamente tutte le derivazioni
di lunghezza 0, 1, 2, etc. Se la stringa appartiene al linguaggio prima o poi verr`a trovata.
Pi`u in dettaglio: un algoritmo che, data una stringa u e una grammatica11 G di tipo 0, semi-decide se u L(G) e` il seguente.
Sia Ln linsieme delle stringhe che possiamo ottenere a partire dallassioma in al pi`u n passi. Ovviamente, data u T ? ,
u L(G) se e solo se u Ln per qualche n.
Possiamo definire induttivamente gli Ln nel modo seguente.
L0 = {S}
Ln+1 = Ln { | per qualche Ln }
Tale definizione induttiva e` effettiva, ossia possiamo via via costruire gli Ln in modo algoritmico, in quanto:
L0 e` finito
quindi, assumendo induttivamente a ogni passo che Ln sia finito, Ln+1 e` finito e pu`o essere costruito considerando tutte
le stringhe in Ln , che possono essere decomposte in un numero finito di modi come , e il numero di produzioni
applicabili a e` finito.
10 In realt`
a questo non e` vero perche la definizione di grammatica context-free permette produzioni con  a destra, non ammesse nelle grammatiche di tipo 1 e
nelle grammatiche di tipo 2: vedremo nel seguito come modificare le definizioni in modo che si abbia effettivamente linclusione.
11 Si noti che la grammatica e
` un input, ossia lalgoritmo deve funzionare per qualunque grammatica e non essere costruito ad-hoc a partire da questultima.

22

Dato che esistono linguaggi ricorsivamente enumerabili che non sono ricorsivi, non si pu`o migliorare questo risultato, ossia
esistono grammatiche di tipo 0 tali che il linguaggio generato non e` ricorsivo.
Teorema 4.3 Ogni linguaggio di tipo 1 (ossia, generato da una grammatica di tipo 1) e` ricorsivo.
Prova In breve: come sopra, possiamo generare esaustivamente tutte le derivazioni di lunghezza 0, 1, 2, etc., e se la stringa
appartiene al linguaggio prima o poi verr`a trovata. In questo caso tuttavia, dato che le produzioni sono non decrescenti, e`
intuitivamente chiaro che prima o poi generer`o solo nuove stringhe di lunghezza maggiore di |u|, e quindi (se non lho trovata
prima) potr`o concludere che la stringa non pu`o essere generata.
Pi`u in dettaglio: un algoritmo che, data una stringa u e una grammatica G di tipo 1, decide se u L(G) e` il seguente.
Sia L`n il linguaggio delle stringhe di lunghezza minore o uguale a ` generate in al pi`u n passi. Ovviamente, data u T ? ,
|u|
u L(G) se e solo se u Ln per qualche n.
Fissato `, possiamo definire induttivamente gli L`n nel modo seguente.
L`0 = {S} per ` 1
L`n+1 = L`n { | || `, per qualche L`n }
Tale definizione induttiva e` effettiva, ossia possiamo via via costruire gli L`n in modo algoritmico, analogamente a quanto visto
per il teorema precedente.
tale che L`n +1 = L`n , e quindi L`n = L`n per ogni n n
. Quindi, per
Inoltre, dato che L` e` un insieme finito, dovr`a esistere un n
`
`
decidere se u L , basta controllare se u Ln .
Dato che i linguaggi di programmazione sono di tipo 1, il precedente teorema garantisce che il problema di decidere se un
programma appartiene a un certo linguaggio di programmazione e` decidibile, quindi ha senso cercare di costuire un programma
riconoscitore.
La definizione di grammatica di tipo 1 che abbiamo dato non ammette che il linguaggio generato contenga la stringa vuota.
Tuttavia, sembra ragionevole che se esistono una descrizione finita e un algoritmo di riconoscimento per un linguaggio L, allora
lo stesso sia possibile per L {}. Non posso per`o aggiungere produzioni del tipo A ::=  nella definizione di grammatica
context-sensitive perche come abbiamo visto la non decrescenza gioca un ruolo fondamentale nella prova.
Soluzione: esiste trasformazione canonica che presa G di tipo 1 produce G0 di tipo 1 equivalente tale che lassioma non compaia
mai a destra nelle produzioni. La trasformazione consiste semplicemente nellaggiungere un nuovo assioma S 0 e una produzione
S 0 ::= per ogni produzione S ::= .In questo modo, se il linguaggio contiene  possiamo aggiungere la produzione S 0 ::=  e
questa potr`a essere usata esclusivamente al primo passo di derivazione, per generare la stringa vuota.
Quindi nuova definizione di tipo 1: come prima pi`u eventuale produzione S ::=  e in questo caso S non appare mai a destra. Si
modifica in modo ovvio lalgoritmo.
Per il tipo 2 la definizione ammette produzioni A ::= , ma si pu`o vedere che ci si pu`o ridurre a forma normale di Greibach pi`u
eventuale regola S ::=  con S che non appare mai a destra, in questo modo si ottiene un caso particolare di una grammatica
context sensitive.
Infine, per il tipo 3 si pu`o ammettere anche S ::=  con analoga restrizione.
Si pu`o vedere che L3 coincide con la classe dei linguaggi regolari. Infatti:
Dato L generato da una grammatica lineare destra hT, N, P, Si, allora L e` riconosciuto dal NFA costruito nel modo
seguente:
linsieme degli stati e` N {}
lalfabeto e` T
la funzione di transizione e` definita da:
B (A, ) se e solo se A ::= B P
(A, ) se e solo se A ::= P
(, ) = per ogni T
lo stato iniziale e` S
linsieme degli stati finali e` costituito da , pi`u S se e` presente la produzione S ::= 
u)
Si pu`o provare per induzione aritmetica sulla lunghezza di u (esercizio) che, per ogni A N (quindi A 6= ) si ha A (S,
se e solo se S ? uA.
Da questo risultato, per come abbiamo definito gli stati finali, si ha:
) F 6=
S ?  se e solo se (S,
23

u) e
S ? u se e solo se esiste A tale che S ? uA e A ::= e` una produzione. Ci`o accade se e solo se A (S,

(A, ), ossia (S, u).


Viceversa, se L e` un linguaggio regolare, allora e` generato da una grammatica lineare destra. Infatti, sia M = hQ, , , q0 , F i il
DFA che riconosce L. Possiamo costruire una grammatica lineare destra che generi L nel modo seguente:
linsieme dei terminali e`
linsieme dei non terminali e` Q
vi e` una produzione A ::= B se e solo se (A, ) = B
vi e` una produzione A ::=  se e solo se A F .
0 , u) = q se e solo se q0 uq
Si pu`o provare per induzione induzione aritmetica sulla lunghezza di u (esercizio) che (q
(in un numero di passi pari alla lunghezza della stringa).
0 , u) F se e solo se q0 ? u (in un numero di passi pari alla lunghezza
A questo punto si ha immediatamente che (q
della stringa)..
Questa grammatica ha produzioni del tipo A ::= , ma pu`o essere portata alla forma normale con la trasformazione
canonica.

Macchine di Turing

La Teoria della Calcolabilit`a ha come obiettivo principale quello di identificare dei criteri formali per identificare la classe di
problemi effettivamente risolvibili tramite un elaboratore. Il risultato forse pi`u sorprendente della Teoria della Calcolabilit`a e`
lesistenza di problemi irrisolvibili. Almeno idealmente dovremmo sempre, prima di iniziare a scrivere codice, essere sicuri di
poter risolvere completamente il problema che ci accingiamo ad affrontare. Una volta individuati alcuni problemi irrisolvibili, la
nozione di riduzione tra problemi pu`o facilitare questo task.
La formalizzazione della nozione di risolvibilit`a di un problema e` tecnicamente molto complessa. Turing ha studiato la calcolabilit`a tramite modelli ideali di elaboratore e programma. Per semplificare lo scenario consideriamo solo problemi decisionali,
cio`e problemi che possono essere modellati tramite funzioni da una stringa in input a un valore si/no (un booleano). In questo
caso particolare si parla quindi di problemi decidibili e indecidibili. Come esempio di problema decisionale, consideriamo il
problema della membership (appartenenza di una stringa a un linguaggio).
Dato un automa a stati finiti12 M e una stringa u, vogliamo decidere se u L(M) cio`e se u e` accettata o meno da
M.
Sappiamo da quanto visto nella Sezione 2.1 che questo problema e` decidibile, cio`e risolvibile in maniera algoritmica. Consideriamo ora il seguente problema.
Dati due linguaggi context-free L1 ed L2 , vogliamo decidere se la loro intersezione e` vuota.
Non affrettatevi a scrivere un algoritmo per questo problema. Il problema infatti e` noto essere irrisolvibile (indecidibile).
Per poter ragionare sulla risolvibilit`a o meno di un problema decisionale abbiamo bisogno di formalizzare diversi punti. Innanzitutto dobbiamo formalizzare la rappresentazione di un algoritmo (linguaggio di programmazione, formato dellinput, formato
delloutput) e la definizione di algoritmo che risolve un problema (funzione input/output definita dal programma). In un articolo
fondamentale Turing [?] ha proposto come modello di elaboratore ideale unestensione naturale degli automi a stati finiti verso un
modello con memoria infinita che viene comunemente chiamata macchina di Turing (MT). Per capire questo passaggio partiamo
dalle caratteristiche salienti di un automa finito:
Come menzionato nella Sezione 2.1, si pu`o pensare a un automa finito come a una macchina che legge caratteri scritti su
un nastro infinito attraverso una testina che scorre il nastro da sinistra a destra.
Lo stato iniziale del nastro rappresenta la stringa da analizzare a partire dallo stato iniziale della testina posizionata
allinizio.
Il programma che controlla la macchina e` definito da una matrice di transizione che determina un possibile cambiamento
di stato della testina quando il carattere corrente pu`o essere letto dalla testina (cio`e esiste una transizione definita sullo stato
e simbolo corrente).
12 Diremo

anche per brevit`a automa finito (FA).

24

In un automa non deterministico a ogni passo si pu`o scegliere una transizione tra quelle abilitate nello stato corrente.
Un FA legge il nastro solo in una direzione (quindi pu`o solo consumare caratteri) e ha a disposizione solo una memoria
finita (gli stati della testina).
Proviamo a estendere il modello, similmente a quanto fatto per gli automi a pila nella Sezione 3.4, in modo da usare in maniera pi`u
intelligente la memoria (potenzialmente infinita) fornita dal nastro che assumiamo sia infinito nelle due direzioni (o estendibile a
piacimento). Lestensione che sembra pi`u naturale e` quella di permettere alla testina di scorrere sia in avanti che allindietro nel
nastro, modificando al suo passaggio le celle visitate. Larchitettura (la macchina di calcolo) e` simile a quella usata per eseguire
un automa finito. Tuttavia nelle MT abbiamo un set di istruzioni pi`u esteso per gestire la memoria (nastro).
Anche senza aver formalizzato le definizioni, possiamo immaginare subito di avere a disposizione un modello con memoria
potenzialmente infinita. Per esempio, possiamo pensare di simulare un automa a pila dividendo in due parti il nastro, attraverso
un simbolo speciale, a partire dalla cella iniziale. Nella parte a sinistra del separatore rappresentiamo lo stack. Nella parte a
destra del separatore rappresentiamo linput. Le transizioni di un automa a pila verranno simulate spostando la testina avanti e
indietro tra la parte di nastro dedicata allo stack e quella dellinput.
Notiamo che il linguaggio di programmazione delle MT non ha a disposizione istruzioni tipo goto per saltare da una cella
allaltra. Inoltre, le celle non sono identificate da indici che possiamo usare nei programmi (come accade per esempio con la
memoria di un elaboratore). Le operazioni sul nastro sono quindi guidate solo dal contenuto delle celle. Un salto dalla cella
corrente a una cella che contiene un certo simbolo si pu`o comunque realizzare tramite una serie di spostamenti elementari in
una certa direzione. Inoltre, dato che possiamo spostarci nelle due direzioni, consumare linput deve corrispondere a una vera
cancellazione dei simboli letti. Per esempio, si pu`o sovrascrivere un simbolo consumato con un carattere speciale, oppure si pu`o
spostare la sequenza di simboli rimanente di una posizione a sinistra.
Queste capacit`a aggiuntive della testina hanno un fortissimo impatto sullespressivit`a del modello. Possiamo infatti usare la parte
a sinistra del nastro come coda, lista, albero, insieme di strutture dati e la parte a destra per consumare linput ed eventualmente
per produrre risultati intermedi e finali. In altre parole, abbiamo ora un macchina che pu`o fare transizioni tra stati complessi che
includono la control location (stato della testina) e lo stato corrente della memoria (parte finita di nastro usato). Chiameremo ID le
descrizioni istantanee della macchine. Questo tipo di macchina pu`o essere vista come una versione ancora grezza dellarchitettura
di Von Neumann [?] dove la memoria e` ad accesso diretto e le istruzioni manipolano direttamente i valori e gli indirizzi di
memoria invece del contenuto del nastro. Provando a scrivere programmi per le due macchine ci si rende conto subito della
difficolt`a addizionale di sviluppare programmi su una MT.
Sulla base delle precedenti considerazioni, sembra plausibile pensare che una MT possa codificare gli stessi algoritmi che possiamo codificare in linguaggio assembly (visto che possiamo rappresentare memoria e istruzioni anche cicliche navigando sul
nastro). Inoltre, sembra possibile definire interpreti di altri linguaggi attraverso MT che prendono in input programmi e che
simulano la loro semantica partizionando il nastro in diversi segmenti (codice da eseguire, memoria, stack, ecc.). Una MT in
grado di simulare altre MT viene chiamata universale e rappresenta lidea alla base dei calcolatori e del ciclo di fetch con cui
opera la macchina di Von Neumann.
Utilizzando luniversalit`a e attraverso una tecnica chiamata diagonalizzazione (usata per esempio per distinguere la cardinalit`a
dei numeri naturali e reali), Turing ha dimostrato che non e` possibile decidere se una MT termina o no. Se si potesse fare,
studiando la terminazione della MT universale, potremmo decidere a priori se un qualsiasi programma termina o no su un certo
input. Infatti, anche senza dimostrazione formale, intuitivamente per risolvere questo problema sembra necessario un oracolo
che anticipi la conclusione dellesecuzione. Unalternativa potrebbe essere simulare lesecuzione del programma passo per passo
(come in molti debugger). Il tracking passo per passo e` utile tuttavia solo se lesecuzione termina. Se il programma non termina,
anche il tracking non termina. Dobbiamo quindi usare altre indicazioni, come per esempio confrontare stati diversi e cercare di
capire se la computazione continuer`a a generarne di nuovi o prima o poi generer`a solo stati gi`a visitati. Ma in un programma
posso codificare funzioni matematiche arbitrarie e quindi mi servirebbe un oracolo per poter estrapolare il comportamento di una
funzione a partire da un insieme finito di punti (stati generati dopo un numero finito di passi). In conclusione, dati un programma
qualsiasi e un suo input qualsiasi, il task sembra veramente complicato, infatti come detto prima risulta essere indecidibile.
La tesi di Church-Turing afferma inoltre che le funzioni calcolabili con un algoritmo sono tutte e sole quelle definite da una
macchina di Turing. Ogni altro tentativo di definire modelli universali ha solo rafforzato questa tesi. Modelli come le funzioni
ricorsive, il lambda-calcolo, le Random Access Machine, le macchine a contatori sono tutte risultate essere equivalenti alle
macchine di Turing (nel senso che definiscono la stessa classe di funzioni calcolabili). Vedremo pi`u avanti le funzioni ricorsive e
altri modelli di computazione. Iniziamo tuttavia a formalizzare la nozione di macchina di Turing per poter poi definire la classe
dei linguaggi ricorsivi e ricorsivamente enumerabili e parlare di decidibilit`a e indecidibilit`a in maniera pi`u precisa.

5.1

Definizione delle macchine di Turing

Vediamo subito la definizione formale, ispirata alla definizione di automa, di una macchina di Turing.

25

Def. 5.1 [Macchina di Turing deterministica (MT)] Una MT M e` definita come una tupla
M = hQ, , , , q0 , B, F i
dove
Q: e` un insieme finito di stati di controllo.
: e` un insieme finito di simboli di input.
: e` un insieme finito di simboli del nastro; .
: Q Q {L, R}: e` la funzione (parziale13 ) di transizione.
q0 Q e` lo stato iniziale della testina.
B e` un simbolo speciale in \ che rappresenta la cella vuota (blank).
F Q e` un insieme di stati finali.
La funzione di transizione definisce quindi il programma di controllo della macchina e in particolare definisce la prossima mossa
della testina sulla base della storia della computazione passata (stato della testina e memoria del nastro). Infatti se (q, X) =
hp, Y, Di, allora quando la testina e` nello stato q e si trova su una cella che contiene X:
p e` il prossimo stato della macchina.
Y e` il simbolo in che sovrascrive X nella cella corrente.
D e` la direzione, L (left) o R (right), nella quale si muove la testina.
La funzione di transizione definisce staticamente il comportamento di una MT. Dobbiamo ora definire il concetto di esecuzione
di una MT o meglio di computazione attraverso la definizione del funzionamento del nostro modello (in termine tecnico semantica
operazionale).

5.2

Semantica operazionale

Per poter dare una semantica formale del comportamento di una MT abbiamo bisogno di definire la nozione di descrizione istantanea (configurazione o stato) di una macchina, che chiameremo ID (instantaneous description), e la nozione di cambiamento di
stato (transizione da una descrizione istantanea a unaltra).
5.2.1

Descrizioni istantanee

Le informazioni rilevanti per descrivere lo stato di una macchina sono: lo stato della testina (un simbolo in Q) e il contenuto delle
celle nel nastro (simboli in ). Pi`u precisamente, e` sufficiente rappresentare la porzione di nastro significativa, ossia ottenuta
escludendo le due sequenze illimitate di celle vuote sempre presenti a sinistra e a destra. Notiamo come il fatto che la porzione
significativa sia sempre finita segue dal fatto che modelliamo gli stati raggiungibili dopo un numero finito di passi elementari di
una macchina. Formalmente, per rappresentare un ID usiamo la stringa wqv su Q dove
w rappresenta i simboli a sinistra della testina
v rappresenta i simboli a destra
q e` lo stato della testina.
v 6=  il simbolo puntato dalla testina e` quindi il primo simbolo a sinistra di v, altrimenti la testina punta ad una cella che
contiene B.
Avendo definita la nozione di descrizione istantanea possiamo ora definire un singolo passo di esecuzione. Sia M = hQ, , , , q0 , B, F i
una MT. Usiamo una relazione 1 `M 2 per specificare la relazione tra due ID indotta dalla funzione di transizione , definita
per casi su 1 , 2 , come segue:
Dati v, w, v , X, Y, Z , allora:
13 Nel caso deterministico consideriamo una funzione parziale. Nelle MT non deterministiche si considerano relazioni, o funzioni che generano insiemi di
possibili mosse.

26

wqXv `M wY q 0 v, se (q, X) = hq 0 , Y, Ri
wq `M wY q 0 , se (q, B) = hq 0 , Y, Ri
wZqXv `M wq 0 ZY v, se (q, X) = hq 0 , Y, Li
qXv `M q 0 BY v, se (q, X) = hq 0 , Y, Li
Se `M 0 , diciamo che 0 e` un successore di (e che e` un predecessore di 0 ). Inoltre, data una descrizione istantanea
= X1 . . . qXi . . . Xn , definiamo state() = q.
5.2.2

Computazioni

Per codificare linput, una stringa w in ? , su cui lavora la macchina, assumiamo che w sia inizialmente memorizzata sul nastro
(in una posizione qualsiasi) da sinistra a destra in celle consecutive. Inoltre assumiamo che inizialmente la testina sia posizionata
sul primo simbolo di w.
Def. 5.2 [Configurazione iniziale] Sia M = hQ, , , , q0 , B, F i una MT. Data una stringa w ? , definiamo la configurazione
iniziale per linput w come 0 = q0 w.
Possiamo finalmente definire cosa vuol dire computazione in una MT. Similmente allesecuzione di un programma C, e` una
sequenza di descrizioni istantanee che fotografano lo stato della memoria (nastro) e la control location (testina, anchessa e` una
sorta di memoria finita).
Def. 5.3 [Computazione di una MT] Una computazione di una MT M sullinput w ? e` una sequenza 0 1 2 . . . i . . . finita o
infinita di descrizioni istantanee che parte dalla configurazione iniziale 0 = q0 w tale che i `M i+1 , cio`e i+1 e` un successore
di i , per i 0.
Una MT termina su w ? se la computazione che parte da q0 w e` finita, cio`e partendo da q0 w la MT pu`o effettuare solo un
numero finito di passi. La relazione di raggiungibilit`a tra ID e` definita come la chiusura riflessiva e transitiva14 della funzione di
transizione. Cio`e 0 e` raggiungibile da 0 se 0 `?M 0 , ossia se esiste una computazione 0 1 . . . n con n = 0 .

5.3

Riconoscere linguaggi e calcolare funzioni

Vediamo ora come definire la nozione di riconoscimento di un linguaggio.


Def. 5.4 [Linguaggio riconosciuto da una MT] Una computazione 0 1 . . . riconosce un input w se esiste un i tale che state(i )
F , cio`e esiste una configurazione i raggiungibile da 0 dove la testina e` in uno stato finale. Il linguaggio L(M ) ?
riconosciuto da una MT M e` definito come segue:
L(M ) = {w ? | w riconosciuta da una computazione di M }
Notiamo che il linguaggio e` definito sul sottoinsieme di simboli . Lidea e` infatti che i simboli aggiuntivi siano usati solo
durante la computazione.
La nozione di riconoscimento si pu`o esprimere alternativamente attraverso la nozione di terminazione. Cio`e w e` riconosciuta se
la macchina termina sullinput w.
Def. 5.5 [Linguaggi ricorsivamente enumerabili] La classe dei linguaggi ricorsivamente enumerabili RE e` costituita dai linguaggi che si possono riconoscere tramite una qualche MT, cio`e RE = {L | M.M riconosce L}.
Vediamo un esempio. Il set di istruzioni si pu`o facilmente estendere aggiungendo istruzioni che non cambiano la posizione
della testina, cio`e aggiungendo la direzione nulla in modo che (q, X) = hq 0 , Y, i sovrascriva la cella corrente con Y senza
cambiare posizione. Possiamo inoltre aggiungere istruzioni che cambiano stato indipendentemente dal simbolo corrente, cio`e
aggiungendo il simbolo speciale a in modo che (q, ) = hq 0 , , di cambia lo stato senza modificare il simbolo corrente.
Vediamo ora un esempio di programma e in particolare vediamo come definire la MT che riconosce il linguaggio regolare
L = {0m 1n | n, m 0}
con = {0, 1}. Data una stringa w ? , inizialmente la testina e` posizionata allinizio di w. Lalgoritmo e` definito come
segue:
14 Vedi

Definizione A.4.

27

Leggiamo tutti i simboli 0 spostandoci a destra.


Quando troviamo un 1 cambiamo stato e leggiamo tutti i simboli 1 spostandoci a destra.
Se troviamo B la stringa e` accettata, se troviamo 0 la macchina si blocca in uno stato di non accettazione.
Usiamo un formato tabellare per specificare la funzione di transizione di questa MT:

q0
q1

0
q0 , 0, R

1
q1 , 1, R
q1 , 1, R

B
q2 , B,
q2 , B,

dove q0 e` lo stato iniziale e q2 e` lunico stato finale (assumiamo che non ci siamo mai transizioni da uno stato finale e quindi
omettiamo la corrispondente riga nella tabella).
Vediamo ora un esempio di esecuzione della MT sullinput w = 0011.
q0 0011 `M 0q0 011 `M 00q0 11 `M 001q1 1 `M 0011q1 B `M 0011q2 B
Per esempio su 010:
q0 010 `M 0q0 10 `M 01q1 0 6 `M
dove lultimo ID non ha successori.
Vediamo ora come usare le MT per calcolare funzioni. Nellarticolo originale di Turing le MT rappresentano un computer
ideale per calcolare funzioni parziali sui naturali f [Nk N]. I naturali sono codificati in notazione unaria, ossia come
sequenze di 0 (per esempio, la codifica di 5 e` 5 = 05 = 00000). Linput e` una stringa che codifica gli argomenti da passare alla
funzione che si vuole calcolare, per esempio della forma n1 1 . . . 1nk dove 1 e` utilizzato come separatore degli argomenti. Come
convenzione di output, possiamo assumere che il risultato della funzione sia rappresentato dalla stringa (su ? ) che rimane sul
nastro quando lesecuzione termina su uno stato finale. Pi`u precisamente possiamo assumere che una configurazione qf w0 con
w0 ? rappresenti loutput w0 calcolato dalla macchina.
Con questa convenzione, possiamo definire la nozione di funzione calcolata.
Def. 5.6 [Funzione calcolata da una MT] Consideriamo lalfabeto = {0, 1} e un singolo stato finale halt. La funzione
fM : Nk N calcolata da una MT M e` definita come segue:
fM (n1 , . . . , nk ) = v
sse
M con input n1 1 . . . 1nk termina con uno stato di accettazione e output v.
Notiamo che se la macchina non termina, o si blocca su uno stato non finale, o termina su uno stato finale con una stringa
sul nastro mal formata (per esempio, diverse stringhe separate da blank), allora la funzione calcolata non e` definita sullinput
considerato (essendo deterministica la computazione e` univocamente determinata dallinput).
Notiamo subito che, fissato = {0, 1} e una codifica (unaria) di true e f alse, riconoscere un linguaggio L ? corrisponde a
calcolare la sua funzione caratteristica (indicatrice) L : ? {true, f alse}, cio`e la funzione (L (w) = true sse w L).

5.4

Programmazione nelle MT

Usare un interprete pu`o essere utile per provare a scrivere altri esempi di MT. Usando la sintassi del simulatore on-line
http://morphett.info/turing/turing.html
dove B viene indicato con , R con r e L con l, possiamo per esempio riscrivere il programma che riconosce 0m 1n come segue:
;sintassi del simulatore http://morphett.info/turing/turing.html
;stato simbolo_corrente simbolo_nuovo direzione(r,l,*) nuovo_stato
;Q={0,1,halt} 0=stato iniziale halt=stato finale
0 0 0 r 0
0 1 1 r 1
0 _ _ * halt
1 1 1 r 1
1 _ _ * halt

28

5.4.1

Riconoscere 0n 1n

Vediamo ora come definire la MT che riconosce il linguaggio (non regolare) L = {0n 1n | n 1}.
Come prima soluzione possiamo usare un programma che sovrascrive il primo 0 che trova con X, poi il primo 1 che trova con
Y , torna indietro e ricomincia se ci sono ancora 0. Se non ci sono pi`u 0 allora scorre tutto linput modificato controllando che
non ci siano pi`u 1. Usiamo un formato tabellare per specificare la funzione di transizione di questa MT:

q0
q1
q2
q3
q4

0
q1 , X, R
q1 , 0, R
q2 , 0, L
q1 , X, R

q2 , Y, L
q4 , X, R

q1 , Y, R
q2 , Y, L
q4 , Y, R
q4 , Y, R

q5 , B, R

q0 e` lo stato iniziale e q5 e` lo stato finale.


Le celle vuote nella tabella precedente mostrano che la funzione di transizione pu`o essere parziale cio`e una MT pu`o finire in
vicoli ciechi che bloccano il calcolo. Questo e` quello che succede per esempio se la stringa in input non appartiene al linguaggio
L.
Vediamo ora un esempio di esecuzione della MT sullinput w = 0011.
q0 0011 `M Xq1 011 `M X0q1 11 `M Xq2 0Y 1 `M q2 X0Y 1 `M Xq3 0Y 1 `M XXq1 Y 1 `M
XXY q1 1 `M XXq2 Y Y `M Xq2 XY Y `M XXq3 Y Y `M XXY q4 Y `M XXY Y q4 B `M XXY Y Bq5 B
M si blocca subito su stringhe che iniziano con 1 oppure durante la scansione di stringhe che contengono 10 oppure del tipo
0m 1n con m 6= n. Per esempio su 011:
q0 011 `M Xq1 11 `M q2 XY 1 `M Xq3 Y 1 `M XY q4 1
dove lultimo ID non ha successori. Usando la sintassi del simulatore on-line http://morphett.info/turing/turing.html
dove B viene indicato con , R con r e L con l possiamo riscrivere il programma (ed eseguirlo) come segue:
;sintassi del simulatore http://morphett.info/turing/turing.html
;stato simbolo_corrente simbolo_nuovo direzione(r,l,*) nuovo_stato
;Q={0,halt,go_r,go_l,test,check_r} 0=stato iniziale halt=stato finale
0
0 X r goR
goR
0 0 r goR
goR
1 Y l goL
goR
Y Y r goR
goL
0 0 l goL
goL
X X r test
goL
Y Y l goL
test
0 X r goR
test
Y Y r check
check
Y Y r check
check
_ _ * halt
dove 0 = q0 , q1 = goR, q2 = goL, q3 = test, q4 = check, q5 = halt.
5.4.2

Funzione somma di numeri in unario

Vediamo come definire la MT che calcola la somma di due numeri codificati in unario separati da #, es. 1n #1m deve dare come
output 1n+m . Lalgoritmo semplicemente sposta tutti gli 1 prima di # alla fine del secondo argomento cancellando alla fine il
separatore. Quando la testina ritorna indietro occorre usare due stati diversi per sapere quando la testina ha superato il separatore
(per decidere quando terminare gli spostamenti). Il programma e` definito come segue.

q0
q1
q2
q3
q4

1
q1 , B, R
q1 , 1, R
q2 , 1, L
q3 , 1, L
q1 , B, R

q1 , #, R
q3 , #, L

q2 , 1, L
q4 , B, R

q5 , B, R
29

q0 e` lo stato iniziale e q5 e` lo stato finale.


;sintassi del simulatore http://morphett.info/turing/turing.html
;stato simbolo_corrente simbolo_nuovo direzione(r,l,*) nuovo_stato
;Q={0,go_r,go_l,go1_l,test,halt} 0=stato iniziale halt=stato finale
0
# _ r halt
0
1 _ r go_r
go_r
# # r go_r
go_r
1 1 r go_r
go_r
_ 1 l go_l
go_l
1 1 l go_l
go_l
# # l go1_l
go1_l
1 1 l go1_l
go1_l
_ _ r test
test
1 _ r go_r
test
# _ r halt
5.4.3

Ordinamento di stringhe

Vediamo come definire la MT che data una stringa con simboli in 0, 1 li ordina mettendo prima tutti gli zero e poi tutti gli uno.
Lalgoritmo effettua i seguenti passi.
1. Innanzitutto posizioniamo la testina al primo simbolo 1 saltando quindi tutti i simboli 0. Se non ci sono 1 la stringa e`
ordinata.
2. Continuiamo a spostare la testina leggendo altri 1 alla sua destra fino a incontrare uno 0. Se non ci sono zero la stringa
e` ordinata.
3. Se la testina e` posizionata su uno 0, scriviamo 1 e ritorniamo indietro al primo 1 alla sua sinistra (se ci sono diversi 1 ci
posiziamo su quello pi`u a sinistra).
3. Cambiano 1 in 0 e torniamo al passo 2.
Il programma e` definito come segue.
q0
q1
q2
q3

0
q0 , 0, R
q2 , 1, L
q3 , 0, R

1
q1 , 1, R
q1 , 1, R
q2 , 1, L
q1 , 0, R

B
q4 , B, R
q4 , B, R
q3 , B, R

q0 e` lo stato iniziale e q4 e` lo stato finale.


;sintassi del simulatore http://morphett.info/turing/turing.html
;stato simbolo_corrente simbolo_nuovo direzione(r,l,*) nuovo_stato
;Q={0,rzero,rone,lone,change,halt} 0=stato iniziale halt=stato finale
0
rzero
rzero
rzero
rone
rone
rone
lone
lone
lone
change

* * *
0
_ _ *
1 1 r
1 1 r
_ _ *
0 1 l
1 1 l
0 0 r
_ _ r
1 0 r

rzero
0 r rzero
halt
rone
rone
halt
lone
lone
change
change
rone

30

5.4.4

Conteggio simboli

Consideriamo lalfabeto = {0, 1}. Dati s e w , definiamo contas (w) come il numero di occorrenze del simbolo s
in w (es. conta1 (10101) = 3).
Definiamo una Macchina di Turing M che accetta tutte e sole le stringhe w con un numero doppio di occorrenze di 1
rispetto alle occorrenze di 0, i.e.,
L(M ) = {w | conta1 (w) = 2 conta0 (w)}
Ad esempio, 010111 e 111000111 devono appartenere a L(M ) mentre 0011 non appartiene. Un possibile algoritmo per risolvere
il problema esegue i seguenti passi. Usiamo il simbolo X per cancellare simboli processati.
(1) Partendo dal primo simbolo leggiamo linput da sinistra a destra:
Se non ci sono simboli (stringa vuota in input) o sono tutti X (termine processo di validazione) accettiamo la stringa
Altrimenti
Se non ci sono 0 la macchina si blocca
Se troviamo invece uno 0 lo cancelliamo e andiamo in fondo a destra
(2) Partendo dal primo simbolo a destra leggiamo linput da destra a sinistra:
Se non ci sono 1 la macchina si blocca
Se troviamo un 1 lo cancelliamo e ce ne ricordiamo cambiando stato per cercare il secondo 1
Nel nuovo stato se non ci sono 1 la macchina si blocca
Se troviamo il secondo 1 lo cancelliamo, andiamo fino in fondo a sinistra, poi torniamo a (1)
Implementiamo lalgoritmo tramite la seguente MT definita sullalfabeto = {0, 1, X, B} con
Q = {init, cerco 0, cerco 1, cerco 2, vado dx, vado sx, halt}
init stato iniziale, QF = {halt} e B=blank.
init: controlla se ci sono solo X oppure cerca e cancella uno 0
cerco 0: so che non sono in uno stato finale, cerco uno 0
vado dx: salto in fondo a destra alla stringa
cerco 1: cerco il primo 1 (associato ad uno 0 che ho gi`a cancellato) da cancellare
cerco 2: cerco il secondo 1 (associato ad uno 0 e ad un 1 che ho gi`a cancellato) da cancellare
vado sx: ho cancellato uno 0 e due 1 torno allinizio della stringa (a sinistra)
halt: stato finale con regole di posizionamento della testina allinizio della stringa
La funzione di transizione (deterministica, parziale) e` definita come segue.

init
halt
vado dx
cerco 0
cerco 1
cerco 2
vado sx

5.5

0
hvado dx, X, Ri
hhalt, 0, Li
hvado dx, 0, Ri
hvado dx, X, Ri
hcerco 1, 0, Li
hcerco 2, 0, Li
hvado sx, 0, Li

1
hcerco 0, 1, Ri
hhalt, 1, Li
hvado dx, 1, Ri
hcerco 0, 1, Ri
hcerco 2, X, Li
hvado sx, X, Li
hvado sx, 1, Li

X
hinit, X, Ri
hhalt, X, Li
hvado dx, X, Ri
hcerco 0, X, Ri
hcerco 1, X, Li
hcerco 2, X, Li
hvado sx, X, Li

B
hhalt, B, Li
hhalt, B, Ri
hcerco 1, B, Li

hinit, B, Ri

Varianti al Modello di Base

In questa sezione studieremo varianti del modello di MT visto precedentemente. In particolare siamo interessati a versioni non
deterministiche delle MT e alla loro codifica attraverso macchine deterministiche. Per semplificare la codifica di una macchina
non deterministica introduciamo prima una variante con nastro multiplo.
31

5.5.1

Multitape MT

Una Multitape MT (macchina di Turing multinastro) e` una MT con k nastri e k testine coordinate da un singolo programma di
controllo. Una descrizione istantanea e` formata quindi da k ID di MT single tape. Lo stato della testina in ogni singola ID e`
tuttavia sempre lo stesso. Per esempio, nel caso di due nastri potremmo avere configurazioni come hXqY, XqXY Y i. La testina
di ogni nastro si muove indipendentemente dallaltra. La funzione di transizione e` quindi una funzione
: Q k Q ( {L, R, })k
dove indica una mossa stazionaria. Per esempio con due nastri la transizione
(q, hX, Y i) = (q 0 , hhX 0 , Li, hY 0 , Rii)
controlla che la prima testina sia su X nel primo nastro e su Y nel secondo, spostandosi a sinistra sul primo e a destra sul secondo.
La nozione di computazione, terminazione e accettazione pu`o essere estesa alle Multitape MT considerando lo stato comune
raggiunto dalla testina durante lesecuzione e scegliendo a priori da quale nastro leggere linput e da quale recuperare loutput.
Lasciamo come esercizio la definizione formale di descrizioni istantanee e semantica operazionale delle Multitape MT.
Chiaramente una Multitape MT ha almeno lespressivit`a di una MT con un solo nastro. Vale anche il viceversa? Cio`e possiamo
emulare una Multi-tape MT attraverso un MT con un solo nastro? La risposta e` sicuramente positiva in quanto abbiamo pi`u volte
affermato che le MT hanno capacit`a universale e possono interpretare qualsiasi altro linguaggio.
Data una Multitape MT M con simboli in e stati in Q che riconosce un linguaggio L, vediamo a grandi linee come costruire
una MT che riconosce lo stesso linguaggio. Lidea e` la seguente. In un ID della macchina emulatrice, come, per esempio:

X
X
X
hX
qs X B hX . . . Z
Y
X
hY
Y
ogni simbolo sul nastro corrisponde a k (tre nellesempio) simboli in , come rappresentato dalle colonne racchiuse tra parentesi
quadre nella figura. Inoltre, per esempio nel primo elemento della prima colonna in figura, un simbolo in pu`o essere accoppiato
a un simbolo speciale h (sempre lo stesso) a indicare che su quel nastro la testina e` posizionata su quel simbolo. Lo stato corrente
s della macchina multitape viene memorizzato nella control location della macchina singletaple. In questo modo, rappresentiamo
su un solo tape simultaneamente lo stato dei diversi nastri (righe orizzontali nel disegno, che chiameremo tracce (track).
Abbiamo bisogno di codificare in un singolo alfabeto tutte le possibili configurazioni delle celle. Se i simboli in sono n1 allora
abbiamo bisogno di 2n1 simboli per rappresentare celle con simboli in puntati o meno da una testina. Possiamo quindi usare
(un alfabeto che rappresenti) le tuple con k di tali simboli, quindi di cardinalit`a (2 n1 )k .
Le celle dei nastri simulati possono contenere blank (diversi dai blank della macchina che esegue la simulazione). Nella figura,
qs denota la stato corrente della testina della macchina simulatrice (s e` lo stato della macchina simulata) che lavora quindi su un
alfabeto di k-tuple.
Per simulare le operazioni sulle singole celle puntate dalle testine, la macchina pu`o operare analizzando un nastro alla volta.
Prima cerca la posizione della testina nel primo nastro, controlla quale regola applicare e memorizza lazione da compiere nel
suo stato. Poi ripete le stesse operazioni sugli altri nastri. Essendo i nastri k, basta una memoria finita per memorizzare quanti
nastri sono stati gi`a analizzati e quali regole devono essere applicate su ogni nastro. In una seconda fase si visitano di nuovo le
tuple e si applicano le modifiche e gli spostamenti nastro per nastro. La terminazione/accettazione della macchina si pu`o quindi
codificare come terminazione/accettazione della macchina host controllando la control location della multitape. Possiamo inoltre
dimostrare la seguente propriet`a che caratterizza la complessit`a worst-case della simulazione discussa sopra.
Prop. 5.7 La simulazione di m passi di una MT con k-nastri si pu`o effettuare con un numero di passi proporzionale a m2 con
una MT con un solo nastro.
Infatti dopo m passi la distanza massima tra le testine sui diversi nastri pu`o essere al pi`u 2m. Nel caso peggiore ogni singolo
passo di simulazione richiede un numero costante (in k) di scansioni del nastro (ad esempio per cercare la posizione p su una
traccia) ed un numero costante di aggiustamenti di celle e testina (riscrittura della cella corrente e di una sua vicina). Quindi
il costo per m passi e` proporzionale a m2 . Una codifica alternativa consiste nel mantenere sempre tutte le celle puntate dalle
testine allineate sulla stessa verticale. In altre parole invece di spostare le singole testine si fanno scorrere a destra o sinistra di
una posizione tutte le celle dei k-nastri. Questa rappresentazione elimina il problema di dover rappresentare le posizioni delle
singole testine ma richiede un maggior numero di spostamenti.

32

5.5.2

MT non deterministica

Vediamo ora unaltra variante delle MT che ammette il non determinismo. Una MT (con un solo nastro) non deterministica ha le
stesse componenti di un MT deterministica. Tuttavia le mosse possibili sono definite tramite una funzione
: Q (Q {L, R, })
dove ricordiamo che (A) denota linsieme dei sottoinsiemi di A. In altre parole, come gi`a visto per le versioni non deterministiche di automi a stati finiti e automi a pila, un ID pu`o avere diversi possibili successori che corrispondono a diverse possibili
computazioni. Nel caso di una configurazione con pi`u successori, possiamo pensare che un agente esterno scelga in maniera
casuale un successore per proseguire lelaborazione. Ad esempio abbiamo regole come:
wqXv `M wY q 0 v
se hq 0 , Y, Ri (q, X), cio`e scegliamo in maniera casuale una delle mosse possibili nello stato q. Gli altri casi si definiscono in
maniera simile.
In generale quindi a partire da una configurazione iniziale possiamo avere uninsieme di possibili computazioni, cio`e un albero
di computazioni con ampiezza finita ma rami potenzialmente infiniti. Ovviamente occorre ridefinire la nozione di accettazione.
Laccettazione di un input w in una macchina non deterministica richiede lesistenza di almeno una computazione (tra tutte quelle
possibili) su w che termini in uno stato finale.
Def. 5.8 Sia M una MT non deterministica con stato iniziale q0 e stati finali in F . Allora:
L(M ) = {w | .q0 w`?M , state() F }
Le computazioni che rifiutano una stringa sono quelle che a partire da q0 w si bloccano, ossia terminano in uno stato non finale.
Altre computazioni che partono da q0 w possono non terminare. In generale quindi lunione delle computazioni che accettano
con quelle che rifiutano non coincide con linsieme di tutte le computazioni.
Esempio 5.9 Usiamo ancora un formato tabellare per specificare la funzione di transizione di una MT non deterministica per
riconoscere il linguaggio u00 con u {0, 1}? (cio`e stringhe terminate da due 0)

q0
q1
q2

0
1
B
hq0 , 0, Ri, hq1 , 0, Ri hq0 , 1, Ri
hq2 , 0, Ri
hqf , B, i

dove q0 e` lo stato iniziale e qf e` lo stato finale. Questo programma effettua una scelta non deterministica nello stato q0 quando si
legge il simbolo 0: si continua a leggere simboli o si prova a controllare se il simbolo 0 era il primo dei due 0 finali. Il controllo
viene fatto dagli stati q1 e q2 . La scelta non deterministica e` rappresentata da pi`u tuple in una singola cella.
Vediamo ora un esempio di esecuzione accettante della MT sullinput w = 0100.
q0 0100 `M 0q0 100 `M 01q0 00 `M 010q1 0 `M 0100q2 B `M 0100qf B
Esistono tuttavia altre possibili computazioni come per esempio
q0 0100 `M 0q1 100
che si blocca perch`e in q0 abbiamo fatto la scelta sbagliata.
Il non determinismo e` in generale molto utile a rappresentare in maniera compatta soluzioni del tipo generate-and-test a problemi
che richiedono lesplorazione di uno spazio di ricerca molto complesso. Unesempio classico e` lalgoritmo generate-and-test per
risolvere il problema dellesistenza di un ciclo hamiltoniano. La MT non deterministica che lo risolve, data una rappresentazione
del grafo come stringa che rappresenta la lista di nodi e di archi,
generate: genera in maniera non deterministica una permutazione dei nodi per esempio usando un nastro di appoggio.
Per generare una permutazione possiamo in maniera non deterministica selezionare un nodo, cancellarlo e copiarlo nel
secondo nastro, fino a che la lista dei nodi e` stata consumata completamente.
test: controlla che la sequenza sia collegata da archi in modo da formare un ciclo.
Notiamo che una computazione di successo non ha bisogno di esplorare tutto lo spazio di ricerca ma costruisce un solo cammino.
Il non determinismo e` viene quindi usato per costruire un oracolo per generare un possibile ciclo hamiltoniano.
33

Figura 3: Enumerazione delle scelte


5.5.3

Simulazione di una MT non deterministica

Il non determinismo aumenta il potere espressivo delle MT? La risposta e` no. Infatti si pu`o dimostrare che data una MT non
deterministica M che riconosce un linguaggio L possiamo definire una macchina deterministica che riconosce lo stesso linguaggio L. Intuitivamente, occorre costruire una MT deterministica M 0 in grado di in esplorare lalbero delle computazioni di M .
Abbiamo bisogno quindi di
Enumerare le possibili computazioni di M .
Scelta una computazione, simulare M .
Controllare se nella simulazione possiamo raggiungere uno stato di accettazione di M e trasformarlo in uno stato di
accettazione di M 0 .
Notiamo subito un problema. Non tutte le visite dellalbero di computazioni di M risultano adeguate. Per esempio una visita
depth-first di una computazione infinita potrebbe a sua volta non terminare. Usiamo quindi una visita breadth-first dellalbero
delle computazioni. Inoltre dobbiamo rendere la visita deterministica cio`e enumerare in un certo ordine tutti i cammini livello
per livello. Partendo dal primo livello numeriamo i successori di una configurazione in maniera progressiva in base alle possibili
scelte della relazione di transizione come in Figura 3. Le scelte a partire da uno stato q e da un simbolo X sono sempre finite
e quindi si possono codificare con numeri dordine. Un cammino dalla radice (q0 w) a un certo ID e` quindi univocamente
determinato da una sequenza di numeri dordine. Per esempio la sequenza 1.2.1.3 corrisponde alla derivazione dove si sceglie
il primo successore al primo passo, il secondo al secondo passo, il primo al terzo passo, il terzo al quarto passo. Per facilitare
il compito usiamo una MT con tre nastri. Il primo nastro contiene linput w. Il secondo e` un nastro di lavoro. Il terzo contiene
le sequenze che rappresentano cammini che vogliamo simulare. La simulazione ha bisogno quindi di un sottoprogramma che,
dato un livello l, enumera tutte le sequenze di lunghezza l composte da numeri in 1, . . . , max dove max e` il numero massimo di
scelte possibili in una certa configurazione (determinato da ).
Lalgoritmo procede nel seguente modo. Sia l = 0.
(1) Se l = 0 oppure abbiamo esplorato tutte le sequenze a profondit`a l, si incrementa l di uno (cio`e si aumenta di uno la
profondit`a della visita). Altrimenti si genera la prossima sequenza di lunghezza l nel terzo nastro.
(2) Copiamo linput nel secondo nastro.
(3) Simuliamo la macchina M seguendo le scelte specificate in controllando che siano possibili cio`e che per ogni scelta
ci sia una tranzione eseguibile. Poich`e ha una rappresentazione finita applicare una per volta le mosse specificate da
e` sicuramente possibile tramite un algoritmo deterministico. Per ogni nuova configurazione generata (ottenuta modificando la configurazione iniziale nel secondo nastro) controlliamo se lo stato raggiunto e` finale e in tal caso accettiamo e
lalgoritmo termina. Se la simulazione si blocca in uno stato non finale, cancelliamo il nastro e torniamo a (1).
Lalgoritmo accetta w se e solo se esiste una computazione di M che accetta w.

34

5.6

Macchine con nastro semi-infinito

Consideriamo ora un nuovo modello ottenuto come restrizione delle macchine di Turing. In particolare consideriamo una macchina con un nastro semi-infinito (ossia, infinito solo da un lato) e con regole che non sovrascrivono mai simboli con B. La
testina si pu`o ancora muovere avanti e indietro ma non pu`o mai superare il limite sinistro del nastro semi-infinito. Vedremo
in questa sezione che il nuovo modello e` equivalente al modello con nastro infinito. La dimostrazione si basa sulla codifica di
una macchina MT M con simboli in , blank B e stati in Q in una macchina M 0 con nastro semi-infinito. Lidea e` quella di
codificare in due track del nastro semi-infinito due parti di nastro che insieme formano il nastro di M . Usiamo quindi un alfabeto
di simboli


a
con a {B 0 }, b {B 0 } {#}
b
dove # e` un simbolo speciale che identifica lultima cella a sinistra nel nastro semi-infinito e B 0 indica una cella dopo una
cancellazione (non possiamo usare B per sovrascrivere il contenuto di una cella). Una stringa di simboli di M
X1 X2 . . . Xn
pu`o essere rappresentata quindi da una stringa di simboli di M 0 del tipo


 


Xk+1
Xk+2
Xn1
Xn
...
#
Xk
X2
X1
In generale le due tracce potrebbero contenere dei suffissi con simboli B (celle non ancora visitate durante la simulazione).
Completiamo la macchina M 0 utilizzando gli stati Q0 = {q0 } (Q {U, L}). Lo stato hq, U i denota una configurazione dove la
testina e` nello stato q e punta a una cella nella parte di nastro rappresentata dalla track superiore (inferiore) U per upper (L per
lower).
Consideriamo ora la funzione di transizione di M . Possiamo modificare in modo da non usare mai B per sovrascrivere
simboli. Infatti possiamo usare definire 1 in modo da inserire B 0 ogni volta che produce B. Poniamo inoltre 1 (q, B 0 ) =
(q, B).
Vediamo ora come simulare 1 . Innanzitutto inizializziamo stati e nastro con la seguente regola:




X
X
0
(q0 ,
) = hhq0 , U i,
, i
B
#
Se 1 (q, X) = hq 0 , Y, Ri e Z 6= # allora








X
Y
Z
Z
0 (hq, U i,
) = hhq 0 , U i,
, Ri 0 (hq, Li,
) = hhq 0 , Li,
, Li
Z
Z
X
Y
Se 1 (q, X) = hq 0 , Y, Li e Z 6= # allora








X
Y
Z
Z
0 (hq, U i,
) = hhq 0 , U i,
, Li 0 (hq, Li,
) = hhq 0 , Li,
, Ri
Z
Z
X
Y
Se 1 (q, X) = hq 0 , Y, Li allora
0

(hq, U i,

X
#




Y
0
) = hhq , Li,
, Ri
#

In questo caso abbiamo raggiunto la parte finale della track superiore del nastro semi-infinito e ci muoviamo quindi in quella
inferiore cambiando direzione.
Infine, se 1 (q, X) = hq 0 , Y, Ri allora




X
Y
0 (hq, Li,
) = hhq 0 , U i,
, Ri
#
#
In questo caso abbiamo raggiunto la parte finale della track inferiore del nastro semi-infinito e ci muoviamo quindi in quella
superiore cambiando direzione.

35

5.7

Macchine multistack

Consideriamo ora un modello che estende gli automi a pila con la possibilit`a di gestire simultaneamente k stack invece di uno
solo. Per avvicinarci alle MT assumiamo che linput sia memorizzato in uno degli stack e che le transizioni non abbiano etichette
ma lavorino esclusivamente sugli stack. Una macchina multistack M = hQ, , , q0 , Z0 , F i e` definita da un insieme finito di
stati Q, un alfabeto dello stack , una funzione di transizione, uno stato iniziale q0 e un insieme di stati finali F . Tuttavia, la
funzione di transizione in questo caso ha forma15
: Q k (Q (? )k )
Intuitivamente se
(q, X1 , . . . , Xk ) = hq 0 , 1 , . . . , k i
allora se la macchina M si trova nello stato q, il simbolo X1 e` sulla cima del primo stack, X2 sulla cima del secondo, etc. fino a
Xk , allora M toglie X1 , . . . , Xk (ossia, effettua il pop simultaneamente su tutti i k stack) e li sostituisce con 1 , . . . , k (fa push
simultaneamente su tutti gli stack). Una configurazione e` quindi definita come una tupla in
Q . . .
{z
}
|
ktimes

i.e., hq, w1 , . . . , wk i con w1 , . . . , wk . Data una configurazione


c = hq, X1 w1 , . . . , Xk wk i
lapplicazione della funzione di transizione (q, X1 , . . . , Xn ) = hq 0 , 1 , . . . , k i genera il successore
c = hq, 1 w1 , . . . , k wk i
La nozione di computazione e` definita in maniera naturale come sequenza di configurazioni dove a ogni passo si applica per
ottenere uno stato successore. La macchina M accetta un dato input quando raggiunge uno stato di accettazione in F . Possiamo
assumere che ogni stack abbia un terminatore # in modo da poter controllare facilmente quando lo stack e` vuoto (usando regole
definite sul simbolo #).
Teorema 5.10 Per ogni MT M , esiste una Multistack Machine M 0 tale che L(M ) = L(M 0 ).
Per dimostrare il teorema, data una macchina di Turing M = hQ, , , , q0 , F i, costruiamo una Multistack Machine M 0 che
riconosce lo stesso linguaggio di M . La codifica e` simile a quella usata per un nastro semi-infinito. Spezziamo il nastro infinito
in due parti: la parte a sinistra della testina viene memorizzata nel primo stack, la parte rimanente nel secondo stack. Il simbolo
in cima al secondo stack rappresenta la cella puntata dalla testina.
Vediamo ora come modellare attraverso la relazione 0 di M 0 .
Se (q, X) = hq 0 , Y, Ri, allora 0 (q, hZ, Xi) = hq 0 , hY Z, ii per ogni Z.16
Se (q, B) = hq 0 , Y, Ri, allora 0 (q, hZ, #i) = hq 0 , hY Z, #ii per ogni Z.
Se (q, X) = hq 0 , Y, Li, allora 0 (q, hZ, Xi) = hq 0 , h, ZY ii per ogni Z 6= #, e 0 (q, h#, Xi) = hq 0 , h#, BY ii.
Se (q, B) = hq 0 , Y, Li, allora 0 (q, hZ, #i) = hq 0 , h, ZY #ii per ogni Z 6= # e 0 (q, h#, #i) = hq 0 , h#, BY #ii.
Gli stati di accettazione di M 0 sono quelli di M .
Come esercizio proviamo a dimostrare che la codifica e` corretta, cio`e che la macchina M 0 accetta un input w solo se M accetta w.
Innanzitutto definiamo una codifica tra configurazioni. Data w usiamo wR per identificare la stringa rovesciata, es. se w = aabc
allora wR = cbaa. Per semplicit`a assumiamo che M non possa produrre nuovi B. Inoltre consideriamo anche stringhe del tipo
wq (invece di wqB).
Definiamo quindi h(wqv) = hq, hwR #, v#ii.
Per esempio h(XY qZ) = hq, hY X#, Z#ii, h(qZ) = hq, h#, Z#ii, h(Zq) = hq, hZ#, #ii, h(qBZ) = hq, h#, BZ#ii,
h(q) = hq, h#, #ii.
Inoltre definiamo h1 (hq, hw#, v#ii) = wR qv.
Per esempio h1 (hq, hY X#, Z#ii) = XY qZ, h1 (hq, h#, Z#ii) = qZ, h1 (hq, hZ#, #ii) = Zq, ecc.
15 Per
16 Ci

semplificare la prova del Teorema 5.10 non consideriamo transizioni silenti.


serve una regola per ogni simbolo Z perch`e abbiamo assunto di togliere almeno un simbolo da ogni stack.

36

Per dimostrare la correttezza dimostriamo un risultato pi`u forte, cio`e che per ogni computazione di M esiste una computazione
di M 0 ottenuta attraverso h e viceversa per ogni computazione di M 0 esiste una computazione di M ottenuta attraverso h1 .
: Dimostriamo che se 0 1 . . . n e` una computazione di M , h(0 )h(1 ) . . . h(n ) e` una computazione di M 0 . La dimostrazione e` per induzione su n.
Base n = 0: Immediato.
Passo induttivo: Supponiamo che lipotesi valga per n 0 e dimostriamo la tesi per n + 1. Per ipotesi induttiva h(0 ) . . . h(n )
e` una computazione di M 0 . Consideriamo ora una transizione n n+1 . Vogliamo dimostrare che h(n ) ha come successore
h(n+1 ). Ragioniamo per casi su n e .
Sia n = wZqXv
Se (q, X) = hp, Y, Ri, allora n+1 = uqv con u = wZY . Per definizione 0 (q, hZ, Xi) = hp, hY Z, ii. Quindi
h(n ) = hq, hZwR #, Xv#ii ha come successore c0 = hp, hY ZwR #, v#ii ma Y Z(wR ) = (wZY )R = uR .
Quindi c0 = hp, huR #, v#ii = h(n+1 ).
Se (q, X) = hp, Y, Li, allora n+1 = wqu con u = ZY v. Per definizione 0 (q, hZ, Xi) = hp, h, ZY ii. Quindi h(n ) = hq, hZwR #, Xv#ii ha come successore c0 = hp, hwR #, ZY v#ii Quindi c0 = hp, hwR #, u#ii =
h(n+1 ).
Sia n = qXv:
Se (q, X) = hp, Y, Ri, allora n+1 = Y qv. Per definizione 0 (q, h#, Xi) = hp, hY #, ii. Quindi h(n ) =
hq, h#, Xv#ii ha come successore c0 = hp, hY #, v#ii ma Y R = Y . Quindi c0 = h(n+1 ).
Se (q, X) = hp, Y, Li, allora n+1 = qBY u. Per definizione 0 (q, h#, Xi) = hp, h#, BY ii. Quindi h(n ) =
hq, h#, Xv#ii ha come successore c0 = hp, h#, BY v#ii = h(n+1 ).
Sia n = wZq:
Se (q, B) = hp, Y, Ri, allora n+1 = uq con u = wZY . Per definizione 0 (q, hZ, #i) = hp, hY Z, #ii. Quindi
h(n ) = hq, hZwR #, #ii ha come successore c0 = hp, hY ZwR #, #ii ma Y ZwR = uR . Quindi c0 = h(n+1 ).
Se (q, B) = hp, Y, Li, allora n+1 = wqZY . Per definizione 0 (q, hZ, #i) = hp, h, ZY #ii. Quindi h(n ) =
hq, hwZ#, #ii ha come successore c0 = hp, hw#, ZY #ii = h(n+1 ).
Sia n = q.
Se (q, B) = hp, Y, Ri, allora n+1 = Y q. Per definizione 0 (q, h#, #i) = hp, hY #, #ii (istanza della secondo
caso nella def. di 0 istanziando Z con #). Quindi h(n ) = hq, h#, #ii ha come successore c0 = hp, hY R #, #ii =
h(n+1 ).
Se (q, B) = hp, Y, Li, allora n+1 = qBY . Per definizione 0 (q, h#, #i) = hp, h#, BY #ii. Quindi h(n ) =
hq, h#, #ii ha come successore c0 = hp, h#, BY #ii = h(n+1 ).
: Dimostriamo ora che se c0 c1 . . . cn e` una computazione di M 0 , h1 (c0 ) . . . h1 (cn ) e` una computazione di M . La dimostrazione e` per induzione su n.
Base n = 0: Immediato.
Passo induttivo: Supponiamo che lipotesi valga per n 0 e dimostriamo la tesi per n + 1.
Per ipotesi induttiva h1 (c0 )h1 (c1 ) . . . h1 (cn ) e` una computazione di M . Consideriamo ora una transizione cn cn+1 . Vogliamo dimostrare che h1 (cn ) ha come successore h1 (cn+1 ). Ragioniamo per casi su cn e 0 .
Consideriamo uno solo dei possibili casi. Supponiamo che cn = hq, hZw#, Xv#ii. Se 0 (q, hZ, Xi) = hp, hY Z, ii allora
cn+1 = hp, hY Z#, v#ii. Notiamo che, per definizione, 0 deriva da (q, X) = hp, Y, Ri. Quindi h1 (cn ) = wR Zqv ha come
successore 0 = wR ZY pv = h1 (cn+1 ) poich`e wR ZY = (Y Zw)R .
Gli altri casi si ottengono in maniera analoga al precedente.
5.7.1

Osservazioni

Nelle ultime sezioni abbiamo visto una tecnica generale per dimostrare lequivalenza di modelli computazionali. Due modelli
M e M 0 sono equivalenti, rispetto ai linguaggi riconosciuti, se L(M ) = L(M 0 ). Per dimostrare che L(M ) L(M 0 ) (cio`e
M 0 e` almeno espressiva quanto M ) occorre dimostrare che per ogni computazione che accetta una stringa w in M esiste una
computazione che accetta w in M 0 . Esibire una codifica delle configurazioni di M in quelle di M 0 e della funzione di transizione
di M in transizioni in M 0 permette di simulare ogni singolo passo di M in M 0 . Tale codifica da M in M 0 pu`o essere quindi vista
come lusuale compilazione di un linguaggio in unaltro.
37

Altri Modelli

Consideriamo ora una restrizione delle Macchine Multistack ottenuta considerando un alfabeto con un singolo carattere 1 e un
simbolo speciale # usato solo per rappresentare il fondo dello stack (per controllare se uno stack e` vuoto). In altre parole ogni
stack pu`o solo contenere stringe del tipo 1n #. Questo tipo di macchina pu`o essere interpretato come una macchina con uno stato
di controllo (la testina) e k-contatori definiti su numeri naturali. Le transizioni permettono la modifica dello stato di controllo
simultaneamente a operazioni sui contatori quali incremento, decremento e test = 0. Per esempio in un automa a pila possiamo
codificare queste operazioni sul singolo contatore c come segue: (q, #) = hq 0 , #i codifica il test c == 0, (q, X) = hq 0 , 1Xi
per X {1, #} codifica c := c + 1, (q, 1) = hq 0 , i codifica c := c 1.
Chiamiamo il modello risultate Macchina con Contatori (o Minsky Machine da Marvin Minsky). Per semplicit`a usiamo la
notazione hq, q 0 , opi per le istruzioni di questo modello, es. hq, q 0 , c := c + 1i ecc.
Utilizzando lo stato di controllo non e` difficile definire operazioni complesse a partire da quelle di base, quali per esempio la
copia di un contatore in un altro contatore, la somma di due contatori (memorizzata in un terzo) e la loro moltiplicazione o
divisione intera. Ecco alcuni esempi:
Per sommare c a d (o copiare c in d), possiamo usare un contatore ausiliario aux e un ciclo del tipo
hq, q, c := c 1, d := d + 1, aux := aux + 1i, hq, q 0 , c == 0i
e quindi ripristinare c come segue
hq 0 , q 0 , c := c + 1, aux := aux 1i, hq 0 , q 00 , aux == 0i
Partendo dalla configurazione hq, c = N, d = M, aux = 0i otteniamo hq 0 , c = N, d = N + M, aux = 0i. Se M = 0
allora d avr`a lo stesso valore di c.
Per moltiplicare c per d, possiamo usare un contatore ausiliario aux, copiare c in aux, sommare aux a d con un ciclo in
cui si decrementa aux ed incrementa d fino a che aux == 0, quindi decrementare c e ricominciare fino a che c == 0.
Una propriet`a interessante di questo modello e` la seguente.
Teorema 6.1 Le Macchine con 2 stack sono equivalenti a macchine con 3 contatori.
La dimostrazione e` basata su una codifica di macchine con 2 stack attraverso i contatori. Il punto focale e` la rappresentazione del
contenuto X1 . . . Xn dello stack tramite un singolo contatore. Supponiamo che lalfabeto dei simboli contenga r 1 simboli.
Rappresentiamo tali simboli con le cifre da 1 a r 1. Per esempio se simboli sono X, Y, Z possiamo rappresentarli con le cifre
0, 1, 2. Allora la stringa w = X1 . . . Xn pu`o essere rappresentata dalla codifica in base r:
h(w) = Xn rn1 + . . . + X2 r1 + X1
Dato w con h(w) = Xn rn1 + . . . + X2 r1 + X1 , loperazione di pop corrisponde quindi a h(w)/r (divisione per r), i.e.,
Xn rn2 + . . . + X2 . Loperazione di push di Z corrisponde a (h(w) r) + Z, i.e., h(w) = Xn rn + . . . + X2 r2 + X1 r + Z.
Loperazione di update da X1 a Z della cima dello stack corrisponde alla somma di Z X1 ad h(w). Tutte queste operazioni si
possono implementare usando un solo contatore di supporto.
Possiamo ridurre ulteriormente le risorse del modello senza perdere espressivit`a.
Teorema 6.2 Le Macchine con 3 contatori sono equivalenti a macchine con 2 soli contatori.
La dimostrazione si basa nuovamente sulla codifica di macchine a 3 contatori con 2 soli contatori. Il trucco usato in questa
codifica consiste nel rappresentare in un solo contatore il valore corrente c1 , c2 , c3 dei 3 contatori usando il secondo contatore
come supporto. Per fare questo possiamo usare la seguente codifica
h(c1 , c2 , c3 ) = 2c1 3c2 5c3
Questa rappresentazione assicura ununica decomposizione (2, 3, 5 sono numeri primi) che si pu`o usare per simulare le operazioni
sui singoli contatori. Supponiamo di memorizzare h(c1 , c2 , c3 ) nel contatore MC. Come esempio, per incrementare c2 dobbiamo
moltiplicare MC per 3. Per decrementare c2 dobbiamo dividere MC per 3. Per controllare se c2 e` zero controlliamo che MC non
sia divisibile per 3 (se e` divisibile allora non e` zero). Queste operazioni si possono effettuare con un solo contatore di supporto
SC. Per esempio, per moltiplicare MC per tre: decrementiamo MC ed sommiamo 3 a SC fino a che MC e` zero. Poi copiamo SC
in MC (decrementando SC di 1 e incrementando SC di 1 fino a che SC diventa zero). Per controllare se MC e` divisibile per tre:
decrementiamo MC di 3 e sommiamo 3 a SC fino a che MC e` zero. Se M C diventa zero prima prima dellultima sottrazione
allora MC non e` divisibile per 3, altrimenti e` divisibile.
Grazie alla riduzione delle MT in Macchine con 2 stack otteniamo quindi il seguente risultato.
38

Teorema 6.3 Le Macchine di Turing sono equivalenti a Macchine con 2 stack e a Macchine con 2 contatori.
Unaltra osservazione interessante e` che le macchine a contatori senza test per zero sono equivalenti a un modello di calcolo
chiamato Reti di Petri ed utilizzato per rappresentare sistemi concorrenti.

6.1

Macchine di Turing e Computer

Studiamo ora la corrispondenza tra macchine di Turing e computer con architettura Von Neuman (macchina VN per semplicit`a).
Consideriamo innanzitutto il problema di simulare una MT attraverso un programma eseguibile su un computer. Il problema
principale e` la simulazione del nastro infinito, le altre informazioni sono tutte facilmente manipolabili. Per poter gestire un nastro
infinito possiamo pensare di estendere il modello di Von Neuman verso un computer in cui la memoria fisica si pu`o estendere
dinamicamente ad esempio usando la rete (eventualmente aggiungendo una macchina quando serve) oppure comprando nuovi
dischi e collegandoli al computer utilizzato.
La simulazione di una macchina VN attraverso una MT richiede alcuni passaggi. Innanzitutto possiamo usare una macchina
multinastro. Il primo nastro viene usato per rappresentare la memoria ad accesso diretto in forma di lista di coppie
hind1 , val1 i, hind2 , val2 i, . . . , hindk , valk i
codificati come stringa (usando opportuni separatori). Supponiamo che nel programma di partenza sia sufficiente considerare
parole di memoria di c0 bit e d0 indirizzi distinti.
Nella configurazione iniziale il nastro 1 contiene la codifica di istruzioni e dati. Le istruzioni tipiche di una macchina VN sono
operazioni elementari su registri e celle di memoria (incremento, decremento, somma, test) e istruzioni di salto (jump). Possiamo
codificare le istruzioni nuovamente come stringhe separando operatore da operandi (indirizzi/valori). Per semplicit`a assumiamo
che le istruzioni possono solo creare nuovi indirizzi o valori che si possono rappresentare aggiungendo al pi`u un bit rispetto alla
codifica degli operandi (es. permettiamo operazioni come incremento di 1 ma non moltiplicazioni). Assumiamo anche ogni
istruzione generi un numero costante di nuovi valori/indirizzi (es. uno solo). Nel secondo nastro, che simula la program location,
memorizziamo lindirizzo della prossima istruzione da eseguire. Usiamo inoltre altri nastri di supporto per simulare registri e per
manipolare la nostra rappresentazione della memoria. In particolare loperazione pi`u delicata e` laggiornamento del contenuto
del primo nastro quando occorre ampliare la dimensione di un valore o indirizzo. Questa operazione si pu`o fare copiando il
contenuto che segue lindirizzo/valore da aggiornare in un nastro di supporto, modificando poi la rappresentazione (es. usando
un bit in pi`u) e quindi ricopiando dal nastro di supporto la parte rimossa. Usando una tecnica simile potremmo utilizzare sempre
rappresentazioni con lo stesso numero di bit per indirizzi e valori (ogni volta che aggiorniamo un campo, riscriviamo tutto la
stringa).
Unaltra operazione importante e` la fase di lookup per cercare un dato indirizzo (memorizzato sul terzo nastro) nella stringa
che rappresenta la memoria. Questa operazione si implementa facilmente scorrendo il primo nastro in parallelo con il nastro di
supporto (registro) da sinistra a destra (ripartendo con il confronto per ogni indirizzo nel prino nastro).
Con queste due operazioni possiamo simulare il comportamento delle singole istruzioni in maniera naturale. Il costo dominante
e` la gestione del primo nastro che nel caso peggiore richiede lo scorrimento di tutto il suo contenuto corrente. Gli altri passi di
simulazione di unistruzioni possono essere effettuati in tempo polinomiale nel numero di nastri utilizzati. La terminazione della
macchina VN si pu`o rappresentare attraverso il raggiungimento di uno stato di accettazione nella MT: ogni volta che la program
location contiene listruzione HALT la MT si muove in uno stato finale.
Se ora consideriamo n passi di una macchina VN, con le assunzioni fatte sulle istruzioni, notiamo potremo visitare un numero di
celle proporzionale a 2 (d0 + n) (c0 + n) (valori/indirizzi dopo n passi * loro dimensione max) cio`e il nastro avr`a lunghezza
quadratica in n. Poich`e la simulazione di ogni istruzione ha come costo dominante lo scorrimento del primo nastro, la simulazione
di n passi VN richiede nel caso peggiore un numero di passi M T proporzionale a n3 .
Dalla Prop. 5.7 otteniamo quindi la seguente propriet`a.
Prop. 6.4 Esiste una MT con un solo nastro che simula n passi di una macchina VN con un numero di passi proporzionale a n6
(n3 passi multitape; (n3 )2 passi single tape).
Con la precedente analisi abbiamo, informalmente, dimostrato che le MT sono un possibile computer (modello di calcolo) ideale
o almeno equivalente ai modelli che usualmente consideriamo quando sviluppiamo ed eseguiamo algoritmi e programmi17 .

Linguaggi Ricorsivi e Ricorsivamente Enumerabili

Usiamo le MT come formalismo per rappresentare soluzioni algoritmiche a problemi decisionali. Assumiamo di poter codificare
un problema decisionale P come un linguaggio LP su un alfabeto prefissato per esempio = {0, 1}. Per questo passaggio
17 Notiamo che in realt`
a i nostri computer hanno sempre risorse finite e quindi sono assimilabili ad automi finiti. Tuttavia il modello di calcolo alla VN funziona
anche senza upper bound alla memoria.

39

preliminare possiamo pensare di passare attraverso una codifica dellalfabeto 0 in (potenzialmente potremmo usare anche un
singolo simbolo oltre a B). Vediamo qualche esempio.
Consideriamo il problema di decidere se una stringa in A = {0, 1}? ha un numero pari di 1. Il problema decisionale si pu`o
rappresentare direttamente in ? .
Consideriamo ora il problema di decidere se una stringa in A = {a, b}? ha un numero pari di a. Dobbiamo effettuare una
codifica per poter ragionare su . Codifichiamo a come la stringa 0 e b come la stringa 00 usiamo 1 come separatore. La
stringa aba diventa allora 010010. Il problema decisionale si pu`o rappresentare allora come il linguaggio L ? costituito
da tutte le stringhe in ? che rappresentano stringhe di A che hanno un numero pari di a.
Consideriamo ora lappartenenza di una stringa a un linguaggio regolare L fissato definito su un alfabeto . In questo caso
il linguaggio che ci interessa e` formato da tutte le codifiche di coppie u L in ? .
Dato un alfabeto , presi in input sia lautoma A che la stringa u, consideriamo ora lappartenenza di u al linguaggio
generato da A. In questo caso il linguaggio che ci interessa e` formato da tutte le codifiche in ? di coppie A, u tale che
u L(A).
In tutti i casi precedenti la MT a cui siamo interessati deve accettare le stringhe del linguaggio che rappresenta le istanze positive
del problema. Stiamo considerando quindi MT che calcolano funzioni (anche parziali) ? dove = {0, 1}.
Linput viene rappresentato come il contenuto iniziale del nastro, loutput come il contenuto del nastro quando la macchina
raggiunge uno stato finale in F . Linsieme delle funzioni che si possono calcolare tramite una MT (non necessariamente con
computazioni tutte finite) vengono chiamate funzioni calcolabili. Tramite opportune codifiche possiamo codificare su ?
funzioni sia unarie che ennarie su un qualsiasi alfabeto finito.
Vediamo ora la definizione di linguaggio decidibile e semi-decidibile.
Def. 7.1 Un linguaggio L ? viene detto ricorsivo o decidibile se esiste una MT M tale che, per ogni stringa w ? , la
computazione di M su w termina e restituisce 1 se e solo se w L.
Def. 7.2 Un problema decisionale P si dice decidibile se il corrispondente linguaggio LP e` ricorsivo.
In altre parole un problema e` decidibile se esiste una MT (un algoritmo) che termina sempre fornendo la risposta corretta.
Def. 7.3 Un linguaggio L ? viene detto ricorsivamente enumerabile o semi-decidibile se esiste una MT M tale che, per
ogni stringa in input, la computazione di M su w termina e restituisce 1 se w L, mentre potrebbe sia terminare con 0 sia non
terminare se w 6 L.
Def. 7.4 Un problema decisionale P si dice semi-decidibile se il corrispondente linguaggio LP e` ricorsivamente enumerabile.
In altre parole un problema e` semi-decidibile se esiste una MT (un algoritmo) che termina fornendo la risposta corretta su istanze
positive, ma che potrebbe dare risposta negativa o non terminare su istanze negative.
Usiamo R per indicare la classe dei linguaggi ricorsivi in ? e RE per la classe dei linguaggi ric. enumerabili in ? . Allora
abbiamo che
R RE
Infatti dato L R la MT M che termina sempre e accetta solo stringhe in L soddisfa anche le condizioni dei linguaggi semidecidibili. Anzi si potrebbe facilmente trasformare in una nuova MT che non termina sse M termina con 0. Basta aggiungere
allultimo stato dopo la stampa di 0 un sottoprogramma che semplicemente cicla per sempre.
In realt`a come accennato nellintroduzione le due classi sono distinte, cio`e R RE. La dimostrazione richiede la definizione di
macchina universale e di alcune convenzioni sulla codifica delle macchine.

7.1

Macchine come Stringhe

Abbiamo parlato nella sezione precedente di MT che interpretano instanze specifiche di varianti come macchine multinatro.
Unaltra classe interessante di MT sono le macchine in grado di prendere in input un programma e interpretarlo. In particolare
possiamo focalizzarci su macchine che fungono da interpreti di altre MT, cio`e che prendono in input una codifica di una MT M
come stringa wM e una stringa di input per M ed eseguono M su w. Questa idea si pu`o applicare in maniera generale scegliendo
un modo uniforme di codificare sullo stesso alfabeto una qualsiasi MT. La cosa e` possibile. Infatti possiamo pensare di avere
a disposizione un alfabeto infinito di simboli S = {s1 , s1 . . .} dal quale scegliere i sottoinsiemi finiti e Q che servono per
codificare simboli e macchina di una certa macchina M . Notiamo infatti che il funzionamento della macchina indipendente
dal particolare set di simboli e stati. In altre parole ragionando modulo isomorfismo di alfabeti possiamo lavorare sempre con
40

stati e simboli numerati 0, 1, . . .. Sulla base di questa assunzione possiamo pensare a una codifica universale di una qualsiasi
MT come stringa sullalfabeto {0, 1}. Codifichiamo il numero dordine di stati e simboli (che possiamo assumere siano tutti
distinti) in unario usando stringhe di 0. Possiamo fare la stessa cosa per codificare le direzioni L, R. Rappresentiamo allora una
singola transizione come la sequenza dei numeri dordine sei corrispondenti elementi separati da 1. Per esempio, se codifichiamo
L ed R con 0 e 00, q0 e q1 con 000 e 0000, B, X e Y con 00000, 000000 e 0000000, allora possiamo rappresentare la regola
r = hq0 , X, q1 , Y, Ri con la stringa wr = 00010000001000010000000100. La funzione di transizione si pu`o quindi codificare
come la concatenazione delle stringhe che rappresentano le regole separate dal separatore 11, i.e., w = wr1 11wr2 . . . 11wrn per
e` composta da n quintuple. Possiamo rendere univoca la codifica di mantenendo ordinate in maniera lessicografica le stringhe
wr1 , . . . , wrn Una stringa in input u per la macchina M avr`a una codifica simile, cio`e sar`a una stringa wu composta di codifiche
di caratteri separate da 1. Useremo infine il separatore 111 per distinguere dallinput u, i.e., la stringa wM = w 111wu su
= {0, 1} determina univocamente la macchina M se per esempio assumiamo che lo stato finale sia unico e coincida sempre
con la stesso codice (per esempio 0000) in tutte le MT.
Se siamo convinti che questa codifica ci permetta di rappresentare una qualsiasi MT M su {0, 1}? possiamo anche pensare di
ordinare le rappresentazioni delle macchine ordinando le corrispondenti stringhe binarie secondo la loro rappresentazione come
naturali. In altre parole tutte le possibili macchine di Turing formano un insieme infinito ma numerabile rappresentato dalle
stringhe w0 w1 . . . La macchina Mi e` associata quindi alla stringa wi .
La MT che intepreta altre macchine dovr`a essere in grado di prendere in input quindi una stringa wi e un input u. Prima
di ragionare su questo aspetto, sfruttiamo la codifica con stringhe su {0, 1} per definire un linguaggio molto particolare, il
linguaggio di diagonalizzazione Ld .

7.2

Linguaggio di Diagonalizzazione

Consideriamo macchine di Turing che lavorano sullalfabeto = {0, 1} e quindi accettano linguaggi definiti su tale alfabeto. Consideriamo inoltre la numerazione delle codifica w1 , w2 , . . . con stringe su delle MT M1 , M2 , . . .. Definiamo ora il
linguaggio formato dalle stringhe hwi , wj i tale che la macchina Mi riconosce linput wj (cio`e termina su wj con uno stato di
accettazione) rappresentato dalle coppie con 1 nelle entry della seguente tabella infinita:
w0
w1
w2
...

w0
0
0
1
...

w1
1
1
0
...

w2
1
1
1
...

...
...
...
...
...

Consideriamo ora la diagonale della tabella. Rappresenta le coppie di stringhe hwi , wi i associate a MT Mi che riconoscono la
loro stessa rappresentazione wi (cio`e Mi con input wi termina in uno stato di accettazione). Complementiamo ora il linguaggio
sulla diagonale e definiamo quindi Ld :
Def. 7.5 Ld e` linsieme di stringhe wi tale che Mi non riconosce la sua stessa rappresentazione wi (cio`e hwi i Ld se Mi con
input wi si blocca o non termina).
Possiamo ora provare che Ld non e` ricorsivo.
Teorema 7.6 Ld 6 RE (non e` ricorsivamente enumerabile).
Prova Per assurdo supponiamo che Ld RE, cio`e che esista una MT Md tale che per ogni w {0, 1}? Md termina con 1 se
w Ld . Nella nostra codifica delle macchine, esiste allora una stringa wi che codifica Md . Consideriamo allora la stringa wi .
Per ipotesi Md = Mi . Se wi Ld allora Mi riconosce wi ma per definizione wi Ld sse Mi non riconosce wi . Se wi 6 Ld
allora Mi non riconosce wi ma per definizione wi 6 Ld sse Mi riconosce wi . E quindi abbiamo una contraddizione. Possiamo
anche dimostrare la propriet`a notando che Ld non pu`o coincidere con nessuna riga della tabella vista sopra.
Cerchiamo ora di capire come dimostrare linclusione stretta tra R e RE.

7.3

Macchina e Linguaggio Universale

Consideriamo macchine di Turing che lavorano sullalfabeto = {0, 1} e quindi accettano linguaggi definiti su tale alfabeto.
Consideriamo inoltre la numerazione delle codifica w1 , w2 , . . . con stringe su delle MT M1 , M2 , . . .. Definiamo allora il
Linguaggio Universale LU come
LU = {u |u = wi 111w, w L(Mi )}
cio`e linsieme di stringhe che rappresentano codifiche di coppie hM, wi tale che M riconosce w. Definiamo ora una macchina
in grado di riconoscere LU .
41

Teorema 7.7 Esiste una macchina MU , la macchina universale, che riconosce LU .


Prova Consideriamo una Macchina M con 3 nastri. M prende in input la codifica wi 111w di Mi e wi . Come primo passo copia
linput w sul secondo nastro e lo stato iniziale sul terzo. Usa quindi il secondo nastro per simulare levoluzione del nastro di Mi
(cio`e la sequenza di ID generati da una computazione) e il terzo per memorizzare lo stato corrente di Mi . Pelultimo punto non
possiamo usare la control location perch`e dovrebbe memorizzare un numero infinito di possibili stati (quelli di tutte le possibili
MT). La simulazione di ogni singolo stato e` basata sulla ricerca di una regola che fa match con lo stato corrente e il simbolo
corrente il matching si pu`o definire scorrendo in parallelo le sequenze di 0 delle codifiche di stati e simboli sui diversi nastri.
Una volta applicata una regola possiamo aggiungere un nuovo ID nel secondo nastro copiando il precedente e modificando solo i
simboli coinvolti dalla regola. MU e` ottenuta come codifica deterministica e con un solo nastro di M . MU e` chiamata Macchina
di Turing universale. Dal teorema precedente abbiamo il seguente corollario.
Corollary 7.8 LU RE, i.e., e` ricorsivamente enumerabile.
Mostriamo ora che LU non e` ricorsivo.
Notiamo prima che la seguente propriet`a vale per i linguaggi ricorsivamente enumerabili.
Lemma 7.9 Dato L sia L = \L. L RE e L RE sse L R.
Prova Proviamo che se L RE e L RE, allora L R. Consideriamo le MT M1 che riconosce L e M2 che riconosce L.
Costruiamo una macchina M con due nastri che esegue in parallelo M1 e M2 prendendo come control location le coppie di
control location delle due macchine di partenza e simulando su ogni nastro i passi corrispondenti a partire dallo stesso input.
Allora possiamo fare in modo che la macchina M risponda si quando M1 termina in uno stato di accettazione e no quando
M2 termina in uno stato di accettazione. Dobbiamo semplicemente riconoscere le corrispondenti control location durante la
simulazione parallela di M1 ed M2 . Allora M e` una MT che termina sempre con si se w L e con no se w 6 L. Quindi L e`
ricorsivo.
Per limplicazione contraria basta notare che se L R allora possiamo costruire una MT che riconosce L semplicemente
complementando loutput della MT che accetta L. Allora abbiamo il seguente risultato.
Teorema 7.10 LU 6 R.
Prova Supponiamo che LU sia ricorsivo. Costruiamo M 0 che prende in input wi costruisce la stringa wi 111wi e la passa alla
macchina MU . Il linguaggio costituito da codifiche di coppie hMi , wi i sarebbe quindi ricorsivo. Cio`e sia Ld che Ld sarebbero
ricorsivamente enumerabili in contraddizione con il fatto che Ld 6 RE. Quindi abbiamo dimostrato che R RE, Ld 6 RE e
LU RE \ R.

7.4

Riduzioni tra Problemi

Consideriamo ora due problemi decisionali (linguaggi) P1 e P2 . Il problema P1 si riduce al problema P2 (P1 P2 ) se esiste un
algoritmo che data una soluzione per P2 restituisce una soluzione per P1 .
Le riduzioni usano un algoritmo di codifica da istanze di P1 in istanze di P2 in modo che se esiste un algoritmo di (semi)decisione
per P2 possiamo comporlo con lalgoritmo di codifica (ed eventualmente altri sottoprogrammi) per ottenere un algoritmo di
(semi)decisione per P1 . Quindi se P1 P2 allora P2 e` difficile almeno quanto P1 .
Lesistenza di una riduzione da P1 a P2 permette di provare lindecidibilit`a di P2 a partire dallindecidibilit`a di P1 . Infatti, se per
assurdo, esistesse un algoritmo di decisione per P2 allora attraverso la costruzione basata sullalgoritmo di codifica menzionato
sopra avremmo un algoritmo di decisione anche per P1 .
Vediamo alcuni esempi di dimostrazione di indecidibilit`a basate su riduzione tra problemi. Per semplificare la presentazione
useremo M e w per rappresentare la codifica della macchina M e dellinput w come stringhe su {0, 1} come nelle sezioni
precedenti e hM, wi per rappresentare la stringa M 111w (ottenuta concatenando le due sottostringhe).
7.4.1

LU LH

Definiamo il linguaggio LH che caratterizza il problema della terminazione (Halting Problem) per le macchine di Turing.
NellHalting Problem, data una MT (deterministica) M e un input w ci chiediamo se M termina con input w. Formalmente,
LH = {hM, wi |M termina sull0 input w}
Notiamo la differenza con LU : hM, wi LU se M termina con input w in uno stato di accettazione.
Dimostriamo ora che LH e` indecidibile usando una riduzione da LU . Per assurdo, supponiamo che LH sia ricorsivo e sia
accettato da una MT MH . Possiamo vedere MH come un decisore DH per LH : DH (M, w) = 1 se M termina su w, = 0
altrimenti. Usiamo quindi DH come sottoprocedura (oracolo) per costruire un decisore (una MT che termina sempre) DU per
LU . Fissiamo unistanza di LU definita da M e w. Come primo passo DU invoca DH (M, w)
42

Se DH (M, w) = 0, allora anche DU restituisce 0 (se M non termina su w, sicuramente M , essendo deterministica, non
pu`o accettare w).
Se DH (M, w) = 1, allora sappiamo che M con input w termina sicuramente in un numero finito di passi. Possiamo quindi
usare MU (la MT universale) per simulare M su w con garanzia di terminazione. Quando la simulazione termina controlliamo lo stato raggiunto da MU . Se lo stato raggiunto rappresenta uno stato finale per M , DU restituisce 1. Altrimenti DU
restituisce 0.
Abbiamo ottenuto quindi una contraddizione. Infatti LU non e` ricorsivo e quindi non pu`o esistere DU . Quindi DH non pu`o
esistere, cio`e LH non e` ricorsivo (lHalting Problem e` indecidibile).
Nota: Notate che nella costruzione di DU usiamo MU . Sono tuttavia due macchine diverse MU e` la macchina che abbiamo
usato per mostrare che LU e` ric. enumerabile (MU e` quindi un semi-decisore per LU ). DU invece e` lalgoritmo che cerchiamo
di costruire usando DH e MU come sottoprocedure.
7.4.2

LU LE

Definiamo il linguaggio LE che caratterizza le macchine di Turing che riconoscono il linguaggio vuoto. Nellemptiness problem,
data una MT (deterministica) M ci chiediamo se M non riconosce nessun input.
LE = {M |L(M ) = }
Dimostriamo ora che LE e` indecidibile usando una riduzione da LU . Per assurdo, supponiamo che LE sia ricorsivo e sia accettato
da una MT ME . Possiamo vedere ME come un decisore DE per LE : DE (M ) = 1 se L(M ) = , = 0 altrimenti. Usiamo quindi
DE come sottoprocedura (oracolo) per costruire un decisore (una MT che termina sempre) DU per LU . Fissiamo unistanza di
LU definita da M e w. Come primo passo DU deve produrre un possibile input, una MT M 0 , che sia usabile con DE per decidere
LU . Il goal e` mettere in relazione il linguaggio riconosciuto da M 0 con il riconoscimento di w da parte di M . In particolare
L(M 0 ) 6= sse M riconosce w. Costruiamo la MT M 0 come segue. Dato un qualsiasi input x, definiamo delle regole per
cancellare x dal nastro e scrivere al suo posto M e w. Usiamo quindi le regole della MT MU per simulare M su w. Avendo a
disposizione le regole per MU , la macchina M 0 si pu`o costruire in maniera effettiva a partire da M e w (aggiungendo le regole
per cancellare x e scrivere M e w sul nastro). Inoltre M 0 restituisce 1 sse M accetta w. Per costruzione quindi L(M 0 ) = se
M riconosce w e = se M non riconosce w (rifiuta o non termina).
Dati M e w, DU costruisce quindi M 0 e la passa in input a DE . Se DE (M 0 ) = 1 (L(M 0 ) = ) allora DU restituisce 0. Se
DE (M 0 ) = 0 (L(M 0 ) 6= ) allora DU restituisce 1.
Abbiamo ottenuto quindi una contraddizione. Infatti LU non e` ricorsivo e quindi non pu`o esistere DU . Quindi a sua volta DE
non pu`o esistere, cio`e LH non e` ricorsivo (lHalting Problem e` indecidibile).
Nota: Notate che dobbiamo solo mostrare di poter costruire M 0 in maniera effettiva (cio`e poter definire le regole di M 0 ) mentre
non ci serve simulare M 0 . Una volta costruite le regole per M 0 lasciamo a DE il compito di capire che linguaggio genera M 0 .
Tuttavia DE e` unoracolo di cui ci interessa solo la risposta (anche perch`e la dimostrazione e` per assurdo e quindi non pu`o
esistere DE ).
7.4.3

LU LN E

Definiamo il linguaggio LN E che caratterizza le macchine di Turing che riconoscono un linguaggio non vuoto. Data una MT
(deterministica) M ci chiediamo quindi se M riconosce almeno un input.
LN E = {M | L(M ) 6= }
Possiamo modificare la dimostrazione di indecidibilit`a per LE per dimostrare che anche LN E e` indecidibile. Basta infatti
invocare DE ed invertire loutput.
Notiamo anche che LN E e` ricorsivamente enumerabile. Infatti, data M possiamo enumerare tutti i possibili input e per ognuno
di essi simulare M su w usando la MT MU . Se M riconosce almeno un input prima o poi il procedimento termina e quindi
fornisce una procedura di semi-decisione.
Da questo segue che LE non solo non e` ricorsivo ma neppure ricorsivamente enumerabile.
7.4.4

LU LR

Definiamo il linguaggio LR che caratterizza le macchine di Turing che riconoscono un linguaggio regolare. Data una MT
(deterministica) M ci chiediamo quindi se L(M ) e` regolare.
LR = {M | L(M ) regolare}
43

Dimostriamo ora che LR e` indecidibile usando una riduzione da LU . Per assurdo, supponiamo che LR sia ricorsivo e abbia un
decisore DR : DR (M ) = 1 se L(M ) e` regolare, = 0 altrimenti. Usiamo quindi DR come sottoprocedura (oracolo) per costruire
un decisore (una MT che termina sempre) DU per LU . Fissiamo unistanza di LU definita da M e w. Come primo passo DU
deve produrre un possibile input, una MT M 0 , che sia usabile con DR per decidere LU . Il goal e` mettere in relazione il linguaggio
riconosciuto da M 0 con il riconoscimento di w da parte di M . In particolare L(M 0 ) deve essere regolare sse M riconosce w.
Costruiamo la MT M 0 come segue. Scegliamo un linguaggio non regolare L0 = {0n 1n |n 0}. Ovviamente possiamo costruire
una MT che accetta L0 . Definiamo quindi le regole che per un input x controllano se x L0 , restituendo 1 in caso positivo. In
caso negativo (x 6 L0 ) aggiungiamo delle regole per resettare il nastro e scrivere su di esso il nuovo input M e w. Usiamo quindi
le regole della MT MU per simulare M su w in modo che M 0 restituisca 1 sse M riconosce w.
Per costruzione quindi L(M 0 ) = se M riconosce w (infatti M 0 riconosce in questo caso sia x L0 che x 6 L0 ) mentre
L(M ) = L0 se M non riconosce w (rifiuta o non termina).
Dati M e w, DU costruisce quindi M 0 e lo passa a DR . Se DR (M 0 ) = 1 (L(M 0 ) e` regolare) allora DU restituisce 1. Se
DR (M 0 ) = 0 (L(M 0 ) = L0 non regolare) allora DU restituisce 0.
Abbiamo ottenuto quindi una contraddizione. Infatti LU non e` ricorsivo e quindi non pu`o esistere DU . Quindi a sua volta DR
non pu`o esistere, cio`e LR non e` ricorsivo.
7.4.5

LU Lk

Definiamo il linguaggio Lk che caratterizza le macchine di Turing che riconoscono linguaggi di cardinalit`a k per un certo k 0.
Data una MT (deterministica) M ci chiediamo quindi se L(M ) ha esattamente k elementi.
Lk = {M | |L(M )| = k}
Dimostriamo ora che Lk e` indecidibile usando una riduzione da LU . Per assurdo, supponiamo che Lk sia ricorsivo e abbia un
decisore Dk : Dk (M ) = 1 se |L(M )| = k, = 0 altrimenti. Usiamo quindi Dk come sottoprocedura (oracolo) per costruire un
decisore (una MT che termina sempre) DU per LU . Fissiamo unistanza di LU definita da M e w. Scegliamo un linguaggio
L0 qualsiasi con cardinalit`a k. Ovviamente possiamo costruire una MT che accetta L0 . Costruiamo una macchina M 0 tale che
L(M 0 ) = L0 sse M non accetta w. Definiamo quindi le regole che per un input x controllano se x L0 , restituendo 1 in caso
positivo. In caso negativo (x 6 L0 ) aggiungiamo delle regole per resettare il nastro e scrivere su di esso il nuovo input M e w.
Usiamo quindi le regole della MT MU per simulare M su w in modo che M 0 restituisca 1 sse M riconosce w.
Per costruzione quindi L(M 0 ) = se M riconosce w (infatti M 0 riconosce in questo caso sia x L0 che x 6 L0 ) mentre
L(M ) = L0 se M non riconosce w (rifiuta o non termina).
Dati M e w, DU costruisce quindi M 0 e lo passa a Dk . Se Dk (M 0 ) = 1 (L(M 0 ) = ) allora DU restituisce 1. Se Dk (M 0 ) = 0
(L(M 0 ) = L1 ) allora DU restituisce 0.
Abbiamo ottenuto quindi una contraddizione. Infatti LU non e` ricorsivo e quindi non pu`o esistere DU . Quindi a sua volta Dk
non pu`o esistere, cio`e Lk non e` ricorsivo per qualsiasi k ed in particolare per k = 1.

7.5

Teorema di Rice

Vediamo ora come generalizzare tutte le riduzioni viste in precedenza per problemi definiti su macchine di Turing. Consideriamo
un linguaggio L costituito da macchine di Turing che soddisfano una certa propriet`a P , i.e., L = {M | P (M ) = vero}, ad es.
P (M ) potrebbe essere L(M ) = . Assumiamo che se L(M ) = L(M 0 ) allora M, M 0 L.
Teorema 7.11 Ogni linguaggio L non banale, cio`e che non sia vuoto o che non contenga tutte le possibili (codifiche) di MT, non
e` ricorsivo (`e indecidibile).
Prova Dimostriamo che L e` indecidibile usando una riduzione da LU . Assumiamo inizialmente che L non contenga macchine
M 0 con L(M 0 ) = . Toglieremo questa ipotesi successivamente.
Per assurdo, supponiamo che L sia ricorsivo e sia accettato da un decisore D t.c. D(M ) = 1 se M L (e L(M ) 6= ), = 0
altrimenti. Usiamo quindi D come sottoprocedura (oracolo) per costruire un decisore (una MT che termina sempre) DU per LU .
Fissiamo unistanza di LU definita da M e w. Come primo passo DU deve produrre un possibile input, una MT M 0 , che sia
usabile con D per decidere LU . Costruiamo la MT M 0 come segue. Poich`e L 6= , possiamo scegliere una (codifica) di macchina
N L. Dato un qualsiasi input x, usiamo le regole della MT MU per simulare N su x in modo che M 0 proceda con lesecuzione
sse N accetta x. Se N accetta x allora usiamo le regole della MT MU per simulare M su w in modo che M 0 restituisca 1 sse M
accetta w. Per costruzione quindi L(M 0 ) = L(N ) (quindi M 0 L) se M riconosce w e L(M 0 ) = (quindi M 0 6 L) se M non
riconosce w (rifiuta o non termina). Dati M e w, DU costruisce quindi M 0 e la passa in input a D. Se D(M 0 ) = 1 allora DU
restituisce 1. Se D(M 0 ) = 0 allora DU restituisce 0.
Abbiamo ottenuto quindi una contraddizione. Infatti LU non e` ricorsivo e quindi non pu`o esistere DU . Quindi a sua volta D non
pu`o esistere cio`e L non e` ricorsivo.
44

Per eliminare lassunzione che L non possa contenere le MT M tali che L(M ) = , possiamo considerare il complemento di L,
L, e modificare la dimostrazione precedente per mostrare che non e` ricorsivo. Da questo otteniamo che anche L non e` ricorsivo.
Il Teorema di Rice ha immediata applicazione per dimostrare lindecidibilit`a di linguaggi come LH , LR , ed Lk . Infatti per
ognuno di essi esistono esempi di macchine che stanno nel linguaggio come esempi di macchine che non ci stanno (sono insiemi
non banali di macchine di Turing). Altri esempi di problemi indecidibili sono quindi:
Decidere se una MT M con input w non termina
Decidere se una MT M con input w pu`o scrivere un certo simbolo sul nastro
Decidere se una MT M con input w pu`o eseguire una certa istruzione un certo numero di volte
Notiamo invece che propriet`a legate al codice e non al linguaggio riconosciuto di una MT quali ad es. decidere se una MT ha
k stati possono essere decise ispezionando la definizione della macchina stessa (senza necessit`a di esecuzione). Le propriet`a
comportamentali tipo decidere se sullinput 010 la macchina non va mai a sinistra possono talvolta essere decidibili tramite ad
es. simulazioni controllate che necessitano di un numero finito di passi.

7.6

Altri esempi

Consideriamo il linguaggio
Lm = {M | L(M ) = }
Dal Teorema di Rice sappiamo che Lm non e` ricorsivo. Per costruire una riduzione di LU a Lm , assumiamo che Lm sia ricorsivo
e usiamo il suo decisore Dm per decidere LU . Data una coppia M, w (istanza di LU ) definiamo (con un algoritmo che genera
la sua definizione, cio`e stati, alfabeto e lista di regole) una MT M 0 che ingloba le regole di una codifica di MU (macchina
universale) e data in input una stringa qualsiasi x la cancella dal nastro e al suo posto scrive M e w (le loro codifiche) e poi passa
il controllo ad MU . M 0 accetta se MU accetta (cio`e lo statp finale di MU e` finale per M 0 ). Allora L(M 0 ) = sse M riconosce
w. Notiamo che non dobbiamo eseguire M 0 ma solo definire un algoritmo che scrive in output le sue regole. Possiamo quindi
costruire un ipotetico algoritmo per LU : prendiamo M, w in input, generiamo M 0 , invochiamo loracolo Dm . Se Dm (M 0 ) dice
si allora accettiamo, altrimento rifiutiamo. Quindi se Lm fosse ricorsivo allora LU sarebbe ricorsivo.
Lm non e` neppure ricorsivamente enumerabile. Intuitivamente data una MT M per potere dire si dovremmo enumerare tutti
gli input w e per ognuno controllare se M accetta w. Per dimostrare questa propriet`a, possiamo considerare macchine che
accettano o divergono. Il problema della terminazione su ogni input ALLH si riduce ad Lm (basta rendere ogni stato di possibile
terminazione uno stato finale). ALLH non e` ricors. enumerabile e quindi anche Lm non e` ricorsivamente enumerabile. La
dimostrazione che ALLH non e` ric. enumerabile si pu`o fare studiando problemi di (non)terminazione per MT con input vuoto.
In particolare la terminazione di una macchina su input vuoto si riduce al complemento di ALLH (non terminazione su qualche
input). Da questo segue che la non terminazione di una macchina su input vuoto si riduce a ALLH. La non terminazione e` un
problema non e` ric. enumerabile (infatti la terminazione su input vuoto e` semidecidibile ma non decidibile).
In sintesi sia Lm che il suo complemento NON sono ric. enumerabili (esattamente come per il linguaggio
Lt = {M |M termina su tutti input}

Post Correspondence Problem

Vediamo ora un esempio di problema indecidibile formulato su insiemi di stringhe invece che su macchine di Turing. Il Post
Correspondence Problem (PCP) e` definito come segue.
Sia un alfabeto finito e hw1 , u1 i, . . . , hwn , un i uninsieme di coppie di stringhe su , i.e. wi , ui for i : 1, . . . , k.
Una soluzione di PCP e` una qualsiasi sequenza di indici (anche ripetuti) i1 , . . . , im con m > 0 e ij {1, . . . , n} tale che
wi1 . . . wim = ui1 . . . uim
Una variante, MPCP, equivalente a PCP e` definita richiedendo che una soluzione abbia come prima coppia sempre quella con
indice 1: Una soluzione di MPCP e` una qualsiasi sequenza di indici (anche ripetuti) i1 , . . . , im con ij {1, . . . , n} e m 0 tale
che
w1 wi1 . . . wim = u1 ui1 . . . uim
PCP e MPCP sono problemi indecidibili. Una possibile dimostrazione si basa su una riduzione di LU a MPCP. Lidea e` la
seguente. Data una macchina M = hQ, , , , q0 , B, F i e un input w definiamo unistanza di MPCP che ha una soluzione sse M
45

riconosce w. Listanza di MPCP associata a M e w costruisce una possibile esecuzione di M su w attraverso uninsieme di coppie
che usano le stringe wi come precondizione per lapplicazione di e le stringhe ui per generare la configurazione successiva. Le
configurazioni sono separate da un simbolo speciale # che non sta in . La prima coppia e` formata da h#, #q0 w#i. Inoltre per
ogni X {#} definiamo una coppia {X, X} che viene usata per completare le configurazioni. Le coppie associate a sono
definite come segue:
se (q, X) = hp, Y, Ri defiamo la coppia hqX, Y pi;
se (q, B) = hp, Y, Ri defiamo la coppia hq#, Y p#i;
se (q, X) = hp, Y, Li, definiamo la coppia h#qX, #pBY i ed inoltre per ogni Z definiamo la coppia hZqX, pZY i.
Quando applicate a partire dalla prima coppia, le coppie associate a (insieme a quelle che copiano i simboli) simulano i singoli
passi di M estendendo la stringa definita dalla concatenazione delle seconde componenti delle coppie con la nuova configurazione
come nellesempio che segue:
#
#q0 w#
#q0 w#Xq1 v#
#q0 w# #q0 w#Xq1 v #q0 w#Xq1 v#XZq2 u
Definiamo infine delle coppie che servono a gestire il riconoscimento dello stato finale (supponiamo sia unico qF ) in maniera
da chiudere la costruzione facendo coincidere le stringhe costruite con le due componenti. hZqF X, qF i, hqF X, qF i, hZqF , qF i
e hqF ##, #i. Ad esempio possiamo usare le precedenti coppie per consumare il nastro quando lo stato e` finale in maniera da
ottenere due stringhe della stessa lunghezza come segue:
#
#ZqF XY

#ZqF XY #
#ZqF XY #qF Y #
#ZqF XY #qF Y # #ZqF XY #qF Y #qF #

#ZqF XY #qF Y #qF ##


#ZqF XY #qF Y #qF ##

Si pu`o dimostrare che il problema MPCP risultante ha una soluzione sse M riconosce w. Quindi MPCP (e PCP) sono problemi
indecidibili.

8.1

PCP e Context-Free Languages

Possiamo usare PCP per dimostrare che alcune propriet`a dei linguaggi CF sono indecidibili. Consideriamo ad esempio il problema dellambiguit`a: data una CFG G vogliamo decidere se e` ambigua cio`e se esiste w derivabile da S in due maniere diverse.
Possiamo ridurre PCP a questo problema in maniera abbastanza naturale. Consideriamo unistanza hw1 , u1 i, . . . , hwn , un i di
PCP. Definiamo la grammatica CF con produzioni
A ::= wi Aai | wi ai
e la grammatica CF con produzioni
B ::= ui Bai | ui ai
per ogni indice i : 1, . . . , n. Aggiungiamo la produzione S ::= A|B. Allora se S ha due derivazioni per la stessa stringa w tale
stringa deve avere la forma wi1 . . . wim aim . . . ai1 = ui1 . . . uim aim . . . ai1 , cio`e wi1 . . . wim = ui1 . . . uim e le due
stringhe sono state generate usando le coppie nello stesso ordine i1 , . . . , im . Quindi il problema dellambiguit`a e` indecidibile per
le grammatiche CF.
Usando nuovamente le grammatiche A e B possiamo dimostrare che il test di emptiness (o non emptiness) dellintersezione di
due linguaggi CF e` indecidibile. La stessa cosa vale per il test di equivalenza dei linguaggi generati da due grammatiche CF e
per lequivalenza tra una grammatica CF e un linguaggio regolare.
La dimostrazione che L(G1 ) = L(G2 ) e` indecibile si basa sui seguenti punti. Nella riduzione di PCP allambiguit`a di
grammatiche CF abbiamo usato la grammatica GA con produzioni
A ::= wi Aai | wi ai
e la grammatica GB con produzioni
B ::= ui Bai | ui ai
per ogni indice i : 1, . . . , n. Allora L(GA ) L(GB ) 6= sse la corrispondente istanza di PCP ha una soluzione Non potendo
costruire lautoma intersezione possiamo ragionare sul complemento. Losservazione importante e` che il complemento di L(GA )
(e GB ) e` ancora CF. Intuitivamente lidea per accettare L(GA ) = \ L(GA ) e` quella di leggere linput e mettere sulla pila la
parte senza simboli ai . Se non ci sono simboli ai si rifiuta la stringa. Se si incontra un simbolo ai si fa pop dallo stack e si accetta
se la stringa ottenuta non fa match con ai altrimenti si continua a processare lo stack. Se si arriva in fondo allo stack si accetta
46

se ci sono ancora simboli in input, altrimenti si rifiuta (la stringa nellultimo caso e` in L(GA )). Quindi L(GA ) e` un esempio
interessante di linguaggio CF con complemento ancora CF.
Tornando al problema originale. Quindi possiamo costruire un automa a pila G che riconosce L(GA )L(GB ) = L(GA ) L(GB ).
Ma questo linguaggio rappresenta tutte le istanze che non sono soluzione dellistanza PCP di partenza. E quindi confrontando il
suo linguaggio con quello della grammatica che genera possiamo risolvere PCP (se L(G1 ) = allora non ci sono soluzioni
a PCP, mentre se L(G1 ) 6= allora ci sono soluzioni).

Automi come Modelli di Sistemi: LTS

In questa sezione consideriamo gli automi come un possibile modello di computazione. Astraendo dalla nozione di linguaggio
consideriamo rappresentiamo gli stati dellautoma come stati di un sistema e le transizioni come azioni (con un certa etichetta)
che rappresentano update di stato. Usiamo quindi una versione semplificata che chiamiamo LTS (labeled transition system)
definito dalla tupla T = hS, , s0 i dove S e` un insieme di stati e S A e` una relazione con etichette in tra stati.
Usiamo s a s0 per indicare una transizione da s a s0 con etichetta .
Indichiamo con T rf (T ) linsieme delle tracce (finite) di esecuzione T rf (T ) = {a1 . . . ak |s0 a1 s1 . . . ak sk }. Una
traccia rappresenta quindi una possibile esecuzione di T . T e` quindi un automa che rappresenta computazioni. Per semplicit`a
consideriamo solo computazioni finite. Se T modella un sistema allora potrebbe essere interessante analizzare le sue propriet`a
usando la teoria degli automi. Ad esempio dati T1 e T2 mi potrei chiedere se T1 e T2 sono equivalenti. Esiste una gamma
molto ampia di equivalenze che possiamo definire. Quella pi`u stringente e` lisomorfismo di T1 e T2 (cio`e ci chiediamo se
rappresentano lo stesso grafo modulo renaming degli stati). Una nozione di equivalenza pi`u ragionevole e` definita confrontando
le tracce: T1 T T2 sse T r(T1 ) = T r(T2 ). Questo tipo di equivalenza e` simile allequivalenza dei linguaggi generati da automi
(considerando tracce che raggiungono uno stato finale). Consideriamo ad esempio




s2 b s3
T1 =
s1 a s2
T2 = s01 a s02 b s03
s2 b s4
Allora i due LTS sono equivalenti secondo T . Le tracce tuttavia non modellano in maniera completa il comportamento di un
sistema. Consideriamo infatti i due seguenti sistemi:


 0

s2 b s3
s1 a s02
s02 b s04
T1 =
s1 a s2
T2 =
s2 c s4
s01 a s03
s03 c s05
I due sistemi hanno le stesse tracce. Tuttavia nel primo dopo aver eseguito a ho ancora la scelta tra b e c. Nel secondo lesecuzione
di a mi porta ad una scelta obbligata (scelta in maniera non deterministica dal sistema). Se a=metto 50c nel distributore,
b=selezione il latte, c=seleziono il caffe, allora lesempio diventa forse pi`u chiaro.
Per poter distinguere T1 e T2 possiamo usare una relazione di equivalenza che avevamo visto nel caso della minimizzazione di
automi. Intuitivamente vorremmo trovare una relazione R che modella il fatto che uno stato simula il comportamento di unaltro
e viceversa, cio`e(s, t) R sse per ogni a
se s a s0 allora esiste t0 t.c. t a t0 e (s0 , t0 ) R
se t a t0 allora esiste s0 t.c. s a s0 e (s0 , t0 ) R
Tuttavia la condizione precedente (data con il sse) definisce R in termini di se stessa dobbiamo quindi risolvere unequazione
ricorsiva del tipo X = f (X). Notiamo anche che f non presenta immediatamente un caso base. In effetti possiamo avere diverse
R che soddisfano tale propriet`a. Ad esempio la relazione vuota soddisfa lequazione.
Per capire meglio come definire bene la nostra equivalenza definiamo la nozione di bisimulazione forte. R e` una relazione di
bisimulazione forte se R soddisfa la seguente propriet`a: se (s, t) R allora per ogni a
se s a s0 allora esiste t0 t.c. t a t0 e (s0 , t0 ) R
se t a t0 allora esiste s0 t.c. s a s0 e (s0 , t0 ) R
Abbiamo quindi rilassato la condizione iniziale. Tra tutte le bisimulazioni quella pi`u interessante e` quella pi`u grande (ottenuta
come unione di tutte le bisimulazioni forti), chiamata equivalenza forte F
[
F =
R
R bisim. f orte

47

Per dimostrare che due stati sono equivalenti serve quindi mostrare che esiste una bisimulazione che li contiene (tale bisimulazione e` contenuta per definizione anche nellequivalenza forte). Due LTS sono equivalenti secondo F se i corrispondenti stati
iniziali sono bisimili (esiste una bisimulazione forte che li mette in relazione).
Lequivalenza forte si pu`o costruire utilizzando un algoritmo di raffinamento simile a quello usato per calcolare lautoma mimimo
(calcolato su Q Q invece che su due insiemi distinti di stati). Inizialmente poniamo nella stessa classe tutti gli stati che non
hanno transizioni uscenti (stati finali di un automa) e formiamo una seconda classe che contiene tutti gli altri. Raffiniamo
incrementalmente le partizioni calcolando gli stati predecessori P 0 = P rea (P ) della partizione P rispetto ad a per a
P rea (P ) = {s|s a t, t P }
Usiamo P 0 per raffinare tutte le partizioni correnti. Data una partizione Q aggiungiamo se non risultano vuote Q \ P 0 e Q
P 0 elimando Q se le nuove partizioni sono contenute in Q. Questa operazione potrebbe spezzare Q in sottopartizioni (cio`e
distinguere maggiormente gli stati). Il procedimento prosegue fino a che non e` pi`u possibile raffinare le partizioni (linsieme di
partizioni si stabilizza). La partizione ottenuta rappresenta lequivalenza forte F .
Nel primo esempio otteniamo la relazione: {(s3 , s03 ), (s4 , s03 ), (s1 , s01 ), (s2 , s02 )} cio`e possiamo identificare gli stati alla stessa
profondit`a. Nel secondo esempio otteniamo la relazione: {(s3 , s04 ), (s3 , s05 ), (s4 , s04 ), (s4 , s05 )} cio`e possiamo identificare solo gli
stati finali.
La definizione di bisimulazione e` data in maniera ricorsiva apparentemente senza una base. In questo modo si pu`o applicare
anche a LTS senza stati finali. Consideriamo i seguenti due LTS




T1 = s1 a s2 s2 b s2
T2 = s01 a s02 b s03 b . . .
Il secondo rappresenta lunfolding del ciclo con etichetta b in T1 . In questo caso possiamo ancora definire una bisimulazione
forte che mette in relazione s1 e s01 e s2 con si per i > 1 e quindi provare che i due LTS sono equivalenti

48

Appendice

A.1

Relazioni, funzioni e famiglie

Def. A.1 [Relazioni e funzioni] Dati due insiemi A e B, una relazione R da A in B e` un sottoinsieme di A B; una relazione
su A e` una relazione da A in A. Se ha, bi R si scrive anche aRb.
Una funzione da A in B e` una relazione f da A in B che gode della propriet`a di univocit`a, cio`e per ogni a A esiste al pi`u un
b B tale che ha, bi R; tale b, se esiste, e` denotato con f (a). Se f e` una funzione da A in B si scrive f : A B; [A B]
denota linsieme delle funzioni da A in B. Una funzione f da A in B si dice totale se f (a) esiste per ogni a A, altrimenti si
dice parziale.
Def. A.2 [Predicato] Dato un insieme A, un predicato su A e` una funzione totale da A in B.
Def. A.3 [Relazione di equivalenza] Una relazione di equivalenza su A e` una relazione su A che sia:
riflessiva, ossia aRa per ogni a A,
simmetrica, ossia se aRa0 , allora a0 Ra, per ogni a, a0 A,
transitiva, ossia se aRa0 e a0 Ra00 , allora aRa00 , per ogni a, a0 , a00 A.
Per ogni a A, la sua classe di equivalenza [a] e` linsieme degli elementi di A in relazione con a. Linsieme quoziente A/ e`
linsieme i cui elementi sono le classi di equivalenza.
Def. A.4 [Chiusura riflessiva e transitiva] Se R e` una relazione su A, la chiusura transitiva di R e` la relazione R+ su A definita
come segue:
per ogni a, a0 A, aR+ a0 sse a = a0 Ra1 , a1 Ra2 , . . . , an1 Ran = a0 , per qualche a1 , . . . , an1 .
La chiusura riflessiva e transitiva di R e` la relazione R? su A definita da: R? = R+ {ha, ai | a A}.
Equivalentemente, R? pu`o essere definita induttivamente, vedi Sezione A.2, come segue18 :
aRa per ogni a A,
se aRa0 , allora aR? a0 ,
se aR? a0 e a0 R? a00 , allora aR? a00
e analogamente R+ escludendo la prima metaregola.
Def. A.5 [Famiglia di insiemi] Una famiglia di insiemi (o semplicemente famiglia) (indiciata su S) e` una funzione totale che
associa ad ogni s S un insieme. Se A e` una famiglia di insiemi indiciata su S, per ogni s S linsieme associato ad s si indica
As .
Si noti la differenza tra una famiglia ed un insieme; ad esempio la famiglia A indiciata su a, b, c definita da Aa = Z, Ab = B,
Ac = Z e` diversa dallinsieme {Aa , Ab , Ac } = {Z, B}.
Le usuali operazioni sugli insiemi (ad esempio unione, intersezione, differenza) si estendono alle famiglie, componente per
componente (`e necessario che le famiglie coinvolte siano indiciate tutte sullo stesso insiemi di indici).
In modo esattamente analogo ad una famiglia di insiemi si definisce una famiglia indiciata su S di funzioni.

A.2

Definizioni induttive, prove per induzione e punti fissi

A.2.1

Definizioni induttive

In matematica e informatica si usano molto spesso definizioni ricorsive, cio`e definizioni in cui lespressione che definisce loggetto fa riferimento alloggetto stesso. Un tipo di definizioni ricorsive alle quali e` possibile attribuire in modo semplice un
significato preciso sono le definizioni cosiddette induttive, illustrate nel seguito. Lidea base e` quella di definire un insieme come
il pi`u piccolo tra tutti gli insiemi X che verificano delle condizioni di chiusura del tipo se certi elementi appartengono a X,
allora anche un certo altro elemento deve appartenere a X.
Sia nel seguito U un insieme fissato detto universo.
18 Ossia,

come la pi`u piccola relazione riflessiva e transitiva che contiene R.

49

Pr
, dove Pr U e` linsieme delle premesse
c
Pr
e c U e` la conseguenza della regola. Un insieme X U e` chiuso rispetto a una regola
se Pr X implica c X; e`
c
chiuso rispetto a R se e` chiuso rispetto a ogni regola di R. Linsieme I(R) definito induttivamente da R e` il pi`u piccolo19 insieme
chiuso rispetto a R.
Def. A.6 [Definizione induttiva] Una definizione induttiva R e` un insieme di regole

Una definizione induttiva viene in genere data in modo pi`u leggibile utilizzando un qualche metalinguaggio (per esempio lusuale
metalinguaggio matematico). Spesso consiste di un insieme di metaregole, contenenti metavariabili da istanziare con elementi
delluniverso, in modo che ogni metaregola descriva un insieme anche infinito di regole. Si dice che le (meta)regole con un
insieme vuoto di premesse costituiscono la base mentre le altre (meta)regole costituiscono il passo induttivo della definizione
induttiva.
Esempio A.7 Linsieme dei numeri pari e` definito nel modo seguente:
0 e` un numero pari,
se n e` un numero pari, allora n + 2 e` un numero pari.
Si pu`o vedere pi`u chiaramente che si tratta di una definizione induttiva riscrivendola nello stile a regole di inferenza, in cui le
premesse vengono scritte sopra la linea di frazione, la conseguenza sotto e le eventuali condizioni a lato. Si ha:
n
n+2

n
In questo caso, linsieme universo e` N, e la definizione induttiva e` , formalmente, { } {
| n N}.
0
n+2
A.2.2

Principio di induzione

Prop. A.8 [Principio di induzione (forma generale)] Sia R una definizione induttiva, U un insieme tale che I(R) U , e P un
predicato su U , cio`e una funzione P : U {T , F }.
Pr
R
(P (x ) = T per ogni x Pr ) implica P (c) = T allora: P (x ) = T per ogni x I(R).
Se: per ogni
c
Prova Poniamo C = {x |P (x ) = T } e osserviamo che la condizione in giallo pu`o essere scritta nella forma equivalente:
Pr C implica c C.
ossia corrisponde a richiedere che C sia chiuso rispetto a R. Quindi, per definizione I(R) C, ossia P (x ) = T per ogni
x I(R).
Si noti che nel caso di una regola con insieme di premesse vuoto la condizione in giallo equivale a P (c) = T . Ci`o suggerisce
lusuale formulazione del principio di induzione spezzata in base e passo induttivo, dove la base corrisponde alle (meta)regole
senza premesse.
Un caso particolare del principio di induzione dato qui in forma generale e` il principio di induzione aritmetica.
Prop. A.9 [Principio di induzione aritmetica] Sia P un predicato sui numeri naturali tale che
1. P (0) = T ;
2. per ogni n N, P (n) = T implica P (n + 1) = T .
Allora P (n) = T per ogni n N.
Prova N pu`o essere visto come il sottoinsieme dei naturali definito induttivamente da
0 N;
se n N allora n + 1 N.
19 Nel senso dellinclusione insiemistica, ossia lintersezione di tutti gli insiemi chiusi che si vede facilmente essere a sua volta un insieme chiuso.

Si noti anche
che vi e` sempre almeno un insieme chiuso, luniverso U , quindi la definizione non e` vuota. Infine, si noti che e` sempre possibile considerare come universo
linsieme dagli elementi delle coppie di R, o anche solo gli elementi conseguenza, quindi in realt`a non e` necessario fissare un universo a priori.

50

Allora la proposizione e` un caso particolare del principio di induzione.


Prop. A.10 [Principio di induzione aritmetica completa (o forte)] Sia P un predicato sui numeri naturali tale che
Base vale P (0)
Passo induttivo se vale P (m) per ogni m < n allora vale P (n),
allora P (n) vale per ogni n N.
Prova N pu`o essere visto come linsieme definito induttivamente da
0N
se {m | m < n} N allora n N.
Quindi la proposizione e` un caso particolare del principio di induzione.
A.2.3

Definizioni induttive multiple

Sono spesso utili in informatica le definizioni induttive di famiglie di insiemi (Def.A.5), dette anche definizioni induttive multiple
o mutuamente induttive, con lassociato principio di induzione multipla. Si tratta di una facile generalizzazione delle definizioni
e dei risultati gi`a dati.
Sia U una famiglia (indiciata su S) fissata detta universo.
Pr
Def. A.11 [Definizioni induttive multiple] Una definizione induttiva multipla e` un insieme di regole
, dove Pr U (cio`e
c : s
Pr s Us per ogni s S) e` linsieme delle premesse, e c : s, dove s S e c Us, e` la conseguenza della regola. Una famiglia
Pr
se Pr s Xs per ogni s S implica c Xs; e` chiusa rispetto a R se e` chiusa
X U e` chiusa rispetto a una regola
c : s
rispetto a ogni regola di R. La famiglia I(R) definita induttivamente da R e` la pi`u piccola20 famiglia chiusa rispetto a R.
Analogamente a quanto si e` visto per le definizioni induttive non multiple, i sistemi induttivi sono in generale presentati dando
un insieme di regole di inferenza o metaregole. Il principio di induzione si estende al caso multiplo.
Prop. A.12 [Principio di induzione multipla] Sia R una definizione induttiva multipla, U una famiglia di insiemi (indiciata su
S) tale che I(R) U , e P una famiglia di predicati su U .
Pr
Se: per ogni
R
(Ps (x ) = T per ogni x Pr s , per ogni s S) implica Ps(c) = T
c : s
allora: Ps (x ) = T per ogni x Is (R), per ogni s S.
Prova Analoga a quella del caso non multiplo.
Anche qui lipotesi del principio di induzione pu`o essere utilmente spezzata in base e passo induttivo in corrispondenza
dellanaloga suddivisione delle (meta)regole. In conclusione nel caso multiplo si ragiona e procede come nel caso non multiplo,
eccetto per il fatto che si ha a che fare con una famiglia di insiemi e che occorre quindi tener conto dellappartenenza di un
elemento a un particolare insieme della famiglia.
A.2.4

Punti fissi e definizioni conduttive

Una definizione induttiva pu`o essere vista equivalentemente come una trasformazione di insiemi, e linsieme definito induttivamente come il minimo punto fisso di tale trasformazione.
Sia f : A A una funzione e a A, allora a e` un punto fisso di f se f (a) = a.
Sia f : (U) (U), e X U, allora X e` un punto fisso di f se f (X) = X, e` un punto prefisso di f (X e` f -chiuso)
sef (X) X.
X e` un minimo punto (pre)fisso di f se f (Y ) Y implica X Y , o, equivalentemente, X e` lintersezione dei punti
(pre)fissi.
f e` monotona se X Y implica f (X) f (Y ).
20 Nel

senso dellinclusione di famiglie, ossia lintersezione di tutte le famiglie chiuse.

51

Teorema A.13 Data R una definizione induttiva con universo U, definiamo fR : (U) (U) nel modo seguente:
per ogni X U, fR (X) = {c |

Pr
R, Pr X}.
c

Allora, fR e` monotona e I(R) e` il minimo punto prefisso di fR (X).


Teorema A.14 Data f : (U) (U) monotona, sia Rf definita da:
Rf = {

Pr
| Pr U, c f (Pr )}
c

Allora, I(Rf ) e` il minimo punto prefisso di f .


Quella come definizione induttiva (minimo punto fisso) e` probabilmente la pi`u semplice e naturale, ma non lunica interpretazione
possibile di una trasformazione di insiemi. In alcuni casi vogliamo invece uninterpretazione conduttiva, ossia vogliamo prendere
il massimo punto fisso della trasformazione.
Assumendo che X sia un sottoinsieme dei numeri naturali,
X = {0} X
lequazione (definizione ricorsiva) ammette infinite soluzioni: tutti gli insiemi S (N) tali che 0 S, quindi X non e` ben
definito.
Tuttavia X risulta ben definito se scegliamo:
la soluzione pi`u piccola(definizione induttiva): X = {0}
la soluzione pi`u grande (definizione conduttiva): X = N.
Come gi`a detto sopra, una definizione ricorsiva pu`o essere vista come una funzione, per esempio X = {0} X corrisponde alla
funzione f :(N) (N) tale che
f (X) = {0} X
Allora X e` una soluzione dellequazione se e solo se X e` un punto fisso di f :
f (X) = X
In particolare:
{0} e` il minimo punto fisso di f
N e` il massimo punto fisso di f
Si pu`o provare che, sotto opportune condizioni, il minimo punto fisso lfp f e il massimo punto fisso gfp f di una funzione
f :(U ) (U ) possono essere costruiti per approssimazioni successive nel modo seguente:
1. lfp f = sup{f n () | n N}
2. gfp f = inf{f n (U ) | n N}.

52

You might also like