✖

Simularea unui automat nedeterminist

Dacă avem un automat nedeterminist și vrem să aflăm dacă acceptă un anumit cuvânt, putem converti automatul într-unul determinist, putem încerca cumva să-l verificăm sau putem folosi un algoritm care simulează funcționarea AFN-ului.

Principiul algoritmului

Vom arăta principiul pe un exemplu potrivit. Fie acest automat:

Este un automat finit nedeterminist care acceptă un anumit limbaj. Acum nu ne interesează deloc care anume. Vom vedea cum poate arăta calculul unui astfel de automat pentru cuvântul de intrare 11001. Raționamentul este următorul: prelucrăm un simbol din cuvânt și ne uităm în ce stări putem ajunge datorită tranzițiilor multiple pentru același simbol. Reținem toate aceste stări și, în pasul următor, presupunem că ne aflăm „în toate aceste stări simultan” și ne interesează unde putem ajunge mai departe din ele.

Vom reține astfel mulțimea stărilor în care ne putem afla și partea necitită a cuvântului. La început avem perechea ⟨{q0}, 11001⟩. Pornim din starea q0 (starea inițială), iar la intrare avem cuvântul 11001. Automatul arată astfel; cu roșu și îngroșat este evidențiată starea în care ne aflăm:

Primul simbol este 1, iar din starea q0 pleacă o singură tranziție pentru simbolul 1, deci ajungem în starea q1. Reținem perechea ⟨{q1}, 1001⟩. Automatul arată astfel:

Continuăm. Partea necitită a cuvântului este 1001, deci căutăm din nou tranzițiile pentru 1. Acum sunt două – înapoi în starea q0 și mai departe în starea q3. Ne îndreptăm acum în ambele stări deodată. Reținem astfel perechea ⟨{q0, q3}, 001⟩.

Care este logica? Știm că există un drum prin care, cu cuvântul 11, ajungem din starea inițială atât în starea q3, cât și în starea q0. Încă nu știm care ramură ne va fi utilă, așa că le reținem pe amândouă. Continuăm. La intrare avem simbolul 0. Acum trebuie să ne uităm atât la tranzițiile din q0, cât și la cele din q3. Din starea q0 pleacă tranziții spre stările q1 și q2, iar din starea q3 pleacă o tranziție înapoi spre q1. Luăm în calcul toate aceste stări și obținem perechea ⟨{q1, q2}, 01⟩:

Dar încă nu am terminat acest pas. Vedem că din starea q2 pleacă o ε-tranziție spre starea q4. Știm că putem trece printr-o ε-tranziție „oricând”, fără să citim un alt simbol. Cu alte cuvinte, fără să citim următorul simbol din cuvântul de intrare, ne mai putem muta în starea q4. Adăugăm astfel starea q4 la stările în care ne putem afla: ⟨{q1, q2, q4}, 01⟩. Am colora automatul astfel:

Mai departe, la intrare este 0. Ne uităm unde ne putem muta din cele trei stări în care ne aflăm. Din q1 nu ne putem muta nicăieri, deoarece lipsește tranziția pentru 0. Calculul pe această ramură se oprește. Nici din starea q4 nu ajungem nicăieri. Din starea q2 ajungem înapoi în starea q2. Dar, cum din starea q2 pleacă din nou o ε-tranziție spre starea q4, putem ajunge și în starea q4. Din mulțimea de stări {q1, q2, q4} putem ajunge astfel, pentru simbolul 0, în mulțimea de stări {q2, q4} și obținem perechea ⟨{q2, q4}, 1⟩:

La final avem la intrare simbolul 1. Din starea q2 nu ajungem nicăieri, iar calculul pe această ramură se oprește. Din starea q4 însă ajungem în stările q3 și q5. Obținem perechea ⟨{q3, q5}, ε⟩:

Automatul a citit acum tot cuvântul și „se află” în două stări: q3, q5. Deoarece cel puțin una dintre ele este stare finală, automatul acceptă cuvântul 11001.

Algoritmul

Mai întâi avem nevoie de o funcție care primește ca parametru o mulțime de stări și calculează în ce alte stări mai putem ajunge prin ε-tranziții. Intrarea este automatul ⟨Q, Σ, δ, q0, F⟩ și mulțimea de stări States, iar ieșirea este o supermulțime a acestor stări, formată din stările în care se poate ajunge prin ε-tranziții. Această operație o vom numi ε-închiderea mulțimii States.

FunctionEpsilonClosure(⟨Q,Σ,δ,q0,F⟩,States)NextStates←∅ForEachq∈StatesDoNextStates←NextStates∪{q}∪δ(q,ε)EndForIfNextStates∖States=∅DoReturnStatesElseReturnEpsilonClosure(⟨Q,Σ,δ,q0,F⟩,NextStates)EndIfEndFunction

Această funcție o folosim în funcția care va simula funcționarea automatului nedeterminist. Intrarea este automatul, cuvântul de intrare w = w1w2… wn și mulțimea de stări în care se află automatul în acel moment. Ieșirea este răspunsul Da sau Nu, după cum automatul acceptă sau nu cuvântul dat.

FunctionComputeNFA(⟨Q,Σ,δ,q0,F⟩,w,States)Ifw=ϵDoIfStates∩F≠∅DoReturnYESElseReturnNOEndIfEndIfNextStates←∅ForEachq∈StatesDoNextStates←NextStates∪δ(q,w1)EndForNextStates←EpsilonClosure(⟨Q,Σ,δ,q0,F⟩,NextStates)ReturnComputeNFA(⟨Q,Σ,δ,q0,F⟩,w2w3…wn,NextStates)EndFunction

Dacă vrem să verificăm dacă automatul acceptă cuvântul w, apelăm funcția astfel: ComputeNFA(⟨Q, Σ, δ, q0, F⟩, w, EpsilonClosure(⟨Q, Σ, δ, q0, F⟩, {q0})).

Surse

Capitole: Automat finit, Automat complet, Automat finit nedeterminist, Simularea AFN, Conversia AFN în AFD