Algorithm Search⌘K

Proofs: Useless symbol elimination

These are the human proofs of Useless symbol elimination, at full length.

TRIM keeps exactly the productions made of useful symbols, preserves the language and the parse trees, and stops in linear time full

This proof shows: correctness, termination.

We use the notation of the context-free grammar page and the pseudocode TRIM of the page. G=(V,Σ,P,S)G = (V, \Sigma, P, S), a nonterminal may have no production, and a symbol is useful if it occurs in some derivation S⇒∗αXβ⇒∗wS \Rightarrow^* \alpha X \beta \Rightarrow^* w with w∈Σ∗w \in \Sigma^*.

Lemma 1: the generating pass

Invariant. Call a nonterminal processed when line L5 has added it to Gen and line L6 has run for it. Then:

(a) count[p]\mathrm{count}[p] is the number of occurrences in the right side of pp of nonterminals that are not processed;

(b) every nonterminal on WW is the left side of a production whose counter is 0;

(c) every left side of a production with counter 0 is in Gen or on WW.

Initially no nonterminal is processed, (a) holds by line L1, and line L2 puts on WW exactly the left sides of the productions with counter 0, which gives (b) and (c). An iteration that skips X∈X \in Gen changes nothing except removing a copy of XX, which is in Gen, so (c) still holds. An iteration that processes XX decreases, by line L6, the counter of pp once for each occurrence of XX in pp, so (a) holds with XX processed; every counter that reaches 0 has its left side pushed, which keeps (b) and (c). Since a nonterminal is processed only once (line L4 skips it later), no counter goes below 0.

Termination. Each push onto WW follows a counter reaching 0 (or line L2), which happens at most once per production, so at most ∣P∣|P| elements are pushed, and the loop runs at most ∣P∣|P| times.

Soundness. Every element of Gen is generating. By induction on the order of processing: XX was pushed for a production X→αX \to \alpha with counter 0, so by (a) all nonterminals of α\alpha were processed before, hence generating; terminals are generating; so α⇒∗w\alpha \Rightarrow^* w for some w∈Σ∗w \in \Sigma^* and X⇒α⇒∗wX \Rightarrow \alpha \Rightarrow^* w.

Completeness. Every generating nonterminal is in Gen at the end. Let A⇒∗wA \Rightarrow^* w, and take a parse tree of ww from AA of minimum height h≥1h \ge 1. The root uses p=A→αp = A \to \alpha, and each nonterminal child BB has a tree of height less than hh, so by induction on hh it is in Gen at the end, hence processed (every element of Gen is processed in the same iteration). By (a) at the end, count[p]=0\mathrm{count}[p] = 0, and by (c) with WW empty, A∈A \in Gen. □\square

Lemma 2: the reachable pass

Let P1P_1 be the set of line L7, and say BB is reachable in P1P_1 if S⇒P1∗γBδS \Rightarrow^*_{P_1} \gamma B \delta.

Every element of Reach is reachable in P1P_1: SS is, by the empty derivation, and if AA is reachable by S⇒∗γAδS \Rightarrow^* \gamma A \delta and A→α1Bα2∈P1A \to \alpha_1 B \alpha_2 \in P_1, then S⇒∗γα1Bα2δS \Rightarrow^* \gamma \alpha_1 B \alpha_2 \delta. Conversely, if S⇒P1∗γBδS \Rightarrow^*_{P_1} \gamma B \delta in mm steps, then by induction on mm the occurrence of BB was introduced by a step with a production A→α1Bα2∈P1A \to \alpha_1 B \alpha_2 \in P_1 applied to an occurrence of AA in a sentential form derived in fewer steps; A∈A \in Reach by induction, AA was pushed and popped once, and line L10 then added BB if it was not already present. Each nonterminal is pushed at most once, so the loop runs at most ∣V∣|V| times. □\square

Lemma 3: the output is the set of useful productions

Call a production useful if some derivation S⇒∗wS \Rightarrow^* w with w∈Σ∗w \in \Sigma^* uses it. Let P′P' be the output of line L11.

Every useful production is in P′P'. Let A→αA \to \alpha be used in S⇒∗γAδ⇒γαδ⇒∗wS \Rightarrow^* \gamma A \delta \Rightarrow \gamma \alpha \delta \Rightarrow^* w. Every symbol in a sentential form of a derivation of a terminal string derives a substring of ww, so it is generating; hence every production used in the derivation has all its symbols in Gen by Lemma 1, and is in P1P_1. The derivation of γAδ\gamma A \delta therefore uses only P1P_1, so AA is reachable in P1P_1, and A∈A \in Reach by Lemma 2. So A→α∈P′A \to \alpha \in P'.

Every production of P′P' is useful. Let A→α∈P′A \to \alpha \in P'. By Lemma 2, S⇒P1∗γAδS \Rightarrow^*_{P_1} \gamma A \delta, and by the definition of P1P_1 every symbol of this sentential form and of α\alpha is generating. Indeed, each such symbol is a symbol of a right side of a production in P1P_1, all of which are generating by the definition of P1P_1, or it is the start symbol SS; and SS is the left side of the first production of the derivation, or S=AS = A when the derivation is empty, and every left side of P1P_1 is in Gen. Replacing each symbol of γαδ\gamma \alpha \delta by a terminal string it derives gives S⇒∗γAδ⇒γαδ⇒∗wS \Rightarrow^* \gamma A \delta \Rightarrow \gamma \alpha \delta \Rightarrow^* w. □\square

Theorem

L(G′)=L(G)L(G') = L(G), every parse tree of a sentence of GG is a parse tree of G′G' and conversely, and if L(G)≠∅L(G) \ne \emptyset, every symbol of G′G' is useful in G′G'.

Proof. A parse tree of a sentence of GG uses only useful productions, which are in P′P' by Lemma 3; and P′⊆PP' \subseteq P, so every tree of G′G' is a tree of GG. Equality of trees gives equality of languages. For the last part, every production of P′P' is used in some derivation of a sentence in GG; that derivation uses only useful productions, so it is a derivation in G′G', and every symbol of the production is useful in G′G'. If L(G)=∅L(G) = \emptyset, no production is useful and P′=∅P' = \emptyset. □\square

Running time

Lemma 1 bounds the iterations of lines L3 to L6 by ∣P∣|P|, and the decrements of line L6 by the number of nonterminal occurrences, since each nonterminal is processed once and visits its own occurrences. Lines L1, L2 and L7 are single passes over PP. Lemma 2 bounds the iterations of lines L9 and L10 by ∣V∣|V|, and each production of P1P_1 is visited when its left side is popped, once. Line L11 is a pass over P1P_1. With constant-time set and map operations, the total is O(∣G∣+∣V∣)O(|G| + |V|), which is O(∣G∣)O(|G|) when every nonterminal occurs in some production. The algorithm terminates on every input.

Back to Useless symbol elimination