import Mathlib import Langlib.Grammars.ContextFree.EquivMathlibCFG import Langlib.Classes.ContextFree.NormalForms.ChomskyNormalFormTranslation import Langlib.Classes.ContextFree.Pumping.ParseTree /-! # Decidability of Emptiness This file proves that emptiness is decidable for regular languages. ## Main results - `regular_emptiness_decidable` – emptiness of a regular language is decidable -/ open List Relation /-! ## Part 1: Regular Languages -/ section Regular variable {α σ : Type*} /-- Any state reachable by a DFA can be reached by a word of length at most `Fintype.card σ`. By the pigeonhole principle. -/ lemma DFA.short_word_of_reachable [Fintype σ] [DecidableEq σ] (M : DFA α σ) (w : List α) : ∃ w' : List α, w'.length ≤ Fintype.card σ ∧ M.evalFrom M.start w' = M.evalFrom M.start w := by induction' h : w.length using Nat.strong_induction_on with n ih generalizing w M by_cases hn : n ≤ Fintype.card σ · exact ⟨w, h.symm ▸ hn, rfl⟩ · obtain ⟨i, j, hij, h_eq⟩ : ∃ i j : Fin (w.length + 1), i < j ∧ M.evalFrom M.start (w.take i) = M.evalFrom M.start (w.take j) := by by_contra! hc exact absurd (Finset.card_le_univ (Finset.image (fun i : Fin (w.length + 1) => M.evalFrom M.start (take (i : ℕ) w)) Finset.univ)) (by rw [Finset.card_image_of_injective _ fun i j hij => le_antisymm (not_lt.1 fun hi => hc _ _ hi hij.symm) (not_lt.1 fun hj => hc _ _ hj hij)] simpa using by linarith) obtain ⟨w', hw'⟩ : ∃ w' : List α, w' = w.take i ++ w.drop j ∧ M.evalFrom M.start w' = M.evalFrom M.start w := by simp_all +decide [DFA.evalFrom] conv_rhs => rw [← List.take_append_drop j w, List.foldl_append] have h_ind : w'.length < n := by grind exact Exists.elim (ih _ h_ind _ _ rfl) fun w'' hw'' => ⟨w'', hw''.1, hw''.2.trans hw'.2⟩ /-- The set of states reachable from `M.start` by following transitions. -/ def DFA.reachableSet [Fintype α] [Fintype σ] [DecidableEq σ] (M : DFA α σ) : Finset σ := let step := fun (S : Finset σ) => S ∪ Finset.univ.biUnion (fun a => S.image (M.step · a)) step^[Fintype.card σ] {M.start} /-- A state is in `reachableSet` iff it is reachable from `M.start` by some word. -/ lemma DFA.mem_reachableSet_iff [Fintype α] [Fintype σ] [DecidableEq σ] (M : DFA α σ) (s : σ) : s ∈ M.reachableSet ↔ ∃ w : List α, M.evalFrom M.start w = s := by constructor <;> intro h · contrapose! h have h_ind : ∀ n : ℕ, ∀ s : σ, (∀ w : List α, M.evalFrom M.start w ≠ s) → s ∉ (fun (S : Finset σ) => S ∪ Finset.univ.biUnion (fun a => S.image (M.step · a)))^[n] {M.start} := by intro n s hs induction' n with n ih generalizing s <;> simp_all +decide [Function.iterate_succ_apply'] · exact fun h => hs [] (by simp +decide [h]) · intro a t ht hts specialize ih t simp_all +decide obtain ⟨w, rfl⟩ := ih specialize hs (w ++ [a]) simp_all +decide [DFA.evalFrom] exact h_ind _ _ h · obtain ⟨w, rfl⟩ := h have h_ind : ∀ k ≤ Fintype.card σ, ∀ w : List α, w.length ≤ k → M.evalFrom M.start w ∈ (fun S => S ∪ (Finset.univ : Finset α).biUnion (fun a => S.image (M.step · a)))^[k] {M.start} := by intro k hk w hw induction' w using List.reverseRecOn with w ih generalizing k · induction' k with k ih <;> simp_all +decide [Function.iterate_succ_apply'] exact Or.inl (ih hk.le) · rcases k with (_ | k) <;> simp_all +decide [Function.iterate_succ_apply'] exact Or.inr ⟨ih, _, by rename_i h; exact h k hk.le hw, rfl⟩ obtain ⟨w', hw', hw'_eq⟩ := M.short_word_of_reachable w exact hw'_eq ▸ h_ind _ le_rfl _ hw' /-- Emptiness of a DFA's accepted language is decidable. -/ private noncomputable def dfa_emptiness_decidable [Fintype α] [Fintype σ] [DecidableEq α] [DecidableEq σ] (M : DFA α σ) [DecidablePred (· ∈ M.accept)] : Decidable (M.accepts = (∅ : Set (List α))) := by have key : M.accepts = (∅ : Set (List α)) ↔ ∀ s ∈ M.reachableSet, s ∉ M.accept := by constructor · intro h s hs hsa rw [M.mem_reachableSet_iff] at hs obtain ⟨w, rfl⟩ := hs have : w ∈ M.accepts := hsa rw [h] at this exact this · intro h apply Set.subset_eq_empty (fun w (hw : w ∈ M.accepts) => ?_) rfl exact h _ ((M.mem_reachableSet_iff _).mpr ⟨w, rfl⟩) hw rw [key] infer_instance /-- Emptiness of a regular language is decidable. -/ noncomputable def regular_emptiness_decidable [Fintype α] [DecidableEq α] (L : Language α) (hL : L.IsRegular) : Decidable (L = (∅ : Set (List α))) := by classical let σ := Classical.choose hL let hσ := Classical.choose_spec hL let _ : Fintype σ := Classical.choose hσ let hσ' := Classical.choose_spec hσ let M : DFA α σ := Classical.choose hσ' let hM : M.accepts = L := Classical.choose_spec hσ' rw [← hM] exact dfa_emptiness_decidable M end Regular