Every unrestricted grammar is equivalent to one with finitely many nonterminals #
Since an unrestricted grammar stores its rules in a List, only finitely many
nonterminals can ever appear in a derivation from the initial symbol. We restrict
the nonterminal type to those that actually occur in the grammar, producing an
equivalent grammar whose nonterminal type carries a Fintype instance.
Main results #
restrictGrammar— restrict any grammar to one withFintypenonterminals.grammar_language_eq_restrictGrammar— the restricted grammar generates the same language.grammar_equivalent_finiteNT— every unrestricted grammar has an equivalent one withFinitenonterminals.
Extracting nonterminals from symbol lists #
Extract all nonterminals from a list of symbols.
Equations
- symbolsNTs [] = []
- symbolsNTs (symbol.terminal a :: rest) = symbolsNTs rest
- symbolsNTs (symbol.nonterminal n :: rest) = n :: symbolsNTs rest
Instances For
@[simp]
@[simp]
Used nonterminals of a grammar #
All nonterminals mentioned in a grammar rule.
Equations
- ruleNTs r = symbolsNTs r.input_L ++ [r.input_N] ++ symbolsNTs r.input_R ++ symbolsNTs r.output_string
Instances For
The list of all nonterminals used in a grammar.
Equations
- usedNTsList g = [g.initial] ++ List.flatMap ruleNTs g.rules
Instances For
The restricted grammar #
Equations
- usedNT_fintype g = Fintype.subtype (usedNTs g) ⋯
Restrict a symbol to UsedNT g.
Equations
- restrictSym g (symbol.terminal t) = symbol.terminal t
- restrictSym g (symbol.nonterminal n) = symbol.nonterminal (restrictNT g n)
Instances For
Embed a symbol over UsedNT g back into a symbol over g.nt.
Equations
- embedSym g (symbol.terminal t) = symbol.terminal t
- embedSym g (symbol.nonterminal ⟨n, property⟩) = symbol.nonterminal n
Instances For
The grammar restricted to its used nonterminals.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Equations
Properties of restrictSym and embedSym #
@[simp]
@[simp]
theorem
embedSym_restrictSym
{T : Type}
{g : grammar T}
{s : symbol T g.nt}
(h : ∀ (n : g.nt), s = symbol.nonterminal n → n ∈ usedNTs g)
:
The allNTsUsed predicate #
theorem
allNTsUsed_of_rule_input_L
{T : Type}
{g : grammar T}
{r : grule T g.nt}
(hr : r ∈ g.rules)
:
allNTsUsed g r.input_L
theorem
allNTsUsed_of_rule_input_R
{T : Type}
{g : grammar T}
{r : grule T g.nt}
(hr : r ∈ g.rules)
:
allNTsUsed g r.input_R
Roundtrip properties for lists #
theorem
map_embedSym_map_restrictSym
{T : Type}
{g : grammar T}
{l : List (symbol T g.nt)}
(h : allNTsUsed g l)
:
theorem
map_restrictSym_terminal
{T : Type}
(g : grammar T)
(w : List T)
:
List.map (restrictSym g) (List.map (fun (t : T) => symbol.terminal t) w) = List.map (fun (t : T) => symbol.terminal t) w
theorem
map_embedSym_terminal
{T : Type}
(g : grammar T)
(w : List T)
:
List.map (embedSym g) (List.map (fun (t : T) => symbol.terminal t) w) = List.map (fun (t : T) => symbol.terminal t) w
Preservation of allNTsUsed through derivations #
theorem
allNTsUsed_preserved_by_transform
{T : Type}
{g : grammar T}
{u v : List (symbol T g.nt)}
(ht : grammar_transforms g u v)
(hu : allNTsUsed g u)
:
allNTsUsed g v
theorem
allNTsUsed_preserved_by_derives
{T : Type}
{g : grammar T}
{u v : List (symbol T g.nt)}
(hd : grammar_derives g u v)
(hu : allNTsUsed g u)
:
allNTsUsed g v
Rule membership in the restricted grammar #
theorem
restrictGrammar_rule_of_mem
{T : Type}
{g : grammar T}
{r : grule T g.nt}
(hr : r ∈ g.rules)
:
{ input_L := List.map (restrictSym g) r.input_L, input_N := restrictNT g r.input_N,
input_R := List.map (restrictSym g) r.input_R, output_string := List.map (restrictSym g) r.output_string } ∈ (restrictGrammar g).rules
theorem
restrictGrammar_rule_mem
{T : Type}
{g : grammar T}
{r' : grule T (UsedNT g)}
(hr' : r' ∈ (restrictGrammar g).rules)
:
∃ r ∈ g.rules,
r'.input_L = List.map (restrictSym g) r.input_L ∧ r'.input_N = restrictNT g r.input_N ∧ r'.input_R = List.map (restrictSym g) r.input_R ∧ r'.output_string = List.map (restrictSym g) r.output_string
Derivation correspondence #
theorem
transforms_restrict
{T : Type}
{g : grammar T}
{u v : List (symbol T g.nt)}
(ht : grammar_transforms g u v)
(_hu : allNTsUsed g u)
:
grammar_transforms (restrictGrammar g) (List.map (restrictSym g) u) (List.map (restrictSym g) v)
theorem
derives_restrict
{T : Type}
{g : grammar T}
{u v : List (symbol T g.nt)}
(hd : grammar_derives g u v)
(hu : allNTsUsed g u)
:
grammar_derives (restrictGrammar g) (List.map (restrictSym g) u) (List.map (restrictSym g) v)
theorem
transforms_embed
{T : Type}
{g : grammar T}
{u v : List (symbol T (UsedNT g))}
(ht : grammar_transforms (restrictGrammar g) u v)
:
grammar_transforms g (List.map (embedSym g) u) (List.map (embedSym g) v)
theorem
derives_embed
{T : Type}
{g : grammar T}
{u v : List (symbol T (UsedNT g))}
(hd : grammar_derives (restrictGrammar g) u v)
:
grammar_derives g (List.map (embedSym g) u) (List.map (embedSym g) v)
Main theorem #
theorem
grammar_equivalent_finiteNT
{T : Type}
(g : grammar T)
:
∃ (g' : grammar T), Finite g'.nt ∧ grammar_language g = grammar_language g'
Every unrestricted grammar is equivalent to one with finitely many nonterminals.