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