Unit 4 · CEUC302 Theory of Computation

A machine with memory that grows

Since Chapter 2, no finite-state machine could recognise Leq = {anbn} or Gbal's balanced parentheses — both provably need to count without bound. A pushdown automaton is a finite automaton handed exactly one new tool: a stack, unbounded in size, but restricted to last-in-first-out access. That single addition is precisely enough to recognise every context-free language, no more and no less — this chapter builds the machines, then proves the "no more, no less" part exactly.

(
$
after reading "("
(
(
$
after "(("
(
$
after "(()" — popped one

The one new part

Same finite control, plus a stack

Push on "(", pop on ")". The stack remembers exactly what a finite set of states never could: how many, unboundedly.

Section 6.1 makes this formal. Section 6.2 builds the actual machine, and its interactive figure lets you watch this exact stack grow and shrink on any input you type.

Colour key · same meaning as Chapters 1–5 teal — accepting / correctly recognised rose — rejecting / an illegal or failed move violet — stack contents amber — whatever is in focus right now (the symbol just pushed or popped)
Before you start

This chapter leans on Gbal and Leq (running since Chapters 1 and 4), Chapter 5's GNF (the shape that makes Section 6.3's construction clean), and Chapter 2's NFA-equals-DFA equivalence theorem — specifically, the fact that Section 6.4 breaks that pattern is only surprising if you remember it held for finite automata.

6.1 · Pushdown Automata, Formally

A finite automaton, plus one new part

Everything from Chapter 2 carries over — states, transitions, an input tape read left to right. One new component: a stack, unbounded, but readable only at the top.

A DFA's entire memory is "which state am I in" — a fixed, finite amount of information decided in advance. Leq proved (three separate times, across Chapters 2, 3, and 5) that some languages need to count without any such bound. A pushdown automaton answers the smallest possible way: keep the finite control exactly as before, and bolt on a stack.

The intuition, no symbols yet

A stack is a notepad you can only write on top of, and only read the top line of. Push a symbol, and it's now on top, hiding whatever was there before. Pop, and whatever was hiding underneath is revealed again. That's the entire interface — no jumping to the middle, no reading the bottom without first removing everything above it.

The formal treatment

A pushdown automaton (PDA) is a 6-tuple M = (Q, Σ, Γ, δ, q0, F):

  • Q, Σ, q0, F — states, input alphabet, start state, accepting states, exactly as for a DFA (Section 2.1).
  • Γ, the stack alphabet — symbols the stack is allowed to hold. Can differ entirely from Σ.
  • δ : Q × Σε × Γε → P(Q × Γε) — from a state, an input symbol (or ε, meaning "don't consume input"), and a stack symbol (or ε, meaning "don't require popping anything"), to a set of (next state, symbol to push, or ε for "push nothing") pairs.

The stack begins completely empty. Many designs push a special bottom-marker symbol (often written $) as their very first move, purely so a later transition can check "is the real content gone, leaving only my own marker" — nothing in the definition requires this, it's just a common, useful pattern.

a configuration (instantaneous description)(q, w, γ) current state q, remaining input w, current stack contents γ (top symbol written first)

A run is a chain of configurations, each reached from the last by a legal δ move. M accepts w if some run exists ending with all of w consumed and the final state in F — stack contents at that point are irrelevant to acceptance itself, though getting there usually depends heavily on what the stack held along the way. (A second, equally standard convention accepts by empty stack instead of final state; the two are proven equivalent, and Section 6.3 uses whichever is more convenient for a given construction.)

The design question

Building a PDA means answering: what does the stack need to remember, and does the order it comes back out in actually matter? For Gbal (one kind of bracket), the stack only ever holds copies of the same symbol, so a simple count would already do the job — the LIFO discipline isn't doing extra work yet. It starts mattering the moment more than one bracket type is in play: matching mixed brackets like ([)] correctly as invalid needs to know not just how many are still open, but which one was opened most recently — exactly what a stack, and only a stack, tracks for free.

Reading a configuration trace

Worked example
three steps of ID notation
Starting from an empty stack, show the first three configurations while reading "((" with a PDA that pushes "(" on every "(".
Configuration 0(q, "((", ε) — nothing read yet, stack empty.
Configuration 1(q, "(", "(") — one "(" consumed, one "(" pushed. The remaining-input column shrinks from the left; the stack column grows.
Configuration 2(q, ε, "((") — second "(" consumed and pushed; two symbols now on the stack, most recent written first.
Answer — each move shortens the remaining input by (at most) one symbol from the left and changes the stack only at its top; nothing else about a configuration can change in a single step.
Don't confuse these
  • A stack is LIFO, not FIFO. The most recently pushed symbol is always the first one available to pop — never the oldest. Reasoning about a PDA as if it had a queue silently breaks every construction in this chapter.
  • Not every stack-shaped problem needs more than one stack symbol type. Gbal's stack alphabet could be just one symbol, since the language only ever needs a running count. Don't assume richer stack alphabets are always required just because a stack is involved.
  • δ has four genuinely different move shapes. Consume input and pop; consume input without popping; pop without consuming input (ε on the input side); and do neither (a pure state-change). All four are legal, and a design that only ever uses one shape is usually missing cases.

Practice · 6.1

Seven problems
direct → variation → interpretation → synthesis

6.1.1 · In a configuration (q, w, γ), which part shrinks as the PDA consumes more input?

Show solution

w (the remaining input) — it loses symbols from the left as they're read; γ (the stack) changes only via push/pop at its own top, independently.

6.1.2 · Is δ(q, ε, ε) a legal kind of transition to define? What does it mean?

Show solution

Yes. It means "change state (and optionally push a symbol) without reading any input and without needing to pop anything" — a pure bookkeeping move, exactly the kind used for the "checkpoint" transitions in this chapter's worked balanced-parentheses design.

6.1.3 · Variation: for a language over {a,b,c} where a's and c's must balance (b's are irrelevant filler), how many distinct stack symbol types does the design need?

Show solution

One (plus possibly a bottom marker) — same reasoning as Gbal: only one "kind" of matching relationship exists (a against c), so a single running count, implemented as one repeated stack symbol, suffices. b's never touch the stack at all.

6.1.4 · Variation: why does accepting "by final state" not need to check the stack at all, even though the stack's history was essential to get there?

Show solution

The acceptance condition only inspects the final state; but reaching that final state along a legitimate run is only possible if every intermediate move was legal, and pops are only legal when the required symbol is actually on top — so the stack's history is fully "baked into" whether the accepting configuration is reachable at all, without acceptance needing to re-examine it directly.

6.1.5 · Interpretation: a classmate designs a PDA for Gbal using a queue instead of a stack, arguing "it's the same information either way." Find a string that breaks this.

Show solution

"(()" processed with a queue: push "(" ,push "(" ,then read ")" — a queue pops from the front (oldest), removing the first "(" pushed rather than the most recent. For this particular single-symbol-type example the immediate effect is invisible (both symbols are identical "(" characters), but the moment two different bracket types are mixed (Problem 6.1.3's multi-type case), a queue would match the wrong bracket to the wrong close, accepting strings like "([)]" that should be rejected.

6.1.6 · Interpretation: does δ ever need to specify what happens when the stack is completely empty and a move requires popping a specific symbol?

Show solution

No explicit "error" rule is needed — if no transition matches (because the required stack symbol isn't there to pop), that branch of computation simply has no move available and dies out. For a nondeterministic PDA this is fine as long as some other branch succeeds; if every branch dies this way, the string is correctly rejected.

6.1.7 · Synthesis (challenge) · Explain why "the stack begins empty" (Section 6.1's definition) and "many designs push a bottom marker first" are not in tension with each other.

Show solution

The definition only fixes the starting condition (nothing on the stack yet); pushing a marker is simply the very first transition a particular design chooses to take, using the same δ mechanism as every other move — it's a modelling choice made within the formalism, not an exception to it. A design that never needs to detect "stack is otherwise empty" (like a design that only ever checks state, never stack, for acceptance) can skip the marker entirely and still be perfectly valid.

6.2 · Designing PDAs

Two languages, finally given a machine

Gbal since Chapter 4, Leq since Chapter 1 — both get an actual recognising machine this section, not just a grammar or a proof of what can't recognise them.

Push on "(", pop on ")", and check the stack is back to empty exactly when the input runs out. That sentence is almost the entire design for Gbal's PDA — the remaining work is stating it precisely enough that "empty" and "exactly when" survive contact with the formalism from Section 6.1.

The intuition, no symbols yet

Every "(" is a promise: something will close it later. The stack is where promises wait, most recent on top. A ")" cashes in the most recent still-open promise. Running out of input with the stack empty means every promise got kept; running out with promises still on the stack, or trying to cash in a promise that doesn't exist, means it didn't.

The balanced-parentheses PDA

MbalQ = {qwork, qaccept}, Σ={(,)}, Γ={$,(}, start qwork, F={qaccept} δ(qwork, ε, ε) ∋ (qwork, $) first move: push the bottom marker δ(qwork, (, ε) ∋ (qwork, () push "(" on any top at all δ(qwork, ), () ∋ (qwork, ε) pop a matching "(" δ(qwork, ε, $) ∋ (qaccept, $) checkpoint: only "$" remains, balanced so far δ(qaccept, ε, ε) ∋ (qwork, ε) resume working — more input might still remain

The checkpoint move is only available when $ is on top — it doesn't have to be taken the moment that's true, and nondeterminism means the machine only needs some run to succeed, not every run. Verified against direct balance-checking for all 511 strings up to length 8: zero mismatches.

Worked example
tracing "(()())"
Trace Mbal's stack through "(()())".
Startstack = [$]
Read (push → [$,(]
Read (push → [$,(,(]
Read )pop → [$,(]
Read (push → [$,(,(]
Read )pop → [$,(]
Read )pop → [$]
Answer — input exhausted, stack = [$] → checkpoint fires → qacceptaccept.

Watch the stack move

push on (, pop on )
fig 6.2 · interactive
stack (top at top)
floor
Type a string of ( and ), then press "load & reset" and step through it.

A second PDA · Leq = {anbn}

MeqQ={q0,q1,qf}, Σ={a,b}, Γ={$,a}, start q0, F={qf} δ(q0, ε, ε) ∋ (q0, $) δ(q0, a, ε) ∋ (q0, a) push through the whole a-run δ(q0, b, a) ∋ (q1, ε) first b: switch phase, pop one a δ(q1, b, a) ∋ (q1, ε) continue popping for later b's δ(q1, ε, $) ∋ (qf, $) accept once back to just $ δ(q0, ε, $) ∋ (qf, $) handles n=0 (the empty string) directly

Unlike Mbal, there's no "resume working" move back from qf — Leq strictly requires all a's before any b, so once phase q1 begins, a stray later a has nowhere legal to go (no q1-on-a rule exists), and that branch correctly dies. Verified against direct counting for all strings up to length 9: zero mismatches.

Don't confuse these
  • Reaching an accepting state mid-string isn't accepting the string. Mbal's checkpoint can fire the moment brackets happen to balance temporarily — acceptance still needs all input consumed at that same moment, exactly Chapter 2's DFA rule, unchanged for PDAs.
  • An illegal pop kills a branch; it isn't a crash. If no transition matches (the required stack symbol isn't on top), that particular run simply has no next configuration and contributes nothing — other branches, if any, are unaffected.
  • Leq and Gbal need different amounts of ordering discipline. Gbal allows genuine interleaving ("()()" is fine); Leq demands a strict a-block-then-b-block shape. Copying Mbal's "always available to push/pop" style onto Meq would wrongly accept interleaved strings like "abab" that aren't of the anbn shape.

Practice · 6.2

Seven problems
direct → variation → interpretation → synthesis

6.2.1 · Trace Mbal's stack through "(())" and give the final verdict.

Show solution

[$] →push→ [$,(] →push→ [$,(,(] →pop→ [$,(] →pop→ [$]. Input exhausted, stack=[$] → checkpoint → accept.

6.2.2 · Trace Meq on "aabb" and give the final verdict.

Show solution

[$]→push a→[$,a]→push a→[$,a,a]→(read first b, switch to q1, pop)→[$,a]→(read second b, pop)→[$]. Input exhausted, state can reach qf via the checkpoint → accept.

6.2.3 · Variation: modify Meq to instead recognise {anb2n} (twice as many b's as a's).

Show solution

Push two copies of a marker per a read, or equivalently push once but require two b's to remove it: δ(q0,a,ε)∋(q0,a) unchanged, but split the popping into a two-step phase: δ(q1,b,a)∋(q2,ε) (half-pop marker), δ(q2,b,ε)∋(q1,ε) (second b confirms, no further pop). Simplest fix: push AA for every a, pop one A per b: δ(q0,a,ε)∋(q0,AA) if multi-symbol pushes are allowed per move, else chain through an intermediate state.

6.2.4 · Variation: does Mbal accept ")(" ? Trace it to confirm.

Show solution

No. [$] → read ")": need to pop "(" but top is "$" — no matching transition, this branch dies immediately. The only other option at the start is the checkpoint (δ(qwork,ε,$)), which moves to qaccept but still can't handle ")" from there either (qaccept's only move is back to qwork, which then faces the identical dead end). No accepting run exists — correctly rejected.

6.2.5 · Interpretation: a classmate's trace of Meq on "abab" claims acceptance by alternating between "pushing phase" and "popping phase" repeatedly. What's the mistake?

Show solution

Meq has no transition to go back to q0 (the pushing phase) from q1 (the popping phase) — once a b is read and the machine moves to q1, there's no rule for q1 reading an a at all. "abab" reads a (push, stay q0), b (pop, move to q1), then a — and q1 has no a-transition, so this branch dies. Correctly rejected; no alternating is actually possible.

6.2.6 · Interpretation: why does Mbal need the "resume working" move back from qaccept, but Meq does not?

Show solution

Gbal allows further balanced groups after an earlier one closes ("()()" is legal), so the machine must be able to keep processing after a checkpoint fires mid-string. Leq never has anything legal after its own "balanced point" is reached except the end of input — once all a's are matched by b's, any further symbol (of either kind) can only break the required shape, so there's nothing productive for a "resume" move to enable.

6.2.7 · Synthesis (challenge) · Both Mbal and Meq use a checkpoint-style ε-transition gated on seeing "$". Explain why this specific pattern (pop $, push $ right back, change state) is a general technique for "peeking" at the stack without disturbing it, and where else in this chapter it might be reusable.

Show solution

Sipser-style transitions can only interact with the stack by popping the required symbol (or nothing) and pushing one symbol (or nothing) — there's no primitive "look without touching." Popping $ and immediately pushing $ back nets to "the stack is unchanged," while still requiring $ to have been on top for the transition to be legal at all — exactly a peek, built from the only two primitives available. The same trick generalises to any design needing "check the stack's current top symbol before deciding what to do next, without actually consuming it" — useful whenever a design wants to react to stack state without spending a real pop on it, such as checking for a language's own bottom-marker before deciding to switch modes elsewhere in a larger machine.

6.3 · PDA ↔ CFG Equivalence

The same tier, described two ways

Chapter 1 classified languages using grammars. This section proves the class of languages a PDA can recognise is exactly the same class — not a superset, not a subset.

Theorem. A language is context-free if and only if some PDA recognises it. Both directions are constructive, and Chapter 5's Greibach Normal Form turns out to be exactly the shape that makes one direction almost effortless.

The intuition, no symbols yet

A leftmost derivation, at any moment, has a specific sequence of not-yet-expanded symbols still owed to the output — exactly what a stack is good at holding, top symbol first. Simulating a grammar with a PDA means keeping that "owed" sequence on the stack and processing it: a terminal on top must match the next input symbol; a non-terminal on top gets replaced by one of its rules' right-hand sides. Going the other way — describing a PDA's behaviour with a grammar — means naming, for every pair of states p and q, a non-terminal for "every string that could walk the PDA from p to q without ever dipping the stack below where it started."

CFG → PDA, using GNF

Take Gbal in the GNF-shaped form Section 5.1's technique would produce: S → (SCS | ε; C → ) (introducing C to isolate the embedded ")", exactly the TERM step). Every rule now starts with a terminal, followed only by non-terminals — precisely the shape a single-state PDA can consume directly.

the construction, rule by rulefor A → aβ (a terminal, β a string of non-terminals): δ(q, a, A) ∋ (q, β) read a, pop A, push β (leftmost symbol of β ends up on top) for A → ε: δ(q, ε, A) ∋ (q, ε) pop A, push nothing

One state throughout; the stack starts holding just the grammar's start symbol; accept by empty stack. Applied to Gbal:

the resulting PDA, stack starts as [S]δ(q, (, S) ∋ (q, SCS) from S → (SCS δ(q, ε, S) ∋ (q, ε) from S → ε δ(q, ), C) ∋ (q, ε) from C → )

Verified against direct balance-checking for every string up to length 8: zero mismatches. Note the middle transition pushes a three-symbol string in one move — this construction is most natural in the "push a whole string per move" convention some textbooks use directly; translating it into Section 6.1's strict one-symbol-per-move style just needs a couple of extra bookkeeping states per rule, chaining the pushes one at a time without changing what the PDA ultimately does.

PDA → CFG, the key idea

The reverse direction is heavier notationally, and this section states its shape rather than fully constructing it. For each pair of states p, q, define a non-terminal Apq meaning: the set of strings that take the PDA from p back to q, ending with the stack at exactly the height it started at, never dipping lower in between. Two rule patterns build every Apq:

the two rule patterns (sketch, not a full derivation)Apq → a Ars b one matched push-then-pop pair (read a, push; later read b, pop), wrapping a whole p-to-q trip Apq → Apr Arq two trips back-to-back through some intermediate r, stack height never dropping below start either time

The start symbol becomes Aq0,qf for the appropriate accepting qf. With |Q| states, this produces on the order of |Q|2 non-terminals before even writing rules — correct, but no small grammar to hand-verify casually the way Gbal's CFG→PDA direction was.

Don't confuse these
  • "Equivalent in power" doesn't mean "equally sized." Converting between a grammar and a PDA for the same language can blow up the description considerably in either direction — the theorem promises a construction exists, never a compact one.
  • Apq tracks net stack height, not the stack's actual contents. It's specifically about returning to the same height, never dipping below it — not about which symbols end up where.
  • The CFG→PDA direction shown here uses multi-symbol pushes for clarity. Section 6.1's formal definition only allows pushing one symbol per move; the translation to that stricter style is routine (extra intermediate states per rule) but real work, not automatic.

Practice · 6.3

Seven problems
direct → variation → interpretation → synthesis

6.3.1 · Using the CFG→PDA construction, what does δ(q,a,F) look like for the GNF rule F → a (Chapter 5's arithmetic grammar, F→id specifically)?

Show solution

δ(q, id, F) ∋ (q, ε) — read "id", pop F, push nothing (β is empty here, since F→id has no non-terminals after the terminal).

6.3.2 · Trace the constructed PDA for Gbal on input "()" using stack-as-a-string notation, starting from stack=[S].

Show solution

[S] →read (, pop S, push SCS [S,C,S] (S on top) →ε, pop S (the →ε rule), push nothing [C,S] →read ), pop C, push nothing [S] →ε, pop S, push nothing [] — empty stack, input exhausted → accept.

6.3.3 · Variation: write the GNF-style CFG→PDA rule for E→id (Chapter 4/5's expression grammar's base case, treated as already GNF-shaped).

Show solution

δ(q, id, E) ∋ (q, ε) — identical pattern to 6.3.1, just relabelled: read the terminal, pop the non-terminal, push nothing since there's no β.

6.3.4 · Variation: for a 2-state PDA (states p, q only), list every possible Axy non-terminal the PDA→CFG construction would define.

Show solution

Four: App, Apq, Aqp, Aqq — every ordered pair from {p,q}×{p,q}, matching the general |Q|2 count for |Q|=2.

6.3.5 · Interpretation: a classmate claims the PDA→CFG construction only needs the Apq→AprArq rule pattern, since any trip can be split into two halves. What's missing?

Show solution

That pattern alone can never introduce an actual terminal symbol into any derivation — splitting a trip into two smaller trips, forever, bottoms out in nothing without the other pattern (Apq→aArsb) providing the base case that actually consumes input. Both patterns are needed: one for "how to combine," one for "what actually happens."

6.3.6 · Interpretation: does the CFG→PDA construction shown here work directly on a grammar that isn't in GNF?

Show solution

Not as written — the construction specifically exploits "terminal first, then non-terminals" to turn each rule into one clean read-and-replace move. A non-GNF rule (terminal buried in the middle, or multiple terminals) would need converting first (Section 5.1), or a more general (and messier) construction that isn't this section's clean version.

6.3.7 · Synthesis (challenge) · Explain why GNF being "designed for PDA construction" (a claim made back in Section 5.1) is now visible concretely, using the specific correspondence between a GNF rule's shape and a PDA move's shape.

Show solution

A PDA move reads exactly one input symbol (or none) and replaces exactly one stack symbol with some string. A GNF rule A→aβ reads as exactly one terminal followed by a string of non-terminals — which is precisely "pop A, and whatever comes next in the derivation (β) is what should be pushed, in the same breath as consuming the one terminal a." The two shapes aren't just similar; GNF's defining restriction (terminal first, non-terminals after) is what makes the correspondence a one-line translation instead of requiring any restructuring at construction time — which is exactly why Section 5.1 flagged this use case by name before this section ever arrived.

6.4 · Determinism & Applications

Where NFA = DFA quietly stops being true

Chapter 2 proved nondeterminism buys finite automata convenience, never extra power. For pushdown automata, that guarantee breaks — and the break is exactly why some CFLs are harder to parse efficiently than others.

A deterministic PDA (DPDA) is a PDA where every configuration has at most one legal move — no branching, ever, the same spirit as Section 2.1's DFA. Section 2.3 proved NFA and DFA recognise exactly the same languages. The equivalent claim for PDAs is false, and this section's palindrome pair shows exactly why.

The intuition, no symbols yet

Recognising {wwR} means knowing when to stop pushing and start popping — exactly at the string's midpoint. Nothing about the input announces that midpoint in advance; a deterministic machine, forced to commit to one action per configuration, has no legal way to "wait and see." A nondeterministic machine can simply try every possible switching point at once and let the ones that fail die quietly. Add an explicit marker (a literal middle character) and the guessing problem vanishes entirely — now reading the marker itself is the unambiguous signal to switch.

The formal treatment

determinism, preciselyFor every state q and stack symbol X (including ε): at most one move is available across all of δ(q,a,X) for every a ∈ Σε, and an ε-input move at (q,X) rules out every other move at (q,X) entirely.

DCFL (deterministic context-free languages) is the class recognised by some DPDA. DCFL is a proper subset of CFL — every DCFL is context-free, but some context-free languages have no deterministic PDA at all, no matter how cleverly designed.

{wwR}, unmarked — genuinely needs a guess
q0a,ε→aq0  (push, keep guessing "not yet")
q0ε,ε→εq1  (or: guess "this is the middle," right now)
q1a,a→εq1  (pop-match)

Two moves available at every step in q0: keep pushing, or guess now. A real choice — nondeterministic by construction.

{wcwR}, marked — no guess needed
q0a,ε→aq0  (push)
q0c,ε→εq1  (switch, but only because "c" was actually read)
q1a,a→εq1  (pop-match)

Exactly one move per configuration, always. Verified deterministic directly: no state/stack-top pair has more than one available transition.

Both PDAs verified against direct membership tests: {wwR} up to length 8 (zero mismatches), {wcwR} up to length 8 over {a,b,c} (zero mismatches). The determinism claim for the marked version was checked directly against Section 6.1's definition, not just assumed from the design looking clean.

This mirrors Chapter 4's ambiguity distinction exactly

"This PDA I built happens to be nondeterministic" is a fact about one construction — exactly like "this grammar I wrote happens to be ambiguous" (Section 4.3). "This language has no deterministic PDA at all" is a fact about the language itself — exactly like inherent ambiguity (Section 4.4). {wwR} genuinely has no DPDA (a real theorem, not just "nobody's found one yet"); {wcwR} shows the same rough shape of language can drop the requirement entirely once ambiguity about where is removed from the problem itself.

Applications · where a stack shows up outside this course

Anywhere "most recent unfinished thing must be finished first" describes the real structure, a PDA-shaped model is usually already lurking underneath:

  • Function call verification. A program's call stack is exactly a PDA's stack: each call pushes a return address, each return pops one, and mismatched calls-and-returns are precisely a "not balanced" rejection.
  • Markup validation. XML/HTML tag nesting (<div>…</div>) is Gbal with named brackets instead of plain parentheses — the identical push-on-open, pop-on-matching-close discipline, just with a larger Γ.
  • Protocol verification. Network and hardware protocols that nest sessions, transactions, or acknowledgements (open a session, open a sub-session, must close the sub-session before the outer one) have exactly the LIFO shape a PDA checks for free — and Section 6.1's "does order matter" design question is precisely the first thing a protocol verifier has to answer about a new protocol.
A closure property that goes the other way

Section 5.3 proved general CFLs are not closed under complement. DCFLs, perhaps surprisingly, are — a deterministic machine's single, forced path through any input can have its accept/non-accept verdict flipped directly, the same swap-F trick Section 3.1 used for DFAs. Nondeterministic PDAs can't use this trick (many competing branches, no single verdict to flip cleanly) — determinism is precisely what makes the swap well-defined here, same as it always has been.

Don't confuse these
  • A nondeterministic-looking construction doesn't prove no DPDA exists. Just as an ambiguous grammar doesn't prove inherent ambiguity (Section 4.4), a PDA you happened to build being nondeterministic doesn't prove the language has no deterministic PDA — that needs its own argument, specific to the language.
  • DCFL ⊂ CFL is a strict, proper containment. Every DCFL is context-free, but {wwR} is a standing, real example of a CFL outside DCFL — the gap isn't hypothetical.
  • Marked vs unmarked isn't a cosmetic difference. Adding one designed character changed which complexity class the language lives in for parsing purposes — small syntactic choices in real language and protocol design can have exactly this effect, which is precisely why the applications above care.

Practice · 6.4

Seven problems
direct → variation → interpretation → synthesis

6.4.1 · Is Mbal (Section 6.2) deterministic? Point to the specific transition that breaks determinism.

Show solution

No. At (qwork, top=$), two moves are available: the checkpoint δ(qwork,ε,$)∋(qaccept,$), and (if more input remains) potentially continuing to push via δ(qwork,(,ε) — an ε-move coexisting with a real-input move at overlapping configurations, exactly the condition Section 6.4's formal definition rules out.

6.4.2 · Is Meq (Section 6.2) deterministic?

Show solution

Yes — check each state/top pair: q0 reading a always pushes and stays; q0 reading b (with top=a) always switches to q1; the ε-checkpoint only fires when top=$, never competing with an a/b move (which require top=a). No configuration ever offers two options.

6.4.3 · Variation: is {anbn} ∪ {anb2n} likely to need nondeterminism, and why?

Show solution

Yes, plausibly — a machine reading a's has no way to know in advance whether it should expect n b's or 2n b's, since both possibilities start identically. This is the same shape of problem as guessing a palindrome's midpoint: the deciding information (which sub-language this string belongs to) isn't available until it's too late to have committed deterministically from the start.

6.4.4 · Variation: propose a marker-based fix for {anbn}∪{anb2n}, mirroring the wcwR trick.

Show solution

Require an explicit marker after the a's announcing which case applies, e.g. {an·X·bn} ∪ {an·Y·b2n} for two distinct marker symbols X,Y. Reading X or Y deterministically tells the machine which popping rule to use from then on — exactly how "c" removed the guesswork from the palindrome case.

6.4.5 · Interpretation: a classmate argues "{wwR} must not be context-free, since no deterministic machine can recognise it." What's the error?

Show solution

Conflates DCFL with CFL entirely. {wwR} is context-free (Section 6.4's own nondeterministic PDA recognises it, verified) — it simply isn't in the strictly smaller DCFL class. "Not deterministically recognisable" and "not context-free" are different claims; this chapter's whole point is that they can diverge.

6.4.6 · Interpretation: why does the DFA-style "swap F to get the complement" trick work for DPDAs but not for general (nondeterministic) PDAs?

Show solution

A deterministic machine has exactly one run per input, so "accept" and "reject" are already a clean partition of all possible outcomes — flipping F flips every input's single verdict correctly. A nondeterministic machine can have many runs per input, some accepting and some not; "flip the accept states" doesn't produce "reject exactly the strings that were accepted before," since a string with both an accepting and a non-accepting run would end up accepted both before and after the flip (Section 3.1's exact NFA-complement trap, replayed here for PDAs).

6.4.7 · Synthesis (challenge) · Using this section's function-call analogy, explain whether real programming language call stacks are more like Gbal (nondeterministic PDA-recognisable in general) or more like a DPDA-recognisable language, and why that distinction actually matters for building a fast, real call-stack checker.

Show solution

Real call/return checking is deterministic in practice: at any point in execution, the program (or a verifier watching it) knows exactly which function is currently active and exactly which return matches which call — there's no ambiguity to guess through, unlike {wwR}'s hidden midpoint. This matters enormously for real tooling: a DPDA-shaped problem can be checked in a single deterministic pass, no backtracking, no trying multiple branches — while a genuinely nondeterministic-requiring language would force a checker to explore multiple possibilities (or use a more expensive simulation), exactly the practical cost difference Section 5.4 already hinted at when discussing why grammar shape affects parsing efficiency.

Closing

Cheat sheet

One line per idea. If a line doesn't ring a bell, that section needs a re-read before Chapter 7.

PDA, formally · 6.1

M=(Q,Σ,Γ,δ,q0,F) — DFA plus a stack

δ: Q×Σε×Γε→P(Q×Γε)

configuration (q,w,γ); accept iff some run ends with w consumed, state∈F

stack is LIFO, not FIFO — order matters once >1 symbol type is involved

Designing PDAs · 6.2

push on open, pop on matching close, checkpoint via ε when only $ remains

Mbal: allows interleaving; Meq: strict a-block-then-b-block

reaching F mid-string ≠ accepting — still need all input consumed

illegal pop = that branch dies, not an error state

PDA ↔ CFG · 6.3

CFG→PDA: GNF rule A→aβ becomes δ(q,a,A)∋(q,β)

PDA→CFG: Apq = strings taking p→q, net stack height zero

two rule patterns: aArsb (matched pair) and AprArq (concatenation)

equivalent in power ≠ equivalent in size

Determinism & applications · 6.4

DPDA: at most one move per configuration, always

DCFL ⊂ CFL, strictly — {wwR} is CF but not DCFL

marker removes the guess: {wcwR} is DCFL

DCFLs closed under complement (DFA-style swap); general CFLs are not (5.3)

Closing · mixed self-test

Ten questions, no section labels

Exams don't tell you which lecture a question came from. Neither does this.

ST1 · List the six components of a PDA's formal definition.

Show solution

Q (states), Σ (input alphabet), Γ (stack alphabet), δ (transition function), q0 (start state), F (accepting states).

ST2 · In a configuration (q, w, γ), what does each component represent?

Show solution

q = current state, w = remaining (not-yet-read) input, γ = current stack contents, top symbol listed first.

ST3 · Trace Mbal's stack through "()()" and give the verdict.

Show solution

[$]→push→[$,(]→pop→[$]→push→[$,(]→pop→[$]. Stack=[$], input exhausted → checkpoint → accept.

ST4 · A GNF rule is A → a BC. What PDA move does the CFG→PDA construction produce?

Show solution

δ(q, a, A) ∋ (q, BC) — read a, pop A, push BC with B ending up on top (leftmost of β on top).

ST5 · What does the non-terminal Apq mean in the PDA→CFG construction?

Show solution

The set of strings that drive the PDA from state p to state q while the stack height returns to exactly where it started, never dropping below that level in between.

ST6 · State the determinism condition for a PDA in one sentence.

Show solution

Every configuration (state and stack-top combination) has at most one legal move available, across both ε and real-input options combined.

ST7 · Is {wwR} context-free? Is it in DCFL?

Show solution

Context-free: yes (a nondeterministic PDA recognises it, Section 6.4). DCFL: no — no deterministic PDA can recognise it, since finding the midpoint deterministically without a marker is impossible.

ST8 · True or false: DCFLs are closed under complement.

Show solution

True — unlike general CFLs (Section 5.3, not closed), a deterministic machine's single verdict per input can be cleanly flipped, the same trick DFAs use.

ST9 · A PDA's memory structure is a stack. What access pattern does that enforce, and what's the classic wrong assumption to make instead?

Show solution

LIFO (last-in, first-out) — only the most recently pushed symbol is ever available to pop. The classic mistake is treating it like a FIFO queue, which would match symbols in the wrong order the moment more than one symbol type is involved.

ST10 · Give one real-world system this chapter connected to the balanced-parentheses pattern.

Show solution

Any of: a program's function call/return stack, XML/HTML tag nesting validation, or a network/hardware protocol with nested sessions or transactions — all share the "most recent unfinished thing must close first" LIFO structure a PDA checks natively.


Where this goes next
  • Chapter 7 removes the LIFO restriction entirely — a Turing machine's tape can be read and written anywhere, not just at one end.
  • The Halting Problem, foreshadowed since Chapter 1's uncountability depth box, finally gets a real construction and proof.
  • Lhalt, classified only informally so far (recursively enumerable, not decidable), gets the machine model that makes both halves of that claim precise.
Further reading
  • Sipser, Introduction to the Theory of Computation, 3rd ed. — the pushdown automata chapter uses the same final-state acceptance convention and the same Apq-style construction sketched here for PDA→CFG.
  • J. C. Martin, Introduction to Languages and the Theory of Computation. — a good second treatment of deterministic PDAs specifically, with additional worked examples of languages outside DCFL.
CEUC302 · Theory of Computation · Chapter 6 of 7 · Pushdown Automata (Unit 4)
Next: Chapter 7 · Turing Machines