module public import Langlib.Classes.Recursive.Decidability.Membership import Langlib.Utilities.PrimrecHelpers import Mathlib.Tactic /-! # Recursive Closure Under Kleene Star This file proves that recursive languages are closed under Kleene star. The decider builds a dynamic-programming table for the input word `w`. The table entry at index `j` records whether the prefix `w.take j` belongs to `L∗`; to fill entry `j + 1`, it searches all earlier cut positions `i` and checks whether the left prefix is already accepted and the nonempty block `w.drop i |>.take (j + 1 - i)` belongs to `L`. -/ variable {T : Type} [DecidableEq T] [Fintype T] [Primcodable T] private def starCellSearch (f : List T → Bool) (w : List T) (table : List Bool) (j : ℕ) (k : ℕ) : Bool := Nat.rec false (fun i acc => acc || (table.getD i false && f ((w.drop i).take (j - i)))) k private def starCell (f : List T → Bool) (w : List T) (table : List Bool) (j : ℕ) : Bool := starCellSearch f w table j j private def starTable (f : List T → Bool) (w : List T) (n : ℕ) : List Bool := Nat.rec [true] (fun j table => table ++ [starCell f w table (j + 1)]) n private def starDecider (f : List T → Bool) (w : List T) : Bool := (starTable f w w.length).getD w.length false omit [DecidableEq T] [Fintype T] [Primcodable T] in private lemma starCellSearch_rec_true_iff (f : List T → Bool) (w : List T) (table : List Bool) (j : ℕ) : ∀ k : ℕ, starCellSearch f w table j k = true ↔ ∃ i, i < k ∧ table.getD i false = true ∧ f ((w.drop i).take (j - i)) = true | 0 => by simp [starCellSearch] | k + 1 => by change (starCellSearch f w table j k || (table.getD k false && f ((w.drop k).take (j - k)))) = true ↔ ∃ i, i < k + 1 ∧ table.getD i false = true ∧ f ((w.drop i).take (j - i)) = true rw [Bool.or_eq_true, Bool.and_eq_true, starCellSearch_rec_true_iff f w table j k] constructor · rintro (⟨i, hi, htab, hmem⟩ | ⟨htab, hmem⟩) · exact ⟨i, Nat.lt_trans hi (Nat.lt_succ_self k), htab, hmem⟩ · exact ⟨k, Nat.lt_succ_self k, htab, hmem⟩ · rintro ⟨i, hi, htab, hmem⟩ rcases Nat.lt_or_eq_of_le (Nat.lt_succ_iff.mp hi) with hi' | rfl · exact Or.inl ⟨i, hi', htab, hmem⟩ · exact Or.inr ⟨htab, hmem⟩ omit [DecidableEq T] [Fintype T] [Primcodable T] in private lemma starCell_rec_true_iff (f : List T → Bool) (w : List T) (table : List Bool) (j : ℕ) : starCell f w table j = true ↔ ∃ i, i < j ∧ table.getD i false = true ∧ f ((w.drop i).take (j - i)) = true := by simpa [starCell] using starCellSearch_rec_true_iff f w table j j omit [DecidableEq T] [Fintype T] in private theorem starCell_computable {f : List T → Bool} (hf : Computable f) : Computable (fun ctx : List T × List Bool × ℕ => starCell f ctx.1 ctx.2.1 ctx.2.2) := by unfold starCell have hstep : Computable₂ (fun (ctx : List T × List Bool × ℕ) (p : ℕ × Bool) => p.2 || (ctx.2.1.getD p.1 false && f ((ctx.1.drop p.1).take (ctx.2.2 - p.1)))) := by apply Computable₂.mk have hidx : Computable (fun q : (List T × List Bool × ℕ) × (ℕ × Bool) => q.2.1) := Computable.fst.comp Computable.snd have hword : Computable (fun q : (List T × List Bool × ℕ) × (ℕ × Bool) => q.1.1) := Computable.fst.comp Computable.fst have htable : Computable (fun q : (List T × List Bool × ℕ) × (ℕ × Bool) => q.1.2.1) := Computable.fst.comp (Computable.snd.comp Computable.fst) have hj : Computable (fun q : (List T × List Bool × ℕ) × (ℕ × Bool) => q.1.2.2) := Computable.snd.comp (Computable.snd.comp Computable.fst) have hacc : Computable (fun q : (List T × List Bool × ℕ) × (ℕ × Bool) => q.2.2) := Computable.snd.comp Computable.snd have htab : Computable (fun q : (List T × List Bool × ℕ) × (ℕ × Bool) => q.1.2.1.getD q.2.1 false) := (Primrec.list_getD false).to_comp.comp htable hidx have hdrop : Computable (fun q : (List T × List Bool × ℕ) × (ℕ × Bool) => q.1.1.drop q.2.1) := (primrec₂_list_drop (α := T)).to_comp.comp hidx hword have hlen : Computable (fun q : (List T × List Bool × ℕ) × (ℕ × Bool) => q.1.2.2 - q.2.1) := (Primrec.nat_sub.to_comp).comp hj hidx have hseg : Computable (fun q : (List T × List Bool × ℕ) × (ℕ × Bool) => (q.1.1.drop q.2.1).take (q.1.2.2 - q.2.1)) := (primrec₂_list_take (α := T)).to_comp.comp hlen hdrop have hboth : Computable (fun q : (List T × List Bool × ℕ) × (ℕ × Bool) => q.1.2.1.getD q.2.1 false && f ((q.1.1.drop q.2.1).take (q.1.2.2 - q.2.1))) := (Primrec.and.to_comp).comp htab (hf.comp hseg) exact (Primrec.or.to_comp).comp hacc hboth exact Computable.nat_rec (Computable.snd.comp Computable.snd) (Computable.const false) hstep omit [DecidableEq T] [Fintype T] in private theorem starTable_computable {f : List T → Bool} (hf : Computable f) : Computable (fun w : List T => starTable f w w.length) := by unfold starTable have hstep : Computable₂ (fun (w : List T) (p : ℕ × List Bool) => p.2 ++ [starCell f w p.2 (p.1 + 1)]) := by apply Computable₂.mk have hcell : Computable (fun q : List T × (ℕ × List Bool) => starCell f q.1 q.2.2 (q.2.1 + 1)) := (starCell_computable hf).comp (Computable.fst.pair ((Computable.snd.comp Computable.snd).pair (Computable.succ.comp (Computable.fst.comp Computable.snd)))) have hsingleton : Computable (fun q : List T × (ℕ × List Bool) => [starCell f q.1 q.2.2 (q.2.1 + 1)]) := (Primrec.list_cons.to_comp).comp hcell (Computable.const []) exact (Primrec.list_append.to_comp).comp (Computable.snd.comp Computable.snd) hsingleton exact Computable.nat_rec Computable.list_length (Computable.const [true]) hstep omit [DecidableEq T] [Fintype T] in private theorem starDecider_computable {f : List T → Bool} (hf : Computable f) : Computable (starDecider f) := by unfold starDecider exact (Primrec.list_getD false).to_comp.comp (starTable_computable hf) Computable.list_length omit [DecidableEq T] [Fintype T] [Primcodable T] in private lemma kstar_append_mem {L : Language T} {u v : List T} (hu : u ∈ KStar.kstar L) (hv : v ∈ L) : u ++ v ∈ KStar.kstar L := by rw [Language.mem_kstar] at hu ⊢ rcases hu with ⟨S, rfl, hS⟩ refine ⟨S ++ [v], by simp, ?_⟩ intro y hy rw [List.mem_append] at hy rcases hy with hy | hy · exact hS y hy · have hy_eq : y = v := by simpa using hy simpa [hy_eq] using hv omit [DecidableEq T] [Fintype T] [Primcodable T] in private lemma take_split_eq (w : List T) {i j : ℕ} (hij : i ≤ j) : w.take j = w.take i ++ (w.drop i).take (j - i) := by calc w.take j = (w.take j).take i ++ (w.take j).drop i := (List.take_append_drop i (w.take j)).symm _ = w.take i ++ (w.drop i).take (j - i) := by simp [List.take_take, List.drop_take, Nat.min_eq_left hij] omit [DecidableEq T] [Fintype T] [Primcodable T] in private lemma starCell_correct {L : Language T} {f : List T → Bool} (hmem : ∀ x : List T, x ∈ L ↔ f x = true) (w : List T) (table : List Bool) {j : ℕ} (hjpos : 0 < j) (hjle : j ≤ w.length) (htable : ∀ i, i < j → (table.getD i false = true ↔ w.take i ∈ KStar.kstar L)) : starCell f w table j = true ↔ w.take j ∈ KStar.kstar L := by rw [starCell_rec_true_iff] constructor · rintro ⟨i, hij, htab, hseg⟩ have hprefix : w.take i ∈ KStar.kstar L := (htable i hij).mp htab have hblock : (w.drop i).take (j - i) ∈ L := (hmem _).mpr hseg have hsplit : w.take j = w.take i ++ (w.drop i).take (j - i) := take_split_eq w hij.le rw [hsplit] exact kstar_append_mem hprefix hblock · intro hstar rw [Language.mem_kstar_iff_exists_nonempty] at hstar rcases hstar with ⟨S, hflat, hS⟩ induction' S using List.reverseRecOn with S y ih · have : (w.take j).length = 0 := by simp [hflat] rw [List.length_take, Nat.min_eq_left hjle] at this omega · have hy : y ∈ L ∧ y ≠ [] := hS y (by simp) let i := S.flatten.length have hlen : j = i + y.length := by have h := congrArg List.length hflat simp [List.length_flatten, Nat.min_eq_left hjle] at h have hi : i = (List.map List.length S).sum := by simp [i, List.length_flatten] omega have hprefix : w.take i ∈ KStar.kstar L := by have hSi : S.flatten ∈ KStar.kstar L := by rw [Language.mem_kstar] exact ⟨S, rfl, fun z hz => (hS z (by simp [hz])).1⟩ have htake : w.take i = S.flatten := by have htake' : (w.take j).take i = S.flatten := by simp [hflat, i] have hile : i ≤ j := by omega simpa [List.take_take, Nat.min_eq_left hile] using htake' simpa [htake] using hSi have hseg : (w.drop i).take (j - i) ∈ L := by have hdrop : (w.drop i).take (j - i) = y := by have hdrop' : (w.take j).drop i = y := by simp [hflat, i] simpa [List.drop_take] using hdrop' simpa [hdrop] using hy.1 have hij : i < j := by have hypos : 0 < y.length := by cases y with | nil => exact (hy.2 rfl).elim | cons _ _ => simp omega exact ⟨i, hij, (htable i hij).mpr hprefix, (hmem _).mp hseg⟩ omit [DecidableEq T] [Fintype T] [Primcodable T] in private lemma starTable_length (f : List T → Bool) (w : List T) : ∀ n : ℕ, (starTable f w n).length = n + 1 | 0 => by simp [starTable] | n + 1 => by change (starTable f w n ++ [starCell f w (starTable f w n) (n + 1)]).length = n + 1 + 1 simp [starTable_length f w n, Nat.add_assoc] omit [DecidableEq T] [Fintype T] [Primcodable T] in private lemma starTable_correct {L : Language T} {f : List T → Bool} (hmem : ∀ x : List T, x ∈ L ↔ f x = true) (w : List T) : ∀ n : ℕ, n ≤ w.length → ∀ j, j ≤ n → ((starTable f w n).getD j false = true ↔ w.take j ∈ KStar.kstar L) | 0, _hn, j, hj => by cases Nat.eq_zero_of_le_zero hj simp [starTable, Language.nil_mem_kstar] | n + 1, hn, j, hj => by rcases Nat.lt_or_eq_of_le hj with hjlt | rfl · have hjn : j ≤ n := Nat.lt_succ_iff.mp hjlt have hstable : (starTable f w (n + 1)).getD j false = (starTable f w n).getD j false := by change (starTable f w n ++ [starCell f w (starTable f w n) (n + 1)]).getD j false = (starTable f w n).getD j false rw [List.getD_append] simpa [starTable_length f w n] using hjlt rw [hstable] exact starTable_correct hmem w n (Nat.le_trans (Nat.le_succ n) hn) j hjn · have hnew : (starTable f w (n + 1)).getD (n + 1) false = starCell f w (starTable f w n) (n + 1) := by change (starTable f w n ++ [starCell f w (starTable f w n) (n + 1)]).getD (n + 1) false = starCell f w (starTable f w n) (n + 1) rw [List.getD_append_right] · simp [starTable_length f w n] · simp [starTable_length f w n] rw [hnew] exact starCell_correct hmem w (starTable f w n) (Nat.succ_pos n) hn (fun i hi => starTable_correct hmem w n (Nat.le_trans (Nat.le_succ n) hn) i (Nat.lt_succ_iff.mp hi)) omit [DecidableEq T] [Fintype T] [Primcodable T] in private lemma starDecider_true_iff {L : Language T} {f : List T → Bool} (hmem : ∀ x : List T, x ∈ L ↔ f x = true) (w : List T) : starDecider f w = true ↔ w ∈ KStar.kstar L := by unfold starDecider simpa using starTable_correct hmem w w.length le_rfl w.length le_rfl /-- Recursive languages over finite, primcodable alphabets are closed under Kleene star. -/ public theorem is_Recursive_star {L : Language T} (hL : is_Recursive L) : is_Recursive (KStar.kstar L) := by obtain ⟨f, hf, hs⟩ := ComputablePred.computable_iff.mp (Recursive_membership_computable hL) have hmem : ∀ x : List T, x ∈ L ↔ f x = true := fun x => by simpa using (iff_of_eq (congrFun hs x)) refine is_Recursive_of_computable_decide (KStar.kstar L) (starDecider f) (starDecider_computable hf) ?_ intro w exact (starDecider_true_iff hmem w).symm /-- The class of recursive languages is closed under Kleene star. -/ public theorem Recursive_closedUnderKleeneStar : ClosedUnderKleeneStar (α := T) is_Recursive := fun _ hL => is_Recursive_star hL