Foundations to FrontierPart IV: Algorithms and systemsBezhig

W07: The reach and limits of computational proof

5 exercises, each with a complete solution. 1 code listing.

On this page
  1. Prerequisites and observable goals
  2. The central question: which class of objects is being decided?
  3. A finite automaton carries only a finite summary
  4. Equivalence becomes reachability in a product graph
  5. A proof that finite states are insufficient for one language
  6. Why a universal halting decider leads to contradiction
  7. Reductions transfer a problem, not an adjective
  8. Independent practice
  9. Complete solutions: W07
  10. Retention and readiness

Prerequisites and observable goals#

Before

C04–C08 and C15–C16: logic, graphs, automata, grammars, reductions, and complexity classes.

After

Construct a finite-model equivalence algorithm and its proof; distinguish nonregularity, undecidability, and intractability; use a reduction in the correct direction.

The central question: which class of objects is being decided?#

A program that checks every state of a finite model may prove a property of that model. It does not thereby decide the property for every unbounded program. A language that cannot be recognized by a finite automaton may still have a simple stack algorithm. A problem believed computationally difficult can still be decidable. These distinctions matter in compiler tooling, protocol verification, security review, and algorithm selection.

State the input class, acceptance condition, and resource measure before using a word such as “impossible.” Three claims are different: no machine of a specified restricted kind solves the task; no algorithm always decides the task for arbitrary inputs; and no known efficient algorithm solves the task under a specified complexity model. A finite counterexample can refute a universal claim; a million successful cases cannot establish an arbitrary universal statement without a covering argument.

A finite automaton carries only a finite summary#

A deterministic finite automaton (DFA) consists of a finite state set QQ, finite alphabet Σ\Sigma, total transition function δ:Q×Σ→Q\delta:Q\times\Sigma\to Q, start state q0q_0, and accepting set F⊆QF\subseteq Q. After a word ww, its current state summarizes all relevant history for future acceptance. Two prefixes ending in the same state cannot be distinguished by any common continuation.

For parity of the number of ones in a binary string, two states suffice: even and odd. A 0 leaves the state unchanged and a 1 toggles it. If the start and accepting state are even, the empty string is accepted. That last case must be tested; a word of length zero is not the same object as “no result found.”

Equivalence becomes reachability in a product graph#

Given DFAs AA and BB over the same alphabet, form states (qA,qB)(q_A,q_B). Start at the pair of start states. A symbol advances both machines. A reachable pair where exactly one component accepts is a distinguishing state: the word used to reach it is accepted by exactly one automaton. If no such pair is reachable, they accept the same language.

The proof is induction on word length. The empty word leaves the start pair. Appending a symbol applies exactly the paired transition, so the product’s state is always the pair of individual states after that word. Every possible word corresponds to a path. Breadth-first search explores reachable pairs in nondecreasing path length, so the first acceptance mismatch gives a shortest distinguishing word. Exhausting the finite graph proves no word distinguishes them, not merely no short word in a sampled list.

If there are nn and mm states, at most nmnm pairs exist. With alphabet size kk, a direct BFS examines at most knmknm transitions. A shortest path to a mismatching reachable state need not repeat a product state, so its length is at most nm−1nm-1. This is a finite automaton result; a similar claim for arbitrary program states would lack the finite bound.

A proof that finite states are insufficient for one language#

Consider L={anbn:n≥0}L=\{a^n b^n:n\ge0\}. Suppose some DFA with pp states recognizes it. While reading the first pp copies of aa in apbpa^p b^p, the machine visits p+1p+1 prefix states including the start. By the pigeonhole principle, two states coincide after ii and jj letters with 0≤i<j≤p0\le i<j\le p. The segment of j−ij-i copies of aa forms a loop. Repeating that loop once leaves the machine in the same state before the remaining input, so it must also accept ap+(j−i)bpa^{p+(j-i)}b^p. The counts differ, contradicting the definition of LL. Therefore no DFA recognizes LL.

This does not prove that LL is undecidable. A stack machine can push for each aa, then pop for each bb, reject an aa after the bb phase or an unmatched pop, and accept exactly when the input ends with an empty stack. The grammar S→aSb∣εS\to aSb\mid\varepsilon generates the same language. More memory changes what the model can express. The proof is a concrete pumping argument, not permission to “pump any chosen substring” without connecting it to repeated states.

Why a universal halting decider leads to contradiction#

Assume an algorithm H(P,x)H(P,x) always terminates and correctly decides whether program PP halts on input xx. Programs are encoded as finite strings, so one program can receive another’s encoding. Construct D(y)D(y): ask H(y,y)H(y,y); if it predicts halting, loop forever; otherwise halt. Now run DD on its own encoding. If HH predicts that D(D)D(D) halts, its definition makes it loop. If HH predicts nonhalting, its definition makes it halt. Both predictions contradict correctness, so the assumed universal decider cannot exist.

The argument does not say we can never prove that a particular program terminates. The binary search variant in W02 and the forward-only bytecode verifier in GP1 provide such proofs within bounded or structured classes. A timeout does not decide the universal question: after the deadline an uncompleted execution might halt later or never halt. A tool may also conservatively answer “unknown.” That is not the always-correct yes/no decider assumed in the contradiction.

Reductions transfer a problem, not an adjective#

To show that solving BB would solve AA, construct a transformation ff such that x∈Ax\in A exactly when f(x)∈Bf(x)\in B. Then a hypothetical solver for BB applied to f(x)f(x) solves AA. To transfer undecidability from a known undecidable AA to BB, reduce AA to BB, not the reverse. A simple problem reducing to BB does not establish that BB is difficult.

For complexity reductions, also bound the transformation’s resources. Polynomial-time many-one reductions preserve a particular computational relationship. A decision problem is in NP when yes instances have polynomial-size certificates verifiable in polynomial time, under the standard model. NP does not mean “not polynomial.” Every problem in P is in NP. NP-hardness says every NP problem reduces to the target under the chosen reduction notion; NP-completeness adds that the target itself lies in NP. The general equality P=NP remains unresolved; using these distinctions does not assume an answer. [PNP]

A shortest-path certificate and a maximum-flow/minimum-cut certificate show how existence and optimality can have checkable evidence. Not every optimization task has a similarly simple known optimality certificate. When presenting a heuristic, separate “found a feasible result,” “proved the optimum,” and “measured useful performance on this distribution.”

Independent practice#

F foundation C standard course work T transfer S optional stretch L runnable lab or project. Attempt the complete set before opening its solutions.

W07.01CSolution

Construct a complete binary DFA that accepts exactly strings with an even number of ones. Trace the empty word, 101, and 111. Explain which state property is the invariant.

W07.02TSolution

Automaton A accepts even parity of ones; B accepts every binary string. Find a shortest distinguishing word. Explain why BFS on their product finds one, and give the general state/word-length bound for DFAs with n,mn,m states.

W07.03TSolution

Prove that {anbn:n≥0}\{a^n b^n:n\ge0\} is not regular using repeated states. Then describe a terminating algorithm deciding it and explain why the two claims are compatible.

W07.04TSolution

A report says, “We reduced sorting to our problem, therefore our problem is NP-hard. Our solver timed out, proving this instance has no solution.” Identify both invalid conclusions and give the type of evidence each stronger claim would require.

W07.05LSolution

Implement distinguishing_word and accepts for the complete bounded DFA schema in integration_code/starters/dfa_compare.py. Validate states, alphabets, total transitions, start, and accepting states. Return a shortest witness string, including the empty string when appropriate, or None for equivalence. Test isomorphic machines and acceptance mismatches, and explain the exhaustive finite-model guarantee.

Optional small hints

For .02 the shortest witness need not contain both alphabet symbols. For .03 focus on the states reached before any bb is read. For .05 distinguish "" from None; a truthiness check alone loses that distinction.

Complete solutions: W07#

Compare the first step where your work differs. A corrected answer is not yet an independent success.

W07.01Show solution

The state records parity, not the whole prefix

Use states E and O, start E, accepting set {E}\{E\}, and transitions δ(E,0)=E\delta(E,0)=E, δ(E,1)=O\delta(E,1)=O, δ(O,0)=O\delta(O,0)=O, δ(O,1)=E\delta(O,1)=E. The invariant is that E means the processed prefix contains an even number of ones and O means an odd number. It holds for the empty prefix and each transition preserves it. The empty word is accepted, 101 ends E and is accepted, and 111 ends O and is rejected. This proves all strings by induction, not just the three traces.

Back to W07.01
W07.02Show solution

Reach an acceptance mismatch

The empty word is accepted by both. Word 0 is also accepted by both; word 1 is rejected by A and accepted by B, so 1 is a shortest witness. The product-state induction proves that the paired acceptance flags represent the same consumed word. BFS first reaches a mismatching state at minimum path length. There are at most nmnm states, and a shortest witnessing path has no repeated state, giving length at most nm−1nm-1. If BFS exhausts all reachable pairs without a mismatch, every word ends with matching acceptance and the machines are equivalent.

Back to W07.02
W07.03Show solution

A restricted model can fail while an algorithm exists

Assume a pp-state DFA recognizes the language. Among the p+1p+1 prefix states after zero through pp letters of apa^p, two repeat at i<ji<j. Inserting the loop of j−i>0j-i>0 additional aa’s yields the same state before the remaining suffix, hence an accepted word with more aa’s than bb’s. Contradiction. A deciding algorithm scans left to right, counts the aa’s, then decrements for each bb, rejecting wrong order or negative count and accepting at the end exactly when count is zero. It terminates after finitely many input characters. Its unbounded counter across arbitrary input lengths is not finite-state memory, so no contradiction follows.

Back to W07.03
W07.04Show solution

An easy source and a timeout establish neither claim

Sorting has efficient algorithms; reducing it to another task does not show the target can express every NP problem. An NP-hardness proof needs a suitable reduction from a known NP-hard problem (or all NP problems through established transitivity), with a valid resource bound and equivalence of yes instances. A timeout establishes only that this run did not complete by the deadline. Proving infeasibility needs a valid mathematical argument, exhaustive coverage of a correctly bounded search space, or another sound certificate. Neither a slow run nor failure to find a witness establishes nonexistence. Also distinguish sorting’s function problem from the precise decision formulation used in a complexity claim.

Back to W07.04
W07.05Show solution

A finite exhaustive proof connected to code

The reference checks that every state has a transition for every alphabet symbol. It stores visited state pairs and predecessor symbols, so reaching a mismatch reconstructs a shortest word. It checks the initial pair before expanding, preserving the empty-word case. The validation bounds keep the educational state space manageable; they are not a theorem that all protocol models fit those bounds.

integration_code/solutions/dfa_compare.pyPython
"""W07: a complete DFA comparison, not an arbitrary program-equivalence solver."""
from collections import deque


def validate(machine,alphabet):
    if type(machine) is not dict or set(machine)!={'states','start','accept','transition'}:
        raise ValueError("wrong DFA schema")
    n=machine['states']
    if type(n) is not int or not 1<=n<=100 or type(machine['start']) is not int or not 0<=machine['start']<n:
        raise ValueError("bounded state count and valid start required")
    if any(type(q) is not int or not 0<=q<n for q in machine['accept']):raise ValueError("bad accepting state")
    expected={(q,a) for q in range(n) for a in alphabet}
    if set(machine['transition'])!=expected:raise ValueError("complete transition table required")
    if any(type(q) is not int or not 0<=q<n for q in machine['transition'].values()):raise ValueError("bad target")


def distinguishing_word(left,right,alphabet=('a','b')):
    alphabet=tuple(alphabet)
    if not alphabet or len(set(alphabet))!=len(alphabet) or any(type(a) is not str or len(a)!=1 for a in alphabet):
        raise ValueError("unique one-character alphabet symbols required")
    validate(left,alphabet);validate(right,alphabet)
    start=(left['start'],right['start'])
    parent={start:None};todo=deque([start])
    while todo:
        pair=todo.popleft()
        if (pair[0] in left['accept']) != (pair[1] in right['accept']):
            symbols=[]
            while parent[pair] is not None:
                previous,symbol=parent[pair];symbols.append(symbol);pair=previous
            return ''.join(reversed(symbols))
        for symbol in alphabet:
            nxt=(left['transition'][pair[0],symbol],right['transition'][pair[1],symbol])
            if nxt not in parent:
                parent[nxt]=pair,symbol;todo.append(nxt)
    return None


def accepts(machine,word):
    state=machine['start']
    for symbol in word:state=machine['transition'][state,symbol]
    return state in machine['accept']


if __name__=='__main__':
    even={'states':2,'start':0,'accept':{0},
          'transition':{(0,'a'):1,(1,'a'):0,(0,'b'):0,(1,'b'):1}}
    everything={'states':1,'start':0,'accept':{0},'transition':{(0,'a'):0,(0,'b'):0}}
    print(repr(distinguishing_word(even,everything)))

Tests compare renamed equivalent machines, a one-symbol mismatch, an empty-word mismatch, and malformed transitions. The correctness argument covers every word for the supplied complete machines because it exhausts their finite reachable product, not because the tests enumerate a large prefix set. Extending this tool to nondeterministic automata, pushdown machines, or arbitrary programs requires a new representation, algorithm, complexity analysis, and claim boundary.

Back to W07.05

Retention and readiness#

Explain nonregular, undecidable, and NP-hard using different examples. Draw the direction of a reduction before stating the conclusion. When a verification tool says “proved,” ask what model, assumptions, and state-space bound its proof concerns.