Calcolabilità e Macchine di Turing

Pagina creata da Alice Cocco
 
CONTINUA A LEGGERE
Capitolo 1

Calcolabilità e Macchine di Turing

Tra la fine del XIX e l’inizio del XX secolo la Matematica, che aveva per altro raggiunto risultati importantis-
simi, stava attraversando un periodo di “crisi”, legato alla scoperta che i suoi “fondamenti” non fossero così
solidi come si era sempre creduto. Ecco che in quel periodo si potevano trovare alcuni dei maggiori matematici
farsi domande alquanto imbarazzanti, come ad esempio: “cos’è un numero”?
       Un atteggiamento che da allora in poi ha accompagnato i progressi della Matematica è il costruttivismo,
che corrisponde a cercare di utilizzare esclusivamente concetti che possono essere concretamente costruiti a
partire da altri. Ad esempio, un ragionamento costruttivista non si accontenta di utilizzare un elemento di un
insieme sulla base del fatto che se ne è dimostrata l’esistenza, ma pretende che si sia effettivamente individuato
l’elemento di cui si sta parlando.
       Nello stesso periodo, il progresso delle scienze sperimentali e della tecnologia, che erano stati di stimolo
ed erano stati a loro volta stimolato dal progresso della Matematica, richiedevano l’esecuzione di un numero
sempre maggiore di calcoli e sempre più complessi ed era molto naturale chiedersi se la scienza meccanica,
che tanti incredibili successi aveva raggiunto, non potesse aiutare anche in questo (è di pochi anni precedente il
visionario tentativo di Charles Babbage [1791-1871] di costruire un calcolatore meccanico).
      Ecco che, ben prima che fossero effettivamente disponibili dei veri calcolatori, alcune delle migliori
menti matematiche della prima parte del XX secolo si applicarono nella ricerca dei fondamenti teorici del
calcolo e, in particolare, nella definizione del concetto stesso di calcolo.

1.1 Formalismi di calcolo

Molti furono i matematici che studiarono e proposero dei formalismi di calcolo, cioè una serie di regole, le più
semplici possibili, che potessero prestarsi a definire che cosa è un calcolo. Questi formalismi dovevano essere
basati su operazioni semplici che, almeno in linea di principio, potessero essere eseguita da una macchina: per
questo gli oggetti che rispondono alle richieste del formalismo vengono spesso chiamate “macchine”. Il più
famoso e fortunato di questi formalismi è noto come il formalismo delle Macchine di Turing, dal nome di Alan
Turing [1912-1954], il matematico che lo ha inventato.
       Noi non seguiremo qui l’andamento storico della scoperta di questi concetti, che pure sarebbe interes-
sante, ma ne daremo una descrizione “moderna”.

1.1.1 Automi a stati finiti

Prima di vedere come sono fatte le macchine di Turing, dobbiamo capire che cos’è un automa (o macchina) a
stati finiti. Prima di darne una definizione, che risulterebbe arida ed un po’ astrusa, preferiamo cercare di darne
un’idea.
      Questa consiste nell’immaginare il nostro automa come un sistema fisico che inizialmente si trova in
uno stato ben preciso e che successivamente evolve seguendo regole ben precise; l’evoluzione dell’automa può

                                                        1
CAPITOLO 1. CALCOLABILITÀ E MACCHINE DI TURING                                                                    2

essere condizionata, sempre secondo regole ben precise, dagli stimoli cui viene sottoposto dall’esterno. In ogni
istante, l’automa si troverà quindi in un ben preciso stato dipendente dallo stato iniziale e dagli stimoli cui
l’automa è stato via via sottoposto.
      Ma che cos è lo stato di un automa? Questo concetto è derivato dal concetto di stato di un sistema fisico.

Definizione 1 Lo stato di un sistema fisico è l’insieme di grandezze fisiche note le quali è possibile prevedere
il suo comportamento futuro, assumendo di conoscere a quali stimoli esterni verrà sottoposto.

      Nel nostro caso, al fine di garantirsi la sua effettiva costruibilità e la finitezza della sua descrizione,
chiediamo che il nostro automa possa trovarsi solo in un numero finito di stati, che possiamo quindi numerare
con numeri naturali a partire da 0 fino a n − 1, dove n è il numero degli stati dell’automa.
       Inoltre, chiediamo che le transizioni di stato avvengano istantaneamente, il che serve ad assicurarsi che
l’automa sia sempre in uno stato ben definito, e che anche gli stimoli esterni cui l’automa può essere sottoposto
siano finiti.
       Infine, consideriamo che un sottoinsieme degli stati dell’automa siano stati terminali, tali per cui l’automa
si ferma quando li raggiunge.

Definizione 2 (automa a stati finiti) Un automa a stati finiti è costituito da:

   • un insieme finito e non vuoto di stati S = {s0 , s1 , . . . , sn−1 }, con n ∈ N+ ;

   • un sottoinsieme T di S di stati terminali;

   • un insieme finito e non vuoto di possibili ingressi I = {i0 , i1 , . . . , im−1 } con m ∈ N+ ;

   • una funzione di transizione t : S\T × I → S che determina in quale stato si troverà l’automa a partire
     dal suo stato attuale e dall’ingresso cui è sottoposto.

      È possibile utilizzare un automa a stati finiti per eseguire direttamente dei calcoli.

Esempio 1 Vogliamo realizzare un automa a stati finiti che “conta modulo 3”, cioè che ricevendo in ingresso
una sequenza di simboli, stabilisca qual è il loro numero modulo 3 (si dice che l’automa riceve in ingresso un
numero espresso in notazione unaria).
      Possiamo immaginare il seguente automa a stati finiti:

   • S = {s0 , s1 , s2 }

   • T =∅

   • I = {i0 }

                    s0 s1 s2
   • t(s, i) =
                 i0 s1 s2 s0

      Ponendo inizialmente l’automa nello stato s0 ed inviandogli in ingresso una sequenza di i0 , questo si
troverà in uno stato sm tale per cui il numero degli 1 forniti in ingresso modulo 3 sarà pari ad m (sei capace
di dimostrarlo?).

      Generalmente, si dà agli automi a stati finiti una rappresentazione grafica che è più espressiva di quella
che abbiamo utilizzato per la definizione:

   • ogni stato viene rappresentato con un cerchio con all’interno il suo nome;
CAPITOLO 1. CALCOLABILITÀ E MACCHINE DI TURING                                                                    3

   • gli stati terminali vengono rappresentati con un doppio cerchio concentrico (o un colore diverso);

   • la funzione di transizione (e, contemporaneamente, l’insieme di ingresso) viene rappresentata da frecce
     che partono da uno stato ed arrivano ad un altro stato, etichettate con il corrispondente valore di ingresso.

Esempio 2 L’automa dell’esempio precedente può essere rappresentato nel modo seguente:

                                           i0                         i0

                             s0                         s1                          s2

                                                        i0

      Ad un automa a stati finiti può essere associata anche una funzione di uscita che fà corrispondere un
simbolo preso da un apposito insieme (anch’esso finito) ad ogni transizione dell’automa. In questo caso, gene-
ralmente, il risultato di una computazione viene considerato la sequenza di simboli emessi dall’automa durante
la computazione.
       Un automa a stati finiti, in definitiva, è completamente definito dalla tupla S, T, I, U, t, u, dove (U e u
sono, rispettivamente, l’insieme dei simboli in uscita e la funzione di uscita). I e U prendono anche il nome di
alfabeti rispettivamente, di ingresso e di uscita.

1.1.2 Macchine di Turing

Le capacità di calcolo degli automi a stati finiti sono però troppo limitate; ad esempio, non è possibile realizzare
un contatore naturale, cioè un automa che conta il numero di simboli in ingresso (sapresti dimostrarlo?).
       Alan Turing si rese conto che la poca espressività degli automi a stati finiti era dovuta proprio alla
finitezza degli stati; in sostanza, il numero di stati rappresenta la capacità dell’automa di ricordare cosa è
successo in precedenza, cioè la sua memoria.
       Provò allora a dotare un automa a stati finiti di una memoria infinita, che immaginò essere una nastro
formato da un numero infinito di caselle in cui potevano essere memorizzati dei simboli appartenenti ad un pre-
determinato alfabeto. L’idea consiste nell’immaginare che l’automa abbia una testina posta in corrispondenza
di una ben determinata posizione del nastro in grado di leggere il simbolo posto nella casella corrispondente,
agendo poi considerandolo come simbolo di ingresso; a seconda della transizione di stato che viene determinata
nell’automa, la testina scrive nella medesima casella un altro simbolo e si sposta a avanti o a indietro di essa.
     Ci si rende conto che tutto questo può essere descritto formalmente nei termini della definizione di
automa a stati finiti che abbiamo visto.

Definizione 3 (macchina di Turing) Una macchina di Turing (MdT) è costituita da:

   • un automa a stati finiti (S, T, I, U, t, u), dove U = I × {avanti, indietro}

   • un nastro costituito da un numero infinito, ma numerabile, di caselle contenenti ciascuna un elemento di
     I;

   • una testina in grado:

         1. leggere il contenuto della casella su cui è posta;
         2. fornire il simbolo letto in ingresso all’automa;
CAPITOLO 1. CALCOLABILITÀ E MACCHINE DI TURING                                                                4

        3. ricevere la coppia di elementi in uscita dall’automa;
        4. scrivere il primo simbolo della coppia nella casella;
        5. spostarsi nella casella successiva o precedente del nastro a seconda del valore del secondo simbolo
           della coppia.

      Possiamo anche definire il concetto di computazione.

Definizione 4 (computazione di una MdT) Una computazione per una MdT è il processo che si ottiene fa-
cendo evolvere la MdT a partire dalla seguente situazione:

   1. sul nastro è presente un numero finito di elementi diversi da i0 , che viene spesso indicato anche con ∇);

   2. la testina è posizionata sulla prima casella del nastro;

   3. l’automa che controlla la MdT è nello stato s0 .

      La computazione termina se l’automa raggiunge uno stato terminale o se la testina riceve il comando
di andare alla casella precedente essendo sulla prima casella del nastro; ovviamente, una computazione può
anche non terminare.
       La configurazione iniziale del nastro viene considerato il valore di ingresso della computazione, mentre
il valore di uscita è la sua configurazione finale nel caso la computazione termini ed è invece indefinita se la
computazione non termina.

Esempio 3 (funzione successore) Vogliamo realizzare una MdT che calcoli il successore di un numero natu-
rale.
      Possiamo seguire questa strategia:

   • rappresentiamo i numeri naturali in formato unario come sequenze contigue di simboli i1 a partire dalla
     prima casella del nastro;

   • facciamo scorrere la testina verso la casella successiva fintanto che troviamo il simbolo i1 (dal momento
     che dobbiamo anche scrivere nella casella, riscriveremo sempre lo stesso simbolo i1 );

   • quando troviamo il simbolo i0 , significa che siamo arrivati alla fine del numero da incrementare: scri-
     viamo allora il simbolo i1 sulla casella e terminiamo la computazione.

      Per realizzare questa strategia, possiamo definire la MdT in questo modo:

   • S = {s0 , s1 }

   • T = {s1 }

   • I = {∇, 1}
               
                 s0 (i = 1)
   • t(s, i) =
                 s1 (i = ∇)

   • u(s, i) = (1, avanti)

        Possiamo rappresentare graficamente la computazione. Se immaginiamo di voler calcolare il successore
di 2, la situazione iniziale è la seguente:
CAPITOLO 1. CALCOLABILITÀ E MACCHINE DI TURING                                                                  5

                                         1        1   ∇       ∇    ∇        ···

                                                          ∇

                                    1        s0                        s1

          Dopo il primo passo, avremo:

                                         1        1   ∇       ∇    ∇        ···

                                                          ∇

                                    1        s0                        s1

e poi:

                                         1        1   ∇       ∇    ∇        ···

                                                          ∇

                                    1        s0                        s1

infine:

                                         1        1   1       ∇    ∇        ···

                                                          ∇

                                    1        s0                        s1

1.1.3 Funzioni Parziali Ricorsive

Facciamo ora solo qualche cenno ad un altro, tra i tanti, formalismi di calcolo che sono stati definiti nel tempo;
quello delle Funzioni Parziali Ricorsive (FPR).
CAPITOLO 1. CALCOLABILITÀ E MACCHINE DI TURING                                                                  6

        L’idea generale è che esistano un certo numero di “funzioni basilari” che sono in qualche modo calco-
labili per definizione, cioè che servono esse stesse per definire che cosa è calcolabile, e da alcune “regole” per
trovare tutte le altre funzioni calcolabili a partire dalle prime.

Definizione 5 (Funzioni Primitive Ricorsive) La sottoclasse principale delle Funzioni Parziali Ricorsive è
quella delle Funzioni Primitive Ricorsive. In essa vengono definite innanzi tutto le funzioni di base:

   • Le funzioni zero, che hanno, per ogni n ∈ N, n argomenti e che assumono sempre il valore 0:

                                                       0n (x1 , x2 , . . . , xn ) = 0

   • La funzione successore, che ha un solo argomento ed assume come valore il suo successore:

                                                            S(x) = x + 1

   • Le funzioni di proiezione, che, per ogni n ∈ N e m ∈ [1, n], hanno n argomenti ed assumono come
     valore quello dell’argomento in m-esima posizione:

                                                    Pn,m (x1 , x2 , . . . , xn ) = xm

      Vengono poi definiti degli operatori che permettono di ottenere tutte (e sole) le altre funzioni:

   • L’operatore di composizione: data la funzione primitiva ricorsiva con k argomenti f e k funzioni a j
     argomenti g1 . . . gk , la funzione a j argomenti:

                               h(x1 , . . . , xj ) = f (g1 (x1 , . . . , xj ), . . . , gk (x1 , . . . , xj ))

      è primitiva ricorsiva.

   • L’operatore di ricorsione primitiva: data la funzione primitiva ricorsiva a k argomenti f e la funzione
     primitiva ricorsiva a k + 2 argomenti g, la funzione a k + 1 argomenti:
                          
                                h(0, x1 , . . . , xk )    = f (x1 , . . . , xk )
                     h=
                                h(S(n), x1 , . . . , xk ) = g (h(n, x1 , . . . , xk ), n, x1 , . . . , xk )

      è primitiva ricorsiva.

Esempio 4 (somma) La somma di due numeri naturali è una Funzione Primitiva Ricorsiva, perché può essere
ottenuta nel seguente modo:

                                         somma(0, x) = P1,1 (x)
                                    somma(S(n), x) = g(somma(n, x), n, x)

      dove:

                                               g(x, y, z) = S (P3,1 (x, y, z))
CAPITOLO 1. CALCOLABILITÀ E MACCHINE DI TURING                                                                    7

Esempio 5 (uguaglianza) La funzione uguale di due argomenti, che vale 0 se i due argomenti sono uguali e
1 altrimenti, è una Funzione Primitiva Ricorsiva perché può essere ottenuta nel seguente modo:

                             uguale(x, y) = somma(maggiore(x, y), minore(x, y))

      dove:

                                   minore(x, y) = zero(sottrazione(x, y))

                               maggiore(x, y) = minore(P2,2 (x, y), P2,1 (x, y))

                                       zero(0) = 00
                                    zero(S(n)) = S(02 (zero(n), n))

      e la funzione sottrazione è quella definita nell’esercizio 16.

Funzioni non primitive ricorsive

Esistono funzioni intuitivamente calcolabili (o, se si vuole usare un concetto ben formalizzato, calcolabili da
una MdT) che non sono primitive ricorsive (vedi esercizio 17).
      Questo è in qualche modo ovvio, visto che le funzioni primitive ricorsive sono tutte totali, cioè assumono
un valore per qualsiasi combinazione di argomenti che vengano loro forniti. Come vedremo più avanti, esistono
però anche funzioni calcolabili totali che non sono primitive ricorsive; la più celebre delle quali è la cosiddetta
funzione di Ackermann, che è stato il primo esempio di funzione di questo genere che è stato scoperto.

L’operatore di ricerca illimitata

Per poter quindi raggiungere una maggiore potenza espressiva, viene definito un nuovo operatore, quello di
ricerca illimitata.

Definizione 6 (operatore di ricerca illimitata µ) Data una funzione a k + 1 argomenti f (y, x1 , . . . , xk )
l’operatore di ricerca illimitata, detto anche di minimizzazione µf (y, x1 , . . . , xk ) definisce una funzione che
assume come valore il più piccolo y tale per cui entrambe le seguenti condizioni sono soddisfatte:

   • f (z, x1 , . . . , xk ) è sempre definito per ogni z < y

   • f (y, x1 , . . . , xk ) = 0

      Se queste condizioni non sono mai soddisfatte, allora il valore della funzione è indefinito.

      Ecco che ora possiamo dare la definizione di Funzione Parziale Ricorsiva.

Definizione 7 (Funzioni Parziali Ricorsive) Le Funzioni Parziali Ricorsive (FPR) sono tutte e sole le funzioni
che possono essere ricavate tramite le seguenti regole:

   • Le Funzioni Primitive Ricorsive sono FPR.

   • Data una FPR a k + 1 argomenti f y, x1 , . . . , xk , la funzione a k argomenti µyf y, x1 , . . . , xk è FPR.
CAPITOLO 1. CALCOLABILITÀ E MACCHINE DI TURING                                                                   8

Esempio 6 (sottrazione) La sottrazione parziale, definita nell’esercizio 17 è FPR, infatti può essere definita
nel seguente modo:

                                        sottrazione(x, z) = µf (y, z, x)

      dove:

                              f (y, z, x) = uguale(P3,3 (y, z, x), g(y, z, x))
                              g(y, z, x) = somma(P3,1 (y, z, x), P3,2 (y, z, x))

1.1.4 Equivalenza dei formalismi e Tesi di Church

Abbiamo definito due formalismi (ma ne sono stati definiti tanti altri) per specificare il concetto di calcolo e di
funzione calcolabile, ma, al di là delle differenze “tecniche”, definiscono insiemi di funzioni uguali o diversi?
Abbiamo visto che tutte le principali funzioni di uso “normale” possono essere definite in entrambi i formalismi,
ma ce ne sono altre che possono essere definite in un formalismo e non in un altro?
       A queste domande è stata data una risposta precisa: FPR e MdT, così come moltissimi altri formalismi,
definiscono esattamente lo stesso insieme di funzioni, che, d’ora in avanti, chiameremo quindi semplicemente
funzioni calcolabili (o computabili), senza dire secondo quale formalismo.
       La dimostrazione di equivalenza tra due formalismi, di solito, è lunga e noiosa, ma la strategia che si
segue è sempre quella e consiste nel “simulare” un formalismo nell’altro: ad esempio, è possibile dimostrare che
le FPR sono anche MdT computabili semplicemente costruendo delle MdT che calcolano le funzioni basilari
e mostrando come è possibile costruire delle MdT che realizzano la composizione, la ricorsione primitiva e la
ricerca illimitata; allo stesso modo, è possibile costruire delle FPR che si comportano come le varie parti di una
MdT.
       Questo processo è stato fatto per tutti i formalismi che sono stati definiti che non sono strettamente meno
potenti di quello delle MdT, tanto che si è arrivati alla conclusione che viene tramandata col nome di Tesi
di Church, dal nome del matematico Alonzo Church (1903-1995), l’inventore del lambda-calcolo, un altro
formalismo di calcolo molto famoso, da cui deriva il linguaggio di programmazione “LisP”, nota anche come
Tesi di Church-Turing, secondo la quale non esistono formalismi di calcolo più potenti di quello delle MdT (e,
naturalmente, delle FPR, o del Lambda-calcolo, ...) che abbiano la caratteristica di poter essere definiti da una
sequenza finita di simboli presi da una alfabeto finito, come sono, appunto, i formalismi di cui abbiamo parlato.
      Osserviamo di sfuggita che questo è vero anche per i moderni linguaggi di programmazione, che non
sono altro che altri formalismi per la definizione di funzioni calcolabili.
       La Tesi di Church, pur essendo in sé indimostrabile, è molto comoda perché permette, se la si accetta,
cosa che la comunità scientifica internazionale ha senz’altro fatto, di risparmiare le parti più lunghe e noiose
di molte dimostrazioni (che, peraltro, possono sempre essere realizzate ...). Ad esempio, in base alla Tesi di
Church, è del tutto inutile aggiungere altri nastri alle MdT, o usare nastri infiniti nelle due direzioni, o fare
chissà quali altre diavolerie (che però possano essere descritte finitamente), perché tanto si otterrà sempre lo
stesso insieme di funzioni calcolabili (naturalmente, tutte queste cose sono state dimostrate).
       Vedremo prossimo paragrafo come queste “dimostrazioni” sulla base della Tesi di Church, possano
essere molto utili per risparmiare fatica.

1.1.5 Composizione di MdT

Una delle cose belle del formalismo delle FPR è che è possibile (con qualche cautela) riutilizzare una funzione
definita in precedenza per definirne di nuove. Lo stesso non è possibile, direttamente, in base alla definizione
di MdT: se “compongo” due MdT, cioè, ad esempio, utilizzo il risultato fornito da una MdT come ingresso per
un’altra, quella che ottengo non è una MdT.
CAPITOLO 1. CALCOLABILITÀ E MACCHINE DI TURING                                                                    9

       Naturalmente, è possibile dimostrare che esiste una MdT che si comporta come la composizione di due
MdT, ma farlo è lungo e noioso (e, proprio per questo, è anche molto facile sbagliare!). La Tesi di Church ci
fornisce una facile scappatoia: siccome la descrizione di un formalismo in cui si possono comporre le MdT
sarebbe comunque finito, ecco che “deve” essere possibile realizzare una MdT che ne compone due, così come
“deve” essere possibile realizzare una MdT che si comporta come due o più MdT in parallelo.
       Cose di questo genere vengono spesso utilizzate per dimostrare che una certa funzione è calcolabile: se
si può realizzare componendo tra loro un numero finito di MdT, allora la si può realizzare anche con una singola
MdT, anche se molto più complicata.

1.2 Gödelizzazione

Abbiamo dunque visto che sono stati definiti molti formalismi di calcolo, diversi tra loro, ma, almeno se abba-
stanza potenti, equivalenti. Tutti questi formalismi, anche se ne abbiamo visti esplicitamente solo due, hanno
in comune che tutte le funzioni che vengono definite tramite questi formalismi possono essere completamente
specificate in modo finito o, più precisamente, tramite una sequenza finita di simboli tratti da un alfabeto finito.
      Come ovvio, nel momento in cui si cerca di descrivere in modo finito una cosa in sé infinita, come ad
esempio una funzione dai naturali ai naturali, si hanno alcune limitazioni, ma, come vedremo, anche alcune
importanti caratteristiche, di cui vediamo le più significative.
      L’importantissimo logico-matematico Kurt Gödel, nella prima metà del XX secolo, si era appunto inter-
rogato sulla possibilità di capire quali teoremi potessero essere veramente dimostrati all’interno di un sistema
logico finito. Proprio ragionando su questo tema, Gödel arrivò ai suoi due importantissimi teoremi, che, in
sostanza, misero la parola fine al cosiddetto “programma di Hilbert”, cioè di trovare un metodo per dimostrare
automaticamente tutti i teoremi di un dato sistema logico.
       Non possiamo, in questo contesto, entrare nei dettagli, molto profondi, del programma di Hilbert e dei
teoremi di Gödel; ci capiterà ancora, comunque, di incrociare queste tematiche nelle pagine seguenti. Per
ora, invece, prendiamo solo una piccola parte del lavoro di Gödel, il procedimento chiamato, appunto, di
gödelizzazione delle funzioni.
      L’idea fondamentale, gravida di conseguenze, è di rappresentare funzioni, risultati ed argomenti come
numeri naturali. Questo è possibile perché, essendo tutte queste entità delle sequenze finite di simboli finiti,
esse possono essere messe in ordine e, quindi, messe in corrispondenza biunivoca con i numeri naturali. Molto
banalmente, possiamo, stabilito un ordine tra i simboli dell’alfabeto utilizzato, mettere tutte le sequenze legali
di simboli in ordine “lessicografico”.
        Questa apparentemente banale osservazione (in realtà, Gödel definì in modo molto più preciso come fare
questa operazione) ci porta immediatamente ad una considerazione in qualche modo sorprendente: tutto quello
che possiamo calcolare utilizzando questi formalismi è rappresentabile da una funzione dai naturali ai naturali.
Se questa limitazione può essere “assorbita” per calcoli riguardanti i numeri interi relativi o anche i razionali
(si tratta sempre di numeri che possono essere “contati” tramite i naturali), nulla di più che approssimazioni
possiamo fare per i numeri reali.

1.3 Funzioni calcolabili

Un aspetto importantissimo del procedimento di gödelizzazione è che esso può essere realizzato grazie ad una
MdT, così come è possibile realizzare una MdT che descrive una MdT a partire dal suo numero di Gödel.
Questo permette di considerare una MdT sostanzialmente equivalente al suo numero di Gödel.
       Tutte le funzioni a cui siamo in grado istintivamente di pensare sono calcolabili utilizzando una ben
specifica MdT: appartengono a questa categoria tutte le operazioni matematiche elementari, come addizione,
sottrazione, moltiplicazione, divisione, e, di conseguenza, anche tutte quelle che abbiamo conosciuto nei nostri
studi, che sono essenzialmente basate sulle prime, come elevazione a potenza, radice quadrata, logaritmo,
le funzioni trigonometriche, . . . (per quanto riguarda le funzioni reali, abbiamo comunque dei procedimenti
calcolabili per ottenere delle approssimazioni vicine quanto vogliamo al risultato).
CAPITOLO 1. CALCOLABILITÀ E MACCHINE DI TURING                                                                   10

1.3.1 Macchine di Turing Universali

Il fatto che l’operazione di gödelizzazione sia calcolabile, così come l’operazione inversa (in realtà è stato
dimostrato che queste funzioni sono Primitive Ricorsive), assieme alla Tesi di Church, permette di mostrare, se
non di dimostrare, la calcolabilità di un gran numero di funzioni: basta pensare alla potenza del meccanismo
secondo cui a partire da un indice è possibile trovare la MdT corrispondente e quindi eseguirla, così come è
possibile costruire in qualche modo una MdT e poi calcolarne il numero corrispondente.
      Un esempio nient’affatto banale di questo è la possibilità di avere Macchine di Turing Universali (MTU).

Teorema 1 La funzione:

                                       f (i, x1 , . . . , xk ) = φi (x1 , . . . , xk )

      è calcolabile.

Dimostrazione
     Possiamo pensare di procedere in questo modo: a partire da i, come abbiamo visto, possiamo ricavare
la MdT corrispondente, che calcola la funzione φi . A questo punto, possiamo far calcolare la MdT trovata
dandogli come argomenti gli x1 , . . . , xk .
      Essendo questo chiaramente fattibile, in base alla Tesi di Church, esisterà una MdT che realizza lo stesso
calcolo.
                                                                                                                 
       Macchine di Turing Universali sono state effettivamente realizzate. In un certo senso, il concetto di MTU
è anticipatore di quello di moderno calcolatore, infatti, possiamo pensare ad una MTU come ad un’unica MdT
in grado di fare qualsiasi calcolo, a partire dall’indice della funzione calcolare e dai suoi argomenti, esattamente
come un calcolatore programmabile.

1.4 Funzioni non calcolabili

Abbiamo dunque stabilito che, dato un qualsiasi formalismo finito di calcolo ed un ben preciso processo di
gödelizzazione, ogni funzione può essere rappresentata biunivocamente da un numero naturale. Un primo
problema che questo comporta è dato dal seguente teorema, dovuto al matematico Georg Cantor (1845-1918).

Teorema 2 Le funzioni dai naturali ai naturali non possono essere messe in corrispondenza biunivoca coi
numeri naturali.

Dimostrazione
       Supponiamo che sia possibile enumerare le funzioni dai naturali ai naturali: possiamo allora costruire la
tabella seguente (infinita in entrambe le direzioni):

                                             0         1     2       3   ···
                                      0    f0 (0)    f0 (1) · · · f0 (m) · · ·
                                      1    f1 (0)    f1 (1) · · · f1 (m) · · ·
                                      ..      ..
                                       .       .
                                      n fn (0) fn (1) · · · fn (m) · · ·
                                      ..   ..
                                       .    .

dove fi rappresenta la i-esima funzione dell’enumerazione.
CAPITOLO 1. CALCOLABILITÀ E MACCHINE DI TURING                                                                       11

       Ora, costruiamo una funzione definita in questo modo:
                                            
                                                fn (n) + 1 se fn (n) definita
                                       f=                                                                         (1.1)
                                                0          altrimenti

Essa, è diversa da ogni altra funzione della lista, il che costituisce una contraddizione rispetto all’ipotesi iniziale,
che è quindi falsa.
                                                                                                                     
       Il procedimento dimostrativo che abbiamo visto, che è del tutto indipendente dal formalismo utilizzato,
si chiama diagonalizzazione ed ha una grandissima importanza in Matematica.
       Un corollario immediato di questo teorema è il seguente teorema.

Teorema 3 Per ogni formalismo di calcolo finito, esistono infinite funzioni non calcolabili.

1.4.1 Il problema della fermata

Ci si può chiedere, quindi, se quella trovata sia una limitazione reale o solo teorica e, comunque, quale sia una
funzione non artefatta, come la 1.1, non calcolabile.

Teorema 4 Non esiste una MdT capace di predire per ogni ingresso e per ogni MdT se questa terminerà il
calcolo a partire da quell’ingresso; una funzione cioè tale che:
                                                      
                                                          1 se φi (j) definita
                                         f (i, j) =                                                               (1.2)
                                                          0 altrimenti

dove φi è l’i-esima MdT secondo una ben precisa enumerazione.

Dimostrazione
       Consideriamo la funzione:
                                                                    
                              φn (n) + 1 se φn (n) definita              φn (n) + 1 se f (n, n) = 1
                 g(n) =                                     =
                              0          altrimenti                      0          altrimenti

Essa è diversa da ogni altra funzione della lista, che comprende tutte le funzioni calcolabili, quindi non è
calcolabile. Di conseguenza, non può essere calcolabile la 1.2; infatti g(n) = f (n, n).
                                                                                                                     
        Frastornati dal formalismo, potremmo pensare che anche la funzione 1.2 sia una funzione “artefatta”, in
realtà poco importante. Tutt’altro! Se pensiamo ad un linguaggio di programmazione, invece che alle MdT,
questo significa né più né meno che non è possibile progettare un programma che verifichi la terminazione di
altri programmi; cosa che ha un impatto fondamentale sull’insicurezza insita nei sistemi informatici. Se poi
pensiamo che, con ragionamenti simili, si arriva anche a dimostrare che non esistono MdT che siano in grado di
verificare che due MdT calcolino la stessa funzione e neppure se una MdT termini sempre, o calcoli una certa
funzione ben definita, si vede quanto questa limitazione sia fondamentale.
       Per quanti poi pensino che le conseguenze di tutto questo sono significative per l’Informatica, ma non per
la Matematica, possiamo citare la scoperta fatta da Yuri Matijasevic, che riferendosi al famosissimo X problema
di Hilbert (si può ben dire che il povero Hilbert è stato parecchio maltrattato dai matematici del XX secolo ...
e pensare che è stato proprio lui ad indicare loro la strada!), se cioè esista una procedura in grado di risolvere
qualsiasi equazione diofantea, ha dimostrato che esso è in realtà equivalente proprio al problema della fermata
di una MdT.
CAPITOLO 1. CALCOLABILITÀ E MACCHINE DI TURING                                                               12

1.4.2 Funzioni totali

Infine, vediamo un ultimo risultato: abbiamo visto come le limitazioni cui vanno incontro le MdT siano legate
al fatto che esse calcolano funzioni parziali. Vero è che il formalismo delle Funzioni Primitive Ricorsive non è
sufficientemente potente, in quanto esistono funzioni totali che non sono primitive ricorsive, ma potrebbe rima-
nere il dubbio che definendo opportunamente un formalismo che definisce solo funzioni totali, sia comunque
possibile definirle tutte.
      L’idea viene smontata dal seguente teorema.

Teorema 5 Se un formalismo permette di calcolare solo funzioni totali, allora non permette di calcolarle tutte.

Dimostrazione
      La dimostrazione è del tutto analoga a quella del Teorema 2. L’unica differenza è che, al posto della
funzione 1.1, bisogna usare:

                                               f (n) = fn (n) + 1

       Osserviamo che il fatto che f (n) non sia calcolabile col formalismo utilizzato non è in contrasto con la
Tesi di Church, in quanto il formalismo utilizzato è chiaramente meno potente di quello delle MdT.
                                                                                                              

Esercizi

   1. dimostra che l’automa dell’esempio 1 calcola il numero di ingressi cui è sottoposto modulo 3.

   2. progetta un automa a stati finiti che calcola modulo 5 il numero di ingressi cui è sottoposto.

   3. progetta una automa che somma tra loro modulo 4 due numeri espressi in formato unario e dimostra la
      sua correttezza.

   4. dimostra che non è possibile progettare un automa a stati finiti che calcola il numero di ingressi cui è
      sottoposto.

   5. progetta un automa a stati finiti che ricevendo in ingresso una sequenza di parentesi aperte e chiuse in
      cui non ci sono più di 4 annidamenti dica se la sequenza è corretta o no (cioè se ogni parentesi chiusa
      corrisponde ad una aperta).

   6. dimostra che la MdT dell’esempio 3 calcola la funzione successore.

   7. progetta una MdT che calcola la funzione successore utilizzando la notazione binaria. Dimostrane la
      correttezza.

   8. progetta una MdT che calcola la differenza di due numeri.

   9. progetta una MdT che verifica se una sequenza di caratteri è palindroma, cioè se si legge allo stesso modo
      partendo da entrambe le estremità.

 10. progetta una MdT che verifica la correttezza di una sequenza di parentesi comunque annidata.

 11. dimostra che il prodotto di due numeri naturali è una funzione primitiva ricorsiva.

 12. dimostra che il l’elevazione a potenza di due numeri naturali è una funzione primitiva ricorsiva.

 13. dimostra che il fattoriale è una funzione primitiva ricorsiva.
CAPITOLO 1. CALCOLABILITÀ E MACCHINE DI TURING                                                               13

 14. dimostra che i numeri di Fibonacci definiscono è una funzione primitiva ricorsiva.

 15. dimostra che i coefficienti binomiali definiscono è una funzione primitiva ricorsiva.

 16. dimostra che la sottrazione limitata tra naturali è una funzione primitiva ricorsiva (nella sottrazione
     limitata, se il secondo argomento è maggiore del primo il risultato è sempre 0).

 17. dimostra che la sottrazione parziale tra naturali non è una funzione primitiva ricorsiva (nella sottrazione
     parziale, se il secondo argomento è maggiore del primo il risultato è indefinito)
     Suggerimento: dimostra che tutte le funzioni primitive ricorsive sono totali, cioè non ammettono valori
     indefiniti.
Indice

1   Calcolabilità e Macchine di Turing                                                                             1
    1.1   Formalismi di calcolo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .      1
          1.1.1   Automi a stati finiti . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .    1
          1.1.2   Macchine di Turing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .       3
          1.1.3   Funzioni Parziali Ricorsive . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .      5
          1.1.4   Equivalenza dei formalismi e Tesi di Church . . . . . . . . . . . . . . . . . . . . . .          8
          1.1.5   Composizione di MdT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .          8
    1.2   Gödelizzazione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .       9
    1.3   Funzioni calcolabili . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .     9
          1.3.1   Macchine di Turing Universali . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .       10
    1.4   Funzioni non calcolabili    . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .   10
          1.4.1   Il problema della fermata . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .     11
          1.4.2   Funzioni totali . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .     12

                                                         14
Puoi anche leggere