Skip to content

Commit 7b5ad89

Browse files
committed
Prove lang-doubling Theorem 1
1 parent ab9f2c4 commit 7b5ad89

1 file changed

Lines changed: 99 additions & 30 deletions

File tree

TraceTheoryLean/LangDouble.lean

Lines changed: 99 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
import Mathlib.Data.Fintype.Basic
2-
import Mathlib.Data.Finset.Basic
2+
import Mathlib.Data.Fintype.Prod
33
import Mathlib.Data.List.Basic
44
import Mathlib.Computability.DFA
55
import Mathlib.Computability.Language
66
import Mathlib.Computability.NFA
7-
import Mathlib.Logic.Relation
87

98
universe u v
109
variable {α : Type u} {σ : Type v} {M : NFA α σ}
@@ -23,6 +22,8 @@ end Language
2322
namespace NFA
2423

2524
variable (M) in
25+
/-- If [M] recognizes a language [L], [M.double] is an NFA constructed
26+
such that it should recognize exactly [double L]. -/
2627
def 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). -/
3438
lemma 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). -/
4956
lemma 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]. -/
6271
lemma 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]. -/
6979
lemma 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 -/
7791
theorem 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

113128
variable (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-
136139
variable (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]. -/
137142
lemma 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]. -/
172201
theorem 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

180233
variable (M) in
181234
def lang_half : (NFA α σ) where
@@ -187,7 +240,23 @@ end NFA
187240

188241
namespace 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

193262
end Language

0 commit comments

Comments
 (0)