Algorithm Search⌘K

Proofs: NFA simulation

These are the human proofs of NFA simulation, at full length.

NFA simulation accepts exactly the strings of the NFA and stops in O(l(n + m)) steps full

This proof shows: correctness, termination.

Let N=(Q,Σ,δ,q0,F)N = (Q, \Sigma, \delta, q_0, F) be the input, with δ:Q×(Σ∪{ε})→P(Q)\delta : Q \times (\Sigma \cup \{\varepsilon\}) \to \mathcal{P}(Q), and let w=a1⋯aℓw = a_1 \cdots a_\ell. For S⊆QS \subseteq Q, let E(S)E(S) be the set of states rr such that there is a path p0,p1,…,pkp_0, p_1, \ldots, p_k with k≥0k \ge 0, p0∈Sp_0 \in S, pk=rp_k = r and pj∈δ(pj−1,ε)p_j \in \delta(p_{j-1}, \varepsilon) for 1≤j≤k1 \le j \le k.

A run of NN on v=b1⋯btv = b_1 \cdots b_t is a sequence of moves that starts in q0q_0 and whose labels, in order, are b1,…,btb_1, \ldots, b_t with any number of ε\varepsilon labels before, between and after them. Let R(v)R(v) be the set of the last states of the runs on vv. By definition, v∈L(N)v \in L(N) if and only if R(v)∩F≠∅R(v) \cap F \ne \emptyset.

Lemma 1 (CLOSE). On input SS, CLOSE stops after at most ∣Q∣|Q| pops and returns E(S)E(S).

Proof. A state is pushed on KK only at the moment it is added to CC, at line L9 or line L12, and states are never removed from CC. So each state is pushed at most once, there are at most ∣Q∣|Q| pops, and the loop stops.

C⊆E(S)C \subseteq E(S): the claim holds after line L9, since S⊆E(S)S \subseteq E(S) with paths of length 0. Line L12 adds rr only when r∈δ(q,ε)r \in \delta(q, \varepsilon) for some q∈Cq \in C; a path from SS to qq followed by the move to rr is a path from SS to rr.

E(S)⊆CE(S) \subseteq C: each state that enters CC also enters KK, and the loop stops only when KK is empty, so each state of the final CC was popped at line L11, and line L12 then put all its ε\varepsilon-successors in CC. So the final CC contains SS and is closed under ε\varepsilon-moves. Take r∈E(S)r \in E(S) with a path p0,…,pk=rp_0, \ldots, p_k = r. By induction on jj, pj∈Cp_j \in C: p0∈S⊆Cp_0 \in S \subseteq C, and pj∈δ(pj−1,ε)p_{j} \in \delta(p_{j-1}, \varepsilon) with pj−1∈Cp_{j-1} \in C gives pj∈Cp_j \in C. □\square

Lemma 2 (one step). For each v∈Σ∗v \in \Sigma^* and a∈Σa \in \Sigma, R(va)=E(⋃q∈R(v)δ(q,a))R(va) = E\big(\bigcup_{q \in R(v)} \delta(q, a)\big).

Proof. (⊇\supseteq) Let rr be in the right side. Then there are q∈R(v)q \in R(v), p∈δ(q,a)p \in \delta(q, a) and a path of ε\varepsilon-moves from pp to rr. A run on vv that ends in qq, followed by the move q→pq \to p on aa and the path to rr, is a run on vava that ends in rr.

(⊆\subseteq) Let r∈R(va)r \in R(va), with a run on vava that ends in rr. The run reads aa in exactly one move with a label in Σ\Sigma after it has read vv; let this move go from qq to pp, so p∈δ(q,a)p \in \delta(q, a). The moves before it form a run on vv that ends in qq, so q∈R(v)q \in R(v). The moves after it are ε\varepsilon-moves from pp to rr, so r∈E({p})r \in E(\{p\}). Hence rr is in the right side. □\square

Lemma 3 (invariant). If the algorithm reaches the test of line L2 after ii passes of the loop, then S=R(a1⋯ai)S = R(a_1 \cdots a_i).

Proof. By induction on ii. For i=0i = 0, line L1 sets S=E({q0})S = E(\{q_0\}) by Lemma 1, and R(ε)=E({q0})R(\varepsilon) = E(\{q_0\}), since a run on ε\varepsilon uses only ε\varepsilon-moves. For the step, assume S=R(v)S = R(v) with v=a1⋯ai−1v = a_1 \cdots a_{i-1} before pass ii. Lines L3 to L5 make T=⋃q∈Sδ(q,ai)T = \bigcup_{q \in S} \delta(q, a_i), and line L6 sets S=E(T)S = E(T) by Lemma 1. By Lemma 2 this is R(vai)R(v a_i). If line L7 returns, the next test of line L2 is never reached, and the claim holds vacuously. □\square

Theorem. NFA-SIMULATION(N,w)(N, w) stops and returns true if and only if w∈L(N)w \in L(N).

Proof. The loop at line L2 makes at most ℓ\ell passes, and each call of CLOSE stops by Lemma 1, so the algorithm stops.

If it returns false at line L7 in pass ii, then R(a1⋯ai)=∅R(a_1 \cdots a_i) = \emptyset by Lemma 3 and the computation of pass ii. Each run on ww begins with a run on a1⋯aia_1 \cdots a_i: the part of it up to and including the move that reads aia_i is a run on a1⋯aia_1 \cdots a_i. That prefix would end in a state of R(a1⋯ai)R(a_1 \cdots a_i), so there is no run on ww, and w∉L(N)w \notin L(N).

Otherwise, after all ℓ\ell passes, S=R(w)S = R(w) by Lemma 3, and line L8 returns true if and only if R(w)∩F≠∅R(w) \cap F \ne \emptyset, that is, if and only if w∈L(N)w \in L(N). ■\blacksquare

Running time. In one pass, lines L4 and L5 read each aia_i-move of each state of SS once, at most mm moves, and SS has at most nn states. By Lemma 1, CLOSE pops at most nn states, and it reads the ε\varepsilon-moves of each popped state once, at most mm moves. With a boolean array for membership, each "add" and each test is O(1)O(1). So a pass costs O(n+m)O(n + m), and the ℓ\ell passes cost O(ℓ(n+m))O(\ell (n + m)). The space is the two sets, the stack and the array: O(n)O(n).

Back to NFA simulation