Simulazione di un automa non deterministico
Se abbiamo un automa non deterministico e vogliamo sapere se accetta una data parola, possiamo convertirlo in un automa deterministico, possiamo andare per tentativi, oppure possiamo usare un algoritmo che simula il funzionamento dell’NFA.
Il principio dell’algoritmo
Illustriamo il principio con un esempio adatto. Prendiamo questo automa:
Si tratta di un automa a stati finiti non deterministico che accetta un certo linguaggio. Per ora non ci interessa affatto quale. Vediamo come può svolgersi il calcolo di un automa di questo tipo sulla parola in ingresso 11001. Il ragionamento è questo: elaboriamo un simbolo della parola e guardiamo in quali stati possiamo andare grazie alle transizioni multiple per lo stesso simbolo. Ci ricordiamo tutti questi stati e nel passo successivo supponiamo di trovarci «in tutti questi stati contemporaneamente»; ci interessa allora dove possiamo arrivare da questi stati.
Ci ricordiamo così un insieme di stati in cui possiamo trovarci e la parte non ancora letta della parola. All’inizio abbiamo quindi la coppia ⟨{q0}, 11001⟩. Partiamo dallo stato q0 (stato iniziale) e in ingresso c’è la parola 11001. L’automa si presenta così; in rosso e in grassetto è evidenziato lo stato in cui ci troviamo:
Il primo simbolo è 1; dallo stato q0 c’è una sola transizione per il simbolo 1, quindi arriviamo nello stato q1. Ci ricordiamo la coppia ⟨{q1}, 1001⟩. L’automa si presenta così:
Andiamo avanti. La parte non letta della parola è 1001, quindi cerchiamo di nuovo le transizioni per 1. Ora sono due: una che torna nello stato q0 e una verso lo stato q3. Questa volta andiamo in entrambi gli stati contemporaneamente. Ci ricordiamo quindi la coppia ⟨{q0, q3}, 001⟩.
Qual è la logica? Sappiamo che esiste un cammino che, con la parola 11, porta dallo stato iniziale sia nello stato q3 sia nello stato q0. Non sappiamo ancora quale ramo ci servirà, quindi ci ricordiamo semplicemente entrambi. Andiamo avanti. In ingresso c’è il simbolo 0. Ora dobbiamo guardare sia le transizioni da q0 sia quelle da q3. Da q0 partono transizioni verso gli stati q1 e q2, da q3 parte una transizione di nuovo verso q1. Teniamo conto di tutti questi stati e otteniamo la coppia ⟨{q1, q2}, 01⟩:
In questo passo, però, non abbiamo ancora finito. Vediamo che dallo stato q2 parte una ε-transizione verso lo stato q4. Sappiamo che una ε-transizione si può percorrere «in qualsiasi momento», senza leggere un altro carattere. In altre parole: senza leggere il simbolo successivo della parola in ingresso, possiamo ancora spostarci nello stato q4. Aggiungiamo quindi lo stato q4 agli stati in cui possiamo trovarci: ⟨{q1, q2, q4}, 01⟩. L’automa lo coloreremmo così:
Poi in ingresso c’è 0. Guardiamo dove possiamo spostarci dai tre stati in cui ci troviamo. Da q1 non possiamo andare da nessuna parte, perché manca la transizione per 0: il calcolo in questo ramo termina. Anche da q4 non arriviamo da nessuna parte. Da q2 torniamo nello stato q2. Ma poiché da q2 parte di nuovo una ε-transizione verso q4, possiamo arrivare anche nello stato q4. Dall’insieme di stati {q1, q2, q4} con il simbolo 0 possiamo quindi arrivare all’insieme di stati {q2, q4} e otteniamo la coppia ⟨{q2, q4}, 1⟩:
Infine in ingresso c’è il simbolo 1. Da q2 non arriviamo da nessuna parte e il calcolo in questo ramo termina. Da q4 invece arriviamo negli stati q3 e q5. Otteniamo la coppia ⟨{q3, q5}, ε⟩:
L’automa ha ora letto tutta la parola e «si trova» in due stati: q3, q5. Poiché almeno uno dei due è uno stato finale, l’automa accetta la parola 11001.
L’algoritmo
Per prima cosa ci serve una funzione che prenda come parametro un insieme di stati e calcoli in quali altri stati si può arrivare con le ε-transizioni. L’ingresso è quindi l’automa ⟨Q, Σ, δ, q0, F⟩ e un insieme di stati States; l’uscita è un sovrainsieme di questi stati, formato dagli stati raggiungibili con le ε-transizioni. Questa operazione la chiameremo ε-chiusura dell’insieme States.
Usiamo questa funzione in quella che simula il funzionamento dell’automa non deterministico. L’ingresso è l’automa, la parola in ingresso w = w1w2… wn e l’insieme di stati in cui l’automa si trova al momento. L’uscita è la risposta Sì oppure No, a seconda che l’automa accetti o non accetti la parola data.
Se vogliamo verificare se l’automa accetta la parola w, chiamiamo la funzione così: ComputeNFA(⟨Q, Σ, δ, q0, F⟩, w, EpsilonClosure(⟨Q, Σ, δ, q0, F⟩, {q0})).
Fonti
Capitoli: Automa a stati finiti, Automa completo, Automa a stati finiti non deterministico, Simulazione di un automa non deterministico, Conversione da NFA a DFA