11import Mathlib.Data.Fintype.Basic
2- import Mathlib.Data.Finset.Basic
2+ import Mathlib.Data.Fintype.Prod
33import Mathlib.Data.List.Basic
44import Mathlib.Computability.DFA
55import Mathlib.Computability.Language
66import Mathlib.Computability.NFA
7- import Mathlib.Logic.Relation
87
98universe u v
109variable {α : Type u} {σ : Type v} {M : NFA α σ}
@@ -23,6 +22,8 @@ end Language
2322namespace NFA
2423
2524variable (M) in
25+ /-- If [ M ] recognizes a language [ L ] , [ M.double ] is an NFA constructed
26+ such that it should recognize exactly [double L]. -/
2627def double : (NFA α (σ ⊕ (σ × α))) where
2728 step := fun st a =>
2829 match st with
@@ -31,21 +32,27 @@ def double : (NFA α (σ ⊕ (σ × α))) where
3132 start := M.start.image Sum.inl
3233 accept := M.accept.image Sum.inl
3334
35+ /-- Taking two steps [a, a] in [ M.double ] should lead to the same set of states
36+ as taking one step [ a ] in [ M ] (starting from any set of states) (with Sum.inl
37+ to correct the fact that the sets have different types). -/
3438lemma double_step_equal (a : α) (S : Set σ) :
3539 (M.stepSet S a).image Sum.inl = M.double.stepSet (M.double.stepSet (S.image Sum.inl) a) a := by
3640 simp [stepSet]
3741 simp [double]
3842 --- vvv by LLM recommendation vvv ---
43+ -- probably useful to get familiar with the kind of syntax below
3944 ext x
4045 simp
4146 constructor
4247 · -- Forward direction: x ∈ image of union → x ∈ union of images
4348 rintro ⟨t, ⟨s, hs, ht⟩, rfl⟩
44- exact ⟨s, hs, t, ht, rfl⟩ -- probably useful to get used to this syntax
49+ exact ⟨s, hs, t, ht, rfl⟩
4550 · -- Reverse direction: x ∈ union of images → x ∈ image of union
4651 rintro ⟨s, hs, t, ht, rfl⟩
4752 exact ⟨t, ⟨s, hs, ht⟩, rfl⟩
4853
54+ /-- Following [double w] in [ M.double ] should lead to the same set of states
55+ as following [ w ] in [ M ] (starting from any set of states). -/
4956lemma double_steps_equal {w : List α} :
5057 ∀ S : Set σ,
5158 Sum.inl '' M.evalFrom S w
@@ -59,26 +66,34 @@ lemma double_steps_equal {w : List α} :
5966 rw [<- M.double_step_equal a s]
6067 rw [IH]
6168
69+ /-- Evaluating [double w] in [ M.double ] should lead to the same set of states
70+ as evaluating [ w ] in [ M ] . -/
6271lemma double_eval_equal {w : List α} :
6372 (M.eval w).image Sum.inl = M.double.eval (str_double w) := by
6473 simp [eval]
6574 nth_rw 2 [double]
6675 simp
6776 rw [double_steps_equal]
6877
78+ /-- [ M.double ] accepts [double w] iff [ M ] accepts [ w ] . -/
6979lemma mem_iff_double_in_double_lang {w : List α} :
7080 (w ∈ M.accepts) <-> (str_double w ∈ M.double.accepts) := by
7181 simp [accepts]
7282 repeat rw [Set.mem_setOf]
7383 rw [<- double_eval_equal]
7484 simp [double]
7585
76- --- vvv per LLM generation vvv ---
86+ /-- A generic induction principle for two-element induction on lists.
87+ Allows a List to be decomposed into cases
88+ | hnil
89+ | hsingle a
90+ | hcons a b u IH -/
7791theorem list_induction_two {α} {P : List α → Prop } (l : List α)
7892 (hnil : P [])
7993 (hsingle : ∀ a, P [a])
8094 (hcons : ∀ a b tail, P tail → P (a :: b :: tail)) : P l := by
81- -- Generic induction principle for two-element induction on lists
95+ --- vvv per LLM generation vvv ---
96+ -- inducts on length of list
8297 have Q : ∀ (n : Nat) (l' : List α), l'.length = n → P l' := by
8398 intro n
8499 induction' n using Nat.strong_induction_on with n IH
@@ -112,47 +127,42 @@ theorem list_induction_two {α} {P : List α → Prop} (l : List α)
112127
113128variable (M) in
114129@[simp]
115- theorem stepSets_empty (x : List α) : List.foldl M.stepSet ∅ x = ∅ := by
130+ theorem stepSets_empty (x : List α) :
131+ List.foldl M.stepSet ∅ x = ∅ := by
116132 induction x with
117133 | nil =>
118134 simp
119135 | cons a y IH =>
120136 simp [stepSet]
121137 exact IH
122138
123- /-variable (M) in
124- lemma no_even_two_steps_to_no_even {S : Set (σ ⊕ (σ × α))} (a : α) :
125- (∃ x : σ, Sum.inl x ∈ M.double.stepSet (M.double.stepSet S a) a)
126- -> (∃ x : σ, Sum.inl x ∈ S) := by
127- simp [double, stepSet]
128- by_cases h_empt : ∃ p, Sum.inl p ∈ S
129- · simp [ h_empt ]
130- · intro _ p h
131- exfalso
132- apply h_empt
133- use p
134- -/
135-
136139variable (M) in
140+ /-- If [ S ] consists only of states in [ M ] , taking two steps [a, a] in [ M.double ]
141+ leads only to states also in [ M ] . -/
137142lemma even_two_steps_to_even {S : Set σ} (a : α) :
138143 ∃ T : Set σ, Sum.inl '' T = M.double.stepSet (M.double.stepSet (Sum.inl '' S) a) a := by
139144 rw [<- double_step_equal]
140145 use M.stepSet S a
141146
142- lemma mem_of_double_lang_is_double {w : List α} :
147+ /-- If [ w ] leads from some set [ S ] (of only states in [ M ] )
148+ to an accepted state in [ M.double ] , [ w ] must be the double of a string. -/
149+ lemma even_to_accepted_is_double {w : List α} :
143150 (∃ (S : Set σ), ∃ x ∈ M.accept, Sum.inl x ∈ M.double.evalFrom (Sum.inl '' S) w)
144151 -> ∃ j : List α, w = str_double j := by
145152 induction w using list_induction_two with
146- | hnil =>
153+ | hnil => -- empty list, is double of []
147154 intro h
148155 use []
149156 simp [str_double]
150- | hsingle a =>
157+ | hsingle a => -- singleton list, cannot lead to accepted states
151158 simp [double]
152159 simp [stepSet]
153- | hcons a b u IH =>
160+ | hcons a b u IH => -- list of 2+ elements a :: b :: u
154161 by_cases h_ab : a = b
155- · rw [<- h_ab]
162+ · rw [<- h_ab] -- case a = b, use IH
163+ /- if [a :: a :: u] leads from some set [ S ] to an accepted state,
164+ [ u ] leads from [M.double.step (M.double.step S a) a] to an accepted state
165+ so we can use [M.double.step (M.double.step S a) a] to satisfy IH condition. -/
156166 intro h
157167 simp at h
158168 obtain ⟨h_ex1, ⟨h_ex2, h⟩⟩ := h
@@ -166,16 +176,59 @@ lemma mem_of_double_lang_is_double {w : List α} :
166176 use a :: j
167177 simp [str_double]
168178 exact h_double
169- · simp [double, evalFrom, stepSet]
179+ · simp [double, evalFrom, stepSet] -- case a ≠ b, cannot lead to accepted states
170180 simp [Ne.symm h_ab]
171181
182+ /-- If [ w ] is accepted by [ M.double ] , [ w ] must be the double of a string. -/
183+ lemma mem_of_double_lang_is_double {w : List α} :
184+ w ∈ M.double.accepts → ∃ j : List α, w = str_double j := by
185+ simp [accepts, eval]
186+ intro h
187+ rw [Set.mem_setOf] at h
188+ rcases h with h | h
189+ · have h_st : M.double.start = Sum.inl '' M.start := by simp [double]
190+ rw [h_st] at h
191+ apply M.even_to_accepted_is_double
192+ use M.start
193+ obtain ⟨a, h⟩ := h
194+ nth_rw 1 [double] at h
195+ simp at h
196+ use a
197+ · simp [double] at h -- impossible case
198+
199+ /-- The language accepted by [ M.double ] is the double of the language
200+ accepted by [ M ] . -/
172201theorem lang_of_double_is_double_of_lang {L : Language α} : -- Theorem-1
173202 L = M.accepts -> L.double = M.double.accepts := by
174203 intro h
175- simp [Language.double]
176- sorry
204+ ext x
205+ constructor
206+ · -- x ∈ L.double → x ∈ M.double.accepts
207+ -- essentially proven by [ mem_iff_double_in_double_lang ]
208+ simp [Language.double]
209+ rw [Set.mem_setOf, h]
210+ intro h
211+ obtain ⟨w, ⟨h_w, h_d⟩⟩ := h
212+ rw [mem_iff_double_in_double_lang, h_d] at h_w
213+ exact h_w
214+ · -- x ∈ M.double.accepts → x ∈ L.double
215+ /- use [ mem_of_double_lang_is_double ] to prove
216+ that [ M.double.accepts ] contains only doubled-strings -/
217+ intro h_x
218+ have h_xd : ∃ j, x = str_double j := by
219+ apply mem_of_double_lang_is_double at h_x
220+ exact h_x
221+ obtain ⟨j, h_xd⟩ := h_xd
222+ /- then use [ mem_iff_double_in_double_lang ] to prove those
223+ strings have halves accepted by [ M ] -/
224+ rw [h_xd, <- mem_iff_double_in_double_lang] at h_x
225+ rw [h]
226+ simp [Language.double]
227+ rw [Set.mem_setOf]
228+ use j
229+ simp [h_x, h_xd]
177230
178- -- Todo
231+ -- Todo: Theorem 2
179232
180233variable (M) in
181234def lang_half : (NFA α σ) where
@@ -187,7 +240,23 @@ end NFA
187240
188241namespace Language
189242
190- protected theorem IsRegular.double {L : Language α} (h : L.IsRegular) : L.double.IsRegular :=
191- sorry
243+ -- Theorem-1
244+ -- If language [ L ] is regular, the language [double L] is regular.
245+ protected theorem IsRegular.double {α : Type } [hf_α : Fintype α]
246+ {L : Language α} (h : L.IsRegular) : L.double.IsRegular := by
247+ simp [IsRegular] at h
248+ simp [IsRegular]
249+ obtain ⟨σ, hNe, M, hAcc⟩ := h
250+ use Set (σ ⊕ (σ × α))
251+ -- prove (Set (σ ⊕ σ × α)) is nonempty & finite, so that it can
252+ -- be used as the state set of a DFA/NFA
253+ have h_dirsum : Nonempty (Fintype (Set (σ ⊕ σ × α))) := by
254+ have h_mem_σ : Fintype σ := Classical.choice hNe
255+ exact ⟨Fintype.ofFinite (Set (σ ⊕ σ × α))⟩
256+ use h_dirsum, M.toNFA.double.toDFA
257+ simp
258+ rw [NFA.lang_of_double_is_double_of_lang]
259+ simp
260+ rw [hAcc]
192261
193262end Language
0 commit comments