4.6.2 · D3Theory of Computation

Worked examples — Finite automata — DFA - formal definition (5-tuple), state diagrams

2,405 words11 min readBack to topic

Before we start, one reminder in plain words so no symbol is unearned:

Recall The four symbols we reuse everywhere

::: the finite set of circles (states). ::: the alphabet — the letters the machine is allowed to read. ::: "from circle , reading letter , hop to which circle?" — always exactly one answer. ::: run the whole string from , one letter at a time, and report the final circle. Accept iff that circle is in (the double-circle set).


The scenario matrix

Every DFA question is really a combination of these "cells". The examples below are labelled by the cell(s) they cover, and together they hit every row.

Cell What makes it different Covered by
A. Normal accept ordinary string that lands in Ex 1, Ex 4
B. Normal reject ordinary string that lands outside Ex 1, Ex 3
C. Empty string "read nothing" — answer depends only on Ex 2
D. Degenerate / trap missing arrows → hidden dead state; string that can never recover Ex 3
E. Self-loop / irrelevant symbol a letter that must NOT change memory Ex 4
F. Length / counting memory remember a count modulo , not the count itself Ex 4, Ex 5
G. Substring / suffix memory remember "how much of a target pattern matched so far" Ex 6
H. Real-world word problem translate an English spec into a machine Ex 7 (tokenizer)
I. Exam twist given only the tuple, forecast the language, then verify Ex 8

Geometric/diagram examples get a figure so you can watch the token hop.


Example 1 — Cells A & B: normal accept and normal reject

Forecast: State is a trap for good news — once you see a single 1 you can never leave . So the machine accepts iff the string has at least one 1. has a 1 (expect accept); has none (expect reject).

Look at the figure — state means "no 1 yet", state means "seen a 1".

Figure — Finite automata — DFA -  formal definition (5-tuple), state diagrams
  1. Trace from . . Why this step? Each 0 is a self-loop (still no 1 seen); the final 1 flips us into the accept region .
  2. Check membership. End state accepted.
  3. Trace from . . Why this step? Only 0s means we never trigger the escape arrow to .
  4. Check membership. End state rejected.

Verify: contains a 1 → should be in the language ✓. contains no 1 → correctly rejected ✓. This covers Cell A (accept) and Cell B (reject).


Example 2 — Cell C: the empty string

Forecast: "Read nothing" cannot flip any state, so you stay put at the start. Since start is not accepting, expect reject.

  1. Apply the base case of . By definition , so . Why this step? has no last letter, so the recursion never fires — reading nothing changes nothing.
  2. Check membership. rejected.

Verify: The rule " is accepted iff " says: here , so reject. Matches ✓. (Sanity: contains zero 1s, so it should not be in "contains at least one 1" — correct.)


Example 3 — Cell D: the hidden dead / trap state

Forecast: A DFA's must be total — every (state, letter) pair needs a target. The missing arrows secretly all go to a dead state that loops on everything and never accepts. So any string that "goes off the drawn path" dies. starts with the wrong letter (expect reject); over-runs past ab (expect reject).

The figure shows the drawn arrows in orange and the implied dead-state arrows in dashed grey.

Figure — Finite automata — DFA -  formal definition (5-tuple), state diagrams
  1. Complete the machine. Add with , and route every missing pair to : . Why this step? Without this the object is not a DFA at all — you cannot leave a transition undefined.
  2. Trace . . Why this step? The first letter b is not the path's expected a, so we fall into the trap immediately, and traps are inescapable.
  3. Check. rejected.
  4. Trace . . Why this step? We correctly matched ab and reached , but the extra a has nowhere legal to go, so it dies.
  5. Check. rejected.

Verify: The language is exactly . ✓ rejected; ✓ rejected. Only the exact string (, ending in ) is accepted. Cell D covered.


Example 4 — Cells A, E, F: parity with an irrelevant symbol

Forecast: Count the as: abba has two as → even → expect accept. The bs should slide by harmlessly.

The figure: the a-arrows cross between the two circles (they flip parity), the b-arrows are loops (they do nothing).

Figure — Finite automata — DFA -  formal definition (5-tuple), state diagrams
  1. Read a. . Why? First a makes the count odd.
  2. Read b. . Why? A b is irrelevant to counting as → self-loop, parity unchanged.
  3. Read b. . Why? Same — still one a seen.
  4. Read a. . Why? Second a flips odd→even.
  5. Check. End state accepted.

Verify: abba has exactly occurrences of a, and is even, so it should be accepted ✓. This shows Cell E (self-loop on the irrelevant b) and Cell F (memory = count mod 2).


Example 5 — Cell F pushed further: divisibility by 3

Forecast: , divisible by 3 → expect accept. We only ever store the remainder (one of 3 values), never the whole number — that is why finite memory suffices.

Let's build the transitions from the rule :

  1. Read 1. : . Why? Value so far , remainder .
  2. Read 1. : . Why? Value so far , which is .
  3. Read 0. : . Why? Value so far , still .
  4. Check. End state accepted.

Verify: , and ✓. Try a non-multiple mentally: , , ends → rejected, and is not divisible by 3 ✓. See Regular languages and the Pumping Lemma for why "divisible by " is always regular.


Example 6 — Cell G: substring memory ("contains ab")

Forecast: Scan for an a immediately followed by a b. In baab the substring ab appears (positions 3–4). Expect accept. State is a good trap — once you've found ab, nothing can undo it.

The figure shows progress: how far along the pattern ab we are.

Figure — Finite automata — DFA -  formal definition (5-tuple), state diagrams
  1. Read b. . Why? No a seen yet; a leading b cannot begin ab.
  2. Read a. . Why? We now hold a candidate a, waiting for a b.
  3. Read a. . Why? Another a doesn't complete ab, but it's still a fresh candidate — stay in .
  4. Read b. . Why? a then b = pattern complete!
  5. Check. End state accepted.

Verify: baab literally contains ab (chars 3–4) ✓. Compare with ba: , ends → rejected, and ba has no ab ✓. This "how-much-matched" idea is exactly what Regular expressions compile down to.


Example 7 — Cell H: a real-world word problem (mini tokenizer)

Forecast: A number literal = at least one digit and no stray characters. So dd should accept, empty should reject (need at least one digit), and dx should reject (illegal character). This is the classic Cell H translation of English → machine.

Design. , start , . Why start ∉ F? Because (no digits at all) must be rejected — so the start state cannot be accepting. Why err is a trap? Once a bad character appears the whole token is invalid, forever.

  1. Trace dd. . Why? First digit reaches the accepting num; more digits self-loop there.
  2. Check. accepted — "42" is a valid literal.
  3. Trace . . Why? Empty input — base case, stay at start.
  4. Check. rejected — an empty token is not a number ✓.
  5. Trace dx. . Why? Good first digit, then an illegal character drops us into the trap.
  6. Check. rejected — "4a" is not a valid integer literal ✓.

Verify: "42" accept ✓, "" reject ✓, "4a" reject ✓ — exactly what a real lexer's integer rule does. This same shape appears when building the scanner in Lexical analysis / tokenizers.


Example 8 — Cell I: the exam twist (given tuple → forecast language)

Forecast: 0 swaps ; 1 never moves. Accepting state is , and we start at . So we accept iff the number of 0s is even. This is the Myhill–Nerode "what does each state remember?" reasoning in reverse.

  1. Identify what each state means. "even number of 0s so far", "odd". Why? Only 0 toggles, and it toggles every time — that is exactly parity.
  2. Trace . . Why? Two 0s toggle twice (back to start); the 1s do nothing.
  3. Check. End accepted. ( has two 0s → even ✓.)
  4. Trace . . Why? Two 0s (even) with a harmless 1 between them.
  5. Check. End accepted. ( has two 0s → even ✓.)

Verify: . Both traces have an even count of 0s and both accept ✓. A quick reject-check: alone → , ends , rejected, and one 0 is odd ✓. Note this is the same language as Example 4 read over a different alphabet — an NFA or subset construction could also produce it.


Recall Self-test: match each string to its cell and answer

on 000 — accept or reject, which cell? ::: Reject (Cell B); no 1 ever seen, stays in . on any machine — what single fact decides it? ::: Whether (Cell C). A string that "goes off the drawn arrows" ends where? ::: In the hidden dead/trap state, always rejected (Cell D). Divisible-by-3 machine on 110 — accept? ::: Accept; , and (Cell F). Contains-ab machine on ba — accept? ::: Reject; reaches but never a following b, (Cell G).