module public import Langlib.Utilities.ClosurePredicates public import Langlib.Classes.RecursivelyEnumerable.Definition import Langlib.Classes.RecursivelyEnumerable.Closure.Concatenation import Langlib.Classes.RecursivelyEnumerable.Closure.Homomorphism import Langlib.Classes.RecursivelyEnumerable.Closure.Intersection import Langlib.Classes.RecursivelyEnumerable.Closure.InverseHomomorphism import Langlib.Classes.RecursivelyEnumerable.Closure.Star import Langlib.Classes.RecursivelyEnumerable.Closure.Union import Langlib.Classes.Regular.Closure.Homomorphism import Langlib.Classes.Regular.Examples.TopBot import Langlib.Classes.Regular.Inclusion.RecursivelyEnumerable import Mathlib.Algebra.Order.Floor.Extended import Mathlib.Algebra.Order.Floor.Semifield import Mathlib.Algebra.Order.Interval.Basic import Mathlib.Analysis.Complex.UpperHalfPlane.Basic import Mathlib.Analysis.SpecialFunctions.Bernstein import Mathlib.Analysis.SpecialFunctions.Gamma.Basic import Mathlib.Analysis.SpecialFunctions.Trigonometric.DerivHyp import Mathlib.Combinatorics.Enumerative.DyckWord import Mathlib.Combinatorics.SimpleGraph.Triangle.Removal import Mathlib.Data.NNRat.Floor import Mathlib.Data.Nat.Factorial.DoubleFactorial import Mathlib.Geometry.Euclidean.Altitude import Mathlib.NumberTheory.Height.Basic import Mathlib.NumberTheory.LucasLehmer import Mathlib.NumberTheory.SelbergSieve import Mathlib.Tactic.NormNum.BigOperators import Mathlib.Tactic.NormNum.Irrational import Mathlib.Tactic.NormNum.IsCoprime import Mathlib.Tactic.NormNum.IsSquare import Mathlib.Tactic.NormNum.LegendreSymbol import Mathlib.Tactic.NormNum.ModEq import Mathlib.Tactic.NormNum.NatFactorial import Mathlib.Tactic.NormNum.NatFib import Mathlib.Tactic.NormNum.NatLog import Mathlib.Tactic.NormNum.NatSqrt import Mathlib.Tactic.NormNum.Ordinal import Mathlib.Tactic.NormNum.Parity import Mathlib.Tactic.NormNum.Prime import Mathlib.Tactic.NormNum.RealSqrt import Mathlib.Topology.Sheaves.Init @[expose] public section /-! # RE Closure Under Substitution This file proves that recursively enumerable languages over finite alphabets are closed under finite-alphabet substitution. The key result is `RE_closedUnderSubstitution`: encode each substituted symbol as a block `inl a :: map inr u`, take the Kleene star of the RE block language, restrict the projected source word to the original RE language by inverse homomorphism and intersection, then erase the source-symbol markers by homomorphism. ## Main declarations - `RE_of_subst_RE` - `RE_closedUnderSubstitution` -/ open scoped Classical variable {α β ι : Type} /-- RE languages are closed under finite indexed union. -/ theorem RE_of_finite_iUnion [Fintype α] [Fintype ι] (L : ι → Language α) (hL : ∀ i, is_RE (L i)) : is_RE ((⋃ i, L i) : Language α) := by classical have hfin : ∀ s : Finset ι, is_RE ((⋃ i ∈ s, L i) : Language α) := by intro s induction s using Finset.induction_on with | empty => simpa using is_RE_of_isRegular (Language.isRegular_bot : (⊥ : Language α).IsRegular) | insert a s has ih => let U : Language α := (⋃ i ∈ s, L i) have hEq : ((⋃ i ∈ insert a s, L i) : Language α) = ((L a : Language α) + U : Language α) := by ext w have hU_mp : w ∈ U → ∃ i, ∃ _ : i ∈ s, w ∈ L i := by intro hw change w ∈ (⋃ i ∈ s, L i : Set (List α)) at hw simpa only [Set.mem_iUnion] using hw have hU_mpr : (∃ i, ∃ _ : i ∈ s, w ∈ L i) → w ∈ U := by intro hw change w ∈ (⋃ i ∈ s, L i : Set (List α)) simpa only [Set.mem_iUnion] using hw rw [Language.mem_add] constructor · intro hw simp only [Set.mem_iUnion, Finset.mem_insert] at hw rcases hw with ⟨i, hi, hwi⟩ rcases hi with rfl | his · exact Or.inl hwi · exact Or.inr (hU_mpr ⟨i, his, hwi⟩) · intro hw simp only [Set.mem_iUnion, Finset.mem_insert] rcases hw with hwa | hU · exact ⟨a, Or.inl rfl, hwa⟩ · obtain ⟨i, his, hwi⟩ := hU_mp hU exact ⟨i, Or.inr his, hwi⟩ rw [hEq] exact RE_of_RE_u_RE (L a : Language α) U ⟨hL a, ih⟩ simpa using hfin Finset.univ namespace Language /-- Projection from encoded substitution blocks to the source alphabet. -/ def substProj (x : α ⊕ β) : List α := match x with | Sum.inl a => [a] | Sum.inr _ => [] /-- Erasure from encoded substitution blocks to the target alphabet. -/ def substErase (x : α ⊕ β) : List β := match x with | Sum.inl _ => [] | Sum.inr b => [b] @[simp] theorem substProj_map_inr (u : List β) : (u.map Sum.inr).flatMap (@substProj α β) = [] := by induction u <;> simp [substProj, *] @[simp] theorem substErase_map_inr (u : List β) : (u.map Sum.inr).flatMap (@substErase α β) = u := by induction u <;> simp [substErase, *] /-- The language of one encoded substitution block. -/ def substBlock (f : α → Language β) : Language (α ⊕ β) := ⋃ a, ({[Sum.inl a]} : Language (α ⊕ β)) * ((f a).homomorphicImage fun b => [Sum.inr b]) @[simp] theorem substProj_block (a : α) (u : List β) : (Sum.inl a :: u.map Sum.inr).flatMap (@substProj α β) = [a] := by simp [substProj] @[simp] theorem substErase_block (a : α) (u : List β) : (Sum.inl a :: u.map Sum.inr).flatMap (@substErase α β) = u := by simp [substErase] theorem mem_homomorphicImage_iff_flatMap (L : Language α) (h : α → List β) (w : List β) : w ∈ L.homomorphicImage h ↔ ∃ x ∈ L, x.flatMap h = w := by simp only [homomorphicImage, subst] constructor · rintro ⟨x, hx, hw⟩ exact ⟨x, hx, ((mem_prod_singletons_iff_flatMap x h w).mp hw).symm⟩ · rintro ⟨x, hx, rfl⟩ exact ⟨x, hx, (mem_prod_singletons_iff_flatMap x h _).mpr rfl⟩ theorem mem_substBlock_iff (f : α → Language β) (z : List (α ⊕ β)) : z ∈ substBlock f ↔ ∃ a u, u ∈ f a ∧ z = Sum.inl a :: u.map Sum.inr := by constructor · intro hz change z ∈ (⋃ a, ({[Sum.inl a]} : Language (α ⊕ β)) * ((f a).homomorphicImage fun b => [Sum.inr b])) at hz simp only [Set.mem_iUnion] at hz obtain ⟨a, x, hx, y, hy, rfl⟩ := hz subst x obtain ⟨u, hu, hflat⟩ := (mem_homomorphicImage_iff_flatMap (f a) (fun b => [Sum.inr b]) y).mp hy have hy_eq : y = u.map Sum.inr := by rw [← hflat] simpa [Function.comp_def] using (List.flatMap_pure_eq_map (fun b : β => Sum.inr b) u) exact ⟨a, u, hu, by simp [hy_eq]⟩ · rintro ⟨a, u, hu, rfl⟩ change Sum.inl a :: List.map Sum.inr u ∈ (⋃ a, ({[Sum.inl a]} : Language (α ⊕ β)) * ((f a).homomorphicImage fun b => [Sum.inr b])) simp only [Set.mem_iUnion] refine ⟨a, ?_⟩ refine ⟨[Sum.inl a], Set.mem_singleton _, u.map Sum.inr, ?_, rfl⟩ exact (mem_homomorphicImage_iff_flatMap (f a) (fun b => [Sum.inr b]) _).mpr ⟨u, hu, by simpa [Function.comp_def] using (List.flatMap_pure_eq_map (fun b : β => Sum.inr b) u)⟩ private theorem forall₂_mem_map {f : α → Language β} : ∀ {W : List (List β)} {x : List α}, List.Forall₂ (fun u a => u ∈ f a) W x → List.Forall₂ (fun u L => u ∈ L) W (x.map f) | [], [], _ => by simp | _ :: _, [], h => by cases h | [], _ :: _, h => by cases h | u :: W, a :: x, h => by cases h with | cons hu hrest => exact List.Forall₂.cons hu (forall₂_mem_map hrest) private theorem encode_subst_witness (f : α → Language β) : ∀ {W : List (List β)} {x : List α}, List.Forall₂ (fun u a => u ∈ f a) W x → ∃ ys : List (List (α ⊕ β)), ys.flatten.flatMap (@substProj α β) = x ∧ ys.flatten.flatMap (@substErase α β) = W.flatten ∧ ∀ y ∈ ys, y ∈ substBlock f | [], [], _ => by refine ⟨[], by simp, by simp, by simp⟩ | _ :: _, [], h => by cases h | [], _ :: _, h => by cases h | u :: W, a :: x, h => by rw [List.forall₂_cons] at h obtain ⟨ys, hproj, herase, hys⟩ := encode_subst_witness f h.2 refine ⟨(Sum.inl a :: u.map Sum.inr) :: ys, ?_, ?_, ?_⟩ · simp [substProj, hproj, List.flatMap_append] · simp [substErase, herase, List.flatMap_append] · intro y hy rcases (List.mem_cons.mp hy) with hyHead | hyTail · rw [hyHead] exact (mem_substBlock_iff f _).mpr ⟨a, u, h.1, rfl⟩ · exact hys y hyTail private theorem decode_subst_blocks (f : α → Language β) : ∀ Y : List (List (α ⊕ β)), (∀ y ∈ Y, y ∈ substBlock f) → ∃ x W, List.Forall₂ (fun u a => u ∈ f a) W x ∧ Y.flatten.flatMap (@substProj α β) = x ∧ Y.flatten.flatMap (@substErase α β) = W.flatten | [], _ => by exact ⟨[], [], by simp, by simp, by simp⟩ | y :: Y, hY => by have hy : y ∈ substBlock f := hY y (by simp) obtain ⟨a, u, hu, rfl⟩ := (mem_substBlock_iff f y).mp hy obtain ⟨x, W, hW, hproj, herase⟩ := decode_subst_blocks f Y (fun z hz => hY z (List.mem_cons_of_mem _ hz)) refine ⟨a :: x, u :: W, ?_, ?_, ?_⟩ · rw [List.forall₂_cons] exact ⟨hu, hW⟩ · simp [substProj, hproj, List.flatMap_append] · simp [substErase, herase, List.flatMap_append] theorem subst_coding_eq_subst (L : Language α) (f : α → Language β) : (((KStar.kstar (substBlock f)) ⊓ ({ y : List (α ⊕ β) | y.flatMap (@substProj α β) ∈ L } : Language (α ⊕ β))) ).homomorphicImage (@substErase α β) = L.subst f := by ext w rw [mem_homomorphicImage_iff_flatMap] constructor · rintro ⟨y, hy, herase⟩ rcases hy with ⟨hyStar, hyProj⟩ obtain ⟨Y, rfl, hY⟩ := Language.mem_kstar.mp hyStar obtain ⟨x, W, hW, hproj, hflatten⟩ := decode_subst_blocks f Y hY refine ⟨x, ?_, ?_⟩ · change Y.flatten.flatMap (@substProj α β) ∈ L at hyProj rwa [hproj] at hyProj · rw [← herase, hflatten] exact (Language.mem_list_prod_iff_forall2 (x.map f) W.flatten).mpr ⟨W, rfl, forall₂_mem_map hW⟩ · intro hw simp only [subst] at hw obtain ⟨x, hxL, hwprod⟩ := hw obtain ⟨W, hWflat, hW⟩ := (Language.mem_list_prod_iff_forall2 (x.map f) w).mp hwprod have hW' : List.Forall₂ (fun u a => u ∈ f a) W x := by clear hWflat hxL hwprod induction x generalizing W with | nil => cases W <;> simp_all | cons a x ih => cases W with | nil => cases hW | cons u W => cases hW with | cons hu hrest => exact List.Forall₂.cons hu (ih W hrest) obtain ⟨Y, hproj, herase, hY⟩ := encode_subst_witness f hW' refine ⟨Y.flatten, ⟨?_, ?_⟩, ?_⟩ · exact Language.join_mem_kstar hY · change Y.flatten.flatMap (@substProj α β) ∈ L rwa [hproj] · rw [herase, ← hWflat] end Language variable [Fintype α] [Fintype β] /-- The encoded single-block language for an RE substitution family is RE. -/ theorem RE_of_substBlock_RE (f : α → Language β) (hf : ∀ a, is_RE (f a)) : is_RE (Language.substBlock f) := by classical apply (RE_of_finite_iUnion (α := α ⊕ β) (ι := α) (fun a => ({[Sum.inl a]} : Language (α ⊕ β)) * ((f a).homomorphicImage fun b => [Sum.inr b]))) intro a have hmarker : is_RE ({[Sum.inl a]} : Language (α ⊕ β)) := is_RE_of_isRegular (Language.isRegular_singleton_word [Sum.inl a]) have hchunk : is_RE ((f a).homomorphicImage fun b => [Sum.inr b]) := RE_closed_under_homomorphism (α := β) (β := α ⊕ β) (f a) (fun b => [Sum.inr b]) (hf a) exact RE_of_RE_c_RE ({[Sum.inl a]} : Language (α ⊕ β)) ((f a).homomorphicImage fun b => [Sum.inr b]) ⟨hmarker, hchunk⟩ /-- RE languages over finite alphabets are closed under substitution. -/ theorem RE_of_subst_RE (L : Language α) (f : α → Language β) (hL : is_RE L) (hf : ∀ a, is_RE (f a)) : is_RE (L.subst f) := by classical have hBlock : is_RE (Language.substBlock f) := RE_of_substBlock_RE f hf have hStar : is_RE (KStar.kstar (Language.substBlock f)) := RE_of_star_RE (Language.substBlock f) hBlock have hInv : is_RE ({ y : List (α ⊕ β) | y.flatMap (@Language.substProj α β) ∈ L } : Language (α ⊕ β)) := RE_of_inverseHomomorphism_RE L (@Language.substProj α β) hL have hCoded : is_RE ((KStar.kstar (Language.substBlock f)) ⊓ ({ y : List (α ⊕ β) | y.flatMap (@Language.substProj α β) ∈ L } : Language (α ⊕ β))) := RE_of_RE_i_RE (KStar.kstar (Language.substBlock f)) ({ y : List (α ⊕ β) | y.flatMap (@Language.substProj α β) ∈ L } : Language (α ⊕ β)) ⟨hStar, hInv⟩ have hImage : is_RE ((((KStar.kstar (Language.substBlock f)) ⊓ ({ y : List (α ⊕ β) | y.flatMap (@Language.substProj α β) ∈ L } : Language (α ⊕ β))).homomorphicImage (@Language.substErase α β))) := RE_closed_under_homomorphism ((KStar.kstar (Language.substBlock f)) ⊓ ({ y : List (α ⊕ β) | y.flatMap (@Language.substProj α β) ∈ L } : Language (α ⊕ β))) (@Language.substErase α β) hCoded rwa [Language.subst_coding_eq_subst] at hImage /-- The class of recursively enumerable languages is closed under substitution. -/ theorem RE_closedUnderSubstitution : ClosedUnderSubstitution is_RE := fun L f hL hf => RE_of_subst_RE L f hL hf