Two teams shipped different finite automata for one message-filter rule; how do you decide whether they accept exactly the same strings?
answer
- testing strings proves nothing
- a disagreement is a single string
- exactly one side accepts
- symmetric difference, then emptiness
- emptiness is reachability in the graph
basics
~20 sTurn equality into emptiness. Build the product of the two machines, mark a pair accepting when exactly one component accepts, and search for a reachable accepting pair. None found means the machines agree; the first one found hands you a disagreeing string.
solid answer
~40 sTwo languages are equal exactly when their **symmetric difference** is empty, and both operations are constructions you already have. Pair the machines and mark a pair `(p, q)` accepting when exactly one of `p` and `q` is accepting in its own machine; that product recognises the strings on which the two disagree. Deciding whether it accepts anything is then pure graph reachability: breadth-first search from the start pair, following transitions as edges. If no accepting pair is reachable, the machines are equivalent. If one is, the path that got you there **spells a counterexample string** — the shortest one, if you search breadth-first. Both machines must be deterministic and total for the pairing to be sound, and you explore pairs lazily rather than materialising the whole product.
code
pseudocode · 15 linesstart_pair <- (start1, start2)
seen <- { start_pair }
worklist <- [ (start_pair, "") ] // pair plus the string that reached it
while worklist is not empty:
((p, q), w) <- remove oldest from worklist
if accepting1(p) is not accepting2(q):
return "differ on: " + w
for each symbol a in alphabet:
nxt <- (step1(p, a), step2(q, a))
if nxt not in seen:
add nxt to seen
append (nxt, w + a) to worklist
return "equivalent"go deeper
Know that whether two finite automata accept the same strings is a question with a definite, computable answer, and that checking sample inputs is not how you get it.
Explain the reduction: equality of languages becomes emptiness of the symmetric difference, built by pairing the machines and accepting when exactly one component accepts.
Run it as an engineer would: complete both machines, search reachable pairs breadth-first, stop at the first disagreement, and turn the path into a regression test the owning team cannot argue with.
Make the check part of the release path for a rule engine, so any rewrite of a rule is verified against its predecessor, and budget for the one determinisation step that can dominate the cost.
## Why testing strings is not an answer The tempting reply is "generate a few million messages and compare verdicts". That is a smoke test, not a decision: two machines can agree on every string shorter than some length and diverge immediately afterwards, and nothing in a random sample tells you where the boundary is. Equivalence of finite automata is **decidable**, exactly and cheaply, so an interviewer treats sampling as an admission that you do not know the construction. The second tempting reply — compare the transition tables — is also wrong. The same language admits machines with different state counts, different state names, unreachable junk and differently shaped loops. Structural equality implies language equality; the converse does not hold. ## Reduce equality to emptiness The standard move is to express the property you want as the **emptiness** of a language you can construct: - `L1 = L2` holds exactly when no string lies in one language but not the other. - The strings that do lie in exactly one are the **symmetric difference**: `(L1 minus L2)` united with `(L2 minus L1)`. - So `L1 = L2` holds exactly when the symmetric difference is empty. And the symmetric difference is one line of the product construction. Pair the two machines, keep the lockstep transitions, and mark `(p, q)` accepting when exactly one of the two components is accepting in its own machine. Nothing else about the product changes. Getting the accepting condition backwards is the most common error in this material. "Both accept" is intersection and answers a different question entirely; you want **exactly one**. ## Emptiness is a reachability search A finite automaton accepts nothing precisely when no accepting state is reachable from the start state. Acceptance means a path from the start to an accepting state whose edge labels spell the input, so no such path means no such input. The decision procedure is therefore an ordinary traversal of the transition graph — no automata theory beyond the reduction itself: 1. Start from the pair of start states. 2. Visit pairs breadth-first, expanding each pair on every alphabet symbol. 3. Stop at the first pair where exactly one component accepts. 4. If the search exhausts the reachable pairs without finding one, the machines are equivalent. Because you stop at the first disagreement, the search usually touches a tiny fraction of the worst-case pair count, and you never build the full product. ## The counterexample is the real payoff A yes/no verdict is worth much less than what the search hands you on the way. Carry the string spelled by the path alongside each pair in the queue, and the moment you hit a disagreeing pair you have a **concrete message** that one machine accepts and the other rejects. Breadth-first order makes it the shortest such message. That artefact goes straight into the regression suite, into the bug report, and into the conversation with whichever team owns the rule — it turns "your machines differ" into "they differ on this input, and here is what each does with it". ## Preconditions and costs | condition | why it matters | |---|---| | both machines deterministic | the pair must track one state per machine, not a set of them | | both machines total | a stuck component ends the joint run and can hide a disagreement | | same alphabet | pairs step on shared symbols; differing alphabets must be reconciled first | | lazy exploration | the reachable pairs are usually far fewer than the product bound | If one machine is nondeterministic, determinise the side that ends up being complemented before pairing — that is the step that can blow up exponentially, and it is worth arranging so it happens at most once. A second route to the same verdict reduces each machine to a canonical form and compares those directly; it answers the question but yields no counterexample, and the canonicalisation algorithm is a separate subject. ## What the interviewer is checking That you reach for a reduction rather than a test harness; that you name **emptiness** as the primitive and reachability as its implementation; that you get the accepting condition the right way round; and that you notice the failing path is itself the deliverable. A candidate who ends on "and then I have a counterexample string I can put in a test" has demonstrated the difference between knowing the theory and having used it.
- Why is comparing the two transition tables not a valid equivalence test?Because layout is not language. Equivalent machines can differ in state count, state naming, unreachable regions and loop shape, so table comparison reports differences that do not exist. Only a canonical form makes structural comparison meaningful, and producing that canonical form is an extra algorithm the product-and-emptiness route does not need.
- What changes when one of the two machines is nondeterministic?The pair can no longer track a single state on that side, so determinise it first, which may cost exponentially many states. If you only need one direction — every string the first accepts is also accepted by the second — you can leave the first nondeterministic and pair it with a deterministic total second machine, looking for a pair where the first accepts and the second does not.
- How do you decide whether one filter rule is strictly stronger than another?Run the search twice with asymmetric accepting conditions. Looking for a pair where the first accepts and the second rejects tests containment one way; swapping the roles tests the other. No witness in either direction means equal; a witness in exactly one direction means that side is strictly larger, and the witness string proves it.
saying these in an interview costs you the question
- Tests a large sample of strings and concludes the machines agree
- Compares state counts or transition tables and calls the machines different
- Marks a product pair accepting when both components accept, rather than exactly one
- Thinks equivalence of two finite automata is undecidable
- Forgets to complete both machines, so an early dead end hides a disagreement
- Believes every pair must be built before the search can answer