From c3f7a58ac47dd83ab36e9226c2a3a9e96840fe34 Mon Sep 17 00:00:00 2001 From: Samuel Schlesinger Date: Fri, 30 Oct 2026 15:07:57 +0000 Subject: [PATCH 01/19] feat(logspace): prove the local row compression lemma The Phase 4 estimator needs to retain only a bounded list of exceptions without losing stability when that list changes. Formalize the native two-coordinate compression update of OpenAI2026LogSpace Section 8.2, equations (8.5)-(8.6), and all conclusions of Lemma 8.1. Prove small-entry replacement, signed large-entry preservation, coordinatewise interpolation, monotone defaults, strict candidate capacity and containment, and uniform 28-Lipschitz stability. Also prove the local 6u change bound used by the subsequent preloss argument. Add concrete tests of partial clipping, signed values, positive-default padding, empty rows, candidate selection and perturbations. This advances #1721 and #1444. Iterated propagation and its slack conversion (8.7), rarity estimates, recursive estimation and machine-space realization remain open. No selected formal abstract or roadmap endpoint changes. Validation on Lean v4.36.0-rc2, based on main ef811c832d4ac280d1655cf4b8d89d32f5c39da0: - Strict focused build of the module and concrete tests passed. - scripts/check.sh passed all six gates: strict full build, mk_all check, strict full tests (including the global axiom audit), lint, lint-style, and checkInitImports. - check_changed_files.py, check_tidy_surface.py, and check_hygiene.py passed. - Focused hygiene with --check-simp and git diff --check passed. Independent non-author review: Codex agent /root/compression_review approved source tree e70d93b914c6cef421eb3ee4171e40daae6073b4, including primary-source correspondence, APIs, boundary cases, tests and the one-step change bound. No requested fixes remain. This is agent review, not human approval. Worker: codex-row-compression-20261030, branch feat/logspace-compression-update. AI assistance: OpenAI Codex implementation and independent Codex review. --- Complexity.lean | 1 + .../Foundations/Analysis/RowCompression.lean | 369 ++++++++++++++++++ ComplexityTests/RowCompression.lean | 102 +++++ 3 files changed, 472 insertions(+) create mode 100644 Complexity/Foundations/Analysis/RowCompression.lean create mode 100644 ComplexityTests/RowCompression.lean diff --git a/Complexity.lean b/Complexity.lean index e9ed8c9a26..69f36f90fa 100644 --- a/Complexity.lean +++ b/Complexity.lean @@ -2351,6 +2351,7 @@ public import Complexity.Foundations.Analysis.LpNorm public import Complexity.Foundations.Analysis.LpNormMeasure public import Complexity.Foundations.Analysis.MarkovBrothersInequality public import Complexity.Foundations.Analysis.RootError +public import Complexity.Foundations.Analysis.RowCompression public import Complexity.Foundations.Analysis.SpecialFunctions.Arccos public import Complexity.Foundations.Analysis.SpecialFunctions.SmoothSwitch public import Complexity.Foundations.BooleanAnalysis.Bernoulli diff --git a/Complexity/Foundations/Analysis/RowCompression.lean b/Complexity/Foundations/Analysis/RowCompression.lean new file mode 100644 index 0000000000..6e5dd86110 --- /dev/null +++ b/Complexity/Foundations/Analysis/RowCompression.lean @@ -0,0 +1,369 @@ +/- +Copyright (c) 2026 Samuel Schlesinger. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Samuel Schlesinger +-/ + +module +-- upstream: candidate + +public import Complexity.Foundations.Data.Finset.KthLargest +public import Mathlib.Basic.Real.Basic +import Mathlib.Algebra.Order.Group.MinMax +import Mathlib.Tactic.FinCases +import Mathlib.Tactic.Linarith +import Mathlib.Tactic.Positivity +import Mathlib.Tactic.Ring + +/-! +# Compression of two-coordinate rows + +The local update of [OpenAI2026LogSpace, Section 8.2, (8.5)--(8.6), Lemma 8.1] replaces a +real row by a common default and a bounded number of exceptions. This is the deterministic +compression step of the logspace estimator; no probability or machine-space bound is asserted. + +For an old default `(z, 0)`, a floor `ρ`, and an input row `w`, put +`m y = max |w y 0| |w y 1|` and `u = max z (max ρ (rank_n m))`. The new default is +`z' = max u (min (max z (rank_K (w · 0))) (3 * u))`. Every displacement from `(z', 0)` +is clipped to radius `7 * max (m y - 2 * u) 0`. + +`Finset.kthLargest` pads with zeros. For a nonnegative old default `z`, taking `max z` of this +rank accounts for the paper's dummy copies of `(z, 0)`. In the size rank this maximum is already +absorbed by `u`. The finite set `s` consists of real endpoint IDs; dummy positions never enter +the support count. Input coordinates may be negative. Positive `n` and `K` suffice for stability; +the later condition `K ≤ n` is not needed for this local result. + +## Main definitions + +* `Cslib.RowCompression.threshold`, `Cslib.RowCompression.newDefault`: the thresholds. +* `Cslib.RowCompression.update`: the compressed row, as a mathematical function. +* `Cslib.RowCompression.candidates`: a list of possible exceptions, selected by input size. + +## Main results + +* `Cslib.RowCompression.update_eq_default_of_size_le`: small entries become default. +* `Cslib.RowCompression.update_eq_self_of_three_mul_le`: large entries are unchanged. +* `Cslib.RowCompression.update_mem_Icc`: each coordinate lies between input and default. +* `Cslib.RowCompression.abs_update_sub_le_six_mul`: one update changes a coordinate by at most + six times its threshold, the local bound used in the subsequent preloss argument. +* `Cslib.RowCompression.le_newDefault`: defaults are nondecreasing. +* `Cslib.RowCompression.card_candidates_lt`: fewer than `n` candidates suffice. +* `Cslib.RowCompression.update_eq_default_of_not_mem_candidates`: the candidate set represents + the entire row on `s`. +* `Cslib.RowCompression.candidates_subset`: candidates come from the previous list and new IDs. +* `Cslib.RowCompression.abs_update_sub_update_le`: the full update is uniformly 28-Lipschitz. + +## References + +* [OpenAI, *Exact Derandomization of Logarithmic Space: L = RL = BPL*][OpenAI2026LogSpace], + Section 8.2, (8.5)--(8.6), Lemma 8.1 (23 September 2026, revision `7ef5c0cc`, not peer reviewed). +-/ + +public section + +namespace Cslib.RowCompression + +open Finset + +variable {ι : Type*} + +/-- The sup norm of a two-coordinate entry. -/ +@[expose] noncomputable def entrySize (w : Fin 2 → ℝ) : ℝ := max |w 0| |w 1| + +/-- The common default entry `(z, 0)`. -/ +@[expose] def defaultEntry (z : ℝ) (ν : Fin 2) : ℝ := if ν = 0 then z else 0 + +/-- The clipping radius for an entry at threshold `u`. -/ +@[expose] noncomputable def radius (u : ℝ) (w : Fin 2 → ℝ) : ℝ := + 7 * max (entrySize w - 2 * u) 0 + +/-- Clip each displacement from `(z, 0)` to the entry's radius. -/ +@[expose] noncomputable def updateEntry (u z : ℝ) (w : Fin 2 → ℝ) (ν : Fin 2) : ℝ := + defaultEntry z ν + max (-radius u w) (min (w ν - defaultEntry z ν) (radius u w)) + +/-- The size threshold, with dummy copies of the old default included in its rank. -/ +@[expose] noncomputable def threshold (s : Finset ι) (n : ℕ) (ρ z : ℝ) + (w : ι → Fin 2 → ℝ) : ℝ := + max z (max ρ (kthLargest n s fun y => entrySize (w y))) + +/-- The new nonnegative default; `max z` accounts for dummy copies in the first-coordinate rank. +For nonnegative `z` this is exactly (8.5) of [OpenAI2026LogSpace]. -/ +@[expose] noncomputable def newDefault (s : Finset ι) (n K : ℕ) (ρ z : ℝ) + (w : ι → Fin 2 → ℝ) : ℝ := + max (threshold s n ρ z w) + (min (max z (kthLargest K s fun y => w y 0)) (3 * threshold s n ρ z w)) + +/-- The compression update of [OpenAI2026LogSpace, (8.6)]. -/ +@[expose] noncomputable def update (s : Finset ι) (n K : ℕ) (ρ z : ℝ) + (w : ι → Fin 2 → ℝ) (y : ι) : Fin 2 → ℝ := + updateEntry (threshold s n ρ z w) (newDefault s n K ρ z w) (w y) + +/-- A coarse candidate list: every non-default output has input size greater than `u`. -/ +@[expose] noncomputable def candidates (s : Finset ι) (n : ℕ) (ρ z : ℝ) + (w : ι → Fin 2 → ℝ) : Finset ι := + {y ∈ s | threshold s n ρ z w < entrySize (w y)} + +variable {s : Finset ι} {n K : ℕ} {ρ z : ℝ} {w : ι → Fin 2 → ℝ} + +theorem entrySize_nonneg (v : Fin 2 → ℝ) : 0 ≤ entrySize v := + (abs_nonneg _).trans (le_max_left _ _) + +theorem abs_apply_le_entrySize (v : Fin 2 → ℝ) (ν : Fin 2) : |v ν| ≤ entrySize v := by + fin_cases ν + · exact le_max_left _ _ + · exact le_max_right _ _ + +@[simp] +theorem entrySize_defaultEntry (hz : 0 ≤ z) : entrySize (defaultEntry z) = z := by + simp [entrySize, defaultEntry, abs_of_nonneg hz, hz] + +theorem radius_nonneg (u : ℝ) (v : Fin 2 → ℝ) : 0 ≤ radius u v := by + unfold radius + positivity + +theorem threshold_nonneg : 0 ≤ threshold s n ρ z w := + kthLargest_nonneg.trans ((le_max_right _ _).trans (le_max_right _ _)) + +theorem le_threshold : z ≤ threshold s n ρ z w := le_max_left _ _ + +theorem floor_le_threshold : ρ ≤ threshold s n ρ z w := + (le_max_left _ _).trans (le_max_right _ _) + +theorem threshold_le_newDefault : threshold s n ρ z w ≤ newDefault s n K ρ z w := + le_max_left _ _ + +theorem newDefault_le_three_mul : newDefault s n K ρ z w ≤ 3 * threshold s n ρ z w := + max_le (by linarith [threshold_nonneg (s := s) (n := n) (ρ := ρ) (z := z) (w := w)]) + (min_le_right _ _) + +theorem le_newDefault : z ≤ newDefault s n K ρ z w := + le_threshold.trans threshold_le_newDefault + +theorem newDefault_nonneg : 0 ≤ newDefault s n K ρ z w := + threshold_nonneg.trans threshold_le_newDefault + +theorem updateEntry_eq_default_of_size_le {u b : ℝ} {v : Fin 2 → ℝ} + (hv : entrySize v ≤ 2 * u) : updateEntry u b v = defaultEntry b := by + funext ν + simp [updateEntry, radius, max_eq_right (sub_nonpos.mpr hv)] + +theorem updateEntry_eq_self_of_three_mul_le {u b : ℝ} {v : Fin 2 → ℝ} + (hu : 0 ≤ u) (hb : 0 ≤ b) (hb' : b ≤ 3 * u) (hv : 3 * u ≤ entrySize v) : + updateEntry u b v = v := by + have hr : radius u v = 7 * (entrySize v - 2 * u) := by + rw [radius, max_eq_left (by linarith)] + funext ν + have hν := abs_apply_le_entrySize v ν + have hd : |defaultEntry b ν| ≤ 3 * u := by + unfold defaultEntry + split_ifs + · simpa [abs_of_nonneg hb] using hb' + · simpa using mul_nonneg (by norm_num : (0 : ℝ) ≤ 3) hu + have hdiff : |v ν - defaultEntry b ν| ≤ radius u v := by + calc |v ν - defaultEntry b ν| ≤ |v ν| + |defaultEntry b ν| := abs_sub _ _ + _ ≤ radius u v := by rw [hr]; linarith + rw [updateEntry, min_eq_left (abs_le.mp hdiff).2, + max_eq_right (abs_le.mp hdiff).1, add_sub_cancel] + +private theorem add_clip_mem_Icc (b x r : ℝ) (hr : 0 ≤ r) : + b + max (-r) (min (x - b) r) ∈ Set.Icc (min x b) (max x b) := by + rcases le_total x b with h | h + · rw [min_eq_left h, max_eq_right h, min_eq_left (by linarith : x - b ≤ r)] + exact ⟨by linarith [le_max_right (-r) (x - b)], + by have := max_le (by linarith : -r ≤ 0) (sub_nonpos.mpr h); linarith⟩ + · rw [min_eq_right h, max_eq_left h] + have hlo : 0 ≤ max (-r) (min (x - b) r) := + (le_min (sub_nonneg.mpr h) hr).trans (le_max_right _ _) + have hhi : max (-r) (min (x - b) r) ≤ x - b := + max_le (by linarith) (min_le_left _ _) + exact ⟨by linarith, by linarith⟩ + +theorem updateEntry_mem_Icc (u b : ℝ) (v : Fin 2 → ℝ) (ν : Fin 2) : + updateEntry u b v ν ∈ Set.Icc (min (v ν) (defaultEntry b ν)) + (max (v ν) (defaultEntry b ν)) := + add_clip_mem_Icc _ _ _ (radius_nonneg _ _) + +/-- Clipping toward the default changes a coordinate by no more than its distance to it. -/ +theorem abs_updateEntry_sub_le (u b : ℝ) (v : Fin 2 → ℝ) (ν : Fin 2) : + |updateEntry u b v ν - v ν| ≤ |v ν - defaultEntry b ν| := by + have h := updateEntry_mem_Icc u b v ν + rcases le_total (v ν) (defaultEntry b ν) with hle | hle + · rw [min_eq_left hle, max_eq_right hle] at h + rw [abs_of_nonneg (sub_nonneg.mpr h.1), abs_of_nonpos (sub_nonpos.mpr hle)] + linarith [h.2] + · rw [min_eq_right hle, max_eq_left hle] at h + rw [abs_of_nonpos (sub_nonpos.mpr h.2), abs_of_nonneg (sub_nonneg.mpr hle)] + linarith [h.1] + +/-- Entries of size at most twice the threshold become the new default. -/ +theorem update_eq_default_of_size_le {y : ι} + (hy : entrySize (w y) ≤ 2 * threshold s n ρ z w) : + update s n K ρ z w y = defaultEntry (newDefault s n K ρ z w) := + updateEntry_eq_default_of_size_le hy + +/-- Entries of size at least three times the threshold are preserved, including signed entries. -/ +theorem update_eq_self_of_three_mul_le {y : ι} + (hy : 3 * threshold s n ρ z w ≤ entrySize (w y)) : update s n K ρ z w y = w y := + updateEntry_eq_self_of_three_mul_le threshold_nonneg newDefault_nonneg newDefault_le_three_mul hy + +/-- Compression moves each coordinate toward the new default without overshooting. -/ +theorem update_mem_Icc (y : ι) (ν : Fin 2) : + update s n K ρ z w y ν ∈ Set.Icc (min (w y ν) (defaultEntry (newDefault s n K ρ z w) ν)) + (max (w y ν) (defaultEntry (newDefault s n K ρ z w) ν)) := + updateEntry_mem_Icc _ _ _ _ + +/-- The local change bound used before the first overflow in [OpenAI2026LogSpace, Section 8.3]. +When the threshold equals the prescribed floor `ρ`, each coordinate changes by at most `6 * ρ`. +This does not yet sum changes over a schedule or prove the later weighted preloss estimate. -/ +theorem abs_update_sub_le_six_mul (y : ι) (ν : Fin 2) : + |update s n K ρ z w y ν - w y ν| ≤ 6 * threshold s n ρ z w := by + by_cases hy : 3 * threshold s n ρ z w ≤ entrySize (w y) + · rw [update_eq_self_of_three_mul_le hy, sub_self, abs_zero] + exact mul_nonneg (by norm_num) threshold_nonneg + have hm : entrySize (w y) < 3 * threshold s n ρ z w := lt_of_not_ge hy + have hb : |defaultEntry (newDefault s n K ρ z w) ν| ≤ 3 * threshold s n ρ z w := by + unfold defaultEntry + split_ifs + · rw [abs_of_nonneg newDefault_nonneg] + exact newDefault_le_three_mul + · simpa using mul_nonneg (by norm_num : (0 : ℝ) ≤ 3) + (threshold_nonneg (s := s) (n := n) (ρ := ρ) (z := z) (w := w)) + calc |update s n K ρ z w y ν - w y ν| + ≤ |w y ν - defaultEntry (newDefault s n K ρ z w) ν| := abs_updateEntry_sub_le _ _ _ _ + _ ≤ |w y ν| + |defaultEntry (newDefault s n K ρ z w) ν| := abs_sub _ _ + _ ≤ 6 * threshold s n ρ z w := by linarith [abs_apply_le_entrySize (w y) ν] + +/-- The coarse candidate list is strictly smaller than the capacity, hence also at most `n`. -/ +theorem card_candidates_lt (hn : 0 < n) : #(candidates s n ρ z w) < n := by + apply Nat.lt_of_not_ge + intro h + have hlt := (lt_kthLargest_iff hn threshold_nonneg).mpr h + exact (not_lt_of_ge ((le_max_right _ _).trans (le_max_right _ _))) hlt + +/-- Outside the candidate list every real endpoint has the new default value. -/ +theorem update_eq_default_of_not_mem_candidates {y : ι} (hy : y ∈ s) + (hnot : y ∉ candidates s n ρ z w) : + update s n K ρ z w y = defaultEntry (newDefault s n K ρ z w) := by + have hle : entrySize (w y) ≤ threshold s n ρ z w := by + simpa only [candidates, mem_filter, hy, true_and, not_lt] using hnot + have hnonneg : 0 ≤ threshold s n ρ z w := threshold_nonneg + exact update_eq_default_of_size_le (by linarith) + +open scoped Classical in +/-- The exact exception set is smaller than `n`, regardless of coincidences with the default. -/ +theorem card_exceptions_lt (hn : 0 < n) : + #{y ∈ s | update s n K ρ z w y ≠ defaultEntry (newDefault s n K ρ z w)} < n := by + refine (card_le_card ?_).trans_lt (card_candidates_lt (s := s) (ρ := ρ) (z := z) (w := w) hn) + intro y hy + simp only [mem_filter] at hy + by_contra h + exact hy.2 (update_eq_default_of_not_mem_candidates hy.1 h) + +/-- Candidates can be selected entirely from any set containing the non-default input IDs. +Use the union of the previous exception list and the newly touched IDs for that set. -/ +theorem candidates_subset (hz : 0 ≤ z) (t : Finset ι) + (hw : ∀ y ∈ s, y ∉ t → w y = defaultEntry z) : candidates s n ρ z w ⊆ t := by + intro y hy + obtain ⟨hys, hy⟩ := mem_filter.mp hy + by_contra hyt + rw [hw y hys hyt, entrySize_defaultEntry hz] at hy + exact (not_lt_of_ge le_threshold) hy + +/-! ## Stability independent of the row width -/ + +private theorem abs_max_sub_max_le {a b c d ε : ℝ} (ha : |a - c| ≤ ε) + (hb : |b - d| ≤ ε) : |max a b - max c d| ≤ ε := + (abs_max_sub_max_le_max _ _ _ _).trans (max_le ha hb) + +private theorem abs_min_sub_min_le {a b c d ε : ℝ} (ha : |a - c| ≤ ε) + (hb : |b - d| ≤ ε) : |min a b - min c d| ≤ ε := + (abs_min_sub_min_le_max _ _ _ _).trans (max_le ha hb) + +theorem abs_entrySize_sub_entrySize_le {v v' : Fin 2 → ℝ} {δ : ℝ} + (h : ∀ ν, |v ν - v' ν| ≤ δ) : |entrySize v - entrySize v'| ≤ δ := + abs_max_sub_max_le ((abs_abs_sub_abs_le _ _).trans (h 0)) + ((abs_abs_sub_abs_le _ _).trans (h 1)) + +theorem abs_defaultEntry_sub_defaultEntry_le {b b' δ : ℝ} (hδ : 0 ≤ δ) + (hb : |b - b'| ≤ δ) (ν : Fin 2) : |defaultEntry b ν - defaultEntry b' ν| ≤ δ := by + unfold defaultEntry + split_ifs + · exact hb + · simpa using hδ + +variable {z' δ : ℝ} {w' : ι → Fin 2 → ℝ} + +/-- The threshold varies by at most the sup perturbation of the row and old default. -/ +theorem abs_threshold_sub_threshold_le (hn : 0 < n) (hδ : 0 ≤ δ) (hz : |z - z'| ≤ δ) + (hw : ∀ y ∈ s, ∀ ν, |w y ν - w' y ν| ≤ δ) : + |threshold s n ρ z w - threshold s n ρ z' w'| ≤ δ := by + refine abs_max_sub_max_le hz (abs_max_sub_max_le (by simpa using hδ) ?_) + exact abs_kthLargest_sub_kthLargest_le hn hδ fun y hy => + abs_entrySize_sub_entrySize_le (hw y hy) + +/-- The default has Lipschitz constant three, uniformly in the capacities and row width. -/ +theorem abs_newDefault_sub_newDefault_le (hn : 0 < n) (hK : 0 < K) (hδ : 0 ≤ δ) + (hz : |z - z'| ≤ δ) (hw : ∀ y ∈ s, ∀ ν, |w y ν - w' y ν| ≤ δ) : + |newDefault s n K ρ z w - newDefault s n K ρ z' w'| ≤ 3 * δ := by + have hu := abs_threshold_sub_threshold_le (ρ := ρ) hn hδ hz hw + have hq : |max z (kthLargest K s fun y => w y 0) - + max z' (kthLargest K s fun y => w' y 0)| ≤ δ := + abs_max_sub_max_le hz (abs_kthLargest_sub_kthLargest_le hK hδ fun y hy => hw y hy 0) + refine abs_max_sub_max_le (hu.trans (by linarith)) + (abs_min_sub_min_le (hq.trans (by linarith)) ?_) + rw [← mul_sub, abs_mul, abs_of_pos (by norm_num : (0 : ℝ) < 3)] + exact mul_le_mul_of_nonneg_left hu (by norm_num) + +/-- The radius is 21-Lipschitz jointly in the entry and the threshold. -/ +theorem abs_radius_sub_radius_le {u u' : ℝ} {v v' : Fin 2 → ℝ} (hδ : 0 ≤ δ) + (hu : |u - u'| ≤ δ) (hv : ∀ ν, |v ν - v' ν| ≤ δ) : + |radius u v - radius u' v'| ≤ 21 * δ := by + have hm := abs_entrySize_sub_entrySize_le hv + have hsub : |(entrySize v - 2 * u) - (entrySize v' - 2 * u')| ≤ 3 * δ := by + calc |(entrySize v - 2 * u) - (entrySize v' - 2 * u')| + = |(entrySize v - entrySize v') - 2 * (u - u')| := by congr 1; ring + _ ≤ |entrySize v - entrySize v'| + |2 * (u - u')| := abs_sub _ _ + _ ≤ 3 * δ := by rw [abs_mul, abs_of_pos (by norm_num : (0 : ℝ) < 2)]; linarith + have hmax := abs_max_sub_max_le (b := 0) (d := 0) hsub + (by simpa using (show 0 ≤ 3 * δ by positivity)) + unfold radius + rw [← mul_sub, abs_mul, abs_of_pos (by norm_num : (0 : ℝ) < 7)] + linarith + +/-- The update is 28-Lipschitz in the row and old default, with the floor and capacities fixed. +The estimate is on real endpoints `y ∈ s`; it is independent of their number and magnitudes. -/ +theorem abs_update_sub_update_le (hn : 0 < n) (hK : 0 < K) (hδ : 0 ≤ δ) + (hz : |z - z'| ≤ δ) (hw : ∀ y ∈ s, ∀ ν, |w y ν - w' y ν| ≤ δ) + {y : ι} (hy : y ∈ s) (ν : Fin 2) : + |update s n K ρ z w y ν - update s n K ρ z' w' y ν| ≤ 28 * δ := by + have hu := abs_threshold_sub_threshold_le (ρ := ρ) hn hδ hz hw + have hb := abs_newDefault_sub_newDefault_le (ρ := ρ) hn hK hδ hz hw + have hbν := abs_defaultEntry_sub_defaultEntry_le (by positivity : 0 ≤ 3 * δ) hb ν + have hr := abs_radius_sub_radius_le hδ hu (hw y hy) + have hd : |(w y ν - defaultEntry (newDefault s n K ρ z w) ν) - + (w' y ν - defaultEntry (newDefault s n K ρ z' w') ν)| ≤ 4 * δ := by + calc _ = |(w y ν - w' y ν) - + (defaultEntry (newDefault s n K ρ z w) ν - + defaultEntry (newDefault s n K ρ z' w') ν)| := by congr 1; ring + _ ≤ |w y ν - w' y ν| + |defaultEntry (newDefault s n K ρ z w) ν - + defaultEntry (newDefault s n K ρ z' w') ν| := abs_sub _ _ + _ ≤ 4 * δ := by linarith [hw y hy ν] + have hneg : |-radius (threshold s n ρ z w) (w y) - + -radius (threshold s n ρ z' w') (w' y)| ≤ 21 * δ := by + simpa only [neg_sub_neg, abs_sub_comm] using hr + have hclip := abs_max_sub_max_le hneg + (abs_min_sub_min_le (hd.trans (by linarith : 4 * δ ≤ 21 * δ)) hr) + unfold update updateEntry + calc _ ≤ |defaultEntry (newDefault s n K ρ z w) ν - + defaultEntry (newDefault s n K ρ z' w') ν| + + |max (-radius (threshold s n ρ z w) (w y)) + (min (w y ν - defaultEntry (newDefault s n K ρ z w) ν) + (radius (threshold s n ρ z w) (w y))) - + max (-radius (threshold s n ρ z' w') (w' y)) + (min (w' y ν - defaultEntry (newDefault s n K ρ z' w') ν) + (radius (threshold s n ρ z' w') (w' y)))| := by + rw [add_sub_add_comm] + exact abs_add_le _ _ + _ ≤ 28 * δ := by linarith + +end Cslib.RowCompression diff --git a/ComplexityTests/RowCompression.lean b/ComplexityTests/RowCompression.lean new file mode 100644 index 0000000000..a071786ead --- /dev/null +++ b/ComplexityTests/RowCompression.lean @@ -0,0 +1,102 @@ +/- +Copyright (c) 2026 Samuel Schlesinger. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Samuel Schlesinger +-/ + +import Complexity.Foundations.Analysis.RowCompression +import Mathlib.LinearAlgebra.Matrix.Notation +import Mathlib.Tactic.FinCases +import Mathlib.Tactic.NormNum + +/-! +# Concrete compression updates + +These examples exercise a preserved large entry, actual partial clipping between the two size +thresholds, negative inputs, dummy padding with a positive default, and the exception capacity. +-/ + +namespace ComplexityTests.RowCompression + +open Finset Cslib.RowCompression + +private def largeRow : Fin 2 → Fin 2 → ℝ := ![![10, 0], ![0, 0]] + +private theorem large_threshold : threshold univ 2 1 0 largeRow = 1 := by + norm_num [threshold, kthLargest, entrySize, largeRow, Fin.univ_succ, filter_insert, + filter_singleton] + +private theorem large_default : newDefault univ 2 1 1 0 largeRow = 3 := by + unfold newDefault + rw [large_threshold] + norm_num [kthLargest, largeRow, Fin.univ_succ, filter_insert, filter_singleton] + +-- A large entry survives and the small entry becomes the new default. +example : update univ 2 1 1 0 largeRow = ![![10, 0], ![3, 0]] := by + unfold update + rw [large_threshold, large_default] + funext y ν + fin_cases y <;> fin_cases ν <;> + norm_num [updateEntry, defaultEntry, radius, entrySize, largeRow] + +-- The list really has one exception, strictly fewer than the capacity two. +example : candidates univ 2 1 0 largeRow = {0} := by + unfold candidates + rw [large_threshold] + ext y + fin_cases y <;> norm_num [entrySize, largeRow] + +private noncomputable def transitionRow : Fin 2 → Fin 2 → ℝ := ![![0, 21 / 10], ![0, 0]] + +private theorem transition_threshold : threshold univ 2 1 0 transitionRow = 1 := by + have hr : kthLargest 2 univ (fun y => entrySize (transitionRow y)) = 0 := by + refine le_antisymm (not_lt.mp fun hlt => ?_) kthLargest_nonneg + have hcard := (lt_kthLargest_iff (by norm_num) le_rfl).mp hlt + have hsupport : ({y | 0 < entrySize (transitionRow y)} : Finset (Fin 2)) = {0} := by + ext y + fin_cases y <;> norm_num [entrySize, transitionRow] + rw [hsupport] at hcard + norm_num at hcard + norm_num [threshold, hr] + +private theorem transition_default : newDefault univ 2 1 1 0 transitionRow = 1 := by + unfold newDefault + rw [transition_threshold] + norm_num [kthLargest, transitionRow, Fin.univ_succ, filter_insert, filter_singleton] + +-- Size 2.1 is in the transition band (2,3); radius 0.7 clips both coordinates. +example : update univ 2 1 1 0 transitionRow = ![![3 / 10, 7 / 10], ![1, 0]] := by + unfold update + rw [transition_threshold, transition_default] + funext y ν + fin_cases y <;> fin_cases ν <;> + norm_num [updateEntry, defaultEntry, radius, entrySize, transitionRow] + +-- Large signed entries are preserved; no nonnegativity premise on row entries is hidden. +example : updateEntry 1 3 (![(-10), -4] : Fin 2 → ℝ) = ![-10, -4] := by + apply updateEntry_eq_self_of_three_mul_le <;> norm_num [entrySize] + +-- The old default exceeds the floor, and K exceeds the number of real positions. +-- The dummy padding still gives default two, with no candidate IDs. +example : newDefault (univ : Finset (Fin 1)) 2 3 1 2 (fun _ => defaultEntry 2) = 2 ∧ + candidates (univ : Finset (Fin 1)) 2 1 2 (fun _ => defaultEntry 2) = ∅ := by + norm_num [newDefault, candidates, threshold, kthLargest, entrySize, defaultEntry, + Fin.univ_succ] + +-- The empty real row also has a well-defined default; dummies are not counted as real IDs. +example : newDefault (∅ : Finset (Fin 2)) 1 1 1 2 largeRow = 2 ∧ + candidates (∅ : Finset (Fin 2)) 1 1 2 largeRow = ∅ := by + norm_num [newDefault, candidates, threshold, kthLargest] + +-- A concrete perturbation invokes the width-independent stability theorem. +example (y : Fin 2) (ν : Fin 2) : + |update univ 2 1 1 0 largeRow y ν - + update univ 2 1 1 (1 / 10) (fun y ν => largeRow y ν + 1 / 10) y ν| ≤ 14 / 5 := by + have h := abs_update_sub_update_le (s := univ) (n := 2) (K := 1) (ρ := 1) + (z := 0) (z' := 1 / 10) (δ := 1 / 10) (w := largeRow) + (w' := fun y ν => largeRow y ν + 1 / 10) (by norm_num) (by norm_num) (by norm_num) + (by norm_num) (fun y _ ν => by norm_num) (mem_univ y) ν + norm_num at h ⊢ + exact h + +end ComplexityTests.RowCompression From c4d5e70a57485632955a258d70d06b58a93aec6c Mon Sep 17 00:00:00 2001 From: Samuel Schlesinger Date: Fri, 30 Oct 2026 15:29:56 +0000 Subject: [PATCH 02/19] feat(logspace): iterate row compression and bound accumulated loss Add concrete increment-and-compression states and schedules. Prove width-independent 28^j propagation, exact restarts, a fifth-power slack bound under an explicit group-count condition, and accumulated row/default loss before overflow. This establishes the update-only part of OpenAI2026LogSpace (8.7) and the unweighted part of Lemma 8.2; weighted preloss and the final root functions remain separate. Validation on base c3f7a58ac47dd83ab36e9226c2a3a9e96840fe34: direct Lean 4.36.0-rc2 checks of both new modules with project options passed without diagnostics, using isolated output files and the parent checkout dependencies read-only. Concrete tests cover a two-group nonzero-loss execution, satisfied no-overflow bounds, an actual overflow after lowering capacity, and distinct initial-state perturbations. Focused proof hygiene including --check-simp and git diff --check passed. Aggregate regeneration and full project gates are delegated to integration. AI assistance: ChatGPT implemented and checked these proofs as worker codex-compression-iteration-20261030. Independent agent source/API review: codex-source-release-20261030 approved the library and tests at 7d08e44bbdb626b74adaa9c4d63e07faa28ce525. Publication adds only the generated aggregate import. Integrated targeted build, tests, aggregate check, hygiene and whitespace checks pass. Full gates run in PR CI. --- Complexity.lean | 1 + .../Analysis/RowCompression/Iteration.lean | 282 ++++++++++++++++++ ComplexityTests/RowCompressionIteration.lean | 109 +++++++ 3 files changed, 392 insertions(+) create mode 100644 Complexity/Foundations/Analysis/RowCompression/Iteration.lean create mode 100644 ComplexityTests/RowCompressionIteration.lean diff --git a/Complexity.lean b/Complexity.lean index 69f36f90fa..4902f4c799 100644 --- a/Complexity.lean +++ b/Complexity.lean @@ -2352,6 +2352,7 @@ public import Complexity.Foundations.Analysis.LpNormMeasure public import Complexity.Foundations.Analysis.MarkovBrothersInequality public import Complexity.Foundations.Analysis.RootError public import Complexity.Foundations.Analysis.RowCompression +public import Complexity.Foundations.Analysis.RowCompression.Iteration public import Complexity.Foundations.Analysis.SpecialFunctions.Arccos public import Complexity.Foundations.Analysis.SpecialFunctions.SmoothSwitch public import Complexity.Foundations.BooleanAnalysis.Bernoulli diff --git a/Complexity/Foundations/Analysis/RowCompression/Iteration.lean b/Complexity/Foundations/Analysis/RowCompression/Iteration.lean new file mode 100644 index 0000000000..f14c8c92ef --- /dev/null +++ b/Complexity/Foundations/Analysis/RowCompression/Iteration.lean @@ -0,0 +1,282 @@ +/- +Copyright (c) 2026 Samuel Schlesinger. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Samuel Schlesinger +-/ + +module +-- upstream: candidate + +public import Complexity.Foundations.Analysis.RowCompression +public import Mathlib.Algebra.BigOperators.Group.Finset.Defs +import Mathlib.Algebra.BigOperators.Group.Finset.Basic +import Mathlib.Tactic.Linarith +import Mathlib.Tactic.Positivity +import Mathlib.Tactic.Ring + +/-! +# Iterated row compression + +This module iterates the concrete update of [OpenAI2026LogSpace, Section 8.2, (8.5)--(8.6)]. +At group `i`, add the increment `Δ i` to the current row, then compress using capacities +`n i`, `K i` and floor `ρ i`. The state contains the entire row and its common default, so two +calculations need not select the same exception lists. + +The stability bound is the update-only part of (8.7): an initial absolute perturbation `δ` +is at most `28 ^ j * δ` after `j` updates with the same increments. Restarting at any group +gives the same assertion for a perturbation introduced there. The paper's final root functions +are not formalized here. The optional conversion to a fifth power of a slack assumes the +explicit scheduling fact `2 ^ j ≤ d + 1`; no halving schedule is constructed in this module. + +The accumulated row loss is at most six times the sum of the actual compression thresholds. +Before the first overflow, each threshold is its floor, yielding the unweighted estimate +`6 * ∑ i < j, ρ i` in the first assertion of [OpenAI2026LogSpace, Lemma 8.2]. This does not +assert the weighted preloss estimate (8.9), the small-floor estimates (8.8), stationary-reference +preservation, or a machine-space bound. + +## Main definitions + +* `Cslib.RowCompression.State`: the default and full two-coordinate row. +* `Cslib.RowCompression.advance`, `Cslib.RowCompression.iterate`: one update and its iteration. +* `Cslib.RowCompression.inputRow`, `Cslib.RowCompression.stepThreshold`: the input and actual + threshold at each group. +* `Cslib.RowCompression.uncompressedRow`: the initial row plus the prefix sum of increments. + +## Main results + +* `Cslib.RowCompression.iterate_stability`: width-independent propagation by `28 ^ j`. +* `Cslib.RowCompression.iterate_add`: restart a calculation at any group. +* `Cslib.RowCompression.iterate_stability_from`: propagate a perturbation from any group. +* `Cslib.RowCompression.iterate_stability_of_pow_le`: a polynomial bound given a slack bound. +* `Cslib.RowCompression.abs_iterate_sub_uncompressed_le`: accumulated compression loss. +* `Cslib.RowCompression.abs_iterate_sub_uncompressed_le_of_no_overflow`: the floor-sum bound. +* `Cslib.RowCompression.iterate_defaultValue_monotone`: defaults never decrease. + +## References + +* [OpenAI, *Exact Derandomization of Logarithmic Space: L = RL = BPL*][OpenAI2026LogSpace], + Sections 8.2--8.3, (8.7) and the unweighted assertion of Lemma 8.2 + (23 September 2026, revision `7ef5c0cc`, not peer reviewed). +-/ + +public section + +namespace Cslib.RowCompression + +open Finset + +variable {ι : Type*} + +/-- A compressed row represented by its full values and its common default. The finite +exception list is intentionally not part of the mathematical state. -/ +structure State (ι : Type*) where + /-- The first coordinate of the default entry; its second coordinate is zero. -/ + defaultValue : ℝ + /-- The full row, including values at positions represented by the default. -/ + row : ι → Fin 2 → ℝ + +/-- Add an increment and apply the concrete compression update. -/ +@[expose] noncomputable def advance (s : Finset ι) (n K : ℕ) (ρ : ℝ) + (Δ : ι → Fin 2 → ℝ) (a : State ι) : State ι := + { defaultValue := newDefault s n K ρ a.defaultValue (a.row + Δ) + row := update s n K ρ a.defaultValue (a.row + Δ) } + +/-- The state after `j` increment-and-compression groups, indexed starting at zero. -/ +@[expose] noncomputable def iterate (s : Finset ι) (n K : ℕ → ℕ) (ρ : ℕ → ℝ) + (Δ : ℕ → ι → Fin 2 → ℝ) (a : State ι) : ℕ → State ι + | 0 => a + | j + 1 => advance s (n j) (K j) (ρ j) (Δ j) (iterate s n K ρ Δ a j) + +/-- The row immediately after adding group `j` and before compressing it. -/ +@[expose] noncomputable def inputRow (s : Finset ι) (n K : ℕ → ℕ) (ρ : ℕ → ℝ) + (Δ : ℕ → ι → Fin 2 → ℝ) (a : State ι) (j : ℕ) : ι → Fin 2 → ℝ := + (iterate s n K ρ Δ a j).row + Δ j + +/-- The actual threshold of compression group `j`, including the old default and the size rank. -/ +@[expose] noncomputable def stepThreshold (s : Finset ι) (n K : ℕ → ℕ) (ρ : ℕ → ℝ) + (Δ : ℕ → ι → Fin 2 → ℝ) (a : State ι) (j : ℕ) : ℝ := + threshold s (n j) (ρ j) (iterate s n K ρ Δ a j).defaultValue (inputRow s n K ρ Δ a j) + +/-- The initial row plus all increments before group `j`, with no compression. -/ +@[expose] noncomputable def uncompressedRow (Δ : ℕ → ι → Fin 2 → ℝ) + (w : ι → Fin 2 → ℝ) (j : ℕ) (y : ι) (ν : Fin 2) : ℝ := + w y ν + ∑ i ∈ range j, Δ i y ν + +variable {s : Finset ι} {n K : ℕ → ℕ} {ρ : ℕ → ℝ} + {Δ : ℕ → ι → Fin 2 → ℝ} {a b : State ι} + +@[simp] +theorem iterate_zero : iterate s n K ρ Δ a 0 = a := rfl + +theorem iterate_succ (j : ℕ) : iterate s n K ρ Δ a (j + 1) = + advance s (n j) (K j) (ρ j) (Δ j) (iterate s n K ρ Δ a j) := rfl + +@[simp] +theorem uncompressedRow_zero {w : ι → Fin 2 → ℝ} : uncompressedRow Δ w 0 = w := by + funext y ν + simp [uncompressedRow] + +theorem uncompressedRow_succ {w : ι → Fin 2 → ℝ} (j : ℕ) (y : ι) (ν : Fin 2) : + uncompressedRow Δ w (j + 1) y ν = uncompressedRow Δ w j y ν + Δ j y ν := by + simp only [uncompressedRow, sum_range_succ] + ring + +theorem stepThreshold_nonneg (j : ℕ) : 0 ≤ stepThreshold s n K ρ Δ a j := + threshold_nonneg + +theorem floor_le_stepThreshold (j : ℕ) : ρ j ≤ stepThreshold s n K ρ Δ a j := + floor_le_threshold + +/-- The one-step compression loss, before any accumulation over the schedule. -/ +theorem abs_iterate_succ_sub_inputRow_le (j : ℕ) (y : ι) (ν : Fin 2) : + |(iterate s n K ρ Δ a (j + 1)).row y ν - inputRow s n K ρ Δ a j y ν| ≤ + 6 * stepThreshold s n K ρ Δ a j := + abs_update_sub_le_six_mul y ν + +/-- Addition of the same increment cancels in the one-step stability estimate. -/ +theorem advance_stability {n K : ℕ} {ρ δ : ℝ} {Δ : ι → Fin 2 → ℝ} + (hn : 0 < n) (hK : 0 < K) (hδ : 0 ≤ δ) (hz : |a.defaultValue - b.defaultValue| ≤ δ) + (hw : ∀ y ∈ s, ∀ ν, |a.row y ν - b.row y ν| ≤ δ) : + |(advance s n K ρ Δ a).defaultValue - (advance s n K ρ Δ b).defaultValue| ≤ 28 * δ ∧ + ∀ y ∈ s, ∀ ν, |(advance s n K ρ Δ a).row y ν - + (advance s n K ρ Δ b).row y ν| ≤ 28 * δ := by + have hadd : ∀ y ∈ s, ∀ ν, |(a.row + Δ) y ν - (b.row + Δ) y ν| ≤ δ := by + intro y hy ν + simpa only [Pi.add_apply, add_sub_add_right_eq_sub] using hw y hy ν + constructor + · exact (abs_newDefault_sub_newDefault_le hn hK hδ hz hadd).trans (by linarith) + · intro y hy ν + exact abs_update_sub_update_le hn hK hδ hz hadd hy ν + +/-- An absolute perturbation of the full initial state grows by at most `28 ^ j` through +`j` compression groups with the same increments [OpenAI2026LogSpace, (8.7)]. -/ +theorem iterate_stability {δ : ℝ} (hδ : 0 ≤ δ) (hz : |a.defaultValue - b.defaultValue| ≤ δ) + (hw : ∀ y ∈ s, ∀ ν, |a.row y ν - b.row y ν| ≤ δ) (j : ℕ) + (hn : ∀ i < j, 0 < n i) (hK : ∀ i < j, 0 < K i) : + |(iterate s n K ρ Δ a j).defaultValue - (iterate s n K ρ Δ b j).defaultValue| ≤ + 28 ^ j * δ ∧ + ∀ y ∈ s, ∀ ν, |(iterate s n K ρ Δ a j).row y ν - + (iterate s n K ρ Δ b j).row y ν| ≤ 28 ^ j * δ := by + induction j with + | zero => simpa using And.intro hz hw + | succ j ih => + have h := ih (fun i hi => hn i (Nat.lt_succ_of_lt hi)) + (fun i hi => hK i (Nat.lt_succ_of_lt hi)) + have hnext := advance_stability (ρ := ρ j) (Δ := Δ j) (hn j (Nat.lt_succ_self j)) + (hK j (Nat.lt_succ_self j)) (by positivity : 0 ≤ 28 ^ j * δ) h.1 h.2 + simpa only [iterate_succ, pow_succ, mul_assoc, mul_left_comm, mul_comm] using hnext + +/-- Restarting the indexed schedule preserves exactly the same states. -/ +theorem iterate_add (i j : ℕ) : iterate s n K ρ Δ a (i + j) = + iterate s (fun k => n (i + k)) (fun k => K (i + k)) (fun k => ρ (i + k)) + (fun k => Δ (i + k)) (iterate s n K ρ Δ a i) j := by + induction j with + | zero => rfl + | succ j ih => simp only [Nat.add_succ, iterate_succ, ih] + +/-- A perturbation present after group `i` propagates through the next `j` updates with factor +at most `28 ^ j`, without requiring agreement of earlier states or exception lists. -/ +theorem iterate_stability_from (i j : ℕ) {δ : ℝ} (hδ : 0 ≤ δ) + (hz : |(iterate s n K ρ Δ a i).defaultValue - + (iterate s n K ρ Δ b i).defaultValue| ≤ δ) + (hw : ∀ y ∈ s, ∀ ν, |(iterate s n K ρ Δ a i).row y ν - + (iterate s n K ρ Δ b i).row y ν| ≤ δ) + (hn : ∀ k < j, 0 < n (i + k)) (hK : ∀ k < j, 0 < K (i + k)) : + |(iterate s n K ρ Δ a (i + j)).defaultValue - + (iterate s n K ρ Δ b (i + j)).defaultValue| ≤ 28 ^ j * δ ∧ + ∀ y ∈ s, ∀ ν, |(iterate s n K ρ Δ a (i + j)).row y ν - + (iterate s n K ρ Δ b (i + j)).row y ν| ≤ 28 ^ j * δ := by + rw [iterate_add (a := a) i j, iterate_add (a := b) i j] + exact iterate_stability hδ hz hw j hn hK + +/-- A schedule with `2 ^ j ≤ d + 1` turns the propagation factor into a polynomial in the +slack. We enlarge `28` to `2 ^ 5`, avoiding real exponents in this explicit coarse bound. -/ +theorem propagation_le_slack_pow_five {j d : ℕ} (hjd : 2 ^ j ≤ d + 1) : + (28 : ℝ) ^ j ≤ ((d : ℝ) + 1) ^ 5 := by + calc (28 : ℝ) ^ j ≤ ((2 : ℝ) ^ 5) ^ j := + pow_le_pow_left₀ (by norm_num) (by norm_num) j + _ = ((2 : ℝ) ^ j) ^ 5 := by rw [← pow_mul, ← pow_mul, Nat.mul_comm] + _ ≤ ((d : ℝ) + 1) ^ 5 := pow_le_pow_left₀ (by positivity) (by exact_mod_cast hjd) 5 + +/-- The full state has polynomial perturbation growth under the explicit logarithmic +group-count condition. The condition is a premise about the schedule, not a claimed +construction of the paper's halving schedule. -/ +theorem iterate_stability_of_pow_le {δ : ℝ} (hδ : 0 ≤ δ) + (hz : |a.defaultValue - b.defaultValue| ≤ δ) + (hw : ∀ y ∈ s, ∀ ν, |a.row y ν - b.row y ν| ≤ δ) (j d : ℕ) + (hn : ∀ i < j, 0 < n i) (hK : ∀ i < j, 0 < K i) (hjd : 2 ^ j ≤ d + 1) : + |(iterate s n K ρ Δ a j).defaultValue - (iterate s n K ρ Δ b j).defaultValue| ≤ + ((d : ℝ) + 1) ^ 5 * δ ∧ + ∀ y ∈ s, ∀ ν, |(iterate s n K ρ Δ a j).row y ν - + (iterate s n K ρ Δ b j).row y ν| ≤ ((d : ℝ) + 1) ^ 5 * δ := by + have h := iterate_stability (ρ := ρ) (Δ := Δ) hδ hz hw j hn hK + have hscale := mul_le_mul_of_nonneg_right (propagation_le_slack_pow_five hjd) hδ + exact ⟨h.1.trans hscale, fun y hy ν => (h.2 y hy ν).trans hscale⟩ + +/-- The default never decreases, independently of the increments or the capacities. -/ +theorem iterate_defaultValue_monotone : Monotone fun j => (iterate s n K ρ Δ a j).defaultValue := + monotone_nat_of_le_succ fun _ => le_newDefault + +/-- The default is nonnegative when the initial default is. -/ +theorem iterate_defaultValue_nonneg (ha : 0 ≤ a.defaultValue) (j : ℕ) : + 0 ≤ (iterate s n K ρ Δ a j).defaultValue := + ha.trans (iterate_defaultValue_monotone (Nat.zero_le j)) + +/-- The accumulated row loss is bounded by six times the sum of the actual thresholds. +The increments cancel between the compressed and uncompressed calculations. -/ +theorem abs_iterate_sub_uncompressed_le (j : ℕ) (y : ι) (ν : Fin 2) : + |(iterate s n K ρ Δ a j).row y ν - uncompressedRow Δ a.row j y ν| ≤ + 6 * ∑ i ∈ range j, stepThreshold s n K ρ Δ a i := by + induction j with + | zero => simp + | succ j ih => + have hstep := abs_iterate_succ_sub_inputRow_le (s := s) (n := n) (K := K) (ρ := ρ) + (Δ := Δ) (a := a) j y ν + have hdiff : |inputRow s n K ρ Δ a j y ν - uncompressedRow Δ a.row (j + 1) y ν| = + |(iterate s n K ρ Δ a j).row y ν - uncompressedRow Δ a.row j y ν| := by + rw [uncompressedRow_succ] + simp only [inputRow, Pi.add_apply, add_sub_add_right_eq_sub] + calc _ ≤ |(iterate s n K ρ Δ a (j + 1)).row y ν - inputRow s n K ρ Δ a j y ν| + + |inputRow s n K ρ Δ a j y ν - uncompressedRow Δ a.row (j + 1) y ν| := + abs_sub_le _ _ _ + _ ≤ 6 * stepThreshold s n K ρ Δ a j + 6 * ∑ i ∈ range j, + stepThreshold s n K ρ Δ a i := by rw [hdiff]; exact add_le_add hstep ih + _ = _ := by rw [sum_range_succ]; ring + +/-- Before the first overflow, the accumulated loss is at most six times the sum of floors +[OpenAI2026LogSpace, Lemma 8.2, unweighted assertion]. The hypothesis says precisely that no +earlier group's actual threshold exceeds its prescribed floor. -/ +theorem abs_iterate_sub_uncompressed_le_of_no_overflow (j : ℕ) + (hno : ∀ i < j, stepThreshold s n K ρ Δ a i ≤ ρ i) (y : ι) (ν : Fin 2) : + |(iterate s n K ρ Δ a j).row y ν - uncompressedRow Δ a.row j y ν| ≤ + 6 * ∑ i ∈ range j, ρ i := by + exact (abs_iterate_sub_uncompressed_le j y ν).trans + (mul_le_mul_of_nonneg_left (sum_le_sum fun i hi => hno i (mem_range.mp hi)) (by norm_num)) + +/-- The default has an accumulated change bound of three times the threshold sum. This also +controls the dummy positions, which receive no increments. -/ +theorem iterate_defaultValue_sub_le_three_mul_sum (ha : 0 ≤ a.defaultValue) (j : ℕ) : + (iterate s n K ρ Δ a j).defaultValue - a.defaultValue ≤ + 3 * ∑ i ∈ range j, stepThreshold s n K ρ Δ a i := by + induction j with + | zero => simp + | succ j ih => + have hz := iterate_defaultValue_nonneg (s := s) (n := n) (K := K) (ρ := ρ) (Δ := Δ) ha j + have hnew : (iterate s n K ρ Δ a (j + 1)).defaultValue ≤ + 3 * stepThreshold s n K ρ Δ a j := newDefault_le_three_mul + rw [sum_range_succ] + linarith + +/-- Before overflow, the default (and hence every dummy entry) has accumulated change at most +three times the floor sum. -/ +theorem abs_iterate_defaultValue_sub_le_of_no_overflow (ha : 0 ≤ a.defaultValue) (j : ℕ) + (hno : ∀ i < j, stepThreshold s n K ρ Δ a i ≤ ρ i) : + |(iterate s n K ρ Δ a j).defaultValue - a.defaultValue| ≤ + 3 * ∑ i ∈ range j, ρ i := by + have hmono : a.defaultValue ≤ (iterate s n K ρ Δ a j).defaultValue := + iterate_defaultValue_monotone (Nat.zero_le j) + rw [abs_of_nonneg (sub_nonneg.mpr hmono)] + exact (iterate_defaultValue_sub_le_three_mul_sum ha j).trans + (mul_le_mul_of_nonneg_left (sum_le_sum fun i hi => hno i (mem_range.mp hi)) (by norm_num)) + +end Cslib.RowCompression diff --git a/ComplexityTests/RowCompressionIteration.lean b/ComplexityTests/RowCompressionIteration.lean new file mode 100644 index 0000000000..c53d2df481 --- /dev/null +++ b/ComplexityTests/RowCompressionIteration.lean @@ -0,0 +1,109 @@ +/- +Copyright (c) 2026 Samuel Schlesinger. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Samuel Schlesinger +-/ + +import Complexity.Foundations.Analysis.RowCompression.Iteration +import Mathlib.LinearAlgebra.Matrix.Notation +import Mathlib.Tactic.FinCases +import Mathlib.Tactic.IntervalCases +import Mathlib.Tactic.NormNum + +/-! +# Iterated compression with genuine increments and loss + +The first group adds ten and preserves it. The second subtracts ten, after which compression +introduces the new default four. Both thresholds equal their floors. Reducing the first capacity +from two to one produces an overflow, so the no-overflow hypothesis is not automatic. +-/ + +namespace ComplexityTests.RowCompressionIteration + +open Finset Cslib.RowCompression + +private def initial : State (Fin 1) := { defaultValue := 0, row := fun _ => ![0, 0] } + +private def increments (i : ℕ) : Fin 1 → Fin 2 → ℝ := + fun _ => if i = 0 then ![10, 0] else ![-10, 0] + +private def floors (i : ℕ) : ℝ := if i = 0 then 1 else 4 + +private noncomputable def run : ℕ → State (Fin 1) := + iterate univ (fun _ => 2) (fun _ => 1) floors increments initial + +private theorem first_state : (run 1).defaultValue = 3 ∧ (run 1).row 0 = ![10, 0] := by + constructor + · norm_num [run, iterate, advance, initial, increments, floors, newDefault, threshold, + kthLargest, entrySize, Fin.univ_succ, filter_insert, filter_singleton] + · funext ν + fin_cases ν <;> + norm_num [run, iterate, advance, initial, increments, floors, newDefault, threshold, + kthLargest, entrySize, update, updateEntry, radius, defaultEntry, Fin.univ_succ, + filter_insert, filter_singleton] + +private theorem second_state : (run 2).defaultValue = 4 ∧ (run 2).row 0 = ![4, 0] := by + have hrow : (run 1).row = fun _ => (![10, 0] : Fin 2 → ℝ) := by + funext y + fin_cases y + exact first_state.2 + change (advance univ 2 1 4 (increments 1) (run 1)).defaultValue = 4 ∧ + (advance univ 2 1 4 (increments 1) (run 1)).row 0 = ![4, 0] + simp only [advance, first_state.1, hrow] + constructor + · norm_num [increments, newDefault, threshold, kthLargest, entrySize, Fin.univ_succ, + filter_insert, filter_singleton] + · funext ν + fin_cases ν <;> + norm_num [increments, newDefault, threshold, kthLargest, entrySize, update, updateEntry, + radius, defaultEntry, Fin.univ_succ, filter_insert, filter_singleton] + +-- Compression has introduced a nonzero loss, although the raw increments cancel. +example : (run 2).row 0 0 - uncompressedRow increments initial.row 2 0 0 = 4 := by + rw [second_state.2] + norm_num [uncompressedRow, initial, increments, sum_range_succ] + +private theorem no_overflow (i : ℕ) (hi : i < 2) : + stepThreshold univ (fun _ => 2) (fun _ => 1) floors increments initial i ≤ floors i := by + interval_cases i + · norm_num [stepThreshold, inputRow, iterate, initial, increments, floors, threshold, + kthLargest, entrySize, Fin.univ_succ, filter_insert, filter_singleton] + · change threshold univ 2 4 (run 1).defaultValue ((run 1).row + increments 1) ≤ 4 + have hrow : (run 1).row = fun _ => (![10, 0] : Fin 2 → ℝ) := by + funext y + fin_cases y + exact first_state.2 + rw [first_state.1, hrow] + norm_num [increments, threshold, kthLargest, entrySize, Fin.univ_succ, filter_insert, + filter_singleton] + +-- The derived prefix-loss theorem applies to an actual nonzero-loss execution. +example (ν : Fin 2) : |(run 2).row 0 ν - uncompressedRow increments initial.row 2 0 ν| ≤ 30 := by + have h := abs_iterate_sub_uncompressed_le_of_no_overflow 2 no_overflow 0 ν + norm_num [floors, sum_range_succ] at h + exact h + +-- An undersized capacity causes overflow already at the first group. +example : ¬ stepThreshold univ (fun _ => 1) (fun _ => 1) floors increments initial 0 ≤ + floors 0 := by + norm_num [stepThreshold, inputRow, iterate, initial, increments, floors, threshold, + kthLargest, entrySize, Fin.univ_succ, filter_insert, filter_singleton] + +private noncomputable def perturbed : State (Fin 1) := + { defaultValue := 1 / 10, row := fun _ => ![1 / 10, 1 / 10] } + +-- The polynomial propagation estimate applies to genuinely different full initial states. +example (y : Fin 1) (ν : Fin 2) : + |(run 2).row y ν - + (iterate univ (fun _ => 2) (fun _ => 1) floors increments perturbed 2).row y ν| ≤ + 512 / 5 := by + have h := iterate_stability_of_pow_le (s := univ) (n := fun _ => 2) (K := fun _ => 1) + (ρ := floors) (Δ := increments) (a := initial) (b := perturbed) (δ := 1 / 10) + (by norm_num) (by norm_num [initial, perturbed]) + (fun y _ ν => by fin_cases ν <;> norm_num [initial, perturbed]) 2 3 + (by intros; norm_num) (by intros; norm_num) (by norm_num) + have hy := h.2 y (mem_univ y) ν + norm_num at hy + exact hy + +end ComplexityTests.RowCompressionIteration From 1edba8550d8f6051c2b4b73f4f92774f497954c2 Mon Sep 17 00:00:00 2001 From: Samuel Schlesinger Date: Fri, 30 Oct 2026 15:33:16 +0000 Subject: [PATCH 03/19] feat(logspace): construct explicit small floors for halving schedules Use decreasing power-of-two slacks and the explicit floors eta * (1/1024)^slack. Derive consecutive floor separation, both finite-sum bounds from source equation (8.8), and the local 8*rho <= eta margin. Bound propagation for the actual remaining group count, distinguishing updates after the current group from those including it. The source uses unscaled inverse powers of two; this mathematical witness explicitly scales by eta and does not choose an exponent for the full integrated estimator. Validation: direct Lean 4.36.0-rc2 checks of Floors.lean and RowCompressionFloors.lean with project options passed without diagnostics, using private outputs and parent dependencies read-only. Tests compute nonzero floors, check halving and empty schedules, and apply the sum theorem to a concrete no-overflow compression execution. Focused hygiene including --check-simp and git diff --check passed. Base is iteration milestone 7d08e44bbdb626b74adaa9c4d63e07faa28ce525; aggregate and full project validation remain integration tasks. AI assistance: ChatGPT implemented and checked the proofs as worker codex-compression-iteration-20261030. Independent agent source/API review: codex-source-release-20261030 approved module/tests at bd14fc247724f63e650ced31e7b0e6c4d30fcee1. Publication adds only generated import registration. Integrated strict module/test build, focused hygiene and whitespace checks pass. Full gates run in PR CI. --- Complexity.lean | 1 + .../Analysis/RowCompression/Floors.lean | 183 ++++++++++++++++++ ComplexityTests/RowCompressionFloors.lean | 87 +++++++++ 3 files changed, 271 insertions(+) create mode 100644 Complexity/Foundations/Analysis/RowCompression/Floors.lean create mode 100644 ComplexityTests/RowCompressionFloors.lean diff --git a/Complexity.lean b/Complexity.lean index 4902f4c799..0a2080c1d4 100644 --- a/Complexity.lean +++ b/Complexity.lean @@ -2352,6 +2352,7 @@ public import Complexity.Foundations.Analysis.LpNormMeasure public import Complexity.Foundations.Analysis.MarkovBrothersInequality public import Complexity.Foundations.Analysis.RootError public import Complexity.Foundations.Analysis.RowCompression +public import Complexity.Foundations.Analysis.RowCompression.Floors public import Complexity.Foundations.Analysis.RowCompression.Iteration public import Complexity.Foundations.Analysis.SpecialFunctions.Arccos public import Complexity.Foundations.Analysis.SpecialFunctions.SmoothSwitch diff --git a/Complexity/Foundations/Analysis/RowCompression/Floors.lean b/Complexity/Foundations/Analysis/RowCompression/Floors.lean new file mode 100644 index 0000000000..fdb665828b --- /dev/null +++ b/Complexity/Foundations/Analysis/RowCompression/Floors.lean @@ -0,0 +1,183 @@ +/- +Copyright (c) 2026 Samuel Schlesinger. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Samuel Schlesinger +-/ + +module +-- upstream: candidate + +public import Complexity.Foundations.Analysis.RowCompression.Iteration +import Mathlib.Algebra.Order.GroupWithZero.Basic +import Mathlib.Tactic.Linarith +import Mathlib.Tactic.Positivity +import Mathlib.Tactic.Ring + +/-! +# Explicit small floors for a halving compression schedule + +For `m` groups, indexed by `i < m`, set `d_i = 2 ^ (m - (i + 1))`. These slacks halve down +to one, as in [OpenAI2026LogSpace, Section 8.1]. We construct the floors +`ρ_i = η * (1 / 1024) ^ d_i` for any fixed `η > 0`. + +The paper uses the unscaled floors `2 ^ (-c₁ * d_i)` and chooses `c₁` large depending on its +fixed sensitivity margin `η`. Our explicit witness instead uses exponent ten and scales by `η`. +It proves the two numerical inequalities in (8.8), and `8 * ρ_i ≤ η`, for every positive `η`. +It does not select `c₁` against the other exponents in the integrated compression argument. + +Consecutive floors grow by at least a factor of 1024. A finite induction therefore bounds the +sum before group `i` by `ρ_i / 1023`, and the sum over all groups by `η / 1023`. Multiplication +by six gives the two `/100` bounds, with no assumed small-sum hypothesis. + +There are `m - (i + 1)` updates after group `i`, whose power of two equals `d_i`. Counting the +current group too introduces one extra factor of 28 in the perturbation bound; this is absorbed +by the unspecified outer constant in the source's (8.7). + +## Main definitions + +* `Cslib.RowCompression.dyadicSlack`: the decreasing power-of-two slacks. +* `Cslib.RowCompression.dyadicFloor`: the explicit margin-scaled floors. + +## Main results + +* `Cslib.RowCompression.six_sum_range_dyadicFloor_le`: prior floors are small relative to the + current floor. +* `Cslib.RowCompression.six_sum_range_dyadicFloor_le_scale`: all floors are small relative to + the sensitivity margin. +* `Cslib.RowCompression.eight_mul_dyadicFloor_le`: the local margin condition. +* `Cslib.RowCompression.propagation_le_dyadicSlack`: polynomial perturbation growth for the + actual number of remaining groups. + +## References + +* [OpenAI, *Exact Derandomization of Logarithmic Space: L = RL = BPL*][OpenAI2026LogSpace], + Sections 8.1--8.3, (8.7)--(8.8) (23 September 2026, revision `7ef5c0cc`, not peer reviewed). +-/ + +public section + +namespace Cslib.RowCompression + +open Finset + +/-- The decreasing power-of-two slacks of a schedule with `m` groups. Indices `i ≥ m` are +defined too, with value one, but are not additional groups in the schedule. -/ +@[expose] def dyadicSlack (m i : ℕ) : ℕ := 2 ^ (m - (i + 1)) + +/-- An explicit floor schedule at sensitivity scale `η`. The finite schedule consists of +indices `i < m`; the total function is convenient as an argument to `iterate`. -/ +@[expose] noncomputable def dyadicFloor (η : ℝ) (m i : ℕ) : ℝ := + η * (1 / 1024) ^ dyadicSlack m i + +theorem dyadicSlack_pos (m i : ℕ) : 0 < dyadicSlack m i := by + unfold dyadicSlack + positivity + +@[simp] +theorem dyadicSlack_last (m : ℕ) : dyadicSlack (m + 1) m = 1 := by + simp [dyadicSlack] + +/-- Each slack is twice the next one while both indices are actual groups. -/ +theorem dyadicSlack_succ {m i : ℕ} (hi : i + 1 < m) : + dyadicSlack m i = 2 * dyadicSlack m (i + 1) := by + have h : m - (i + 1) = m - (i + 1 + 1) + 1 := by omega + unfold dyadicSlack + rw [h, pow_succ, Nat.mul_comm] + +theorem dyadicFloor_nonneg {η : ℝ} (hη : 0 ≤ η) (m i : ℕ) : + 0 ≤ dyadicFloor η m i := by + unfold dyadicFloor + positivity + +theorem dyadicFloor_pos {η : ℝ} (hη : 0 < η) (m i : ℕ) : + 0 < dyadicFloor η m i := by + unfold dyadicFloor + positivity + +@[simp] +theorem dyadicFloor_last (η : ℝ) (m : ℕ) : dyadicFloor η (m + 1) m = η / 1024 := by + simp [dyadicFloor, div_eq_mul_inv] + +private theorem pow_dyadicSlack_le (m i : ℕ) : + (1 / 1024 : ℝ) ^ dyadicSlack m i ≤ 1 / 1024 := by + simpa only [pow_one] using pow_le_pow_of_le_one (by norm_num : (0 : ℝ) ≤ 1 / 1024) + (by norm_num : (1 / 1024 : ℝ) ≤ 1) (dyadicSlack_pos m i) + +/-- Every floor is at most `η / 1024`, including the final floor where equality holds. -/ +theorem dyadicFloor_le_scale_div {η : ℝ} (hη : 0 ≤ η) (m i : ℕ) : + dyadicFloor η m i ≤ η / 1024 := by + simpa only [dyadicFloor, mul_one_div] using + mul_le_mul_of_nonneg_left (pow_dyadicSlack_le m i) hη + +/-- Consecutive floors are separated by a factor of at least 1024. -/ +theorem dyadicFloor_mul_le_succ {η : ℝ} (hη : 0 ≤ η) {m i : ℕ} (hi : i + 1 < m) : + 1024 * dyadicFloor η m i ≤ dyadicFloor η m (i + 1) := by + have hbase := pow_dyadicSlack_le m (i + 1) + have hnonneg := dyadicFloor_nonneg hη m (i + 1) + have hmul := mul_le_mul_of_nonneg_left hbase hnonneg + have heq : dyadicFloor η m i = + dyadicFloor η m (i + 1) * (1 / 1024) ^ dyadicSlack m (i + 1) := by + unfold dyadicFloor + rw [dyadicSlack_succ hi, two_mul, pow_add, mul_assoc] + rw [← heq] at hmul + linarith + +/-- The sum of earlier floors is bounded by the geometric factor `1 / 1023` times the +current floor. This is derived from the concrete schedule, without a small-sum premise. -/ +theorem sum_range_dyadicFloor_le {η : ℝ} (hη : 0 ≤ η) {m j : ℕ} (hj : j < m) : + ∑ i ∈ range j, dyadicFloor η m i ≤ dyadicFloor η m j / 1023 := by + induction j with + | zero => simpa using div_nonneg (dyadicFloor_nonneg hη m 0) (by norm_num : (0 : ℝ) ≤ 1023) + | succ j ih => + have hprev := ih (Nat.lt_of_succ_lt hj) + have hstep := dyadicFloor_mul_le_succ hη hj + rw [sum_range_succ] + linarith + +/-- The first small-floor estimate of [OpenAI2026LogSpace, (8.8)], for the explicit scaled +schedule: all earlier compression changes total at most one hundredth of the current floor. -/ +theorem six_sum_range_dyadicFloor_le {η : ℝ} (hη : 0 ≤ η) {m j : ℕ} (hj : j < m) : + 6 * ∑ i ∈ range j, dyadicFloor η m i ≤ dyadicFloor η m j / 100 := by + have hsum := sum_range_dyadicFloor_le hη hj + have hfloor := dyadicFloor_nonneg hη m j + linarith + +/-- The finite sum of all floors is at most `η / 1023`, uniformly in the number of groups. -/ +theorem sum_range_dyadicFloor_le_scale {η : ℝ} (hη : 0 ≤ η) (m : ℕ) : + ∑ i ∈ range m, dyadicFloor η m i ≤ η / 1023 := by + cases m with + | zero => simpa using div_nonneg hη (by norm_num : (0 : ℝ) ≤ 1023) + | succ m => + have hsum := sum_range_dyadicFloor_le hη (Nat.lt_succ_self m) + rw [sum_range_succ, dyadicFloor_last] + rw [dyadicFloor_last] at hsum + linarith + +/-- The second small-floor estimate of [OpenAI2026LogSpace, (8.8)], uniformly in the number +of groups. -/ +theorem six_sum_range_dyadicFloor_le_scale {η : ℝ} (hη : 0 ≤ η) (m : ℕ) : + 6 * ∑ i ∈ range m, dyadicFloor η m i ≤ η / 100 := by + have hsum := sum_range_dyadicFloor_le_scale hη m + linarith + +/-- Every floor satisfies the local margin condition used in the weighted preloss estimate. -/ +theorem eight_mul_dyadicFloor_le {η : ℝ} (hη : 0 ≤ η) (m i : ℕ) : + 8 * dyadicFloor η m i ≤ η := by + have hfloor := dyadicFloor_le_scale_div hη m i + linarith + +/-- The exact power-of-two count of updates strictly after the current group is its slack. -/ +theorem two_pow_remaining_eq_dyadicSlack (m i : ℕ) : + 2 ^ (m - (i + 1)) = dyadicSlack m i := rfl + +/-- Including the current group, the propagation cost is at most an extra factor 28 times a +fifth-degree polynomial in its slack [OpenAI2026LogSpace, (8.7)]. -/ +theorem propagation_le_dyadicSlack {m i : ℕ} (hi : i < m) : + (28 : ℝ) ^ (m - i) ≤ 28 * ((dyadicSlack m i : ℝ) + 1) ^ 5 := by + have hcount : m - i = m - (i + 1) + 1 := by omega + have hpow : (28 : ℝ) ^ (m - (i + 1)) ≤ ((dyadicSlack m i : ℝ) + 1) ^ 5 := + propagation_le_slack_pow_five (Nat.le_succ (dyadicSlack m i)) + rw [hcount, pow_succ] + nlinarith + +end Cslib.RowCompression diff --git a/ComplexityTests/RowCompressionFloors.lean b/ComplexityTests/RowCompressionFloors.lean new file mode 100644 index 0000000000..44238a5eeb --- /dev/null +++ b/ComplexityTests/RowCompressionFloors.lean @@ -0,0 +1,87 @@ +/- +Copyright (c) 2026 Samuel Schlesinger. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Samuel Schlesinger +-/ + +import Complexity.Foundations.Analysis.RowCompression.Floors +import Mathlib.LinearAlgebra.Matrix.Notation +import Mathlib.Tactic.FinCases +import Mathlib.Tactic.IntervalCases +import Mathlib.Tactic.NormNum + +/-! +# Concrete small-floor schedules + +Check the explicit halving slacks and nonzero floors, including the empty schedule. A two-group +compression execution with zero raw increments acquires a positive default; its no-overflow +property is checked directly, then the floor sum controls its actual compression loss. +-/ + +namespace ComplexityTests.RowCompressionFloors + +open Finset Cslib.RowCompression + +example : dyadicSlack 3 0 = 4 ∧ dyadicSlack 3 1 = 2 ∧ dyadicSlack 3 2 = 1 := by + norm_num [dyadicSlack] + +example : dyadicFloor 1 3 0 = 1 / 1099511627776 ∧ + dyadicFloor 1 3 1 = 1 / 1048576 ∧ dyadicFloor 1 3 2 = 1 / 1024 := by + norm_num [dyadicFloor, dyadicSlack] + +-- Actual nonzero previous floors satisfy the hundredth-of-current-floor estimate. +example : 6 * (dyadicFloor 1 3 0 + dyadicFloor 1 3 1) ≤ dyadicFloor 1 3 2 / 100 := by + norm_num [dyadicFloor, dyadicSlack] + +-- The total-sum theorem includes a schedule with no groups. +example : (∑ i ∈ range 0, dyadicFloor (2 / 3) 0 i) = 0 := by simp + +-- The scale need not be one, and the number of groups is arbitrary. +example (m : ℕ) : 6 * ∑ i ∈ range m, dyadicFloor (2 / 3) m i ≤ 1 / 150 := by + have h := six_sum_range_dyadicFloor_le_scale (η := 2 / 3) (by norm_num) m + norm_num at h + exact h + +private def initial : State (Fin 1) := { defaultValue := 0, row := fun _ => ![0, 0] } + +private noncomputable def run : ℕ → State (Fin 1) := + iterate univ (fun _ => 2) (fun _ => 1) (dyadicFloor 1 2) (fun _ => 0) initial + +private theorem first_state : (run 1).defaultValue = 1 / 1048576 ∧ + (run 1).row = fun _ => defaultEntry (1 / 1048576) := by + constructor + · norm_num [run, iterate, advance, initial, dyadicFloor, dyadicSlack, newDefault, threshold, + kthLargest, entrySize, Fin.univ_succ, filter_insert, filter_singleton] + · funext y ν + fin_cases y + fin_cases ν <;> + norm_num [run, iterate, advance, initial, dyadicFloor, dyadicSlack, newDefault, threshold, + kthLargest, entrySize, update, updateEntry, radius, defaultEntry, Fin.univ_succ, + filter_insert, filter_singleton] + +private theorem no_overflow (i : ℕ) (hi : i < 2) : + stepThreshold univ (fun _ => 2) (fun _ => 1) (dyadicFloor 1 2) (fun _ => 0) initial i ≤ + dyadicFloor 1 2 i := by + interval_cases i + · norm_num [stepThreshold, inputRow, iterate, initial, dyadicFloor, dyadicSlack, threshold, + kthLargest, entrySize, Fin.univ_succ, filter_insert, filter_singleton] + · change threshold univ 2 (dyadicFloor 1 2 1) (run 1).defaultValue ((run 1).row + 0) ≤ + dyadicFloor 1 2 1 + rw [first_state.1, first_state.2, add_zero] + norm_num [dyadicFloor, dyadicSlack, threshold, kthLargest, entrySize, defaultEntry, + Fin.univ_succ, filter_insert, filter_singleton] + +-- The new numerical schedule closes the small-total-loss premise for a real execution. +example (y : Fin 1) (ν : Fin 2) : |(run 2).row y ν| ≤ 1 / 100 := by + have h := abs_iterate_sub_uncompressed_le_of_no_overflow 2 no_overflow y ν + have hsum := six_sum_range_dyadicFloor_le_scale (η := 1) (by norm_num) 2 + have h' := h.trans hsum + fin_cases ν <;> simpa [uncompressedRow, initial, run] using h' + +-- There are three updates left including group one, but only two strictly after it. +example : dyadicSlack 4 1 = 4 ∧ (28 : ℝ) ^ (4 - 1) ≤ 28 * (4 + 1) ^ 5 := by + constructor + · norm_num [dyadicSlack] + · simpa [dyadicSlack] using propagation_le_dyadicSlack (m := 4) (i := 1) (by norm_num) + +end ComplexityTests.RowCompressionFloors From fe32886a35bef3cbaa59e3e3dc1516326b8d43da Mon Sep 17 00:00:00 2001 From: Samuel Schlesinger Date: Fri, 30 Oct 2026 15:40:58 +0000 Subject: [PATCH 04/19] feat: add rational polynomial switches with Lipschitz fourth roots Supply a computable rational degree-seven transition and its rescaling, with real endpoint, monotonicity, and value/complement fourth-root Lipschitz laws. Exact rational cast lemmas connect the arithmetic definitions to the real analysis. Concrete tests cover interior values, affine rescaling, clamping, equal endpoints, and root perturbations across both transition boundaries. This advances issue #1721's fourth-moment route. The pinned primary source OpenAI2026LogSpace, atoms.tex Section 5.1 at revision 7ef5c0cc, uses the same normalized-integral construction with s = 8. This implementation specializes it to s = 4 and does not claim eighth-root regularity, complete hierarchy admissibility, or machine resource bounds. No OpenAI Lean was consulted. Validation on base 2d1638ce with the two added files: both modules compile under the repository's Lean options with warnings as errors using isolated temporary outputs and read-only existing dependencies; focused check_hygiene.py --check-simp and git diff --cached --check pass. The final documentation-only wording change was inspected after those builds. Full repository integration gates and independent review remain for coordinator integration; no aggregate file has been edited. Authored by worker codex-logspace-polynomial-cutoffs-20261030 with ChatGPT. Independent agent source/API review: codex-compression-iteration-20261030 approved source a6967d13aafee47ae16b61ac2b12f533426f9971 and freshly compiled both files. Publication adds only the generated aggregate import. Integrated strict module/test builds, hygiene and whitespace checks pass. Full gates run in PR CI. --- Complexity.lean | 4 + .../SpecialFunctions/PolynomialSwitch.lean | 299 ++++++++++++++++++ ComplexityTests/PolynomialSwitch.lean | 77 +++++ 3 files changed, 380 insertions(+) create mode 100644 Complexity/Foundations/Analysis/SpecialFunctions/PolynomialSwitch.lean create mode 100644 ComplexityTests/PolynomialSwitch.lean diff --git a/Complexity.lean b/Complexity.lean index 9a3bc3cdea..257d53cdd7 100644 --- a/Complexity.lean +++ b/Complexity.lean @@ -2352,7 +2352,11 @@ public import Complexity.Foundations.Analysis.LpNorm public import Complexity.Foundations.Analysis.LpNormMeasure public import Complexity.Foundations.Analysis.MarkovBrothersInequality public import Complexity.Foundations.Analysis.RootError +public import Complexity.Foundations.Analysis.RowCompression +public import Complexity.Foundations.Analysis.RowCompression.Floors +public import Complexity.Foundations.Analysis.RowCompression.Iteration public import Complexity.Foundations.Analysis.SpecialFunctions.Arccos +public import Complexity.Foundations.Analysis.SpecialFunctions.PolynomialSwitch public import Complexity.Foundations.Analysis.SpecialFunctions.SmoothSwitch public import Complexity.Foundations.BooleanAnalysis.Bernoulli public import Complexity.Foundations.BooleanAnalysis.Bonami diff --git a/Complexity/Foundations/Analysis/SpecialFunctions/PolynomialSwitch.lean b/Complexity/Foundations/Analysis/SpecialFunctions/PolynomialSwitch.lean new file mode 100644 index 0000000000..1ee62aee99 --- /dev/null +++ b/Complexity/Foundations/Analysis/SpecialFunctions/PolynomialSwitch.lean @@ -0,0 +1,299 @@ +/- +Copyright (c) 2026 Samuel Schlesinger. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Samuel Schlesinger +-/ + +module +-- upstream: candidate + +public import Complexity.Init +public import Mathlib.Basic.Real.Basic +public import Mathlib.Analysis.Calculus.Deriv.Pow +public import Mathlib.Analysis.SpecialFunctions.Pow.Real +public import Mathlib.Topology.MetricSpace.Lipschitz +import Mathlib.Analysis.Calculus.ContDiff.RCLike +import Mathlib.Analysis.Calculus.Deriv.MeanValue +import Mathlib.Analysis.Normed.MulAction +import Mathlib.Analysis.SpecialFunctions.Pow.Deriv +import Mathlib.Data.Rat.Cast.Order +import Mathlib.Tactic.FunProp +import Mathlib.Tactic.Linarith +import Mathlib.Tactic.Positivity +import Mathlib.Tactic.Ring + +/-! +# Polynomial switches with Lipschitz fourth roots + +The fourth-moment workstream of complexitylib issue #1721 needs a monotone switch whose fourth +root and complementary fourth root are Lipschitz. The switch of [OpenAI2026LogSpace, Section 5.1] +is a rescaled normalized integral of `t^(s-1) (1-t)^(s-1)` on `[0,1]`. +For the fourth-moment route (`s = 4`), its polynomial +is `35 t^4 - 84 t^5 + 70 t^6 - 20 t^7`. + +We give that polynomial as the equivalent factored expression +`t^4 * (1 + 4(1-t) + 10(1-t)^2 + 20(1-t)^3)` and clamp its input to `[0,1]`. +The polynomial, clamped transition and rescaled switch use only field arithmetic and min/max; +their definitions also specialize to computable functions on `ℚ`. The cast lemmas identify those +exact rational evaluations with the real functions used by the analysis. They assert no machine +resource bound or rational approximation to the fourth root. + +The factor after `t^4` is at least one on `[0,1]`. Thus the fourth root is `t` times the fourth +root of a positive polynomial, which is continuously differentiable on that interval and hence +Lipschitz there. Composing with clamping gives a global Lipschitz bound. The complement follows +by reflection. These primitives do not yet provide the complete admissible hierarchy parameters, +their threshold ladder, or the regularity of the unbounded correction ramp. + +## Main definitions + +* `Cslib.transitionPolynomial4`: the polynomial whose value at zero and complement at one + vanish to fourth order. +* `Cslib.polynomialTransition4`: its clamped transition from zero to one. +* `Cslib.polynomialSwitch4`: its rescaling to an arbitrary nondegenerate interval. + +## Main results + +* `Cslib.polynomialSwitch4_nonneg`, `Cslib.polynomialSwitch4_le_one`: range bounds. +* `Cslib.polynomialSwitch4_eq_zero_iff`, `Cslib.polynomialSwitch4_eq_one_iff`: exact endpoints. +* `Cslib.monotone_polynomialSwitch4`: monotonicity. +* `Cslib.exists_lipschitzWith_polynomialSwitch4_root`, + `Cslib.exists_lipschitzWith_one_sub_polynomialSwitch4_root`: Lipschitz fourth roots. +* `Cslib.polynomialSwitch4_ratCast`: exact compatibility with rational evaluation. + +## References + +* [OpenAI, *Exact Derandomization of Logarithmic Space: L = RL = BPL*][OpenAI2026LogSpace], + Section 5.1 (23 September 2026, revision `7ef5c0cc`, not peer reviewed). The paper uses `s = 8`; + this module gives the same normalized-integral construction for the project's `s = 4` route. +-/ + +public section + +namespace Cslib + +/-- The normalized integral polynomial for the fourth-moment switch, in a form displaying its +fourth-order zero and a positive remaining factor on `[0,1]`. -/ +@[expose] def transitionPolynomial4 {R : Type*} [CommRing R] (t : R) : R := + t ^ 4 * (1 + 4 * (1 - t) + 10 * (1 - t) ^ 2 + 20 * (1 - t) ^ 3) + +/-- The degree-seven transition polynomial, clamped to the unit interval. Its generic definition +can be evaluated exactly on rational inputs. -/ +@[expose] def polynomialTransition4 {R : Type*} [CommRing R] [LinearOrder R] (t : R) : R := + transitionPolynomial4 (max 0 (min 1 t)) + +/-- Rescale the fourth-moment polynomial transition from `[0,1]` to `[α,β]`. The switch laws +assume `α < β`; the arithmetic expression itself is defined for all endpoints. -/ +@[expose] def polynomialSwitch4 {R : Type*} [Field R] [LinearOrder R] (α β t : R) : R := + polynomialTransition4 ((t - α) / (β - α)) + +section Polynomial + +variable {R : Type*} [CommRing R] + +theorem transitionPolynomial4_expanded (t : R) : + transitionPolynomial4 t = 35 * t ^ 4 - 84 * t ^ 5 + 70 * t ^ 6 - 20 * t ^ 7 := by + unfold transitionPolynomial4 + ring + +@[simp] theorem transitionPolynomial4_zero : transitionPolynomial4 (0 : R) = 0 := by + simp [transitionPolynomial4] + +@[simp] theorem transitionPolynomial4_one : transitionPolynomial4 (1 : R) = 1 := by + simp [transitionPolynomial4] + +/-- Reflection interchanges the transition polynomial and its complement. -/ +theorem one_sub_transitionPolynomial4 (t : R) : + 1 - transitionPolynomial4 t = transitionPolynomial4 (1 - t) := by + unfold transitionPolynomial4 + ring + +end Polynomial + +private theorem factor_pos {t : ℝ} (ht : t ≤ 1) : + 0 < 1 + 4 * (1 - t) + 10 * (1 - t) ^ 2 + 20 * (1 - t) ^ 3 := by + have h : 0 ≤ 1 - t := sub_nonneg.mpr ht + positivity + +/-- The derivative identifies the normalization of the integral `t^3 (1-t)^3`. -/ +theorem hasDerivAt_transitionPolynomial4 (t : ℝ) : + HasDerivAt transitionPolynomial4 (140 * t ^ 3 * (1 - t) ^ 3) t := by + convert (((hasDerivAt_pow 4 t).const_mul 35).sub + ((hasDerivAt_pow 5 t).const_mul 84) |>.add ((hasDerivAt_pow 6 t).const_mul 70)).sub + ((hasDerivAt_pow 7 t).const_mul 20) using 1 + · funext x + exact transitionPolynomial4_expanded x + · ring + +theorem monotoneOn_transitionPolynomial4 : + MonotoneOn (transitionPolynomial4 : ℝ → ℝ) (Set.Icc 0 1) := by + refine monotoneOn_of_deriv_nonneg (convex_Icc 0 1) + (fun x _ => (hasDerivAt_transitionPolynomial4 x).continuousAt.continuousWithinAt) + (fun x _ => (hasDerivAt_transitionPolynomial4 x).differentiableAt.differentiableWithinAt) + fun x hx => ?_ + rw [(hasDerivAt_transitionPolynomial4 x).deriv] + have hx' : x ∈ Set.Icc (0 : ℝ) 1 := interior_subset hx + have h0 : 0 ≤ x := hx'.1 + have h1 : 0 ≤ 1 - x := sub_nonneg.mpr hx'.2 + positivity + +private theorem clamp_mem (t : ℝ) : max 0 (min 1 t) ∈ Set.Icc (0 : ℝ) 1 := + ⟨le_max_left _ _, max_le zero_le_one (min_le_left _ _)⟩ + +theorem polynomialTransition4_nonneg (t : ℝ) : 0 ≤ polynomialTransition4 t := by + have h := monotoneOn_transitionPolynomial4 (Set.left_mem_Icc.mpr zero_le_one) (clamp_mem t) + (clamp_mem t).1 + simpa only [polynomialTransition4, transitionPolynomial4_zero] using h + +theorem polynomialTransition4_le_one (t : ℝ) : polynomialTransition4 t ≤ 1 := by + have h := monotoneOn_transitionPolynomial4 (clamp_mem t) (Set.right_mem_Icc.mpr zero_le_one) + (clamp_mem t).2 + simpa only [polynomialTransition4, transitionPolynomial4_one] using h + +theorem polynomialTransition4_of_nonpos {t : ℝ} (ht : t ≤ 0) : polynomialTransition4 t = 0 := by + rw [polynomialTransition4, min_eq_right (ht.trans zero_le_one), max_eq_left ht] + exact transitionPolynomial4_zero + +theorem polynomialTransition4_of_one_le {t : ℝ} (ht : 1 ≤ t) : polynomialTransition4 t = 1 := by + rw [polynomialTransition4, min_eq_left ht, max_eq_right zero_le_one] + exact transitionPolynomial4_one + +theorem polynomialTransition4_of_mem {t : ℝ} (ht : t ∈ Set.Icc 0 1) : + polynomialTransition4 t = transitionPolynomial4 t := by + rw [polynomialTransition4, min_eq_right ht.2, max_eq_right ht.1] + +theorem monotone_polynomialTransition4 : Monotone (polynomialTransition4 : ℝ → ℝ) := + fun x y hxy => monotoneOn_transitionPolynomial4 (clamp_mem x) (clamp_mem y) + (max_le_max le_rfl (min_le_min le_rfl hxy)) + +/-- Reflection interchanges the clamped transition and its complement. -/ +theorem one_sub_polynomialTransition4 (t : ℝ) : + 1 - polynomialTransition4 t = polynomialTransition4 (1 - t) := by + by_cases ht0 : t ≤ 0 + · rw [polynomialTransition4_of_nonpos ht0, + polynomialTransition4_of_one_le (by linarith : 1 ≤ 1 - t), sub_zero] + by_cases ht1 : 1 ≤ t + · rw [polynomialTransition4_of_one_le ht1, + polynomialTransition4_of_nonpos (by linarith : 1 - t ≤ 0), sub_self] + have ht : t ∈ Set.Icc (0 : ℝ) 1 := ⟨(not_le.mp ht0).le, (not_le.mp ht1).le⟩ + have ht' : 1 - t ∈ Set.Icc (0 : ℝ) 1 := ⟨by linarith [ht.2], by linarith [ht.1]⟩ + rw [polynomialTransition4_of_mem ht, polynomialTransition4_of_mem ht', + one_sub_transitionPolynomial4] + +theorem polynomialTransition4_eq_zero_iff {t : ℝ} : polynomialTransition4 t = 0 ↔ t ≤ 0 := by + refine ⟨fun h => ?_, polynomialTransition4_of_nonpos⟩ + by_contra ht + have hp : 0 < max 0 (min 1 t) := + (lt_min zero_lt_one (lt_of_not_ge ht)).trans_le (le_max_right _ _) + have hf := factor_pos (clamp_mem t).2 + have : 0 < polynomialTransition4 t := by + unfold polynomialTransition4 transitionPolynomial4 + positivity + exact this.ne' h + +theorem polynomialTransition4_eq_one_iff {t : ℝ} : polynomialTransition4 t = 1 ↔ 1 ≤ t := by + refine ⟨fun h => ?_, polynomialTransition4_of_one_le⟩ + have hz : polynomialTransition4 (1 - t) = 0 := by + rw [← one_sub_polynomialTransition4, h, sub_self] + have := polynomialTransition4_eq_zero_iff.mp hz + linarith + +/-! ## Fourth-root regularity -/ + +private theorem root_eq {t : ℝ} (ht : t ∈ Set.Icc 0 1) : + transitionPolynomial4 t ^ (4⁻¹ : ℝ) = + t * (1 + 4 * (1 - t) + 10 * (1 - t) ^ 2 + 20 * (1 - t) ^ 3) ^ (4⁻¹ : ℝ) := by + rw [transitionPolynomial4, Real.mul_rpow (pow_nonneg ht.1 _) (factor_pos ht.2).le] + congr 1 + convert Real.pow_rpow_inv_natCast ht.1 (by norm_num : (4 : ℕ) ≠ 0) using 1 + +/-- The fourth root is Lipschitz globally; the transition has fourth-order vanishing at zero. -/ +theorem exists_lipschitzWith_polynomialTransition4_root : + ∃ K, LipschitzWith K fun t : ℝ => polynomialTransition4 t ^ (4⁻¹ : ℝ) := by + have hf : ContDiffOn ℝ 1 (fun t : ℝ => + t * (1 + 4 * (1 - t) + 10 * (1 - t) ^ 2 + 20 * (1 - t) ^ 3) ^ (4⁻¹ : ℝ)) + (Set.Icc 0 1) := by + apply contDiffOn_id.mul + apply ContDiffOn.rpow_const_of_ne (by fun_prop) + exact fun t ht => (factor_pos ht.2).ne' + obtain ⟨K, hK⟩ := hf.exists_lipschitzOnWith one_ne_zero (convex_Icc 0 1) isCompact_Icc + refine ⟨K, LipschitzWith.of_dist_le_mul fun x y => ?_⟩ + have hproj := (LipschitzWith.projIcc (zero_le_one' ℝ)).dist_le_mul x y + have hb := hK.dist_le_mul _ (clamp_mem x) _ (clamp_mem y) + rw [← root_eq (clamp_mem x), ← root_eq (clamp_mem y)] at hb + refine hb.trans ?_ + simp only [Subtype.dist_eq, NNReal.coe_one, one_mul, Set.coe_projIcc] at hproj + exact mul_le_mul_of_nonneg_left hproj K.2 + +/-- The fourth root of the complement is Lipschitz, by reflection at `1/2`. -/ +theorem exists_lipschitzWith_one_sub_polynomialTransition4_root : + ∃ K, LipschitzWith K fun t : ℝ => (1 - polynomialTransition4 t) ^ (4⁻¹ : ℝ) := by + obtain ⟨K, hK⟩ := exists_lipschitzWith_polynomialTransition4_root + refine ⟨K, LipschitzWith.of_dist_le_mul fun x y => ?_⟩ + simp only [one_sub_polynomialTransition4] + simpa only [dist_sub_left] using hK.dist_le_mul (1 - x) (1 - y) + +/-! ## Rescaling and exact rational values -/ + +variable {α β t : ℝ} + +theorem polynomialSwitch4_nonneg (α β t : ℝ) : 0 ≤ polynomialSwitch4 α β t := + polynomialTransition4_nonneg _ + +theorem polynomialSwitch4_le_one (α β t : ℝ) : polynomialSwitch4 α β t ≤ 1 := + polynomialTransition4_le_one _ + +theorem polynomialSwitch4_eq_zero_iff (hαβ : α < β) : + polynomialSwitch4 α β t = 0 ↔ t ≤ α := by + rw [polynomialSwitch4, polynomialTransition4_eq_zero_iff, div_le_iff₀ (sub_pos.mpr hαβ), + zero_mul, sub_nonpos] + +theorem polynomialSwitch4_eq_one_iff (hαβ : α < β) : + polynomialSwitch4 α β t = 1 ↔ β ≤ t := by + rw [polynomialSwitch4, polynomialTransition4_eq_one_iff, one_le_div (sub_pos.mpr hαβ), + sub_le_sub_iff_right] + +theorem polynomialSwitch4_of_le (hαβ : α < β) (ht : t ≤ α) : polynomialSwitch4 α β t = 0 := + (polynomialSwitch4_eq_zero_iff hαβ).mpr ht + +theorem polynomialSwitch4_of_ge (hαβ : α < β) (ht : β ≤ t) : polynomialSwitch4 α β t = 1 := + (polynomialSwitch4_eq_one_iff hαβ).mpr ht + +theorem monotone_polynomialSwitch4 (hαβ : α ≤ β) : Monotone (polynomialSwitch4 α β) := + fun _ _ h => monotone_polynomialTransition4 + (div_le_div_of_nonneg_right (sub_le_sub_right h α) (sub_nonneg.mpr hαβ)) + +/-- Rescaled switches have Lipschitz fourth roots, even for reversed or equal endpoints. -/ +theorem exists_lipschitzWith_polynomialSwitch4_root (α β : ℝ) : + ∃ K, LipschitzWith K fun t => polynomialSwitch4 α β t ^ (4⁻¹ : ℝ) := by + obtain ⟨K, hK⟩ := exists_lipschitzWith_polynomialTransition4_root + refine ⟨K * (‖(β - α)⁻¹‖₊ * 1), ?_⟩ + simpa only [polynomialSwitch4, Function.comp_def, smul_eq_mul, sub_eq_add_neg, div_eq_mul_inv, + mul_comm] using hK.comp + ((lipschitzWith_smul (β - α)⁻¹).comp (isometry_add_right (-α)).lipschitzWith) + +/-- The complementary rescaled switches also have Lipschitz fourth roots. -/ +theorem exists_lipschitzWith_one_sub_polynomialSwitch4_root (α β : ℝ) : + ∃ K, LipschitzWith K fun t => (1 - polynomialSwitch4 α β t) ^ (4⁻¹ : ℝ) := by + obtain ⟨K, hK⟩ := exists_lipschitzWith_one_sub_polynomialTransition4_root + refine ⟨K * (‖(β - α)⁻¹‖₊ * 1), ?_⟩ + simpa only [polynomialSwitch4, Function.comp_def, smul_eq_mul, sub_eq_add_neg, div_eq_mul_inv, + mul_comm] using hK.comp + ((lipschitzWith_smul (β - α)⁻¹).comp (isometry_add_right (-α)).lipschitzWith) + +@[simp, norm_cast] +theorem transitionPolynomial4_ratCast (t : ℚ) : + transitionPolynomial4 (t : ℝ) = (transitionPolynomial4 t : ℚ) := by + simp [transitionPolynomial4] + +@[simp, norm_cast] +theorem polynomialTransition4_ratCast (t : ℚ) : + polynomialTransition4 (t : ℝ) = (polynomialTransition4 t : ℚ) := by + simp only [polynomialTransition4, ← transitionPolynomial4_ratCast, Rat.cast_max, Rat.cast_min, + Rat.cast_zero, Rat.cast_one] + +@[simp, norm_cast] +theorem polynomialSwitch4_ratCast (α β t : ℚ) : + polynomialSwitch4 (α : ℝ) β t = (polynomialSwitch4 α β t : ℚ) := by + simp only [polynomialSwitch4, ← polynomialTransition4_ratCast, Rat.cast_div, Rat.cast_sub] + +end Cslib diff --git a/ComplexityTests/PolynomialSwitch.lean b/ComplexityTests/PolynomialSwitch.lean new file mode 100644 index 0000000000..bc5f89fc93 --- /dev/null +++ b/ComplexityTests/PolynomialSwitch.lean @@ -0,0 +1,77 @@ +/- +Copyright (c) 2026 Samuel Schlesinger. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Samuel Schlesinger +-/ +import Complexity.Foundations.Analysis.SpecialFunctions.PolynomialSwitch +import Mathlib.Tactic.NormNum + +/-! +# Tests for rational polynomial switches and fourth-root bounds + +These examples evaluate the transition on rational inputs, transport an exact value to the real +switch, and use the global fourth-root bounds with concrete thresholds. They concern the `s = 4` +adaptation in issue #1721, not the pinned preprint's `s = 8` choice. +-/ + +namespace ComplexityTests.PolynomialSwitch + +open Cslib +open scoped NNReal + +-- The first-quarter value tests the interior polynomial, rather than only its plateau values. +example : polynomialTransition4 (1 / 4 : ℚ) = 289 / 4096 := by + norm_num [polynomialTransition4, transitionPolynomial4] + +example : polynomialTransition4 (3 / 4 : ℚ) = 3807 / 4096 := by + norm_num [polynomialTransition4, transitionPolynomial4] + +-- A translated and rescaled interval retains the exact rational transition. +example : polynomialSwitch4 (2 : ℚ) 6 3 = 289 / 4096 := by + norm_num [polynomialSwitch4, polynomialTransition4, transitionPolynomial4] + +example : polynomialSwitch4 (2 : ℚ) 6 4 = 1 / 2 := by + norm_num [polynomialSwitch4, polynomialTransition4, transitionPolynomial4] + +example : polynomialSwitch4 (2 : ℚ) 6 (-10) = 0 ∧ polynomialSwitch4 (2 : ℚ) 6 10 = 1 := by + norm_num [polynomialSwitch4, polynomialTransition4, transitionPolynomial4] + +-- The real analysis uses exactly the same values as the rational arithmetic. +example : polynomialSwitch4 (2 : ℝ) 6 3 = 289 / 4096 := by + have h : polynomialSwitch4 (2 : ℚ) 6 3 = 289 / 4096 := by + norm_num [polynomialSwitch4, polynomialTransition4, transitionPolynomial4] + have hc := polynomialSwitch4_ratCast (2 : ℚ) 6 3 + rw [h] at hc + norm_num at hc ⊢ + exact hc + +-- A zero-width interval is defined by field division by zero, without a false endpoint law. +example (t : ℚ) : polynomialSwitch4 2 2 t = 0 := by + simp [polynomialSwitch4, polynomialTransition4] + +-- Reflection is an identity for every real input, including both plateaus. +example (t : ℝ) : + 1 - polynomialTransition4 t = polynomialTransition4 (1 - t) := + one_sub_polynomialTransition4 t + +-- The fourth-root perturbation estimate remains valid across the lower transition endpoint. +example : ∃ K : ℝ≥0, ∀ t : ℝ, + |polynomialSwitch4 2 6 t ^ (4⁻¹ : ℝ)| ≤ K * |t - 2| := by + obtain ⟨K, hK⟩ := exists_lipschitzWith_polynomialSwitch4_root 2 6 + refine ⟨K, fun t => ?_⟩ + have h := hK.dist_le_mul t 2 + rw [polynomialSwitch4_of_le (by norm_num : (2 : ℝ) < 6) le_rfl, + Real.zero_rpow (by norm_num : (4⁻¹ : ℝ) ≠ 0)] at h + simpa only [Real.dist_eq, sub_zero] using h + +-- The complementary root has the corresponding bound at the upper transition endpoint. +example : ∃ K : ℝ≥0, ∀ t : ℝ, + |(1 - polynomialSwitch4 2 6 t) ^ (4⁻¹ : ℝ)| ≤ K * |t - 6| := by + obtain ⟨K, hK⟩ := exists_lipschitzWith_one_sub_polynomialSwitch4_root 2 6 + refine ⟨K, fun t => ?_⟩ + have h := hK.dist_le_mul t 6 + rw [polynomialSwitch4_of_ge (by norm_num : (2 : ℝ) < 6) le_rfl, sub_self, + Real.zero_rpow (by norm_num : (4⁻¹ : ℝ) ≠ 0)] at h + simpa only [Real.dist_eq, sub_zero] using h + +end ComplexityTests.PolynomialSwitch From ce9a0be4205a4ec7e91ae0af544d7585e77c0479 Mon Sep 17 00:00:00 2001 From: Samuel Schlesinger Date: Fri, 30 Oct 2026 15:44:43 +0000 Subject: [PATCH 05/19] fix(logspace): keep cutoff aggregate independent of compression Remove three aggregate imports that came from untracked source copies during integration. The polynomial switch module and tests are unchanged. Validate import targets against the committed Git tree before publication. --- Complexity.lean | 3 --- 1 file changed, 3 deletions(-) diff --git a/Complexity.lean b/Complexity.lean index 257d53cdd7..bccc4b1393 100644 --- a/Complexity.lean +++ b/Complexity.lean @@ -2352,9 +2352,6 @@ public import Complexity.Foundations.Analysis.LpNorm public import Complexity.Foundations.Analysis.LpNormMeasure public import Complexity.Foundations.Analysis.MarkovBrothersInequality public import Complexity.Foundations.Analysis.RootError -public import Complexity.Foundations.Analysis.RowCompression -public import Complexity.Foundations.Analysis.RowCompression.Floors -public import Complexity.Foundations.Analysis.RowCompression.Iteration public import Complexity.Foundations.Analysis.SpecialFunctions.Arccos public import Complexity.Foundations.Analysis.SpecialFunctions.PolynomialSwitch public import Complexity.Foundations.Analysis.SpecialFunctions.SmoothSwitch From 90e85dbb79f6125ed1ece783a3f811233f2f51a2 Mon Sep 17 00:00:00 2001 From: Samuel Schlesinger Date: Fri, 30 Oct 2026 15:51:18 +0000 Subject: [PATCH 06/19] feat(logspace): prove weighted compression preloss Prove the weighted preloss assertion of OpenAI2026LogSpace Lemma 8.2 for the actual compression recursion, with explicit constant12(1+eta)/eta. Apply it to the concrete dyadic floors, discharging numerical small-floor conditions. Stationary-reference preservation, relative stability after overflow, and the complete estimator remain separate obligations. Independent agent source/API review: codex-logspace-polynomial-cutoffs-20261030 approved599c5e8a and the dyadic application delta4cc6581b. Published library/tests are identical to the reviewed source, with generated aggregate registration. Strict private Lean source/test checks, hygiene and whitespace checks pass. Full integration gates run in PR CI. Worker codex-compression-preloss-20261030; AI-assisted implementation and review. --- Complexity.lean | 1 + .../Analysis/RowCompression/Preloss.lean | 184 ++++++++++++++++++ ComplexityTests/RowCompressionPreloss.lean | 86 ++++++++ 3 files changed, 271 insertions(+) create mode 100644 Complexity/Foundations/Analysis/RowCompression/Preloss.lean create mode 100644 ComplexityTests/RowCompressionPreloss.lean diff --git a/Complexity.lean b/Complexity.lean index 0a2080c1d4..93cdc9f6f5 100644 --- a/Complexity.lean +++ b/Complexity.lean @@ -2354,6 +2354,7 @@ public import Complexity.Foundations.Analysis.RootError public import Complexity.Foundations.Analysis.RowCompression public import Complexity.Foundations.Analysis.RowCompression.Floors public import Complexity.Foundations.Analysis.RowCompression.Iteration +public import Complexity.Foundations.Analysis.RowCompression.Preloss public import Complexity.Foundations.Analysis.SpecialFunctions.Arccos public import Complexity.Foundations.Analysis.SpecialFunctions.SmoothSwitch public import Complexity.Foundations.BooleanAnalysis.Bernoulli diff --git a/Complexity/Foundations/Analysis/RowCompression/Preloss.lean b/Complexity/Foundations/Analysis/RowCompression/Preloss.lean new file mode 100644 index 0000000000..6be76e8a3b --- /dev/null +++ b/Complexity/Foundations/Analysis/RowCompression/Preloss.lean @@ -0,0 +1,184 @@ +/- +Copyright (c) 2026 Samuel Schlesinger. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Samuel Schlesinger +-/ + +module +-- upstream: candidate + +public import Complexity.Foundations.Analysis.RowCompression.Floors +import Mathlib.Tactic.FieldSimp +import Mathlib.Tactic.Linarith +import Mathlib.Tactic.Positivity +import Mathlib.Tactic.Ring + +/-! +# Weighted loss before a compression overflow + +The preloss estimate of [OpenAI2026LogSpace, Lemma 8.2, (8.9)] bounds the error introduced by +compression in terms of the errors of the uncompressed prefixes. At an endpoint with true first +coordinate `d ≥ η > 0`, a compression change is possible only when the current entry is small. +If the preceding compression loss is at most the current floor `ρ` and `8 * ρ ≤ η`, the raw +prefix is then at most half of `d`. Its clipped relative error is bounded below by +`η / (2 * (1 + η))`. Combining this with the local change bound `6 * ρ` charges the change to +the raw prefix error, with the explicit constant `12 * (1 + η) / η`. + +The main theorem applies this argument to the actual recursion `Cslib.RowCompression.iterate`. +It assumes that each earlier threshold is at most its floor and that +`6 * ∑ k < i, ρ k ≤ ρ i`. These hypotheses are weaker than the corresponding small-floor +conditions in (8.8). A corollary discharges both numerical hypotheses for the concrete scaled +dyadic floors constructed in `Cslib.RowCompression.dyadicFloor`. The clipped +error is (8.3), with channel indices `0, 1` and group indices starting at zero, so group `i` +uses the uncompressed prefix at `i + 1`. The argument is independent of the moment exponent. + +This module proves the weighted preloss assertion of Lemma 8.2. It does not assert preservation +of row functions by the stationary reference, stability after overflow, or a machine-space bound. + +## Main definitions + +* `Cslib.RowCompression.clippedError`: the maximum of the clipped relative first-channel error + and the clipped absolute second-channel error. + +## Main results + +* `Cslib.RowCompression.abs_update_sub_le_mul_clippedError`: the local weighted change bound. +* `Cslib.RowCompression.abs_iterate_sub_uncompressed_le_weighted`: the weighted preloss estimate + for the concrete increment-and-compression recursion. +* `Cslib.RowCompression.abs_iterate_sub_uncompressed_le_weighted_dyadic`: the same estimate with + the numerical floor conditions discharged by the explicit dyadic schedule. + +## References + +* [OpenAI, *Exact Derandomization of Logarithmic Space: L = RL = BPL*][OpenAI2026LogSpace], + Section 8.3, Lemma 8.2, weighted preloss assertion (8.9) + (23 September 2026, revision `7ef5c0cc`, not peer reviewed). +-/ + +public section + +namespace Cslib.RowCompression + +open Finset + +variable {ι : Type*} + +/-- The clipped endpoint error of [OpenAI2026LogSpace, (8.3)]. The first true coordinate is +nonnegative in applications; the second coordinate is measured by absolute error. -/ +@[expose] noncomputable def clippedError (d v : ℝ) (w : Fin 2 → ℝ) : ℝ := + max (min 1 (|w 0 - d| / (1 + d))) (min 1 |w 1 - v|) + +theorem clippedError_nonneg (d v : ℝ) (w : Fin 2 → ℝ) : 0 ≤ clippedError d v w := + (le_min (by norm_num) (abs_nonneg _)).trans (le_max_right _ _) + +theorem clippedError_le_one (d v : ℝ) (w : Fin 2 → ℝ) : clippedError d v w ≤ 1 := + max_le (min_le_left _ _) (min_le_left _ _) + +@[simp] +theorem clippedError_self (d v : ℝ) (w : Fin 2 → ℝ) (hd : w 0 = d) (hv : w 1 = v) : + clippedError d v w = 0 := by + simp [clippedError, hd, hv] + +private theorem le_clipped_relative_error {η d r ρ : ℝ} (hη : 0 < η) (hd : η ≤ d) + (hsmall : 8 * ρ ≤ η) (hr : r ≤ 4 * ρ) : + η / (2 * (1 + η)) ≤ min 1 (|r - d| / (1 + d)) := by + have hden : 0 < 1 + d := by linarith + have hηden : 0 < 2 * (1 + η) := by positivity + have hdiff : d ≤ 2 * |r - d| := by linarith [neg_le_abs (r - d)] + refine le_min ?_ ?_ + · apply (div_le_iff₀ hηden).2 + linarith + · apply (div_le_div_iff₀ hηden hden).2 + nlinarith [mul_nonneg (show 0 ≤ 1 + η by positivity) + (show 0 ≤ 2 * |r - d| - d by linarith)] + +/-- Before overflow, a change at a genuinely large target can be charged to the raw prefix's +clipped error. `raw` is the uncompressed prefix; `w` also includes preceding compression loss. +Only the first coordinate of that preceding loss is needed. -/ +theorem abs_update_sub_le_mul_clippedError {s : Finset ι} {n K : ℕ} {ρ z η d v : ℝ} + {w : ι → Fin 2 → ℝ} {raw : Fin 2 → ℝ} (hη : 0 < η) (hd : η ≤ d) + (hno : threshold s n ρ z w ≤ ρ) (hsmall : 8 * ρ ≤ η) {y : ι} + (hprev : |w y 0 - raw 0| ≤ ρ) (ν : Fin 2) : + |update s n K ρ z w y ν - w y ν| ≤ + (12 * (1 + η) / η) * ρ * clippedError d v raw := by + have hρ : 0 ≤ ρ := threshold_nonneg.trans hno + have hC : 0 ≤ 12 * (1 + η) / η := by positivity + by_cases hlarge : 3 * threshold s n ρ z w ≤ entrySize (w y) + · rw [update_eq_self_of_three_mul_le hlarge, sub_self, abs_zero] + exact mul_nonneg (mul_nonneg hC hρ) (clippedError_nonneg _ _ _) + have hsize : entrySize (w y) < 3 * threshold s n ρ z w := lt_of_not_ge hlarge + have hraw : raw 0 ≤ 4 * ρ := by + have hw := (le_abs_self (w y 0)).trans (abs_apply_le_entrySize (w y) 0) + have hp := (abs_le.mp hprev).1 + linarith + have he : η / (2 * (1 + η)) ≤ clippedError d v raw := + (le_clipped_relative_error hη hd hsmall hraw).trans (le_max_left _ _) + have hcancel : (12 * (1 + η) / η) * ρ * (η / (2 * (1 + η))) = 6 * ρ := by + field_simp + ring + calc |update s n K ρ z w y ν - w y ν| ≤ 6 * ρ := + (abs_update_sub_le_six_mul y ν).trans (mul_le_mul_of_nonneg_left hno (by norm_num)) + _ = (12 * (1 + η) / η) * ρ * (η / (2 * (1 + η))) := hcancel.symm + _ ≤ (12 * (1 + η) / η) * ρ * clippedError d v raw := + mul_le_mul_of_nonneg_left he (mul_nonneg hC hρ) + +/-- The weighted preloss estimate [OpenAI2026LogSpace, Lemma 8.2, (8.9)] for actual iterates. +The right-hand errors use raw prefixes, not compressed rows. No target upper bound is needed. -/ +theorem abs_iterate_sub_uncompressed_le_weighted {s : Finset ι} {n K : ℕ → ℕ} + {ρ : ℕ → ℝ} {Δ : ℕ → ι → Fin 2 → ℝ} {a : State ι} {η d v : ℝ} + (hη : 0 < η) (hd : η ≤ d) (j : ℕ) + (hno : ∀ i < j, stepThreshold s n K ρ Δ a i ≤ ρ i) + (hsmall : ∀ i < j, 8 * ρ i ≤ η) + (hprior : ∀ i < j, 6 * ∑ k ∈ range i, ρ k ≤ ρ i) (y : ι) (ν : Fin 2) : + |(iterate s n K ρ Δ a j).row y ν - uncompressedRow Δ a.row j y ν| ≤ + (12 * (1 + η) / η) * ∑ i ∈ range j, + ρ i * clippedError d v (uncompressedRow Δ a.row (i + 1) y) := by + induction j with + | zero => simp + | succ j ih => + have hj := Nat.lt_succ_self j + have hno' : ∀ i < j, stepThreshold s n K ρ Δ a i ≤ ρ i := + fun i hi => hno i (Nat.lt_succ_of_lt hi) + have hprev : |inputRow s n K ρ Δ a j y 0 - + uncompressedRow Δ a.row (j + 1) y 0| ≤ ρ j := by + rw [uncompressedRow_succ] + simp only [inputRow, Pi.add_apply, add_sub_add_right_eq_sub] + exact (abs_iterate_sub_uncompressed_le_of_no_overflow j hno' y 0).trans (hprior j hj) + have hstep := abs_update_sub_le_mul_clippedError (K := K j) (v := v) hη hd + (hno j hj) (hsmall j hj) hprev ν + have hbefore := ih hno' (fun i hi => hsmall i (Nat.lt_succ_of_lt hi)) + (fun i hi => hprior i (Nat.lt_succ_of_lt hi)) + have hdiff : |inputRow s n K ρ Δ a j y ν - uncompressedRow Δ a.row (j + 1) y ν| = + |(iterate s n K ρ Δ a j).row y ν - uncompressedRow Δ a.row j y ν| := by + rw [uncompressedRow_succ] + simp only [inputRow, Pi.add_apply, add_sub_add_right_eq_sub] + calc _ ≤ |(iterate s n K ρ Δ a (j + 1)).row y ν - inputRow s n K ρ Δ a j y ν| + + |inputRow s n K ρ Δ a j y ν - uncompressedRow Δ a.row (j + 1) y ν| := + abs_sub_le _ _ _ + _ ≤ (12 * (1 + η) / η) * ρ j * + clippedError d v (uncompressedRow Δ a.row (j + 1) y) + + (12 * (1 + η) / η) * ∑ i ∈ range j, + ρ i * clippedError d v (uncompressedRow Δ a.row (i + 1) y) := by + rw [hdiff] + exact add_le_add hstep hbefore + _ = _ := by rw [sum_range_succ]; ring + +/-- Weighted preloss for the concrete dyadic floors. The numerical small-floor hypotheses are +proved by the schedule; only the absence of overflow before the selected prefix remains assumed. +The parameter choice against the later estimator's noise/capacity constants is separate. -/ +theorem abs_iterate_sub_uncompressed_le_weighted_dyadic {s : Finset ι} {n K : ℕ → ℕ} + {Δ : ℕ → ι → Fin 2 → ℝ} {a : State ι} {η d v : ℝ} + (hη : 0 < η) (hd : η ≤ d) (m j : ℕ) (hj : j ≤ m) + (hno : ∀ i < j, stepThreshold s n K (dyadicFloor η m) Δ a i ≤ dyadicFloor η m i) + (y : ι) (ν : Fin 2) : + |(iterate s n K (dyadicFloor η m) Δ a j).row y ν - uncompressedRow Δ a.row j y ν| ≤ + (12 * (1 + η) / η) * ∑ i ∈ range j, + dyadicFloor η m i * clippedError d v (uncompressedRow Δ a.row (i + 1) y) := by + apply abs_iterate_sub_uncompressed_le_weighted hη hd j hno + · exact fun i _ => eight_mul_dyadicFloor_le hη.le m i + · intro i hi + have hsum := six_sum_range_dyadicFloor_le hη.le (hi.trans_le hj) + have hfloor := dyadicFloor_nonneg hη.le m i + linarith + +end Cslib.RowCompression diff --git a/ComplexityTests/RowCompressionPreloss.lean b/ComplexityTests/RowCompressionPreloss.lean new file mode 100644 index 0000000000..7b86bd2808 --- /dev/null +++ b/ComplexityTests/RowCompressionPreloss.lean @@ -0,0 +1,86 @@ +/- +Copyright (c) 2026 Samuel Schlesinger. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Samuel Schlesinger +-/ + +import Complexity.Foundations.Analysis.RowCompression.Preloss +import Mathlib.LinearAlgebra.Matrix.Notation +import Mathlib.Tactic.FinCases +import Mathlib.Tactic.IntervalCases +import Mathlib.Tactic.NormNum + +/-! +# Weighted compression preloss examples + +A two-group calculation has actual nonzero compression loss, satisfies the small-floor and +no-overflow hypotheses, and invokes the weighted theorem. Other examples check saturation, +negative raw first coordinates, and exact targets with zero error. +-/ + +namespace ComplexityTests.RowCompressionPreloss + +open Finset Cslib.RowCompression + +private def zeroState : State (Fin 1) := ⟨0, fun _ => ![0, 0]⟩ + +private noncomputable def floors (i : ℕ) : ℝ := if i = 0 then 1 / 100 else 1 / 10 + +private theorem no_overflow (i : ℕ) (hi : i < 2) : + stepThreshold univ (fun _ => 1) (fun _ => 1) floors (fun _ => 0) zeroState i ≤ + floors i := by + interval_cases i <;> + norm_num [stepThreshold, inputRow, iterate, advance, zeroState, floors, threshold, + newDefault, update, updateEntry, radius, entrySize, defaultEntry, kthLargest, Fin.univ_succ] + +-- Two genuine compression changes: the raw prefix stays zero while the stored row becomes 0.1. +example : (iterate univ (fun _ => 1) (fun _ => 1) floors (fun _ => 0) zeroState 2).row 0 0 = + 1 / 10 := by + norm_num [iterate, advance, zeroState, floors, threshold, newDefault, update, updateEntry, + radius, entrySize, defaultEntry, kthLargest, Fin.univ_succ] + +-- The theorem applies to this concrete schedule; its weighted right side is 24·(0.01+0.1)/2. +example (ν : Fin 2) : + |(iterate univ (fun _ => 1) (fun _ => 1) floors (fun _ => 0) zeroState 2).row 0 ν - + uncompressedRow (fun _ => 0) zeroState.row 2 0 ν| ≤ 33 / 25 := by + have h := abs_iterate_sub_uncompressed_le_weighted (s := univ) (n := fun _ => 1) + (K := fun _ => 1) (ρ := floors) (Δ := fun _ => 0) (a := zeroState) + (η := 1) (d := 1) (v := 0) (by norm_num) le_rfl 2 no_overflow + (by intro i hi; interval_cases i <;> norm_num [floors]) + (by intro i hi; interval_cases i <;> norm_num [floors, sum_range_succ]) 0 ν + norm_num [floors, uncompressedRow, zeroState, clippedError, sum_range_succ] at h + simpa [uncompressedRow, zeroState] using h + +-- Relative error saturates at one, and either channel can attain the maximum. +example : clippedError 1 0 (![-4, 0] : Fin 2 → ℝ) = 1 ∧ + clippedError 1 0 (![1, 2] : Fin 2 → ℝ) = 1 := by + norm_num [clippedError] + +-- Exact targets above the sensitivity floor force zero compression change in both coordinates. +example (d v : ℝ) (hd : 1 ≤ d) (w : Fin 1 → Fin 2 → ℝ) + (hw : w 0 = ![d, v]) (hno : threshold univ 2 (1 / 10) 0 w ≤ 1 / 10) (ν : Fin 2) : + update univ 2 1 (1 / 10) 0 w 0 ν = w 0 ν := by + have h := abs_update_sub_le_mul_clippedError (K := 1) (η := 1) (d := d) (v := v) + (raw := ![d, v]) (by norm_num) hd hno (by norm_num) + (by rw [hw]; norm_num) ν + have he : clippedError d v (![d, v] : Fin 2 → ℝ) = 0 := by simp [clippedError] + rw [he, mul_zero] at h + exact sub_eq_zero.mp (abs_nonpos_iff.mp h) + +-- The explicit dyadic schedule discharges all small-floor conditions, even with a real change. +example : + |(iterate univ (fun _ => 1) (fun _ => 1) (dyadicFloor 1 1) + (fun _ => 0) zeroState 1).row 0 0 - + uncompressedRow (fun _ => 0) zeroState.row 1 0 0| ≤ 3 / 256 := by + have h := abs_iterate_sub_uncompressed_le_weighted_dyadic (s := univ) + (n := fun _ => 1) (K := fun _ => 1) (Δ := fun _ => 0) (a := zeroState) + (η := 1) (d := 1) (v := 0) (by norm_num) le_rfl 1 1 le_rfl + (by + intro i hi + interval_cases i + norm_num [stepThreshold, inputRow, iterate, zeroState, dyadicFloor, dyadicSlack, + threshold, kthLargest, entrySize, Fin.univ_succ]) 0 0 + norm_num [dyadicFloor, dyadicSlack, uncompressedRow, zeroState, clippedError] at h ⊢ + exact h + +end ComplexityTests.RowCompressionPreloss From 13625a79f47c613501e2ee1ab77da3565f7993b4 Mon Sep 17 00:00:00 2001 From: Samuel Schlesinger Date: Fri, 30 Oct 2026 15:54:01 +0000 Subject: [PATCH 07/19] feat(logspace): preserve stationary reference outputs under compression Define the padded first-coordinate rank and prove concrete threshold, default, row-bound and rank preservation results for stationary references. Above the flat region, the rank stays fixed; inside it, the rank remains in the flat region. A gated row output with separated entry support therefore survives each update and any finite zero-increment schedule with floors at most eta and capacities at least the fixed positive rank K. This formalizes the stationary-output assertion of OpenAI2026LogSpace, Section 8.3, Lemma 8.2, revision 7ef5c0cc. It does not assert equality of whole rows, a root-discrepancy estimate, or post-overflow stability. The explicit support and gate hypotheses do not assume the preservation conclusion. Validation on base 7d08e44bbdb626b74adaa9c4d63e07faa28ce525: direct Lean 4.36.0-rc2 checks of both new files passed without diagnostics, using private outputs and existing parent-checkout dependencies read-only. Tests exhibit an above-flat rank fixed at 1/2 while a zero entry moves to 3/8, an arbitrary stationary iteration retaining nonzero output 21/2, and a low rank moving from zero to 1/8 while output 41/4 is preserved. Focused proof hygiene including --check-simp and staged git diff --check passed. Aggregate regeneration and the full project gates remain integration work. AI assistance: ChatGPT implemented and checked these proofs as worker codex-compression-iteration-20261030. Independent agent source/API review: codex-logspace-polynomial-cutoffs-20261030 approved 10a516829a8cf8ea4fd0da6a65abe00147525b46. Publication changes only dependency ancestry and generated aggregate registration. Integrated strict module/test builds and committed import/hygiene checks pass. Full gates run in PR CI. --- Complexity.lean | 1 + .../Analysis/RowCompression/Reference.lean | 292 ++++++++++++++++++ ComplexityTests/RowCompressionReference.lean | 177 +++++++++++ 3 files changed, 470 insertions(+) create mode 100644 Complexity/Foundations/Analysis/RowCompression/Reference.lean create mode 100644 ComplexityTests/RowCompressionReference.lean diff --git a/Complexity.lean b/Complexity.lean index 93cdc9f6f5..e492a325c8 100644 --- a/Complexity.lean +++ b/Complexity.lean @@ -2355,6 +2355,7 @@ public import Complexity.Foundations.Analysis.RowCompression public import Complexity.Foundations.Analysis.RowCompression.Floors public import Complexity.Foundations.Analysis.RowCompression.Iteration public import Complexity.Foundations.Analysis.RowCompression.Preloss +public import Complexity.Foundations.Analysis.RowCompression.Reference public import Complexity.Foundations.Analysis.SpecialFunctions.Arccos public import Complexity.Foundations.Analysis.SpecialFunctions.SmoothSwitch public import Complexity.Foundations.BooleanAnalysis.Bernoulli diff --git a/Complexity/Foundations/Analysis/RowCompression/Reference.lean b/Complexity/Foundations/Analysis/RowCompression/Reference.lean new file mode 100644 index 0000000000..e366049ce8 --- /dev/null +++ b/Complexity/Foundations/Analysis/RowCompression/Reference.lean @@ -0,0 +1,292 @@ +/- +Copyright (c) 2026 Samuel Schlesinger. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Samuel Schlesinger +-/ + +module +-- upstream: candidate + +public import Complexity.Foundations.Analysis.RowCompression.Iteration +import Mathlib.Tactic.Linarith + +/-! +# Stationary reference rows under compression + +This module proves the stationary-output assertion of [OpenAI2026LogSpace, Lemma 8.2]. +The first coordinates of a reference row are at least `-η`, and the absolute values of its +second coordinates are at most `η`. Compression has floor at most `η` and capacity `n ≥ K`. +Write `q` for the `K`-th first-coordinate rank padded by the old default. The actual threshold, +new default and new padded rank are at most `max η q`. If `η < q`, the padded rank is preserved +exactly; otherwise both old and new ranks remain in `[0,η]`. The row bounds are preserved too. + +A row output `H(first, second, rank)` is preserved when it is zero below an entry threshold `e`, +zero above a gate-closing rank `g`, and independent of rank within `[0,η]`, where +`η < g` and `3 * g < e`. When the gate is open, entries above `e` are unchanged and entries +below `e` cannot enter the support. The theorem also iterates the concrete updates with no +increments, allowing arbitrary floors at most `η` and capacities at least the fixed rank `K`. + +This is output preservation, not equality of whole rows: defaults and small entries may move. +No root-discrepancy bound, comparison with a perturbed reference, or post-overflow error estimate +is asserted. The arithmetic rank includes zero padding; for the source's nonnegative defaults +it agrees with padding by arbitrarily many copies of the default. + +## Main definitions + +* `Cslib.RowCompression.firstRank`: the padded first-coordinate rank. + +## Main results + +* `Cslib.RowCompression.reference_threshold_le`: the actual threshold is at most `max η q`. +* `Cslib.RowCompression.reference_firstRank_eq`: ranks above `η` are preserved exactly. +* `Cslib.RowCompression.reference_update_output_eq`: a gated row output is preserved. +* `Cslib.RowCompression.reference_iterate_output_eq`: preservation through zero-increment + iteration. + +## References + +* [OpenAI, *Exact Derandomization of Logarithmic Space: L = RL = BPL*][OpenAI2026LogSpace], + Section 8.3, Lemma 8.2, stationary-reference assertion + (23 September 2026, revision `7ef5c0cc`, not peer reviewed). +-/ + +public section + +namespace Cslib.RowCompression + +open Finset + +variable {ι : Type*} + +/-- The first-coordinate rank, padded by the old default as well as zero. For a nonnegative +default this is the rank obtained by adjoining arbitrarily many copies of `(z,0)`. -/ +@[expose] noncomputable def firstRank (s : Finset ι) (K : ℕ) (z : ℝ) + (w : ι → Fin 2 → ℝ) : ℝ := max z (kthLargest K s fun y => w y 0) + +variable {s : Finset ι} {n K : ℕ} {ρ z η : ℝ} {w : ι → Fin 2 → ℝ} + +theorem firstRank_nonneg : 0 ≤ firstRank s K z w := + kthLargest_nonneg.trans (le_max_right _ _) + +theorem default_le_firstRank : z ≤ firstRank s K z w := le_max_left _ _ + +theorem kthLargest_le_firstRank : kthLargest K s (fun y => w y 0) ≤ firstRank s K z w := + le_max_right _ _ + +/-- With small negative first coordinates and small second coordinates, size ranks cannot +exceed the first-coordinate rank or `η`, whichever is larger. -/ +theorem reference_threshold_le (hη : 0 ≤ η) (hρ : ρ ≤ η) (hK : 0 < K) (hKn : K ≤ n) + (hfirst : ∀ y ∈ s, -η ≤ w y 0) (hsecond : ∀ y ∈ s, |w y 1| ≤ η) : + threshold s n ρ z w ≤ max η (firstRank s K z w) := by + let Q := max η (firstRank s K z w) + have hηQ : η ≤ Q := le_max_left _ _ + have hqQ : firstRank s K z w ≤ Q := le_max_right _ _ + have hQ0 : 0 ≤ Q := hη.trans hηQ + have hrank : kthLargest n s (fun y => entrySize (w y)) ≤ Q := by + by_contra h + have hcard := (lt_kthLargest_iff (hK.trans_le hKn) hQ0).mp (lt_of_not_ge h) + have hsub : ({y ∈ s | Q < entrySize (w y)} : Finset ι) ⊆ {y ∈ s | Q < w y 0} := by + intro y hy + obtain ⟨hys, hy⟩ := mem_filter.mp hy + refine mem_filter.mpr ⟨hys, ?_⟩ + by_contra hfirstQ + have hsize : entrySize (w y) ≤ Q := + max_le (abs_le.mpr ⟨by linarith [hfirst y hys], not_lt.mp hfirstQ⟩) + ((hsecond y hys).trans hηQ) + exact (not_lt_of_ge hsize) hy + have hfirstRank : Q < kthLargest K s (fun y => w y 0) := + (lt_kthLargest_iff hK hQ0).mpr (hKn.trans (hcard.trans (card_le_card hsub))) + exact (not_lt_of_ge (kthLargest_le_firstRank.trans hqQ)) hfirstRank + exact max_le (default_le_firstRank.trans hqQ) (max_le (hρ.trans hηQ) hrank) + +/-- The new default is at most the larger of `η` and the old padded rank. -/ +theorem reference_newDefault_le (hη : 0 ≤ η) (hρ : ρ ≤ η) (hK : 0 < K) (hKn : K ≤ n) + (hfirst : ∀ y ∈ s, -η ≤ w y 0) (hsecond : ∀ y ∈ s, |w y 1| ≤ η) : + newDefault s n K ρ z w ≤ max η (firstRank s K z w) := + max_le (reference_threshold_le hη hρ hK hKn hfirst hsecond) + ((min_le_left _ _).trans (le_max_right _ _)) + +/-- Moving coordinates toward a nonnegative first-coordinate default and zero second +coordinate preserves the reference row's small negative and second-coordinate bounds. -/ +theorem reference_update_bounds (hη : 0 ≤ η) {y : ι} + (hfirst : -η ≤ w y 0) (hsecond : |w y 1| ≤ η) : + -η ≤ update s n K ρ z w y 0 ∧ |update s n K ρ z w y 1| ≤ η := by + have h0 := update_mem_Icc (s := s) (n := n) (K := K) (ρ := ρ) (z := z) (w := w) y 0 + have h1 := update_mem_Icc (s := s) (n := n) (K := K) (ρ := ρ) (z := z) (w := w) y 1 + change min (w y 0) (newDefault s n K ρ z w) ≤ update s n K ρ z w y 0 ∧ + update s n K ρ z w y 0 ≤ max (w y 0) (newDefault s n K ρ z w) at h0 + change min (w y 1) 0 ≤ update s n K ρ z w y 1 ∧ + update s n K ρ z w y 1 ≤ max (w y 1) 0 at h1 + have hznew : 0 ≤ newDefault s n K ρ z w := newDefault_nonneg + refine ⟨(le_min hfirst (by linarith)).trans h0.1, abs_le.mpr ⟨?_, ?_⟩⟩ + · exact (le_min (abs_le.mp hsecond).1 (by linarith)).trans h1.1 + · exact h1.2.trans (max_le (abs_le.mp hsecond).2 hη) + +/-- The new padded rank is at most the larger of `η` and the old padded rank. -/ +theorem reference_firstRank_le (hη : 0 ≤ η) (hρ : ρ ≤ η) (hK : 0 < K) (hKn : K ≤ n) + (hfirst : ∀ y ∈ s, -η ≤ w y 0) (hsecond : ∀ y ∈ s, |w y 1| ≤ η) : + firstRank s K (newDefault s n K ρ z w) (update s n K ρ z w) ≤ + max η (firstRank s K z w) := by + let Q := max η (firstRank s K z w) + have hQ0 : 0 ≤ Q := hη.trans (le_max_left _ _) + have hb : newDefault s n K ρ z w ≤ Q := + reference_newDefault_le hη hρ hK hKn hfirst hsecond + refine max_le hb ?_ + by_contra h + have hcard := (lt_kthLargest_iff hK hQ0).mp (lt_of_not_ge h) + have hsub : ({y ∈ s | Q < update s n K ρ z w y 0} : Finset ι) ⊆ + {y ∈ s | Q < w y 0} := by + intro y hy + obtain ⟨hys, hy⟩ := mem_filter.mp hy + refine mem_filter.mpr ⟨hys, ?_⟩ + by_contra hfirstQ + have hu := (update_mem_Icc (s := s) (n := n) (K := K) (ρ := ρ) (z := z) (w := w) y 0).2 + change update s n K ρ z w y 0 ≤ max (w y 0) (newDefault s n K ρ z w) at hu + exact (not_lt_of_ge (hu.trans (max_le (not_lt.mp hfirstQ) hb))) hy + have hfirstRank : Q < kthLargest K s (fun y => w y 0) := + (lt_kthLargest_iff hK hQ0).mpr (hcard.trans (card_le_card hsub)) + exact (not_lt_of_ge (kthLargest_le_firstRank.trans (le_max_right _ _))) hfirstRank + +/-- Above the flat rank region, the padded rank is preserved exactly. If the new default +does not already equal the old rank, all old rank witnesses lie in the identity region. -/ +theorem reference_firstRank_eq (hη : 0 ≤ η) (hρ : ρ ≤ η) (hK : 0 < K) (hKn : K ≤ n) + (hfirst : ∀ y ∈ s, -η ≤ w y 0) (hsecond : ∀ y ∈ s, |w y 1| ≤ η) + (hq : η < firstRank s K z w) : + firstRank s K (newDefault s n K ρ z w) (update s n K ρ z w) = firstRank s K z w := by + have hu : threshold s n ρ z w ≤ firstRank s K z w := by + simpa only [max_eq_right hq.le] using + reference_threshold_le (z := z) hη hρ hK hKn hfirst hsecond + refine le_antisymm ?_ ?_ + · simpa only [max_eq_right hq.le] using + reference_firstRank_le (z := z) hη hρ hK hKn hfirst hsecond + by_cases hqu : firstRank s K z w ≤ 3 * threshold s n ρ z w + · have hb : newDefault s n K ρ z w = firstRank s K z w := by + change max (threshold s n ρ z w) (min (firstRank s K z w) (3 * threshold s n ρ z w)) = _ + rw [min_eq_left hqu, max_eq_right hu] + exact hb ▸ (default_le_firstRank (s := s) (K := K) (z := newDefault s n K ρ z w) + (w := update s n K ρ z w)) + have h3u : 3 * threshold s n ρ z w < firstRank s K z w := lt_of_not_ge hqu + have hzq : z < firstRank s K z w := by + have hz : z ≤ threshold s n ρ z w := le_threshold + have hu0 : 0 ≤ threshold s n ρ z w := threshold_nonneg + linarith + have hqreal : firstRank s K z w ≤ kthLargest K s (fun y => w y 0) := by + have hmax := le_max_iff.mp + (show firstRank s K z w ≤ max z (kthLargest K s fun y => w y 0) from le_rfl) + exact hmax.resolve_left (not_le.mpr hzq) + have hq0 : 0 < firstRank s K z w := hη.trans_lt hq + have hcard := (le_kthLargest_iff hK hq0).mp hqreal + have hsub : ({y ∈ s | firstRank s K z w ≤ w y 0} : Finset ι) ⊆ + {y ∈ s | firstRank s K z w ≤ update s n K ρ z w y 0} := by + intro y hy + obtain ⟨hys, hy⟩ := mem_filter.mp hy + refine mem_filter.mpr ⟨hys, ?_⟩ + have hid : update s n K ρ z w y = w y := + update_eq_self_of_three_mul_le + (h3u.le.trans ((hy.trans (le_abs_self _)).trans (abs_apply_le_entrySize (w y) 0))) + rw [hid] + exact hy + exact ((le_kthLargest_iff hK hq0).mpr (hcard.trans (card_le_card hsub))).trans + kthLargest_le_firstRank + +/-- Compression preserves any row output with a separated entry support and rank gate, and +with no rank sensitivity in `[0,η]`. These are the structural hypotheses used in the +stationary-reference part of [OpenAI2026LogSpace, Lemma 8.2]. -/ +theorem reference_update_output_eq {H : ℝ → ℝ → ℝ → ℝ} {g e : ℝ} + (hη : 0 ≤ η) (hρ : ρ ≤ η) (hK : 0 < K) (hKn : K ≤ n) + (hfirst : ∀ y ∈ s, -η ≤ w y 0) (hsecond : ∀ y ∈ s, |w y 1| ≤ η) + (hηg : η < g) (hge : 3 * g < e) + (hentry : ∀ x v r, x ≤ e → H x v r = 0) + (hgate : ∀ x v r, g ≤ r → H x v r = 0) + (hflat : ∀ x v q r, q ∈ Set.Icc 0 η → r ∈ Set.Icc 0 η → H x v q = H x v r) + (y : ι) (_hy : y ∈ s) : + H (update s n K ρ z w y 0) (update s n K ρ z w y 1) + (firstRank s K (newDefault s n K ρ z w) (update s n K ρ z w)) = + H (w y 0) (w y 1) (firstRank s K z w) := by + let q := firstRank s K z w + let q' := firstRank s K (newDefault s n K ρ z w) (update s n K ρ z w) + change H (update s n K ρ z w y 0) (update s n K ρ z w y 1) q' = H (w y 0) (w y 1) q + by_cases hclosed : g ≤ q + · have heq : q' = q := + reference_firstRank_eq hη hρ hK hKn hfirst hsecond (hηg.trans_le hclosed) + rw [heq, hgate _ _ _ hclosed, hgate _ _ _ hclosed] + have hQg : max η q < g := max_lt hηg (lt_of_not_ge hclosed) + have hg0 : 0 < g := hη.trans_lt hηg + have hu : threshold s n ρ z w ≤ max η q := + reference_threshold_le hη hρ hK hKn hfirst hsecond + have hb : newDefault s n K ρ z w ≤ max η q := + reference_newDefault_le hη hρ hK hKn hfirst hsecond + have hb_e : newDefault s n K ρ z w ≤ e := by linarith + by_cases hsmall : w y 0 ≤ e + · have hcoord := (update_mem_Icc (s := s) (n := n) (K := K) (ρ := ρ) (z := z) + (w := w) y 0).2 + change update s n K ρ z w y 0 ≤ max (w y 0) (newDefault s n K ρ z w) at hcoord + have hnew : update s n K ρ z w y 0 ≤ e := hcoord.trans (max_le hsmall hb_e) + rw [hentry _ _ _ hnew, hentry _ _ _ hsmall] + have h3u : 3 * threshold s n ρ z w < e := by linarith + have hid : update s n K ρ z w y = w y := + update_eq_self_of_three_mul_le (h3u.le.trans ((lt_of_not_ge hsmall).le.trans + ((le_abs_self _).trans (abs_apply_le_entrySize (w y) 0)))) + rw [hid] + by_cases hq : η < q + · have heq : q' = q := reference_firstRank_eq hη hρ hK hKn hfirst hsecond hq + rw [heq] + have hqη : q ≤ η := not_lt.mp hq + have hq'η : q' ≤ η := by + have h := reference_firstRank_le (z := z) hη hρ hK hKn hfirst hsecond + exact h.trans (max_le le_rfl hqη) + exact hflat _ _ _ _ ⟨firstRank_nonneg, hq'η⟩ ⟨firstRank_nonneg, hqη⟩ + +section Iteration + +variable {n : ℕ → ℕ} {ρ : ℕ → ℝ} {a : State ι} + +/-- Zero-increment compression preserves the reference row's coordinate bounds at every +stage. This uses only movement toward the nonnegative default, not rank preservation. -/ +theorem reference_iterate_bounds (hη : 0 ≤ η) + (hfirst : ∀ y ∈ s, -η ≤ a.row y 0) (hsecond : ∀ y ∈ s, |a.row y 1| ≤ η) (j : ℕ) : + (∀ y ∈ s, -η ≤ (iterate s n (fun _ => K) ρ (fun _ => 0) a j).row y 0) ∧ + ∀ y ∈ s, |(iterate s n (fun _ => K) ρ (fun _ => 0) a j).row y 1| ≤ η := by + induction j with + | zero => exact ⟨hfirst, hsecond⟩ + | succ j ih => + have h (y : ι) (hy : y ∈ s) := reference_update_bounds (s := s) (n := n j) (K := K) + (ρ := ρ j) (z := (iterate s n (fun _ => K) ρ (fun _ => 0) a j).defaultValue) + hη (ih.1 y hy) (ih.2 y hy) + constructor + · intro y hy + simpa only [iterate_succ, advance, add_zero] using (h y hy).1 + · intro y hy + simpa only [iterate_succ, advance, add_zero] using (h y hy).2 + +/-- Stationary reference outputs survive any finite zero-increment compression schedule +whose floors are at most `η` and whose capacities are at least the fixed rank `K`. +Neither the row entries, the defaults, nor the chosen exception lists need remain fixed. -/ +theorem reference_iterate_output_eq {H : ℝ → ℝ → ℝ → ℝ} {g e : ℝ} + (hη : 0 ≤ η) (hK : 0 < K) + (hfirst : ∀ y ∈ s, -η ≤ a.row y 0) (hsecond : ∀ y ∈ s, |a.row y 1| ≤ η) + (hηg : η < g) (hge : 3 * g < e) + (hentry : ∀ x v r, x ≤ e → H x v r = 0) + (hgate : ∀ x v r, g ≤ r → H x v r = 0) + (hflat : ∀ x v q r, q ∈ Set.Icc 0 η → r ∈ Set.Icc 0 η → H x v q = H x v r) + (j : ℕ) (hn : ∀ i < j, K ≤ n i) (hρ : ∀ i < j, ρ i ≤ η) (y : ι) (hy : y ∈ s) : + H ((iterate s n (fun _ => K) ρ (fun _ => 0) a j).row y 0) + ((iterate s n (fun _ => K) ρ (fun _ => 0) a j).row y 1) + (firstRank s K (iterate s n (fun _ => K) ρ (fun _ => 0) a j).defaultValue + (iterate s n (fun _ => K) ρ (fun _ => 0) a j).row) = + H (a.row y 0) (a.row y 1) (firstRank s K a.defaultValue a.row) := by + induction j with + | zero => rfl + | succ j ih => + have hb := reference_iterate_bounds (n := n) (K := K) (ρ := ρ) hη hfirst hsecond j + have hstep := reference_update_output_eq (n := n j) (K := K) (ρ := ρ j) + (z := (iterate s n (fun _ => K) ρ (fun _ => 0) a j).defaultValue) + (H := H) hη (hρ j (Nat.lt_succ_self j)) hK (hn j (Nat.lt_succ_self j)) + hb.1 hb.2 hηg hge hentry hgate hflat y hy + have hprev := ih (fun i hi => hn i (Nat.lt_succ_of_lt hi)) + (fun i hi => hρ i (Nat.lt_succ_of_lt hi)) + simpa only [iterate_succ, advance, add_zero] using hstep.trans hprev + +end Iteration + +end Cslib.RowCompression diff --git a/ComplexityTests/RowCompressionReference.lean b/ComplexityTests/RowCompressionReference.lean new file mode 100644 index 0000000000..bac8284bf8 --- /dev/null +++ b/ComplexityTests/RowCompressionReference.lean @@ -0,0 +1,177 @@ +/- +Copyright (c) 2026 Samuel Schlesinger. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Samuel Schlesinger +-/ + +import Complexity.Foundations.Analysis.RowCompression.Reference +import Mathlib.LinearAlgebra.Matrix.Notation +import Mathlib.Tactic.FinCases +import Mathlib.Tactic.Linarith +import Mathlib.Tactic.NormNum + +/-! +# Stationary reference examples + +In the first example the padded rank is above the flat region and stays exactly `1/2`, while a +zero row entry moves to the new default `3/8`. In the second example the padded rank itself +moves from zero to `1/8`, inside the flat region. A nonzero gated output is preserved in both. +-/ + +namespace ComplexityTests.RowCompressionReference + +open Finset Cslib.RowCompression + +private theorem univ_three : (univ : Finset (Fin 3)) = {0, 1, 2} := by decide + +private noncomputable def highRow : Fin 3 → Fin 2 → ℝ := ![![10, 0], ![1 / 2, 0], ![0, 0]] + +private theorem high_rank : firstRank univ 2 0 highRow = 1 / 2 := by + have hle : kthLargest 2 univ (fun y => highRow y 0) ≤ 1 / 2 := by + refine not_lt.mp fun hlt => ?_ + have hcard := (lt_kthLargest_iff (by norm_num) + (by norm_num : (0 : ℝ) ≤ 1 / 2)).mp hlt + have hsupport : ({y | (1 / 2 : ℝ) < highRow y 0} : Finset (Fin 3)) = {0} := by + ext y + fin_cases y <;> norm_num [highRow] + rw [hsupport] at hcard + norm_num at hcard + have hge : (1 / 2 : ℝ) ≤ kthLargest 2 univ (fun y => highRow y 0) := by + apply (le_kthLargest_iff (by norm_num) (by norm_num : (0 : ℝ) < 1 / 2)).mpr + have hsupport : ({y | (1 / 2 : ℝ) ≤ highRow y 0} : Finset (Fin 3)) = {0, 1} := by + ext y + fin_cases y <;> norm_num [highRow] + rw [hsupport] + norm_num + unfold firstRank + rw [le_antisymm hle hge] + norm_num + +private theorem high_threshold : threshold univ 3 (1 / 8) 0 highRow = 1 / 8 := by + have hr : kthLargest 3 univ (fun y => entrySize (highRow y)) = 0 := by + refine le_antisymm (not_lt.mp fun hlt => ?_) kthLargest_nonneg + have hcard := (lt_kthLargest_iff (by norm_num) le_rfl).mp hlt + have hsupport : ({y | 0 < entrySize (highRow y)} : Finset (Fin 3)) = {0, 1} := by + ext y + fin_cases y <;> norm_num [entrySize, highRow] + rw [hsupport] at hcard + norm_num at hcard + norm_num [threshold, hr] + +private theorem high_default : newDefault univ 3 2 (1 / 8) 0 highRow = 3 / 8 := by + change max (threshold univ 3 (1 / 8) 0 highRow) + (min (firstRank univ 2 0 highRow) (3 * threshold univ 3 (1 / 8) 0 highRow)) = _ + rw [high_threshold, high_rank] + norm_num + +private theorem high_update : update univ 3 2 (1 / 8) 0 highRow = + ![![10, 0], ![1 / 2, 0], ![3 / 8, 0]] := by + unfold update + rw [high_threshold, high_default] + funext y ν + fin_cases y <;> fin_cases ν <;> + norm_num [updateEntry, radius, entrySize, defaultEntry, highRow] + +private theorem high_first (y : Fin 3) (_hy : y ∈ (univ : Finset (Fin 3))) : + -(1 / 4 : ℝ) ≤ highRow y 0 := by + fin_cases y <;> norm_num [highRow] + +private theorem high_second (y : Fin 3) (_hy : y ∈ (univ : Finset (Fin 3))) : + |highRow y 1| ≤ (1 / 4 : ℝ) := by + fin_cases y <;> norm_num [highRow] + +-- The rank theorem applies to a row whose default and some actual entries really move. +example : firstRank univ 2 (newDefault univ 3 2 (1 / 8) 0 highRow) + (update univ 3 2 (1 / 8) 0 highRow) = 1 / 2 := by + have h := reference_firstRank_eq (η := 1 / 4) (by norm_num) (by norm_num : (1 / 8 : ℝ) ≤ 1 / 4) + (by norm_num : 0 < (2 : ℕ)) (by norm_num : (2 : ℕ) ≤ 3) high_first high_second + (by rw [high_rank]; norm_num) + exact h.trans high_rank + +example : update univ 3 2 (1 / 8) 0 highRow 2 0 ≠ highRow 2 0 := by + rw [high_update] + norm_num [highRow] + +private noncomputable def rowOutput (x v r : ℝ) : ℝ := + if x ≤ 4 then 0 else if 1 ≤ r then 0 else x + v + max (1 / 4) r + +private theorem output_entry (x v r : ℝ) (hx : x ≤ 4) : rowOutput x v r = 0 := by + simp [rowOutput, hx] + +private theorem output_gate (x v r : ℝ) (hr : 1 ≤ r) : rowOutput x v r = 0 := by + simp [rowOutput, hr] + +private theorem output_flat (x v q r : ℝ) (hq : q ∈ Set.Icc 0 (1 / 4 : ℝ)) + (hr : r ∈ Set.Icc 0 (1 / 4 : ℝ)) : rowOutput x v q = rowOutput x v r := by + have hq' : ¬1 ≤ q := by linarith [hq.2] + have hr' : ¬1 ≤ r := by linarith [hr.2] + simp only [rowOutput, hq', hr', ↓reduceIte, max_eq_left hq.2, max_eq_left hr.2] + +private noncomputable def initial : State (Fin 3) := { defaultValue := 0, row := highRow } + +-- An arbitrary number of zero-increment updates preserves the nonzero output 10.5. +example (j : ℕ) : + let a := iterate univ (fun _ => 3) (fun _ => 2) (fun _ => 1 / 8) (fun _ => 0) initial j + rowOutput (a.row 0 0) (a.row 0 1) (firstRank univ 2 a.defaultValue a.row) = 21 / 2 := by + have h := reference_iterate_output_eq (s := univ) (n := fun _ => 3) (K := 2) + (ρ := fun _ => 1 / 8) (a := initial) (η := 1 / 4) (H := rowOutput) (g := 1) (e := 4) + (by norm_num) (by norm_num) high_first high_second (by norm_num) (by norm_num) + output_entry output_gate output_flat j (by intros; norm_num) (by intros; norm_num) 0 + (mem_univ 0) + refine h.trans ?_ + change rowOutput 10 0 (firstRank univ 2 0 highRow) = 21 / 2 + rw [high_rank] + norm_num [rowOutput] + +private def lowRow : Fin 3 → Fin 2 → ℝ := ![![10, 0], ![0, 0], ![0, 0]] + +private theorem low_rank : firstRank univ 2 0 lowRow = 0 := by + norm_num [firstRank, kthLargest, lowRow, univ_three, filter_insert, filter_image, + filter_singleton] + +private theorem low_threshold : threshold univ 3 (1 / 8) 0 lowRow = 1 / 8 := by + norm_num [threshold, kthLargest, lowRow, entrySize, univ_three, filter_insert, + filter_image, filter_singleton] + +private theorem low_default : newDefault univ 3 2 (1 / 8) 0 lowRow = 1 / 8 := by + change max (threshold univ 3 (1 / 8) 0 lowRow) + (min (firstRank univ 2 0 lowRow) (3 * threshold univ 3 (1 / 8) 0 lowRow)) = _ + rw [low_threshold, low_rank] + norm_num + +private theorem low_update : update univ 3 2 (1 / 8) 0 lowRow = + ![![10, 0], ![1 / 8, 0], ![1 / 8, 0]] := by + unfold update + rw [low_threshold, low_default] + funext y ν + fin_cases y <;> fin_cases ν <;> + norm_num [updateEntry, radius, entrySize, defaultEntry, lowRow] + +-- A low padded rank may change; the theorem requires only flat output dependence there. +example : firstRank univ 2 (newDefault univ 3 2 (1 / 8) 0 lowRow) + (update univ 3 2 (1 / 8) 0 lowRow) = 1 / 8 ∧ firstRank univ 2 0 lowRow = 0 := by + refine ⟨le_antisymm ?_ ?_, low_rank⟩ + · have h := reference_firstRank_le (s := univ) (n := 3) (K := 2) (ρ := 1 / 8) (z := 0) + (w := lowRow) (η := 1 / 8) (by norm_num) le_rfl (by norm_num) (by norm_num) + (fun y _ => by fin_cases y <;> norm_num [lowRow]) + (fun y _ => by fin_cases y <;> norm_num [lowRow]) + simpa only [low_rank, max_eq_left (by norm_num : (0 : ℝ) ≤ 1 / 8)] using h + · have h := default_le_firstRank (s := univ) (K := 2) + (z := newDefault univ 3 2 (1 / 8) 0 lowRow) (w := update univ 3 2 (1 / 8) 0 lowRow) + simpa only [low_default] using h + +example : rowOutput (update univ 3 2 (1 / 8) 0 lowRow 0 0) + (update univ 3 2 (1 / 8) 0 lowRow 0 1) + (firstRank univ 2 (newDefault univ 3 2 (1 / 8) 0 lowRow) + (update univ 3 2 (1 / 8) 0 lowRow)) = 41 / 4 := by + have h := reference_update_output_eq (s := univ) (n := 3) (K := 2) (ρ := 1 / 8) (z := 0) + (w := lowRow) (η := 1 / 4) (H := rowOutput) (g := 1) (e := 4) + (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (fun y _ => by fin_cases y <;> norm_num [lowRow]) + (fun y _ => by fin_cases y <;> norm_num [lowRow]) + (by norm_num) (by norm_num) output_entry output_gate output_flat 0 (mem_univ 0) + refine h.trans ?_ + rw [low_rank] + norm_num [rowOutput, lowRow] + +end ComplexityTests.RowCompressionReference From 92e41efe0ccab99b797f4b22c6a8aead445564c7 Mon Sep 17 00:00:00 2001 From: Samuel Schlesinger Date: Fri, 30 Oct 2026 15:57:57 +0000 Subject: [PATCH 08/19] feat: construct a rational correction ramp with Lipschitz fourth root Use Q(t) = a*u^4/(1+u)^3 with u = max(0,(t-theta)/a). For a>0, prove nonnegativity, the upper ramp bound, lower defect theta+3*a, monotonicity, and global Lipschitz constant one. The fourth root is globally Lipschitz with explicit constant |a^(1/4)|*|a^-1|; the proof also bounds its derivative at arbitrarily large positive inputs. Definitions use exact rational arithmetic and have real cast lemmas. This is an alternative rational witness for the correction-ramp conditions of OpenAI2026LogSpace Section 4.1 at revision 7ef5c0cc, adapted to issue #1721's fourth-moment route. The primary source uses eighth roots. Full hierarchy threshold/cutoff instantiation is a separate next component; no machine resource bound is asserted and no OpenAI Lean was consulted. Validation atop a6967d13: the module and focused tests compile with the repository Lean options and warnings as errors, using private temporary outputs and read-only existing dependencies. Tests cover exact rational values, negative and large inputs, real cast compatibility, uniform ramp bounds, ordinary perturbation, and the explicit fourth-root Lipschitz constant 8 when a=1/16. Focused hygiene --check-simp and diffcheck pass. Independent review and full integration gates remain for the coordinator. Authored by worker codex-logspace-polynomial-cutoffs-20261030 with ChatGPT. Independent agent source/API review: codex-source-release-20261030 approved d3d62d9ff7fe1e54fabbf8b3ce779f929736f6ba. Publication preserves source/tests and adds generated import registration. Integrated strict module/test builds and hygiene/committed import checks pass. Full gates run in PR CI. --- Complexity.lean | 1 + .../SpecialFunctions/RationalRamp.lean | 253 ++++++++++++++++++ ComplexityTests/RationalRamp.lean | 65 +++++ 3 files changed, 319 insertions(+) create mode 100644 Complexity/Foundations/Analysis/SpecialFunctions/RationalRamp.lean create mode 100644 ComplexityTests/RationalRamp.lean diff --git a/Complexity.lean b/Complexity.lean index bccc4b1393..ed57380e4f 100644 --- a/Complexity.lean +++ b/Complexity.lean @@ -2354,6 +2354,7 @@ public import Complexity.Foundations.Analysis.MarkovBrothersInequality public import Complexity.Foundations.Analysis.RootError public import Complexity.Foundations.Analysis.SpecialFunctions.Arccos public import Complexity.Foundations.Analysis.SpecialFunctions.PolynomialSwitch +public import Complexity.Foundations.Analysis.SpecialFunctions.RationalRamp public import Complexity.Foundations.Analysis.SpecialFunctions.SmoothSwitch public import Complexity.Foundations.BooleanAnalysis.Bernoulli public import Complexity.Foundations.BooleanAnalysis.Bonami diff --git a/Complexity/Foundations/Analysis/SpecialFunctions/RationalRamp.lean b/Complexity/Foundations/Analysis/SpecialFunctions/RationalRamp.lean new file mode 100644 index 0000000000..f4b694acae --- /dev/null +++ b/Complexity/Foundations/Analysis/SpecialFunctions/RationalRamp.lean @@ -0,0 +1,253 @@ +/- +Copyright (c) 2026 Samuel Schlesinger. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Samuel Schlesinger +-/ + +module +-- upstream: candidate + +public import Complexity.Init +public import Mathlib.Basic.Real.Basic +public import Mathlib.Analysis.SpecialFunctions.Pow.Real +public import Mathlib.Topology.MetricSpace.Lipschitz +import Mathlib.Analysis.Calculus.Deriv.MeanValue +import Mathlib.Analysis.Calculus.Deriv.Pow +import Mathlib.Analysis.Calculus.MeanValue +import Mathlib.Analysis.Normed.MulAction +import Mathlib.Analysis.SpecialFunctions.Pow.Deriv +import Mathlib.Data.Rat.Cast.Order +import Mathlib.Tactic.FieldSimp +import Mathlib.Tactic.Linarith +import Mathlib.Tactic.Positivity +import Mathlib.Tactic.Ring + +/-! +# A rational correction ramp with Lipschitz fourth root + +For `a > 0`, put `u = max 0 ((t - θ) / a)` and `Q t = a * u^4 / (1 + u)^3`. +This gives a monotone, one-Lipschitz correction ramp with +`t - (θ + 3a) ≤ Q t ≤ max (t - θ) 0`. Its fourth root is globally Lipschitz. +The definitions specialize to exact rational arithmetic; this is not a machine-space bound. + +This is an alternative rational witness for the ramp conditions in +[OpenAI2026LogSpace, Section 4.1, (4.2)], adapted to the fourth-moment workstream of complexitylib +issue #1721. The pinned preprint requires eighth-root regularity and gives a piecewise-polynomial +example; this module proves fourth-root regularity for the displayed rational construction. + +## Main definitions + +* `Cslib.rationalRamp4Unit`: the normalized ramp, zero on nonpositive inputs. +* `Cslib.rationalRamp4`: translation and rescaling of the normalized ramp. + +## Main results + +* `Cslib.rationalRamp4_nonneg`, `Cslib.rationalRamp4_le`, `Cslib.le_rationalRamp4`: ramp bounds. +* `Cslib.monotone_rationalRamp4`, `Cslib.lipschitzWith_rationalRamp4`: monotonicity and Lipschitz + constant one. +* `Cslib.lipschitzWith_rationalRamp4_root`: global fourth-root regularity. +* `Cslib.rationalRamp4_ratCast`: compatibility with exact rational evaluation. + +## References + +* [OpenAI, *Exact Derandomization of Logarithmic Space: L = RL = BPL*][OpenAI2026LogSpace], + Section 4.1 (23 September 2026, revision `7ef5c0cc`, not peer reviewed). +-/ + +public section + +namespace Cslib + +open scoped NNReal + +/-- The normalized rational ramp, with fourth-order vanishing at zero. -/ +@[expose] def rationalRamp4Unit {R : Type*} [Field R] [LinearOrder R] (t : R) : R := + (max 0 t) ^ 4 / (1 + max 0 t) ^ 3 + +/-- A rational correction ramp with lower support threshold `θ` and width parameter `a`. +The analytic ramp laws assume `0 < a`. -/ +@[expose] def rationalRamp4 {R : Type*} [Field R] [LinearOrder R] (θ a t : R) : R := + a * rationalRamp4Unit ((t - θ) / a) + +private theorem core_hasDerivAt {t : ℝ} (ht : 0 ≤ t) : + HasDerivAt (fun t : ℝ => t ^ 4 / (1 + t) ^ 3) + (t ^ 3 * (t + 4) / (1 + t) ^ 4) t := by + have hp : 0 < 1 + t := by positivity + convert (hasDerivAt_pow 4 t).div (((hasDerivAt_id t).const_add 1).pow 3) + (pow_ne_zero _ hp.ne') using 1 + · rfl + · simp only [Pi.pow_apply, id_eq] + field_simp + ring + +private theorem core_deriv_nonneg {t : ℝ} (ht : 0 ≤ t) : + 0 ≤ t ^ 3 * (t + 4) / (1 + t) ^ 4 := by positivity + +private theorem core_deriv_le_one {t : ℝ} (ht : 0 ≤ t) : + t ^ 3 * (t + 4) / (1 + t) ^ 4 ≤ 1 := by + apply (div_le_one (by positivity : 0 < (1 + t) ^ 4)).2 + nlinarith [sq_nonneg t] + +private theorem core_monotoneOn : + MonotoneOn (fun t : ℝ => t ^ 4 / (1 + t) ^ 3) (Set.Ici 0) := by + refine monotoneOn_of_hasDerivWithinAt_nonneg (convex_Ici 0) + (fun t ht => (core_hasDerivAt ht).continuousAt.continuousWithinAt) + (fun t ht => (core_hasDerivAt (interior_subset ht)).hasDerivWithinAt) ?_ + exact fun t ht => core_deriv_nonneg (interior_subset ht) + +private theorem core_lipschitzOnWith : + LipschitzOnWith 1 (fun t : ℝ => t ^ 4 / (1 + t) ^ 3) (Set.Ici 0) := by + refine (convex_Ici 0).lipschitzOnWith_of_nnnorm_hasDerivWithin_le + (fun t ht => (core_hasDerivAt ht).hasDerivWithinAt) ?_ + intro t ht + change |t ^ 3 * (t + 4) / (1 + t) ^ 4| ≤ (1 : ℝ) + rw [abs_of_nonneg (core_deriv_nonneg ht)] + exact core_deriv_le_one ht + +theorem rationalRamp4Unit_nonneg (t : ℝ) : 0 ≤ rationalRamp4Unit t := by + unfold rationalRamp4Unit + positivity + +theorem rationalRamp4Unit_le (t : ℝ) : rationalRamp4Unit t ≤ max 0 t := by + have hu : 0 ≤ max 0 t := le_max_left _ _ + have hpow : 0 ≤ (max 0 t) ^ 3 := by positivity + apply (div_le_iff₀ (by positivity : 0 < (1 + max 0 t) ^ 3)).2 + nlinarith [sq_nonneg (max 0 t)] + +theorem sub_three_le_rationalRamp4Unit (t : ℝ) : t - 3 ≤ rationalRamp4Unit t := by + have hu : 0 ≤ max 0 t := le_max_left _ _ + apply (le_div_iff₀ (by positivity : 0 < (1 + max 0 t) ^ 3)).2 + have h := mul_le_mul_of_nonneg_right (sub_le_sub_right (le_max_right 0 t) 3) + (show 0 ≤ (1 + max 0 t) ^ 3 by positivity) + nlinarith [sq_nonneg (max 0 t)] + +theorem rationalRamp4Unit_of_nonpos {t : ℝ} (ht : t ≤ 0) : rationalRamp4Unit t = 0 := by + simp [rationalRamp4Unit, max_eq_left ht] + +theorem monotone_rationalRamp4Unit : Monotone (rationalRamp4Unit : ℝ → ℝ) := + fun _ _ h => core_monotoneOn (le_max_left _ _) (le_max_left _ _) (max_le_max le_rfl h) + +theorem lipschitzWith_rationalRamp4Unit : LipschitzWith 1 (rationalRamp4Unit : ℝ → ℝ) := by + refine LipschitzWith.of_dist_le_mul fun x y => ?_ + have h := core_lipschitzOnWith.dist_le_mul (max 0 x) (le_max_left _ _) + (max 0 y) (le_max_left _ _) + simp only [NNReal.coe_one, one_mul] at h + have hc := (LipschitzWith.id.const_max (0 : ℝ)).dist_le_mul x y + exact h.trans hc + +/-! ## Fourth roots -/ + +private theorem core_root_eq {t : ℝ} (ht : 0 ≤ t) : + (t ^ 4 / (1 + t) ^ 3) ^ (4⁻¹ : ℝ) = t * (1 + t) ^ (-(3 / 4 : ℝ)) := by + have hfour : (t ^ 4) ^ (4⁻¹ : ℝ) = t := by + convert Real.pow_rpow_inv_natCast ht (by norm_num : (4 : ℕ) ≠ 0) using 1 + rw [Real.div_rpow (by positivity) (by positivity), hfour, + ← Real.rpow_natCast_mul (by positivity), Real.rpow_neg (by positivity), div_eq_mul_inv] + norm_num + +private theorem root_hasDerivAt {t : ℝ} (ht : 0 ≤ t) : + HasDerivAt (fun t : ℝ => t * (1 + t) ^ (-(3 / 4 : ℝ))) + ((1 + t) ^ (-(7 / 4 : ℝ)) * (1 + t / 4)) t := by + have hp : 0 < 1 + t := by positivity + have he : (1 + t) ^ (-(3 / 4 : ℝ)) = (1 + t) ^ (-(7 / 4 : ℝ)) * (1 + t) := by + rw [← Real.rpow_add_one hp.ne'] + norm_num + convert (hasDerivAt_id t).mul (((hasDerivAt_id t).const_add 1).rpow_const + (p := -(3 / 4 : ℝ)) (Or.inl hp.ne')) + using 1 + · rfl + · simp only [id_eq, one_mul] + rw [he] + norm_num + ring + +private theorem root_deriv_nonneg {t : ℝ} (ht : 0 ≤ t) : + 0 ≤ (1 + t) ^ (-(7 / 4 : ℝ)) * (1 + t / 4) := by positivity + +private theorem root_deriv_le_one {t : ℝ} (ht : 0 ≤ t) : + (1 + t) ^ (-(7 / 4 : ℝ)) * (1 + t / 4) ≤ 1 := by + have hp : 0 < 1 + t := by positivity + calc (1 + t) ^ (-(7 / 4 : ℝ)) * (1 + t / 4) ≤ + (1 + t) ^ (-(7 / 4 : ℝ)) * (1 + t) := + mul_le_mul_of_nonneg_left (by linarith) (Real.rpow_nonneg hp.le _) + _ = (1 + t) ^ (-(3 / 4 : ℝ)) := by rw [← Real.rpow_add_one hp.ne']; norm_num + _ ≤ 1 := Real.rpow_le_one_of_one_le_of_nonpos (by linarith) (by norm_num) + +private theorem root_lipschitzOnWith : + LipschitzOnWith 1 (fun t : ℝ => t * (1 + t) ^ (-(3 / 4 : ℝ))) (Set.Ici 0) := by + refine (convex_Ici 0).lipschitzOnWith_of_nnnorm_hasDerivWithin_le + (fun t ht => (root_hasDerivAt ht).hasDerivWithinAt) ?_ + intro t ht + change |(1 + t) ^ (-(7 / 4 : ℝ)) * (1 + t / 4)| ≤ (1 : ℝ) + rw [abs_of_nonneg (root_deriv_nonneg ht)] + exact root_deriv_le_one ht + +/-- The normalized ramp's fourth root has global Lipschitz constant one. -/ +theorem lipschitzWith_rationalRamp4Unit_root : + LipschitzWith 1 fun t : ℝ => rationalRamp4Unit t ^ (4⁻¹ : ℝ) := by + refine LipschitzWith.of_dist_le_mul fun x y => ?_ + have h := root_lipschitzOnWith.dist_le_mul (max 0 x) (le_max_left _ _) + (max 0 y) (le_max_left _ _) + rw [← core_root_eq (le_max_left _ _), ← core_root_eq (le_max_left _ _)] at h + simp only [NNReal.coe_one, one_mul] at h + exact h.trans ((LipschitzWith.id.const_max (0 : ℝ)).dist_le_mul x y) + +/-! ## Translation and rescaling -/ + +variable {θ a t : ℝ} + +theorem rationalRamp4_nonneg (ha : 0 ≤ a) (θ t : ℝ) : 0 ≤ rationalRamp4 θ a t := + mul_nonneg ha (rationalRamp4Unit_nonneg _) + +theorem rationalRamp4_le (ha : 0 < a) (θ t : ℝ) : + rationalRamp4 θ a t ≤ max (t - θ) 0 := by + calc rationalRamp4 θ a t ≤ a * max 0 ((t - θ) / a) := + mul_le_mul_of_nonneg_left (rationalRamp4Unit_le _) ha.le + _ = max (t - θ) 0 := by + rw [mul_max_of_nonneg _ _ ha.le, mul_zero] + simp [mul_div_cancel₀, ha.ne', max_comm] + +theorem le_rationalRamp4 (ha : 0 < a) (θ t : ℝ) : + t - (θ + 3 * a) ≤ rationalRamp4 θ a t := by + calc t - (θ + 3 * a) = a * ((t - θ) / a - 3) := by field_simp; ring + _ ≤ rationalRamp4 θ a t := + mul_le_mul_of_nonneg_left (sub_three_le_rationalRamp4Unit _) ha.le + +theorem rationalRamp4_of_le (ha : 0 < a) (ht : t ≤ θ) : rationalRamp4 θ a t = 0 := by + rw [rationalRamp4, rationalRamp4Unit_of_nonpos (div_nonpos_of_nonpos_of_nonneg + (sub_nonpos.mpr ht) ha.le), mul_zero] + +theorem monotone_rationalRamp4 (ha : 0 < a) (θ : ℝ) : Monotone (rationalRamp4 θ a) := + fun _ _ h => mul_le_mul_of_nonneg_left (monotone_rationalRamp4Unit + (div_le_div_of_nonneg_right (sub_le_sub_right h θ) ha.le)) ha.le + +/-- The scale factor cancels the input rescaling, preserving Lipschitz constant one. -/ +theorem lipschitzWith_rationalRamp4 (ha : 0 < a) (θ : ℝ) : + LipschitzWith 1 (rationalRamp4 θ a) := by + change LipschitzWith 1 (fun t : ℝ => a * rationalRamp4Unit ((t - θ) / a)) + have h := (lipschitzWith_smul a).comp (lipschitzWith_rationalRamp4Unit.comp + ((lipschitzWith_smul a⁻¹).comp (isometry_add_right (-θ)).lipschitzWith)) + simpa only [mul_one, one_mul, ← nnnorm_mul, mul_inv_cancel₀ ha.ne', nnnorm_one, + Function.comp_def, smul_eq_mul, sub_eq_add_neg, div_eq_mul_inv, mul_comm] + using h + +/-- The rescaled ramp's fourth root is globally Lipschitz, including arbitrarily large inputs. -/ +theorem lipschitzWith_rationalRamp4_root (ha : 0 < a) (θ : ℝ) : + LipschitzWith (‖a ^ (4⁻¹ : ℝ)‖₊ * ‖a⁻¹‖₊) + fun t : ℝ => rationalRamp4 θ a t ^ (4⁻¹ : ℝ) := by + have h := (lipschitzWith_smul (a ^ (4⁻¹ : ℝ))).comp (lipschitzWith_rationalRamp4Unit_root.comp + ((lipschitzWith_smul a⁻¹).comp (isometry_add_right (-θ)).lipschitzWith)) + simpa only [mul_one, one_mul, rationalRamp4, Real.mul_rpow ha.le (rationalRamp4Unit_nonneg _), + Function.comp_def, smul_eq_mul, sub_eq_add_neg, div_eq_mul_inv, mul_comm] using h + +@[simp, norm_cast] +theorem rationalRamp4Unit_ratCast (t : ℚ) : + rationalRamp4Unit (t : ℝ) = (rationalRamp4Unit t : ℚ) := by + simp [rationalRamp4Unit, Rat.cast_max] + +@[simp, norm_cast] +theorem rationalRamp4_ratCast (θ a t : ℚ) : + rationalRamp4 (θ : ℝ) a t = (rationalRamp4 θ a t : ℚ) := by + simp only [rationalRamp4, Rat.cast_mul, ← rationalRamp4Unit_ratCast, Rat.cast_div, Rat.cast_sub] + +end Cslib diff --git a/ComplexityTests/RationalRamp.lean b/ComplexityTests/RationalRamp.lean new file mode 100644 index 0000000000..f3cc6d5a2a --- /dev/null +++ b/ComplexityTests/RationalRamp.lean @@ -0,0 +1,65 @@ +/- +Copyright (c) 2026 Samuel Schlesinger. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Samuel Schlesinger +-/ +import Complexity.Foundations.Analysis.SpecialFunctions.RationalRamp +import Mathlib.Tactic.NormNum + +/-! +# Tests for the rational correction ramp + +Exact rational evaluations exercise the transition and large inputs. The real examples use the +proved defect, one-Lipschitz bound and the nontrivial fourth-root rescaling constant. +-/ + +namespace ComplexityTests.RationalRamp + +open Cslib + +example : rationalRamp4Unit (1 : ℚ) = 1 / 8 := by + norm_num [rationalRamp4Unit] + +example : rationalRamp4Unit (10 : ℚ) = 10000 / 1331 := by + norm_num [rationalRamp4Unit] + +example : rationalRamp4 (1 : ℚ) 2 9 = 512 / 125 := by + norm_num [rationalRamp4, rationalRamp4Unit] + +example : rationalRamp4 (1 : ℚ) 2 (-5) = 0 ∧ rationalRamp4 (1 : ℚ) 2 1 = 0 := by + norm_num [rationalRamp4, rationalRamp4Unit] + +example : rationalRamp4 (1 : ℝ) 2 9 = 512 / 125 := by + have h : rationalRamp4 (1 : ℚ) 2 9 = 512 / 125 := by + norm_num [rationalRamp4, rationalRamp4Unit] + have hc := rationalRamp4_ratCast (1 : ℚ) 2 9 + rw [h] at hc + norm_num at hc ⊢ + exact hc + +-- The upper and lower bounds are uniform on the whole real line. +example (t : ℝ) : t - 7 ≤ rationalRamp4 1 2 t ∧ rationalRamp4 1 2 t ≤ max (t - 1) 0 := by + constructor + · have h := le_rationalRamp4 (by norm_num : (0 : ℝ) < 2) 1 t + norm_num at h + exact (sub_le_iff_le_add).mpr h + · exact rationalRamp4_le (by norm_num) 1 t + +example (x y : ℝ) : |rationalRamp4 1 2 x - rationalRamp4 1 2 y| ≤ |x - y| := by + simpa only [Real.dist_eq, NNReal.coe_one, one_mul] using + (lipschitzWith_rationalRamp4 (by norm_num : (0 : ℝ) < 2) 1).dist_le_mul x y + +-- A width of `1/16` gives the explicit fourth-root Lipschitz constant `8`. +example (θ x y : ℝ) : + |rationalRamp4 θ (1 / 16) x ^ (4⁻¹ : ℝ) - + rationalRamp4 θ (1 / 16) y ^ (4⁻¹ : ℝ)| ≤ 8 * |x - y| := by + have h := (lipschitzWith_rationalRamp4_root (by norm_num : (0 : ℝ) < 1 / 16) θ).dist_le_mul x y + have hr : (1 / 16 : ℝ) ^ (4⁻¹ : ℝ) = 1 / 2 := by + rw [show (1 / 16 : ℝ) = (1 / 2) ^ 4 by norm_num] + convert Real.pow_rpow_inv_natCast (by norm_num : (0 : ℝ) ≤ 1 / 2) + (by norm_num : (4 : ℕ) ≠ 0) using 1 + rw [hr] at h + norm_num [Real.dist_eq] at h ⊢ + exact h + +end ComplexityTests.RationalRamp From 675c2e386388bec54ebfe559deb810ad320d05f2 Mon Sep 17 00:00:00 2001 From: Samuel Schlesinger Date: Fri, 30 Oct 2026 16:00:55 +0000 Subject: [PATCH 09/19] feat: construct hierarchy parameters with Lipschitz fourth roots Extend HierarchyParams with the strict core threshold ladder, a positive iteration count, strict copy-count inequality, monotone bounded cutoffs, row-gate closure, and root/complement regularity. Prove the strengthened bundle nonempty using an actual rational ramp and polynomial cutoffs. The construction chooses theta = 1/(128q), width 1/(384q), theta2 = 1/(64q), copy thresholds 1/(8q) and 1/(4q), then the factorial-tail iteration count, copies, and detector ranks in the primary source's dependency order. This advances #1721's fourth-moment hierarchy gap. It is an explicit s=4 adaptation of OpenAI2026LogSpace Sections 4.1-4.4 and Remark 4.6 at pinned revision 7ef5c0cc; the source uses s=8. It does not prove eighth-root regularity, every later atom/access-score margin, a recursive estimator, or a machine-space bound. Existing HierarchyParams APIs are unchanged. Validation atop d3d62d9f: new module and focused tests compile with pinned Lean and repository options, warnings as errors, using private outputs and read-only dependencies. Tests extract actual witnesses at q=2, prove nonzero ramp and exact plateau values, use row-root perturbation at its closed endpoint, and feed the underlying parameters into the existing stage API for a nonzero two-vertex matrix. Focused hygiene --check-simp and diffcheck pass. No aggregate or existing source file was modified. Independent review and full integration gates remain for the coordinator. Authored by worker codex-logspace-polynomial-cutoffs-20261030 with ChatGPT. Independent agent source/API review: codex-compression-iteration-20261030 approved c7ac6dea11574e721ded46aeb0f76c2ccaf79df9 and independently compiled both files. Publication preserves the reviewed source/tests and adds only generated import registration. Integrated strict source/test builds, tracked aggregate check, whitespace and committed import checks pass. Full integration gates run in PR CI. --- Complexity.lean | 1 + .../FourthRootHierarchyParams.lean | 261 ++++++++++++++++++ .../FourthRootHierarchyParams.lean | 76 +++++ 3 files changed, 338 insertions(+) create mode 100644 Complexity/Foundations/Probability/FourthRootHierarchyParams.lean create mode 100644 ComplexityTests/FourthRootHierarchyParams.lean diff --git a/Complexity.lean b/Complexity.lean index ed57380e4f..2fe378be1b 100644 --- a/Complexity.lean +++ b/Complexity.lean @@ -2729,6 +2729,7 @@ public import Complexity.Foundations.Probability.ColumnDetector public import Complexity.Foundations.Probability.CorrectionAtom public import Complexity.Foundations.Probability.DetectedHierarchy public import Complexity.Foundations.Probability.DetectedStage +public import Complexity.Foundations.Probability.FourthRootHierarchyParams public import Complexity.Foundations.Probability.Gaussian.Multivariate public import Complexity.Foundations.Probability.Gaussian.Real public import Complexity.Foundations.Probability.Gaussian.Sheppard diff --git a/Complexity/Foundations/Probability/FourthRootHierarchyParams.lean b/Complexity/Foundations/Probability/FourthRootHierarchyParams.lean new file mode 100644 index 0000000000..0f61df732c --- /dev/null +++ b/Complexity/Foundations/Probability/FourthRootHierarchyParams.lean @@ -0,0 +1,261 @@ +/- +Copyright (c) 2026 Samuel Schlesinger. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Samuel Schlesinger +-/ + +module +-- upstream: candidate + +public import Complexity.Foundations.Probability.HierarchyParams +public import Complexity.Foundations.Analysis.SpecialFunctions.PolynomialSwitch +public import Complexity.Foundations.Analysis.SpecialFunctions.RationalRamp +import Mathlib.Algebra.Order.Floor.Semiring +import Mathlib.Tactic.FieldSimp +import Mathlib.Tactic.Linarith +import Mathlib.Tactic.Positivity +import Mathlib.Tactic.Ring + +/-! +# Concrete hierarchy parameters with Lipschitz fourth roots + +This module supplies an actual regular witness extending `Matrix.HierarchyParams`. Its correction +ramp is rational, its five bounded cutoffs are polynomial switches, and all required fourth roots +and complementary fourth roots are globally Lipschitz. The strict threshold ladder is +`0 < θ < θ₂ < 1/(32q)`, `0 < δ₀ < δ₁ < θ/100`, and +`0 < η < η₂ < δ₀/3`, with copy thresholds `1/(8q)` and `1/(4q)`. + +The construction fixes `θ = 1/(128q)` and width `a = 1/(384q)`, giving +`θ₂ = θ + 3a = 1/(64q)` for the rational ramp. It then chooses a positive iteration count from +the factorial tail, the number of copies, and the detector ranks, in that order. Thus the +existence theorem proves the new conditions; they are not extra premises on an unspecified stage. +The underlying `HierarchyParams` can be passed directly to all existing stage theorems. + +This is the fourth-moment adaptation in complexitylib issue #1721 of the core hierarchy +conditions in [OpenAI2026LogSpace, Sections 4.1--4.4]. The pinned preprint uses eighth roots. +The witness does not establish eighth-root regularity, every later atom/access-score margin, +the recursive estimator, or rational-machine resource bounds. When `q` is rational, the displayed +scalar functions use only rational arithmetic and min/max; selecting the iteration count and +integer ranks here is an existence argument. + +## Main definitions + +* `Matrix.FourthRootHierarchyParams`: reduced algebraic-stage data together with the strict + core threshold ladder, monotone cutoffs, and fourth-root regularity. + +## Main results + +* `Matrix.FourthRootHierarchyParams.nonempty`: a concrete regular witness exists for `q > 0` + and `cπ > 0`. + +## References + +* [OpenAI, *Exact Derandomization of Logarithmic Space: L = RL = BPL*][OpenAI2026LogSpace], + Sections 4.1--4.4 and Remark 4.6 (23 September 2026, revision `7ef5c0cc`, not peer reviewed). +-/ + +public section + +namespace Matrix + +open Cslib + +/-- Concrete regularity requirements for the fourth-moment hierarchy, extending the existing +algebraic-stage interface. The core threshold ladder is included, but later access-score margins +are not asserted by this structure. -/ +structure FourthRootHierarchyParams (q cπ Cπ Cpair Cvar : ℝ) + extends HierarchyParams q cπ Cπ Cpair Cvar where + /-- Upper support threshold of the row gate. -/ + η₂ : ℝ + θ_lt_θ₂ : θ < θ₂ + θ₂_lt : θ₂ < 1 / (32 * q) + k_pos : 0 < k + tail_small : Real.exp (1 / θ) * (L / θ) ^ k / k.factorial ≤ 1 / (32 * q) + copies_strict : q * ((k : ℝ) + 1) < m + 1 + τ₀_eq : τ₀ = 1 / (8 * q) + τ₁_eq : τ₁ = 1 / (4 * q) + δ₀_lt_δ₁ : δ₀ < δ₁ + δ₁_lt : δ₁ < θ / 100 + η_lt_η₂ : η < η₂ + η₂_lt : η₂ < δ₀ / 3 + χ_mono : Monotone χ + ϕ_mono : Monotone ϕ + ρ_nonneg : ∀ t, 0 ≤ ρ t + ρ_antitone : Antitone ρ + ρ_zero : ∀ t, η₂ ≤ t → ρ t = 0 + κ_mono : Monotone κ + κ_one_ge : ∀ t, 1 / 2 ≤ t → κ t = 1 + Q_root : ∃ K, LipschitzWith K fun t => Q t ^ (4⁻¹ : ℝ) + cutoff_roots : ∀ F ∈ [χ, ϕ, ρ, γ, κ], + (∃ K, LipschitzWith K fun t => F t ^ (4⁻¹ : ℝ)) ∧ + (∃ K, LipschitzWith K fun t => (1 - F t) ^ (4⁻¹ : ℝ)) + +namespace FourthRootHierarchyParams + +variable {q cπ Cπ Cpair Cvar : ℝ} + +/-- A concrete hierarchy witness with a rational ramp, polynomial cutoffs, the strict core +threshold ladder, and global fourth-root regularity. -/ +theorem nonempty (hq : 0 < q) (hcπ : 0 < cπ) : + Nonempty (FourthRootHierarchyParams q cπ Cπ Cpair Cvar) := by + set θ : ℝ := 1 / (128 * q) + set a : ℝ := 1 / (384 * q) + set θ₂ : ℝ := θ + 3 * a + have hθ : 0 < θ := by positivity + have ha : 0 < a := by positivity + have hθ₂ : θ₂ = 1 / (64 * q) := by + dsimp [θ₂, θ, a] + field_simp + ring + have hθ₂small : θ₂ < 1 / (32 * q) := by + rw [hθ₂, div_lt_div_iff_of_pos_left one_pos (by positivity) (by positivity)] + linarith + have hτ : 1 / (8 * q) < 1 / (4 * q) := by + rw [div_lt_div_iff_of_pos_left one_pos (by positivity) (by positivity)] + linarith + have hτ₁ : 1 / (4 * q) ≤ 1 / q := by + rw [div_le_div_iff_of_pos_left one_pos (by positivity) hq] + linarith + set δ₀ : ℝ := θ / 400 + set δ₁ : ℝ := θ / 200 + set η : ℝ := δ₀ / 1000 + set η₂ : ℝ := δ₀ / 500 + have hδ₀ : 0 < δ₀ := by positivity + have hδ : δ₀ < δ₁ := by dsimp [δ₀, δ₁]; linarith + have hη : 0 < η := by positivity + have hη₂ : η < η₂ := by dsimp [η, η₂]; linarith + obtain ⟨k, hk⟩ := exists_factorial_bound_le θ 1 + (δ := min (1 / (32 * q)) (Real.exp (1 / θ) / 2)) (by positivity) + have htail : Real.exp (1 / θ) * (1 / θ) ^ k / k.factorial ≤ 1 / (32 * q) := + hk.trans (min_le_left _ _) + have hkpos : 0 < k := by + by_contra h + have hzero : k = 0 := Nat.eq_zero_of_not_pos h + have hb := hk.trans (min_le_right _ _) + simp only [hzero, pow_zero, Nat.factorial_zero, Nat.cast_one, mul_one, div_one] at hb + linarith [Real.exp_pos (1 / θ)] + set m : ℕ := ⌈q⌉₊ * (k + 1) + have hcopies : q * ((k : ℝ) + 1) < (m : ℝ) + 1 := by + have hqc : q ≤ ⌈q⌉₊ := Nat.le_ceil q + have hm : (m : ℝ) = ⌈q⌉₊ * ((k : ℝ) + 1) := by simp [m] + rw [hm] + nlinarith [(Nat.cast_nonneg (α := ℝ) k)] + set J : ℕ := ⌈(2 * Cπ * m * k * (k + 1)) / δ₀⌉₊ + 1 + set K : ℕ := ⌈160 * (1 + Cpair * k / η)⌉₊ + set R : ℝ := (4 * J + 40 * |Cvar|) / cπ + have hR : 4 * (J : ℝ) + 40 * |Cvar| ≤ cπ * R := by + dsimp [R] + rw [mul_div_cancel₀ _ hcπ.ne'] + have hγ : (1 / 2 : ℝ) < 4 / 5 := by norm_num + have hκ : (1 / 4 : ℝ) < 1 / 2 := by norm_num + refine ⟨{ + Q := rationalRamp4 θ a + θ := θ + θ₂ := θ₂ + L := 1 + k := k + m := m + τ₀ := 1 / (8 * q) + τ₁ := 1 / (4 * q) + χ := polynomialSwitch4 (1 / (8 * q)) (1 / (4 * q)) + δ₀ := δ₀ + δ₁ := δ₁ + ϕ := polynomialSwitch4 δ₀ δ₁ + η := η + ρ := fun t => 1 - polynomialSwitch4 η η₂ t + γ := fun t => 1 - polynomialSwitch4 (1 / 2) (4 / 5) t + κ := polynomialSwitch4 (1 / 4) (1 / 2) + J := J + K := K + R := R + Q_nonneg := rationalRamp4_nonneg ha.le θ + Q_le := rationalRamp4_le ha θ + le_Q := le_rationalRamp4 ha θ + Q_mono := monotone_rationalRamp4 ha θ + Q_lipschitz := fun s t hst => ?_ + θ_pos := hθ + L_nonneg := zero_le_one + truncation := ?_ + χ_nonneg := polynomialSwitch4_nonneg _ _ + χ_le_one := polynomialSwitch4_le_one _ _ + χ_zero := fun _ h => polynomialSwitch4_of_le hτ h + χ_one := fun _ h => polynomialSwitch4_of_ge hτ h + τ₁_le := hτ₁ + copies := ?_ + δ₀_pos := hδ₀ + ϕ_nonneg := polynomialSwitch4_nonneg _ _ + ϕ_le_one := polynomialSwitch4_le_one _ _ + ϕ_zero := fun _ h => polynomialSwitch4_of_le hδ h + ϕ_one := fun _ h => polynomialSwitch4_of_ge hδ h + η_pos := hη + ρ_le_one := fun t => sub_le_self _ (polynomialSwitch4_nonneg _ _ t) + ρ_one := fun t h => by rw [polynomialSwitch4_of_le hη₂ h, sub_zero] + γ_nonneg := fun t => sub_nonneg.mpr (polynomialSwitch4_le_one _ _ t) + γ_le_one := fun t => sub_le_self _ (polynomialSwitch4_nonneg _ _ t) + γ_antitone := fun _ _ h => sub_le_sub_left (monotone_polynomialSwitch4 hγ.le h) 1 + γ_one := fun t h => by rw [polynomialSwitch4_of_le hγ h, sub_zero] + γ_zero := fun t h => by rw [polynomialSwitch4_of_ge hγ h, sub_self] + κ_nonneg := polynomialSwitch4_nonneg _ _ + κ_le_one := polynomialSwitch4_le_one _ _ + κ_zero := fun _ h => polynomialSwitch4_of_le hκ h + κ_one := fun _ h => polynomialSwitch4_of_ge hκ h.le + J_pos := Nat.succ_pos _ + rank := ?_ + gate := Nat.le_ceil _ + R_rank := by linarith [abs_nonneg Cvar] + R_var := by linarith [le_abs_self Cvar] + η₂ := η₂ + θ_lt_θ₂ := by dsimp [θ₂]; linarith + θ₂_lt := hθ₂small + k_pos := hkpos + tail_small := htail + copies_strict := hcopies + τ₀_eq := rfl + τ₁_eq := rfl + δ₀_lt_δ₁ := hδ + δ₁_lt := by dsimp [δ₁]; linarith + η_lt_η₂ := hη₂ + η₂_lt := by dsimp [η₂]; linarith + χ_mono := monotone_polynomialSwitch4 hτ.le + ϕ_mono := monotone_polynomialSwitch4 hδ.le + ρ_nonneg := fun t => sub_nonneg.mpr (polynomialSwitch4_le_one _ _ t) + ρ_antitone := fun _ _ h => sub_le_sub_left (monotone_polynomialSwitch4 hη₂.le h) 1 + ρ_zero := fun t h => by rw [polynomialSwitch4_of_ge hη₂ h, sub_self] + κ_mono := monotone_polynomialSwitch4 hκ.le + κ_one_ge := fun _ h => polynomialSwitch4_of_ge hκ h + Q_root := ⟨_, lipschitzWith_rationalRamp4_root ha θ⟩ + cutoff_roots := ?_ }⟩ + · have h := (lipschitzWith_rationalRamp4 ha θ).dist_le_mul t s + rw [Real.dist_eq, Real.dist_eq, abs_of_nonneg (sub_nonneg.mpr hst)] at h + exact (le_abs_self _).trans h + · calc θ₂ + Real.exp (1 / θ) * (1 / θ) ^ k / k.factorial ≤ θ₂ + 1 / (32 * q) := by + linarith + _ = (3 / 64) / q := by rw [hθ₂]; field_simp; ring + _ ≤ (1 / 8) / q := div_le_div_of_nonneg_right (by norm_num) hq.le + _ = 1 / (8 * q) := by ring + · rw [div_le_div_iff₀ (by positivity) hq, one_mul] + simpa only [mul_comm] using hcopies.le + · have hJ : (2 * Cπ * m * k * (k + 1)) / δ₀ ≤ (J : ℝ) := by + dsimp [J] + push_cast + exact (Nat.le_ceil _).trans (by linarith) + have hb := (div_le_iff₀ hδ₀).mp hJ + linarith + · intro F hF + simp only [List.mem_cons, List.not_mem_nil, or_false] at hF + rcases hF with rfl | rfl | rfl | rfl | rfl + · exact ⟨exists_lipschitzWith_polynomialSwitch4_root _ _, + exists_lipschitzWith_one_sub_polynomialSwitch4_root _ _⟩ + · exact ⟨exists_lipschitzWith_polynomialSwitch4_root _ _, + exists_lipschitzWith_one_sub_polynomialSwitch4_root _ _⟩ + · refine ⟨exists_lipschitzWith_one_sub_polynomialSwitch4_root _ _, ?_⟩ + simpa only [sub_sub_cancel] using exists_lipschitzWith_polynomialSwitch4_root η η₂ + · refine ⟨exists_lipschitzWith_one_sub_polynomialSwitch4_root _ _, ?_⟩ + simpa only [sub_sub_cancel] using + exists_lipschitzWith_polynomialSwitch4_root (1 / 2) (4 / 5) + · exact ⟨exists_lipschitzWith_polynomialSwitch4_root _ _, + exists_lipschitzWith_one_sub_polynomialSwitch4_root _ _⟩ + +end FourthRootHierarchyParams + +end Matrix diff --git a/ComplexityTests/FourthRootHierarchyParams.lean b/ComplexityTests/FourthRootHierarchyParams.lean new file mode 100644 index 0000000000..83fddc6c0b --- /dev/null +++ b/ComplexityTests/FourthRootHierarchyParams.lean @@ -0,0 +1,76 @@ +/- +Copyright (c) 2026 Samuel Schlesinger. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Samuel Schlesinger +-/ +import Complexity.Foundations.Probability.FourthRootHierarchyParams +import Mathlib.LinearAlgebra.Matrix.Notation +import Mathlib.Tactic.FinCases +import Mathlib.Tactic.Linarith +import Mathlib.Tactic.NormNum + +/-! +# Tests for the regular fourth-moment hierarchy witness + +The examples use the concrete existence construction at `q = 2`, derive nonzero ramp and exact +plateau values, use complementary root regularity at a closed row gate, and pass the strengthened +parameters into the existing stage API on a nonzero two-vertex transition matrix. +-/ + +namespace ComplexityTests.FourthRootHierarchyParams + +open Matrix +open scoped NNReal + +-- The actual witness has zero correction below its threshold, unbounded correction above it, +-- and the prescribed copy/row plateaus. These values use no extra cutoff assumptions. +example : ∃ P : FourthRootHierarchyParams 2 1 1 1 0, + P.Q 0 = 0 ∧ 1 ≤ P.Q (P.θ₂ + 1) ∧ P.χ (1 / 16) = 0 ∧ P.χ (1 / 8) = 1 ∧ + P.ρ P.η₂ = 0 ∧ P.κ (1 / 2) = 1 := by + obtain ⟨P⟩ := FourthRootHierarchyParams.nonempty (q := 2) (cπ := 1) (Cπ := 1) + (Cpair := 1) (Cvar := 0) (by norm_num) (by norm_num) + refine ⟨P, ?_, ?_, ?_, ?_, P.ρ_zero _ le_rfl, P.κ_one_ge _ le_rfl⟩ + · apply le_antisymm _ (P.Q_nonneg 0) + simpa only [max_eq_right (by linarith [P.θ_pos] : (0 : ℝ) - P.θ ≤ 0)] using P.Q_le 0 + · have h := P.le_Q (P.θ₂ + 1) + linarith + · apply P.χ_zero + rw [P.τ₀_eq] + norm_num + · apply P.χ_one + rw [P.τ₁_eq] + norm_num + +-- The row gate closes strictly before the detector entry factor can become nonzero. +example (P : FourthRootHierarchyParams 2 1 1 1 0) : + 3 * P.η₂ < P.δ₀ ∧ P.ϕ (3 * P.η₂) = 0 := by + have h : 3 * P.η₂ < P.δ₀ := by linarith [P.η₂_lt] + exact ⟨h, P.ϕ_zero _ h.le⟩ + +-- Root regularity gives a perturbation bound at the closed endpoint of the actual row gate. +example (P : FourthRootHierarchyParams 2 1 1 1 0) : + ∃ K : ℝ≥0, ∀ t : ℝ, |P.ρ t ^ (4⁻¹ : ℝ)| ≤ K * |t - P.η₂| := by + obtain ⟨K, hK⟩ := (P.cutoff_roots P.ρ (by simp)).1 + refine ⟨K, fun t => ?_⟩ + have h := hK.dist_le_mul t P.η₂ + rw [P.ρ_zero _ le_rfl, Real.zero_rpow (by norm_num : (4⁻¹ : ℝ) ≠ 0)] at h + simpa only [Real.dist_eq, sub_zero] using h + +/-- One edge of weight `1/2` on two vertices. -/ +private noncomputable def C : Matrix (Fin 2) (Fin 2) ℝ := !![0, 1 / 2; 0, 0] + +-- Existing stage theorems consume the parent interface directly: the constructed cutoffs give +-- a nonnegative and substochastic next transition on the copied vertices of this nonzero input. +example : ∃ P : FourthRootHierarchyParams 2 1 1 1 0, + let X : Unit → Fin 2 → Prop := fun _ _ => True + let A := P.toHierarchyParams.next X X 1 C + (∀ x y, 0 ≤ A x y) ∧ A *ᵥ 1 ≤ 1 := by + obtain ⟨P⟩ := FourthRootHierarchyParams.nonempty (q := 2) (cπ := 1) (Cπ := 1) + (Cpair := 1) (Cvar := 0) (by norm_num) (by norm_num) + have hC : ∀ x y, 0 ≤ C x y := by intro x y; fin_cases x <;> fin_cases y <;> norm_num [C] + have hC1 : C *ᵥ 1 ≤ 1 := by intro x; fin_cases x <;> norm_num [C, mulVec, dotProduct] + refine ⟨P, ?_, ?_⟩ + · exact P.toHierarchyParams.next_nonneg (by norm_num) hC + · exact P.toHierarchyParams.next_mulVec_one_le (by norm_num) hC hC1 + +end ComplexityTests.FourthRootHierarchyParams From 62a7cba7828b1b2a34cb6314543aa2701f45d355 Mon Sep 17 00:00:00 2001 From: Samuel Schlesinger Date: Fri, 30 Oct 2026 16:13:08 +0000 Subject: [PATCH 10/19] feat(logspace): construct and compare stationary compression references Construct the reference state from the actual current default and true row plus accumulated compression preloss. Derive its small-negative and second-coordinate bounds from no-overflow dyadic floors, then preserve gated outputs through the remaining capacities and floors at their original indices with zero increments. Add a separate weighted root comparison with the true zero-padded output. Sensitive targets use the existing weighted preloss bound at eta/2; uniform small loss and lower clipping remove the low targets from the rank comparison. The theorem assumes scalar support, flatness and root-Lipschitz laws and a raw-prefix error envelope only at sensitive targets, not the final output estimate. It is exponent-parametric. Instantiating all source row functions and comparison to a subsequent incremented or post-overflow calculation remain separate. Source mapping: OpenAI2026LogSpace, Section 8.3, Lemma 8.2, revision 7ef5c0cc. This connects the reviewed Preloss and Reference layers using the documented margin-scaled dyadic witness. Existing files and aggregates are unchanged. Validation: pinned Lean 4.36.0-rc2 checked the new module and tests without diagnostics, using private outputs and read-only shared dependencies. Tests exhibit a nonzero increment, nonzero actual preloss, preserved nonzero output through the shifted remaining schedule, and a strictly positive fourth-root discrepancy. The review-requested low-target regression raises the padded rank from zero to 1/1048576 while a rank-dependent fourth-root output remains exactly one under a zero sensitive-target error envelope. Focused hygiene with --check-simp and staged diff checking pass. Full project gates and aggregate regeneration remain integration work. AI assistance: ChatGPT implemented and checked this milestone as worker codex-compression-iteration-20261030. Independent reviewer codex-logspace-polynomial-cutoffs-20261030 requested the low-target regression and is reviewing the frozen revision. Independent non-author source/API review by compression_review approved exact source revision c7873d034846fbab13b83d3d9a4d596343c9d191, including a rank-dependent low-target regression. Reviewed source files are unchanged. Integrated strict source/test builds, tracked aggregate check, whitespace and committed import checks pass. Full integration gates run in PR CI. --- Complexity.lean | 1 + .../Analysis/RowCompression/Stationary.lean | 307 ++++++++++++++++ ComplexityTests/RowCompressionStationary.lean | 330 ++++++++++++++++++ 3 files changed, 638 insertions(+) create mode 100644 Complexity/Foundations/Analysis/RowCompression/Stationary.lean create mode 100644 ComplexityTests/RowCompressionStationary.lean diff --git a/Complexity.lean b/Complexity.lean index e492a325c8..ee0aafd7a5 100644 --- a/Complexity.lean +++ b/Complexity.lean @@ -2356,6 +2356,7 @@ public import Complexity.Foundations.Analysis.RowCompression.Floors public import Complexity.Foundations.Analysis.RowCompression.Iteration public import Complexity.Foundations.Analysis.RowCompression.Preloss public import Complexity.Foundations.Analysis.RowCompression.Reference +public import Complexity.Foundations.Analysis.RowCompression.Stationary public import Complexity.Foundations.Analysis.SpecialFunctions.Arccos public import Complexity.Foundations.Analysis.SpecialFunctions.SmoothSwitch public import Complexity.Foundations.BooleanAnalysis.Bernoulli diff --git a/Complexity/Foundations/Analysis/RowCompression/Stationary.lean b/Complexity/Foundations/Analysis/RowCompression/Stationary.lean new file mode 100644 index 0000000000..b892efd0d2 --- /dev/null +++ b/Complexity/Foundations/Analysis/RowCompression/Stationary.lean @@ -0,0 +1,307 @@ +/- +Copyright (c) 2026 Samuel Schlesinger. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Samuel Schlesinger +-/ + +module +-- upstream: candidate + +public import Complexity.Foundations.Analysis.RowCompression.Preloss +public import Complexity.Foundations.Analysis.RowCompression.Reference +public import Mathlib.Analysis.SpecialFunctions.Pow.Real +import Mathlib.Algebra.Order.BigOperators.Group.Finset +import Mathlib.Algebra.Order.Group.MinMax +import Mathlib.Tactic.Linarith + +/-! +# The stationary reference constructed from actual preloss + +At the input of zero-based group `j`, the stationary reference in +[OpenAI2026LogSpace, Lemma 8.2] has the current default and row `truth + loss`, where `loss` is +the actual compressed prefix minus its uncompressed counterpart. `stationaryState` constructs +this state from `iterate`; `stationaryContinuation` runs the remaining capacities and floors +from their original indices, with no further increments. + +For the explicit scaled dyadic floors, absence of overflow in groups `i < j ≤ m` bounds this +loss by `η / 100`. Consequently a true row with nonnegative first coordinates and second +coordinates of magnitude at most `η / 2` produces a reference with first coordinates at least +`-η` and second coordinates of magnitude at most `η`. The stationary preservation theorem then +applies to the actual remaining schedule. Its entry-support, rank-gate, and flat-region +hypotheses are scalar properties of the row output, not an assumed preservation conclusion. + +Under explicit scalar support, flatness and root-Lipschitz laws, weighted preloss also controls +the reference's discrepancy from the true zero-padded output. A lower clipping at `η` removes +the influence of targets below `η / 2`, while rank stability controls the sensitive targets. +This comparison allows any exponent satisfying the stated scalar law; instantiating those laws +for all of the paper's row functions remains a separate obligation. + +The zero-based prefix loss here is the paper's `L_{j-1}` before its group `j`. The floors are +the explicitly documented margin-scaled witness from `RowCompression.Floors`. This module +does not assert a post-overflow comparison with the incremented calculation or a machine-space +bound. + +## Main definitions + +* `Cslib.RowCompression.stationaryState`: the true row plus the actual accumulated preloss. +* `Cslib.RowCompression.stationaryContinuation`: the reference's shifted zero-increment run. + +## Main results + +* `Cslib.RowCompression.abs_stationaryState_row_sub_le_dyadic`: uniform small preloss. +* `Cslib.RowCompression.stationaryState_bounds_dyadic`: the constructed reference's shape. +* `Cslib.RowCompression.stationaryContinuation_output_eq_dyadic`: preservation along the + remaining compression schedule. +* `Cslib.RowCompression.abs_stationaryState_root_sub_le_weighted_dyadic`: a weighted + root-discrepancy bound under explicit scalar root-Lipschitz and support laws. + +## References + +* [OpenAI, *Exact Derandomization of Logarithmic Space: L = RL = BPL*][OpenAI2026LogSpace], + Section 8.3, Lemma 8.2, stationary-reference construction, preservation, and root comparison + (23 September 2026, revision `7ef5c0cc`, not peer reviewed). +-/ + +public section + +namespace Cslib.RowCompression + +open Finset + +variable {ι : Type*} + +/-- The reference at a prefix has the current default and the true row plus the compression +loss already accumulated by the actual calculation. -/ +@[expose] noncomputable def stationaryState (s : Finset ι) (n K : ℕ → ℕ) (ρ : ℕ → ℝ) + (Δ : ℕ → ι → Fin 2 → ℝ) (a : State ι) (truth : ι → Fin 2 → ℝ) (j : ℕ) : State ι := + { defaultValue := (iterate s n K ρ Δ a j).defaultValue + row := fun y ν => truth y ν + + ((iterate s n K ρ Δ a j).row y ν - uncompressedRow Δ a.row j y ν) } + +/-- Continue the constructed reference with the actual capacities and floors starting at +group `j`, a fixed positive rank in applications, and no further increments. -/ +@[expose] noncomputable def stationaryContinuation (s : Finset ι) (n : ℕ → ℕ) (K : ℕ) + (ρ : ℕ → ℝ) (Δ : ℕ → ι → Fin 2 → ℝ) (a : State ι) (truth : ι → Fin 2 → ℝ) + (j r : ℕ) : State ι := + iterate s (fun i => n (j + i)) (fun _ => K) (fun i => ρ (j + i)) (fun _ => 0) + (stationaryState s n (fun _ => K) ρ Δ a truth j) r + +variable {s : Finset ι} {n K : ℕ → ℕ} {ρ : ℕ → ℝ} + {Δ : ℕ → ι → Fin 2 → ℝ} {a : State ι} {truth : ι → Fin 2 → ℝ} {η : ℝ} + +/-- The reference's discrepancy from truth is exactly the actual compression loss. -/ +theorem stationaryState_row_sub (j : ℕ) (y : ι) (ν : Fin 2) : + (stationaryState s n K ρ Δ a truth j).row y ν - truth y ν = + (iterate s n K ρ Δ a j).row y ν - uncompressedRow Δ a.row j y ν := by + simp only [stationaryState, add_sub_cancel_left] + +private theorem six_sum_prefix_dyadicFloor_le (hη : 0 ≤ η) {m j : ℕ} (hj : j ≤ m) : + 6 * ∑ i ∈ range j, dyadicFloor η m i ≤ η / 100 := by + have hsum : ∑ i ∈ range j, dyadicFloor η m i ≤ ∑ i ∈ range m, dyadicFloor η m i := + sum_le_sum_of_subset_of_nonneg (range_mono hj) (fun i _ _ => dyadicFloor_nonneg hη m i) + exact (mul_le_mul_of_nonneg_left hsum (by norm_num)).trans + (six_sum_range_dyadicFloor_le_scale hη m) + +/-- The constructed reference differs from truth by at most `η / 100` before overflow. +The numerical bound comes from the actual dyadic schedule, not an assumed error budget. -/ +theorem abs_stationaryState_row_sub_le_dyadic (hη : 0 ≤ η) (m j : ℕ) (hj : j ≤ m) + (hno : ∀ i < j, stepThreshold s n K (dyadicFloor η m) Δ a i ≤ dyadicFloor η m i) + (y : ι) (ν : Fin 2) : + |(stationaryState s n K (dyadicFloor η m) Δ a truth j).row y ν - truth y ν| ≤ η / 100 := by + rw [stationaryState_row_sub] + exact (abs_iterate_sub_uncompressed_le_of_no_overflow j hno y ν).trans + (six_sum_prefix_dyadicFloor_le hη hj) + +/-- The true-row bounds and the proved preloss bound imply the shape needed by stationary +compression preservation. The reference row itself need not be nonnegative. -/ +theorem stationaryState_bounds_dyadic (hη : 0 ≤ η) (m j : ℕ) (hj : j ≤ m) + (hno : ∀ i < j, stepThreshold s n K (dyadicFloor η m) Δ a i ≤ dyadicFloor η m i) + (hfirst : ∀ y ∈ s, 0 ≤ truth y 0) (hsecond : ∀ y ∈ s, |truth y 1| ≤ η / 2) : + (∀ y ∈ s, -η ≤ (stationaryState s n K (dyadicFloor η m) Δ a truth j).row y 0) ∧ + ∀ y ∈ s, |(stationaryState s n K (dyadicFloor η m) Δ a truth j).row y 1| ≤ η := by + constructor + · intro y hy + have h := (abs_le.mp (abs_stationaryState_row_sub_le_dyadic (truth := truth) + hη m j hj hno y 0)).1 + linarith [hfirst y hy] + · intro y hy + have h := abs_le.mp (abs_stationaryState_row_sub_le_dyadic (truth := truth) + hη m j hj hno y 1) + have ht := abs_le.mp (hsecond y hy) + exact abs_le.mpr ⟨by linarith, by linarith⟩ + +/-- A small initial default remains below the flat-rank threshold before overflow. This is +useful when comparing the padded reference rank to the true row's zero-padded rank. -/ +theorem stationaryState_defaultValue_le_dyadic (hη : 0 ≤ η) + (ha : 0 ≤ a.defaultValue) (haη : a.defaultValue ≤ η / 2) (m j : ℕ) (hj : j ≤ m) + (hno : ∀ i < j, stepThreshold s n K (dyadicFloor η m) Δ a i ≤ dyadicFloor η m i) : + (stationaryState s n K (dyadicFloor η m) Δ a truth j).defaultValue ≤ η := by + have h := le_of_abs_le (abs_iterate_defaultValue_sub_le_of_no_overflow ha j hno) + have hsum := six_sum_prefix_dyadicFloor_le hη hj + change (iterate s n K (dyadicFloor η m) Δ a j).defaultValue ≤ η + linarith + +/-- The stationary reference constructed from actual preloss preserves its output through +any initial segment of the remaining schedule. Only earlier groups must avoid overflow. -/ +theorem stationaryContinuation_output_eq_dyadic {K : ℕ} {H : ℝ → ℝ → ℝ → ℝ} {g e : ℝ} + (hη : 0 ≤ η) (hK : 0 < K) (m j r : ℕ) (hr : j + r ≤ m) + (hno : ∀ i < j, + stepThreshold s n (fun _ => K) (dyadicFloor η m) Δ a i ≤ dyadicFloor η m i) + (hfirst : ∀ y ∈ s, 0 ≤ truth y 0) (hsecond : ∀ y ∈ s, |truth y 1| ≤ η / 2) + (hn : ∀ i, j ≤ i → i < m → K ≤ n i) (hηg : η < g) (hge : 3 * g < e) + (hentry : ∀ x v q, x ≤ e → H x v q = 0) + (hgate : ∀ x v q, g ≤ q → H x v q = 0) + (hflat : ∀ x v q q', q ∈ Set.Icc 0 η → q' ∈ Set.Icc 0 η → H x v q = H x v q') + (y : ι) (hy : y ∈ s) : + let b := stationaryState s n (fun _ => K) (dyadicFloor η m) Δ a truth j + let c := stationaryContinuation s n K (dyadicFloor η m) Δ a truth j r + H (c.row y 0) (c.row y 1) (firstRank s K c.defaultValue c.row) = + H (b.row y 0) (b.row y 1) (firstRank s K b.defaultValue b.row) := by + have hj : j ≤ m := (Nat.le_add_right j r).trans hr + have hb := stationaryState_bounds_dyadic hη m j hj hno hfirst hsecond + apply reference_iterate_output_eq hη hK hb.1 hb.2 hηg hge hentry hgate hflat r + · intro i hi + exact hn (j + i) (Nat.le_add_right _ _) (by omega) + · intro i _ + have h := dyadicFloor_le_scale_div hη m (j + i) + linarith + · exact hy + +/-! ## Weighted discrepancy from the true output -/ + +/-- Weighted preloss applies at the smaller sensitivity threshold `η / 2` while using the +same floors scaled by `η`. Their explicit size also proves this stronger local margin. -/ +theorem abs_stationaryState_row_sub_le_weighted_dyadic (hη : 0 < η) (m j : ℕ) (hj : j ≤ m) + (hno : ∀ i < j, stepThreshold s n K (dyadicFloor η m) Δ a i ≤ dyadicFloor η m i) + (y : ι) (hd : η / 2 ≤ truth y 0) (ν : Fin 2) : + |(stationaryState s n K (dyadicFloor η m) Δ a truth j).row y ν - truth y ν| ≤ + (12 * (1 + η / 2) / (η / 2)) * ∑ i ∈ range j, + dyadicFloor η m i * + clippedError (truth y 0) (truth y 1) (uncompressedRow Δ a.row (i + 1) y) := by + rw [stationaryState_row_sub] + apply abs_iterate_sub_uncompressed_le_weighted (by linarith : 0 < η / 2) hd j hno + · intro i _ + have h := dyadicFloor_le_scale_div hη.le m i + linarith + · intro i hi + have hsum := six_sum_range_dyadicFloor_le hη.le (hi.trans_le hj) + have hfloor := dyadicFloor_nonneg hη.le m i + linarith + +private theorem max_rank_le_add_of_clipped {K : ℕ} {f g : ι → ℝ} {δ : ℝ} + (hK : 0 < K) (hη : 0 ≤ η) (hδ : 0 ≤ δ) + (h : ∀ y ∈ s, max η (f y) ≤ max η (g y) + δ) : + max η (kthLargest K s f) ≤ max η (kthLargest K s g) + δ := by + have ht : 0 ≤ max η (kthLargest K s g) := hη.trans (le_max_left _ _) + refine max_le (by linarith [le_max_left η (kthLargest K s g)]) ?_ + by_contra hrank + have hc := (lt_kthLargest_iff hK (add_nonneg ht hδ)).mp (lt_of_not_ge hrank) + have hsub : ({y ∈ s | max η (kthLargest K s g) + δ < f y} : Finset ι) ⊆ + {y ∈ s | max η (kthLargest K s g) < g y} := by + intro y hy + obtain ⟨hys, hy⟩ := mem_filter.mp hy + refine mem_filter.mpr ⟨hys, ?_⟩ + have hmax : max η (kthLargest K s g) < max η (g y) := by + linarith [h y hys, le_max_right η (f y)] + exact (lt_max_iff.mp hmax).resolve_left (not_lt_of_ge (le_max_left _ _)) + have hg := (lt_kthLargest_iff hK ht).mpr (hc.trans (card_le_card hsub)) + exact (not_lt_of_ge (le_max_right _ _)) hg + +private theorem abs_clipped_firstRank_sub_le {K : ℕ} {z z' δ : ℝ} + {w w' : ι → Fin 2 → ℝ} (hK : 0 < K) (hη : 0 ≤ η) (hδ : 0 ≤ δ) + (hz : z ≤ η) (hz' : z' ≤ η) + (h : ∀ y ∈ s, |max η (w y 0) - max η (w' y 0)| ≤ δ) : + |max η (firstRank s K z w) - max η (firstRank s K z' w')| ≤ δ := by + simp only [firstRank, ← max_assoc, max_eq_left hz, max_eq_left hz'] + rw [abs_sub_le_iff] + constructor + · exact sub_le_iff_le_add'.mpr (max_rank_le_add_of_clipped hK hη hδ fun y hy => + sub_le_iff_le_add'.mp (le_of_abs_le (h y hy))) + · exact sub_le_iff_le_add'.mpr (max_rank_le_add_of_clipped hK hη hδ fun y hy => + sub_le_iff_le_add'.mp (le_of_abs_le ((abs_sub_comm _ _).trans_le (h y hy)))) + +private theorem output_eq_lowerClipped {H : ℝ → ℝ → ℝ → ℝ} (hη : 0 ≤ η) + (hentry : ∀ x v q, x ≤ η → H x v q = 0) + (hflat : ∀ x v q q', q ∈ Set.Icc 0 η → q' ∈ Set.Icc 0 η → H x v q = H x v q') + (x v q : ℝ) (hq : 0 ≤ q) : H x v q = H (max η x) v (max η q) := by + by_cases hx : x ≤ η + · rw [max_eq_left hx, hentry _ _ _ hx, hentry _ _ _ le_rfl] + rw [max_eq_right (not_le.mp hx).le] + by_cases hqη : q ≤ η + · rw [max_eq_left hqη] + exact hflat x v q η ⟨hq, hqη⟩ ⟨hη, le_rfl⟩ + rw [max_eq_right (not_le.mp hqη).le] + +/-- A weighted discrepancy bound between the constructed stationary reference and truth. + +`ε i` bounds the clipped errors of the actual uncompressed prefix at endpoints with true first +coordinate at least `η / 2`. +The scalar root output is assumed Lipschitz on the clipped first-coordinate and rank region; +this is a regularity hypothesis about `H`, independent of the compression calculation. +Targets below `η / 2` remain below entry support by the proved uniform loss bound. Their +possibly larger relative errors therefore do not enter the weighted rank comparison. + +This theorem supplies the comparison at the start of the stationary calculation. Combined with +`stationaryContinuation_output_eq_dyadic`, it gives the same bound after its remaining updates. +Verifying these scalar laws for particular row functions is a separate obligation. -/ +theorem abs_stationaryState_root_sub_le_weighted_dyadic {K : ℕ} + {H : ℝ → ℝ → ℝ → ℝ} {p C : ℝ} {ε : ℕ → ℝ} + (hη : 0 < η) (hK : 0 < K) (hC : 0 ≤ C) + (ha : 0 ≤ a.defaultValue) (haη : a.defaultValue ≤ η / 2) + (m j : ℕ) (hj : j ≤ m) + (hno : ∀ i < j, + stepThreshold s n (fun _ => K) (dyadicFloor η m) Δ a i ≤ dyadicFloor η m i) + (hε : ∀ i < j, 0 ≤ ε i) + (herr : ∀ i < j, ∀ y ∈ s, η / 2 ≤ truth y 0 → + clippedError (truth y 0) (truth y 1) (uncompressedRow Δ a.row (i + 1) y) ≤ ε i) + (hentry : ∀ x v q, x ≤ η → H x v q = 0) + (hflat : ∀ x v q q', q ∈ Set.Icc 0 η → q' ∈ Set.Icc 0 η → H x v q = H x v q') + (hroot : ∀ x v q x' v' q', η ≤ x → η ≤ x' → η ≤ q → η ≤ q' → + |H x v q ^ p - H x' v' q' ^ p| ≤ + C * (|x - x'| + |v - v'| + |q - q'|)) (y : ι) (hy : y ∈ s) : + let b := stationaryState s n (fun _ => K) (dyadicFloor η m) Δ a truth j + |H (b.row y 0) (b.row y 1) (firstRank s K b.defaultValue b.row) ^ p - + H (truth y 0) (truth y 1) (firstRank s K 0 truth) ^ p| ≤ + 3 * C * ((12 * (1 + η / 2) / (η / 2)) * ∑ i ∈ range j, dyadicFloor η m i * ε i) := by + let b := stationaryState s n (fun _ => K) (dyadicFloor η m) Δ a truth j + let B := (12 * (1 + η / 2) / (η / 2)) * ∑ i ∈ range j, dyadicFloor η m i * ε i + change |H (b.row y 0) (b.row y 1) (firstRank s K b.defaultValue b.row) ^ p - + H (truth y 0) (truth y 1) (firstRank s K 0 truth) ^ p| ≤ 3 * C * B + have hcoef : 0 ≤ 12 * (1 + η / 2) / (η / 2) := by positivity + have hB : 0 ≤ B := mul_nonneg hcoef (sum_nonneg fun i hi => + mul_nonneg (dyadicFloor_nonneg hη.le m i) (hε i (mem_range.mp hi))) + have huniform (y : ι) (ν : Fin 2) : |b.row y ν - truth y ν| ≤ η / 100 := + abs_stationaryState_row_sub_le_dyadic hη.le m j hj hno y ν + have hweighted (y : ι) (hy : y ∈ s) (hd : η / 2 ≤ truth y 0) (ν : Fin 2) : + |b.row y ν - truth y ν| ≤ B := by + refine (abs_stationaryState_row_sub_le_weighted_dyadic hη m j hj hno y hd ν).trans ?_ + exact mul_le_mul_of_nonneg_left (sum_le_sum fun i hi => + mul_le_mul_of_nonneg_left (herr i (mem_range.mp hi) y hy hd) + (dyadicFloor_nonneg hη.le m i)) hcoef + have hlow (y : ι) (hy : truth y 0 < η / 2) : b.row y 0 ≤ η ∧ truth y 0 ≤ η := by + have h := le_of_abs_le (huniform y 0) + constructor <;> linarith + have hclipped (y : ι) (hy : y ∈ s) : |max η (b.row y 0) - max η (truth y 0)| ≤ B := by + by_cases hd : η / 2 ≤ truth y 0 + · exact (abs_max_sub_max_le_max _ _ _ _).trans + (max_le (by simpa using hB) (hweighted y hy hd 0)) + · have hl := hlow y (not_le.mp hd) + simpa only [max_eq_left hl.1, max_eq_left hl.2, sub_self, abs_zero] using hB + have hrank : |max η (firstRank s K b.defaultValue b.row) - + max η (firstRank s K 0 truth)| ≤ B := + abs_clipped_firstRank_sub_le hK hη.le hB + (stationaryState_defaultValue_le_dyadic hη.le ha haη m j hj hno) hη.le hclipped + by_cases hd : η / 2 ≤ truth y 0 + · rw [output_eq_lowerClipped hη.le hentry hflat _ _ _ firstRank_nonneg, + output_eq_lowerClipped hη.le hentry hflat _ _ _ firstRank_nonneg] + calc _ ≤ C * (|max η (b.row y 0) - max η (truth y 0)| + |b.row y 1 - truth y 1| + + |max η (firstRank s K b.defaultValue b.row) - max η (firstRank s K 0 truth)|) := + hroot _ _ _ _ _ _ (le_max_left _ _) (le_max_left _ _) (le_max_left _ _) (le_max_left _ _) + _ ≤ C * (B + B + B) := mul_le_mul_of_nonneg_left + (add_le_add (add_le_add (hclipped y hy) (hweighted y hy hd 1)) hrank) hC + _ = 3 * C * B := by ring + · have hl := hlow y (not_le.mp hd) + rw [hentry _ _ _ hl.1, hentry _ _ _ hl.2, sub_self, abs_zero] + positivity + +end Cslib.RowCompression diff --git a/ComplexityTests/RowCompressionStationary.lean b/ComplexityTests/RowCompressionStationary.lean new file mode 100644 index 0000000000..71a159bfac --- /dev/null +++ b/ComplexityTests/RowCompressionStationary.lean @@ -0,0 +1,330 @@ +/- +Copyright (c) 2026 Samuel Schlesinger. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Samuel Schlesinger +-/ + +import Complexity.Foundations.Analysis.RowCompression.Stationary +import Mathlib.Algebra.Order.Group.MinMax +import Mathlib.LinearAlgebra.Matrix.Notation +import Mathlib.Tactic.FinCases +import Mathlib.Tactic.Linarith +import Mathlib.Tactic.NormNum +import Mathlib.Tactic.Ring + +/-! +# Constructed stationary-reference examples + +The first of two dyadic groups has a nonzero increment and actual nonzero compression loss. +The reference adds that loss to a different true row and retains the actual current default. +The remaining group preserves a nonzero gated output. A fourth-power ramp exhibits a strictly +positive fourth-root discrepancy and satisfies the weighted comparison theorem's scalar laws. +-/ + +namespace ComplexityTests.RowCompressionStationary + +open Finset Cslib.RowCompression + +private def initial : State (Fin 2) := { defaultValue := 0, row := ![![20, 0], ![0, 0]] } + +private def truth : Fin 2 → Fin 2 → ℝ := ![![20, 0], ![2, 0]] + +private noncomputable def increments (i : ℕ) : Fin 2 → Fin 2 → ℝ := + if i = 0 then ![![0, 0], ![1 / 2097152, 0]] else 0 + +private noncomputable def rawRow : Fin 2 → Fin 2 → ℝ := ![![20, 0], ![1 / 2097152, 0]] + +private theorem floor_zero : dyadicFloor 1 2 0 = 1 / 1048576 := by + norm_num [dyadicFloor, dyadicSlack] + +private theorem raw_rank_le : kthLargest 2 univ (fun y => rawRow y 0) ≤ 1 / 1048576 := by + refine not_lt.mp fun hlt => ?_ + have hcard := (lt_kthLargest_iff (by norm_num) + (by norm_num : (0 : ℝ) ≤ 1 / 1048576)).mp hlt + have hsupport : ({y | (1 / 1048576 : ℝ) < rawRow y 0} : Finset (Fin 2)) = {0} := by + ext y + fin_cases y <;> norm_num [rawRow] + rw [hsupport] at hcard + norm_num at hcard + +private theorem raw_threshold : threshold univ 2 (1 / 1048576) 0 rawRow = 1 / 1048576 := by + have hs : (fun y => entrySize (rawRow y)) = fun y => rawRow y 0 := by + funext y + fin_cases y <;> norm_num [entrySize, rawRow] + refine le_antisymm ?_ floor_le_threshold + unfold threshold + rw [hs] + exact max_le (by norm_num) (max_le le_rfl raw_rank_le) + +private theorem raw_default : newDefault univ 2 2 (1 / 1048576) 0 rawRow = 1 / 1048576 := by + unfold newDefault + rw [raw_threshold] + exact max_eq_left ((min_le_left _ _).trans (max_le (by norm_num) raw_rank_le)) + +private theorem raw_one : uncompressedRow increments initial.row 1 = rawRow := by + funext y ν + fin_cases y <;> fin_cases ν <;> norm_num [uncompressedRow, initial, increments, rawRow] + +private theorem actual_one : + iterate univ (fun _ => 2) (fun _ => 2) (dyadicFloor 1 2) increments initial 1 = + { defaultValue := 1 / 1048576, row := ![![20, 0], ![1 / 1048576, 0]] } := by + have hin : initial.row + increments 0 = rawRow := by + funext y ν + fin_cases y <;> fin_cases ν <;> norm_num [initial, increments, rawRow] + change advance univ 2 2 (dyadicFloor 1 2 0) (increments 0) initial = _ + unfold advance + rw [hin, floor_zero] + change State.mk (newDefault univ 2 2 (1 / 1048576) 0 rawRow) + (update univ 2 2 (1 / 1048576) 0 rawRow) = _ + rw [raw_default] + congr 1 + unfold update + rw [raw_threshold, raw_default] + funext y ν + fin_cases y <;> fin_cases ν <;> + norm_num [updateEntry, radius, entrySize, defaultEntry, rawRow] + +private theorem no_overflow : ∀ i < 1, + stepThreshold univ (fun _ => 2) (fun _ => 2) (dyadicFloor 1 2) increments initial i ≤ + dyadicFloor 1 2 i := by + intro i hi + have hi0 : i = 0 := by omega + subst i + have hin : inputRow univ (fun _ => 2) (fun _ => 2) (dyadicFloor 1 2) increments initial 0 = + rawRow := by + funext y ν + fin_cases y <;> fin_cases ν <;> norm_num [inputRow, initial, increments, rawRow] + unfold stepThreshold + rw [hin, iterate_zero, floor_zero] + exact raw_threshold.le + +private noncomputable def reference : State (Fin 2) := + stationaryState univ (fun _ => 2) (fun _ => 2) (dyadicFloor 1 2) increments initial truth 1 + +private theorem reference_eq : reference = + { defaultValue := 1 / 1048576, row := ![![20, 0], ![2 + 1 / 2097152, 0]] } := by + unfold reference stationaryState + rw [actual_one, raw_one] + congr 1 + funext y ν + fin_cases y <;> fin_cases ν <;> norm_num [truth, rawRow] + +-- The state is constructed from a nonzero increment and a strictly positive actual preloss. +example : increments 0 1 0 = 1 / 2097152 ∧ + reference.row 1 0 - truth 1 0 = 1 / 2097152 ∧ + reference.defaultValue = + (iterate univ (fun _ => 2) (fun _ => 2) (dyadicFloor 1 2) + increments initial 1).defaultValue := by + rw [reference_eq, actual_one] + norm_num [increments, truth] + +private theorem reference_rank : firstRank univ 2 reference.defaultValue reference.row = + 2 + 1 / 2097152 := by + have hle : kthLargest 2 univ (fun y => reference.row y 0) ≤ 2 + 1 / 2097152 := by + refine not_lt.mp fun hlt => ?_ + have hc := (lt_kthLargest_iff (by norm_num) + (by norm_num : (0 : ℝ) ≤ 2 + 1 / 2097152)).mp hlt + have hs : ({y | (2 + 1 / 2097152 : ℝ) < reference.row y 0} : Finset (Fin 2)) = {0} := by + ext y + rw [reference_eq] + fin_cases y <;> norm_num + rw [hs] at hc + norm_num at hc + have hge : (2 + 1 / 2097152 : ℝ) ≤ kthLargest 2 univ (fun y => reference.row y 0) := by + apply (le_kthLargest_iff (by norm_num) (by norm_num : (0 : ℝ) < 2 + 1 / 2097152)).mpr + have hs : ({y | (2 + 1 / 2097152 : ℝ) ≤ reference.row y 0} : Finset (Fin 2)) = univ := by + ext y + rw [reference_eq] + fin_cases y <;> norm_num + rw [hs] + norm_num + exact le_antisymm (max_le (by rw [reference_eq]; norm_num) hle) + (hge.trans kthLargest_le_firstRank) + +private noncomputable def gatedOutput (x v r : ℝ) : ℝ := + if x ≤ 10 then 0 else if 3 ≤ r then 0 else x + v + max 1 r + +private theorem gate_flat (x v q r : ℝ) (hq : q ∈ Set.Icc 0 (1 : ℝ)) + (hr : r ∈ Set.Icc 0 (1 : ℝ)) : gatedOutput x v q = gatedOutput x v r := by + have hq' : ¬3 ≤ q := by linarith [hq.2] + have hr' : ¬3 ≤ r := by linarith [hr.2] + simp only [gatedOutput, hq', hr', ↓reduceIte, max_eq_left hq.2, max_eq_left hr.2] + +-- The actual remaining schedule preserves a nonzero output of the constructed reference. +example : + let c := stationaryContinuation univ (fun _ => 2) 2 (dyadicFloor 1 2) + increments initial truth 1 1 + gatedOutput (c.row 0 0) (c.row 0 1) (firstRank univ 2 c.defaultValue c.row) = + 22 + 1 / 2097152 := by + have h := stationaryContinuation_output_eq_dyadic (s := univ) (n := fun _ => 2) (K := 2) + (Δ := increments) (a := initial) (truth := truth) (η := 1) (H := gatedOutput) + (g := 3) (e := 10) (by norm_num) (by norm_num) 2 1 1 (by norm_num) no_overflow + (fun y _ => by fin_cases y <;> norm_num [truth]) + (fun y _ => by fin_cases y <;> norm_num [truth]) (by intros; norm_num) + (by norm_num) (by norm_num) (fun _ _ _ hx => by simp [gatedOutput, hx]) + (fun _ _ _ hr => by simp [gatedOutput, hr]) gate_flat 0 (mem_univ 0) + refine h.trans ?_ + change gatedOutput (reference.row 0 0) (reference.row 0 1) + (firstRank univ 2 reference.defaultValue reference.row) = _ + rw [reference_rank, reference_eq] + norm_num [gatedOutput] + +private noncomputable def fourthPowerRamp (x _v _r : ℝ) : ℝ := (max 0 (x - 1)) ^ 4 + +private theorem ramp_root (x v r : ℝ) : + fourthPowerRamp x v r ^ (4⁻¹ : ℝ) = max 0 (x - 1) := by + exact Real.pow_rpow_inv_natCast (le_max_left _ _) (by norm_num : (4 : ℕ) ≠ 0) + +private theorem ramp_root_lipschitz (x v q x' v' q' : ℝ) : + |fourthPowerRamp x v q ^ (4⁻¹ : ℝ) - fourthPowerRamp x' v' q' ^ (4⁻¹ : ℝ)| ≤ + 1 * (|x - x'| + |v - v'| + |q - q'|) := by + rw [ramp_root, ramp_root] + have hm := abs_max_sub_max_le_max (0 : ℝ) (x - 1) 0 (x' - 1) + have he : (x - 1) - (x' - 1) = x - x' := by ring + simp only [sub_self, abs_zero, he, max_eq_right (abs_nonneg (x - x'))] at hm + linarith [abs_nonneg (v - v'), abs_nonneg (q - q')] + +-- The root discrepancy really is positive, rather than an equality between identical rows. +example : + |fourthPowerRamp (reference.row 1 0) (reference.row 1 1) + (firstRank univ 2 reference.defaultValue reference.row) ^ (4⁻¹ : ℝ) - + fourthPowerRamp (truth 1 0) (truth 1 1) (firstRank univ 2 0 truth) ^ (4⁻¹ : ℝ)| = + 1 / 2097152 := by + rw [ramp_root, ramp_root, reference_eq] + norm_num [truth] + +-- A constant-one raw-prefix envelope is valid, and the theorem gives a concrete finite bound. +example : + |fourthPowerRamp (reference.row 1 0) (reference.row 1 1) + (firstRank univ 2 reference.defaultValue reference.row) ^ (4⁻¹ : ℝ) - + fourthPowerRamp (truth 1 0) (truth 1 1) (firstRank univ 2 0 truth) ^ (4⁻¹ : ℝ)| ≤ + 27 / 262144 := by + have h := abs_stationaryState_root_sub_le_weighted_dyadic (s := univ) (n := fun _ => 2) + (K := 2) (Δ := increments) (a := initial) (truth := truth) (η := 1) + (H := fourthPowerRamp) (p := (4⁻¹ : ℝ)) (C := 1) (ε := fun _ => 1) + (by norm_num) (by norm_num) (by norm_num) (by norm_num [initial]) (by norm_num [initial]) + 2 1 (by norm_num) no_overflow (by intros; norm_num) + (fun _ _ _ _ _ => clippedError_le_one _ _ _) + (fun x _ _ hx => by simp [fourthPowerRamp, max_eq_left (by linarith : x - 1 ≤ 0)]) + (by intros; rfl) (fun x v q x' v' q' _ _ _ _ => ramp_root_lipschitz x v q x' v' q') + 1 (mem_univ 1) + norm_num [sum_range_succ, floor_zero] at h ⊢ + exact h + +/-! The sensitivity clipping also handles low targets without charging their prefix errors. -/ + +private noncomputable def unitCutoff (x : ℝ) : ℝ := min 1 (max 0 (x - 1)) + +private theorem cutoff_nonneg (x : ℝ) : 0 ≤ unitCutoff x := + le_min zero_le_one (le_max_left _ _) + +private theorem cutoff_le_one (x : ℝ) : unitCutoff x ≤ 1 := min_le_left _ _ + +private theorem cutoff_zero {x : ℝ} (hx : x ≤ 1) : unitCutoff x = 0 := by + simp [unitCutoff, max_eq_left (by linarith : x - 1 ≤ 0)] + +private theorem cutoff_lipschitz (x x' : ℝ) : |unitCutoff x - unitCutoff x'| ≤ |x - x'| := by + have hmax := abs_max_sub_max_le_max (0 : ℝ) (x - 1) 0 (x' - 1) + have he : (x - 1) - (x' - 1) = x - x' := by ring + simp only [sub_self, abs_zero, he, max_eq_right (abs_nonneg (x - x'))] at hmax + have hmin := abs_min_sub_min_le_max (1 : ℝ) (max 0 (x - 1)) 1 (max 0 (x' - 1)) + simp only [sub_self, abs_zero, + max_eq_right (abs_nonneg (max 0 (x - 1) - max 0 (x' - 1)))] at hmin + exact hmin.trans hmax + +private noncomputable def rankOutput (x _v r : ℝ) : ℝ := + (unitCutoff x * (1 + unitCutoff r)) ^ 4 + +private theorem rank_output_root (x v r : ℝ) : + rankOutput x v r ^ (4⁻¹ : ℝ) = unitCutoff x * (1 + unitCutoff r) := by + exact Real.pow_rpow_inv_natCast + (mul_nonneg (cutoff_nonneg x) (add_nonneg zero_le_one (cutoff_nonneg r))) + (by norm_num : (4 : ℕ) ≠ 0) + +private theorem rank_output_lipschitz (x v q x' v' q' : ℝ) : + |rankOutput x v q ^ (4⁻¹ : ℝ) - rankOutput x' v' q' ^ (4⁻¹ : ℝ)| ≤ + 2 * (|x - x'| + |v - v'| + |q - q'|) := by + rw [rank_output_root, rank_output_root] + have hp : 0 ≤ 1 + unitCutoff q' := add_nonneg zero_le_one (cutoff_nonneg q') + have he : unitCutoff x * (1 + unitCutoff q) - unitCutoff x' * (1 + unitCutoff q') = + unitCutoff x * (unitCutoff q - unitCutoff q') + + (unitCutoff x - unitCutoff x') * (1 + unitCutoff q') := by ring + calc + _ ≤ |unitCutoff x * (unitCutoff q - unitCutoff q')| + + |(unitCutoff x - unitCutoff x') * (1 + unitCutoff q')| := by + rw [he] + exact abs_add_le _ _ + _ = unitCutoff x * |unitCutoff q - unitCutoff q'| + + |unitCutoff x - unitCutoff x'| * (1 + unitCutoff q') := by + rw [abs_mul, abs_mul, abs_of_nonneg (cutoff_nonneg x), abs_of_nonneg hp] + _ ≤ 1 * |q - q'| + |x - x'| * 2 := add_le_add + (mul_le_mul (cutoff_le_one x) (cutoff_lipschitz q q') (abs_nonneg _) zero_le_one) + (mul_le_mul (cutoff_lipschitz x x') (by linarith [cutoff_le_one q']) hp (abs_nonneg _)) + _ ≤ 2 * (|x - x'| + |v - v'| + |q - q'|) := by + linarith [abs_nonneg (q - q'), abs_nonneg (v - v')] + +-- This output is rank-flat on [0,1], but it really depends on ranks above that interval. +example : rankOutput 20 0 0 = 1 ∧ rankOutput 20 0 2 = 16 := by + norm_num [rankOutput, unitCutoff] + +private noncomputable def lowReference : State (Fin 2) := + stationaryState univ (fun _ => 2) (fun _ => 2) (dyadicFloor 1 2) + increments initial initial.row 1 + +private theorem low_reference_eq : lowReference = + { defaultValue := 1 / 1048576, row := rawRow } := by + unfold lowReference stationaryState + rw [actual_one, raw_one] + congr 1 + funext y ν + fin_cases y <;> fin_cases ν <;> norm_num [initial, rawRow] + +private theorem low_reference_rank : firstRank univ 2 lowReference.defaultValue lowReference.row = + 1 / 1048576 := by + rw [low_reference_eq] + exact max_eq_left raw_rank_le + +private theorem true_rank_zero : firstRank univ 2 0 initial.row = 0 := by + norm_num [firstRank, kthLargest, initial, Fin.univ_succ, filter_insert, filter_singleton] + +-- The low true target receives nonzero preloss and raises the padded rank within [0,eta]. +example : lowReference.row 1 0 - initial.row 1 0 = 1 / 2097152 ∧ + firstRank univ 2 0 initial.row = 0 ∧ + 0 < firstRank univ 2 lowReference.defaultValue lowReference.row ∧ + firstRank univ 2 lowReference.defaultValue lowReference.row ≤ 1 := by + rw [low_reference_rank, true_rank_zero, low_reference_eq] + norm_num [initial, rawRow] + +-- Zero prefix error at every sensitive target suffices despite nonzero error at the low target. +-- The rank-dependent fourth root at the high endpoint remains exactly one. +example : rankOutput (lowReference.row 0 0) (lowReference.row 0 1) + (firstRank univ 2 lowReference.defaultValue lowReference.row) ^ (4⁻¹ : ℝ) = 1 := by + have herr : ∀ i < 1, ∀ y ∈ (univ : Finset (Fin 2)), (1 : ℝ) / 2 ≤ initial.row y 0 → + clippedError (initial.row y 0) (initial.row y 1) + (uncompressedRow increments initial.row (i + 1) y) ≤ 0 := by + intro i hi y _ hd + have hi0 : i = 0 := by omega + subst i + rw [raw_one] + fin_cases y + · norm_num [clippedError, initial, rawRow] + · norm_num [initial] at hd + have h := abs_stationaryState_root_sub_le_weighted_dyadic (s := univ) (n := fun _ => 2) + (K := 2) (Δ := increments) (a := initial) (truth := initial.row) (η := 1) + (H := rankOutput) (p := (4⁻¹ : ℝ)) (C := 2) (ε := fun _ => 0) + (by norm_num) (by norm_num) (by norm_num) (by norm_num [initial]) (by norm_num [initial]) + 2 1 (by norm_num) no_overflow (by intros; norm_num) herr + (fun x _ _ hx => by simp [rankOutput, cutoff_zero hx]) + (fun _ _ _ _ hq hr => by simp only [rankOutput, cutoff_zero hq.2, cutoff_zero hr.2]) + (fun x v q x' v' q' _ _ _ _ => rank_output_lipschitz x v q x' v' q') 0 (mem_univ 0) + have heq : rankOutput (lowReference.row 0 0) (lowReference.row 0 1) + (firstRank univ 2 lowReference.defaultValue lowReference.row) ^ (4⁻¹ : ℝ) = + rankOutput (initial.row 0 0) (initial.row 0 1) + (firstRank univ 2 0 initial.row) ^ (4⁻¹ : ℝ) := by + simp only [mul_zero, sum_const_zero] at h + apply sub_eq_zero.mp + exact abs_eq_zero.mp (le_antisymm h (abs_nonneg _)) + rw [heq, rank_output_root, true_rank_zero] + norm_num [initial, unitCutoff] + +end ComplexityTests.RowCompressionStationary From d885c30f31306ac55c232f9811c3d240f4525d2a Mon Sep 17 00:00:00 2001 From: Samuel Schlesinger Date: Fri, 30 Oct 2026 16:30:11 +0000 Subject: [PATCH 11/19] feat(probability): construct polynomial atom cutoffs and row laws Define actual rational polynomial preparation, row-gate, auxiliary-score and broad-witness functions. Prove their range and closed threshold laws, flat rank regions, incoming-score compatibility, joint Lipschitz fourth roots, and exact rational-cast identities. Preserve the existing exponential AtomCutoffs API and Christian Reitwiessner's source credit. This is the fourth-moment adaptation for #1721 of the threshold template in OpenAI2026LogSpace (5.5), and the witness in the support-margin proof and compression-threshold table of Section 5.5, revision 7ef5c0cc. The source uses eighth roots; these degree-seven cutoffs only establish fourth-root regularity. The actual functions are proved regular, rather than an assumed regularity bundle. Normalized main outputs, access enumeration and machine-resource bounds remain separate. Validation: the new module and full focused test file compile without diagnostics with Lean 4.36.0-rc2 and repository strict options, using private outputs and read-only dependencies. Executable rational tests evaluate all three row functions to 1/4 with both switches in their transition regions. Further tests check signed inputs, closed endpoints and the witness's strict 82 > 3*27 margin, real/rational agreement, nonzero existing atomPrep and auxScore expressions on a concrete matrix, and nonconstant fourth-root variation. Focused --check-simp hygiene and staged diff checking pass. Independent review and full integration gates remain pending; aggregate regeneration belongs to the coordinator. AI assistance: implemented by worker /root/compression_review on feat/logspace-polynomial-atom-cutoffs, based on the reviewed hierarchy lane. The Stationary specialization will be a separate cross-lane change. Independent non-author source/API review by lean_environment approved exact source revision a4eae07bdd9993e038a83aea84cc3c4b31c794d9 against pinned atoms.tex, with no findings. Reviewed source files are unchanged. Integrated strict source/test builds, tracked aggregate check, whitespace and committed import checks pass. Full integration gates run in PR CI. --- Complexity.lean | 1 + .../Probability/PolynomialAtomCutoffs.lean | 294 ++++++++++++++++++ ComplexityTests/PolynomialAtomCutoffs.lean | 88 ++++++ 3 files changed, 383 insertions(+) create mode 100644 Complexity/Foundations/Probability/PolynomialAtomCutoffs.lean create mode 100644 ComplexityTests/PolynomialAtomCutoffs.lean diff --git a/Complexity.lean b/Complexity.lean index 2fe378be1b..9736efc521 100644 --- a/Complexity.lean +++ b/Complexity.lean @@ -2734,6 +2734,7 @@ public import Complexity.Foundations.Probability.Gaussian.Multivariate public import Complexity.Foundations.Probability.Gaussian.Real public import Complexity.Foundations.Probability.Gaussian.Sheppard public import Complexity.Foundations.Probability.HierarchyParams +public import Complexity.Foundations.Probability.PolynomialAtomCutoffs public import Complexity.Foundations.Probability.RootMetric public import Complexity.Foundations.Probability.SecondMoment public import Complexity.Foundations.Probability.StochasticAtom diff --git a/Complexity/Foundations/Probability/PolynomialAtomCutoffs.lean b/Complexity/Foundations/Probability/PolynomialAtomCutoffs.lean new file mode 100644 index 0000000000..52858c0ed9 --- /dev/null +++ b/Complexity/Foundations/Probability/PolynomialAtomCutoffs.lean @@ -0,0 +1,294 @@ +/- +Copyright (c) 2026 Christian Reitwiessner, Samuel Schlesinger. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Christian Reitwiessner, Samuel Schlesinger +-/ + +module +-- upstream: candidate + +public import Complexity.Foundations.Analysis.SpecialFunctions.PolynomialSwitch +import Mathlib.Tactic.Linarith +import Mathlib.Tactic.Positivity +import Mathlib.Tactic.Ring + +/-! +# Polynomial preparation, score, and witness cutoffs + +These are concrete polynomial versions of the atom threshold template in +[OpenAI2026LogSpace, (5.5)] and the broad witness in the proof of its support-margin lemma. +For a fixed support scale `θ > 0`, they define the preparation `hθ(v) Rθ(r)`, auxiliary score +`Iθ(v,r)`, and witness `Jθ(v,r)`. They take values in `[0,1]`, have globally Lipschitz fourth +roots jointly in the entry and rank, and use rational arithmetic when their inputs are rational. + +Their entry-zero and rank-closure thresholds `(e,g)` are respectively +`(θ/2, θ/500)`, `(θ/8, θ/50)`, and `(82θ/1000, 27θ/1000)`. Each has `3g < e`, including the +witness's strict margin `θ/1000`. All rank factors are one near zero. These are scalar laws for +the concrete row functions, suitable for the stationary-reference compression comparison. +The first argument is the full raw entry and the second is the prescribed full-row rank; +only function evaluation applies the switches' scalar clipping. + +This is the fourth-moment adaptation in complexitylib issue #1721. The pinned preprint uses +eighth roots. These polynomial cutoffs do not replace the existing exponential `AtomCutoffs` +API, which proves regularity for every positive power. Normalized main atom functions, access +enumeration, eighth-root regularity, and machine-resource bounds are separate obligations. + +## Main definitions + +* `Cslib.polynomialPrepCutoff4`, `Cslib.polynomialRowCutoff4`: the preparatory and row factors. +* `Cslib.polynomialPrepRow4`, `Cslib.polynomialAuxCutoff4`, `Cslib.polynomialWitnessCutoff4`: + the three concrete pre-incoming row functions. + +## Main results + +* The endpoint, rank-flatness, and range lemmas for each function. +* `Cslib.exists_abs_polynomialPrepRow4_root_sub_le`, + `Cslib.exists_abs_polynomialAuxCutoff4_root_sub_le`, + `Cslib.exists_abs_polynomialWitnessCutoff4_root_sub_le`: joint fourth-root bounds. +* The `*_ratCast` lemmas: exact compatibility with rational evaluation. + +## References + +* [OpenAI, *Exact Derandomization of Logarithmic Space: L = RL = BPL*][OpenAI2026LogSpace], + Section 5.1, (5.5), support-margin lemma and compression-threshold table in Section 5.5 + (23 September 2026, revision `7ef5c0cc`, not peer reviewed). +-/ + +public section + +namespace Cslib + +section Definitions + +variable {R : Type*} [Field R] [LinearOrder R] + +/-- The polynomial preparation factor with transition from `θ/2` to `3θ/4`. -/ +@[expose] def polynomialPrepCutoff4 (θ v : R) : R := + polynomialSwitch4 (θ / 2) (3 * θ / 4) v + +/-- The polynomial row gate, full through `θ/1000` and closed from `θ/500`. -/ +@[expose] def polynomialRowCutoff4 (θ r : R) : R := + 1 - polynomialSwitch4 (θ / 1000) (θ / 500) r + +/-- The actual unnormalized pre-incoming preparation `hθ(v) Rθ(r)`. -/ +@[expose] def polynomialPrepRow4 (θ v r : R) : R := + polynomialPrepCutoff4 θ v * polynomialRowCutoff4 θ r + +/-- The auxiliary score with the threshold intervals of [OpenAI2026LogSpace, (5.5)]. -/ +@[expose] def polynomialAuxCutoff4 (θ v r : R) : R := + polynomialSwitch4 (θ / 8) (θ / 4) v * + (1 - polynomialSwitch4 (θ / 100) (θ / 50) r) + +/-- The broad analytical witness `Jθ` of the support-margin lemma. Its support is not required +to have a further witness. -/ +@[expose] def polynomialWitnessCutoff4 (θ v r : R) : R := + polynomialSwitch4 (82 * θ / 1000) (90 * θ / 1000) v * + (1 - polynomialSwitch4 (26 * θ / 1000) (27 * θ / 1000) r) + +end Definitions + +variable {θ v r : ℝ} + +/-! ## Range and threshold laws -/ + +theorem polynomialPrepCutoff4_nonneg (θ v : ℝ) : 0 ≤ polynomialPrepCutoff4 θ v := + polynomialSwitch4_nonneg _ _ _ + +theorem polynomialPrepCutoff4_le_one (θ v : ℝ) : polynomialPrepCutoff4 θ v ≤ 1 := + polynomialSwitch4_le_one _ _ _ + +theorem polynomialPrepCutoff4_eq_zero (hθ : 0 < θ) (hv : v ≤ θ / 2) : + polynomialPrepCutoff4 θ v = 0 := polynomialSwitch4_of_le (by linarith) hv + +theorem polynomialPrepCutoff4_eq_one (hθ : 0 < θ) (hv : 3 * θ / 4 ≤ v) : + polynomialPrepCutoff4 θ v = 1 := polynomialSwitch4_of_ge (by linarith) hv + +theorem polynomialRowCutoff4_nonneg (θ r : ℝ) : 0 ≤ polynomialRowCutoff4 θ r := + sub_nonneg.mpr (polynomialSwitch4_le_one _ _ _) + +theorem polynomialRowCutoff4_le_one (θ r : ℝ) : polynomialRowCutoff4 θ r ≤ 1 := + sub_le_self _ (polynomialSwitch4_nonneg _ _ _) + +theorem polynomialRowCutoff4_eq_one (hθ : 0 < θ) (hr : r ≤ θ / 1000) : + polynomialRowCutoff4 θ r = 1 := by + rw [polynomialRowCutoff4, polynomialSwitch4_of_le (by linarith) hr, sub_zero] + +theorem polynomialRowCutoff4_eq_zero_iff (hθ : 0 < θ) : + polynomialRowCutoff4 θ r = 0 ↔ θ / 500 ≤ r := by + rw [polynomialRowCutoff4, sub_eq_zero, eq_comm, polynomialSwitch4_eq_one_iff (by linarith)] + +theorem polynomialRowCutoff4_eq_zero (hθ : 0 < θ) (hr : θ / 500 ≤ r) : + polynomialRowCutoff4 θ r = 0 := (polynomialRowCutoff4_eq_zero_iff hθ).mpr hr + +theorem polynomialPrepRow4_nonneg (θ v r : ℝ) : 0 ≤ polynomialPrepRow4 θ v r := + mul_nonneg (polynomialPrepCutoff4_nonneg _ _) (polynomialRowCutoff4_nonneg _ _) + +theorem polynomialPrepRow4_le_one (θ v r : ℝ) : polynomialPrepRow4 θ v r ≤ 1 := + (mul_le_of_le_one_right (polynomialPrepCutoff4_nonneg _ _) + (polynomialRowCutoff4_le_one _ _)).trans (polynomialPrepCutoff4_le_one _ _) + +theorem polynomialPrepRow4_eq_zero_of_entry_le (hθ : 0 < θ) (hv : v ≤ θ / 2) : + polynomialPrepRow4 θ v r = 0 := by + rw [polynomialPrepRow4, polynomialPrepCutoff4_eq_zero hθ hv, zero_mul] + +theorem polynomialPrepRow4_eq_zero_of_rank_ge (hθ : 0 < θ) (hr : θ / 500 ≤ r) : + polynomialPrepRow4 θ v r = 0 := by + rw [polynomialPrepRow4, polynomialRowCutoff4_eq_zero hθ hr, mul_zero] + +theorem polynomialPrepRow4_of_rank_le (hθ : 0 < θ) (hr : r ≤ θ / 1000) : + polynomialPrepRow4 θ v r = polynomialPrepCutoff4 θ v := by + rw [polynomialPrepRow4, polynomialRowCutoff4_eq_one hθ hr, mul_one] + +theorem polynomialAuxCutoff4_nonneg (θ v r : ℝ) : 0 ≤ polynomialAuxCutoff4 θ v r := + mul_nonneg (polynomialSwitch4_nonneg _ _ _) (sub_nonneg.mpr (polynomialSwitch4_le_one _ _ _)) + +theorem polynomialAuxCutoff4_le_one (θ v r : ℝ) : polynomialAuxCutoff4 θ v r ≤ 1 := + (mul_le_of_le_one_right (polynomialSwitch4_nonneg _ _ _) + (sub_le_self _ (polynomialSwitch4_nonneg _ _ _))).trans (polynomialSwitch4_le_one _ _ _) + +theorem polynomialAuxCutoff4_eq_zero_of_entry_le (hθ : 0 < θ) (hv : v ≤ θ / 8) : + polynomialAuxCutoff4 θ v r = 0 := by + rw [polynomialAuxCutoff4, polynomialSwitch4_of_le (by linarith) hv, zero_mul] + +theorem polynomialAuxCutoff4_eq_zero_of_rank_ge (hθ : 0 < θ) (hr : θ / 50 ≤ r) : + polynomialAuxCutoff4 θ v r = 0 := by + rw [polynomialAuxCutoff4, polynomialSwitch4_of_ge (by linarith) hr, sub_self, mul_zero] + +theorem polynomialAuxCutoff4_of_rank_le (hθ : 0 < θ) (hr : r ≤ θ / 100) : + polynomialAuxCutoff4 θ v r = polynomialSwitch4 (θ / 8) (θ / 4) v := by + rw [polynomialAuxCutoff4, polynomialSwitch4_of_le (by linarith) hr, sub_zero, mul_one] + +theorem polynomialAuxCutoff4_eq_one (hθ : 0 < θ) (hv : θ / 4 ≤ v) (hr : r ≤ θ / 100) : + polynomialAuxCutoff4 θ v r = 1 := by + rw [polynomialAuxCutoff4_of_rank_le hθ hr, polynomialSwitch4_of_ge (by linarith) hv] + +/-- On the support relevant to the incoming cap, the concrete auxiliary score is one. -/ +theorem polynomialAuxCutoff4_eq_one_of_rowCutoff_ne_zero (hθ : 0 < θ) (hv : θ / 4 ≤ v) + (hr : polynomialRowCutoff4 θ r ≠ 0) : polynomialAuxCutoff4 θ v r = 1 := by + have hsmall : r < θ / 500 := lt_of_not_ge fun h => hr (polynomialRowCutoff4_eq_zero hθ h) + exact polynomialAuxCutoff4_eq_one hθ hv (by linarith) + +theorem polynomialWitnessCutoff4_nonneg (θ v r : ℝ) : 0 ≤ polynomialWitnessCutoff4 θ v r := + mul_nonneg (polynomialSwitch4_nonneg _ _ _) (sub_nonneg.mpr (polynomialSwitch4_le_one _ _ _)) + +theorem polynomialWitnessCutoff4_le_one (θ v r : ℝ) : polynomialWitnessCutoff4 θ v r ≤ 1 := + (mul_le_of_le_one_right (polynomialSwitch4_nonneg _ _ _) + (sub_le_self _ (polynomialSwitch4_nonneg _ _ _))).trans (polynomialSwitch4_le_one _ _ _) + +theorem polynomialWitnessCutoff4_eq_zero_of_entry_le (hθ : 0 < θ) (hv : v ≤ 82 * θ / 1000) : + polynomialWitnessCutoff4 θ v r = 0 := by + rw [polynomialWitnessCutoff4, polynomialSwitch4_of_le (by linarith) hv, zero_mul] + +theorem polynomialWitnessCutoff4_eq_zero_of_rank_ge (hθ : 0 < θ) (hr : 27 * θ / 1000 ≤ r) : + polynomialWitnessCutoff4 θ v r = 0 := by + rw [polynomialWitnessCutoff4, polynomialSwitch4_of_ge (by linarith) hr, sub_self, mul_zero] + +theorem polynomialWitnessCutoff4_of_rank_le (hθ : 0 < θ) (hr : r ≤ 26 * θ / 1000) : + polynomialWitnessCutoff4 θ v r = polynomialSwitch4 (82 * θ / 1000) (90 * θ / 1000) v := by + rw [polynomialWitnessCutoff4, polynomialSwitch4_of_le (by linarith) hr, sub_zero, mul_one] + +theorem polynomialWitnessCutoff4_eq_one (hθ : 0 < θ) (hv : 90 * θ / 1000 ≤ v) + (hr : r ≤ 26 * θ / 1000) : polynomialWitnessCutoff4 θ v r = 1 := by + rw [polynomialWitnessCutoff4_of_rank_le hθ hr, polynomialSwitch4_of_ge (by linarith) hv] + +/-! ## Joint fourth-root regularity -/ + +private theorem exists_abs_switch_product_root_sub_le (α β γ δ : ℝ) : + ∃ C : ℝ, 0 ≤ C ∧ ∀ v r v' r', + |(polynomialSwitch4 α β v * (1 - polynomialSwitch4 γ δ r)) ^ (4⁻¹ : ℝ) - + (polynomialSwitch4 α β v' * (1 - polynomialSwitch4 γ δ r')) ^ (4⁻¹ : ℝ)| ≤ + C * (|v - v'| + |r - r'|) := by + obtain ⟨Ka, hKa⟩ := exists_lipschitzWith_polynomialSwitch4_root α β + obtain ⟨Kb, hKb⟩ := exists_lipschitzWith_one_sub_polynomialSwitch4_root γ δ + refine ⟨max (Ka : ℝ) Kb, le_max_of_le_left Ka.2, ?_⟩ + intro v r v' r' + set A : ℝ → ℝ := fun x => polynomialSwitch4 α β x ^ (4⁻¹ : ℝ) + set B : ℝ → ℝ := fun x => (1 - polynomialSwitch4 γ δ x) ^ (4⁻¹ : ℝ) + have ha0 (x : ℝ) : 0 ≤ A x := Real.rpow_nonneg (polynomialSwitch4_nonneg _ _ _) _ + have hb0 (x : ℝ) : 0 ≤ B x := + Real.rpow_nonneg (sub_nonneg.mpr (polynomialSwitch4_le_one _ _ _)) _ + have ha1 (x : ℝ) : A x ≤ 1 := + Real.rpow_le_one (polynomialSwitch4_nonneg _ _ _) (polynomialSwitch4_le_one _ _ _) + (by norm_num) + have hb1 (x : ℝ) : B x ≤ 1 := + Real.rpow_le_one (sub_nonneg.mpr (polynomialSwitch4_le_one _ _ _)) + (sub_le_self _ (polynomialSwitch4_nonneg _ _ _)) (by norm_num) + have hda : |A v - A v'| ≤ Ka * |v - v'| := by + simpa only [Real.dist_eq] using hKa.dist_le_mul v v' + have hdb : |B r - B r'| ≤ Kb * |r - r'| := by + simpa only [Real.dist_eq] using hKb.dist_le_mul r r' + rw [Real.mul_rpow (polynomialSwitch4_nonneg _ _ _) + (sub_nonneg.mpr (polynomialSwitch4_le_one _ _ _)), + Real.mul_rpow (polynomialSwitch4_nonneg _ _ _) + (sub_nonneg.mpr (polynomialSwitch4_le_one _ _ _))] + change |A v * B r - A v' * B r'| ≤ _ + have hsplit : A v * B r - A v' * B r' = + (A v - A v') * B r + A v' * (B r - B r') := by ring + rw [hsplit] + calc + _ ≤ |A v - A v'| * B r + A v' * |B r - B r'| := by + refine (abs_add_le _ _).trans_eq ?_ + rw [abs_mul, abs_mul, abs_of_nonneg (hb0 r), abs_of_nonneg (ha0 v')] + _ ≤ |A v - A v'| + |B r - B r'| := by + exact add_le_add (mul_le_of_le_one_right (abs_nonneg _) (hb1 r)) + (mul_le_of_le_one_left (abs_nonneg _) (ha1 v')) + _ ≤ (Ka : ℝ) * |v - v'| + (Kb : ℝ) * |r - r'| := add_le_add hda hdb + _ ≤ max (Ka : ℝ) Kb * (|v - v'| + |r - r'|) := by + rw [mul_add] + exact add_le_add (mul_le_mul_of_nonneg_right (le_max_left _ _) (abs_nonneg _)) + (mul_le_mul_of_nonneg_right (le_max_right _ _) (abs_nonneg _)) + +/-- The actual preparatory row function has a globally Lipschitz fourth root. -/ +theorem exists_abs_polynomialPrepRow4_root_sub_le (θ : ℝ) : + ∃ C : ℝ, 0 ≤ C ∧ ∀ v r v' r', + |polynomialPrepRow4 θ v r ^ (4⁻¹ : ℝ) - polynomialPrepRow4 θ v' r' ^ (4⁻¹ : ℝ)| ≤ + C * (|v - v'| + |r - r'|) := + exists_abs_switch_product_root_sub_le _ _ _ _ + +/-- The actual auxiliary score has a globally Lipschitz fourth root. -/ +theorem exists_abs_polynomialAuxCutoff4_root_sub_le (θ : ℝ) : + ∃ C : ℝ, 0 ≤ C ∧ ∀ v r v' r', + |polynomialAuxCutoff4 θ v r ^ (4⁻¹ : ℝ) - polynomialAuxCutoff4 θ v' r' ^ (4⁻¹ : ℝ)| ≤ + C * (|v - v'| + |r - r'|) := + exists_abs_switch_product_root_sub_le _ _ _ _ + +/-- The broad witness also has a globally Lipschitz fourth root. -/ +theorem exists_abs_polynomialWitnessCutoff4_root_sub_le (θ : ℝ) : + ∃ C : ℝ, 0 ≤ C ∧ ∀ v r v' r', + |polynomialWitnessCutoff4 θ v r ^ (4⁻¹ : ℝ) - + polynomialWitnessCutoff4 θ v' r' ^ (4⁻¹ : ℝ)| ≤ C * (|v - v'| + |r - r'|) := + exists_abs_switch_product_root_sub_le _ _ _ _ + +/-! ## Exact rational evaluation -/ + +@[simp, norm_cast] +theorem polynomialPrepCutoff4_ratCast (θ v : ℚ) : + polynomialPrepCutoff4 (θ : ℝ) v = (polynomialPrepCutoff4 θ v : ℚ) := by + simp only [polynomialPrepCutoff4, ← polynomialSwitch4_ratCast, Rat.cast_div, Rat.cast_mul, + Rat.cast_ofNat] + +@[simp, norm_cast] +theorem polynomialRowCutoff4_ratCast (θ r : ℚ) : + polynomialRowCutoff4 (θ : ℝ) r = (polynomialRowCutoff4 θ r : ℚ) := by + simp only [polynomialRowCutoff4, Rat.cast_sub, Rat.cast_one, ← polynomialSwitch4_ratCast, + Rat.cast_div, Rat.cast_ofNat] + +@[simp, norm_cast] +theorem polynomialPrepRow4_ratCast (θ v r : ℚ) : + polynomialPrepRow4 (θ : ℝ) v r = (polynomialPrepRow4 θ v r : ℚ) := by + simp only [polynomialPrepRow4, polynomialPrepCutoff4_ratCast, polynomialRowCutoff4_ratCast, + Rat.cast_mul] + +@[simp, norm_cast] +theorem polynomialAuxCutoff4_ratCast (θ v r : ℚ) : + polynomialAuxCutoff4 (θ : ℝ) v r = (polynomialAuxCutoff4 θ v r : ℚ) := by + simp only [polynomialAuxCutoff4, Rat.cast_mul, Rat.cast_sub, Rat.cast_one, + ← polynomialSwitch4_ratCast, Rat.cast_div, Rat.cast_ofNat] + +@[simp, norm_cast] +theorem polynomialWitnessCutoff4_ratCast (θ v r : ℚ) : + polynomialWitnessCutoff4 (θ : ℝ) v r = (polynomialWitnessCutoff4 θ v r : ℚ) := by + simp only [polynomialWitnessCutoff4, Rat.cast_mul, Rat.cast_sub, Rat.cast_one, + ← polynomialSwitch4_ratCast, Rat.cast_div, Rat.cast_ofNat] + +end Cslib diff --git a/ComplexityTests/PolynomialAtomCutoffs.lean b/ComplexityTests/PolynomialAtomCutoffs.lean new file mode 100644 index 0000000000..917ce9d985 --- /dev/null +++ b/ComplexityTests/PolynomialAtomCutoffs.lean @@ -0,0 +1,88 @@ +/- +Copyright (c) 2026 Samuel Schlesinger. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Samuel Schlesinger +-/ + +import Complexity.Foundations.Probability.PolynomialAtomCutoffs +import Complexity.Foundations.Probability.CorrectionAtom +import Mathlib.LinearAlgebra.Matrix.Notation +import Mathlib.Tactic.Linarith +import Mathlib.Tactic.NormNum + +/-! +# Tests for polynomial atom cutoffs + +Both switches vary in each interior example, producing exact value `1/4`. The broad witness +retains its strict entry/rank margin at its closed endpoints. Concrete existing atom and score +expressions use the new polynomial factors, and the witness's fourth-root variation forces +its Lipschitz constant to be positive. +-/ + +namespace ComplexityTests.PolynomialAtomCutoffs + +open Cslib Finset Matrix + +-- All three functions execute with rational inputs, including both transition regions. +/-- info: true -/ +#guard_msgs in +#eval [polynomialPrepRow4 (8 : ℚ) 5 (3 / 250), + polynomialAuxCutoff4 (8 : ℚ) (3 / 2) (3 / 25), + polynomialWitnessCutoff4 (1000 : ℚ) 86 (53 / 2)] == [1 / 4, 1 / 4, 1 / 4] + +private theorem witness_quarter : polynomialWitnessCutoff4 (1000 : ℚ) 86 (53 / 2) = 1 / 4 := by + norm_num [polynomialWitnessCutoff4, polynomialSwitch4, polynomialTransition4, + transitionPolynomial4] + +-- Rational evaluation is exactly the real function used by the analytic theorems. +example : polynomialWitnessCutoff4 (1000 : ℝ) 86 (53 / 2) = 1 / 4 := by + have h := polynomialWitnessCutoff4_ratCast 1000 86 (53 / 2) + norm_num only [Rat.cast_ofNat, Rat.cast_div, witness_quarter] at h + exact h + +example : polynomialPrepRow4 (8 : ℝ) (-4) (-1) = 0 ∧ + polynomialAuxCutoff4 (8 : ℝ) (-4) (-1) = 0 ∧ + polynomialWitnessCutoff4 (1000 : ℝ) (-4) (-1) = 0 := by + exact ⟨polynomialPrepRow4_eq_zero_of_entry_le (by norm_num) (by norm_num), + polynomialAuxCutoff4_eq_zero_of_entry_le (by norm_num) (by norm_num), + polynomialWitnessCutoff4_eq_zero_of_entry_le (by norm_num) (by norm_num)⟩ + +-- The exact witness margin is 82 - 3*27 = 1; closure includes both boundary points. +example : (3 : ℝ) * 27 < 82 ∧ polynomialWitnessCutoff4 (1000 : ℝ) 82 0 = 0 ∧ + polynomialWitnessCutoff4 (1000 : ℝ) 90 27 = 0 ∧ + polynomialWitnessCutoff4 (1000 : ℝ) 90 26 = 1 := by + exact ⟨by norm_num, + polynomialWitnessCutoff4_eq_zero_of_entry_le (by norm_num) (by norm_num), + polynomialWitnessCutoff4_eq_zero_of_rank_ge (by norm_num) (by norm_num), + polynomialWitnessCutoff4_eq_one (by norm_num) (by norm_num) (by norm_num)⟩ + +private noncomputable def G : Matrix (Fin 2) (Fin 2) ℝ := !![0, 8; 0, 0] + +private theorem first_row_rank : kthLargest 2 univ (fun y => G 0 y / 1) = 0 := by + norm_num [kthLargest, G, Fin.univ_succ, filter_insert, filter_singleton] + +-- This is an actual atom preparation and actual auxiliary score, not separate scalar formulas. +example : atomPrep (polynomialPrepCutoff4 8) (polynomialRowCutoff4 8) 2 1 G univ 0 1 = 1 ∧ + auxScore (polynomialAuxCutoff4 8) 2 1 G univ 0 1 = 1 := by + constructor + · rw [atomPrep, rowGate, first_row_rank] + have hv : G 0 1 / 1 = 8 := by norm_num [G] + rw [hv, polynomialPrepCutoff4_eq_one (by norm_num) (by norm_num), + polynomialRowCutoff4_eq_one (by norm_num) (by norm_num), mul_one] + · rw [auxScore, first_row_rank] + have hv : G 0 1 / 1 = 8 := by norm_num [G] + rw [hv] + exact polynomialAuxCutoff4_eq_one (by norm_num) (by norm_num) (by norm_num) + +-- The analytic constant cannot be zero: the fourth root changes from zero to one over width 8. +example : ∃ C : ℝ, 1 / 8 ≤ C ∧ ∀ v r v' r', + |polynomialWitnessCutoff4 1000 v r ^ (4⁻¹ : ℝ) - + polynomialWitnessCutoff4 1000 v' r' ^ (4⁻¹ : ℝ)| ≤ C * (|v - v'| + |r - r'|) := by + obtain ⟨C, _, hC⟩ := exists_abs_polynomialWitnessCutoff4_root_sub_le 1000 + have h := hC 90 0 82 0 + rw [polynomialWitnessCutoff4_eq_one (by norm_num) (by norm_num) (by norm_num), + polynomialWitnessCutoff4_eq_zero_of_entry_le (by norm_num) (by norm_num)] at h + norm_num at h + exact ⟨C, by linarith, hC⟩ + +end ComplexityTests.PolynomialAtomCutoffs From 0cbb2f1bcf5bc00008e98352973a9f10462209a2 Mon Sep 17 00:00:00 2001 From: Samuel Schlesinger Date: Fri, 30 Oct 2026 16:47:13 +0000 Subject: [PATCH 12/19] feat(logspace): charge false overflows to actual prefix errors Prove uniqueness of the first-overflow index, a signed light-target error lower bound, the explicit 2^(p+1)/(n*rho^p) moment charge, and its specialization to the actual dyadic iterate with previous default and preloss bounds derived. Conditional heavy-count rarity, relative post-overflow stability and integrated compression remain open under #1721 and #1444. Strict isolated Lean compilation with warningAsError=true and empty diagnostics passed for the module and a signed two-group run with nonzero preloss. Focused hygiene and whitespace checks passed. AI-assisted implementation; independent review pending before publication. Independent non-author source/API review by lean_environment approved exact source revision e0066c8a1015c2270c0a9ffaec1a3209225b2ce3 against pinned compression.tex Section 8.4, with no findings. Reviewed source files are unchanged. Integrated strict source/test builds, tracked aggregate check, whitespace and committed import checks pass. Full integration gates run in PR CI. --- Complexity.lean | 1 + .../RowCompression/FalseOverflow.lean | 198 ++++++++++++++++++ .../RowCompressionFalseOverflow.lean | 113 ++++++++++ 3 files changed, 312 insertions(+) create mode 100644 Complexity/Foundations/Analysis/RowCompression/FalseOverflow.lean create mode 100644 ComplexityTests/RowCompressionFalseOverflow.lean diff --git a/Complexity.lean b/Complexity.lean index ee0aafd7a5..a11b5860a7 100644 --- a/Complexity.lean +++ b/Complexity.lean @@ -2352,6 +2352,7 @@ public import Complexity.Foundations.Analysis.LpNormMeasure public import Complexity.Foundations.Analysis.MarkovBrothersInequality public import Complexity.Foundations.Analysis.RootError public import Complexity.Foundations.Analysis.RowCompression +public import Complexity.Foundations.Analysis.RowCompression.FalseOverflow public import Complexity.Foundations.Analysis.RowCompression.Floors public import Complexity.Foundations.Analysis.RowCompression.Iteration public import Complexity.Foundations.Analysis.RowCompression.Preloss diff --git a/Complexity/Foundations/Analysis/RowCompression/FalseOverflow.lean b/Complexity/Foundations/Analysis/RowCompression/FalseOverflow.lean new file mode 100644 index 0000000000..35d292f0db --- /dev/null +++ b/Complexity/Foundations/Analysis/RowCompression/FalseOverflow.lean @@ -0,0 +1,198 @@ +/- +Copyright (c) 2026 Samuel Schlesinger. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Samuel Schlesinger +-/ + +module +-- upstream: candidate + +public import Complexity.Foundations.Analysis.RowCompression.Preloss +import Mathlib.Tactic.FieldSimp +import Mathlib.Tactic.Linarith +import Mathlib.Tactic.Positivity +import Mathlib.Tactic.Ring + +/-! +# Charging a first overflow to errors at light targets + +At the first group whose compression threshold exceeds its floor, sufficiently many real entries +exceed that floor: the preceding default is too small to cause the overflow. If fewer than half +as many true endpoints are heavy, at least half the overflowing entries are light. At each light +endpoint, a large input and small preceding compression loss force a large raw-prefix error. + +This module proves the deterministic counting and charging assertion of +[OpenAI2026LogSpace, Section 8.4, (8.12)]. For a floor `0 < ρ ≤ 1`, a true first coordinate in +`[0, ρ / 4]`, a zero true second coordinate, and preloss at most `ρ / 100`, an input of size +greater than `ρ` has clipped error at least `ρ / 2`. Thus a false-type overflow satisfies +`1 ≤ 2 ^ (p + 1) / (n * ρ ^ p) * ∑ y, error y ^ p`, for every natural moment exponent `p`. + +The final theorem applies this to the actual iterated compression with the explicit dyadic +floors and zero initial default. It derives the previous-default and preloss bounds from the +absence of earlier overflow. The error is taken from the uncompressed prefix at `j + 1`, not +from the compressed row. The first-overflow index is also proved unique. + +This is the pointwise false-overflow charge. Conditional rarity of true heavy counts, stability +after overflow, and the integrated compression theorem remain separate obligations. + +## Main results + +* `Cslib.RowCompression.IsFirstOverflow.unique`: first-overflow events are disjoint. +* `Cslib.RowCompression.half_floor_le_clippedError`: a large light entry forces raw-prefix error. +* `Cslib.RowCompression.one_le_sum_clippedError_pow_of_overflow`: the explicit moment charge. +* `Cslib.RowCompression.one_le_sum_clippedError_pow_of_firstOverflow_dyadic`: the charge for the + actual compression recursion, with numerical floor conditions discharged. + +## References + +* [OpenAI, *Exact Derandomization of Logarithmic Space: L = RL = BPL*][OpenAI2026LogSpace], + Section 8.4, equation labelled `buf-false-charge` + (23 September 2026, revision `7ef5c0cc`, not peer reviewed). +-/ + +public section + +namespace Cslib.RowCompression + +open Finset + +variable {ι : Type*} + +/-- Group `j` is the first whose actual threshold exceeds its prescribed floor. -/ +@[expose] def IsFirstOverflow (s : Finset ι) (n K : ℕ → ℕ) (ρ : ℕ → ℝ) + (Δ : ℕ → ι → Fin 2 → ℝ) (a : State ι) (j : ℕ) : Prop := + (∀ i < j, stepThreshold s n K ρ Δ a i ≤ ρ i) ∧ ρ j < stepThreshold s n K ρ Δ a j + +/-- A run cannot have two different first-overflow groups. -/ +theorem IsFirstOverflow.unique {s : Finset ι} {n K : ℕ → ℕ} {ρ : ℕ → ℝ} + {Δ : ℕ → ι → Fin 2 → ℝ} {a : State ι} {j k : ℕ} + (hj : IsFirstOverflow s n K ρ Δ a j) (hk : IsFirstOverflow s n K ρ Δ a k) : j = k := by + rcases lt_trichotomy j k with h | h | h + · exact False.elim (not_lt_of_ge (hk.1 j h) hj.2) + · exact h + · exact False.elim (not_lt_of_ge (hj.1 k h) hk.2) + +/-- A light true target cannot produce a large compression input without a large raw error. +Both input channels may have either sign. -/ +theorem half_floor_le_clippedError {ρ d v : ℝ} {w raw : Fin 2 → ℝ} + (hρ : 0 < ρ) (hρ1 : ρ ≤ 1) (hd : 0 ≤ d) (hdρ : d ≤ ρ / 4) (hv : v = 0) + (hprev : ∀ ν, |w ν - raw ν| ≤ ρ / 100) (hsize : ρ < entrySize w) : + ρ / 2 ≤ clippedError d v raw := by + have hsmall : ρ / 2 ≤ 1 := by linarith + rcases lt_max_iff.mp hsize with hfirst | hsecond + · have hraw : |w 0| ≤ ρ / 100 + (|raw 0 - d| + d) := by + calc + _ ≤ |w 0 - raw 0| + |raw 0| := by + simpa only [sub_zero] using abs_sub_le (w 0) (raw 0) 0 + _ ≤ ρ / 100 + (|raw 0 - d| + d) := by + apply add_le_add (hprev 0) + simpa only [sub_zero, abs_of_nonneg hd] using abs_sub_le (raw 0) d 0 + have hden : 0 < 1 + d := by linarith + have hrel : ρ / 2 ≤ |raw 0 - d| / (1 + d) := by + apply (le_div_iff₀ hden).2 + calc + _ ≤ (ρ / 2) * (5 / 4) := mul_le_mul_of_nonneg_left (by linarith) (by positivity) + _ ≤ _ := by linarith + exact (le_min hsmall hrel).trans (le_max_left _ _) + · have hraw : |w 1| ≤ ρ / 100 + |raw 1| := by + have h : |w 1| ≤ |w 1 - raw 1| + |raw 1| := by + simpa only [sub_zero] using abs_sub_le (w 1) (raw 1) 0 + exact h.trans (add_le_add (hprev 1) le_rfl) + have hrel : ρ / 2 ≤ |raw 1 - v| := by rw [hv, sub_zero]; linarith + exact (le_min hsmall hrel).trans (le_max_right _ _) + +/-- If the old default is below the floor, an overflow needs at least `n` real large entries. -/ +theorem le_card_large_of_overflow {s : Finset ι} {n : ℕ} {ρ z : ℝ} + {w : ι → Fin 2 → ℝ} (hn : 0 < n) (hρ : 0 ≤ ρ) (hz : z ≤ ρ) + (hover : ρ < threshold s n ρ z w) : + n ≤ #{y ∈ s | ρ < entrySize (w y)} := by + apply (lt_kthLargest_iff hn hρ).mp + unfold threshold at hover + rcases lt_max_iff.mp hover with h | h + · exact False.elim (not_lt_of_ge hz h) + · simpa only [lt_max_iff, lt_self_iff_false, false_or] using h + +/-- The moment sum pays for an overflow unless at least half its capacity is truly heavy. +The constant is explicit, and the bound allows arbitrary dependence between entries. -/ +theorem one_le_sum_clippedError_pow_of_overflow {s : Finset ι} {n : ℕ} {ρ z : ℝ} + {w raw truth : ι → Fin 2 → ℝ} (hn : 0 < n) (hρ : 0 < ρ) (hρ1 : ρ ≤ 1) + (hz : z ≤ ρ) (hover : ρ < threshold s n ρ z w) + (hfirst : ∀ y ∈ s, 0 ≤ truth y 0) + (hsecond : ∀ y ∈ s, truth y 0 ≤ ρ / 4 → truth y 1 = 0) + (hprev : ∀ y ∈ s, ∀ ν, |w y ν - raw y ν| ≤ ρ / 100) + (hheavy : 2 * #{y ∈ s | ρ / 4 < truth y 0} < n) (p : ℕ) : + 1 ≤ (2 : ℝ) ^ (p + 1) / ((n : ℝ) * ρ ^ p) * + ∑ y ∈ s, clippedError (truth y 0) (truth y 1) (raw y) ^ p := by + classical + let large := {y ∈ s | ρ < entrySize (w y)} + let heavy := {y ∈ s | ρ / 4 < truth y 0} + let light := {y ∈ large | truth y 0 ≤ ρ / 4} + have hnlarge : n ≤ #large := le_card_large_of_overflow hn hρ.le hz hover + have hcover : large ⊆ light ∪ heavy := by + intro y hy + by_cases hd : truth y 0 ≤ ρ / 4 + · exact mem_union_left _ (mem_filter.mpr ⟨hy, hd⟩) + · exact mem_union_right _ (mem_filter.mpr ⟨(mem_filter.mp hy).1, lt_of_not_ge hd⟩) + have hcount : n ≤ 2 * #light := by + have hcard := (card_le_card hcover).trans (card_union_le light heavy) + change 2 * #heavy < n at hheavy + omega + have hhalf : (n : ℝ) / 2 ≤ #light := by + have hc : (n : ℝ) ≤ 2 * (#light : ℝ) := by exact_mod_cast hcount + linarith + have hsubset : light ⊆ s := fun _ hy => (mem_filter.mp (mem_filter.mp hy).1).1 + have hsum : (#light : ℝ) * (ρ / 2) ^ p ≤ + ∑ y ∈ s, clippedError (truth y 0) (truth y 1) (raw y) ^ p := by + calc + _ = ∑ _y ∈ light, (ρ / 2) ^ p := by simp + _ ≤ ∑ y ∈ light, clippedError (truth y 0) (truth y 1) (raw y) ^ p := by + apply sum_le_sum + intro y hy + have hys := hsubset hy + exact pow_le_pow_left₀ (by positivity) (half_floor_le_clippedError hρ hρ1 + (hfirst y hys) (mem_filter.mp hy).2 (hsecond y hys (mem_filter.mp hy).2) + (hprev y hys) (mem_filter.mp (mem_filter.mp hy).1).2) p + _ ≤ _ := sum_le_sum_of_subset_of_nonneg hsubset fun y _ _ => + pow_nonneg (clippedError_nonneg _ _ _) _ + have hcharge := (mul_le_mul_of_nonneg_right hhalf + (pow_nonneg (by positivity : 0 ≤ ρ / 2) p)).trans hsum + have hn' : (0 : ℝ) < n := by exact_mod_cast hn + have hden : 0 < (n : ℝ) / 2 * (ρ / 2) ^ p := by positivity + calc + 1 ≤ (∑ y ∈ s, clippedError (truth y 0) (truth y 1) (raw y) ^ p) / + ((n : ℝ) / 2 * (ρ / 2) ^ p) := (le_div_iff₀ hden).2 (by simpa using hcharge) + _ = _ := by + rw [div_pow, pow_succ] + field_simp + +/-- The false-overflow charge for the actual dyadic compression run. Earlier non-overflow and +the explicit floor separation imply all default and preloss hypotheses of the local charge. -/ +theorem one_le_sum_clippedError_pow_of_firstOverflow_dyadic {s : Finset ι} + {n K : ℕ → ℕ} {Δ : ℕ → ι → Fin 2 → ℝ} {a : State ι} {truth : ι → Fin 2 → ℝ} + {η : ℝ} (hη : 0 < η) (hη1 : η ≤ 1) (ha : a.defaultValue = 0) + (m j : ℕ) (hj : j < m) (hn : 0 < n j) + (hover : IsFirstOverflow s n K (dyadicFloor η m) Δ a j) + (hfirst : ∀ y ∈ s, 0 ≤ truth y 0) + (hsecond : ∀ y ∈ s, truth y 0 ≤ dyadicFloor η m j / 4 → truth y 1 = 0) + (hheavy : 2 * #{y ∈ s | dyadicFloor η m j / 4 < truth y 0} < n j) (p : ℕ) : + 1 ≤ (2 : ℝ) ^ (p + 1) / ((n j : ℝ) * dyadicFloor η m j ^ p) * + ∑ y ∈ s, clippedError (truth y 0) (truth y 1) + (uncompressedRow Δ a.row (j + 1) y) ^ p := by + have hρ := dyadicFloor_pos hη m j + have hρ1 : dyadicFloor η m j ≤ 1 := by + have h := dyadicFloor_le_scale_div hη.le m j + linarith + have hsum := six_sum_range_dyadicFloor_le hη.le hj + have hzabs := abs_iterate_defaultValue_sub_le_of_no_overflow + (show 0 ≤ a.defaultValue by rw [ha]) j hover.1 + rw [ha, sub_zero] at hzabs + have hz : (iterate s n K (dyadicFloor η m) Δ a j).defaultValue ≤ dyadicFloor η m j := by + have h := le_abs_self (iterate s n K (dyadicFloor η m) Δ a j).defaultValue + linarith + apply one_le_sum_clippedError_pow_of_overflow hn hρ hρ1 hz hover.2 hfirst hsecond ?_ hheavy p + intro y _ ν + rw [uncompressedRow_succ] + simp only [inputRow, Pi.add_apply, add_sub_add_right_eq_sub] + exact (abs_iterate_sub_uncompressed_le_of_no_overflow j hover.1 y ν).trans hsum + +end Cslib.RowCompression diff --git a/ComplexityTests/RowCompressionFalseOverflow.lean b/ComplexityTests/RowCompressionFalseOverflow.lean new file mode 100644 index 0000000000..55ef176c1d --- /dev/null +++ b/ComplexityTests/RowCompressionFalseOverflow.lean @@ -0,0 +1,113 @@ +/- +Copyright (c) 2026 Samuel Schlesinger. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Samuel Schlesinger +-/ +import Complexity.Foundations.Analysis.RowCompression.FalseOverflow +import Mathlib.LinearAlgebra.Matrix.Notation +import Mathlib.Tactic.FinCases +import Mathlib.Tactic.NormNum + +/-! +# Tests for charging false overflows + +An actual two-group run first compresses a zero row to a nonzero default, then receives a negative +first-channel increment at one endpoint and a positive second-channel increment at another. +The first overflow is group one. Neither true target is heavy, and the charge is verified using +the actual raw prefix, despite the nonzero preceding compression loss. +-/ + +namespace ComplexityTests.RowCompressionFalseOverflow + +open Finset Cslib.RowCompression + +-- A negative first channel can cause the light-target error just as a positive one can. +example : (1 / 2 : ℝ) ≤ clippedError (1 / 4) 0 ![-2, 0] := by + apply half_floor_le_clippedError (w := ![-2, 0]) (by norm_num) le_rfl + (by norm_num) le_rfl rfl + · intro ν + norm_num + · norm_num [entrySize] + +-- The second-channel case does not rely on the first coordinate being large. +example : (1 / 2 : ℝ) ≤ clippedError 0 0 ![0, -2] := by + apply half_floor_le_clippedError (w := ![0, -2]) (by norm_num) le_rfl + le_rfl (by norm_num) rfl + · intro ν + norm_num + · norm_num [entrySize] + +private def initial : State (Fin 2) := { defaultValue := 0, row := 0 } + +private noncomputable def increments (i : ℕ) (y : Fin 2) : Fin 2 → ℝ := + if i = 0 then 0 else if y = 0 then ![-1 / 512, 0] else ![0, 1 / 512] + +private noncomputable def run : ℕ → State (Fin 2) := + iterate univ (fun _ => 2) (fun _ => 1) (dyadicFloor 1 2) increments initial + +private theorem first_state : (run 1).defaultValue = 1 / 1048576 ∧ + (run 1).row = fun _ => defaultEntry (1 / 1048576) := by + constructor + · norm_num [run, iterate, advance, initial, increments, dyadicFloor, dyadicSlack, + newDefault, threshold, kthLargest, entrySize, Fin.univ_succ, filter_insert, filter_singleton] + · funext y ν + fin_cases y <;> fin_cases ν <;> + norm_num [run, iterate, advance, initial, increments, dyadicFloor, dyadicSlack, + newDefault, threshold, kthLargest, entrySize, update, updateEntry, radius, defaultEntry, + Fin.univ_succ, filter_insert, filter_singleton] + +private theorem first_overflow : + IsFirstOverflow univ (fun _ => 2) (fun _ => 1) (dyadicFloor 1 2) increments initial 1 := by + constructor + · intro i hi + have hi0 : i = 0 := by omega + subst i + norm_num [stepThreshold, inputRow, iterate, initial, increments, dyadicFloor, dyadicSlack, + threshold, kthLargest, entrySize, Fin.univ_succ, filter_insert, filter_singleton] + · change dyadicFloor 1 2 1 < threshold univ 2 (dyadicFloor 1 2 1) + (run 1).defaultValue ((run 1).row + increments 1) + rw [first_state.1, first_state.2] + have hlarge : ∀ y ∈ (univ : Finset (Fin 2)), dyadicFloor 1 2 1 < + entrySize (defaultEntry (1 / 1048576) + increments 1 y) := by + intro y _ + fin_cases y <;> norm_num [increments, dyadicFloor, dyadicSlack, entrySize, defaultEntry] + have hcard : 2 ≤ #{y ∈ (univ : Finset (Fin 2)) | dyadicFloor 1 2 1 < + entrySize (defaultEntry (1 / 1048576) + increments 1 y)} := by + rw [filter_eq_self.mpr hlarge] + norm_num + have hrank := (lt_kthLargest_iff (by norm_num : 0 < 2) + (dyadicFloor_nonneg (by norm_num : (0 : ℝ) ≤ 1) 2 1)).mpr hcard + exact hrank.trans_le ((le_max_right _ _).trans (le_max_right _ _)) + +-- There is genuine preloss at the previous group, so the zero-loss case is insufficient. +example : (run 1).row 0 0 - uncompressedRow increments initial.row 1 0 0 = 1 / 1048576 := by + rw [first_state.2] + norm_num [uncompressedRow, increments, initial, defaultEntry] + +-- First-overflow events are disjoint for this concrete run as well. +example (j : ℕ) + (hj : IsFirstOverflow univ (fun _ => 2) (fun _ => 1) (dyadicFloor 1 2) increments initial j) : + j = 1 := hj.unique first_overflow + +-- The actual moment theorem applies, discharging every earlier-threshold and light-target premise. +example : 1 ≤ (2 : ℝ) ^ (4 + 1) / (2 * dyadicFloor 1 2 1 ^ 4) * + ∑ y : Fin 2, clippedError 0 0 (uncompressedRow increments initial.row 2 y) ^ 4 := by + apply one_le_sum_clippedError_pow_of_firstOverflow_dyadic (truth := fun _ => 0) + (by norm_num) le_rfl rfl 2 1 (by norm_num) (by norm_num) first_overflow + · intro y _ + exact le_rfl + · intro y _ _ + rfl + · norm_num [dyadicFloor, dyadicSlack] + +-- Both endpoints contribute exactly (1/512)^4; the error is measured before compression. +example : (∑ y : Fin 2, + clippedError 0 0 (uncompressedRow increments initial.row 2 y) ^ 4) = 1 / 34359738368 := by + norm_num [uncompressedRow, increments, initial, clippedError, Fin.sum_univ_two, sum_range_succ] + +example : (2 : ℝ) ^ (4 + 1) / (2 * dyadicFloor 1 2 1 ^ 4) * + ∑ y : Fin 2, clippedError 0 0 (uncompressedRow increments initial.row 2 y) ^ 4 = 512 := by + norm_num [uncompressedRow, increments, initial, clippedError, dyadicFloor, dyadicSlack, + Fin.sum_univ_two, sum_range_succ] + +end ComplexityTests.RowCompressionFalseOverflow From c9f089087bbdebaf705660cd93b5bac245e80b4d Mon Sep 17 00:00:00 2001 From: Samuel Schlesinger Date: Fri, 30 Oct 2026 16:52:52 +0000 Subject: [PATCH 13/19] feat(logspace): bound heavy-count rarity and masked mean errors Prove the conditional true-heavy-count estimate, deterministic endpoint-error and retained-row maximum bounds, and the actual affine-channel instance at two rates. This is the conditional-rarity component of OpenAI2026LogSpace Lemma 8.4 (revision 7ef5c0cc), contributing to #1721 and #1444. Validation: rebuilt the complete 23-module Complexity dependency closure from exact source with pinned Lean 4.36.0-rc2 and strict warnings, then checked the final concrete tests and existing RootMetric tests. Hygiene, tracked import aggregate, focused module-doc name checks and whitespace checks pass. Full project gates run in CI. AI-assisted implementation and tests: OpenAI Codex. Independent nonauthor agent /root/review_heavy_rarity approved source tree 8549f1f49b84a4eea95c59c53e59ad85f37224ea after checking the pinned source and final regression delta. A cache/source mismatch found in review was resolved by exposing exactly the two norm definitions consumed here and rebuilding all local prerequisites. No human approval or full estimator endpoint is claimed. --- Complexity.lean | 3 + .../Foundations/Probability/HeavyCount.lean | 143 +++++++++++ .../Probability/HeavyCountRarity.lean | 181 +++++++++++++ .../Foundations/Probability/RootMetric.lean | 4 +- .../PairwiseIndependentHash/HeavyCount.lean | 74 ++++++ ComplexityTests/HeavyCountRarity.lean | 237 ++++++++++++++++++ 6 files changed, 640 insertions(+), 2 deletions(-) create mode 100644 Complexity/Foundations/Probability/HeavyCount.lean create mode 100644 Complexity/Foundations/Probability/HeavyCountRarity.lean create mode 100644 Complexity/Probability/PairwiseIndependentHash/HeavyCount.lean create mode 100644 ComplexityTests/HeavyCountRarity.lean diff --git a/Complexity.lean b/Complexity.lean index 9735d61c91..d01a34f7e2 100644 --- a/Complexity.lean +++ b/Complexity.lean @@ -2732,6 +2732,8 @@ public import Complexity.Foundations.Probability.DetectedStage public import Complexity.Foundations.Probability.Gaussian.Multivariate public import Complexity.Foundations.Probability.Gaussian.Real public import Complexity.Foundations.Probability.Gaussian.Sheppard +public import Complexity.Foundations.Probability.HeavyCount +public import Complexity.Foundations.Probability.HeavyCountRarity public import Complexity.Foundations.Probability.HierarchyParams public import Complexity.Foundations.Probability.RootMetric public import Complexity.Foundations.Probability.SecondMoment @@ -3001,6 +3003,7 @@ public import Complexity.Probability.PairwiseIndependentHash public import Complexity.Probability.PairwiseIndependentHash.Affine public import Complexity.Probability.PairwiseIndependentHash.AtomChannels public import Complexity.Probability.PairwiseIndependentHash.DetectorChannels +public import Complexity.Probability.PairwiseIndependentHash.HeavyCount public import Complexity.Probability.PairwiseIndependentHash.HierarchyChannels public import Complexity.Probability.PairwiseIndependentHash.Retention public import Complexity.Probability.PairwiseIndependentHash.RetentionChannel diff --git a/Complexity/Foundations/Probability/HeavyCount.lean b/Complexity/Foundations/Probability/HeavyCount.lean new file mode 100644 index 0000000000..7d54813038 --- /dev/null +++ b/Complexity/Foundations/Probability/HeavyCount.lean @@ -0,0 +1,143 @@ +/- +Copyright (c) 2026 Samuel Schlesinger. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Samuel Schlesinger +-/ + +module +-- upstream: candidate + +public import Complexity.Foundations.Probability.CorrectionAtom +import Complexity.Foundations.Data.Finset.Markov +import Mathlib.Tactic.FieldSimp +import Mathlib.Tactic.Linarith +import Mathlib.Tactic.Positivity +import Mathlib.Tactic.Ring + +/-! +# Conditional rarity of retained heavy entries + +A row with first signal `d` has bounded mass `a * ∑ w, d w ≤ M`. At a floor `ρ > 0`, +there are at most `4 * M / (a * ρ)` entries above `ρ / 4`. Suppose that, on a finite slice +of draws, every endpoint other than one specified endpoint is retained on at most a +`c * a` fraction of the draws. The specified endpoint can contribute one retained entry. +Markov's inequality then bounds the fraction of draws retaining at least `n / 2` heavy +entries by `2 * (1 + 4 * c * M) / (n * ρ)` when `ρ ≤ 1`. + +The slice is arbitrary: it may condition on a narrower endpoint channel and a start channel, +provided its explicit pair bound holds. No independence among the heavy-entry hits is required. +The division-free estimate also permits an empty slice or zero capacity. This is the counting +part of [OpenAI2026LogSpace, Lemma 8.4]; weighting deterministic mean errors and the complete +integrated compression bound are separate steps. + +## Main definitions + +* `Cslib.Probability.heavyCountEvent`: at least half the capacity is truly heavy and retained. + +## Main results + +* `Cslib.Probability.card_filter_heavy_mul_le`: the deterministic heavy-set mass bound. +* `Cslib.Probability.card_filter_heavyCountEvent_mul_le`: rarity without division. +* `Cslib.Probability.card_filter_heavyCountEvent_le`: the explicit conditional rarity factor. + +## References + +* [OpenAI, *Exact Derandomization of Logarithmic Space: L = RL = BPL*][OpenAI2026LogSpace], + Section 8.4, Lemma 8.4, equation labelled `buf-rarity` + (23 September 2026, revision `7ef5c0cc`, not peer reviewed). +-/ + +public section + +open Finset +open scoped BigOperators + +namespace Cslib.Probability + +variable {Ω V : Type*} [Fintype V] + +open Classical in +/-- A true heavy count at floor `ρ`: at least half the capacity `n` consists of retained +endpoints whose deterministic first signal exceeds `ρ / 4`. -/ +@[expose] def heavyCountEvent (Y : Ω → V → Prop) (d : V → ℝ) (ρ : ℝ) (n : ℕ) + (σ : Ω) : Prop := + n ≤ 2 * #{w | Y σ w ∧ ρ / 4 < d w} + +/-- The deterministic mass bounds the number of entries above a quarter of the floor. +The multiplied form remains valid at zero scale and for every floor. -/ +theorem card_filter_heavy_mul_le {a ρ M : ℝ} {d : V → ℝ} (ha : 0 ≤ a) + (hd : ∀ w, 0 ≤ d w) (hmass : a * ∑ w, d w ≤ M) : + (#{w | ρ / 4 < d w} : ℝ) * (a * ρ) ≤ 4 * M := by + classical + have hcount : (#{w | ρ / 4 < d w} : ℝ) * (ρ / 4) ≤ ∑ w, d w := + card_filter_mul_le_sum univ _ d (fun w _ => hd w) fun _ _ hw => hw.le + have h := (mul_le_mul_of_nonneg_left hcount ha).trans hmass + linarith + +open Classical in +/-- Conditional rarity of a true heavy count, without division. The endpoint `y` may be +forced by the conditioning slice, while all other endpoints satisfy its pair-count bound. +The slice and the capacity may be empty or zero. -/ +theorem card_filter_heavyCountEvent_mul_le (Y : Ω → V → Prop) (T : Finset Ω) (y : V) + {d : V → ℝ} {a ρ c M : ℝ} (ha : 0 < a) (hρ : 0 < ρ) (hc : 0 ≤ c) + (hd : ∀ w, 0 ≤ d w) (hmass : a * ∑ w, d w ≤ M) + (hpair : ∀ w, w ≠ y → (#{σ ∈ T | Y σ w} : ℝ) ≤ c * a * #T) (n : ℕ) : + (#{σ ∈ T | heavyCountEvent Y d ρ n σ} : ℝ) * n * ρ ≤ + #T * (2 * (ρ + 4 * c * M)) := by + classical + let D : Finset V := {w | ρ / 4 < d w} + have hfilter (σ : Ω) : ({w ∈ D | Y σ w} : Finset V) = + ({w | Y σ w ∧ ρ / 4 < d w} : Finset V) := by + ext w + simp [D, and_comm] + have hevent (σ : Ω) : (n + 1) / 2 ≤ #{w ∈ D | Y σ w} ↔ + heavyCountEvent Y d ρ n σ := by + rw [hfilter] + unfold heavyCountEvent + omega + have hcount := card_filter_le_card_filter_mul_le Y T D y (mul_nonneg hc ha.le) + (fun w _ hw => hpair w hw) ((n + 1) / 2) + simp only [hevent] at hcount + have hn : (n : ℝ) ≤ 2 * (((n + 1) / 2 : ℕ) : ℝ) := by + exact_mod_cast (show n ≤ 2 * ((n + 1) / 2) by omega) + have hmassD : (#D : ℝ) * (a * ρ) ≤ 4 * M := + card_filter_heavy_mul_le ha.le hd hmass + have hmassc : c * a * #D * ρ ≤ 4 * c * M := by + have h := mul_le_mul_of_nonneg_left hmassD hc + nlinarith + calc + _ ≤ (#{σ ∈ T | heavyCountEvent Y d ρ n σ} : ℝ) * + (2 * (((n + 1) / 2 : ℕ) : ℝ)) * ρ := + mul_le_mul_of_nonneg_right (mul_le_mul_of_nonneg_left hn (by positivity)) hρ.le + _ = 2 * ((#{σ ∈ T | heavyCountEvent Y d ρ n σ} : ℝ) * + (((n + 1) / 2 : ℕ) : ℝ)) * ρ := by ring + _ ≤ 2 * (#T * (1 + c * a * #D)) * ρ := + mul_le_mul_of_nonneg_right (mul_le_mul_of_nonneg_left hcount (by norm_num)) hρ.le + _ = #T * (2 * (ρ + c * a * #D * ρ)) := by ring + _ ≤ #T * (2 * (ρ + 4 * c * M)) := + mul_le_mul_of_nonneg_left + (mul_le_mul_of_nonneg_left (add_le_add le_rfl hmassc) (by norm_num)) (by positivity) + +open Classical in +/-- The conditional rarity factor `2 * (1 + 4 * c * M) / (n * ρ)` for a positive capacity +and a floor in `(0, 1]`. Empty slices require no special convention. -/ +theorem card_filter_heavyCountEvent_le (Y : Ω → V → Prop) (T : Finset Ω) (y : V) + {d : V → ℝ} {a ρ c M : ℝ} (ha : 0 < a) (hρ : 0 < ρ) (hρ1 : ρ ≤ 1) + (hc : 0 ≤ c) (hd : ∀ w, 0 ≤ d w) (hmass : a * ∑ w, d w ≤ M) + (hpair : ∀ w, w ≠ y → (#{σ ∈ T | Y σ w} : ℝ) ≤ c * a * #T) + {n : ℕ} (hn : 0 < n) : + (#{σ ∈ T | heavyCountEvent Y d ρ n σ} : ℝ) ≤ + (2 * (1 + 4 * c * M) / ((n : ℝ) * ρ)) * #T := by + classical + have h := card_filter_heavyCountEvent_mul_le Y T y ha hρ hc hd hmass hpair n + have hn' : (0 : ℝ) < n := by exact_mod_cast hn + rw [div_mul_eq_mul_div, le_div_iff₀ (mul_pos hn' hρ)] + calc + _ = (#{σ ∈ T | heavyCountEvent Y d ρ n σ} : ℝ) * n * ρ := by ring + _ ≤ #T * (2 * (ρ + 4 * c * M)) := h + _ ≤ #T * (2 * (1 + 4 * c * M)) := + mul_le_mul_of_nonneg_left + (mul_le_mul_of_nonneg_left (add_le_add hρ1 le_rfl) (by norm_num)) (by positivity) + _ = _ := by ring + +end Cslib.Probability diff --git a/Complexity/Foundations/Probability/HeavyCountRarity.lean b/Complexity/Foundations/Probability/HeavyCountRarity.lean new file mode 100644 index 0000000000..e1891c7a33 --- /dev/null +++ b/Complexity/Foundations/Probability/HeavyCountRarity.lean @@ -0,0 +1,181 @@ +/- +Copyright (c) 2026 Samuel Schlesinger. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Samuel Schlesinger +-/ + +module +-- upstream: candidate + +public import Complexity.Foundations.Probability.RootMetric +public import Complexity.Foundations.Probability.HeavyCount +import Mathlib.Algebra.Order.BigOperators.Expect +import Mathlib.Algebra.BigOperators.Field +import Mathlib.Tactic.Positivity +import Mathlib.Tactic.Ring + +/-! +# Conditional rarity and deterministic mean errors + +A rare row event reduces the integrated contribution of a deterministic endpoint error +by its conditional probability, even when endpoint retention events are dependent. +The conditioning slice includes both the source and the endpoint. Empty slices and empty +environments are allowed: the hypotheses use cardinalities instead of conditional division. + +The error table `b x y` is independent of the environment. The row quantity may depend on +which endpoints were retained, provided its power is bounded by the sum of endpoint error +powers. This includes the retained-row supremum used in the compression argument. +Arbitrary random noise cannot use the same rarity factor, since it may be concentrated on +the rare event. + +These are the integrated, exponent-parametric assertions in the proof of +[OpenAI2026LogSpace, Lemma 8.4, Section 8.4], at revision `7ef5c0cc`. They apply in particular +to fourth moments. They do not assert the recursive estimator's induction or space bound. + +## Main results + +* `Cslib.rowNormPow_event_le`: conditional rarity contracts deterministic endpoint errors. +* `Cslib.vertexNormPow_event_le_rowNormPow`: the corresponding bound for a row error dominated + by the endpoint error powers. +* `Cslib.vertexNormPow_kthLargest_event_le`: rarity bounds the actual retained-row maximum. +* `Cslib.vertexNormPow_heavyCountEvent_le`: the bound with the concrete heavy-count event and + its explicit factor derived from the row-mass and conditional pair estimates. + +## References + +* [OpenAI, *Exact Derandomization of Logarithmic Space: L = RL = BPL*][OpenAI2026LogSpace], + Section 8.4, Lemma 8.4, revision `7ef5c0cc` (preprint, not peer reviewed). +-/ + +public section + +open Finset +open scoped BigOperators + +namespace Cslib + +variable {Ω V : Type*} [Fintype Ω] [Fintype V] + +private theorem sum_masked_const_le {ι : Type*} [Fintype ι] + (E F : Ω → ι → Prop) [∀ σ i, Decidable (E σ i)] [∀ σ i, Decidable (F σ i)] + (w : ι → ℝ) (hw : ∀ i, 0 ≤ w i) {q : ℝ} + (h : ∀ i, (#{σ | E σ i} : ℝ) ≤ q * #{σ | F σ i}) : + (∑ σ, ∑ i, if E σ i then w i else 0) ≤ + q * ∑ σ, ∑ i, if F σ i then w i else 0 := by + rw [sum_comm, sum_comm (f := fun σ i => if F σ i then w i else 0), mul_sum] + refine sum_le_sum fun i _ => ?_ + simp only [← sum_filter, sum_const, nsmul_eq_mul] + exact (mul_le_mul_of_nonneg_right (h i) (hw i)).trans_eq (by ring) + +variable {s : ℕ} {N u : ℝ} {X Y Θ : Ω → V → Prop} + [∀ σ x, Decidable (X σ x)] [∀ σ y, Decidable (Y σ y)] + [∀ σ x, Decidable (Θ σ x)] + +/-- Conditional rarity on each source/endpoint slice contracts the integrated power norm of +a deterministic error table. The exponent is positive; zero powers do not preserve masking. +No independence between the two masks or the row event is required. -/ +theorem rowNormPow_event_le (hs : s ≠ 0) (hNu : 0 ≤ N * u) {q : ℝ} + (hrare : ∀ x y, (#{σ | X σ x ∧ Y σ y ∧ Θ σ x} : ℝ) ≤ + q * #{σ | X σ x ∧ Y σ y}) (b : V → V → ℝ) : + rowNormPow s N u X Y (fun σ x y => if Θ σ x then b x y else 0) ≤ + q * rowNormPow s N u X Y (fun _ x y => b x y) := by + have hsum := sum_masked_const_le + (fun σ (i : V × V) => X σ i.1 ∧ Y σ i.2 ∧ Θ σ i.1) + (fun σ (i : V × V) => X σ i.1 ∧ Y σ i.2) + (fun i => |b i.1 i.2| ^ s) (fun _ => by positivity) (fun i => hrare i.1 i.2) + have hpoint (σ : Ω) : + (∑ x ∈ ({x | X σ x} : Finset V), ∑ y ∈ ({y | Y σ y} : Finset V), + |if Θ σ x then b x y else 0| ^ s) = + ∑ i : V × V, if X σ i.1 ∧ Y σ i.2 ∧ Θ σ i.1 then |b i.1 i.2| ^ s else 0 := by + rw [Fintype.sum_prod_type, sum_filter] + refine sum_congr rfl fun x _ => ?_ + by_cases hx : X σ x <;> by_cases hΘ : Θ σ x <;> simp [hx, hΘ, sum_filter, hs] + have hpoint' (σ : Ω) : + (∑ x ∈ ({x | X σ x} : Finset V), ∑ y ∈ ({y | Y σ y} : Finset V), |b x y| ^ s) = + ∑ i : V × V, if X σ i.1 ∧ Y σ i.2 then |b i.1 i.2| ^ s else 0 := by + rw [Fintype.sum_prod_type, sum_filter] + refine sum_congr rfl fun x _ => ?_ + by_cases hx : X σ x <;> simp [hx, sum_filter] + simp only [rowNormPow, expect_eq_sum_div_card, card_univ, hpoint, hpoint'] + calc + _ ≤ (N * u)⁻¹ * + ((q * ∑ σ, ∑ i : V × V, + if X σ i.1 ∧ Y σ i.2 then |b i.1 i.2| ^ s else 0) / Fintype.card Ω) := + mul_le_mul_of_nonneg_left + (div_le_div_of_nonneg_right hsum (Nat.cast_nonneg _)) (inv_nonneg.mpr hNu) + _ = _ := by ring + +/-- A retained-row supremum, or any row error dominated by the sum of deterministic endpoint +error powers, gains the same conditional rarity factor. Dependence of the row quantity on the +retained set is allowed; the endpoint magnitudes `b x y` are fixed. -/ +theorem vertexNormPow_event_le_rowNormPow (hs : s ≠ 0) (hNu : 0 ≤ N * u) {q : ℝ} + (hrare : ∀ x y, (#{σ | X σ x ∧ Y σ y ∧ Θ σ x} : ℝ) ≤ + q * #{σ | X σ x ∧ Y σ y}) (b : V → V → ℝ) (v : Ω → V → ℝ) + (hv : ∀ σ x, X σ x → |v σ x| ^ s ≤ + ∑ y ∈ ({y | Y σ y} : Finset V), |b x y| ^ s) : + vertexNormPow s N u X (fun σ x => if Θ σ x then v σ x else 0) ≤ + q * rowNormPow s N u X Y (fun _ x y => b x y) := by + calc + _ ≤ rowNormPow s N u X Y (fun σ x y => if Θ σ x then b x y else 0) := by + unfold vertexNormPow rowNormPow + refine mul_le_mul_of_nonneg_left (expect_le_expect fun σ _ => ?_) (inv_nonneg.mpr hNu) + refine sum_le_sum fun x hx => ?_ + by_cases hΘ : Θ σ x + · simp only [hΘ, ↓reduceIte] + exact hv σ x (mem_filter.mp hx).2 + · simp [hΘ, hs] + _ ≤ _ := rowNormPow_event_le hs hNu hrare b + +omit [Fintype V] in +private theorem abs_kthLargest_pow_le_sum (S : Finset V) (b : V → ℝ) + (hs : s ≠ 0) : |kthLargest 1 S (fun y => |b y|)| ^ s ≤ ∑ y ∈ S, |b y| ^ s := by + classical + have hmem : kthLargest 1 S (fun y => |b y|) ∈ + insert 0 ((S.filter fun y => 1 ≤ #{w ∈ S | |b y| ≤ |b w|}).image fun y => |b y|) := + max'_mem _ _ + rcases mem_insert.mp hmem with hz | hmem + · rw [hz, abs_zero, zero_pow hs] + positivity + · obtain ⟨y, hy, heq⟩ := mem_image.mp hmem + rw [← heq, abs_abs] + exact single_le_sum (f := fun y => |b y| ^ s) + (fun _ _ => by positivity) (mem_filter.mp hy).1 + +/-- Conditional rarity controls the maximum deterministic error magnitude among retained +endpoints, with zero as the maximum of an empty row. -/ +theorem vertexNormPow_kthLargest_event_le (hs : s ≠ 0) (hNu : 0 ≤ N * u) {q : ℝ} + (hrare : ∀ x y, (#{σ | X σ x ∧ Y σ y ∧ Θ σ x} : ℝ) ≤ + q * #{σ | X σ x ∧ Y σ y}) (b : V → V → ℝ) : + vertexNormPow s N u X (fun σ x => + if Θ σ x then kthLargest 1 {y | Y σ y} (fun y => |b x y|) else 0) ≤ + q * rowNormPow s N u X Y (fun _ x y => b x y) := + vertexNormPow_event_le_rowNormPow hs hNu hrare b _ + (fun _ _ _ => abs_kthLargest_pow_le_sum _ _ hs) + +open Classical in +/-- **The heavy-count rarity gain for a retained-row mean error.** The pair bound is stated on +the actual source/usage-endpoint slice. The rank channel `Y` may have a wider rate than `Yt`; +only the explicit conditional bound is used. This is the mean-error portion of +[OpenAI2026LogSpace, Lemma 8.4], with an explicit constant and arbitrary positive exponent. -/ +theorem vertexNormPow_heavyCountEvent_le (hs : s ≠ 0) (hNu : 0 ≤ N * u) + (X Y Yt : Ω → V → Prop) [∀ σ x, Decidable (X σ x)] [∀ σ y, Decidable (Yt σ y)] + {a ρ c M : ℝ} {n : ℕ} (ha : 0 < a) (hρ : 0 < ρ) (hρ1 : ρ ≤ 1) + (hc : 0 ≤ c) (hn : 0 < n) (d : V → V → ℝ) (hd : ∀ x y, 0 ≤ d x y) + (hmass : ∀ x, a * ∑ y, d x y ≤ M) + (hpair : ∀ x y w, w ≠ y → + (#{σ | X σ x ∧ Yt σ y ∧ Y σ w} : ℝ) ≤ + c * a * #{σ | X σ x ∧ Yt σ y}) (b : V → V → ℝ) : + vertexNormPow s N u X (fun σ x => + if Probability.heavyCountEvent Y (d x) ρ n σ then + kthLargest 1 {y | Yt σ y} (fun y => |b x y|) else 0) ≤ + (2 * (1 + 4 * c * M) / ((n : ℝ) * ρ)) * + rowNormPow s N u X Yt (fun _ x y => b x y) := by + classical + refine vertexNormPow_kthLargest_event_le hs hNu (fun x y => ?_) b + have h := Probability.card_filter_heavyCountEvent_le Y + ({σ | X σ x ∧ Yt σ y} : Finset Ω) y ha hρ hρ1 hc (hd x) (hmass x) + (fun w hwy => ?_) hn + · simpa only [filter_filter, and_assoc] using h + · simpa only [filter_filter, and_assoc] using hpair x y w hwy + +end Cslib diff --git a/Complexity/Foundations/Probability/RootMetric.lean b/Complexity/Foundations/Probability/RootMetric.lean index 419b8cccd2..651f7bbf26 100644 --- a/Complexity/Foundations/Probability/RootMetric.lean +++ b/Complexity/Foundations/Probability/RootMetric.lean @@ -71,7 +71,7 @@ variable (s : ℕ) (N u : ℝ) (X Y : Ω → V → Prop) [∀ σ v, Decidable (X /-- The `s`-th power `‖Z‖^s_{u,a;s}` of the integrated row norm of a random table [OpenAI2026LogSpace, (5.19)]. -/ -noncomputable def rowNormPow (Z : Ω → V → V → ℝ) : ℝ := +@[expose] noncomputable def rowNormPow (Z : Ω → V → V → ℝ) : ℝ := (N * u)⁻¹ * 𝔼 σ, ∑ x ∈ ({x | X σ x} : Finset V), ∑ y ∈ ({y | Y σ y} : Finset V), |Z σ x y| ^ s /-- The `s`-th power `d_{u,a}(H, H')^s` of the root distance of two random tables @@ -81,7 +81,7 @@ noncomputable def rootDistPow (H H' : Ω → V → V → ℝ) : ℝ := /-- The `s`-th power `‖v‖^s_{u;s}` of the integrated norm of a random vertex array [OpenAI2026LogSpace, (5.20)]. -/ -noncomputable def vertexNormPow (v : Ω → V → ℝ) : ℝ := +@[expose] noncomputable def vertexNormPow (v : Ω → V → ℝ) : ℝ := (N * u)⁻¹ * 𝔼 σ, ∑ x ∈ ({x | X σ x} : Finset V), |v σ x| ^ s end Definitions diff --git a/Complexity/Probability/PairwiseIndependentHash/HeavyCount.lean b/Complexity/Probability/PairwiseIndependentHash/HeavyCount.lean new file mode 100644 index 0000000000..65235d6604 --- /dev/null +++ b/Complexity/Probability/PairwiseIndependentHash/HeavyCount.lean @@ -0,0 +1,74 @@ +/- +Copyright (c) 2026 Samuel Schlesinger. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Samuel Schlesinger +-/ + +module +-- upstream: candidate + +public import Complexity.Foundations.Probability.HeavyCount +public import Complexity.Probability.PairwiseIndependentHash.AtomChannels +import Mathlib.Tactic.Linarith +import Mathlib.Tactic.Positivity + +/-! +# Heavy-count rarity for affine retention channels + +The conditional heavy-count bound applies to the actual affine retention channels with nominal +rate `a ^ H` and box side `⌈P * a⌉`. Conditioning on a specified endpoint retained by any narrower +box of side `L_t` preserves the off-diagonal pair bound `2 ^ H * a ^ H`. Thus a nonnegative row +of nominal mass at most `M` retains at least half of a positive capacity `n` above floor `ρ / 4` +on at most a `2 * (1 + 4 * 2 ^ H * M) / (n * ρ)` fraction of these conditional draws. + +The result concerns the true heavy-count event on the actual shared seed. It assumes neither +independence among retained endpoints nor a rarity hypothesis. An empty conditioning slice is +allowed. This supplies the affine-channel instance of [OpenAI2026LogSpace, Lemma 8.4]. + +## Main results + +* `Cslib.Probability.card_heavyCountEvent_affineRetains_le`: rarity after a narrower endpoint hit. + +## References + +* [OpenAI, *Exact Derandomization of Logarithmic Space: L = RL = BPL*][OpenAI2026LogSpace], + Section 8.4, Lemma 8.4 (23 September 2026, revision `7ef5c0cc`, not peer reviewed). +-/ + +public section + +open Finset +open scoped BigOperators + +namespace Cslib.Probability + +open Classical in +/-- The true heavy count for the actual affine channel is rare even after conditioning on +a hit at a narrower rate. Its nominal row-mass scale is `a ^ H`, not the box side `a`. -/ +theorem card_heavyCountEvent_affineRetains_le {V : Type*} [Fintype V] {P H : ℕ} + [Fact P.Prime] {ident : V → ZMod P} (hident : Function.Injective ident) + {a : ℝ} (hPa : 1 ≤ P * a) (ha : a ≤ 1) {Lt : ℕ} (hLt : Lt ≤ ⌈P * a⌉₊) + {d : V → ℝ} {ρ M : ℝ} (hρ : 0 < ρ) (hρ1 : ρ ≤ 1) + (hd : ∀ w, 0 ≤ d w) (hmass : a ^ H * ∑ w, d w ≤ M) {n : ℕ} (hn : 0 < n) (y : V) : + (#{s | affineRetains P H Lt s (ident y) ∧ + heavyCountEvent (fun s w => affineRetains P H ⌈P * a⌉₊ s (ident w)) d ρ n s} : ℝ) ≤ + (2 * (1 + 4 * (2 : ℝ) ^ H * M) / ((n : ℝ) * ρ)) * + #{s | affineRetains P H Lt s (ident y)} := by + classical + have ha0 : 0 < a := by + by_contra h + have := mul_nonpos_of_nonneg_of_nonpos (Nat.cast_nonneg P) (not_lt.mp h) + linarith + have hLtP : Lt ≤ P := hLt.trans (affineRetains_rates (H := H) hPa ha).1 + simpa only [filter_filter] using card_filter_heavyCountEvent_le + (fun s w => affineRetains P H ⌈P * a⌉₊ s (ident w)) + ({s | affineRetains P H Lt s (ident y)} : Finset _) y + (pow_pos ha0 H) hρ hρ1 (by positivity : 0 ≤ (2 : ℝ) ^ H) hd hmass + (fun w hwy => by + have h := card_affineRetains_and_affineRetains_le (H := H) hident hPa ha hLtP hwy + convert h using 2 + congr 1 + ext s + simp only [mem_filter, mem_univ, true_and]) hn + +end Cslib.Probability diff --git a/ComplexityTests/HeavyCountRarity.lean b/ComplexityTests/HeavyCountRarity.lean new file mode 100644 index 0000000000..123f9aed24 --- /dev/null +++ b/ComplexityTests/HeavyCountRarity.lean @@ -0,0 +1,237 @@ +/- +Copyright (c) 2026 Samuel Schlesinger. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Samuel Schlesinger +-/ +import Complexity.Foundations.Probability.HeavyCount +import Complexity.Foundations.Probability.HeavyCountRarity +import Complexity.Probability.PairwiseIndependentHash.HeavyCount +import Mathlib.Tactic.NormNum + +/-! +# Tests for heavy-count rarity and deterministic mean errors + +The heavy endpoints in the first example are perfectly correlated except for one always-kept +endpoint. The integrated examples use a separate event coordinate, correlated source/endpoint +masks, and nonzero signed fourth-moment errors. A noise counterexample records why the mean +error must be independent of the environment after fixing the source and endpoint. +-/ + +namespace ComplexityTests.HeavyCountRarity + +open Finset Cslib Cslib.Probability +open scoped BigOperators + +private abbrev correlated (σ y : Fin 5) : Prop := y = 0 ∨ σ = 0 + +-- All four non-forced endpoints appear together with probability `1/5`. +example : ({σ | correlated σ 1 ∧ correlated σ 2} : Finset (Fin 5)) = {0} := by + decide + +private theorem heavy_iff (σ : Fin 5) : + heavyCountEvent correlated (fun _ => 1 / 3) 1 8 σ ↔ σ = 0 := by + classical + by_cases hσ : σ = 0 + · subst σ + norm_num [heavyCountEvent, correlated] + · have hsingle : ({y : Fin 5 | y = 0} : Finset (Fin 5)) = {0} := by + ext y + simp + norm_num [heavyCountEvent, correlated, hσ, hsingle] + +-- The rare event has positive probability, and the explicit upper bound is below one. +open scoped Classical in +example : (dens {σ | heavyCountEvent correlated (fun _ => 1 / 3) 1 8 σ} : ℝ) = 1 / 5 := by + classical + have hevent : ({σ | heavyCountEvent correlated (fun _ => 1 / 3) 1 8 σ} : + Finset (Fin 5)) = {0} := by + ext σ + simp only [mem_filter, mem_univ, true_and, mem_singleton] + exact heavy_iff σ + rw [hevent, dens_eq_card_div_card] + norm_num + +open scoped Classical in +example : (#{σ : Fin 5 | heavyCountEvent correlated (fun _ => 1 / 3) 1 8 σ} : ℝ) ≤ + (7 / 12) * Fintype.card (Fin 5) := by + classical + have hpair : ∀ y : Fin 5, y ≠ 0 → + (#{σ ∈ (univ : Finset (Fin 5)) | correlated σ y} : ℝ) ≤ + (1 : ℝ) * (1 / 5) * #(univ : Finset (Fin 5)) := by + intro y hy + have hs : ({σ : Fin 5 | correlated σ y} : Finset (Fin 5)) = {0} := by + ext σ + simp [correlated, hy] + norm_num [hs] + have h := @card_filter_heavyCountEvent_le (Fin 5) (Fin 5) (inferInstance : Fintype (Fin 5)) + correlated univ (0 : Fin 5) + (a := 1 / 5) (ρ := 1) (c := 1) (M := 1 / 3) (d := fun _ => 1 / 3) + (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (fun _ => by norm_num) (by norm_num) + (by + intro w hw + convert hpair w hw using 1 + congr 2 + ext σ + simp) (n := 8) (by decide) + norm_num at h ⊢ + exact h + +-- An odd capacity requires rounding up; equality with the heavy threshold is excluded. +example : ¬ heavyCountEvent (fun (_ : Unit) (y : Fin 3) => y = 0) + (fun _ => 1) 1 3 () := by + classical + norm_num [heavyCountEvent, show ({y : Fin 3 | y = 0} : Finset (Fin 3)) = {0} by decide] + +example : heavyCountEvent (fun (_ : Unit) (y : Fin 3) => y ≠ 2) + (fun _ => 1) 1 3 () := by + classical + norm_num [heavyCountEvent, show ({y : Fin 3 | y ≠ 2} : Finset (Fin 3)) = {0, 1} by decide] + +example : ¬ heavyCountEvent (fun (_ : Unit) (_ : Fin 3) => True) + (fun _ => 1 / 4) 1 1 () := by + classical + norm_num [heavyCountEvent] + +private abbrev kept (σ : Fin 2 × Fin 2) (x : Fin 2) : Prop := σ.1 = x +private abbrev rare (σ : Fin 2 × Fin 2) (_ : Fin 2) : Prop := σ.2 = 0 +private def meanError (x _ : Fin 2) : ℝ := if x = 0 then -2 else 3 + +private theorem rare_on_slice (x y : Fin 2) : + (#{σ | kept σ x ∧ kept σ y ∧ rare σ x} : ℝ) ≤ + (1 / 2) * #{σ | kept σ x ∧ kept σ y} := by + have hn : ∀ x y : Fin 2, #{σ | kept σ x ∧ kept σ y ∧ rare σ x} = + if x = y then 1 else 0 := by decide + have hd : ∀ x y : Fin 2, #{σ | kept σ x ∧ kept σ y} = + if x = y then 2 else 0 := by decide + rw [hn, hd] + split_ifs <;> norm_num + +example : + rowNormPow 4 2 (1 / 2) kept kept + (fun σ x y => if rare σ x then meanError x y else 0) ≤ + (1 / 2) * rowNormPow 4 2 (1 / 2) kept kept (fun _ x y => meanError x y) := + rowNormPow_event_le (by decide) (by norm_num) rare_on_slice meanError + +example : + vertexNormPow 4 2 (1 / 2) kept (fun σ x => + if rare σ x then kthLargest 1 {y | kept σ y} (fun y => |meanError x y|) else 0) ≤ + (1 / 2) * rowNormPow 4 2 (1 / 2) kept kept (fun _ x y => meanError x y) := + vertexNormPow_kthLargest_event_le (by decide) (by norm_num) rare_on_slice meanError + +example : + vertexNormPow 4 2 (1 / 2) kept + (fun σ x => if rare σ x then meanError x x else 0) ≤ + (1 / 2) * rowNormPow 4 2 (1 / 2) kept kept (fun _ x y => meanError x y) := by + apply vertexNormPow_event_le_rowNormPow (by decide) (by norm_num) rare_on_slice meanError + (fun _ x => meanError x x) + intro σ x hx + have hY : ({y | kept σ y} : Finset (Fin 2)) = {x} := by + ext y + simp only [mem_filter, mem_univ, true_and, mem_singleton, kept] + rw [show σ.1 = x from hx] + exact eq_comm + rw [hY, sum_singleton] + +private theorem card_kept (x : Fin 2) : #{y : Fin 2 | x = y} = 1 := by + have h : ({y : Fin 2 | x = y} : Finset (Fin 2)) = {x} := by + ext y + simp [eq_comm] + rw [h, card_singleton] + +private theorem full_mean_power : + rowNormPow 4 2 (1 / 2) kept kept (fun _ x y => meanError x y) = 97 / 2 := by + norm_num [rowNormPow, kept, meanError, sum_filter, expect_eq_sum_div_card, + Fintype.sum_prod_type, Fin.sum_univ_two, card_kept] + +private theorem masked_mean_power : + rowNormPow 4 2 (1 / 2) kept kept + (fun σ x y => if rare σ x then meanError x y else 0) = 97 / 4 := by + norm_num [rowNormPow, kept, rare, meanError, sum_filter, expect_eq_sum_div_card, + Fintype.sum_prod_type, Fin.sum_univ_two, card_kept] + +-- Both means are nonzero, and masking halves the integrated fourth moment exactly. +example : + rowNormPow 4 2 (1 / 2) kept kept + (fun σ x y => if rare σ x then meanError x y else 0) = + (1 / 2) * rowNormPow 4 2 (1 / 2) kept kept (fun _ x y => meanError x y) := by + rw [masked_mean_power, full_mean_power] + norm_num + +private def noise (σ : Fin 2 × Fin 2) (x y : Fin 2) : ℝ := + if rare σ x then meanError x y else 0 + +-- Environment-dependent noise concentrated on the rare event receives no rarity gain. +example : + ¬ rowNormPow 4 2 (1 / 2) kept kept + (fun σ x y => if rare σ x then noise σ x y else 0) ≤ + (1 / 2) * rowNormPow 4 2 (1 / 2) kept kept noise := by + norm_num [rowNormPow, kept, rare, noise, meanError, sum_filter, expect_eq_sum_div_card, + Fintype.sum_prod_type, Fin.sum_univ_two, card_kept] + +-- Empty conditioning slices and an empty environment have zero integrated contribution. +example : rowNormPow 4 2 (1 / 2) (fun (_ : Fin 2 × Fin 2) (_ : Fin 2) => False) + kept (fun _ x y => meanError x y) = 0 := by + simp [rowNormPow] + +example : rowNormPow 4 1 1 (fun (_ : Empty) (_ : Fin 1) => True) + (fun _ _ => True) (fun _ _ _ => 5) = 0 := by + simp [rowNormPow] + +private instance : Fact (Nat.Prime 5) := ⟨by decide⟩ + +-- The concrete affine channel has a conditional bound strictly below one. +open scoped Classical in +example : + (#{σ | affineRetains 5 1 1 σ 0 ∧ heavyCountEvent + (fun σ (y : ZMod 5) => affineRetains 5 1 1 σ y) (fun _ => 1 / 3) 1 8 σ} : ℝ) ≤ + (11 / 12) * #{σ | affineRetains 5 1 1 σ 0} := by + classical + have h := card_heavyCountEvent_affineRetains_le + (V := ZMod 5) (P := 5) (H := 1) (ident := id) Function.injective_id + (a := 1 / 5) (by norm_num) (by norm_num) (Lt := 1) (by norm_num) + (d := fun _ => 1 / 3) (ρ := 1) (M := 1 / 3) + (by norm_num) (by norm_num) (fun _ => by norm_num) (by norm_num) + (n := 8) (by decide) 0 + norm_num at h ⊢ + exact h + +private abbrev forced (_ : Fin 5) (y : Fin 5) : Prop := y = 0 + +-- The actual nonempty heavy event controls the retained maximum after narrowing the usage mask. +open scoped Classical in +example : + vertexNormPow 4 5 1 (fun (_ _ : Fin 5) => True) (fun σ _ => + if heavyCountEvent correlated (fun _ => 1 / 3) 1 8 σ then + kthLargest 1 {y | forced σ y} (fun _ => |(2 : ℝ)|) else 0) ≤ + (7 / 12) * rowNormPow 4 5 1 (fun (_ _ : Fin 5) => True) forced (fun _ _ _ => 2) := by + classical + have hpair : ∀ x y w : Fin 5, w ≠ y → + (#{σ | True ∧ forced σ y ∧ correlated σ w} : ℝ) ≤ + (1 : ℝ) * (1 / 5) * #{σ | True ∧ forced σ y} := by + intro _ y w hwy + by_cases hy : y = 0 + · subst y + have hs : ({σ : Fin 5 | correlated σ w} : Finset (Fin 5)) = {0} := by + ext σ + simp [correlated, hwy] + norm_num [forced, hs] + · simp [forced, hy] + have h := vertexNormPow_heavyCountEvent_le (Ω := Fin 5) (V := Fin 5) + (s := 4) (N := 5) (u := 1) + (by decide) (by norm_num) (fun (_ _ : Fin 5) => True) correlated forced + (a := 1 / 5) (ρ := 1) (c := 1) (M := 1 / 3) (n := 8) + (by norm_num) (by norm_num) (by norm_num) (by norm_num) (by decide) + (fun _ _ => 1 / 3) (fun _ _ => by norm_num) (fun _ => by norm_num) + (by + intro x y w hwy + convert hpair x y w hwy using 1 + congr 2 + ext σ + simp) (fun _ _ => 2) + have hfactor : (2 * (1 + 4 * (1 : ℝ) * (1 / 3)) / (((8 : ℕ) : ℝ) * 1)) = 7 / 12 := by + norm_num + rw [hfactor] at h + exact h + +end ComplexityTests.HeavyCountRarity From c1b1f794e1f5b18ab86fc8a4e91bd77cd6d98cf1 Mon Sep 17 00:00:00 2001 From: Samuel Schlesinger Date: Fri, 30 Oct 2026 16:53:29 +0000 Subject: [PATCH 14/19] feat(logspace): instantiate stationary polynomial atom rows Add the concrete preparation, auxiliary-score, and broad-witness row consumers of the stationary-reference compression results for issue #1721. The three-constructor PolynomialAtomRow selects actual rational polynomial functions; no scalar support or regularity contract is assumed. Prove strict retained support, zero default output, rank flatness, stationary preservation, and a weighted fourth-root comparison with a constant quantified before the endpoint type, row, rank, schedule, and error envelopes. Bridge the existing Matrix.atomPrep and Matrix.auxScore expressions at their zero-padded ranks. Source mapping: OpenAI2026LogSpace revision 7ef5c0cc, atoms.tex Section 5.5 support margins and compression-threshold table, and compression.tex Section 8.3 Lemma 8.2 stationary preservation/root comparison. This is the explicit fourth-moment adaptation, not the source's eighth-root endpoint. The sufficient scale margin is 0 < eta <= theta/10000. Normalized main atoms, incoming-gate assembly, access enumeration, overflow stability, and machine resource bounds remain open. No curated abstract changes. Tests construct nonzero actual preloss, move the true witness rank into its polynomial transition, prove positive output and positive root discrepancy, and apply the uniform weighted theorem. A remaining compression group changes the default and erases a nonzero second coordinate while preserving the witness. A separate K > cardinality example distinguishes positive dummy padding from zero padding, with a signed raw coordinate. Validation: library and tests independently compiled without diagnostics using Lean 4.36.0-rc2 and -DwarningAsError=true under project linter options, private outputs and read-only shared dependencies. Focused hygiene --check-simp and staged git diff --check pass. Full integration gates are coordinator-owned. No aggregate changes. Authored with AI assistance by worker codex-logspace-polynomial-cutoffs-20261030; independent review pending. Dependencies: local integration merge 35e8a8ec combines independently reviewed PolynomialAtomCutoffs a4eae07b and Stationary c7873d03 unchanged. Only the two new PolynomialAtomRows files belong to this implementation. Independent non-author source/API review by lean_environment approved exact source revision 5925d6e06da530885fbf5144a844439fcf8084a6 and its unchanged reviewed cutoff/compression dependencies, with no findings. The two implementation files are unchanged after joining the published dependency lanes. Integrated strict source/test builds, tracked aggregate check, whitespace and committed import checks pass. Full integration gates run in PR CI. --- Complexity.lean | 1 + .../Probability/PolynomialAtomRows.lean | 271 ++++++++++++++++++ ComplexityTests/PolynomialAtomRows.lean | 254 ++++++++++++++++ 3 files changed, 526 insertions(+) create mode 100644 Complexity/Foundations/Probability/PolynomialAtomRows.lean create mode 100644 ComplexityTests/PolynomialAtomRows.lean diff --git a/Complexity.lean b/Complexity.lean index 1ebdc52dc5..3992c6b222 100644 --- a/Complexity.lean +++ b/Complexity.lean @@ -2741,6 +2741,7 @@ public import Complexity.Foundations.Probability.Gaussian.Real public import Complexity.Foundations.Probability.Gaussian.Sheppard public import Complexity.Foundations.Probability.HierarchyParams public import Complexity.Foundations.Probability.PolynomialAtomCutoffs +public import Complexity.Foundations.Probability.PolynomialAtomRows public import Complexity.Foundations.Probability.RootMetric public import Complexity.Foundations.Probability.SecondMoment public import Complexity.Foundations.Probability.StochasticAtom diff --git a/Complexity/Foundations/Probability/PolynomialAtomRows.lean b/Complexity/Foundations/Probability/PolynomialAtomRows.lean new file mode 100644 index 0000000000..97f83fd5b7 --- /dev/null +++ b/Complexity/Foundations/Probability/PolynomialAtomRows.lean @@ -0,0 +1,271 @@ +/- +Copyright (c) 2026 Samuel Schlesinger. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Samuel Schlesinger +-/ + +module +-- upstream: candidate + +public import Complexity.Foundations.Probability.PolynomialAtomCutoffs +public import Complexity.Foundations.Probability.CorrectionAtom +public import Complexity.Foundations.Analysis.RowCompression.Stationary +import Mathlib.Tactic.Linarith +import Mathlib.Tactic.Positivity + +/-! +# Polynomial atom rows under stationary compression + +The preparation, auxiliary score, and broad witness are concrete two-variable polynomial +functions from `Complexity.Foundations.Probability.PolynomialAtomCutoffs`. This file proves +their strict retained-support bound, zero default output, preservation along the constructed +stationary reference, and a weighted fourth-root comparison with truth. `PolynomialAtomRow` +is a closed choice of those three functions; no scalar regularity or support law is assumed. + +The common sufficient margin is `0 < η ≤ θ / 10000`, where `θ` is the atom's support scale +and `η` is the compression scale. The comparison constant depends only on the chosen function, +`θ`, and `η`; it is independent of the row, finite retained set, rank, schedule, and error +envelope. The rank includes the actual compressed default. Only the true row uses zero padding. +The bridges to `Matrix.atomPrep` and `Matrix.auxScore` use their existing zero-padded ranks. + +These results instantiate the scalar laws in the stationary-reference portion of +[OpenAI2026LogSpace, Lemma 8.2] for the three pre-incoming row functions of Section 5.5. +They belong to the fourth-moment adaptation in complexitylib issue #1721; the pinned paper +uses eighth roots. Normalized main atoms, incoming-gate assembly, enumeration, post-overflow +stability, and a machine-space certificate remain separate. + +## Main results + +* `Cslib.PolynomialAtomRow.card_filter_eval_ne_zero_lt`: actual support has fewer than `K` entries. +* `Cslib.PolynomialAtomRow.stationaryContinuation_eval_eq`: preservation through the remaining + real compression schedule after a prefix without overflow. +* `Cslib.PolynomialAtomRow.exists_stationaryContinuation_root_bound`: a uniform weighted + fourth-root discrepancy bound with all scalar hypotheses discharged. + +## References + +* [OpenAI, *Exact Derandomization of Logarithmic Space: L = RL = BPL*][OpenAI2026LogSpace], + Section 5.5, support-margin lemma and compression-threshold table; Section 8.3, Lemma 8.2 + (23 September 2026, revision `7ef5c0cc`, not peer reviewed). +-/ + +public section + +namespace Cslib + +/-- The three concrete pre-incoming row functions with polynomial fourth-root regularity. -/ +inductive PolynomialAtomRow + | preparation + | auxiliary + | witness + deriving DecidableEq + +namespace PolynomialAtomRow + +open Finset RowCompression + +/-- Evaluate the chosen concrete function, using rational arithmetic for rational arguments. -/ +@[expose] def eval {R : Type*} [Field R] [LinearOrder R] (kind : PolynomialAtomRow) + (θ v r : R) : R := + match kind with + | preparation => polynomialPrepRow4 θ v r + | auxiliary => polynomialAuxCutoff4 θ v r + | witness => polynomialWitnessCutoff4 θ v r + +/-- The closed entry-zero threshold of the chosen function. -/ +@[expose] def entryThreshold {R : Type*} [Field R] (kind : PolynomialAtomRow) (θ : R) : R := + match kind with + | preparation => θ / 2 + | auxiliary => θ / 8 + | witness => 82 * θ / 1000 + +/-- The closed rank-zero threshold of the chosen function. -/ +@[expose] def gateThreshold {R : Type*} [Field R] (kind : PolynomialAtomRow) (θ : R) : R := + match kind with + | preparation => θ / 500 + | auxiliary => θ / 50 + | witness => 27 * θ / 1000 + +variable (kind : PolynomialAtomRow) {θ η v r r' : ℝ} + +theorem eval_nonneg (θ v r : ℝ) : 0 ≤ kind.eval θ v r := by + cases kind + · exact polynomialPrepRow4_nonneg _ _ _ + · exact polynomialAuxCutoff4_nonneg _ _ _ + · exact polynomialWitnessCutoff4_nonneg _ _ _ + +theorem eval_le_one (θ v r : ℝ) : kind.eval θ v r ≤ 1 := by + cases kind + · exact polynomialPrepRow4_le_one _ _ _ + · exact polynomialAuxCutoff4_le_one _ _ _ + · exact polynomialWitnessCutoff4_le_one _ _ _ + +theorem entryThreshold_pos (hθ : 0 < θ) : 0 < kind.entryThreshold θ := by + cases kind <;> dsimp only [entryThreshold] <;> positivity + +theorem gateThreshold_pos (hθ : 0 < θ) : 0 < kind.gateThreshold θ := by + cases kind <;> dsimp only [gateThreshold] <;> positivity + +theorem three_mul_gateThreshold_lt_entryThreshold (hθ : 0 < θ) : + 3 * kind.gateThreshold θ < kind.entryThreshold θ := by + cases kind <;> dsimp only [gateThreshold, entryThreshold] <;> linarith + +theorem gateThreshold_lt_entryThreshold (hθ : 0 < θ) : + kind.gateThreshold θ < kind.entryThreshold θ := by + linarith [kind.gateThreshold_pos hθ, kind.three_mul_gateThreshold_lt_entryThreshold hθ] + +theorem scale_lt_gateThreshold (hθ : 0 < θ) (hη : η ≤ θ / 10000) : + η < kind.gateThreshold θ := by + cases kind <;> dsimp only [gateThreshold] <;> linarith + +theorem eval_eq_zero_of_entry_le (hθ : 0 < θ) (hv : v ≤ kind.entryThreshold θ) : + kind.eval θ v r = 0 := by + cases kind + · exact polynomialPrepRow4_eq_zero_of_entry_le hθ hv + · exact polynomialAuxCutoff4_eq_zero_of_entry_le hθ hv + · exact polynomialWitnessCutoff4_eq_zero_of_entry_le hθ hv + +theorem eval_eq_zero_of_rank_ge (hθ : 0 < θ) (hr : kind.gateThreshold θ ≤ r) : + kind.eval θ v r = 0 := by + cases kind + · exact polynomialPrepRow4_eq_zero_of_rank_ge hθ hr + · exact polynomialAuxCutoff4_eq_zero_of_rank_ge hθ hr + · exact polynomialWitnessCutoff4_eq_zero_of_rank_ge hθ hr + +/-- All three actual rank factors are constant throughout the common flat region. -/ +theorem eval_eq_of_rank_le (hθ : 0 < θ) (hη : η ≤ θ / 10000) (hr : r ≤ η) (hr' : r' ≤ η) : + kind.eval θ v r = kind.eval θ v r' := by + cases kind + · exact (polynomialPrepRow4_of_rank_le hθ (by linarith)).trans + (polynomialPrepRow4_of_rank_le hθ (by linarith)).symm + · exact (polynomialAuxCutoff4_of_rank_le hθ (by linarith)).trans + (polynomialAuxCutoff4_of_rank_le hθ (by linarith)).symm + · exact (polynomialWitnessCutoff4_of_rank_le hθ (by linarith)).trans + (polynomialWitnessCutoff4_of_rank_le hθ (by linarith)).symm + +theorem exists_abs_eval_root_sub_le (θ : ℝ) : + ∃ C : ℝ, 0 ≤ C ∧ ∀ v r v' r', + |kind.eval θ v r ^ (4⁻¹ : ℝ) - kind.eval θ v' r' ^ (4⁻¹ : ℝ)| ≤ + C * (|v - v'| + |r - r'|) := by + cases kind + · exact exists_abs_polynomialPrepRow4_root_sub_le θ + · exact exists_abs_polynomialAuxCutoff4_root_sub_le θ + · exact exists_abs_polynomialWitnessCutoff4_root_sub_le θ + +variable {ι : Type*} {s : Finset ι} {K : ℕ} {z : ℝ} {w : ι → Fin 2 → ℝ} + +/-- Zero padding in the compression rank agrees with the existing atom rank, including when +`K` exceeds the retained cardinality or the raw first coordinates are negative. -/ +theorem eval_firstRank_zero (θ v : ℝ) : + kind.eval θ v (firstRank s K 0 w) = kind.eval θ v (kthLargest K s fun y => w y 0) := by + rw [firstRank, max_eq_right kthLargest_nonneg] + +/-- The actual default entry always has zero output, with no sign restriction on the default. -/ +theorem eval_default_eq_zero (hθ : 0 < θ) : + kind.eval θ z (firstRank s K z w) = 0 := by + by_cases hz : z ≤ kind.entryThreshold θ + · exact kind.eval_eq_zero_of_entry_le hθ hz + exact kind.eval_eq_zero_of_rank_ge hθ + ((kind.gateThreshold_lt_entryThreshold hθ).le.trans + ((not_le.mp hz).le.trans default_le_firstRank)) + +/-- Fewer than `K` retained endpoints have nonzero output for the actual padded rank. -/ +theorem card_filter_eval_ne_zero_lt (hθ : 0 < θ) (hK : 0 < K) : + #{y ∈ s | kind.eval θ (w y 0) (firstRank s K z w) ≠ 0} < K := by + classical + by_contra hlt + have hle : K ≤ #{y ∈ s | kind.eval θ (w y 0) (firstRank s K z w) ≠ 0} := not_lt.mp hlt + have hsub : ({y ∈ s | kind.eval θ (w y 0) (firstRank s K z w) ≠ 0} : Finset ι) ⊆ + {y ∈ s | kind.entryThreshold θ < w y 0} := by + intro y hy + obtain ⟨hys, hy⟩ := mem_filter.mp hy + exact mem_filter.mpr ⟨hys, not_le.mp fun h => hy (kind.eval_eq_zero_of_entry_le hθ h)⟩ + have hrank : kind.entryThreshold θ < kthLargest K s (fun y => w y 0) := + (lt_kthLargest_iff hK (kind.entryThreshold_pos hθ).le).mpr (hle.trans (card_le_card hsub)) + obtain ⟨y, hy⟩ := card_pos.mp (hK.trans_le hle) + exact (mem_filter.mp hy).2 (kind.eval_eq_zero_of_rank_ge hθ + ((kind.gateThreshold_lt_entryThreshold hθ).le.trans (hrank.le.trans kthLargest_le_firstRank))) + +variable {n : ℕ → ℕ} {Δ : ℕ → ι → Fin 2 → ℝ} {a : State ι} {truth : ι → Fin 2 → ℝ} + +/-- The constructed stationary reference preserves each actual polynomial row output through +the remaining compression schedule. Scalar support, gate, flatness, and margin laws are proved. -/ +theorem stationaryContinuation_eval_eq (hθ : 0 < θ) (hη : 0 ≤ η) (hmargin : η ≤ θ / 10000) + (hK : 0 < K) (m j r : ℕ) (hr : j + r ≤ m) + (hno : ∀ i < j, + stepThreshold s n (fun _ => K) (dyadicFloor η m) Δ a i ≤ dyadicFloor η m i) + (hfirst : ∀ y ∈ s, 0 ≤ truth y 0) (hsecond : ∀ y ∈ s, |truth y 1| ≤ η / 2) + (hn : ∀ i, j ≤ i → i < m → K ≤ n i) (y : ι) (hy : y ∈ s) : + let b := stationaryState s n (fun _ => K) (dyadicFloor η m) Δ a truth j + let c := stationaryContinuation s n K (dyadicFloor η m) Δ a truth j r + kind.eval θ (c.row y 0) (firstRank s K c.defaultValue c.row) = + kind.eval θ (b.row y 0) (firstRank s K b.defaultValue b.row) := by + exact stationaryContinuation_output_eq_dyadic (H := fun x _ q => kind.eval θ x q) + hη hK m j r hr hno hfirst hsecond hn (kind.scale_lt_gateThreshold hθ hmargin) + (kind.three_mul_gateThreshold_lt_entryThreshold hθ) + (fun _ _ _ hx => kind.eval_eq_zero_of_entry_le hθ hx) + (fun _ _ _ hq => kind.eval_eq_zero_of_rank_ge hθ hq) + (fun _ _ _ _ hq hq' => kind.eval_eq_of_rank_le hθ hmargin hq.2 hq'.2) y hy + +/-- A constant depending only on the concrete row function and its two scales bounds the +continued reference's fourth-root error by actual prefix-error envelopes. No Lipschitz or +support law is assumed; low-target endpoints need no relative-error hypothesis. -/ +theorem exists_stationaryContinuation_root_bound (hθ : 0 < θ) (hη : 0 < η) + (hmargin : η ≤ θ / 10000) : + ∃ C : ℝ, 0 ≤ C ∧ ∀ {ι : Type*} (s : Finset ι) (n : ℕ → ℕ) (Δ : ℕ → ι → Fin 2 → ℝ) + (a : State ι) (truth : ι → Fin 2 → ℝ) (K : ℕ), + 0 < K → 0 ≤ a.defaultValue → a.defaultValue ≤ η / 2 → + ∀ (m j r : ℕ), j + r ≤ m → + (∀ i < j, stepThreshold s n (fun _ => K) (dyadicFloor η m) Δ a i ≤ dyadicFloor η m i) → + (∀ y ∈ s, 0 ≤ truth y 0) → (∀ y ∈ s, |truth y 1| ≤ η / 2) → + (∀ i, j ≤ i → i < m → K ≤ n i) → + ∀ (ε : ℕ → ℝ), (∀ i < j, 0 ≤ ε i) → + (∀ i < j, ∀ y ∈ s, η / 2 ≤ truth y 0 → + clippedError (truth y 0) (truth y 1) (uncompressedRow Δ a.row (i + 1) y) ≤ ε i) → + ∀ y ∈ s, + let c := stationaryContinuation s n K (dyadicFloor η m) Δ a truth j r + |kind.eval θ (c.row y 0) (firstRank s K c.defaultValue c.row) ^ (4⁻¹ : ℝ) - + kind.eval θ (truth y 0) (firstRank s K 0 truth) ^ (4⁻¹ : ℝ)| ≤ + C * ∑ i ∈ range j, dyadicFloor η m i * ε i := by + obtain ⟨L, hL, hroot⟩ := kind.exists_abs_eval_root_sub_le θ + refine ⟨3 * L * (12 * (1 + η / 2) / (η / 2)), by positivity, ?_⟩ + intro ι s n Δ a truth K hK ha haη m j r hr hno hfirst hsecond hn ε hε herr y hy + have hentry : ∀ (x v q : ℝ), x ≤ η → (fun x (_ : ℝ) q => kind.eval θ x q) x v q = 0 := by + intro x _ q hx + exact kind.eval_eq_zero_of_entry_le hθ (hx.trans + ((kind.scale_lt_gateThreshold hθ hmargin).le.trans + (kind.gateThreshold_lt_entryThreshold hθ).le)) + have hbound := abs_stationaryState_root_sub_le_weighted_dyadic + (H := fun x _ q => kind.eval θ x q) (p := (4⁻¹ : ℝ)) (C := L) + hη hK hL ha haη m j ((Nat.le_add_right j r).trans hr) hno hε herr hentry + (fun _ _ _ _ hq hq' => kind.eval_eq_of_rank_le hθ hmargin hq.2 hq'.2) + (fun x v q x' v' q' _ _ _ _ => (hroot x q x' q').trans + (mul_le_mul_of_nonneg_left (by linarith [abs_nonneg (v - v')]) hL)) y hy + dsimp only + rw [kind.stationaryContinuation_eval_eq hθ hη.le hmargin hK m j r hr hno hfirst hsecond hn y hy] + simpa only [mul_assoc] using hbound + +end PolynomialAtomRow +end Cslib + +namespace Matrix + +open Finset + +variable {V : Type*} + +/-- The existing preparatory expression is the concrete polynomial preparation row. -/ +theorem atomPrep_polynomial_eq (θ : ℝ) (K : ℕ) (a : ℝ) (G : Matrix V V ℝ) + (T : Finset V) (x y : V) : + atomPrep (Cslib.polynomialPrepCutoff4 θ) (Cslib.polynomialRowCutoff4 θ) K a G T x y = + Cslib.PolynomialAtomRow.preparation.eval θ (G x y / a) + (kthLargest K T fun z => G x z / a) := rfl + +/-- The existing auxiliary-score expression is the concrete polynomial auxiliary row. -/ +theorem auxScore_polynomial_eq (θ : ℝ) (K : ℕ) (a : ℝ) (G : Matrix V V ℝ) + (T : Finset V) (x y : V) : + auxScore (Cslib.polynomialAuxCutoff4 θ) K a G T x y = + Cslib.PolynomialAtomRow.auxiliary.eval θ (G x y / a) + (kthLargest K T fun z => G x z / a) := rfl + +end Matrix diff --git a/ComplexityTests/PolynomialAtomRows.lean b/ComplexityTests/PolynomialAtomRows.lean new file mode 100644 index 0000000000..d60379331b --- /dev/null +++ b/ComplexityTests/PolynomialAtomRows.lean @@ -0,0 +1,254 @@ +/- +Copyright (c) 2026 Samuel Schlesinger. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Samuel Schlesinger +-/ + +import Complexity.Foundations.Probability.PolynomialAtomRows +import Mathlib.LinearAlgebra.Matrix.Notation +import Mathlib.Tactic.FinCases +import Mathlib.Tactic.Linarith +import Mathlib.Tactic.NormNum + +/-! +# Concrete polynomial stationary rows + +A nonzero first increment incurs actual preloss `1/2097152`. Adding it to a true low entry +of `260` moves the witness rank strictly into its transition interval `(260,270)`. The true +high-endpoint witness is one, while the reference witness lies strictly between zero and one. +The remaining group raises the default and erases a second-coordinate value of `1/4`, yet +preserves that nonzero witness. Its fourth-root error satisfies the new weighted bound. +-/ + +namespace ComplexityTests.PolynomialAtomRows + +open Finset Cslib Cslib.RowCompression + +private def initial : State (Fin 2) := { defaultValue := 0, row := ![![900, 0], ![0, 0]] } + +private noncomputable def truth : Fin 2 → Fin 2 → ℝ := ![![900, 0], ![260, 1 / 4]] + +private noncomputable def increments (i : ℕ) : Fin 2 → Fin 2 → ℝ := + if i = 0 then ![![0, 0], ![1 / 2097152, 0]] else 0 + +private noncomputable def rawRow : Fin 2 → Fin 2 → ℝ := ![![900, 0], ![1 / 2097152, 0]] + +private theorem floor_zero : dyadicFloor 1 2 0 = 1 / 1048576 := by + norm_num [dyadicFloor, dyadicSlack] + +private theorem raw_rank_le : kthLargest 2 univ (fun y => rawRow y 0) ≤ 1 / 1048576 := by + refine not_lt.mp fun hlt => ?_ + have hcard := (lt_kthLargest_iff (by norm_num) + (by norm_num : (0 : ℝ) ≤ 1 / 1048576)).mp hlt + have hsupport : ({y | (1 / 1048576 : ℝ) < rawRow y 0} : Finset (Fin 2)) = {0} := by + ext y + fin_cases y <;> norm_num [rawRow] + rw [hsupport] at hcard + norm_num at hcard + +private theorem raw_threshold : threshold univ 2 (1 / 1048576) 0 rawRow = 1 / 1048576 := by + have hs : (fun y => entrySize (rawRow y)) = fun y => rawRow y 0 := by + funext y + fin_cases y <;> norm_num [entrySize, rawRow] + refine le_antisymm ?_ floor_le_threshold + unfold threshold + rw [hs] + exact max_le (by norm_num) (max_le le_rfl raw_rank_le) + +private theorem raw_default : newDefault univ 2 2 (1 / 1048576) 0 rawRow = 1 / 1048576 := by + unfold newDefault + rw [raw_threshold] + exact max_eq_left ((min_le_left _ _).trans (max_le (by norm_num) raw_rank_le)) + +private theorem raw_one : uncompressedRow increments initial.row 1 = rawRow := by + funext y ν + fin_cases y <;> fin_cases ν <;> norm_num [uncompressedRow, initial, increments, rawRow] + +private theorem actual_one : + iterate univ (fun _ => 2) (fun _ => 2) (dyadicFloor 1 2) increments initial 1 = + { defaultValue := 1 / 1048576, row := ![![900, 0], ![1 / 1048576, 0]] } := by + have hin : initial.row + increments 0 = rawRow := by + funext y ν + fin_cases y <;> fin_cases ν <;> norm_num [initial, increments, rawRow] + change advance univ 2 2 (dyadicFloor 1 2 0) (increments 0) initial = _ + unfold advance + rw [hin, floor_zero] + change State.mk (newDefault univ 2 2 (1 / 1048576) 0 rawRow) + (update univ 2 2 (1 / 1048576) 0 rawRow) = _ + rw [raw_default] + congr 1 + unfold update + rw [raw_threshold, raw_default] + funext y ν + fin_cases y <;> fin_cases ν <;> + norm_num [updateEntry, radius, entrySize, defaultEntry, rawRow] + +private theorem no_overflow : ∀ i < 1, + stepThreshold univ (fun _ => 2) (fun _ => 2) (dyadicFloor 1 2) increments initial i ≤ + dyadicFloor 1 2 i := by + intro i hi + have hi0 : i = 0 := by omega + subst i + have hin : inputRow univ (fun _ => 2) (fun _ => 2) (dyadicFloor 1 2) increments initial 0 = + rawRow := by + funext y ν + fin_cases y <;> fin_cases ν <;> norm_num [inputRow, initial, increments, rawRow] + unfold stepThreshold + rw [hin, iterate_zero, floor_zero] + exact raw_threshold.le + +private noncomputable def reference : State (Fin 2) := + stationaryState univ (fun _ => 2) (fun _ => 2) (dyadicFloor 1 2) increments initial truth 1 + +private theorem reference_eq : reference = + { defaultValue := 1 / 1048576, row := ![![900, 0], ![260 + 1 / 2097152, 1 / 4]] } := by + unfold reference stationaryState + rw [actual_one, raw_one] + congr 1 + funext y ν + fin_cases y <;> fin_cases ν <;> norm_num [truth, rawRow] + +example : increments 0 1 0 = 1 / 2097152 ∧ + reference.row 1 0 - truth 1 0 = 1 / 2097152 := by + rw [reference_eq] + norm_num [increments, truth] + +private theorem reference_rank : firstRank univ 2 reference.defaultValue reference.row = + 260 + 1 / 2097152 := by + have hle : kthLargest 2 univ (fun y => reference.row y 0) ≤ 260 + 1 / 2097152 := by + refine not_lt.mp fun hlt => ?_ + have hc := (lt_kthLargest_iff (by norm_num) + (by norm_num : (0 : ℝ) ≤ 260 + 1 / 2097152)).mp hlt + have hs : ({y | (260 + 1 / 2097152 : ℝ) < reference.row y 0} : Finset (Fin 2)) = {0} := by + ext y + rw [reference_eq] + fin_cases y <;> norm_num + rw [hs] at hc + norm_num at hc + have hge : (260 + 1 / 2097152 : ℝ) ≤ kthLargest 2 univ (fun y => reference.row y 0) := by + apply (le_kthLargest_iff (by norm_num) (by norm_num : (0 : ℝ) < 260 + 1 / 2097152)).mpr + have hs : ({y | (260 + 1 / 2097152 : ℝ) ≤ reference.row y 0} : Finset (Fin 2)) = univ := by + ext y + rw [reference_eq] + fin_cases y <;> norm_num + rw [hs] + norm_num + exact le_antisymm (max_le (by rw [reference_eq]; norm_num) hle) + (hge.trans kthLargest_le_firstRank) + +private theorem true_rank : firstRank univ 2 0 truth = 260 := by + norm_num [firstRank, kthLargest, truth, Fin.univ_succ, filter_insert, filter_singleton] + +private noncomputable def output (a : State (Fin 2)) : ℝ := + PolynomialAtomRow.witness.eval 10000 (a.row 0 0) (firstRank univ 2 a.defaultValue a.row) + +private theorem reference_output : output reference = + 1 - polynomialSwitch4 260 270 (260 + 1 / 2097152) := by + unfold output + rw [reference_rank, reference_eq] + change polynomialWitnessCutoff4 10000 900 (260 + 1 / 2097152) = _ + norm_num only [polynomialWitnessCutoff4] + rw [polynomialSwitch4_of_ge (by norm_num) le_rfl, one_mul] + +private theorem output_between : 0 < output reference ∧ output reference < 1 := by + rw [reference_output] + have h0 := polynomialSwitch4_nonneg 260 270 (260 + 1 / 2097152) + have h1 := polynomialSwitch4_le_one 260 270 (260 + 1 / 2097152) + have hn0 : polynomialSwitch4 (260 : ℝ) 270 (260 + 1 / 2097152) ≠ 0 := by + rw [ne_eq, polynomialSwitch4_eq_zero_iff (by norm_num)] + norm_num + have hn1 : polynomialSwitch4 (260 : ℝ) 270 (260 + 1 / 2097152) ≠ 1 := by + rw [ne_eq, polynomialSwitch4_eq_one_iff (by norm_num)] + norm_num + constructor + · by_contra hn + exact hn1 (by linarith) + · by_contra hn + exact hn0 (by linarith) + +private theorem true_output : PolynomialAtomRow.witness.eval 10000 (truth 0 0) + (firstRank univ 2 0 truth) = 1 := by + rw [true_rank] + exact polynomialWitnessCutoff4_eq_one (by norm_num) (by norm_num [truth]) (by norm_num) + +private noncomputable def continued : State (Fin 2) := + stationaryContinuation univ (fun _ => 2) 2 (dyadicFloor 1 2) increments initial truth 1 1 + +private theorem preserved : output continued = output reference := by + exact PolynomialAtomRow.witness.stationaryContinuation_eval_eq + (s := univ) (n := fun _ => 2) (Δ := increments) (a := initial) (truth := truth) + (θ := 10000) (η := 1) (by norm_num) (by norm_num) (by norm_num) (by norm_num) + 2 1 1 (by norm_num) no_overflow + (fun y _ => by fin_cases y <;> norm_num [truth]) + (fun y _ => by fin_cases y <;> norm_num [truth]) (by intros; norm_num) 0 (mem_univ 0) + +-- The remaining group changes both the actual default and a row coordinate. +example : reference.defaultValue < continued.defaultValue ∧ + reference.row 1 1 = 1 / 4 ∧ continued.row 1 1 = 0 := by + have hc : continued = advance univ 2 2 (dyadicFloor 1 2 1) 0 reference := rfl + rw [hc, reference_eq] + norm_num [advance, update, newDefault, threshold, firstRank, kthLargest, entrySize, + dyadicFloor, dyadicSlack, Fin.univ_succ, filter_insert, filter_singleton, + updateEntry, radius, defaultEntry] + +-- The preserved output and its root discrepancy are both nonzero. +example : 0 < output continued ∧ + 0 < |output continued ^ (4⁻¹ : ℝ) - + PolynomialAtomRow.witness.eval 10000 (truth 0 0) (firstRank univ 2 0 truth) ^ (4⁻¹ : ℝ)| := by + rw [preserved, true_output, Real.one_rpow] + refine ⟨output_between.1, abs_pos.mpr ?_⟩ + exact sub_ne_zero.mpr (ne_of_lt (Real.rpow_lt_one output_between.1.le output_between.2 + (by norm_num))) + +-- Apply the theorem to a valid raw-prefix error envelope, with no scalar-law premises. +example : ∃ C : ℝ, 0 ≤ C ∧ + |output continued ^ (4⁻¹ : ℝ) - 1| ≤ C / 1048576 := by + obtain ⟨C, hC, hbound⟩ := PolynomialAtomRow.witness.exists_stationaryContinuation_root_bound + (θ := 10000) (η := 1) (by norm_num) (by norm_num) (by norm_num) + refine ⟨C, hC, ?_⟩ + have h := hbound univ (fun _ => 2) increments initial truth 2 (by norm_num) + (by norm_num [initial]) (by norm_num [initial]) 2 1 1 (by norm_num) no_overflow + (fun y _ => by fin_cases y <;> norm_num [truth]) + (fun y _ => by fin_cases y <;> norm_num [truth]) (by intros; norm_num) + (fun _ => 1) (by intros; norm_num) (fun _ _ _ _ _ => clippedError_le_one _ _ _) + 0 (mem_univ 0) + change |output continued ^ (4⁻¹ : ℝ) - + PolynomialAtomRow.witness.eval 10000 (truth 0 0) + (firstRank univ 2 0 truth) ^ (4⁻¹ : ℝ)| ≤ _ at h + simpa only [true_output, Real.one_rpow, sum_range_succ, sum_range_zero, zero_add, mul_one, + floor_zero, div_eq_mul_inv, one_mul] using h + +-- The actual retained output has strict capacity, and a positive default still emits zero. +example : #{y ∈ (univ : Finset (Fin 2)) | PolynomialAtomRow.witness.eval 10000 + (reference.row y 0) (firstRank univ 2 reference.defaultValue reference.row) ≠ 0} < 2 := + PolynomialAtomRow.witness.card_filter_eval_ne_zero_lt (by norm_num) (by norm_num) + +example : PolynomialAtomRow.witness.eval 10000 reference.defaultValue + (firstRank univ 2 reference.defaultValue reference.row) = 0 := + PolynomialAtomRow.witness.eval_default_eq_zero (by norm_num) + +-- When K exceeds the retained cardinality, positive dummy padding still affects the output. +-- The second raw coordinate is negative; it is not an input to this pre-incoming function. +example : + let w : Unit → Fin 2 → ℝ := fun _ => ![900, -7] + PolynomialAtomRow.witness.eval 10000 900 (firstRank univ 2 265 w) = 1 / 2 ∧ + PolynomialAtomRow.witness.eval 10000 900 (firstRank univ 2 0 w) = 1 := by + norm_num [PolynomialAtomRow.eval, firstRank, kthLargest, polynomialWitnessCutoff4, + polynomialSwitch4, polynomialTransition4, transitionPolynomial4] + +-- Both bridges expose the polynomial row functions in the existing atom API. +example (G : Matrix (Fin 2) (Fin 2) ℝ) (x y : Fin 2) : + Matrix.atomPrep (polynomialPrepCutoff4 10000) (polynomialRowCutoff4 10000) 2 1 G univ x y = + PolynomialAtomRow.preparation.eval 10000 (G x y) + (firstRank univ 2 0 fun z _ => G x z) := by + rw [Matrix.atomPrep_polynomial_eq, PolynomialAtomRow.eval_firstRank_zero] + simp only [div_one] + +example (G : Matrix (Fin 2) (Fin 2) ℝ) (x y : Fin 2) : + Matrix.auxScore (polynomialAuxCutoff4 10000) 2 1 G univ x y = + PolynomialAtomRow.auxiliary.eval 10000 (G x y) + (firstRank univ 2 0 fun z _ => G x z) := by + rw [Matrix.auxScore_polynomial_eq, PolynomialAtomRow.eval_firstRank_zero] + simp only [div_one] + +end ComplexityTests.PolynomialAtomRows From bb98219ee5322990623409f682f4d9f9aa8c7e3c Mon Sep 17 00:00:00 2001 From: Samuel Schlesinger Date: Fri, 30 Oct 2026 17:10:44 +0000 Subject: [PATCH 15/19] feat(logspace): prove exact sentinel compression invariance Prove Finset.kthLargest_eq_of_eq_or_gt in the existing order-statistic module, preserving Christian Reitwiessner's credit. Values may change arbitrarily when both versions remain strictly above a nonnegative ceiling; if one positive-order rank is at most that ceiling, the actual ranks agree. The boundary rank = ceiling and zero padding are included. Define actual first-coordinate sentinel replacement, leaving every second coordinate unchanged. Derive equality of padded first ranks, size thresholds, and new defaults. The bounded modified rank implies marked cardinality < K. Under the explicit 3R separation, both channels of marked entries are in the compression identity region, and replacement commutes with the concrete update at every retained endpoint. No output equality is assumed. Source mapping for issue #1721: OpenAI2026LogSpace revision 7ef5c0cc, compression.tex Section 8.3, proof of Lemma 8.3, sentinel replacement and removal in the fewer-than-K large-entry case. This is the exact local rank/update argument, independent of the root exponent. Relative-error control through later increments, the iterated coupling, scalar upper saturation, heavy-count closure, and full post-overflow stability remain open. Sentinels are proof devices, not an algorithmic enumeration claim. No curated abstract or catalogue impact; no aggregate changes. Tests use [1000000,4,2,-1] with sentinel 100, K=n=3, positive old default 1/2, and floor 1. Rank and threshold equal the ceiling 2; smaller signed entries actually compress, while a marked second coordinate of -17 is preserved. Further cases exercise K above the retained cardinality and demonstrate why changing a value exactly at the ceiling can change the rank. Validation: KthLargest, Sentinel, and RowCompressionSentinel tests compile without diagnostics under Lean 4.36.0-rc2, warningAsError=true and project linter options, using isolated private outputs and shared dependencies read-only. Focused hygiene --check-simp and staged git diff --check pass. Full integration gates and independent exact-revision review are left to the coordinator. Base is reviewed Reference 10a5168; only these three files belong to this milestone. AI assistance: ChatGPT worker codex-logspace-polynomial-cutoffs-20261030 authored and validated the change. Independent non-author source/API review by agent derandomization_plan approved source revision 68a162675ea79cd7e6e29b0831c725d0dca9bbb2 with no findings. Integrated source and tests are byte-identical to that reviewed revision. Integrated strict source/test builds, tracked aggregate check, whitespace and committed import checks pass. Full integration gates run in PR CI. --- Complexity.lean | 1 + .../Analysis/RowCompression/Sentinel.lean | 184 ++++++++++++++++++ .../Foundations/Data/Finset/KthLargest.lean | 34 +++- ComplexityTests/RowCompressionSentinel.lean | 131 +++++++++++++ 4 files changed, 348 insertions(+), 2 deletions(-) create mode 100644 Complexity/Foundations/Analysis/RowCompression/Sentinel.lean create mode 100644 ComplexityTests/RowCompressionSentinel.lean diff --git a/Complexity.lean b/Complexity.lean index a11b5860a7..3827d9b925 100644 --- a/Complexity.lean +++ b/Complexity.lean @@ -2357,6 +2357,7 @@ public import Complexity.Foundations.Analysis.RowCompression.Floors public import Complexity.Foundations.Analysis.RowCompression.Iteration public import Complexity.Foundations.Analysis.RowCompression.Preloss public import Complexity.Foundations.Analysis.RowCompression.Reference +public import Complexity.Foundations.Analysis.RowCompression.Sentinel public import Complexity.Foundations.Analysis.RowCompression.Stationary public import Complexity.Foundations.Analysis.SpecialFunctions.Arccos public import Complexity.Foundations.Analysis.SpecialFunctions.SmoothSwitch diff --git a/Complexity/Foundations/Analysis/RowCompression/Sentinel.lean b/Complexity/Foundations/Analysis/RowCompression/Sentinel.lean new file mode 100644 index 0000000000..78656333b2 --- /dev/null +++ b/Complexity/Foundations/Analysis/RowCompression/Sentinel.lean @@ -0,0 +1,184 @@ +/- +Copyright (c) 2026 Samuel Schlesinger. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Samuel Schlesinger +-/ + +module +-- upstream: candidate + +public import Complexity.Foundations.Analysis.RowCompression.Reference +import Mathlib.Tactic.Linarith + +/-! +# Exact sentinel replacement under row compression + +Replace the first coordinate at a finite set of marked endpoints by one common positive +sentinel, leaving every second coordinate unchanged. When the modified first rank and size +threshold are at most `R ≥ 0`, and both old and sentinel first coordinates at marked endpoints +are strictly above `3R`, the original and modified calculations have identical ranks, thresholds, +and new defaults. Compression is identity in both channels at marked endpoints, and sentinel +replacement commutes with the actual update on every retained endpoint. + +The proof uses `Finset.kthLargest_eq_of_eq_or_gt`, including its boundary case where a rank equals +the ceiling. It preserves actual padded ranks, rather than only clipped ranks. No bound on the +largest original entry is needed. The modified first-rank bound also implies that fewer than +`K` retained endpoints can be marked. + +This is the exact rank and update step in the sentinel argument of [OpenAI2026LogSpace, +Lemma 8.3], when the proof removes its modification of first coordinates above `L₁`. It does not +identify or store sentinels in the algorithm. Maintaining the large-coordinate bounds through +later increments, iterating the comparison, upper saturation of row outputs, and the full +post-overflow stability estimate remain separate. No root exponent or machine-resource bound +is asserted here. + +## Main definitions + +* `Cslib.RowCompression.sentinelFirst`: change only the marked first coordinates. + +## Main results + +* `Cslib.RowCompression.firstRank_eq_sentinelFirst`, + `Cslib.RowCompression.threshold_eq_sentinelFirst`, + `Cslib.RowCompression.newDefault_eq_sentinelFirst`: exact invariance below the ceiling. +* `Cslib.RowCompression.update_eq_self_of_mem_sentinelFirst`: both channels at marked endpoints + are in the actual compression identity region. +* `Cslib.RowCompression.sentinelFirst_update`: one-step commutation on retained endpoints. + +## References + +* [OpenAI, *Exact Derandomization of Logarithmic Space: L = RL = BPL*][OpenAI2026LogSpace], + Section 8.3, proof of Lemma 8.3, the sentinel replacement and its removal + (23 September 2026, revision `7ef5c0cc`, not peer reviewed). +-/ + +public section + +namespace Cslib.RowCompression + +open Finset + +variable {ι : Type*} + +open scoped Classical in +/-- Replace marked first coordinates by one sentinel, keeping every second coordinate. -/ +@[expose] noncomputable def sentinelFirst (marked : Finset ι) (L : ℝ) + (w : ι → Fin 2 → ℝ) (y : ι) (ν : Fin 2) : ℝ := + if y ∈ marked ∧ ν = 0 then L else w y ν + +variable {s marked : Finset ι} {n K : ℕ} {ρ z R L : ℝ} {w : ι → Fin 2 → ℝ} {y : ι} + +theorem sentinelFirst_zero_of_mem (hy : y ∈ marked) : sentinelFirst marked L w y 0 = L := by + simp [sentinelFirst, hy] + +theorem sentinelFirst_one : sentinelFirst marked L w y 1 = w y 1 := by + simp [sentinelFirst] + +theorem sentinelFirst_of_not_mem (hy : y ∉ marked) : sentinelFirst marked L w y = w y := by + funext ν + simp [sentinelFirst, hy] + +/-- A padded first rank below the ceiling is unchanged by replacing larger first coordinates. -/ +theorem firstRank_eq_sentinelFirst (hK : 0 < K) (hR : 0 ≤ R) (hL : R < L) + (hw : ∀ y ∈ s, y ∈ marked → R < w y 0) + (hq : firstRank s K z (sentinelFirst marked L w) ≤ R) : + firstRank s K z w = firstRank s K z (sentinelFirst marked L w) := by + have hrank : kthLargest K s (fun y => w y 0) = + kthLargest K s (fun y => sentinelFirst marked L w y 0) := by + apply kthLargest_eq_of_eq_or_gt hK hR _ (kthLargest_le_firstRank.trans hq) + intro y hy + by_cases hm : y ∈ marked + · exact Or.inr ⟨hw y hy hm, by rwa [sentinelFirst_zero_of_mem hm]⟩ + · exact Or.inl (congrFun (sentinelFirst_of_not_mem hm) 0).symm + exact congrArg (max z) hrank + +/-- The actual size threshold is unchanged, including its floor and old-default terms. -/ +theorem threshold_eq_sentinelFirst (hn : 0 < n) (hR : 0 ≤ R) (hL : R < L) + (hw : ∀ y ∈ s, y ∈ marked → R < w y 0) + (hu : threshold s n ρ z (sentinelFirst marked L w) ≤ R) : + threshold s n ρ z w = threshold s n ρ z (sentinelFirst marked L w) := by + have hrank : kthLargest n s (fun y => entrySize (w y)) = + kthLargest n s (fun y => entrySize (sentinelFirst marked L w y)) := by + apply kthLargest_eq_of_eq_or_gt hn hR _ + (((le_max_right _ _).trans (le_max_right _ _)).trans hu) + intro y hy + by_cases hm : y ∈ marked + · refine Or.inr ⟨(hw y hy hm).trans_le + ((le_abs_self _).trans (abs_apply_le_entrySize _ 0)), ?_⟩ + have hs : R < sentinelFirst marked L w y 0 := by rwa [sentinelFirst_zero_of_mem hm] + exact hs.trans_le ((le_abs_self _).trans (abs_apply_le_entrySize _ 0)) + · exact Or.inl (congrArg entrySize (sentinelFirst_of_not_mem hm)).symm + exact congrArg (fun q => max z (max ρ q)) hrank + +/-- Both actual rank quantities, and consequently the new default, agree exactly. -/ +theorem newDefault_eq_sentinelFirst (hn : 0 < n) (hK : 0 < K) (hR : 0 ≤ R) (hL : R < L) + (hw : ∀ y ∈ s, y ∈ marked → R < w y 0) + (hq : firstRank s K z (sentinelFirst marked L w) ≤ R) + (hu : threshold s n ρ z (sentinelFirst marked L w) ≤ R) : + newDefault s n K ρ z w = newDefault s n K ρ z (sentinelFirst marked L w) := by + change max (threshold s n ρ z w) (min (firstRank s K z w) (3 * threshold s n ρ z w)) = + max (threshold s n ρ z (sentinelFirst marked L w)) + (min (firstRank s K z (sentinelFirst marked L w)) + (3 * threshold s n ρ z (sentinelFirst marked L w))) + rw [threshold_eq_sentinelFirst hn hR hL hw hu, firstRank_eq_sentinelFirst hK hR hL hw hq] + +/-- The bounded modified first rank itself forces strict cardinality of the marked set. -/ +theorem card_marked_lt_of_sentinelFirst (hK : 0 < K) (hR : 0 ≤ R) (hL : R < L) + (hmarked : marked ⊆ s) (hq : firstRank s K z (sentinelFirst marked L w) ≤ R) : + #marked < K := by + classical + refine not_le.mp fun hc => ?_ + have hsub : marked ⊆ {y ∈ s | R < sentinelFirst marked L w y 0} := by + intro y hy + exact mem_filter.mpr ⟨hmarked hy, by rwa [sentinelFirst_zero_of_mem hy]⟩ + have hlt := (lt_kthLargest_iff hK hR).mpr (hc.trans (card_le_card hsub)) + exact (not_lt_of_ge (kthLargest_le_firstRank.trans hq)) hlt + +/-- Original and sentinel entries are both in the identity region at every marked retained ID. +The second coordinate is untouched, even if it is signed or large. -/ +theorem update_eq_self_of_mem_sentinelFirst (hn : 0 < n) (hR : 0 ≤ R) (hL : 3 * R < L) + (hw : ∀ y ∈ s, y ∈ marked → 3 * R < w y 0) + (hu : threshold s n ρ z (sentinelFirst marked L w) ≤ R) + (hy : y ∈ s) (hm : y ∈ marked) : + update s n K ρ z w y = w y ∧ + update s n K ρ z (sentinelFirst marked L w) y = sentinelFirst marked L w y := by + have hL' : R < L := by linarith + have hw' : ∀ y ∈ s, y ∈ marked → R < w y 0 := by + intro y hy hm + linarith [hw y hy hm] + have hu' : threshold s n ρ z w ≤ R := + (threshold_eq_sentinelFirst hn hR hL' hw' hu).trans_le hu + constructor + · apply update_eq_self_of_three_mul_le + exact (by linarith [hw y hy hm] : 3 * threshold s n ρ z w ≤ w y 0).trans + ((le_abs_self _).trans (abs_apply_le_entrySize _ 0)) + · apply update_eq_self_of_three_mul_le + have hfirst : 3 * R < sentinelFirst marked L w y 0 := by + rwa [sentinelFirst_zero_of_mem hm] + exact (by linarith : 3 * threshold s n ρ z (sentinelFirst marked L w) ≤ + sentinelFirst marked L w y 0).trans ((le_abs_self _).trans (abs_apply_le_entrySize _ 0)) + +/-- Sentinel replacement commutes with the concrete compression update on every retained ID. +This also gives equality of both channels off the marked set; it assumes no row-output law. -/ +theorem sentinelFirst_update (hK : 0 < K) (hKn : K ≤ n) (hR : 0 ≤ R) (hL : 3 * R < L) + (hw : ∀ y ∈ s, y ∈ marked → 3 * R < w y 0) + (hq : firstRank s K z (sentinelFirst marked L w) ≤ R) + (hu : threshold s n ρ z (sentinelFirst marked L w) ≤ R) (hy : y ∈ s) : + sentinelFirst marked L (update s n K ρ z w) y = + update s n K ρ z (sentinelFirst marked L w) y := by + have hn : 0 < n := hK.trans_le hKn + by_cases hm : y ∈ marked + · obtain ⟨ho, hs⟩ := update_eq_self_of_mem_sentinelFirst hn hR hL hw hu hy hm + rw [hs] + funext ν + simp only [sentinelFirst, ho] + · have hL' : R < L := by linarith + have hw' : ∀ y ∈ s, y ∈ marked → R < w y 0 := by + intro y hy hm + linarith [hw y hy hm] + rw [sentinelFirst_of_not_mem hm] + unfold update + rw [threshold_eq_sentinelFirst hn hR hL' hw' hu, + newDefault_eq_sentinelFirst hn hK hR hL' hw' hq hu, sentinelFirst_of_not_mem hm] + +end Cslib.RowCompression diff --git a/Complexity/Foundations/Data/Finset/KthLargest.lean b/Complexity/Foundations/Data/Finset/KthLargest.lean index 33b6107d35..6421b25585 100644 --- a/Complexity/Foundations/Data/Finset/KthLargest.lean +++ b/Complexity/Foundations/Data/Finset/KthLargest.lean @@ -1,7 +1,7 @@ /- -Copyright (c) 2026 Christian Reitwiessner. All rights reserved. +Copyright (c) 2026 Christian Reitwiessner, Samuel Schlesinger. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Christian Reitwiessner +Authors: Christian Reitwiessner, Samuel Schlesinger -/ module @@ -32,6 +32,7 @@ is at least `t` exactly when at least `k` values are at least `t` (`Finset.le_kt * `Finset.kthLargest_nonneg`, `Finset.kthLargest_le`: bounds. * `Finset.lt_kthLargest_iff`, `Finset.le_kthLargest_iff`: the threshold characterizations. +* `Finset.kthLargest_eq_of_eq_or_gt`: replacing values strictly above a bounded rank preserves it. * `Finset.kthLargest_le_kthLargest_add`, `Finset.abs_kthLargest_sub_kthLargest_le`: stability under perturbation of the values. @@ -116,6 +117,35 @@ theorem le_kthLargest_iff (hk : 0 < k) (ht : 0 < t) : obtain ⟨x, hxs, htx, hkx⟩ := exists_le_card hk (t ≤ ·) hcard exact htx.trans (le_kthLargest_of_le_card hxs hkx) +/-- Changing only values strictly above a nonnegative ceiling preserves every positive-order +rank at most that ceiling. The bound may be an equality, and other values may be negative. -/ +theorem kthLargest_eq_of_eq_or_gt {f g : α → R} (hk : 0 < k) (ht : 0 ≤ t) + (h : ∀ x ∈ s, f x = g x ∨ (t < f x ∧ t < g x)) + (hg : kthLargest k s g ≤ t) : kthLargest k s f = kthLargest k s g := by + classical + have hfilter (a : R) (ha : a ≤ t) : + ({x ∈ s | a < f x} : Finset α) = {x ∈ s | a < g x} := by + ext x + by_cases hx : x ∈ s + · rcases h x hx with heq | ⟨hf, hg⟩ + · simp [heq] + · simp [hx, ha.trans_lt hf, ha.trans_lt hg] + · simp [hx] + have hf : kthLargest k s f ≤ t := by + refine not_lt.mp fun hlt => ?_ + have hc := (lt_kthLargest_iff hk ht).mp hlt + rw [hfilter t le_rfl] at hc + exact (not_lt_of_ge hg) ((lt_kthLargest_iff hk ht).mpr hc) + apply le_antisymm + · refine not_lt.mp fun hlt => ?_ + have hc := (lt_kthLargest_iff hk kthLargest_nonneg).mp hlt + rw [hfilter _ hg] at hc + exact lt_irrefl _ ((lt_kthLargest_iff hk kthLargest_nonneg).mpr hc) + · refine not_lt.mp fun hlt => ?_ + have hc := (lt_kthLargest_iff hk kthLargest_nonneg).mp hlt + rw [← hfilter _ hf] at hc + exact lt_irrefl _ ((lt_kthLargest_iff hk kthLargest_nonneg).mpr hc) + section Stability variable {R : Type*} [AddCommGroup R] [LinearOrder R] [IsOrderedAddMonoid R] {k : ℕ} diff --git a/ComplexityTests/RowCompressionSentinel.lean b/ComplexityTests/RowCompressionSentinel.lean new file mode 100644 index 0000000000..de51668523 --- /dev/null +++ b/ComplexityTests/RowCompressionSentinel.lean @@ -0,0 +1,131 @@ +/- +Copyright (c) 2026 Samuel Schlesinger. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Samuel Schlesinger +-/ + +import Complexity.Foundations.Analysis.RowCompression.Sentinel +import Mathlib.LinearAlgebra.Matrix.Notation +import Mathlib.Tactic.FinCases +import Mathlib.Tactic.NormNum + +/-! +# Exact sentinel compression examples + +Replacing the first entry `1000000` by `100` preserves a third rank and size threshold exactly +at their ceiling `2`. The old default is positive. Compression changes smaller signed entries, +while the marked entry's negative second coordinate `-17` is unchanged in both calculations. +Further cases check zero padding and why changing values exactly at the ceiling is excluded. +-/ + +namespace ComplexityTests.RowCompressionSentinel + +open Finset Cslib.RowCompression + +private def original : Fin 4 → Fin 2 → ℝ := ![![1000000, -17], ![4, 0], ![2, -1], ![-1, 1]] + +private noncomputable def modified : Fin 4 → Fin 2 → ℝ := sentinelFirst {0} 100 original + +private theorem modified_rank : firstRank univ 3 (1 / 2) modified = 2 := by + norm_num [firstRank, kthLargest, modified, original, sentinelFirst, Fin.univ_succ, + filter_insert, filter_singleton] + +private theorem modified_threshold : threshold univ 3 1 (1 / 2) modified = 2 := by + norm_num [threshold, kthLargest, entrySize, modified, original, sentinelFirst, Fin.univ_succ, + filter_insert, filter_singleton] + +private theorem marked_high : ∀ y ∈ (univ : Finset (Fin 4)), y ∈ ({0} : Finset (Fin 4)) → + (3 : ℝ) * 2 < original y 0 := by + intro y _ hy + have hy0 : y = 0 := mem_singleton.mp hy + subst y + norm_num [original] + +private theorem marked_above : ∀ y ∈ (univ : Finset (Fin 4)), y ∈ ({0} : Finset (Fin 4)) → + (2 : ℝ) < original y 0 := by + intro y _ hy + have hy0 : y = 0 := mem_singleton.mp hy + subst y + norm_num [original] + +private theorem original_rank : firstRank univ 3 (1 / 2) original = 2 := by + rw [firstRank_eq_sentinelFirst (marked := {0}) (L := 100) (R := 2) + (by norm_num) (by norm_num) (by norm_num) marked_above modified_rank.le] + exact modified_rank + +private theorem original_threshold : threshold univ 3 1 (1 / 2) original = 2 := by + rw [threshold_eq_sentinelFirst (marked := {0}) (L := 100) (R := 2) + (by norm_num) (by norm_num) (by norm_num) marked_above modified_threshold.le] + exact modified_threshold + +private theorem modified_default : newDefault univ 3 3 1 (1 / 2) modified = 2 := by + change max (threshold univ 3 1 (1 / 2) modified) + (min (firstRank univ 3 (1 / 2) modified) (3 * threshold univ 3 1 (1 / 2) modified)) = 2 + rw [modified_threshold, modified_rank] + norm_num + +private theorem original_default : newDefault univ 3 3 1 (1 / 2) original = 2 := by + rw [newDefault_eq_sentinelFirst (marked := {0}) (L := 100) (R := 2) + (by norm_num) (by norm_num) (by norm_num) (by norm_num) + marked_above modified_rank.le modified_threshold.le] + exact modified_default + +-- Both ranks meet the ceiling exactly; the old default is neither zero nor the new default. +example : firstRank univ 3 (1 / 2) original = 2 ∧ + threshold univ 3 1 (1 / 2) original = 2 ∧ + newDefault univ 3 3 1 (1 / 2) original = 2 := + ⟨original_rank, original_threshold, original_default⟩ + +-- This is the actual commutation theorem, with every structural hypothesis discharged. +example (y : Fin 4) : sentinelFirst {0} 100 (update univ 3 3 1 (1 / 2) original) y = + update univ 3 3 1 (1 / 2) modified y := by + exact sentinelFirst_update (R := 2) (by norm_num) (by norm_num) (by norm_num) + (by norm_num) marked_high modified_rank.le modified_threshold.le (mem_univ y) + +-- Both channels of the marked entry survive, even though its second coordinate is negative. +example : update univ 3 3 1 (1 / 2) original 0 = ![1000000, -17] ∧ + update univ 3 3 1 (1 / 2) modified 0 = ![100, -17] := by + have h := update_eq_self_of_mem_sentinelFirst (K := 3) (R := 2) + (by norm_num) (by norm_num) (by norm_num) marked_high modified_threshold.le + (mem_univ 0) (mem_singleton_self 0) + refine ⟨h.1, h.2.trans ?_⟩ + funext ν + fin_cases ν <;> norm_num [sentinelFirst, original] + +-- The step is not identity on the whole row: these signed coordinates really change. +example : original 2 1 = -1 ∧ original 3 0 = -1 ∧ + update univ 3 3 1 (1 / 2) original 2 = ![2, 0] ∧ + update univ 3 3 1 (1 / 2) original 3 = ![2, 0] := by + have h2 : update univ 3 3 1 (1 / 2) original 2 = ![2, 0] := by + unfold update + rw [original_threshold, original_default] + funext ν + fin_cases ν <;> norm_num [updateEntry, radius, entrySize, defaultEntry, original] + have h3 : update univ 3 3 1 (1 / 2) original 3 = ![2, 0] := by + unfold update + rw [original_threshold, original_default] + funext ν + fin_cases ν <;> norm_num [updateEntry, radius, entrySize, defaultEntry, original] + exact ⟨by norm_num [original], by norm_num [original], h2, h3⟩ + +-- The rank bound proves the strict capacity of the marked set, rather than assuming it. +example : #({0} : Finset (Fin 4)) < 3 := + card_marked_lt_of_sentinelFirst (R := 2) (w := original) (by norm_num) (by norm_num) + (by norm_num : (2 : ℝ) < 100) (subset_univ _) modified_rank.le + +-- Arbitrarily large positive replacement values cannot defeat zero padding when K > #s. +example : kthLargest 3 univ (![(-4 : ℝ), 1000000] : Fin 2 → ℝ) = 0 := by + have h := kthLargest_eq_of_eq_or_gt (k := 3) (s := univ) (t := (0 : ℝ)) + (f := (![-4, 1000000] : Fin 2 → ℝ)) (g := (![-4, 10] : Fin 2 → ℝ)) + (by norm_num) (by norm_num) + (fun y _ => by fin_cases y <;> norm_num) + (by norm_num [kthLargest, Fin.univ_succ, filter_insert, filter_singleton]) + rw [h] + norm_num [kthLargest, Fin.univ_succ, filter_insert, filter_singleton] + +-- Strictness above the ceiling matters: replacing a value by the ceiling can change the rank. +example : kthLargest 1 univ (![(5 : ℝ), 4] : Fin 2 → ℝ) = 5 ∧ + kthLargest 1 univ (![(4 : ℝ), 4] : Fin 2 → ℝ) = 4 := by + norm_num [kthLargest, Fin.univ_succ, filter_insert, filter_singleton] + +end ComplexityTests.RowCompressionSentinel From 2e1f9fc929bb01bf1efe8ec21e65d6624a150fc0 Mon Sep 17 00:00:00 2001 From: Samuel Schlesinger Date: Fri, 30 Oct 2026 17:12:08 +0000 Subject: [PATCH 16/19] feat(logspace): bound conditional true heavy counts Derive the deterministic heavy-set bound from nonnegative row mass, then apply finite Markov at ceil(n/2) with one distinguished endpoint. The conditional frequency is at most (2 + 8*c*Cmass)/(n*rho), including empty conditioning slices. An independent start slice preserves the bound. The actual affine broad/narrow specialization obtains c = 2^H from the existing cross-rate pair count and uses rate alpha^H. Regression examples have perfectly correlated off-endpoint hits with exact frequency 1/8 and bound 1/2, odd capacity, empty conditioning and the strict heavy threshold. The affine example uses P=7, broad side 2, narrow side 1, and the nontrivial bound 19/21, with both exceptional and nonexceptional seeds in the same conditioning slice. Validation on base c172011fc0702d7c7a4317b0ad94e57ae13e3bb1 plus these two files: direct Lean 4.36.0-rc2 elaboration of the module and its test file, with -DwarningAsError=true, -DautoImplicit=false and repository weak linter options, both exit 0 with blank diagnostics. Existing dependencies were read-only and outputs private. Focused check_hygiene.py --check-simp and git diff --cached --check passed. Aggregate and full hosted gates are left to coordinator integration under the shared disk constraint. Source: OpenAI 2026 preprint revision 7ef5c0cc, compression.tex Section 8.4, lemma/equation buf-rarity. This closes conditional true-heavy-count rarity only; masked mean/noise estimates, post-overflow stability and integrated compression remain open. No curated abstract changes. AI assistance: ChatGPT implemented and self-checked the Lean proofs and tests. Independent exact-revision review is requested from the coordinator. Independent non-author source/API review by agent derandomization_plan approved source revision 2391fbec3d50c9927750105dff0466330717b951 with no findings. Review covered finite Markov counting, the forced endpoint, odd capacities, empty slices, the actual affine specialization, and nonvacuous tests. Integrated source and tests are byte-identical to that reviewed revision. Integrated strict source/test builds, tracked aggregate check, whitespace and committed import checks pass. Full integration gates run in PR CI. --- Complexity.lean | 1 + .../Probability/CompressionHeavyCount.lean | 193 ++++++++++++++++++ ComplexityTests/CompressionHeavyCount.lean | 148 ++++++++++++++ 3 files changed, 342 insertions(+) create mode 100644 Complexity/Foundations/Probability/CompressionHeavyCount.lean create mode 100644 ComplexityTests/CompressionHeavyCount.lean diff --git a/Complexity.lean b/Complexity.lean index a11b5860a7..74edcde9ea 100644 --- a/Complexity.lean +++ b/Complexity.lean @@ -2730,6 +2730,7 @@ public import Complexity.Foundations.Order.Changes public import Complexity.Foundations.Order.UpperLower public import Complexity.Foundations.Probability.AtomCutoffs public import Complexity.Foundations.Probability.ColumnDetector +public import Complexity.Foundations.Probability.CompressionHeavyCount public import Complexity.Foundations.Probability.CorrectionAtom public import Complexity.Foundations.Probability.DetectedHierarchy public import Complexity.Foundations.Probability.DetectedStage diff --git a/Complexity/Foundations/Probability/CompressionHeavyCount.lean b/Complexity/Foundations/Probability/CompressionHeavyCount.lean new file mode 100644 index 0000000000..a62aaa9b2d --- /dev/null +++ b/Complexity/Foundations/Probability/CompressionHeavyCount.lean @@ -0,0 +1,193 @@ +/- +Copyright (c) 2026 Samuel Schlesinger. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Samuel Schlesinger +-/ + +module +-- upstream: candidate + +public import Complexity.Foundations.Probability.CorrectionAtom +public import Complexity.Probability.PairwiseIndependentHash.AtomChannels +import Complexity.Foundations.Data.Finset.Markov +import Mathlib.Tactic.Linarith +import Mathlib.Tactic.Positivity +import Mathlib.Tactic.Ring + +/-! +# Conditional rarity of true heavy counts + +A nonnegative deterministic row `d` with `a * ∑ y, d y ≤ Cmass` has few entries above +`ρ / 4`. On a finite conditioning slice, suppose every such endpoint other than one specified +endpoint is retained with frequency at most `c * a`. The specified endpoint contributes at +most one, regardless of its own retention probability. Finite Markov then bounds the event +`n ≤ 2 * #{retained y | ρ / 4 < d y}` by `(2 + 8 * c * Cmass) / (n * ρ)`. + +The bound allows arbitrary dependence among the endpoint hits. Its affine specialization uses +the actual cross-rate pair count, with broad side `⌈P * α⌉` and an endpoint condition of any +smaller side. Empty conditioning slices have frequency zero; the division-free count theorem +also applies without positivity of the capacity. + +This is the conditional true-heavy-count rarity assertion of [OpenAI2026LogSpace, Section 8.4], +the equation labelled `buf-rarity`. The normalized deterministic row and its mass bound are +explicit inputs. Masked mean and noise estimates, post-overflow stability, and the integrated +compression theorem remain separate. + +## Main results + +* `Finset.card_heavy_mul_le_mass`: derive the deterministic heavy-set bound from row mass. +* `Finset.card_filter_heavyCount_mul_le`: bound the actual exceptional seed count. +* `Finset.card_filter_heavyCount_div_card_le`: the conditional frequency bound, including + empty conditioning slices. +* `Finset.card_filter_heavyCount_product_div_card_le`: an independent start slice preserves + the same bound, including an empty start slice. +* `Cslib.Probability.card_affineRetains_heavyCount_div_card_le`: the actual affine sampler at + broad and narrower endpoint conditions. + +## References + +* [OpenAI, *Exact Derandomization of Logarithmic Space: L = RL = BPL*][OpenAI2026LogSpace], + Section 8.4, lemma and equation labelled `buf-rarity` + (23 September 2026, revision `7ef5c0cc`, not peer reviewed). +-/ + +public section + +open scoped BigOperators + +namespace Finset + +variable {Ω V : Type*} + +/-- The scaled number of deterministic entries above `ρ / 4` is controlled by the actual +nonnegative row mass. No retained-set or independence hypothesis is used. -/ +theorem card_heavy_mul_le_mass (T : Finset V) {d : V → ℝ} {a ρ Cmass : ℝ} + (ha : 0 ≤ a) (hd : ∀ y ∈ T, 0 ≤ d y) (hmass : a * ∑ y ∈ T, d y ≤ Cmass) : + a * (#{y ∈ T | ρ / 4 < d y} : ℝ) * ρ ≤ 4 * Cmass := by + have h := mul_le_mul_of_nonneg_left + (card_filter_mul_le_sum T (fun y => ρ / 4 < d y) d hd + (fun _ _ hy => hy.le)) ha + nlinarith [h.trans hmass] + +/-- **True-heavy-count rarity as a finite count.** Only off-endpoint conditional pair counts +are required. The one specified endpoint costs at most one retained entry per draw. +The capacity may be zero, and the seed slice may be empty. -/ +theorem card_filter_heavyCount_mul_le (X : Ω → V → Prop) [∀ σ y, Decidable (X σ y)] + (S : Finset Ω) (T : Finset V) (x : V) {d : V → ℝ} {a c ρ Cmass : ℝ} + (ha : 0 ≤ a) (hc : 0 ≤ c) (hρ : 0 < ρ) (hρ1 : ρ ≤ 1) + (hd : ∀ y ∈ T, 0 ≤ d y) (hmass : a * ∑ y ∈ T, d y ≤ Cmass) + (hpair : ∀ y ∈ T, ρ / 4 < d y → y ≠ x → + (#{σ ∈ S | X σ y} : ℝ) ≤ c * a * #S) (n : ℕ) : + (#{σ ∈ S | n ≤ 2 * #{y ∈ T | X σ y ∧ ρ / 4 < d y}} : ℝ) * n * ρ ≤ + #S * (2 + 8 * c * Cmass) := by + classical + let D : Finset V := {y ∈ T | ρ / 4 < d y} + have hD := card_heavy_mul_le_mass T (ρ := ρ) ha hd hmass + have hmarkov := card_filter_le_card_filter_mul_le X S D x (mul_nonneg hc ha) + (fun y hy hyx => hpair y (mem_filter.mp hy).1 (mem_filter.mp hy).2 hyx) ((n + 1) / 2) + have hevent : {σ ∈ S | (n + 1) / 2 ≤ #{y ∈ D | X σ y}} = + {σ ∈ S | n ≤ 2 * #{y ∈ T | X σ y ∧ ρ / 4 < d y}} := by + apply filter_congr + intro σ _ + have hset : {y ∈ D | X σ y} = {y ∈ T | X σ y ∧ ρ / 4 < d y} := by + ext y + simp [D, and_left_comm, and_comm] + rw [hset] + omega + rw [hevent] at hmarkov + have hn : (n : ℝ) ≤ 2 * ((n + 1) / 2 : ℕ) := by + exact_mod_cast (show n ≤ 2 * ((n + 1) / 2) by omega) + have hfirst : + (#{σ ∈ S | n ≤ 2 * #{y ∈ T | X σ y ∧ ρ / 4 < d y}} : ℝ) * n ≤ + 2 * (#S : ℝ) * (1 + c * a * #D) := by + nlinarith [mul_le_mul_of_nonneg_left hn + (show (0 : ℝ) ≤ #{σ ∈ S | n ≤ 2 * #{y ∈ T | X σ y ∧ ρ / 4 < d y}} by positivity)] + have hmassD : c * a * (#D : ℝ) * ρ ≤ 4 * c * Cmass := by + dsimp only [D] + nlinarith [mul_le_mul_of_nonneg_left hD hc] + calc + _ ≤ (2 * (#S : ℝ) * (1 + c * a * #D)) * ρ := + mul_le_mul_of_nonneg_right hfirst hρ.le + _ ≤ #S * (2 + 8 * c * Cmass) := by + have hfactor : 2 * (1 + c * a * (#D : ℝ)) * ρ ≤ 2 + 8 * c * Cmass := by + nlinarith + nlinarith [mul_le_mul_of_nonneg_left hfactor (Nat.cast_nonneg #S : (0 : ℝ) ≤ #S)] + +/-- The conditional true-heavy-count frequency is small. An empty conditioning slice has +frequency zero, so no nonemptiness hypothesis is needed. -/ +theorem card_filter_heavyCount_div_card_le (X : Ω → V → Prop) [∀ σ y, Decidable (X σ y)] + (S : Finset Ω) (T : Finset V) (x : V) {d : V → ℝ} {a c ρ Cmass : ℝ} + (ha : 0 ≤ a) (hc : 0 ≤ c) (hρ : 0 < ρ) (hρ1 : ρ ≤ 1) + (hd : ∀ y ∈ T, 0 ≤ d y) (hmass : a * ∑ y ∈ T, d y ≤ Cmass) + (hpair : ∀ y ∈ T, ρ / 4 < d y → y ≠ x → + (#{σ ∈ S | X σ y} : ℝ) ≤ c * a * #S) {n : ℕ} (hn : 0 < n) : + (#{σ ∈ S | n ≤ 2 * #{y ∈ T | X σ y ∧ ρ / 4 < d y}} : ℝ) / #S ≤ + (2 + 8 * c * Cmass) / ((n : ℝ) * ρ) := by + have hC : 0 ≤ Cmass := (mul_nonneg ha (sum_nonneg hd)).trans hmass + rcases S.eq_empty_or_nonempty with rfl | hS + · simp only [filter_empty, card_empty, Nat.cast_zero, zero_div] + positivity + have hnρ : (0 : ℝ) < n * ρ := mul_pos (by exact_mod_cast hn) hρ + have hSpos : (0 : ℝ) < #S := by exact_mod_cast hS.card_pos + rw [div_le_div_iff₀ hSpos hnρ] + simpa only [mul_assoc, mul_comm, mul_left_comm] using + card_filter_heavyCount_mul_le X S T x ha hc hρ hρ1 hd hmass hpair n + +/-- Conditioning independently on a start seed does not increase the heavy-count bound. +The product slice and retained count are explicit; either conditioning slice may be empty. -/ +theorem card_filter_heavyCount_product_div_card_le {Γ : Type*} + (X : Ω → V → Prop) [∀ σ y, Decidable (X σ y)] + (R : Finset Γ) (S : Finset Ω) (T : Finset V) (x : V) {d : V → ℝ} {a c ρ Cmass : ℝ} + (ha : 0 ≤ a) (hc : 0 ≤ c) (hρ : 0 < ρ) (hρ1 : ρ ≤ 1) + (hd : ∀ y ∈ T, 0 ≤ d y) (hmass : a * ∑ y ∈ T, d y ≤ Cmass) + (hpair : ∀ y ∈ T, ρ / 4 < d y → y ≠ x → + (#{σ ∈ S | X σ y} : ℝ) ≤ c * a * #S) {n : ℕ} (hn : 0 < n) : + (#{σ ∈ R ×ˢ S | n ≤ 2 * #{y ∈ T | X σ.2 y ∧ ρ / 4 < d y}} : ℝ) / #(R ×ˢ S) ≤ + (2 + 8 * c * Cmass) / ((n : ℝ) * ρ) := by + classical + refine card_filter_heavyCount_div_card_le (fun (σ : Γ × Ω) y => X σ.2 y) + (R ×ˢ S) T x ha hc hρ hρ1 hd hmass ?_ hn + intro y hy hdy hyx + have hset : {σ ∈ R ×ˢ S | X σ.2 y} = R ×ˢ {σ ∈ S | X σ y} := by + ext σ + simp [and_assoc] + rw [hset, card_product, card_product, Nat.cast_mul, Nat.cast_mul] + simpa only [mul_assoc, mul_comm, mul_left_comm] using + mul_le_mul_of_nonneg_left (hpair y hy hdy hyx) (Nat.cast_nonneg #R : (0 : ℝ) ≤ #R) + +end Finset + +namespace Cslib.Probability + +open Finset + +variable {V : Type*} {P H : ℕ} [Fact P.Prime] + +/-- **Conditional true-heavy-count rarity for affine channels.** The broad rate parameter is +`α ^ H`, and the actual cross-rate pair estimate supplies `c = 2 ^ H`. The conditioning side +may equal the broad side or be narrower, including zero; no conditional error independence is +assumed. -/ +theorem card_affineRetains_heavyCount_div_card_le (T : Finset V) {ident : V → ZMod P} + (hident : Function.Injective ident) {α : ℝ} (hPα : 1 ≤ P * α) (hα1 : α ≤ 1) + {Lt : ℕ} (hLt : Lt ≤ ⌈P * α⌉₊) (x : V) {d : V → ℝ} {ρ Cmass : ℝ} + (hρ : 0 < ρ) (hρ1 : ρ ≤ 1) (hd : ∀ y ∈ T, 0 ≤ d y) + (hmass : α ^ H * ∑ y ∈ T, d y ≤ Cmass) {n : ℕ} (hn : 0 < n) : + (#{σ ∈ ({σ | affineRetains P H Lt σ (ident x)} : + Finset (Matrix (Fin H) (Fin 1) (ZMod P) × (Fin H → ZMod P))) | + n ≤ 2 * #{y ∈ T | affineRetains P H ⌈P * α⌉₊ σ (ident y) ∧ ρ / 4 < d y}} : ℝ) / + #{σ | affineRetains P H Lt σ (ident x)} ≤ + (2 + 8 * (2 : ℝ) ^ H * Cmass) / ((n : ℝ) * ρ) := by + have hα : 0 < α := by + by_contra h + have hP : (0 : ℝ) ≤ P := Nat.cast_nonneg P + nlinarith [mul_nonpos_of_nonneg_of_nonpos hP (not_lt.mp h)] + obtain ⟨hL, -, -, -, -⟩ := affineRetains_rates (H := H) hPα hα1 + refine card_filter_heavyCount_div_card_le + (fun σ y => affineRetains P H ⌈P * α⌉₊ σ (ident y)) + {σ | affineRetains P H Lt σ (ident x)} T x (pow_nonneg hα.le H) + (by positivity) hρ hρ1 hd hmass ?_ hn + intro y _ _ hyx + simpa only [filter_filter] using + card_affineRetains_and_affineRetains_le hident hPα hα1 (hLt.trans hL) hyx + +end Cslib.Probability diff --git a/ComplexityTests/CompressionHeavyCount.lean b/ComplexityTests/CompressionHeavyCount.lean new file mode 100644 index 0000000000..bb2bd26a1d --- /dev/null +++ b/ComplexityTests/CompressionHeavyCount.lean @@ -0,0 +1,148 @@ +/- +Copyright (c) 2026 Samuel Schlesinger. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Samuel Schlesinger +-/ +import Complexity.Foundations.Probability.CompressionHeavyCount +import Mathlib.Tactic.NormNum + +/-! +# Tests for conditional heavy-count rarity + +Three off-endpoint hits are perfectly correlated: they all occur on one of eight draws. +The distinguished endpoint is always retained. All four targets have value `1/2`, so with +`a = 1/8`, `ρ = 1`, and capacity eight, the exceptional frequency is exactly `1/8` and the +proved bound is `1/2 < 1`. An odd capacity exercises the ceiling in finite Markov. + +The affine example uses all seven field elements, broad side two and narrower endpoint side +one. Its deterministic row is constantly `1/3`; the actual bound is `19/21 < 1`. The zero +affine map is an exceptional seed in the conditioning slice, while the identity map belongs +to the same slice and is not exceptional. +-/ + +namespace ComplexityTests.CompressionHeavyCount + +open Finset Cslib.Probability +open scoped BigOperators + +private abbrev hit (σ : Fin 8) (y : Fin 4) : Prop := y = 0 ∨ σ = 0 + +private theorem row_mass : (1 / 8 : ℝ) * ∑ _y : Fin 4, (1 / 2 : ℝ) ≤ 1 / 4 := by + norm_num + +private theorem pair_count (y : Fin 4) (_ : y ∈ (univ : Finset (Fin 4))) + (_ : (1 : ℝ) / 4 < 1 / 2) (hy : y ≠ 0) : + (#{σ ∈ (univ : Finset (Fin 8)) | hit σ y} : ℝ) ≤ 1 * (1 / 8) * #(univ : Finset (Fin 8)) := by + have hset : {σ ∈ (univ : Finset (Fin 8)) | hit σ y} = {0} := by + ext σ + simp [hit, hy] + rw [hset] + norm_num + +private theorem retained_heavy (σ : Fin 8) : + {y ∈ (univ : Finset (Fin 4)) | hit σ y ∧ (1 : ℝ) / 4 < 1 / 2} = + if σ = 0 then univ else {0} := by + by_cases hσ : σ = 0 <;> ext y <;> norm_num [hit, hσ] + +private theorem bad_seeds : + {σ ∈ (univ : Finset (Fin 8)) | + 8 ≤ 2 * #{y ∈ (univ : Finset (Fin 4)) | hit σ y ∧ (1 : ℝ) / 4 < 1 / 2}} = {0} := by + ext σ + simp only [mem_filter, mem_univ, true_and, retained_heavy, mem_singleton] + by_cases hσ : σ = 0 <;> simp [hσ] + +-- Distinct off-endpoint hits are correlated, not independent Bernoulli trials. +example : ({σ : Fin 8 | hit σ 1 ∧ hit σ 2} : Finset (Fin 8)) = {0} ∧ + (1 / 8 : ℝ) ≠ (1 / 8) ^ 2 := by + constructor + · ext σ + norm_num [hit] + · norm_num + +example : (#{σ ∈ (univ : Finset (Fin 8)) | + 8 ≤ 2 * #{y ∈ (univ : Finset (Fin 4)) | hit σ y ∧ (1 : ℝ) / 4 < 1 / 2}} : ℝ) / + #(univ : Finset (Fin 8)) = 1 / 8 := by + rw [bad_seeds] + norm_num + +-- The theorem consumes the actual row mass and off-endpoint pair counts. +example : (#{σ ∈ (univ : Finset (Fin 8)) | + 8 ≤ 2 * #{y ∈ (univ : Finset (Fin 4)) | hit σ y ∧ (1 : ℝ) / 4 < 1 / 2}} : ℝ) / + #(univ : Finset (Fin 8)) ≤ 1 / 2 ∧ (1 / 2 : ℝ) < 1 := by + have h := card_filter_heavyCount_div_card_le hit univ univ 0 + (d := fun _ => (1 / 2 : ℝ)) (a := 1 / 8) (c := 1) (ρ := 1) (Cmass := 1 / 4) + (by norm_num) (by norm_num) (by norm_num) (by norm_num) (fun _ _ => by norm_num) + row_mass pair_count (n := 8) (by decide) + norm_num at h ⊢ + exact h + +example : (#{σ ∈ (univ : Finset (Fin 8)) | + 7 ≤ 2 * #{y ∈ (univ : Finset (Fin 4)) | hit σ y ∧ (1 : ℝ) / 4 < 1 / 2}} : ℝ) / + #(univ : Finset (Fin 8)) ≤ 4 / 7 := by + have h := card_filter_heavyCount_div_card_le hit univ univ 0 + (d := fun _ => (1 / 2 : ℝ)) (a := 1 / 8) (c := 1) (ρ := 1) (Cmass := 1 / 4) + (by norm_num) (by norm_num) (by norm_num) (by norm_num) (fun _ _ => by norm_num) + row_mass pair_count (n := 7) (by decide) + norm_num at h ⊢ + exact h + +-- A value exactly at the light/heavy threshold is not heavy. +example : #{y ∈ (univ : Finset (Fin 4)) | (1 : ℝ) / 4 < if y = 0 then 1 / 4 else 1 / 2} = 3 := by + have hset : {y ∈ (univ : Finset (Fin 4)) | + (1 : ℝ) / 4 < if y = 0 then 1 / 4 else 1 / 2} = (univ : Finset (Fin 4)).erase 0 := by + ext y + by_cases hy : y = 0 <;> norm_num [hy] + rw [hset] + norm_num + +-- Either conditioning slice may be empty. +example : (#{σ ∈ (∅ : Finset (Fin 8)) | + 8 ≤ 2 * #{y ∈ (univ : Finset (Fin 4)) | hit σ y ∧ (1 : ℝ) / 4 < 1 / 2}} : ℝ) / + #(∅ : Finset (Fin 8)) ≤ 1 / 2 := by + have h := card_filter_heavyCount_div_card_le hit ∅ univ 0 + (d := fun _ => (1 / 2 : ℝ)) (a := 1 / 8) (c := 1) (ρ := 1) (Cmass := 1 / 4) + (by norm_num) (by norm_num) (by norm_num) (by norm_num) (fun _ _ => by norm_num) + row_mass (fun _ _ _ _ => by simp) (n := 8) (by decide) + norm_num at h ⊢ + +example (R : Finset Bool) : + (#{σ ∈ R ×ˢ (univ : Finset (Fin 8)) | + 8 ≤ 2 * #{y ∈ (univ : Finset (Fin 4)) | hit σ.2 y ∧ (1 : ℝ) / 4 < 1 / 2}} : ℝ) / + #(R ×ˢ (univ : Finset (Fin 8))) ≤ 1 / 2 := by + have h := card_filter_heavyCount_product_div_card_le hit R univ univ 0 + (d := fun _ => (1 / 2 : ℝ)) (a := 1 / 8) (c := 1) (ρ := 1) (Cmass := 1 / 4) + (by norm_num) (by norm_num) (by norm_num) (by norm_num) (fun _ _ => by norm_num) + row_mass pair_count (n := 8) (by decide) + norm_num at h ⊢ + exact h + +private instance : Fact (Nat.Prime 7) := ⟨by decide⟩ + +private abbrev AffineSeed := Matrix (Fin 1) (Fin 1) (ZMod 7) × (Fin 1 → ZMod 7) +private def narrowSlice : Finset AffineSeed := {σ | affineRetains 7 1 1 σ 0} +private abbrev affineBad (σ : AffineSeed) : Prop := + 14 ≤ 2 * #({y : ZMod 7 | affineRetains 7 1 2 σ y} : Finset (ZMod 7)) + +-- An actual affine specialization with a strictly narrower positive endpoint box. +example : (#{σ ∈ narrowSlice | affineBad σ} : ℝ) / #narrowSlice ≤ 19 / 21 ∧ + (19 / 21 : ℝ) < 1 := by + have h := card_affineRetains_heavyCount_div_card_le (univ : Finset (ZMod 7)) + Function.injective_id (H := 1) (α := (2 / 7 : ℝ)) (by norm_num) (by norm_num) + (Lt := 1) (by norm_num) 0 (d := fun _ => (1 / 3 : ℝ)) (ρ := 1) (Cmass := 2 / 3) + (by norm_num) (by norm_num) (fun _ _ => by norm_num) (by norm_num) (n := 14) (by decide) + norm_num [narrowSlice, affineBad] at h ⊢ + exact h + +-- The conditioning event and exceptional event are nonempty, while not all its seeds are bad. +example : ((0, 0) : AffineSeed) ∈ narrowSlice ∧ affineBad (0, 0) := by + constructor + · decide + · decide + +example : ((fun _ _ => 1, 0) : AffineSeed) ∈ narrowSlice ∧ + ¬ affineBad (fun _ _ => 1, 0) := by + constructor + · decide + · decide + +end ComplexityTests.CompressionHeavyCount From daa97e764dc6ae5810e86f5ac63454a7e92b9156 Mon Sep 17 00:00:00 2001 From: Samuel Schlesinger Date: Fri, 30 Oct 2026 17:16:40 +0000 Subject: [PATCH 17/19] feat(logspace): iterate actual sentinel compression coupling For issue #1721, construct the modified initial state and increments: retain the common default, replace marked first entries by L, clear only marked first-channel increments, and retain all second-channel increments. Prove coupling of the actual original and modified iterates at every prefix. Their defaults agree, the modified full row is exactly the sentinel replacement of the original row, and both original marked coordinates equal their actual raw prefixes. The large-input condition is derived from cumulative raw absolute variation: 3R plus the full first-channel variation is below each marked initial first coordinate. Only the actual modified input ranks and step thresholds are assumed bounded by R. A post-update rank bound is used by the main result to prove exact padded-rank equality and the same ceiling after every positive prefix. No original compressed-input or final-output contract is assumed, and no bound depends on the largest original first coordinate. Source mapping: OpenAI2026LogSpace revision 7ef5c0cc, compression.tex Section 8.3, proof of Lemma 8.3, the induction removing the sentinel modification. Deriving the ceilings and variation bounds from clipped errors, scalar upper saturation, the heavy-count case, and the complete post-overflow estimate remain separate. Sentinels are analytical devices; this adds no enumeration or machine-resource certificate. No curated abstract impact and no aggregate changes. The test runs two actual groups with marked first increments -5,+7 and second increments +2,-3. It computes the modified intermediate states and both ceiling bounds, then applies the theorem to recover the original marked raw prefix (1000002,-18), common increased default 2, and final padded-rank equality. An unmarked raw first prefix -2 becomes compressed value 2, so the test exercises real compression as well as nonzero signed increments in both channels. Validation: both new files compile without diagnostics under Lean 4.36.0-rc2, warningAsError=true, and all project linter options, with private outputs and shared dependencies read-only. Focused hygiene --check-simp and staged git diff --check pass. Full integration gates and independent exact-revision review remain coordinator-owned. This commit adds only SentinelIteration and its tests atop reviewed Sentinel 68a16267, which is unchanged and preserved on its original branch. AI assistance: ChatGPT worker codex-logspace-polynomial-cutoffs-20261030 authored and validated the change. Independent non-author source/API review by agent lean_environment approved source revision 6626a870805138484aed78a8c97c1218e3c89899 with no findings. Review covered the actual-run induction, original total variation, modified-only ceilings, full-function equality, both signed coordinates, post-update ranks, and the nontrivial two-step test. Integrated source and tests are byte-identical to that reviewed revision. Integrated strict source/test builds, tracked aggregate check, whitespace and committed import checks pass. Full integration gates run in PR CI. --- Complexity.lean | 1 + .../RowCompression/SentinelIteration.lean | 247 ++++++++++++++++++ .../RowCompressionSentinelIteration.lean | 182 +++++++++++++ 3 files changed, 430 insertions(+) create mode 100644 Complexity/Foundations/Analysis/RowCompression/SentinelIteration.lean create mode 100644 ComplexityTests/RowCompressionSentinelIteration.lean diff --git a/Complexity.lean b/Complexity.lean index 3827d9b925..60b8dd9f09 100644 --- a/Complexity.lean +++ b/Complexity.lean @@ -2358,6 +2358,7 @@ public import Complexity.Foundations.Analysis.RowCompression.Iteration public import Complexity.Foundations.Analysis.RowCompression.Preloss public import Complexity.Foundations.Analysis.RowCompression.Reference public import Complexity.Foundations.Analysis.RowCompression.Sentinel +public import Complexity.Foundations.Analysis.RowCompression.SentinelIteration public import Complexity.Foundations.Analysis.RowCompression.Stationary public import Complexity.Foundations.Analysis.SpecialFunctions.Arccos public import Complexity.Foundations.Analysis.SpecialFunctions.SmoothSwitch diff --git a/Complexity/Foundations/Analysis/RowCompression/SentinelIteration.lean b/Complexity/Foundations/Analysis/RowCompression/SentinelIteration.lean new file mode 100644 index 0000000000..5a1558e23f --- /dev/null +++ b/Complexity/Foundations/Analysis/RowCompression/SentinelIteration.lean @@ -0,0 +1,247 @@ +/- +Copyright (c) 2026 Samuel Schlesinger. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Samuel Schlesinger +-/ + +module +-- upstream: candidate + +public import Complexity.Foundations.Analysis.RowCompression.Sentinel +import Mathlib.Algebra.Order.BigOperators.Group.Finset +import Mathlib.Tactic.Linarith + +/-! +# Removing sentinels through an actual compression schedule + +The modified calculation starts from `sentinelState marked L a` and uses increments +`sentinelFirst marked 0 (Δ i)`. Thus only marked first-channel increments are removed; second +increments are unchanged. If the actual modified input ranks and thresholds are bounded by +`R ≥ 0`, and `3R` plus the total absolute first-channel variation is below every marked initial +first coordinate, the two actual calculations remain coupled at every prefix. + +Their defaults agree, the modified full row is the sentinel replacement of the original row, +and both original marked coordinates follow their actual uncompressed prefixes. The latter +fact derives the large-input condition needed at the next step. After every positive prefix, +the padded first ranks also agree and are at most `R`. + +This supplies the removal induction in [OpenAI2026LogSpace, Lemma 8.3]. It assumes explicit +ceilings only for the modified calculation; no bound on original compressed inputs or desired +final output is assumed. Deriving the ceilings and variation hypothesis from clipped errors, +upper saturation of row functions, the heavy-count case, and full post-overflow stability remain +separate. No implementation for finding or storing the analytical sentinels is asserted. + +## Main definitions + +* `Cslib.RowCompression.sentinelState`: preserve the default and replace marked first entries. + +## Main results + +* `Cslib.RowCompression.firstRank_update_le_of_le`: explicit input rank and threshold ceilings + bound the updated padded rank, without reference-row shape hypotheses. +* `Cslib.RowCompression.iterate_sentinelState_of_sum_abs_lt`: actual multi-step removal with + raw-prefix preservation at marked endpoints and exact rank equality after positive prefixes. + +## References + +* [OpenAI, *Exact Derandomization of Logarithmic Space: L = RL = BPL*][OpenAI2026LogSpace], + Section 8.3, proof of Lemma 8.3, induction removing the sentinel modification + (23 September 2026, revision `7ef5c0cc`, not peer reviewed). +-/ + +public section + +namespace Cslib.RowCompression + +open Finset + +variable {ι : Type*} + +/-- Replace marked first entries in a state, retaining its actual common default. -/ +@[expose] noncomputable def sentinelState (marked : Finset ι) (L : ℝ) (a : State ι) : State ι := + { defaultValue := a.defaultValue, row := sentinelFirst marked L a.row } + +/-- Clearing marked first increments makes addition commute exactly with sentinel replacement. -/ +theorem sentinelFirst_add (marked : Finset ι) (L : ℝ) (w Δ : ι → Fin 2 → ℝ) : + sentinelFirst marked L (w + Δ) = sentinelFirst marked L w + sentinelFirst marked 0 Δ := by + classical + funext y ν + by_cases h : y ∈ marked ∧ ν = 0 <;> simp [sentinelFirst, h] + +section Update + +variable {s marked : Finset ι} {n K : ℕ} {ρ z R L : ℝ} {w : ι → Fin 2 → ℝ} + +/-- The updated padded first rank remains below a common input rank and threshold ceiling. +No lower bound on raw first entries or upper bound on second entries is needed. -/ +theorem firstRank_update_le_of_le (hK : 0 < K) (hR : 0 ≤ R) + (hq : firstRank s K z w ≤ R) (hu : threshold s n ρ z w ≤ R) : + firstRank s K (newDefault s n K ρ z w) (update s n K ρ z w) ≤ R := by + have hb : newDefault s n K ρ z w ≤ R := + max_le hu ((min_le_left _ _).trans hq) + refine max_le hb ?_ + by_contra h + have hcard := (lt_kthLargest_iff hK hR).mp (lt_of_not_ge h) + have hsub : ({y ∈ s | R < update s n K ρ z w y 0} : Finset ι) ⊆ + {y ∈ s | R < w y 0} := by + intro y hy + obtain ⟨hys, hy⟩ := mem_filter.mp hy + refine mem_filter.mpr ⟨hys, ?_⟩ + by_contra hfirst + have hout := (update_mem_Icc (s := s) (n := n) (K := K) (ρ := ρ) (z := z) (w := w) y 0).2 + change update s n K ρ z w y 0 ≤ max (w y 0) (newDefault s n K ρ z w) at hout + exact (not_lt_of_ge (hout.trans (max_le (not_lt.mp hfirst) hb))) hy + have hlt := (lt_kthLargest_iff hK hR).mpr (hcard.trans (card_le_card hsub)) + exact (not_lt_of_ge (kthLargest_le_firstRank.trans hq)) hlt + +private theorem sentinelFirst_update_all (hmarked : marked ⊆ s) + (hK : 0 < K) (hKn : K ≤ n) (hR : 0 ≤ R) (hL : 3 * R < L) + (hw : ∀ y ∈ s, y ∈ marked → 3 * R < w y 0) + (hq : firstRank s K z (sentinelFirst marked L w) ≤ R) + (hu : threshold s n ρ z (sentinelFirst marked L w) ≤ R) : + sentinelFirst marked L (update s n K ρ z w) = + update s n K ρ z (sentinelFirst marked L w) := by + funext y + by_cases hm : y ∈ marked + · exact sentinelFirst_update hK hKn hR hL hw hq hu (hmarked hm) + · have hL' : R < L := by linarith + have hw' : ∀ y ∈ s, y ∈ marked → R < w y 0 := by + intro y hy hm + linarith [hw y hy hm] + rw [sentinelFirst_of_not_mem hm] + unfold update + rw [threshold_eq_sentinelFirst (hK.trans_le hKn) hR hL' hw' hu, + newDefault_eq_sentinelFirst (hK.trans_le hKn) hK hR hL' hw' hq hu, + sentinelFirst_of_not_mem hm] + +private theorem advance_sentinelState {a : State ι} {Δ : ι → Fin 2 → ℝ} + (hmarked : marked ⊆ s) (hK : 0 < K) (hKn : K ≤ n) (hR : 0 ≤ R) (hL : 3 * R < L) + (hw : ∀ y ∈ s, y ∈ marked → 3 * R < (a.row + Δ) y 0) + (hq : firstRank s K a.defaultValue (sentinelFirst marked L (a.row + Δ)) ≤ R) + (hu : threshold s n ρ a.defaultValue (sentinelFirst marked L (a.row + Δ)) ≤ R) : + advance s n K ρ (sentinelFirst marked 0 Δ) (sentinelState marked L a) = + sentinelState marked L (advance s n K ρ Δ a) := by + have hL' : R < L := by linarith + have hw' : ∀ y ∈ s, y ∈ marked → R < (a.row + Δ) y 0 := by + intro y hy hm + linarith [hw y hy hm] + unfold advance sentinelState + rw [← sentinelFirst_add] + congr 1 + · exact (newDefault_eq_sentinelFirst (hK.trans_le hKn) hK hR hL' hw' hq hu).symm + · exact (sentinelFirst_update_all hmarked hK hKn hR hL hw hq hu).symm + +end Update + +section Iteration + +variable {s marked : Finset ι} {n : ℕ → ℕ} {K : ℕ} {ρ : ℕ → ℝ} {R L : ℝ} + {Δ : ℕ → ι → Fin 2 → ℝ} {a : State ι} + +private theorem raw_first_gt_of_sum_abs_lt {m j : ℕ} {y : ι} (hj : j ≤ m) + (hvar : 3 * R + ∑ i ∈ range m, |Δ i y 0| < a.row y 0) : + 3 * R < uncompressedRow Δ a.row j y 0 := by + have hsum : ∑ i ∈ range j, |Δ i y 0| ≤ ∑ i ∈ range m, |Δ i y 0| := + sum_le_sum_of_subset_of_nonneg (range_mono hj) (fun _ _ _ => abs_nonneg _) + have habs : |∑ i ∈ range j, Δ i y 0| ≤ ∑ i ∈ range m, |Δ i y 0| := + (abs_sum_le_sum_abs _ _).trans hsum + have hlo := (abs_le.mp habs).1 + change 3 * R < a.row y 0 + ∑ i ∈ range j, Δ i y 0 + linarith + +/-- **Actual multi-step sentinel removal**. Only the modified run's input ranks and thresholds +are assumed bounded. Total raw first-channel variation proves that original marked inputs stay +in the compression identity region. Both original marked channels follow their raw prefixes. + +The result also identifies the actual padded ranks after every positive prefix and bounds them +by `R`. No equality or regularity law for final row outputs is assumed. -/ +theorem iterate_sentinelState_of_sum_abs_lt (m : ℕ) (hmarked : marked ⊆ s) + (hK : 0 < K) (hKn : ∀ i < m, K ≤ n i) (hR : 0 ≤ R) (hL : 3 * R < L) + (hvar : ∀ y ∈ marked, 3 * R + ∑ i ∈ range m, |Δ i y 0| < a.row y 0) : + let Δ' := fun i => sentinelFirst marked 0 (Δ i) + let b := sentinelState marked L a + (∀ i < m, firstRank s K (iterate s n (fun _ => K) ρ Δ' b i).defaultValue + (inputRow s n (fun _ => K) ρ Δ' b i) ≤ R) → + (∀ i < m, stepThreshold s n (fun _ => K) ρ Δ' b i ≤ R) → + ∀ j ≤ m, + let original := iterate s n (fun _ => K) ρ Δ a j + let modified := iterate s n (fun _ => K) ρ Δ' b j + modified = sentinelState marked L original ∧ + (∀ y ∈ marked, original.row y = uncompressedRow Δ a.row j y) ∧ + (0 < j → firstRank s K original.defaultValue original.row = + firstRank s K modified.defaultValue modified.row ∧ + firstRank s K modified.defaultValue modified.row ≤ R) := by + let Δ' := fun i => sentinelFirst marked 0 (Δ i) + let b := sentinelState marked L a + let A := iterate s n (fun _ => K) ρ Δ a + let B := iterate s n (fun _ => K) ρ Δ' b + change (∀ i < m, firstRank s K (B i).defaultValue + (inputRow s n (fun _ => K) ρ Δ' b i) ≤ R) → + (∀ i < m, stepThreshold s n (fun _ => K) ρ Δ' b i ≤ R) → + ∀ j ≤ m, B j = sentinelState marked L (A j) ∧ + (∀ y ∈ marked, (A j).row y = uncompressedRow Δ a.row j y) ∧ + (0 < j → firstRank s K (A j).defaultValue (A j).row = + firstRank s K (B j).defaultValue (B j).row ∧ + firstRank s K (B j).defaultValue (B j).row ≤ R) + intro hq hu j + induction j with + | zero => + intro _ + refine ⟨rfl, ?_, fun h => (Nat.not_lt_zero _ h).elim⟩ + intro y _ + simp only [uncompressedRow_zero, A, iterate_zero] + | succ j ih => + intro hj + have hjm : j < m := (Nat.lt_succ_self j).trans_le hj + obtain ⟨heq, hraw, _⟩ := ih ((Nat.le_succ j).trans hj) + have hinput : inputRow s n (fun _ => K) ρ Δ' b j = + sentinelFirst marked L (inputRow s n (fun _ => K) ρ Δ a j) := by + change (B j).row + Δ' j = sentinelFirst marked L ((A j).row + Δ j) + rw [heq] + exact (sentinelFirst_add marked L (A j).row (Δ j)).symm + have hq' : firstRank s K (A j).defaultValue + (sentinelFirst marked L (inputRow s n (fun _ => K) ρ Δ a j)) ≤ R := by + have h := hq j hjm + rw [hinput, heq] at h + exact h + have hu' : threshold s (n j) (ρ j) (A j).defaultValue + (sentinelFirst marked L (inputRow s n (fun _ => K) ρ Δ a j)) ≤ R := by + have h := hu j hjm + change threshold s (n j) (ρ j) (B j).defaultValue + (inputRow s n (fun _ => K) ρ Δ' b j) ≤ R at h + rw [hinput, heq] at h + exact h + have hrawInput (y : ι) (hy : y ∈ marked) : + inputRow s n (fun _ => K) ρ Δ a j y = uncompressedRow Δ a.row (j + 1) y := by + funext ν + change (A j).row y ν + Δ j y ν = _ + rw [hraw y hy, uncompressedRow_succ] + have hhigh : ∀ y ∈ s, y ∈ marked → + 3 * R < inputRow s n (fun _ => K) ρ Δ a j y 0 := by + intro y _ hy + rw [hrawInput y hy] + exact raw_first_gt_of_sum_abs_lt hj (hvar y hy) + have hnext : B (j + 1) = sentinelState marked L (A (j + 1)) := by + change advance s (n j) K (ρ j) (Δ' j) (B j) = + sentinelState marked L (advance s (n j) K (ρ j) (Δ j) (A j)) + rw [heq] + exact advance_sentinelState hmarked hK (hKn j hjm) hR hL hhigh hq' hu' + have hrawNext (y : ι) (hy : y ∈ marked) : + (A (j + 1)).row y = uncompressedRow Δ a.row (j + 1) y := by + exact (update_eq_self_of_mem_sentinelFirst (hK.trans_le (hKn j hjm)) hR hL + hhigh hu' (hmarked hy) hy).1.trans (hrawInput y hy) + have hbound : firstRank s K (B (j + 1)).defaultValue (B (j + 1)).row ≤ R := + firstRank_update_le_of_le hK hR (hq j hjm) (hu j hjm) + have hfinal : firstRank s K (A (j + 1)).defaultValue (A (j + 1)).row = + firstRank s K (B (j + 1)).defaultValue (B (j + 1)).row := by + rw [hnext] at hbound ⊢ + apply firstRank_eq_sentinelFirst hK hR (by linarith) _ hbound + intro y _ hy + rw [hrawNext y hy] + have h := raw_first_gt_of_sum_abs_lt hj (hvar y hy) + linarith + exact ⟨hnext, hrawNext, fun _ => ⟨hfinal, hbound⟩⟩ + +end Iteration + +end Cslib.RowCompression diff --git a/ComplexityTests/RowCompressionSentinelIteration.lean b/ComplexityTests/RowCompressionSentinelIteration.lean new file mode 100644 index 0000000000..90ce23a6c0 --- /dev/null +++ b/ComplexityTests/RowCompressionSentinelIteration.lean @@ -0,0 +1,182 @@ +/- +Copyright (c) 2026 Samuel Schlesinger. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Samuel Schlesinger +-/ + +import Complexity.Foundations.Analysis.RowCompression.SentinelIteration +import Mathlib.LinearAlgebra.Matrix.Notation +import Mathlib.Tactic.FinCases +import Mathlib.Tactic.NormNum + +/-! +# Two actual sentinel compression steps + +The marked first coordinate receives increments `-5,+7`; its second coordinate receives +`+2,-3`. The modified calculation clears only those first increments. Its two input rank and +threshold ceilings are proved by evaluating its actual intermediate states. The coupling theorem +then recovers the original marked raw prefix, common defaults, and exact final rank equality. +An unmarked endpoint has raw first prefix `-2` but compressed value `2`, so the calculation is +not globally identical to its uncompressed prefixes. +-/ + +namespace ComplexityTests.RowCompressionSentinelIteration + +open Finset Cslib.RowCompression + +private noncomputable def initial : State (Fin 4) := + { defaultValue := 1 / 2, row := ![![1000000, -17], ![4, 0], ![2, -1], ![-1, 1]] } + +private def increments (i : ℕ) : Fin 4 → Fin 2 → ℝ := + if i = 0 then ![![-5, 2], ![0, 0], ![0, 0], ![0, 0]] + else if i = 1 then ![![7, -3], ![0, 0], ![0, 0], ![-1, 1]] else 0 + +private noncomputable def cleared (i : ℕ) : Fin 4 → Fin 2 → ℝ := + sentinelFirst {0} 0 (increments i) + +private noncomputable def modifiedStart : State (Fin 4) := sentinelState {0} 100 initial + +private noncomputable def originalRun : ℕ → State (Fin 4) := + iterate univ (fun _ => 3) (fun _ => 3) (fun _ => 1) increments initial + +private noncomputable def modifiedRun : ℕ → State (Fin 4) := + iterate univ (fun _ => 3) (fun _ => 3) (fun _ => 1) cleared modifiedStart + +private noncomputable def modifiedInput : ℕ → Fin 4 → Fin 2 → ℝ := + inputRow univ (fun _ => 3) (fun _ => 3) (fun _ => 1) cleared modifiedStart + +private def inputZero : Fin 4 → Fin 2 → ℝ := ![![100, -15], ![4, 0], ![2, -1], ![-1, 1]] + +private def inputOne : Fin 4 → Fin 2 → ℝ := ![![100, -18], ![2, 0], ![2, 0], ![1, 1]] + +private theorem modified_input_zero : modifiedInput 0 = inputZero := by + funext y ν + fin_cases y <;> fin_cases ν <;> + norm_num [modifiedInput, inputRow, modifiedStart, sentinelState, initial, cleared, + sentinelFirst, increments, inputZero] + +private theorem rank_zero : firstRank univ 3 (1 / 2) inputZero = 2 := by + norm_num [firstRank, kthLargest, inputZero, Fin.univ_succ, filter_insert, filter_singleton] + +private theorem threshold_zero : threshold univ 3 1 (1 / 2) inputZero = 2 := by + norm_num [threshold, entrySize, kthLargest, inputZero, Fin.univ_succ, + filter_insert, filter_singleton] + +private theorem default_zero : newDefault univ 3 3 1 (1 / 2) inputZero = 2 := by + change max (threshold univ 3 1 (1 / 2) inputZero) + (min (firstRank univ 3 (1 / 2) inputZero) (3 * threshold univ 3 1 (1 / 2) inputZero)) = 2 + rw [threshold_zero, rank_zero] + norm_num + +private theorem modified_one : modifiedRun 1 = + { defaultValue := 2, row := ![![100, -15], ![2, 0], ![2, 0], ![2, 0]] } := by + have hin : modifiedStart.row + cleared 0 = inputZero := modified_input_zero + change advance univ 3 3 1 (cleared 0) modifiedStart = _ + unfold advance + rw [hin] + change State.mk (newDefault univ 3 3 1 (1 / 2) inputZero) + (update univ 3 3 1 (1 / 2) inputZero) = _ + rw [default_zero] + congr 1 + unfold update + rw [threshold_zero, default_zero] + funext y ν + fin_cases y <;> fin_cases ν <;> + norm_num [updateEntry, radius, entrySize, defaultEntry, inputZero] + +private theorem modified_input_one : modifiedInput 1 = inputOne := by + change (modifiedRun 1).row + cleared 1 = inputOne + rw [modified_one] + funext y ν + fin_cases y <;> fin_cases ν <;> norm_num [cleared, sentinelFirst, increments, inputOne] + +private theorem rank_one : firstRank univ 3 2 inputOne = 2 := by + norm_num [firstRank, kthLargest, inputOne, Fin.univ_succ, filter_insert, filter_singleton] + +private theorem threshold_one : threshold univ 3 1 2 inputOne = 2 := by + norm_num [threshold, entrySize, kthLargest, inputOne, Fin.univ_succ, + filter_insert, filter_singleton] + +private theorem default_one : newDefault univ 3 3 1 2 inputOne = 2 := by + change max (threshold univ 3 1 2 inputOne) + (min (firstRank univ 3 2 inputOne) (3 * threshold univ 3 1 2 inputOne)) = 2 + rw [threshold_one, rank_one] + norm_num + +private theorem modified_two : modifiedRun 2 = + { defaultValue := 2, row := ![![100, -18], ![2, 0], ![2, 0], ![2, 0]] } := by + have hin : (modifiedRun 1).row + cleared 1 = inputOne := modified_input_one + change advance univ 3 3 1 (cleared 1) (modifiedRun 1) = _ + unfold advance + rw [hin, modified_one] + rw [default_one] + congr 1 + unfold update + rw [threshold_one, default_one] + funext y ν + fin_cases y <;> fin_cases ν <;> + norm_num [updateEntry, radius, entrySize, defaultEntry, inputOne] + +private theorem modified_ceilings (i : ℕ) (hi : i < 2) : + firstRank univ 3 (modifiedRun i).defaultValue (modifiedInput i) ≤ 2 ∧ + threshold univ 3 1 (modifiedRun i).defaultValue (modifiedInput i) ≤ 2 := by + have hi' : i = 0 ∨ i = 1 := by omega + rcases hi' with rfl | rfl + · change firstRank univ 3 (1 / 2) (modifiedInput 0) ≤ 2 ∧ + threshold univ 3 1 (1 / 2) (modifiedInput 0) ≤ 2 + rw [modified_input_zero] + exact ⟨rank_zero.le, threshold_zero.le⟩ + · rw [modified_input_one, modified_one] + exact ⟨rank_one.le, threshold_one.le⟩ + +private theorem coupling (j : ℕ) (hj : j ≤ 2) : + modifiedRun j = sentinelState {0} 100 (originalRun j) ∧ + (∀ y ∈ ({0} : Finset (Fin 4)), + (originalRun j).row y = uncompressedRow increments initial.row j y) ∧ + (0 < j → firstRank univ 3 (originalRun j).defaultValue (originalRun j).row = + firstRank univ 3 (modifiedRun j).defaultValue (modifiedRun j).row ∧ + firstRank univ 3 (modifiedRun j).defaultValue (modifiedRun j).row ≤ 2) := by + apply iterate_sentinelState_of_sum_abs_lt (s := univ) (marked := {0}) (n := fun _ => 3) + (K := 3) (ρ := fun _ => 1) (Δ := increments) (a := initial) (R := 2) (L := 100) + 2 (subset_univ _) (by norm_num) (by intros; norm_num) (by norm_num) (by norm_num) + _ (fun i hi => (modified_ceilings i hi).1) (fun i hi => (modified_ceilings i hi).2) j hj + intro y hy + have hy0 : y = 0 := mem_singleton.mp hy + subst y + norm_num [sum_range_succ, increments, initial] + +-- Only the marked first increments are removed; nonzero signed second increments survive. +example : increments 0 0 0 = -5 ∧ increments 1 0 0 = 7 ∧ + cleared 0 0 0 = 0 ∧ cleared 1 0 0 = 0 ∧ cleared 0 0 1 = 2 ∧ cleared 1 0 1 = -3 := by + norm_num [increments, cleared, sentinelFirst] + +-- The original marked entry follows both raw prefixes, derived from the actual coupling theorem. +example : (originalRun 2).row 0 = ![1000002, -18] := by + rw [(coupling 2 (by norm_num)).2.1 0 (mem_singleton_self 0)] + funext ν + fin_cases ν <;> norm_num [uncompressedRow, initial, increments, sum_range_succ] + +-- The defaults genuinely rise from 1/2 to 2 and agree in the two actual calculations. +example : initial.defaultValue = 1 / 2 ∧ + (originalRun 2).defaultValue = 2 ∧ (modifiedRun 2).defaultValue = 2 := by + have heq := congrArg State.defaultValue (coupling 2 (by norm_num)).1 + rw [modified_two] at heq ⊢ + exact ⟨rfl, heq.symm, rfl⟩ + +-- Unmarked first values need not follow raw prefixes; actual compression still takes place. +example : (originalRun 2).row 3 0 = 2 ∧ + uncompressedRow increments initial.row 2 3 0 = -2 := by + have h := congrArg (fun a : State (Fin 4) => a.row 3 0) (coupling 2 (by norm_num)).1 + rw [modified_two] at h + have hfirst : (originalRun 2).row 3 0 = 2 := by + norm_num [sentinelState, sentinelFirst] at h + exact h.symm + exact ⟨hfirst, by norm_num [uncompressedRow, initial, increments, sum_range_succ]⟩ + +-- The post-update rank helper is consumed by the actual final-rank conclusion. +example : firstRank univ 3 (originalRun 2).defaultValue (originalRun 2).row = + firstRank univ 3 (modifiedRun 2).defaultValue (modifiedRun 2).row ∧ + firstRank univ 3 (modifiedRun 2).defaultValue (modifiedRun 2).row ≤ 2 := + (coupling 2 (by norm_num)).2.2 (by norm_num) + +end ComplexityTests.RowCompressionSentinelIteration From f9e5a7c9c39677ee28bddcb41f8fc98a5f647357 Mon Sep 17 00:00:00 2001 From: Samuel Schlesinger Date: Fri, 30 Oct 2026 19:02:13 +0000 Subject: [PATCH 18/19] feat(logspace): derive sentinel coupling from clipped prefix budgets Compare actual compression schedules with different increments using the exact 28-weighted propagation sum. Prove that stationary references preserve initial rank ceilings and bound their actual input thresholds. For fewer than K true first entries above a fixed level L0, derive every input rank, threshold and total-variation hypothesis of the existing sentinel-removal induction from clipped raw-prefix errors. The fixed sentinel is 16*(L0+1), the rank ceiling is 2*L0+1, and the small weighted budget is at most 1/8 after scaling by 1+16*(L0+1). No bound on the largest true entry, original compressed inputs, or final output discrepancy is assumed. Both marked original channels follow their actual raw prefixes, with exact default and padded-rank agreement. The 202-line signed behavioral suite exercises a genuine first overflow, default change and erasure of a negative low second channel, nonconstant raw evolution of a true first entry 1000, exact coupling to sentinel 32, and weighted budget 9933/125000. Its zero-initial global run verifies the local indexing: start from the already-added overflow input and use a zero first local increment. The preceding global raw prefix has large error and is not a required premise. It also checks failure of the heavy-count branch and of unclipping at error 1. Both libraries and the behavioral suite pass strict isolated direct Lean checks with warningAsError=true and no diagnostics. Focused hygiene with check-simp and whitespace checks pass. Full integration gates remain for hosted CI. This is the small-heavy-set sentinel coupling step of the relative-stability proof, not the full output comparison. Upper saturation, the at-least-K large entry branch, and integrated compression remain open under #1721 and #1444. AI-assisted implementation by ChatGPT agent polynomial_false_finish; exact revision independent review pending before publication. Independent non-author agent polynomial_false_review approved exact source fd5e03c3ea1a7eb550f0d731bc4548a9da535bd3 with no remaining findings. The only review correction normalized three module-comment headings; final integration strictly rechecked all source and tests and preserves reviewed bytes. Integrated strict source/test builds, tracked aggregate check, whitespace and committed import checks pass. Full integration gates run in PR CI. --- Complexity.lean | 2 + .../Analysis/RowCompression/Perturbation.lean | 168 +++++++ .../RowCompression/SentinelRelative.lean | 409 ++++++++++++++++++ .../RowCompressionSentinelRelative.lean | 203 +++++++++ 4 files changed, 782 insertions(+) create mode 100644 Complexity/Foundations/Analysis/RowCompression/Perturbation.lean create mode 100644 Complexity/Foundations/Analysis/RowCompression/SentinelRelative.lean create mode 100644 ComplexityTests/RowCompressionSentinelRelative.lean diff --git a/Complexity.lean b/Complexity.lean index 60b8dd9f09..50f8c718ea 100644 --- a/Complexity.lean +++ b/Complexity.lean @@ -2355,10 +2355,12 @@ public import Complexity.Foundations.Analysis.RowCompression public import Complexity.Foundations.Analysis.RowCompression.FalseOverflow public import Complexity.Foundations.Analysis.RowCompression.Floors public import Complexity.Foundations.Analysis.RowCompression.Iteration +public import Complexity.Foundations.Analysis.RowCompression.Perturbation public import Complexity.Foundations.Analysis.RowCompression.Preloss public import Complexity.Foundations.Analysis.RowCompression.Reference public import Complexity.Foundations.Analysis.RowCompression.Sentinel public import Complexity.Foundations.Analysis.RowCompression.SentinelIteration +public import Complexity.Foundations.Analysis.RowCompression.SentinelRelative public import Complexity.Foundations.Analysis.RowCompression.Stationary public import Complexity.Foundations.Analysis.SpecialFunctions.Arccos public import Complexity.Foundations.Analysis.SpecialFunctions.SmoothSwitch diff --git a/Complexity/Foundations/Analysis/RowCompression/Perturbation.lean b/Complexity/Foundations/Analysis/RowCompression/Perturbation.lean new file mode 100644 index 0000000000..7536d0b75a --- /dev/null +++ b/Complexity/Foundations/Analysis/RowCompression/Perturbation.lean @@ -0,0 +1,168 @@ +/- +Copyright (c) 2026 Samuel Schlesinger. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Samuel Schlesinger +-/ + +module +-- upstream: candidate + +public import Complexity.Foundations.Analysis.RowCompression.Reference +import Mathlib.Algebra.BigOperators.Ring.Finset +import Mathlib.Algebra.Order.BigOperators.Group.Finset +import Mathlib.Tactic.Linarith +import Mathlib.Tactic.Positivity +import Mathlib.Tactic.Ring + +/-! +# Perturbations of compression schedules + +The concrete compression update has Lipschitz constant `28`. Comparing schedules with different +increments gives an initial-error term `28 ^ m * δ` and a sum of increment-error terms +`28 ^ (m - i) * ε i`. Both defaults and all retained coordinates satisfy the same bound. + +A zero-increment reference with the usual small negative and second-coordinate bounds preserves +an initial padded-rank ceiling above the floor scale. Its actual thresholds satisfy that ceiling +as well. These estimates are the absolute-error ingredients of the sentinel comparison in +[OpenAI2026LogSpace, Section 8.3, Lemma 8.3]. They do not by themselves convert relative errors +at unbounded first coordinates to absolute errors or prove the final row-output comparison. + +## Main results + +* `Cslib.RowCompression.iterate_stability_of_increment_error`: weighted stability for two actual + schedules with different increments. +* `Cslib.RowCompression.reference_iterate_firstRank_le`: a uniform padded-rank ceiling for + zero-increment references. +* `Cslib.RowCompression.reference_stepThreshold_le`: the corresponding actual threshold bound. + +## References + +* [OpenAI, *Exact Derandomization of Logarithmic Space: L = RL = BPL*][OpenAI2026LogSpace], + Section 8.3, proof of Lemma 8.3, the absolute comparison after sentinel replacement + (23 September 2026, revision `7ef5c0cc`, not peer reviewed). +-/ + +public section + +namespace Cslib.RowCompression + +open Finset + +variable {ι : Type*} {s : Finset ι} {a b : State ι} + +/-- One update with an increment discrepancy adds that discrepancy before the factor `28`. +The initial defaults and both full rows may already differ. -/ +theorem advance_stability_of_increment_error {n K : ℕ} {ρ δ ε : ℝ} + {Δ Δ' : ι → Fin 2 → ℝ} (hn : 0 < n) (hK : 0 < K) (hδ : 0 ≤ δ) (hε : 0 ≤ ε) + (hz : |a.defaultValue - b.defaultValue| ≤ δ) + (hw : ∀ y ∈ s, ∀ ν, |a.row y ν - b.row y ν| ≤ δ) + (hΔ : ∀ y ∈ s, ∀ ν, |Δ y ν - Δ' y ν| ≤ ε) : + |(advance s n K ρ Δ a).defaultValue - (advance s n K ρ Δ' b).defaultValue| ≤ + 28 * (δ + ε) ∧ + ∀ y ∈ s, ∀ ν, + |(advance s n K ρ Δ a).row y ν - (advance s n K ρ Δ' b).row y ν| ≤ + 28 * (δ + ε) := by + have hinput (y : ι) (hy : y ∈ s) (ν : Fin 2) : + |(a.row + Δ) y ν - (b.row + Δ') y ν| ≤ δ + ε := by + calc + _ = |(a.row y ν - b.row y ν) + (Δ y ν - Δ' y ν)| := by + congr 1 + simp only [Pi.add_apply] + ring + _ ≤ |a.row y ν - b.row y ν| + |Δ y ν - Δ' y ν| := abs_add_le _ _ + _ ≤ δ + ε := add_le_add (hw y hy ν) (hΔ y hy ν) + have hz' : |a.defaultValue - b.defaultValue| ≤ δ + ε := hz.trans (le_add_of_nonneg_right hε) + constructor + · exact (abs_newDefault_sub_newDefault_le hn hK (add_nonneg hδ hε) hz' hinput).trans + (by nlinarith) + · intro y hy ν + exact abs_update_sub_update_le hn hK (add_nonneg hδ hε) hz' hinput hy ν + +private theorem propagation_succ (δ : ℝ) (ε : ℕ → ℝ) (j : ℕ) : + 28 * (28 ^ j * δ + ∑ i ∈ range j, 28 ^ (j - i) * ε i + ε j) = + 28 ^ (j + 1) * δ + ∑ i ∈ range (j + 1), 28 ^ (j + 1 - i) * ε i := by + have hsum : (∑ i ∈ range j, (28 : ℝ) ^ (j + 1 - i) * ε i) = + 28 * ∑ i ∈ range j, (28 : ℝ) ^ (j - i) * ε i := by + rw [mul_sum] + apply sum_congr rfl + intro i hi + have hexp : j + 1 - i = (j - i) + 1 := by + have hi' := mem_range.mp hi + omega + rw [hexp, pow_succ] + ring + rw [sum_range_succ, hsum] + simp only [Nat.add_sub_cancel_left, pow_succ] + ring + +/-- Different increments contribute at the group where they are actually added, with one +factor `28` for that update and for each subsequent update. No threshold ceiling is assumed. -/ +theorem iterate_stability_of_increment_error {n K : ℕ → ℕ} {ρ : ℕ → ℝ} + {Δ Δ' : ℕ → ι → Fin 2 → ℝ} {δ : ℝ} {ε : ℕ → ℝ} + (hδ : 0 ≤ δ) (hz : |a.defaultValue - b.defaultValue| ≤ δ) + (hw : ∀ y ∈ s, ∀ ν, |a.row y ν - b.row y ν| ≤ δ) (m : ℕ) + (hn : ∀ i < m, 0 < n i) (hK : ∀ i < m, 0 < K i) + (hε : ∀ i < m, 0 ≤ ε i) + (hΔ : ∀ i < m, ∀ y ∈ s, ∀ ν, |Δ i y ν - Δ' i y ν| ≤ ε i) : + |(iterate s n K ρ Δ a m).defaultValue - (iterate s n K ρ Δ' b m).defaultValue| ≤ + 28 ^ m * δ + ∑ i ∈ range m, 28 ^ (m - i) * ε i ∧ + ∀ y ∈ s, ∀ ν, + |(iterate s n K ρ Δ a m).row y ν - (iterate s n K ρ Δ' b m).row y ν| ≤ + 28 ^ m * δ + ∑ i ∈ range m, 28 ^ (m - i) * ε i := by + induction m with + | zero => simpa using And.intro hz hw + | succ m ih => + have ih' := ih (fun i hi => hn i (Nat.lt_succ_of_lt hi)) + (fun i hi => hK i (Nat.lt_succ_of_lt hi)) + (fun i hi => hε i (Nat.lt_succ_of_lt hi)) + (fun i hi => hΔ i (Nat.lt_succ_of_lt hi)) + have hbudget : 0 ≤ 28 ^ m * δ + ∑ i ∈ range m, 28 ^ (m - i) * ε i := by + exact add_nonneg (mul_nonneg (by positivity) hδ) + (sum_nonneg fun i hi => mul_nonneg (by positivity) + (hε i (Nat.lt_succ_of_lt (mem_range.mp hi)))) + have h := advance_stability_of_increment_error (ρ := ρ m) + (hn m (Nat.lt_succ_self m)) (hK m (Nat.lt_succ_self m)) hbudget + (hε m (Nat.lt_succ_self m)) ih'.1 ih'.2 (hΔ m (Nat.lt_succ_self m)) + simpa only [iterate_succ, propagation_succ] using h + +section Reference + +variable {n : ℕ → ℕ} {K : ℕ} {ρ : ℕ → ℝ} {η Q : ℝ} + +/-- A stationary reference's padded first rank stays below any initial ceiling above the +reference scale. The hypotheses are only on its initial row and the finite schedule. -/ +theorem reference_iterate_firstRank_le (hη : 0 ≤ η) (hηQ : η ≤ Q) (hK : 0 < K) + (hfirst : ∀ y ∈ s, -η ≤ a.row y 0) (hsecond : ∀ y ∈ s, |a.row y 1| ≤ η) + (hq : firstRank s K a.defaultValue a.row ≤ Q) (m : ℕ) + (hn : ∀ i < m, K ≤ n i) (hρ : ∀ i < m, ρ i ≤ η) : + firstRank s K (iterate s n (fun _ => K) ρ (fun _ => 0) a m).defaultValue + (iterate s n (fun _ => K) ρ (fun _ => 0) a m).row ≤ Q := by + induction m with + | zero => exact hq + | succ m ih => + have hprev := ih (fun i hi => hn i (Nat.lt_succ_of_lt hi)) + (fun i hi => hρ i (Nat.lt_succ_of_lt hi)) + have hb := reference_iterate_bounds (n := n) (K := K) (ρ := ρ) hη hfirst hsecond m + have hnext := reference_firstRank_le + (z := (iterate s n (fun _ => K) ρ (fun _ => 0) a m).defaultValue) + hη (hρ m (Nat.lt_succ_self m)) hK + (hn m (Nat.lt_succ_self m)) hb.1 hb.2 + simpa only [iterate_succ, advance, add_zero] using hnext.trans (max_le hηQ hprev) + +/-- The same initial reference ceiling controls every actual input threshold. -/ +theorem reference_stepThreshold_le (hη : 0 ≤ η) (hηQ : η ≤ Q) (hK : 0 < K) + (hfirst : ∀ y ∈ s, -η ≤ a.row y 0) (hsecond : ∀ y ∈ s, |a.row y 1| ≤ η) + (hq : firstRank s K a.defaultValue a.row ≤ Q) (m : ℕ) + (hn : ∀ i ≤ m, K ≤ n i) (hρ : ∀ i ≤ m, ρ i ≤ η) : + stepThreshold s n (fun _ => K) ρ (fun _ => 0) a m ≤ Q := by + have hb := reference_iterate_bounds (n := n) (K := K) (ρ := ρ) hη hfirst hsecond m + have hr := reference_iterate_firstRank_le hη hηQ hK hfirst hsecond hq m + (fun i hi => hn i hi.le) (fun i hi => hρ i hi.le) + have ht := reference_threshold_le + (z := (iterate s n (fun _ => K) ρ (fun _ => 0) a m).defaultValue) + hη (hρ m le_rfl) hK (hn m le_rfl) hb.1 hb.2 + simpa only [stepThreshold, inputRow, add_zero] using ht.trans (max_le hηQ hr) + +end Reference + +end Cslib.RowCompression diff --git a/Complexity/Foundations/Analysis/RowCompression/SentinelRelative.lean b/Complexity/Foundations/Analysis/RowCompression/SentinelRelative.lean new file mode 100644 index 0000000000..e7d4293220 --- /dev/null +++ b/Complexity/Foundations/Analysis/RowCompression/SentinelRelative.lean @@ -0,0 +1,409 @@ +/- +Copyright (c) 2026 Samuel Schlesinger. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Samuel Schlesinger +-/ + +module +-- upstream: candidate + +public import Complexity.Foundations.Analysis.RowCompression.Perturbation +public import Complexity.Foundations.Analysis.RowCompression.Preloss +public import Complexity.Foundations.Analysis.RowCompression.SentinelIteration +import Mathlib.Algebra.BigOperators.Ring.Finset +import Mathlib.Algebra.Order.BigOperators.Group.Finset +import Mathlib.Algebra.Order.Group.MinMax +import Mathlib.Tactic.FinCases +import Mathlib.Tactic.Linarith +import Mathlib.Tactic.Positivity +import Mathlib.Tactic.Ring + +/-! +# Deriving sentinel comparison bounds from clipped prefix errors + +Suppose fewer than `K` true first entries exceed `L₀`, and the actual raw prefixes have small +clipped errors. Replace first entries above `16 * (L₀ + 1)` by that common sentinel and clear +only their later first increments. The modified calculation has bounded actual input ranks and +thresholds, and the original marked entries remain in the compression identity region. + +The ceilings and the total-variation hypothesis of +`Cslib.RowCompression.iterate_sentinelState_of_sum_abs_lt` are derived here, rather than assumed. +The comparison reference has the true row plus the same small initial loss and no increments. +The finite error budget is the exact `28`-weighted sum supplied by absolute update stability. +No upper bound on the largest true entry, original compressed input, or final output error is +assumed. + +For a first-overflow application, start the local calculation from the already-added input of +that group, use a zero first local increment, and then use the subsequent actual increments. +Both the initial and first local prefix errors then concern the overflow group's raw input. +This does not require an error estimate for the preceding global prefix. + +This supplies the small-heavy-set sentinel comparison in the proof of +[OpenAI2026LogSpace, Section 8.3, Lemma 8.3]. Upper saturation and the row-output comparison, +the case of at least `K` large true entries, and the full relative-stability estimate remain +separate. Sentinels are analytical devices, not objects stored by the compression algorithm. + +## Main results + +* `Cslib.RowCompression.abs_sub_le_of_clippedError_le`: small clipped errors give the actual + relative first-channel and absolute second-channel bounds. +* `Cslib.RowCompression.iterate_sentinelState_of_clippedError_le`: actual sentinel coupling + from clipped prefix budgets and a strict true-heavy-count bound. + +## References + +* [OpenAI, *Exact Derandomization of Logarithmic Space: L = RL = BPL*][OpenAI2026LogSpace], + Section 8.3, proof of Lemma 8.3, the branch with fewer than `K` entries above `L₀` + (23 September 2026, revision `7ef5c0cc`, not peer reviewed). +-/ + +public section + +namespace Cslib.RowCompression + +open Finset + +/-- Below one, clipping discards no information. The first target may be arbitrarily large. -/ +theorem abs_sub_le_of_clippedError_le {d v ε : ℝ} {w : Fin 2 → ℝ} + (hd : 0 ≤ d) (hε : ε < 1) (he : clippedError d v w ≤ ε) : + |w 0 - d| ≤ (1 + d) * ε ∧ |w 1 - v| ≤ ε := by + have hfirst : |w 0 - d| / (1 + d) ≤ ε := + (min_le_iff.mp ((le_max_left _ _).trans he)).resolve_left (not_le.mpr hε) + have hsecond : |w 1 - v| ≤ ε := + (min_le_iff.mp ((le_max_right _ _).trans he)).resolve_left (not_le.mpr hε) + refine ⟨?_, hsecond⟩ + simpa only [mul_comm] using (div_le_iff₀ (by linarith : 0 < 1 + d)).mp hfirst + +private def budget (ε : ℕ → ℝ) (m : ℕ) : ℝ := + 28 ^ m * ε 0 + ∑ i ∈ range m, 28 ^ (m - i) * (ε i + ε (i + 1)) + +private theorem budget_nonneg {ε : ℕ → ℝ} {m : ℕ} (hε : ∀ i ≤ m, 0 ≤ ε i) : + 0 ≤ budget ε m := by + apply add_nonneg (mul_nonneg (by positivity) (hε 0 (Nat.zero_le m))) + refine sum_nonneg fun i hi => mul_nonneg (by positivity) (add_nonneg ?_ ?_) + · exact hε i (mem_range.mp hi).le + · exact hε (i + 1) (mem_range.mp hi) + +private theorem budget_mono {ε : ℕ → ℝ} {j m : ℕ} + (hε : ∀ i ≤ m, 0 ≤ ε i) (hj : j ≤ m) : budget ε j ≤ budget ε m := by + apply add_le_add + · exact mul_le_mul_of_nonneg_right (pow_le_pow_right₀ (by norm_num) hj) + (hε 0 (Nat.zero_le m)) + calc + _ ≤ ∑ i ∈ range j, (28 : ℝ) ^ (m - i) * (ε i + ε (i + 1)) := by + refine sum_le_sum fun i hi => mul_le_mul_of_nonneg_right + (pow_le_pow_right₀ (by norm_num) (Nat.sub_le_sub_right hj i)) ?_ + exact add_nonneg (hε i ((mem_range.mp hi).le.trans hj)) + (hε (i + 1) ((mem_range.mp hi).trans_le hj)) + _ ≤ _ := sum_le_sum_of_subset_of_nonneg (range_mono hj) fun i hi _ => + mul_nonneg (by positivity) + (add_nonneg (hε i (mem_range.mp hi).le) (hε (i + 1) (mem_range.mp hi))) + +private theorem sum_errors_le_budget {ε : ℕ → ℝ} {m : ℕ} + (hε : ∀ i ≤ m, 0 ≤ ε i) : + ε 0 + ∑ i ∈ range m, (ε i + ε (i + 1)) ≤ budget ε m := by + apply add_le_add + · exact le_mul_of_one_le_left (hε 0 (Nat.zero_le m)) (one_le_pow₀ (by norm_num)) + · exact sum_le_sum fun i hi => le_mul_of_one_le_left + (add_nonneg (hε i (mem_range.mp hi).le) (hε (i + 1) (mem_range.mp hi))) + (one_le_pow₀ (by norm_num)) + +private theorem error_le_budget {ε : ℕ → ℝ} {m i : ℕ} + (hε : ∀ i ≤ m, 0 ≤ ε i) (hi : i ≤ m) : ε i ≤ budget ε m := by + have hsum := sum_errors_le_budget hε + have hs0 : 0 ≤ ∑ k ∈ range m, (ε k + ε (k + 1)) := + sum_nonneg fun k hk => add_nonneg (hε k (mem_range.mp hk).le) + (hε (k + 1) (mem_range.mp hk)) + cases i with + | zero => exact (le_add_of_nonneg_right hs0).trans hsum + | succ i => + have hsingle := single_le_sum (s := range m) (f := fun k => ε k + ε (k + 1)) + (fun k hk => add_nonneg (hε k (mem_range.mp hk).le) (hε (k + 1) (mem_range.mp hk))) + (mem_range.mpr hi) + have hi0 := hε i (Nat.le_of_lt hi) + have h00 := hε 0 (Nat.zero_le m) + linarith + +private theorem input_budget_le {ε : ℕ → ℝ} {m i : ℕ} + (hε : ∀ k ≤ m, 0 ≤ ε k) (hi : i < m) : + budget ε i + (ε i + ε (i + 1)) ≤ budget ε m := by + apply le_trans (b := budget ε (i + 1)) _ (budget_mono hε hi) + unfold budget + rw [sum_range_succ] + simp only [Nat.add_sub_cancel_left, pow_one] + conv_rhs => rw [← add_assoc] + apply add_le_add + · apply add_le_add + · exact mul_le_mul_of_nonneg_right + (pow_le_pow_right₀ (by norm_num) (Nat.le_succ i)) (hε 0 (Nat.zero_le m)) + · refine sum_le_sum fun k hk => mul_le_mul_of_nonneg_right + (pow_le_pow_right₀ (by norm_num) (Nat.sub_le_sub_right (Nat.le_succ i) k)) ?_ + exact add_nonneg (hε k ((mem_range.mp hk).le.trans hi.le)) + (hε (k + 1) ((mem_range.mp hk).trans_le hi.le)) + · exact le_mul_of_one_le_left (add_nonneg (hε i hi.le) (hε (i + 1) hi)) (by norm_num) + +variable {ι : Type*} + +private theorem sentinel_reference_bounds {s : Finset ι} {K : ℕ} {η L₀ z : ℝ} + {truth loss : ι → Fin 2 → ℝ} (hη : 0 ≤ η) (hL₀ : η ≤ L₀) (hK : 0 < K) (hz : z ≤ η) + (hfirst : ∀ y ∈ s, 0 ≤ truth y 0) (hsecond : ∀ y ∈ s, |truth y 1| ≤ η / 2) + (hloss : ∀ y ∈ s, ∀ ν, |loss y ν| ≤ η / 2) + (hcount : #{y ∈ s | L₀ < truth y 0} < K) : + let marked := {y ∈ s | 16 * (L₀ + 1) < truth y 0} + let b := sentinelState marked (16 * (L₀ + 1)) ⟨z, truth + loss⟩ + (∀ y ∈ s, -η ≤ b.row y 0) ∧ (∀ y ∈ s, |b.row y 1| ≤ η) ∧ + firstRank s K b.defaultValue b.row ≤ 2 * L₀ := by + classical + let marked := {y ∈ s | 16 * (L₀ + 1) < truth y 0} + let b := sentinelState marked (16 * (L₀ + 1)) ⟨z, truth + loss⟩ + change (∀ y ∈ s, -η ≤ b.row y 0) ∧ (∀ y ∈ s, |b.row y 1| ≤ η) ∧ + firstRank s K b.defaultValue b.row ≤ 2 * L₀ + have hL₀0 : 0 ≤ L₀ := hη.trans hL₀ + have hshape : (∀ y ∈ s, -η ≤ b.row y 0) ∧ (∀ y ∈ s, |b.row y 1| ≤ η) := by + constructor + · intro y hy + by_cases hm : y ∈ marked + · change -η ≤ sentinelFirst marked (16 * (L₀ + 1)) (truth + loss) y 0 + rw [sentinelFirst_zero_of_mem hm] + linarith + · change -η ≤ sentinelFirst marked (16 * (L₀ + 1)) (truth + loss) y 0 + rw [sentinelFirst_of_not_mem hm] + have hl := (abs_le.mp (hloss y hy 0)).1 + change -η ≤ truth y 0 + loss y 0 + linarith [hfirst y hy] + · intro y hy + change |sentinelFirst marked (16 * (L₀ + 1)) (truth + loss) y 1| ≤ η + rw [sentinelFirst_one] + exact (abs_add_le _ _).trans (by linarith [hsecond y hy, hloss y hy 1]) + refine ⟨hshape.1, hshape.2, max_le (by change z ≤ 2 * L₀; linarith) ?_⟩ + by_contra hq + have hcard := (lt_kthLargest_iff hK (by positivity : 0 ≤ 2 * L₀)).mp (lt_of_not_ge hq) + have hsub : ({y ∈ s | 2 * L₀ < b.row y 0} : Finset ι) ⊆ + {y ∈ s | L₀ < truth y 0} := by + intro y hy + obtain ⟨hys, hy⟩ := mem_filter.mp hy + refine mem_filter.mpr ⟨hys, ?_⟩ + by_cases hm : y ∈ marked + · have hlarge := (mem_filter.mp hm).2 + linarith + · change 2 * L₀ < sentinelFirst marked (16 * (L₀ + 1)) (truth + loss) y 0 at hy + rw [sentinelFirst_of_not_mem hm] at hy + have hl := (abs_le.mp (hloss y hys 0)).2 + change 2 * L₀ < truth y 0 + loss y 0 at hy + linarith + exact (not_le.mpr hcount) (hcard.trans (card_le_card hsub)) + +open Classical in +/-- **Sentinel coupling from actual clipped-prefix budgets.** The threshold and variation +conditions of the removal induction follow from the true heavy-count branch and the weighted +prefix budget. `loss` is the common initial preloss; it is not a final-error hypothesis. + +Only marked first increments are cleared. Both original marked channels follow their actual +raw prefixes, and all positive-prefix padded ranks agree exactly. -/ +theorem iterate_sentinelState_of_clippedError_le {s : Finset ι} {n : ℕ → ℕ} {K : ℕ} + {ρ : ℕ → ℝ} {η L₀ z : ℝ} {truth raw₀ loss : ι → Fin 2 → ℝ} + {Δ : ℕ → ι → Fin 2 → ℝ} {ε : ℕ → ℝ} (m : ℕ) + (hη : 0 ≤ η) (hL₀ : η ≤ L₀) (hzη : z ≤ η) (hK : 0 < K) + (hKn : ∀ i < m, K ≤ n i) (hρ : ∀ i < m, ρ i ≤ η) + (hfirst : ∀ y ∈ s, 0 ≤ truth y 0) (hsecond : ∀ y ∈ s, |truth y 1| ≤ η / 2) + (hloss : ∀ y ∈ s, ∀ ν, |loss y ν| ≤ η / 2) + (hcount : #{y ∈ s | L₀ < truth y 0} < K) + (hε : ∀ i ≤ m, 0 ≤ ε i) + (herr : ∀ i ≤ m, ∀ y ∈ s, + clippedError (truth y 0) (truth y 1) (uncompressedRow Δ raw₀ i y) ≤ ε i) + (hsmall : (1 + 16 * (L₀ + 1)) * + (28 ^ m * ε 0 + ∑ i ∈ range m, 28 ^ (m - i) * (ε i + ε (i + 1))) ≤ 1 / 8) : + let L := 16 * (L₀ + 1) + let R := 2 * L₀ + 1 + let marked := {y ∈ s | L < truth y 0} + let a : State ι := ⟨z, raw₀ + loss⟩ + let original := iterate s n (fun _ => K) ρ Δ a + let modified := iterate s n (fun _ => K) ρ + (fun i => sentinelFirst marked 0 (Δ i)) (sentinelState marked L a) + ∀ j ≤ m, modified j = sentinelState marked L (original j) ∧ + (∀ y ∈ marked, (original j).row y = uncompressedRow Δ a.row j y) ∧ + (0 < j → firstRank s K (original j).defaultValue (original j).row = + firstRank s K (modified j).defaultValue (modified j).row ∧ + firstRank s K (modified j).defaultValue (modified j).row ≤ R) := by + classical + let L := 16 * (L₀ + 1) + let R := 2 * L₀ + 1 + let c := 1 + L + let marked := {y ∈ s | L < truth y 0} + let a : State ι := ⟨z, raw₀ + loss⟩ + let b : State ι := ⟨z, truth + loss⟩ + let a' := sentinelState marked L a + let b' := sentinelState marked L b + let Δ' := fun i => sentinelFirst marked 0 (Δ i) + let A := iterate s n (fun _ => K) ρ Δ' a' + let B := iterate s n (fun _ => K) ρ (fun _ => 0) b' + have hL₀0 : 0 ≤ L₀ := hη.trans hL₀ + have hc1 : 1 ≤ c := by dsimp only [c, L]; linarith + have hc0 : 0 ≤ c := (by norm_num : (0 : ℝ) ≤ 1).trans hc1 + have hR : 0 ≤ R := by dsimp only [R]; positivity + have hL : 3 * R < L := by dsimp only [R, L]; linarith + have hmarked : marked ⊆ s := filter_subset _ _ + have hsmall' : c * budget ε m ≤ 1 / 8 := hsmall + have hE : budget ε m ≤ 1 / 8 := + (le_mul_of_one_le_left (budget_nonneg hε) hc1).trans hsmall' + have hεlt (i : ℕ) (hi : i ≤ m) : ε i < 1 := by + have h := (error_le_budget hε hi).trans hE + linarith + have hraw (i : ℕ) (hi : i ≤ m) (y : ι) (hy : y ∈ s) : + |uncompressedRow Δ raw₀ i y 0 - truth y 0| ≤ (1 + truth y 0) * ε i ∧ + |uncompressedRow Δ raw₀ i y 1 - truth y 1| ≤ ε i := + abs_sub_le_of_clippedError_le (hfirst y hy) (hεlt i hi) (herr i hi y hy) + have hincr (i : ℕ) (hi : i < m) (y : ι) (hy : y ∈ s) : + |Δ i y 0| ≤ (1 + truth y 0) * (ε i + ε (i + 1)) ∧ + |Δ i y 1| ≤ ε i + ε (i + 1) := by + have hbefore := hraw i hi.le y hy + have hafter := hraw (i + 1) hi y hy + have heq (ν : Fin 2) : Δ i y ν = + (uncompressedRow Δ raw₀ (i + 1) y ν - truth y ν) - + (uncompressedRow Δ raw₀ i y ν - truth y ν) := by + rw [uncompressedRow_succ] + ring + constructor + · rw [heq 0] + exact (abs_sub _ _).trans (by linarith [hbefore.1, hafter.1]) + · rw [heq 1] + exact (abs_sub _ _).trans (by linarith [hbefore.2, hafter.2]) + have hoff (y : ι) (hy : y ∈ s) (hm : y ∉ marked) : truth y 0 ≤ L := by + exact not_lt.mp fun h => hm (mem_filter.mpr ⟨hy, h⟩) + have hinit (y : ι) (hy : y ∈ s) (ν : Fin 2) : |a'.row y ν - b'.row y ν| ≤ c * ε 0 := by + have hr := hraw 0 (Nat.zero_le m) y hy + simp only [uncompressedRow_zero] at hr + fin_cases ν + · by_cases hm : y ∈ marked + · change |sentinelFirst marked L a.row y 0 - sentinelFirst marked L b.row y 0| ≤ _ + rw [sentinelFirst_zero_of_mem hm, sentinelFirst_zero_of_mem hm, sub_self, abs_zero] + exact mul_nonneg hc0 (hε 0 (Nat.zero_le m)) + · change |sentinelFirst marked L a.row y 0 - sentinelFirst marked L b.row y 0| ≤ _ + rw [sentinelFirst_of_not_mem hm, sentinelFirst_of_not_mem hm] + change |raw₀ y 0 + loss y 0 - (truth y 0 + loss y 0)| ≤ _ + rw [add_sub_add_right_eq_sub] + exact hr.1.trans (mul_le_mul_of_nonneg_right (by dsimp only [c]; linarith [hoff y hy hm]) + (hε 0 (Nat.zero_le m))) + · change |sentinelFirst marked L a.row y 1 - sentinelFirst marked L b.row y 1| ≤ _ + rw [sentinelFirst_one, sentinelFirst_one] + change |raw₀ y 1 + loss y 1 - (truth y 1 + loss y 1)| ≤ _ + rw [add_sub_add_right_eq_sub] + exact hr.2.trans (le_mul_of_one_le_left (hε 0 (Nat.zero_le m)) hc1) + have hΔ' (i : ℕ) (hi : i < m) (y : ι) (hy : y ∈ s) (ν : Fin 2) : + |Δ' i y ν - (0 : ι → Fin 2 → ℝ) y ν| ≤ c * (ε i + ε (i + 1)) := by + have hsum0 := add_nonneg (hε i hi.le) (hε (i + 1) hi) + simp only [Pi.zero_apply, sub_zero] + fin_cases ν + · by_cases hm : y ∈ marked + · change |sentinelFirst marked 0 (Δ i) y 0| ≤ _ + rw [sentinelFirst_zero_of_mem hm, abs_zero] + exact mul_nonneg hc0 hsum0 + · change |sentinelFirst marked 0 (Δ i) y 0| ≤ _ + rw [sentinelFirst_of_not_mem hm] + exact (hincr i hi y hy).1.trans (mul_le_mul_of_nonneg_right + (by dsimp only [c]; linarith [hoff y hy hm]) hsum0) + · change |sentinelFirst marked 0 (Δ i) y 1| ≤ _ + rw [sentinelFirst_one] + exact (hincr i hi y hy).2.trans (le_mul_of_one_le_left hsum0 hc1) + have hreference := sentinel_reference_bounds hη hL₀ hK hzη hfirst hsecond hloss hcount + change (∀ y ∈ s, -η ≤ b'.row y 0) ∧ (∀ y ∈ s, |b'.row y 1| ≤ η) ∧ + firstRank s K b'.defaultValue b'.row ≤ 2 * L₀ at hreference + have hstates (i : ℕ) (hi : i ≤ m) : + |(A i).defaultValue - (B i).defaultValue| ≤ c * budget ε i ∧ + ∀ y ∈ s, ∀ ν, |(A i).row y ν - (B i).row y ν| ≤ c * budget ε i := by + have hz' : |a'.defaultValue - b'.defaultValue| ≤ c * ε 0 := by + change |z - z| ≤ _ + simpa only [sub_self, abs_zero] using mul_nonneg hc0 (hε 0 (Nat.zero_le m)) + have hs := iterate_stability_of_increment_error (ρ := ρ) + (mul_nonneg hc0 (hε 0 (Nat.zero_le m))) hz' hinit i + (fun k hk => hK.trans_le (hKn k (hk.trans_le hi))) (fun _ _ => hK) + (fun k hk => mul_nonneg hc0 + (add_nonneg (hε k (hk.le.trans hi)) (hε (k + 1) (hk.trans_le hi)))) + (fun k hk => hΔ' k (hk.trans_le hi)) + have heq : (28 : ℝ) ^ i * (c * ε 0) + + ∑ k ∈ range i, 28 ^ (i - k) * (c * (ε k + ε (k + 1))) = c * budget ε i := by + simp only [budget, mul_add, mul_sum] + congr 1 + · ring + · apply sum_congr rfl + intro k _ + ring + rw [heq] at hs + exact hs + have hceil (i : ℕ) (hi : i < m) : + firstRank s K (A i).defaultValue (inputRow s n (fun _ => K) ρ Δ' a' i) ≤ R ∧ + stepThreshold s n (fun _ => K) ρ Δ' a' i ≤ R := by + let D := c * (budget ε i + (ε i + ε (i + 1))) + have hD0 : 0 ≤ D := mul_nonneg hc0 (add_nonneg + (budget_nonneg fun k hk => hε k (hk.trans hi.le)) + (add_nonneg (hε i hi.le) (hε (i + 1) hi))) + have hD : D ≤ 1 / 8 := + (mul_le_mul_of_nonneg_left (input_budget_le hε hi) hc0).trans hsmall' + have hs := hstates i hi.le + have hzD : |(A i).defaultValue - (B i).defaultValue| ≤ D := + hs.1.trans (mul_le_mul_of_nonneg_left (le_add_of_nonneg_right + (add_nonneg (hε i hi.le) (hε (i + 1) hi))) hc0) + have hwD (y : ι) (hy : y ∈ s) (ν : Fin 2) : + |inputRow s n (fun _ => K) ρ Δ' a' i y ν - (B i).row y ν| ≤ D := by + have hd := hΔ' i hi y hy ν + simp only [Pi.zero_apply, sub_zero] at hd + change |(A i).row y ν + Δ' i y ν - (B i).row y ν| ≤ _ + calc + _ = |((A i).row y ν - (B i).row y ν) + Δ' i y ν| := by congr 1; ring + _ ≤ |(A i).row y ν - (B i).row y ν| + |Δ' i y ν| := abs_add_le _ _ + _ ≤ c * budget ε i + c * (ε i + ε (i + 1)) := add_le_add (hs.2 y hy ν) hd + _ = D := by dsimp only [D]; ring + have hqref : firstRank s K (B i).defaultValue (B i).row ≤ 2 * L₀ := + reference_iterate_firstRank_le hη (by linarith) hK hreference.1 hreference.2.1 + hreference.2.2 i (fun k hk => hKn k (hk.trans hi)) (fun k hk => hρ k (hk.trans hi)) + have huref : threshold s (n i) (ρ i) (B i).defaultValue (B i).row ≤ 2 * L₀ := by + have h := reference_stepThreshold_le hη (by linarith) hK hreference.1 hreference.2.1 + hreference.2.2 i (fun k hk => hKn k (hk.trans_lt hi)) + (fun k hk => hρ k (hk.trans_lt hi)) + simpa only [stepThreshold, inputRow, add_zero] using h + have hqdiff : |firstRank s K (A i).defaultValue + (inputRow s n (fun _ => K) ρ Δ' a' i) - + firstRank s K (B i).defaultValue (B i).row| ≤ D := + (abs_max_sub_max_le_max _ _ _ _).trans + (max_le hzD (abs_kthLargest_sub_kthLargest_le hK hD0 (fun y hy => hwD y hy 0))) + have hudiff := abs_threshold_sub_threshold_le (ρ := ρ i) (hK.trans_le (hKn i hi)) + hD0 hzD hwD + constructor + · have h := (le_abs_self _).trans hqdiff + change firstRank s K (A i).defaultValue (inputRow s n (fun _ => K) ρ Δ' a' i) - + firstRank s K (B i).defaultValue (B i).row ≤ D at h + dsimp only [R] + linarith + · have h := (le_abs_self _).trans hudiff + change threshold s (n i) (ρ i) (A i).defaultValue + (inputRow s n (fun _ => K) ρ Δ' a' i) - + threshold s (n i) (ρ i) (B i).defaultValue (B i).row ≤ D at h + change threshold s (n i) (ρ i) (A i).defaultValue + (inputRow s n (fun _ => K) ρ Δ' a' i) ≤ R + dsimp only [R] + linarith + have hvar (y : ι) (hy : y ∈ marked) : + 3 * R + ∑ i ∈ range m, |Δ i y 0| < a.row y 0 := by + have hys := hmarked hy + have hd := (mem_filter.mp hy).2 + have hraw₀ := (hraw 0 (Nat.zero_le m) y hys).1 + simp only [uncompressedRow_zero] at hraw₀ + have hlo := (abs_le.mp hraw₀).1 + have hlosslo := (abs_le.mp (hloss y hys 0)).1 + have hs : ∑ i ∈ range m, |Δ i y 0| ≤ + (1 + truth y 0) * ∑ i ∈ range m, (ε i + ε (i + 1)) := by + rw [mul_sum] + exact sum_le_sum fun i hi => (hincr i (mem_range.mp hi) y hys).1 + have he : (1 + truth y 0) * (ε 0 + ∑ i ∈ range m, (ε i + ε (i + 1))) ≤ + (1 + truth y 0) / 8 := by + have h := mul_le_mul_of_nonneg_left ((sum_errors_le_budget hε).trans hE) + (by linarith [hfirst y hys] : 0 ≤ 1 + truth y 0) + linarith + change 3 * R + ∑ i ∈ range m, |Δ i y 0| < raw₀ y 0 + loss y 0 + dsimp only [L] at hd + dsimp only [R] + nlinarith + exact iterate_sentinelState_of_sum_abs_lt m hmarked hK hKn hR hL hvar + (fun i hi => (hceil i hi).1) (fun i hi => (hceil i hi).2) + +end Cslib.RowCompression diff --git a/ComplexityTests/RowCompressionSentinelRelative.lean b/ComplexityTests/RowCompressionSentinelRelative.lean new file mode 100644 index 0000000000..9f32172018 --- /dev/null +++ b/ComplexityTests/RowCompressionSentinelRelative.lean @@ -0,0 +1,203 @@ +/- +Copyright (c) 2026 Samuel Schlesinger. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Samuel Schlesinger +-/ + +import Complexity.Foundations.Analysis.RowCompression.SentinelRelative +import Complexity.Foundations.Analysis.RowCompression.FalseOverflow +import Mathlib.LinearAlgebra.Matrix.Notation +import Mathlib.Tactic.FinCases +import Mathlib.Tactic.IntervalCases +import Mathlib.Tactic.NormNum + +/-! +# Clipped-prefix budgets for an actual sentinel comparison + +The true first row is `(1000, 0)`, with one entry above the fixed threshold `1`. A local +two-group calculation starts from the already-added input of its first group. Its first +increment is zero; its second increment changes a large first entry and signed second entries. +The first actual threshold is `10⁻⁷`, strictly above the floor `10⁻⁹`. Compression raises the +default and erases the low entry's negative second channel. Every raw prefix nevertheless has +clipped error at most `10⁻⁶`. + +The theorem derives coupling to the common sentinel `32`, including exact defaults and padded +ranks and the original marked channels' nonconstant raw evolution. A zero-initial global run +has the same two-group result, while its preceding raw prefix has large error. This checks why +the local comparison starts after adding the first overflow group's input. +-/ + +namespace ComplexityTests.RowCompressionSentinelRelative + +open Finset Cslib.RowCompression +open scoped BigOperators + +private noncomputable def truth : Fin 2 → Fin 2 → ℝ := ![![1000, 0], ![0, 0]] + +private noncomputable def raw₀ : Fin 2 → Fin 2 → ℝ := + ![![1000, -1 / 4000000], ![1 / 10000000, -1 / 20000000]] + +private noncomputable def later : Fin 2 → Fin 2 → ℝ := + ![![1 / 10000, 1 / 8000000], ![-1 / 20000000, 1 / 40000000]] + +private noncomputable def increments (i : ℕ) : Fin 2 → Fin 2 → ℝ := + if i = 1 then later else 0 + +private noncomputable def initial : State (Fin 2) := ⟨0, raw₀⟩ + +private noncomputable def original : ℕ → State (Fin 2) := + iterate univ (fun _ => 2) (fun _ => 2) (fun _ => 1 / 1000000000) increments initial + +private noncomputable def modified : ℕ → State (Fin 2) := + iterate univ (fun _ => 2) (fun _ => 2) (fun _ => 1 / 1000000000) + (fun i => sentinelFirst {0} 0 (increments i)) (sentinelState {0} 32 initial) + +private theorem heavy_set : ({y | (1 : ℝ) < truth y 0} : Finset (Fin 2)) = {0} := by + ext y + fin_cases y <;> norm_num [truth] + +private theorem marked_set : ({y | (32 : ℝ) < truth y 0} : Finset (Fin 2)) = {0} := by + ext y + fin_cases y <;> norm_num [truth] + +private theorem prefix_error (i : ℕ) (hi : i ≤ 2) (y : Fin 2) : + clippedError (truth y 0) (truth y 1) (uncompressedRow increments raw₀ i y) ≤ + 1 / 1000000 := by + interval_cases i <;> fin_cases y <;> + norm_num [clippedError, uncompressedRow, increments, raw₀, later, truth, sum_range_succ] + +-- This is the exact finite weighted budget used by the theorem, including the initial error. +example : (1 + 16 * ((1 : ℝ) + 1)) * + (28 ^ 2 * (1 / 1000000) + ∑ i ∈ range 2, + 28 ^ (2 - i) * (1 / 1000000 + 1 / 1000000)) = 9933 / 125000 := by + norm_num [sum_range_succ] + +private theorem coupling (j : ℕ) (hj : j ≤ 2) : + modified j = sentinelState {0} 32 (original j) ∧ + (∀ y ∈ ({0} : Finset (Fin 2)), (original j).row y = + uncompressedRow increments initial.row j y) ∧ + (0 < j → firstRank univ 2 (original j).defaultValue (original j).row = + firstRank univ 2 (modified j).defaultValue (modified j).row ∧ + firstRank univ 2 (modified j).defaultValue (modified j).row ≤ 3) := by + have h := iterate_sentinelState_of_clippedError_le (s := (univ : Finset (Fin 2))) + (n := fun _ => 2) (K := 2) (ρ := fun _ => 1 / 1000000000) + (η := 1) (L₀ := 1) (z := 0) (truth := truth) (raw₀ := raw₀) + (loss := 0) (Δ := increments) (ε := fun _ => 1 / 1000000) 2 + (by norm_num) le_rfl (by norm_num) (by norm_num) + (by intros; exact le_rfl) (by intros; norm_num) + (by intro y _; fin_cases y <;> norm_num [truth]) + (by intro y _; fin_cases y <;> norm_num [truth]) + (by intros; norm_num) + (by rw [heavy_set]; norm_num) + (by intros; norm_num) (by intro i hi y _; exact prefix_error i hi y) + (by norm_num [sum_range_succ]) j hj + norm_num only [show (16 : ℝ) * (1 + 1) = 32 by norm_num, + show (2 : ℝ) * 1 + 1 = 3 by norm_num, marked_set, add_zero] at h + exact h + +private theorem rank_two (v : Fin 2 → ℝ) + (h0 : v 0 = 1000) (h1 : v 1 = 1 / 10000000) : + kthLargest 2 univ v = 1 / 10000000 := by + apply le_antisymm + · refine not_lt.mp fun hlt => ?_ + have hc := (lt_kthLargest_iff (by norm_num) + (by norm_num : (0 : ℝ) ≤ 1 / 10000000)).mp hlt + have hs : ({y | (1 / 10000000 : ℝ) < v y} : Finset (Fin 2)) = {0} := by + ext y + fin_cases y <;> norm_num [h0, h1] + rw [hs] at hc + norm_num at hc + · apply (le_kthLargest_iff (by norm_num) (by norm_num : (0 : ℝ) < 1 / 10000000)).mpr + have hs : ({y | (1 / 10000000 : ℝ) ≤ v y} : Finset (Fin 2)) = univ := by + ext y + fin_cases y <;> norm_num [h0, h1] + rw [hs] + norm_num + +private theorem first_threshold : + threshold univ 2 (1 / 1000000000) 0 raw₀ = 1 / 10000000 := by + unfold threshold + rw [rank_two (fun y => entrySize (raw₀ y)) (by norm_num [raw₀, entrySize]) + (by norm_num [raw₀, entrySize])] + norm_num + +private theorem first_default : + newDefault univ 2 2 (1 / 1000000000) 0 raw₀ = 1 / 10000000 := by + unfold newDefault + rw [first_threshold, rank_two (fun y => raw₀ y 0) (by norm_num [raw₀]) + (by norm_num [raw₀])] + norm_num + +private theorem first_state : original 1 = + ⟨1 / 10000000, ![![1000, -1 / 4000000], ![1 / 10000000, 0]]⟩ := by + change advance univ 2 2 (1 / 1000000000) (increments 0) initial = _ + simp only [advance, initial, increments, show (0 : ℕ) ≠ 1 by decide, ↓reduceIte, add_zero] + rw [first_default] + congr 1 + unfold update + rw [first_threshold, first_default] + funext y ν + fin_cases y <;> fin_cases ν <;> + norm_num [updateEntry, radius, entrySize, defaultEntry, raw₀] + +-- There is a genuine first overflow, nonzero default, and erased negative second channel. +example : IsFirstOverflow univ (fun _ => 2) (fun _ => 2) (fun _ => 1 / 1000000000) + increments initial 0 ∧ + (original 1).defaultValue = 1 / 10000000 ∧ + uncompressedRow increments initial.row 1 1 1 = -1 / 20000000 ∧ + (original 1).row 1 1 = 0 := by + refine ⟨⟨by simp, ?_⟩, ?_⟩ + · simpa only [stepThreshold, inputRow, iterate_zero, initial, increments, + show (0 : ℕ) ≠ 1 by decide, ↓reduceIte, add_zero, first_threshold] using + (show (1 / 1000000000 : ℝ) < 1 / 10000000 by norm_num) + · rw [first_state] + norm_num [uncompressedRow, initial, increments, raw₀] + +-- Original marked first and signed second channels evolve; only the modified first is fixed. +example : (original 2).row 0 0 = 10000001 / 10000 ∧ + (original 2).row 0 1 = -1 / 8000000 ∧ + (modified 2).row 0 0 = 32 ∧ (modified 2).row 0 1 = -1 / 8000000 ∧ + (modified 2).defaultValue = (original 2).defaultValue ∧ + firstRank univ 2 (original 2).defaultValue (original 2).row = + firstRank univ 2 (modified 2).defaultValue (modified 2).row := by + obtain ⟨heq, hraw, hq⟩ := coupling 2 le_rfl + have hraw0 := hraw 0 (by simp) + rw [heq] + simp only [sentinelState, sentinelFirst_zero_of_mem (by simp : (0 : Fin 2) ∈ ({0} : Finset _)), + sentinelFirst_one, hraw0] + norm_num [uncompressedRow, initial, increments, raw₀, later, sum_range_succ] + simpa only [heq, sentinelState] using (hq (by norm_num)).1 + +private noncomputable def globalIncrements (i : ℕ) : Fin 2 → Fin 2 → ℝ := + if i = 0 then raw₀ else increments i + +private noncomputable def globalRun : ℕ → State (Fin 2) := + iterate univ (fun _ => 2) (fun _ => 2) (fun _ => 1 / 1000000000) + globalIncrements ⟨0, 0⟩ + +-- Start the comparison after adding the overflow input: the local first increment is zero. +example : globalRun 2 = original 2 ∧ increments 0 = 0 ∧ + uncompressedRow globalIncrements 0 1 = raw₀ ∧ + 1 / 1000000 < clippedError (truth 0 0) (truth 0 1) + (uncompressedRow globalIncrements 0 0 0) := by + have hfirst : globalRun 1 = original 1 := by + simp only [globalRun, original, iterate_succ, iterate_zero, advance, initial, + globalIncrements, increments, show (0 : ℕ) ≠ 1 by decide, ↓reduceIte, zero_add, add_zero] + refine ⟨?_, ?_, ?_, ?_⟩ + · change advance univ 2 2 (1 / 1000000000) (globalIncrements 1) (globalRun 1) = + advance univ 2 2 (1 / 1000000000) (increments 1) (original 1) + rw [hfirst] + rfl + · simp [increments] + · funext y ν + simp [uncompressedRow, globalIncrements] + · norm_num [uncompressedRow, clippedError, truth] + +-- The small-heavy-set branch is a real restriction, and unclipping needs a strict bound below one. +example : ¬ #{y : Fin 2 | (1 : ℝ) < (![1000, 1000] : Fin 2 → ℝ) y} < 2 := by + norm_num [Fin.univ_succ, filter_insert, filter_singleton] + +example : clippedError 0 0 ![2, 0] = 1 ∧ ¬ |(2 : ℝ) - 0| ≤ (1 + 0) * 1 := by + norm_num [clippedError] + +end ComplexityTests.RowCompressionSentinelRelative From 40b330e3436224e4ccb51b05725c0608f668ff73 Mon Sep 17 00:00:00 2001 From: Samuel Schlesinger Date: Fri, 30 Oct 2026 20:01:00 +0000 Subject: [PATCH 19/19] feat(Probability): bound concrete polynomial rows without overflow Prove the actual-to-truth fourth-root error bound for no-overflow dyadic compression runs of all three concrete polynomial row families. The bound separates weighted prefix preloss from final clipped raw error; the final coefficient is fixed before the compression scale. The theorem includes the empty schedule and does not assume a capacity lower bound. Use a reusable common-loss comparison with arbitrary common default and upper-capped order statistics. Move existing scalar saturation and small clipped-error decoding lemmas into shared topic modules, preserving their statements and proofs and promoting the common gate-scale bound. Regression examples cover strictly positive static and empty-schedule errors, negative common default and large signed second-channel loss, nonempty capacity below rank with error one, and positive actual preloss with zero final raw error. Existing sentinel-relative, relative and first-overflow clients remain valid. Focused validation on the exact source blobs: twelve library/test modules compiled with warningAsError and project linter options; explicit-file proof hygiene with --check-simp and git diff --check passed. The three moved statements/proofs match the parent byte-for-byte. The coordinator owns aggregate generation, full hosted project gates, and publication. Mathematical source: OpenAI2026LogSpace, Section 8.3, the no-overflow comparison following Lemma 8.2, pinned revision 7ef5c0cc. This completes the deterministic concrete-family no-overflow comparison, not normalized atoms, integrated probabilities, or the recursive estimator. AI assistance: implemented and checked with ChatGPT. Independent exact revision review is required before integration. Independent non-author agent polynomial_false_review approved exact source 0427ad65ce71c51c1c0c194da1f3b7edea110f19 with no findings, including the three unchanged statement/proof extractions and intended gate-lemma visibility promotion. Integration preserves the reviewed source/test bytes. Integrated strict source/test builds, tracked aggregate check, whitespace and committed import checks pass. Full integration gates run in PR CI. --- Complexity.lean | 5 + .../Analysis/RowCompression/ClippedError.lean | 41 ++++ .../RowCompression/SentinelRelative.lean | 15 +- .../Data/Finset/KthLargest/Truncation.lean | 55 +++++ .../PolynomialAtomRows/ClippedError.lean | 134 ++++++++++++ .../PolynomialAtomRows/NoOverflow.lean | 109 ++++++++++ .../PolynomialAtomRows/Relative.lean | 21 +- .../PolynomialAtomRows/Saturation.lean | 53 +++++ ComplexityTests/PolynomialAtomNoOverflow.lean | 202 ++++++++++++++++++ ComplexityTests/PolynomialAtomRows.lean | 143 +++++++++++++ 10 files changed, 744 insertions(+), 34 deletions(-) create mode 100644 Complexity/Foundations/Analysis/RowCompression/ClippedError.lean create mode 100644 Complexity/Foundations/Data/Finset/KthLargest/Truncation.lean create mode 100644 Complexity/Foundations/Probability/PolynomialAtomRows/ClippedError.lean create mode 100644 Complexity/Foundations/Probability/PolynomialAtomRows/NoOverflow.lean create mode 100644 Complexity/Foundations/Probability/PolynomialAtomRows/Saturation.lean create mode 100644 ComplexityTests/PolynomialAtomNoOverflow.lean diff --git a/Complexity.lean b/Complexity.lean index d6c169806d..780587becb 100644 --- a/Complexity.lean +++ b/Complexity.lean @@ -2354,6 +2354,7 @@ public import Complexity.Foundations.Analysis.LpNormMeasure public import Complexity.Foundations.Analysis.MarkovBrothersInequality public import Complexity.Foundations.Analysis.RootError public import Complexity.Foundations.Analysis.RowCompression +public import Complexity.Foundations.Analysis.RowCompression.ClippedError public import Complexity.Foundations.Analysis.RowCompression.FalseOverflow public import Complexity.Foundations.Analysis.RowCompression.Floors public import Complexity.Foundations.Analysis.RowCompression.GateClosure @@ -2584,6 +2585,7 @@ public import Complexity.Foundations.Data.Finset.Average public import Complexity.Foundations.Data.Finset.Expect public import Complexity.Foundations.Data.Finset.Finpartition public import Complexity.Foundations.Data.Finset.KthLargest +public import Complexity.Foundations.Data.Finset.KthLargest.Truncation public import Complexity.Foundations.Data.Finset.Markov public import Complexity.Foundations.Data.Finset.OrderGlue public import Complexity.Foundations.Data.Finset.OrderedFilter @@ -2754,9 +2756,12 @@ public import Complexity.Foundations.Probability.HierarchyParams public import Complexity.Foundations.Probability.PolynomialAtomCutoffs public import Complexity.Foundations.Probability.PolynomialAtomFalseOverflow public import Complexity.Foundations.Probability.PolynomialAtomRows +public import Complexity.Foundations.Probability.PolynomialAtomRows.ClippedError public import Complexity.Foundations.Probability.PolynomialAtomRows.FirstOverflow +public import Complexity.Foundations.Probability.PolynomialAtomRows.NoOverflow public import Complexity.Foundations.Probability.PolynomialAtomRows.Relative public import Complexity.Foundations.Probability.PolynomialAtomRows.RootError +public import Complexity.Foundations.Probability.PolynomialAtomRows.Saturation public import Complexity.Foundations.Probability.RootMetric public import Complexity.Foundations.Probability.SecondMoment public import Complexity.Foundations.Probability.StochasticAtom diff --git a/Complexity/Foundations/Analysis/RowCompression/ClippedError.lean b/Complexity/Foundations/Analysis/RowCompression/ClippedError.lean new file mode 100644 index 0000000000..fce89c9059 --- /dev/null +++ b/Complexity/Foundations/Analysis/RowCompression/ClippedError.lean @@ -0,0 +1,41 @@ +/- +Copyright (c) 2026 Samuel Schlesinger. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Samuel Schlesinger +-/ + +module +-- upstream: candidate + +public import Complexity.Foundations.Analysis.RowCompression.Preloss +import Mathlib.Tactic.Linarith + +/-! +# Recovering coordinate bounds from small clipped errors + +Below one, the maximum of the clipped relative first-channel error and clipped absolute +second-channel error bounds both original errors. This shared fact is used by the static +polynomial comparison and by the adjacent-prefix sentinel estimates. + +## Main results + +* `Cslib.RowCompression.abs_sub_le_of_clippedError_le`: small clipped error gives the actual + relative first-coordinate and absolute second-coordinate bounds. +-/ + +public section + +namespace Cslib.RowCompression + +/-- Below one, clipping discards no information. The first target may be arbitrarily large. -/ +theorem abs_sub_le_of_clippedError_le {d v ε : ℝ} {w : Fin 2 → ℝ} + (hd : 0 ≤ d) (hε : ε < 1) (he : clippedError d v w ≤ ε) : + |w 0 - d| ≤ (1 + d) * ε ∧ |w 1 - v| ≤ ε := by + have hfirst : |w 0 - d| / (1 + d) ≤ ε := + (min_le_iff.mp ((le_max_left _ _).trans he)).resolve_left (not_le.mpr hε) + have hsecond : |w 1 - v| ≤ ε := + (min_le_iff.mp ((le_max_right _ _).trans he)).resolve_left (not_le.mpr hε) + refine ⟨?_, hsecond⟩ + simpa only [mul_comm] using (div_le_iff₀ (by linarith : 0 < 1 + d)).mp hfirst + +end Cslib.RowCompression diff --git a/Complexity/Foundations/Analysis/RowCompression/SentinelRelative.lean b/Complexity/Foundations/Analysis/RowCompression/SentinelRelative.lean index 1bbb1fdc5b..8e21861a90 100644 --- a/Complexity/Foundations/Analysis/RowCompression/SentinelRelative.lean +++ b/Complexity/Foundations/Analysis/RowCompression/SentinelRelative.lean @@ -8,7 +8,7 @@ module -- upstream: candidate public import Complexity.Foundations.Analysis.RowCompression.Perturbation -public import Complexity.Foundations.Analysis.RowCompression.Preloss +public import Complexity.Foundations.Analysis.RowCompression.ClippedError public import Complexity.Foundations.Analysis.RowCompression.SentinelIteration import Mathlib.Algebra.BigOperators.Ring.Finset import Mathlib.Algebra.Order.BigOperators.Group.Finset @@ -50,8 +50,6 @@ devices, not objects stored by the compression algorithm. ## Main results -* `Cslib.RowCompression.abs_sub_le_of_clippedError_le`: small clipped errors give the actual - relative first-channel and absolute second-channel bounds. * `Cslib.RowCompression.abs_increment_le_of_clippedError_le`: adjacent prefix errors bound the actual two-channel increment. * `Cslib.RowCompression.iterate_sentinelState_stability_of_clippedError_le`: quantitative @@ -72,17 +70,6 @@ namespace Cslib.RowCompression open Finset -/-- Below one, clipping discards no information. The first target may be arbitrarily large. -/ -theorem abs_sub_le_of_clippedError_le {d v ε : ℝ} {w : Fin 2 → ℝ} - (hd : 0 ≤ d) (hε : ε < 1) (he : clippedError d v w ≤ ε) : - |w 0 - d| ≤ (1 + d) * ε ∧ |w 1 - v| ≤ ε := by - have hfirst : |w 0 - d| / (1 + d) ≤ ε := - (min_le_iff.mp ((le_max_left _ _).trans he)).resolve_left (not_le.mpr hε) - have hsecond : |w 1 - v| ≤ ε := - (min_le_iff.mp ((le_max_right _ _).trans he)).resolve_left (not_le.mpr hε) - refine ⟨?_, hsecond⟩ - simpa only [mul_comm] using (div_le_iff₀ (by linarith : 0 < 1 + d)).mp hfirst - /-- Adjacent small clipped-prefix errors control the actual increment in both channels. -/ theorem abs_increment_le_of_clippedError_le {ι : Type*} {Δ : ℕ → ι → Fin 2 → ℝ} {raw₀ : ι → Fin 2 → ℝ} {truth : Fin 2 → ℝ} {ε ε' : ℝ} {i : ℕ} {y : ι} diff --git a/Complexity/Foundations/Data/Finset/KthLargest/Truncation.lean b/Complexity/Foundations/Data/Finset/KthLargest/Truncation.lean new file mode 100644 index 0000000000..7c197e2a3f --- /dev/null +++ b/Complexity/Foundations/Data/Finset/KthLargest/Truncation.lean @@ -0,0 +1,55 @@ +/- +Copyright (c) 2026 Samuel Schlesinger. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Samuel Schlesinger +-/ + +module +-- upstream: candidate + +public import Complexity.Foundations.Data.Finset.KthLargest + +/-! +# Upper truncation of zero-padded order statistics + +Capping every value at a nonnegative threshold caps the positive-order `k`-th largest value +at the same threshold. Nonnegativity of the cap preserves the zero padding. Input values may +be negative, and the retained cardinality may be smaller than the requested rank. + +## Main results + +* `Finset.kthLargest_min`: upper truncation commutes with the padded order statistic. +-/ + +public section + +namespace Finset + +variable {α R : Type*} [LinearOrder R] [Zero R] {s : Finset α} {k : ℕ} {f : α → R} {t : R} + +/-- An upper cap that preserves zero commutes with every positive-order padded rank. -/ +theorem kthLargest_min (hk : 0 < k) (ht : 0 ≤ t) : + kthLargest k s (fun x => min t (f x)) = min t (kthLargest k s f) := by + classical + apply le_antisymm + · refine le_min (kthLargest_le ht fun _ _ => min_le_left _ _) ?_ + refine not_lt.mp fun hlt => ?_ + have hc := (lt_kthLargest_iff hk kthLargest_nonneg).mp hlt + have hs : ({x ∈ s | kthLargest k s f < min t (f x)} : Finset α) ⊆ + {x ∈ s | kthLargest k s f < f x} := by + intro x hx + exact mem_filter.mpr ⟨(mem_filter.mp hx).1, + (mem_filter.mp hx).2.trans_le (min_le_right _ _)⟩ + exact lt_irrefl _ ((lt_kthLargest_iff hk kthLargest_nonneg).mpr + (hc.trans (card_le_card hs))) + · by_cases hzero : min t (kthLargest k s f) ≤ 0 + · exact hzero.trans kthLargest_nonneg + have hpos : 0 < min t (kthLargest k s f) := not_le.mp hzero + apply (le_kthLargest_iff hk hpos).mpr + have hc := (le_kthLargest_iff hk hpos).mp (min_le_right t (kthLargest k s f)) + apply hc.trans (card_le_card ?_) + intro x hx + exact mem_filter.mpr ⟨(mem_filter.mp hx).1, + le_min (min_le_left _ _) (mem_filter.mp hx).2⟩ + +end Finset diff --git a/Complexity/Foundations/Probability/PolynomialAtomRows/ClippedError.lean b/Complexity/Foundations/Probability/PolynomialAtomRows/ClippedError.lean new file mode 100644 index 0000000000..52cecd6122 --- /dev/null +++ b/Complexity/Foundations/Probability/PolynomialAtomRows/ClippedError.lean @@ -0,0 +1,134 @@ +/- +Copyright (c) 2026 Samuel Schlesinger. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Samuel Schlesinger +-/ + +module +-- upstream: candidate + +public import Complexity.Foundations.Probability.PolynomialAtomRows.RootError +public import Complexity.Foundations.Probability.PolynomialAtomRows.Saturation +public import Complexity.Foundations.Analysis.RowCompression.ClippedError +import Complexity.Foundations.Data.Finset.KthLargest.Truncation +import Mathlib.Algebra.Order.Group.MinMax +import Mathlib.Tactic.Linarith +import Mathlib.Tactic.Positivity + +/-! +# Static polynomial row comparison from clipped raw error + +Compare a raw row and the true row after adding the same bounded first-coordinate loss and +using the same arbitrary default. Their actual polynomial fourth-root outputs differ by at +most a fixed coefficient times the clipped raw-error envelope. The coefficient depends only +on the concrete function and support scale, independently of the largest true entry. + +Upper entry saturation and gate closure let us cap entries and padded ranks at `θ` without +changing any output. For error at most `1/2`, entries with true first coordinate above +`4 * (θ + 1)` cap to the same value; every other capped discrepancy is at most +`(4 * θ + 5) * ε`. Capping commutes with the zero-padded order statistic, so the same bound +controls the capped rank. Larger errors are handled by the proved output range. + +This is the static final-prefix comparison used in the no-overflow bound following Lemma 8.2 +of [OpenAI2026LogSpace, Section 8.3]. No threshold bound, count branch, compression schedule, or +assumed final-output estimate occurs in this module. + +## Main results + +* `Cslib.PolynomialAtomRow.eval_eq_upperCapped`: actual output is invariant under upper caps + on its entry and rank arguments. +* `Cslib.PolynomialAtomRow.exists_commonLoss_root_bound`: actual clipped raw error controls + output-root error after a common bounded first-coordinate loss and arbitrary common default. + +## References + +* [OpenAI, *Exact Derandomization of Logarithmic Space: L = RL = BPL*][OpenAI2026LogSpace], + Section 8.3, the no-overflow comparison following Lemma 8.2 + (23 September 2026, revision `7ef5c0cc`, not peer reviewed). +-/ + +public section + +namespace Cslib.PolynomialAtomRow + +open Finset RowCompression + +variable (kind : PolynomialAtomRow) {θ : ℝ} + +/-- Capping either scalar argument at the support scale leaves the actual output unchanged. -/ +theorem eval_eq_upperCapped (hθ : 0 < θ) (v r : ℝ) : + kind.eval θ v r = kind.eval θ (min θ v) (min θ r) := by + have hentry : kind.eval θ v r = kind.eval θ (min θ v) r := by + by_cases hv : v ≤ θ + · rw [min_eq_right hv] + · rw [min_eq_left (not_le.mp hv).le] + exact kind.eval_eq_of_entry_ge hθ (not_le.mp hv).le le_rfl + apply hentry.trans + by_cases hr : r ≤ θ + · rw [min_eq_right hr] + · rw [min_eq_left (not_le.mp hr).le] + exact (kind.eval_eq_zero_of_rank_ge hθ + ((kind.gateThreshold_le_scale hθ).trans (not_le.mp hr).le)).trans + (kind.eval_eq_zero_of_rank_ge hθ (kind.gateThreshold_le_scale hθ)).symm + +private theorem abs_min_add_sub_min_add_le {d raw loss ε : ℝ} (hθ : 0 < θ) + (hε : 0 ≤ ε) (hεsmall : ε ≤ 1 / 2) + (hraw : |raw - d| ≤ (1 + d) * ε) (hloss : |loss| ≤ θ) : + |min θ (raw + loss) - min θ (d + loss)| ≤ (4 * θ + 5) * ε := by + have hδ : 0 ≤ (4 * θ + 5) * ε := by positivity + by_cases hdlarge : d ≤ 4 * (θ + 1) + · apply (abs_min_sub_min_le_max _ _ _ _).trans + refine max_le (by simpa only [sub_self, abs_zero] using hδ) ?_ + simp only [add_sub_add_right_eq_sub] + exact hraw.trans (mul_le_mul_of_nonneg_right (by linarith) hε) + · have hproduct := mul_le_mul_of_nonneg_left hεsmall (by linarith [not_le.mp hdlarge] : 0 ≤ 1 + d) + have hrawlo := (abs_le.mp hraw).1 + have hlosslo := (abs_le.mp hloss).1 + have hcapraw : θ ≤ raw + loss := by nlinarith [not_le.mp hdlarge] + have hcaptruth : θ ≤ d + loss := by linarith [not_le.mp hdlarge] + simpa only [min_eq_left hcapraw, min_eq_left hcaptruth, sub_self, abs_zero] using hδ + +/-- A clipped raw-error envelope controls the actual polynomial root outputs after a common +loss. Only the first loss coordinate is bounded; second coordinates and the common default +are unrestricted. The final coefficient is independent of all row data and entry magnitudes. -/ +theorem exists_commonLoss_root_bound (hθ : 0 < θ) : + ∃ C : ℝ, 0 ≤ C ∧ ∀ {ι : Type*} (s : Finset ι) (K : ℕ) (z : ℝ) + (truth raw loss : ι → Fin 2 → ℝ), 0 < K → + (∀ y ∈ s, 0 ≤ truth y 0) → (∀ y ∈ s, |loss y 0| ≤ θ) → + ∀ (ε : ℝ), 0 ≤ ε → + (∀ y ∈ s, clippedError (truth y 0) (truth y 1) (raw y) ≤ ε) → + ∀ y ∈ s, + |kind.stateRootError θ s K ⟨z, raw + loss⟩ ⟨z, truth + loss⟩ y| ≤ C * ε := by + obtain ⟨A, hA, hroot⟩ := kind.exists_abs_eval_root_sub_le θ + let B := 4 * θ + 5 + have hB : 0 ≤ B := by dsimp only [B]; positivity + refine ⟨2 + 2 * A * B, by positivity, ?_⟩ + intro ι s K z truth raw loss hK hfirst hloss ε hε herr y hy + by_cases hsmall : ε ≤ 1 / 2 + · have hcap (x : ι) (hx : x ∈ s) : + |min θ ((raw + loss) x 0) - min θ ((truth + loss) x 0)| ≤ B * ε := + abs_min_add_sub_min_add_le hθ hε hsmall + (abs_sub_le_of_clippedError_le (hfirst x hx) (by linarith : ε < 1) (herr x hx)).1 + (hloss x hx) + have hq : |min θ (firstRank s K z (raw + loss)) - + min θ (firstRank s K z (truth + loss))| ≤ B * ε := by + simp only [firstRank, min_max_distrib_left] + rw [← kthLargest_min (f := fun x => (raw + loss) x 0) hK hθ.le, + ← kthLargest_min (f := fun x => (truth + loss) x 0) hK hθ.le] + exact (abs_max_sub_max_le_max _ _ _ _).trans (max_le + (by simpa only [sub_self, abs_zero] using mul_nonneg hB hε) + (abs_kthLargest_sub_kthLargest_le hK (mul_nonneg hB hε) hcap)) + unfold stateRootError + rw [kind.eval_eq_upperCapped hθ ((raw + loss) y 0) (firstRank s K z (raw + loss)), + kind.eval_eq_upperCapped hθ ((truth + loss) y 0) (firstRank s K z (truth + loss))] + calc + _ ≤ A * (|min θ ((raw + loss) y 0) - min θ ((truth + loss) y 0)| + + |min θ (firstRank s K z (raw + loss)) - + min θ (firstRank s K z (truth + loss))|) := hroot _ _ _ _ + _ ≤ A * (B * ε + B * ε) := mul_le_mul_of_nonneg_left (add_le_add (hcap y hy) hq) hA + _ ≤ (2 + 2 * A * B) * ε := by nlinarith + · apply (kind.abs_stateRootError_le_one θ s K ⟨z, raw + loss⟩ ⟨z, truth + loss⟩ y).trans + have hlarge : 1 / 2 < ε := not_le.mp hsmall + nlinarith [mul_nonneg (mul_nonneg hA hB) hε] + +end Cslib.PolynomialAtomRow diff --git a/Complexity/Foundations/Probability/PolynomialAtomRows/NoOverflow.lean b/Complexity/Foundations/Probability/PolynomialAtomRows/NoOverflow.lean new file mode 100644 index 0000000000..175bcc1a9a --- /dev/null +++ b/Complexity/Foundations/Probability/PolynomialAtomRows/NoOverflow.lean @@ -0,0 +1,109 @@ +/- +Copyright (c) 2026 Samuel Schlesinger. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Samuel Schlesinger +-/ + +module +-- upstream: candidate + +public import Complexity.Foundations.Probability.PolynomialAtomRows.ClippedError +import Mathlib.Tactic.Linarith + +/-! +# Actual polynomial row errors when no overflow occurs + +For an actual dyadic compression run with no overflow, the final polynomial fourth-root error +is bounded by the weighted preloss sum plus the final raw-prefix error. The final-error +coefficient depends only on the chosen concrete row function and support scale and is fixed +before the compression scale. The preloss coefficient may also depend on that scale. + +The comparison uses the actual common preloss: the final compressed row is the final raw row +plus this loss, while the stationary reference is the true row plus the same loss and has the +same actual default. The static capped comparison bounds the first discrepancy. The proved +stationary comparison, with no remaining updates, bounds the second by weighted preloss. + +The result includes the empty schedule and imposes no capacity lower bound: there are no +reference continuation updates. All errors concern actual raw prefixes; no final-output bound, +small-error premise, count branch, or bound on the largest true entry is assumed. + +This supplies the deterministic no-overflow comparison in [OpenAI2026LogSpace, Section 8.3] +for the concrete preparation, auxiliary-score, and witness functions with fourth roots. +Integrated probabilities, normalized atoms, and the recursive estimator remain separate. + +## Main results + +* `Cslib.PolynomialAtomRow.exists_noOverflow_root_bound`: the all-horizon actual-to-truth + comparison with separate weighted-preloss and final-prefix terms. + +## References + +* [OpenAI, *Exact Derandomization of Logarithmic Space: L = RL = BPL*][OpenAI2026LogSpace], + Section 8.3, the no-overflow comparison following Lemma 8.2 + (23 September 2026, revision `7ef5c0cc`, not peer reviewed). +-/ + +public section + +namespace Cslib.PolynomialAtomRow + +open Finset RowCompression + +variable (kind : PolynomialAtomRow) {θ : ℝ} + +/-- **No-overflow actual-to-truth comparison.** The final-prefix coefficient is fixed before +choosing `η`. Weighted preloss needs prefix envelopes only at true first targets at least +`η / 2`; the independent final-prefix envelope covers every retained endpoint. The horizon +may be zero, and no capacity lower bound or small-error premise is needed. -/ +theorem exists_noOverflow_root_bound (hθ : 0 < θ) : + ∃ Cfinal : ℝ, 0 ≤ Cfinal ∧ ∀ (η : ℝ), 0 < η → η ≤ θ / 10000 → + ∃ Cpre : ℝ, 0 ≤ Cpre ∧ ∀ {ι : Type*} (s : Finset ι) (n : ℕ → ℕ) + (Δ : ℕ → ι → Fin 2 → ℝ) (a : State ι) (truth : ι → Fin 2 → ℝ) (K : ℕ), + 0 < K → a.defaultValue = 0 → ∀ (m : ℕ), + (∀ i < m, stepThreshold s n (fun _ => K) (dyadicFloor η m) Δ a i ≤ + dyadicFloor η m i) → + (∀ y ∈ s, 0 ≤ truth y 0) → (∀ y ∈ s, |truth y 1| ≤ η / 2) → + ∀ (ε : ℕ → ℝ), (∀ i < m, 0 ≤ ε i) → + (∀ i < m, ∀ y ∈ s, η / 2 ≤ truth y 0 → + clippedError (truth y 0) (truth y 1) (uncompressedRow Δ a.row (i + 1) y) ≤ ε i) → + ∀ (εfinal : ℝ), 0 ≤ εfinal → + (∀ y ∈ s, + clippedError (truth y 0) (truth y 1) (uncompressedRow Δ a.row m y) ≤ εfinal) → + ∀ y ∈ s, + |kind.stateRootError θ s K (iterate s n (fun _ => K) (dyadicFloor η m) Δ a m) + ⟨0, truth⟩ y| ≤ Cpre * ∑ i ∈ range m, dyadicFloor η m i * ε i + Cfinal * εfinal := by + obtain ⟨Cfinal, hCfinal, hfinal⟩ := kind.exists_commonLoss_root_bound hθ + refine ⟨Cfinal, hCfinal, ?_⟩ + intro η hη hmargin + obtain ⟨Cpre, hCpre, hpre⟩ := kind.exists_stationaryContinuation_root_bound hθ hη hmargin + refine ⟨Cpre, hCpre, ?_⟩ + intro ι s n Δ a truth K hK ha m hno hfirst hsecond ε hε herr εfinal hεfinal herrfinal y hy + let actual := iterate s n (fun _ => K) (dyadicFloor η m) Δ a m + let raw := uncompressedRow Δ a.row m + let loss := fun y ν => actual.row y ν - raw y ν + let reference := stationaryState s n (fun _ => K) (dyadicFloor η m) Δ a truth m + have hloss (x : ι) (_hx : x ∈ s) : |loss x 0| ≤ θ := by + have h := abs_stationaryState_row_sub_le_dyadic (truth := truth) hη.le m m (le_refl m) + hno x 0 + rw [stationaryState_row_sub] at h + change |loss x 0| ≤ η / 100 at h + linarith + have hrow : raw + loss = actual.row := by + funext x ν + simp [loss] + have hactual := hfinal s K actual.defaultValue truth raw loss hK hfirst hloss + εfinal hεfinal herrfinal y hy + rw [hrow] at hactual + change |kind.stateRootError θ s K actual reference y| ≤ Cfinal * εfinal at hactual + have hreference := hpre s n Δ a truth K hK (by rw [ha]) (by rw [ha]; linarith) + m m 0 (by omega) hno hfirst hsecond (by intro i hi hi'; omega) ε hε herr y hy + change |kind.stateRootError θ s K reference ⟨0, truth⟩ y| ≤ + Cpre * ∑ i ∈ range m, dyadicFloor η m i * ε i at hreference + calc + _ ≤ |kind.stateRootError θ s K actual reference y| + + |kind.stateRootError θ s K reference ⟨0, truth⟩ y| := abs_sub_le _ _ _ + _ ≤ Cfinal * εfinal + Cpre * ∑ i ∈ range m, dyadicFloor η m i * ε i := + add_le_add hactual hreference + _ = _ := add_comm _ _ + +end Cslib.PolynomialAtomRow diff --git a/Complexity/Foundations/Probability/PolynomialAtomRows/Relative.lean b/Complexity/Foundations/Probability/PolynomialAtomRows/Relative.lean index 29f54fba94..c3ac65f309 100644 --- a/Complexity/Foundations/Probability/PolynomialAtomRows/Relative.lean +++ b/Complexity/Foundations/Probability/PolynomialAtomRows/Relative.lean @@ -8,6 +8,7 @@ module -- upstream: candidate public import Complexity.Foundations.Probability.PolynomialAtomRows.RootError +public import Complexity.Foundations.Probability.PolynomialAtomRows.Saturation public import Complexity.Foundations.Analysis.RowCompression.GateClosure public import Complexity.Foundations.Analysis.RowCompression.SentinelRelative import Mathlib.Algebra.Order.Group.MinMax @@ -31,7 +32,6 @@ ceiling, or scalar regularity assumption is passed to the public comparison theo ## Main results -* `Cslib.PolynomialAtomRow.eval_eq_of_entry_ge`: upper entry saturation for all three functions. * `Cslib.PolynomialAtomRow.exists_iterate_root_bound`: uniform relative fourth-root stability for the actual calculation and its stationary reference, for every error budget. @@ -50,25 +50,6 @@ open Finset RowCompression variable (kind : PolynomialAtomRow) {θ η : ℝ} -/-- All three entry factors have saturated by the common sufficient bound `θ`. -/ -theorem eval_eq_of_entry_ge {v v' r : ℝ} (hθ : 0 < θ) (hv : θ ≤ v) (hv' : θ ≤ v') : - kind.eval θ v r = kind.eval θ v' r := by - cases kind - · simp only [eval, polynomialPrepRow4, - polynomialPrepCutoff4_eq_one hθ (by linarith : 3 * θ / 4 ≤ v), - polynomialPrepCutoff4_eq_one hθ (by linarith : 3 * θ / 4 ≤ v')] - · simp only [eval, polynomialAuxCutoff4, - polynomialSwitch4_of_ge (by linarith : θ / 8 < θ / 4) (by linarith : θ / 4 ≤ v), - polynomialSwitch4_of_ge (by linarith : θ / 8 < θ / 4) (by linarith : θ / 4 ≤ v')] - · simp only [eval, polynomialWitnessCutoff4, - polynomialSwitch4_of_ge (by linarith : 82 * θ / 1000 < 90 * θ / 1000) - (by linarith : 90 * θ / 1000 ≤ v), - polynomialSwitch4_of_ge (by linarith : 82 * θ / 1000 < 90 * θ / 1000) - (by linarith : 90 * θ / 1000 ≤ v')] - -private theorem gateThreshold_le_scale (hθ : 0 < θ) : kind.gateThreshold θ ≤ θ := by - cases kind <;> dsimp only [gateThreshold] <;> linarith - private theorem three_mul_scale_le_of_small_error {d e raw loss : ℝ} (hθ : 0 < θ) (hmargin : η ≤ θ / 10000) (hd : 16 * (θ + 1) < d) (he : e ≤ 1 / 8) (hraw : |raw - d| ≤ (1 + d) * e) (hloss : |loss| ≤ η / 2) : diff --git a/Complexity/Foundations/Probability/PolynomialAtomRows/Saturation.lean b/Complexity/Foundations/Probability/PolynomialAtomRows/Saturation.lean new file mode 100644 index 0000000000..bcad6939d5 --- /dev/null +++ b/Complexity/Foundations/Probability/PolynomialAtomRows/Saturation.lean @@ -0,0 +1,53 @@ +/- +Copyright (c) 2026 Samuel Schlesinger. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Samuel Schlesinger +-/ + +module +-- upstream: candidate + +public import Complexity.Foundations.Probability.PolynomialAtomRows +import Mathlib.Tactic.Linarith + +/-! +# Common saturation and gate bounds for polynomial rows + +Every concrete polynomial entry factor has saturated by its support scale `θ`, and every rank +gate has closed by the same bound. These scalar facts are shared by the static clipped-error +comparison and the iterated sentinel comparison. They do not involve compression schedules. + +## Main results + +* `Cslib.PolynomialAtomRow.eval_eq_of_entry_ge`: any two first entries at least `θ` give the + same output at a fixed rank. +* `Cslib.PolynomialAtomRow.gateThreshold_le_scale`: `θ` bounds every rank-gate close threshold. +-/ + +public section + +namespace Cslib.PolynomialAtomRow + +variable (kind : PolynomialAtomRow) {θ : ℝ} + +/-- All three entry factors have saturated by the common sufficient bound `θ`. -/ +theorem eval_eq_of_entry_ge {v v' r : ℝ} (hθ : 0 < θ) (hv : θ ≤ v) (hv' : θ ≤ v') : + kind.eval θ v r = kind.eval θ v' r := by + cases kind + · simp only [eval, polynomialPrepRow4, + polynomialPrepCutoff4_eq_one hθ (by linarith : 3 * θ / 4 ≤ v), + polynomialPrepCutoff4_eq_one hθ (by linarith : 3 * θ / 4 ≤ v')] + · simp only [eval, polynomialAuxCutoff4, + polynomialSwitch4_of_ge (by linarith : θ / 8 < θ / 4) (by linarith : θ / 4 ≤ v), + polynomialSwitch4_of_ge (by linarith : θ / 8 < θ / 4) (by linarith : θ / 4 ≤ v')] + · simp only [eval, polynomialWitnessCutoff4, + polynomialSwitch4_of_ge (by linarith : 82 * θ / 1000 < 90 * θ / 1000) + (by linarith : 90 * θ / 1000 ≤ v), + polynomialSwitch4_of_ge (by linarith : 82 * θ / 1000 < 90 * θ / 1000) + (by linarith : 90 * θ / 1000 ≤ v')] + +/-- The common support scale is above every concrete rank-gate closure threshold. -/ +theorem gateThreshold_le_scale (hθ : 0 < θ) : kind.gateThreshold θ ≤ θ := by + cases kind <;> dsimp only [gateThreshold] <;> linarith + +end Cslib.PolynomialAtomRow diff --git a/ComplexityTests/PolynomialAtomNoOverflow.lean b/ComplexityTests/PolynomialAtomNoOverflow.lean new file mode 100644 index 0000000000..1db615da86 --- /dev/null +++ b/ComplexityTests/PolynomialAtomNoOverflow.lean @@ -0,0 +1,202 @@ +/- +Copyright (c) 2026 Samuel Schlesinger. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Samuel Schlesinger +-/ + +import Complexity.Foundations.Probability.PolynomialAtomRows.NoOverflow +import Complexity.Foundations.Data.Finset.KthLargest.Truncation +import Mathlib.LinearAlgebra.Matrix.Notation +import Mathlib.Tactic.FinCases +import Mathlib.Tactic.NormNum + +/-! +# Static clipped comparison and no-overflow boundary cases + +A small raw perturbation crosses the preparation support boundary. The static comparison +allows a negative common default and arbitrarily large signed second-coordinate loss. The +empty-schedule theorem retains the same strictly positive output error and has no preloss term. + +A nonempty run uses size capacity one and rank two, so `K ≤ n` is false. Every raw input is +zero and the run has no overflow, yet its true preparation is one. The no-overflow comparison +applies with final envelope one, covering the range fallback and the absent capacity premise. +The separate `PolynomialAtomRows` regression exercises nonzero preloss with final raw error zero. +-/ + +namespace ComplexityTests.PolynomialAtomNoOverflow + +open Finset Cslib Cslib.RowCompression + +private noncomputable def truth : Fin 2 → Fin 2 → ℝ := ![![1 / 2, 0], ![0, 0]] + +private noncomputable def raw : Fin 2 → Fin 2 → ℝ := ![![1 / 2 + 1 / 100000000, 0], ![0, 0]] + +private noncomputable def signedLoss : Fin 2 → Fin 2 → ℝ := ![![0, 1000], ![0, -1000]] + +private theorem second_rank_zero {v : Fin 2 → ℝ} (hv : v 1 = 0) : kthLargest 2 univ v = 0 := by + apply le_antisymm _ kthLargest_nonneg + refine not_lt.mp fun hlt => ?_ + have hc := (lt_kthLargest_iff (by norm_num) (le_refl (0 : ℝ))).mp hlt + have hs : ({y | 0 < v y} : Finset (Fin 2)) ⊆ {0} := by + intro y hy + fin_cases y + · simp + · simp [hv] at hy + have hb := hc.trans (card_le_card hs) + norm_num at hb + +private theorem boundary_error (y : Fin 2) : + clippedError (truth y 0) (truth y 1) (raw y) ≤ 1 / 10000000 := by + fin_cases y <;> norm_num [truth, raw, clippedError] + +private theorem positive_boundary_error (z : ℝ) (hz : z ≤ 0) (loss : Fin 2 → Fin 2 → ℝ) + (hloss : ∀ y, loss y 0 = 0) : + 0 < PolynomialAtomRow.preparation.stateRootError 1 univ 2 + ⟨z, raw + loss⟩ ⟨z, truth + loss⟩ 0 := by + have hq : firstRank univ 2 z (raw + loss) = 0 := by + unfold firstRank + rw [second_rank_zero (by simp [raw, hloss])] + exact max_eq_right hz + have ha : PolynomialAtomRow.preparation.eval 1 ((raw + loss) 0 0) + (firstRank univ 2 z (raw + loss)) = + polynomialSwitch4 (1 / 2) (3 / 4) (1 / 2 + 1 / 100000000) := by + rw [hq] + have hv : (raw + loss) 0 0 = 1 / 2 + 1 / 100000000 := by simp [raw, hloss] + rw [hv] + change polynomialPrepRow4 1 (1 / 2 + 1 / 100000000) 0 = _ + rw [polynomialPrepRow4_of_rank_le (by norm_num) (by norm_num)] + norm_num [polynomialPrepCutoff4] + have hb : PolynomialAtomRow.preparation.eval 1 ((truth + loss) 0 0) + (firstRank univ 2 z (truth + loss)) = 0 := + polynomialPrepRow4_eq_zero_of_entry_le (by norm_num) (by simp [truth, hloss]) + have hp : 0 < polynomialSwitch4 (1 / 2 : ℝ) (3 / 4) (1 / 2 + 1 / 100000000) := by + have hn : polynomialSwitch4 (1 / 2 : ℝ) (3 / 4) (1 / 2 + 1 / 100000000) ≠ 0 := by + rw [ne_eq, polynomialSwitch4_eq_zero_iff (by norm_num)] + norm_num + exact lt_of_le_of_ne (polynomialSwitch4_nonneg _ _ _) (Ne.symm hn) + unfold PolynomialAtomRow.stateRootError + rw [ha, hb, Real.zero_rpow (by norm_num : (4⁻¹ : ℝ) ≠ 0), sub_zero] + exact Real.rpow_pos_of_pos hp _ + +-- A negative common default and large signed second-coordinate losses are admissible, while +-- the actual polynomial root error is strictly positive. +example : signedLoss 0 1 = 1000 ∧ signedLoss 1 1 = -1000 ∧ + ∃ C : ℝ, 0 ≤ C ∧ + 0 < PolynomialAtomRow.preparation.stateRootError 1 univ 2 + ⟨-7, raw + signedLoss⟩ ⟨-7, truth + signedLoss⟩ 0 ∧ + |PolynomialAtomRow.preparation.stateRootError 1 univ 2 + ⟨-7, raw + signedLoss⟩ ⟨-7, truth + signedLoss⟩ 0| ≤ C / 10000000 := by + refine ⟨by norm_num [signedLoss], by norm_num [signedLoss], ?_⟩ + obtain ⟨C, hC, hbound⟩ := PolynomialAtomRow.preparation.exists_commonLoss_root_bound + (θ := 1) (by norm_num) + refine ⟨C, hC, positive_boundary_error (-7) (by norm_num) signedLoss + (fun y => by fin_cases y <;> norm_num [signedLoss]), ?_⟩ + have h := hbound univ 2 (-7) truth raw signedLoss (by norm_num) + (fun y _ => by fin_cases y <;> norm_num [truth]) + (fun y _ => by fin_cases y <;> norm_num [signedLoss]) + (1 / 10000000) (by norm_num) (fun y _ => boundary_error y) 0 (mem_univ 0) + simpa only [div_eq_mul_inv, one_mul] using h + +-- Upper capping also preserves zero padding when the rank exceeds the retained cardinality +-- and an uncapped input is negative. +example : kthLargest 3 univ (fun y : Fin 2 => min (1 : ℝ) ((![-4, 1000] : Fin 2 → ℝ) y)) = 0 := by + rw [kthLargest_min (by norm_num) (by norm_num)] + norm_num [kthLargest, Fin.univ_succ, filter_insert, filter_singleton] + +-- The empty schedule has a positive final-prefix output error and an exactly zero preloss sum. +example : ∃ C : ℝ, 0 ≤ C ∧ + 0 < PolynomialAtomRow.preparation.stateRootError 1 univ 2 ⟨0, raw⟩ ⟨0, truth⟩ 0 ∧ + |PolynomialAtomRow.preparation.stateRootError 1 univ 2 ⟨0, raw⟩ ⟨0, truth⟩ 0| ≤ + C / 10000000 := by + obtain ⟨Cfinal, hCfinal, hscales⟩ := PolynomialAtomRow.preparation.exists_noOverflow_root_bound + (θ := 1) (by norm_num) + obtain ⟨Cpre, _, hbound⟩ := hscales (1 / 20000) (by norm_num) (by norm_num) + refine ⟨Cfinal, hCfinal, ?_, ?_⟩ + · simpa only [add_zero] using positive_boundary_error 0 (le_refl 0) 0 (by intros; rfl) + · have h := hbound univ (fun _ => 0) (fun _ => 0) ⟨0, raw⟩ truth 2 (by norm_num) rfl 0 + (by simp) (fun y _ => by fin_cases y <;> norm_num [truth]) + (fun y _ => by fin_cases y <;> norm_num [truth]) (fun _ => 0) (by simp) (by simp) + (1 / 10000000) (by norm_num) + (fun y _ => by simpa only [uncompressedRow_zero] using boundary_error y) 0 (mem_univ 0) + simpa only [iterate_zero, sum_range_zero, mul_zero, zero_add, div_eq_mul_inv, one_mul] using h + +private noncomputable def smallCapacityTruth : Fin 2 → Fin 2 → ℝ := ![![1, 0], ![0, 0]] + +private noncomputable def smallCapacityActual : State (Fin 2) := + iterate univ (fun _ => 1) (fun _ => 2) (dyadicFloor (1 / 20000) 1) + (fun _ => 0) ⟨0, 0⟩ 1 + +private theorem smallCapacity_threshold : + threshold (univ : Finset (Fin 2)) 1 (dyadicFloor (1 / 20000) 1 0) 0 0 = 1 / 20480000 := by + norm_num [threshold, kthLargest, dyadicFloor, dyadicSlack, entrySize] + +private theorem smallCapacity_default : + newDefault (univ : Finset (Fin 2)) 1 2 (dyadicFloor (1 / 20000) 1 0) 0 0 = + 1 / 20480000 := by + rw [newDefault, smallCapacity_threshold] + norm_num [kthLargest] + +private theorem smallCapacity_state : smallCapacityActual = + ⟨1 / 20480000, fun _ => defaultEntry (1 / 20480000)⟩ := by + change advance univ 1 2 (dyadicFloor (1 / 20000) 1 0) 0 ⟨0, 0⟩ = _ + simp only [advance, add_zero, smallCapacity_default] + congr 1 + funext y + rw [← smallCapacity_default] + apply update_eq_default_of_size_le + rw [smallCapacity_threshold] + norm_num [entrySize] + +private theorem smallCapacity_no_overflow : ∀ i < 1, + stepThreshold (univ : Finset (Fin 2)) (fun _ => 1) (fun _ => 2) (dyadicFloor (1 / 20000) 1) + (fun _ => 0) ⟨0, 0⟩ i ≤ dyadicFloor (1 / 20000) 1 i := by + intro i hi + have hi0 : i = 0 := by omega + subst i + simp only [stepThreshold, inputRow, iterate_zero, add_zero] + rw [smallCapacity_threshold] + norm_num [dyadicFloor, dyadicSlack] + +private theorem smallCapacity_error : + |PolynomialAtomRow.preparation.stateRootError 1 univ 2 smallCapacityActual + ⟨0, smallCapacityTruth⟩ 0| = 1 := by + have ha : PolynomialAtomRow.preparation.eval 1 (smallCapacityActual.row 0 0) + (firstRank univ 2 smallCapacityActual.defaultValue smallCapacityActual.row) = 0 := by + apply polynomialPrepRow4_eq_zero_of_entry_le (by norm_num) + rw [smallCapacity_state] + norm_num [defaultEntry] + have hq : firstRank univ 2 0 smallCapacityTruth = 0 := by + rw [firstRank, second_rank_zero (by norm_num [smallCapacityTruth])] + norm_num + have hb : PolynomialAtomRow.preparation.eval 1 (smallCapacityTruth 0 0) + (firstRank univ 2 0 smallCapacityTruth) = 1 := by + rw [hq] + change polynomialPrepRow4 1 1 0 = 1 + rw [polynomialPrepRow4_of_rank_le (by norm_num) (by norm_num)] + exact polynomialPrepCutoff4_eq_one (by norm_num) (by norm_num) + unfold PolynomialAtomRow.stateRootError + rw [ha, hb, Real.zero_rpow (by norm_num : (4⁻¹ : ℝ) ≠ 0), Real.one_rpow] + norm_num + +-- This positive-error, nonempty no-overflow run has n=1 1) (fun _ => 0) ⟨0, 0⟩ smallCapacityTruth 2 + (by norm_num) rfl 1 smallCapacity_no_overflow + (fun y _ => by fin_cases y <;> norm_num [smallCapacityTruth]) + (fun y _ => by fin_cases y <;> norm_num [smallCapacityTruth]) (fun _ => 1) + (by intros; norm_num) (fun _ _ _ _ _ => clippedError_le_one _ _ _) + 1 (by norm_num) (fun _ _ => clippedError_le_one _ _ _) 0 (mem_univ 0) + change |PolynomialAtomRow.preparation.stateRootError 1 univ 2 smallCapacityActual + ⟨0, smallCapacityTruth⟩ 0| ≤ _ at h + rw [smallCapacity_error] at h + norm_num [dyadicFloor, dyadicSlack] at h + simpa only [div_eq_mul_inv, one_mul] using h + +end ComplexityTests.PolynomialAtomNoOverflow diff --git a/ComplexityTests/PolynomialAtomRows.lean b/ComplexityTests/PolynomialAtomRows.lean index 2b2fe09c9c..82e5a11bd5 100644 --- a/ComplexityTests/PolynomialAtomRows.lean +++ b/ComplexityTests/PolynomialAtomRows.lean @@ -5,9 +5,11 @@ Authors: Samuel Schlesinger -/ import Complexity.Foundations.Probability.PolynomialAtomRows.FirstOverflow +import Complexity.Foundations.Probability.PolynomialAtomRows.NoOverflow import Mathlib.LinearAlgebra.Matrix.Notation import Mathlib.Tactic.FinCases import Mathlib.Tactic.Linarith +import Mathlib.Tactic.IntervalCases import Mathlib.Tactic.NormNum /-! @@ -20,6 +22,8 @@ The remaining group raises the default and erases a second-coordinate value of ` preserves that nonzero witness. Its fourth-root error satisfies the weighted bound. Completing the second actual raw input to truth then gives a real first overflow at group one, zero tail error, and a strictly positive actual-to-truth error paid entirely by weighted preloss. +Increasing the size capacity to three gives a second completion with no overflow at all. Its +final raw error is zero and the same positive witness error is paid entirely by weighted preloss. -/ namespace ComplexityTests.PolynomialAtomRows @@ -359,4 +363,143 @@ example : ∃ C : ℝ, 0 ≤ C ∧ norm_num [sum_range_succ, sum_Ico_eq_sum_range, floor_zero] at h simpa only [div_eq_mul_inv, one_mul, completedRun] using h +private theorem third_rank_zero (v : Fin 2 → ℝ) : kthLargest 3 univ v = 0 := by + apply le_antisymm _ kthLargest_nonneg + refine not_lt.mp fun hlt => ?_ + have hc := (lt_kthLargest_iff (by norm_num) (le_refl (0 : ℝ))).mp hlt + have hb := card_filter_le (s := (univ : Finset (Fin 2))) (p := fun y => 0 < v y) + norm_num at hb + omega + +private noncomputable def spaciousRun : ℕ → State (Fin 2) := + iterate univ (fun _ => 3) (fun _ => 2) (dyadicFloor 1 2) completingIncrements initial + +private theorem spacious_one : spaciousRun 1 = + ⟨1 / 1048576, ![![900, 0], ![1 / 1048576, 0]]⟩ := by + have ht : threshold univ 3 (1 / 1048576) 0 rawRow = 1 / 1048576 := by + rw [threshold, third_rank_zero] + norm_num + have hd : newDefault univ 3 2 (1 / 1048576) 0 rawRow = 1 / 1048576 := by + unfold newDefault + rw [ht] + exact max_eq_left ((min_le_left _ _).trans (max_le (by norm_num) raw_rank_le)) + have hin : initial.row + completingIncrements 0 = rawRow := by + funext y ν + fin_cases y <;> fin_cases ν <;> norm_num [initial, completingIncrements, increments, rawRow] + change advance univ 3 2 (dyadicFloor 1 2 0) (completingIncrements 0) initial = _ + unfold advance + rw [hin, floor_zero] + change State.mk (newDefault univ 3 2 (1 / 1048576) 0 rawRow) + (update univ 3 2 (1 / 1048576) 0 rawRow) = _ + rw [hd] + congr 1 + unfold update + rw [ht, hd] + funext y ν + fin_cases y <;> fin_cases ν <;> norm_num [rawRow, updateEntry, radius, entrySize, defaultEntry] + +private theorem spacious_input_one : + inputRow univ (fun _ => 3) (fun _ => 2) (dyadicFloor 1 2) + completingIncrements initial 1 = reference.row := by + change (spaciousRun 1).row + completingIncrements 1 = reference.row + rw [spacious_one, reference_eq] + funext y ν + fin_cases y <;> fin_cases ν <;> norm_num [completingIncrements, truth, rawRow] + +private theorem spacious_no_overflow : ∀ i < 2, + stepThreshold univ (fun _ => 3) (fun _ => 2) (dyadicFloor 1 2) + completingIncrements initial i ≤ dyadicFloor 1 2 i := by + intro i hi + interval_cases i + · simp only [stepThreshold, iterate_zero, initial, threshold, third_rank_zero] + norm_num [dyadicFloor, dyadicSlack] + · unfold stepThreshold + rw [spacious_input_one] + change threshold univ 3 (dyadicFloor 1 2 1) (spaciousRun 1).defaultValue reference.row ≤ _ + rw [spacious_one] + simp only [threshold, third_rank_zero] + norm_num [dyadicFloor, dyadicSlack] + +private theorem reference_kth : kthLargest 2 univ (fun y => reference.row y 0) = + 260 + 1 / 2097152 := by + have hz : reference.defaultValue < 260 + 1 / 2097152 := by rw [reference_eq]; norm_num + have hle : 260 + 1 / 2097152 ≤ + max reference.defaultValue (kthLargest 2 univ fun y => reference.row y 0) := reference_rank.ge + exact le_antisymm (kthLargest_le_firstRank.trans reference_rank.le) + ((le_max_iff.mp hle).resolve_left (not_le.mpr hz)) + +private theorem spacious_two : spaciousRun 2 = ⟨3 / 1024, reference.row⟩ := by + have ht : threshold univ 3 (1 / 1024) (1 / 1048576) reference.row = 1 / 1024 := by + rw [threshold, third_rank_zero] + norm_num + have hd : newDefault univ 3 2 (1 / 1024) (1 / 1048576) reference.row = 3 / 1024 := by + unfold newDefault + rw [ht, reference_kth] + norm_num + change advance univ 3 2 (dyadicFloor 1 2 1) (completingIncrements 1) (spaciousRun 1) = _ + have hrow : (spaciousRun 1).row + completingIncrements 1 = reference.row := spacious_input_one + unfold advance + rw [hrow, spacious_one, show dyadicFloor (1 : ℝ) 2 1 = 1 / 1024 by + norm_num [dyadicFloor, dyadicSlack], hd] + congr 1 + unfold update + rw [ht, hd, reference_eq] + funext y ν + fin_cases y <;> fin_cases ν <;> norm_num [updateEntry, radius, entrySize, defaultEntry] + +private theorem spacious_output : PolynomialAtomRow.witness.eval 10000 + ((spaciousRun 2).row 0 0) (firstRank univ 2 (spaciousRun 2).defaultValue (spaciousRun 2).row) = + output reference := by + have hq : firstRank univ 2 (3 / 1024) reference.row = 260 + 1 / 2097152 := by + unfold firstRank + rw [reference_kth] + norm_num + rw [spacious_two] + change PolynomialAtomRow.witness.eval 10000 (reference.row 0 0) + (firstRank univ 2 (3 / 1024) reference.row) = output reference + rw [hq] + unfold output + rw [reference_rank] + +-- Two actual compression groups avoid overflow, but the first group's nonzero preloss shifts +-- the final witness rank. The final raw prefix is exactly truth, so the final-error term is zero. +example : (∀ i < 2, stepThreshold univ (fun _ => 3) (fun _ => 2) (dyadicFloor 1 2) + completingIncrements initial i ≤ dyadicFloor 1 2 i) ∧ + uncompressedRow completingIncrements initial.row 2 = truth ∧ + (spaciousRun 1).row 1 0 - rawRow 1 0 = 1 / 2097152 ∧ + 0 < |PolynomialAtomRow.witness.stateRootError 10000 univ 2 (spaciousRun 2) ⟨0, truth⟩ 0| := by + refine ⟨spacious_no_overflow, completing_raw_two, ?_, ?_⟩ + · rw [spacious_one] + norm_num [rawRow] + · unfold PolynomialAtomRow.stateRootError + rw [spacious_output, true_output, Real.one_rpow] + exact abs_pos.mpr (sub_ne_zero.mpr (ne_of_lt (Real.rpow_lt_one + output_between.1.le output_between.2 (by norm_num)))) + +example : ∃ C : ℝ, 0 ≤ C ∧ + |PolynomialAtomRow.witness.stateRootError 10000 univ 2 (spaciousRun 2) ⟨0, truth⟩ 0| ≤ + C / 1048576 := by + obtain ⟨Cfinal, _, hscales⟩ := PolynomialAtomRow.witness.exists_noOverflow_root_bound + (θ := 10000) (by norm_num) + obtain ⟨Cpre, hCpre, hbound⟩ := hscales 1 (by norm_num) (by norm_num) + refine ⟨Cpre, hCpre, ?_⟩ + have h := hbound univ (fun _ => 3) completingIncrements initial truth 2 (by norm_num) rfl + 2 spacious_no_overflow + (fun y _ => by fin_cases y <;> norm_num [truth]) + (fun y _ => by fin_cases y <;> norm_num [truth]) + (fun i => if i = 0 then 1 else 0) (by intro i _; split_ifs <;> norm_num) + (by + intro i hi y _ _ + interval_cases i + · simpa only [↓reduceIte] using clippedError_le_one (truth y 0) (truth y 1) + (uncompressedRow completingIncrements initial.row 1 y) + · change clippedError (truth y 0) (truth y 1) + (uncompressedRow completingIncrements initial.row 2 y) ≤ 0 + rw [completing_raw_two, clippedError_self _ _ _ rfl rfl]) + 0 (le_refl 0) (by + intro y _ + rw [completing_raw_two, clippedError_self _ _ _ rfl rfl]) 0 (mem_univ 0) + norm_num [sum_range_succ, floor_zero] at h + simpa only [div_eq_mul_inv, one_mul, spaciousRun] using h + end ComplexityTests.PolynomialAtomRows