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. , a nonterminal may have no production, and a symbol is useful if it occurs in some derivation with .
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) is the number of occurrences in the right side of of nonterminals that are not processed;
(b) every nonterminal on 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 .
Initially no nonterminal is processed, (a) holds by line L1, and line L2 puts on exactly the left sides of the productions with counter 0, which gives (b) and (c). An iteration that skips Gen changes nothing except removing a copy of , which is in Gen, so (c) still holds. An iteration that processes decreases, by line L6, the counter of once for each occurrence of in , so (a) holds with 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 follows a counter reaching 0 (or line L2), which happens at most once per production, so at most elements are pushed, and the loop runs at most times.
Soundness. Every element of Gen is generating. By induction on the order of processing: was pushed for a production with counter 0, so by (a) all nonterminals of were processed before, hence generating; terminals are generating; so for some and .
Completeness. Every generating nonterminal is in Gen at the end. Let , and take a parse tree of from of minimum height . The root uses , and each nonterminal child has a tree of height less than , so by induction on it is in Gen at the end, hence processed (every element of Gen is processed in the same iteration). By (a) at the end, , and by (c) with empty, Gen.
Lemma 2: the reachable pass
Let be the set of line L7, and say is reachable in if .
Every element of Reach is reachable in : is, by the empty derivation, and if is reachable by and , then . Conversely, if in steps, then by induction on the occurrence of was introduced by a step with a production applied to an occurrence of in a sentential form derived in fewer steps; Reach by induction, was pushed and popped once, and line L10 then added if it was not already present. Each nonterminal is pushed at most once, so the loop runs at most times.
Lemma 3: the output is the set of useful productions
Call a production useful if some derivation with uses it. Let be the output of line L11.
Every useful production is in . Let be used in . Every symbol in a sentential form of a derivation of a terminal string derives a substring of , so it is generating; hence every production used in the derivation has all its symbols in Gen by Lemma 1, and is in . The derivation of therefore uses only , so is reachable in , and Reach by Lemma 2. So .
Every production of is useful. Let . By Lemma 2, , and by the definition of every symbol of this sentential form and of is generating. Indeed, each such symbol is a symbol of a right side of a production in , all of which are generating by the definition of , or it is the start symbol ; and is the left side of the first production of the derivation, or when the derivation is empty, and every left side of is in Gen. Replacing each symbol of by a terminal string it derives gives .
Theorem
, every parse tree of a sentence of is a parse tree of and conversely, and if , every symbol of is useful in .
Proof. A parse tree of a sentence of uses only useful productions, which are in by Lemma 3; and , so every tree of is a tree of . Equality of trees gives equality of languages. For the last part, every production of is used in some derivation of a sentence in ; that derivation uses only useful productions, so it is a derivation in , and every symbol of the production is useful in . If , no production is useful and .
Running time
Lemma 1 bounds the iterations of lines L3 to L6 by , 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 . Lemma 2 bounds the iterations of lines L9 and L10 by , and each production of is visited when its left side is popped, once. Line L11 is a pass over . With constant-time set and map operations, the total is , which is when every nonterminal occurs in some production. The algorithm terminates on every input.