✖

Simulering av ikke-deterministisk automat

Hvis vi har en ikke-deterministisk automat og vil finne ut om den aksepterer et gitt ord, kan vi omforme automaten til en deterministisk, vi kan prøve oss fram på en eller annen måte, eller vi kan bruke en algoritme som simulerer virkemåten til NFA-en.

Prinsippet bak algoritmen

Prinsippet viser vi best på et passende eksempel. La oss ha denne automaten:

Dette er en ikke-deterministisk endelig automat som aksepterer et språk. Hvilket, trenger vi overhodet ikke å bry oss om nå. Vi skal vise hvordan beregningen i en slik automat kan se ut for inputordet 11001. Tanken er at vi behandler ett symbol fra ordet og ser hvor vi kan gå på grunn av flere overganger for samme symbol. Vi husker alle disse tilstandene, og i neste steg antar vi at vi er «i alle disse tilstandene samtidig», og vi er interessert i hvor vi kan komme videre fra disse tilstandene.

Vi husker altså en mengde av tilstander vi kan befinne oss i, og den delen av ordet som ikke er lest. I begynnelsen har vi derfor paret ⟨{q0}, 11001⟩. Vi begynner i tilstanden q0 (starttilstanden), og input er ordet 11001. Automaten ser slik ut, og tilstanden vi er i, er uthevet med rødt og fet skrift:

Det første symbolet er 1, og fra tilstanden q0 går det bare én overgang for symbolet 1, så vi kommer til tilstanden q1. Vi husker paret ⟨{q1}, 1001⟩. Automaten ser slik ut:

Vi fortsetter. Den delen av ordet som ikke er lest, er 1001, så vi leter igjen etter overganger for 1. Nå er det to — tilbake til tilstanden q0 og videre til tilstanden q3. Vi går nå til begge tilstandene samtidig. Vi husker altså paret ⟨{q0, q3}, 001⟩.

Hva er logikken i dette? Vi vet at det finnes en vei fra starttilstanden som med ordet 11 tar oss både til tilstanden q3 og til tilstanden q0. Ennå vet vi ikke hvilken gren som kommer til å passe, så vi husker rett og slett begge. Vi fortsetter. Nå har vi symbolet 0 som input. Nå må vi se både på overgangene fra q0 og på overgangene fra q3. Fra tilstanden q0 går det overganger til tilstandene q1 og q2, og fra tilstanden q3 går det en overgang tilbake til q1. Vi tar med alle disse tilstandene, og da får vi paret ⟨{q1, q2}, 01⟩:

Men vi er ikke ferdige med dette steget ennå. Vi ser at det fra tilstanden q2 går en epsilonovergang til tilstanden q4. Vi vet at vi kan «gå når som helst» etter en epsilonovergang uten å lese noe tegn til. Med andre ord — uten å lese et nytt symbol fra inputordet kan vi også flytte oss til tilstanden q4. Vi legger derfor tilstanden q4 til blant tilstandene vi kan befinne oss i: ⟨{q1, q2, q4}, 01⟩. Automaten ville vi farget slik:

Videre er input 0. Vi ser på hvor vi kan flytte oss fra de tre tilstandene vi er i. Fra q1 kan vi ikke flytte oss noen steder, for overgangen for 0 mangler. Beregningen i denne grenen slutter. Fra tilstanden q4 kommer vi heller ikke noen steder. Fra tilstanden q2 kommer vi tilbake til tilstanden q2. Men siden det igjen går en epsilonovergang fra tilstanden q2 til tilstanden q4, kan vi også komme til tilstanden q4. Fra mengden av tilstander {q1, q2, q4} kan vi altså for symbolet 0 komme til mengden av tilstander {q2, q4}, og vi får paret ⟨{q2, q4}, 1⟩:

Til slutt har vi symbolet 1 som input. Fra tilstanden q2 kommer vi ingen steder, og beregningen i denne grenen slutter. Fra tilstanden q4 kommer vi derimot til tilstandene q3 og q5. Vi får paret ⟨{q3, q5}, ε⟩:

Automaten har nå lest hele ordet og «befinner seg» i to tilstander: q3, q5. Siden minst én av dem er en sluttilstand, aksepterer automaten ordet 11001.

Algoritmen

Først trenger vi en funksjon som tar en mengde av tilstander som parameter og regner ut hvilke tilstander vi i tillegg kan komme til ved hjelp av epsilonoverganger. Input er altså automaten ⟨Q, Σ, δ, q0, F⟩ og mengden av tilstander States, og output er en supermengde av disse tilstandene, der vi kan komme til ved hjelp av epsilonoverganger. Denne operasjonen kaller vi epsilontillukningen av mengden States.

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

Denne funksjonen bruker vi i funksjonen som skal simulere virkemåten til den ikke-deterministiske automaten. Input er automaten, inputordet w = w1w2… wn og mengden av tilstander automaten befinner seg i akkurat nå. Output er enten svaret YES eller NO, alt etter om automaten aksepterer det gitte ordet eller ikke.

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

Hvis vi vil sjekke om automaten aksepterer ordet w, kaller vi funksjonen slik: ComputeNFA(⟨Q, Σ, δ, q0, F⟩, w, EpsilonClosure(⟨Q, Σ, δ, q0, F⟩, {q0})).

Kilder

Kapitler: Endelig automat, Total automat, Ikke-deterministisk endelig automat, Simulering av ikke-deterministisk automat, Omforming av NFA til DFA