✖

Simulering av en icke-deterministisk automat

När vi har en icke-deterministisk automat och vill ta reda på om den accepterar ett visst ord kan vi omvandla automaten till en deterministisk, vi kan pröva oss fram på något sätt, eller så kan vi använda en algoritm som simulerar hur en NFA arbetar.

Algoritmens princip

Vi visar principen med ett lämpligt exempel. Låt oss ta den här automaten:

Det är en icke-deterministisk ändlig automat som accepterar något språk. Vi behöver inte alls bry oss om vilket. Vi ska se hur beräkningen i en sådan automat kan se ut för ordet 11001. Tanken är att vi läser en symbol i ordet och tittar på alla tillstånd som vi kan komma till tack vare flera övergångar för samma symbol. Vi kommer ihåg alla dessa tillstånd, och i nästa steg utgår vi från att vi befinner oss ”i alla dessa tillstånd samtidigt” och undersöker vart vi kan komma härifrån.

Vi kommer alltså ihåg en mängd tillstånd som vi kan befinna oss i, och den del av ordet som ännu inte är läst. I början har vi därför paret ⟨{q0}, 11001⟩. Vi börjar i tillståndet q0 (starttillståndet) och indata är ordet 11001. Automaten ser ut så här, där tillståndet vi befinner oss i är markerat med rött och fetstil:

Den första symbolen är 1. Från q0 finns bara en övergång för symbolen 1, så vi kommer till q1. Vi kommer ihåg paret ⟨{q1}, 1001⟩. Automaten ser ut så här:

Vi fortsätter. Den olästa delen av ordet är 1001, så vi söker återigen övergångar för 1. Nu finns det två: tillbaka till q0 och vidare till q3. Vi går nu till båda tillstånden samtidigt. Vi kommer alltså ihåg paret ⟨{q0, q3}, 001⟩.

Vad är logiken i det här? Vi vet att det finns en väg från starttillståndet som med ordet 11 leder både till q3 och till q0. Ännu vet vi inte vilken gren som kommer att behövas, så vi kommer helt enkelt ihåg båda. Vi fortsätter. Nästa symbol i indata är 0. Nu måste vi titta på övergångarna både från q0 och från q3. Från q0 går övergångar till q1 och q2, och från q3 går en övergång tillbaka till q1. Vi tar med alla dessa tillstånd och får paret ⟨{q1, q2}, 01⟩:

Vi är dock inte klara med det här steget. Vi ser att det går en epsilonövergång från q2 till q4. Vi vet att vi kan ”gå längs” en epsilonövergång när som helst utan att läsa något mer tecken. Med andra ord kan vi flytta oss till q4 utan att läsa nästa symbol i indata. Vi lägger därför till q4 bland de tillstånd som vi kan befinna oss i: ⟨{q1, q2, q4}, 01⟩. Automaten skulle vi färglägga så här:

Därefter är nästa symbol i indata 0. Vi tittar på vart vi kan flytta oss från de tre tillstånden som vi befinner oss i. Från q1 kan vi inte flytta oss någonstans, eftersom övergången för 0 saknas. Beräkningen i den grenen tar slut. Inte heller från q4 kommer vi någonstans. Från q2 kommer vi tillbaka till q2. Men eftersom det återigen går en epsilonövergång från q2 till q4 kan vi också komma till q4. Från mängden av tillstånd {q1, q2, q4} kan vi alltså för symbolen 0 komma till mängden {q2, q4}, och vi får paret ⟨{q2, q4}, 1⟩:

Till sist har vi symbolen 1 i indata. Från q2 kommer vi ingenstans, och beräkningen i den grenen tar slut. Från q4 kommer vi däremot till tillstånden q3 och q5. Vi får paret ⟨{q3, q5}, ε⟩:

Automaten har nu läst hela ordet och ”befinner sig” i två tillstånd: q3, q5. Eftersom minst ett av dem är ett sluttillstånd accepterar automaten ordet 11001.

Algoritmen

Först behöver vi en funktion som tar en mängd tillstånd som parameter och beräknar vilka tillstånd vi dessutom kan komma till med hjälp av epsilonövergångar. Indata är alltså en automat ⟨Q, Σ, δ, q0, F⟩ och en mängd tillstånd States, och utdata är en övermängd av dessa tillstånd som innehåller de tillstånd som kan nås med epsilonövergångar. Den här operationen kallar vi epsilonslutningen av mängden States.

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

Den här funktionen använder vi i en funktion som simulerar hur en icke-deterministisk automat arbetar. Indata är automaten, ett indataord w = w1w2… wn och den mängd tillstånd som automaten för tillfället befinner sig i. Utdata är antingen svaret Ja eller Nej, beroende på om automaten accepterar ordet eller inte.

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

Om vi vill kontrollera om automaten accepterar ordet w anropar vi funktionen så här: ComputeNFA(⟨Q, Σ, δ, q0, F⟩, w, EpsilonClosure(⟨Q, Σ, δ, q0, F⟩, {q0})).

Källor

Kapitel: Ändlig automat, Total automat, Icke-deterministisk ändlig automat, Simulering av en icke-deterministisk automat, Omvandling av NFA till DFA