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]
}