✖

Simulatie van een niet-deterministische automaat

Als we een niet-deterministische automaat hebben en willen weten of hij een gegeven woord accepteert, kunnen we de automaat omzetten naar een deterministische, we kunnen het op de gok proberen, of we kunnen een algoritme gebruiken dat de werking van de NFA simuleert.

Principe van het algoritme

Het principe laten we zien aan een geschikt voorbeeld. Neem deze automaat:

Dit is een niet-deterministische eindige automaat die een bepaalde taal accepteert. Welke taal, hoeft ons nu helemaal niet te interesseren. We laten zien hoe de berekening van zo'n automaat voor het invoerwoord 11001 eruit kan zien. De gedachtegang is als volgt: we verwerken een symbool van het woord en kijken waar we overal heen kunnen gaan dankzij meerdere overgangen voor hetzelfde symbool. Al die toestanden onthouden we en in de volgende stap gaan we ervan uit dat we “in al die toestanden tegelijk zitten”, en we kijken vanuit die toestanden verder waar we heen kunnen.

We onthouden dus een verzameling toestanden waarin we ons kunnen bevinden, en het nog niet gelezen deel van het woord. Aan het begin hebben we dus het paar ⟨{q0}, 11001⟩. We beginnen in toestand q0 (de begintoestand) en de invoer is het woord 11001. De automaat ziet er zo uit; rood en vet is de toestand waarin we zitten:

Het eerste symbool is 1. Vanuit toestand q0 is er maar één overgang voor het symbool 1, dus we komen in toestand q1. We onthouden het paar ⟨{q1}, 1001⟩. De automaat ziet er zo uit:

We gaan verder. Het nog niet gelezen deel van het woord is 1001, dus we zoeken weer overgangen voor 1. Dat zijn er nu twee — terug naar toestand q0 en naar toestand q3. We gaan nu naar beide toestanden tegelijk. We onthouden dus het paar ⟨{q0, q3}, 001⟩.

Wat is hier de logica van? We weten dat er een pad bestaat om met het woord 11 vanuit de begintoestand zowel in toestand q3 als in toestand q0 te komen. We weten nog niet welke tak ons van pas komt, dus onthouden we er gewoon allebei. We gaan verder. De invoer is het symbool 0. Nu moeten we zowel naar de overgangen vanuit q0 kijken als naar de overgangen vanuit q3. Vanuit toestand q0 lopen overgangen naar de toestanden q1 en q2, vanuit toestand q3 loopt een overgang terug naar q1. We nemen al deze toestanden mee, zodat we het paar ⟨{q1, q2}, 01⟩ krijgen:

In deze stap zijn we echter nog niet klaar. We zien dat vanuit toestand q2 een epsilonovergang naar toestand q4 loopt. We weten dat we een epsilonovergang “op elk moment kunnen nemen”, zonder een volgend teken te lezen. Met andere woorden: zonder een volgend symbool van het invoerwoord te lezen, kunnen we nog naar toestand q4 gaan. We voegen toestand q4 dus toe aan de toestanden waarin we ons kunnen bevinden: ⟨{q1, q2, q4}, 01⟩. De automaat zouden we zo kleuren:

Vervolgens is de invoer 0. We kijken waar we heen kunnen vanuit die drie toestanden waarin we zitten. Vanuit q1 kunnen we nergens heen, want er ontbreekt een overgang voor 0. De berekening in deze tak eindigt. Vanuit toestand q4 komen we ook nergens. Vanuit toestand q2 komen we terug in toestand q2. Maar omdat vanuit toestand q2 weer een epsilonovergang naar toestand q4 loopt, kunnen we ook in toestand q4 komen. Vanuit de verzameling toestanden {q1, q2, q4} komen we met het symbool 0 dus in de verzameling toestanden {q2, q4}, en we krijgen het paar ⟨{q2, q4}, 1⟩:

Tot slot is de invoer het symbool 1. Vanuit toestand q2 komen we nergens, de berekening in deze tak eindigt. Vanuit toestand q4 komen we echter in de toestanden q3 en q5. We krijgen het paar ⟨{q3, q5}, ε⟩:

De automaat heeft nu het hele woord gelezen en “bevindt zich” in twee toestanden: q3, q5. Omdat minstens één daarvan een eindtoestand is, accepteert de automaat het woord 11001.

Algoritme

Eerst hebben we een functie nodig die als parameter een verzameling toestanden neemt en berekent in welke toestanden we met behulp van epsilonovergangen nog kunnen komen. De invoer is dus een automaat ⟨Q, Σ, δ, q0, F⟩ en een verzameling toestanden States, en de uitvoer is een bovenverzameling van deze toestanden, waarin we met behulp van epsilonovergangen kunnen komen. Deze bewerking noemen we de epsilonafsluiting van de verzameling States.

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

Deze functie gebruiken we in de functie die de werking van een niet-deterministische automaat simuleert. De invoer is de automaat, het invoerwoord w = w1w2… wn en de verzameling toestanden waarin de automaat zich op dat moment bevindt. De uitvoer is het antwoord Ja of Nee, al naargelang de automaat het gegeven woord accepteert of niet.

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

Als we willen controleren of de automaat het woord w accepteert, roepen we de functie zo aan: ComputeNFA(⟨Q, Σ, δ, q0, F⟩, w, EpsilonClosure(⟨Q, Σ, δ, q0, F⟩, {q0})).

Bronnen

Hoofdstukken: Eindige automaat, Totale automaat, Niet-deterministische eindige automaat, Simulatie van een niet-deterministische automaat, Omzetting van NFA naar DFA