Skip to content

Commit 0a2fc20

Browse files
committed
Add more related lemmas + quality fixes
1 parent e0328ea commit 0a2fc20

1 file changed

Lines changed: 130 additions & 14 deletions

File tree

TraceTheory/TraceTheory/Basic.lean

Lines changed: 130 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ namespace List
1616
- if it holds for a list `l`, then it holds for `l ++ [a]` for any `a`.
1717
-/
1818
theorem induction_right {α} {P : List α → Prop}
19-
(h_nil : P [])
20-
(h_snoc : ∀ (l : List α) (a : α), P l → P (l ++ [a])) :
19+
(nil : P [])
20+
(snoc : ∀ (l : List α) (a : α), P l → P (l ++ [a])) :
2121
∀ l : List α, P l := by
2222
/-
2323
We want to prove P l for all lists l, using right induction.
@@ -47,7 +47,7 @@ theorem induction_right {α} {P : List α → Prop}
4747
By the induction hypothesis (IH), from P (k ++ [a]) we get P ((k ++ [a]) ++ l').
4848
Thus, we chain these two steps to get the result.
4949
-/
50-
have hka : P (k ++ [a]) := h_snoc k a hk
50+
have hka : P (k ++ [a]) := snoc k a hk
5151
have : k ++ (a :: l') = (k ++ [a]) ++ l' := by simp [append_assoc]
5252
rw [this]
5353
exact IH (k ++ [a]) hka
@@ -58,13 +58,34 @@ theorem induction_right {α} {P : List α → Prop}
5858
| nil => exact h_base
5959
| cons a l'' IH => exact h_step a l'' IH
6060
-- Finally, to recover the original goal, specialize to k = [] and use h_nil : P [].
61-
exact hQ l [] h_nil
61+
exact hQ l [] nil
6262

63+
/--
64+
Every nonempty list `w` can be written as `w' ++ [a]` for some `w'` and `a`.
65+
This is a canonical example where right induction is natural:
66+
at each step, we peel off the last element, reducing the problem to a shorter list.
67+
-/
68+
example (w : List α) (h : w ≠ []) : ∃ (w' : List α) (a : α), w = w' ++ [a] := by
69+
induction w using induction_right with
70+
| nil =>
71+
-- Base case: contradiction, since w = [].
72+
contradiction
73+
| snoc w' a IH =>
74+
-- Inductive step: w = w' ++ [a]
75+
use w', a
76+
77+
/--
78+
The projection of a word onto an alphabet: remove all symbols not in the alphabet.
79+
This is a standard operation in trace theory.
80+
-/
6381
def proj (Sigma : Alphabet α) (w : List α) : List α :=
6482
match w with
6583
| [] => []
6684
| a :: w' => if a ∈ Sigma then a :: proj Sigma w' else proj Sigma w'
6785

86+
/--
87+
Projection distributes over concatenation: projecting a concatenation is the same as concatenating the projections.
88+
-/
6889
@[simp]
6990
lemma proj_distrib_over_concat (Sigma : Alphabet α) (w₁ w₂ : List α) :
7091
proj Sigma (w₁ ++ w₂) = proj Sigma w₁ ++ proj Sigma w₂ :=
@@ -88,8 +109,11 @@ lemma proj_distrib_over_concat (Sigma : Alphabet α) (w₁ w₂ : List α) :
88109
-- By induction, this is proj Sigma w₁' ++ proj Sigma w₂
89110
simp [proj, h, IH]
90111

112+
/--
113+
Projection commutes with reversal: projecting then reversing is the same as reversing then projecting.
114+
-/
91115
@[simp]
92-
lemma proj_and_reverse_commute (Sigma : Alphabet α) (w : List α) :
116+
lemma proj_commutes_with_reverse (Sigma : Alphabet α) (w : List α) :
93117
reverse (proj Sigma w) = proj Sigma (reverse w) := by
94118
-- We proceed by induction on w.
95119
induction w with
@@ -116,13 +140,37 @@ lemma proj_and_reverse_commute (Sigma : Alphabet α) (w : List α) :
116140
-- Since a ∉ Sigma, proj Sigma [a] = [], so right side is proj Sigma (reverse w')
117141
simp [proj, h, IH]
118142

143+
/--
144+
Cancel the first occurrence of a symbol from the left of a word.
145+
If the symbol is not present, the word is unchanged.
146+
-/
119147
def cancel_left (w : List α) (a : α) : List α :=
120148
match w with
121149
| [] => []
122150
| b :: w' => if a = b then w' else b :: cancel_left w' a
123151

152+
/--
153+
Left-cancelling from an empty list yields an empty list.
154+
-/
155+
@[simp]
156+
lemma cancel_left_nil (a : α) : cancel_left [] a = [] := by
157+
-- By definition, cancel_left [] a = []
158+
rfl
159+
160+
/--
161+
Left-cancelling from a nonempty list: if the head matches the target, remove it; otherwise, cancellation recurses on the tail and preserves the head.
162+
-/
124163
@[simp]
125-
lemma cancel_left_proj_eq_proj_when_a_notin_sigma (Sigma : Alphabet α) (w : List α) (a : α) :
164+
lemma cancel_left_cons (w : List α) (a b : α) :
165+
cancel_left (b :: w) a = if a = b then w else b :: cancel_left w a := by
166+
-- By definition, cancel_left (b :: w) a = if a = b then w else b :: cancel_left w a
167+
rfl
168+
169+
/--
170+
If the symbol `a` is not in the alphabet, then projecting and then cancelling `a` from the left does nothing.
171+
-/
172+
@[simp]
173+
lemma cancel_left_proj_eq_self_when_symb_notin_alph (Sigma : Alphabet α) (w : List α) (a : α) :
126174
a ∉ Sigma → cancel_left (proj Sigma w) a = proj Sigma w := by
127175
intro h
128176
-- We proceed by induction on w.
@@ -138,24 +186,27 @@ lemma cancel_left_proj_eq_proj_when_a_notin_sigma (Sigma : Alphabet α) (w : Lis
138186
· -- If a = b, then in proj Sigma w, b will only appear if b ∈ Sigma.
139187
-- But since a ∉ Sigma, b ∉ Sigma, so proj Sigma (b :: w') = proj Sigma w'.
140188
-- cancel_left (proj Sigma w') a = proj Sigma w' by induction.
141-
rw [h_ab] at h
142-
simp [proj, h]
189+
have h_bS : b ∉ Sigma := h_ab h
190+
simp [proj, h_bS]
143191
exact IH
144192
· -- If a ≠ b, consider whether b ∈ Sigma.
145193
by_cases h_bS : b ∈ Sigma
146194
· -- If b ∈ Sigma, then proj Sigma (b :: w') = b :: proj Sigma w'.
147195
-- cancel_left (b :: proj Sigma w') a = b :: cancel_left (proj Sigma w') a
148196
-- By induction, cancel_left (proj Sigma w') a = proj Sigma w', so both sides match.
149197
simp [proj, h_bS]
150-
simp [cancel_left, h_ab]
198+
simp [h_ab]
151199
exact IH
152200
· -- If b ∉ Sigma, then proj Sigma (b :: w') = proj Sigma w'.
153201
-- cancel_left (proj Sigma w') a = proj Sigma w' by induction.
154202
simp [proj, h_bS]
155203
exact IH
156204

205+
/--
206+
Projection commutes with left-cancellation: projecting then cancelling is the same as cancelling then projecting.
207+
-/
157208
@[simp]
158-
lemma proj_and_cancel_left_commute (Sigma : Alphabet α) (w : List α) (a : α) :
209+
lemma proj_commutes_with_cancel_left (Sigma : Alphabet α) (w : List α) (a : α) :
159210
cancel_left (proj Sigma w) a = proj Sigma (cancel_left w a) := by
160211
-- We prove by induction on w.
161212
induction w with
@@ -173,11 +224,11 @@ lemma proj_and_cancel_left_commute (Sigma : Alphabet α) (w : List α) (a : α)
173224
by_cases h_ab : a = b
174225
· -- If a = b, then cancel_left (b :: proj Sigma w') a = proj Sigma w'.
175226
-- On the right, cancel_left (b :: w') a = w', so proj Sigma w' = proj Sigma w'.
176-
simp [cancel_left, h_ab]
227+
simp [h_ab]
177228
· -- If a ≠ b, then cancel_left (b :: proj Sigma w') a = b :: cancel_left (proj Sigma w') a
178229
-- By induction, cancel_left (proj Sigma w') a = proj Sigma (cancel_left w' a)
179230
-- On the right, cancel_left (b :: w') a = b :: cancel_left w' a, so proj Sigma (b :: cancel_left w' a) = b :: proj Sigma (cancel_left w' a)
180-
simp [cancel_left, h_ab]
231+
simp [h_ab]
181232
simp [proj, h_bS]
182233
exact IH
183234
· -- If b ∉ Sigma, then proj Sigma (b :: w') = proj Sigma w'.
@@ -191,14 +242,79 @@ lemma proj_and_cancel_left_commute (Sigma : Alphabet α) (w : List α) (a : α)
191242
simp [proj, h_bS]
192243
exact IH
193244

245+
/--
246+
Cancel the first occurrence of a symbol from the right of a word.
247+
-/
194248
def cancel_right (w : List α) (a : α) : List α :=
195249
reverse (cancel_left (reverse w) a)
196250

251+
/--
252+
Right-cancelling from an empty list yields an empty list.
253+
-/
254+
@[simp]
255+
lemma cancel_right_nil (a : α) : cancel_right [] a = [] := by
256+
-- By definition, cancel_right [] a = reverse (cancel_left (reverse []) a) = reverse (cancel_left [] a) = reverse [] = []
257+
simp [cancel_right]
258+
259+
/--
260+
Right-cancelling from a nonempty list: if the last element matches the target, remove it; otherwise, cancellation recurses on the prefix and preserves the last element.
261+
-/
262+
@[simp]
263+
lemma cancel_right_snoc (w : List α) (a b : α) :
264+
cancel_right (w ++ [b]) a = if a = b then w else cancel_right w a ++ [b] := by
265+
by_cases h : a = b
266+
· -- If a = b, then cancel_right (w ++ [b]) a = reverse (cancel_left (reverse (w ++ [b])) a)
267+
-- = reverse (cancel_left (reverse [b] ++ reverse w) a) = reverse (cancel_left ([b] ++ reverse w) a)
268+
-- = reverse (cancel_left (b :: reverse w) a) = reverse (reverse w) = w
269+
simp [cancel_right, h]
270+
· -- If a ≠ b, then cancel_right (w ++ [b]) a = reverse (cancel_left (reverse (w ++ [b])) a)
271+
-- = reverse (cancel_left (reverse [b] ++ reverse w) a) = reverse (cancel_left ([b] ++ reverse w) a)
272+
-- = reverse (cancel_left (b :: reverse w) a) = reverse (b :: cancel_left (reverse w) a) = reverse (cancel_left (reverse w) a) ++ [b] = cancel_right w a ++ [b]
273+
simp [cancel_right, h]
274+
275+
/--
276+
If the symbol `a` is not in the alphabet, then projecting and then cancelling `a` from the right does nothing.
277+
-/
278+
@[simp]
279+
lemma cancel_right_proj_eq_self_when_symb_notin_alph (Sigma : Alphabet α) (w : List α) (a : α) :
280+
a ∉ Sigma → cancel_right (proj Sigma w) a = proj Sigma w := by
281+
induction w using induction_right with
282+
| nil =>
283+
-- Base case: w = [].
284+
-- Both sides are cancel_right [] a = [] and proj Sigma [] = [], so equality holds.
285+
simp [cancel_right, proj]
286+
| snoc w' b IH =>
287+
intro h
288+
by_cases h_ab : a = b
289+
· -- Case 1: a = b. Since a ∉ Sigma, b ∉ Sigma as well.
290+
-- The projection removes b, so proj Sigma (w' ++ [b]) = proj Sigma w'.
291+
-- Right-cancelling a from proj Sigma w is the same as right-cancelling from proj Sigma w',
292+
-- which by the induction hypothesis is just proj Sigma w'.
293+
have h_bS : b ∉ Sigma := h_ab ▸ h
294+
simp [proj, h_bS]
295+
exact IH h
296+
· -- Case 2: a ≠ b. Now consider whether b ∈ Sigma.
297+
by_cases h_bS : b ∈ Sigma
298+
· -- Subcase: b ∈ Sigma. Then proj Sigma (w' ++ [b]) = proj Sigma w' ++ [b].
299+
-- Right-cancelling a from proj Sigma w is cancel_right (proj Sigma w') a ++ [b].
300+
-- By the induction hypothesis, cancel_right (proj Sigma w') a = proj Sigma w', so both sides match.
301+
simp [proj, h_bS]
302+
simp [h_ab]
303+
exact IH h
304+
· -- Subcase: b ∉ Sigma. Then proj Sigma (w' ++ [b]) = proj Sigma w'.
305+
-- Right-cancelling a from proj Sigma w is the same as right-cancelling from proj Sigma w',
306+
-- which by the induction hypothesis is just proj Sigma w'.
307+
simp [proj, h_bS]
308+
exact IH h
309+
310+
/--
311+
Projection commutes with right-cancellation: projecting then cancelling is the same as cancelling then projecting.
312+
-/
197313
@[simp]
198-
lemma proj_and_cancel_right_commute (Sigma : Alphabet α) (w : List α) (a : α) :
314+
lemma proj_commutes_with_cancel_right (Sigma : Alphabet α) (w : List α) (a : α) :
199315
cancel_right (proj Sigma w) a = proj Sigma (cancel_right w a) := by
200316
-- The right-cancellation is defined as reversing, left-cancelling, then reversing again.
201317
-- Since proj and reverse commute (by proj_and_reverse_commute), the operations can be swapped.
202-
simp [cancel_right, proj_and_reverse_commute]
318+
simp [cancel_right, proj_commutes_with_reverse]
203319

204320
end List

0 commit comments

Comments
 (0)