Proofs: Thompson's NFA simulation
These are the human proofs of Thompson's NFA simulation, at full length.
Thompson's NFA simulation decides membership and search in O(mn) time full
This proof shows: correctness.
Statement. Let be a regular expression of size , let be its Thompson NFA with start and accepting state , and let . THOMPSON-MATCH returns true if and only if , and it runs in time and extra space. The search version returns true if and only if some substring of is in , within the same bounds.
Notation. For a set of states, is the set of states reachable from a state of by a path of zero or more -moves. For a string , is the set of states such that some path from to reads (the symbols on its moves spell , and -moves read nothing). By definition, accepts if and only if . Two facts about follow from splitting a path at its last symbol move: , and .
Lemma 1 (ADD). Suppose that before a call ADD the states with mark are exactly the states of , and the set of these states is closed under -moves (every -target of a state of is in ). After the call, the states with mark are exactly the states of , holds each of them once, and as a set .
Proof. A state is appended at line L14 only when its mark is not , and its mark becomes at the same moment, so no state is appended twice and the marks match throughout. Every appended state is in , by induction on the order of pushes: is, and every other pushed state is an -target of an appended state. Conversely, let with a path of -moves. If , the whole path is in because is closed. Otherwise is pushed and, when popped, appended. Whenever some is appended, all its -targets are pushed, so is pushed and is popped before the stack empties; at that point it is in , either appended now or earlier. By induction on , ends in . The loop ends because each state is appended at most once and each appended state pushes at most two states.
After the call, the set is again closed under -moves, since and are. So the hypothesis of Lemma 1 holds before each later call with the same and . Before the first call with a given , no state has mark , because marks only take the values before step , and is empty, so the hypothesis holds with .
Lemma 2 (invariant). After line L2, and after line L7 of pass , the list holds each state of exactly once and nothing else, and exactly for the states of .
Proof. For , Lemma 1 gives . Assume the claim for . In pass , the loop of lines L5 and L6 calls ADD for each move with ; there is at most one such move per state. By Lemma 1, applied call after call, ends as the union of over these , each state once, which is . The marks with value are exactly the states of . Line L7 sets .
Theorem (match version). If line L8 returns false at pass , then . Every path that reads has a prefix that reads and ends in a state of , so no path reads and . Otherwise the loop runs to the end, and by Lemma 2 the test at line L9 holds if and only if , that is, . The Thompson construction gives . So the answer is correct.
Search version. Write : the states in which some run that started at a position can be after reading up to position . The search version adds ADD at the end of pass . Since ADD gives , and the same argument as in Lemma 2 gives, after pass ,
The version returns true at the first with , which means that some substring is in . If it never returns true, then for every , so no substring is in . With the start state added at each step, always contains , so the early exit of line L8 does not apply.
Complexity. By Thompson's construction, has at most states, at most moves, and each state has at most two outgoing moves; building it costs . In one pass, Lemma 1 shows that each state is appended at most once, so all the calls of ADD in the pass together append at most states. Each push at line L15 is charged to the appended state that makes it, so there are at most pushes from line L15 and one push per call at line L10. The calls at line L6 number at most , and the search version makes one more. Each pop costs , so a pass costs , and passes cost . The NFA, the arrays , the lists and and the stack each have entries, which gives extra space.