Skip to content

Commit 7f08527

Browse files
committed
feat: add Cslib/Foundations/Data/OmegaSequence/Flatten.lean
1 parent e912abd commit 7f08527

File tree

2 files changed

+151
-0
lines changed

2 files changed

+151
-0
lines changed

Cslib.lean

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import Cslib.Foundations.Data.FinFun
1313
import Cslib.Foundations.Data.HasFresh
1414
import Cslib.Foundations.Data.Nat.Segment
1515
import Cslib.Foundations.Data.OmegaSequence.Defs
16+
import Cslib.Foundations.Data.OmegaSequence.Flatten
1617
import Cslib.Foundations.Data.OmegaSequence.Init
1718
import Cslib.Foundations.Data.Relation
1819
import Cslib.Foundations.Semantics.LTS.Basic
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
/-
2+
Copyright (c) 2025 Ching-Tsun Chou. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Authors: Ching-Tsun Chou
5+
-/
6+
7+
import Cslib.Foundations.Data.Nat.Segment
8+
import Cslib.Foundations.Data.OmegaSequence.Init
9+
import Mathlib.Tactic
10+
11+
/-!
12+
# Flattening an infinite sequence of lists
13+
14+
Given an ω-sequence `ls` of (nonempty) lists, `ls.flatten` is the infinite sequence
15+
formed by the concatenation of all of them.
16+
-/
17+
18+
namespace Cslib
19+
20+
open Nat Function
21+
22+
namespace ωSequence
23+
24+
universe u v w
25+
variable {α : Type u} {β : Type v} {δ : Type w}
26+
27+
/-- Given an ω-sequence `ls` of lists, `ls.cumLen k` is the cumulative sum
28+
of `(ls k).length` for `k = 0, ..., k - 1`. -/
29+
def cumLen (ls : ωSequence (List α)) : ℕ → ℕ
30+
| 0 => 0
31+
| k + 1 => ls.cumLen k + (ls k).length
32+
33+
/- The following are some helper theorems about `ls.cumLen`. -/
34+
35+
@[simp, scoped grind =]
36+
theorem cumLen_zero {ls : ωSequence (List α)} :
37+
ls.cumLen 0 = 0 :=
38+
rfl
39+
40+
theorem cumLen_succ (ls : ωSequence (List α)) (k : ℕ) :
41+
ls.cumLen (k + 1) = ls.cumLen k + (ls k).length :=
42+
rfl
43+
44+
theorem cumLen_1plus_drop (ls : ωSequence (List α)) (k : ℕ) :
45+
ls.cumLen (1 + k) = (ls 0).length + (ls.drop 1).cumLen k := by
46+
induction k
47+
case zero => simp [cumLen_zero, cumLen_succ]
48+
case succ k h_ind =>
49+
rw [← add_assoc, cumLen_succ, h_ind, cumLen_succ, add_assoc]
50+
congr 2 ; rw [get_drop]
51+
52+
/-- If all lists in `ls` are nonempty, then `ls.cumLen` is strictly monotonic. -/
53+
theorem cumLen_strict_mono {ls : ωSequence (List α)} (h_ls : ∀ k, (ls k).length > 0) :
54+
StrictMono ls.cumLen := by
55+
apply strictMono_nat_of_lt_succ
56+
intro k ; have := h_ls k
57+
rw [cumLen_succ] ; omega
58+
59+
@[simp, scoped grind =]
60+
theorem cumLen_segment_zero {ls : ωSequence (List α)} (h_ls : ∀ k, (ls k).length > 0)
61+
(n : ℕ) (h_n : n < (ls 0).length) : segment ls.cumLen n = 0 := by
62+
have h0 : ls.cumLen 0 ≤ n := by simp [cumLen_zero]
63+
have h1 : n < ls.cumLen 1 := by simpa [cumLen_succ, cumLen_zero]
64+
exact segment_range_val (cumLen_strict_mono h_ls) h0 h1
65+
66+
open scoped Classical in
67+
theorem cumLen_segment_1plus {ls : ωSequence (List α)} (h_ls : ∀ k, (ls k).length > 0)
68+
(n : ℕ) (h_n : (ls 0).length ≤ n) :
69+
segment ls.cumLen n = 1 + segment (ls.drop 1).cumLen (n - (ls 0).length) := by
70+
have h0 : (ls.drop 1).cumLen 0 = 0 := by simp [cumLen_zero]
71+
rw [add_comm, segment_plus_one h0] ; unfold Nat.segment
72+
simp only [Nat.count_eq_card_filter_range]
73+
have h1 : {x ∈ Finset.range (n + 1) | x ∈ Set.range ls.cumLen} = insert 0
74+
{x ∈ Finset.range (n + 1) | x ∈ Set.range ls.cumLen ∧ (ls 0).length ≤ x} := by
75+
ext k ; simp only [Set.mem_range, Finset.mem_filter, Finset.mem_range, Finset.mem_insert]
76+
constructor
77+
· rintro ⟨h_k, i, rfl⟩
78+
simp only [h_k, exists_apply_eq_apply, true_and, or_iff_not_imp_left]
79+
intro h_i
80+
suffices h : i = 1 + (i - 1) by rw [h, cumLen_1plus_drop] ; omega
81+
suffices h : 0 < i by omega
82+
rw [← StrictMono.lt_iff_lt (cumLen_strict_mono h_ls), cumLen_zero] ; omega
83+
· rintro (rfl | _)
84+
· simp only [lt_add_iff_pos_left, add_pos_iff, zero_lt_one, or_true, true_and]
85+
use 0 ; rw [cumLen_zero]
86+
· grind
87+
have h2 : 0 ∉ {x ∈ Finset.range (n + 1) | x ∈ Set.range ls.cumLen ∧ (ls 0).length ≤ x} := by
88+
suffices h : ¬ (ls 0).length ≤ 0 by simp [h]
89+
grind
90+
rw [h1, Finset.card_insert_of_notMem h2, Nat.add_one_sub_one] ; symm
91+
apply Set.BijOn.finsetCard_eq (fun n ↦ n + (ls 0).length)
92+
unfold Set.BijOn ; constructorm* _ ∧ _
93+
· intro k ; simp only [Set.mem_range, Finset.coe_filter, Finset.mem_range, Set.mem_setOf_eq,
94+
le_add_iff_nonneg_left, _root_.zero_le, and_true]
95+
rintro ⟨h_k, i, rfl⟩ ; constructorm* _ ∧ _
96+
· omega
97+
· use (1 + i) ; rw [cumLen_1plus_drop, add_comm]
98+
· apply Set.injOn_of_injective ; intro i j ; grind
99+
· intro k
100+
simp only [Set.mem_range, Finset.coe_filter, Finset.mem_range, Set.mem_setOf_eq, Set.mem_image]
101+
rintro ⟨h_k, ⟨i, rfl⟩, h_l0⟩
102+
use (ls.cumLen i - (ls 0).length)
103+
simp (disch := omega) only [Nat.sub_add_cancel, and_true] ; constructor
104+
· omega
105+
· use (i - 1)
106+
have := cumLen_1plus_drop ls (i - 1)
107+
have : 1 + (i - 1) = i := by
108+
suffices 0 < i by omega
109+
rw [← StrictMono.lt_iff_lt (cumLen_strict_mono h_ls), cumLen_zero]
110+
grind
111+
grind
112+
113+
/-- Given an ω-sequence `ls` of lists, `ls.flatten` is the infinite sequence
114+
formed by the concatenation of all of them. For the definition to make proper
115+
sense, we will consistently assume that all lists in `ls` are nonempty. -/
116+
noncomputable def flatten [Inhabited α] (ls : ωSequence (List α)) : ωSequence α :=
117+
fun n ↦ (ls (segment ls.cumLen n))[n - ls.cumLen (segment ls.cumLen n)]!
118+
119+
theorem flatten_def [Inhabited α] (ls : ωSequence (List α)) (n : ℕ) :
120+
flatten ls n = (ls (segment ls.cumLen n))[n - ls.cumLen (segment ls.cumLen n)]! :=
121+
rfl
122+
123+
/-- `ls.flatten` equals the concatenation of `ls.head` and `ls.tail.flatten`. -/
124+
@[simp, scoped grind =]
125+
theorem flatten_cons [Inhabited α] {ls : ωSequence (List α)} (h_ls : ∀ k, (ls k).length > 0) :
126+
ls.head ++ω ls.tail.flatten = ls.flatten := by
127+
ext n ; rw [flatten_def, head, tail_eq_drop]
128+
rcases (show n < (ls 0).length ∨ n ≥ (ls 0).length by omega) with h_n | h_n
129+
· simp (disch := omega) [get_append_left, cumLen_segment_zero, cumLen_zero]
130+
· simp (disch := omega) [get_append_right', flatten_def, cumLen_segment_1plus, cumLen_1plus_drop]
131+
congr 2 ; omega
132+
133+
/-- `ls.flatten` equals the concatenation of `(ls.take n).flatten` and `(ls.drop n).flatten`. -/
134+
@[simp, scoped grind =]
135+
theorem flatten_append [Inhabited α] {ls : ωSequence (List α)} (h_ls : ∀ k, (ls k).length > 0)
136+
(n : ℕ) : (ls.take n).flatten ++ω (ls.drop n).flatten = ls.flatten := by
137+
revert ls
138+
induction n
139+
case zero => simp
140+
case succ n h_ind =>
141+
intro ls h_ls
142+
specialize h_ind (ls := ls.drop 1) (by grind)
143+
rw [drop_drop, add_comm] at h_ind
144+
rw [take_succ, List.flatten_cons, append_append_ωSequence, tail_eq_drop,
145+
h_ind, ← tail_eq_drop]
146+
apply flatten_cons h_ls
147+
148+
end ωSequence
149+
150+
end Cslib

0 commit comments

Comments
 (0)