From f56971160062679f8d0f3b14cb741f05297fbba2 Mon Sep 17 00:00:00 2001 From: Chi-Yun Hsu Date: Tue, 14 Jul 2026 18:16:12 -0700 Subject: [PATCH 01/89] add regex_of_dfa, matches'_sum_map, IsRegular.regex --- .../Languages/RegularLanguage.lean | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/Cslib/Computability/Languages/RegularLanguage.lean b/Cslib/Computability/Languages/RegularLanguage.lean index 6e1bbcc8e0..a2059e7bbd 100644 --- a/Cslib/Computability/Languages/RegularLanguage.lean +++ b/Cslib/Computability/Languages/RegularLanguage.lean @@ -13,6 +13,7 @@ public import Cslib.Computability.Automata.NA.Concat public import Cslib.Computability.Automata.NA.Loop public import Cslib.Computability.Automata.NA.ToDA public import Mathlib.Computability.DFA +public import Mathlib.Computability.RegularExpressions public import Mathlib.Data.Finite.Sum public import Mathlib.Data.Set.Card @@ -184,4 +185,52 @@ theorem IsRegular.congr_fin_index {Symbol : Type} use Quotient c.eq, inferInstance, ⟨c.toDA, {a}⟩ exact DA.FinAcc.congr_language_eq +/- We use Kleene's Algorithm for DFA to prove a regular language can be expressed as a regex. -/ +section RegularExpression + +open RegularExpression + +variable {State : Type*} [Finite State] + +noncomputable instance : Fintype State := Fintype.ofFinite State + +/- +regex_of_dfa i j k is the regex for the path from state i to state j passing through states < k. +When k = 0, i = j, the regex is ε union all characters from state i to state i. +When k = 0, i ≠ j, the regex is all characters from state i to state j. +For k + 1, the regex is the union of regex_of_dfa i j k and +regex_of_dfa i k k concat (regex_of_dfa k k k)^* concat regex_of_dfa k j k. +-/ +-- Brooke can work on this +noncomputable def regex_of_dfa (dfa : DA.FinAcc State Symbol) + (i j : Fin (Fintype.card State)) : ℕ → RegularExpression Symbol + | 0 => if i = j then sorry else sorry + | k + 1 => if k ≥ Fintype.card State then regex_of_dfa dfa i j k else sorry + +/- From Yi-Siong's PR: https://github.com/leanprover-community/mathlib4/pull/35600 -/ +theorem matches'_sum_map {α : Type*} (L : List α) (f : α → RegularExpression Symbol) : + (L.map f).sum.matches' = ⋃ x ∈ L, (f x).matches' := by + induction L with + | nil => simp [Language.zero_def] + | cons b L' ih => + simp only [List.map_cons, List.sum_cons, matches', add_eq_sup, List.mem_cons, + iUnion_iUnion_eq_or_left, ih] + rfl + +theorem IsRegular.regex {l : Language Symbol} (h : l.IsRegular) : + ∃ r : RegularExpression Symbol, matches' r = l := by + obtain ⟨State, h_fin, ⟨da, acc⟩, rfl⟩ := Cslib.Language.IsRegular.iff_dfa.mp h + let : Fintype State := Fintype.ofFinite State + let eq : State ≃ Fin (Fintype.card State) := Fintype.equivFin State + let acc_List : List (Fin (Fintype.card State)) := + (acc.toFinset.map eq.toEmbedding).sort (· ≤ ·) + let regex := + (acc_List.map (fun i => regex_of_dfa ⟨da, acc⟩ (eq da.start) i (Fintype.card State))).sum + use regex + ext xs + simp only [matches'_sum_map, mem_language, Accepts, regex] + sorry + +end RegularExpression + end Cslib.Language From 1152ce81fd04bc9617c58fa734cd61a2001f8b15 Mon Sep 17 00:00:00 2001 From: Chi-Yun Hsu Date: Wed, 15 Jul 2026 09:52:09 -0700 Subject: [PATCH 02/89] Add language_sum --- .../Languages/RegularLanguage.lean | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/Cslib/Computability/Languages/RegularLanguage.lean b/Cslib/Computability/Languages/RegularLanguage.lean index a2059e7bbd..cd660cd9c1 100644 --- a/Cslib/Computability/Languages/RegularLanguage.lean +++ b/Cslib/Computability/Languages/RegularLanguage.lean @@ -217,9 +217,22 @@ theorem matches'_sum_map {α : Type*} (L : List α) (f : α → RegularExpressio iUnion_iUnion_eq_or_left, ih] rfl +/- +Should later be put in Computability/Automata/DA +The language defined by a DFA is equal to +the union of the languages defined by the DFA with only one accepting state. +-/ +-- Brooke can work on this. I am not sure whether it is definitely needed later though. +theorem language_sum {dfa : DA.FinAcc State Symbol} : + language dfa = + ⋃ s ∈ dfa.accept, language {dfa with accept := {s}} := by + sorry + theorem IsRegular.regex {l : Language Symbol} (h : l.IsRegular) : ∃ r : RegularExpression Symbol, matches' r = l := by - obtain ⟨State, h_fin, ⟨da, acc⟩, rfl⟩ := Cslib.Language.IsRegular.iff_dfa.mp h + obtain ⟨State, h_fin, dfa, rfl⟩ := Cslib.Language.IsRegular.iff_dfa.mp h + rw [language_sum] + obtain ⟨da, acc⟩ := dfa let : Fintype State := Fintype.ofFinite State let eq : State ≃ Fin (Fintype.card State) := Fintype.equivFin State let acc_List : List (Fin (Fintype.card State)) := @@ -227,8 +240,7 @@ theorem IsRegular.regex {l : Language Symbol} (h : l.IsRegular) : let regex := (acc_List.map (fun i => regex_of_dfa ⟨da, acc⟩ (eq da.start) i (Fintype.card State))).sum use regex - ext xs - simp only [matches'_sum_map, mem_language, Accepts, regex] + simp only [matches'_sum_map, regex] sorry end RegularExpression From ff56e6a5cd0c86ba0f1ede7d9485d905b1241f45 Mon Sep 17 00:00:00 2001 From: Chi-Yun Hsu Date: Thu, 16 Jul 2026 18:06:21 -0700 Subject: [PATCH 03/89] Changes union to sum to preserve Language API --- .../Languages/RegularLanguage.lean | 44 +++++++++++++------ 1 file changed, 31 insertions(+), 13 deletions(-) diff --git a/Cslib/Computability/Languages/RegularLanguage.lean b/Cslib/Computability/Languages/RegularLanguage.lean index 33bea83894..be3899bd4e 100644 --- a/Cslib/Computability/Languages/RegularLanguage.lean +++ b/Cslib/Computability/Languages/RegularLanguage.lean @@ -12,6 +12,7 @@ public import Cslib.Computability.Automata.DA.ToNA public import Cslib.Computability.Automata.NA.Concat public import Cslib.Computability.Automata.NA.Loop public import Cslib.Computability.Automata.NA.ToDA +public import Cslib.Computability.Automata.Acceptors.Acceptor public import Mathlib.Computability.DFA public import Mathlib.Computability.RegularExpressions public import Mathlib.Data.Finite.Sum @@ -220,6 +221,11 @@ theorem IsRegular.regex {r : RegularExpression Symbol} : | star P hP => grind [RegularExpression.matches', IsRegular.kstar] /- We use Kleene's Algorithm for DFA to prove a regular language can be expressed as a regex. -/ +lemma mem_add_language_iff {xs : List Symbol} {l₁ l₂ : Language Symbol} : + xs ∈ l₁ + l₂ ↔ xs ∈ l₁ ∨ xs ∈ l₂ := by + rw [Language.add_def] + exact mem_union xs l₁ l₂ + section RegularExpression open RegularExpression @@ -242,28 +248,40 @@ noncomputable def regex_of_dfa (dfa : DA.FinAcc State Symbol) | k + 1 => if k ≥ Fintype.card State then regex_of_dfa dfa i j k else sorry /- From Yi-Siong's PR: https://github.com/leanprover-community/mathlib4/pull/35600 -/ -theorem matches'_sum_map {α : Type*} (L : List α) (f : α → RegularExpression Symbol) : - (L.map f).sum.matches' = ⋃ x ∈ L, (f x).matches' := by +-- theorem matches'_sum_map0 {α : Type*} (L : List α) (f : α → RegularExpression Symbol) : +-- (L.map f).sum.matches' = ⋃ x ∈ L, (f x).matches' := by +-- induction L with +-- | nil => simp [Language.zero_def] +-- | cons b L' ih => +-- simp only [List.map_cons, List.sum_cons, matches', add_eq_sup, List.mem_cons, +-- iUnion_iUnion_eq_or_left, ih] +-- rfl + +/- Modified from Yi-Siong's PR: https://github.com/leanprover-community/mathlib4/pull/35600 -/ +theorem matches'_sum (L : List (RegularExpression Symbol)) : + (L.sum).matches' = (L.map matches').sum := by induction L with - | nil => simp [Language.zero_def] - | cons b L' ih => - simp only [List.map_cons, List.sum_cons, matches', add_eq_sup, List.mem_cons, - iUnion_iUnion_eq_or_left, ih] - rfl + | nil => simp + | cons b L' ih => simp [ih] /- Should later be put in Computability/Automata/DA The language defined by a DFA is equal to the union of the languages defined by the DFA with only one accepting state. -/ --- Brooke can work on this. I am not sure whether it is definitely needed later though. +-- I need to modify the statement to use addition rather than union. +-- Union is true but I need to make it compatible with Finset sum and List sum. +theorem language_union {dfa : DA.FinAcc State Symbol} : + language dfa = + ⋃ s ∈ dfa.accept, language {dfa with accept := {s}} := by sorry + theorem language_sum {dfa : DA.FinAcc State Symbol} : language dfa = - ⋃ s ∈ dfa.accept, language {dfa with accept := {s}} := by - sorry + ∑ s ∈ dfa.accept.toFinset, language {dfa with accept := {s}} := by sorry -theorem IsRegular.regex {l : Language Symbol} (h : l.IsRegular) : - ∃ r : RegularExpression Symbol, matches' r = l := by +theorem IsRegular.iff_regex [DecidableEq State] {l : Language Symbol} : + l.IsRegular ↔ ∃ r : RegularExpression Symbol, l = matches' r := by + refine ⟨fun h => ?_, fun ⟨r, hr⟩ => hr ▸ IsRegular.regex⟩ obtain ⟨State, h_fin, dfa, rfl⟩ := Cslib.Language.IsRegular.iff_dfa.mp h rw [language_sum] obtain ⟨da, acc⟩ := dfa @@ -274,7 +292,7 @@ theorem IsRegular.regex {l : Language Symbol} (h : l.IsRegular) : let regex := (acc_List.map (fun i => regex_of_dfa ⟨da, acc⟩ (eq da.start) i (Fintype.card State))).sum use regex - simp only [matches'_sum_map, regex] + simp only [matches'_sum, regex] sorry end RegularExpression From 9fce52990b819c2a080f4a9febd413d2a30123ee Mon Sep 17 00:00:00 2001 From: Brooke Gill <96643991+brooke-gill@users.noreply.github.com> Date: Mon, 20 Jul 2026 21:55:28 -0700 Subject: [PATCH 04/89] Initial progress --- .../Languages/RegularLanguage.lean | 48 +++++++++++++++++-- 1 file changed, 44 insertions(+), 4 deletions(-) diff --git a/Cslib/Computability/Languages/RegularLanguage.lean b/Cslib/Computability/Languages/RegularLanguage.lean index be3899bd4e..5b8a2961dc 100644 --- a/Cslib/Computability/Languages/RegularLanguage.lean +++ b/Cslib/Computability/Languages/RegularLanguage.lean @@ -234,6 +234,7 @@ variable {State : Type*} [Finite State] noncomputable instance : Fintype State := Fintype.ofFinite State + /- regex_of_dfa i j k is the regex for the path from state i to state j passing through states < k. When k = 0, i = j, the regex is ε union all characters from state i to state i. @@ -242,10 +243,25 @@ For k + 1, the regex is the union of regex_of_dfa i j k and regex_of_dfa i k k concat (regex_of_dfa k k k)^* concat regex_of_dfa k j k. -/ -- Brooke can work on this + +variable [Fintype Symbol] + +open scoped Classical in noncomputable def regex_of_dfa (dfa : DA.FinAcc State Symbol) (i j : Fin (Fintype.card State)) : ℕ → RegularExpression Symbol - | 0 => if i = j then sorry else sorry - | k + 1 => if k ≥ Fintype.card State then regex_of_dfa dfa i j k else sorry + | 0 => + let e := Fintype.equivFin State + let chars := (Finset.univ.filter + (fun x : Symbol ↦ dfa.tr (e.symm i) x = e.symm j)).toList.map RegularExpression.char + if i = j then 1 + chars.sum else chars.sum + | k + 1 => + if h : k ≥ Fintype.card State then regex_of_dfa dfa i j k + else + let kFin : Fin (Fintype.card State) := ⟨k, by omega⟩ + regex_of_dfa dfa i j k + + regex_of_dfa dfa i kFin k * (regex_of_dfa dfa kFin kFin k).star * + regex_of_dfa dfa kFin j k + /- From Yi-Siong's PR: https://github.com/leanprover-community/mathlib4/pull/35600 -/ -- theorem matches'_sum_map0 {α : Type*} (L : List α) (f : α → RegularExpression Symbol) : @@ -271,13 +287,37 @@ the union of the languages defined by the DFA with only one accepting state. -/ -- I need to modify the statement to use addition rather than union. -- Union is true but I need to make it compatible with Finset sum and List sum. + +omit [Finite State] [Fintype Symbol] in theorem language_union {dfa : DA.FinAcc State Symbol} : language dfa = - ⋃ s ∈ dfa.accept, language {dfa with accept := {s}} := by sorry + ⋃ s ∈ dfa.accept, language {dfa with accept := {s}} := by + ext xs + simp only [mem_language] + constructor + · intro h1 + refine Set.mem_biUnion h1 ?_ + rfl + · intro h1 + obtain ⟨s, hs, hmem⟩ := Set.mem_iUnion₂.mp h1 + change dfa.mtr dfa.start xs ∈ dfa.accept + change dfa.mtr dfa.start xs = s at hmem + rw [hmem] + exact hs + + + theorem language_sum {dfa : DA.FinAcc State Symbol} : language dfa = - ∑ s ∈ dfa.accept.toFinset, language {dfa with accept := {s}} := by sorry + ∑ s ∈ dfa.accept.toFinset, language {dfa with accept := {s}} := by + + ext xs + simp + constructor + intro h1 + + theorem IsRegular.iff_regex [DecidableEq State] {l : Language Symbol} : l.IsRegular ↔ ∃ r : RegularExpression Symbol, l = matches' r := by From bdaac4a9bedcd93e8265b2c903e0f20a28057f2b Mon Sep 17 00:00:00 2001 From: Chi-Yun Hsu Date: Tue, 21 Jul 2026 16:12:31 -0700 Subject: [PATCH 05/89] Added regex_of_dfa' to avoid equiv with Fin n --- .../Languages/RegularLanguage.lean | 88 ++++++++++++------- 1 file changed, 55 insertions(+), 33 deletions(-) diff --git a/Cslib/Computability/Languages/RegularLanguage.lean b/Cslib/Computability/Languages/RegularLanguage.lean index 6363eed702..fb572501e7 100644 --- a/Cslib/Computability/Languages/RegularLanguage.lean +++ b/Cslib/Computability/Languages/RegularLanguage.lean @@ -228,6 +228,18 @@ section RegularExpression open RegularExpression +-- Brooke can work on this (SECOND EASIEST) +theorem IsRegular.iff_dfa' {l : Language Symbol} : + l.IsRegular ↔ ∃ (n : ℕ), ∃ dfa : DA.FinAcc (Fin n) Symbol, language dfa = l := by + #check IsRegular.iff_dfa + constructor + · intro h_reg + obtain ⟨State, h_fin, dfa_abs, rfl⟩ := IsRegular.iff_dfa.mp h_reg + -- Use Fintype.equivFin State to get an equivalence of State with Fin n. + -- Construct dfa from dfa_abs using the equivalence + sorry + · sorry + variable {State : Type*} [Finite State] noncomputable instance : Fintype State := Fintype.ofFinite State @@ -240,7 +252,6 @@ When k = 0, i ≠ j, the regex is all characters from state i to state j. For k + 1, the regex is the union of regex_of_dfa i j k and regex_of_dfa i k k concat (regex_of_dfa k k k)^* concat regex_of_dfa k j k. -/ --- Brooke can work on this variable [Fintype Symbol] @@ -260,6 +271,11 @@ noncomputable def regex_of_dfa (dfa : DA.FinAcc State Symbol) regex_of_dfa dfa i kFin k * (regex_of_dfa dfa kFin kFin k).star * regex_of_dfa dfa kFin j k +-- Brooke can work on this (EASIEST) +noncomputable def regex_of_dfa' {n : ℕ} (dfa : DA.FinAcc (Fin n) Symbol) + (i j : Fin n) : ℕ → RegularExpression Symbol + | 0 => sorry + | k + 1 => sorry /- From Yi-Siong's PR: https://github.com/leanprover-community/mathlib4/pull/35600 -/ -- theorem matches'_sum_map0 {α : Type*} (L : List α) (f : α → RegularExpression Symbol) : @@ -290,48 +306,54 @@ omit [Finite State] [Fintype Symbol] in theorem language_union {dfa : DA.FinAcc State Symbol} : language dfa = ⋃ s ∈ dfa.accept, language {dfa with accept := {s}} := by - ext xs - simp only [mem_language] - constructor - · intro h1 - refine Set.mem_biUnion h1 ?_ - rfl - · intro h1 - obtain ⟨s, hs, hmem⟩ := Set.mem_iUnion₂.mp h1 - change dfa.mtr dfa.start xs ∈ dfa.accept - change dfa.mtr dfa.start xs = s at hmem - rw [hmem] - exact hs - - - - -theorem language_sum {dfa : DA.FinAcc State Symbol} : - language dfa = - ∑ s ∈ dfa.accept.toFinset, language {dfa with accept := {s}} := by - - ext xs - simp - constructor - intro h1 + ext xs + simp only [mem_language] + constructor + · intro h1 + refine Set.mem_biUnion h1 ?_ + rfl + · intro h1 + obtain ⟨s, hs, hmem⟩ := Set.mem_iUnion₂.mp h1 + change dfa.mtr dfa.start xs ∈ dfa.accept + change dfa.mtr dfa.start xs = s at hmem + rw [hmem] + exact hs + +-- Brooke can work on this (Work on this last) +theorem language_sum {n : ℕ} {dfa : DA.FinAcc (Fin n) Symbol} : + language dfa = (((dfa.accept.toFinset).sort (· ≤ ·)).map + (fun s => language {dfa with accept := {s}})).sum := by + #check DFA.mk + sorry +/- IsRegular.iff_regex in the situation where the there is a single accepting state -/ +omit [Finite State] [Fintype Symbol] in +theorem acc_singleton {n : ℕ} {s : Fin n} {dfa : DA.FinAcc (Fin n) Symbol} (h : dfa.accept = {s}) : + language dfa = matches' (regex_of_dfa' dfa dfa.start s n) := by sorry theorem IsRegular.iff_regex [DecidableEq State] {l : Language Symbol} : l.IsRegular ↔ ∃ r : RegularExpression Symbol, l = matches' r := by refine ⟨fun h => ?_, fun ⟨r, hr⟩ => hr ▸ IsRegular.regex⟩ - obtain ⟨State, h_fin, dfa, rfl⟩ := Cslib.Language.IsRegular.iff_dfa.mp h + obtain ⟨n, dfa, rfl⟩ := Cslib.Language.IsRegular.iff_dfa'.mp h + -- obtain ⟨da, acc⟩ := dfa + -- let : Fintype State := Fintype.ofFinite State + -- let eq : State ≃ Fin (Fintype.card State) := Fintype.equivFin State + set acc_List : List (Fin n) := (dfa.accept.toFinset).sort (· ≤ ·) with h_acc + rw [language_sum] - obtain ⟨da, acc⟩ := dfa - let : Fintype State := Fintype.ofFinite State - let eq : State ≃ Fin (Fintype.card State) := Fintype.equivFin State - let acc_List : List (Fin (Fintype.card State)) := - (acc.toFinset.map eq.toEmbedding).sort (· ≤ ·) let regex := - (acc_List.map (fun i => regex_of_dfa ⟨da, acc⟩ (eq da.start) i (Fintype.card State))).sum + (acc_List.map (fun i => regex_of_dfa' dfa (dfa.start) i n)).sum use regex simp only [matches'_sum, regex] - sorry + apply congrArg + rw [← h_acc, List.map_map] + suffices h : + (fun s => language {dfa with accept := {s}}) = + (matches' ∘ fun i => regex_of_dfa' {dfa with accept := {i}} dfa.start i n) by sorry + funext s + simp only [Function.comp_apply] + exact acc_singleton rfl end RegularExpression From 1dd27bfbe9765e50efbff9068eadb465a5f56d48 Mon Sep 17 00:00:00 2001 From: Brooke Gill <96643991+brooke-gill@users.noreply.github.com> Date: Thu, 23 Jul 2026 14:05:00 -0700 Subject: [PATCH 06/89] Added regex_of_dfa' --- Cslib/Computability/Languages/RegularLanguage.lean | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/Cslib/Computability/Languages/RegularLanguage.lean b/Cslib/Computability/Languages/RegularLanguage.lean index fb572501e7..3d19203e04 100644 --- a/Cslib/Computability/Languages/RegularLanguage.lean +++ b/Cslib/Computability/Languages/RegularLanguage.lean @@ -274,8 +274,17 @@ noncomputable def regex_of_dfa (dfa : DA.FinAcc State Symbol) -- Brooke can work on this (EASIEST) noncomputable def regex_of_dfa' {n : ℕ} (dfa : DA.FinAcc (Fin n) Symbol) (i j : Fin n) : ℕ → RegularExpression Symbol - | 0 => sorry - | k + 1 => sorry + | 0 => + let chars := (Finset.univ.filter + (fun x : Symbol ↦ dfa.tr i x = j)).toList.map RegularExpression.char + if i = j then 1 + chars.sum else chars.sum + | k + 1 => + if h : k ≥ n then regex_of_dfa' dfa i j k + else + let kFin : Fin n := ⟨k, by omega⟩ + regex_of_dfa' dfa i j k + + regex_of_dfa' dfa i kFin k * (regex_of_dfa' dfa kFin kFin k).star * + regex_of_dfa' dfa kFin j k /- From Yi-Siong's PR: https://github.com/leanprover-community/mathlib4/pull/35600 -/ -- theorem matches'_sum_map0 {α : Type*} (L : List α) (f : α → RegularExpression Symbol) : From f141577e796c7b2d9fc28bcad4fda4590d81c87c Mon Sep 17 00:00:00 2001 From: Brooke Gill <96643991+brooke-gill@users.noreply.github.com> Date: Sun, 26 Jul 2026 14:47:08 -0700 Subject: [PATCH 07/89] Finished iff_dfa' --- Cslib/Computability/Languages/RegularLanguage.lean | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/Cslib/Computability/Languages/RegularLanguage.lean b/Cslib/Computability/Languages/RegularLanguage.lean index 3d19203e04..66c3cda748 100644 --- a/Cslib/Computability/Languages/RegularLanguage.lean +++ b/Cslib/Computability/Languages/RegularLanguage.lean @@ -231,14 +231,22 @@ open RegularExpression -- Brooke can work on this (SECOND EASIEST) theorem IsRegular.iff_dfa' {l : Language Symbol} : l.IsRegular ↔ ∃ (n : ℕ), ∃ dfa : DA.FinAcc (Fin n) Symbol, language dfa = l := by - #check IsRegular.iff_dfa constructor · intro h_reg obtain ⟨State, h_fin, dfa_abs, rfl⟩ := IsRegular.iff_dfa.mp h_reg + have : Fintype State := Fintype.ofFinite State + let n := Fintype.card State + let dfa := DFA.mk dfa_abs.tr dfa_abs.start dfa_abs.accept + let dfa2 := DFA.reindex (Fintype.equivFin State) (dfa) + let dfa3 := DA.FinAcc.mk {tr := dfa2.step, start := dfa2.start} dfa2.accept + use n, dfa3 + exact DFA.accepts_reindex dfa (Fintype.equivFin State) -- Use Fintype.equivFin State to get an equivalence of State with Fin n. -- Construct dfa from dfa_abs using the equivalence - sorry - · sorry + · intro h1 + obtain ⟨n, dfa, h⟩ := h1 + apply IsRegular.iff_dfa.mpr + exact ⟨Fin n, inferInstance, dfa, h⟩ variable {State : Type*} [Finite State] From 123456789360ad75204bcdf1e06463f7ff33e984 Mon Sep 17 00:00:00 2001 From: Brooke Gill <96643991+brooke-gill@users.noreply.github.com> Date: Mon, 27 Jul 2026 16:17:02 -0700 Subject: [PATCH 08/89] Finished language_sum --- .../Languages/RegularLanguage.lean | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/Cslib/Computability/Languages/RegularLanguage.lean b/Cslib/Computability/Languages/RegularLanguage.lean index 66c3cda748..1c49f2645f 100644 --- a/Cslib/Computability/Languages/RegularLanguage.lean +++ b/Cslib/Computability/Languages/RegularLanguage.lean @@ -337,11 +337,27 @@ theorem language_union {dfa : DA.FinAcc State Symbol} : exact hs -- Brooke can work on this (Work on this last) +omit [Fintype Symbol] in theorem language_sum {n : ℕ} {dfa : DA.FinAcc (Fin n) Symbol} : language dfa = (((dfa.accept.toFinset).sort (· ≤ ·)).map (fun s => language {dfa with accept := {s}})).sum := by - #check DFA.mk - sorry + ext xs + simp only [mem_language] + have memsum (l : List (Fin n)) : xs ∈ (l.map (fun s => language {dfa with accept := {s}})).sum + ↔ ∃ s ∈ l, xs ∈ language {dfa with accept := {s}} := by + induction l with + | nil => + simp + | cons a l ih => + simp only [List.map_cons, List.sum_cons, Language.mem_add, List.mem_cons, ih] + grind + rw [memsum] + simp only [Finset.mem_sort, Set.mem_toFinset, mem_language] + grind [Accepts] + + + + /- IsRegular.iff_regex in the situation where the there is a single accepting state -/ omit [Finite State] [Fintype Symbol] in From c1fcd5b684a72df6a9807cff81f7d166ebb36005 Mon Sep 17 00:00:00 2001 From: Chi-Yun Hsu Date: Tue, 28 Jul 2026 09:37:08 -0700 Subject: [PATCH 09/89] minimum golf --- .../Languages/RegularLanguage.lean | 42 +++++++++---------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/Cslib/Computability/Languages/RegularLanguage.lean b/Cslib/Computability/Languages/RegularLanguage.lean index 1c49f2645f..833cd51f8a 100644 --- a/Cslib/Computability/Languages/RegularLanguage.lean +++ b/Cslib/Computability/Languages/RegularLanguage.lean @@ -228,24 +228,25 @@ section RegularExpression open RegularExpression + -- Brooke can work on this (SECOND EASIEST) theorem IsRegular.iff_dfa' {l : Language Symbol} : l.IsRegular ↔ ∃ (n : ℕ), ∃ dfa : DA.FinAcc (Fin n) Symbol, language dfa = l := by + rw [IsRegular.iff_dfa] -- do this in front of constructor constructor - · intro h_reg - obtain ⟨State, h_fin, dfa_abs, rfl⟩ := IsRegular.iff_dfa.mp h_reg + · rintro ⟨State, h_fin, ⟨⟨flts, start⟩, acc⟩, rfl⟩ + -- intro h_reg + -- obtain ⟨State, h_fin, dfa_abs, rfl⟩ := h_reg have : Fintype State := Fintype.ofFinite State - let n := Fintype.card State - let dfa := DFA.mk dfa_abs.tr dfa_abs.start dfa_abs.accept - let dfa2 := DFA.reindex (Fintype.equivFin State) (dfa) - let dfa3 := DA.FinAcc.mk {tr := dfa2.step, start := dfa2.start} dfa2.accept - use n, dfa3 - exact DFA.accepts_reindex dfa (Fintype.equivFin State) - -- Use Fintype.equivFin State to get an equivalence of State with Fin n. - -- Construct dfa from dfa_abs using the equivalence - · intro h1 - obtain ⟨n, dfa, h⟩ := h1 - apply IsRegular.iff_dfa.mpr + -- let n := Fintype.card State + let dfa := DFA.mk flts.tr start acc -- mathlib + let dfa2 := DFA.reindex (Fintype.equivFin State) dfa -- mathlib on Fin n + let dfa3 := DA.FinAcc.mk {tr := dfa2.step, start := dfa2.start} dfa2.accept -- cslib on Fin n + -- use n, dfa3 + exact ⟨Fintype.card State, dfa3, DFA.accepts_reindex dfa (Fintype.equivFin State)⟩ + -- exact ⟨n, dfa3, DFA.accepts_reindex dfa (Fintype.equivFin State)⟩ + -- exact DFA.accepts_reindex dfa (Fintype.equivFin State) + · intro ⟨n, dfa, h⟩ exact ⟨Fin n, inferInstance, dfa, h⟩ variable {State : Type*} [Finite State] @@ -340,25 +341,20 @@ theorem language_union {dfa : DA.FinAcc State Symbol} : omit [Fintype Symbol] in theorem language_sum {n : ℕ} {dfa : DA.FinAcc (Fin n) Symbol} : language dfa = (((dfa.accept.toFinset).sort (· ≤ ·)).map - (fun s => language {dfa with accept := {s}})).sum := by + (fun s ↦ language {dfa with accept := {s}})).sum := by ext xs simp only [mem_language] - have memsum (l : List (Fin n)) : xs ∈ (l.map (fun s => language {dfa with accept := {s}})).sum + have memsum (l : List (Fin n)) : xs ∈ (l.map (fun s ↦ language {dfa with accept := {s}})).sum ↔ ∃ s ∈ l, xs ∈ language {dfa with accept := {s}} := by induction l with - | nil => - simp + | nil => simp | cons a l ih => simp only [List.map_cons, List.sum_cons, Language.mem_add, List.mem_cons, ih] grind - rw [memsum] - simp only [Finset.mem_sort, Set.mem_toFinset, mem_language] + -- rw [memsum] + simp only [memsum, Finset.mem_sort, Set.mem_toFinset, mem_language] grind [Accepts] - - - - /- IsRegular.iff_regex in the situation where the there is a single accepting state -/ omit [Finite State] [Fintype Symbol] in theorem acc_singleton {n : ℕ} {s : Fin n} {dfa : DA.FinAcc (Fin n) Symbol} (h : dfa.accept = {s}) : From 31decc21277209c488526abfb1a26a1c3701e5a5 Mon Sep 17 00:00:00 2001 From: Chi-Yun Hsu Date: Tue, 28 Jul 2026 14:44:29 -0700 Subject: [PATCH 10/89] Trial statement relating regex_of_dfa with path --- .../Languages/RegularLanguage.lean | 48 ++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/Cslib/Computability/Languages/RegularLanguage.lean b/Cslib/Computability/Languages/RegularLanguage.lean index 833cd51f8a..88b3e4225c 100644 --- a/Cslib/Computability/Languages/RegularLanguage.lean +++ b/Cslib/Computability/Languages/RegularLanguage.lean @@ -18,6 +18,9 @@ public import Mathlib.Computability.RegularExpressions public import Mathlib.Data.Finite.Sum public import Mathlib.Data.Set.Card +public import Mathlib.Computability.NFA +public import Mathlib.Computability.EpsilonNFA + /-! # Regular languages -/ @@ -295,6 +298,50 @@ noncomputable def regex_of_dfa' {n : ℕ} (dfa : DA.FinAcc (Fin n) Symbol) regex_of_dfa' dfa i kFin k * (regex_of_dfa' dfa kFin kFin k).star * regex_of_dfa' dfa kFin j k +#check εNFA.IsPath +-- Mimicing the definition of NFA.Path. Path s xs is the type of +-- inductive Path : State → List Symbol → Type (max u_1 u_2) +-- | nil (s : State) : Path s [] +-- | cons (s u : State) (a : Symbol) (x : List Symbol) : Path (flts.tr s a) x → Path s (a :: x) + +def Path_supp (flts : FLTS State Symbol) : State → List Symbol → Set State + | _, [] => ∅ + | _, [_] => ∅ + | s, a :: x => {flts.tr s a} ∪ Path_supp flts (flts.tr s a) x + +-- /-- An `Acceptor` is a machine that recognises strings (lists of symbols in an alphabet). -/ +-- class Acceptor (A : Type u) (Symbol : outParam (Type v)) where +-- /-- Predicate that establishes whether a string `xs` is accepted. -/ +-- Accepts (a : A) (xs : List Symbol) : Prop + +-- /-- The language of an `Acceptor` is the set of strings it `Accepts`. -/ +-- @[scoped grind .] +-- def language [Acceptor A Symbol] (a : A) : Language Symbol := +-- { xs | Accepts a xs } + +structure Path_of_FLTS (n : ℕ) (Symbol : Type*) extends FLTS (Fin n) Symbol where + start : Fin n + finish : Fin n + bound : ℕ + +instance {n : ℕ} : Acceptor (Path_of_FLTS n Symbol) Symbol where + Accepts (a : Path_of_FLTS n Symbol) (xs : List Symbol) := + a.mtr a.start xs = a.finish ∧ (∀ i ∈ Path_supp a.toFLTS a.start xs, i < a.bound) + +theorem language_path_eq_regex_of_dfa {n k : ℕ} {i j : Fin n} {dfa : DA.FinAcc (Fin n) Symbol} : + language (Path_of_FLTS.mk dfa.toFLTS i j k) = matches' (regex_of_dfa' dfa i j k) := by + ext xs + simp only [mem_language, Accepts] + induction k with + | zero => + simp only [not_lt_zero, imp_false, regex_of_dfa'] + split_ifs with heq + · rw [heq, matches'_add] + sorry + · sorry + | succ => + sorry + /- From Yi-Siong's PR: https://github.com/leanprover-community/mathlib4/pull/35600 -/ -- theorem matches'_sum_map0 {α : Type*} (L : List α) (f : α → RegularExpression Symbol) : -- (L.map f).sum.matches' = ⋃ x ∈ L, (f x).matches' := by @@ -356,7 +403,6 @@ theorem language_sum {n : ℕ} {dfa : DA.FinAcc (Fin n) Symbol} : grind [Accepts] /- IsRegular.iff_regex in the situation where the there is a single accepting state -/ -omit [Finite State] [Fintype Symbol] in theorem acc_singleton {n : ℕ} {s : Fin n} {dfa : DA.FinAcc (Fin n) Symbol} (h : dfa.accept = {s}) : language dfa = matches' (regex_of_dfa' dfa dfa.start s n) := by sorry From 47a454a4b422067d6575504f33dda532ced12d67 Mon Sep 17 00:00:00 2001 From: Chi-Yun Hsu Date: Tue, 28 Jul 2026 16:20:06 -0700 Subject: [PATCH 11/89] Added assignments for next week --- .../Languages/RegularLanguage.lean | 43 +++++++++++-------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/Cslib/Computability/Languages/RegularLanguage.lean b/Cslib/Computability/Languages/RegularLanguage.lean index 88b3e4225c..89142499a7 100644 --- a/Cslib/Computability/Languages/RegularLanguage.lean +++ b/Cslib/Computability/Languages/RegularLanguage.lean @@ -231,21 +231,17 @@ section RegularExpression open RegularExpression - --- Brooke can work on this (SECOND EASIEST) +-- Ask Chou whether to add reindex lemma for cslib DFA, +-- rather than using reindex lemma for mathlib DFA. theorem IsRegular.iff_dfa' {l : Language Symbol} : l.IsRegular ↔ ∃ (n : ℕ), ∃ dfa : DA.FinAcc (Fin n) Symbol, language dfa = l := by - rw [IsRegular.iff_dfa] -- do this in front of constructor + rw [IsRegular.iff_dfa] constructor · rintro ⟨State, h_fin, ⟨⟨flts, start⟩, acc⟩, rfl⟩ - -- intro h_reg - -- obtain ⟨State, h_fin, dfa_abs, rfl⟩ := h_reg have : Fintype State := Fintype.ofFinite State - -- let n := Fintype.card State let dfa := DFA.mk flts.tr start acc -- mathlib let dfa2 := DFA.reindex (Fintype.equivFin State) dfa -- mathlib on Fin n let dfa3 := DA.FinAcc.mk {tr := dfa2.step, start := dfa2.start} dfa2.accept -- cslib on Fin n - -- use n, dfa3 exact ⟨Fintype.card State, dfa3, DFA.accepts_reindex dfa (Fintype.equivFin State)⟩ -- exact ⟨n, dfa3, DFA.accepts_reindex dfa (Fintype.equivFin State)⟩ -- exact DFA.accepts_reindex dfa (Fintype.equivFin State) @@ -283,7 +279,6 @@ noncomputable def regex_of_dfa (dfa : DA.FinAcc State Symbol) regex_of_dfa dfa i kFin k * (regex_of_dfa dfa kFin kFin k).star * regex_of_dfa dfa kFin j k --- Brooke can work on this (EASIEST) noncomputable def regex_of_dfa' {n : ℕ} (dfa : DA.FinAcc (Fin n) Symbol) (i j : Fin n) : ℕ → RegularExpression Symbol | 0 => @@ -309,6 +304,15 @@ def Path_supp (flts : FLTS State Symbol) : State → List Symbol → Set State | _, [_] => ∅ | s, a :: x => {flts.tr s a} ∪ Path_supp flts (flts.tr s a) x +-- When cardinality of path_supp = 0, then length xs = 0 or 1. +-- When cardinality of path_supp = 1, then length xs = 2 or above. +-- When cardinality of path_supp = 2, then length xs = 3 or above. +-- When cardinality of path_supp = n > 0, then length xs ≥ n + 1 and assume all values. +-- Brooke can work on this (Second Easiest) +lemma empty_or_char_of_path_supp_empty {flts : FLTS State Symbol} {s : State} {xs : List Symbol} + (h : Path_supp flts s xs = ∅) : xs = [] ∨ (∃ a : Symbol, xs = [a]) := + by sorry + -- /-- An `Acceptor` is a machine that recognises strings (lists of symbols in an alphabet). -/ -- class Acceptor (A : Type u) (Symbol : outParam (Type v)) where -- /-- Predicate that establishes whether a string `xs` is accepted. -/ @@ -336,12 +340,24 @@ theorem language_path_eq_regex_of_dfa {n k : ℕ} {i j : Fin n} {dfa : DA.FinAcc | zero => simp only [not_lt_zero, imp_false, regex_of_dfa'] split_ifs with heq - · rw [heq, matches'_add] + · -- The case of i = j, k = 0 + rw [heq, matches'_add] + sorry + · -- The case of i ≠ j, k = 0 sorry - · sorry | succ => sorry +-- Brooke can work on this (Easiest) +lemma aux {n : ℕ} {s : Fin n} {dfa : DA.FinAcc (Fin n) Symbol} (h : dfa.accept = {s}) : + language dfa = language (Path_of_FLTS.mk dfa.toFLTS dfa.start s n) := by sorry + +/- IsRegular.iff_regex in the situation where the there is a single accepting state -/ +theorem acc_singleton {n : ℕ} {s : Fin n} {dfa : DA.FinAcc (Fin n) Symbol} (h : dfa.accept = {s}) : + language dfa = matches' (regex_of_dfa' dfa dfa.start s n) := by + rw [aux h] + exact language_path_eq_regex_of_dfa + /- From Yi-Siong's PR: https://github.com/leanprover-community/mathlib4/pull/35600 -/ -- theorem matches'_sum_map0 {α : Type*} (L : List α) (f : α → RegularExpression Symbol) : -- (L.map f).sum.matches' = ⋃ x ∈ L, (f x).matches' := by @@ -384,7 +400,6 @@ theorem language_union {dfa : DA.FinAcc State Symbol} : rw [hmem] exact hs --- Brooke can work on this (Work on this last) omit [Fintype Symbol] in theorem language_sum {n : ℕ} {dfa : DA.FinAcc (Fin n) Symbol} : language dfa = (((dfa.accept.toFinset).sort (· ≤ ·)).map @@ -398,15 +413,9 @@ theorem language_sum {n : ℕ} {dfa : DA.FinAcc (Fin n) Symbol} : | cons a l ih => simp only [List.map_cons, List.sum_cons, Language.mem_add, List.mem_cons, ih] grind - -- rw [memsum] simp only [memsum, Finset.mem_sort, Set.mem_toFinset, mem_language] grind [Accepts] -/- IsRegular.iff_regex in the situation where the there is a single accepting state -/ -theorem acc_singleton {n : ℕ} {s : Fin n} {dfa : DA.FinAcc (Fin n) Symbol} (h : dfa.accept = {s}) : - language dfa = matches' (regex_of_dfa' dfa dfa.start s n) := by sorry - - theorem IsRegular.iff_regex [DecidableEq State] {l : Language Symbol} : l.IsRegular ↔ ∃ r : RegularExpression Symbol, l = matches' r := by refine ⟨fun h => ?_, fun ⟨r, hr⟩ => hr ▸ IsRegular.regex⟩ From 00000000c07c7168cee5fccc7a67c799e92b0f9d Mon Sep 17 00:00:00 2001 From: Brooke Gill <96643991+brooke-gill@users.noreply.github.com> Date: Thu, 30 Jul 2026 19:50:47 -0700 Subject: [PATCH 12/89] Finished aux --- Cslib/Computability/Languages/RegularLanguage.lean | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Cslib/Computability/Languages/RegularLanguage.lean b/Cslib/Computability/Languages/RegularLanguage.lean index 89142499a7..02b67bf0d3 100644 --- a/Cslib/Computability/Languages/RegularLanguage.lean +++ b/Cslib/Computability/Languages/RegularLanguage.lean @@ -349,8 +349,12 @@ theorem language_path_eq_regex_of_dfa {n k : ℕ} {i j : Fin n} {dfa : DA.FinAcc sorry -- Brooke can work on this (Easiest) +omit [Fintype Symbol] in lemma aux {n : ℕ} {s : Fin n} {dfa : DA.FinAcc (Fin n) Symbol} (h : dfa.accept = {s}) : - language dfa = language (Path_of_FLTS.mk dfa.toFLTS dfa.start s n) := by sorry + language dfa = language (Path_of_FLTS.mk dfa.toFLTS dfa.start s n) := by + ext xs + simp only [mem_language, Accepts, Fin.is_lt, implies_true, and_true] + grind /- IsRegular.iff_regex in the situation where the there is a single accepting state -/ theorem acc_singleton {n : ℕ} {s : Fin n} {dfa : DA.FinAcc (Fin n) Symbol} (h : dfa.accept = {s}) : From 1aa573235da80bf1e78689d1c7ab29ab7de262da Mon Sep 17 00:00:00 2001 From: Chi-Yun Hsu Date: Sun, 2 Aug 2026 15:53:42 -0700 Subject: [PATCH 13/89] Change the assumption of regex_of_dfa to depend only on da --- .../Languages/RegularLanguage.lean | 27 +++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/Cslib/Computability/Languages/RegularLanguage.lean b/Cslib/Computability/Languages/RegularLanguage.lean index 02b67bf0d3..1fd4f44e3d 100644 --- a/Cslib/Computability/Languages/RegularLanguage.lean +++ b/Cslib/Computability/Languages/RegularLanguage.lean @@ -279,19 +279,19 @@ noncomputable def regex_of_dfa (dfa : DA.FinAcc State Symbol) regex_of_dfa dfa i kFin k * (regex_of_dfa dfa kFin kFin k).star * regex_of_dfa dfa kFin j k -noncomputable def regex_of_dfa' {n : ℕ} (dfa : DA.FinAcc (Fin n) Symbol) +noncomputable def regex_of_dfa' {n : ℕ} (da : DA (Fin n) Symbol) (i j : Fin n) : ℕ → RegularExpression Symbol | 0 => let chars := (Finset.univ.filter - (fun x : Symbol ↦ dfa.tr i x = j)).toList.map RegularExpression.char + (fun x : Symbol ↦ da.tr i x = j)).toList.map RegularExpression.char if i = j then 1 + chars.sum else chars.sum | k + 1 => - if h : k ≥ n then regex_of_dfa' dfa i j k + if h : k ≥ n then regex_of_dfa' da i j k else let kFin : Fin n := ⟨k, by omega⟩ - regex_of_dfa' dfa i j k + - regex_of_dfa' dfa i kFin k * (regex_of_dfa' dfa kFin kFin k).star * - regex_of_dfa' dfa kFin j k + regex_of_dfa' da i j k + + regex_of_dfa' da i kFin k * (regex_of_dfa' da kFin kFin k).star * + regex_of_dfa' da kFin j k #check εNFA.IsPath -- Mimicing the definition of NFA.Path. Path s xs is the type of @@ -332,8 +332,8 @@ instance {n : ℕ} : Acceptor (Path_of_FLTS n Symbol) Symbol where Accepts (a : Path_of_FLTS n Symbol) (xs : List Symbol) := a.mtr a.start xs = a.finish ∧ (∀ i ∈ Path_supp a.toFLTS a.start xs, i < a.bound) -theorem language_path_eq_regex_of_dfa {n k : ℕ} {i j : Fin n} {dfa : DA.FinAcc (Fin n) Symbol} : - language (Path_of_FLTS.mk dfa.toFLTS i j k) = matches' (regex_of_dfa' dfa i j k) := by +theorem language_path_eq_regex_of_dfa {n k : ℕ} {i j : Fin n} {da : DA (Fin n) Symbol} : + language (Path_of_FLTS.mk da.toFLTS i j k) = matches' (regex_of_dfa' da i j k) := by ext xs simp only [mem_language, Accepts] induction k with @@ -358,7 +358,7 @@ lemma aux {n : ℕ} {s : Fin n} {dfa : DA.FinAcc (Fin n) Symbol} (h : dfa.accept /- IsRegular.iff_regex in the situation where the there is a single accepting state -/ theorem acc_singleton {n : ℕ} {s : Fin n} {dfa : DA.FinAcc (Fin n) Symbol} (h : dfa.accept = {s}) : - language dfa = matches' (regex_of_dfa' dfa dfa.start s n) := by + language dfa = matches' (regex_of_dfa' dfa.toDA dfa.start s n) := by rw [aux h] exact language_path_eq_regex_of_dfa @@ -420,7 +420,7 @@ theorem language_sum {n : ℕ} {dfa : DA.FinAcc (Fin n) Symbol} : simp only [memsum, Finset.mem_sort, Set.mem_toFinset, mem_language] grind [Accepts] -theorem IsRegular.iff_regex [DecidableEq State] {l : Language Symbol} : +theorem IsRegular.iff_regex {l : Language Symbol} : l.IsRegular ↔ ∃ r : RegularExpression Symbol, l = matches' r := by refine ⟨fun h => ?_, fun ⟨r, hr⟩ => hr ▸ IsRegular.regex⟩ obtain ⟨n, dfa, rfl⟩ := Cslib.Language.IsRegular.iff_dfa'.mp h @@ -428,19 +428,18 @@ theorem IsRegular.iff_regex [DecidableEq State] {l : Language Symbol} : -- let : Fintype State := Fintype.ofFinite State -- let eq : State ≃ Fin (Fintype.card State) := Fintype.equivFin State set acc_List : List (Fin n) := (dfa.accept.toFinset).sort (· ≤ ·) with h_acc - rw [language_sum] let regex := - (acc_List.map (fun i => regex_of_dfa' dfa (dfa.start) i n)).sum + (acc_List.map (fun i => regex_of_dfa' dfa.toDA (dfa.start) i n)).sum use regex simp only [matches'_sum, regex] apply congrArg rw [← h_acc, List.map_map] + simp only [map_inj_left, Function.comp_apply] suffices h : (fun s => language {dfa with accept := {s}}) = - (matches' ∘ fun i => regex_of_dfa' {dfa with accept := {i}} dfa.start i n) by sorry + (fun i => matches' (regex_of_dfa' dfa.toDA dfa.start i n)) by exact fun i hi ↦ congrFun h i funext s - simp only [Function.comp_apply] exact acc_singleton rfl end RegularExpression From 3ca35a86cff61d81b482610d549ecae66a10d511 Mon Sep 17 00:00:00 2001 From: Chi-Yun Hsu Date: Mon, 3 Aug 2026 13:24:11 -0700 Subject: [PATCH 14/89] Some progress on main thm; add lemmas on matches --- .../Languages/RegularExpressions.lean | 40 ++++++++++++++ .../Languages/RegularLanguage.lean | 52 +++++++++++++------ 2 files changed, 76 insertions(+), 16 deletions(-) create mode 100644 Cslib/Computability/Languages/RegularExpressions.lean diff --git a/Cslib/Computability/Languages/RegularExpressions.lean b/Cslib/Computability/Languages/RegularExpressions.lean new file mode 100644 index 0000000000..8adb8742e9 --- /dev/null +++ b/Cslib/Computability/Languages/RegularExpressions.lean @@ -0,0 +1,40 @@ +/- +Copyright (c) 2026 Brooke Gill and Chi-Yun Hsu. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Brooke Gill and Chi-Yun Hsu +-/ + +module + +public import Mathlib.Computability.RegularExpressions + +open RegularExpression + +variable {α : Type*} + +theorem mem_zero_matches'_iff (x : List α) : + x ∈ (0 : RegularExpression α).matches' ↔ False := by + classical + rw [← rmatch_iff_matches'] + sorry + +theorem mem_one_matches'_iff (x : List α) : + x ∈ (1 : RegularExpression α).matches' ↔ x = [] := by + classical + rw [← rmatch_iff_matches', one_rmatch_iff] + +theorem mem_char_matches'_iff (a : α) (x : List α) : + x ∈ (char a).matches' ↔ x = [a] := by sorry + +theorem mem_star_matches'_iff (P : RegularExpression α) (x : List α) : + x ∈ (star P).matches' ↔ ∃ S : List (List α), x + = S.flatten ∧ ∀ t ∈ S, t ≠ [] ∧ t ∈ P.matches' := by sorry + +theorem mem_sum_matches'_iff (P Q : RegularExpression α) (x : List α) : + x ∈ (P + Q).matches' ↔ x ∈ P.matches' ∨ x ∈ Q.matches' := by + classical + repeat rw [← rmatch_iff_matches'] + rw [add_rmatch_iff] + +theorem mem_prod_matches'_iff (P Q : RegularExpression α) (x : List α) : + x ∈ (P * Q).matches' ↔ ∃ y z, x = y ++ z ∧ y ∈ P.matches' ∧ z ∈ Q.matches' := by sorry diff --git a/Cslib/Computability/Languages/RegularLanguage.lean b/Cslib/Computability/Languages/RegularLanguage.lean index 1fd4f44e3d..660a7903c5 100644 --- a/Cslib/Computability/Languages/RegularLanguage.lean +++ b/Cslib/Computability/Languages/RegularLanguage.lean @@ -20,6 +20,7 @@ public import Mathlib.Data.Set.Card public import Mathlib.Computability.NFA public import Mathlib.Computability.EpsilonNFA +public import Cslib.Computability.Languages.RegularExpressions /-! # Regular languages @@ -279,19 +280,19 @@ noncomputable def regex_of_dfa (dfa : DA.FinAcc State Symbol) regex_of_dfa dfa i kFin k * (regex_of_dfa dfa kFin kFin k).star * regex_of_dfa dfa kFin j k -noncomputable def regex_of_dfa' {n : ℕ} (da : DA (Fin n) Symbol) +noncomputable def regex_of_da' {n : ℕ} (da : DA (Fin n) Symbol) (i j : Fin n) : ℕ → RegularExpression Symbol | 0 => let chars := (Finset.univ.filter (fun x : Symbol ↦ da.tr i x = j)).toList.map RegularExpression.char if i = j then 1 + chars.sum else chars.sum | k + 1 => - if h : k ≥ n then regex_of_dfa' da i j k + if h : k ≥ n then regex_of_da' da i j k else let kFin : Fin n := ⟨k, by omega⟩ - regex_of_dfa' da i j k + - regex_of_dfa' da i kFin k * (regex_of_dfa' da kFin kFin k).star * - regex_of_dfa' da kFin j k + regex_of_da' da i j k + + regex_of_da' da i kFin k * (regex_of_da' da kFin kFin k).star * + regex_of_da' da kFin j k #check εNFA.IsPath -- Mimicing the definition of NFA.Path. Path s xs is the type of @@ -309,8 +310,8 @@ def Path_supp (flts : FLTS State Symbol) : State → List Symbol → Set State -- When cardinality of path_supp = 2, then length xs = 3 or above. -- When cardinality of path_supp = n > 0, then length xs ≥ n + 1 and assume all values. -- Brooke can work on this (Second Easiest) -lemma empty_or_char_of_path_supp_empty {flts : FLTS State Symbol} {s : State} {xs : List Symbol} - (h : Path_supp flts s xs = ∅) : xs = [] ∨ (∃ a : Symbol, xs = [a]) := +lemma empty_or_char_of_path_supp_empty {flts : FLTS State Symbol} {s : State} {xs : List Symbol} : + Path_supp flts s xs = ∅ ↔ xs = [] ∨ (∃ a : Symbol, xs = [a]) := by sorry -- /-- An `Acceptor` is a machine that recognises strings (lists of symbols in an alphabet). -/ @@ -332,21 +333,40 @@ instance {n : ℕ} : Acceptor (Path_of_FLTS n Symbol) Symbol where Accepts (a : Path_of_FLTS n Symbol) (xs : List Symbol) := a.mtr a.start xs = a.finish ∧ (∀ i ∈ Path_supp a.toFLTS a.start xs, i < a.bound) +lemma set_aux {α : Type*} (A : Set α) : (∀ (i : α), i ∉ A) ↔ A = ∅ := by sorry + theorem language_path_eq_regex_of_dfa {n k : ℕ} {i j : Fin n} {da : DA (Fin n) Symbol} : - language (Path_of_FLTS.mk da.toFLTS i j k) = matches' (regex_of_dfa' da i j k) := by + language (Path_of_FLTS.mk da.toFLTS i j k) = matches' (regex_of_da' da i j k) := by ext xs simp only [mem_language, Accepts] - induction k with + induction k generalizing i j with | zero => - simp only [not_lt_zero, imp_false, regex_of_dfa'] + simp only [not_lt_zero, imp_false, regex_of_da'] split_ifs with heq · -- The case of i = j, k = 0 - rw [heq, matches'_add] + rw [heq, matches'_add, set_aux, empty_or_char_of_path_supp_empty] + + sorry · -- The case of i ≠ j, k = 0 sorry - | succ => - sorry + | succ k h => + constructor + · rintro ⟨h_ends, h_path⟩ + classical + rw [← rmatch_iff_matches'] + + sorry + · intro hxs + simp only [regex_of_da', ge_iff_le] at hxs + by_cases hk : n ≤ k + · simp only [hk, ↓reduceDIte] at hxs + rw [← h] at hxs + obtain ⟨h_ends, h_path⟩ := hxs + exact ⟨h_ends, fun i_1 => (fun hi_1 => lt_trans (h_path i_1 hi_1) (by norm_num))⟩ + · simp only [hk, ↓reduceDIte, matches'] at hxs + + sorry -- Brooke can work on this (Easiest) omit [Fintype Symbol] in @@ -358,7 +378,7 @@ lemma aux {n : ℕ} {s : Fin n} {dfa : DA.FinAcc (Fin n) Symbol} (h : dfa.accept /- IsRegular.iff_regex in the situation where the there is a single accepting state -/ theorem acc_singleton {n : ℕ} {s : Fin n} {dfa : DA.FinAcc (Fin n) Symbol} (h : dfa.accept = {s}) : - language dfa = matches' (regex_of_dfa' dfa.toDA dfa.start s n) := by + language dfa = matches' (regex_of_da' dfa.toDA dfa.start s n) := by rw [aux h] exact language_path_eq_regex_of_dfa @@ -430,7 +450,7 @@ theorem IsRegular.iff_regex {l : Language Symbol} : set acc_List : List (Fin n) := (dfa.accept.toFinset).sort (· ≤ ·) with h_acc rw [language_sum] let regex := - (acc_List.map (fun i => regex_of_dfa' dfa.toDA (dfa.start) i n)).sum + (acc_List.map (fun i => regex_of_da' dfa.toDA (dfa.start) i n)).sum use regex simp only [matches'_sum, regex] apply congrArg @@ -438,7 +458,7 @@ theorem IsRegular.iff_regex {l : Language Symbol} : simp only [map_inj_left, Function.comp_apply] suffices h : (fun s => language {dfa with accept := {s}}) = - (fun i => matches' (regex_of_dfa' dfa.toDA dfa.start i n)) by exact fun i hi ↦ congrFun h i + (fun i => matches' (regex_of_da' dfa.toDA dfa.start i n)) by exact fun i hi ↦ congrFun h i funext s exact acc_singleton rfl From fd72bc38f30bce97204c6cf10b8c92d11cbffcf0 Mon Sep 17 00:00:00 2001 From: Chi-Yun Hsu Date: Mon, 3 Aug 2026 16:27:33 -0700 Subject: [PATCH 15/89] golf on main thm --- .../Languages/RegularExpressions.lean | 6 ++-- .../Languages/RegularLanguage.lean | 32 +++++++------------ 2 files changed, 16 insertions(+), 22 deletions(-) diff --git a/Cslib/Computability/Languages/RegularExpressions.lean b/Cslib/Computability/Languages/RegularExpressions.lean index 8adb8742e9..77a39e08d1 100644 --- a/Cslib/Computability/Languages/RegularExpressions.lean +++ b/Cslib/Computability/Languages/RegularExpressions.lean @@ -8,6 +8,8 @@ module public import Mathlib.Computability.RegularExpressions +namespace Cslib.Language + open RegularExpression variable {α : Type*} @@ -30,11 +32,11 @@ theorem mem_star_matches'_iff (P : RegularExpression α) (x : List α) : x ∈ (star P).matches' ↔ ∃ S : List (List α), x = S.flatten ∧ ∀ t ∈ S, t ≠ [] ∧ t ∈ P.matches' := by sorry -theorem mem_sum_matches'_iff (P Q : RegularExpression α) (x : List α) : +theorem mem_add_matches'_iff (P Q : RegularExpression α) (x : List α) : x ∈ (P + Q).matches' ↔ x ∈ P.matches' ∨ x ∈ Q.matches' := by classical repeat rw [← rmatch_iff_matches'] rw [add_rmatch_iff] -theorem mem_prod_matches'_iff (P Q : RegularExpression α) (x : List α) : +theorem mem_mul_matches'_iff (P Q : RegularExpression α) (x : List α) : x ∈ (P * Q).matches' ↔ ∃ y z, x = y ++ z ∧ y ∈ P.matches' ∧ z ∈ Q.matches' := by sorry diff --git a/Cslib/Computability/Languages/RegularLanguage.lean b/Cslib/Computability/Languages/RegularLanguage.lean index 660a7903c5..ebdb964893 100644 --- a/Cslib/Computability/Languages/RegularLanguage.lean +++ b/Cslib/Computability/Languages/RegularLanguage.lean @@ -273,7 +273,7 @@ noncomputable def regex_of_dfa (dfa : DA.FinAcc State Symbol) (fun x : Symbol ↦ dfa.tr (e.symm i) x = e.symm j)).toList.map RegularExpression.char if i = j then 1 + chars.sum else chars.sum | k + 1 => - if h : k ≥ Fintype.card State then regex_of_dfa dfa i j k + if h : Fintype.card State ≤ k then regex_of_dfa dfa i j k else let kFin : Fin (Fintype.card State) := ⟨k, by omega⟩ regex_of_dfa dfa i j k + @@ -287,7 +287,7 @@ noncomputable def regex_of_da' {n : ℕ} (da : DA (Fin n) Symbol) (fun x : Symbol ↦ da.tr i x = j)).toList.map RegularExpression.char if i = j then 1 + chars.sum else chars.sum | k + 1 => - if h : k ≥ n then regex_of_da' da i j k + if h : n ≤ k then regex_of_da' da i j k else let kFin : Fin n := ⟨k, by omega⟩ regex_of_da' da i j k + @@ -345,28 +345,20 @@ theorem language_path_eq_regex_of_dfa {n k : ℕ} {i j : Fin n} {da : DA (Fin n) split_ifs with heq · -- The case of i = j, k = 0 rw [heq, matches'_add, set_aux, empty_or_char_of_path_supp_empty] - - sorry · -- The case of i ≠ j, k = 0 sorry | succ k h => - constructor - · rintro ⟨h_ends, h_path⟩ - classical - rw [← rmatch_iff_matches'] - - sorry - · intro hxs - simp only [regex_of_da', ge_iff_le] at hxs - by_cases hk : n ≤ k - · simp only [hk, ↓reduceDIte] at hxs - rw [← h] at hxs - obtain ⟨h_ends, h_path⟩ := hxs - exact ⟨h_ends, fun i_1 => (fun hi_1 => lt_trans (h_path i_1 hi_1) (by norm_num))⟩ - · simp only [hk, ↓reduceDIte, matches'] at hxs - - sorry + simp only [regex_of_da'] + split_ifs with hk + · rw [← h] + exact ⟨fun ⟨h_ends, h_path⟩ + => ⟨h_ends, fun i_1 => (fun hi_1 => lt_of_lt_of_le (by norm_num) hk)⟩, + fun ⟨h_ends, h_path⟩ + => ⟨h_ends, fun i_1 => (fun hi_1 => lt_trans (h_path i_1 hi_1) (by norm_num))⟩⟩ + · constructor + · sorry + · sorry -- Brooke can work on this (Easiest) omit [Fintype Symbol] in From 479fd182057122a5d81dcd24043181f6d15aca54 Mon Sep 17 00:00:00 2001 From: Brooke Gill <96643991+brooke-gill@users.noreply.github.com> Date: Mon, 3 Aug 2026 15:57:53 -0700 Subject: [PATCH 16/89] Worked on empty_or_char_of_path_supp_empty --- .../Computability/Languages/RegularLanguage.lean | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/Cslib/Computability/Languages/RegularLanguage.lean b/Cslib/Computability/Languages/RegularLanguage.lean index ebdb964893..5d6b6534e7 100644 --- a/Cslib/Computability/Languages/RegularLanguage.lean +++ b/Cslib/Computability/Languages/RegularLanguage.lean @@ -310,9 +310,20 @@ def Path_supp (flts : FLTS State Symbol) : State → List Symbol → Set State -- When cardinality of path_supp = 2, then length xs = 3 or above. -- When cardinality of path_supp = n > 0, then length xs ≥ n + 1 and assume all values. -- Brooke can work on this (Second Easiest) +omit [Finite State] [Fintype Symbol] in lemma empty_or_char_of_path_supp_empty {flts : FLTS State Symbol} {s : State} {xs : List Symbol} : - Path_supp flts s xs = ∅ ↔ xs = [] ∨ (∃ a : Symbol, xs = [a]) := - by sorry + Path_supp flts s xs = ∅ ↔ xs = [] ∨ (∃ a : Symbol, xs = [a]) := by + constructor + · intro h + rcases xs with _ | ⟨x, _ | ⟨y, rest⟩⟩ + · grind + · grind + · simp + have h1 : flts.tr s x ∈ Path_supp flts s (x :: y :: rest) := by + unfold Path_supp + grind + grind + · sorry -- /-- An `Acceptor` is a machine that recognises strings (lists of symbols in an alphabet). -/ -- class Acceptor (A : Type u) (Symbol : outParam (Type v)) where From b513f77bd639979749c19f671214fab0f39f8b1e Mon Sep 17 00:00:00 2001 From: Chi-Yun Hsu Date: Mon, 3 Aug 2026 17:02:10 -0700 Subject: [PATCH 17/89] Small change --- Cslib/Computability/Languages/RegularExpressions.lean | 11 +++++++++-- Cslib/Computability/Languages/RegularLanguage.lean | 6 ++---- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/Cslib/Computability/Languages/RegularExpressions.lean b/Cslib/Computability/Languages/RegularExpressions.lean index 77a39e08d1..793ef6db88 100644 --- a/Cslib/Computability/Languages/RegularExpressions.lean +++ b/Cslib/Computability/Languages/RegularExpressions.lean @@ -8,6 +8,8 @@ module public import Mathlib.Computability.RegularExpressions +@[expose] public section + namespace Cslib.Language open RegularExpression @@ -29,8 +31,8 @@ theorem mem_char_matches'_iff (a : α) (x : List α) : x ∈ (char a).matches' ↔ x = [a] := by sorry theorem mem_star_matches'_iff (P : RegularExpression α) (x : List α) : - x ∈ (star P).matches' ↔ ∃ S : List (List α), x - = S.flatten ∧ ∀ t ∈ S, t ≠ [] ∧ t ∈ P.matches' := by sorry + x ∈ (star P).matches' ↔ + ∃ S : List (List α), x = S.flatten ∧ ∀ t ∈ S, t ≠ [] ∧ t ∈ P.matches' := by sorry theorem mem_add_matches'_iff (P Q : RegularExpression α) (x : List α) : x ∈ (P + Q).matches' ↔ x ∈ P.matches' ∨ x ∈ Q.matches' := by @@ -40,3 +42,8 @@ theorem mem_add_matches'_iff (P Q : RegularExpression α) (x : List α) : theorem mem_mul_matches'_iff (P Q : RegularExpression α) (x : List α) : x ∈ (P * Q).matches' ↔ ∃ y z, x = y ++ z ∧ y ∈ P.matches' ∧ z ∈ Q.matches' := by sorry + +theorem mem_sum_matches'_iff (L : List (RegularExpression α)) (x : List α) : + x ∈ (L.sum).matches' ↔ ∃ P ∈ L, x ∈ P.matches' := by sorry + +end Cslib.Language diff --git a/Cslib/Computability/Languages/RegularLanguage.lean b/Cslib/Computability/Languages/RegularLanguage.lean index ebdb964893..f234a09495 100644 --- a/Cslib/Computability/Languages/RegularLanguage.lean +++ b/Cslib/Computability/Languages/RegularLanguage.lean @@ -352,10 +352,8 @@ theorem language_path_eq_regex_of_dfa {n k : ℕ} {i j : Fin n} {da : DA (Fin n) simp only [regex_of_da'] split_ifs with hk · rw [← h] - exact ⟨fun ⟨h_ends, h_path⟩ - => ⟨h_ends, fun i_1 => (fun hi_1 => lt_of_lt_of_le (by norm_num) hk)⟩, - fun ⟨h_ends, h_path⟩ - => ⟨h_ends, fun i_1 => (fun hi_1 => lt_trans (h_path i_1 hi_1) (by norm_num))⟩⟩ + exact ⟨fun ⟨h_ends, h_path⟩ => ⟨h_ends, fun _ _ => lt_of_lt_of_le (by norm_num) hk⟩, + fun ⟨h_ends, h_path⟩ => ⟨h_ends, fun l hl => lt_trans (h_path l hl) (by norm_num)⟩⟩ · constructor · sorry · sorry From 3ef773d8ab16683034e870938f2f73f776a7cb21 Mon Sep 17 00:00:00 2001 From: Chi-Yun Hsu Date: Mon, 3 Aug 2026 17:27:16 -0700 Subject: [PATCH 18/89] Comment out unnecessary assumptions --- .../Languages/RegularLanguage.lean | 104 +++++++++--------- 1 file changed, 55 insertions(+), 49 deletions(-) diff --git a/Cslib/Computability/Languages/RegularLanguage.lean b/Cslib/Computability/Languages/RegularLanguage.lean index f0a5d28e20..9c091b8500 100644 --- a/Cslib/Computability/Languages/RegularLanguage.lean +++ b/Cslib/Computability/Languages/RegularLanguage.lean @@ -249,9 +249,9 @@ theorem IsRegular.iff_dfa' {l : Language Symbol} : · intro ⟨n, dfa, h⟩ exact ⟨Fin n, inferInstance, dfa, h⟩ -variable {State : Type*} [Finite State] +variable {State : Type*} --[Finite State] -noncomputable instance : Fintype State := Fintype.ofFinite State +-- noncomputable instance : Fintype State := Fintype.ofFinite State /- @@ -262,25 +262,25 @@ For k + 1, the regex is the union of regex_of_dfa i j k and regex_of_dfa i k k concat (regex_of_dfa k k k)^* concat regex_of_dfa k j k. -/ -variable [Fintype Symbol] - -open scoped Classical in -noncomputable def regex_of_dfa (dfa : DA.FinAcc State Symbol) - (i j : Fin (Fintype.card State)) : ℕ → RegularExpression Symbol - | 0 => - let e := Fintype.equivFin State - let chars := (Finset.univ.filter - (fun x : Symbol ↦ dfa.tr (e.symm i) x = e.symm j)).toList.map RegularExpression.char - if i = j then 1 + chars.sum else chars.sum - | k + 1 => - if h : Fintype.card State ≤ k then regex_of_dfa dfa i j k - else - let kFin : Fin (Fintype.card State) := ⟨k, by omega⟩ - regex_of_dfa dfa i j k + - regex_of_dfa dfa i kFin k * (regex_of_dfa dfa kFin kFin k).star * - regex_of_dfa dfa kFin j k - -noncomputable def regex_of_da' {n : ℕ} (da : DA (Fin n) Symbol) +-- variable [Fintype Symbol] + +-- open scoped Classical in +-- noncomputable def regex_of_dfa (dfa : DA.FinAcc State Symbol) +-- (i j : Fin (Fintype.card State)) : ℕ → RegularExpression Symbol +-- | 0 => +-- let e := Fintype.equivFin State +-- let chars := (Finset.univ.filter +-- (fun x : Symbol ↦ dfa.tr (e.symm i) x = e.symm j)).toList.map RegularExpression.char +-- if i = j then 1 + chars.sum else chars.sum +-- | k + 1 => +-- if h : Fintype.card State ≤ k then regex_of_dfa dfa i j k +-- else +-- let kFin : Fin (Fintype.card State) := ⟨k, by omega⟩ +-- regex_of_dfa dfa i j k + +-- regex_of_dfa dfa i kFin k * (regex_of_dfa dfa kFin kFin k).star * +-- regex_of_dfa dfa kFin j k + +noncomputable def regex_of_da' [Fintype Symbol] {n : ℕ} (da : DA (Fin n) Symbol) (i j : Fin n) : ℕ → RegularExpression Symbol | 0 => let chars := (Finset.univ.filter @@ -310,7 +310,7 @@ def Path_supp (flts : FLTS State Symbol) : State → List Symbol → Set State -- When cardinality of path_supp = 2, then length xs = 3 or above. -- When cardinality of path_supp = n > 0, then length xs ≥ n + 1 and assume all values. -- Brooke can work on this (Second Easiest) -omit [Finite State] [Fintype Symbol] in +-- omit [Finite State] [Fintype Symbol] in lemma empty_or_char_of_path_supp_empty {flts : FLTS State Symbol} {s : State} {xs : List Symbol} : Path_supp flts s xs = ∅ ↔ xs = [] ∨ (∃ a : Symbol, xs = [a]) := by constructor @@ -346,7 +346,8 @@ instance {n : ℕ} : Acceptor (Path_of_FLTS n Symbol) Symbol where lemma set_aux {α : Type*} (A : Set α) : (∀ (i : α), i ∉ A) ↔ A = ∅ := by sorry -theorem language_path_eq_regex_of_dfa {n k : ℕ} {i j : Fin n} {da : DA (Fin n) Symbol} : +theorem language_path_eq_regex_of_dfa [Fintype Symbol] {n k : ℕ} {i j : Fin n} + {da : DA (Fin n) Symbol} : language (Path_of_FLTS.mk da.toFLTS i j k) = matches' (regex_of_da' da i j k) := by ext xs simp only [mem_language, Accepts] @@ -355,10 +356,11 @@ theorem language_path_eq_regex_of_dfa {n k : ℕ} {i j : Fin n} {da : DA (Fin n) simp only [not_lt_zero, imp_false, regex_of_da'] split_ifs with heq · -- The case of i = j, k = 0 - rw [heq, matches'_add, set_aux, empty_or_char_of_path_supp_empty] - sorry + rw [set_aux, mem_add_matches'_iff, mem_sum_matches'_iff, empty_or_char_of_path_supp_empty] + aesop · -- The case of i ≠ j, k = 0 - sorry + rw [set_aux, mem_sum_matches'_iff, empty_or_char_of_path_supp_empty] + aesop | succ k h => simp only [regex_of_da'] split_ifs with hk @@ -370,7 +372,7 @@ theorem language_path_eq_regex_of_dfa {n k : ℕ} {i j : Fin n} {da : DA (Fin n) · sorry -- Brooke can work on this (Easiest) -omit [Fintype Symbol] in +-- omit [Fintype Symbol] in lemma aux {n : ℕ} {s : Fin n} {dfa : DA.FinAcc (Fin n) Symbol} (h : dfa.accept = {s}) : language dfa = language (Path_of_FLTS.mk dfa.toFLTS dfa.start s n) := by ext xs @@ -378,8 +380,8 @@ lemma aux {n : ℕ} {s : Fin n} {dfa : DA.FinAcc (Fin n) Symbol} (h : dfa.accept grind /- IsRegular.iff_regex in the situation where the there is a single accepting state -/ -theorem acc_singleton {n : ℕ} {s : Fin n} {dfa : DA.FinAcc (Fin n) Symbol} (h : dfa.accept = {s}) : - language dfa = matches' (regex_of_da' dfa.toDA dfa.start s n) := by +theorem acc_singleton [Fintype Symbol] {n : ℕ} {s : Fin n} {dfa : DA.FinAcc (Fin n) Symbol} + (h : dfa.accept = {s}) : language dfa = matches' (regex_of_da' dfa.toDA dfa.start s n) := by rw [aux h] exact language_path_eq_regex_of_dfa @@ -408,24 +410,28 @@ the union of the languages defined by the DFA with only one accepting state. -- I need to modify the statement to use addition rather than union. -- Union is true but I need to make it compatible with Finset sum and List sum. -omit [Finite State] [Fintype Symbol] in -theorem language_union {dfa : DA.FinAcc State Symbol} : - language dfa = - ⋃ s ∈ dfa.accept, language {dfa with accept := {s}} := by - ext xs - simp only [mem_language] - constructor - · intro h1 - refine Set.mem_biUnion h1 ?_ - rfl - · intro h1 - obtain ⟨s, hs, hmem⟩ := Set.mem_iUnion₂.mp h1 - change dfa.mtr dfa.start xs ∈ dfa.accept - change dfa.mtr dfa.start xs = s at hmem - rw [hmem] - exact hs - -omit [Fintype Symbol] in +-- omit [Finite State] [Fintype Symbol] in +-- theorem language_union {dfa : DA.FinAcc State Symbol} : +-- language dfa = +-- ⋃ s ∈ dfa.accept, language {dfa with accept := {s}} := by +-- ext xs +-- simp only [mem_language] +-- constructor +-- · intro h1 +-- refine Set.mem_biUnion h1 ?_ +-- rfl +-- · intro h1 +-- obtain ⟨s, hs, hmem⟩ := Set.mem_iUnion₂.mp h1 +-- change dfa.mtr dfa.start xs ∈ dfa.accept +-- change dfa.mtr dfa.start xs = s at hmem +-- rw [hmem] +-- exact hs + + +noncomputable instance {n : ℕ} (dfa : DA.FinAcc (Fin n) Symbol) : + Fintype dfa.accept := Fintype.ofFinite dfa.accept + +-- omit [Fintype Symbol] in theorem language_sum {n : ℕ} {dfa : DA.FinAcc (Fin n) Symbol} : language dfa = (((dfa.accept.toFinset).sort (· ≤ ·)).map (fun s ↦ language {dfa with accept := {s}})).sum := by @@ -441,15 +447,15 @@ theorem language_sum {n : ℕ} {dfa : DA.FinAcc (Fin n) Symbol} : simp only [memsum, Finset.mem_sort, Set.mem_toFinset, mem_language] grind [Accepts] -theorem IsRegular.iff_regex {l : Language Symbol} : +theorem IsRegular.iff_regex [Finite Symbol] {l : Language Symbol} : l.IsRegular ↔ ∃ r : RegularExpression Symbol, l = matches' r := by refine ⟨fun h => ?_, fun ⟨r, hr⟩ => hr ▸ IsRegular.regex⟩ obtain ⟨n, dfa, rfl⟩ := Cslib.Language.IsRegular.iff_dfa'.mp h -- obtain ⟨da, acc⟩ := dfa - -- let : Fintype State := Fintype.ofFinite State -- let eq : State ≃ Fin (Fintype.card State) := Fintype.equivFin State set acc_List : List (Fin n) := (dfa.accept.toFinset).sort (· ≤ ·) with h_acc rw [language_sum] + let : Fintype Symbol := Fintype.ofFinite Symbol let regex := (acc_List.map (fun i => regex_of_da' dfa.toDA (dfa.start) i n)).sum use regex From f7a69bfa9151797d87a424627b1252998a3dd68c Mon Sep 17 00:00:00 2001 From: Brooke Gill <96643991+brooke-gill@users.noreply.github.com> Date: Mon, 3 Aug 2026 18:10:12 -0700 Subject: [PATCH 19/89] Added backwards direction --- Cslib/Computability/Languages/RegularLanguage.lean | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Cslib/Computability/Languages/RegularLanguage.lean b/Cslib/Computability/Languages/RegularLanguage.lean index 9c091b8500..2bb44f3ff4 100644 --- a/Cslib/Computability/Languages/RegularLanguage.lean +++ b/Cslib/Computability/Languages/RegularLanguage.lean @@ -323,7 +323,8 @@ lemma empty_or_char_of_path_supp_empty {flts : FLTS State Symbol} {s : State} {x unfold Path_supp grind grind - · sorry + · unfold Path_supp + grind -- /-- An `Acceptor` is a machine that recognises strings (lists of symbols in an alphabet). -/ -- class Acceptor (A : Type u) (Symbol : outParam (Type v)) where From b4249133d825eacde5b5fdb41ba8e84df2e50d72 Mon Sep 17 00:00:00 2001 From: Chi-Yun Hsu Date: Tue, 4 Aug 2026 10:53:28 -0700 Subject: [PATCH 20/89] Code suggestion and some progress --- .../Languages/RegularLanguage.lean | 57 ++++++++++++------- 1 file changed, 38 insertions(+), 19 deletions(-) diff --git a/Cslib/Computability/Languages/RegularLanguage.lean b/Cslib/Computability/Languages/RegularLanguage.lean index 2bb44f3ff4..d16e361a29 100644 --- a/Cslib/Computability/Languages/RegularLanguage.lean +++ b/Cslib/Computability/Languages/RegularLanguage.lean @@ -301,8 +301,7 @@ noncomputable def regex_of_da' [Fintype Symbol] {n : ℕ} (da : DA (Fin n) Symbo -- | cons (s u : State) (a : Symbol) (x : List Symbol) : Path (flts.tr s a) x → Path s (a :: x) def Path_supp (flts : FLTS State Symbol) : State → List Symbol → Set State - | _, [] => ∅ - | _, [_] => ∅ + | _, [] | _, [_] => ∅ | s, a :: x => {flts.tr s a} ∪ Path_supp flts (flts.tr s a) x -- When cardinality of path_supp = 0, then length xs = 0 or 1. @@ -313,18 +312,23 @@ def Path_supp (flts : FLTS State Symbol) : State → List Symbol → Set State -- omit [Finite State] [Fintype Symbol] in lemma empty_or_char_of_path_supp_empty {flts : FLTS State Symbol} {s : State} {xs : List Symbol} : Path_supp flts s xs = ∅ ↔ xs = [] ∨ (∃ a : Symbol, xs = [a]) := by - constructor - · intro h - rcases xs with _ | ⟨x, _ | ⟨y, rest⟩⟩ - · grind - · grind - · simp - have h1 : flts.tr s x ∈ Path_supp flts s (x :: y :: rest) := by - unfold Path_supp - grind - grind - · unfold Path_supp + match xs with + | [] | [_] => grind [Path_supp] + | x :: y :: ys => + have h1 : flts.tr s x ∈ Path_supp flts s (x :: y :: ys) := by grind [Path_supp] grind + -- constructor + -- · intro h + -- rcases xs with _ | ⟨x, _ | ⟨y, rest⟩⟩ + -- · grind + -- · grind + -- · simp + -- have h1 : flts.tr s x ∈ Path_supp flts s (x :: y :: rest) := by + -- unfold Path_supp + -- grind + -- grind + -- · unfold Path_supp + -- grind -- /-- An `Acceptor` is a machine that recognises strings (lists of symbols in an alphabet). -/ -- class Acceptor (A : Type u) (Symbol : outParam (Type v)) where @@ -368,17 +372,32 @@ theorem language_path_eq_regex_of_dfa [Fintype Symbol] {n k : ℕ} {i j : Fin n} · rw [← h] exact ⟨fun ⟨h_ends, h_path⟩ => ⟨h_ends, fun _ _ => lt_of_lt_of_le (by norm_num) hk⟩, fun ⟨h_ends, h_path⟩ => ⟨h_ends, fun l hl => lt_trans (h_path l hl) (by norm_num)⟩⟩ - · constructor - · sorry - · sorry + · rw [mem_add_matches'_iff, mem_mul_matches'_iff] + constructor + · intro ⟨h_ends, h_path⟩ + by_cases h_bound : ∀ l ∈ Path_supp da.toFLTS i xs, l < k + · -- Easy + sorry + · right + push Not at h_bound + rcases h_bound with ⟨l, ⟨hl1, hl2⟩⟩ + have hl : l = k + 1 := by sorry + sorry + · intro hxs + + sorry -- Brooke can work on this (Easiest) -- omit [Fintype Symbol] in lemma aux {n : ℕ} {s : Fin n} {dfa : DA.FinAcc (Fin n) Symbol} (h : dfa.accept = {s}) : language dfa = language (Path_of_FLTS.mk dfa.toFLTS dfa.start s n) := by - ext xs - simp only [mem_language, Accepts, Fin.is_lt, implies_true, and_true] - grind + ext xs + simp only [mem_language, Accepts] + grind + -- -- Wrong indents + -- ext xs + -- simp only [mem_language, Accepts, Fin.is_lt, implies_true, and_true] + -- grind /- IsRegular.iff_regex in the situation where the there is a single accepting state -/ theorem acc_singleton [Fintype Symbol] {n : ℕ} {s : Fin n} {dfa : DA.FinAcc (Fin n) Symbol} From f2cd0f99dcb06e9300044e825f4a4da79e2cf225 Mon Sep 17 00:00:00 2001 From: Chi-Yun Hsu Date: Tue, 4 Aug 2026 11:02:46 -0700 Subject: [PATCH 21/89] Change regex_of_da' to regex_of_flts --- .../Languages/RegularLanguage.lean | 30 ++++++++++--------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/Cslib/Computability/Languages/RegularLanguage.lean b/Cslib/Computability/Languages/RegularLanguage.lean index d16e361a29..98b9262f2d 100644 --- a/Cslib/Computability/Languages/RegularLanguage.lean +++ b/Cslib/Computability/Languages/RegularLanguage.lean @@ -280,19 +280,19 @@ regex_of_dfa i k k concat (regex_of_dfa k k k)^* concat regex_of_dfa k j k. -- regex_of_dfa dfa i kFin k * (regex_of_dfa dfa kFin kFin k).star * -- regex_of_dfa dfa kFin j k -noncomputable def regex_of_da' [Fintype Symbol] {n : ℕ} (da : DA (Fin n) Symbol) +noncomputable def regex_of_flts [Fintype Symbol] {n : ℕ} (flts : FLTS (Fin n) Symbol) (i j : Fin n) : ℕ → RegularExpression Symbol | 0 => let chars := (Finset.univ.filter - (fun x : Symbol ↦ da.tr i x = j)).toList.map RegularExpression.char + (fun x : Symbol ↦ flts.tr i x = j)).toList.map RegularExpression.char if i = j then 1 + chars.sum else chars.sum | k + 1 => - if h : n ≤ k then regex_of_da' da i j k + if h : n ≤ k then regex_of_flts flts i j k else let kFin : Fin n := ⟨k, by omega⟩ - regex_of_da' da i j k + - regex_of_da' da i kFin k * (regex_of_da' da kFin kFin k).star * - regex_of_da' da kFin j k + regex_of_flts flts i j k + + regex_of_flts flts i kFin k * (regex_of_flts flts kFin kFin k).star * + regex_of_flts flts kFin j k #check εNFA.IsPath -- Mimicing the definition of NFA.Path. Path s xs is the type of @@ -349,16 +349,18 @@ instance {n : ℕ} : Acceptor (Path_of_FLTS n Symbol) Symbol where Accepts (a : Path_of_FLTS n Symbol) (xs : List Symbol) := a.mtr a.start xs = a.finish ∧ (∀ i ∈ Path_supp a.toFLTS a.start xs, i < a.bound) +def path_head {n : ℕ} (da : DA (Fin n) Symbol) (xs : List Symbol) (l : Fin n) : List Symbol := sorry + lemma set_aux {α : Type*} (A : Set α) : (∀ (i : α), i ∉ A) ↔ A = ∅ := by sorry theorem language_path_eq_regex_of_dfa [Fintype Symbol] {n k : ℕ} {i j : Fin n} - {da : DA (Fin n) Symbol} : - language (Path_of_FLTS.mk da.toFLTS i j k) = matches' (regex_of_da' da i j k) := by + {flts : FLTS (Fin n) Symbol} : + language (Path_of_FLTS.mk flts i j k) = matches' (regex_of_flts flts i j k) := by ext xs simp only [mem_language, Accepts] induction k generalizing i j with | zero => - simp only [not_lt_zero, imp_false, regex_of_da'] + simp only [not_lt_zero, imp_false, regex_of_flts] split_ifs with heq · -- The case of i = j, k = 0 rw [set_aux, mem_add_matches'_iff, mem_sum_matches'_iff, empty_or_char_of_path_supp_empty] @@ -367,7 +369,7 @@ theorem language_path_eq_regex_of_dfa [Fintype Symbol] {n k : ℕ} {i j : Fin n} rw [set_aux, mem_sum_matches'_iff, empty_or_char_of_path_supp_empty] aesop | succ k h => - simp only [regex_of_da'] + simp only [regex_of_flts] split_ifs with hk · rw [← h] exact ⟨fun ⟨h_ends, h_path⟩ => ⟨h_ends, fun _ _ => lt_of_lt_of_le (by norm_num) hk⟩, @@ -375,7 +377,7 @@ theorem language_path_eq_regex_of_dfa [Fintype Symbol] {n k : ℕ} {i j : Fin n} · rw [mem_add_matches'_iff, mem_mul_matches'_iff] constructor · intro ⟨h_ends, h_path⟩ - by_cases h_bound : ∀ l ∈ Path_supp da.toFLTS i xs, l < k + by_cases h_bound : ∀ l ∈ Path_supp flts i xs, l < k · -- Easy sorry · right @@ -401,7 +403,7 @@ lemma aux {n : ℕ} {s : Fin n} {dfa : DA.FinAcc (Fin n) Symbol} (h : dfa.accept /- IsRegular.iff_regex in the situation where the there is a single accepting state -/ theorem acc_singleton [Fintype Symbol] {n : ℕ} {s : Fin n} {dfa : DA.FinAcc (Fin n) Symbol} - (h : dfa.accept = {s}) : language dfa = matches' (regex_of_da' dfa.toDA dfa.start s n) := by + (h : dfa.accept = {s}) : language dfa = matches' (regex_of_flts dfa.toFLTS dfa.start s n) := by rw [aux h] exact language_path_eq_regex_of_dfa @@ -477,7 +479,7 @@ theorem IsRegular.iff_regex [Finite Symbol] {l : Language Symbol} : rw [language_sum] let : Fintype Symbol := Fintype.ofFinite Symbol let regex := - (acc_List.map (fun i => regex_of_da' dfa.toDA (dfa.start) i n)).sum + (acc_List.map (fun i => regex_of_flts dfa.toFLTS (dfa.start) i n)).sum use regex simp only [matches'_sum, regex] apply congrArg @@ -485,7 +487,7 @@ theorem IsRegular.iff_regex [Finite Symbol] {l : Language Symbol} : simp only [map_inj_left, Function.comp_apply] suffices h : (fun s => language {dfa with accept := {s}}) = - (fun i => matches' (regex_of_da' dfa.toDA dfa.start i n)) by exact fun i hi ↦ congrFun h i + (fun i => matches' (regex_of_flts dfa.toFLTS dfa.start i n)) by exact fun i hi ↦ congrFun h i funext s exact acc_singleton rfl From 172b6d420771ad911b780141431809dafc4fe4c4 Mon Sep 17 00:00:00 2001 From: Chi-Yun Hsu Date: Tue, 4 Aug 2026 14:58:18 -0700 Subject: [PATCH 22/89] Add new lemmas --- .../Languages/RegularLanguage.lean | 34 +++++++++++++++---- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/Cslib/Computability/Languages/RegularLanguage.lean b/Cslib/Computability/Languages/RegularLanguage.lean index 98b9262f2d..42b6478d39 100644 --- a/Cslib/Computability/Languages/RegularLanguage.lean +++ b/Cslib/Computability/Languages/RegularLanguage.lean @@ -279,7 +279,6 @@ regex_of_dfa i k k concat (regex_of_dfa k k k)^* concat regex_of_dfa k j k. -- regex_of_dfa dfa i j k + -- regex_of_dfa dfa i kFin k * (regex_of_dfa dfa kFin kFin k).star * -- regex_of_dfa dfa kFin j k - noncomputable def regex_of_flts [Fintype Symbol] {n : ℕ} (flts : FLTS (Fin n) Symbol) (i j : Fin n) : ℕ → RegularExpression Symbol | 0 => @@ -294,6 +293,17 @@ noncomputable def regex_of_flts [Fintype Symbol] {n : ℕ} (flts : FLTS (Fin n) regex_of_flts flts i kFin k * (regex_of_flts flts kFin kFin k).star * regex_of_flts flts kFin j k +lemma regex1 [Fintype Symbol] {n : ℕ} (flts : FLTS (Fin n) Symbol) (k : Fin n) : + (regex_of_flts flts k k (k + 1)).matches' = ((regex_of_flts flts k k k).matches')∗ := by sorry + +lemma regex2 [Fintype Symbol] {n : ℕ} (flts : FLTS (Fin n) Symbol) (i k : Fin n) : + (regex_of_flts flts i k (k + 1)).matches' = + ((regex_of_flts flts i k k) * (regex_of_flts flts k k k + 1)).matches' := by sorry + +lemma regex3 [Fintype Symbol] {n : ℕ} (flts : FLTS (Fin n) Symbol) (j k : Fin n) : + (regex_of_flts flts k j (k + 1)).matches' = + ((regex_of_flts flts k k (k + 1)) * (regex_of_flts flts k j k)).matches' := by sorry + #check εNFA.IsPath -- Mimicing the definition of NFA.Path. Path s xs is the type of -- inductive Path : State → List Symbol → Type (max u_1 u_2) @@ -349,9 +359,19 @@ instance {n : ℕ} : Acceptor (Path_of_FLTS n Symbol) Symbol where Accepts (a : Path_of_FLTS n Symbol) (xs : List Symbol) := a.mtr a.start xs = a.finish ∧ (∀ i ∈ Path_supp a.toFLTS a.start xs, i < a.bound) -def path_head {n : ℕ} (da : DA (Fin n) Symbol) (xs : List Symbol) (l : Fin n) : List Symbol := sorry +-- The function sending a string to its head which first ends at state `t` +def path_head {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) : List Symbol → List Symbol + | [] => [] + | a :: x => if flts.tr s a = t then [a] else a :: path_head flts (flts.tr s a) t x -lemma set_aux {α : Type*} (A : Set α) : (∀ (i : α), i ∉ A) ↔ A = ∅ := by sorry +lemma isPrefix_path_head {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) (xs : List Symbol) : + IsPrefix (path_head flts s t xs) xs := by sorry + +def path_tail {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) (xs : List Symbol) : + List Symbol := by sorry + +lemma set_aux {α : Type*} (A : Set α) : (∀ (i : α), i ∉ A) ↔ A = ∅ := by + sorry theorem language_path_eq_regex_of_dfa [Fintype Symbol] {n k : ℕ} {i j : Fin n} {flts : FLTS (Fin n) Symbol} : @@ -374,7 +394,7 @@ theorem language_path_eq_regex_of_dfa [Fintype Symbol] {n k : ℕ} {i j : Fin n} · rw [← h] exact ⟨fun ⟨h_ends, h_path⟩ => ⟨h_ends, fun _ _ => lt_of_lt_of_le (by norm_num) hk⟩, fun ⟨h_ends, h_path⟩ => ⟨h_ends, fun l hl => lt_trans (h_path l hl) (by norm_num)⟩⟩ - · rw [mem_add_matches'_iff, mem_mul_matches'_iff] + · rw [mem_add_matches'_iff] constructor · intro ⟨h_ends, h_path⟩ by_cases h_bound : ∀ l ∈ Path_supp flts i xs, l < k @@ -385,9 +405,9 @@ theorem language_path_eq_regex_of_dfa [Fintype Symbol] {n k : ℕ} {i j : Fin n} rcases h_bound with ⟨l, ⟨hl1, hl2⟩⟩ have hl : l = k + 1 := by sorry sorry - · intro hxs - - sorry + · rintro (h1 | h2) + · grind [h.mpr h1] + · sorry -- Brooke can work on this (Easiest) -- omit [Fintype Symbol] in From 36527ad29cf912134c23718783762e7f1338a3d0 Mon Sep 17 00:00:00 2001 From: Chi-Yun Hsu Date: Tue, 4 Aug 2026 16:22:37 -0700 Subject: [PATCH 23/89] Deleted unnecessary info --- .../Languages/RegularExpressions.lean | 2 + .../Languages/RegularLanguage.lean | 152 +++--------------- 2 files changed, 28 insertions(+), 126 deletions(-) diff --git a/Cslib/Computability/Languages/RegularExpressions.lean b/Cslib/Computability/Languages/RegularExpressions.lean index 793ef6db88..ab072c686d 100644 --- a/Cslib/Computability/Languages/RegularExpressions.lean +++ b/Cslib/Computability/Languages/RegularExpressions.lean @@ -16,6 +16,7 @@ open RegularExpression variable {α : Type*} +-- Brooke can do all the lemmas here (second) theorem mem_zero_matches'_iff (x : List α) : x ∈ (0 : RegularExpression α).matches' ↔ False := by classical @@ -43,6 +44,7 @@ theorem mem_add_matches'_iff (P Q : RegularExpression α) (x : List α) : theorem mem_mul_matches'_iff (P Q : RegularExpression α) (x : List α) : x ∈ (P * Q).matches' ↔ ∃ y z, x = y ++ z ∧ y ∈ P.matches' ∧ z ∈ Q.matches' := by sorry +-- Brooke can work on this lemma (third) theorem mem_sum_matches'_iff (L : List (RegularExpression α)) (x : List α) : x ∈ (L.sum).matches' ↔ ∃ P ∈ L, x ∈ P.matches' := by sorry diff --git a/Cslib/Computability/Languages/RegularLanguage.lean b/Cslib/Computability/Languages/RegularLanguage.lean index 42b6478d39..b2924ca08b 100644 --- a/Cslib/Computability/Languages/RegularLanguage.lean +++ b/Cslib/Computability/Languages/RegularLanguage.lean @@ -223,11 +223,6 @@ theorem IsRegular.regex {r : RegularExpression Symbol} : | star P hP => grind [RegularExpression.matches', IsRegular.kstar] /- We use Kleene's Algorithm for DFA to prove a regular language can be expressed as a regex. -/ -lemma mem_add_language_iff {xs : List Symbol} {l₁ l₂ : Language Symbol} : - xs ∈ l₁ + l₂ ↔ xs ∈ l₁ ∨ xs ∈ l₂ := by - rw [Language.add_def] - exact mem_union xs l₁ l₂ - section RegularExpression open RegularExpression @@ -249,60 +244,35 @@ theorem IsRegular.iff_dfa' {l : Language Symbol} : · intro ⟨n, dfa, h⟩ exact ⟨Fin n, inferInstance, dfa, h⟩ -variable {State : Type*} --[Finite State] - --- noncomputable instance : Fintype State := Fintype.ofFinite State - - /- -regex_of_dfa i j k is the regex for the path from state i to state j passing through states < k. +regex i j k is the regex for the path from state i to state j passing through states < k. When k = 0, i = j, the regex is ε union all characters from state i to state i. When k = 0, i ≠ j, the regex is all characters from state i to state j. -For k + 1, the regex is the union of regex_of_dfa i j k and -regex_of_dfa i k k concat (regex_of_dfa k k k)^* concat regex_of_dfa k j k. +For k + 1, the regex is the union of regex i j k and +regex i k k concat (regex k k k)^* concat regex k j k. -/ - --- variable [Fintype Symbol] - --- open scoped Classical in --- noncomputable def regex_of_dfa (dfa : DA.FinAcc State Symbol) --- (i j : Fin (Fintype.card State)) : ℕ → RegularExpression Symbol --- | 0 => --- let e := Fintype.equivFin State --- let chars := (Finset.univ.filter --- (fun x : Symbol ↦ dfa.tr (e.symm i) x = e.symm j)).toList.map RegularExpression.char --- if i = j then 1 + chars.sum else chars.sum --- | k + 1 => --- if h : Fintype.card State ≤ k then regex_of_dfa dfa i j k --- else --- let kFin : Fin (Fintype.card State) := ⟨k, by omega⟩ --- regex_of_dfa dfa i j k + --- regex_of_dfa dfa i kFin k * (regex_of_dfa dfa kFin kFin k).star * --- regex_of_dfa dfa kFin j k -noncomputable def regex_of_flts [Fintype Symbol] {n : ℕ} (flts : FLTS (Fin n) Symbol) +noncomputable def Regex [Fintype Symbol] {n : ℕ} (flts : FLTS (Fin n) Symbol) (i j : Fin n) : ℕ → RegularExpression Symbol | 0 => let chars := (Finset.univ.filter (fun x : Symbol ↦ flts.tr i x = j)).toList.map RegularExpression.char if i = j then 1 + chars.sum else chars.sum | k + 1 => - if h : n ≤ k then regex_of_flts flts i j k + if h : n ≤ k then Regex flts i j k else let kFin : Fin n := ⟨k, by omega⟩ - regex_of_flts flts i j k + - regex_of_flts flts i kFin k * (regex_of_flts flts kFin kFin k).star * - regex_of_flts flts kFin j k + Regex flts i j k + Regex flts i kFin k * (Regex flts kFin kFin k).star * Regex flts kFin j k lemma regex1 [Fintype Symbol] {n : ℕ} (flts : FLTS (Fin n) Symbol) (k : Fin n) : - (regex_of_flts flts k k (k + 1)).matches' = ((regex_of_flts flts k k k).matches')∗ := by sorry + (Regex flts k k k + 1).matches' = ((Regex flts k k k).matches')∗ := by sorry lemma regex2 [Fintype Symbol] {n : ℕ} (flts : FLTS (Fin n) Symbol) (i k : Fin n) : - (regex_of_flts flts i k (k + 1)).matches' = - ((regex_of_flts flts i k k) * (regex_of_flts flts k k k + 1)).matches' := by sorry + (Regex flts i k k + 1).matches' = + ((Regex flts i k k) * (Regex flts k k k + 1)).matches' := by sorry lemma regex3 [Fintype Symbol] {n : ℕ} (flts : FLTS (Fin n) Symbol) (j k : Fin n) : - (regex_of_flts flts k j (k + 1)).matches' = - ((regex_of_flts flts k k (k + 1)) * (regex_of_flts flts k j k)).matches' := by sorry + (Regex flts k j k + 1).matches' = + ((Regex flts k k k + 1) * (Regex flts k j k)).matches' := by sorry #check εNFA.IsPath -- Mimicing the definition of NFA.Path. Path s xs is the type of @@ -314,41 +284,13 @@ def Path_supp (flts : FLTS State Symbol) : State → List Symbol → Set State | _, [] | _, [_] => ∅ | s, a :: x => {flts.tr s a} ∪ Path_supp flts (flts.tr s a) x --- When cardinality of path_supp = 0, then length xs = 0 or 1. --- When cardinality of path_supp = 1, then length xs = 2 or above. --- When cardinality of path_supp = 2, then length xs = 3 or above. --- When cardinality of path_supp = n > 0, then length xs ≥ n + 1 and assume all values. --- Brooke can work on this (Second Easiest) --- omit [Finite State] [Fintype Symbol] in -lemma empty_or_char_of_path_supp_empty {flts : FLTS State Symbol} {s : State} {xs : List Symbol} : - Path_supp flts s xs = ∅ ↔ xs = [] ∨ (∃ a : Symbol, xs = [a]) := by +lemma empty_or_char_of_path_supp_empty {State : Type*} {flts : FLTS State Symbol} {s : State} + {xs : List Symbol} : Path_supp flts s xs = ∅ ↔ xs = [] ∨ (∃ a : Symbol, xs = [a]) := by match xs with | [] | [_] => grind [Path_supp] | x :: y :: ys => have h1 : flts.tr s x ∈ Path_supp flts s (x :: y :: ys) := by grind [Path_supp] grind - -- constructor - -- · intro h - -- rcases xs with _ | ⟨x, _ | ⟨y, rest⟩⟩ - -- · grind - -- · grind - -- · simp - -- have h1 : flts.tr s x ∈ Path_supp flts s (x :: y :: rest) := by - -- unfold Path_supp - -- grind - -- grind - -- · unfold Path_supp - -- grind - --- /-- An `Acceptor` is a machine that recognises strings (lists of symbols in an alphabet). -/ --- class Acceptor (A : Type u) (Symbol : outParam (Type v)) where --- /-- Predicate that establishes whether a string `xs` is accepted. -/ --- Accepts (a : A) (xs : List Symbol) : Prop - --- /-- The language of an `Acceptor` is the set of strings it `Accepts`. -/ --- @[scoped grind .] --- def language [Acceptor A Symbol] (a : A) : Language Symbol := --- { xs | Accepts a xs } structure Path_of_FLTS (n : ℕ) (Symbol : Type*) extends FLTS (Fin n) Symbol where start : Fin n @@ -370,17 +312,18 @@ lemma isPrefix_path_head {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) (x def path_tail {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) (xs : List Symbol) : List Symbol := by sorry +-- Brooke can do this (first) lemma set_aux {α : Type*} (A : Set α) : (∀ (i : α), i ∉ A) ↔ A = ∅ := by sorry -theorem language_path_eq_regex_of_dfa [Fintype Symbol] {n k : ℕ} {i j : Fin n} +theorem language_path_eq_regex [Fintype Symbol] {n k : ℕ} {i j : Fin n} {flts : FLTS (Fin n) Symbol} : - language (Path_of_FLTS.mk flts i j k) = matches' (regex_of_flts flts i j k) := by + language (Path_of_FLTS.mk flts i j k) = matches' (Regex flts i j k) := by ext xs simp only [mem_language, Accepts] induction k generalizing i j with | zero => - simp only [not_lt_zero, imp_false, regex_of_flts] + simp only [not_lt_zero, imp_false, Regex] split_ifs with heq · -- The case of i = j, k = 0 rw [set_aux, mem_add_matches'_iff, mem_sum_matches'_iff, empty_or_char_of_path_supp_empty] @@ -389,7 +332,7 @@ theorem language_path_eq_regex_of_dfa [Fintype Symbol] {n k : ℕ} {i j : Fin n} rw [set_aux, mem_sum_matches'_iff, empty_or_char_of_path_supp_empty] aesop | succ k h => - simp only [regex_of_flts] + simp only [Regex] split_ifs with hk · rw [← h] exact ⟨fun ⟨h_ends, h_path⟩ => ⟨h_ends, fun _ _ => lt_of_lt_of_le (by norm_num) hk⟩, @@ -397,8 +340,10 @@ theorem language_path_eq_regex_of_dfa [Fintype Symbol] {n k : ℕ} {i j : Fin n} · rw [mem_add_matches'_iff] constructor · intro ⟨h_ends, h_path⟩ - by_cases h_bound : ∀ l ∈ Path_supp flts i xs, l < k - · -- Easy + by_cases h_bound : ∀ l ∈ Path_supp flts i xs, l < k + · -- Brooke can work on this (Last) + -- Given xs in regex i j k + 1, if xs does not go through k, then xs is in regex i j k. + left sorry · right push Not at h_bound @@ -409,33 +354,17 @@ theorem language_path_eq_regex_of_dfa [Fintype Symbol] {n k : ℕ} {i j : Fin n} · grind [h.mpr h1] · sorry --- Brooke can work on this (Easiest) --- omit [Fintype Symbol] in lemma aux {n : ℕ} {s : Fin n} {dfa : DA.FinAcc (Fin n) Symbol} (h : dfa.accept = {s}) : language dfa = language (Path_of_FLTS.mk dfa.toFLTS dfa.start s n) := by ext xs simp only [mem_language, Accepts] grind - -- -- Wrong indents - -- ext xs - -- simp only [mem_language, Accepts, Fin.is_lt, implies_true, and_true] - -- grind /- IsRegular.iff_regex in the situation where the there is a single accepting state -/ theorem acc_singleton [Fintype Symbol] {n : ℕ} {s : Fin n} {dfa : DA.FinAcc (Fin n) Symbol} - (h : dfa.accept = {s}) : language dfa = matches' (regex_of_flts dfa.toFLTS dfa.start s n) := by + (h : dfa.accept = {s}) : language dfa = matches' (Regex dfa.toFLTS dfa.start s n) := by rw [aux h] - exact language_path_eq_regex_of_dfa - -/- From Yi-Siong's PR: https://github.com/leanprover-community/mathlib4/pull/35600 -/ --- theorem matches'_sum_map0 {α : Type*} (L : List α) (f : α → RegularExpression Symbol) : --- (L.map f).sum.matches' = ⋃ x ∈ L, (f x).matches' := by --- induction L with --- | nil => simp [Language.zero_def] --- | cons b L' ih => --- simp only [List.map_cons, List.sum_cons, matches', add_eq_sup, List.mem_cons, --- iUnion_iUnion_eq_or_left, ih] --- rfl + exact language_path_eq_regex /- Modified from Yi-Siong's PR: https://github.com/leanprover-community/mathlib4/pull/35600 -/ theorem matches'_sum (L : List (RegularExpression Symbol)) : @@ -444,36 +373,9 @@ theorem matches'_sum (L : List (RegularExpression Symbol)) : | nil => simp | cons b L' ih => simp [ih] -/- -Should later be put in Computability/Automata/DA -The language defined by a DFA is equal to -the union of the languages defined by the DFA with only one accepting state. --/ --- I need to modify the statement to use addition rather than union. --- Union is true but I need to make it compatible with Finset sum and List sum. - --- omit [Finite State] [Fintype Symbol] in --- theorem language_union {dfa : DA.FinAcc State Symbol} : --- language dfa = --- ⋃ s ∈ dfa.accept, language {dfa with accept := {s}} := by --- ext xs --- simp only [mem_language] --- constructor --- · intro h1 --- refine Set.mem_biUnion h1 ?_ --- rfl --- · intro h1 --- obtain ⟨s, hs, hmem⟩ := Set.mem_iUnion₂.mp h1 --- change dfa.mtr dfa.start xs ∈ dfa.accept --- change dfa.mtr dfa.start xs = s at hmem --- rw [hmem] --- exact hs - - noncomputable instance {n : ℕ} (dfa : DA.FinAcc (Fin n) Symbol) : Fintype dfa.accept := Fintype.ofFinite dfa.accept --- omit [Fintype Symbol] in theorem language_sum {n : ℕ} {dfa : DA.FinAcc (Fin n) Symbol} : language dfa = (((dfa.accept.toFinset).sort (· ≤ ·)).map (fun s ↦ language {dfa with accept := {s}})).sum := by @@ -493,13 +395,11 @@ theorem IsRegular.iff_regex [Finite Symbol] {l : Language Symbol} : l.IsRegular ↔ ∃ r : RegularExpression Symbol, l = matches' r := by refine ⟨fun h => ?_, fun ⟨r, hr⟩ => hr ▸ IsRegular.regex⟩ obtain ⟨n, dfa, rfl⟩ := Cslib.Language.IsRegular.iff_dfa'.mp h - -- obtain ⟨da, acc⟩ := dfa - -- let eq : State ≃ Fin (Fintype.card State) := Fintype.equivFin State set acc_List : List (Fin n) := (dfa.accept.toFinset).sort (· ≤ ·) with h_acc rw [language_sum] let : Fintype Symbol := Fintype.ofFinite Symbol let regex := - (acc_List.map (fun i => regex_of_flts dfa.toFLTS (dfa.start) i n)).sum + (acc_List.map (fun i => Regex dfa.toFLTS (dfa.start) i n)).sum use regex simp only [matches'_sum, regex] apply congrArg @@ -507,7 +407,7 @@ theorem IsRegular.iff_regex [Finite Symbol] {l : Language Symbol} : simp only [map_inj_left, Function.comp_apply] suffices h : (fun s => language {dfa with accept := {s}}) = - (fun i => matches' (regex_of_flts dfa.toFLTS dfa.start i n)) by exact fun i hi ↦ congrFun h i + (fun i => matches' (Regex dfa.toFLTS dfa.start i n)) by exact fun i hi ↦ congrFun h i funext s exact acc_singleton rfl From 62d550760037fbfed18a7bf219b7190592b634b9 Mon Sep 17 00:00:00 2001 From: Brooke Gill <96643991+brooke-gill@users.noreply.github.com> Date: Wed, 5 Aug 2026 09:58:06 -0700 Subject: [PATCH 24/89] Finished set_aux --- Cslib/Computability/Languages/RegularLanguage.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cslib/Computability/Languages/RegularLanguage.lean b/Cslib/Computability/Languages/RegularLanguage.lean index b2924ca08b..5e39777369 100644 --- a/Cslib/Computability/Languages/RegularLanguage.lean +++ b/Cslib/Computability/Languages/RegularLanguage.lean @@ -314,7 +314,7 @@ def path_tail {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) (xs : List Sy -- Brooke can do this (first) lemma set_aux {α : Type*} (A : Set α) : (∀ (i : α), i ∉ A) ↔ A = ∅ := by - sorry + grind theorem language_path_eq_regex [Fintype Symbol] {n k : ℕ} {i j : Fin n} {flts : FLTS (Fin n) Symbol} : From 719d5d74ed682c09e7877adde8a396e2568e0466 Mon Sep 17 00:00:00 2001 From: Chi-Yun Hsu Date: Fri, 7 Aug 2026 10:41:09 -0700 Subject: [PATCH 25/89] Major revision --- .../Languages/RegularExpressions.lean | 1 + .../Languages/RegularLanguage.lean | 187 +++++++++++++----- 2 files changed, 134 insertions(+), 54 deletions(-) diff --git a/Cslib/Computability/Languages/RegularExpressions.lean b/Cslib/Computability/Languages/RegularExpressions.lean index ab072c686d..f260a79231 100644 --- a/Cslib/Computability/Languages/RegularExpressions.lean +++ b/Cslib/Computability/Languages/RegularExpressions.lean @@ -17,6 +17,7 @@ open RegularExpression variable {α : Type*} -- Brooke can do all the lemmas here (second) +-- Pause on doing this as we might not need these lemmas anymore. theorem mem_zero_matches'_iff (x : List α) : x ∈ (0 : RegularExpression α).matches' ↔ False := by classical diff --git a/Cslib/Computability/Languages/RegularLanguage.lean b/Cslib/Computability/Languages/RegularLanguage.lean index 5e39777369..fdc10bc3f4 100644 --- a/Cslib/Computability/Languages/RegularLanguage.lean +++ b/Cslib/Computability/Languages/RegularLanguage.lean @@ -263,54 +263,148 @@ noncomputable def Regex [Fintype Symbol] {n : ℕ} (flts : FLTS (Fin n) Symbol) let kFin : Fin n := ⟨k, by omega⟩ Regex flts i j k + Regex flts i kFin k * (Regex flts kFin kFin k).star * Regex flts kFin j k -lemma regex1 [Fintype Symbol] {n : ℕ} (flts : FLTS (Fin n) Symbol) (k : Fin n) : - (Regex flts k k k + 1).matches' = ((Regex flts k k k).matches')∗ := by sorry - -lemma regex2 [Fintype Symbol] {n : ℕ} (flts : FLTS (Fin n) Symbol) (i k : Fin n) : - (Regex flts i k k + 1).matches' = - ((Regex flts i k k) * (Regex flts k k k + 1)).matches' := by sorry - -lemma regex3 [Fintype Symbol] {n : ℕ} (flts : FLTS (Fin n) Symbol) (j k : Fin n) : - (Regex flts k j k + 1).matches' = - ((Regex flts k k k + 1) * (Regex flts k j k)).matches' := by sorry - #check εNFA.IsPath -- Mimicing the definition of NFA.Path. Path s xs is the type of -- inductive Path : State → List Symbol → Type (max u_1 u_2) -- | nil (s : State) : Path s [] -- | cons (s u : State) (a : Symbol) (x : List Symbol) : Path (flts.tr s a) x → Path s (a :: x) -def Path_supp (flts : FLTS State Symbol) : State → List Symbol → Set State +def PathSupp {State : Type*} (flts : FLTS State Symbol) : State → List Symbol → Set State | _, [] | _, [_] => ∅ - | s, a :: x => {flts.tr s a} ∪ Path_supp flts (flts.tr s a) x + | s, a :: x => {flts.tr s a} ∪ PathSupp flts (flts.tr s a) x -lemma empty_or_char_of_path_supp_empty {State : Type*} {flts : FLTS State Symbol} {s : State} - {xs : List Symbol} : Path_supp flts s xs = ∅ ↔ xs = [] ∨ (∃ a : Symbol, xs = [a]) := by +lemma pathSupp_empty_iff_empty_or_char {State : Type*} {flts : FLTS State Symbol} {s : State} + {xs : List Symbol} : PathSupp flts s xs = ∅ ↔ xs = [] ∨ (∃ a : Symbol, xs = [a]) := by match xs with - | [] | [_] => grind [Path_supp] + | [] | [_] => grind [PathSupp] | x :: y :: ys => - have h1 : flts.tr s x ∈ Path_supp flts s (x :: y :: ys) := by grind [Path_supp] + have h1 : flts.tr s x ∈ PathSupp flts s (x :: y :: ys) := by grind [PathSupp] grind -structure Path_of_FLTS (n : ℕ) (Symbol : Type*) extends FLTS (Fin n) Symbol where +lemma pathSupp_head {State : Type*} {flts : FLTS State Symbol} {s : State} + {a : Symbol} {xs : List Symbol} (hxs : xs ≠ []) : + PathSupp flts s (a :: xs) = {flts.tr s a} ∪ PathSupp flts (flts.tr s a) xs := by + grind [PathSupp] + +lemma pathSupp_append {State : Type*} {flts : FLTS State Symbol} {s : State} + {xs ys : List Symbol} (hxs : xs ≠ [] ∧ ys ≠ []) : + PathSupp flts s (xs ++ ys) = + {flts.mtr s xs} ∪ PathSupp flts s xs ∪ PathSupp flts (flts.mtr s xs) ys := by + induction xs generalizing s with + | nil => grind [PathSupp] + | cons a xs ih => + sorry + +structure BoundedPath (n : ℕ) (Symbol : Type*) extends FLTS (Fin n) Symbol where start : Fin n finish : Fin n bound : ℕ -instance {n : ℕ} : Acceptor (Path_of_FLTS n Symbol) Symbol where - Accepts (a : Path_of_FLTS n Symbol) (xs : List Symbol) := - a.mtr a.start xs = a.finish ∧ (∀ i ∈ Path_supp a.toFLTS a.start xs, i < a.bound) +instance {n : ℕ} : Acceptor (BoundedPath n Symbol) Symbol where + Accepts (a : BoundedPath n Symbol) (xs : List Symbol) := + a.mtr a.start xs = a.finish ∧ (∀ i ∈ PathSupp a.toFLTS a.start xs, i < a.bound) + +-- This is the original aux +lemma language_path_eq_dfa {n : ℕ} (flts : FLTS (Fin n) Symbol) (i j : Fin n) {k : ℕ} (hk : n ≤ k) : + language (BoundedPath.mk flts i j k) = + language (DA.FinAcc.mk {tr := flts.tr, start := i} {j}) := by + ext xs + simp only [mem_language, Accepts] + grind --- The function sending a string to its head which first ends at state `t` -def path_head {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) : List Symbol → List Symbol +-- The function sending a string to its shortest suffix which starts at state `t`. +def splitLast [DecidableEq Symbol] {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) : + List Symbol → List Symbol | [] => [] - | a :: x => if flts.tr s a = t then [a] else a :: path_head flts (flts.tr s a) t x + | a :: x => if (splitLast flts (flts.tr s a) t x = x) ∧ flts.tr s a ≠ t then a :: x + else splitLast flts (flts.tr s a) t x -lemma isPrefix_path_head {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) (xs : List Symbol) : - IsPrefix (path_head flts s t xs) xs := by sorry +lemma isSuffix_splitLast [DecidableEq Symbol] {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) (xs : List Symbol) : + IsSuffix (splitLast flts s t xs) xs := by + induction xs with + | nil => simp [splitLast] + | cons a xs ih => sorry -def path_tail {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) (xs : List Symbol) : - List Symbol := by sorry +-- Add the analogous definitions and lemmas as below +-- Brooke can work on this (fifth) + +lemma path1 {n : ℕ} (flts : FLTS (Fin n) Symbol) (i j k : Fin n) : + language (BoundedPath.mk flts i j (k + 1)) = language (BoundedPath.mk flts i j k) + + (language (BoundedPath.mk flts i k (k + 1)) * language (BoundedPath.mk flts k j k)) := by + ext xs + rw [Language.mem_add, Language.mem_mul] + constructor + · intro h + by_cases h' : xs ∈ language (BoundedPath.mk flts i j k) + · left; exact h' + right + sorry + · sorry + +-- The function sending a string to its shortest prefix which ends at state `t`. +def splitFirst {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) : List Symbol → List Symbol + | [] => [] + | a :: x => if flts.tr s a = t then [a] else a :: splitFirst flts (flts.tr s a) t x + +-- Brooke can work on this lemma (fourth) +lemma isPrefix_splitFirst {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) (xs : List Symbol) : + IsPrefix (splitFirst flts s t xs) xs := by + sorry + +noncomputable def splitFirstCompl {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) + (xs : List Symbol) : List Symbol := (isPrefix_splitFirst flts s t xs).choose + +lemma splitFirst_append {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) (xs : List Symbol) : + splitFirst flts s t xs ++ splitFirstCompl flts s t xs = xs := by + grind [splitFirst, splitFirstCompl] + +lemma splitFirst_mem {n : ℕ} {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : List Symbol} + (h : xs ∈ (language (BoundedPath.mk flts i k (k.val + 1)))) : + splitFirst flts i k xs ∈ language (BoundedPath.mk flts i k k.val) := by + induction xs generalizing i with + | nil => simpa [Accepts, splitFirst, PathSupp] using h + | cons a xs ih => + simp only [mem_language, Accepts, Order.lt_add_one_iff, splitFirst] at ih h ⊢ + obtain ⟨h1, h2⟩ := h + split_ifs with ha + · refine ⟨by grind, ?_⟩ + have : PathSupp flts i [a] = ∅ := by grind [PathSupp] + simp [this] + · have : flts.mtr i (a :: splitFirst flts (flts.tr i a) k xs) = + flts.mtr (flts.tr i a) (splitFirst flts (flts.tr i a) k xs) := by grind + by_cases hxs : xs = [] + · grind + rw [pathSupp_head hxs] at h2 + by_cases hPath : splitFirst flts (flts.tr i a) k xs = [] + · grind + rw [this, pathSupp_head hPath] + grind + +lemma splitFirstCompl_mem {n : ℕ} {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : List Symbol} + (h : xs ∈ (language (BoundedPath.mk flts i k (k.val + 1)))) : + splitFirstCompl flts i ⟨k, by omega⟩ xs ∈ language (BoundedPath.mk flts k k (k.val + 1)) := by + sorry + +lemma path2 {n : ℕ} (flts : FLTS (Fin n) Symbol) (i k : Fin n) : + language (BoundedPath.mk flts i k (k + 1)) = + language (BoundedPath.mk flts i k k) * language (BoundedPath.mk flts k k (k + 1)) := by + ext xs + rw [Language.mem_mul] + constructor + · intro h + use splitFirst flts i k xs, splitFirst_mem h, + splitFirstCompl flts i k xs, splitFirstCompl_mem h, + splitFirst_append flts _ _ _ + · simp only [mem_language, Accepts] + intro ⟨ys, ⟨⟨hys, hsuppys⟩, ⟨zs, ⟨⟨hzs, hsuppzs⟩, happend⟩⟩⟩⟩ + refine ⟨by grind, ?_⟩ + by_cases ys = [] ∨ zs = [] + · grind + grind [pathSupp_append] + +lemma path3 {n : ℕ} (flts : FLTS (Fin n) Symbol) (k : Fin n) : + language (BoundedPath.mk flts k k (k + 1)) = (language (BoundedPath.mk flts k k k))∗ := by + sorry -- Brooke can do this (first) lemma set_aux {α : Type*} (A : Set α) : (∀ (i : α), i ∉ A) ↔ A = ∅ := by @@ -318,44 +412,29 @@ lemma set_aux {α : Type*} (A : Set α) : (∀ (i : α), i ∉ A) ↔ A = ∅ := theorem language_path_eq_regex [Fintype Symbol] {n k : ℕ} {i j : Fin n} {flts : FLTS (Fin n) Symbol} : - language (Path_of_FLTS.mk flts i j k) = matches' (Regex flts i j k) := by - ext xs - simp only [mem_language, Accepts] + language (BoundedPath.mk flts i j k) = matches' (Regex flts i j k) := by induction k generalizing i j with | zero => + ext xs + simp only [mem_language, Accepts] simp only [not_lt_zero, imp_false, Regex] split_ifs with heq · -- The case of i = j, k = 0 - rw [set_aux, mem_add_matches'_iff, mem_sum_matches'_iff, empty_or_char_of_path_supp_empty] + rw [set_aux, mem_add_matches'_iff, mem_sum_matches'_iff, pathSupp_empty_iff_empty_or_char] aesop · -- The case of i ≠ j, k = 0 - rw [set_aux, mem_sum_matches'_iff, empty_or_char_of_path_supp_empty] + rw [set_aux, mem_sum_matches'_iff, pathSupp_empty_iff_empty_or_char] aesop - | succ k h => + | succ k ih => simp only [Regex] split_ifs with hk - · rw [← h] - exact ⟨fun ⟨h_ends, h_path⟩ => ⟨h_ends, fun _ _ => lt_of_lt_of_le (by norm_num) hk⟩, - fun ⟨h_ends, h_path⟩ => ⟨h_ends, fun l hl => lt_trans (h_path l hl) (by norm_num)⟩⟩ - · rw [mem_add_matches'_iff] - constructor - · intro ⟨h_ends, h_path⟩ - by_cases h_bound : ∀ l ∈ Path_supp flts i xs, l < k - · -- Brooke can work on this (Last) - -- Given xs in regex i j k + 1, if xs does not go through k, then xs is in regex i j k. - left - sorry - · right - push Not at h_bound - rcases h_bound with ⟨l, ⟨hl1, hl2⟩⟩ - have hl : l = k + 1 := by sorry - sorry - · rintro (h1 | h2) - · grind [h.mpr h1] - · sorry + · rw [← ih, language_path_eq_dfa flts i j hk, language_path_eq_dfa flts i j (by omega)] + rw [path1 (k := ⟨k, by omega⟩), path2, path3] + simp only [matches'_add, matches'_mul, matches'_star] + grind lemma aux {n : ℕ} {s : Fin n} {dfa : DA.FinAcc (Fin n) Symbol} (h : dfa.accept = {s}) : - language dfa = language (Path_of_FLTS.mk dfa.toFLTS dfa.start s n) := by + language dfa = language (BoundedPath.mk dfa.toFLTS dfa.start s n) := by ext xs simp only [mem_language, Accepts] grind From 1eb056bb7b29f56d8a08fb2901e2dd6aa8342154 Mon Sep 17 00:00:00 2001 From: Chi-Yun Hsu Date: Fri, 7 Aug 2026 10:45:28 -0700 Subject: [PATCH 26/89] Update --- Cslib/Computability/Languages/RegularLanguage.lean | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Cslib/Computability/Languages/RegularLanguage.lean b/Cslib/Computability/Languages/RegularLanguage.lean index fdc10bc3f4..2a6de505e7 100644 --- a/Cslib/Computability/Languages/RegularLanguage.lean +++ b/Cslib/Computability/Languages/RegularLanguage.lean @@ -325,7 +325,8 @@ lemma isSuffix_splitLast [DecidableEq Symbol] {n : ℕ} (flts : FLTS (Fin n) Sym | nil => simp [splitLast] | cons a xs ih => sorry --- Add the analogous definitions and lemmas as below +-- Add the analogous lemmas for splitLast like the lemmas of splitFirst below +-- Statements first. Work on the proof only if you have time. -- Brooke can work on this (fifth) lemma path1 {n : ℕ} (flts : FLTS (Fin n) Symbol) (i j k : Fin n) : @@ -349,7 +350,9 @@ def splitFirst {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) : List Symbo -- Brooke can work on this lemma (fourth) lemma isPrefix_splitFirst {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) (xs : List Symbol) : IsPrefix (splitFirst flts s t xs) xs := by - sorry + induction xs with + | nil => simp [splitFirst] + | cons a xs ih => sorry noncomputable def splitFirstCompl {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) (xs : List Symbol) : List Symbol := (isPrefix_splitFirst flts s t xs).choose From 2c2b45046a8264b5a0edb187b70909a16e4f0af1 Mon Sep 17 00:00:00 2001 From: Brooke Gill <96643991+brooke-gill@users.noreply.github.com> Date: Sun, 9 Aug 2026 14:11:03 -0700 Subject: [PATCH 27/89] Finished mem_sum_matches'_iff --- Cslib/Computability/Languages/RegularExpressions.lean | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Cslib/Computability/Languages/RegularExpressions.lean b/Cslib/Computability/Languages/RegularExpressions.lean index f260a79231..33a1856db8 100644 --- a/Cslib/Computability/Languages/RegularExpressions.lean +++ b/Cslib/Computability/Languages/RegularExpressions.lean @@ -47,6 +47,11 @@ theorem mem_mul_matches'_iff (P Q : RegularExpression α) (x : List α) : -- Brooke can work on this lemma (third) theorem mem_sum_matches'_iff (L : List (RegularExpression α)) (x : List α) : - x ∈ (L.sum).matches' ↔ ∃ P ∈ L, x ∈ P.matches' := by sorry + x ∈ (L.sum).matches' ↔ ∃ P ∈ L, x ∈ P.matches' := by + induction L with + | nil => simp + | cons head tail ih => + simp only [List.sum_cons, matches', List.mem_cons, exists_eq_or_imp, List.sum_cons, + Language.mem_add, ih] end Cslib.Language From 10c728f2ee75d6f882dc32d5bec6783d4f3adcf7 Mon Sep 17 00:00:00 2001 From: Brooke Gill <96643991+brooke-gill@users.noreply.github.com> Date: Mon, 10 Aug 2026 20:19:11 -0700 Subject: [PATCH 28/89] Finished isPrefix_splitFirst --- Cslib/Computability/Languages/RegularExpressions.lean | 3 +-- Cslib/Computability/Languages/RegularLanguage.lean | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Cslib/Computability/Languages/RegularExpressions.lean b/Cslib/Computability/Languages/RegularExpressions.lean index 33a1856db8..2ff70530f6 100644 --- a/Cslib/Computability/Languages/RegularExpressions.lean +++ b/Cslib/Computability/Languages/RegularExpressions.lean @@ -51,7 +51,6 @@ theorem mem_sum_matches'_iff (L : List (RegularExpression α)) (x : List α) : induction L with | nil => simp | cons head tail ih => - simp only [List.sum_cons, matches', List.mem_cons, exists_eq_or_imp, List.sum_cons, - Language.mem_add, ih] + simp only [List.sum_cons, matches', List.mem_cons, exists_eq_or_imp, Language.mem_add, ih] end Cslib.Language diff --git a/Cslib/Computability/Languages/RegularLanguage.lean b/Cslib/Computability/Languages/RegularLanguage.lean index 2a6de505e7..1066ad0763 100644 --- a/Cslib/Computability/Languages/RegularLanguage.lean +++ b/Cslib/Computability/Languages/RegularLanguage.lean @@ -350,9 +350,9 @@ def splitFirst {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) : List Symbo -- Brooke can work on this lemma (fourth) lemma isPrefix_splitFirst {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) (xs : List Symbol) : IsPrefix (splitFirst flts s t xs) xs := by - induction xs with + induction xs generalizing s with | nil => simp [splitFirst] - | cons a xs ih => sorry + | cons a xs ih => grind [splitFirst] noncomputable def splitFirstCompl {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) (xs : List Symbol) : List Symbol := (isPrefix_splitFirst flts s t xs).choose From 90c9ccc2555b6722d6022a74469c638a15addf66 Mon Sep 17 00:00:00 2001 From: Chi-Yun Hsu Date: Tue, 11 Aug 2026 11:13:03 -0700 Subject: [PATCH 29/89] Finished isSuffix_splitLast --- .../Languages/RegularLanguage.lean | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/Cslib/Computability/Languages/RegularLanguage.lean b/Cslib/Computability/Languages/RegularLanguage.lean index 1066ad0763..06a64c131f 100644 --- a/Cslib/Computability/Languages/RegularLanguage.lean +++ b/Cslib/Computability/Languages/RegularLanguage.lean @@ -319,11 +319,11 @@ def splitLast [DecidableEq Symbol] {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : | a :: x => if (splitLast flts (flts.tr s a) t x = x) ∧ flts.tr s a ≠ t then a :: x else splitLast flts (flts.tr s a) t x -lemma isSuffix_splitLast [DecidableEq Symbol] {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) (xs : List Symbol) : - IsSuffix (splitLast flts s t xs) xs := by - induction xs with +lemma isSuffix_splitLast [DecidableEq Symbol] {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) + (xs : List Symbol) : IsSuffix (splitLast flts s t xs) xs := by + induction xs generalizing s with | nil => simp [splitLast] - | cons a xs ih => sorry + | cons a xs ih => grind [splitLast] -- Add the analogous lemmas for splitLast like the lemmas of splitFirst below -- Statements first. Work on the proof only if you have time. @@ -383,10 +383,19 @@ lemma splitFirst_mem {n : ℕ} {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : rw [this, pathSupp_head hPath] grind +theorem mtr_append_eq {State Label : Type*} {flts : FLTS State Label} {s : State} + {xs ys : List Label} : flts.mtr s (xs ++ ys) = flts.mtr (flts.mtr s xs) ys := by grind + lemma splitFirstCompl_mem {n : ℕ} {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : List Symbol} (h : xs ∈ (language (BoundedPath.mk flts i k (k.val + 1)))) : - splitFirstCompl flts i ⟨k, by omega⟩ xs ∈ language (BoundedPath.mk flts k k (k.val + 1)) := by - sorry + splitFirstCompl flts i k xs ∈ language (BoundedPath.mk flts k k (k.val + 1)) := by + simp only [mem_language, Accepts] at h ⊢ + rw [← splitFirst_append flts i k xs] at h + obtain ⟨h1, h2⟩ := h + rw [mtr_append_eq] at h1 + constructor + · sorry + · sorry lemma path2 {n : ℕ} (flts : FLTS (Fin n) Symbol) (i k : Fin n) : language (BoundedPath.mk flts i k (k + 1)) = From 2d767052aef3c06328adb6abb6a1a900d860de3e Mon Sep 17 00:00:00 2001 From: Brooke Gill <96643991+brooke-gill@users.noreply.github.com> Date: Tue, 11 Aug 2026 13:48:54 -0700 Subject: [PATCH 30/89] Added proofs for isSuffix_splitLast, splitLastCompl, splitLast_append --- Cslib/Computability/Languages/RegularLanguage.lean | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Cslib/Computability/Languages/RegularLanguage.lean b/Cslib/Computability/Languages/RegularLanguage.lean index 06a64c131f..f476debb9e 100644 --- a/Cslib/Computability/Languages/RegularLanguage.lean +++ b/Cslib/Computability/Languages/RegularLanguage.lean @@ -325,6 +325,14 @@ lemma isSuffix_splitLast [DecidableEq Symbol] {n : ℕ} (flts : FLTS (Fin n) Sym | nil => simp [splitLast] | cons a xs ih => grind [splitLast] +noncomputable def splitLastCompl [DecidableEq Symbol] {n : ℕ} (flts : FLTS (Fin n) Symbol) + (s t : Fin n) (xs : List Symbol) : List Symbol := (isSuffix_splitLast flts s t xs).choose + +lemma splitLast_append [DecidableEq Symbol] {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) + (xs : List Symbol) : + splitLastCompl flts s t xs ++ splitLast flts s t xs = xs := by + grind [splitLast, splitLastCompl] + -- Add the analogous lemmas for splitLast like the lemmas of splitFirst below -- Statements first. Work on the proof only if you have time. -- Brooke can work on this (fifth) From c5b4be8f3cda084ba48a122e6cea9ca3899f2dde Mon Sep 17 00:00:00 2001 From: Brooke Gill <96643991+brooke-gill@users.noreply.github.com> Date: Tue, 11 Aug 2026 14:51:19 -0700 Subject: [PATCH 31/89] Added defs for splitLast_mem, splitLastCompl_mem --- .../Computability/Languages/RegularLanguage.lean | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/Cslib/Computability/Languages/RegularLanguage.lean b/Cslib/Computability/Languages/RegularLanguage.lean index f476debb9e..b72467a3e5 100644 --- a/Cslib/Computability/Languages/RegularLanguage.lean +++ b/Cslib/Computability/Languages/RegularLanguage.lean @@ -62,6 +62,7 @@ theorem IsRegular.iff_nfa {l : Language Symbol} : use Set State, inferInstance, na.toDAFinAcc grind + /-- The complementation of a regular language is regular. -/ theorem IsRegular.compl {l : Language Symbol} (h : l.IsRegular) : (lᶜ).IsRegular := by rw [IsRegular.iff_dfa] at h ⊢ @@ -333,10 +334,22 @@ lemma splitLast_append [DecidableEq Symbol] {n : ℕ} (flts : FLTS (Fin n) Symbo splitLastCompl flts s t xs ++ splitLast flts s t xs = xs := by grind [splitLast, splitLastCompl] +lemma splitLast_mem [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} + {i j k : Fin n} {xs : List Symbol} + (h : xs ∈ language (BoundedPath.mk flts i j (k.val + 1))) + (h' : xs ∉ language (BoundedPath.mk flts i j k.val)) : + splitLast flts i k xs ∈ language (BoundedPath.mk flts k j k.val) := by sorry + +lemma splitLastCompl_mem [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} + {i j k : Fin n} {xs : List Symbol} + (h : xs ∈ language (BoundedPath.mk flts i j (k.val + 1))) + (h' : xs ∉ language (BoundedPath.mk flts i j k.val)) : + splitLastCompl flts i k xs ∈ language (BoundedPath.mk flts i k (k.val + 1)) := by sorry + -- Add the analogous lemmas for splitLast like the lemmas of splitFirst below -- Statements first. Work on the proof only if you have time. -- Brooke can work on this (fifth) - +set_option pp.structureInstances false -- delete this once lemmas are resolved lemma path1 {n : ℕ} (flts : FLTS (Fin n) Symbol) (i j k : Fin n) : language (BoundedPath.mk flts i j (k + 1)) = language (BoundedPath.mk flts i j k) + (language (BoundedPath.mk flts i k (k + 1)) * language (BoundedPath.mk flts k j k)) := by From e4f35c8e0c7c51a80bd408a6a22f0bb66c4bdb33 Mon Sep 17 00:00:00 2001 From: Chi-Yun Hsu Date: Tue, 11 Aug 2026 15:45:20 -0700 Subject: [PATCH 32/89] Assign new tasks --- .../Languages/RegularExpressions.lean | 5 +---- .../Languages/RegularLanguage.lean | 19 +++++++++++++------ 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/Cslib/Computability/Languages/RegularExpressions.lean b/Cslib/Computability/Languages/RegularExpressions.lean index 2ff70530f6..0753cc85b2 100644 --- a/Cslib/Computability/Languages/RegularExpressions.lean +++ b/Cslib/Computability/Languages/RegularExpressions.lean @@ -16,7 +16,6 @@ open RegularExpression variable {α : Type*} --- Brooke can do all the lemmas here (second) -- Pause on doing this as we might not need these lemmas anymore. theorem mem_zero_matches'_iff (x : List α) : x ∈ (0 : RegularExpression α).matches' ↔ False := by @@ -45,12 +44,10 @@ theorem mem_add_matches'_iff (P Q : RegularExpression α) (x : List α) : theorem mem_mul_matches'_iff (P Q : RegularExpression α) (x : List α) : x ∈ (P * Q).matches' ↔ ∃ y z, x = y ++ z ∧ y ∈ P.matches' ∧ z ∈ Q.matches' := by sorry --- Brooke can work on this lemma (third) theorem mem_sum_matches'_iff (L : List (RegularExpression α)) (x : List α) : x ∈ (L.sum).matches' ↔ ∃ P ∈ L, x ∈ P.matches' := by induction L with | nil => simp - | cons head tail ih => - simp only [List.sum_cons, matches', List.mem_cons, exists_eq_or_imp, Language.mem_add, ih] + | cons head tail ih => simp [Language.mem_add, ih] end Cslib.Language diff --git a/Cslib/Computability/Languages/RegularLanguage.lean b/Cslib/Computability/Languages/RegularLanguage.lean index b72467a3e5..5c1f70a8ac 100644 --- a/Cslib/Computability/Languages/RegularLanguage.lean +++ b/Cslib/Computability/Languages/RegularLanguage.lean @@ -287,6 +287,7 @@ lemma pathSupp_head {State : Type*} {flts : FLTS State Symbol} {s : State} PathSupp flts s (a :: xs) = {flts.tr s a} ∪ PathSupp flts (flts.tr s a) xs := by grind [PathSupp] +-- Brooke can work on this lemma (first) lemma pathSupp_append {State : Type*} {flts : FLTS State Symbol} {s : State} {xs ys : List Symbol} (hxs : xs ≠ [] ∧ ys ≠ []) : PathSupp flts s (xs ++ ys) = @@ -338,7 +339,17 @@ lemma splitLast_mem [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} {i j k : Fin n} {xs : List Symbol} (h : xs ∈ language (BoundedPath.mk flts i j (k.val + 1))) (h' : xs ∉ language (BoundedPath.mk flts i j k.val)) : - splitLast flts i k xs ∈ language (BoundedPath.mk flts k j k.val) := by sorry + splitLast flts i k xs ∈ language (BoundedPath.mk flts k j k.val) := by + induction xs with + | nil => -- Brooke can work on this (second) + sorry + | cons a xs ih => + simp only [splitLast] + split_ifs + · -- Harder. Will deduce that i = k + sorry + -- Brooke can work on this (third/fourth) Easier + sorry lemma splitLastCompl_mem [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} {i j k : Fin n} {xs : List Symbol} @@ -346,9 +357,7 @@ lemma splitLastCompl_mem [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Sym (h' : xs ∉ language (BoundedPath.mk flts i j k.val)) : splitLastCompl flts i k xs ∈ language (BoundedPath.mk flts i k (k.val + 1)) := by sorry --- Add the analogous lemmas for splitLast like the lemmas of splitFirst below --- Statements first. Work on the proof only if you have time. --- Brooke can work on this (fifth) +-- Brooke can work on this (third/fourth) set_option pp.structureInstances false -- delete this once lemmas are resolved lemma path1 {n : ℕ} (flts : FLTS (Fin n) Symbol) (i j k : Fin n) : language (BoundedPath.mk flts i j (k + 1)) = language (BoundedPath.mk flts i j k) + @@ -368,7 +377,6 @@ def splitFirst {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) : List Symbo | [] => [] | a :: x => if flts.tr s a = t then [a] else a :: splitFirst flts (flts.tr s a) t x --- Brooke can work on this lemma (fourth) lemma isPrefix_splitFirst {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) (xs : List Symbol) : IsPrefix (splitFirst flts s t xs) xs := by induction xs generalizing s with @@ -439,7 +447,6 @@ lemma path3 {n : ℕ} (flts : FLTS (Fin n) Symbol) (k : Fin n) : language (BoundedPath.mk flts k k (k + 1)) = (language (BoundedPath.mk flts k k k))∗ := by sorry --- Brooke can do this (first) lemma set_aux {α : Type*} (A : Set α) : (∀ (i : α), i ∉ A) ↔ A = ∅ := by grind From 751d19877f0db8c3cf31e2a438eda6c4d87b43b6 Mon Sep 17 00:00:00 2001 From: Chi-Yun Hsu Date: Tue, 11 Aug 2026 16:46:09 -0700 Subject: [PATCH 33/89] Proved splitFirstCompl_mem --- Cslib/Computability/Languages/RegularLanguage.lean | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Cslib/Computability/Languages/RegularLanguage.lean b/Cslib/Computability/Languages/RegularLanguage.lean index 5c1f70a8ac..10a98f84f5 100644 --- a/Cslib/Computability/Languages/RegularLanguage.lean +++ b/Cslib/Computability/Languages/RegularLanguage.lean @@ -418,13 +418,13 @@ theorem mtr_append_eq {State Label : Type*} {flts : FLTS State Label} {s : State lemma splitFirstCompl_mem {n : ℕ} {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : List Symbol} (h : xs ∈ (language (BoundedPath.mk flts i k (k.val + 1)))) : splitFirstCompl flts i k xs ∈ language (BoundedPath.mk flts k k (k.val + 1)) := by - simp only [mem_language, Accepts] at h ⊢ - rw [← splitFirst_append flts i k xs] at h - obtain ⟨h1, h2⟩ := h - rw [mtr_append_eq] at h1 - constructor - · sorry - · sorry + have h' := splitFirst_mem h + simp only [mem_language, Accepts] at h h' ⊢ + rw [← splitFirst_append flts i k xs, mtr_append_eq] at h + refine ⟨by simpa [h'.1] using h.1, ?_⟩ + by_cases splitFirst flts i k xs = [] ∨ splitFirstCompl flts i k xs = [] + · grind [PathSupp] + grind [pathSupp_append] lemma path2 {n : ℕ} (flts : FLTS (Fin n) Symbol) (i k : Fin n) : language (BoundedPath.mk flts i k (k + 1)) = From 147606eb471c781231cec9d5fef33a70da204a0b Mon Sep 17 00:00:00 2001 From: Chi-Yun Hsu Date: Mon, 17 Aug 2026 15:12:33 -0700 Subject: [PATCH 34/89] Proved path3 --- .../Languages/RegularLanguage.lean | 44 ++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/Cslib/Computability/Languages/RegularLanguage.lean b/Cslib/Computability/Languages/RegularLanguage.lean index 10a98f84f5..30832dac56 100644 --- a/Cslib/Computability/Languages/RegularLanguage.lean +++ b/Cslib/Computability/Languages/RegularLanguage.lean @@ -335,6 +335,9 @@ lemma splitLast_append [DecidableEq Symbol] {n : ℕ} (flts : FLTS (Fin n) Symbo splitLastCompl flts s t xs ++ splitLast flts s t xs = xs := by grind [splitLast, splitLastCompl] +theorem mtr_head_eq {State Label : Type*} {flts : FLTS State Label} {s : State} + {x : Label} {xs : List Label} : flts.mtr s (x :: xs) = flts.mtr (flts.tr s x) xs := by grind + lemma splitLast_mem [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} {i j k : Fin n} {xs : List Symbol} (h : xs ∈ language (BoundedPath.mk flts i j (k.val + 1))) @@ -412,6 +415,16 @@ lemma splitFirst_mem {n : ℕ} {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : rw [this, pathSupp_head hPath] grind +lemma splitFirst_mem' {n : ℕ} {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : List Symbol} + (hxs : xs ≠ []) (h : xs ∈ (language (BoundedPath.mk flts i k (k.val + 1)))) : + splitFirst flts i k xs ∈ language (BoundedPath.mk flts i k k.val) - 1 := by + rw [Language.mem_sub] + refine ⟨splitFirst_mem h, ?_⟩ + simp only [Language.mem_one] + induction xs with + | nil => contradiction + | cons a xs ih => grind [splitFirst] + theorem mtr_append_eq {State Label : Type*} {flts : FLTS State Label} {s : State} {xs ys : List Label} : flts.mtr s (xs ++ ys) = flts.mtr (flts.mtr s xs) ys := by grind @@ -443,9 +456,38 @@ lemma path2 {n : ℕ} (flts : FLTS (Fin n) Symbol) (i k : Fin n) : · grind grind [pathSupp_append] +lemma kstar_eq {α : Type*} (l : Language α) : l∗ = (l - 1)∗ := by + ext x + rw [Language.kstar_def_nonempty, Language.mem_kstar] + -- aesop + exact ⟨fun ⟨S, hx, h⟩ => ⟨S, ⟨hx, fun y ys => h y ys⟩⟩, + fun ⟨S, ⟨hx, h⟩⟩ => ⟨S, hx, fun y ys => h y ys⟩⟩ + lemma path3 {n : ℕ} (flts : FLTS (Fin n) Symbol) (k : Fin n) : language (BoundedPath.mk flts k k (k + 1)) = (language (BoundedPath.mk flts k k k))∗ := by - sorry + rw [← mul_one (language (BoundedPath.mk flts k k ↑k))∗] + rw [kstar_eq] + refine (Language.self_eq_mul_add_iff (by simp [Language.mem_sub])).mp ?_ + -- mimic the proof of path2 + ext xs + simp only [Language.mem_add, Language.mem_mul, Language.mem_sub] + constructor + · intro h + by_cases h' : xs ∈ (1 : Language Symbol) + · grind + left + use splitFirst flts k k xs, splitFirst_mem' h' h, + splitFirstCompl flts k k xs, splitFirstCompl_mem h, + splitFirst_append flts _ _ _ + · rintro (⟨ys, ⟨⟨⟨hys, hsuppys⟩, hysnotempty⟩, ⟨zs, ⟨⟨hzs, hsuppzs⟩, happend⟩⟩⟩⟩ | hempty) + · refine ⟨by grind, ?_⟩ + by_cases zs = [] + · grind + rw [Language.mem_one] at hysnotempty + grind [pathSupp_append] + · rw [Language.mem_one] at hempty + simp only [mem_language, Accepts] + grind [PathSupp] lemma set_aux {α : Type*} (A : Set α) : (∀ (i : α), i ∉ A) ↔ A = ∅ := by grind From 02219ae2abe066a2ca60afcebe334dfa6d91e2a1 Mon Sep 17 00:00:00 2001 From: Brooke Gill <96643991+brooke-gill@users.noreply.github.com> Date: Mon, 17 Aug 2026 16:46:19 -0700 Subject: [PATCH 35/89] Finished pathSupp_append --- Cslib/Computability/Languages/RegularLanguage.lean | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/Cslib/Computability/Languages/RegularLanguage.lean b/Cslib/Computability/Languages/RegularLanguage.lean index 30832dac56..deb2c12a06 100644 --- a/Cslib/Computability/Languages/RegularLanguage.lean +++ b/Cslib/Computability/Languages/RegularLanguage.lean @@ -295,7 +295,18 @@ lemma pathSupp_append {State : Type*} {flts : FLTS State Symbol} {s : State} induction xs generalizing s with | nil => grind [PathSupp] | cons a xs ih => - sorry + have h1 : flts.mtr s (a :: xs) = flts.mtr (flts.tr s a) xs := by rfl + rw [h1] + by_cases hx : xs = [] + · have h2 : PathSupp flts s (a :: xs) = ∅ := by aesop + rw [h2] + rw [List.cons_append, pathSupp_head (by simp [hxs.2])] + grind + · have h2 : PathSupp flts s (a :: xs) = {flts.tr s a} ∪ PathSupp flts (flts.tr s a) xs := + (pathSupp_head hx) + rw [h2] + rw [List.cons_append, pathSupp_head (by simp [hxs.2])] + grind structure BoundedPath (n : ℕ) (Symbol : Type*) extends FLTS (Fin n) Symbol where start : Fin n From 48af610b4dc16b08ae42b0db0e781e615ba31fa3 Mon Sep 17 00:00:00 2001 From: Brooke Gill <96643991+brooke-gill@users.noreply.github.com> Date: Mon, 17 Aug 2026 16:52:31 -0700 Subject: [PATCH 36/89] Golfed pathSupp_append --- Cslib/Computability/Languages/RegularLanguage.lean | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/Cslib/Computability/Languages/RegularLanguage.lean b/Cslib/Computability/Languages/RegularLanguage.lean index deb2c12a06..2128e3e757 100644 --- a/Cslib/Computability/Languages/RegularLanguage.lean +++ b/Cslib/Computability/Languages/RegularLanguage.lean @@ -295,17 +295,10 @@ lemma pathSupp_append {State : Type*} {flts : FLTS State Symbol} {s : State} induction xs generalizing s with | nil => grind [PathSupp] | cons a xs ih => - have h1 : flts.mtr s (a :: xs) = flts.mtr (flts.tr s a) xs := by rfl - rw [h1] + rw [List.cons_append, pathSupp_head (by simp [hxs.2])] by_cases hx : xs = [] - · have h2 : PathSupp flts s (a :: xs) = ∅ := by aesop - rw [h2] - rw [List.cons_append, pathSupp_head (by simp [hxs.2])] - grind - · have h2 : PathSupp flts s (a :: xs) = {flts.tr s a} ∪ PathSupp flts (flts.tr s a) xs := - (pathSupp_head hx) - rw [h2] - rw [List.cons_append, pathSupp_head (by simp [hxs.2])] + · grind [PathSupp] + · rw [pathSupp_head hx] grind structure BoundedPath (n : ℕ) (Symbol : Type*) extends FLTS (Fin n) Symbol where From 3eb5173dead1e7a67055f928da127d1b16f61fed Mon Sep 17 00:00:00 2001 From: Brooke Gill <96643991+brooke-gill@users.noreply.github.com> Date: Mon, 17 Aug 2026 20:46:22 -0700 Subject: [PATCH 37/89] Finished hole #1 of splitLast_mem --- Cslib/Computability/Languages/RegularLanguage.lean | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Cslib/Computability/Languages/RegularLanguage.lean b/Cslib/Computability/Languages/RegularLanguage.lean index 2128e3e757..bd41129d6c 100644 --- a/Cslib/Computability/Languages/RegularLanguage.lean +++ b/Cslib/Computability/Languages/RegularLanguage.lean @@ -348,8 +348,10 @@ lemma splitLast_mem [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} (h' : xs ∉ language (BoundedPath.mk flts i j k.val)) : splitLast flts i k xs ∈ language (BoundedPath.mk flts k j k.val) := by induction xs with - | nil => -- Brooke can work on this (second) - sorry + | nil => + simp only [mem_language, Accepts] at h h' ⊢ + have h1 : PathSupp flts i [] = ∅ := by aesop + grind | cons a xs ih => simp only [splitLast] split_ifs From 5912e0d111ba043a71ef0e38c9b8e3f4e88748fc Mon Sep 17 00:00:00 2001 From: Brooke Gill <96643991+brooke-gill@users.noreply.github.com> Date: Mon, 17 Aug 2026 22:52:36 -0700 Subject: [PATCH 38/89] Finished a hole in splitLast_mem --- Cslib/Computability/Languages/RegularLanguage.lean | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cslib/Computability/Languages/RegularLanguage.lean b/Cslib/Computability/Languages/RegularLanguage.lean index bd41129d6c..574742d9cc 100644 --- a/Cslib/Computability/Languages/RegularLanguage.lean +++ b/Cslib/Computability/Languages/RegularLanguage.lean @@ -342,6 +342,7 @@ lemma splitLast_append [DecidableEq Symbol] {n : ℕ} (flts : FLTS (Fin n) Symbo theorem mtr_head_eq {State Label : Type*} {flts : FLTS State Label} {s : State} {x : Label} {xs : List Label} : flts.mtr s (x :: xs) = flts.mtr (flts.tr s x) xs := by grind +set_option pp.structureInstances false -- remove later; this just makes the goals easier to read lemma splitLast_mem [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} {i j k : Fin n} {xs : List Symbol} (h : xs ∈ language (BoundedPath.mk flts i j (k.val + 1))) @@ -350,15 +351,14 @@ lemma splitLast_mem [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} induction xs with | nil => simp only [mem_language, Accepts] at h h' ⊢ - have h1 : PathSupp flts i [] = ∅ := by aesop - grind + grind [PathSupp] | cons a xs ih => simp only [splitLast] - split_ifs + split_ifs with hc · -- Harder. Will deduce that i = k sorry -- Brooke can work on this (third/fourth) Easier - sorry + · lemma splitLastCompl_mem [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} {i j k : Fin n} {xs : List Symbol} From 0dec154a77c2ddf8ab8d6c0ed6e63fdb25dc7820 Mon Sep 17 00:00:00 2001 From: Brooke Gill <96643991+brooke-gill@users.noreply.github.com> Date: Tue, 18 Aug 2026 02:30:00 -0700 Subject: [PATCH 39/89] Finished path1 hole --- Cslib/Computability/Languages/RegularLanguage.lean | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Cslib/Computability/Languages/RegularLanguage.lean b/Cslib/Computability/Languages/RegularLanguage.lean index 574742d9cc..a01363a75b 100644 --- a/Cslib/Computability/Languages/RegularLanguage.lean +++ b/Cslib/Computability/Languages/RegularLanguage.lean @@ -371,6 +371,7 @@ set_option pp.structureInstances false -- delete this once lemmas are resolved lemma path1 {n : ℕ} (flts : FLTS (Fin n) Symbol) (i j k : Fin n) : language (BoundedPath.mk flts i j (k + 1)) = language (BoundedPath.mk flts i j k) + (language (BoundedPath.mk flts i k (k + 1)) * language (BoundedPath.mk flts k j k)) := by + classical ext xs rw [Language.mem_add, Language.mem_mul] constructor @@ -378,7 +379,9 @@ lemma path1 {n : ℕ} (flts : FLTS (Fin n) Symbol) (i j k : Fin n) : by_cases h' : xs ∈ language (BoundedPath.mk flts i j k) · left; exact h' right - sorry + use splitLastCompl flts i k xs, splitLastCompl_mem h h', + splitLast flts i k xs, splitLast_mem h h', + splitLast_append flts _ _ _ · sorry -- The function sending a string to its shortest prefix which ends at state `t`. From 9d6e4587de4a29889498510b34a34ba5f5cbecda Mon Sep 17 00:00:00 2001 From: Brooke Gill <96643991+brooke-gill@users.noreply.github.com> Date: Tue, 18 Aug 2026 07:29:54 -0700 Subject: [PATCH 40/89] Finished path1 --- Cslib/Computability/Languages/RegularLanguage.lean | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Cslib/Computability/Languages/RegularLanguage.lean b/Cslib/Computability/Languages/RegularLanguage.lean index a01363a75b..027b6f4f93 100644 --- a/Cslib/Computability/Languages/RegularLanguage.lean +++ b/Cslib/Computability/Languages/RegularLanguage.lean @@ -367,7 +367,7 @@ lemma splitLastCompl_mem [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Sym splitLastCompl flts i k xs ∈ language (BoundedPath.mk flts i k (k.val + 1)) := by sorry -- Brooke can work on this (third/fourth) -set_option pp.structureInstances false -- delete this once lemmas are resolved +set_option pp.structureInstances false -- delete this after meeting lemma path1 {n : ℕ} (flts : FLTS (Fin n) Symbol) (i j k : Fin n) : language (BoundedPath.mk flts i j (k + 1)) = language (BoundedPath.mk flts i j k) + (language (BoundedPath.mk flts i k (k + 1)) * language (BoundedPath.mk flts k j k)) := by @@ -382,7 +382,14 @@ lemma path1 {n : ℕ} (flts : FLTS (Fin n) Symbol) (i j k : Fin n) : use splitLastCompl flts i k xs, splitLastCompl_mem h h', splitLast flts i k xs, splitLast_mem h h', splitLast_append flts _ _ _ - · sorry + · simp only [mem_language, Accepts] + rintro (h_left | ⟨ys, ⟨⟨hys, hsuppys⟩, ⟨zs, ⟨⟨hzs, hsuppzs⟩, happend⟩⟩⟩⟩) + · grind + · refine ⟨by grind, ?_⟩ + by_cases ys = [] ∨ zs = [] + · grind + grind [pathSupp_append] + -- The function sending a string to its shortest prefix which ends at state `t`. def splitFirst {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) : List Symbol → List Symbol From 2f591f9d446d252bf22d1131cfa29e792a0b67ee Mon Sep 17 00:00:00 2001 From: Chi-Yun Hsu Date: Tue, 18 Aug 2026 12:13:02 -0700 Subject: [PATCH 41/89] Slight golf --- .../Languages/RegularLanguage.lean | 30 ++++++++++--------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/Cslib/Computability/Languages/RegularLanguage.lean b/Cslib/Computability/Languages/RegularLanguage.lean index 027b6f4f93..a11ecfc456 100644 --- a/Cslib/Computability/Languages/RegularLanguage.lean +++ b/Cslib/Computability/Languages/RegularLanguage.lean @@ -298,8 +298,9 @@ lemma pathSupp_append {State : Type*} {flts : FLTS State Symbol} {s : State} rw [List.cons_append, pathSupp_head (by simp [hxs.2])] by_cases hx : xs = [] · grind [PathSupp] - · rw [pathSupp_head hx] - grind + · grind [pathSupp_head hx] + -- rw [pathSupp_head hx] + -- grind structure BoundedPath (n : ℕ) (Symbol : Type*) extends FLTS (Fin n) Symbol where start : Fin n @@ -342,6 +343,9 @@ lemma splitLast_append [DecidableEq Symbol] {n : ℕ} (flts : FLTS (Fin n) Symbo theorem mtr_head_eq {State Label : Type*} {flts : FLTS State Label} {s : State} {x : Label} {xs : List Label} : flts.mtr s (x :: xs) = flts.mtr (flts.tr s x) xs := by grind +theorem mtr_append_eq {State Label : Type*} {flts : FLTS State Label} {s : State} + {xs ys : List Label} : flts.mtr s (xs ++ ys) = flts.mtr (flts.mtr s xs) ys := by grind + set_option pp.structureInstances false -- remove later; this just makes the goals easier to read lemma splitLast_mem [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} {i j k : Fin n} {xs : List Symbol} @@ -349,16 +353,18 @@ lemma splitLast_mem [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} (h' : xs ∉ language (BoundedPath.mk flts i j k.val)) : splitLast flts i k xs ∈ language (BoundedPath.mk flts k j k.val) := by induction xs with - | nil => - simp only [mem_language, Accepts] at h h' ⊢ - grind [PathSupp] + | nil => -- Brooke can work on this (second) + simp [Accepts, PathSupp] at h h' + contradiction + -- simp only [mem_language, Accepts] at h h' ⊢ + -- grind [PathSupp] | cons a xs ih => simp only [splitLast] split_ifs with hc · -- Harder. Will deduce that i = k sorry -- Brooke can work on this (third/fourth) Easier - · + · sorry lemma splitLastCompl_mem [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} {i j k : Fin n} {xs : List Symbol} @@ -382,15 +388,15 @@ lemma path1 {n : ℕ} (flts : FLTS (Fin n) Symbol) (i j k : Fin n) : use splitLastCompl flts i k xs, splitLastCompl_mem h h', splitLast flts i k xs, splitLast_mem h h', splitLast_append flts _ _ _ - · simp only [mem_language, Accepts] + · --simp only [mem_language, Accepts] rintro (h_left | ⟨ys, ⟨⟨hys, hsuppys⟩, ⟨zs, ⟨⟨hzs, hsuppzs⟩, happend⟩⟩⟩⟩) - · grind + · simp only [mem_language, Accepts] at h_left ⊢ + grind · refine ⟨by grind, ?_⟩ by_cases ys = [] ∨ zs = [] · grind grind [pathSupp_append] - -- The function sending a string to its shortest prefix which ends at state `t`. def splitFirst {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) : List Symbol → List Symbol | [] => [] @@ -441,9 +447,6 @@ lemma splitFirst_mem' {n : ℕ} {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : | nil => contradiction | cons a xs ih => grind [splitFirst] -theorem mtr_append_eq {State Label : Type*} {flts : FLTS State Label} {s : State} - {xs ys : List Label} : flts.mtr s (xs ++ ys) = flts.mtr (flts.mtr s xs) ys := by grind - lemma splitFirstCompl_mem {n : ℕ} {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : List Symbol} (h : xs ∈ (language (BoundedPath.mk flts i k (k.val + 1)))) : splitFirstCompl flts i k xs ∈ language (BoundedPath.mk flts k k (k.val + 1)) := by @@ -465,8 +468,7 @@ lemma path2 {n : ℕ} (flts : FLTS (Fin n) Symbol) (i k : Fin n) : use splitFirst flts i k xs, splitFirst_mem h, splitFirstCompl flts i k xs, splitFirstCompl_mem h, splitFirst_append flts _ _ _ - · simp only [mem_language, Accepts] - intro ⟨ys, ⟨⟨hys, hsuppys⟩, ⟨zs, ⟨⟨hzs, hsuppzs⟩, happend⟩⟩⟩⟩ + · intro ⟨ys, ⟨⟨hys, hsuppys⟩, ⟨zs, ⟨⟨hzs, hsuppzs⟩, happend⟩⟩⟩⟩ refine ⟨by grind, ?_⟩ by_cases ys = [] ∨ zs = [] · grind From 38a1fc147be836e91e015b8192888d51487c9910 Mon Sep 17 00:00:00 2001 From: Brooke Gill <96643991+brooke-gill@users.noreply.github.com> Date: Tue, 18 Aug 2026 13:49:49 -0700 Subject: [PATCH 42/89] Finished part of splitLast_mem --- .../Computability/Languages/RegularLanguage.lean | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/Cslib/Computability/Languages/RegularLanguage.lean b/Cslib/Computability/Languages/RegularLanguage.lean index a11ecfc456..cfd669dcde 100644 --- a/Cslib/Computability/Languages/RegularLanguage.lean +++ b/Cslib/Computability/Languages/RegularLanguage.lean @@ -352,19 +352,25 @@ lemma splitLast_mem [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} (h : xs ∈ language (BoundedPath.mk flts i j (k.val + 1))) (h' : xs ∉ language (BoundedPath.mk flts i j k.val)) : splitLast flts i k xs ∈ language (BoundedPath.mk flts k j k.val) := by - induction xs with - | nil => -- Brooke can work on this (second) + induction xs generalizing i with + | nil => simp [Accepts, PathSupp] at h h' contradiction - -- simp only [mem_language, Accepts] at h h' ⊢ - -- grind [PathSupp] | cons a xs ih => simp only [splitLast] split_ifs with hc · -- Harder. Will deduce that i = k sorry -- Brooke can work on this (third/fourth) Easier - · sorry + · by_cases hxs : xs = [] + · aesop + · by_cases flts.tr i a = k + · apply ih + simp only [mem_language, Accepts, pathSupp_head hxs] at h ⊢ + grind + sorry + · exact ih (by simp only [mem_language, Accepts, pathSupp_head hxs] at h ⊢; grind) + (by simp only [mem_language, Accepts, pathSupp_head hxs] at h h' ⊢; grind) lemma splitLastCompl_mem [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} {i j k : Fin n} {xs : List Symbol} From 8337681c6665edd10e0a2e9c8c42b00107024614 Mon Sep 17 00:00:00 2001 From: Chi-Yun Hsu Date: Tue, 18 Aug 2026 16:15:25 -0700 Subject: [PATCH 43/89] Task assigned --- .../Languages/RegularLanguage.lean | 58 ++++++++++++++----- 1 file changed, 42 insertions(+), 16 deletions(-) diff --git a/Cslib/Computability/Languages/RegularLanguage.lean b/Cslib/Computability/Languages/RegularLanguage.lean index cfd669dcde..f4097b08ed 100644 --- a/Cslib/Computability/Languages/RegularLanguage.lean +++ b/Cslib/Computability/Languages/RegularLanguage.lean @@ -287,7 +287,6 @@ lemma pathSupp_head {State : Type*} {flts : FLTS State Symbol} {s : State} PathSupp flts s (a :: xs) = {flts.tr s a} ∪ PathSupp flts (flts.tr s a) xs := by grind [PathSupp] --- Brooke can work on this lemma (first) lemma pathSupp_append {State : Type*} {flts : FLTS State Symbol} {s : State} {xs ys : List Symbol} (hxs : xs ≠ [] ∧ ys ≠ []) : PathSupp flts s (xs ++ ys) = @@ -299,8 +298,6 @@ lemma pathSupp_append {State : Type*} {flts : FLTS State Symbol} {s : State} by_cases hx : xs = [] · grind [PathSupp] · grind [pathSupp_head hx] - -- rw [pathSupp_head hx] - -- grind structure BoundedPath (n : ℕ) (Symbol : Type*) extends FLTS (Fin n) Symbol where start : Fin n @@ -358,19 +355,51 @@ lemma splitLast_mem [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} contradiction | cons a xs ih => simp only [splitLast] + +-- def splitLast [DecidableEq Symbol] {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) : +-- List Symbol → List Symbol +-- | [] => [] +-- | a :: x => if (splitLast flts (flts.tr s a) t x = x) ∧ flts.tr s a ≠ t then a :: x +-- else splitLast flts (flts.tr s a) t x + split_ifs with hc · -- Harder. Will deduce that i = k sorry - -- Brooke can work on this (third/fourth) Easier - · by_cases hxs : xs = [] - · aesop - · by_cases flts.tr i a = k - · apply ih - simp only [mem_language, Accepts, pathSupp_head hxs] at h ⊢ - grind + -- Brooke can work on this + · rw [not_and_or, not_not] at hc + rcases hc with hc1 | hc2 + · sorry + · simp only [mem_language, Accepts, Order.lt_add_one_iff, Fin.val_fin_le, Fin.val_fin_lt, + not_and, not_forall, not_lt] at h h' + rw [mtr_head_eq] at h h' + by_cases hxs : xs = [] + · sorry + · rw [pathSupp_head hxs] at h + have : xs ∈ language (BoundedPath.mk flts (flts.tr i a) j (↑k + 1)) := by + simp [mem_language, Accepts] + grind + have ih' := ih this + apply ih' sorry - · exact ih (by simp only [mem_language, Accepts, pathSupp_head hxs] at h ⊢; grind) - (by simp only [mem_language, Accepts, pathSupp_head hxs] at h h' ⊢; grind) + + -- Prove the goal from simplifying `h'`, in a similar way we simplify `h` + + -- have : PathSupp flts i (a :: xs) = PathSupp flts (flts.tr i a) xs ∪ {flts.tr i a} := by sorry +-- lemma pathSupp_head {State : Type*} {flts : FLTS State Symbol} {s : State} +-- {a : Symbol} {xs : List Symbol} (hxs : xs ≠ []) : +-- PathSupp flts s (a :: xs) = {flts.tr s a} ∪ PathSupp flts (flts.tr s a) xs := by +-- grind [PathSupp] + + + -- by_cases hxs : xs = [] + -- · aesop + -- · by_cases flts.tr i a = k + -- · apply ih + -- simp only [mem_language, Accepts, pathSupp_head hxs] at h ⊢ + -- grind + -- sorry + -- · exact ih (by simp only [mem_language, Accepts, pathSupp_head hxs] at h ⊢; grind) + -- (by simp only [mem_language, Accepts, pathSupp_head hxs] at h h' ⊢; grind) lemma splitLastCompl_mem [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} {i j k : Fin n} {xs : List Symbol} @@ -378,8 +407,6 @@ lemma splitLastCompl_mem [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Sym (h' : xs ∉ language (BoundedPath.mk flts i j k.val)) : splitLastCompl flts i k xs ∈ language (BoundedPath.mk flts i k (k.val + 1)) := by sorry --- Brooke can work on this (third/fourth) -set_option pp.structureInstances false -- delete this after meeting lemma path1 {n : ℕ} (flts : FLTS (Fin n) Symbol) (i j k : Fin n) : language (BoundedPath.mk flts i j (k + 1)) = language (BoundedPath.mk flts i j k) + (language (BoundedPath.mk flts i k (k + 1)) * language (BoundedPath.mk flts k j k)) := by @@ -394,8 +421,7 @@ lemma path1 {n : ℕ} (flts : FLTS (Fin n) Symbol) (i j k : Fin n) : use splitLastCompl flts i k xs, splitLastCompl_mem h h', splitLast flts i k xs, splitLast_mem h h', splitLast_append flts _ _ _ - · --simp only [mem_language, Accepts] - rintro (h_left | ⟨ys, ⟨⟨hys, hsuppys⟩, ⟨zs, ⟨⟨hzs, hsuppzs⟩, happend⟩⟩⟩⟩) + · rintro (h_left | ⟨ys, ⟨⟨hys, hsuppys⟩, ⟨zs, ⟨⟨hzs, hsuppzs⟩, happend⟩⟩⟩⟩) · simp only [mem_language, Accepts] at h_left ⊢ grind · refine ⟨by grind, ?_⟩ From 27af11b7790b7ba03e08af384ab841d671a285cb Mon Sep 17 00:00:00 2001 From: Chi-Yun Hsu Date: Tue, 18 Aug 2026 16:15:38 -0700 Subject: [PATCH 44/89] Update --- Cslib/Computability/Languages/RegularLanguage.lean | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Cslib/Computability/Languages/RegularLanguage.lean b/Cslib/Computability/Languages/RegularLanguage.lean index f4097b08ed..b3368f545b 100644 --- a/Cslib/Computability/Languages/RegularLanguage.lean +++ b/Cslib/Computability/Languages/RegularLanguage.lean @@ -368,12 +368,12 @@ lemma splitLast_mem [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} -- Brooke can work on this · rw [not_and_or, not_not] at hc rcases hc with hc1 | hc2 - · sorry + · sorry -- It is possible we do not need to do rcases hc · simp only [mem_language, Accepts, Order.lt_add_one_iff, Fin.val_fin_le, Fin.val_fin_lt, not_and, not_forall, not_lt] at h h' rw [mtr_head_eq] at h h' by_cases hxs : xs = [] - · sorry + · sorry -- easiest · rw [pathSupp_head hxs] at h have : xs ∈ language (BoundedPath.mk flts (flts.tr i a) j (↑k + 1)) := by simp [mem_language, Accepts] @@ -381,7 +381,6 @@ lemma splitLast_mem [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} have ih' := ih this apply ih' sorry - -- Prove the goal from simplifying `h'`, in a similar way we simplify `h` -- have : PathSupp flts i (a :: xs) = PathSupp flts (flts.tr i a) xs ∪ {flts.tr i a} := by sorry From f43a101c82fa3fef5a2d213a8382cc9fc9ea2741 Mon Sep 17 00:00:00 2001 From: Chi-Yun Hsu Date: Wed, 19 Aug 2026 10:05:13 -0700 Subject: [PATCH 45/89] Proved the harder part of splitLast_mem --- .../Languages/RegularLanguage.lean | 38 +++++++++++++++++-- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/Cslib/Computability/Languages/RegularLanguage.lean b/Cslib/Computability/Languages/RegularLanguage.lean index b3368f545b..66621de69f 100644 --- a/Cslib/Computability/Languages/RegularLanguage.lean +++ b/Cslib/Computability/Languages/RegularLanguage.lean @@ -316,7 +316,10 @@ lemma language_path_eq_dfa {n : ℕ} (flts : FLTS (Fin n) Symbol) (i j : Fin n) simp only [mem_language, Accepts] grind --- The function sending a string to its shortest suffix which starts at state `t`. +/-- The function sending a string to its shortest suffix which starts at state `t`. +If the string ends at state `t`, then the function returns the empty string. +If the string never passes through state `t` (starting state can be `t`), +then the function returns the original string. -/ def splitLast [DecidableEq Symbol] {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) : List Symbol → List Symbol | [] => [] @@ -337,6 +340,17 @@ lemma splitLast_append [DecidableEq Symbol] {n : ℕ} (flts : FLTS (Fin n) Symbo splitLastCompl flts s t xs ++ splitLast flts s t xs = xs := by grind [splitLast, splitLastCompl] +lemma splitLast_neq_of_mem_PathSupp [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} + {s t : Fin n} {xs : List Symbol} (h : t ∈ PathSupp flts s xs) : + ¬(splitLast flts s t xs = xs) := by + induction xs generalizing s with + | nil => grind [splitLast, PathSupp] + | cons a xs ih => + by_cases hxs : xs = [] + · grind [splitLast, PathSupp] + rw [pathSupp_head hxs, Set.mem_union, Set.mem_singleton_iff] at h + grind [splitLast, (isSuffix_splitLast flts (flts.tr s a) t xs).length_le] + theorem mtr_head_eq {State Label : Type*} {flts : FLTS State Label} {s : State} {x : Label} {xs : List Label} : flts.mtr s (x :: xs) = flts.mtr (flts.tr s x) xs := by grind @@ -364,7 +378,22 @@ lemma splitLast_mem [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} split_ifs with hc · -- Harder. Will deduce that i = k - sorry + simp only [mem_language, Accepts, Order.lt_add_one_iff, Fin.val_fin_le, Fin.val_fin_lt, not_and, + not_forall, not_lt, and_imp, ne_eq] at * + simp only [mtr_head_eq] at * + simp only [h, forall_const] at h' + obtain ⟨x, ⟨hx, hxk⟩⟩ := h' + have eq := le_antisymm (h.2 x hx) hxk + rw [eq] at hx + by_cases hxs : xs = [] + · grind [PathSupp] + rw [pathSupp_head hxs] at hx h + rcases hx with hx1 | hx2 + · have := hc.2 + simp only [mem_singleton_iff] at hx1 + symm at hx1 + contradiction + · grind [splitLast_neq_of_mem_PathSupp hx2] -- Brooke can work on this · rw [not_and_or, not_not] at hc rcases hc with hc1 | hc2 @@ -428,7 +457,10 @@ lemma path1 {n : ℕ} (flts : FLTS (Fin n) Symbol) (i j k : Fin n) : · grind grind [pathSupp_append] --- The function sending a string to its shortest prefix which ends at state `t`. +/-- The function sending a string to its shortest prefix which ends at state `t`. +The function returns the empty string if and only if the string is empty. +If the string never passes through state `t` (starting state can be `t`), +then the function returns the original string. -/ def splitFirst {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) : List Symbol → List Symbol | [] => [] | a :: x => if flts.tr s a = t then [a] else a :: splitFirst flts (flts.tr s a) t x From e88753a03a014f5b50b4bf29b0f0fab6ad711e59 Mon Sep 17 00:00:00 2001 From: Chi-Yun Hsu Date: Wed, 19 Aug 2026 21:38:00 -0700 Subject: [PATCH 46/89] Proved splitLastCompl_mem --- .../Languages/RegularLanguage.lean | 121 +++++++++++++++--- 1 file changed, 102 insertions(+), 19 deletions(-) diff --git a/Cslib/Computability/Languages/RegularLanguage.lean b/Cslib/Computability/Languages/RegularLanguage.lean index 66621de69f..c55f22100f 100644 --- a/Cslib/Computability/Languages/RegularLanguage.lean +++ b/Cslib/Computability/Languages/RegularLanguage.lean @@ -335,11 +335,32 @@ lemma isSuffix_splitLast [DecidableEq Symbol] {n : ℕ} (flts : FLTS (Fin n) Sym noncomputable def splitLastCompl [DecidableEq Symbol] {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) (xs : List Symbol) : List Symbol := (isSuffix_splitLast flts s t xs).choose +noncomputable def splitLastCompl' [DecidableEq Symbol] {n : ℕ} (flts : FLTS (Fin n) Symbol) + (s t : Fin n) : List Symbol → List Symbol + | [] => [] + | a :: x => if (splitLastCompl' flts (flts.tr s a) t x = []) ∧ flts.tr s a ≠ t then [] + else a :: splitLastCompl' flts (flts.tr s a) t x + lemma splitLast_append [DecidableEq Symbol] {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) (xs : List Symbol) : splitLastCompl flts s t xs ++ splitLast flts s t xs = xs := by grind [splitLast, splitLastCompl] +lemma splitLast_append' [DecidableEq Symbol] {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) + (xs : List Symbol) : + splitLastCompl' flts s t xs ++ splitLast flts s t xs = xs := by + induction xs generalizing s with + | nil => grind [splitLast, splitLastCompl'] + | cons a xs ih => + simp only [splitLast, splitLastCompl'] + split_ifs with h h' h' + · simp + · grind [ih (s := flts.tr s a)] + · have := h'.1 ▸ ih (s := flts.tr s a) + simp at this + grind + · simpa using ih (s := flts.tr s a) + lemma splitLast_neq_of_mem_PathSupp [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} {s t : Fin n} {xs : List Symbol} (h : t ∈ PathSupp flts s xs) : ¬(splitLast flts s t xs = xs) := by @@ -351,12 +372,54 @@ lemma splitLast_neq_of_mem_PathSupp [DecidableEq Symbol] {n : ℕ} {flts : FLTS rw [pathSupp_head hxs, Set.mem_union, Set.mem_singleton_iff] at h grind [splitLast, (isSuffix_splitLast flts (flts.tr s a) t xs).length_le] +lemma splitLastCompl_eq [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} + {s t : Fin n} {xs : List Symbol} (h : t ∉ PathSupp flts s xs) (h' : t = flts.mtr s xs) : + splitLastCompl' flts s t xs = xs := by + induction xs generalizing s with + | nil => grind [splitLastCompl', PathSupp] + | cons a xs ih => + by_cases hxs : xs = [] + · grind [splitLastCompl', PathSupp] + rw [pathSupp_head hxs, Set.mem_union, Set.mem_singleton_iff] at h + grind [splitLastCompl', (isSuffix_splitLast flts (flts.tr s a) t xs).length_le] + +lemma mem_PathSupp_of_nonempty_splitLastCompl [DecidableEq Symbol] {n : ℕ} + {flts : FLTS (Fin n) Symbol} {s t : Fin n} {xs : List Symbol} + (h : ¬(splitLastCompl' flts s t xs = [])) : + t ∈ PathSupp flts s xs ∨ t = flts.mtr s xs := by + induction xs generalizing s with + | nil => contradiction + | cons a xs ih => + by_cases hxs : xs = [] <;> grind [splitLastCompl', PathSupp] + theorem mtr_head_eq {State Label : Type*} {flts : FLTS State Label} {s : State} {x : Label} {xs : List Label} : flts.mtr s (x :: xs) = flts.mtr (flts.tr s x) xs := by grind theorem mtr_append_eq {State Label : Type*} {flts : FLTS State Label} {s : State} {xs ys : List Label} : flts.mtr s (xs ++ ys) = flts.mtr (flts.mtr s xs) ys := by grind +lemma splitLast_aux [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} + {i j k : Fin n} {xs : List Symbol} {a : Symbol} + (h : a :: xs ∈ language (BoundedPath.mk flts i j (k.val + 1))) + (h' : a :: xs ∉ language (BoundedPath.mk flts i j k.val)) + (hc : splitLast flts (flts.tr i a) k xs = xs ∧ flts.tr i a ≠ k) : False := by + simp only [mem_language, Accepts, Order.lt_add_one_iff, Fin.val_fin_le, Fin.val_fin_lt, not_and, + not_forall, not_lt, ne_eq] at * + simp only [mtr_head_eq] at * + simp only [h, forall_const] at h' + obtain ⟨x, ⟨hx, hxk⟩⟩ := h' + have eq := le_antisymm (h.2 x hx) hxk + rw [eq] at hx + by_cases hxs : xs = [] + · grind [PathSupp] + rw [pathSupp_head hxs] at hx h + rcases hx with hx1 | hx2 + · have := hc.2 + simp only [mem_singleton_iff] at hx1 + symm at hx1 + contradiction + · grind [splitLast_neq_of_mem_PathSupp hx2] + set_option pp.structureInstances false -- remove later; this just makes the goals easier to read lemma splitLast_mem [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} {i j k : Fin n} {xs : List Symbol} @@ -378,22 +441,7 @@ lemma splitLast_mem [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} split_ifs with hc · -- Harder. Will deduce that i = k - simp only [mem_language, Accepts, Order.lt_add_one_iff, Fin.val_fin_le, Fin.val_fin_lt, not_and, - not_forall, not_lt, and_imp, ne_eq] at * - simp only [mtr_head_eq] at * - simp only [h, forall_const] at h' - obtain ⟨x, ⟨hx, hxk⟩⟩ := h' - have eq := le_antisymm (h.2 x hx) hxk - rw [eq] at hx - by_cases hxs : xs = [] - · grind [PathSupp] - rw [pathSupp_head hxs] at hx h - rcases hx with hx1 | hx2 - · have := hc.2 - simp only [mem_singleton_iff] at hx1 - symm at hx1 - contradiction - · grind [splitLast_neq_of_mem_PathSupp hx2] + exfalso; exact splitLast_aux h h' hc -- Brooke can work on this · rw [not_and_or, not_not] at hc rcases hc with hc1 | hc2 @@ -429,11 +477,46 @@ lemma splitLast_mem [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} -- · exact ih (by simp only [mem_language, Accepts, pathSupp_head hxs] at h ⊢; grind) -- (by simp only [mem_language, Accepts, pathSupp_head hxs] at h h' ⊢; grind) +lemma language_BoundedPath_head_iff {n : ℕ} {flts : FLTS (Fin n) Symbol} + {i j : Fin n} {k : ℕ} {a : Symbol} {xs : List Symbol} : + a :: xs ∈ language (BoundedPath.mk flts i j k) ↔ + xs ∈ language (BoundedPath.mk flts (flts.tr i a) j k) ∧ (flts.tr i a < k ∨ xs = []) := by + simp only [mem_language, Accepts] + by_cases hxs : xs = [] + · grind [PathSupp] + grind [pathSupp_head hxs] + lemma splitLastCompl_mem [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} {i j k : Fin n} {xs : List Symbol} (h : xs ∈ language (BoundedPath.mk flts i j (k.val + 1))) (h' : xs ∉ language (BoundedPath.mk flts i j k.val)) : - splitLastCompl flts i k xs ∈ language (BoundedPath.mk flts i k (k.val + 1)) := by sorry + splitLastCompl' flts i k xs ∈ language (BoundedPath.mk flts i k (k.val + 1)) := by + induction xs generalizing i with + | nil => + simp [Accepts, PathSupp] at h h' + contradiction + | cons a xs ih => + simp only [splitLastCompl'] + split_ifs with hc + · exfalso; exact splitLast_aux h h' (by grind [splitLast_append']) + · rw [not_and_or, not_not] at hc + -- The last `k` is later than `flts.tr i a` or equal to it. + by_cases hc1 : ¬splitLastCompl' flts (flts.tr i a) k xs = [] + · by_cases hxs : xs = [] + · grind [splitLastCompl'] + have haux := language_BoundedPath_head_iff.mp h + simp only [hxs, or_false] at haux + refine language_BoundedPath_head_iff.mpr ⟨?_, Or.inl haux.2⟩ + by_cases hk : k ∈ PathSupp flts (flts.tr i a) xs + · apply ih haux.1 + simp [Accepts] + grind + · have eq : k = flts.mtr (flts.tr i a) xs := by + simpa [hk] using (mem_PathSupp_of_nonempty_splitLastCompl hc1) + rw [splitLastCompl_eq hk eq] + simpa [← mtr_head_eq, eq, h.1] using haux.1 + · rw [not_not] at hc1 + simpa [hc1, Accepts, PathSupp, FLTS.mtr] using hc lemma path1 {n : ℕ} (flts : FLTS (Fin n) Symbol) (i j k : Fin n) : language (BoundedPath.mk flts i j (k + 1)) = language (BoundedPath.mk flts i j k) + @@ -446,9 +529,9 @@ lemma path1 {n : ℕ} (flts : FLTS (Fin n) Symbol) (i j k : Fin n) : by_cases h' : xs ∈ language (BoundedPath.mk flts i j k) · left; exact h' right - use splitLastCompl flts i k xs, splitLastCompl_mem h h', + use splitLastCompl' flts i k xs, splitLastCompl_mem h h', splitLast flts i k xs, splitLast_mem h h', - splitLast_append flts _ _ _ + splitLast_append' flts _ _ _ · rintro (h_left | ⟨ys, ⟨⟨hys, hsuppys⟩, ⟨zs, ⟨⟨hzs, hsuppzs⟩, happend⟩⟩⟩⟩) · simp only [mem_language, Accepts] at h_left ⊢ grind From d32d270afdc64568ec6b8512b7904ffa4d75f9ec Mon Sep 17 00:00:00 2001 From: Brooke Gill <96643991+brooke-gill@users.noreply.github.com> Date: Sun, 23 Aug 2026 20:10:09 -0700 Subject: [PATCH 47/89] Finished first hole --- Cslib/Computability/Languages/RegularLanguage.lean | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Cslib/Computability/Languages/RegularLanguage.lean b/Cslib/Computability/Languages/RegularLanguage.lean index d256b60ea7..3ef9555eb0 100644 --- a/Cslib/Computability/Languages/RegularLanguage.lean +++ b/Cslib/Computability/Languages/RegularLanguage.lean @@ -461,7 +461,16 @@ lemma splitLast_mem [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} -- Brooke can work on this · rw [not_and_or, not_not] at hc rcases hc with hc1 | hc2 - · sorry -- It is possible we do not need to do rcases hc + · simp only [mem_language, Accepts, Order.lt_add_one_iff, Fin.val_fin_le, Fin.val_fin_lt, + not_and, not_forall, not_lt] at h h' + rw [mtr_head_eq] at h h' + apply ih + simp only [mem_language, Accepts] + by_cases hxs : xs = [] + · aesop + · rw [pathSupp_head hxs] at h + aesop + simp only [mem_language, Accepts] · simp only [mem_language, Accepts, Order.lt_add_one_iff, Fin.val_fin_le, Fin.val_fin_lt, not_and, not_forall, not_lt] at h h' rw [mtr_head_eq] at h h' From 48c65d15585780d15024835225aeff7850f7f515 Mon Sep 17 00:00:00 2001 From: Brooke Gill <96643991+brooke-gill@users.noreply.github.com> Date: Mon, 24 Aug 2026 12:20:19 -0700 Subject: [PATCH 48/89] Finished second hole in splitLast_mem --- Cslib/Computability/Languages/RegularLanguage.lean | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Cslib/Computability/Languages/RegularLanguage.lean b/Cslib/Computability/Languages/RegularLanguage.lean index 3ef9555eb0..e7ea5b2406 100644 --- a/Cslib/Computability/Languages/RegularLanguage.lean +++ b/Cslib/Computability/Languages/RegularLanguage.lean @@ -475,7 +475,12 @@ lemma splitLast_mem [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} not_and, not_forall, not_lt] at h h' rw [mtr_head_eq] at h h' by_cases hxs : xs = [] - · sorry -- easiest + · simp only [mem_language, Accepts] + have h1 : flts.tr i a = j := by grind + have h2 : j = k := by grind + subst hxs + simp only [splitLast, PathSupp] + grind · rw [pathSupp_head hxs] at h have : xs ∈ language (BoundedPath.mk flts (flts.tr i a) j (↑k + 1)) := by simp [mem_language, Accepts] From 458c9bffd55ef94c16c83c30ea9d66507fb4a01b Mon Sep 17 00:00:00 2001 From: Brooke Gill <96643991+brooke-gill@users.noreply.github.com> Date: Mon, 24 Aug 2026 12:26:45 -0700 Subject: [PATCH 49/89] Golfing --- Cslib/Computability/Languages/RegularLanguage.lean | 2 -- 1 file changed, 2 deletions(-) diff --git a/Cslib/Computability/Languages/RegularLanguage.lean b/Cslib/Computability/Languages/RegularLanguage.lean index e7ea5b2406..ff1c96818b 100644 --- a/Cslib/Computability/Languages/RegularLanguage.lean +++ b/Cslib/Computability/Languages/RegularLanguage.lean @@ -476,8 +476,6 @@ lemma splitLast_mem [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} rw [mtr_head_eq] at h h' by_cases hxs : xs = [] · simp only [mem_language, Accepts] - have h1 : flts.tr i a = j := by grind - have h2 : j = k := by grind subst hxs simp only [splitLast, PathSupp] grind From efe6912cd2062ce26073d9850c8c9750138c6618 Mon Sep 17 00:00:00 2001 From: Chi-Yun Hsu Date: Tue, 25 Aug 2026 18:32:10 -0700 Subject: [PATCH 50/89] Assign tasks --- .../Languages/RegularLanguage.lean | 72 ++++++++++++++----- 1 file changed, 53 insertions(+), 19 deletions(-) diff --git a/Cslib/Computability/Languages/RegularLanguage.lean b/Cslib/Computability/Languages/RegularLanguage.lean index ff1c96818b..3157e585e2 100644 --- a/Cslib/Computability/Languages/RegularLanguage.lean +++ b/Cslib/Computability/Languages/RegularLanguage.lean @@ -388,6 +388,15 @@ lemma splitLast_neq_of_mem_PathSupp [DecidableEq Symbol] {n : ℕ} {flts : FLTS rw [pathSupp_head hxs, Set.mem_union, Set.mem_singleton_iff] at h grind [splitLast, (isSuffix_splitLast flts (flts.tr s a) t xs).length_le] +lemma mem_PathSupp_of_neq_splitLast [DecidableEq Symbol] {n : ℕ} + {flts : FLTS (Fin n) Symbol} {s t : Fin n} {xs : List Symbol} + (h : ¬(splitLast flts s t xs = xs)) : + t ∈ PathSupp flts s xs ∨ t = flts.mtr s xs := by + induction xs generalizing s with + | nil => contradiction + | cons a xs ih => + by_cases hxs : xs = [] <;> grind [splitLast, PathSupp] + lemma splitLastCompl_eq [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} {s t : Fin n} {xs : List Symbol} (h : t ∉ PathSupp flts s xs) (h' : t = flts.mtr s xs) : splitLastCompl' flts s t xs = xs := by @@ -399,6 +408,11 @@ lemma splitLastCompl_eq [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symb rw [pathSupp_head hxs, Set.mem_union, Set.mem_singleton_iff] at h grind [splitLastCompl', (isSuffix_splitLast flts (flts.tr s a) t xs).length_le] +lemma splitLast_eq [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} + {s t : Fin n} {xs : List Symbol} (h : t ∉ PathSupp flts s xs) (h' : t = flts.mtr s xs) : + splitLast flts s t xs = [] := by + simpa [splitLastCompl_eq h h'] using splitLast_append' flts s t xs + lemma mem_PathSupp_of_nonempty_splitLastCompl [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} {s t : Fin n} {xs : List Symbol} (h : ¬(splitLastCompl' flts s t xs = [])) : @@ -436,6 +450,15 @@ lemma splitLast_aux [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} contradiction · grind [splitLast_neq_of_mem_PathSupp hx2] +lemma language_BoundedPath_head_iff {n : ℕ} {flts : FLTS (Fin n) Symbol} + {i j : Fin n} {k : ℕ} {a : Symbol} {xs : List Symbol} : + a :: xs ∈ language (BoundedPath.mk flts i j k) ↔ + xs ∈ language (BoundedPath.mk flts (flts.tr i a) j k) ∧ (flts.tr i a < k ∨ xs = []) := by + simp only [mem_language, Accepts] + by_cases hxs : xs = [] + · grind [PathSupp] + grind [pathSupp_head hxs] + set_option pp.structureInstances false -- remove later; this just makes the goals easier to read lemma splitLast_mem [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} {i j k : Fin n} {xs : List Symbol} @@ -448,18 +471,38 @@ lemma splitLast_mem [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} contradiction | cons a xs ih => simp only [splitLast] - --- def splitLast [DecidableEq Symbol] {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) : --- List Symbol → List Symbol --- | [] => [] --- | a :: x => if (splitLast flts (flts.tr s a) t x = x) ∧ flts.tr s a ≠ t then a :: x --- else splitLast flts (flts.tr s a) t x - split_ifs with hc - · -- Harder. Will deduce that i = k - exfalso; exact splitLast_aux h h' hc - -- Brooke can work on this + · exfalso; exact splitLast_aux h h' hc · rw [not_and_or, not_not] at hc + -- The last `k` is later than `flts.tr i a` or equal to it. + by_cases hc1 : ¬splitLast flts (flts.tr i a) k xs = xs + · by_cases hxs : xs = [] + · grind [splitLast] + -- First hypothesis of `ih` is implied by `h` + have haux := language_BoundedPath_head_iff.mp h + simp only [hxs, or_false] at haux + + + -- Assumptions `h` and `h'` combined says that `k ∈ PathSupp flts i (a :: xs)` + by_cases hk : k ∈ PathSupp flts (flts.tr i a) xs + · -- `k` appears in PathSupp + apply ih haux.1 + -- Now the goal is the second hypothesis of `ih` + -- `h'` implies second hypothesis of `ih`?! + -- Contrapositve with `h'` and use `language_BoundedPath_head_iff.mpr` + -- ACTUALLY, INSTEAD OF THE ABOVE, USE `hk` TO CONCLUDE THE GOAL + -- (Brooke do this first) + sorry + · -- `k` only appears at the end state + -- `hk` should contradict with `h` and `h'` + -- use `mem_PathSupp_of_neq_splitLast` and `splitLast_eq` + -- (Brooke do this second) + sorry + · -- The last `k` is equal to `flts.tr i a` + -- Cannot apply ih + -- Directly prove the goal from definition + sorry + rcases hc with hc1 | hc2 · simp only [mem_language, Accepts, Order.lt_add_one_iff, Fin.val_fin_le, Fin.val_fin_lt, not_and, not_forall, not_lt] at h h' @@ -505,15 +548,6 @@ lemma splitLast_mem [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} -- · exact ih (by simp only [mem_language, Accepts, pathSupp_head hxs] at h ⊢; grind) -- (by simp only [mem_language, Accepts, pathSupp_head hxs] at h h' ⊢; grind) -lemma language_BoundedPath_head_iff {n : ℕ} {flts : FLTS (Fin n) Symbol} - {i j : Fin n} {k : ℕ} {a : Symbol} {xs : List Symbol} : - a :: xs ∈ language (BoundedPath.mk flts i j k) ↔ - xs ∈ language (BoundedPath.mk flts (flts.tr i a) j k) ∧ (flts.tr i a < k ∨ xs = []) := by - simp only [mem_language, Accepts] - by_cases hxs : xs = [] - · grind [PathSupp] - grind [pathSupp_head hxs] - lemma splitLastCompl_mem [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} {i j k : Fin n} {xs : List Symbol} (h : xs ∈ language (BoundedPath.mk flts i j (k.val + 1))) From d80c57414ac6a59f8893aae631af14be92f01eab Mon Sep 17 00:00:00 2001 From: Brooke Gill <96643991+brooke-gill@users.noreply.github.com> Date: Wed, 26 Aug 2026 15:46:52 -0700 Subject: [PATCH 51/89] Removed leftover code --- .../Languages/RegularLanguage.lean | 52 +++++++++---------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/Cslib/Computability/Languages/RegularLanguage.lean b/Cslib/Computability/Languages/RegularLanguage.lean index 3157e585e2..611a2c387d 100644 --- a/Cslib/Computability/Languages/RegularLanguage.lean +++ b/Cslib/Computability/Languages/RegularLanguage.lean @@ -503,32 +503,32 @@ lemma splitLast_mem [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} -- Directly prove the goal from definition sorry - rcases hc with hc1 | hc2 - · simp only [mem_language, Accepts, Order.lt_add_one_iff, Fin.val_fin_le, Fin.val_fin_lt, - not_and, not_forall, not_lt] at h h' - rw [mtr_head_eq] at h h' - apply ih - simp only [mem_language, Accepts] - by_cases hxs : xs = [] - · aesop - · rw [pathSupp_head hxs] at h - aesop - simp only [mem_language, Accepts] - · simp only [mem_language, Accepts, Order.lt_add_one_iff, Fin.val_fin_le, Fin.val_fin_lt, - not_and, not_forall, not_lt] at h h' - rw [mtr_head_eq] at h h' - by_cases hxs : xs = [] - · simp only [mem_language, Accepts] - subst hxs - simp only [splitLast, PathSupp] - grind - · rw [pathSupp_head hxs] at h - have : xs ∈ language (BoundedPath.mk flts (flts.tr i a) j (↑k + 1)) := by - simp [mem_language, Accepts] - grind - have ih' := ih this - apply ih' - sorry + -- rcases hc with hc1 | hc2 + -- · simp only [mem_language, Accepts, Order.lt_add_one_iff, Fin.val_fin_le, Fin.val_fin_lt, + -- not_and, not_forall, not_lt] at h h' + -- rw [mtr_head_eq] at h h' + -- apply ih + -- simp only [mem_language, Accepts] + -- by_cases hxs : xs = [] + -- · aesop + -- · rw [pathSupp_head hxs] at h + -- aesop + -- simp only [mem_language, Accepts] + -- · simp only [mem_language, Accepts, Order.lt_add_one_iff, Fin.val_fin_le, Fin.val_fin_lt, + -- not_and, not_forall, not_lt] at h h' + -- rw [mtr_head_eq] at h h' + -- by_cases hxs : xs = [] + -- · simp only [mem_language, Accepts] + -- subst hxs + -- simp only [splitLast, PathSupp] + -- grind + -- · rw [pathSupp_head hxs] at h + -- have : xs ∈ language (BoundedPath.mk flts (flts.tr i a) j (↑k + 1)) := by + -- simp [mem_language, Accepts] + -- grind + -- have ih' := ih this + -- apply ih' + -- sorry -- Prove the goal from simplifying `h'`, in a similar way we simplify `h` -- have : PathSupp flts i (a :: xs) = PathSupp flts (flts.tr i a) xs ∪ {flts.tr i a} := by sorry From 19abbc31df1d719d4a2c1eb01de426528a81fcaa Mon Sep 17 00:00:00 2001 From: Brooke Gill <96643991+brooke-gill@users.noreply.github.com> Date: Thu, 27 Aug 2026 23:01:22 -0700 Subject: [PATCH 52/89] Finished hole 3 --- Cslib/Computability/Languages/RegularLanguage.lean | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Cslib/Computability/Languages/RegularLanguage.lean b/Cslib/Computability/Languages/RegularLanguage.lean index 611a2c387d..700adb6435 100644 --- a/Cslib/Computability/Languages/RegularLanguage.lean +++ b/Cslib/Computability/Languages/RegularLanguage.lean @@ -501,7 +501,13 @@ lemma splitLast_mem [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} · -- The last `k` is equal to `flts.tr i a` -- Cannot apply ih -- Directly prove the goal from definition - sorry + rw [not_not] at hc1 + rw [hc1] + have h1 : flts.tr i a = k := by grind + rcases hc with hc' | heq + · apply absurd hc1 hc' + · have haux := language_BoundedPath_head_iff.mp h + grind -- rcases hc with hc1 | hc2 -- · simp only [mem_language, Accepts, Order.lt_add_one_iff, Fin.val_fin_le, Fin.val_fin_lt, From efd54e5dce37228042c9b0dd1805c280adb33c54 Mon Sep 17 00:00:00 2001 From: Brooke Gill <96643991+brooke-gill@users.noreply.github.com> Date: Thu, 27 Aug 2026 23:19:08 -0700 Subject: [PATCH 53/89] Golfed hole 3 --- Cslib/Computability/Languages/RegularLanguage.lean | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/Cslib/Computability/Languages/RegularLanguage.lean b/Cslib/Computability/Languages/RegularLanguage.lean index 700adb6435..c72c9d4d3d 100644 --- a/Cslib/Computability/Languages/RegularLanguage.lean +++ b/Cslib/Computability/Languages/RegularLanguage.lean @@ -503,11 +503,8 @@ lemma splitLast_mem [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} -- Directly prove the goal from definition rw [not_not] at hc1 rw [hc1] - have h1 : flts.tr i a = k := by grind - rcases hc with hc' | heq - · apply absurd hc1 hc' - · have haux := language_BoundedPath_head_iff.mp h - grind + have haux := language_BoundedPath_head_iff.mp h + grind -- rcases hc with hc1 | hc2 -- · simp only [mem_language, Accepts, Order.lt_add_one_iff, Fin.val_fin_le, Fin.val_fin_lt, From 70fe2a9909f8af86d197843301f2de502cc04777 Mon Sep 17 00:00:00 2001 From: Brooke Gill <96643991+brooke-gill@users.noreply.github.com> Date: Thu, 27 Aug 2026 23:21:36 -0700 Subject: [PATCH 54/89] One line!! --- Cslib/Computability/Languages/RegularLanguage.lean | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Cslib/Computability/Languages/RegularLanguage.lean b/Cslib/Computability/Languages/RegularLanguage.lean index c72c9d4d3d..49f89b0520 100644 --- a/Cslib/Computability/Languages/RegularLanguage.lean +++ b/Cslib/Computability/Languages/RegularLanguage.lean @@ -501,10 +501,7 @@ lemma splitLast_mem [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} · -- The last `k` is equal to `flts.tr i a` -- Cannot apply ih -- Directly prove the goal from definition - rw [not_not] at hc1 - rw [hc1] - have haux := language_BoundedPath_head_iff.mp h - grind + grind [language_BoundedPath_head_iff.mp h] -- rcases hc with hc1 | hc2 -- · simp only [mem_language, Accepts, Order.lt_add_one_iff, Fin.val_fin_le, Fin.val_fin_lt, From 301d35dff0e8d77d5e9d93b9f604b9fa56c1ff20 Mon Sep 17 00:00:00 2001 From: Brooke Gill <96643991+brooke-gill@users.noreply.github.com> Date: Sat, 29 Aug 2026 16:27:18 -0700 Subject: [PATCH 55/89] Finished hole 2 --- .../Languages/RegularLanguage.lean | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/Cslib/Computability/Languages/RegularLanguage.lean b/Cslib/Computability/Languages/RegularLanguage.lean index 49f89b0520..a324692313 100644 --- a/Cslib/Computability/Languages/RegularLanguage.lean +++ b/Cslib/Computability/Languages/RegularLanguage.lean @@ -492,12 +492,32 @@ lemma splitLast_mem [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} -- Contrapositve with `h'` and use `language_BoundedPath_head_iff.mpr` -- ACTUALLY, INSTEAD OF THE ABOVE, USE `hk` TO CONCLUDE THE GOAL -- (Brooke do this first) - sorry + intro sha + have h1 : splitLast flts (flts.tr i a) k xs = [] := by sorry + + have h2 : flts.mtr (flts.tr i a) xs ≠ k := by sorry + +-- lemma splitLast_eq [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} +-- {s t : Fin n} {xs : List Symbol} (h : t ∉ PathSupp flts s xs) (h' : t = flts.mtr s xs) : +-- splitLast flts s t xs = [] := by +-- simpa [splitLastCompl_eq h h'] using splitLast_append' flts s t xs + + apply mem_PathSupp_of_neq_splitLast at hc1 · -- `k` only appears at the end state -- `hk` should contradict with `h` and `h'` -- use `mem_PathSupp_of_neq_splitLast` and `splitLast_eq` -- (Brooke do this second) - sorry + apply mem_PathSupp_of_neq_splitLast at hc1 + have h2 : k = flts.mtr (flts.tr i a) xs := by grind + #check splitLast_eq -- h : t ∉ PathSupp flts s xs) (h' : t = flts.mtr s xs) : splitLast flts s t xs = [] (t = k, s = (flts.tr i a)) + have h3 : splitLast flts (flts.tr i a) k xs = [] := by + apply splitLast_eq hk h2 + rw [h3] + simp [Accepts] at haux + have h4 : k = j := by grind + simp [Accepts, PathSupp] + trivial + · -- The last `k` is equal to `flts.tr i a` -- Cannot apply ih -- Directly prove the goal from definition From 416bfc1fbb92bfce12c1b7c53e81c067cb9749a9 Mon Sep 17 00:00:00 2001 From: Brooke Gill <96643991+brooke-gill@users.noreply.github.com> Date: Sat, 29 Aug 2026 17:24:37 -0700 Subject: [PATCH 56/89] Finished IsRegular.iff_regex --- Cslib/Computability/Languages/RegularLanguage.lean | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/Cslib/Computability/Languages/RegularLanguage.lean b/Cslib/Computability/Languages/RegularLanguage.lean index a324692313..547e98aaf9 100644 --- a/Cslib/Computability/Languages/RegularLanguage.lean +++ b/Cslib/Computability/Languages/RegularLanguage.lean @@ -493,16 +493,13 @@ lemma splitLast_mem [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} -- ACTUALLY, INSTEAD OF THE ABOVE, USE `hk` TO CONCLUDE THE GOAL -- (Brooke do this first) intro sha - have h1 : splitLast flts (flts.tr i a) k xs = [] := by sorry - - have h2 : flts.mtr (flts.tr i a) xs ≠ k := by sorry - + simp [Accepts] at sha + grind -- lemma splitLast_eq [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} -- {s t : Fin n} {xs : List Symbol} (h : t ∉ PathSupp flts s xs) (h' : t = flts.mtr s xs) : -- splitLast flts s t xs = [] := by -- simpa [splitLastCompl_eq h h'] using splitLast_append' flts s t xs - apply mem_PathSupp_of_neq_splitLast at hc1 · -- `k` only appears at the end state -- `hk` should contradict with `h` and `h'` -- use `mem_PathSupp_of_neq_splitLast` and `splitLast_eq` From 0ac954c233661978cc45ac90bfe7a25b24931999 Mon Sep 17 00:00:00 2001 From: Chi-Yun Hsu Date: Mon, 31 Aug 2026 09:07:14 -0700 Subject: [PATCH 57/89] Golf a hole --- Cslib/Computability/Languages/RegularLanguage.lean | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Cslib/Computability/Languages/RegularLanguage.lean b/Cslib/Computability/Languages/RegularLanguage.lean index 547e98aaf9..3bb3ca9400 100644 --- a/Cslib/Computability/Languages/RegularLanguage.lean +++ b/Cslib/Computability/Languages/RegularLanguage.lean @@ -481,8 +481,6 @@ lemma splitLast_mem [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} -- First hypothesis of `ih` is implied by `h` have haux := language_BoundedPath_head_iff.mp h simp only [hxs, or_false] at haux - - -- Assumptions `h` and `h'` combined says that `k ∈ PathSupp flts i (a :: xs)` by_cases hk : k ∈ PathSupp flts (flts.tr i a) xs · -- `k` appears in PathSupp @@ -492,8 +490,7 @@ lemma splitLast_mem [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} -- Contrapositve with `h'` and use `language_BoundedPath_head_iff.mpr` -- ACTUALLY, INSTEAD OF THE ABOVE, USE `hk` TO CONCLUDE THE GOAL -- (Brooke do this first) - intro sha - simp [Accepts] at sha + simp [Accepts] grind -- lemma splitLast_eq [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} -- {s t : Fin n} {xs : List Symbol} (h : t ∉ PathSupp flts s xs) (h' : t = flts.mtr s xs) : From c132ee11d552bb72b0327785d7b7db94c20517d6 Mon Sep 17 00:00:00 2001 From: Chi-Yun Hsu Date: Mon, 31 Aug 2026 09:13:36 -0700 Subject: [PATCH 58/89] golf another hole; please continue to golf it --- Cslib/Computability/Languages/RegularLanguage.lean | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Cslib/Computability/Languages/RegularLanguage.lean b/Cslib/Computability/Languages/RegularLanguage.lean index 3bb3ca9400..799552b0a6 100644 --- a/Cslib/Computability/Languages/RegularLanguage.lean +++ b/Cslib/Computability/Languages/RegularLanguage.lean @@ -496,7 +496,6 @@ lemma splitLast_mem [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} -- {s t : Fin n} {xs : List Symbol} (h : t ∉ PathSupp flts s xs) (h' : t = flts.mtr s xs) : -- splitLast flts s t xs = [] := by -- simpa [splitLastCompl_eq h h'] using splitLast_append' flts s t xs - · -- `k` only appears at the end state -- `hk` should contradict with `h` and `h'` -- use `mem_PathSupp_of_neq_splitLast` and `splitLast_eq` @@ -509,9 +508,7 @@ lemma splitLast_mem [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} rw [h3] simp [Accepts] at haux have h4 : k = j := by grind - simp [Accepts, PathSupp] - trivial - + simp [Accepts, PathSupp, h4] · -- The last `k` is equal to `flts.tr i a` -- Cannot apply ih -- Directly prove the goal from definition From d5eb9313deddbf957c64b68ddb1fe549fd17c11e Mon Sep 17 00:00:00 2001 From: Chi-Yun Hsu Date: Mon, 31 Aug 2026 09:17:31 -0700 Subject: [PATCH 59/89] Deleting old codes --- .../Languages/RegularLanguage.lean | 56 +------------------ 1 file changed, 1 insertion(+), 55 deletions(-) diff --git a/Cslib/Computability/Languages/RegularLanguage.lean b/Cslib/Computability/Languages/RegularLanguage.lean index 799552b0a6..57763a0284 100644 --- a/Cslib/Computability/Languages/RegularLanguage.lean +++ b/Cslib/Computability/Languages/RegularLanguage.lean @@ -459,7 +459,6 @@ lemma language_BoundedPath_head_iff {n : ℕ} {flts : FLTS (Fin n) Symbol} · grind [PathSupp] grind [pathSupp_head hxs] -set_option pp.structureInstances false -- remove later; this just makes the goals easier to read lemma splitLast_mem [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} {i j k : Fin n} {xs : List Symbol} (h : xs ∈ language (BoundedPath.mk flts i j (k.val + 1))) @@ -485,24 +484,15 @@ lemma splitLast_mem [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} by_cases hk : k ∈ PathSupp flts (flts.tr i a) xs · -- `k` appears in PathSupp apply ih haux.1 - -- Now the goal is the second hypothesis of `ih` - -- `h'` implies second hypothesis of `ih`?! - -- Contrapositve with `h'` and use `language_BoundedPath_head_iff.mpr` - -- ACTUALLY, INSTEAD OF THE ABOVE, USE `hk` TO CONCLUDE THE GOAL -- (Brooke do this first) simp [Accepts] grind --- lemma splitLast_eq [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} --- {s t : Fin n} {xs : List Symbol} (h : t ∉ PathSupp flts s xs) (h' : t = flts.mtr s xs) : --- splitLast flts s t xs = [] := by --- simpa [splitLastCompl_eq h h'] using splitLast_append' flts s t xs · -- `k` only appears at the end state -- `hk` should contradict with `h` and `h'` -- use `mem_PathSupp_of_neq_splitLast` and `splitLast_eq` -- (Brooke do this second) apply mem_PathSupp_of_neq_splitLast at hc1 have h2 : k = flts.mtr (flts.tr i a) xs := by grind - #check splitLast_eq -- h : t ∉ PathSupp flts s xs) (h' : t = flts.mtr s xs) : splitLast flts s t xs = [] (t = k, s = (flts.tr i a)) have h3 : splitLast flts (flts.tr i a) k xs = [] := by apply splitLast_eq hk h2 rw [h3] @@ -512,53 +502,9 @@ lemma splitLast_mem [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} · -- The last `k` is equal to `flts.tr i a` -- Cannot apply ih -- Directly prove the goal from definition + -- (Brooke can do this last) grind [language_BoundedPath_head_iff.mp h] - -- rcases hc with hc1 | hc2 - -- · simp only [mem_language, Accepts, Order.lt_add_one_iff, Fin.val_fin_le, Fin.val_fin_lt, - -- not_and, not_forall, not_lt] at h h' - -- rw [mtr_head_eq] at h h' - -- apply ih - -- simp only [mem_language, Accepts] - -- by_cases hxs : xs = [] - -- · aesop - -- · rw [pathSupp_head hxs] at h - -- aesop - -- simp only [mem_language, Accepts] - -- · simp only [mem_language, Accepts, Order.lt_add_one_iff, Fin.val_fin_le, Fin.val_fin_lt, - -- not_and, not_forall, not_lt] at h h' - -- rw [mtr_head_eq] at h h' - -- by_cases hxs : xs = [] - -- · simp only [mem_language, Accepts] - -- subst hxs - -- simp only [splitLast, PathSupp] - -- grind - -- · rw [pathSupp_head hxs] at h - -- have : xs ∈ language (BoundedPath.mk flts (flts.tr i a) j (↑k + 1)) := by - -- simp [mem_language, Accepts] - -- grind - -- have ih' := ih this - -- apply ih' - -- sorry - -- Prove the goal from simplifying `h'`, in a similar way we simplify `h` - - -- have : PathSupp flts i (a :: xs) = PathSupp flts (flts.tr i a) xs ∪ {flts.tr i a} := by sorry --- lemma pathSupp_head {State : Type*} {flts : FLTS State Symbol} {s : State} --- {a : Symbol} {xs : List Symbol} (hxs : xs ≠ []) : --- PathSupp flts s (a :: xs) = {flts.tr s a} ∪ PathSupp flts (flts.tr s a) xs := by --- grind [PathSupp] - - - -- by_cases hxs : xs = [] - -- · aesop - -- · by_cases flts.tr i a = k - -- · apply ih - -- simp only [mem_language, Accepts, pathSupp_head hxs] at h ⊢ - -- grind - -- sorry - -- · exact ih (by simp only [mem_language, Accepts, pathSupp_head hxs] at h ⊢; grind) - -- (by simp only [mem_language, Accepts, pathSupp_head hxs] at h h' ⊢; grind) - lemma splitLastCompl_mem [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} {i j k : Fin n} {xs : List Symbol} (h : xs ∈ language (BoundedPath.mk flts i j (k.val + 1))) From c80620c4017221ba0712980ee74b267438e4989c Mon Sep 17 00:00:00 2001 From: Brooke Gill <96643991+brooke-gill@users.noreply.github.com> Date: Mon, 31 Aug 2026 21:55:37 -0700 Subject: [PATCH 60/89] Golfed hole 2 to remove `have` --- Cslib/Computability/Languages/RegularLanguage.lean | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/Cslib/Computability/Languages/RegularLanguage.lean b/Cslib/Computability/Languages/RegularLanguage.lean index 57763a0284..15b51a3b3e 100644 --- a/Cslib/Computability/Languages/RegularLanguage.lean +++ b/Cslib/Computability/Languages/RegularLanguage.lean @@ -492,13 +492,9 @@ lemma splitLast_mem [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} -- use `mem_PathSupp_of_neq_splitLast` and `splitLast_eq` -- (Brooke do this second) apply mem_PathSupp_of_neq_splitLast at hc1 - have h2 : k = flts.mtr (flts.tr i a) xs := by grind - have h3 : splitLast flts (flts.tr i a) k xs = [] := by - apply splitLast_eq hk h2 - rw [h3] + rw [splitLast_eq hk (by grind)] simp [Accepts] at haux - have h4 : k = j := by grind - simp [Accepts, PathSupp, h4] + simp [Accepts, PathSupp] · -- The last `k` is equal to `flts.tr i a` -- Cannot apply ih -- Directly prove the goal from definition From 08514f4e6f68f1c0071bd634c808c251229f3cb3 Mon Sep 17 00:00:00 2001 From: Brooke Gill <96643991+brooke-gill@users.noreply.github.com> Date: Mon, 31 Aug 2026 22:16:08 -0700 Subject: [PATCH 61/89] Golfed hole 2 --- Cslib/Computability/Languages/RegularLanguage.lean | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Cslib/Computability/Languages/RegularLanguage.lean b/Cslib/Computability/Languages/RegularLanguage.lean index 15b51a3b3e..2049e33b1d 100644 --- a/Cslib/Computability/Languages/RegularLanguage.lean +++ b/Cslib/Computability/Languages/RegularLanguage.lean @@ -493,8 +493,7 @@ lemma splitLast_mem [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} -- (Brooke do this second) apply mem_PathSupp_of_neq_splitLast at hc1 rw [splitLast_eq hk (by grind)] - simp [Accepts] at haux - simp [Accepts, PathSupp] + simp_all [Accepts, PathSupp] · -- The last `k` is equal to `flts.tr i a` -- Cannot apply ih -- Directly prove the goal from definition From 5f53ce57ee9216a9e62fe8fd59e2894b21363304 Mon Sep 17 00:00:00 2001 From: Brooke Gill <96643991+brooke-gill@users.noreply.github.com> Date: Tue, 1 Sep 2026 14:20:36 -0700 Subject: [PATCH 62/89] Folded rw statement into simp_all --- Cslib/Computability/Languages/RegularLanguage.lean | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Cslib/Computability/Languages/RegularLanguage.lean b/Cslib/Computability/Languages/RegularLanguage.lean index 2049e33b1d..3c363f2227 100644 --- a/Cslib/Computability/Languages/RegularLanguage.lean +++ b/Cslib/Computability/Languages/RegularLanguage.lean @@ -492,8 +492,7 @@ lemma splitLast_mem [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} -- use `mem_PathSupp_of_neq_splitLast` and `splitLast_eq` -- (Brooke do this second) apply mem_PathSupp_of_neq_splitLast at hc1 - rw [splitLast_eq hk (by grind)] - simp_all [Accepts, PathSupp] + simp_all [Accepts, PathSupp, splitLast_eq] · -- The last `k` is equal to `flts.tr i a` -- Cannot apply ih -- Directly prove the goal from definition From 43ba3354ef2612c246bf171dd1a9ad71fad8c030 Mon Sep 17 00:00:00 2001 From: Chi-Yun Hsu Date: Tue, 1 Sep 2026 14:44:17 -0700 Subject: [PATCH 63/89] Restructuring files until before mtr_head_eq --- .../Languages/KleeneAlgorithm.lean | 189 +++++++++++++++ .../Languages/RegularLanguage.lean | 227 ++++++++++-------- 2 files changed, 318 insertions(+), 98 deletions(-) create mode 100644 Cslib/Computability/Languages/KleeneAlgorithm.lean diff --git a/Cslib/Computability/Languages/KleeneAlgorithm.lean b/Cslib/Computability/Languages/KleeneAlgorithm.lean new file mode 100644 index 0000000000..704ff78028 --- /dev/null +++ b/Cslib/Computability/Languages/KleeneAlgorithm.lean @@ -0,0 +1,189 @@ +/- +Copyright (c) 2026 Brooke Gill and Chi-Yun Hsu. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Brooke Gill and Chi-Yun Hsu +-/ + +module + +public import Cslib.Computability.Automata.Acceptors.Acceptor +public import Cslib.Computability.Automata.DA.Basic +public import Mathlib.Computability.RegularExpressions + + +/-! +# Kleene's Algorithm +-/ + +@[expose] public section + +namespace Cslib.Language + +open scoped FLTS + +variable {Symbol : Type*} + +section PathSupp + +variable {State : Type*} + +/-- PathSupp s xs is the set of states that can be reached from state s by reading the string xs, +not including the starting state and the ending state. -/ +def PathSupp (flts : FLTS State Symbol) : State → List Symbol → Set State + | _, [] | _, [_] => ∅ + | s, a :: x => {flts.tr s a} ∪ PathSupp flts (flts.tr s a) x + +theorem pathSupp_empty_iff_empty_or_char {flts : FLTS State Symbol} {s : State} {xs : List Symbol} : + PathSupp flts s xs = ∅ ↔ xs = [] ∨ (∃ a : Symbol, xs = [a]) := by + match xs with + | [] | [_] => grind [PathSupp] + | x :: y :: ys => + have : flts.tr s x ∈ PathSupp flts s (x :: y :: ys) := by grind [PathSupp] + grind + +theorem pathSupp_head {flts : FLTS State Symbol} {s : State} {a : Symbol} {xs : List Symbol} + (hxs : xs ≠ []) : PathSupp flts s (a :: xs) = + {flts.tr s a} ∪ PathSupp flts (flts.tr s a) xs := by + grind [PathSupp] + +theorem pathSupp_append {flts : FLTS State Symbol} {s : State} {xs ys : List Symbol} + (hxs : xs ≠ [] ∧ ys ≠ []) : PathSupp flts s (xs ++ ys) = + {flts.mtr s xs} ∪ PathSupp flts s xs ∪ PathSupp flts (flts.mtr s xs) ys := by + induction xs generalizing s with + | nil => grind [PathSupp] + | cons a xs ih => + rw [List.cons_append, pathSupp_head (by simp [hxs.2])] + by_cases hx : xs = [] + · grind [PathSupp] + · grind [pathSupp_head hx] + +end PathSupp + +open Automata Acceptor + +/-- A Bounded Path (`BddPath`) has states `Fin n` and accepts strings (lists of symbols) +starting with state `start` and ending with state `finish` +with the intermediate states less than `bound`. -/ +structure BddPath (n : ℕ) (Symbol : Type*) extends FLTS (Fin n) Symbol where + start : Fin n + finish : Fin n + bound : ℕ + +instance {n : ℕ} : Acceptor (BddPath n Symbol) Symbol where + Accepts (a : BddPath n Symbol) (xs : List Symbol) := + a.mtr a.start xs = a.finish ∧ (∀ i ∈ PathSupp a.toFLTS a.start xs, i < a.bound) + +theorem language_bddpath_head_iff {n k : ℕ} {flts : FLTS (Fin n) Symbol} {i j : Fin n} + {a : Symbol} {xs : List Symbol} : + a :: xs ∈ language (BddPath.mk flts i j k) ↔ + xs ∈ language (BddPath.mk flts (flts.tr i a) j k) ∧ (flts.tr i a < k ∨ xs = []) := by + simp only [mem_language, Accepts] + by_cases hxs : xs = [] + · grind [PathSupp] + grind [pathSupp_head hxs] + +theorem language_bddpath_eq_dfa {n k : ℕ} (flts : FLTS (Fin n) Symbol) (i j : Fin n) (hk : n ≤ k) : + language (BddPath.mk flts i j k) = language (DA.FinAcc.mk {tr := flts.tr, start := i} {j}) := by + ext xs + simp only [mem_language, Accepts] + grind + +section splitLast + +open List + +-- variable [DecidableEq Symbol] + +/-- The function `splitLast` sends a string to its shortest suffix starting at state `t`. +If the string ends at state `t`, then `splitLast` returns the empty string. +If the string never passes through state `t` (starting state can be `t`), +then `splitLast` returns the original string. -/ +def splitLast [DecidableEq Symbol] {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) : + List Symbol → List Symbol + | [] => [] + | a :: x => if (splitLast flts (flts.tr s a) t x = x) ∧ flts.tr s a ≠ t then a :: x + else splitLast flts (flts.tr s a) t x + +theorem isSuffix_splitLast [DecidableEq Symbol] {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) + (xs : List Symbol) : IsSuffix (splitLast flts s t xs) xs := by + induction xs generalizing s with + | nil => simp [splitLast] + | cons a xs ih => grind [splitLast] + +def splitLastCompl {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) : List Symbol → List Symbol + | [] => [] + | a :: x => if (splitLastCompl flts (flts.tr s a) t x = []) ∧ flts.tr s a ≠ t then [] + else a :: splitLastCompl flts (flts.tr s a) t x + +theorem splitLast_append [DecidableEq Symbol] {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) + (xs : List Symbol) : splitLastCompl flts s t xs ++ splitLast flts s t xs = xs := by + induction xs generalizing s with + | nil => grind [splitLast, splitLastCompl] + | cons a xs ih => + simp only [splitLast, splitLastCompl] + split_ifs with h h' h' + · simp + · grind [ih (s := flts.tr s a)] + · have := h'.1 ▸ ih (s := flts.tr s a) + simp at this + grind + · simpa using ih (s := flts.tr s a) + +theorem splitLast_eq [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} {s t : Fin n} + {xs : List Symbol} (h : t ∉ PathSupp flts s xs) (h' : t = flts.mtr s xs) : + splitLast flts s t xs = [] := by + induction xs generalizing s with + | nil => grind [splitLast, PathSupp] + | cons a xs ih => + by_cases hxs : xs = [] + · grind [splitLast, PathSupp] + rw [pathSupp_head hxs, Set.mem_union, Set.mem_singleton_iff] at h + grind [splitLast, (isSuffix_splitLast flts (flts.tr s a) t xs).length_le] + +theorem splitLastCompl_eq {n : ℕ} {flts : FLTS (Fin n) Symbol} {s t : Fin n} + {xs : List Symbol} (h : t ∉ PathSupp flts s xs) (h' : t = flts.mtr s xs) : + splitLastCompl flts s t xs = xs := by + classical + simpa [splitLast_eq h h'] using splitLast_append flts s t xs + +theorem splitLast_neq_iff_mem_PathSupp [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} + {s t : Fin n} {xs : List Symbol} (hxs : xs ≠ []) : + ¬(splitLast flts s t xs = xs) ↔ t ∈ PathSupp flts s xs ∨ t = flts.mtr s xs := by + induction xs generalizing s with + | nil => contradiction + | cons a xs ih => + by_cases hxs' : xs = [] + · grind [splitLast, PathSupp] + rw [pathSupp_head hxs', Set.mem_union, Set.mem_singleton_iff] + grind [splitLast, (isSuffix_splitLast flts (flts.tr s a) t xs).length_le] + +theorem splitLastCompl_nonempty_iff_mem_PathSupp {n : ℕ} {flts : FLTS (Fin n) Symbol} + {s t : Fin n} {xs : List Symbol} (hxs : xs ≠ []) : + ¬(splitLastCompl flts s t xs = []) ↔ t ∈ PathSupp flts s xs ∨ t = flts.mtr s xs := by + classical + rw [← splitLast_neq_iff_mem_PathSupp hxs, not_iff_not] + nth_rw 3 [← splitLast_append flts s t xs] + simp + +end splitLast + +/- +Regex i j k is the regex for the path from state i to state j passing through states < k. +When k = 0, i = j, the regex is ε union all characters from state i to state i. +When k = 0, i ≠ j, the regex is all characters from state i to state j. +For k + 1, the regex is the union of Regex i j k and +(Regex i k k) (Regex k k k)∗ (Regex k j k). +-/ +noncomputable def Regex [Fintype Symbol] {n : ℕ} (flts : FLTS (Fin n) Symbol) + (i j : Fin n) : ℕ → RegularExpression Symbol + | 0 => + let chars := (Finset.univ.filter + (fun x : Symbol ↦ flts.tr i x = j)).toList.map RegularExpression.char + if i = j then 1 + chars.sum else chars.sum + | k + 1 => + if h : n ≤ k then Regex flts i j k + else + let kFin : Fin n := ⟨k, by omega⟩ + Regex flts i j k + Regex flts i kFin k * (Regex flts kFin kFin k).star * Regex flts kFin j k + +end Cslib.Language diff --git a/Cslib/Computability/Languages/RegularLanguage.lean b/Cslib/Computability/Languages/RegularLanguage.lean index 3c363f2227..4c2802dbf9 100644 --- a/Cslib/Computability/Languages/RegularLanguage.lean +++ b/Cslib/Computability/Languages/RegularLanguage.lean @@ -261,12 +261,12 @@ theorem IsRegular.iff_dfa' {l : Language Symbol} : · intro ⟨n, dfa, h⟩ exact ⟨Fin n, inferInstance, dfa, h⟩ -/- -regex i j k is the regex for the path from state i to state j passing through states < k. +/-- +Regex i j k is the regex for the path from state i to state j passing through states < k. When k = 0, i = j, the regex is ε union all characters from state i to state i. When k = 0, i ≠ j, the regex is all characters from state i to state j. -For k + 1, the regex is the union of regex i j k and -regex i k k concat (regex k k k)^* concat regex k j k. +For k + 1, the regex is the union of Regex i j k and +(Regex i k k) (Regex k k k)∗ (Regex k j k). -/ noncomputable def Regex [Fintype Symbol] {n : ℕ} (flts : FLTS (Fin n) Symbol) (i j : Fin n) : ℕ → RegularExpression Symbol @@ -286,8 +286,10 @@ noncomputable def Regex [Fintype Symbol] {n : ℕ} (flts : FLTS (Fin n) Symbol) -- | nil (s : State) : Path s [] -- | cons (s u : State) (a : Symbol) (x : List Symbol) : Path (flts.tr s a) x → Path s (a :: x) +/-- PathSupp s xs is the set of states that can be reached from state s by reading the string xs, +not including the starting state and the ending state. -/ def PathSupp {State : Type*} (flts : FLTS State Symbol) : State → List Symbol → Set State - | _, [] | _, [_] => ∅ + | _, [] | _, [_] => ∅ | s, a :: x => {flts.tr s a} ∪ PathSupp flts (flts.tr s a) x lemma pathSupp_empty_iff_empty_or_char {State : Type*} {flts : FLTS State Symbol} {s : State} @@ -295,7 +297,7 @@ lemma pathSupp_empty_iff_empty_or_char {State : Type*} {flts : FLTS State Symbol match xs with | [] | [_] => grind [PathSupp] | x :: y :: ys => - have h1 : flts.tr s x ∈ PathSupp flts s (x :: y :: ys) := by grind [PathSupp] + have : flts.tr s x ∈ PathSupp flts s (x :: y :: ys) := by grind [PathSupp] grind lemma pathSupp_head {State : Type*} {flts : FLTS State Symbol} {s : State} @@ -315,18 +317,17 @@ lemma pathSupp_append {State : Type*} {flts : FLTS State Symbol} {s : State} · grind [PathSupp] · grind [pathSupp_head hx] -structure BoundedPath (n : ℕ) (Symbol : Type*) extends FLTS (Fin n) Symbol where +structure BddPath (n : ℕ) (Symbol : Type*) extends FLTS (Fin n) Symbol where start : Fin n finish : Fin n bound : ℕ -instance {n : ℕ} : Acceptor (BoundedPath n Symbol) Symbol where - Accepts (a : BoundedPath n Symbol) (xs : List Symbol) := +instance {n : ℕ} : Acceptor (BddPath n Symbol) Symbol where + Accepts (a : BddPath n Symbol) (xs : List Symbol) := a.mtr a.start xs = a.finish ∧ (∀ i ∈ PathSupp a.toFLTS a.start xs, i < a.bound) --- This is the original aux -lemma language_path_eq_dfa {n : ℕ} (flts : FLTS (Fin n) Symbol) (i j : Fin n) {k : ℕ} (hk : n ≤ k) : - language (BoundedPath.mk flts i j k) = +lemma language_bddpath_eq_dfa {n k : ℕ} (flts : FLTS (Fin n) Symbol) (i j : Fin n) (hk : n ≤ k) : + language (BddPath.mk flts i j k) = language (DA.FinAcc.mk {tr := flts.tr, start := i} {j}) := by ext xs simp only [mem_language, Accepts] @@ -348,27 +349,27 @@ lemma isSuffix_splitLast [DecidableEq Symbol] {n : ℕ} (flts : FLTS (Fin n) Sym | nil => simp [splitLast] | cons a xs ih => grind [splitLast] -noncomputable def splitLastCompl [DecidableEq Symbol] {n : ℕ} (flts : FLTS (Fin n) Symbol) - (s t : Fin n) (xs : List Symbol) : List Symbol := (isSuffix_splitLast flts s t xs).choose +-- noncomputable def splitLastCompl' [DecidableEq Symbol] {n : ℕ} (flts : FLTS (Fin n) Symbol) +-- (s t : Fin n) (xs : List Symbol) : List Symbol := (isSuffix_splitLast flts s t xs).choose -noncomputable def splitLastCompl' [DecidableEq Symbol] {n : ℕ} (flts : FLTS (Fin n) Symbol) +def splitLastCompl {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) : List Symbol → List Symbol | [] => [] - | a :: x => if (splitLastCompl' flts (flts.tr s a) t x = []) ∧ flts.tr s a ≠ t then [] - else a :: splitLastCompl' flts (flts.tr s a) t x + | a :: x => if (splitLastCompl flts (flts.tr s a) t x = []) ∧ flts.tr s a ≠ t then [] + else a :: splitLastCompl flts (flts.tr s a) t x + +-- lemma splitLast_append' [DecidableEq Symbol] {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) +-- (xs : List Symbol) : +-- splitLastCompl' flts s t xs ++ splitLast flts s t xs = xs := by +-- grind [splitLast, splitLastCompl'] lemma splitLast_append [DecidableEq Symbol] {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) (xs : List Symbol) : splitLastCompl flts s t xs ++ splitLast flts s t xs = xs := by - grind [splitLast, splitLastCompl] - -lemma splitLast_append' [DecidableEq Symbol] {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) - (xs : List Symbol) : - splitLastCompl' flts s t xs ++ splitLast flts s t xs = xs := by induction xs generalizing s with - | nil => grind [splitLast, splitLastCompl'] + | nil => grind [splitLast, splitLastCompl] | cons a xs ih => - simp only [splitLast, splitLastCompl'] + simp only [splitLast, splitLastCompl] split_ifs with h h' h' · simp · grind [ih (s := flts.tr s a)] @@ -377,50 +378,79 @@ lemma splitLast_append' [DecidableEq Symbol] {n : ℕ} (flts : FLTS (Fin n) Symb grind · simpa using ih (s := flts.tr s a) -lemma splitLast_neq_of_mem_PathSupp [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} - {s t : Fin n} {xs : List Symbol} (h : t ∈ PathSupp flts s xs) : - ¬(splitLast flts s t xs = xs) := by +-- Combine the following two lemmas into one lemma. +lemma splitLast_neq_iff_mem_PathSupp [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} + {s t : Fin n} {xs : List Symbol} (hxs : xs ≠ []) : + ¬(splitLast flts s t xs = xs) ↔ t ∈ PathSupp flts s xs ∨ t = flts.mtr s xs := by induction xs generalizing s with - | nil => grind [splitLast, PathSupp] + | nil => contradiction | cons a xs ih => - by_cases hxs : xs = [] + by_cases hxs' : xs = [] · grind [splitLast, PathSupp] - rw [pathSupp_head hxs, Set.mem_union, Set.mem_singleton_iff] at h + rw [pathSupp_head hxs', Set.mem_union, Set.mem_singleton_iff] grind [splitLast, (isSuffix_splitLast flts (flts.tr s a) t xs).length_le] -lemma mem_PathSupp_of_neq_splitLast [DecidableEq Symbol] {n : ℕ} - {flts : FLTS (Fin n) Symbol} {s t : Fin n} {xs : List Symbol} - (h : ¬(splitLast flts s t xs = xs)) : - t ∈ PathSupp flts s xs ∨ t = flts.mtr s xs := by - induction xs generalizing s with - | nil => contradiction - | cons a xs ih => - by_cases hxs : xs = [] <;> grind [splitLast, PathSupp] +-- lemma splitLast_neq_of_mem_PathSupp [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} +-- {s t : Fin n} {xs : List Symbol} (h : t ∈ PathSupp flts s xs) : +-- ¬(splitLast flts s t xs = xs) := by +-- induction xs generalizing s with +-- | nil => grind [splitLast, PathSupp] +-- | cons a xs ih => +-- by_cases hxs : xs = [] +-- · grind [splitLast, PathSupp] +-- rw [pathSupp_head hxs, Set.mem_union, Set.mem_singleton_iff] at h +-- grind [splitLast, (isSuffix_splitLast flts (flts.tr s a) t xs).length_le] + +-- lemma mem_PathSupp_of_neq_splitLast [DecidableEq Symbol] {n : ℕ} +-- {flts : FLTS (Fin n) Symbol} {s t : Fin n} {xs : List Symbol} +-- (h : ¬(splitLast flts s t xs = xs)) : +-- t ∈ PathSupp flts s xs ∨ t = flts.mtr s xs := by +-- induction xs generalizing s with +-- | nil => contradiction +-- | cons a xs ih => +-- by_cases hxs : xs = [] <;> grind [splitLast, PathSupp] -lemma splitLastCompl_eq [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} +lemma splitLast_eq [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} {s t : Fin n} {xs : List Symbol} (h : t ∉ PathSupp flts s xs) (h' : t = flts.mtr s xs) : - splitLastCompl' flts s t xs = xs := by + splitLast flts s t xs = [] := by induction xs generalizing s with - | nil => grind [splitLastCompl', PathSupp] + | nil => grind [splitLast, PathSupp] | cons a xs ih => by_cases hxs : xs = [] - · grind [splitLastCompl', PathSupp] + · grind [splitLast, PathSupp] rw [pathSupp_head hxs, Set.mem_union, Set.mem_singleton_iff] at h - grind [splitLastCompl', (isSuffix_splitLast flts (flts.tr s a) t xs).length_le] + grind [splitLast, (isSuffix_splitLast flts (flts.tr s a) t xs).length_le] + -- simpa [splitLastCompl_eq h h'] using splitLast_append flts s t xs -lemma splitLast_eq [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} +lemma splitLastCompl_eq {n : ℕ} {flts : FLTS (Fin n) Symbol} {s t : Fin n} {xs : List Symbol} (h : t ∉ PathSupp flts s xs) (h' : t = flts.mtr s xs) : - splitLast flts s t xs = [] := by - simpa [splitLastCompl_eq h h'] using splitLast_append' flts s t xs - -lemma mem_PathSupp_of_nonempty_splitLastCompl [DecidableEq Symbol] {n : ℕ} - {flts : FLTS (Fin n) Symbol} {s t : Fin n} {xs : List Symbol} - (h : ¬(splitLastCompl' flts s t xs = [])) : - t ∈ PathSupp flts s xs ∨ t = flts.mtr s xs := by - induction xs generalizing s with - | nil => contradiction - | cons a xs ih => - by_cases hxs : xs = [] <;> grind [splitLastCompl', PathSupp] + splitLastCompl flts s t xs = xs := by + classical + simpa [splitLast_eq h h'] using splitLast_append flts s t xs + -- induction xs generalizing s with + -- | nil => grind [splitLastCompl, PathSupp] + -- | cons a xs ih => + -- by_cases hxs : xs = [] + -- · grind [splitLastCompl, PathSupp] + -- rw [pathSupp_head hxs, Set.mem_union, Set.mem_singleton_iff] at h + -- grind [splitLastCompl, (isSuffix_splitLast flts (flts.tr s a) t xs).length_le] + +theorem splitLastCompl_nonempty_iff_mem_PathSupp {n : ℕ} {flts : FLTS (Fin n) Symbol} + {s t : Fin n} {xs : List Symbol} (hxs : xs ≠ []) : + ¬(splitLastCompl flts s t xs = []) ↔ t ∈ PathSupp flts s xs ∨ t = flts.mtr s xs := by + classical + rw [← splitLast_neq_iff_mem_PathSupp hxs, not_iff_not] + nth_rw 3 [← splitLast_append flts s t xs] + simp + +-- lemma mem_PathSupp_of_nonempty_splitLastCompl [DecidableEq Symbol] {n : ℕ} +-- {flts : FLTS (Fin n) Symbol} {s t : Fin n} {xs : List Symbol} +-- (h : ¬(splitLastCompl flts s t xs = [])) : +-- t ∈ PathSupp flts s xs ∨ t = flts.mtr s xs := by +-- induction xs generalizing s with +-- | nil => contradiction +-- | cons a xs ih => +-- by_cases hxs : xs = [] <;> grind [splitLastCompl, PathSupp] theorem mtr_head_eq {State Label : Type*} {flts : FLTS State Label} {s : State} {x : Label} {xs : List Label} : flts.mtr s (x :: xs) = flts.mtr (flts.tr s x) xs := by grind @@ -430,8 +460,8 @@ theorem mtr_append_eq {State Label : Type*} {flts : FLTS State Label} {s : State lemma splitLast_aux [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} {i j k : Fin n} {xs : List Symbol} {a : Symbol} - (h : a :: xs ∈ language (BoundedPath.mk flts i j (k.val + 1))) - (h' : a :: xs ∉ language (BoundedPath.mk flts i j k.val)) + (h : a :: xs ∈ language (BddPath.mk flts i j (k.val + 1))) + (h' : a :: xs ∉ language (BddPath.mk flts i j k.val)) (hc : splitLast flts (flts.tr i a) k xs = xs ∧ flts.tr i a ≠ k) : False := by simp only [mem_language, Accepts, Order.lt_add_one_iff, Fin.val_fin_le, Fin.val_fin_lt, not_and, not_forall, not_lt, ne_eq] at * @@ -448,12 +478,12 @@ lemma splitLast_aux [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} simp only [mem_singleton_iff] at hx1 symm at hx1 contradiction - · grind [splitLast_neq_of_mem_PathSupp hx2] + · grind [(splitLast_neq_iff_mem_PathSupp hxs).mpr (Or.inl hx2)] -lemma language_BoundedPath_head_iff {n : ℕ} {flts : FLTS (Fin n) Symbol} +lemma language_bddpath_head_iff {n : ℕ} {flts : FLTS (Fin n) Symbol} {i j : Fin n} {k : ℕ} {a : Symbol} {xs : List Symbol} : - a :: xs ∈ language (BoundedPath.mk flts i j k) ↔ - xs ∈ language (BoundedPath.mk flts (flts.tr i a) j k) ∧ (flts.tr i a < k ∨ xs = []) := by + a :: xs ∈ language (BddPath.mk flts i j k) ↔ + xs ∈ language (BddPath.mk flts (flts.tr i a) j k) ∧ (flts.tr i a < k ∨ xs = []) := by simp only [mem_language, Accepts] by_cases hxs : xs = [] · grind [PathSupp] @@ -461,9 +491,9 @@ lemma language_BoundedPath_head_iff {n : ℕ} {flts : FLTS (Fin n) Symbol} lemma splitLast_mem [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} {i j k : Fin n} {xs : List Symbol} - (h : xs ∈ language (BoundedPath.mk flts i j (k.val + 1))) - (h' : xs ∉ language (BoundedPath.mk flts i j k.val)) : - splitLast flts i k xs ∈ language (BoundedPath.mk flts k j k.val) := by + (h : xs ∈ language (BddPath.mk flts i j (k.val + 1))) + (h' : xs ∉ language (BddPath.mk flts i j k.val)) : + splitLast flts i k xs ∈ language (BddPath.mk flts k j k.val) := by induction xs generalizing i with | nil => simp [Accepts, PathSupp] at h h' @@ -478,7 +508,7 @@ lemma splitLast_mem [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} · by_cases hxs : xs = [] · grind [splitLast] -- First hypothesis of `ih` is implied by `h` - have haux := language_BoundedPath_head_iff.mp h + have haux := language_bddpath_head_iff.mp h simp only [hxs, or_false] at haux -- Assumptions `h` and `h'` combined says that `k ∈ PathSupp flts i (a :: xs)` by_cases hk : k ∈ PathSupp flts (flts.tr i a) xs @@ -491,60 +521,61 @@ lemma splitLast_mem [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} -- `hk` should contradict with `h` and `h'` -- use `mem_PathSupp_of_neq_splitLast` and `splitLast_eq` -- (Brooke do this second) - apply mem_PathSupp_of_neq_splitLast at hc1 + apply (splitLast_neq_iff_mem_PathSupp hxs).mp at hc1 simp_all [Accepts, PathSupp, splitLast_eq] · -- The last `k` is equal to `flts.tr i a` -- Cannot apply ih -- Directly prove the goal from definition -- (Brooke can do this last) - grind [language_BoundedPath_head_iff.mp h] + grind [language_bddpath_head_iff.mp h] -lemma splitLastCompl_mem [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} +lemma splitLastCompl_mem {n : ℕ} {flts : FLTS (Fin n) Symbol} {i j k : Fin n} {xs : List Symbol} - (h : xs ∈ language (BoundedPath.mk flts i j (k.val + 1))) - (h' : xs ∉ language (BoundedPath.mk flts i j k.val)) : - splitLastCompl' flts i k xs ∈ language (BoundedPath.mk flts i k (k.val + 1)) := by + (h : xs ∈ language (BddPath.mk flts i j (k.val + 1))) + (h' : xs ∉ language (BddPath.mk flts i j k.val)) : + splitLastCompl flts i k xs ∈ language (BddPath.mk flts i k (k.val + 1)) := by + classical induction xs generalizing i with | nil => simp [Accepts, PathSupp] at h h' contradiction | cons a xs ih => - simp only [splitLastCompl'] + simp only [splitLastCompl] split_ifs with hc - · exfalso; exact splitLast_aux h h' (by grind [splitLast_append']) + · exfalso; exact splitLast_aux h h' (by grind [splitLast_append]) · rw [not_and_or, not_not] at hc -- The last `k` is later than `flts.tr i a` or equal to it. - by_cases hc1 : ¬splitLastCompl' flts (flts.tr i a) k xs = [] + by_cases hc1 : ¬splitLastCompl flts (flts.tr i a) k xs = [] · by_cases hxs : xs = [] - · grind [splitLastCompl'] - have haux := language_BoundedPath_head_iff.mp h + · grind [splitLastCompl] + have haux := language_bddpath_head_iff.mp h simp only [hxs, or_false] at haux - refine language_BoundedPath_head_iff.mpr ⟨?_, Or.inl haux.2⟩ + refine language_bddpath_head_iff.mpr ⟨?_, Or.inl haux.2⟩ by_cases hk : k ∈ PathSupp flts (flts.tr i a) xs · apply ih haux.1 simp [Accepts] grind · have eq : k = flts.mtr (flts.tr i a) xs := by - simpa [hk] using (mem_PathSupp_of_nonempty_splitLastCompl hc1) + simpa [hk] using (splitLastCompl_nonempty_iff_mem_PathSupp hxs).mp hc1 rw [splitLastCompl_eq hk eq] simpa [← mtr_head_eq, eq, h.1] using haux.1 · rw [not_not] at hc1 simpa [hc1, Accepts, PathSupp, FLTS.mtr] using hc lemma path1 {n : ℕ} (flts : FLTS (Fin n) Symbol) (i j k : Fin n) : - language (BoundedPath.mk flts i j (k + 1)) = language (BoundedPath.mk flts i j k) + - (language (BoundedPath.mk flts i k (k + 1)) * language (BoundedPath.mk flts k j k)) := by + language (BddPath.mk flts i j (k + 1)) = language (BddPath.mk flts i j k) + + (language (BddPath.mk flts i k (k + 1)) * language (BddPath.mk flts k j k)) := by classical ext xs rw [Language.mem_add, Language.mem_mul] constructor · intro h - by_cases h' : xs ∈ language (BoundedPath.mk flts i j k) + by_cases h' : xs ∈ language (BddPath.mk flts i j k) · left; exact h' right - use splitLastCompl' flts i k xs, splitLastCompl_mem h h', + use splitLastCompl flts i k xs, splitLastCompl_mem h h', splitLast flts i k xs, splitLast_mem h h', - splitLast_append' flts _ _ _ + splitLast_append flts _ _ _ · rintro (h_left | ⟨ys, ⟨⟨hys, hsuppys⟩, ⟨zs, ⟨⟨hzs, hsuppzs⟩, happend⟩⟩⟩⟩) · simp only [mem_language, Accepts] at h_left ⊢ grind @@ -575,8 +606,8 @@ lemma splitFirst_append {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) (xs grind [splitFirst, splitFirstCompl] lemma splitFirst_mem {n : ℕ} {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : List Symbol} - (h : xs ∈ (language (BoundedPath.mk flts i k (k.val + 1)))) : - splitFirst flts i k xs ∈ language (BoundedPath.mk flts i k k.val) := by + (h : xs ∈ (language (BddPath.mk flts i k (k.val + 1)))) : + splitFirst flts i k xs ∈ language (BddPath.mk flts i k k.val) := by induction xs generalizing i with | nil => simpa [Accepts, splitFirst, PathSupp] using h | cons a xs ih => @@ -597,8 +628,8 @@ lemma splitFirst_mem {n : ℕ} {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : grind lemma splitFirst_mem' {n : ℕ} {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : List Symbol} - (hxs : xs ≠ []) (h : xs ∈ (language (BoundedPath.mk flts i k (k.val + 1)))) : - splitFirst flts i k xs ∈ language (BoundedPath.mk flts i k k.val) - 1 := by + (hxs : xs ≠ []) (h : xs ∈ (language (BddPath.mk flts i k (k.val + 1)))) : + splitFirst flts i k xs ∈ language (BddPath.mk flts i k k.val) - 1 := by rw [Language.mem_sub] refine ⟨splitFirst_mem h, ?_⟩ simp only [Language.mem_one] @@ -607,8 +638,8 @@ lemma splitFirst_mem' {n : ℕ} {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : | cons a xs ih => grind [splitFirst] lemma splitFirstCompl_mem {n : ℕ} {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : List Symbol} - (h : xs ∈ (language (BoundedPath.mk flts i k (k.val + 1)))) : - splitFirstCompl flts i k xs ∈ language (BoundedPath.mk flts k k (k.val + 1)) := by + (h : xs ∈ (language (BddPath.mk flts i k (k.val + 1)))) : + splitFirstCompl flts i k xs ∈ language (BddPath.mk flts k k (k.val + 1)) := by have h' := splitFirst_mem h simp only [mem_language, Accepts] at h h' ⊢ rw [← splitFirst_append flts i k xs, mtr_append_eq] at h @@ -618,8 +649,8 @@ lemma splitFirstCompl_mem {n : ℕ} {flts : FLTS (Fin n) Symbol} {i k : Fin n} { grind [pathSupp_append] lemma path2 {n : ℕ} (flts : FLTS (Fin n) Symbol) (i k : Fin n) : - language (BoundedPath.mk flts i k (k + 1)) = - language (BoundedPath.mk flts i k k) * language (BoundedPath.mk flts k k (k + 1)) := by + language (BddPath.mk flts i k (k + 1)) = + language (BddPath.mk flts i k k) * language (BddPath.mk flts k k (k + 1)) := by ext xs rw [Language.mem_mul] constructor @@ -641,8 +672,8 @@ lemma kstar_eq {α : Type*} (l : Language α) : l∗ = (l - 1)∗ := by fun ⟨S, ⟨hx, h⟩⟩ => ⟨S, hx, fun y ys => h y ys⟩⟩ lemma path3 {n : ℕ} (flts : FLTS (Fin n) Symbol) (k : Fin n) : - language (BoundedPath.mk flts k k (k + 1)) = (language (BoundedPath.mk flts k k k))∗ := by - rw [← mul_one (language (BoundedPath.mk flts k k ↑k))∗] + language (BddPath.mk flts k k (k + 1)) = (language (BddPath.mk flts k k k))∗ := by + rw [← mul_one (language (BddPath.mk flts k k ↑k))∗] rw [kstar_eq] refine (Language.self_eq_mul_add_iff (by simp [Language.mem_sub])).mp ?_ -- mimic the proof of path2 @@ -669,9 +700,9 @@ lemma path3 {n : ℕ} (flts : FLTS (Fin n) Symbol) (k : Fin n) : lemma set_aux {α : Type*} (A : Set α) : (∀ (i : α), i ∉ A) ↔ A = ∅ := by grind -theorem language_path_eq_regex [Fintype Symbol] {n k : ℕ} {i j : Fin n} +theorem language_bddpath_eq_regex [Fintype Symbol] {n k : ℕ} {i j : Fin n} {flts : FLTS (Fin n) Symbol} : - language (BoundedPath.mk flts i j k) = matches' (Regex flts i j k) := by + language (BddPath.mk flts i j k) = matches' (Regex flts i j k) := by induction k generalizing i j with | zero => ext xs @@ -687,13 +718,13 @@ theorem language_path_eq_regex [Fintype Symbol] {n k : ℕ} {i j : Fin n} | succ k ih => simp only [Regex] split_ifs with hk - · rw [← ih, language_path_eq_dfa flts i j hk, language_path_eq_dfa flts i j (by omega)] + · rw [← ih, language_bddpath_eq_dfa flts i j hk, language_bddpath_eq_dfa flts i j (by omega)] rw [path1 (k := ⟨k, by omega⟩), path2, path3] simp only [matches'_add, matches'_mul, matches'_star] grind lemma aux {n : ℕ} {s : Fin n} {dfa : DA.FinAcc (Fin n) Symbol} (h : dfa.accept = {s}) : - language dfa = language (BoundedPath.mk dfa.toFLTS dfa.start s n) := by + language dfa = language (BddPath.mk dfa.toFLTS dfa.start s n) := by ext xs simp only [mem_language, Accepts] grind @@ -702,7 +733,7 @@ lemma aux {n : ℕ} {s : Fin n} {dfa : DA.FinAcc (Fin n) Symbol} (h : dfa.accept theorem acc_singleton [Fintype Symbol] {n : ℕ} {s : Fin n} {dfa : DA.FinAcc (Fin n) Symbol} (h : dfa.accept = {s}) : language dfa = matches' (Regex dfa.toFLTS dfa.start s n) := by rw [aux h] - exact language_path_eq_regex + exact language_bddpath_eq_regex /- Modified from Yi-Siong's PR: https://github.com/leanprover-community/mathlib4/pull/35600 -/ theorem matches'_sum (L : List (RegularExpression Symbol)) : From 7daf804c75de528fae00f9245dd9da2a2aa7de1e Mon Sep 17 00:00:00 2001 From: Chi-Yun Hsu Date: Tue, 1 Sep 2026 14:51:57 -0700 Subject: [PATCH 64/89] Discard use of mtr lemmas --- .../Languages/RegularLanguage.lean | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/Cslib/Computability/Languages/RegularLanguage.lean b/Cslib/Computability/Languages/RegularLanguage.lean index 4c2802dbf9..0049d8daeb 100644 --- a/Cslib/Computability/Languages/RegularLanguage.lean +++ b/Cslib/Computability/Languages/RegularLanguage.lean @@ -452,11 +452,11 @@ theorem splitLastCompl_nonempty_iff_mem_PathSupp {n : ℕ} {flts : FLTS (Fin n) -- | cons a xs ih => -- by_cases hxs : xs = [] <;> grind [splitLastCompl, PathSupp] -theorem mtr_head_eq {State Label : Type*} {flts : FLTS State Label} {s : State} - {x : Label} {xs : List Label} : flts.mtr s (x :: xs) = flts.mtr (flts.tr s x) xs := by grind +-- theorem mtr_head_eq {State Label : Type*} {flts : FLTS State Label} {s : State} +-- {x : Label} {xs : List Label} : flts.mtr s (x :: xs) = flts.mtr (flts.tr s x) xs := by grind -theorem mtr_append_eq {State Label : Type*} {flts : FLTS State Label} {s : State} - {xs ys : List Label} : flts.mtr s (xs ++ ys) = flts.mtr (flts.mtr s xs) ys := by grind +-- theorem mtr_append_eq {State Label : Type*} {flts : FLTS State Label} {s : State} +-- {xs ys : List Label} : flts.mtr s (xs ++ ys) = flts.mtr (flts.mtr s xs) ys := by grind lemma splitLast_aux [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} {i j k : Fin n} {xs : List Symbol} {a : Symbol} @@ -465,7 +465,7 @@ lemma splitLast_aux [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} (hc : splitLast flts (flts.tr i a) k xs = xs ∧ flts.tr i a ≠ k) : False := by simp only [mem_language, Accepts, Order.lt_add_one_iff, Fin.val_fin_le, Fin.val_fin_lt, not_and, not_forall, not_lt, ne_eq] at * - simp only [mtr_head_eq] at * + -- simp only [mtr_head_eq] at * simp only [h, forall_const] at h' obtain ⟨x, ⟨hx, hxk⟩⟩ := h' have eq := le_antisymm (h.2 x hx) hxk @@ -558,7 +558,8 @@ lemma splitLastCompl_mem {n : ℕ} {flts : FLTS (Fin n) Symbol} · have eq : k = flts.mtr (flts.tr i a) xs := by simpa [hk] using (splitLastCompl_nonempty_iff_mem_PathSupp hxs).mp hc1 rw [splitLastCompl_eq hk eq] - simpa [← mtr_head_eq, eq, h.1] using haux.1 + grind [h.1] + -- simpa [← mtr_head_eq, eq, h.1] using haux.1 · rw [not_not] at hc1 simpa [hc1, Accepts, PathSupp, FLTS.mtr] using hc @@ -642,8 +643,10 @@ lemma splitFirstCompl_mem {n : ℕ} {flts : FLTS (Fin n) Symbol} {i k : Fin n} { splitFirstCompl flts i k xs ∈ language (BddPath.mk flts k k (k.val + 1)) := by have h' := splitFirst_mem h simp only [mem_language, Accepts] at h h' ⊢ - rw [← splitFirst_append flts i k xs, mtr_append_eq] at h - refine ⟨by simpa [h'.1] using h.1, ?_⟩ + -- rw [← splitFirst_append flts i k xs, mtr_append_eq] at h + -- refine ⟨by simpa [h'.1] using h.1, ?_⟩ + rw [← splitFirst_append flts i k xs] at h + refine ⟨by grind, ?_⟩ by_cases splitFirst flts i k xs = [] ∨ splitFirstCompl flts i k xs = [] · grind [PathSupp] grind [pathSupp_append] From 1ad979df1f6434b35c26bb1212b5339e71c95521 Mon Sep 17 00:00:00 2001 From: Chi-Yun Hsu Date: Tue, 1 Sep 2026 17:50:23 -0700 Subject: [PATCH 65/89] Finished splitLast section I redefined splitLast as the complement of splitLastCompl. This is good because we do not need DecidableEq Symbol anymore --- .../Languages/KleeneAlgorithm.lean | 261 +++++++++++++++--- .../Languages/RegularLanguage.lean | 4 - 2 files changed, 215 insertions(+), 50 deletions(-) diff --git a/Cslib/Computability/Languages/KleeneAlgorithm.lean b/Cslib/Computability/Languages/KleeneAlgorithm.lean index 704ff78028..57f06b6ee6 100644 --- a/Cslib/Computability/Languages/KleeneAlgorithm.lean +++ b/Cslib/Computability/Languages/KleeneAlgorithm.lean @@ -94,79 +94,248 @@ open List -- variable [DecidableEq Symbol] -/-- The function `splitLast` sends a string to its shortest suffix starting at state `t`. -If the string ends at state `t`, then `splitLast` returns the empty string. +/-- The function `splitLastCompl` sends a string to its longest prefix ending at state `t`. +If the string ends at state `t`, then `splitLastCompl` returns the original string. If the string never passes through state `t` (starting state can be `t`), -then `splitLast` returns the original string. -/ -def splitLast [DecidableEq Symbol] {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) : - List Symbol → List Symbol - | [] => [] - | a :: x => if (splitLast flts (flts.tr s a) t x = x) ∧ flts.tr s a ≠ t then a :: x - else splitLast flts (flts.tr s a) t x - -theorem isSuffix_splitLast [DecidableEq Symbol] {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) - (xs : List Symbol) : IsSuffix (splitLast flts s t xs) xs := by - induction xs generalizing s with - | nil => simp [splitLast] - | cons a xs ih => grind [splitLast] - +then `splitLastCompl` returns the empty string. -/ def splitLastCompl {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) : List Symbol → List Symbol | [] => [] | a :: x => if (splitLastCompl flts (flts.tr s a) t x = []) ∧ flts.tr s a ≠ t then [] else a :: splitLastCompl flts (flts.tr s a) t x -theorem splitLast_append [DecidableEq Symbol] {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) - (xs : List Symbol) : splitLastCompl flts s t xs ++ splitLast flts s t xs = xs := by +theorem isPrefix_splitLastCompl {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) + (xs : List Symbol) : IsPrefix (splitLastCompl flts s t xs) xs := by induction xs generalizing s with - | nil => grind [splitLast, splitLastCompl] - | cons a xs ih => - simp only [splitLast, splitLastCompl] - split_ifs with h h' h' - · simp - · grind [ih (s := flts.tr s a)] - · have := h'.1 ▸ ih (s := flts.tr s a) - simp at this - grind - · simpa using ih (s := flts.tr s a) + | nil => simp [splitLastCompl] + | cons a xs ih => grind [splitLastCompl] -theorem splitLast_eq [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} {s t : Fin n} +/-- The function `splitLast` sends a string to its shortest suffix starting at state `t`. +If the string ends at state `t`, then `splitLast` returns the empty string. +If the string never passes through state `t` (starting state can be `t`), +then `splitLast` returns the original string. -/ +noncomputable def splitLast {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) + (xs : List Symbol) : List Symbol := (isPrefix_splitLastCompl flts s t xs).choose + +theorem splitLast_append {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) (xs : List Symbol) : + splitLastCompl flts s t xs ++ splitLast flts s t xs = xs := by + grind [splitLastCompl, splitLast] + +theorem splitLast_head {n : ℕ} {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : List Symbol} + {a : Symbol} : splitLast flts i k (a :: xs) = + (if splitLastCompl flts (flts.tr i a) k xs = [] ∧ flts.tr i a ≠ k then a :: xs + else splitLast flts (flts.tr i a) k xs) := by grind [splitLast, splitLastCompl] + +-- def splitLast' [DecidableEq Symbol] {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) : +-- List Symbol → List Symbol +-- | [] => [] +-- | a :: x => if (splitLast' flts (flts.tr s a) t x = x) ∧ flts.tr s a ≠ t then a :: x +-- else splitLast' flts (flts.tr s a) t x + +-- theorem isSuffix_splitLast' [DecidableEq Symbol] {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) +-- (xs : List Symbol) : IsSuffix (splitLast' flts s t xs) xs := by +-- induction xs generalizing s with +-- | nil => simp [splitLast'] +-- | cons a xs ih => grind [splitLast'] + +-- theorem splitLast_append' [DecidableEq Symbol] {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) +-- (xs : List Symbol) : splitLastCompl flts s t xs ++ splitLast' flts s t xs = xs := by +-- induction xs generalizing s with +-- | nil => grind [splitLast', splitLastCompl] +-- | cons a xs ih => +-- simp only [splitLast', splitLastCompl] +-- split_ifs with h h' h' +-- · simp +-- · grind [ih (s := flts.tr s a)] +-- · have := h'.1 ▸ ih (s := flts.tr s a) +-- simp at this +-- grind +-- · simpa using ih (s := flts.tr s a) + +-- theorem splitLast_eq' [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} {s t : Fin n} +-- {xs : List Symbol} (h : t ∉ PathSupp flts s xs) (h' : t = flts.mtr s xs) : +-- splitLast' flts s t xs = [] := by +-- induction xs generalizing s with +-- | nil => grind [splitLast', PathSupp] +-- | cons a xs ih => +-- by_cases hxs : xs = [] +-- · grind [splitLast', PathSupp] +-- rw [pathSupp_head hxs, Set.mem_union, Set.mem_singleton_iff] at h +-- grind [splitLast', (isSuffix_splitLast' flts (flts.tr s a) t xs).length_le] + +theorem splitLastCompl_eq {n : ℕ} {flts : FLTS (Fin n) Symbol} {s t : Fin n} {xs : List Symbol} (h : t ∉ PathSupp flts s xs) (h' : t = flts.mtr s xs) : - splitLast flts s t xs = [] := by + splitLastCompl flts s t xs = xs := by induction xs generalizing s with - | nil => grind [splitLast, PathSupp] + | nil => grind [splitLastCompl, PathSupp] | cons a xs ih => by_cases hxs : xs = [] - · grind [splitLast, PathSupp] + · grind [splitLastCompl, PathSupp] rw [pathSupp_head hxs, Set.mem_union, Set.mem_singleton_iff] at h - grind [splitLast, (isSuffix_splitLast flts (flts.tr s a) t xs).length_le] + grind [splitLastCompl, (isPrefix_splitLastCompl flts (flts.tr s a) t xs).length_le] + -- classical + -- simpa [splitLast_eq h h'] using splitLast_append flts s t xs -theorem splitLastCompl_eq {n : ℕ} {flts : FLTS (Fin n) Symbol} {s t : Fin n} - {xs : List Symbol} (h : t ∉ PathSupp flts s xs) (h' : t = flts.mtr s xs) : - splitLastCompl flts s t xs = xs := by - classical - simpa [splitLast_eq h h'] using splitLast_append flts s t xs +theorem splitLast_eq {n : ℕ} {flts : FLTS (Fin n) Symbol} + {s t : Fin n} {xs : List Symbol} (h : t ∉ PathSupp flts s xs) (h' : t = flts.mtr s xs) : + splitLast flts s t xs = [] := by + simpa [splitLastCompl_eq h h'] using splitLast_append flts s t xs + +-- theorem splitLast_neq_iff_mem_PathSupp' [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} +-- {s t : Fin n} {xs : List Symbol} (hxs : xs ≠ []) : +-- ¬(splitLast' flts s t xs = xs) ↔ t ∈ PathSupp flts s xs ∨ t = flts.mtr s xs := by +-- induction xs generalizing s with +-- | nil => contradiction +-- | cons a xs ih => +-- by_cases hxs' : xs = [] +-- · grind [splitLast', PathSupp] +-- rw [pathSupp_head hxs', Set.mem_union, Set.mem_singleton_iff] +-- grind [splitLast', (isSuffix_splitLast' flts (flts.tr s a) t xs).length_le] -theorem splitLast_neq_iff_mem_PathSupp [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} +theorem splitLastCompl_nonempty_iff_mem_PathSupp {n : ℕ} {flts : FLTS (Fin n) Symbol} {s t : Fin n} {xs : List Symbol} (hxs : xs ≠ []) : - ¬(splitLast flts s t xs = xs) ↔ t ∈ PathSupp flts s xs ∨ t = flts.mtr s xs := by + ¬(splitLastCompl flts s t xs = []) ↔ t ∈ PathSupp flts s xs ∨ t = flts.mtr s xs := by induction xs generalizing s with | nil => contradiction | cons a xs ih => by_cases hxs' : xs = [] - · grind [splitLast, PathSupp] + · grind [splitLastCompl, PathSupp] rw [pathSupp_head hxs', Set.mem_union, Set.mem_singleton_iff] - grind [splitLast, (isSuffix_splitLast flts (flts.tr s a) t xs).length_le] + grind [splitLastCompl, (isPrefix_splitLastCompl flts (flts.tr s a) t xs).length_le] + -- classical + -- rw [← splitLast_neq_iff_mem_PathSupp hxs, not_iff_not] + -- nth_rw 3 [← splitLast_append flts s t xs] + -- simp -theorem splitLastCompl_nonempty_iff_mem_PathSupp {n : ℕ} {flts : FLTS (Fin n) Symbol} +theorem splitLast_neq_iff_mem_PathSupp {n : ℕ} {flts : FLTS (Fin n) Symbol} {s t : Fin n} {xs : List Symbol} (hxs : xs ≠ []) : - ¬(splitLastCompl flts s t xs = []) ↔ t ∈ PathSupp flts s xs ∨ t = flts.mtr s xs := by - classical - rw [← splitLast_neq_iff_mem_PathSupp hxs, not_iff_not] - nth_rw 3 [← splitLast_append flts s t xs] + ¬(splitLast flts s t xs = xs) ↔ t ∈ PathSupp flts s xs ∨ t = flts.mtr s xs := by + rw [← splitLastCompl_nonempty_iff_mem_PathSupp hxs, not_iff_not] + nth_rw 2 [← splitLast_append flts s t xs] simp +theorem splitLastCompl_aux {n : ℕ} {flts : FLTS (Fin n) Symbol} + {i j k : Fin n} {xs : List Symbol} {a : Symbol} + (h : a :: xs ∈ language (BddPath.mk flts i j (k.val + 1))) + (h' : a :: xs ∉ language (BddPath.mk flts i j k.val)) + (hc : splitLastCompl flts (flts.tr i a) k xs = [] ∧ flts.tr i a ≠ k) : False := by + simp only [mem_language, Accepts, Order.lt_add_one_iff, Fin.val_fin_le, Fin.val_fin_lt, not_and, + not_forall, not_lt, ne_eq] at * + simp only [h, forall_const] at h' + obtain ⟨x, ⟨hx, hxk⟩⟩ := h' + have eq := le_antisymm (h.2 x hx) hxk + rw [eq] at hx + by_cases hxs : xs = [] + · grind [PathSupp] + rw [pathSupp_head hxs] at hx h + rcases hx with hx1 | hx2 + · have := hc.2 + simp only [Set.mem_singleton_iff] at hx1 + symm at hx1 + contradiction + · grind [(splitLastCompl_nonempty_iff_mem_PathSupp hxs).mpr (Or.inl hx2)] + +theorem splitLastCompl_mem {n : ℕ} {flts : FLTS (Fin n) Symbol} + {i j k : Fin n} {xs : List Symbol} + (h : xs ∈ language (BddPath.mk flts i j (k.val + 1))) + (h' : xs ∉ language (BddPath.mk flts i j k.val)) : + splitLastCompl flts i k xs ∈ language (BddPath.mk flts i k (k.val + 1)) := by + induction xs generalizing i with + | nil => + simp [Accepts, PathSupp] at h h' + contradiction + | cons a xs ih => + simp only [splitLastCompl] + split_ifs with hc + · exfalso; exact splitLastCompl_aux h h' hc + · rw [not_and_or, not_not] at hc + -- The last `k` is later than `flts.tr i a` or equal to it. + by_cases hc1 : ¬splitLastCompl flts (flts.tr i a) k xs = [] + · by_cases hxs : xs = [] + · grind [splitLastCompl] + have haux := language_bddpath_head_iff.mp h + simp only [hxs, or_false] at haux + refine language_bddpath_head_iff.mpr ⟨?_, Or.inl haux.2⟩ + by_cases hk : k ∈ PathSupp flts (flts.tr i a) xs + · apply ih haux.1 + simp [Accepts] + grind + · have eq : k = flts.mtr (flts.tr i a) xs := by + simpa [hk] using (splitLastCompl_nonempty_iff_mem_PathSupp hxs).mp hc1 + rw [splitLastCompl_eq hk eq] + grind [h.1] + -- simpa [← mtr_head_eq, eq, h.1] using haux.1 + · rw [not_not] at hc1 + simpa [hc1, Accepts, PathSupp, FLTS.mtr] using hc + +theorem splitLast_mem {n : ℕ} {flts : FLTS (Fin n) Symbol} + {i j k : Fin n} {xs : List Symbol} + (h : xs ∈ language (BddPath.mk flts i j (k.val + 1))) + (h' : xs ∉ language (BddPath.mk flts i j k.val)) : + splitLast flts i k xs ∈ language (BddPath.mk flts k j k.val) := by + induction xs generalizing i with + | nil => + simp [Accepts, PathSupp] at h h' + contradiction + | cons a xs ih => + have h'' := splitLastCompl_mem h h' + simp only [splitLastCompl] at h'' + rw [splitLast_head] + split_ifs with hc + · exfalso; exact splitLastCompl_aux h h' hc + · rw [not_and_or, not_not] at hc + -- The last `k` is later than `flts.tr i a` or equal to it. + by_cases hc1 : ¬splitLastCompl flts (flts.tr i a) k xs = [] + · by_cases hxs : xs = [] + · grind [splitLast] + -- First hypothesis of `ih` is implied by `h` + have haux := language_bddpath_head_iff.mp h + simp only [hxs, or_false] at haux + -- Assumptions `h` and `h'` combined says that `k ∈ PathSupp flts i (a :: xs)` + by_cases hk : k ∈ PathSupp flts (flts.tr i a) xs + · -- `k` appears in PathSupp + apply ih haux.1 + simp [Accepts] + grind + · -- `k` only appears at the end state + -- `hk` should contradict with `h` and `h'` + apply (splitLastCompl_nonempty_iff_mem_PathSupp hxs).mp at hc1 + simp_all [Accepts, PathSupp, splitLast_eq] + · -- The last `k` is equal to `flts.tr i a` + -- Cannot apply ih + -- Directly prove the goal from definition + simp only [mem_language, Accepts] at h ⊢ + by_cases hxs : xs = [] + · grind [splitLast_eq, PathSupp] + grind [splitLast_append, splitLastCompl_nonempty_iff_mem_PathSupp, pathSupp_head] + +-- The original path1 +theorem language_bddpath_splitLast {n : ℕ} (flts : FLTS (Fin n) Symbol) (i j k : Fin n) : + language (BddPath.mk flts i j (k + 1)) = language (BddPath.mk flts i j k) + + (language (BddPath.mk flts i k (k + 1)) * language (BddPath.mk flts k j k)) := by + ext xs + rw [Language.mem_add, Language.mem_mul] + constructor + · intro h + by_cases h' : xs ∈ language (BddPath.mk flts i j k) + · left; exact h' + right + use splitLastCompl flts i k xs, splitLastCompl_mem h h', + splitLast flts i k xs, splitLast_mem h h', + splitLast_append flts _ _ _ + · rintro (h_left | ⟨ys, ⟨⟨hys, hsuppys⟩, ⟨zs, ⟨⟨hzs, hsuppzs⟩, happend⟩⟩⟩⟩) + · simp only [mem_language, Accepts] at h_left ⊢ + grind + · refine ⟨by grind, ?_⟩ + by_cases ys = [] ∨ zs = [] + · grind + grind [pathSupp_append] + end splitLast +section splitFirst + +end splitFirst + /- Regex i j k is the regex for the path from state i to state j passing through states < k. When k = 0, i = j, the regex is ε union all characters from state i to state i. diff --git a/Cslib/Computability/Languages/RegularLanguage.lean b/Cslib/Computability/Languages/RegularLanguage.lean index 0049d8daeb..ed9bd5a100 100644 --- a/Cslib/Computability/Languages/RegularLanguage.lean +++ b/Cslib/Computability/Languages/RegularLanguage.lean @@ -514,19 +514,15 @@ lemma splitLast_mem [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} by_cases hk : k ∈ PathSupp flts (flts.tr i a) xs · -- `k` appears in PathSupp apply ih haux.1 - -- (Brooke do this first) simp [Accepts] grind · -- `k` only appears at the end state -- `hk` should contradict with `h` and `h'` - -- use `mem_PathSupp_of_neq_splitLast` and `splitLast_eq` - -- (Brooke do this second) apply (splitLast_neq_iff_mem_PathSupp hxs).mp at hc1 simp_all [Accepts, PathSupp, splitLast_eq] · -- The last `k` is equal to `flts.tr i a` -- Cannot apply ih -- Directly prove the goal from definition - -- (Brooke can do this last) grind [language_bddpath_head_iff.mp h] lemma splitLastCompl_mem {n : ℕ} {flts : FLTS (Fin n) Symbol} From f371d09f2183437d109f9b3e59925e2db1c29910 Mon Sep 17 00:00:00 2001 From: Chi-Yun Hsu Date: Tue, 1 Sep 2026 19:09:54 -0700 Subject: [PATCH 66/89] Finished kstar section. Regex is WIP --- .../Languages/KleeneAlgorithm.lean | 160 +++++++++++++++++- 1 file changed, 156 insertions(+), 4 deletions(-) diff --git a/Cslib/Computability/Languages/KleeneAlgorithm.lean b/Cslib/Computability/Languages/KleeneAlgorithm.lean index 57f06b6ee6..c4ced3112f 100644 --- a/Cslib/Computability/Languages/KleeneAlgorithm.lean +++ b/Cslib/Computability/Languages/KleeneAlgorithm.lean @@ -8,9 +8,9 @@ module public import Cslib.Computability.Automata.Acceptors.Acceptor public import Cslib.Computability.Automata.DA.Basic +public import Mathlib.Computability.Language public import Mathlib.Computability.RegularExpressions - /-! # Kleene's Algorithm -/ @@ -88,11 +88,9 @@ theorem language_bddpath_eq_dfa {n k : ℕ} (flts : FLTS (Fin n) Symbol) (i j : simp only [mem_language, Accepts] grind -section splitLast - open List --- variable [DecidableEq Symbol] +section splitLast /-- The function `splitLastCompl` sends a string to its longest prefix ending at state `t`. If the string ends at state `t`, then `splitLastCompl` returns the original string. @@ -334,8 +332,128 @@ end splitLast section splitFirst +/-- The function `splitFirst` sends a string to its shortest prefix ending at state `t`. +The string is empty if and only if its `splitFirst` is empty. +If the string never passes through state `t` (starting state can be `t`), +then `splitFirst` returns the original string. -/ +def splitFirst {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) : List Symbol → List Symbol + | [] => [] + | a :: x => if flts.tr s a = t then [a] else a :: splitFirst flts (flts.tr s a) t x + +lemma isPrefix_splitFirst {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) (xs : List Symbol) : + IsPrefix (splitFirst flts s t xs) xs := by + induction xs generalizing s with + | nil => simp [splitFirst] + | cons a xs ih => grind [splitFirst] + +noncomputable def splitFirstCompl {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) + (xs : List Symbol) : List Symbol := (isPrefix_splitFirst flts s t xs).choose + +lemma splitFirst_append {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) (xs : List Symbol) : + splitFirst flts s t xs ++ splitFirstCompl flts s t xs = xs := by + grind [splitFirst, splitFirstCompl] + +lemma splitFirst_mem {n : ℕ} {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : List Symbol} + (h : xs ∈ (language (BddPath.mk flts i k (k.val + 1)))) : + splitFirst flts i k xs ∈ language (BddPath.mk flts i k k.val) := by + induction xs generalizing i with + | nil => simpa [Accepts, splitFirst, PathSupp] using h + | cons a xs ih => + simp only [mem_language, Accepts, Order.lt_add_one_iff, splitFirst] at ih h ⊢ + obtain ⟨h1, h2⟩ := h + split_ifs with ha + · refine ⟨by grind, ?_⟩ + have : PathSupp flts i [a] = ∅ := by grind [PathSupp] + simp [this] + · have : flts.mtr i (a :: splitFirst flts (flts.tr i a) k xs) = + flts.mtr (flts.tr i a) (splitFirst flts (flts.tr i a) k xs) := by grind + by_cases hxs : xs = [] + · grind + rw [pathSupp_head hxs] at h2 + by_cases hPath : splitFirst flts (flts.tr i a) k xs = [] + · grind + rw [this, pathSupp_head hPath] + grind + +lemma splitFirst_mem' {n : ℕ} {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : List Symbol} + (hxs : xs ≠ []) (h : xs ∈ (language (BddPath.mk flts i k (k.val + 1)))) : + splitFirst flts i k xs ∈ language (BddPath.mk flts i k k.val) - 1 := by + rw [Language.mem_sub] + refine ⟨splitFirst_mem h, ?_⟩ + simp only [Language.mem_one] + induction xs with + | nil => contradiction + | cons a xs ih => grind [splitFirst] + +lemma splitFirstCompl_mem {n : ℕ} {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : List Symbol} + (h : xs ∈ (language (BddPath.mk flts i k (k.val + 1)))) : + splitFirstCompl flts i k xs ∈ language (BddPath.mk flts k k (k.val + 1)) := by + have h' := splitFirst_mem h + simp only [mem_language, Accepts] at h h' ⊢ + rw [← splitFirst_append flts i k xs] at h + refine ⟨by grind, ?_⟩ + by_cases splitFirst flts i k xs = [] ∨ splitFirstCompl flts i k xs = [] + · grind [PathSupp] + grind [pathSupp_append] + +-- The original path2 +lemma language_bddpath_splitFirst {n : ℕ} (flts : FLTS (Fin n) Symbol) (i k : Fin n) : + language (BddPath.mk flts i k (k + 1)) = + language (BddPath.mk flts i k k) * language (BddPath.mk flts k k (k + 1)) := by + ext xs + rw [Language.mem_mul] + constructor + · intro h + use splitFirst flts i k xs, splitFirst_mem h, + splitFirstCompl flts i k xs, splitFirstCompl_mem h, + splitFirst_append flts _ _ _ + · intro ⟨ys, ⟨⟨hys, hsuppys⟩, ⟨zs, ⟨⟨hzs, hsuppzs⟩, happend⟩⟩⟩⟩ + refine ⟨by grind, ?_⟩ + by_cases ys = [] ∨ zs = [] + · grind + grind [pathSupp_append] + end splitFirst +section kstar + +open Computability + +lemma kstar_eq {α : Type*} (l : Language α) : l∗ = (l - 1)∗ := by + ext x + rw [Language.kstar_def_nonempty, Language.mem_kstar] + exact ⟨fun ⟨S, hx, h⟩ => ⟨S, ⟨hx, fun y ys => h y ys⟩⟩, + fun ⟨S, ⟨hx, h⟩⟩ => ⟨S, hx, fun y ys => h y ys⟩⟩ + +lemma language_bddpath_kstar {n : ℕ} (flts : FLTS (Fin n) Symbol) (k : Fin n) : + language (BddPath.mk flts k k (k + 1)) = (language (BddPath.mk flts k k k))∗ := by + rw [← mul_one (language (BddPath.mk flts k k ↑k))∗] + rw [kstar_eq] + refine (Language.self_eq_mul_add_iff (by simp [Language.mem_sub])).mp ?_ + -- mimic the proof of path2 + ext xs + simp only [Language.mem_add, Language.mem_mul, Language.mem_sub] + constructor + · intro h + by_cases h' : xs ∈ (1 : Language Symbol) + · grind + left + use splitFirst flts k k xs, splitFirst_mem' h' h, + splitFirstCompl flts k k xs, splitFirstCompl_mem h, + splitFirst_append flts _ _ _ + · rintro (⟨ys, ⟨⟨⟨hys, hsuppys⟩, hysnotempty⟩, ⟨zs, ⟨⟨hzs, hsuppzs⟩, happend⟩⟩⟩⟩ | hempty) + · refine ⟨by grind, ?_⟩ + by_cases zs = [] + · grind + rw [Language.mem_one] at hysnotempty + grind [pathSupp_append] + · rw [Language.mem_one] at hempty + simp only [mem_language, Accepts] + grind [PathSupp] + +end kstar + +open Computability /- Regex i j k is the regex for the path from state i to state j passing through states < k. When k = 0, i = j, the regex is ε union all characters from state i to state i. @@ -355,4 +473,38 @@ noncomputable def Regex [Fintype Symbol] {n : ℕ} (flts : FLTS (Fin n) Symbol) let kFin : Fin n := ⟨k, by omega⟩ Regex flts i j k + Regex flts i kFin k * (Regex flts kFin kFin k).star * Regex flts kFin j k +open RegularExpression + +variable {α : Type*} + +theorem mem_sum_matches'_iff (L : List (RegularExpression α)) (x : List α) : + x ∈ (L.sum).matches' ↔ ∃ P ∈ L, x ∈ P.matches' := by + induction L with + | nil => simp + | cons head tail ih => + simp only [sum_cons, matches', Language.mem_add, ih, mem_cons, exists_eq_or_imp] + +theorem language_bddpath_eq_regex [Fintype Symbol] {n k : ℕ} {i j : Fin n} + {flts : FLTS (Fin n) Symbol} : + language (BddPath.mk flts i j k) = (Regex flts i j k).matches' := by + induction k generalizing i j with + | zero => + ext xs + simp only [mem_language, Accepts, not_lt_zero, Regex] + rw [(by grind : (∀ i_1 ∈ PathSupp flts i xs, False) ↔ PathSupp flts i xs = ∅)] + split_ifs with heq + · -- The case of i = j, k = 0 + simp only [matches', Language.mem_add, mem_sum_matches'_iff, pathSupp_empty_iff_empty_or_char] + aesop + · -- The case of i ≠ j, k = 0 + rw [mem_sum_matches'_iff, pathSupp_empty_iff_empty_or_char] + aesop + | succ k ih => + simp only [Regex] + split_ifs with hk + · rw [← ih, language_bddpath_eq_dfa flts i j hk, language_bddpath_eq_dfa flts i j (by omega)] + rw [language_bddpath_splitLast (k := ⟨k, by omega⟩), language_bddpath_splitFirst, + language_bddpath_kstar] + grind [matches'_add, matches'_mul, matches'_star] + end Cslib.Language From d50678458f6a1950b4399639c8a08ecc84515101 Mon Sep 17 00:00:00 2001 From: Chi-Yun Hsu Date: Wed, 2 Sep 2026 15:51:51 -0700 Subject: [PATCH 67/89] Finish first round of proofreading --- .../Languages/KleeneAlgorithm.lean | 61 ++++++++--- .../Languages/RegularLanguage.lean | 102 ++++++++++++++---- 2 files changed, 125 insertions(+), 38 deletions(-) diff --git a/Cslib/Computability/Languages/KleeneAlgorithm.lean b/Cslib/Computability/Languages/KleeneAlgorithm.lean index c4ced3112f..dbc32f1885 100644 --- a/Cslib/Computability/Languages/KleeneAlgorithm.lean +++ b/Cslib/Computability/Languages/KleeneAlgorithm.lean @@ -84,8 +84,7 @@ theorem language_bddpath_head_iff {n k : ℕ} {flts : FLTS (Fin n) Symbol} {i j theorem language_bddpath_eq_dfa {n k : ℕ} (flts : FLTS (Fin n) Symbol) (i j : Fin n) (hk : n ≤ k) : language (BddPath.mk flts i j k) = language (DA.FinAcc.mk {tr := flts.tr, start := i} {j}) := by - ext xs - simp only [mem_language, Accepts] + simp [language, Accepts] grind open List @@ -453,7 +452,19 @@ lemma language_bddpath_kstar {n : ℕ} (flts : FLTS (Fin n) Symbol) (k : Fin n) end kstar -open Computability +open Computability RegularExpression +open scoped DA DA.FinAcc + +section Regex + +theorem mem_sum_matches'_iff {α : Type*} (L : List (RegularExpression α)) (x : List α) : + x ∈ (L.sum).matches' ↔ ∃ P ∈ L, x ∈ P.matches' := by + induction L with + | nil => simp + | cons head tail ih => + simp only [sum_cons, matches', Language.mem_add, ih, mem_cons, exists_eq_or_imp] + +variable [Fintype Symbol] /- Regex i j k is the regex for the path from state i to state j passing through states < k. When k = 0, i = j, the regex is ε union all characters from state i to state i. @@ -461,7 +472,7 @@ When k = 0, i ≠ j, the regex is all characters from state i to state j. For k + 1, the regex is the union of Regex i j k and (Regex i k k) (Regex k k k)∗ (Regex k j k). -/ -noncomputable def Regex [Fintype Symbol] {n : ℕ} (flts : FLTS (Fin n) Symbol) +noncomputable def Regex {n : ℕ} (flts : FLTS (Fin n) Symbol) (i j : Fin n) : ℕ → RegularExpression Symbol | 0 => let chars := (Finset.univ.filter @@ -473,19 +484,7 @@ noncomputable def Regex [Fintype Symbol] {n : ℕ} (flts : FLTS (Fin n) Symbol) let kFin : Fin n := ⟨k, by omega⟩ Regex flts i j k + Regex flts i kFin k * (Regex flts kFin kFin k).star * Regex flts kFin j k -open RegularExpression - -variable {α : Type*} - -theorem mem_sum_matches'_iff (L : List (RegularExpression α)) (x : List α) : - x ∈ (L.sum).matches' ↔ ∃ P ∈ L, x ∈ P.matches' := by - induction L with - | nil => simp - | cons head tail ih => - simp only [sum_cons, matches', Language.mem_add, ih, mem_cons, exists_eq_or_imp] - -theorem language_bddpath_eq_regex [Fintype Symbol] {n k : ℕ} {i j : Fin n} - {flts : FLTS (Fin n) Symbol} : +theorem language_bddpath_eq_regex {n k : ℕ} {flts : FLTS (Fin n) Symbol} {i j : Fin n} : language (BddPath.mk flts i j k) = (Regex flts i j k).matches' := by induction k generalizing i j with | zero => @@ -507,4 +506,32 @@ theorem language_bddpath_eq_regex [Fintype Symbol] {n k : ℕ} {i j : Fin n} language_bddpath_kstar] grind [matches'_add, matches'_mul, matches'_star] +/- IsRegular.iff_regex in the situation where the there is a single accepting state -/ +theorem language_dfa_eq_regex_of_singleton_accept {n : ℕ} {s : Fin n} + {dfa : DA.FinAcc (Fin n) Symbol} (h : dfa.accept = {s}) : + language dfa = (Regex dfa.toFLTS dfa.start s n).matches' := by + simp [← language_bddpath_eq_regex, language, Accepts, h] + rfl + +end Regex + +theorem regex_of_dfa_singleton_accept [Finite Symbol] {State : Type*} (h_fin : Finite State) + {dfa : DA.FinAcc State Symbol} {s : State} (h : dfa.accept = {s}) : + ∃ r : RegularExpression Symbol, language dfa = matches' r := by + have : Fintype State := Fintype.ofFinite State + let e := Fintype.equivFin State + set dfa' := DA.FinAcc.mk {tr := fun s a => e (dfa.tr (e.symm s) a), start := (e dfa.start)} {e s} + with hdfa' + have language_eq : language dfa = language dfa' := by + ext xs + have dfa_eq : dfa'.mtr dfa'.start xs = e (dfa.mtr dfa.start xs) := by + induction xs using List.reverseRec with + | nil => grind + | append_singleton xs x ih => grind + simp only [mem_language, Accepts, h, hdfa', Set.mem_singleton_iff] + rw [dfa_eq] + simp + have : Fintype Symbol := Fintype.ofFinite Symbol + simpa [language_eq] using ⟨_, language_dfa_eq_regex_of_singleton_accept (by dsimp)⟩ + end Cslib.Language diff --git a/Cslib/Computability/Languages/RegularLanguage.lean b/Cslib/Computability/Languages/RegularLanguage.lean index ed9bd5a100..6d1eb2cba8 100644 --- a/Cslib/Computability/Languages/RegularLanguage.lean +++ b/Cslib/Computability/Languages/RegularLanguage.lean @@ -14,6 +14,7 @@ public import Cslib.Computability.Automata.NA.Loop public import Cslib.Computability.Automata.NA.Reverse public import Cslib.Computability.Automata.NA.ToDA public import Cslib.Computability.Automata.Acceptors.Acceptor +-- public import Cslib.Computability.Languages.KleeneAlgorithm public import Mathlib.Computability.DFA public import Mathlib.Computability.RegularExpressions public import Mathlib.Data.Finite.Sum @@ -240,10 +241,10 @@ theorem IsRegular.regex {r : RegularExpression Symbol} : | star P hP => grind [RegularExpression.matches', IsRegular.kstar] /- We use Kleene's Algorithm for DFA to prove a regular language can be expressed as a regex. -/ -section RegularExpression open RegularExpression +-- We do not need this anymore -- Ask Chou whether to add reindex lemma for cslib DFA, -- rather than using reindex lemma for mathlib DFA. theorem IsRegular.iff_dfa' {l : Language Symbol} : @@ -722,20 +723,21 @@ theorem language_bddpath_eq_regex [Fintype Symbol] {n k : ℕ} {i j : Fin n} simp only [matches'_add, matches'_mul, matches'_star] grind -lemma aux {n : ℕ} {s : Fin n} {dfa : DA.FinAcc (Fin n) Symbol} (h : dfa.accept = {s}) : - language dfa = language (BddPath.mk dfa.toFLTS dfa.start s n) := by - ext xs - simp only [mem_language, Accepts] - grind +-- `aux` is almost the same as `language_bddpath_eq_dfa` +-- lemma aux {n : ℕ} {s : Fin n} {dfa : DA.FinAcc (Fin n) Symbol} (h : dfa.accept = {s}) : +-- language dfa = language (BddPath.mk dfa.toFLTS dfa.start s n) := by +-- ext xs +-- simp only [mem_language, Accepts] +-- grind /- IsRegular.iff_regex in the situation where the there is a single accepting state -/ theorem acc_singleton [Fintype Symbol] {n : ℕ} {s : Fin n} {dfa : DA.FinAcc (Fin n) Symbol} (h : dfa.accept = {s}) : language dfa = matches' (Regex dfa.toFLTS dfa.start s n) := by - rw [aux h] - exact language_bddpath_eq_regex + simp [← language_bddpath_eq_regex, language, Accepts, h] + rfl /- Modified from Yi-Siong's PR: https://github.com/leanprover-community/mathlib4/pull/35600 -/ -theorem matches'_sum (L : List (RegularExpression Symbol)) : +theorem matches'_sum' {α : Type*} (L : List (RegularExpression α)) : (L.sum).matches' = (L.map matches').sum := by induction L with | nil => simp @@ -744,7 +746,7 @@ theorem matches'_sum (L : List (RegularExpression Symbol)) : noncomputable instance {n : ℕ} (dfa : DA.FinAcc (Fin n) Symbol) : Fintype dfa.accept := Fintype.ofFinite dfa.accept -theorem language_sum {n : ℕ} {dfa : DA.FinAcc (Fin n) Symbol} : +theorem language_sum' {n : ℕ} {dfa : DA.FinAcc (Fin n) Symbol} : language dfa = (((dfa.accept.toFinset).sort (· ≤ ·)).map (fun s ↦ language {dfa with accept := {s}})).sum := by ext xs @@ -759,26 +761,84 @@ theorem language_sum {n : ℕ} {dfa : DA.FinAcc (Fin n) Symbol} : simp only [memsum, Finset.mem_sort, Set.mem_toFinset, mem_language] grind [Accepts] -theorem IsRegular.iff_regex [Finite Symbol] {l : Language Symbol} : +theorem IsRegular.iff_regex' [Finite Symbol] {l : Language Symbol} : l.IsRegular ↔ ∃ r : RegularExpression Symbol, l = matches' r := by refine ⟨fun h => ?_, fun ⟨r, hr⟩ => hr ▸ IsRegular.regex⟩ obtain ⟨n, dfa, rfl⟩ := Cslib.Language.IsRegular.iff_dfa'.mp h set acc_List : List (Fin n) := (dfa.accept.toFinset).sort (· ≤ ·) with h_acc - rw [language_sum] + rw [language_sum'] let : Fintype Symbol := Fintype.ofFinite Symbol let regex := (acc_List.map (fun i => Regex dfa.toFLTS (dfa.start) i n)).sum use regex - simp only [matches'_sum, regex] + simp only [matches'_sum', regex] apply congrArg rw [← h_acc, List.map_map] - simp only [map_inj_left, Function.comp_apply] - suffices h : - (fun s => language {dfa with accept := {s}}) = - (fun i => matches' (Regex dfa.toFLTS dfa.start i n)) by exact fun i hi ↦ congrFun h i - funext s - exact acc_singleton rfl - -end RegularExpression + simp only [map_inj_left] + have (s : Fin n) : language {dfa with accept := {s}} = + matches' (Regex dfa.toFLTS dfa.start s n) := acc_singleton rfl + exact fun s hs ↦ congrFun (funext this) s + +-- Adding this theorem from KleeneAlgorithm.lean before correcting import +theorem regex_of_dfa_singleton_accept [Finite Symbol] {State : Type*} [Finite State] + (dfa : DA.FinAcc State Symbol) (h : ∃ s, dfa.accept = {s}) : + ∃ r : RegularExpression Symbol, language dfa = matches' r := by + have : Fintype State := Fintype.ofFinite State + let e := Fintype.equivFin State + obtain ⟨s, h⟩ := h + set dfa' := DA.FinAcc.mk {tr := fun s a => e (dfa.tr (e.symm s) a), start := (e dfa.start)} {e s} + with hdfa' + have language_eq : language dfa = language dfa' := by + ext xs + have dfa_eq : dfa'.mtr dfa'.start xs = e (dfa.mtr dfa.start xs) := by + induction xs using List.reverseRec with + | nil => grind + | append_singleton xs x ih => grind + simp only [mem_language, Accepts, h, hdfa', Set.mem_singleton_iff] + rw [dfa_eq] + simp + have : Fintype Symbol := Fintype.ofFinite Symbol + simpa [language_eq] using ⟨_, acc_singleton (by dsimp)⟩ + +/-- We will only retain the following codes in `RegularLanguage.lean` at the end. -/ +theorem matches'_sum {α : Type*} (L : List (RegularExpression α)) : + (L.sum).matches' = (L.map matches').sum := by + induction L with + | nil => simp + | cons b L' ih => simp [ih] + +noncomputable instance {State : Type*} [Fintype State] (dfa : DA.FinAcc State Symbol) : + Fintype dfa.accept := Fintype.ofFinite dfa.accept + +theorem language_sum {State : Type*} [Fintype State] {dfa : DA.FinAcc State Symbol} : + language dfa = (((dfa.accept.toFinset).toList).map + (fun s ↦ language {dfa with accept := {s}})).sum := by + ext xs + simp only [mem_language] + have memsum (l : List State) : xs ∈ (l.map (fun s ↦ language {dfa with accept := {s}})).sum + ↔ ∃ s ∈ l, xs ∈ language {dfa with accept := {s}} := by + induction l with + | nil => simp + | cons a l ih => + simp only [List.map_cons, List.sum_cons, Language.mem_add, List.mem_cons, ih] + grind + rw [memsum] + simp [Accepts] + +theorem IsRegular.iff_regex [Finite Symbol] {l : Language Symbol} : + l.IsRegular ↔ ∃ r : RegularExpression Symbol, l = matches' r := by + refine ⟨fun h => ?_, fun ⟨r, hr⟩ => hr ▸ IsRegular.regex⟩ + obtain ⟨State, _, dfa, rfl⟩ := Cslib.Language.IsRegular.iff_dfa.mp h + have : Fintype State := Fintype.ofFinite State + rw [language_sum] + have : Fintype Symbol := Fintype.ofFinite Symbol + let regex := (dfa.accept.toFinset.toList.map + (fun s => (regex_of_dfa_singleton_accept {dfa with accept := {s}} (by simp)).choose)).sum + use regex + simp only [matches'_sum, regex] + apply congrArg List.sum + have (s : State) := + (regex_of_dfa_singleton_accept (dfa := {dfa with accept := {s}}) (by simp)).choose_spec + simpa using fun s hs ↦ congrFun (funext this) s end Cslib.Language From 50bcb62e7a76a91ed7063417baea5bec8c9c689d Mon Sep 17 00:00:00 2001 From: Chi-Yun Hsu Date: Wed, 2 Sep 2026 16:28:53 -0700 Subject: [PATCH 68/89] Minor notational changes --- .../Languages/KleeneAlgorithm.lean | 195 +++++++++--------- .../Languages/RegularLanguage.lean | 2 +- 2 files changed, 97 insertions(+), 100 deletions(-) diff --git a/Cslib/Computability/Languages/KleeneAlgorithm.lean b/Cslib/Computability/Languages/KleeneAlgorithm.lean index dbc32f1885..62fbdfca67 100644 --- a/Cslib/Computability/Languages/KleeneAlgorithm.lean +++ b/Cslib/Computability/Languages/KleeneAlgorithm.lean @@ -61,6 +61,8 @@ end PathSupp open Automata Acceptor +variable {n : ℕ} + /-- A Bounded Path (`BddPath`) has states `Fin n` and accepts strings (lists of symbols) starting with state `start` and ending with state `finish` with the intermediate states less than `bound`. -/ @@ -69,12 +71,12 @@ structure BddPath (n : ℕ) (Symbol : Type*) extends FLTS (Fin n) Symbol where finish : Fin n bound : ℕ -instance {n : ℕ} : Acceptor (BddPath n Symbol) Symbol where - Accepts (a : BddPath n Symbol) (xs : List Symbol) := - a.mtr a.start xs = a.finish ∧ (∀ i ∈ PathSupp a.toFLTS a.start xs, i < a.bound) +instance : Acceptor (BddPath n Symbol) Symbol where + Accepts (p : BddPath n Symbol) (xs : List Symbol) := + p.mtr p.start xs = p.finish ∧ (∀ i ∈ PathSupp p.toFLTS p.start xs, i < p.bound) -theorem language_bddpath_head_iff {n k : ℕ} {flts : FLTS (Fin n) Symbol} {i j : Fin n} - {a : Symbol} {xs : List Symbol} : +theorem language_bddpath_head_iff {flts : FLTS (Fin n) Symbol} {i j : Fin n} {k : ℕ} + {a : Symbol} {xs : List Symbol} : a :: xs ∈ language (BddPath.mk flts i j k) ↔ xs ∈ language (BddPath.mk flts (flts.tr i a) j k) ∧ (flts.tr i a < k ∨ xs = []) := by simp only [mem_language, Accepts] @@ -82,7 +84,7 @@ theorem language_bddpath_head_iff {n k : ℕ} {flts : FLTS (Fin n) Symbol} {i j · grind [PathSupp] grind [pathSupp_head hxs] -theorem language_bddpath_eq_dfa {n k : ℕ} (flts : FLTS (Fin n) Symbol) (i j : Fin n) (hk : n ≤ k) : +theorem language_bddpath_eq_dfa (flts : FLTS (Fin n) Symbol) (i j : Fin n) {k : ℕ} (hk : n ≤ k) : language (BddPath.mk flts i j k) = language (DA.FinAcc.mk {tr := flts.tr, start := i} {j}) := by simp [language, Accepts] grind @@ -91,34 +93,36 @@ open List section splitLast -/-- The function `splitLastCompl` sends a string to its longest prefix ending at state `t`. -If the string ends at state `t`, then `splitLastCompl` returns the original string. -If the string never passes through state `t` (starting state can be `t`), +/-- Starting at state `i`, the function `splitLastCompl` sends a string to its longest prefix +ending at state `k`. +If the string ends at state `k`, then `splitLastCompl` returns the original string. +If the string never passes through state `k` (starting state can be `k`), then `splitLastCompl` returns the empty string. -/ -def splitLastCompl {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) : List Symbol → List Symbol +def splitLastCompl (flts : FLTS (Fin n) Symbol) (i k : Fin n) : List Symbol → List Symbol | [] => [] - | a :: x => if (splitLastCompl flts (flts.tr s a) t x = []) ∧ flts.tr s a ≠ t then [] - else a :: splitLastCompl flts (flts.tr s a) t x + | a :: x => if (splitLastCompl flts (flts.tr i a) k x = []) ∧ flts.tr i a ≠ k then [] + else a :: splitLastCompl flts (flts.tr i a) k x -theorem isPrefix_splitLastCompl {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) - (xs : List Symbol) : IsPrefix (splitLastCompl flts s t xs) xs := by - induction xs generalizing s with +theorem isPrefix_splitLastCompl (flts : FLTS (Fin n) Symbol) (i k : Fin n) (xs : List Symbol) : + IsPrefix (splitLastCompl flts i k xs) xs := by + induction xs generalizing i with | nil => simp [splitLastCompl] | cons a xs ih => grind [splitLastCompl] -/-- The function `splitLast` sends a string to its shortest suffix starting at state `t`. -If the string ends at state `t`, then `splitLast` returns the empty string. -If the string never passes through state `t` (starting state can be `t`), +/-- Starting at state `i`, the function `splitLast` sends a string to its shortest suffix +starting at state `k`. +If the string ends at state `k`, then `splitLast` returns the empty string. +If the string never passes through state `k` (starting state can be `k`), then `splitLast` returns the original string. -/ -noncomputable def splitLast {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) - (xs : List Symbol) : List Symbol := (isPrefix_splitLastCompl flts s t xs).choose +noncomputable def splitLast (flts : FLTS (Fin n) Symbol) (i k : Fin n) (xs : List Symbol) : + List Symbol := (isPrefix_splitLastCompl flts i k xs).choose -theorem splitLast_append {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) (xs : List Symbol) : - splitLastCompl flts s t xs ++ splitLast flts s t xs = xs := by +theorem splitLast_append (flts : FLTS (Fin n) Symbol) (i k : Fin n) (xs : List Symbol) : + splitLastCompl flts i k xs ++ splitLast flts i k xs = xs := by grind [splitLastCompl, splitLast] -theorem splitLast_head {n : ℕ} {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : List Symbol} - {a : Symbol} : splitLast flts i k (a :: xs) = +theorem splitLast_head (flts : FLTS (Fin n) Symbol) (i k : Fin n) (xs : List Symbol) + (a : Symbol) : splitLast flts i k (a :: xs) = (if splitLastCompl flts (flts.tr i a) k xs = [] ∧ flts.tr i a ≠ k then a :: xs else splitLast flts (flts.tr i a) k xs) := by grind [splitLast, splitLastCompl] @@ -159,23 +163,21 @@ theorem splitLast_head {n : ℕ} {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs -- rw [pathSupp_head hxs, Set.mem_union, Set.mem_singleton_iff] at h -- grind [splitLast', (isSuffix_splitLast' flts (flts.tr s a) t xs).length_le] -theorem splitLastCompl_eq {n : ℕ} {flts : FLTS (Fin n) Symbol} {s t : Fin n} - {xs : List Symbol} (h : t ∉ PathSupp flts s xs) (h' : t = flts.mtr s xs) : - splitLastCompl flts s t xs = xs := by - induction xs generalizing s with +theorem splitLastCompl_eq {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : List Symbol} + (h : k ∉ PathSupp flts i xs) (h' : k = flts.mtr i xs) : splitLastCompl flts i k xs = xs := by + induction xs generalizing i with | nil => grind [splitLastCompl, PathSupp] | cons a xs ih => by_cases hxs : xs = [] · grind [splitLastCompl, PathSupp] rw [pathSupp_head hxs, Set.mem_union, Set.mem_singleton_iff] at h - grind [splitLastCompl, (isPrefix_splitLastCompl flts (flts.tr s a) t xs).length_le] + grind [splitLastCompl, (isPrefix_splitLastCompl flts (flts.tr i a) k xs).length_le] -- classical -- simpa [splitLast_eq h h'] using splitLast_append flts s t xs -theorem splitLast_eq {n : ℕ} {flts : FLTS (Fin n) Symbol} - {s t : Fin n} {xs : List Symbol} (h : t ∉ PathSupp flts s xs) (h' : t = flts.mtr s xs) : - splitLast flts s t xs = [] := by - simpa [splitLastCompl_eq h h'] using splitLast_append flts s t xs +theorem splitLast_eq {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : List Symbol} + (h : k ∉ PathSupp flts i xs) (h' : k = flts.mtr i xs) : splitLast flts i k xs = [] := by + simpa [splitLastCompl_eq h h'] using splitLast_append flts i k xs -- theorem splitLast_neq_iff_mem_PathSupp' [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} -- {s t : Fin n} {xs : List Symbol} (hxs : xs ≠ []) : @@ -188,32 +190,31 @@ theorem splitLast_eq {n : ℕ} {flts : FLTS (Fin n) Symbol} -- rw [pathSupp_head hxs', Set.mem_union, Set.mem_singleton_iff] -- grind [splitLast', (isSuffix_splitLast' flts (flts.tr s a) t xs).length_le] -theorem splitLastCompl_nonempty_iff_mem_PathSupp {n : ℕ} {flts : FLTS (Fin n) Symbol} - {s t : Fin n} {xs : List Symbol} (hxs : xs ≠ []) : - ¬(splitLastCompl flts s t xs = []) ↔ t ∈ PathSupp flts s xs ∨ t = flts.mtr s xs := by - induction xs generalizing s with +theorem splitLastCompl_nonempty_iff_mem_PathSupp {flts : FLTS (Fin n) Symbol} {i k : Fin n} + {xs : List Symbol} (hxs : xs ≠ []) : + ¬(splitLastCompl flts i k xs = []) ↔ k ∈ PathSupp flts i xs ∨ k = flts.mtr i xs := by + induction xs generalizing i with | nil => contradiction | cons a xs ih => by_cases hxs' : xs = [] · grind [splitLastCompl, PathSupp] rw [pathSupp_head hxs', Set.mem_union, Set.mem_singleton_iff] - grind [splitLastCompl, (isPrefix_splitLastCompl flts (flts.tr s a) t xs).length_le] + grind [splitLastCompl, (isPrefix_splitLastCompl flts (flts.tr i a) k xs).length_le] -- classical -- rw [← splitLast_neq_iff_mem_PathSupp hxs, not_iff_not] -- nth_rw 3 [← splitLast_append flts s t xs] -- simp -theorem splitLast_neq_iff_mem_PathSupp {n : ℕ} {flts : FLTS (Fin n) Symbol} - {s t : Fin n} {xs : List Symbol} (hxs : xs ≠ []) : - ¬(splitLast flts s t xs = xs) ↔ t ∈ PathSupp flts s xs ∨ t = flts.mtr s xs := by +theorem splitLast_neq_iff_mem_PathSupp {flts : FLTS (Fin n) Symbol} {i k : Fin n} + {xs : List Symbol} (hxs : xs ≠ []) : + ¬(splitLast flts i k xs = xs) ↔ k ∈ PathSupp flts i xs ∨ k = flts.mtr i xs := by rw [← splitLastCompl_nonempty_iff_mem_PathSupp hxs, not_iff_not] - nth_rw 2 [← splitLast_append flts s t xs] + nth_rw 2 [← splitLast_append flts i k xs] simp -theorem splitLastCompl_aux {n : ℕ} {flts : FLTS (Fin n) Symbol} - {i j k : Fin n} {xs : List Symbol} {a : Symbol} - (h : a :: xs ∈ language (BddPath.mk flts i j (k.val + 1))) - (h' : a :: xs ∉ language (BddPath.mk flts i j k.val)) +theorem splitLastCompl_aux {flts : FLTS (Fin n) Symbol} {i j k : Fin n} {xs : List Symbol} + {a : Symbol} (h : a :: xs ∈ language (BddPath.mk flts i j (k + 1))) + (h' : a :: xs ∉ language (BddPath.mk flts i j k)) (hc : splitLastCompl flts (flts.tr i a) k xs = [] ∧ flts.tr i a ≠ k) : False := by simp only [mem_language, Accepts, Order.lt_add_one_iff, Fin.val_fin_le, Fin.val_fin_lt, not_and, not_forall, not_lt, ne_eq] at * @@ -231,11 +232,10 @@ theorem splitLastCompl_aux {n : ℕ} {flts : FLTS (Fin n) Symbol} contradiction · grind [(splitLastCompl_nonempty_iff_mem_PathSupp hxs).mpr (Or.inl hx2)] -theorem splitLastCompl_mem {n : ℕ} {flts : FLTS (Fin n) Symbol} - {i j k : Fin n} {xs : List Symbol} - (h : xs ∈ language (BddPath.mk flts i j (k.val + 1))) - (h' : xs ∉ language (BddPath.mk flts i j k.val)) : - splitLastCompl flts i k xs ∈ language (BddPath.mk flts i k (k.val + 1)) := by +theorem splitLastCompl_mem {flts : FLTS (Fin n) Symbol} {i j k : Fin n} {xs : List Symbol} + (h : xs ∈ language (BddPath.mk flts i j (k + 1))) + (h' : xs ∉ language (BddPath.mk flts i j k)) : + splitLastCompl flts i k xs ∈ language (BddPath.mk flts i k (k + 1)) := by induction xs generalizing i with | nil => simp [Accepts, PathSupp] at h h' @@ -260,15 +260,13 @@ theorem splitLastCompl_mem {n : ℕ} {flts : FLTS (Fin n) Symbol} simpa [hk] using (splitLastCompl_nonempty_iff_mem_PathSupp hxs).mp hc1 rw [splitLastCompl_eq hk eq] grind [h.1] - -- simpa [← mtr_head_eq, eq, h.1] using haux.1 · rw [not_not] at hc1 simpa [hc1, Accepts, PathSupp, FLTS.mtr] using hc -theorem splitLast_mem {n : ℕ} {flts : FLTS (Fin n) Symbol} - {i j k : Fin n} {xs : List Symbol} - (h : xs ∈ language (BddPath.mk flts i j (k.val + 1))) - (h' : xs ∉ language (BddPath.mk flts i j k.val)) : - splitLast flts i k xs ∈ language (BddPath.mk flts k j k.val) := by +theorem splitLast_mem {flts : FLTS (Fin n) Symbol} {i j k : Fin n} {xs : List Symbol} + (h : xs ∈ language (BddPath.mk flts i j (k + 1))) + (h' : xs ∉ language (BddPath.mk flts i j k)) : + splitLast flts i k xs ∈ language (BddPath.mk flts k j k) := by induction xs generalizing i with | nil => simp [Accepts, PathSupp] at h h' @@ -306,7 +304,7 @@ theorem splitLast_mem {n : ℕ} {flts : FLTS (Fin n) Symbol} grind [splitLast_append, splitLastCompl_nonempty_iff_mem_PathSupp, pathSupp_head] -- The original path1 -theorem language_bddpath_splitLast {n : ℕ} (flts : FLTS (Fin n) Symbol) (i j k : Fin n) : +theorem language_bddpath_splitLast (flts : FLTS (Fin n) Symbol) (i j k : Fin n) : language (BddPath.mk flts i j (k + 1)) = language (BddPath.mk flts i j k) + (language (BddPath.mk flts i k (k + 1)) * language (BddPath.mk flts k j k)) := by ext xs @@ -317,7 +315,7 @@ theorem language_bddpath_splitLast {n : ℕ} (flts : FLTS (Fin n) Symbol) (i j k · left; exact h' right use splitLastCompl flts i k xs, splitLastCompl_mem h h', - splitLast flts i k xs, splitLast_mem h h', + splitLast flts i k xs, splitLast_mem h h', splitLast_append flts _ _ _ · rintro (h_left | ⟨ys, ⟨⟨hys, hsuppys⟩, ⟨zs, ⟨⟨hzs, hsuppzs⟩, happend⟩⟩⟩⟩) · simp only [mem_language, Accepts] at h_left ⊢ @@ -331,30 +329,31 @@ end splitLast section splitFirst -/-- The function `splitFirst` sends a string to its shortest prefix ending at state `t`. +/-- Starting from a state `i`, the function `splitFirst` sends a string to its shortest prefix +ending at state `k`. The string is empty if and only if its `splitFirst` is empty. -If the string never passes through state `t` (starting state can be `t`), +If the string never passes through state `k` (starting state can be `k`), then `splitFirst` returns the original string. -/ -def splitFirst {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) : List Symbol → List Symbol +def splitFirst (flts : FLTS (Fin n) Symbol) (i k : Fin n) : List Symbol → List Symbol | [] => [] - | a :: x => if flts.tr s a = t then [a] else a :: splitFirst flts (flts.tr s a) t x + | a :: x => if flts.tr i a = k then [a] else a :: splitFirst flts (flts.tr i a) k x -lemma isPrefix_splitFirst {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) (xs : List Symbol) : - IsPrefix (splitFirst flts s t xs) xs := by - induction xs generalizing s with +theorem isPrefix_splitFirst (flts : FLTS (Fin n) Symbol) (i k : Fin n) (xs : List Symbol) : + IsPrefix (splitFirst flts i k xs) xs := by + induction xs generalizing i with | nil => simp [splitFirst] | cons a xs ih => grind [splitFirst] -noncomputable def splitFirstCompl {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) - (xs : List Symbol) : List Symbol := (isPrefix_splitFirst flts s t xs).choose +noncomputable def splitFirstCompl (flts : FLTS (Fin n) Symbol) (i k : Fin n) + (xs : List Symbol) : List Symbol := (isPrefix_splitFirst flts i k xs).choose -lemma splitFirst_append {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) (xs : List Symbol) : - splitFirst flts s t xs ++ splitFirstCompl flts s t xs = xs := by +theorem splitFirst_append (flts : FLTS (Fin n) Symbol) (i k : Fin n) (xs : List Symbol) : + splitFirst flts i k xs ++ splitFirstCompl flts i k xs = xs := by grind [splitFirst, splitFirstCompl] -lemma splitFirst_mem {n : ℕ} {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : List Symbol} - (h : xs ∈ (language (BddPath.mk flts i k (k.val + 1)))) : - splitFirst flts i k xs ∈ language (BddPath.mk flts i k k.val) := by +theorem splitFirst_mem {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : List Symbol} + (h : xs ∈ (language (BddPath.mk flts i k (k + 1)))) : + splitFirst flts i k xs ∈ language (BddPath.mk flts i k k) := by induction xs generalizing i with | nil => simpa [Accepts, splitFirst, PathSupp] using h | cons a xs ih => @@ -374,9 +373,9 @@ lemma splitFirst_mem {n : ℕ} {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : rw [this, pathSupp_head hPath] grind -lemma splitFirst_mem' {n : ℕ} {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : List Symbol} - (hxs : xs ≠ []) (h : xs ∈ (language (BddPath.mk flts i k (k.val + 1)))) : - splitFirst flts i k xs ∈ language (BddPath.mk flts i k k.val) - 1 := by +theorem splitFirst_mem_nonempty {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : List Symbol} + (hxs : xs ≠ []) (h : xs ∈ (language (BddPath.mk flts i k (k + 1)))) : + splitFirst flts i k xs ∈ language (BddPath.mk flts i k k) - 1 := by rw [Language.mem_sub] refine ⟨splitFirst_mem h, ?_⟩ simp only [Language.mem_one] @@ -384,9 +383,9 @@ lemma splitFirst_mem' {n : ℕ} {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : | nil => contradiction | cons a xs ih => grind [splitFirst] -lemma splitFirstCompl_mem {n : ℕ} {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : List Symbol} - (h : xs ∈ (language (BddPath.mk flts i k (k.val + 1)))) : - splitFirstCompl flts i k xs ∈ language (BddPath.mk flts k k (k.val + 1)) := by +theorem splitFirstCompl_mem {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : List Symbol} + (h : xs ∈ (language (BddPath.mk flts i k (k + 1)))) : + splitFirstCompl flts i k xs ∈ language (BddPath.mk flts k k (k + 1)) := by have h' := splitFirst_mem h simp only [mem_language, Accepts] at h h' ⊢ rw [← splitFirst_append flts i k xs] at h @@ -396,7 +395,7 @@ lemma splitFirstCompl_mem {n : ℕ} {flts : FLTS (Fin n) Symbol} {i k : Fin n} { grind [pathSupp_append] -- The original path2 -lemma language_bddpath_splitFirst {n : ℕ} (flts : FLTS (Fin n) Symbol) (i k : Fin n) : +theorem language_bddpath_splitFirst (flts : FLTS (Fin n) Symbol) (i k : Fin n) : language (BddPath.mk flts i k (k + 1)) = language (BddPath.mk flts i k k) * language (BddPath.mk flts k k (k + 1)) := by ext xs @@ -414,20 +413,19 @@ lemma language_bddpath_splitFirst {n : ℕ} (flts : FLTS (Fin n) Symbol) (i k : end splitFirst -section kstar - open Computability -lemma kstar_eq {α : Type*} (l : Language α) : l∗ = (l - 1)∗ := by +section kstar + +theorem kstar_eq {α : Type*} (l : Language α) : l∗ = (l - 1)∗ := by ext x rw [Language.kstar_def_nonempty, Language.mem_kstar] exact ⟨fun ⟨S, hx, h⟩ => ⟨S, ⟨hx, fun y ys => h y ys⟩⟩, fun ⟨S, ⟨hx, h⟩⟩ => ⟨S, hx, fun y ys => h y ys⟩⟩ -lemma language_bddpath_kstar {n : ℕ} (flts : FLTS (Fin n) Symbol) (k : Fin n) : +theorem language_bddpath_kstar (flts : FLTS (Fin n) Symbol) (k : Fin n) : language (BddPath.mk flts k k (k + 1)) = (language (BddPath.mk flts k k k))∗ := by - rw [← mul_one (language (BddPath.mk flts k k ↑k))∗] - rw [kstar_eq] + rw [← mul_one (language (BddPath.mk flts k k ↑k))∗, kstar_eq] refine (Language.self_eq_mul_add_iff (by simp [Language.mem_sub])).mp ?_ -- mimic the proof of path2 ext xs @@ -437,7 +435,7 @@ lemma language_bddpath_kstar {n : ℕ} (flts : FLTS (Fin n) Symbol) (k : Fin n) by_cases h' : xs ∈ (1 : Language Symbol) · grind left - use splitFirst flts k k xs, splitFirst_mem' h' h, + use splitFirst flts k k xs, splitFirst_mem_nonempty h' h, splitFirstCompl flts k k xs, splitFirstCompl_mem h, splitFirst_append flts _ _ _ · rintro (⟨ys, ⟨⟨⟨hys, hsuppys⟩, hysnotempty⟩, ⟨zs, ⟨⟨hzs, hsuppzs⟩, happend⟩⟩⟩⟩ | hempty) @@ -452,8 +450,7 @@ lemma language_bddpath_kstar {n : ℕ} (flts : FLTS (Fin n) Symbol) (k : Fin n) end kstar -open Computability RegularExpression -open scoped DA DA.FinAcc +open RegularExpression section Regex @@ -465,6 +462,7 @@ theorem mem_sum_matches'_iff {α : Type*} (L : List (RegularExpression α)) (x : simp only [sum_cons, matches', Language.mem_add, ih, mem_cons, exists_eq_or_imp] variable [Fintype Symbol] + /- Regex i j k is the regex for the path from state i to state j passing through states < k. When k = 0, i = j, the regex is ε union all characters from state i to state i. @@ -472,8 +470,7 @@ When k = 0, i ≠ j, the regex is all characters from state i to state j. For k + 1, the regex is the union of Regex i j k and (Regex i k k) (Regex k k k)∗ (Regex k j k). -/ -noncomputable def Regex {n : ℕ} (flts : FLTS (Fin n) Symbol) - (i j : Fin n) : ℕ → RegularExpression Symbol +noncomputable def Regex (flts : FLTS (Fin n) Symbol) (i j : Fin n) : ℕ → RegularExpression Symbol | 0 => let chars := (Finset.univ.filter (fun x : Symbol ↦ flts.tr i x = j)).toList.map RegularExpression.char @@ -484,7 +481,7 @@ noncomputable def Regex {n : ℕ} (flts : FLTS (Fin n) Symbol) let kFin : Fin n := ⟨k, by omega⟩ Regex flts i j k + Regex flts i kFin k * (Regex flts kFin kFin k).star * Regex flts kFin j k -theorem language_bddpath_eq_regex {n k : ℕ} {flts : FLTS (Fin n) Symbol} {i j : Fin n} : +theorem language_bddpath_eq_regex {k : ℕ} {flts : FLTS (Fin n) Symbol} {i j : Fin n} : language (BddPath.mk flts i j k) = (Regex flts i j k).matches' := by induction k generalizing i j with | zero => @@ -506,20 +503,20 @@ theorem language_bddpath_eq_regex {n k : ℕ} {flts : FLTS (Fin n) Symbol} {i j language_bddpath_kstar] grind [matches'_add, matches'_mul, matches'_star] -/- IsRegular.iff_regex in the situation where the there is a single accepting state -/ -theorem language_dfa_eq_regex_of_singleton_accept {n : ℕ} {s : Fin n} - {dfa : DA.FinAcc (Fin n) Symbol} (h : dfa.accept = {s}) : - language dfa = (Regex dfa.toFLTS dfa.start s n).matches' := by +-- The original `acc_singleton` +theorem language_dfa_eq_regex_of_singleton_accept {dfa : DA.FinAcc (Fin n) Symbol} {s : Fin n} + (h : dfa.accept = {s}) : language dfa = (Regex dfa.toFLTS dfa.start s n).matches' := by simp [← language_bddpath_eq_regex, language, Accepts, h] rfl end Regex -theorem regex_of_dfa_singleton_accept [Finite Symbol] {State : Type*} (h_fin : Finite State) - {dfa : DA.FinAcc State Symbol} {s : State} (h : dfa.accept = {s}) : - ∃ r : RegularExpression Symbol, language dfa = matches' r := by +theorem regex_of_dfa_singleton_accept [Finite Symbol] {State : Type*} [Finite State] + {dfa : DA.FinAcc State Symbol} (h : ∃ s, dfa.accept = {s}) : + ∃ r : RegularExpression Symbol, language dfa = r.matches' := by have : Fintype State := Fintype.ofFinite State let e := Fintype.equivFin State + obtain ⟨s, h⟩ := h set dfa' := DA.FinAcc.mk {tr := fun s a => e (dfa.tr (e.symm s) a), start := (e dfa.start)} {e s} with hdfa' have language_eq : language dfa = language dfa' := by diff --git a/Cslib/Computability/Languages/RegularLanguage.lean b/Cslib/Computability/Languages/RegularLanguage.lean index 6d1eb2cba8..e94ca98553 100644 --- a/Cslib/Computability/Languages/RegularLanguage.lean +++ b/Cslib/Computability/Languages/RegularLanguage.lean @@ -782,7 +782,7 @@ theorem IsRegular.iff_regex' [Finite Symbol] {l : Language Symbol} : -- Adding this theorem from KleeneAlgorithm.lean before correcting import theorem regex_of_dfa_singleton_accept [Finite Symbol] {State : Type*} [Finite State] (dfa : DA.FinAcc State Symbol) (h : ∃ s, dfa.accept = {s}) : - ∃ r : RegularExpression Symbol, language dfa = matches' r := by + ∃ r : RegularExpression Symbol, language dfa = r.matches' := by have : Fintype State := Fintype.ofFinite State let e := Fintype.equivFin State obtain ⟨s, h⟩ := h From 25d560813ecbefeee3ce81088b7e19983953a6af Mon Sep 17 00:00:00 2001 From: Chi-Yun Hsu Date: Wed, 2 Sep 2026 16:59:41 -0700 Subject: [PATCH 69/89] Typo --- Cslib/Computability/Languages/KleeneAlgorithm.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cslib/Computability/Languages/KleeneAlgorithm.lean b/Cslib/Computability/Languages/KleeneAlgorithm.lean index 62fbdfca67..d15bdf74fe 100644 --- a/Cslib/Computability/Languages/KleeneAlgorithm.lean +++ b/Cslib/Computability/Languages/KleeneAlgorithm.lean @@ -512,7 +512,7 @@ theorem language_dfa_eq_regex_of_singleton_accept {dfa : DA.FinAcc (Fin n) Symbo end Regex theorem regex_of_dfa_singleton_accept [Finite Symbol] {State : Type*} [Finite State] - {dfa : DA.FinAcc State Symbol} (h : ∃ s, dfa.accept = {s}) : + (dfa : DA.FinAcc State Symbol) (h : ∃ s, dfa.accept = {s}) : ∃ r : RegularExpression Symbol, language dfa = r.matches' := by have : Fintype State := Fintype.ofFinite State let e := Fintype.equivFin State From 111ea1f9cd7df25c799d32954b44b0f473393e52 Mon Sep 17 00:00:00 2001 From: Brooke Gill <96643991+brooke-gill@users.noreply.github.com> Date: Wed, 2 Sep 2026 18:37:10 -0700 Subject: [PATCH 70/89] Fold "rw/grind" into grind --- .../Languages/KleeneAlgorithm.lean | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/Cslib/Computability/Languages/KleeneAlgorithm.lean b/Cslib/Computability/Languages/KleeneAlgorithm.lean index d15bdf74fe..be6002a262 100644 --- a/Cslib/Computability/Languages/KleeneAlgorithm.lean +++ b/Cslib/Computability/Languages/KleeneAlgorithm.lean @@ -170,8 +170,8 @@ theorem splitLastCompl_eq {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : List | cons a xs ih => by_cases hxs : xs = [] · grind [splitLastCompl, PathSupp] - rw [pathSupp_head hxs, Set.mem_union, Set.mem_singleton_iff] at h - grind [splitLastCompl, (isPrefix_splitLastCompl flts (flts.tr i a) k xs).length_le] + grind [splitLastCompl, (isPrefix_splitLastCompl flts (flts.tr i a) k xs).length_le, + pathSupp_head hxs] -- classical -- simpa [splitLast_eq h h'] using splitLast_append flts s t xs @@ -198,8 +198,8 @@ theorem splitLastCompl_nonempty_iff_mem_PathSupp {flts : FLTS (Fin n) Symbol} {i | cons a xs ih => by_cases hxs' : xs = [] · grind [splitLastCompl, PathSupp] - rw [pathSupp_head hxs', Set.mem_union, Set.mem_singleton_iff] - grind [splitLastCompl, (isPrefix_splitLastCompl flts (flts.tr i a) k xs).length_le] + grind [splitLastCompl, (isPrefix_splitLastCompl flts (flts.tr i a) k xs).length_le, + pathSupp_head hxs'] -- classical -- rw [← splitLast_neq_iff_mem_PathSupp hxs, not_iff_not] -- nth_rw 3 [← splitLast_append flts s t xs] @@ -258,8 +258,7 @@ theorem splitLastCompl_mem {flts : FLTS (Fin n) Symbol} {i j k : Fin n} {xs : Li grind · have eq : k = flts.mtr (flts.tr i a) xs := by simpa [hk] using (splitLastCompl_nonempty_iff_mem_PathSupp hxs).mp hc1 - rw [splitLastCompl_eq hk eq] - grind [h.1] + grind [h.1, splitLastCompl_eq] · rw [not_not] at hc1 simpa [hc1, Accepts, PathSupp, FLTS.mtr] using hc @@ -370,8 +369,7 @@ theorem splitFirst_mem {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : List Sym rw [pathSupp_head hxs] at h2 by_cases hPath : splitFirst flts (flts.tr i a) k xs = [] · grind - rw [this, pathSupp_head hPath] - grind + grind [pathSupp_head] theorem splitFirst_mem_nonempty {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : List Symbol} (hxs : xs ≠ []) (h : xs ∈ (language (BddPath.mk flts i k (k + 1)))) : @@ -442,8 +440,7 @@ theorem language_bddpath_kstar (flts : FLTS (Fin n) Symbol) (k : Fin n) : · refine ⟨by grind, ?_⟩ by_cases zs = [] · grind - rw [Language.mem_one] at hysnotempty - grind [pathSupp_append] + grind [pathSupp_append, Language.mem_one] · rw [Language.mem_one] at hempty simp only [mem_language, Accepts] grind [PathSupp] From ed34707096b58db398df8f3f602c30f66abd9168 Mon Sep 17 00:00:00 2001 From: Brooke Gill <96643991+brooke-gill@users.noreply.github.com> Date: Wed, 2 Sep 2026 21:03:06 -0700 Subject: [PATCH 71/89] Fold "have"s into grind --- Cslib/Computability/Languages/KleeneAlgorithm.lean | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/Cslib/Computability/Languages/KleeneAlgorithm.lean b/Cslib/Computability/Languages/KleeneAlgorithm.lean index be6002a262..a8402a63fe 100644 --- a/Cslib/Computability/Languages/KleeneAlgorithm.lean +++ b/Cslib/Computability/Languages/KleeneAlgorithm.lean @@ -256,9 +256,8 @@ theorem splitLastCompl_mem {flts : FLTS (Fin n) Symbol} {i j k : Fin n} {xs : Li · apply ih haux.1 simp [Accepts] grind - · have eq : k = flts.mtr (flts.tr i a) xs := by - simpa [hk] using (splitLastCompl_nonempty_iff_mem_PathSupp hxs).mp hc1 - grind [h.1, splitLastCompl_eq] + · grind [h.1, splitLastCompl_eq, by + simpa [hk] using (splitLastCompl_nonempty_iff_mem_PathSupp hxs).mp hc1] · rw [not_not] at hc1 simpa [hc1, Accepts, PathSupp, FLTS.mtr] using hc @@ -362,9 +361,7 @@ theorem splitFirst_mem {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : List Sym · refine ⟨by grind, ?_⟩ have : PathSupp flts i [a] = ∅ := by grind [PathSupp] simp [this] - · have : flts.mtr i (a :: splitFirst flts (flts.tr i a) k xs) = - flts.mtr (flts.tr i a) (splitFirst flts (flts.tr i a) k xs) := by grind - by_cases hxs : xs = [] + · by_cases hxs : xs = [] · grind rw [pathSupp_head hxs] at h2 by_cases hPath : splitFirst flts (flts.tr i a) k xs = [] From bbe821ffc4f58f8496cef7df33fea39b83d2e568 Mon Sep 17 00:00:00 2001 From: Brooke Gill <96643991+brooke-gill@users.noreply.github.com> Date: Wed, 2 Sep 2026 21:48:42 -0700 Subject: [PATCH 72/89] Free golfs --- Cslib/Computability/Languages/KleeneAlgorithm.lean | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Cslib/Computability/Languages/KleeneAlgorithm.lean b/Cslib/Computability/Languages/KleeneAlgorithm.lean index a8402a63fe..a57515c6ea 100644 --- a/Cslib/Computability/Languages/KleeneAlgorithm.lean +++ b/Cslib/Computability/Languages/KleeneAlgorithm.lean @@ -119,7 +119,7 @@ noncomputable def splitLast (flts : FLTS (Fin n) Symbol) (i k : Fin n) (xs : Lis theorem splitLast_append (flts : FLTS (Fin n) Symbol) (i k : Fin n) (xs : List Symbol) : splitLastCompl flts i k xs ++ splitLast flts i k xs = xs := by - grind [splitLastCompl, splitLast] + grind [splitLast] theorem splitLast_head (flts : FLTS (Fin n) Symbol) (i k : Fin n) (xs : List Symbol) (a : Symbol) : splitLast flts i k (a :: xs) = @@ -216,8 +216,8 @@ theorem splitLastCompl_aux {flts : FLTS (Fin n) Symbol} {i j k : Fin n} {xs : Li {a : Symbol} (h : a :: xs ∈ language (BddPath.mk flts i j (k + 1))) (h' : a :: xs ∉ language (BddPath.mk flts i j k)) (hc : splitLastCompl flts (flts.tr i a) k xs = [] ∧ flts.tr i a ≠ k) : False := by - simp only [mem_language, Accepts, Order.lt_add_one_iff, Fin.val_fin_le, Fin.val_fin_lt, not_and, - not_forall, not_lt, ne_eq] at * + simp only [mem_language, Accepts, Order.lt_add_one_iff, Fin.val_fin_le, not_and, + not_forall, not_lt] at * simp only [h, forall_const] at h' obtain ⟨x, ⟨hx, hxk⟩⟩ := h' have eq := le_antisymm (h.2 x hx) hxk @@ -271,7 +271,6 @@ theorem splitLast_mem {flts : FLTS (Fin n) Symbol} {i j k : Fin n} {xs : List Sy contradiction | cons a xs ih => have h'' := splitLastCompl_mem h h' - simp only [splitLastCompl] at h'' rw [splitLast_head] split_ifs with hc · exfalso; exact splitLastCompl_aux h h' hc @@ -282,7 +281,6 @@ theorem splitLast_mem {flts : FLTS (Fin n) Symbol} {i j k : Fin n} {xs : List Sy · grind [splitLast] -- First hypothesis of `ih` is implied by `h` have haux := language_bddpath_head_iff.mp h - simp only [hxs, or_false] at haux -- Assumptions `h` and `h'` combined says that `k ∈ PathSupp flts i (a :: xs)` by_cases hk : k ∈ PathSupp flts (flts.tr i a) xs · -- `k` appears in PathSupp From 1ca1b2f4388af49f165748d88d82a29877f9e730 Mon Sep 17 00:00:00 2001 From: Brooke Gill <96643991+brooke-gill@users.noreply.github.com> Date: Wed, 2 Sep 2026 22:12:29 -0700 Subject: [PATCH 73/89] More free golfs --- Cslib/Computability/Languages/KleeneAlgorithm.lean | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Cslib/Computability/Languages/KleeneAlgorithm.lean b/Cslib/Computability/Languages/KleeneAlgorithm.lean index a57515c6ea..95d1e67cfd 100644 --- a/Cslib/Computability/Languages/KleeneAlgorithm.lean +++ b/Cslib/Computability/Languages/KleeneAlgorithm.lean @@ -345,7 +345,7 @@ noncomputable def splitFirstCompl (flts : FLTS (Fin n) Symbol) (i k : Fin n) theorem splitFirst_append (flts : FLTS (Fin n) Symbol) (i k : Fin n) (xs : List Symbol) : splitFirst flts i k xs ++ splitFirstCompl flts i k xs = xs := by - grind [splitFirst, splitFirstCompl] + grind [splitFirstCompl] theorem splitFirst_mem {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : List Symbol} (h : xs ∈ (language (BddPath.mk flts i k (k + 1)))) : @@ -353,7 +353,7 @@ theorem splitFirst_mem {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : List Sym induction xs generalizing i with | nil => simpa [Accepts, splitFirst, PathSupp] using h | cons a xs ih => - simp only [mem_language, Accepts, Order.lt_add_one_iff, splitFirst] at ih h ⊢ + simp only [mem_language, Accepts, splitFirst] at ih h ⊢ obtain ⟨h1, h2⟩ := h split_ifs with ha · refine ⟨by grind, ?_⟩ @@ -517,7 +517,7 @@ theorem regex_of_dfa_singleton_accept [Finite Symbol] {State : Type*} [Finite St induction xs using List.reverseRec with | nil => grind | append_singleton xs x ih => grind - simp only [mem_language, Accepts, h, hdfa', Set.mem_singleton_iff] + simp only [mem_language, Accepts, h, hdfa'] rw [dfa_eq] simp have : Fintype Symbol := Fintype.ofFinite Symbol From 8c00c426fdf13266294fdeafbbaf6d1b029156f2 Mon Sep 17 00:00:00 2001 From: Chi-Yun Hsu Date: Thu, 3 Sep 2026 10:15:08 -0700 Subject: [PATCH 74/89] Rewind some golf I personally prefer to have the list of lemmas given to grind in order of application. I have not seen adding a whole by tactic into grind before. I think it might be too much golfing --- Cslib/Computability/Languages/KleeneAlgorithm.lean | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/Cslib/Computability/Languages/KleeneAlgorithm.lean b/Cslib/Computability/Languages/KleeneAlgorithm.lean index 95d1e67cfd..b404192d6a 100644 --- a/Cslib/Computability/Languages/KleeneAlgorithm.lean +++ b/Cslib/Computability/Languages/KleeneAlgorithm.lean @@ -170,8 +170,8 @@ theorem splitLastCompl_eq {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : List | cons a xs ih => by_cases hxs : xs = [] · grind [splitLastCompl, PathSupp] - grind [splitLastCompl, (isPrefix_splitLastCompl flts (flts.tr i a) k xs).length_le, - pathSupp_head hxs] + grind [pathSupp_head hxs, splitLastCompl, + (isPrefix_splitLastCompl flts (flts.tr i a) k xs).length_le] -- classical -- simpa [splitLast_eq h h'] using splitLast_append flts s t xs @@ -198,8 +198,8 @@ theorem splitLastCompl_nonempty_iff_mem_PathSupp {flts : FLTS (Fin n) Symbol} {i | cons a xs ih => by_cases hxs' : xs = [] · grind [splitLastCompl, PathSupp] - grind [splitLastCompl, (isPrefix_splitLastCompl flts (flts.tr i a) k xs).length_le, - pathSupp_head hxs'] + grind [pathSupp_head hxs', splitLastCompl, + (isPrefix_splitLastCompl flts (flts.tr i a) k xs).length_le] -- classical -- rw [← splitLast_neq_iff_mem_PathSupp hxs, not_iff_not] -- nth_rw 3 [← splitLast_append flts s t xs] @@ -256,8 +256,9 @@ theorem splitLastCompl_mem {flts : FLTS (Fin n) Symbol} {i j k : Fin n} {xs : Li · apply ih haux.1 simp [Accepts] grind - · grind [h.1, splitLastCompl_eq, by - simpa [hk] using (splitLastCompl_nonempty_iff_mem_PathSupp hxs).mp hc1] + · have eq : k = flts.mtr (flts.tr i a) xs := by + simpa [hk] using (splitLastCompl_nonempty_iff_mem_PathSupp hxs).mp hc1 + grind [splitLastCompl_eq, h.1] · rw [not_not] at hc1 simpa [hc1, Accepts, PathSupp, FLTS.mtr] using hc From 3dfe1fbad4066cea7bf77d7b860e9b8d4afbb2eb Mon Sep 17 00:00:00 2001 From: Brooke Gill <96643991+brooke-gill@users.noreply.github.com> Date: Tue, 8 Sep 2026 02:30:25 -0700 Subject: [PATCH 75/89] Added docstring and modified comments --- .../Languages/KleeneAlgorithm.lean | 94 +++++++------------ 1 file changed, 36 insertions(+), 58 deletions(-) diff --git a/Cslib/Computability/Languages/KleeneAlgorithm.lean b/Cslib/Computability/Languages/KleeneAlgorithm.lean index b404192d6a..897f63dfdf 100644 --- a/Cslib/Computability/Languages/KleeneAlgorithm.lean +++ b/Cslib/Computability/Languages/KleeneAlgorithm.lean @@ -13,6 +13,34 @@ public import Mathlib.Computability.RegularExpressions /-! # Kleene's Algorithm + +Every language accepted by a DFA on a set comprised of finite states is the language of a +regular expression. +We prove this by induction on a bound (k) that restricts which interior states a run may pass +through. + + +## Main definitions +- `PathSupp`: The interior states of a run +- `BddPath`: A transition system containing a start state, finish state, and a specific bound on + all interior states +- `Regex flts i j k`: The regular expression for the paths from state `i` to state `j`, + whose interior states are all under a specific bound `k` + +## Main results + +- `regex_of_dfa_singleton_accept`: DFAs with one accepting state have a matching regular + expression +- `language_bddpath_eq_dfa`: A bound that has reached the total number of states no longer +constrains anything +- `language_bddpath_eq_regex`: `Regex flts i j k` matches exactly the same paths from `i` to `j` +with interior states below `k` + + +## References + +* [J. E. Hopcroft, R. Motwani, J. D. Ullman, + *Introduction to Automata Theory, Languages, and Computation*][Hopcroft2006] -/ @[expose] public section @@ -41,6 +69,9 @@ theorem pathSupp_empty_iff_empty_or_char {flts : FLTS State Symbol} {s : State} have : flts.tr s x ∈ PathSupp flts s (x :: y :: ys) := by grind [PathSupp] grind +/-- If xs is nonempty, then the interior states of the run the start at s and reads a :: xs +consists of the state reached after reading a as well as the interior states of the run that starts +at flts.tr s a and reads xs. -/ theorem pathSupp_head {flts : FLTS State Symbol} {s : State} {a : Symbol} {xs : List Symbol} (hxs : xs ≠ []) : PathSupp flts s (a :: xs) = {flts.tr s a} ∪ PathSupp flts (flts.tr s a) xs := by @@ -65,7 +96,7 @@ variable {n : ℕ} /-- A Bounded Path (`BddPath`) has states `Fin n` and accepts strings (lists of symbols) starting with state `start` and ending with state `finish` -with the intermediate states less than `bound`. -/ +with the interior states less than `bound`. -/ structure BddPath (n : ℕ) (Symbol : Type*) extends FLTS (Fin n) Symbol where start : Fin n finish : Fin n @@ -126,43 +157,6 @@ theorem splitLast_head (flts : FLTS (Fin n) Symbol) (i k : Fin n) (xs : List Sym (if splitLastCompl flts (flts.tr i a) k xs = [] ∧ flts.tr i a ≠ k then a :: xs else splitLast flts (flts.tr i a) k xs) := by grind [splitLast, splitLastCompl] --- def splitLast' [DecidableEq Symbol] {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) : --- List Symbol → List Symbol --- | [] => [] --- | a :: x => if (splitLast' flts (flts.tr s a) t x = x) ∧ flts.tr s a ≠ t then a :: x --- else splitLast' flts (flts.tr s a) t x - --- theorem isSuffix_splitLast' [DecidableEq Symbol] {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) --- (xs : List Symbol) : IsSuffix (splitLast' flts s t xs) xs := by --- induction xs generalizing s with --- | nil => simp [splitLast'] --- | cons a xs ih => grind [splitLast'] - --- theorem splitLast_append' [DecidableEq Symbol] {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) --- (xs : List Symbol) : splitLastCompl flts s t xs ++ splitLast' flts s t xs = xs := by --- induction xs generalizing s with --- | nil => grind [splitLast', splitLastCompl] --- | cons a xs ih => --- simp only [splitLast', splitLastCompl] --- split_ifs with h h' h' --- · simp --- · grind [ih (s := flts.tr s a)] --- · have := h'.1 ▸ ih (s := flts.tr s a) --- simp at this --- grind --- · simpa using ih (s := flts.tr s a) - --- theorem splitLast_eq' [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} {s t : Fin n} --- {xs : List Symbol} (h : t ∉ PathSupp flts s xs) (h' : t = flts.mtr s xs) : --- splitLast' flts s t xs = [] := by --- induction xs generalizing s with --- | nil => grind [splitLast', PathSupp] --- | cons a xs ih => --- by_cases hxs : xs = [] --- · grind [splitLast', PathSupp] --- rw [pathSupp_head hxs, Set.mem_union, Set.mem_singleton_iff] at h --- grind [splitLast', (isSuffix_splitLast' flts (flts.tr s a) t xs).length_le] - theorem splitLastCompl_eq {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : List Symbol} (h : k ∉ PathSupp flts i xs) (h' : k = flts.mtr i xs) : splitLastCompl flts i k xs = xs := by induction xs generalizing i with @@ -179,17 +173,6 @@ theorem splitLast_eq {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : List Symbo (h : k ∉ PathSupp flts i xs) (h' : k = flts.mtr i xs) : splitLast flts i k xs = [] := by simpa [splitLastCompl_eq h h'] using splitLast_append flts i k xs --- theorem splitLast_neq_iff_mem_PathSupp' [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} --- {s t : Fin n} {xs : List Symbol} (hxs : xs ≠ []) : --- ¬(splitLast' flts s t xs = xs) ↔ t ∈ PathSupp flts s xs ∨ t = flts.mtr s xs := by --- induction xs generalizing s with --- | nil => contradiction --- | cons a xs ih => --- by_cases hxs' : xs = [] --- · grind [splitLast', PathSupp] --- rw [pathSupp_head hxs', Set.mem_union, Set.mem_singleton_iff] --- grind [splitLast', (isSuffix_splitLast' flts (flts.tr s a) t xs).length_le] - theorem splitLastCompl_nonempty_iff_mem_PathSupp {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : List Symbol} (hxs : xs ≠ []) : ¬(splitLastCompl flts i k xs = []) ↔ k ∈ PathSupp flts i xs ∨ k = flts.mtr i xs := by @@ -200,10 +183,6 @@ theorem splitLastCompl_nonempty_iff_mem_PathSupp {flts : FLTS (Fin n) Symbol} {i · grind [splitLastCompl, PathSupp] grind [pathSupp_head hxs', splitLastCompl, (isPrefix_splitLastCompl flts (flts.tr i a) k xs).length_le] - -- classical - -- rw [← splitLast_neq_iff_mem_PathSupp hxs, not_iff_not] - -- nth_rw 3 [← splitLast_append flts s t xs] - -- simp theorem splitLast_neq_iff_mem_PathSupp {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : List Symbol} (hxs : xs ≠ []) : @@ -262,6 +241,9 @@ theorem splitLastCompl_mem {flts : FLTS (Fin n) Symbol} {i j k : Fin n} {xs : Li · rw [not_not] at hc1 simpa [hc1, Accepts, PathSupp, FLTS.mtr] using hc +/-- If the run of `xs` from `i` to `j` has `k` as the largest interior state, then + `splitLast flts i k xs` (which is the shortest suffix of `xs` starting at `k`) + is a path from `k` to `j` whose interior states are all below `k`. -/ theorem splitLast_mem {flts : FLTS (Fin n) Symbol} {i j k : Fin n} {xs : List Symbol} (h : xs ∈ language (BddPath.mk flts i j (k + 1))) (h' : xs ∉ language (BddPath.mk flts i j k)) : @@ -300,7 +282,6 @@ theorem splitLast_mem {flts : FLTS (Fin n) Symbol} {i j k : Fin n} {xs : List Sy · grind [splitLast_eq, PathSupp] grind [splitLast_append, splitLastCompl_nonempty_iff_mem_PathSupp, pathSupp_head] --- The original path1 theorem language_bddpath_splitLast (flts : FLTS (Fin n) Symbol) (i j k : Fin n) : language (BddPath.mk flts i j (k + 1)) = language (BddPath.mk flts i j k) + (language (BddPath.mk flts i k (k + 1)) * language (BddPath.mk flts k j k)) := by @@ -388,7 +369,6 @@ theorem splitFirstCompl_mem {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : Lis · grind [PathSupp] grind [pathSupp_append] --- The original path2 theorem language_bddpath_splitFirst (flts : FLTS (Fin n) Symbol) (i k : Fin n) : language (BddPath.mk flts i k (k + 1)) = language (BddPath.mk flts i k k) * language (BddPath.mk flts k k (k + 1)) := by @@ -421,7 +401,6 @@ theorem language_bddpath_kstar (flts : FLTS (Fin n) Symbol) (k : Fin n) : language (BddPath.mk flts k k (k + 1)) = (language (BddPath.mk flts k k k))∗ := by rw [← mul_one (language (BddPath.mk flts k k ↑k))∗, kstar_eq] refine (Language.self_eq_mul_add_iff (by simp [Language.mem_sub])).mp ?_ - -- mimic the proof of path2 ext xs simp only [Language.mem_add, Language.mem_mul, Language.mem_sub] constructor @@ -456,7 +435,7 @@ theorem mem_sum_matches'_iff {α : Type*} (L : List (RegularExpression α)) (x : variable [Fintype Symbol] -/- +/-- Regex i j k is the regex for the path from state i to state j passing through states < k. When k = 0, i = j, the regex is ε union all characters from state i to state i. When k = 0, i ≠ j, the regex is all characters from state i to state j. @@ -496,7 +475,6 @@ theorem language_bddpath_eq_regex {k : ℕ} {flts : FLTS (Fin n) Symbol} {i j : language_bddpath_kstar] grind [matches'_add, matches'_mul, matches'_star] --- The original `acc_singleton` theorem language_dfa_eq_regex_of_singleton_accept {dfa : DA.FinAcc (Fin n) Symbol} {s : Fin n} (h : dfa.accept = {s}) : language dfa = (Regex dfa.toFLTS dfa.start s n).matches' := by simp [← language_bddpath_eq_regex, language, Accepts, h] From 67b35f8a603f917b7c292553f3984df983d6b3d2 Mon Sep 17 00:00:00 2001 From: Chi-Yun Hsu Date: Tue, 8 Sep 2026 12:34:39 -0700 Subject: [PATCH 76/89] Small change in comment; delete RegularExpresions.lean RegularExpresions.lean has been saved in SummerResearch2026 --- .../Languages/KleeneAlgorithm.lean | 6 +-- .../Languages/RegularExpressions.lean | 53 ------------------- 2 files changed, 3 insertions(+), 56 deletions(-) delete mode 100644 Cslib/Computability/Languages/RegularExpressions.lean diff --git a/Cslib/Computability/Languages/KleeneAlgorithm.lean b/Cslib/Computability/Languages/KleeneAlgorithm.lean index 897f63dfdf..a93bac2a11 100644 --- a/Cslib/Computability/Languages/KleeneAlgorithm.lean +++ b/Cslib/Computability/Languages/KleeneAlgorithm.lean @@ -69,9 +69,9 @@ theorem pathSupp_empty_iff_empty_or_char {flts : FLTS State Symbol} {s : State} have : flts.tr s x ∈ PathSupp flts s (x :: y :: ys) := by grind [PathSupp] grind -/-- If xs is nonempty, then the interior states of the run the start at s and reads a :: xs -consists of the state reached after reading a as well as the interior states of the run that starts -at flts.tr s a and reads xs. -/ +/-- If xs is nonempty, then the interior states of the run that starts at `s` and reads `a :: xs` +consist of the state reached after reading `a` as well as the interior states of the run that starts +at `flts.tr s a` and reads `xs`. -/ theorem pathSupp_head {flts : FLTS State Symbol} {s : State} {a : Symbol} {xs : List Symbol} (hxs : xs ≠ []) : PathSupp flts s (a :: xs) = {flts.tr s a} ∪ PathSupp flts (flts.tr s a) xs := by diff --git a/Cslib/Computability/Languages/RegularExpressions.lean b/Cslib/Computability/Languages/RegularExpressions.lean deleted file mode 100644 index 0753cc85b2..0000000000 --- a/Cslib/Computability/Languages/RegularExpressions.lean +++ /dev/null @@ -1,53 +0,0 @@ -/- -Copyright (c) 2026 Brooke Gill and Chi-Yun Hsu. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Brooke Gill and Chi-Yun Hsu --/ - -module - -public import Mathlib.Computability.RegularExpressions - -@[expose] public section - -namespace Cslib.Language - -open RegularExpression - -variable {α : Type*} - --- Pause on doing this as we might not need these lemmas anymore. -theorem mem_zero_matches'_iff (x : List α) : - x ∈ (0 : RegularExpression α).matches' ↔ False := by - classical - rw [← rmatch_iff_matches'] - sorry - -theorem mem_one_matches'_iff (x : List α) : - x ∈ (1 : RegularExpression α).matches' ↔ x = [] := by - classical - rw [← rmatch_iff_matches', one_rmatch_iff] - -theorem mem_char_matches'_iff (a : α) (x : List α) : - x ∈ (char a).matches' ↔ x = [a] := by sorry - -theorem mem_star_matches'_iff (P : RegularExpression α) (x : List α) : - x ∈ (star P).matches' ↔ - ∃ S : List (List α), x = S.flatten ∧ ∀ t ∈ S, t ≠ [] ∧ t ∈ P.matches' := by sorry - -theorem mem_add_matches'_iff (P Q : RegularExpression α) (x : List α) : - x ∈ (P + Q).matches' ↔ x ∈ P.matches' ∨ x ∈ Q.matches' := by - classical - repeat rw [← rmatch_iff_matches'] - rw [add_rmatch_iff] - -theorem mem_mul_matches'_iff (P Q : RegularExpression α) (x : List α) : - x ∈ (P * Q).matches' ↔ ∃ y z, x = y ++ z ∧ y ∈ P.matches' ∧ z ∈ Q.matches' := by sorry - -theorem mem_sum_matches'_iff (L : List (RegularExpression α)) (x : List α) : - x ∈ (L.sum).matches' ↔ ∃ P ∈ L, x ∈ P.matches' := by - induction L with - | nil => simp - | cons head tail ih => simp [Language.mem_add, ih] - -end Cslib.Language From 60caa7a98c1438ddf687265735bc46404ec1609c Mon Sep 17 00:00:00 2001 From: Chi-Yun Hsu Date: Tue, 8 Sep 2026 12:39:04 -0700 Subject: [PATCH 77/89] Switched the role of splitLast and splitLastCompl --- .../Languages/KleeneAlgorithm.lean | 132 +++++++++--------- 1 file changed, 66 insertions(+), 66 deletions(-) diff --git a/Cslib/Computability/Languages/KleeneAlgorithm.lean b/Cslib/Computability/Languages/KleeneAlgorithm.lean index a93bac2a11..73c9ba5ea1 100644 --- a/Cslib/Computability/Languages/KleeneAlgorithm.lean +++ b/Cslib/Computability/Languages/KleeneAlgorithm.lean @@ -124,77 +124,77 @@ open List section splitLast -/-- Starting at state `i`, the function `splitLastCompl` sends a string to its longest prefix +/-- Starting at state `i`, the function `splitLast` sends a string to its longest prefix ending at state `k`. -If the string ends at state `k`, then `splitLastCompl` returns the original string. +If the string ends at state `k`, then `splitLast` returns the original string. If the string never passes through state `k` (starting state can be `k`), -then `splitLastCompl` returns the empty string. -/ -def splitLastCompl (flts : FLTS (Fin n) Symbol) (i k : Fin n) : List Symbol → List Symbol +then `splitLast` returns the empty string. -/ +def splitLast (flts : FLTS (Fin n) Symbol) (i k : Fin n) : List Symbol → List Symbol | [] => [] - | a :: x => if (splitLastCompl flts (flts.tr i a) k x = []) ∧ flts.tr i a ≠ k then [] - else a :: splitLastCompl flts (flts.tr i a) k x + | a :: x => if (splitLast flts (flts.tr i a) k x = []) ∧ flts.tr i a ≠ k then [] + else a :: splitLast flts (flts.tr i a) k x -theorem isPrefix_splitLastCompl (flts : FLTS (Fin n) Symbol) (i k : Fin n) (xs : List Symbol) : - IsPrefix (splitLastCompl flts i k xs) xs := by +theorem isPrefix_splitLast (flts : FLTS (Fin n) Symbol) (i k : Fin n) (xs : List Symbol) : + IsPrefix (splitLast flts i k xs) xs := by induction xs generalizing i with - | nil => simp [splitLastCompl] - | cons a xs ih => grind [splitLastCompl] + | nil => simp [splitLast] + | cons a xs ih => grind [splitLast] /-- Starting at state `i`, the function `splitLast` sends a string to its shortest suffix starting at state `k`. If the string ends at state `k`, then `splitLast` returns the empty string. If the string never passes through state `k` (starting state can be `k`), then `splitLast` returns the original string. -/ -noncomputable def splitLast (flts : FLTS (Fin n) Symbol) (i k : Fin n) (xs : List Symbol) : - List Symbol := (isPrefix_splitLastCompl flts i k xs).choose +noncomputable def splitLastCompl (flts : FLTS (Fin n) Symbol) (i k : Fin n) (xs : List Symbol) : + List Symbol := (isPrefix_splitLast flts i k xs).choose -theorem splitLast_append (flts : FLTS (Fin n) Symbol) (i k : Fin n) (xs : List Symbol) : - splitLastCompl flts i k xs ++ splitLast flts i k xs = xs := by - grind [splitLast] +theorem splitLastCompl_append (flts : FLTS (Fin n) Symbol) (i k : Fin n) (xs : List Symbol) : + splitLast flts i k xs ++ splitLastCompl flts i k xs = xs := by + grind [splitLastCompl] -theorem splitLast_head (flts : FLTS (Fin n) Symbol) (i k : Fin n) (xs : List Symbol) - (a : Symbol) : splitLast flts i k (a :: xs) = - (if splitLastCompl flts (flts.tr i a) k xs = [] ∧ flts.tr i a ≠ k then a :: xs - else splitLast flts (flts.tr i a) k xs) := by grind [splitLast, splitLastCompl] +theorem splitLastCompl_head (flts : FLTS (Fin n) Symbol) (i k : Fin n) (xs : List Symbol) + (a : Symbol) : splitLastCompl flts i k (a :: xs) = + (if splitLast flts (flts.tr i a) k xs = [] ∧ flts.tr i a ≠ k then a :: xs + else splitLastCompl flts (flts.tr i a) k xs) := by grind [splitLastCompl, splitLast] -theorem splitLastCompl_eq {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : List Symbol} - (h : k ∉ PathSupp flts i xs) (h' : k = flts.mtr i xs) : splitLastCompl flts i k xs = xs := by +theorem splitLast_eq {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : List Symbol} + (h : k ∉ PathSupp flts i xs) (h' : k = flts.mtr i xs) : splitLast flts i k xs = xs := by induction xs generalizing i with - | nil => grind [splitLastCompl, PathSupp] + | nil => grind [splitLast, PathSupp] | cons a xs ih => by_cases hxs : xs = [] - · grind [splitLastCompl, PathSupp] - grind [pathSupp_head hxs, splitLastCompl, - (isPrefix_splitLastCompl flts (flts.tr i a) k xs).length_le] + · grind [splitLast, PathSupp] + grind [pathSupp_head hxs, splitLast, + (isPrefix_splitLast flts (flts.tr i a) k xs).length_le] -- classical - -- simpa [splitLast_eq h h'] using splitLast_append flts s t xs + -- simpa [splitLastCompl_eq h h'] using splitLastCompl_append flts s t xs -theorem splitLast_eq {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : List Symbol} - (h : k ∉ PathSupp flts i xs) (h' : k = flts.mtr i xs) : splitLast flts i k xs = [] := by - simpa [splitLastCompl_eq h h'] using splitLast_append flts i k xs +theorem splitLastCompl_eq {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : List Symbol} + (h : k ∉ PathSupp flts i xs) (h' : k = flts.mtr i xs) : splitLastCompl flts i k xs = [] := by + simpa [splitLast_eq h h'] using splitLastCompl_append flts i k xs -theorem splitLastCompl_nonempty_iff_mem_PathSupp {flts : FLTS (Fin n) Symbol} {i k : Fin n} +theorem splitLast_nonempty_iff_mem_PathSupp {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : List Symbol} (hxs : xs ≠ []) : - ¬(splitLastCompl flts i k xs = []) ↔ k ∈ PathSupp flts i xs ∨ k = flts.mtr i xs := by + ¬(splitLast flts i k xs = []) ↔ k ∈ PathSupp flts i xs ∨ k = flts.mtr i xs := by induction xs generalizing i with | nil => contradiction | cons a xs ih => by_cases hxs' : xs = [] - · grind [splitLastCompl, PathSupp] - grind [pathSupp_head hxs', splitLastCompl, - (isPrefix_splitLastCompl flts (flts.tr i a) k xs).length_le] + · grind [splitLast, PathSupp] + grind [pathSupp_head hxs', splitLast, + (isPrefix_splitLast flts (flts.tr i a) k xs).length_le] -theorem splitLast_neq_iff_mem_PathSupp {flts : FLTS (Fin n) Symbol} {i k : Fin n} +theorem splitLastCompl_neq_iff_mem_PathSupp {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : List Symbol} (hxs : xs ≠ []) : - ¬(splitLast flts i k xs = xs) ↔ k ∈ PathSupp flts i xs ∨ k = flts.mtr i xs := by - rw [← splitLastCompl_nonempty_iff_mem_PathSupp hxs, not_iff_not] - nth_rw 2 [← splitLast_append flts i k xs] + ¬(splitLastCompl flts i k xs = xs) ↔ k ∈ PathSupp flts i xs ∨ k = flts.mtr i xs := by + rw [← splitLast_nonempty_iff_mem_PathSupp hxs, not_iff_not] + nth_rw 2 [← splitLastCompl_append flts i k xs] simp -theorem splitLastCompl_aux {flts : FLTS (Fin n) Symbol} {i j k : Fin n} {xs : List Symbol} +theorem splitLast_aux {flts : FLTS (Fin n) Symbol} {i j k : Fin n} {xs : List Symbol} {a : Symbol} (h : a :: xs ∈ language (BddPath.mk flts i j (k + 1))) (h' : a :: xs ∉ language (BddPath.mk flts i j k)) - (hc : splitLastCompl flts (flts.tr i a) k xs = [] ∧ flts.tr i a ≠ k) : False := by + (hc : splitLast flts (flts.tr i a) k xs = [] ∧ flts.tr i a ≠ k) : False := by simp only [mem_language, Accepts, Order.lt_add_one_iff, Fin.val_fin_le, not_and, not_forall, not_lt] at * simp only [h, forall_const] at h' @@ -209,25 +209,25 @@ theorem splitLastCompl_aux {flts : FLTS (Fin n) Symbol} {i j k : Fin n} {xs : Li simp only [Set.mem_singleton_iff] at hx1 symm at hx1 contradiction - · grind [(splitLastCompl_nonempty_iff_mem_PathSupp hxs).mpr (Or.inl hx2)] + · grind [(splitLast_nonempty_iff_mem_PathSupp hxs).mpr (Or.inl hx2)] -theorem splitLastCompl_mem {flts : FLTS (Fin n) Symbol} {i j k : Fin n} {xs : List Symbol} +theorem splitLast_mem {flts : FLTS (Fin n) Symbol} {i j k : Fin n} {xs : List Symbol} (h : xs ∈ language (BddPath.mk flts i j (k + 1))) (h' : xs ∉ language (BddPath.mk flts i j k)) : - splitLastCompl flts i k xs ∈ language (BddPath.mk flts i k (k + 1)) := by + splitLast flts i k xs ∈ language (BddPath.mk flts i k (k + 1)) := by induction xs generalizing i with | nil => simp [Accepts, PathSupp] at h h' contradiction | cons a xs ih => - simp only [splitLastCompl] + simp only [splitLast] split_ifs with hc - · exfalso; exact splitLastCompl_aux h h' hc + · exfalso; exact splitLast_aux h h' hc · rw [not_and_or, not_not] at hc -- The last `k` is later than `flts.tr i a` or equal to it. - by_cases hc1 : ¬splitLastCompl flts (flts.tr i a) k xs = [] + by_cases hc1 : ¬splitLast flts (flts.tr i a) k xs = [] · by_cases hxs : xs = [] - · grind [splitLastCompl] + · grind [splitLast] have haux := language_bddpath_head_iff.mp h simp only [hxs, or_false] at haux refine language_bddpath_head_iff.mpr ⟨?_, Or.inl haux.2⟩ @@ -236,32 +236,32 @@ theorem splitLastCompl_mem {flts : FLTS (Fin n) Symbol} {i j k : Fin n} {xs : Li simp [Accepts] grind · have eq : k = flts.mtr (flts.tr i a) xs := by - simpa [hk] using (splitLastCompl_nonempty_iff_mem_PathSupp hxs).mp hc1 - grind [splitLastCompl_eq, h.1] + simpa [hk] using (splitLast_nonempty_iff_mem_PathSupp hxs).mp hc1 + grind [splitLast_eq, h.1] · rw [not_not] at hc1 simpa [hc1, Accepts, PathSupp, FLTS.mtr] using hc /-- If the run of `xs` from `i` to `j` has `k` as the largest interior state, then - `splitLast flts i k xs` (which is the shortest suffix of `xs` starting at `k`) + `splitLastCompl flts i k xs` (which is the shortest suffix of `xs` starting at `k`) is a path from `k` to `j` whose interior states are all below `k`. -/ -theorem splitLast_mem {flts : FLTS (Fin n) Symbol} {i j k : Fin n} {xs : List Symbol} +theorem splitLastCompl_mem {flts : FLTS (Fin n) Symbol} {i j k : Fin n} {xs : List Symbol} (h : xs ∈ language (BddPath.mk flts i j (k + 1))) (h' : xs ∉ language (BddPath.mk flts i j k)) : - splitLast flts i k xs ∈ language (BddPath.mk flts k j k) := by + splitLastCompl flts i k xs ∈ language (BddPath.mk flts k j k) := by induction xs generalizing i with | nil => simp [Accepts, PathSupp] at h h' contradiction | cons a xs ih => - have h'' := splitLastCompl_mem h h' - rw [splitLast_head] + have h'' := splitLast_mem h h' + rw [splitLastCompl_head] split_ifs with hc - · exfalso; exact splitLastCompl_aux h h' hc + · exfalso; exact splitLast_aux h h' hc · rw [not_and_or, not_not] at hc -- The last `k` is later than `flts.tr i a` or equal to it. - by_cases hc1 : ¬splitLastCompl flts (flts.tr i a) k xs = [] + by_cases hc1 : ¬splitLast flts (flts.tr i a) k xs = [] · by_cases hxs : xs = [] - · grind [splitLast] + · grind [splitLastCompl] -- First hypothesis of `ih` is implied by `h` have haux := language_bddpath_head_iff.mp h -- Assumptions `h` and `h'` combined says that `k ∈ PathSupp flts i (a :: xs)` @@ -272,17 +272,17 @@ theorem splitLast_mem {flts : FLTS (Fin n) Symbol} {i j k : Fin n} {xs : List Sy grind · -- `k` only appears at the end state -- `hk` should contradict with `h` and `h'` - apply (splitLastCompl_nonempty_iff_mem_PathSupp hxs).mp at hc1 - simp_all [Accepts, PathSupp, splitLast_eq] + apply (splitLast_nonempty_iff_mem_PathSupp hxs).mp at hc1 + simp_all [Accepts, PathSupp, splitLastCompl_eq] · -- The last `k` is equal to `flts.tr i a` -- Cannot apply ih -- Directly prove the goal from definition simp only [mem_language, Accepts] at h ⊢ by_cases hxs : xs = [] - · grind [splitLast_eq, PathSupp] - grind [splitLast_append, splitLastCompl_nonempty_iff_mem_PathSupp, pathSupp_head] + · grind [splitLastCompl_eq, PathSupp] + grind [splitLastCompl_append, splitLast_nonempty_iff_mem_PathSupp, pathSupp_head] -theorem language_bddpath_splitLast (flts : FLTS (Fin n) Symbol) (i j k : Fin n) : +theorem language_bddpath_splitLastCompl (flts : FLTS (Fin n) Symbol) (i j k : Fin n) : language (BddPath.mk flts i j (k + 1)) = language (BddPath.mk flts i j k) + (language (BddPath.mk flts i k (k + 1)) * language (BddPath.mk flts k j k)) := by ext xs @@ -292,9 +292,9 @@ theorem language_bddpath_splitLast (flts : FLTS (Fin n) Symbol) (i j k : Fin n) by_cases h' : xs ∈ language (BddPath.mk flts i j k) · left; exact h' right - use splitLastCompl flts i k xs, splitLastCompl_mem h h', - splitLast flts i k xs, splitLast_mem h h', - splitLast_append flts _ _ _ + use splitLast flts i k xs, splitLast_mem h h', + splitLastCompl flts i k xs, splitLastCompl_mem h h', + splitLastCompl_append flts _ _ _ · rintro (h_left | ⟨ys, ⟨⟨hys, hsuppys⟩, ⟨zs, ⟨⟨hzs, hsuppzs⟩, happend⟩⟩⟩⟩) · simp only [mem_language, Accepts] at h_left ⊢ grind @@ -471,7 +471,7 @@ theorem language_bddpath_eq_regex {k : ℕ} {flts : FLTS (Fin n) Symbol} {i j : simp only [Regex] split_ifs with hk · rw [← ih, language_bddpath_eq_dfa flts i j hk, language_bddpath_eq_dfa flts i j (by omega)] - rw [language_bddpath_splitLast (k := ⟨k, by omega⟩), language_bddpath_splitFirst, + rw [language_bddpath_splitLastCompl (k := ⟨k, by omega⟩), language_bddpath_splitFirst, language_bddpath_kstar] grind [matches'_add, matches'_mul, matches'_star] From ff12620b9fa05d3d7622b29bd76e3976a6fc4880 Mon Sep 17 00:00:00 2001 From: Chi-Yun Hsu Date: Tue, 8 Sep 2026 12:42:08 -0700 Subject: [PATCH 78/89] Delete a commented proof --- Cslib/Computability/Languages/KleeneAlgorithm.lean | 2 -- 1 file changed, 2 deletions(-) diff --git a/Cslib/Computability/Languages/KleeneAlgorithm.lean b/Cslib/Computability/Languages/KleeneAlgorithm.lean index 73c9ba5ea1..300d902a69 100644 --- a/Cslib/Computability/Languages/KleeneAlgorithm.lean +++ b/Cslib/Computability/Languages/KleeneAlgorithm.lean @@ -166,8 +166,6 @@ theorem splitLast_eq {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : List Symbo · grind [splitLast, PathSupp] grind [pathSupp_head hxs, splitLast, (isPrefix_splitLast flts (flts.tr i a) k xs).length_le] - -- classical - -- simpa [splitLastCompl_eq h h'] using splitLastCompl_append flts s t xs theorem splitLastCompl_eq {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : List Symbol} (h : k ∉ PathSupp flts i xs) (h' : k = flts.mtr i xs) : splitLastCompl flts i k xs = [] := by From b64f5394e8a3f9165c3c7177bdf5f59f60530aab Mon Sep 17 00:00:00 2001 From: Brooke Gill <96643991+brooke-gill@users.noreply.github.com> Date: Tue, 8 Sep 2026 13:29:59 -0700 Subject: [PATCH 79/89] Added docstrings to important theorems --- .../Languages/KleeneAlgorithm.lean | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/Cslib/Computability/Languages/KleeneAlgorithm.lean b/Cslib/Computability/Languages/KleeneAlgorithm.lean index 300d902a69..bdbd739cdc 100644 --- a/Cslib/Computability/Languages/KleeneAlgorithm.lean +++ b/Cslib/Computability/Languages/KleeneAlgorithm.lean @@ -209,6 +209,9 @@ theorem splitLast_aux {flts : FLTS (Fin n) Symbol} {i j k : Fin n} {xs : List Sy contradiction · grind [(splitLast_nonempty_iff_mem_PathSupp hxs).mpr (Or.inl hx2)] +/-- If the run of `xs` from `i` to `j` has `k` as the largest interior state, then + `splitLast flts i k xs` (the longest prefix ending at `k`) + is a path from `i` to `k` whose interior states are all below `k + 1`. -/ theorem splitLast_mem {flts : FLTS (Fin n) Symbol} {i j k : Fin n} {xs : List Symbol} (h : xs ∈ language (BddPath.mk flts i j (k + 1))) (h' : xs ∉ language (BddPath.mk flts i j k)) : @@ -280,6 +283,10 @@ theorem splitLastCompl_mem {flts : FLTS (Fin n) Symbol} {i j k : Fin n} {xs : Li · grind [splitLastCompl_eq, PathSupp] grind [splitLastCompl_append, splitLast_nonempty_iff_mem_PathSupp, pathSupp_head] +/-- The recursion step of Kleene's algorithm. +A run from `i` to `j` whose interior states are all at most `k` either has no interior state equal +to `k`, or it splits at its last visit to `k` into a run from `i` to `k` with interior states +below `k + 1`, followed by a run from `k` to `j` with interior states below `k`. -/ theorem language_bddpath_splitLastCompl (flts : FLTS (Fin n) Symbol) (i j k : Fin n) : language (BddPath.mk flts i j (k + 1)) = language (BddPath.mk flts i j k) + (language (BddPath.mk flts i k (k + 1)) * language (BddPath.mk flts k j k)) := by @@ -367,6 +374,10 @@ theorem splitFirstCompl_mem {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : Lis · grind [PathSupp] grind [pathSupp_append] +/-- Part of Kleene's algorithm. +A run from `i` to `j` whose interior states are all at most `k` splits upon first reaching `k`. +The part before the visit is a run from `i` to `k` with interior states below `k`. +The part after it is a run from `k` to `k` with interior states below `k + 1`. -/ theorem language_bddpath_splitFirst (flts : FLTS (Fin n) Symbol) (i k : Fin n) : language (BddPath.mk flts i k (k + 1)) = language (BddPath.mk flts i k k) * language (BddPath.mk flts k k (k + 1)) := by @@ -395,6 +406,9 @@ theorem kstar_eq {α : Type*} (l : Language α) : l∗ = (l - 1)∗ := by exact ⟨fun ⟨S, hx, h⟩ => ⟨S, ⟨hx, fun y ys => h y ys⟩⟩, fun ⟨S, ⟨hx, h⟩⟩ => ⟨S, hx, fun y ys => h y ys⟩⟩ +/-- A run from `k` to `k` whose interior states are all at most `k` is a concatenation of runs from +`k` to `k` whose interior states are all below `k`. +In Kleene's algorithm, this is the "star" in the recursion. -/ theorem language_bddpath_kstar (flts : FLTS (Fin n) Symbol) (k : Fin n) : language (BddPath.mk flts k k (k + 1)) = (language (BddPath.mk flts k k k))∗ := by rw [← mul_one (language (BddPath.mk flts k k ↑k))∗, kstar_eq] @@ -451,6 +465,9 @@ noncomputable def Regex (flts : FLTS (Fin n) Symbol) (i j : Fin n) : ℕ → Reg let kFin : Fin n := ⟨k, by omega⟩ Regex flts i j k + Regex flts i kFin k * (Regex flts kFin kFin k).star * Regex flts kFin j k +/-- Shows the correctness of Kleene's algorithm. +`Regex flts i j k` exactly matches the strings that have a run starting +at `i`, ending at `j`, and having all interior states below `k`. -/ theorem language_bddpath_eq_regex {k : ℕ} {flts : FLTS (Fin n) Symbol} {i j : Fin n} : language (BddPath.mk flts i j k) = (Regex flts i j k).matches' := by induction k generalizing i j with From 8d895c8ea0e0f139ab62ce171355e907976d6382 Mon Sep 17 00:00:00 2001 From: Brooke Gill <96643991+brooke-gill@users.noreply.github.com> Date: Tue, 8 Sep 2026 14:31:24 -0700 Subject: [PATCH 80/89] Added docstrings to slightly less important theorems --- Cslib/Computability/Languages/KleeneAlgorithm.lean | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Cslib/Computability/Languages/KleeneAlgorithm.lean b/Cslib/Computability/Languages/KleeneAlgorithm.lean index bdbd739cdc..b7563b1e5b 100644 --- a/Cslib/Computability/Languages/KleeneAlgorithm.lean +++ b/Cslib/Computability/Languages/KleeneAlgorithm.lean @@ -171,6 +171,8 @@ theorem splitLastCompl_eq {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : List (h : k ∉ PathSupp flts i xs) (h' : k = flts.mtr i xs) : splitLastCompl flts i k xs = [] := by simpa [splitLast_eq h h'] using splitLastCompl_append flts i k xs +/-- `splitLast flts i k xs` is non-empty exclusively when the run from `i` over xs visits +`k` at some step AFTER the start. -/ theorem splitLast_nonempty_iff_mem_PathSupp {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : List Symbol} (hxs : xs ≠ []) : ¬(splitLast flts i k xs = []) ↔ k ∈ PathSupp flts i xs ∨ k = flts.mtr i xs := by @@ -182,6 +184,8 @@ theorem splitLast_nonempty_iff_mem_PathSupp {flts : FLTS (Fin n) Symbol} {i k : grind [pathSupp_head hxs', splitLast, (isPrefix_splitLast flts (flts.tr i a) k xs).length_le] +/-- `splitLastCompl flts i k xs` is not all of `xs` exclusively when the run from `i` over xs visits +`k` at some step AFTER the start. -/ theorem splitLastCompl_neq_iff_mem_PathSupp {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : List Symbol} (hxs : xs ≠ []) : ¬(splitLastCompl flts i k xs = xs) ↔ k ∈ PathSupp flts i xs ∨ k = flts.mtr i xs := by @@ -189,6 +193,8 @@ theorem splitLastCompl_neq_iff_mem_PathSupp {flts : FLTS (Fin n) Symbol} {i k : nth_rw 2 [← splitLastCompl_append flts i k xs] simp +/-- The run of `a :: xs` from `i` to `j` having `k` as the largest interior state and +no prefix of `a :: xs` (of length 1 or more) ending at state `k` cannot both be true. -/ theorem splitLast_aux {flts : FLTS (Fin n) Symbol} {i j k : Fin n} {xs : List Symbol} {a : Symbol} (h : a :: xs ∈ language (BddPath.mk flts i j (k + 1))) (h' : a :: xs ∉ language (BddPath.mk flts i j k)) @@ -334,6 +340,9 @@ theorem splitFirst_append (flts : FLTS (Fin n) Symbol) (i k : Fin n) (xs : List splitFirst flts i k xs ++ splitFirstCompl flts i k xs = xs := by grind [splitFirstCompl] +/-- If the run of `xs` from `i` to `k` has all interior states below `k + 1`, then + `splitFirst flts i k xs` (the shortest prefix of `xs`) + is a path whose interior states are all below `k`. -/ theorem splitFirst_mem {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : List Symbol} (h : xs ∈ (language (BddPath.mk flts i k (k + 1)))) : splitFirst flts i k xs ∈ language (BddPath.mk flts i k k) := by @@ -363,6 +372,9 @@ theorem splitFirst_mem_nonempty {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : | nil => contradiction | cons a xs ih => grind [splitFirst] +/-- If the run of `xs` from `i` to `k` has all interior states below `k + 1`, then + `splitFirstCompl flts i k xs` (the longest suffix of `xs` starting at `k`) + is a path from `k` to `k` whose interior states are all below `k + 1`. -/ theorem splitFirstCompl_mem {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : List Symbol} (h : xs ∈ (language (BddPath.mk flts i k (k + 1)))) : splitFirstCompl flts i k xs ∈ language (BddPath.mk flts k k (k + 1)) := by From 0d274b3b607ead6f135e6f402478bffdbbb4f04c Mon Sep 17 00:00:00 2001 From: Brooke Gill <96643991+brooke-gill@users.noreply.github.com> Date: Tue, 8 Sep 2026 14:51:58 -0700 Subject: [PATCH 81/89] Fixed double newlines --- Cslib/Computability/Languages/KleeneAlgorithm.lean | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Cslib/Computability/Languages/KleeneAlgorithm.lean b/Cslib/Computability/Languages/KleeneAlgorithm.lean index b7563b1e5b..9ee510358d 100644 --- a/Cslib/Computability/Languages/KleeneAlgorithm.lean +++ b/Cslib/Computability/Languages/KleeneAlgorithm.lean @@ -19,7 +19,6 @@ regular expression. We prove this by induction on a bound (k) that restricts which interior states a run may pass through. - ## Main definitions - `PathSupp`: The interior states of a run - `BddPath`: A transition system containing a start state, finish state, and a specific bound on @@ -28,14 +27,12 @@ through. whose interior states are all under a specific bound `k` ## Main results - - `regex_of_dfa_singleton_accept`: DFAs with one accepting state have a matching regular expression - `language_bddpath_eq_dfa`: A bound that has reached the total number of states no longer -constrains anything + constrains anything - `language_bddpath_eq_regex`: `Regex flts i j k` matches exactly the same paths from `i` to `j` -with interior states below `k` - + with interior states below `k` ## References @@ -509,6 +506,7 @@ theorem language_dfa_eq_regex_of_singleton_accept {dfa : DA.FinAcc (Fin n) Symbo end Regex +/-- DFAs with one accepting state have a matching regular expression -/ theorem regex_of_dfa_singleton_accept [Finite Symbol] {State : Type*} [Finite State] (dfa : DA.FinAcc State Symbol) (h : ∃ s, dfa.accept = {s}) : ∃ r : RegularExpression Symbol, language dfa = r.matches' := by From d8cc3ad59e2dcfbbebdc3cd2dff91fce20d6b68d Mon Sep 17 00:00:00 2001 From: Chi-Yun Hsu Date: Tue, 8 Sep 2026 15:53:12 -0700 Subject: [PATCH 82/89] Notational Cleanups --- .../Languages/KleeneAlgorithm.lean | 55 +- .../Languages/RegularLanguage.lean | 592 +----------------- 2 files changed, 46 insertions(+), 601 deletions(-) diff --git a/Cslib/Computability/Languages/KleeneAlgorithm.lean b/Cslib/Computability/Languages/KleeneAlgorithm.lean index 9ee510358d..a7c55efa11 100644 --- a/Cslib/Computability/Languages/KleeneAlgorithm.lean +++ b/Cslib/Computability/Languages/KleeneAlgorithm.lean @@ -14,17 +14,19 @@ public import Mathlib.Computability.RegularExpressions /-! # Kleene's Algorithm -Every language accepted by a DFA on a set comprised of finite states is the language of a -regular expression. -We prove this by induction on a bound (k) that restricts which interior states a run may pass -through. +Kleene's algorithm constructs a regular expresssion by induction on a bound `k` that restricts +which interior states a run may pass through. +It is used to prove `Cslib.Language.IsRegular.iff_regex`, that every language accepted by +a DFA comprised of finite states is the language of a regular expression. +The special case where the DFA has only one accepting state is proved in +`regex_of_dfa_singleton_accept` in this file. ## Main definitions - `PathSupp`: The interior states of a run - `BddPath`: A transition system containing a start state, finish state, and a specific bound on - all interior states +all interior states - `Regex flts i j k`: The regular expression for the paths from state `i` to state `j`, - whose interior states are all under a specific bound `k` +whose interior states are all under a specific bound `k` ## Main results - `regex_of_dfa_singleton_accept`: DFAs with one accepting state have a matching regular @@ -52,8 +54,8 @@ section PathSupp variable {State : Type*} -/-- PathSupp s xs is the set of states that can be reached from state s by reading the string xs, -not including the starting state and the ending state. -/ +/-- `PathSupp s xs` is the set of states that can be reached from state `s` by reading +the string `xs`, not including the starting state and the ending state. -/ def PathSupp (flts : FLTS State Symbol) : State → List Symbol → Set State | _, [] | _, [_] => ∅ | s, a :: x => {flts.tr s a} ∪ PathSupp flts (flts.tr s a) x @@ -66,7 +68,7 @@ theorem pathSupp_empty_iff_empty_or_char {flts : FLTS State Symbol} {s : State} have : flts.tr s x ∈ PathSupp flts s (x :: y :: ys) := by grind [PathSupp] grind -/-- If xs is nonempty, then the interior states of the run that starts at `s` and reads `a :: xs` +/-- If `xs` is nonempty, then the interior states of the run that starts at `s` and reads `a :: xs` consist of the state reached after reading `a` as well as the interior states of the run that starts at `flts.tr s a` and reads `xs`. -/ theorem pathSupp_head {flts : FLTS State Symbol} {s : State} {a : Symbol} {xs : List Symbol} @@ -137,11 +139,11 @@ theorem isPrefix_splitLast (flts : FLTS (Fin n) Symbol) (i k : Fin n) (xs : List | nil => simp [splitLast] | cons a xs ih => grind [splitLast] -/-- Starting at state `i`, the function `splitLast` sends a string to its shortest suffix +/-- Starting at state `i`, the function `splitLastCompl` sends a string to its shortest suffix starting at state `k`. -If the string ends at state `k`, then `splitLast` returns the empty string. +If the string ends at state `k`, then `splitLastCompl` returns the empty string. If the string never passes through state `k` (starting state can be `k`), -then `splitLast` returns the original string. -/ +then `splitLastCompl` returns the original string. -/ noncomputable def splitLastCompl (flts : FLTS (Fin n) Symbol) (i k : Fin n) (xs : List Symbol) : List Symbol := (isPrefix_splitLast flts i k xs).choose @@ -168,8 +170,8 @@ theorem splitLastCompl_eq {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : List (h : k ∉ PathSupp flts i xs) (h' : k = flts.mtr i xs) : splitLastCompl flts i k xs = [] := by simpa [splitLast_eq h h'] using splitLastCompl_append flts i k xs -/-- `splitLast flts i k xs` is non-empty exclusively when the run from `i` over xs visits -`k` at some step AFTER the start. -/ +/-- `splitLast flts i k xs` is non-empty exclusively when the run from `i` over `xs` +visits `k` at some step AFTER the start. -/ theorem splitLast_nonempty_iff_mem_PathSupp {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : List Symbol} (hxs : xs ≠ []) : ¬(splitLast flts i k xs = []) ↔ k ∈ PathSupp flts i xs ∨ k = flts.mtr i xs := by @@ -181,8 +183,8 @@ theorem splitLast_nonempty_iff_mem_PathSupp {flts : FLTS (Fin n) Symbol} {i k : grind [pathSupp_head hxs', splitLast, (isPrefix_splitLast flts (flts.tr i a) k xs).length_le] -/-- `splitLastCompl flts i k xs` is not all of `xs` exclusively when the run from `i` over xs visits -`k` at some step AFTER the start. -/ +/-- `splitLastCompl flts i k xs` is not all of `xs` exclusively when the run from `i` over `xs` +visits `k` at some step AFTER the start. -/ theorem splitLastCompl_neq_iff_mem_PathSupp {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : List Symbol} (hxs : xs ≠ []) : ¬(splitLastCompl flts i k xs = xs) ↔ k ∈ PathSupp flts i xs ∨ k = flts.mtr i xs := by @@ -213,8 +215,8 @@ theorem splitLast_aux {flts : FLTS (Fin n) Symbol} {i j k : Fin n} {xs : List Sy · grind [(splitLast_nonempty_iff_mem_PathSupp hxs).mpr (Or.inl hx2)] /-- If the run of `xs` from `i` to `j` has `k` as the largest interior state, then - `splitLast flts i k xs` (the longest prefix ending at `k`) - is a path from `i` to `k` whose interior states are all below `k + 1`. -/ +`splitLast flts i k xs` (the longest prefix of `xs` ending at `k`) +is a path from `i` to `k` whose interior states are all below `k + 1`. -/ theorem splitLast_mem {flts : FLTS (Fin n) Symbol} {i j k : Fin n} {xs : List Symbol} (h : xs ∈ language (BddPath.mk flts i j (k + 1))) (h' : xs ∉ language (BddPath.mk flts i j k)) : @@ -246,8 +248,8 @@ theorem splitLast_mem {flts : FLTS (Fin n) Symbol} {i j k : Fin n} {xs : List Sy simpa [hc1, Accepts, PathSupp, FLTS.mtr] using hc /-- If the run of `xs` from `i` to `j` has `k` as the largest interior state, then - `splitLastCompl flts i k xs` (which is the shortest suffix of `xs` starting at `k`) - is a path from `k` to `j` whose interior states are all below `k`. -/ +`splitLastCompl flts i k xs` (the shortest suffix of `xs` starting at `k`) +is a path from `k` to `j` whose interior states are all below `k`. -/ theorem splitLastCompl_mem {flts : FLTS (Fin n) Symbol} {i j k : Fin n} {xs : List Symbol} (h : xs ∈ language (BddPath.mk flts i j (k + 1))) (h' : xs ∉ language (BddPath.mk flts i j k)) : @@ -286,11 +288,11 @@ theorem splitLastCompl_mem {flts : FLTS (Fin n) Symbol} {i j k : Fin n} {xs : Li · grind [splitLastCompl_eq, PathSupp] grind [splitLastCompl_append, splitLast_nonempty_iff_mem_PathSupp, pathSupp_head] -/-- The recursion step of Kleene's algorithm. +/-- Part of the recursion step of Kleene's algorithm. A run from `i` to `j` whose interior states are all at most `k` either has no interior state equal to `k`, or it splits at its last visit to `k` into a run from `i` to `k` with interior states below `k + 1`, followed by a run from `k` to `j` with interior states below `k`. -/ -theorem language_bddpath_splitLastCompl (flts : FLTS (Fin n) Symbol) (i j k : Fin n) : +theorem language_bddpath_splitLast (flts : FLTS (Fin n) Symbol) (i j k : Fin n) : language (BddPath.mk flts i j (k + 1)) = language (BddPath.mk flts i j k) + (language (BddPath.mk flts i k (k + 1)) * language (BddPath.mk flts k j k)) := by ext xs @@ -383,7 +385,7 @@ theorem splitFirstCompl_mem {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : Lis · grind [PathSupp] grind [pathSupp_append] -/-- Part of Kleene's algorithm. +/-- Part of the recursion step of Kleene's algorithm. A run from `i` to `j` whose interior states are all at most `k` splits upon first reaching `k`. The part before the visit is a run from `i` to `k` with interior states below `k`. The part after it is a run from `k` to `k` with interior states below `k + 1`. -/ @@ -415,7 +417,8 @@ theorem kstar_eq {α : Type*} (l : Language α) : l∗ = (l - 1)∗ := by exact ⟨fun ⟨S, hx, h⟩ => ⟨S, ⟨hx, fun y ys => h y ys⟩⟩, fun ⟨S, ⟨hx, h⟩⟩ => ⟨S, hx, fun y ys => h y ys⟩⟩ -/-- A run from `k` to `k` whose interior states are all at most `k` is a concatenation of runs from +/-- Part of the recursion step of Kleene's algorithm. +A run from `k` to `k` whose interior states are all at most `k` is a concatenation of runs from `k` to `k` whose interior states are all below `k`. In Kleene's algorithm, this is the "star" in the recursion. -/ theorem language_bddpath_kstar (flts : FLTS (Fin n) Symbol) (k : Fin n) : @@ -474,7 +477,7 @@ noncomputable def Regex (flts : FLTS (Fin n) Symbol) (i j : Fin n) : ℕ → Reg let kFin : Fin n := ⟨k, by omega⟩ Regex flts i j k + Regex flts i kFin k * (Regex flts kFin kFin k).star * Regex flts kFin j k -/-- Shows the correctness of Kleene's algorithm. +/-- The correctness of Kleene's algorithm. `Regex flts i j k` exactly matches the strings that have a run starting at `i`, ending at `j`, and having all interior states below `k`. -/ theorem language_bddpath_eq_regex {k : ℕ} {flts : FLTS (Fin n) Symbol} {i j : Fin n} : @@ -495,7 +498,7 @@ theorem language_bddpath_eq_regex {k : ℕ} {flts : FLTS (Fin n) Symbol} {i j : simp only [Regex] split_ifs with hk · rw [← ih, language_bddpath_eq_dfa flts i j hk, language_bddpath_eq_dfa flts i j (by omega)] - rw [language_bddpath_splitLastCompl (k := ⟨k, by omega⟩), language_bddpath_splitFirst, + rw [language_bddpath_splitLast (k := ⟨k, by omega⟩), language_bddpath_splitFirst, language_bddpath_kstar] grind [matches'_add, matches'_mul, matches'_star] diff --git a/Cslib/Computability/Languages/RegularLanguage.lean b/Cslib/Computability/Languages/RegularLanguage.lean index e94ca98553..37f791be85 100644 --- a/Cslib/Computability/Languages/RegularLanguage.lean +++ b/Cslib/Computability/Languages/RegularLanguage.lean @@ -14,16 +14,12 @@ public import Cslib.Computability.Automata.NA.Loop public import Cslib.Computability.Automata.NA.Reverse public import Cslib.Computability.Automata.NA.ToDA public import Cslib.Computability.Automata.Acceptors.Acceptor --- public import Cslib.Computability.Languages.KleeneAlgorithm +public import Cslib.Computability.Languages.KleeneAlgorithm public import Mathlib.Computability.DFA public import Mathlib.Computability.RegularExpressions public import Mathlib.Data.Finite.Sum public import Mathlib.Data.Set.Card -public import Mathlib.Computability.NFA -public import Mathlib.Computability.EpsilonNFA -public import Cslib.Computability.Languages.RegularExpressions - /-! # Regular languages -/ @@ -221,13 +217,17 @@ theorem IsRegular.char (a : Symbol) : ({[a]} : Language Symbol).IsRegular := by let flts := FLTS.mk (fun (s : Fin 3) (x : Symbol) ↦ if (s = 0 ∧ x = a) then 1 else 2) use Fin 3, inferInstance, ⟨DA.mk flts 0, {1}⟩ ext xs - induction xs using List.reverseRec with + induction xs using reverseRec with | nil => grind [Accepts, Language.mem_singleton] | append_singleton xs x ih => simp only [mem_language, Accepts, Language.mem_singleton, FLTS.mtr_concat_eq] at ih ⊢ constructor - · induction xs using List.reverseRec <;> grind - · simp_all [flts, List.append_eq_cons_iff] + · induction xs using reverseRec <;> grind + · simp_all [flts, append_eq_cons_iff] + +section RegularExpression + +open RegularExpression /-- Languages matching regular expressions are regular. -/ theorem IsRegular.regex {r : RegularExpression Symbol} : @@ -236,571 +236,10 @@ theorem IsRegular.regex {r : RegularExpression Symbol} : | zero => simp | epsilon => simp | char a => simp [IsRegular.char a] - | plus P Q hP hQ => grind [RegularExpression.matches', IsRegular.add] - | comp P Q hP hQ => grind [RegularExpression.matches', IsRegular.mul] - | star P hP => grind [RegularExpression.matches', IsRegular.kstar] - -/- We use Kleene's Algorithm for DFA to prove a regular language can be expressed as a regex. -/ - -open RegularExpression - --- We do not need this anymore --- Ask Chou whether to add reindex lemma for cslib DFA, --- rather than using reindex lemma for mathlib DFA. -theorem IsRegular.iff_dfa' {l : Language Symbol} : - l.IsRegular ↔ ∃ (n : ℕ), ∃ dfa : DA.FinAcc (Fin n) Symbol, language dfa = l := by - rw [IsRegular.iff_dfa] - constructor - · rintro ⟨State, h_fin, ⟨⟨flts, start⟩, acc⟩, rfl⟩ - have : Fintype State := Fintype.ofFinite State - let dfa := DFA.mk flts.tr start acc -- mathlib - let dfa2 := DFA.reindex (Fintype.equivFin State) dfa -- mathlib on Fin n - let dfa3 := DA.FinAcc.mk {tr := dfa2.step, start := dfa2.start} dfa2.accept -- cslib on Fin n - exact ⟨Fintype.card State, dfa3, DFA.accepts_reindex dfa (Fintype.equivFin State)⟩ - -- exact ⟨n, dfa3, DFA.accepts_reindex dfa (Fintype.equivFin State)⟩ - -- exact DFA.accepts_reindex dfa (Fintype.equivFin State) - · intro ⟨n, dfa, h⟩ - exact ⟨Fin n, inferInstance, dfa, h⟩ - -/-- -Regex i j k is the regex for the path from state i to state j passing through states < k. -When k = 0, i = j, the regex is ε union all characters from state i to state i. -When k = 0, i ≠ j, the regex is all characters from state i to state j. -For k + 1, the regex is the union of Regex i j k and -(Regex i k k) (Regex k k k)∗ (Regex k j k). --/ -noncomputable def Regex [Fintype Symbol] {n : ℕ} (flts : FLTS (Fin n) Symbol) - (i j : Fin n) : ℕ → RegularExpression Symbol - | 0 => - let chars := (Finset.univ.filter - (fun x : Symbol ↦ flts.tr i x = j)).toList.map RegularExpression.char - if i = j then 1 + chars.sum else chars.sum - | k + 1 => - if h : n ≤ k then Regex flts i j k - else - let kFin : Fin n := ⟨k, by omega⟩ - Regex flts i j k + Regex flts i kFin k * (Regex flts kFin kFin k).star * Regex flts kFin j k - -#check εNFA.IsPath --- Mimicing the definition of NFA.Path. Path s xs is the type of --- inductive Path : State → List Symbol → Type (max u_1 u_2) --- | nil (s : State) : Path s [] --- | cons (s u : State) (a : Symbol) (x : List Symbol) : Path (flts.tr s a) x → Path s (a :: x) - -/-- PathSupp s xs is the set of states that can be reached from state s by reading the string xs, -not including the starting state and the ending state. -/ -def PathSupp {State : Type*} (flts : FLTS State Symbol) : State → List Symbol → Set State - | _, [] | _, [_] => ∅ - | s, a :: x => {flts.tr s a} ∪ PathSupp flts (flts.tr s a) x - -lemma pathSupp_empty_iff_empty_or_char {State : Type*} {flts : FLTS State Symbol} {s : State} - {xs : List Symbol} : PathSupp flts s xs = ∅ ↔ xs = [] ∨ (∃ a : Symbol, xs = [a]) := by - match xs with - | [] | [_] => grind [PathSupp] - | x :: y :: ys => - have : flts.tr s x ∈ PathSupp flts s (x :: y :: ys) := by grind [PathSupp] - grind - -lemma pathSupp_head {State : Type*} {flts : FLTS State Symbol} {s : State} - {a : Symbol} {xs : List Symbol} (hxs : xs ≠ []) : - PathSupp flts s (a :: xs) = {flts.tr s a} ∪ PathSupp flts (flts.tr s a) xs := by - grind [PathSupp] - -lemma pathSupp_append {State : Type*} {flts : FLTS State Symbol} {s : State} - {xs ys : List Symbol} (hxs : xs ≠ [] ∧ ys ≠ []) : - PathSupp flts s (xs ++ ys) = - {flts.mtr s xs} ∪ PathSupp flts s xs ∪ PathSupp flts (flts.mtr s xs) ys := by - induction xs generalizing s with - | nil => grind [PathSupp] - | cons a xs ih => - rw [List.cons_append, pathSupp_head (by simp [hxs.2])] - by_cases hx : xs = [] - · grind [PathSupp] - · grind [pathSupp_head hx] - -structure BddPath (n : ℕ) (Symbol : Type*) extends FLTS (Fin n) Symbol where - start : Fin n - finish : Fin n - bound : ℕ - -instance {n : ℕ} : Acceptor (BddPath n Symbol) Symbol where - Accepts (a : BddPath n Symbol) (xs : List Symbol) := - a.mtr a.start xs = a.finish ∧ (∀ i ∈ PathSupp a.toFLTS a.start xs, i < a.bound) - -lemma language_bddpath_eq_dfa {n k : ℕ} (flts : FLTS (Fin n) Symbol) (i j : Fin n) (hk : n ≤ k) : - language (BddPath.mk flts i j k) = - language (DA.FinAcc.mk {tr := flts.tr, start := i} {j}) := by - ext xs - simp only [mem_language, Accepts] - grind - -/-- The function sending a string to its shortest suffix which starts at state `t`. -If the string ends at state `t`, then the function returns the empty string. -If the string never passes through state `t` (starting state can be `t`), -then the function returns the original string. -/ -def splitLast [DecidableEq Symbol] {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) : - List Symbol → List Symbol - | [] => [] - | a :: x => if (splitLast flts (flts.tr s a) t x = x) ∧ flts.tr s a ≠ t then a :: x - else splitLast flts (flts.tr s a) t x - -lemma isSuffix_splitLast [DecidableEq Symbol] {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) - (xs : List Symbol) : IsSuffix (splitLast flts s t xs) xs := by - induction xs generalizing s with - | nil => simp [splitLast] - | cons a xs ih => grind [splitLast] - --- noncomputable def splitLastCompl' [DecidableEq Symbol] {n : ℕ} (flts : FLTS (Fin n) Symbol) --- (s t : Fin n) (xs : List Symbol) : List Symbol := (isSuffix_splitLast flts s t xs).choose - -def splitLastCompl {n : ℕ} (flts : FLTS (Fin n) Symbol) - (s t : Fin n) : List Symbol → List Symbol - | [] => [] - | a :: x => if (splitLastCompl flts (flts.tr s a) t x = []) ∧ flts.tr s a ≠ t then [] - else a :: splitLastCompl flts (flts.tr s a) t x - --- lemma splitLast_append' [DecidableEq Symbol] {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) --- (xs : List Symbol) : --- splitLastCompl' flts s t xs ++ splitLast flts s t xs = xs := by --- grind [splitLast, splitLastCompl'] - -lemma splitLast_append [DecidableEq Symbol] {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) - (xs : List Symbol) : - splitLastCompl flts s t xs ++ splitLast flts s t xs = xs := by - induction xs generalizing s with - | nil => grind [splitLast, splitLastCompl] - | cons a xs ih => - simp only [splitLast, splitLastCompl] - split_ifs with h h' h' - · simp - · grind [ih (s := flts.tr s a)] - · have := h'.1 ▸ ih (s := flts.tr s a) - simp at this - grind - · simpa using ih (s := flts.tr s a) - --- Combine the following two lemmas into one lemma. -lemma splitLast_neq_iff_mem_PathSupp [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} - {s t : Fin n} {xs : List Symbol} (hxs : xs ≠ []) : - ¬(splitLast flts s t xs = xs) ↔ t ∈ PathSupp flts s xs ∨ t = flts.mtr s xs := by - induction xs generalizing s with - | nil => contradiction - | cons a xs ih => - by_cases hxs' : xs = [] - · grind [splitLast, PathSupp] - rw [pathSupp_head hxs', Set.mem_union, Set.mem_singleton_iff] - grind [splitLast, (isSuffix_splitLast flts (flts.tr s a) t xs).length_le] - --- lemma splitLast_neq_of_mem_PathSupp [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} --- {s t : Fin n} {xs : List Symbol} (h : t ∈ PathSupp flts s xs) : --- ¬(splitLast flts s t xs = xs) := by --- induction xs generalizing s with --- | nil => grind [splitLast, PathSupp] --- | cons a xs ih => --- by_cases hxs : xs = [] --- · grind [splitLast, PathSupp] --- rw [pathSupp_head hxs, Set.mem_union, Set.mem_singleton_iff] at h --- grind [splitLast, (isSuffix_splitLast flts (flts.tr s a) t xs).length_le] - --- lemma mem_PathSupp_of_neq_splitLast [DecidableEq Symbol] {n : ℕ} --- {flts : FLTS (Fin n) Symbol} {s t : Fin n} {xs : List Symbol} --- (h : ¬(splitLast flts s t xs = xs)) : --- t ∈ PathSupp flts s xs ∨ t = flts.mtr s xs := by --- induction xs generalizing s with --- | nil => contradiction --- | cons a xs ih => --- by_cases hxs : xs = [] <;> grind [splitLast, PathSupp] - -lemma splitLast_eq [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} - {s t : Fin n} {xs : List Symbol} (h : t ∉ PathSupp flts s xs) (h' : t = flts.mtr s xs) : - splitLast flts s t xs = [] := by - induction xs generalizing s with - | nil => grind [splitLast, PathSupp] - | cons a xs ih => - by_cases hxs : xs = [] - · grind [splitLast, PathSupp] - rw [pathSupp_head hxs, Set.mem_union, Set.mem_singleton_iff] at h - grind [splitLast, (isSuffix_splitLast flts (flts.tr s a) t xs).length_le] - -- simpa [splitLastCompl_eq h h'] using splitLast_append flts s t xs - -lemma splitLastCompl_eq {n : ℕ} {flts : FLTS (Fin n) Symbol} - {s t : Fin n} {xs : List Symbol} (h : t ∉ PathSupp flts s xs) (h' : t = flts.mtr s xs) : - splitLastCompl flts s t xs = xs := by - classical - simpa [splitLast_eq h h'] using splitLast_append flts s t xs - -- induction xs generalizing s with - -- | nil => grind [splitLastCompl, PathSupp] - -- | cons a xs ih => - -- by_cases hxs : xs = [] - -- · grind [splitLastCompl, PathSupp] - -- rw [pathSupp_head hxs, Set.mem_union, Set.mem_singleton_iff] at h - -- grind [splitLastCompl, (isSuffix_splitLast flts (flts.tr s a) t xs).length_le] - -theorem splitLastCompl_nonempty_iff_mem_PathSupp {n : ℕ} {flts : FLTS (Fin n) Symbol} - {s t : Fin n} {xs : List Symbol} (hxs : xs ≠ []) : - ¬(splitLastCompl flts s t xs = []) ↔ t ∈ PathSupp flts s xs ∨ t = flts.mtr s xs := by - classical - rw [← splitLast_neq_iff_mem_PathSupp hxs, not_iff_not] - nth_rw 3 [← splitLast_append flts s t xs] - simp - --- lemma mem_PathSupp_of_nonempty_splitLastCompl [DecidableEq Symbol] {n : ℕ} --- {flts : FLTS (Fin n) Symbol} {s t : Fin n} {xs : List Symbol} --- (h : ¬(splitLastCompl flts s t xs = [])) : --- t ∈ PathSupp flts s xs ∨ t = flts.mtr s xs := by --- induction xs generalizing s with --- | nil => contradiction --- | cons a xs ih => --- by_cases hxs : xs = [] <;> grind [splitLastCompl, PathSupp] - --- theorem mtr_head_eq {State Label : Type*} {flts : FLTS State Label} {s : State} --- {x : Label} {xs : List Label} : flts.mtr s (x :: xs) = flts.mtr (flts.tr s x) xs := by grind - --- theorem mtr_append_eq {State Label : Type*} {flts : FLTS State Label} {s : State} --- {xs ys : List Label} : flts.mtr s (xs ++ ys) = flts.mtr (flts.mtr s xs) ys := by grind - -lemma splitLast_aux [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} - {i j k : Fin n} {xs : List Symbol} {a : Symbol} - (h : a :: xs ∈ language (BddPath.mk flts i j (k.val + 1))) - (h' : a :: xs ∉ language (BddPath.mk flts i j k.val)) - (hc : splitLast flts (flts.tr i a) k xs = xs ∧ flts.tr i a ≠ k) : False := by - simp only [mem_language, Accepts, Order.lt_add_one_iff, Fin.val_fin_le, Fin.val_fin_lt, not_and, - not_forall, not_lt, ne_eq] at * - -- simp only [mtr_head_eq] at * - simp only [h, forall_const] at h' - obtain ⟨x, ⟨hx, hxk⟩⟩ := h' - have eq := le_antisymm (h.2 x hx) hxk - rw [eq] at hx - by_cases hxs : xs = [] - · grind [PathSupp] - rw [pathSupp_head hxs] at hx h - rcases hx with hx1 | hx2 - · have := hc.2 - simp only [mem_singleton_iff] at hx1 - symm at hx1 - contradiction - · grind [(splitLast_neq_iff_mem_PathSupp hxs).mpr (Or.inl hx2)] - -lemma language_bddpath_head_iff {n : ℕ} {flts : FLTS (Fin n) Symbol} - {i j : Fin n} {k : ℕ} {a : Symbol} {xs : List Symbol} : - a :: xs ∈ language (BddPath.mk flts i j k) ↔ - xs ∈ language (BddPath.mk flts (flts.tr i a) j k) ∧ (flts.tr i a < k ∨ xs = []) := by - simp only [mem_language, Accepts] - by_cases hxs : xs = [] - · grind [PathSupp] - grind [pathSupp_head hxs] - -lemma splitLast_mem [DecidableEq Symbol] {n : ℕ} {flts : FLTS (Fin n) Symbol} - {i j k : Fin n} {xs : List Symbol} - (h : xs ∈ language (BddPath.mk flts i j (k.val + 1))) - (h' : xs ∉ language (BddPath.mk flts i j k.val)) : - splitLast flts i k xs ∈ language (BddPath.mk flts k j k.val) := by - induction xs generalizing i with - | nil => - simp [Accepts, PathSupp] at h h' - contradiction - | cons a xs ih => - simp only [splitLast] - split_ifs with hc - · exfalso; exact splitLast_aux h h' hc - · rw [not_and_or, not_not] at hc - -- The last `k` is later than `flts.tr i a` or equal to it. - by_cases hc1 : ¬splitLast flts (flts.tr i a) k xs = xs - · by_cases hxs : xs = [] - · grind [splitLast] - -- First hypothesis of `ih` is implied by `h` - have haux := language_bddpath_head_iff.mp h - simp only [hxs, or_false] at haux - -- Assumptions `h` and `h'` combined says that `k ∈ PathSupp flts i (a :: xs)` - by_cases hk : k ∈ PathSupp flts (flts.tr i a) xs - · -- `k` appears in PathSupp - apply ih haux.1 - simp [Accepts] - grind - · -- `k` only appears at the end state - -- `hk` should contradict with `h` and `h'` - apply (splitLast_neq_iff_mem_PathSupp hxs).mp at hc1 - simp_all [Accepts, PathSupp, splitLast_eq] - · -- The last `k` is equal to `flts.tr i a` - -- Cannot apply ih - -- Directly prove the goal from definition - grind [language_bddpath_head_iff.mp h] - -lemma splitLastCompl_mem {n : ℕ} {flts : FLTS (Fin n) Symbol} - {i j k : Fin n} {xs : List Symbol} - (h : xs ∈ language (BddPath.mk flts i j (k.val + 1))) - (h' : xs ∉ language (BddPath.mk flts i j k.val)) : - splitLastCompl flts i k xs ∈ language (BddPath.mk flts i k (k.val + 1)) := by - classical - induction xs generalizing i with - | nil => - simp [Accepts, PathSupp] at h h' - contradiction - | cons a xs ih => - simp only [splitLastCompl] - split_ifs with hc - · exfalso; exact splitLast_aux h h' (by grind [splitLast_append]) - · rw [not_and_or, not_not] at hc - -- The last `k` is later than `flts.tr i a` or equal to it. - by_cases hc1 : ¬splitLastCompl flts (flts.tr i a) k xs = [] - · by_cases hxs : xs = [] - · grind [splitLastCompl] - have haux := language_bddpath_head_iff.mp h - simp only [hxs, or_false] at haux - refine language_bddpath_head_iff.mpr ⟨?_, Or.inl haux.2⟩ - by_cases hk : k ∈ PathSupp flts (flts.tr i a) xs - · apply ih haux.1 - simp [Accepts] - grind - · have eq : k = flts.mtr (flts.tr i a) xs := by - simpa [hk] using (splitLastCompl_nonempty_iff_mem_PathSupp hxs).mp hc1 - rw [splitLastCompl_eq hk eq] - grind [h.1] - -- simpa [← mtr_head_eq, eq, h.1] using haux.1 - · rw [not_not] at hc1 - simpa [hc1, Accepts, PathSupp, FLTS.mtr] using hc - -lemma path1 {n : ℕ} (flts : FLTS (Fin n) Symbol) (i j k : Fin n) : - language (BddPath.mk flts i j (k + 1)) = language (BddPath.mk flts i j k) + - (language (BddPath.mk flts i k (k + 1)) * language (BddPath.mk flts k j k)) := by - classical - ext xs - rw [Language.mem_add, Language.mem_mul] - constructor - · intro h - by_cases h' : xs ∈ language (BddPath.mk flts i j k) - · left; exact h' - right - use splitLastCompl flts i k xs, splitLastCompl_mem h h', - splitLast flts i k xs, splitLast_mem h h', - splitLast_append flts _ _ _ - · rintro (h_left | ⟨ys, ⟨⟨hys, hsuppys⟩, ⟨zs, ⟨⟨hzs, hsuppzs⟩, happend⟩⟩⟩⟩) - · simp only [mem_language, Accepts] at h_left ⊢ - grind - · refine ⟨by grind, ?_⟩ - by_cases ys = [] ∨ zs = [] - · grind - grind [pathSupp_append] - -/-- The function sending a string to its shortest prefix which ends at state `t`. -The function returns the empty string if and only if the string is empty. -If the string never passes through state `t` (starting state can be `t`), -then the function returns the original string. -/ -def splitFirst {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) : List Symbol → List Symbol - | [] => [] - | a :: x => if flts.tr s a = t then [a] else a :: splitFirst flts (flts.tr s a) t x - -lemma isPrefix_splitFirst {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) (xs : List Symbol) : - IsPrefix (splitFirst flts s t xs) xs := by - induction xs generalizing s with - | nil => simp [splitFirst] - | cons a xs ih => grind [splitFirst] - -noncomputable def splitFirstCompl {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) - (xs : List Symbol) : List Symbol := (isPrefix_splitFirst flts s t xs).choose - -lemma splitFirst_append {n : ℕ} (flts : FLTS (Fin n) Symbol) (s t : Fin n) (xs : List Symbol) : - splitFirst flts s t xs ++ splitFirstCompl flts s t xs = xs := by - grind [splitFirst, splitFirstCompl] - -lemma splitFirst_mem {n : ℕ} {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : List Symbol} - (h : xs ∈ (language (BddPath.mk flts i k (k.val + 1)))) : - splitFirst flts i k xs ∈ language (BddPath.mk flts i k k.val) := by - induction xs generalizing i with - | nil => simpa [Accepts, splitFirst, PathSupp] using h - | cons a xs ih => - simp only [mem_language, Accepts, Order.lt_add_one_iff, splitFirst] at ih h ⊢ - obtain ⟨h1, h2⟩ := h - split_ifs with ha - · refine ⟨by grind, ?_⟩ - have : PathSupp flts i [a] = ∅ := by grind [PathSupp] - simp [this] - · have : flts.mtr i (a :: splitFirst flts (flts.tr i a) k xs) = - flts.mtr (flts.tr i a) (splitFirst flts (flts.tr i a) k xs) := by grind - by_cases hxs : xs = [] - · grind - rw [pathSupp_head hxs] at h2 - by_cases hPath : splitFirst flts (flts.tr i a) k xs = [] - · grind - rw [this, pathSupp_head hPath] - grind - -lemma splitFirst_mem' {n : ℕ} {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : List Symbol} - (hxs : xs ≠ []) (h : xs ∈ (language (BddPath.mk flts i k (k.val + 1)))) : - splitFirst flts i k xs ∈ language (BddPath.mk flts i k k.val) - 1 := by - rw [Language.mem_sub] - refine ⟨splitFirst_mem h, ?_⟩ - simp only [Language.mem_one] - induction xs with - | nil => contradiction - | cons a xs ih => grind [splitFirst] - -lemma splitFirstCompl_mem {n : ℕ} {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : List Symbol} - (h : xs ∈ (language (BddPath.mk flts i k (k.val + 1)))) : - splitFirstCompl flts i k xs ∈ language (BddPath.mk flts k k (k.val + 1)) := by - have h' := splitFirst_mem h - simp only [mem_language, Accepts] at h h' ⊢ - -- rw [← splitFirst_append flts i k xs, mtr_append_eq] at h - -- refine ⟨by simpa [h'.1] using h.1, ?_⟩ - rw [← splitFirst_append flts i k xs] at h - refine ⟨by grind, ?_⟩ - by_cases splitFirst flts i k xs = [] ∨ splitFirstCompl flts i k xs = [] - · grind [PathSupp] - grind [pathSupp_append] - -lemma path2 {n : ℕ} (flts : FLTS (Fin n) Symbol) (i k : Fin n) : - language (BddPath.mk flts i k (k + 1)) = - language (BddPath.mk flts i k k) * language (BddPath.mk flts k k (k + 1)) := by - ext xs - rw [Language.mem_mul] - constructor - · intro h - use splitFirst flts i k xs, splitFirst_mem h, - splitFirstCompl flts i k xs, splitFirstCompl_mem h, - splitFirst_append flts _ _ _ - · intro ⟨ys, ⟨⟨hys, hsuppys⟩, ⟨zs, ⟨⟨hzs, hsuppzs⟩, happend⟩⟩⟩⟩ - refine ⟨by grind, ?_⟩ - by_cases ys = [] ∨ zs = [] - · grind - grind [pathSupp_append] - -lemma kstar_eq {α : Type*} (l : Language α) : l∗ = (l - 1)∗ := by - ext x - rw [Language.kstar_def_nonempty, Language.mem_kstar] - -- aesop - exact ⟨fun ⟨S, hx, h⟩ => ⟨S, ⟨hx, fun y ys => h y ys⟩⟩, - fun ⟨S, ⟨hx, h⟩⟩ => ⟨S, hx, fun y ys => h y ys⟩⟩ - -lemma path3 {n : ℕ} (flts : FLTS (Fin n) Symbol) (k : Fin n) : - language (BddPath.mk flts k k (k + 1)) = (language (BddPath.mk flts k k k))∗ := by - rw [← mul_one (language (BddPath.mk flts k k ↑k))∗] - rw [kstar_eq] - refine (Language.self_eq_mul_add_iff (by simp [Language.mem_sub])).mp ?_ - -- mimic the proof of path2 - ext xs - simp only [Language.mem_add, Language.mem_mul, Language.mem_sub] - constructor - · intro h - by_cases h' : xs ∈ (1 : Language Symbol) - · grind - left - use splitFirst flts k k xs, splitFirst_mem' h' h, - splitFirstCompl flts k k xs, splitFirstCompl_mem h, - splitFirst_append flts _ _ _ - · rintro (⟨ys, ⟨⟨⟨hys, hsuppys⟩, hysnotempty⟩, ⟨zs, ⟨⟨hzs, hsuppzs⟩, happend⟩⟩⟩⟩ | hempty) - · refine ⟨by grind, ?_⟩ - by_cases zs = [] - · grind - rw [Language.mem_one] at hysnotempty - grind [pathSupp_append] - · rw [Language.mem_one] at hempty - simp only [mem_language, Accepts] - grind [PathSupp] - -lemma set_aux {α : Type*} (A : Set α) : (∀ (i : α), i ∉ A) ↔ A = ∅ := by - grind - -theorem language_bddpath_eq_regex [Fintype Symbol] {n k : ℕ} {i j : Fin n} - {flts : FLTS (Fin n) Symbol} : - language (BddPath.mk flts i j k) = matches' (Regex flts i j k) := by - induction k generalizing i j with - | zero => - ext xs - simp only [mem_language, Accepts] - simp only [not_lt_zero, imp_false, Regex] - split_ifs with heq - · -- The case of i = j, k = 0 - rw [set_aux, mem_add_matches'_iff, mem_sum_matches'_iff, pathSupp_empty_iff_empty_or_char] - aesop - · -- The case of i ≠ j, k = 0 - rw [set_aux, mem_sum_matches'_iff, pathSupp_empty_iff_empty_or_char] - aesop - | succ k ih => - simp only [Regex] - split_ifs with hk - · rw [← ih, language_bddpath_eq_dfa flts i j hk, language_bddpath_eq_dfa flts i j (by omega)] - rw [path1 (k := ⟨k, by omega⟩), path2, path3] - simp only [matches'_add, matches'_mul, matches'_star] - grind + | plus P Q hP hQ => grind [matches', IsRegular.add] + | comp P Q hP hQ => grind [matches', IsRegular.mul] + | star P hP => grind [matches', IsRegular.kstar] --- `aux` is almost the same as `language_bddpath_eq_dfa` --- lemma aux {n : ℕ} {s : Fin n} {dfa : DA.FinAcc (Fin n) Symbol} (h : dfa.accept = {s}) : --- language dfa = language (BddPath.mk dfa.toFLTS dfa.start s n) := by --- ext xs --- simp only [mem_language, Accepts] --- grind - -/- IsRegular.iff_regex in the situation where the there is a single accepting state -/ -theorem acc_singleton [Fintype Symbol] {n : ℕ} {s : Fin n} {dfa : DA.FinAcc (Fin n) Symbol} - (h : dfa.accept = {s}) : language dfa = matches' (Regex dfa.toFLTS dfa.start s n) := by - simp [← language_bddpath_eq_regex, language, Accepts, h] - rfl - -/- Modified from Yi-Siong's PR: https://github.com/leanprover-community/mathlib4/pull/35600 -/ -theorem matches'_sum' {α : Type*} (L : List (RegularExpression α)) : - (L.sum).matches' = (L.map matches').sum := by - induction L with - | nil => simp - | cons b L' ih => simp [ih] - -noncomputable instance {n : ℕ} (dfa : DA.FinAcc (Fin n) Symbol) : - Fintype dfa.accept := Fintype.ofFinite dfa.accept - -theorem language_sum' {n : ℕ} {dfa : DA.FinAcc (Fin n) Symbol} : - language dfa = (((dfa.accept.toFinset).sort (· ≤ ·)).map - (fun s ↦ language {dfa with accept := {s}})).sum := by - ext xs - simp only [mem_language] - have memsum (l : List (Fin n)) : xs ∈ (l.map (fun s ↦ language {dfa with accept := {s}})).sum - ↔ ∃ s ∈ l, xs ∈ language {dfa with accept := {s}} := by - induction l with - | nil => simp - | cons a l ih => - simp only [List.map_cons, List.sum_cons, Language.mem_add, List.mem_cons, ih] - grind - simp only [memsum, Finset.mem_sort, Set.mem_toFinset, mem_language] - grind [Accepts] - -theorem IsRegular.iff_regex' [Finite Symbol] {l : Language Symbol} : - l.IsRegular ↔ ∃ r : RegularExpression Symbol, l = matches' r := by - refine ⟨fun h => ?_, fun ⟨r, hr⟩ => hr ▸ IsRegular.regex⟩ - obtain ⟨n, dfa, rfl⟩ := Cslib.Language.IsRegular.iff_dfa'.mp h - set acc_List : List (Fin n) := (dfa.accept.toFinset).sort (· ≤ ·) with h_acc - rw [language_sum'] - let : Fintype Symbol := Fintype.ofFinite Symbol - let regex := - (acc_List.map (fun i => Regex dfa.toFLTS (dfa.start) i n)).sum - use regex - simp only [matches'_sum', regex] - apply congrArg - rw [← h_acc, List.map_map] - simp only [map_inj_left] - have (s : Fin n) : language {dfa with accept := {s}} = - matches' (Regex dfa.toFLTS dfa.start s n) := acc_singleton rfl - exact fun s hs ↦ congrFun (funext this) s - --- Adding this theorem from KleeneAlgorithm.lean before correcting import -theorem regex_of_dfa_singleton_accept [Finite Symbol] {State : Type*} [Finite State] - (dfa : DA.FinAcc State Symbol) (h : ∃ s, dfa.accept = {s}) : - ∃ r : RegularExpression Symbol, language dfa = r.matches' := by - have : Fintype State := Fintype.ofFinite State - let e := Fintype.equivFin State - obtain ⟨s, h⟩ := h - set dfa' := DA.FinAcc.mk {tr := fun s a => e (dfa.tr (e.symm s) a), start := (e dfa.start)} {e s} - with hdfa' - have language_eq : language dfa = language dfa' := by - ext xs - have dfa_eq : dfa'.mtr dfa'.start xs = e (dfa.mtr dfa.start xs) := by - induction xs using List.reverseRec with - | nil => grind - | append_singleton xs x ih => grind - simp only [mem_language, Accepts, h, hdfa', Set.mem_singleton_iff] - rw [dfa_eq] - simp - have : Fintype Symbol := Fintype.ofFinite Symbol - simpa [language_eq] using ⟨_, acc_singleton (by dsimp)⟩ - -/-- We will only retain the following codes in `RegularLanguage.lean` at the end. -/ theorem matches'_sum {α : Type*} (L : List (RegularExpression α)) : (L.sum).matches' = (L.map matches').sum := by induction L with @@ -820,15 +259,16 @@ theorem language_sum {State : Type*} [Fintype State] {dfa : DA.FinAcc State Symb induction l with | nil => simp | cons a l ih => - simp only [List.map_cons, List.sum_cons, Language.mem_add, List.mem_cons, ih] + simp only [map_cons, sum_cons, Language.mem_add, mem_cons, ih] grind rw [memsum] simp [Accepts] +/-- A characterization of `Language.IsRegular` in terms of `RegularExpression`. -/ theorem IsRegular.iff_regex [Finite Symbol] {l : Language Symbol} : l.IsRegular ↔ ∃ r : RegularExpression Symbol, l = matches' r := by refine ⟨fun h => ?_, fun ⟨r, hr⟩ => hr ▸ IsRegular.regex⟩ - obtain ⟨State, _, dfa, rfl⟩ := Cslib.Language.IsRegular.iff_dfa.mp h + obtain ⟨State, _, dfa, rfl⟩ := IsRegular.iff_dfa.mp h have : Fintype State := Fintype.ofFinite State rw [language_sum] have : Fintype Symbol := Fintype.ofFinite Symbol @@ -836,9 +276,11 @@ theorem IsRegular.iff_regex [Finite Symbol] {l : Language Symbol} : (fun s => (regex_of_dfa_singleton_accept {dfa with accept := {s}} (by simp)).choose)).sum use regex simp only [matches'_sum, regex] - apply congrArg List.sum + apply congrArg sum have (s : State) := (regex_of_dfa_singleton_accept (dfa := {dfa with accept := {s}}) (by simp)).choose_spec simpa using fun s hs ↦ congrFun (funext this) s +end RegularExpression + end Cslib.Language From b7171350636fd654cd5859d09af746ea320e9a66 Mon Sep 17 00:00:00 2001 From: Chi-Yun Hsu Date: Tue, 8 Sep 2026 16:16:36 -0700 Subject: [PATCH 83/89] Delete one import --- Cslib/Computability/Languages/RegularLanguage.lean | 1 - 1 file changed, 1 deletion(-) diff --git a/Cslib/Computability/Languages/RegularLanguage.lean b/Cslib/Computability/Languages/RegularLanguage.lean index f68366e80c..c93e195bdf 100644 --- a/Cslib/Computability/Languages/RegularLanguage.lean +++ b/Cslib/Computability/Languages/RegularLanguage.lean @@ -14,7 +14,6 @@ public import Cslib.Computability.Automata.DA.Prod public import Cslib.Computability.Automata.NA.Reverse public import Cslib.Computability.Automata.NA.ToDA public import Cslib.Computability.Automata.DA.ToNA -public import Cslib.Computability.Automata.Acceptors.Acceptor public import Cslib.Computability.Languages.KleeneAlgorithm public import Mathlib.Computability.DFA public import Mathlib.Computability.RegularExpressions From 27204ad065ca313f787836c4cfbb342ccdc0c38c Mon Sep 17 00:00:00 2001 From: Chi-Yun Hsu Date: Tue, 8 Sep 2026 16:20:03 -0700 Subject: [PATCH 84/89] Run lake exe mk_all --- Cslib.lean | 1 + 1 file changed, 1 insertion(+) diff --git a/Cslib.lean b/Cslib.lean index d7e09253d3..3f29cba01d 100644 --- a/Cslib.lean +++ b/Cslib.lean @@ -39,6 +39,7 @@ public import Cslib.Computability.Distributed.FLP.ZeroConsensus public import Cslib.Computability.Languages.Congruences.BuchiCongruence public import Cslib.Computability.Languages.Congruences.RightCongruence public import Cslib.Computability.Languages.ExampleEventuallyZero +public import Cslib.Computability.Languages.KleeneAlgorithm public import Cslib.Computability.Languages.Language public import Cslib.Computability.Languages.LanguageHom public import Cslib.Computability.Languages.MyhillNerode From 1c0a2d5714634f589647b4f15e3650c067283723 Mon Sep 17 00:00:00 2001 From: Chi-Yun Hsu Date: Tue, 8 Sep 2026 16:25:28 -0700 Subject: [PATCH 85/89] Delete accidental added blank line --- Cslib/Computability/Languages/RegularLanguage.lean | 1 - 1 file changed, 1 deletion(-) diff --git a/Cslib/Computability/Languages/RegularLanguage.lean b/Cslib/Computability/Languages/RegularLanguage.lean index c93e195bdf..1a012d62e2 100644 --- a/Cslib/Computability/Languages/RegularLanguage.lean +++ b/Cslib/Computability/Languages/RegularLanguage.lean @@ -60,7 +60,6 @@ theorem IsRegular.iff_nfa {l : Language Symbol} : use Set State, inferInstance, na.toDAFinAcc grind - /-- The complementation of a regular language is regular. -/ theorem IsRegular.compl {l : Language Symbol} (h : l.IsRegular) : (lᶜ).IsRegular := by rw [IsRegular.iff_dfa] at h ⊢ From 5ab53cd4c8491a7291d2f17f45e17f414279962f Mon Sep 17 00:00:00 2001 From: Chi-Yun Hsu Date: Tue, 8 Sep 2026 16:44:33 -0700 Subject: [PATCH 86/89] Update authors --- Cslib/Computability/Languages/KleeneAlgorithm.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cslib/Computability/Languages/KleeneAlgorithm.lean b/Cslib/Computability/Languages/KleeneAlgorithm.lean index a7c55efa11..ef7a603a6b 100644 --- a/Cslib/Computability/Languages/KleeneAlgorithm.lean +++ b/Cslib/Computability/Languages/KleeneAlgorithm.lean @@ -1,7 +1,7 @@ /- Copyright (c) 2026 Brooke Gill and Chi-Yun Hsu. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Brooke Gill and Chi-Yun Hsu +Authors: Brooke Gill, Chi-Yun Hsu -/ module From 064d881a9b4ebedac35ef9e23f7cf4e83b907c32 Mon Sep 17 00:00:00 2001 From: Chi-Yun Hsu Date: Tue, 8 Sep 2026 16:53:51 -0700 Subject: [PATCH 87/89] Added missing docstring --- Cslib/Computability/Languages/KleeneAlgorithm.lean | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Cslib/Computability/Languages/KleeneAlgorithm.lean b/Cslib/Computability/Languages/KleeneAlgorithm.lean index ef7a603a6b..e96bb89a9e 100644 --- a/Cslib/Computability/Languages/KleeneAlgorithm.lean +++ b/Cslib/Computability/Languages/KleeneAlgorithm.lean @@ -97,8 +97,11 @@ variable {n : ℕ} starting with state `start` and ending with state `finish` with the interior states less than `bound`. -/ structure BddPath (n : ℕ) (Symbol : Type*) extends FLTS (Fin n) Symbol where + /-- The starting state of the path. -/ start : Fin n + /-- The finishing state of the path. -/ finish : Fin n + /-- The bound for interior states of the path. -/ bound : ℕ instance : Acceptor (BddPath n Symbol) Symbol where @@ -332,6 +335,11 @@ theorem isPrefix_splitFirst (flts : FLTS (Fin n) Symbol) (i k : Fin n) (xs : Lis | nil => simp [splitFirst] | cons a xs ih => grind [splitFirst] +/-- Starting at state `i`, the function `splitFirstCompl` sends a string to its longest suffix +starting at state `k`. +The string is empty if and only if `splitFirstCompl` is the original string. +If the string never passes through state `k` (starting state can be `k`), +then `splitFirstCompl` returns empty string. -/ noncomputable def splitFirstCompl (flts : FLTS (Fin n) Symbol) (i k : Fin n) (xs : List Symbol) : List Symbol := (isPrefix_splitFirst flts i k xs).choose From a8c7125ece7ec9095dd06dd788e002c0eb0fefe9 Mon Sep 17 00:00:00 2001 From: Chi-Yun Hsu Date: Tue, 8 Sep 2026 18:25:37 -0700 Subject: [PATCH 88/89] Minor --- .../Languages/KleeneAlgorithm.lean | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/Cslib/Computability/Languages/KleeneAlgorithm.lean b/Cslib/Computability/Languages/KleeneAlgorithm.lean index e96bb89a9e..b7bd8d552c 100644 --- a/Cslib/Computability/Languages/KleeneAlgorithm.lean +++ b/Cslib/Computability/Languages/KleeneAlgorithm.lean @@ -150,7 +150,7 @@ then `splitLastCompl` returns the original string. -/ noncomputable def splitLastCompl (flts : FLTS (Fin n) Symbol) (i k : Fin n) (xs : List Symbol) : List Symbol := (isPrefix_splitLast flts i k xs).choose -theorem splitLastCompl_append (flts : FLTS (Fin n) Symbol) (i k : Fin n) (xs : List Symbol) : +theorem splitLast_append (flts : FLTS (Fin n) Symbol) (i k : Fin n) (xs : List Symbol) : splitLast flts i k xs ++ splitLastCompl flts i k xs = xs := by grind [splitLastCompl] @@ -171,7 +171,7 @@ theorem splitLast_eq {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : List Symbo theorem splitLastCompl_eq {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : List Symbol} (h : k ∉ PathSupp flts i xs) (h' : k = flts.mtr i xs) : splitLastCompl flts i k xs = [] := by - simpa [splitLast_eq h h'] using splitLastCompl_append flts i k xs + simpa [splitLast_eq h h'] using splitLast_append flts i k xs /-- `splitLast flts i k xs` is non-empty exclusively when the run from `i` over `xs` visits `k` at some step AFTER the start. -/ @@ -192,7 +192,7 @@ theorem splitLastCompl_neq_iff_mem_PathSupp {flts : FLTS (Fin n) Symbol} {i k : {xs : List Symbol} (hxs : xs ≠ []) : ¬(splitLastCompl flts i k xs = xs) ↔ k ∈ PathSupp flts i xs ∨ k = flts.mtr i xs := by rw [← splitLast_nonempty_iff_mem_PathSupp hxs, not_iff_not] - nth_rw 2 [← splitLastCompl_append flts i k xs] + nth_rw 2 [← splitLast_append flts i k xs] simp /-- The run of `a :: xs` from `i` to `j` having `k` as the largest interior state and @@ -289,7 +289,7 @@ theorem splitLastCompl_mem {flts : FLTS (Fin n) Symbol} {i j k : Fin n} {xs : Li simp only [mem_language, Accepts] at h ⊢ by_cases hxs : xs = [] · grind [splitLastCompl_eq, PathSupp] - grind [splitLastCompl_append, splitLast_nonempty_iff_mem_PathSupp, pathSupp_head] + grind [splitLast_append, splitLast_nonempty_iff_mem_PathSupp, pathSupp_head] /-- Part of the recursion step of Kleene's algorithm. A run from `i` to `j` whose interior states are all at most `k` either has no interior state equal @@ -307,7 +307,7 @@ theorem language_bddpath_splitLast (flts : FLTS (Fin n) Symbol) (i j k : Fin n) right use splitLast flts i k xs, splitLast_mem h h', splitLastCompl flts i k xs, splitLastCompl_mem h h', - splitLastCompl_append flts _ _ _ + splitLast_append flts _ _ _ · rintro (h_left | ⟨ys, ⟨⟨hys, hsuppys⟩, ⟨zs, ⟨⟨hzs, hsuppzs⟩, happend⟩⟩⟩⟩) · simp only [mem_language, Accepts] at h_left ⊢ grind @@ -348,8 +348,8 @@ theorem splitFirst_append (flts : FLTS (Fin n) Symbol) (i k : Fin n) (xs : List grind [splitFirstCompl] /-- If the run of `xs` from `i` to `k` has all interior states below `k + 1`, then - `splitFirst flts i k xs` (the shortest prefix of `xs`) - is a path whose interior states are all below `k`. -/ +`splitFirst flts i k xs` (the shortest prefix of `xs`) +is a path whose interior states are all below `k`. -/ theorem splitFirst_mem {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : List Symbol} (h : xs ∈ (language (BddPath.mk flts i k (k + 1)))) : splitFirst flts i k xs ∈ language (BddPath.mk flts i k k) := by @@ -467,13 +467,11 @@ theorem mem_sum_matches'_iff {α : Type*} (L : List (RegularExpression α)) (x : variable [Fintype Symbol] -/-- -Regex i j k is the regex for the path from state i to state j passing through states < k. +/-- Regex i j k is the regex for the path from state i to state j passing through states < k. When k = 0, i = j, the regex is ε union all characters from state i to state i. When k = 0, i ≠ j, the regex is all characters from state i to state j. For k + 1, the regex is the union of Regex i j k and -(Regex i k k) (Regex k k k)∗ (Regex k j k). --/ +(Regex i k k) (Regex k k k)∗ (Regex k j k). -/ noncomputable def Regex (flts : FLTS (Fin n) Symbol) (i j : Fin n) : ℕ → RegularExpression Symbol | 0 => let chars := (Finset.univ.filter @@ -517,7 +515,7 @@ theorem language_dfa_eq_regex_of_singleton_accept {dfa : DA.FinAcc (Fin n) Symbo end Regex -/-- DFAs with one accepting state have a matching regular expression -/ +/-- A DFA with exactly one accepting state has a matching regular expression. -/ theorem regex_of_dfa_singleton_accept [Finite Symbol] {State : Type*} [Finite State] (dfa : DA.FinAcc State Symbol) (h : ∃ s, dfa.accept = {s}) : ∃ r : RegularExpression Symbol, language dfa = r.matches' := by From 7423fcae0e736764d86a22912d71f0e4f896d511 Mon Sep 17 00:00:00 2001 From: Chi-Yun Hsu Date: Wed, 9 Sep 2026 13:51:12 -0700 Subject: [PATCH 89/89] Change BddPath to BddPathFLTS --- .../Languages/KleeneAlgorithm.lean | 63 ++++++++++--------- Cslib/Foundations/Semantics/FLTS/Basic.lean | 5 ++ 2 files changed, 38 insertions(+), 30 deletions(-) diff --git a/Cslib/Computability/Languages/KleeneAlgorithm.lean b/Cslib/Computability/Languages/KleeneAlgorithm.lean index b7bd8d552c..5afa04e7d6 100644 --- a/Cslib/Computability/Languages/KleeneAlgorithm.lean +++ b/Cslib/Computability/Languages/KleeneAlgorithm.lean @@ -23,7 +23,7 @@ The special case where the DFA has only one accepting state is proved in ## Main definitions - `PathSupp`: The interior states of a run -- `BddPath`: A transition system containing a start state, finish state, and a specific bound on +- `BddPathFLTS`: A transition system containing a start state, finish state, and a specific bound on all interior states - `Regex flts i j k`: The regular expression for the paths from state `i` to state `j`, whose interior states are all under a specific bound `k` @@ -93,10 +93,10 @@ open Automata Acceptor variable {n : ℕ} -/-- A Bounded Path (`BddPath`) has states `Fin n` and accepts strings (lists of symbols) +/-- A Bounded Path (`BddPathFLTS`) has states `Fin n` and accepts strings (lists of symbols) starting with state `start` and ending with state `finish` with the interior states less than `bound`. -/ -structure BddPath (n : ℕ) (Symbol : Type*) extends FLTS (Fin n) Symbol where +structure BddPathFLTS (n : ℕ) (Symbol : Type*) extends FLTS (Fin n) Symbol where /-- The starting state of the path. -/ start : Fin n /-- The finishing state of the path. -/ @@ -104,21 +104,24 @@ structure BddPath (n : ℕ) (Symbol : Type*) extends FLTS (Fin n) Symbol where /-- The bound for interior states of the path. -/ bound : ℕ -instance : Acceptor (BddPath n Symbol) Symbol where - Accepts (p : BddPath n Symbol) (xs : List Symbol) := +instance : Acceptor (BddPathFLTS n Symbol) Symbol where + Accepts (p : BddPathFLTS n Symbol) (xs : List Symbol) := + -- let ss := p.toFLTS.execution p.start xs + -- p.mtr p.start xs = p.finish ∧ ∀ i ∈ ss, i < p.bound p.mtr p.start xs = p.finish ∧ (∀ i ∈ PathSupp p.toFLTS p.start xs, i < p.bound) theorem language_bddpath_head_iff {flts : FLTS (Fin n) Symbol} {i j : Fin n} {k : ℕ} {a : Symbol} {xs : List Symbol} : - a :: xs ∈ language (BddPath.mk flts i j k) ↔ - xs ∈ language (BddPath.mk flts (flts.tr i a) j k) ∧ (flts.tr i a < k ∨ xs = []) := by + a :: xs ∈ language (BddPathFLTS.mk flts i j k) ↔ + xs ∈ language (BddPathFLTS.mk flts (flts.tr i a) j k) ∧ (flts.tr i a < k ∨ xs = []) := by simp only [mem_language, Accepts] by_cases hxs : xs = [] · grind [PathSupp] grind [pathSupp_head hxs] theorem language_bddpath_eq_dfa (flts : FLTS (Fin n) Symbol) (i j : Fin n) {k : ℕ} (hk : n ≤ k) : - language (BddPath.mk flts i j k) = language (DA.FinAcc.mk {tr := flts.tr, start := i} {j}) := by + language (BddPathFLTS.mk flts i j k) = + language (DA.FinAcc.mk {tr := flts.tr, start := i} {j}) := by simp [language, Accepts] grind @@ -198,8 +201,8 @@ theorem splitLastCompl_neq_iff_mem_PathSupp {flts : FLTS (Fin n) Symbol} {i k : /-- The run of `a :: xs` from `i` to `j` having `k` as the largest interior state and no prefix of `a :: xs` (of length 1 or more) ending at state `k` cannot both be true. -/ theorem splitLast_aux {flts : FLTS (Fin n) Symbol} {i j k : Fin n} {xs : List Symbol} - {a : Symbol} (h : a :: xs ∈ language (BddPath.mk flts i j (k + 1))) - (h' : a :: xs ∉ language (BddPath.mk flts i j k)) + {a : Symbol} (h : a :: xs ∈ language (BddPathFLTS.mk flts i j (k + 1))) + (h' : a :: xs ∉ language (BddPathFLTS.mk flts i j k)) (hc : splitLast flts (flts.tr i a) k xs = [] ∧ flts.tr i a ≠ k) : False := by simp only [mem_language, Accepts, Order.lt_add_one_iff, Fin.val_fin_le, not_and, not_forall, not_lt] at * @@ -221,9 +224,9 @@ theorem splitLast_aux {flts : FLTS (Fin n) Symbol} {i j k : Fin n} {xs : List Sy `splitLast flts i k xs` (the longest prefix of `xs` ending at `k`) is a path from `i` to `k` whose interior states are all below `k + 1`. -/ theorem splitLast_mem {flts : FLTS (Fin n) Symbol} {i j k : Fin n} {xs : List Symbol} - (h : xs ∈ language (BddPath.mk flts i j (k + 1))) - (h' : xs ∉ language (BddPath.mk flts i j k)) : - splitLast flts i k xs ∈ language (BddPath.mk flts i k (k + 1)) := by + (h : xs ∈ language (BddPathFLTS.mk flts i j (k + 1))) + (h' : xs ∉ language (BddPathFLTS.mk flts i j k)) : + splitLast flts i k xs ∈ language (BddPathFLTS.mk flts i k (k + 1)) := by induction xs generalizing i with | nil => simp [Accepts, PathSupp] at h h' @@ -254,9 +257,9 @@ theorem splitLast_mem {flts : FLTS (Fin n) Symbol} {i j k : Fin n} {xs : List Sy `splitLastCompl flts i k xs` (the shortest suffix of `xs` starting at `k`) is a path from `k` to `j` whose interior states are all below `k`. -/ theorem splitLastCompl_mem {flts : FLTS (Fin n) Symbol} {i j k : Fin n} {xs : List Symbol} - (h : xs ∈ language (BddPath.mk flts i j (k + 1))) - (h' : xs ∉ language (BddPath.mk flts i j k)) : - splitLastCompl flts i k xs ∈ language (BddPath.mk flts k j k) := by + (h : xs ∈ language (BddPathFLTS.mk flts i j (k + 1))) + (h' : xs ∉ language (BddPathFLTS.mk flts i j k)) : + splitLastCompl flts i k xs ∈ language (BddPathFLTS.mk flts k j k) := by induction xs generalizing i with | nil => simp [Accepts, PathSupp] at h h' @@ -296,13 +299,13 @@ A run from `i` to `j` whose interior states are all at most `k` either has no in to `k`, or it splits at its last visit to `k` into a run from `i` to `k` with interior states below `k + 1`, followed by a run from `k` to `j` with interior states below `k`. -/ theorem language_bddpath_splitLast (flts : FLTS (Fin n) Symbol) (i j k : Fin n) : - language (BddPath.mk flts i j (k + 1)) = language (BddPath.mk flts i j k) + - (language (BddPath.mk flts i k (k + 1)) * language (BddPath.mk flts k j k)) := by + language (BddPathFLTS.mk flts i j (k + 1)) = language (BddPathFLTS.mk flts i j k) + + (language (BddPathFLTS.mk flts i k (k + 1)) * language (BddPathFLTS.mk flts k j k)) := by ext xs rw [Language.mem_add, Language.mem_mul] constructor · intro h - by_cases h' : xs ∈ language (BddPath.mk flts i j k) + by_cases h' : xs ∈ language (BddPathFLTS.mk flts i j k) · left; exact h' right use splitLast flts i k xs, splitLast_mem h h', @@ -351,8 +354,8 @@ theorem splitFirst_append (flts : FLTS (Fin n) Symbol) (i k : Fin n) (xs : List `splitFirst flts i k xs` (the shortest prefix of `xs`) is a path whose interior states are all below `k`. -/ theorem splitFirst_mem {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : List Symbol} - (h : xs ∈ (language (BddPath.mk flts i k (k + 1)))) : - splitFirst flts i k xs ∈ language (BddPath.mk flts i k k) := by + (h : xs ∈ (language (BddPathFLTS.mk flts i k (k + 1)))) : + splitFirst flts i k xs ∈ language (BddPathFLTS.mk flts i k k) := by induction xs generalizing i with | nil => simpa [Accepts, splitFirst, PathSupp] using h | cons a xs ih => @@ -370,8 +373,8 @@ theorem splitFirst_mem {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : List Sym grind [pathSupp_head] theorem splitFirst_mem_nonempty {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : List Symbol} - (hxs : xs ≠ []) (h : xs ∈ (language (BddPath.mk flts i k (k + 1)))) : - splitFirst flts i k xs ∈ language (BddPath.mk flts i k k) - 1 := by + (hxs : xs ≠ []) (h : xs ∈ (language (BddPathFLTS.mk flts i k (k + 1)))) : + splitFirst flts i k xs ∈ language (BddPathFLTS.mk flts i k k) - 1 := by rw [Language.mem_sub] refine ⟨splitFirst_mem h, ?_⟩ simp only [Language.mem_one] @@ -383,8 +386,8 @@ theorem splitFirst_mem_nonempty {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : `splitFirstCompl flts i k xs` (the longest suffix of `xs` starting at `k`) is a path from `k` to `k` whose interior states are all below `k + 1`. -/ theorem splitFirstCompl_mem {flts : FLTS (Fin n) Symbol} {i k : Fin n} {xs : List Symbol} - (h : xs ∈ (language (BddPath.mk flts i k (k + 1)))) : - splitFirstCompl flts i k xs ∈ language (BddPath.mk flts k k (k + 1)) := by + (h : xs ∈ (language (BddPathFLTS.mk flts i k (k + 1)))) : + splitFirstCompl flts i k xs ∈ language (BddPathFLTS.mk flts k k (k + 1)) := by have h' := splitFirst_mem h simp only [mem_language, Accepts] at h h' ⊢ rw [← splitFirst_append flts i k xs] at h @@ -398,8 +401,8 @@ A run from `i` to `j` whose interior states are all at most `k` splits upon firs The part before the visit is a run from `i` to `k` with interior states below `k`. The part after it is a run from `k` to `k` with interior states below `k + 1`. -/ theorem language_bddpath_splitFirst (flts : FLTS (Fin n) Symbol) (i k : Fin n) : - language (BddPath.mk flts i k (k + 1)) = - language (BddPath.mk flts i k k) * language (BddPath.mk flts k k (k + 1)) := by + language (BddPathFLTS.mk flts i k (k + 1)) = + language (BddPathFLTS.mk flts i k k) * language (BddPathFLTS.mk flts k k (k + 1)) := by ext xs rw [Language.mem_mul] constructor @@ -430,8 +433,8 @@ A run from `k` to `k` whose interior states are all at most `k` is a concatenati `k` to `k` whose interior states are all below `k`. In Kleene's algorithm, this is the "star" in the recursion. -/ theorem language_bddpath_kstar (flts : FLTS (Fin n) Symbol) (k : Fin n) : - language (BddPath.mk flts k k (k + 1)) = (language (BddPath.mk flts k k k))∗ := by - rw [← mul_one (language (BddPath.mk flts k k ↑k))∗, kstar_eq] + language (BddPathFLTS.mk flts k k (k + 1)) = (language (BddPathFLTS.mk flts k k k))∗ := by + rw [← mul_one (language (BddPathFLTS.mk flts k k ↑k))∗, kstar_eq] refine (Language.self_eq_mul_add_iff (by simp [Language.mem_sub])).mp ?_ ext xs simp only [Language.mem_add, Language.mem_mul, Language.mem_sub] @@ -487,7 +490,7 @@ noncomputable def Regex (flts : FLTS (Fin n) Symbol) (i j : Fin n) : ℕ → Reg `Regex flts i j k` exactly matches the strings that have a run starting at `i`, ending at `j`, and having all interior states below `k`. -/ theorem language_bddpath_eq_regex {k : ℕ} {flts : FLTS (Fin n) Symbol} {i j : Fin n} : - language (BddPath.mk flts i j k) = (Regex flts i j k).matches' := by + language (BddPathFLTS.mk flts i j k) = (Regex flts i j k).matches' := by induction k generalizing i j with | zero => ext xs diff --git a/Cslib/Foundations/Semantics/FLTS/Basic.lean b/Cslib/Foundations/Semantics/FLTS/Basic.lean index fcae4dcbe5..715ffe660e 100644 --- a/Cslib/Foundations/Semantics/FLTS/Basic.lean +++ b/Cslib/Foundations/Semantics/FLTS/Basic.lean @@ -53,6 +53,11 @@ theorem mtr_concat_eq {flts : FLTS State Label} {s : State} {μs : List Label} { flts.mtr s (μs ++ [μ]) = flts.tr (flts.mtr s μs) μ := by grind +@[scoped grind =] +def execution (flts : FLTS State Label) (s : State) : List Label → List State + | [] => [s] + | μ :: μs => s :: flts.execution (flts.tr s μ) μs + end FLTS end Cslib