Skip to content

Computable reduction of context-free grammars

TheoremA form yielding the empty word contains no terminal#✓fully proved

Let \(G\) be a context-free grammar over terminals \(T\) and let \(\alpha\) be a sentential form of \(G\). If \(\alpha\) yields the empty word in \(G\), then no terminal symbol \(a \in T\) occurs in \(\alpha\).

theorem Yields.terminal_not_mem {G : ContextFreeGrammar T} {α : List (Symbol T G.NT)}
    (h : Yields G α []) {a : T} : Symbol.terminal a ∉ α
Uses 1 · Used by 1
25 fully proved

Nullable nonterminals

DefinitionProductions without terminals of an encoded grammar#✓fully proved

For an encoded context-free grammar \(g\), the encoded grammar with the same start nonterminal whose productions are the productions of \(g\), in their order, whose right-hand sides contain no terminal.

def noTerminals (g : EncodedCFG T) : EncodedCFG T :=
  ⟨g.start, g.rules.filter fun e => e.2.all Sum.isLeft⟩
Uses 1 · Used by 6

DefinitionComputed nullable nonterminals of an encoded grammar#✓fully proved

For an encoded context-free grammar \(g\), the list of generating nonterminals of the encoded grammar that has the start nonterminal of \(g\) and, as productions, the productions of \(g\) whose right-hand sides contain no terminal.

A nonterminal is in this list exactly when it derives the empty word in the grammar denoted by \(g\).

def nullable (g : EncodedCFG T) : List ℕ :=
  g.noTerminals.generating
Uses 3 · Used by 5

TheoremYields of the empty word need only terminal-free productions#✓fully proved

Let \(g\) be an encoded context-free grammar and \(\alpha\) a sentential form of the grammar \(g\) denotes. If \(\alpha\) yields the empty word in that grammar, then \(\alpha\) also yields the empty word in the grammar denoted by the encoded grammar consisting of the productions of \(g\) that contain no terminal.

theorem yields_noTerminals {g : EncodedCFG T} {α : List (Symbol T g.toCFG.NT)}
    (h : Yields g.toCFG α []) : Yields g.noTerminals.toCFG α []
Uses 7 · Used by 1

TheoremTerminal-free productions yield only the empty word#✓fully proved

Let \(g\) be an encoded context-free grammar and consider the grammar of its productions without terminals. If a sentential form \(\alpha\) that contains no terminal yields a word \(w\) in that grammar, then \(w\) is the empty word.

theorem eq_nil_of_yields_noTerminals {g : EncodedCFG T} {α : List (Symbol T g.noTerminals.toCFG.NT)}
    {w : List T}
    (h : Yields g.noTerminals.toCFG α w) (hα : ∀ a, Symbol.terminal a ∉ α) : w = []
Uses 6 · Used by 1

TheoremYields in the terminal-free subgrammar are yields of the grammar#✓fully proved

Let \(g\) be an encoded context-free grammar, \(\alpha\) a sentential form and \(w\) a word. If \(\alpha\) yields \(w\) in the grammar denoted by the encoded grammar consisting of the productions of \(g\) that contain no terminal, then \(\alpha\) yields \(w\) in the grammar \(g\) denotes.

theorem yields_of_yields_noTerminals {g : EncodedCFG T}
    {α : List (Symbol T g.noTerminals.toCFG.NT)} {w : List T}
    (h : Yields g.noTerminals.toCFG α w) : Yields g.toCFG α w
Uses 6 · Used by 1

TheoremThe nullable nonterminals are computed#✓fully proved

For every encoded context-free grammar \(g\) and every natural number \(A\), \(A\) belongs to the computed list of nullable nonterminals of \(g\) (the generating nonterminals of the productions of \(g\) without terminals) if and only if \(A\) is nullable in the grammar denoted by \(g\), that is, \(A\) derives the empty word.

theorem mem_nullable_iff {g : EncodedCFG T} {A : ℕ} : A ∈ g.nullable ↔ Nullable g.toCFG A
Uses 17 · Used by 1

Removing empty productions

DefinitionDeleting nonterminals from an encoded right-hand side#✓fully proved

Let \(N\) be a list of natural numbers and \(u\) an encoded right-hand side, that is, a word whose letters are nonterminals \(i \in \mathbb{N}\) or terminals. The result is the list of all words obtained from \(u\) by deleting some of the occurrences of nonterminals that belong to \(N\) (possibly none, possibly all) and keeping every other letter in order; each choice of deleted occurrences contributes one entry of the list.

def deletions (N : List ℕ) (u : List (ℕ ⊕ T)) : List (List (ℕ ⊕ T)) :=
  u.foldr (fun s acc => acc.map (s :: ·) ++
    cond (Sum.elim (Decidability.memB N) (fun _ => false) s) acc []) [[]]
Uses 1 · Used by 4

TheoremComputed deletions agree with nullable deletions#✓fully proved

Let \(g\) be an encoded context-free grammar. For every encoded word \(u\) and every sentential form \(\alpha\) of the grammar denoted by \(g\), \(\alpha\) is obtained from the decoding of \(u\) by deleting some occurrences of nullable nonterminals of the grammar denoted by \(g\) if and only if \(\alpha\) is the decoding of a word obtained from \(u\) by deleting some occurrences of nonterminals in the computed list of nullable nonterminals of \(g\).

theorem mem_nullableDeletions_iff {g : EncodedCFG T} :
    ∀ (u : List (ℕ ⊕ T)) (α : List (Symbol T ℕ)),
      α ∈ nullableDeletions g.toCFG (u.map decodeSymbol) ↔
        ∃ v ∈ deletions g.nullable u, v.map decodeSymbol = α
Uses 9 · Used by 1

DefinitionRemoving empty productions from an encoded grammar#✓fully proved

For an encoded context-free grammar \(g\), the encoded grammar with the same start nonterminal whose productions are, for each production \(A \to u\) of \(g\), the productions \(A \to v\) for every nonempty word \(v\) obtained from \(u\) by deleting some occurrences of nonterminals in the computed list of nullable nonterminals of \(g\).

def epsElim (g : EncodedCFG T) : EncodedCFG T :=
  let N := g.nullable
  ⟨g.start, g.rules.flatMap fun e =>
    ((deletions N e.2).filter fun v => decide (0 < v.length)).map (e.1, ·)⟩
Uses 3 · Used by 7

TheoremProductions of the computable removal of empty productions#✓fully proved

For every encoded context-free grammar \(g\), a production is a production of the grammar denoted by the encoded grammar obtained from \(g\) by removing empty productions if and only if it is a production of the grammar obtained from the grammar denoted by \(g\) by eliminating empty productions.

theorem mem_epsElim_rules {g : EncodedCFG T} {r : ContextFreeRule T ℕ} :
    r ∈ g.epsElim.toCFG.rules ↔ r ∈ (epsGrammar g.toCFG).rules
Uses 12 · Used by 2

TheoremComputable removal of empty productions agrees with the classical one#✓fully proved

For every encoded context-free grammar \(g\), the grammar denoted by the encoded grammar obtained from \(g\) by removing empty productions is equal to the grammar obtained from the grammar denoted by \(g\) by eliminating empty productions: from each production, all productions obtained by deleting some occurrences of nullable nonterminals from its output, except those with empty output.

theorem epsElim_toCFG (g : EncodedCFG T) : g.epsElim.toCFG = epsGrammar g.toCFG
Uses 7 · Used by 1

TheoremRemoving empty productions drops only the empty word#✓fully proved

For every encoded context-free grammar \(g\), the language of the encoded grammar obtained from \(g\) by removing empty productions consists of the nonempty words of the language of \(g\).

theorem language_epsElim (g : EncodedCFG T) :
    g.epsElim.language = {w | w ∈ g.language ∧ w ≠ []}
Uses 7 · Used by 1

Removing unit productions

DefinitionNonterminals of an encoded grammar#✓fully proved

For an encoded context-free grammar \(g\), the list obtained by duplicate removal from the list made of the start nonterminal of \(g\) followed, for each production of \(g\) in order, by its left-hand side and then the nonterminals of its right-hand side in order. It lists without repetitions the nonterminals that \(g\) mentions.

def ntList (g : EncodedCFG T) : List ℕ :=
  dedupB (g.start :: g.rules.flatMap fun e => e.1 :: e.2.filterMap Sum.getLeft?)
Uses 2 · Used by 5

DefinitionTarget of a unit right-hand side#✓fully proved

For an encoded right-hand side \(u\), a list whose entries are nonterminals \(i \in \mathbb{N}\) or terminals, the optional value is \(B\) when \(u\) consists of the single nonterminal \(B\), and there is no value otherwise.

def unitTarget (u : List (ℕ ⊕ T)) : Option ℕ :=
  cond (decide (u.length = 1)) (u.head?.bind Sum.getLeft?) none
Used by 5

DefinitionOne round of unit reachability#✓fully proved

For an encoded context-free grammar \(g\), a natural number \(A\) and a list \(S\) of natural numbers, the list consisting of \(A\) followed, for each production of \(g\) in order whose left-hand side lies in \(S\) and whose right-hand side is a single nonterminal \(B\), by that nonterminal \(B\).

def unitStep (g : EncodedCFG T) (A : ℕ) (S : List ℕ) : List ℕ :=
  A :: g.rules.filterMap fun e => cond (Decidability.memB S e.1) (unitTarget e.2) none
Uses 3 · Used by 3

DefinitionNonterminals reachable by unit productions in an encoded grammar#✓fully proved

For an encoded context-free grammar \(g\) and a natural number \(A\), let \(n\) be the number of distinct nonterminals mentioned in \(g\) (the start, the left-hand sides, and the nonterminals on right-hand sides). The list is obtained from the empty list by applying one round of unit reachability from \(A\) exactly \(n + 1\) times.

Its entries are exactly the nonterminals \(B\) reachable from \(A\) by a possibly empty chain of unit productions \(A \to \dots \to B\) of \(g\); in particular \(A\) itself is an entry.

def unitReach (g : EncodedCFG T) (A : ℕ) : List ℕ :=
  (g.unitStep A)^[(A :: g.ntList).length] []
Uses 3 · Used by 4

TheoremUnit reachability is computed#✓fully proved

Let \(g\) be an encoded context-free grammar and let \(A\) and \(B\) be natural numbers. Then \(B\) belongs to the computed list of nonterminals reachable from \(A\) by unit productions of \(g\) if and only if there are \(k \ge 0\) and nonterminals \(A = C_0, C_1, \dots, C_k = B\) such that \(C_{i-1} \to C_i\) is a production of the grammar denoted by \(g\) for every \(i\) with \(1 \le i \le k\).

theorem mem_unitReach_iff {g : EncodedCFG T} {A B : ℕ} :
    B ∈ g.unitReach A ↔ UnitSteps g.toCFG A B
Uses 14 · Used by 1

DefinitionUnit elimination for encoded grammars#✓fully proved

For an encoded context-free grammar \(g\), the encoded grammar with the start nonterminal of \(g\) whose productions are listed as follows: for each nonterminal \(A\) in the list of nonterminals of \(g\), and for each production \(B \to u\) of \(g\) in order such that \(B\) is in the computed list of nonterminals reachable from \(A\) by unit productions and \(u\) is not a single nonterminal, the production \(A \to u\).

def unitElim (g : EncodedCFG T) : EncodedCFG T :=
  ⟨g.start, g.ntList.flatMap fun A =>
    let R := g.unitReach A
    g.rules.filterMap fun e =>
      cond (Decidability.memB R e.1 && !(unitTarget e.2).isSome) (some (A, e.2)) none⟩
Uses 5 · Used by 6

TheoremProductions of the encoded unit elimination#✓fully proved

Let \(g\) be an encoded context-free grammar over terminals \(T\) and let \(r\) be a production with terminals in \(T\) and nonterminals in \(\mathbb{N}\). Then \(r\) is a production of the grammar denoted by the encoded unit elimination of \(g\) if and only if \(r\) is a production of the grammar obtained from the grammar denoted by \(g\) by eliminating unit productions.

theorem mem_unitElim_rules {g : EncodedCFG T} {r : ContextFreeRule T ℕ} :
    r ∈ g.unitElim.toCFG.rules ↔ r ∈ (unitGrammar g.toCFG).rules
Uses 20 · Used by 1

TheoremThe encoded unit elimination denotes the unit-eliminated grammar#✓fully proved

For every encoded context-free grammar \(g\), the grammar denoted by the encoded unit elimination of \(g\) is equal to the grammar obtained from the grammar denoted by \(g\) by eliminating unit productions.

theorem unitElim_toCFG (g : EncodedCFG T) : g.unitElim.toCFG = unitGrammar g.toCFG
Uses 9 · Used by 2

Reduction

DefinitionReduction of an encoded grammar#✓fully proved

For an encoded context-free grammar \(g\), the encoded grammar obtained by first removing the empty productions of \(g\) (encoded \(\varepsilon\)-elimination) and then removing the unit productions of the result (encoded unit elimination).

def reduce (g : EncodedCFG T) : EncodedCFG T :=
  g.epsElim.unitElim
Uses 3 · Used by 3

TheoremThe reduced grammar generates the language minus the empty word#✓fully proved

For every encoded context-free grammar \(g\), the language of the reduction of \(g\) (empty productions removed, then unit productions removed) consists of the nonempty words of the language of \(g\).

theorem language_reduce (g : EncodedCFG T) :
    g.reduce.language = {w | w ∈ g.language ∧ w ≠ []}
Uses 10

TheoremThe reduced grammar has no empty and no unit productions#✓fully proved

For every encoded context-free grammar \(g\), every production of the grammar denoted by the reduction of \(g\) (empty productions removed, then unit productions removed) has a nonempty output, and that output is not a single nonterminal.

theorem isReduced_reduce (g : EncodedCFG T) : IsReduced g.reduce.toCFG
Uses 14

Primitive recursiveness

TheoremReduction is primitive recursive#✓fully proved

Let \(T\) be a type of terminals with a primitive recursive encoding. The map sending an encoded context-free grammar \(g\) over \(T\) to its reduction, the encoded grammar obtained from \(g\) by removing empty productions and then unit productions, is primitive recursive, where encoded grammars are encoded as pairs of a start nonterminal and a list of productions.

theorem primrec_reduce : Primrec (reduce (T := T))
Uses 17

The dependency explorer needs JavaScript and its graph data.

Download the complete graph data.