Nondeterministic Finite Automata (NFA)

A step-by-step guide to understanding NFAs, Subset Construction, and epsilon-transitions

Based on CS154/CS305 lecture materials (Ullman)

Use Arrow Keys or the buttons below to navigate. Press S to step through animations.

1

The Big Picture

Where does this lecture fit?

All recognize the SAME languages! (the Regular Languages) +---------+ +---------+ +-----------+ | DFA | <----> | NFA | <----> | epsilon- | | | | | | NFA | +---------+ +---------+ +-----------+ ^ ^ | | Only one that "Free" transitions | can actually (no input consumed) | be executed | on a computer Easiest to design -------+ This lecture teaches you HOW to convert between them.

Why care?

NFAs are much easier to design (fewer states, more flexibility). But computers can only run DFAs (one state at a time). So we need a way to convert NFA -> DFA. That's the Subset Construction.

2

Quick Recap: What's a DFA?

Before we learn NFAs, let's remember DFAs

A DFA (Deterministic Finite Automaton) has:

  • Exactly one current state at any time
  • For each state + input symbol, there is exactly one next state
  • No choices, no ambiguity
Input: "01" Step 0: in state A (start) Step 1: read '0' -> go to B (only option) Step 2: read '1' -> go to C (only option) Done: C is accept? -> YES or NO

Analogy: Following GPS

A DFA is like following GPS directions. At every intersection, you're told exactly one way to turn. There are no choices -- you just follow the instructions.

----0---> ----1---> -->( A ) ( B ) (( C )) <---1---- <---0---- start state: A accept state: C (double circle) Every state has exactly one arrow per symbol.
3

So What's an NFA?

The key difference: CHOICE

An NFA (Nondeterministic Finite Automaton) changes two rules:

  • From one state on one input, there can be zero, one, or MANY possible next states
  • The NFA can be in several states at once (or conceptually, it explores all paths simultaneously)

Acceptance Rule

An NFA accepts a string if ANY sequence of choices leads to a final state. It only needs one successful path.

Analogy: A Maze

Imagine you're in a maze with forking paths. A DFA is like a maze where every junction has exactly one door. An NFA is like a maze where junctions can have multiple doors (or even zero doors!).

The NFA "accepts" if there exists some path through the maze from start to exit. It's as if you can clone yourself at every fork and explore all paths at once.

NFA: "guesses right" -->( q0 )---0--->( q0 ) (stay) | +---0--->( q1 )---1--->(( q2 )) On input '0' from q0: choice 1: stay in q0 choice 2: move to q1 Both happen simultaneously!
4

NFAs in the Real World

You've been using nondeterminism your whole life

🔍

Spell-Checker

When you type "helo", the spell-checker simultaneously considers "hello", "help", "halo", "hero" -- exploring multiple correction paths at once, just like an NFA.

Each candidate is a parallel "branch" of computation.

🗺

GPS Navigation

Your GPS shows 3 routes simultaneously -- via highway, through downtown, scenic route. An NFA explores all paths; a DFA would commit to just one.

If ANY route reaches the destination, you accept it.

💻

grep / Regex

When you run grep "ab*c", it compiles to an NFA internally. The engine explores multiple match positions simultaneously.

That's why regex is fast -- NFA parallelism!

The Pattern

In every example, the system explores multiple possibilities at once and succeeds if any one works out. That's exactly what an NFA does -- parallel exploration with existential acceptance.

5

Why Nondeterminism Matters

It's a design tool, not a physical machine

Nondeterminism = Description Power

An NFA lets you describe WHAT to recognize, not HOW to recognize it. You say "the string ends with 01" and the NFA just guesses when the ending starts.

Design Advantage

NFAs are often exponentially more compact. An NFA for "n-th symbol from the end is 1" needs ~n states. The equivalent DFA needs ~2n states!

Composability

Want L1 ∪ L2? Just add a new start state with epsilon-transitions to both NFAs. Try doing that with DFAs -- it's much harder!

Common Misconception

"NFAs are more powerful than DFAs."

FALSE! They recognize exactly the same languages. Nondeterminism gives you design convenience, not extra power. The subset construction proves this.

Foreshadowing: P vs NP

The "N" in NP stands for Nondeterministic Polynomial time. Same idea, grander scale: "if I could magically guess the right answer, could I verify it quickly?"

For finite automata, nondeterminism doesn't add power. For polynomial time... that's the biggest open question in CS!

6

DFA vs NFA: Side by Side

DFA (Deterministic)

delta(q, a) = ONE state "From state q, reading symbol a, go to exactly ONE state."
  • Always in exactly one state
  • Every state has exactly one transition per input symbol
  • No dead ends (total function)
  • Easy to simulate on a computer

NFA (Nondeterministic)

delta(q, a) = SET of states "From state q, reading symbol a, go to any of THESE states." (could be 0, 1, or many states)
  • Can be in multiple states simultaneously
  • A state may have 0 or many transitions per symbol
  • Dead ends allowed (just kills that path)
  • Easier to design (more compact)

The Punchline

Despite looking more powerful, NFAs recognize exactly the same languages as DFAs -- the regular languages. NFAs are just a more convenient notation. We can always convert NFA -> DFA.

7

Formal Definition of an NFA

The 5-tuple: same components as a DFA, one key difference

An NFA is a 5-tuple (Q, Σ, δ, q0, F):

SymbolMeaningSame as DFA?
QFinite set of statesYes
ΣInput alphabetYes
δTransition functionDIFFERENT!
q0Start state (one state)Yes
FSet of final/accept statesYes

The Key Difference: δ

DFA: δ(q, a) = one state (a single state p)

NFA: δ(q, a) = a SET of states (like {p, r, s} or even {} )

That's it! The only formal difference is that δ returns a set instead of a single state.

DFA: delta(q0, 'a') = q1 (one answer) NFA: delta(q0, 'a') = {q1,q3} (multiple answers) NFA: delta(q2, 'b') = {} (no answer = dead end)
8

Example: Moves on a Chessboard

The slides' first example -- let's break it down carefully

The Setup

Imagine a 3x3 chessboard. The squares alternate in color (like a real chessboard):

+-----+-----+-----+ | 1 | 2 | 3 | | red | BLK | red | +-----+-----+-----+ | 4 | 5 | 6 | | BLK | red | BLK | +-----+-----+-----+ | 7 | 8 | 9 | | red | BLK | red | +-----+-----+-----+

Building the NFA

  • States = the 9 squares (1 through 9)
  • Alphabet = {r, b}
    • r = "move to an adjacent red square"
    • b = "move to an adjacent black square"
  • Start state = square 1 (top-left)
  • Accept state = square 9 (bottom-right, opposite corner)

Why is this an NFA?

From square 5 (center), reading 'r', you could move to 1, 3, 7, or 9. That's four choices -- impossible in a DFA, natural in an NFA!

9

Chessboard: The Transition Table

Where can you go from each square?

"Adjacent" = shares an edge or corner (king's moves in chess).

Stateδ(_, r)δ(_, b)
-> 1{5}{2, 4}
2{1, 3, 5}{4, 6}
3{5}{2, 6}
4{1, 5, 7}{2, 8}
5{1, 3, 7, 9}{2, 4, 6, 8}
6{3, 5, 9}{2, 8}
7{5}{4, 8}
8{5, 7, 9}{4, 6}
* 9{5}{6, 8}

-> = start, * = accept

Reading the table

Row "5", column "r" says {1,3,7,9}. This means: "from center square 5, if you move to an adjacent red square, you could go to any corner."

Does the NFA accept "rr"?

Start: {1} Read 'r': from 1, go to {5} Read 'r': from 5, go to {1,3,7,9} 9 is in the final set, and 9 is an accept state. So: ACCEPT! (Shortest path: 1 → 5 → 9, moving through red squares only.)
10

Try It Yourself: NFA Simulator

Watch the NFA for "ends with 01" process your string step by step

q0 0, 1 0 q1 1 q2

NFA: accepts strings over {0,1} that end with "01"

Active states: -
11

Extended Transition Function

How δ works on entire strings, not just single symbols

We need to extend δ(q, a) -- which handles one symbol -- to δ(q, w) -- which handles an entire string w.

The definition (by induction):

Base case: δ(q, ε) = {q}

"Reading the empty string from q, you're still just at q."

Inductive case: δ(q, wa) = ⋃ δ(p, a) for all p in δ(q, w)

"To process string wa: first process w to get a set of states S. Then, from each state in S, follow the transition on symbol a. Union all results."

Analogy: Spreading Water

Think of the NFA as a network of pipes. You pour water in at the start state. At each symbol, water flows through all possible transitions. The water "spreads" to all reachable states simultaneously. At the end, if water reaches any accept state, the string is accepted.

Language of an NFA

A string w is accepted if δ(q0, w) contains at least one final state.

The language L(N) = { w | δ(q0, w) ∩ F ≠ ∅ }

12

NFAs and DFAs are Equivalent!

The most important theorem of this lecture

Theorem

For every NFA, there exists a DFA that accepts exactly the same language. And vice versa.

Direction 1: DFA -> NFA (trivial)

Every DFA is already an NFA! Just wrap the single next-state in a set:

If the DFA has: delta_D(q, a) = p (single state) Make the NFA: delta_N(q, a) = {p} (set containing one state) The NFA always has sets of size 1, so it behaves identically to the DFA.

Direction 2: NFA -> DFA (the hard part!)

This requires the Subset Construction -- the central algorithm of this lecture.

Heads up: exponential blowup

If the NFA has n states, the equivalent DFA can have up to 2n states! (one for each subset of NFA states). In practice it's usually much less, but the worst case is real.

13

Subset Construction: The Idea

The core insight behind converting NFA to DFA

Core Insight

An NFA can be in a set of states at once. A DFA must be in one state at a time. Solution: make each DFA state represent a set of NFA states!

NFA is in states {q1, q3, q5} | | becomes ONE DFA state v DFA state named "{q1,q3,q5}"

Each DFA state is named by a set, but it IS a single state in the DFA. Don't confuse the name with multiple states!

The Construction Recipe

Given NFA (Q, Σ, δN, q0, F), build DFA:

DFA componentHow to build it
States2Q = all subsets of Q
AlphabetSame Σ
Start state{q0}
Accept statesAny subset containing a member of F
δD(S, a)Union of δN(q, a) for all q in S

Critical point

{p, q} is a single DFA state whose name happens to be a set. Don't think of it as "being in two places."

14

Subset Construction: Step by Step

Let's convert the chessboard NFA to a DFA (lazy construction)

NFA Transition Table (reference)

rb
-> 152,4
21,3,54,6
352,6
41,5,72,8
51,3,7,92,4,6,8
63,5,92,8
754,8
85,7,94,6
*956,8

Building the DFA (lazy -- only states we need)

Step 1: Start state = {1} {1} --r--> delta(1,r) = {5} NEW {1} --b--> delta(1,b) = {2,4} NEW Step 2: Process {5} {5} --r--> {1,3,7,9} NEW {5} --b--> {2,4,6,8} NEW Step 3: Process {2,4} {2,4} --r--> {1,3,5} U {1,5,7} = {1,3,5,7} NEW {2,4} --b--> {4,6} U {2,8} = {2,4,6,8} (seen) Step 4: Process {1,3,7,9} (accept -- contains 9) --r--> {5}U{5}U{5}U{5} = {5} (seen) --b--> {2,4}U{2,6}U{4,8}U{6,8} = {2,4,6,8} (seen) Step 5: Process {2,4,6,8} --r--> {1,3,5}U{1,5,7}U{3,5,9}U{5,7,9} = {1,3,5,7,9} NEW --b--> {4,6}U{2,8}U{2,8}U{4,6} = {2,4,6,8} (self-loop!) ...continue until no new states appear.
15

Chessboard: Completed DFA

The final result after subset construction

DFA Staterb
-> {1}{5}{2,4}
{5}{1,3,7,9}{2,4,6,8}
{2,4}{1,3,5,7}{2,4,6,8}
* {1,3,7,9}{5}{2,4,6,8}
{2,4,6,8}{1,3,5,7,9}{2,4,6,8}
{1,3,5,7}{1,3,5,7,9}{2,4,6,8}
* {1,3,5,7,9}{1,3,5,7,9}{2,4,6,8}

* = accept (contains state 9)

Observations

  • The NFA had 9 states. Worst case DFA: 29 = 512 states!
  • But lazy construction found only 7 reachable states. Much better!
  • Accept states are those whose set contains 9 (the NFA's accept state)
  • Notice {2,4,6,8} loops to itself on 'b' -- black squares lead to black squares via black moves. You can never reach 9 (red) from black squares via 'b'!

"Lazy" vs "Full" construction

We only built states we could actually reach from {1}. The "full" construction would enumerate all 512 subsets -- most would be unreachable waste!

16

Simpler Example: NFA for "string ends with 01"

A cleaner example to solidify the idea

NFA Definition

  • Alphabet: {0, 1}
  • States: {q0, q1, q2}
  • Start: q0  |  Accept: {q2}
Transitions: q0 --0--> {q0, q1} "see 0: stay OR guess this is the final 01" q0 --1--> {q0} "see 1: keep waiting" q1 --1--> {q2} "saw 0, now see 1: accept!" q1 --0--> {} "saw 0, see 0: dead end" q2 --0--> {} "already accepted, dead end" q2 --1--> {} "already accepted, dead end" 0 1 -->(q0)----->(q0) -->(q0)----->(q0) \ 0 \ 1 (q1)---------->((q2))

The NFA's "guessing" strategy

On seeing a 0, state q0 has a choice:

  1. "This 0 might not be the second-to-last character" -> stay in q0
  2. "This 0 might BE the second-to-last character!" -> also go to q1

It pursues both guesses simultaneously. If the guess was wrong (q1 doesn't see a '1' next), that branch dies. If right, it reaches q2!

Why this is hard as a DFA

A DFA can't "guess." It has to somehow remember it saw a 0 while also continuing to process more input. The subset construction handles this automatically.

17

Subset Construction for "ends with 01"

Converting the 3-state NFA to a DFA

NFA transitions (reference)

01
-> q0{q0, q1}{q0}
q1{}{q2}
* q2{}{}

Subset Construction

Start: {q0} {q0}: --0--> delta(q0,0) = {q0,q1} NEW --1--> delta(q0,1) = {q0} (self) {q0,q1}: --0--> delta(q0,0) U delta(q1,0) = {q0,q1} U {} = {q0,q1} (self) --1--> delta(q0,1) U delta(q1,1) = {q0} U {q2} = {q0,q2} NEW {q0,q2}: (ACCEPT -- contains q2) --0--> {q0,q1} U {} = {q0,q1} (seen) --1--> {q0} U {} = {q0} (seen) DONE! No new states discovered.

Resulting DFA

DFA State01
-> {q0}{q0,q1}{q0}
{q0,q1}{q0,q1}{q0,q2}
* {q0,q2}{q0,q1}{q0}
Visually: 0 1 0 -->[{q0}] ---> [{q0,q1}] ---> [{q0,q1}] ^ <--- | <--- | | 1 | 0 | | v 1 | +--------[*{q0,q2}]<--------+ | ^ +--+ (b goes to {q0,q1})

Result

Only 3 DFA states (out of 23=8 possible). The empty set {} and states like {q1}, {q2}, {q1,q2}, {q0,q1,q2} are all unreachable from {q0}.

18

Interactive Subset Construction

Watch the algorithm build a DFA from the "ends with 01" NFA, step by step

NFA Reference

q0 0, 1 0 q1 1 q2
01
-> q0{q0, q1}{q0}
q1{}{q2}
* q2{}{}
Click "Next Step" to begin...

DFA Being Built

DFA State01
19

Why Does Subset Construction Work?

Proof sketch (by induction on string length)

What we need to show

For any string w: δN(q0, w) = δD({q0}, w)

"The set of NFA states after reading w equals the single DFA state (which is named by that set) after reading w."

Base Case: w = ε (empty string)

δN(q0, ε) = {q0} = δD({q0}, ε)

Both just stay at the start.

Inductive Step: w = xa (string x then symbol a)

Assume it works for x: δN(q0, x) = δD({q0}, x) = S

Then for w = xa:

NFA side: delta_N(q0, xa) = Union of delta_N(p, a) for all p in S DFA side: delta_D({q0}, xa) = delta_D(S, a) = Union of delta_N(p, a) for all p in S They're computed the same way!

In plain English

The DFA state after reading w literally IS the set of all NFA states after reading w. The DFA's transition function was defined to make this true. So of course it works!

20

Epsilon-NFA (ε-NFA)

Adding "free" transitions that consume no input

What's new?

An ε-NFA has everything an NFA has, plus transitions on the special symbol ε (epsilon).

ε-transitions

An ε-transition lets the automaton move from one state to another without reading any input. It's a "free move" -- spontaneous, no input consumed.

Analogy: Secret Passages

Think of ε-transitions as secret passages in a maze. You can walk through them at any time without using a key (input symbol). They're like hidden shortcuts between rooms.

Example ε-NFA

A B C E F D B --> 1 E --> 0 C --> 1 D --> 1 F --> 0 D --> 0 D --> ε B --> ε C --> ε

Solid arrows = real transitions (consume input). Dashed arrows = ε (free moves).
E can teleport to B and C via ε. B can teleport to D.

The transition table now has an extra ε column:

01ε
-> A{E}{B}
B{C}{D}
C{D}
* D
E{F}{B,C}
F{D}
21

Epsilon-Closure: CL(q)

Click a state to watch its ε-closure expand step by step

Definition

CL(q) = the set of all states you can reach from q by following zero or more ε-transitions.

Note: q itself is always in CL(q) (zero ε-transitions = stay put).

A B C E F D 1 0 1 1 0 0 D --> ε B --> ε C --> ε

Regular transitions dimmed. ε-transitions highlighted — these are what closure follows.

Explore ε-closure

Click a state to compute CL(q):

Click any state above to visualize its ε-closure...

Follow the chain!

CL(E) isn't just {E, B, C}. Since B has its own ε-transition to D, you must follow that too! CL(E) = {E} ∪ {B,C} ∪ CL(B) ∪ CL(C) = {E, B, C, D}.

Try clicking E to see the chained closure in action.

22

Extended δ for ε-NFA

Processing strings in an ε-NFA means accounting for "free moves" at every step

The algorithm: δ-hat(q, w)

Base: δ̂(q, ε) = CL(q)

"Before reading anything, you can already be in any state reachable via ε-transitions."

Induction: δ̂(q, xa) is computed:

  1. Compute S = δ̂(q, x)   [states after reading x]
  2. For each state p in S, look up δ(p, a)   [follow real transition on 'a']
  3. Take the closure of each result   [follow ε-transitions after]
  4. Union everything

Worked example: δ̂(A, "01")

Step 0: Start delta-hat(A, epsilon) = CL(A) = {A} Step 1: Read '0' From A, delta(A, 0) = {E} Take closure: CL({E}) = {E, B, C, D} So delta-hat(A, "0") = {B, C, D, E} Step 2: Read '1' From B: delta(B, 1) = {C}, CL = {C} From C: delta(C, 1) = {D}, CL = {D} From D: delta(D, 1) = {}, CL = {} From E: delta(E, 1) = {}, CL = {} Union = {C, D} So delta-hat(A, "01") = {C, D} D is an accept state => "01" is ACCEPTED!
23

Converting ε-NFA to ordinary NFA

Eliminating ε-transitions by "baking them in"

The recipe

Given ε-NFA with transition function δE, build an ordinary NFA with δN:

Same states, same alphabet, same start state.

New transitions: δN(q, a) =

  1. Start with CL(q) -- everywhere you can be before reading 'a'
  2. From each state in CL(q), follow the real transition on 'a'
  3. Union all results (but do NOT take closure after -- that will be handled by the next step's closure)

New accept states F': any state q where CL(q) contains a state in F.

(If you can reach an accept state via ε alone, you're accepting too.)

Example result

ε-NFA

01ε
->A{E}{B}
B{C}{D}
C{D}
*D
E{F}{B,C}
F{D}

Ordinary NFA

01
->A{E}{B}
*B{C}
C{D}
*D
*E{F}{C,D}
F{D}

What changed?

  • ε column removed entirely
  • E on '1': CL(E)={E,B,C,D}. B--1-->{C}, C--1-->{D}. So δN(E,1)={C,D}
  • B and E become accept states (CL(B)={B,D} and CL(E)={E,B,C,D} both contain D)
24

Challenge: Does This NFA Accept?

Test your understanding -- trace the computation!

Question 1 of 3

How to solve it

  1. Start with the set containing just the start state
  2. For each symbol in the string, compute the union of all transitions from all active states
  3. After the last symbol, check: does the final set contain an accept state?
25

Challenge: Build the Subset Construction

Fill in the DFA transition table from this NFA

NFA (accepts strings ending with "ab")

States: {q0, q1, q2} Start: q0 | Accept: {q2} Alphabet: {a, b} q0 --a--> {q0, q1} q0 --b--> {q0} q1 --a--> {} q1 --b--> {q2} q2 --a--> {} q2 --b--> {}
ab
-> q0{q0, q1}{q0}
q1{}{q2}
* q2{}{}

Fill in the DFA table

Click each ? cell to select the correct set of states.

26

Challenge: Spot the Bug!

A student did subset construction but made a mistake. Can you find it?

NFA (accepts strings ending with "10")

01
-> p0{p0}{p0, p1}
p1{p2}{}
* p2{}{}

Student's Subset Construction

One cell is WRONG. Click it!

Common Mistakes in Subset Construction

  • Forgetting to union: When multiple NFA states are active, you must union ALL their transitions
  • Missing the empty set: If no transitions exist, the result is {} (not omitted!)
  • Wrong accept states: A DFA state is accepting if it contains ANY NFA accept state
27

Summary: The Complete Picture

Everything connects

+------------------+ subset +------------------+ eliminate +------------------+ | | construction | | epsilon-trans | | | DFA |<-------------- | NFA |<--------------- | epsilon-NFA | | | | | | | | (1 state at a | (may blow up | (multiple states | (use closure | (free moves + | | time, easy to | to 2^n | at once, more | to absorb | real moves) | | implement) | states) | compact) | epsilon-moves) | | +------------------+ +------------------+ +------------------+ | ^ ^ | trivial (just wrap | trivial (it's a | +---------in singleton sets)---------+ special case) ----------+

Key Takeaways

28

Cheat Sheet

Quick reference for exams

Subset Construction (NFA -> DFA)

1. DFA start state = {q0} (NFA start in a set) 2. For each new DFA state S = {p1,...,pk}: For each symbol a: delta_D(S, a) = Union of delta_N(pi, a) for i = 1..k 3. DFA accept states = any S containing a member of F 4. Repeat until no new states appear (use lazy construction -- only reachable states)

ε-NFA -> NFA

1. Same states Q, alphabet Sigma, start q0 2. delta_N(q, a) = Union of delta_E(p, a) for all p in CL(q) 3. F' = { q | CL(q) intersects F } (any state that can epsilon-reach an accept state becomes accepting)

ε-Closure

CL(q) = {q} union { all states reachable from q by following only epsilon-arrows } To compute: BFS/DFS following only epsilon-edges from q. CL(set S) = Union of CL(q) for q in S

Common Mistakes to Avoid

  • Don't forget: {p,q} is ONE DFA state, not two
  • CL() is transitive -- follow the full chain
  • NFA accepts if ANY path succeeds
  • DFA might need the ∅ (dead) state
  • In ε-NFA->NFA, update accept states F' too!
29

Select states in this set