λ Teoria del calcolo

Il problema della fermata: perché è indecidibile

La dimostrazione per diagonalizzazione che nessun algoritmo decide se un programma si ferma, spiegata passo per passo, con le conseguenze per il software.

Sarebbe comodo avere uno strumento che, dato un programma qualsiasi e un suo input, dica se il programma prima o poi termina oppure resta in ciclo per sempre. Un tale strumento troverebbe automaticamente tutti i cicli infiniti, e molto altro. Il problema della fermata (halting problem) chiede esattamente questo, e la risposta della teoria è netta: un algoritmo del genere non può esistere. Non per mancanza di potenza di calcolo, ma per una contraddizione logica.

La formulazione precisa

Il linguaggio della fermata è:

HALT_TM = {⟨M, w⟩ : M è una macchina di Turing che si ferma sull'input w}

Strettamente collegato è il linguaggio di accettazione:

A_TM = {⟨M, w⟩ : M accetta w}

Il teorema afferma che entrambi sono indecidibili: non esiste una macchina di Turing che, su ogni input ⟨M, w⟩, si fermi sempre e risponda correttamente. Entrambi sono però riconoscibili: basta simulare M su w con la macchina universale e aspettare.

La dimostrazione per A_TM

Dimostriamo prima che A_TM è indecidibile, con un argomento per assurdo.

Supponiamo che esista un decisore H tale che:

  • H(⟨M, w⟩) accetta se M accetta w;
  • H(⟨M, w⟩) rifiuta se M non accetta w (perché rifiuta o perché non si ferma).

H si ferma sempre, per ipotesi.

Costruiamo una nuova macchina D che riceve in input la descrizione ⟨M⟩ di una macchina:

  1. esegue H sull'input ⟨M, ⟨M⟩⟩, cioè chiede se M accetta la propria descrizione;
  2. se H accetta, D rifiuta;
  3. se H rifiuta, D accetta.

D si ferma sempre, perché H si ferma sempre. Fa l'opposto di ciò che M farebbe su se stessa.

Ora diamo a D la sua stessa descrizione, ⟨D⟩:

  • se D accetta ⟨D⟩, allora H(⟨D, ⟨D⟩⟩) ha accettato, quindi per costruzione D rifiuta ⟨D⟩;
  • se D rifiuta ⟨D⟩, allora H(⟨D, ⟨D⟩⟩) ha rifiutato, quindi per costruzione D accetta ⟨D⟩.

In entrambi i casi otteniamo una contraddizione. Quindi H non può esistere, e A_TM è indecidibile.

Perché si chiama diagonalizzazione

Immaginiamo una tabella infinita. Le righe sono tutte le macchine di Turing M₁, M₂, M₃, …, che sappiamo essere numerabili. Le colonne sono le loro descrizioni ⟨M₁⟩, ⟨M₂⟩, ⟨M₃⟩, … Nella cella (i, j) scriviamo «accetta» se Mᵢ accetta ⟨Mⱼ⟩, altrimenti «non accetta».

La macchina D è costruita in modo da comportarsi, sulla colonna i, all'opposto di quanto indicato nella cella diagonale (i, i). Dunque D differisce da ogni macchina Mᵢ almeno su un input, ⟨Mᵢ⟩. Ma D è una macchina di Turing, quindi dovrebbe comparire in qualche riga: contraddizione. È lo stesso schema con cui si dimostra che i numeri reali non sono numerabili.

Dalla accettazione alla fermata

Ora mostriamo che anche HALT_TM è indecidibile, con una riduzione. Supponiamo che esista un decisore R per HALT_TM. Allora potremmo decidere A_TM così, su input ⟨M, w⟩:

  1. si esegue R su ⟨M, w⟩;
  2. se R dice che M non si ferma su w, si rifiuta: M certamente non accetta;
  3. se R dice che M si ferma, si simula M su w, sapendo che la simulazione terminerà, e si risponde come M.

Avremmo un decisore per A_TM, che non esiste. Quindi R non esiste.

Un linguaggio nemmeno riconoscibile

Un linguaggio è decidibile se e solo se sia esso sia il suo complemento sono riconoscibili: basta eseguire in parallelo i due riconoscitori e aspettare che uno dei due accetti. Poiché A_TM è riconoscibile ma non decidibile, il suo complemento non è nemmeno riconoscibile. Esistono quindi problemi per cui non si può neppure garantire di confermare tutte le risposte positive.

Che cosa significa davvero, e che cosa no

L'indecidibilità viene spesso fraintesa. Alcune precisazioni:

  • Non significa che non si possa sapere se un programma specifico termina. Per moltissimi programmi concreti lo si dimostra senza difficoltà.
  • Significa che non esiste un unico algoritmo che dia la risposta corretta per tutti i programmi.
  • Gli strumenti reali di analisi statica aggirano il limite in modo onesto: rispondono «termina», «non termina» oppure «non so», oppure limitano il linguaggio analizzato, oppure accettano falsi allarmi.
  • Un timeout non risolve il problema: se un programma non ha ancora finito, non sappiamo se finirà tra un secondo o mai.

Nel mio lavoro questo limite si vede bene nell'analisi del codice sospetto: nessuno strumento può stabilire con certezza, in ogni caso, che cosa farà un programma su tutti gli input. Ci si affida quindi a combinazioni di analisi statica, esecuzione controllata e giudizio umano.

In sintesi

  • Il problema della fermata chiede se una macchina si ferma su un input; non esiste un algoritmo che lo decida sempre.
  • La dimostrazione costruisce una macchina D che contraddice se stessa quando riceve la propria descrizione.
  • È un argomento di diagonalizzazione, lo stesso che mostra la non numerabilità dei reali.
  • A_TM e HALT_TM sono riconoscibili ma non decidibili; i loro complementi non sono neppure riconoscibili.
  • L'indecidibilità riguarda un algoritmo universale, non i singoli programmi.
MM
Marco Marzaduri

Marco Marzaduri si occupa di cybersecurity, informatica forense e sviluppo web. Laureato in informatica, unisce il rigore dell'analisi tecnica all'attenzione per le persone che usano la tecnologia.

Leggi anche