4.6.16 · D3Theory of Computation

Worked examples — Universal Turing machine

2,375 words11 min readBack to topic

This page is a drill. The Universal Turing machine parent note told you what is and why it exists. Here we run it — by hand — across every kind of situation a machine can be in when you hand and to .

Before we start, two symbols you will see everywhere, defined from zero:

We also use the arrow to mean "halts" (stops, gives an answer) and to mean "loops forever" (never stops). These come straight from the parent's halting notation.


The scenario matrix

Every UTM run lands in exactly one of these cells. If you can hand-simulate all of them, you have seen every case class this topic can throw.

# Cell (case class) The tricky thing it tests
A accepts after finitely many steps basic fetch–execute–halt
B rejects after finitely many steps must mirror reject, not accept
C loops forever () loops too — the halting-detection trap
D Empty input (degenerate data) head starts on blank; rule for blank
E No matching rule (partial ) missing table row = implicit halt
F Two-state / two-rule multi-step accept 's state stays fixed while 's grows
G Self-reference code = data; seeds Diagonalization
H Word problem (real interpreter analogy) maps UTM onto software you use
I Exam twist — "how many states does need for a huge ?" fixed finite control

The examples below are labelled with the cell(s) they cover.

Figure — Universal Turing machine

Example A — accepts (the happy path)

  1. Initialize. Tape 3 (state) ; Tape 2 (data) with the head on that 0. Why this step? must start in 's start configuration — same as pressing "run".
  2. Fetch. scans Tape 1 for the rule whose left side is . It finds . Why this step? This is the "look up " line — find which instruction applies.
  3. Execute. Write 1 on Tape 2, move the head R, set Tape 3 . Why this step? Apply the extracted exactly.
  4. Halt check. New state is accepts. Why this step? 's halting must mirror 's: reached accept, so does .

Verify: Direct run of on 0: reads 0, writes 1, goes to → accepts, tape 1. produced accept + tape 1. Same output ✔. Contract holds.


Example B — rejects (mirror the reject)

  1. Initialize. Tape 3 , head reads 0. Why? Start config again.
  2. Fetch. Match → rule . Why? Look up the instruction.
  3. Execute. Write 0, move R, Tape 3 . Why? Apply it faithfully.
  4. Halt check. State is rejects. Why? Halting is not the same as accepting. copies the kind of halt.

Verify: rejects. rejects. Match ✔. Lesson: "halted" splits into two outcomes and must pick the same one would.


Example C — loops forever (the halting trap)

  1. Initialize. Tape 3 , head on the first symbol. Why? Start config.
  2. Fetch. Match . Why? Look up the instruction — it always matches.
  3. Execute. Keep symbol, move R, stay in . Why? Apply it.
  4. Halt check. State is still , never or go to step 2 again. Why? Nothing signals a halt, so the loop repeats — forever.

Verify: on this input never halts (). also never halts (). Match ✔.


Example D — Empty input (degenerate data)

  1. Initialize. Tape 2 is entirely blank; the head sits on a . Tape 3 . Why? An empty input means the working tape is all blanks — the head still reads something, namely . Degenerate inputs never leave the head "reading nothing."
  2. Fetch. Match . Why? The rule for the blank symbol is a genuine table row; we look it up like any other.
  3. Execute. Keep , move R, Tape 3 . Why? Apply it.
  4. Halt check. accept.

Verify: accepts (its only reachable rule leads to ). accepts. Match ✔. Key idea: empty input ≠ undefined behaviour; the blank symbol is a first-class symbol.


Example E — No matching rule (partial )

  1. Initialize. Tape 3 , head reads 1. Why? Start config.
  2. Fetch. scans the whole of Tape 1 for a left side . It reaches the end marker 111 without a match. Why? is a partial function — some (state, symbol) pairs simply have no row.
  3. Halt with no move. By convention, a missing transition means halts and rejects (there is nowhere to go). therefore enters its own reject. Why? must adopt the same convention 's definition uses; "no rule" is a defined, halting outcome, not a bug in .

Verify: has no applicable move → halts, rejects. rejects. Match ✔.


Example F — Multi-step accept (two rules, fixed controller)

  1. Iteration 1 — fetch. State , reads 0 → rule . Why? Look up the first instruction.
  2. Iteration 1 — execute. Keep 0, move R, Tape 3 . Not a halting state → loop again. Why? is neither accept nor reject.
  3. Iteration 2 — fetch. State , reads 1 → rule . Why? Look up the next instruction from the new state.
  4. Iteration 2 — execute + halt. Keep 1, move R, Tape 3 accept. Why? Now we hit an accepting state; halts to mirror it.

Verify: : , accepts after 2 steps. fired its loop 2 times and accepted. Match ✔. Notice: 's own state set never grew — the growing trace lives on the tape, not in 's control (this is Cell I's punchline, previewed).


Example G — Self-reference (code = data)

  1. Type-check. is a finite string over the same alphabet that reads. Why? A program's encoding is just a string; eats strings. So is a perfectly valid input.
  2. Outer runs. It reads off Tape 1 and simulates an inner copy of . Why? Nothing forbids simulating a machine that happens to equal the simulator.
  3. Inner runs on . The inner copy reads and simulates . Why? That is inner-'s whole job.
  4. Outcome equals . Peeling two layers, the net result is . Why? Each simulation layer is faithful, so composing them changes nothing but speed.

Verify (with a concrete inner machine): take = bit-flipper from Example A and . Then = inner- on = = accept, tape 1. Same as Example A ✔. This "programs are data" fact is the hinge of Diagonalization, the Halting Problem, and the Stored-Program Computer idea.


Example H — Word problem (the real-world interpreter)

  1. Identify . The fixed CPU + operating system that never changes between apps. Why? is the one finite controller that stays constant — like your silicon.
  2. Identify . The program you launch (browser.exe, game.bin). Swapping apps = swapping on Tape 1. Why? Different = different behaviour, same . That is von Neumann Architecture: program lives in memory as data.
  3. Identify . The data you feed the app: the URL, the save file, the source .c. Why? is the input string on the simulated tape.
  4. Read off the contract. "CPU running program on data" = .

Verify (dimensional/analogy check): count the pieces. Direct: {program , data } → output. UTM: {, , } → output. The extra piece is the reusable interpreter, and it maps 1-to-1 onto "the hardware you didn't have to rebuild." Consistent ✔. This is precisely the Church-Turing Thesis made physical.


Example I — Exam twist: how many states does need for a giant ?

  1. Locate where 's size lives. All states appear inside on Tape 1 — as data. Why? Encoding turns "'s complexity" into string length, not into 's wiring.
  2. Recall 's loop. only ever does: read, scan-for-rule, extract, write/move, halt-check. That is a fixed number of states, chosen once when was designed. Why? The loop's shape does not depend on which we picked.
  3. Answer. needs a constant number of states — independent of . Not , not even : it is . Why? "Fixed CPU, variable program" — the whole point of universality.

Verify: The parent's [!formula] states "'s state count is independent of ." Our answer is consistent ✔. Contrast with a multi-tape subtlety — see Multi-tape vs Single-tape TM: converting to single-tape keeps the state count finite too (only the tape/steps blow up, not the controller).


Coverage check

Recall Did we hit every cell?

A accept · B reject · C loop · D empty input · E missing rule · F multi-step · G self-reference · H word problem · I exam twist. All nine cells covered. Every case an can be in — accept, reject, loop, degenerate, undefined — has a faithful response, and none of them requires to grow.

Which two distinct halting outcomes must mirror, and why can't it merge them?
Accept and reject; requires the same answer, and merging them would change the machine's language.
If loops on , what does do, and why not report the loop?
loops too; loop-detection for all is the undecidable Halting Problem.
Where does a huge 's complexity live inside ?
On the tape as the string 's own state set stays fixed and finite.
What makes legal?
Programs are encoded as strings over 's input alphabet, so is a valid input — code is data.