The purpose of this step is to construct a λ-free NFA M' such that L(M') = L(M). (By λ-free is meant that there are no λ-transitions.)
To aid in the description, we start with a definition:
Definition: For a state p, λ-closure(p) = { q : there is a walk from p to q labeled λ}
In other words, q ∈ λ-closure(p) if you can get to state q from state p via a walk in which every transition is labeled λ. (In particular, p ∈ λ-closure(p) because there is a walk of length zero satisfying this condition.)
The construction of M' from M = (Q, Σ, δ, q0, F) is as follows:
M' = (Q, Σ, δ', q0, F'), where
In other words, (p,a,q) ∈ δ' iff there exist states r and s such that
Assume that M = (Q, Σ, δ, q0, F) is a λ-free NFA.
Then M' = (2Q, Σ, δ', {q0}, F') is a DFA such that L(M) = L(M'), where
While the above description of M' is correct, it is likely to include a large number of (useless) states that cannot be reached from the initial state. Indeed, in many cases the vast majority of states in M' will not be reachable from the initial state.
For this reason, it makes sense to construct the DFA M' in such a way that no unreachable states are ever "created". The following algorithm accomplishes that. The algorithm uses Q' and δ' as variables, with the idea being that their final values correspond to the state set and transition relation, respectively, of M'. Also used as variables are P and S, whose values are subsets of the state set Q of M. Because each state in M' is identified by a subset of Q, P and S simultaneously can refer to states in M'.
Q' = { {q0} }; // {q0} is the initial state in M' δ' = ∅; // begin with an empty set of transitions queue = empty_queue; // queue holds states in M' for which outgoing queue.enqueue({q0}); // transitions have not yet been computed while (!queue.isEmpty()) { P = queue.frontOf(); queue.dequeue(); // Take a state P off the queue and, for each for each a ∈ Σ { // symbol a, determine the state S to which S = ∅; // there should be a transition from P on a for each p ∈ P { for each q such that (p,a,q) ∈ δ { S = S ∪ {q}; } } if (S ∉ Q') { Q' = Q' ∪ {S}; // Add S as a new state in M' and put S on the queue.enqueue(S); // queue to later compute its outgoing transitions } δ' = δ' ∪ { (P,a,S) }; // Add a transition labeled a } // from P to S (in M') } |