A state may have two or more arcs emanating from it
labeled with the same symbol.
When the symbol occurs in the input, either arc may be followed.
A state may have one or more arcs emanating from it
labeled with l
(the empty string) .
These arcs may optionally be followed without looking at the
input or consuming an input symbol.
Due to nondeterminism, the same string may cause an nfa to end up in one of several different states, some of which may be final while others are not. The string is accepted if any possible ending state is a final state.
There are three ways, two feasible and one not yet feasible, to simulate the second alternative:
Here is a rough outline of such an implementation:
function nfa (state A) returns Boolean: local state B, symbol x; for each l transition from state A to some state B do if nfa (B) then return True; if there is a next symbol then { read next symbol (x); for each x transition from state A to some state B do if nfa (B) then return True; return False; } else { if A is a final state then return True; else return False; }One problem with this implementation is that it could get into an infinite loop if there is a cycle of l transitions. This could be prevented by maintaining a simple counter (How?).
function nfa (state set A) returns Boolean: local state set B, state a, state b, state c, symbol x; for each a in A do for each l transition from a to some state b do add b to B; while there is a next symbol do { read next symbol (x); B := f; for each a in A do { for each l transition from a to some state b do add b to B; for each x transition from a to some state b do add b to B; } for each l transition from some state b in B to some state c not in B do add c to B; A := B; } if any element of A is a final state then return True; else return False;
A nondeterministic finite acceptor or nfa is defined by the quintuple
A DFA is just a special case of an NFA that happens not to have any null transitions or multiple transitions on the same symbol. So DFAs are not more powerful than NFAs.
For any NFA, we can construct an equivalent DFA (see below). So NFAs are not more powerful than DFAs. DFAs and NFAs define the same class of languages -- the regular languages.
To translate an NFA into a DFA, the trick is to label each state in the DFA with a set of states from the NFA. Each state in the DFA summarizes all the states that the NFA might be in. If the NFA contains |Q| states, the resultant DFA could contain as many as |2Q| states. (Usually far fewer states will be needed.)
State {A,B} lacks a transition for x.
From A, x takes us to A (in the NFA), and the null transition
might take us to B; from B, x takes us to B.
So in the DFA, x takes us from {A,B} to {A,B}.
State {A,B} also needs a transition for y. In the NFA, d(A,y)=C and d(B,y)=C, so we need to add a state {C} and an arc y from {A,B} to {C}.
In the NFA, d(C,x)=A,
but then a null transition might or might not take us to B,
so we need to add an arc x from {C} to {A,B}.
Also, there are two arcs from C labeled y, going to states B and C. So in the DFA we need to add the state {B,C} and the arc y from {C} to this new state.
In the NFA, d(B,x)=B and
d(C,x)=A
(and by a l
transition we might get back to B), so we need an x arc
from {B,C} to {A,B}.
d(B,y)=C, while d(C,y) is either B or C, so we have an arc labeled y from {B,C} to {B,C}.
We now have a transition from every state for every symbol in
S.
The only remaining chore is to mark all the final states.
In the original NFA, B was a final state,
so in the DFA, every state containing B is a final state.