Subset Construction
The Subset Construction is an algorithm that carries out a conversion from a nondeterministic automaton to its deterministic equivalent.
Equivalence of DFAs and NFAs
Given two automata and that accept the same language are said to be equivalent. For every NFA , there is a DFA equivalent to .
Converting NFA to DFA
Given an NFA as follows, turn it into an equivalent DFA.
digraph {
rankdir=LR
init[shape=point]
node[shape=doublecircle]; s;
node[shape=circle];
init->s
s->r [label=b]
s->q [label=ε]
q->s [label=a]
r->q [label=a]
r->q [label=b]
r->r [label=a]
}In a DFA, we are not allowed multiple choices, being stuck or to use -jumps. We need to define:
- new states: named after subsets of the original NFA’s states
- new initial state: the set containing the original NFA’s initial state, plus all states that are reachable from it by some -jumps
- new favourable states: those subsets that contain at least one of the original NFA’s favourable states
digraph {
init[shape=point]
node[shape=doublecircle]; s, sq, sr, sqr;
node[shape=circle];
init->sq
s [label="{s}"]
sq [label="{s,q}"]
sr [label="{s,r}"]
sqr [label="{s,q,r}"]
0 [label="{}"]
r [label="{r}"]
q [label="{q}"]
qr [label="{q,r}"]
}The new states are named after subsets of the old states:
digraph {
label="for each symbol x in the input alphabet"
rankdir=LR
P->a
a[label="?"]
}Where is the set of all those states that are reachable from some state in the set , either by a -arrow or by an -arrow followed by possibly one or more -jumps (but not -jump then -arrow).
In a DFA every state must have one -arrow out and one -arrow out. We being with the initial state an compute where two arrows go from it:
We look at the NFA again to find that:
- from we cannot reach anything by an -arrow
- from we can reach by an -arrow
- from we can reach by an -arrow followed by an -jump
Hence the -arrow from state goes to state itself.
- from we can reach by a -arrow
- from we cannot reach anything by a -arrow
The -arrow from state goes to state .
Next, for every obtained new state, we compute where the -arrow and the -arrow goes from it. We do this until there are no newly obtained states.
Final DFA
digraph {
rankdir=LR
init[shape=point]
node[shape=doublecircle]; sq, sqr;
node[shape=circle];
init->sq
sq [label="{s,q}"]
sqr [label="{s,q,r}"]
0 [label="{}"]
r [label="{r}"]
q [label="{q}"]
qr [label="{q,r}"]
sq->sq [label=a]
sq->r [label=b]
r->qr [label=a]
r->q [label=b]
qr->sqr [label=a]
qr->q [label=b]
q->sq [label=a]
q->0 [label=b]
sqr->sqr [label=a]
sqr->qr [label=b]
0->0 [label=a]
0->0 [label=b]
}