Skip to content

Commit ebf4dfa

Browse files
committed
Merge branch 'ys-working' into beta
2 parents 389a3bc + 93f9fd3 commit ebf4dfa

4 files changed

Lines changed: 400 additions & 447 deletions

File tree

TraceTheory/TraceTheory/Basic.lean

Lines changed: 42 additions & 279 deletions
Original file line numberDiff line numberDiff line change
@@ -1,303 +1,66 @@
11
import Mathlib.Computability.Language
22
import Mathlib.Data.Finset.Basic
3-
4-
variable {α : Type*} [DecidableEq α]
5-
6-
/-- An alphabet is a finite set of symbols. -/
7-
abbrev Alphabet α := Finset α
8-
93
namespace List
104

11-
/-- This theorem provides an induction principle for lists where the inductive step
12-
appends an element to the right (i.e., builds lists by snoc rather than cons).
13-
14-
The intuition is that, instead of the usual head recursion, we want to prove a property
15-
for all lists by showing:
16-
- the property holds for the empty list, and
17-
- if it holds for a list `l`, then it holds for `l ++ [a]` for any `a`. -/
18-
theorem induction_right {α} {P : List α → Prop}
19-
(nil : P [])
20-
(snoc : ∀ (l : List α) (a : α), P l → P (l ++ [a])) :
21-
∀ l : List α, P l := by
22-
/-
23-
We want to prove P l for all lists l, using right induction.
24-
However, Lean's built-in induction on lists is left-sided (on cons), not right-sided (on snoc).
25-
To overcome this, we use a classic strengthening technique:
26-
instead of proving just P l, we prove a stronger property
27-
Q l := ∀ k, P k → P (k ++ l)
28-
This means: if we know P holds for any prefix k, then it also holds for k ++ l.
29-
Proving Q l for all l is strictly stronger than just P l, but it allows us to perform induction on l (using cons),
30-
and at the end, we recover the original goal by taking k = [].
31-
-/
32-
intro l
33-
let Q := fun (l : List α) => ∀ (k : List α), P k → P (k ++ l)
34-
-- Base case: l = []. We must show Q []: ∀ k, P k → P (k ++ []).
35-
have h_base : Q [] := by
36-
intro k hk
37-
-- In this case, k ++ [] = k, so P (k ++ []) = P k, which is exactly hk.
38-
rw [append_nil]
39-
exact hk
40-
-- Inductive step: assume Q l', show Q (a :: l') for any a.
41-
have h_step : ∀ (a : α) (l' : List α), Q l' → Q (a :: l') := by
42-
intros a l' IH k hk
43-
/-
44-
Goal: P (k ++ (a :: l')) given P k.
45-
Observe: k ++ (a :: l') = (k ++ [a]) ++ l'.
46-
By the snoc hypothesis, from P k we get P (k ++ [a]).
47-
By the induction hypothesis (IH), from P (k ++ [a]) we get P ((k ++ [a]) ++ l').
48-
Thus, we chain these two steps to get the result.
49-
-/
50-
have hka : P (k ++ [a]) := snoc k a hk
51-
have : k ++ (a :: l') = (k ++ [a]) ++ l' := by simp [append_assoc]
52-
rw [this]
53-
exact IH (k ++ [a]) hka
54-
-- Now, by induction on l (using the usual left induction), we get Q l for all l.
55-
have hQ : ∀ l, Q l := by
56-
intro l'
57-
induction l' with
58-
| nil => exact h_base
59-
| cons a l'' IH => exact h_step a l'' IH
60-
-- Finally, to recover the original goal, specialize to k = [] and use h_nil : P [].
61-
exact hQ l [] nil
62-
63-
/-- The projection of a word onto an alphabet. Removes all symbols not in the alphabet. -/
64-
def proj (Sigma : Alphabet α) (w : List α) : List α :=
65-
match w with
66-
| [] => []
67-
| a :: w' => if a ∈ Sigma then a :: proj Sigma w' else proj Sigma w'
68-
69-
/-- Projection distributes over concatenation. -/
70-
@[simp]
71-
lemma proj_distrib_over_concat (Sigma : Alphabet α) (w₁ w₂ : List α) :
72-
proj Sigma (w₁ ++ w₂) = proj Sigma w₁ ++ proj Sigma w₂ :=
73-
by
74-
-- We proceed by induction on w₁.
75-
induction w₁ with
76-
| nil =>
77-
-- Base case: w₁ = [].
78-
-- proj Sigma ([] ++ w₂) = proj Sigma w₂, and proj Sigma [] = [], so the equality holds.
79-
simp [proj]
80-
| cons a w₁' IH =>
81-
-- Inductive step: w₁ = a :: w₁'.
82-
-- We consider whether a ∈ Sigma.
83-
by_cases h : a ∈ Sigma
84-
· -- If a ∈ Sigma, then proj Sigma (a :: (w₁' ++ w₂)) = a :: proj Sigma (w₁' ++ w₂)
85-
-- By induction, proj Sigma (w₁' ++ w₂) = proj Sigma w₁' ++ proj Sigma w₂
86-
-- So the result is a :: (proj Sigma w₁' ++ proj Sigma w₂) = (a :: proj Sigma w₁') ++ proj Sigma w₂
87-
simp [proj, h, IH]
88-
· -- If a ∉ Sigma, then a is skipped in the projection.
89-
-- So proj Sigma (a :: (w₁' ++ w₂)) = proj Sigma (w₁' ++ w₂)
90-
-- By induction, this is proj Sigma w₁' ++ proj Sigma w₂
91-
simp [proj, h, IH]
92-
93-
/-- Projection commutes with reversal. -/
94-
@[simp]
95-
lemma proj_commutes_with_reverse (Sigma : Alphabet α) (w : List α) :
96-
reverse (proj Sigma w) = proj Sigma (reverse w) := by
97-
-- We proceed by induction on w.
98-
induction w with
99-
| nil =>
100-
-- Base case: w = [].
101-
-- Both sides are reverse [] = [] and proj Sigma [] = [], so equality holds.
102-
rfl
103-
| cons a w' IH =>
104-
-- Inductive step: w = a :: w'.
105-
-- Consider whether a ∈ Sigma.
106-
by_cases h : a ∈ Sigma
107-
· -- If a ∈ Sigma, then proj Sigma (a :: w') = a :: proj Sigma w'.
108-
-- reverse (a :: proj Sigma w') = reverse (proj Sigma w') ++ [a]
109-
-- By induction, reverse (proj Sigma w') = proj Sigma (reverse w')
110-
-- So left side is proj Sigma (reverse w') ++ [a]
111-
-- On the right, reverse (a :: w') = reverse w' ++ [a], so proj Sigma (reverse w' ++ [a])
112-
-- By proj_distrib_over_concat, this is proj Sigma (reverse w') ++ proj Sigma [a]
113-
-- Since a ∈ Sigma, proj Sigma [a] = [a], so both sides match.
114-
simp [proj, h, IH]
115-
· -- If a ∉ Sigma, then proj Sigma (a :: w') = proj Sigma w'.
116-
-- So reverse (proj Sigma w') = proj Sigma (reverse w') by induction.
117-
-- On the right, reverse (a :: w') = reverse w' ++ [a], proj Sigma (reverse w' ++ [a])
118-
-- By proj_distrib_over_concat, this is proj Sigma (reverse w') ++ proj Sigma [a]
119-
-- Since a ∉ Sigma, proj Sigma [a] = [], so right side is proj Sigma (reverse w')
120-
simp [proj, h, IH]
121-
122-
/-- Cancel the first occurrence of a symbol (if any) from the left side of a word. -/
123-
def cancel_left (w : List α) (a : α) : List α :=
124-
match w with
125-
| [] => []
126-
| b :: w' => if a = b then w' else b :: cancel_left w' a
127-
128-
@[simp]
129-
lemma cancel_left_nil (a : α) : cancel_left [] a = [] := by rfl
5+
variable {α : Type} [DecidableEq α]
1306

131-
@[simp]
132-
lemma cancel_left_cons (w : List α) (a b : α) :
133-
cancel_left (b :: w) a = if a = b then w else b :: cancel_left w a := by
134-
rfl
7+
/-- The projection of a string onto an alpabet. Removes all symbols not in the Finset.-/
8+
def proj (S : Finset α) (w : List α) : List α := w.filter (· ∈ S)
1359

136-
/-- If the symbol `a` is not in the alphabet,
137-
then projecting and then cancelling `a` from the left does nothing. -/
13810
@[simp]
139-
lemma cancel_left_proj_eq_self_when_symb_notin_alph (Sigma : Alphabet α) (w : List α) (a : α) :
140-
a ∉ Sigma → cancel_left (proj Sigma w) a = proj Sigma w := by
141-
intro h
142-
-- We proceed by induction on w.
143-
induction w with
144-
| nil =>
145-
-- Base case: w = [].
146-
-- Both sides are cancel_left [] a = [] and proj Sigma [] = [], so equality holds.
147-
rfl
148-
| cons b w' IH =>
149-
-- Inductive step: w = b :: w'.
150-
-- Consider whether a = b.
151-
by_cases h_ab : a = b
152-
· -- If a = b, then in proj Sigma w, b will only appear if b ∈ Sigma.
153-
-- But since a ∉ Sigma, b ∉ Sigma, so proj Sigma (b :: w') = proj Sigma w'.
154-
-- cancel_left (proj Sigma w') a = proj Sigma w' by induction.
155-
have h_bS : b ∉ Sigma := h_ab ▸ h
156-
simp [proj, h_bS]
157-
exact IH
158-
· -- If a ≠ b, consider whether b ∈ Sigma.
159-
by_cases h_bS : b ∈ Sigma
160-
· -- If b ∈ Sigma, then proj Sigma (b :: w') = b :: proj Sigma w'.
161-
-- cancel_left (b :: proj Sigma w') a = b :: cancel_left (proj Sigma w') a
162-
-- By induction, cancel_left (proj Sigma w') a = proj Sigma w', so both sides match.
163-
simp [proj, h_bS]
164-
simp [h_ab]
165-
exact IH
166-
· -- If b ∉ Sigma, then proj Sigma (b :: w') = proj Sigma w'.
167-
-- cancel_left (proj Sigma w') a = proj Sigma w' by induction.
168-
simp [proj, h_bS]
169-
exact IH
11+
lemma proj_append (S : Finset α) (w₁ w₂ : List α) :
12+
proj S (w₁ ++ w₂) = proj S w₁ ++ proj S w₂ := by
13+
simp [proj]
17014

171-
/-- Projection commutes with left-cancellation -/
17215
@[simp]
173-
lemma proj_commutes_with_cancel_left (Sigma : Alphabet α) (w : List α) (a : α) :
174-
cancel_left (proj Sigma w) a = proj Sigma (cancel_left w a) := by
175-
-- We prove by induction on w.
176-
induction w with
177-
| nil =>
178-
-- Base case: w = [].
179-
-- Both sides are cancel_left [] a = [] and proj Sigma [] = [], so equality holds.
180-
rfl
181-
| cons b w' IH =>
182-
-- Inductive step: w = b :: w'.
183-
-- Consider whether b ∈ Sigma.
184-
by_cases h_bS : b ∈ Sigma
185-
· -- If b ∈ Sigma, then proj Sigma (b :: w') = b :: proj Sigma w'.
186-
simp [proj, h_bS]
187-
-- Now consider whether a = b.
188-
by_cases h_ab : a = b
189-
· -- If a = b, then cancel_left (b :: proj Sigma w') a = proj Sigma w'.
190-
-- On the right, cancel_left (b :: w') a = w', so proj Sigma w' = proj Sigma w'.
191-
simp [h_ab]
192-
· -- If a ≠ b, then cancel_left (b :: proj Sigma w') a = b :: cancel_left (proj Sigma w') a
193-
-- By induction, cancel_left (proj Sigma w') a = proj Sigma (cancel_left w' a)
194-
-- 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)
195-
simp [h_ab]
196-
simp [proj, h_bS]
197-
exact IH
198-
· -- If b ∉ Sigma, then proj Sigma (b :: w') = proj Sigma w'.
199-
by_cases h_ab : a = b
200-
· -- If a = b, then cancel_left (b :: w') a = w', so proj Sigma w' = proj Sigma w'.
201-
simp [cancel_left, h_ab]
202-
simp [proj, h_bS]
203-
· -- If a ≠ b, then cancel_left (b :: w') a = b :: cancel_left w' a, but b ∉ Sigma so proj Sigma (b :: cancel_left w' a) = proj Sigma (cancel_left w' a)
204-
-- By induction, cancel_left (proj Sigma w') a = proj Sigma (cancel_left w' a)
205-
simp [cancel_left, h_ab]
206-
simp [proj, h_bS]
207-
exact IH
16+
lemma proj_reverse (S : Finset α) (w : List α) :
17+
reverse (proj S w) = proj S (reverse w) := by
18+
simp [proj]
20819

20920
/-- Cancel the first occurrence of a symbol (if any) from the right of a word. -/
210-
def cancel_right (w : List α) (a : α) : List α :=
211-
reverse (cancel_left (reverse w) a)
21+
def cancelRight (w : List α) (a : α) : List α := reverse (List.erase (reverse w) a)
21222

213-
@[simp]
214-
lemma cancel_right_nil (a : α) : cancel_right [] a = [] := by
215-
-- By definition, cancel_right [] a = reverse (cancel_left (reverse []) a) = reverse (cancel_left [] a) = reverse [] = []
216-
simp [cancel_right]
217-
218-
lemma cancel_right_snoc (w : List α) (a b : α) :
219-
cancel_right (w ++ [b]) a = if a = b then w else cancel_right w a ++ [b] := by
220-
by_cases h : a = b
221-
· -- If a = b, then cancel_right (w ++ [b]) a = reverse (cancel_left (reverse (w ++ [b])) a)
222-
-- = reverse (cancel_left (reverse [b] ++ reverse w) a) = reverse (cancel_left ([b] ++ reverse w) a)
223-
-- = reverse (cancel_left (b :: reverse w) a) = reverse (reverse w) = w
224-
simp [cancel_right, h]
225-
· -- If a ≠ b, then cancel_right (w ++ [b]) a = reverse (cancel_left (reverse (w ++ [b])) a)
226-
-- = reverse (cancel_left (reverse [b] ++ reverse w) a) = reverse (cancel_left ([b] ++ reverse w) a)
227-
-- = 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]
228-
simp [cancel_right, h]
229-
230-
lemma cancel_left_eq_rev_cancel_right_rev (w : List α) (a : α) :
231-
cancel_left w a = reverse (cancel_right (reverse w) a) := by
232-
simp [cancel_right]
23+
/-- Notation for right cancellation. -/
24+
infixl:65 " ÷ " => List.cancelRight
23325

234-
/-- If the symbol `a` is not in the alphabet,
235-
then projecting and then cancelling `a` from the right does nothing. -/
23626
@[simp]
237-
lemma cancel_right_proj_eq_self_when_symb_notin_alph (Sigma : Alphabet α) (w : List α) (a : α) :
238-
a ∉ Sigma → cancel_right (proj Sigma w) a = proj Sigma w := by
239-
induction w using induction_right with
240-
| nil =>
241-
-- Base case: w = [].
242-
-- Both sides are cancel_right [] a = [] and proj Sigma [] = [], so equality holds.
243-
simp [cancel_right, proj]
244-
| snoc w' b IH =>
245-
intro h
246-
by_cases h_ab : a = b
247-
· -- Case 1: a = b. Since a ∉ Sigma, b ∉ Sigma as well.
248-
-- The projection removes b, so proj Sigma (w' ++ [b]) = proj Sigma w'.
249-
-- Right-cancelling a from proj Sigma w is the same as right-cancelling from proj Sigma w',
250-
-- which by the induction hypothesis is just proj Sigma w'.
251-
have h_bS : b ∉ Sigma := h_ab ▸ h
252-
simp [proj, h_bS]
253-
exact IH h
254-
· -- Case 2: a ≠ b. Now consider whether b ∈ Sigma.
255-
by_cases h_bS : b ∈ Sigma
256-
· -- Subcase: b ∈ Sigma. Then proj Sigma (w' ++ [b]) = proj Sigma w' ++ [b].
257-
-- Right-cancelling a from proj Sigma w is cancel_right (proj Sigma w') a ++ [b].
258-
-- By the induction hypothesis, cancel_right (proj Sigma w') a = proj Sigma w', so both sides match.
259-
simp [proj, h_bS]
260-
rw [List.cancel_right_snoc]
261-
simp [h_ab]
262-
exact IH h
263-
· -- Subcase: b ∉ Sigma. Then proj Sigma (w' ++ [b]) = proj Sigma w'.
264-
-- Right-cancelling a from proj Sigma w is the same as right-cancelling from proj Sigma w',
265-
-- which by the induction hypothesis is just proj Sigma w'.
266-
simp [proj, h_bS]
267-
exact IH h
27+
lemma cancelRight_nil (a : α) : [] ÷ a = [] := by rfl
26828

26929
@[simp]
270-
lemma singleton_cancel_right {a : α} : [a].cancel_right a = [] := by
271-
rw [← List.nil_append [a], List.cancel_right_snoc]
272-
simp
30+
lemma cancelRight_snoc (w : List α) (a b : α) :
31+
w ++ [b] ÷ a = if b = a then w else w ÷ a ++ [b] := by
32+
split_ifs with heq <;> simp [cancelRight, heq]
27333

274-
@[simp]
275-
lemma cancel_right_over_concat {w₁ w₂ : List α} (a : α) :
276-
(w₁ ++ w₂).cancel_right a
277-
= if (a ∈ w₂) then w₁ ++ (w₂.cancel_right a) else (w₁.cancel_right a) ++ w₂ := by
278-
induction w₂ using List.induction_right with
34+
lemma append_cancelRight {w₁ w₂ : List α} (a : α) :
35+
(w₁ ++ w₂) ÷ a = if a ∈ w₂ then w₁ ++ (w₂ ÷ a) else (w₁ ÷ a) ++ w₂ := by
36+
induction w₂ using List.reverseRecOn with
27937
| nil =>
28038
simp
281-
| snoc w₂' a' ih =>
282-
nth_rw 1 [← List.append_assoc]
283-
by_cases ha : a ∈ w₂'
284-
all_goals
285-
by_cases heq : a = a'
286-
· rw [List.cancel_right_snoc, List.cancel_right_snoc]
287-
simp [heq]
288-
· rw [List.cancel_right_snoc, List.cancel_right_snoc]
289-
simp [ha, heq, ih]
290-
291-
/-- Notation for right cancellation. -/
292-
infixl:65 " ÷ " => List.cancel_right
39+
| append_singleton w₂' b ih =>
40+
rw [← List.append_assoc, cancelRight_snoc]
41+
by_cases heq : b = a <;> by_cases h_mem : a ∈ w₂'
42+
· simp [heq]
43+
· simp [heq]
44+
· simp [heq, h_mem, ih]
45+
· simp [heq, h_mem, ih, Ne.symm]
29346

294-
/-- Projection commutes with right-cancellation. -/
29547
@[simp]
296-
lemma proj_commutes_with_cancel_right (Sigma : Alphabet α) (w : List α) (a : α) :
297-
cancel_right (proj Sigma w) a = proj Sigma (cancel_right w a) := by
298-
-- The right-cancellation is defined as reversing, left-cancelling, then reversing again.
299-
-- Since proj and reverse commute (by proj_and_reverse_commute), the operations can be swapped.
300-
simp [cancel_right, proj_commutes_with_reverse]
48+
lemma singleton_cancelRight {a : α} : [a] ÷ a = [] := by simp [cancelRight]
49+
50+
lemma proj_cancel_right (S : Finset α) (w : List α) (a : α) :
51+
proj S (w ÷ a) = if a ∈ S then proj S w ÷ a else proj S w := by
52+
induction w using List.reverseRecOn with
53+
| nil =>
54+
simp [proj]
55+
| append_singleton w' b ih =>
56+
split_ifs with ha <;> by_cases heq : b = a
57+
· simp [heq, ha, proj]
58+
· simp [heq, ha, ih]
59+
by_cases hb : b ∈ S
60+
· simp [proj, hb, heq]
61+
· simp [proj, hb]
62+
· simp [heq, ha, proj]
63+
· simp [heq, ha, ih]
30164

30265
end List
30366

0 commit comments

Comments
 (0)