import Langlib.Grammars.ContextFree.EquivMathlibCFG import Langlib.Classes.ContextFree.Basics.FiniteNT import Langlib.Automata.Pushdown.Equivalence.ContextFree.CFGToPDA import Langlib.Automata.Pushdown.Equivalence.ContextFree.PDAToCFG open PDA variable {T : Type} [Fintype T] theorem is_PDA_of_mathlib_cfg (g : ContextFreeGrammar T) [Fintype g.NT] : is_PDA g.language := by classical refine ⟨CFG_to_PDA.Q, Symbol T g.NT, inferInstance, inferInstance, CFG_to_PDA.M g, ?_⟩ symm exact CFG_to_PDA.pda_of_cfg g theorem mathlib_cfg_of_PDA {Q S : Type} [Fintype Q] [Fintype S] (M : PDA Q T S) : (PDA_to_CFG.G M).language = M.acceptsByEmptyStack := PDA_to_CFG.cfg_of_pda M theorem isContextFree_of_is_PDA {L : Language T} : is_PDA L → L.IsContextFree := by rintro ⟨Q, S, _, _, M, hM⟩ refine ⟨PDA_to_CFG.G M, ?_⟩ simpa [hM] using PDA_to_CFG.cfg_of_pda M theorem is_CF_of_is_PDA {L : Language T} : is_PDA L → is_CF L := by intro h rw [is_CF_iff_isContextFree] exact isContextFree_of_is_PDA h /-- Every context-free language (with possibly infinite NT) is accepted by some PDA. This removes the `[Fintype g.NT]` requirement from `is_PDA_of_mathlib_cfg` by first restricting the grammar to one with finite nonterminals. -/ theorem is_PDA_of_isContextFree {L : Language T} (hL : L.IsContextFree) : is_PDA L := by obtain ⟨g, hfin, hg⟩ := ContextFreeGrammar.exists_fintype_nt L hL rw [← hg] haveI := hfin exact is_PDA_of_mathlib_cfg g /-- The PDA-recognizable languages are exactly the context-free languages. -/ theorem is_PDA_iff_isContextFree {L : Language T} : is_PDA L ↔ L.IsContextFree := ⟨isContextFree_of_is_PDA, is_PDA_of_isContextFree⟩ /-- The class of context-free languages equals the class of PDA-recognizable languages. -/ theorem CF_eq_PDA_Class : (CF : Set (Language T)) = PDA.Class := by ext L exact is_CF_iff_isContextFree.trans is_PDA_iff_isContextFree.symm