Theory of Computation
Level 3 — Production (from-scratch derivations, construct-from-memory, explain-out-loud) Time limit: 45 minutes Total marks: 60
Answer all questions. Show every construction step. Diagrams may be described as transition tables.
Q1. (10 marks) — Subset construction (from scratch) Consider the NFA over with states , start , accept , and transitions:
- ,
- has no outgoing transitions.
(a) Describe in one sentence the language . (2) (b) Carry out the subset construction to produce an equivalent DFA. Give the full transition table over the reachable subsets and mark start/accept states. (6) (c) State the number of reachable DFA states you obtained. (2)
Q2. (10 marks) — Pumping lemma (full proof from memory) Prove that is not regular. (a) State the pumping lemma for regular languages precisely (quantifier structure). (3) (b) Give the complete adversary-style proof, choosing an explicit string in terms of the pumping length . (7)
Q3. (12 marks) — CFG and CNF conversion (from scratch) Let grammar have start symbol and productions: (a) Give a leftmost derivation of the string and draw (as a bracketed structure) its parse tree. (3) (b) Convert to Chomsky Normal Form. Show each stage: remove -productions, remove unit productions, then convert to CNF. (9)
Q4. (10 marks) — PDA construction (build from memory) Construct a PDA (by empty stack) that accepts . (a) Give the formal 7-tuple with full transition function. (7) (b) Trace the accepting computation (sequence of configurations) on input . (3)
Q5. (10 marks) — Undecidability (diagonalization, explain-out-loud) (a) Define the language and state precisely what it means for a language to be decidable vs recognizable. (3) (b) Prove that the Halting Problem is undecidable using diagonalization. Structure your answer: assume a decider , build , and derive the contradiction . (7)
Q6. (8 marks) — NP-completeness (reduction + explanation) (a) State what it means for a language to be NP-complete (two conditions). (2) (b) Give a polynomial-time many-one reduction from 3-SAT to CLIQUE, describing the graph construction and why a satisfying assignment corresponds to a clique of the target size. (6)
Answer keyMark scheme & solutions
Q1 (10)
(a) (2) = all strings over containing the substring ; equivalently strings whose penultimate-path requires an then reaching . Since is a dead accept sink reached only via , and loops on both letters, — strings ending in ? Check: after reaching there are no moves, so any further symbol kills the run. Accept exactly when input ends with . (Full 2 marks for "strings ending in "; 1 mark for "containing ".)
(b) (6) No -transitions, so subsets are plain. Start .
| State | ||
|---|---|---|
| (start) | ||
| (accept) |
Accept states = those containing : . (2 marks per row / correct transitions; deduct for missing accept marking.)
(c) (2) 3 reachable DFA states.
Q2 (10)
(a) (3) Pumping lemma: If is regular then such that with , a split with (i) , (ii) , (iii) . (1 mark per quantifier condition set: existence of ; the three conditions; universal over .)
(b) (7)
- Assume regular; let be the pumping length. (1)
- Choose , . (2)
- By the lemma with and . Since , both lie in the first symbols, all 's; so with . (2)
- Pump : . Since , , so this string . (2)
- Contradiction with (iii); hence is not regular.
Q3 (12)
(a) (3) Leftmost derivation of :
(using , then first , inner , second , inner ).
Parse tree (bracketed): S[ S[a S[ε] b] S[a S[ε] b] ].
(1 for valid derivation, 1 for leftmost order, 1 for tree.)
(b) (9) Step 1 — remove : is nullable. Removing from RHS:
- gives and .
- gives , (either factor nullable). Nullable-removed set (add new start to keep since ): ; . (3)
Step 2 — remove unit productions: Units: , . Drop . Replace by 's rules: ; . (3)
Step 3 — CNF: Introduce terminals , . Then , and : introduce , so . Final CNF: (The lone on the start symbol is permitted in CNF because and never appears on a RHS.) (3)
Q4 (10)
(a) (7) PDA accepting by empty stack:
- , , , start state , start stack .
- — push first .
- — push each further .
- — first pops an , switch to matching mode.
- — each subsequent pops an .
- — pop the bottom marker to empty stack (accept). (1 per correct transition, 2 for correct tuple/setup.)
(b) (3) Configurations on (state, remaining input, stack): . Stack empty, input consumed ⇒ accept.
Q5 (10)
(a) (3) .
- Decidable (recursive): some TM halts on every input and decides membership (accepts strings in the language, rejects those not).
- Recognizable (r.e.): some TM accepts exactly the strings in the language, but may loop on non-members. (1 for definition, 1 each for decidable/recognizable distinction.)
(b) (7)
- Suppose (or ) is decidable by a decider : accepts iff accepts , and always halts. (2)
- Construct : on input , run ; if accepts (i.e. accepts ) then rejects; if rejects then accepts. (2)
- is a TM, so consider : (1)
- If accepts , then by construction said does not accept — contradiction.
- If rejects , then said does accept — contradiction. (1)
- Either way contradiction ⇒ no such exists ⇒ the problem is undecidable. (1)
Q6 (8)
(a) (2) is NP-complete iff (i) NP, and (ii) is NP-hard: every NP reduces to in polynomial time (). (1 each.)
(b) (6) Reduction 3-SAT CLIQUE. Given a 3-CNF formula with clauses , each :
- Vertices: one node per literal occurrence: , total . (1)
- Edges: connect – iff (different clauses) and the literals are not contradictory (). (2)
- Target: . Construction is polynomial. (1)
- Correctness: A satisfying assignment picks at least one true literal per clause; those chosen literals are in distinct clauses and mutually consistent (no literal and its negation both true), so they are pairwise adjacent ⇒ an -clique. Conversely an -clique must use one vertex from each of the clauses (edges never join same-clause nodes) and contains no contradictory pair, so setting those literals true is a consistent satisfying assignment. (2)
[
{"claim":"Q1 subset construction yields exactly 3 reachable DFA states",
"code":"start=frozenset({'q0'}); delta={('q0','a'):{'q0','q1'},('q0','b'):{'q0'},('q1','b'):{'q2'}}\ndef move(S,c):\n r=set()\n for s in S: r|=delta.get((s,c),set())\n return frozenset(r)\nseen={start}; stack=[start]\nwhile stack:\n S=stack.pop()\n for c in 'ab':\n T=move(S,c)\n if T not in seen: seen.add(T); stack.append(T)\nresult=(len(seen)==3)"},
{"claim":"Q2 pumping: for w=a^p b^p with y=a^k (k>=1), pumping i=2 leaves unequal counts",
"code":"p=5; k=2; a_count=p+k; b_count=p; result=(a_count!=b_count)"},
{"claim":"Q4 PDA trace on aabb ends with empty stack and empty input",
"code":"config=('q0','aabb',['Z0'])\nsteps=[('q0','abb',['A','Z0']),('q0','bb',['A','A','Z0']),('q1','b',['A','Z0']),('q1','',['Z0']),('q1','',[])]\nfinal=steps[-1]; result=(final[1]=='' and final[2]==[])"},
{"claim":"Q6 3-SAT to CLIQUE: number of vertices is 3m and clique target is m",
"code":"m=4; vertices=3*m; target=m; result=(vertices==12 and target==4)"}
]