From da700d59ab9cc380f07740dd401e10d94dc182df Mon Sep 17 00:00:00 2001 From: Christian Reitwiessner Date: Thu, 29 Oct 2026 23:17:17 +0000 Subject: [PATCH 01/13] =?UTF-8?q?feat(Expander):=20uniform=20spectral=20ga?= =?UTF-8?q?p=20for=20the=20shear-translation=20graph=20on=20ZMod=20n=20?= =?UTF-8?q?=C3=97=20ZMod=20n=20(#1444)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Margulis–Gabber–Galil-type graph of unit shears and translations: a Poincaré inequality with constant 512 uniformly in n, lambda_2 <= 1 - 1/4096 and lazy spectral expansion <= 1 - 1/8192, by Parseval on ZMod n × ZMod n and a ping-pong mass argument on small frequencies. Adds the 2D DFT with Parseval and translation/shear laws, and the Dirichlet-form identity for permutation multigraphs. Co-Authored-By: Claude Opus 5.5 --- Complexity.lean | 2 + .../Analysis/Fourier/ZModProd.lean | 149 ++++ .../Combinatorics/Expander/Perm.lean | 63 ++ .../Expander/ShearTranslation.lean | 683 ++++++++++++++++++ ComplexityTests/ShearTranslationExpander.lean | 65 ++ references.bib | 40 + 6 files changed, 1002 insertions(+) create mode 100644 Complexity/Foundations/Analysis/Fourier/ZModProd.lean create mode 100644 Complexity/Foundations/Combinatorics/Expander/ShearTranslation.lean create mode 100644 ComplexityTests/ShearTranslationExpander.lean diff --git a/Complexity.lean b/Complexity.lean index f59b96f22..f0509049d 100644 --- a/Complexity.lean +++ b/Complexity.lean @@ -2279,6 +2279,7 @@ public import Complexity.Crypto.Protocols.Signature.RandomOracle public import Complexity.Foundations.Algebra.FiniteMagnitude public import Complexity.Foundations.Algebra.GeometricTail public import Complexity.Foundations.Analysis.BernoulliInequality +public import Complexity.Foundations.Analysis.Fourier.ZModProd public import Complexity.Foundations.Analysis.HarmonicMean public import Complexity.Foundations.Analysis.InnerProductSpace.Basic public import Complexity.Foundations.Analysis.LpNorm @@ -2373,6 +2374,7 @@ public import Complexity.Foundations.Combinatorics.Expander.Random public import Complexity.Foundations.Combinatorics.Expander.Reindex public import Complexity.Foundations.Combinatorics.Expander.Reingold public import Complexity.Foundations.Combinatorics.Expander.Replacement +public import Complexity.Foundations.Combinatorics.Expander.ShearTranslation public import Complexity.Foundations.Combinatorics.Expander.SimpleGraph public import Complexity.Foundations.Combinatorics.Expander.SlotGraph public import Complexity.Foundations.Combinatorics.Expander.Spectrum diff --git a/Complexity/Foundations/Analysis/Fourier/ZModProd.lean b/Complexity/Foundations/Analysis/Fourier/ZModProd.lean new file mode 100644 index 000000000..03ce150f2 --- /dev/null +++ b/Complexity/Foundations/Analysis/Fourier/ZModProd.lean @@ -0,0 +1,149 @@ +/- +Copyright (c) 2026 Christian Reitwiessner. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Christian Reitwiessner +-/ + +module +-- upstream: candidate + +public import Complexity.Init +public import Mathlib.Analysis.SpecialFunctions.Complex.CircleAddChar +import Mathlib.Analysis.Complex.Basic +import Mathlib.NumberTheory.LegendreSymbol.AddCharacter + +/-! +# The discrete Fourier transform on `ZMod N × ZMod N` + +The Fourier transform of `f : ZMod N × ZMod N → ℂ` at the frequency `ξ` is +`∑ v, e (-(ξ.1 * v.1 + ξ.2 * v.2)) * f v`, where `e = ZMod.stdAddChar` sends `j` to +`exp (2 π i j / N)`. This is Mathlib's `ZMod.dft` in each coordinate, written for the two +coordinates together. The characters `v ↦ e (ξ.1 * v.1 + ξ.2 * v.2)` are orthogonal, so the +transform preserves the `ℓ²` norm up to the factor `N ^ 2` (Parseval's identity). + +Translations and shears of the plane act on the transform by simple rules: a translation by `t` +multiplies the transform at `ξ` by `e (ξ.1 * t.1 + ξ.2 * t.2)`, and the shear +`(x, y) ↦ (x + k * y, y)` acts on the frequencies by the transposed inverse shear +`(a, b) ↦ (a, b - k * a)`, and symmetrically for `(x, y) ↦ (x, y + k * x)`. + +## Main definitions + +* `ZMod.dftProd`: the discrete Fourier transform on `ZMod N × ZMod N`. + +## Main results + +* `ZMod.sum_norm_sq_dftProd`: Parseval's identity + `∑ ξ, ‖dftProd f ξ‖ ^ 2 = N ^ 2 * ∑ v, ‖f v‖ ^ 2`. +* `ZMod.dftProd_zero`: the transform at the zero frequency is the sum of the values. +* `ZMod.dftProd_comp_add`: translation multiplies the transform by a character value. +* `ZMod.dftProd_comp_shearFst`, `ZMod.dftProd_comp_shearSnd`: shears permute the frequencies. +-/ + +public section + +namespace ZMod + +open Finset ComplexConjugate + +variable {N : ℕ} [NeZero N] + +/-- The discrete Fourier transform of `f : ZMod N × ZMod N → ℂ` at the frequency `ξ`: +`∑ v, e (-(ξ.1 * v.1 + ξ.2 * v.2)) * f v` with `e = ZMod.stdAddChar`. -/ +noncomputable def dftProd (f : ZMod N × ZMod N → ℂ) (ξ : ZMod N × ZMod N) : ℂ := + ∑ v, stdAddChar (-(ξ.1 * v.1 + ξ.2 * v.2)) * f v + +/-- The transform at the zero frequency is the sum of the values. -/ +@[simp] +theorem dftProd_zero (f : ZMod N × ZMod N → ℂ) : dftProd f 0 = ∑ v, f v := by + simp [dftProd] + +/-- The transform is additive. -/ +theorem dftProd_sub (f g : ZMod N × ZMod N → ℂ) : + dftProd (f - g) = dftProd f - dftProd g := by + ext ξ + simp only [dftProd, Pi.sub_apply, mul_sub, sum_sub_distrib] + +/-- **Orthogonality of the characters of `ZMod N × ZMod N`**: summed over all frequencies, a +nontrivial character value vanishes. -/ +private theorem sum_stdAddChar_mul_add (u : ZMod N × ZMod N) : + ∑ ξ : ZMod N × ZMod N, stdAddChar (ξ.1 * u.1 + ξ.2 * u.2) = + if u = 0 then (N : ℂ) ^ 2 else 0 := by + simp only [AddChar.map_add_eq_mul, Fintype.sum_prod_type, ← mul_sum, ← sum_mul, + AddChar.sum_mulShift _ (isPrimitive_stdAddChar N), ZMod.card] + rcases u with ⟨u₁, u₂⟩ + by_cases h₁ : u₁ = 0 <;> by_cases h₂ : u₂ = 0 <;> simp [h₁, h₂, sq] + +/-- **Parseval's identity** on `ZMod N × ZMod N`. -/ +theorem sum_norm_sq_dftProd (f : ZMod N × ZMod N → ℂ) : + ∑ ξ, ‖dftProd f ξ‖ ^ 2 = N ^ 2 * ∑ v, ‖f v‖ ^ 2 := by + apply Complex.ofReal_injective + push_cast + simp only [← Complex.mul_conj', dftProd, map_sum, map_mul, ← AddChar.map_neg_eq_conj, neg_neg, + sum_mul_sum] + calc ∑ ξ : ZMod N × ZMod N, ∑ v, ∑ w, + stdAddChar (-(ξ.1 * v.1 + ξ.2 * v.2)) * f v * (stdAddChar (ξ.1 * w.1 + ξ.2 * w.2) * + conj (f w)) + = ∑ v, ∑ w, f v * conj (f w) * + ∑ ξ : ZMod N × ZMod N, stdAddChar (ξ.1 * (w - v).1 + ξ.2 * (w - v).2) := by + rw [sum_comm] + refine sum_congr rfl fun v _ ↦ ?_ + rw [sum_comm] + refine sum_congr rfl fun w _ ↦ ?_ + rw [mul_sum] + refine sum_congr rfl fun ξ _ ↦ ?_ + have : stdAddChar (ξ.1 * (w - v).1 + ξ.2 * (w - v).2) = + stdAddChar (-(ξ.1 * v.1 + ξ.2 * v.2)) * stdAddChar (ξ.1 * w.1 + ξ.2 * w.2) := by + rw [← AddChar.map_add_eq_mul] + congr 1 + simp only [Prod.fst_sub, Prod.snd_sub] + ring + rw [this] + ring + _ = (N : ℂ) ^ 2 * ∑ v, f v * conj (f v) := by + simp only [sum_stdAddChar_mul_add, sub_eq_zero, mul_ite, mul_zero, sum_ite_eq', + mem_univ, ite_true, mul_sum] + exact sum_congr rfl fun v _ ↦ by ring + +/-- **Translation** multiplies the transform at `ξ` by `e (ξ.1 * t.1 + ξ.2 * t.2)`. -/ +theorem dftProd_comp_add (f : ZMod N × ZMod N → ℂ) (t ξ : ZMod N × ZMod N) : + dftProd (fun v ↦ f (v + t)) ξ = stdAddChar (ξ.1 * t.1 + ξ.2 * t.2) * dftProd f ξ := by + rw [dftProd, dftProd, mul_sum] + refine Fintype.sum_equiv (Equiv.addRight t) _ _ fun v ↦ ?_ + simp only [Equiv.coe_addRight, Prod.fst_add, Prod.snd_add, ← mul_assoc, + ← AddChar.map_add_eq_mul] + congr 2 + ring + +/-- The shear `(x, y) ↦ (x + k * y, y)` of `ZMod N × ZMod N`, as a permutation. -/ +private def shearFstEquiv (k : ZMod N) : Equiv.Perm (ZMod N × ZMod N) where + toFun v := (v.1 + k * v.2, v.2) + invFun v := (v.1 - k * v.2, v.2) + left_inv v := by simp + right_inv v := by simp + +/-- **The shear `(x, y) ↦ (x + k * y, y)`** acts on frequencies by `(a, b) ↦ (a, b - k * a)`. -/ +theorem dftProd_comp_shearFst (f : ZMod N × ZMod N → ℂ) (k : ZMod N) (ξ : ZMod N × ZMod N) : + dftProd (fun v ↦ f (v.1 + k * v.2, v.2)) ξ = dftProd f (ξ.1, ξ.2 - k * ξ.1) := by + rw [dftProd, dftProd] + refine Fintype.sum_equiv (shearFstEquiv k) _ _ fun v ↦ ?_ + simp only [shearFstEquiv, Equiv.coe_fn_mk] + congr 2 + ring + +/-- The shear `(x, y) ↦ (x, y + k * x)` of `ZMod N × ZMod N`, as a permutation. -/ +private def shearSndEquiv (k : ZMod N) : Equiv.Perm (ZMod N × ZMod N) where + toFun v := (v.1, v.2 + k * v.1) + invFun v := (v.1, v.2 - k * v.1) + left_inv v := by simp + right_inv v := by simp + +/-- **The shear `(x, y) ↦ (x, y + k * x)`** acts on frequencies by `(a, b) ↦ (a - k * b, b)`. -/ +theorem dftProd_comp_shearSnd (f : ZMod N × ZMod N → ℂ) (k : ZMod N) (ξ : ZMod N × ZMod N) : + dftProd (fun v ↦ f (v.1, v.2 + k * v.1)) ξ = dftProd f (ξ.1 - k * ξ.2, ξ.2) := by + rw [dftProd, dftProd] + refine Fintype.sum_equiv (shearSndEquiv k) _ _ fun v ↦ ?_ + simp only [shearSndEquiv, Equiv.coe_fn_mk] + congr 2 + ring + +end ZMod diff --git a/Complexity/Foundations/Combinatorics/Expander/Perm.lean b/Complexity/Foundations/Combinatorics/Expander/Perm.lean index 71d6d7202..9ef0e54fa 100644 --- a/Complexity/Foundations/Combinatorics/Expander/Perm.lean +++ b/Complexity/Foundations/Combinatorics/Expander/Perm.lean @@ -41,6 +41,10 @@ are expanders [Hoory, Linial and Wigderson, Theorem 4.16][HooryLinialWigderson20 permutations move out of it, twice. * `Cslib.RotationMap.le_edgeExpansion_ofPerms`: a lower bound on these counts for every set of at most half of the vertices bounds the edge expansion. +* `Cslib.RotationMap.expect_mul_walk_ofPerms`: the Dirichlet form of the walk is the total squared + change of a function along the permutations. +* `Cslib.RotationMap.secondEigenvalue_ofPerms_le`: a Poincaré inequality for the permutations + bounds the second eigenvalue. ## References @@ -133,4 +137,63 @@ theorem le_edgeExpansion_ofPerms [Nontrivial V] {c : ℝ} push_cast at this ⊢ linarith +omit [DecidableEq V] in +/-- **The Dirichlet form of a permutation multigraph**: the correlation of `f` with its walk is +`𝔼 f²` minus `1 / (2 |K|)` times the total squared change `∑ k, 𝔼 v, (f (σ k v) - f v) ^ 2` of `f` +along the permutations. -/ +theorem expect_mul_walk_ofPerms [Nonempty K] (f : V → ℝ) : + 𝔼 v, f v * (ofPerms σ).walk f v = + (𝔼 v, f v ^ 2) - (∑ k, 𝔼 v, (f (σ k v) - f v) ^ 2) / (2 * Fintype.card K) := by + have hK : (0 : ℝ) < Fintype.card K := Nat.cast_pos.2 Fintype.card_pos + have hwalk (v : V) : (ofPerms σ).walk f v = + (∑ k, (f (σ k v) + f ((σ k).symm v))) / (2 * Fintype.card K) := by + rw [walk_apply, Fintype.expect_eq_sum_div_card, Fintype.sum_prod_type, Fintype.card_prod, + Fintype.card_bool] + simp only [Fintype.sum_bool, neighbor_ofPerms_true, neighbor_ofPerms_false, + add_comm (f ((σ _).symm v))] + push_cast + ring + have hsymm (k : K) : ∑ v, f v * f ((σ k).symm v) = ∑ v, f v * f (σ k v) := by + rw [← Equiv.sum_comp (σ k)] + simp [mul_comm] + have hcross (k : K) : ∑ v, (f (σ k v) - f v) ^ 2 = + 2 * ∑ v, f v ^ 2 - 2 * ∑ v, f v * f (σ k v) := by + simp only [sub_sq, sum_add_distrib, sum_sub_distrib, Equiv.sum_comp (σ k) (fun v ↦ f v ^ 2), + mul_sum] + ring_nf + simp only [← sum_mul, mul_comm (f _) (f _)] + calc 𝔼 v, f v * (ofPerms σ).walk f v + = (∑ v, f v * ∑ k, (f (σ k v) + f ((σ k).symm v))) / (2 * Fintype.card K) / + Fintype.card V := by + simp only [hwalk, Fintype.expect_eq_sum_div_card, ← mul_div_assoc, ← sum_div] + _ = (2 * ∑ k, ∑ v, f v * f (σ k v)) / (2 * Fintype.card K) / Fintype.card V := by + congr 2 + simp only [mul_sum, mul_add, sum_add_distrib] + rw [sum_comm, sum_comm (f := fun v k ↦ f v * f ((σ k).symm v))] + simp only [hsymm, ← two_mul, mul_sum] + _ = _ := by + simp only [Fintype.expect_eq_sum_div_card, ← sum_div, hcross, sum_sub_distrib, sum_const, + card_univ, nsmul_eq_mul, ← mul_sum] + field_simp + ring + +omit [DecidableEq V] in +/-- **A Poincaré inequality bounds the second eigenvalue** of a permutation multigraph on at least +two vertices: if `c 𝔼 f² ≤ ∑ k, 𝔼 v, (f (σ k v) - f v) ^ 2` for every `f` of expectation zero, then +`λ₂ ≤ 1 - c / (2 |K|)`. -/ +theorem secondEigenvalue_ofPerms_le [Nonempty K] [Nontrivial V] {c : ℝ} + (h : ∀ f : V → ℝ, 𝔼 v, f v = 0 → c * (𝔼 v, f v ^ 2) ≤ ∑ k, 𝔼 v, (f (σ k v) - f v) ^ 2) : + (ofPerms σ).secondEigenvalue ≤ 1 - c / (2 * Fintype.card K) := by + refine (ofPerms σ).secondEigenvalue_le_iff.2 fun f hf ↦ ?_ + have hK : (0 : ℝ) < 2 * Fintype.card K := by + have := Fintype.card_pos (α := K) + positivity + calc 𝔼 v, f v * (ofPerms σ).walk f v + = (𝔼 v, f v ^ 2) - (∑ k, 𝔼 v, (f (σ k v) - f v) ^ 2) / (2 * Fintype.card K) := + expect_mul_walk_ofPerms σ f + _ ≤ (𝔼 v, f v ^ 2) - c * (𝔼 v, f v ^ 2) / (2 * Fintype.card K) := by + have := div_le_div_of_nonneg_right (h f hf) hK.le + linarith + _ = (1 - c / (2 * Fintype.card K)) * 𝔼 v, f v ^ 2 := by ring + end Cslib.RotationMap diff --git a/Complexity/Foundations/Combinatorics/Expander/ShearTranslation.lean b/Complexity/Foundations/Combinatorics/Expander/ShearTranslation.lean new file mode 100644 index 000000000..c23b98d39 --- /dev/null +++ b/Complexity/Foundations/Combinatorics/Expander/ShearTranslation.lean @@ -0,0 +1,683 @@ +/- +Copyright (c) 2026 Christian Reitwiessner. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Christian Reitwiessner +-/ + +module +-- upstream: candidate + +public import Complexity.Foundations.Combinatorics.Expander.Lazy +public import Complexity.Foundations.Combinatorics.Expander.Perm +public import Mathlib.Data.ZMod.Basic +import Complexity.Foundations.Analysis.Fourier.ZModProd +import Mathlib.Algebra.Order.Chebyshev +import Mathlib.Analysis.SpecialFunctions.Trigonometric.Bounds +import Mathlib.Data.ZMod.ValMinAbs + +/-! +# The shear-translation expander on `ZMod n × ZMod n` + +The four moves `(x, y) ↦ (x + y, y)`, `(x, y) ↦ (x, y + x)`, `(x, y) ↦ (x + 1, y)` and +`(x, y) ↦ (x, y + 1)` of `ZMod n × ZMod n` and their inverses form an `8`-regular multigraph +(`shearTranslation n`). It is an expander uniformly in `n`: its second eigenvalue is at most +`1 - 1 / 4096`, and its lazy version has spectral expansion at most `1 - 1 / 8192`, for every +`n ≥ 1`. It is a variant of the graphs of Margulis [Margulis][Margulis1973] and of Gabber and +Galil [Gabber and Galil][GabberGalil1981], whose expansion the chapter on the Margulis construction +[Hoory, Linial and Wigderson, Section 8][HooryLinialWigderson2006] proves by Fourier analysis +on `ZMod n × ZMod n`, following Jimbo and Maruoka [Jimbo and Maruoka][JimboMaruoka1987]. Here +the translations are separate moves rather than combined with the shears. + +The proof is elementary Fourier analysis, organised differently from the cited one. Write `F` for +the discrete Fourier transform of a function `f` of sum zero (`ZMod.dftProd`), so `F 0 = 0`. By +Parseval's identity, the squared changes of `f` along the moves are the corresponding quantities +for `F`: a translation multiplies `F ξ` by a root of unity, which is far from `1` unless `ξ` is a +small frequency, and a shear permutes the frequencies by a shear. So if `f` changes little along +the moves, the mass `‖F ξ‖ ^ 2` lies mostly on small frequencies and is almost invariant under the +dual shears. On the small frequencies, whose centered representatives are at most `n / 11` in +absolute value, the dual shears by `±4` act as integer shears, and they play ping-pong: they move +the frequencies `(a, b)` with `|b| < |a|` to two disjoint sets of frequencies with `|a| < |b|`, +and those with `0 < |b|`, `|a| ≤ |b|` to two disjoint sets with `|b| < |a|`. Each class therefore +carries at least twice the mass of the other, up to small errors, so both are nearly empty. This +is a finite, quantitative argument in the spirit of the proof of the relative property (T) of +`SL₂(ℤ) ⋉ ℤ²` [Burger][Burger1991]. + +The explicit constants are far from optimal; the point is that they do not depend on `n`. + +## Main definitions + +* `Cslib.shearFst`, `Cslib.shearSnd`: the shears `(x, y) ↦ (x + k * y, y)` and + `(x, y) ↦ (x, y + k * x)` of `R × R`. +* `Cslib.RotationMap.shearTranslationMove`: the four moves of the graph. +* `Cslib.RotationMap.shearTranslation`: the `8`-regular shear-translation multigraph on + `ZMod n × ZMod n`. + +## Main results + +* `Cslib.RotationMap.sum_norm_sq_le_shearTranslation`: the Poincaré inequality + `∑ v, ‖f v‖ ^ 2 ≤ 512 * ∑ k, ∑ v, ‖f (shearTranslationMove n k v) - f v‖ ^ 2` for every + complex function of sum zero. +* `Cslib.RotationMap.secondEigenvalue_shearTranslation_le`: `λ₂ ≤ 1 - 1 / 4096`. +* `Cslib.RotationMap.spectralExpansion_lazy_shearTranslation_le`: the lazy graph has spectral + expansion at most `1 - 1 / 8192`. + +## References + +* [G. A. Margulis, *Explicit constructions of expanders*][Margulis1973] +* [O. Gabber, Z. Galil, *Explicit constructions of linear-sized + superconcentrators*][GabberGalil1981] +* [S. Jimbo, A. Maruoka, *Expanders obtained from affine transformations*][JimboMaruoka1987] +* [M. Burger, *Kazhdan constants for SL(3, ℤ)*][Burger1991] +* [S. Hoory, N. Linial, A. Wigderson, *Expander graphs and their + applications*][HooryLinialWigderson2006] +-/ + +@[expose] public section + +namespace Cslib + +open Finset + +section Shear + +variable {R : Type*} [CommRing R] + +/-- The shear `(x, y) ↦ (x + k * y, y)` of `R × R`, as a permutation. -/ +def shearFst (k : R) : Equiv.Perm (R × R) where + toFun v := (v.1 + k * v.2, v.2) + invFun v := (v.1 - k * v.2, v.2) + left_inv v := by simp + right_inv v := by simp + +/-- The shear `(x, y) ↦ (x, y + k * x)` of `R × R`, as a permutation. -/ +def shearSnd (k : R) : Equiv.Perm (R × R) where + toFun v := (v.1, v.2 + k * v.1) + invFun v := (v.1, v.2 - k * v.1) + left_inv v := by simp + right_inv v := by simp + +@[simp] +theorem shearFst_apply (k : R) (v : R × R) : shearFst k v = (v.1 + k * v.2, v.2) := + rfl + +@[simp] +theorem shearSnd_apply (k : R) (v : R × R) : shearSnd k v = (v.1, v.2 + k * v.1) := + rfl + +/-- The inverse of a shear is the opposite shear. -/ +theorem shearFst_symm (k : R) : (shearFst k).symm = shearFst (-k) := by + ext v <;> simp [shearFst, sub_eq_add_neg] + +/-- The inverse of a shear is the opposite shear. -/ +theorem shearSnd_symm (k : R) : (shearSnd k).symm = shearSnd (-k) := by + ext v <;> simp [shearSnd, sub_eq_add_neg] + +/-- Iterating a shear multiplies its parameter. -/ +theorem shearFst_pow (k : R) (m : ℕ) : shearFst k ^ m = shearFst (m * k) := by + induction m with + | zero => ext v <;> simp + | succ m ih => + rw [pow_succ', ih] + ext v + · simp only [Equiv.Perm.mul_apply, shearFst_apply] + push_cast + ring + · rfl + +/-- Iterating a shear multiplies its parameter. -/ +theorem shearSnd_pow (k : R) (m : ℕ) : shearSnd k ^ m = shearSnd (m * k) := by + induction m with + | zero => ext v <;> simp + | succ m ih => + rw [pow_succ', ih] + ext v + · rfl + · simp only [Equiv.Perm.mul_apply, shearSnd_apply] + push_cast + ring + +end Shear + +namespace RotationMap + +/-- The four moves of the shear-translation graph on `ZMod n × ZMod n`: the shears +`(x, y) ↦ (x + y, y)` and `(x, y) ↦ (x, y + x)` and the translations by `(1, 0)` and `(0, 1)`. -/ +def shearTranslationMove (n : ℕ) : Fin 4 → Equiv.Perm (ZMod n × ZMod n) := + ![shearFst 1, shearSnd 1, Equiv.addRight (1, 0), Equiv.addRight (0, 1)] + +/-- The **shear-translation graph** on `ZMod n × ZMod n`: the `8`-regular multigraph of the two +unit shears and the two unit translations, a variant of the Margulis–Gabber–Galil graphs +[Hoory, Linial and Wigderson, Section 8][HooryLinialWigderson2006]. -/ +def shearTranslation (n : ℕ) : RotationMap (ZMod n × ZMod n) (Fin 4 × Bool) := + ofPerms (shearTranslationMove n) + +/-! ### Squared changes along permutations -/ + +section Energy + +variable {α : Type*} [Fintype α] + +/-- The squared change of `f` along `σ ^ m` is at most `m ^ 2` times that along `σ`. -/ +private theorem sum_norm_sub_sq_pow_le (f : α → ℂ) (σ : Equiv.Perm α) (m : ℕ) : + ∑ v, ‖f ((σ ^ m) v) - f v‖ ^ 2 ≤ m ^ 2 * ∑ v, ‖f (σ v) - f v‖ ^ 2 := by + have htel (v : α) : f ((σ ^ m) v) - f v = + ∑ j ∈ range m, (f (σ ((σ ^ j) v)) - f ((σ ^ j) v)) := by + have := Finset.sum_range_sub (fun j ↦ f ((σ ^ j) v)) m + simp only [pow_succ', Equiv.Perm.mul_apply, pow_zero, Equiv.Perm.one_apply] at this + exact this.symm + calc ∑ v, ‖f ((σ ^ m) v) - f v‖ ^ 2 + ≤ ∑ v, m * ∑ j ∈ range m, ‖f (σ ((σ ^ j) v)) - f ((σ ^ j) v)‖ ^ 2 := by + refine sum_le_sum fun v _ ↦ ?_ + rw [htel] + calc ‖∑ j ∈ range m, (f (σ ((σ ^ j) v)) - f ((σ ^ j) v))‖ ^ 2 + ≤ (∑ j ∈ range m, ‖f (σ ((σ ^ j) v)) - f ((σ ^ j) v)‖) ^ 2 := by + gcongr + exact norm_sum_le _ _ + _ ≤ _ := by + simpa using sq_sum_le_card_mul_sum_sq (s := range m) + (f := fun j ↦ ‖f (σ ((σ ^ j) v)) - f ((σ ^ j) v)‖) + _ = m * ∑ j ∈ range m, ∑ v, ‖f (σ ((σ ^ j) v)) - f ((σ ^ j) v)‖ ^ 2 := by + rw [← mul_sum, sum_comm] + _ = m * ∑ _j ∈ range m, ∑ v, ‖f (σ v) - f v‖ ^ 2 := by + congr 1 + exact sum_congr rfl fun j _ ↦ + Equiv.sum_comp (σ ^ j) (fun v ↦ ‖f (σ v) - f v‖ ^ 2) + _ = _ := by + rw [sum_const, card_range, nsmul_eq_mul] + ring + +/-- The squared change of `f` along `σ⁻¹` equals that along `σ`. -/ +private theorem sum_norm_sub_sq_symm (f : α → ℂ) (σ : Equiv.Perm α) : + ∑ v, ‖f (σ.symm v) - f v‖ ^ 2 = ∑ v, ‖f (σ v) - f v‖ ^ 2 := by + rw [← Equiv.sum_comp σ] + simp [norm_sub_rev] + +/-- **Mass transfer**: moving a set of points by a permutation `g` changes the mass `‖F z‖ ^ 2` +on it by at most `8` times the squared change of `F` along `g` plus `1 / 8` of the total mass. -/ +private theorem sum_norm_sq_le_sum_comp (F : α → ℂ) (g : Equiv.Perm α) (E : Finset α) : + ∑ z ∈ E, ‖F z‖ ^ 2 ≤ + ∑ z ∈ E, ‖F (g z)‖ ^ 2 + 8 * ∑ z, ‖F (g z) - F z‖ ^ 2 + (∑ z, ‖F z‖ ^ 2) / 8 := by + have hpt (x y : ℂ) : ‖x‖ ^ 2 ≤ ‖y‖ ^ 2 + 8 * ‖y - x‖ ^ 2 + (‖x‖ ^ 2 + ‖y‖ ^ 2) / 16 := by + have h : ‖x‖ - ‖y‖ ≤ ‖y - x‖ := by + rw [norm_sub_rev] + exact norm_sub_norm_le x y + nlinarith [mul_le_mul_of_nonneg_right h (add_nonneg (norm_nonneg x) (norm_nonneg y)), + sq_nonneg (‖x‖ + ‖y‖ - 16 * ‖y - x‖), sq_nonneg (‖x‖ - ‖y‖)] + have hE (u : α → ℝ) (hu : ∀ z, 0 ≤ u z) : ∑ z ∈ E, u z ≤ ∑ z, u z := + sum_le_univ_sum_of_nonneg hu + have hg : ∑ z, ‖F (g z)‖ ^ 2 = ∑ z, ‖F z‖ ^ 2 := Equiv.sum_comp g fun z ↦ ‖F z‖ ^ 2 + calc ∑ z ∈ E, ‖F z‖ ^ 2 + ≤ ∑ z ∈ E, (‖F (g z)‖ ^ 2 + 8 * ‖F (g z) - F z‖ ^ 2 + + (‖F z‖ ^ 2 + ‖F (g z)‖ ^ 2) / 16) := sum_le_sum fun z _ ↦ hpt _ _ + _ = ∑ z ∈ E, ‖F (g z)‖ ^ 2 + 8 * ∑ z ∈ E, ‖F (g z) - F z‖ ^ 2 + + (∑ z ∈ E, ‖F z‖ ^ 2 + ∑ z ∈ E, ‖F (g z)‖ ^ 2) / 16 := by + rw [sum_add_distrib, sum_add_distrib, ← mul_sum, ← sum_div, sum_add_distrib] + _ ≤ _ := by + have h₁ := hE (fun z ↦ ‖F (g z) - F z‖ ^ 2) fun _ ↦ by positivity + have h₂ := hE (fun z ↦ ‖F z‖ ^ 2) fun _ ↦ by positivity + have h₃ := hE (fun z ↦ ‖F (g z)‖ ^ 2) fun _ ↦ by positivity + linarith + +omit [Fintype α] in +/-- **Two disjoint images**: if `g₁` and `g₂` map `E` into `T` with disjoint images, the mass of +`T` is at least the masses of the two images together. -/ +private theorem sum_comp_add_sum_comp_le (F : α → ℂ) (g₁ g₂ : Equiv.Perm α) + (E T : Finset α) (h₁ : ∀ z ∈ E, g₁ z ∈ T) (h₂ : ∀ z ∈ E, g₂ z ∈ T) + (hd : ∀ z ∈ E, ∀ w ∈ E, g₁ z ≠ g₂ w) : + ∑ z ∈ E, ‖F (g₁ z)‖ ^ 2 + ∑ z ∈ E, ‖F (g₂ z)‖ ^ 2 ≤ ∑ z ∈ T, ‖F z‖ ^ 2 := by + classical + have hmap (g : Equiv.Perm α) : ∑ z ∈ E, ‖F (g z)‖ ^ 2 = + ∑ z ∈ E.map g.toEmbedding, ‖F z‖ ^ 2 := by + rw [sum_map] + rfl + rw [hmap, hmap, ← sum_union] + · refine sum_le_sum_of_subset_of_nonneg (fun w hw ↦ ?_) fun _ _ _ ↦ by positivity + rcases mem_union.1 hw with hw | hw <;> obtain ⟨z, hz, rfl⟩ := mem_map.1 hw + exacts [h₁ z hz, h₂ z hz] + · refine disjoint_left.2 fun w hw₁ hw₂ ↦ ?_ + obtain ⟨z, hz, rfl⟩ := mem_map.1 hw₁ + obtain ⟨z', hz', hzz'⟩ := mem_map.1 hw₂ + exact hd z hz z' hz' hzz'.symm + +end Energy + +/-! ### Small frequencies -/ + +section Frequencies + +variable {n : ℕ} [NeZero n] + +/-- On small frequencies, a shear by at most `4` acts on the centered representatives as the +integer shear. -/ +private theorem valMinAbs_add_mul {a b : ZMod n} {k : ℤ} (hk : |k| ≤ 4) + (ha : 11 * |a.valMinAbs| ≤ n) (hb : 11 * |b.valMinAbs| ≤ n) : + (a + k * b).valMinAbs = a.valMinAbs + k * b.valMinAbs := by + rw [ZMod.valMinAbs_spec] + refine ⟨by push_cast [ZMod.coe_valMinAbs]; rfl, ?_⟩ + have hn : (0 : ℤ) < n := by exact_mod_cast Nat.pos_of_ne_zero (NeZero.ne n) + have h₁ : |a.valMinAbs + k * b.valMinAbs| ≤ |a.valMinAbs| + |k| * |b.valMinAbs| := + (abs_add_le _ _).trans_eq (by rw [abs_mul]) + have h₂ : |k| * |b.valMinAbs| ≤ 4 * |b.valMinAbs| := + mul_le_mul_of_nonneg_right hk (abs_nonneg _) + have h₃ := neg_abs_le (a.valMinAbs + k * b.valMinAbs) + have h₄ := le_abs_self (a.valMinAbs + k * b.valMinAbs) + constructor <;> linarith + +/-- The ping-pong inequality: a shear by `±4` moves a frequency `(p, q)` with `|p| ≤ |q|` and +`q ≠ 0` to one whose first coordinate is larger than the second. -/ +private theorem abs_lt_abs_add_mul {p q k : ℤ} (hk : |k| = 4) (hpq : |p| ≤ |q|) (hq : q ≠ 0) : + |q| < |p + k * q| := by + have h : |k * q| ≤ |p + k * q| + |p| := by + have := abs_sub (p + k * q) p + rwa [add_sub_cancel_left] at this + rw [abs_mul, hk] at h + have := abs_pos.2 hq + linarith + +/-- The images of a frequency `(p, q)` with `|p| ≤ |q|` under the shears by `4` and `-4` differ. -/ +private theorem add_four_mul_ne {p p' q : ℤ} (hp : |p| ≤ |q|) (hp' : |p'| ≤ |q|) (hq : q ≠ 0) : + p + 4 * q ≠ p' + -4 * q := by + intro h + have h' : p' - p = 8 * q := by linarith + have h₁ : |p' - p| ≤ |p'| + |p| := abs_sub _ _ + rw [h', abs_mul, show |(8 : ℤ)| = 8 by norm_num] at h₁ + have := abs_pos.2 hq + linarith + +/-- A frequency outside the small box is moved far by one of the unit translations: the +corresponding root of unity is at distance at least `1 / sqrt 8` from `1`. -/ +private theorem one_div_eight_le_norm_stdAddChar_sub_one {a : ZMod n} + (ha : (n : ℤ) < 11 * |a.valMinAbs|) : 1 / 8 ≤ ‖ZMod.stdAddChar a - 1‖ ^ 2 := by + set A := a.valMinAbs with hA + have hn : (0 : ℝ) < n := by exact_mod_cast Nat.pos_of_ne_zero (NeZero.ne n) + have hhalf : 2 * |(A : ℝ)| ≤ n := by + have h := ZMod.natAbs_valMinAbs_le a + have : 2 * A.natAbs ≤ n := by omega + rw [← Int.cast_abs, ← Int.natCast_natAbs] + exact_mod_cast this + have hbig : (n : ℝ) < 11 * |(A : ℝ)| := by + rw [← Int.cast_abs] + exact_mod_cast ha + have hexp : ZMod.stdAddChar a = Complex.exp (Complex.I * ((2 * Real.pi * A / n : ℝ) : ℂ)) := by + conv_lhs => rw [← ZMod.coe_valMinAbs a, ← hA, ZMod.stdAddChar_coe] + congr 1 + push_cast + ring + rw [hexp, Complex.norm_exp_I_mul_ofReal_sub_one, norm_mul, Real.norm_eq_abs, + Real.norm_eq_abs, abs_two] + have hsin : 2 / 11 ≤ |Real.sin (2 * Real.pi * A / n / 2)| := by + have hx : 2 * Real.pi * A / n / 2 = Real.pi * A / n := by ring + have hxabs : |Real.sin (Real.pi * A / n)| = Real.sin (Real.pi * |(A : ℝ)| / n) := by + have hle : Real.pi * |(A : ℝ)| / n ≤ Real.pi := by + rw [div_le_iff₀ hn] + nlinarith [Real.pi_pos, abs_nonneg (A : ℝ)] + have hs := Real.sin_nonneg_of_nonneg_of_le_pi (by positivity) hle + rcases le_or_gt 0 (A : ℝ) with h | h + · rw [abs_of_nonneg h] at hs ⊢ + exact abs_of_nonneg hs + · have e : Real.sin (Real.pi * -(A : ℝ) / n) = -Real.sin (Real.pi * A / n) := by + rw [mul_neg, neg_div, Real.sin_neg] + rw [abs_of_neg h, e] at hs ⊢ + exact abs_of_nonpos (by linarith) + rw [hx, hxabs] + have hle : Real.pi * |(A : ℝ)| / n ≤ Real.pi / 2 := by + rw [div_le_iff₀ hn] + nlinarith [Real.pi_pos] + have := Real.mul_le_sin (by positivity) hle + have heq : 2 / Real.pi * (Real.pi * |(A : ℝ)| / n) = 2 * |(A : ℝ)| / n := by + field_simp + rw [heq] at this + have : 2 / 11 ≤ 2 * |(A : ℝ)| / n := by + rw [le_div_iff₀ hn] + linarith + linarith + nlinarith [abs_nonneg (Real.sin (2 * Real.pi * A / n / 2))] + +end Frequencies + +/-! ### The ping-pong argument on the frequencies -/ + +section PingPong + +variable {n : ℕ} [NeZero n] + +/-- The frequencies whose centered representatives are both at most `n / 11` in absolute value. -/ +private def IsSmall (ξ : ZMod n × ZMod n) : Prop := + 11 * |ξ.1.valMinAbs| ≤ n ∧ 11 * |ξ.2.valMinAbs| ≤ n + +private instance : DecidablePred (IsSmall (n := n)) := fun _ ↦ instDecidableAnd + +/-- **The ping-pong inequality** for a function on the frequencies vanishing at `0`: its mass is +at most `6` times its mass outside the small box plus `16` times its squared changes along the +four dual shears by `±4`. -/ +private theorem sum_norm_sq_le_pingPong (F : ZMod n × ZMod n → ℂ) (h0 : F 0 = 0) : + ∑ ξ, ‖F ξ‖ ^ 2 ≤ 6 * ∑ ξ ∈ univ.filter (fun ξ ↦ ¬ IsSmall ξ), ‖F ξ‖ ^ 2 + + 16 * (∑ ξ, ‖F (shearSnd (4 : ZMod n) ξ) - F ξ‖ ^ 2 + + ∑ ξ, ‖F (shearSnd (-4 : ZMod n) ξ) - F ξ‖ ^ 2 + + ∑ ξ, ‖F (shearFst (4 : ZMod n) ξ) - F ξ‖ ^ 2 + + ∑ ξ, ‖F (shearFst (-4 : ZMod n) ξ) - F ξ‖ ^ 2) := by + obtain ⟨Out, hOut⟩ : ∃ s : Finset (ZMod n × ZMod n), s = univ.filter (¬ IsSmall ·) := + ⟨_, rfl⟩ + obtain ⟨X, hX⟩ : ∃ s : Finset (ZMod n × ZMod n), + s = univ.filter (fun ξ ↦ IsSmall ξ ∧ |ξ.2.valMinAbs| < |ξ.1.valMinAbs|) := ⟨_, rfl⟩ + obtain ⟨Y, hY⟩ : ∃ s : Finset (ZMod n × ZMod n), + s = univ.filter (fun ξ ↦ IsSmall ξ ∧ |ξ.1.valMinAbs| ≤ |ξ.2.valMinAbs| ∧ ξ ≠ 0) := + ⟨_, rfl⟩ + rw [← hOut] + have hite (p : Prop) [Decidable p] (ξ : ZMod n × ZMod n) : + 0 ≤ if p then ‖F ξ‖ ^ 2 else 0 := by + split_ifs <;> positivity + -- The two classes and the large frequencies cover everything but `0`, where `F` vanishes. + have hpart : ∑ ξ, ‖F ξ‖ ^ 2 ≤ + ∑ ξ ∈ Out, ‖F ξ‖ ^ 2 + ∑ ξ ∈ X, ‖F ξ‖ ^ 2 + ∑ ξ ∈ Y, ‖F ξ‖ ^ 2 := by + rw [hOut, hX, hY, sum_filter, sum_filter, sum_filter, ← sum_add_distrib, ← sum_add_distrib] + refine sum_le_sum fun ξ _ ↦ ?_ + by_cases h : ξ = 0 + · subst h + simp [h0] + have h₁ := hite (¬ IsSmall ξ) ξ + have h₂ := hite (IsSmall ξ ∧ |ξ.2.valMinAbs| < |ξ.1.valMinAbs|) ξ + have h₃ := hite (IsSmall ξ ∧ |ξ.1.valMinAbs| ≤ |ξ.2.valMinAbs| ∧ ξ ≠ 0) ξ + by_cases hs : IsSmall ξ + · by_cases hlt : |ξ.2.valMinAbs| < |ξ.1.valMinAbs| + · rw [ite_eq_left (show IsSmall ξ ∧ |ξ.2.valMinAbs| < |ξ.1.valMinAbs| from ⟨hs, hlt⟩)] + linarith + · rw [ite_eq_left (show IsSmall ξ ∧ |ξ.1.valMinAbs| ≤ |ξ.2.valMinAbs| ∧ ξ ≠ 0 from + ⟨hs, not_lt.1 hlt, h⟩)] + linarith + · rw [ite_eq_left hs] + linarith + -- A frequency with a larger second coordinate is small and in `Y`, or large. + have hY' : ∑ ξ ∈ univ.filter (fun ξ : ZMod n × ZMod n ↦ |ξ.1.valMinAbs| < |ξ.2.valMinAbs|), + ‖F ξ‖ ^ 2 ≤ ∑ ξ ∈ Y, ‖F ξ‖ ^ 2 + ∑ ξ ∈ Out, ‖F ξ‖ ^ 2 := by + rw [hOut, hY, sum_filter, sum_filter, sum_filter, ← sum_add_distrib] + refine sum_le_sum fun ξ _ ↦ ?_ + have h₁ := hite (¬ IsSmall ξ) ξ + have h₃ := hite (IsSmall ξ ∧ |ξ.1.valMinAbs| ≤ |ξ.2.valMinAbs| ∧ ξ ≠ 0) ξ + by_cases hlt : |ξ.1.valMinAbs| < |ξ.2.valMinAbs| + · have hne : ξ ≠ 0 := by + rintro rfl + simp at hlt + rw [ite_eq_left hlt] + by_cases hs : IsSmall ξ + · rw [ite_eq_left (show IsSmall ξ ∧ |ξ.1.valMinAbs| ≤ |ξ.2.valMinAbs| ∧ ξ ≠ 0 from + ⟨hs, hlt.le, hne⟩)] + linarith + · rw [ite_eq_left hs] + linarith + · rw [ite_eq_right hlt] + linarith + have hX' : ∑ ξ ∈ univ.filter (fun ξ : ZMod n × ZMod n ↦ |ξ.2.valMinAbs| < |ξ.1.valMinAbs|), + ‖F ξ‖ ^ 2 ≤ ∑ ξ ∈ X, ‖F ξ‖ ^ 2 + ∑ ξ ∈ Out, ‖F ξ‖ ^ 2 := by + rw [hOut, hX, sum_filter, sum_filter, sum_filter, ← sum_add_distrib] + refine sum_le_sum fun ξ _ ↦ ?_ + have h₁ := hite (¬ IsSmall ξ) ξ + have h₂ := hite (IsSmall ξ ∧ |ξ.2.valMinAbs| < |ξ.1.valMinAbs|) ξ + by_cases hlt : |ξ.2.valMinAbs| < |ξ.1.valMinAbs| + · rw [ite_eq_left hlt] + by_cases hs : IsSmall ξ + · rw [ite_eq_left (show IsSmall ξ ∧ |ξ.2.valMinAbs| < |ξ.1.valMinAbs| from ⟨hs, hlt⟩)] + linarith + · rw [ite_eq_left hs] + linarith + · rw [ite_eq_right hlt] + linarith + -- The dual shears `(a, b) ↦ (a, b ± 4 a)` move `X` into two disjoint sets of `Y'`. + have hXY : ∑ ξ ∈ X, ‖F (shearSnd (4 : ZMod n) ξ)‖ ^ 2 + + ∑ ξ ∈ X, ‖F (shearSnd (-4 : ZMod n) ξ)‖ ^ 2 ≤ + ∑ ξ ∈ univ.filter (fun ξ : ZMod n × ZMod n ↦ |ξ.1.valMinAbs| < |ξ.2.valMinAbs|), + ‖F ξ‖ ^ 2 := by + have himage (k : ℤ) (hk : |k| = 4) (ξ : ZMod n × ZMod n) (hξ : ξ ∈ X) : + (shearSnd (k : ZMod n) ξ).2.valMinAbs = ξ.2.valMinAbs + k * ξ.1.valMinAbs ∧ + |ξ.1.valMinAbs| < |(shearSnd (k : ZMod n) ξ).2.valMinAbs| := by + simp only [hX, mem_filter, mem_univ, true_and] at hξ + unfold IsSmall at hξ + have h := valMinAbs_add_mul (a := ξ.2) (b := ξ.1) hk.le hξ.1.2 hξ.1.1 + refine ⟨h, ?_⟩ + rw [shearSnd_apply, h] + refine abs_lt_abs_add_mul hk hξ.2.le fun h0 ↦ ?_ + rw [h0, abs_zero] at hξ + exact (abs_nonneg _).not_gt hξ.2 + refine sum_comp_add_sum_comp_le F _ _ X _ (fun ξ hξ ↦ ?_) (fun ξ hξ ↦ ?_) + fun ξ hξ ξ' hξ' h ↦ ?_ + · simpa using (himage 4 (by norm_num) ξ hξ).2 + · simpa using (himage (-4) (by norm_num) ξ hξ).2 + · have h₁ := (himage 4 (by norm_num) ξ hξ).1 + have h₂ := (himage (-4) (by norm_num) ξ' hξ').1 + simp only [Int.cast_ofNat, Int.cast_neg] at h₁ h₂ + have hfst : ξ.1 = ξ'.1 := by simpa using congrArg Prod.fst h + rw [h, h₂, ← hfst] at h₁ + simp only [hX, mem_filter, mem_univ, true_and] at hξ hξ' + refine add_four_mul_ne hξ.2.le (hfst ▸ hξ'.2.le) ?_ h₁.symm + intro h0 + rw [h0, abs_zero] at hξ + exact (abs_nonneg _).not_gt hξ.2 + -- The dual shears `(a, b) ↦ (a ± 4 b, b)` move `Y` into two disjoint sets of `X'`. + have hYX : ∑ ξ ∈ Y, ‖F (shearFst (4 : ZMod n) ξ)‖ ^ 2 + + ∑ ξ ∈ Y, ‖F (shearFst (-4 : ZMod n) ξ)‖ ^ 2 ≤ + ∑ ξ ∈ univ.filter (fun ξ : ZMod n × ZMod n ↦ |ξ.2.valMinAbs| < |ξ.1.valMinAbs|), + ‖F ξ‖ ^ 2 := by + have hq (ξ : ZMod n × ZMod n) (hξ : ξ ∈ Y) : ξ.2.valMinAbs ≠ 0 := by + simp only [hY, mem_filter, mem_univ, true_and] at hξ + intro h0 + rw [h0, abs_zero, abs_nonpos_iff, ZMod.valMinAbs_eq_zero] at hξ + rw [ZMod.valMinAbs_eq_zero] at h0 + exact hξ.2.2 (Prod.ext hξ.2.1 h0) + have himage (k : ℤ) (hk : |k| = 4) (ξ : ZMod n × ZMod n) (hξ : ξ ∈ Y) : + (shearFst (k : ZMod n) ξ).1.valMinAbs = ξ.1.valMinAbs + k * ξ.2.valMinAbs ∧ + |ξ.2.valMinAbs| < |(shearFst (k : ZMod n) ξ).1.valMinAbs| := by + have hq := hq ξ hξ + simp only [hY, mem_filter, mem_univ, true_and] at hξ + unfold IsSmall at hξ + have h := valMinAbs_add_mul (a := ξ.1) (b := ξ.2) hk.le hξ.1.1 hξ.1.2 + refine ⟨h, ?_⟩ + rw [shearFst_apply, h] + exact abs_lt_abs_add_mul hk hξ.2.1 hq + refine sum_comp_add_sum_comp_le F _ _ Y _ (fun ξ hξ ↦ ?_) (fun ξ hξ ↦ ?_) + fun ξ hξ ξ' hξ' h ↦ ?_ + · simpa using (himage 4 (by norm_num) ξ hξ).2 + · simpa using (himage (-4) (by norm_num) ξ hξ).2 + · have h₁ := (himage 4 (by norm_num) ξ hξ).1 + have h₂ := (himage (-4) (by norm_num) ξ' hξ').1 + simp only [Int.cast_ofNat, Int.cast_neg] at h₁ h₂ + have hsnd : ξ.2 = ξ'.2 := by simpa using congrArg Prod.snd h + rw [h, h₂, ← hsnd] at h₁ + have hq := hq ξ hξ + simp only [hY, mem_filter, mem_univ, true_and] at hξ hξ' + exact add_four_mul_ne hξ.2.1 (hsnd ▸ hξ'.2.1) hq h₁.symm + -- Mass transfer along each of the four dual shears. + have t₁ : ∑ ξ ∈ X, ‖F ξ‖ ^ 2 ≤ ∑ ξ ∈ X, ‖F (shearSnd (4 : ZMod n) ξ)‖ ^ 2 + + 8 * ∑ ξ, ‖F (shearSnd (4 : ZMod n) ξ) - F ξ‖ ^ 2 + (∑ ξ, ‖F ξ‖ ^ 2) / 8 := + sum_norm_sq_le_sum_comp F _ X + have t₂ : ∑ ξ ∈ X, ‖F ξ‖ ^ 2 ≤ ∑ ξ ∈ X, ‖F (shearSnd (-4 : ZMod n) ξ)‖ ^ 2 + + 8 * ∑ ξ, ‖F (shearSnd (-4 : ZMod n) ξ) - F ξ‖ ^ 2 + (∑ ξ, ‖F ξ‖ ^ 2) / 8 := + sum_norm_sq_le_sum_comp F _ X + have t₃ : ∑ ξ ∈ Y, ‖F ξ‖ ^ 2 ≤ ∑ ξ ∈ Y, ‖F (shearFst (4 : ZMod n) ξ)‖ ^ 2 + + 8 * ∑ ξ, ‖F (shearFst (4 : ZMod n) ξ) - F ξ‖ ^ 2 + (∑ ξ, ‖F ξ‖ ^ 2) / 8 := + sum_norm_sq_le_sum_comp F _ Y + have t₄ : ∑ ξ ∈ Y, ‖F ξ‖ ^ 2 ≤ ∑ ξ ∈ Y, ‖F (shearFst (-4 : ZMod n) ξ)‖ ^ 2 + + 8 * ∑ ξ, ‖F (shearFst (-4 : ZMod n) ξ) - F ξ‖ ^ 2 + (∑ ξ, ‖F ξ‖ ^ 2) / 8 := + sum_norm_sq_le_sum_comp F _ Y + have s₁ : 2 * ∑ ξ ∈ X, ‖F ξ‖ ^ 2 ≤ (∑ ξ ∈ Y, ‖F ξ‖ ^ 2 + ∑ ξ ∈ Out, ‖F ξ‖ ^ 2) + + 8 * (∑ ξ, ‖F (shearSnd (4 : ZMod n) ξ) - F ξ‖ ^ 2 + + ∑ ξ, ‖F (shearSnd (-4 : ZMod n) ξ) - F ξ‖ ^ 2) + (∑ ξ, ‖F ξ‖ ^ 2) / 4 := by + calc 2 * ∑ ξ ∈ X, ‖F ξ‖ ^ 2 = ∑ ξ ∈ X, ‖F ξ‖ ^ 2 + ∑ ξ ∈ X, ‖F ξ‖ ^ 2 := two_mul _ + _ ≤ _ := add_le_add t₁ t₂ + _ = (∑ ξ ∈ X, ‖F (shearSnd (4 : ZMod n) ξ)‖ ^ 2 + + ∑ ξ ∈ X, ‖F (shearSnd (-4 : ZMod n) ξ)‖ ^ 2) + + 8 * (∑ ξ, ‖F (shearSnd (4 : ZMod n) ξ) - F ξ‖ ^ 2 + + ∑ ξ, ‖F (shearSnd (-4 : ZMod n) ξ) - F ξ‖ ^ 2) + (∑ ξ, ‖F ξ‖ ^ 2) / 4 := by + ring + _ ≤ _ := add_le_add (add_le_add (hXY.trans hY') le_rfl) le_rfl + have s₂ : 2 * ∑ ξ ∈ Y, ‖F ξ‖ ^ 2 ≤ (∑ ξ ∈ X, ‖F ξ‖ ^ 2 + ∑ ξ ∈ Out, ‖F ξ‖ ^ 2) + + 8 * (∑ ξ, ‖F (shearFst (4 : ZMod n) ξ) - F ξ‖ ^ 2 + + ∑ ξ, ‖F (shearFst (-4 : ZMod n) ξ) - F ξ‖ ^ 2) + (∑ ξ, ‖F ξ‖ ^ 2) / 4 := by + calc 2 * ∑ ξ ∈ Y, ‖F ξ‖ ^ 2 = ∑ ξ ∈ Y, ‖F ξ‖ ^ 2 + ∑ ξ ∈ Y, ‖F ξ‖ ^ 2 := two_mul _ + _ ≤ _ := add_le_add t₃ t₄ + _ = (∑ ξ ∈ Y, ‖F (shearFst (4 : ZMod n) ξ)‖ ^ 2 + + ∑ ξ ∈ Y, ‖F (shearFst (-4 : ZMod n) ξ)‖ ^ 2) + + 8 * (∑ ξ, ‖F (shearFst (4 : ZMod n) ξ) - F ξ‖ ^ 2 + + ∑ ξ, ‖F (shearFst (-4 : ZMod n) ξ) - F ξ‖ ^ 2) + (∑ ξ, ‖F ξ‖ ^ 2) / 4 := by + ring + _ ≤ _ := add_le_add (add_le_add (hYX.trans hX') le_rfl) le_rfl + linarith only [s₁, s₂, hpart] + +end PingPong + +/-! ### The Poincaré inequality and the spectral gap -/ + +section Gap + +variable {n : ℕ} [NeZero n] + +/-- Parseval's identity for the change of `f` along a translation. -/ +private theorem sum_norm_sq_translate (f : ZMod n × ZMod n → ℂ) (t : ZMod n × ZMod n) : + ∑ ξ, ‖ZMod.stdAddChar (ξ.1 * t.1 + ξ.2 * t.2) - 1‖ ^ 2 * ‖ZMod.dftProd f ξ‖ ^ 2 = + n ^ 2 * ∑ v, ‖f (v + t) - f v‖ ^ 2 := by + rw [← ZMod.sum_norm_sq_dftProd (fun v ↦ f (v + t) - f v)] + refine sum_congr rfl fun ξ _ ↦ ?_ + have : (fun v ↦ f (v + t) - f v) = (fun v ↦ f (v + t)) - f := rfl + rw [this, ZMod.dftProd_sub, Pi.sub_apply, ZMod.dftProd_comp_add, ← sub_one_mul, norm_mul, + mul_pow] + +/-- Parseval's identity for the change of `f` along the shear `(x, y) ↦ (x + k * y, y)`. -/ +private theorem sum_norm_sq_shearFst (f : ZMod n × ZMod n → ℂ) (k : ZMod n) : + ∑ ξ, ‖ZMod.dftProd f (shearSnd (-k) ξ) - ZMod.dftProd f ξ‖ ^ 2 = + n ^ 2 * ∑ v, ‖f (shearFst k v) - f v‖ ^ 2 := by + rw [← ZMod.sum_norm_sq_dftProd (fun v ↦ f (shearFst k v) - f v)] + refine sum_congr rfl fun ξ _ ↦ ?_ + have : (fun v ↦ f (shearFst k v) - f v) = (fun v ↦ f (v.1 + k * v.2, v.2)) - f := rfl + rw [this, ZMod.dftProd_sub, Pi.sub_apply, ZMod.dftProd_comp_shearFst, shearSnd_apply, neg_mul, + ← sub_eq_add_neg] + +/-- Parseval's identity for the change of `f` along the shear `(x, y) ↦ (x, y + k * x)`. -/ +private theorem sum_norm_sq_shearSnd (f : ZMod n × ZMod n → ℂ) (k : ZMod n) : + ∑ ξ, ‖ZMod.dftProd f (shearFst (-k) ξ) - ZMod.dftProd f ξ‖ ^ 2 = + n ^ 2 * ∑ v, ‖f (shearSnd k v) - f v‖ ^ 2 := by + rw [← ZMod.sum_norm_sq_dftProd (fun v ↦ f (shearSnd k v) - f v)] + refine sum_congr rfl fun ξ _ ↦ ?_ + have : (fun v ↦ f (shearSnd k v) - f v) = (fun v ↦ f (v.1, v.2 + k * v.1)) - f := rfl + rw [this, ZMod.dftProd_sub, Pi.sub_apply, ZMod.dftProd_comp_shearSnd, shearFst_apply, neg_mul, + ← sub_eq_add_neg] + +/-- The change along the shears by `4` and `-4` is at most `16` times that along the unit +shear. -/ +private theorem sum_norm_sq_shearFst_four_le (f : ZMod n × ZMod n → ℂ) : + ∑ v, ‖f (shearFst (4 : ZMod n) v) - f v‖ ^ 2 ≤ 16 * ∑ v, ‖f (shearFst 1 v) - f v‖ ^ 2 ∧ + ∑ v, ‖f (shearFst (-4 : ZMod n) v) - f v‖ ^ 2 ≤ + 16 * ∑ v, ‖f (shearFst 1 v) - f v‖ ^ 2 := by + have h4 : shearFst (4 : ZMod n) = shearFst 1 ^ 4 := by + rw [shearFst_pow] + norm_num + have hle := sum_norm_sub_sq_pow_le f (shearFst (1 : ZMod n)) 4 + rw [← h4, show ((4 : ℕ) : ℝ) ^ 2 = 16 by norm_num] at hle + refine ⟨hle, ?_⟩ + rw [← shearFst_symm, sum_norm_sub_sq_symm] + exact hle + +/-- The change along the shears by `4` and `-4` is at most `16` times that along the unit +shear. -/ +private theorem sum_norm_sq_shearSnd_four_le (f : ZMod n × ZMod n → ℂ) : + ∑ v, ‖f (shearSnd (4 : ZMod n) v) - f v‖ ^ 2 ≤ 16 * ∑ v, ‖f (shearSnd 1 v) - f v‖ ^ 2 ∧ + ∑ v, ‖f (shearSnd (-4 : ZMod n) v) - f v‖ ^ 2 ≤ + 16 * ∑ v, ‖f (shearSnd 1 v) - f v‖ ^ 2 := by + have h4 : shearSnd (4 : ZMod n) = shearSnd 1 ^ 4 := by + rw [shearSnd_pow] + norm_num + have hle := sum_norm_sub_sq_pow_le f (shearSnd (1 : ZMod n)) 4 + rw [← h4, show ((4 : ℕ) : ℝ) ^ 2 = 16 by norm_num] at hle + refine ⟨hle, ?_⟩ + rw [← shearSnd_symm, sum_norm_sub_sq_symm] + exact hle + +/-- **The Poincaré inequality for the shear-translation graph**, uniformly in `n`: a complex +function of sum zero on `ZMod n × ZMod n` has squared norm at most `512` times its total squared +change along the four moves. -/ +theorem sum_norm_sq_le_shearTranslation (f : ZMod n × ZMod n → ℂ) (hf : ∑ v, f v = 0) : + ∑ v, ‖f v‖ ^ 2 ≤ 512 * ∑ k, ∑ v, ‖f (shearTranslationMove n k v) - f v‖ ^ 2 := by + set F := ZMod.dftProd f with hF + have h0 : F 0 = 0 := by simp [F, hf] + have hpp := sum_norm_sq_le_pingPong F h0 + have hM : ∑ ξ, ‖F ξ‖ ^ 2 = n ^ 2 * ∑ v, ‖f v‖ ^ 2 := ZMod.sum_norm_sq_dftProd f + -- Large frequencies are paid for by the translations. + have hOut : ∑ ξ ∈ univ.filter (fun ξ ↦ ¬ IsSmall ξ), ‖F ξ‖ ^ 2 ≤ + 8 * (n ^ 2 * ∑ v, ‖f (v + (1, 0)) - f v‖ ^ 2 + n ^ 2 * ∑ v, ‖f (v + (0, 1)) - f v‖ ^ 2) := by + have hw (ξ : ZMod n × ZMod n) (hs : ¬ IsSmall ξ) : + 1 / 8 ≤ ‖ZMod.stdAddChar ξ.1 - 1‖ ^ 2 + ‖ZMod.stdAddChar ξ.2 - 1‖ ^ 2 := by + unfold IsSmall at hs + rcases not_and_or.1 hs with hs | hs + · linarith [one_div_eight_le_norm_stdAddChar_sub_one (not_le.1 hs), + sq_nonneg ‖ZMod.stdAddChar ξ.2 - 1‖] + · linarith [one_div_eight_le_norm_stdAddChar_sub_one (not_le.1 hs), + sq_nonneg ‖ZMod.stdAddChar ξ.1 - 1‖] + rw [← sum_norm_sq_translate, ← sum_norm_sq_translate, ← sum_add_distrib, mul_sum, sum_filter] + refine sum_le_sum fun ξ _ ↦ ?_ + have e₁ : ξ.1 * ((1, 0) : ZMod n × ZMod n).1 + ξ.2 * ((1, 0) : ZMod n × ZMod n).2 = ξ.1 := by + simp + have e₂ : ξ.1 * ((0, 1) : ZMod n × ZMod n).1 + ξ.2 * ((0, 1) : ZMod n × ZMod n).2 = ξ.2 := by + simp + rw [e₁, e₂] + split_ifs with hs + · positivity + · have := mul_le_mul_of_nonneg_right (hw ξ hs) (sq_nonneg ‖F ξ‖) + linarith + -- The dual shears are paid for by the primal shears. + have hD₁ := sum_norm_sq_shearFst f (-4 : ZMod n) + have hD₂ := sum_norm_sq_shearFst f (4 : ZMod n) + have hD₃ := sum_norm_sq_shearSnd f (-4 : ZMod n) + have hD₄ := sum_norm_sq_shearSnd f (4 : ZMod n) + rw [neg_neg] at hD₁ hD₃ + rw [← hF] at hD₁ hD₂ hD₃ hD₄ + have e₁ := sum_norm_sq_shearFst_four_le f + have e₂ := sum_norm_sq_shearSnd_four_le f + have hn : (0 : ℝ) < (n : ℝ) ^ 2 := by + have : (0 : ℝ) < n := by exact_mod_cast Nat.pos_of_ne_zero (NeZero.ne n) + positivity + simp only [Fin.sum_univ_four, shearTranslationMove, Matrix.cons_val_zero, Matrix.cons_val_one, + Matrix.cons_val_two, Matrix.cons_val_three, Matrix.head_cons, Matrix.tail_cons, + Equiv.coe_addRight] + rw [← mul_le_mul_iff_right₀ hn] + have k₁ := mul_le_mul_of_nonneg_left e₁.1 hn.le + have k₂ := mul_le_mul_of_nonneg_left e₁.2 hn.le + have k₃ := mul_le_mul_of_nonneg_left e₂.1 hn.le + have k₄ := mul_le_mul_of_nonneg_left e₂.2 hn.le + have p₁ : 0 ≤ (n : ℝ) ^ 2 * ∑ v, ‖f (v + (1, 0)) - f v‖ ^ 2 := by positivity + have p₂ : 0 ≤ (n : ℝ) ^ 2 * ∑ v, ‖f (v + (0, 1)) - f v‖ ^ 2 := by positivity + linarith + +/-- **The spectral gap of the shear-translation graph**, uniformly in `n`: its second eigenvalue +is at most `1 - 1 / 4096`. -/ +theorem secondEigenvalue_shearTranslation_le (n : ℕ) [NeZero n] : + (shearTranslation n).secondEigenvalue ≤ 1 - 1 / 4096 := by + rcases subsingleton_or_nontrivial (ZMod n × ZMod n) with hV | hV + · rw [secondEigenvalue_eq_zero_of_subsingleton] + norm_num + have h := secondEigenvalue_ofPerms_le (shearTranslationMove n) (c := 1 / 512) fun f hf ↦ ?_ + · rw [shearTranslation] + refine h.trans_eq ?_ + norm_num + have hsum : ∑ v, (f v : ℂ) = 0 := by + rw [Fintype.expect_eq_sum_div_card, div_eq_zero_iff] at hf + rcases hf with hf | hf + · exact_mod_cast hf + · exact absurd hf (by positivity) + have hP := sum_norm_sq_le_shearTranslation (fun v ↦ (f v : ℂ)) hsum + simp only [← Complex.ofReal_sub, Complex.norm_real, Real.norm_eq_abs, sq_abs] at hP + simp only [Fintype.expect_eq_sum_div_card, ← sum_div] + have hcard : (0 : ℝ) < Fintype.card (ZMod n × ZMod n) := by positivity + rw [← mul_div_assoc, div_le_div_iff_of_pos_right hcard] + linarith + +/-- **The lazy shear-translation graph is an expander** uniformly in `n`: its spectral expansion is +at most `1 - 1 / 8192`. -/ +theorem spectralExpansion_lazy_shearTranslation_le (n : ℕ) [NeZero n] : + (shearTranslation n).lazy.spectralExpansion ≤ 1 - 1 / 8192 := by + have := (shearTranslation n).spectralExpansion_lazy_le_one_add_secondEigenvalue_div_two + have := secondEigenvalue_shearTranslation_le n + linarith + +end Gap + +end RotationMap + +end Cslib diff --git a/ComplexityTests/ShearTranslationExpander.lean b/ComplexityTests/ShearTranslationExpander.lean new file mode 100644 index 000000000..f9461ae48 --- /dev/null +++ b/ComplexityTests/ShearTranslationExpander.lean @@ -0,0 +1,65 @@ +/- +Copyright (c) 2026 Christian Reitwiessner. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Christian Reitwiessner +-/ + +import Complexity.Foundations.Analysis.Fourier.ZModProd +import Complexity.Foundations.Combinatorics.Expander.ShearTranslation +import Complexity.Foundations.Combinatorics.Expander.Mixing +import Mathlib.Algebra.Order.BigOperators.Expect + +/-! +# The shear-translation expander + +Concrete rotations of the shear-translation graph, the Fourier transform at the zero frequency, +and clients of the uniform spectral gap: the Poincaré inequality applied to a concrete function, +and a lower bound on the edges leaving every vertex set, for every `n`. +-/ + +namespace ComplexityTests.ShearTranslationExpander + +open Cslib Cslib.RotationMap Finset + +-- The four forward moves at `(1, 2)` in `ZMod 5 × ZMod 5`, with their return labels. +example : (shearTranslation 5).rot ((1, 2), (0, false)) = ((3, 2), (0, true)) := by decide +example : (shearTranslation 5).rot ((1, 2), (1, false)) = ((1, 3), (1, true)) := by decide +example : (shearTranslation 5).rot ((1, 2), (2, false)) = ((2, 2), (2, true)) := by decide +example : (shearTranslation 5).rot ((1, 2), (3, false)) = ((1, 3), (3, true)) := by decide +-- The backward shear wraps around: `(1, 2) ↦ (1 - 2, 2) = (4, 2)`. +example : (shearTranslation 5).rot ((1, 2), (0, true)) = ((4, 2), (0, false)) := by decide + +-- Iterated shears and their inverses. +example : shearFst (1 : ZMod 7) ^ 3 = shearFst 3 := by + rw [shearFst_pow] + norm_num +example : (shearSnd (2 : ZMod 7)).symm (3, 4) = (3, 5) := by decide + +-- At the zero frequency the transform is the sum: here `5 * 5 = 25` ones. +example : ZMod.dftProd (fun _ : ZMod 5 × ZMod 5 ↦ (1 : ℂ)) 0 = 25 := by + simp only [ZMod.dftProd_zero, sum_const, card_univ, Fintype.card_prod, ZMod.card] + norm_num + +/-- A sum-zero test function: `1` at `(0, 0)` and `-1` at `(1, 0)`. -/ +private noncomputable def dipole (v : ZMod 3 × ZMod 3) : ℂ := + (if v = (0, 0) then 1 else 0) - (if v = (1, 0) then 1 else 0) + +-- The Poincaré inequality applies to it: its hypothesis holds for this concrete function. +example : ∑ v, ‖dipole v‖ ^ 2 ≤ + 512 * ∑ k, ∑ v, ‖dipole (shearTranslationMove 3 k v) - dipole v‖ ^ 2 := + sum_norm_sq_le_shearTranslation dipole (by simp [dipole, sum_sub_distrib]) + +-- The uniform gap bounds the edges leaving every vertex set, for every `n`. +example (n : ℕ) [NeZero n] (S : Finset (ZMod n × ZMod n)) : + (1 - (1 - 1 / 4096) : ℝ) * Fintype.card (Fin 4 × Bool) * #S * #Sᶜ / + Fintype.card (ZMod n × ZMod n) ≤ #((shearTranslation n).interedges S Sᶜ) := by + refine (shearTranslation n).le_card_interedges_compl_of_expect_mul_walk_le (fun f hf ↦ ?_) S + refine ((shearTranslation n).expect_mul_walk_le_secondEigenvalue_mul hf).trans ?_ + exact mul_le_mul_of_nonneg_right (secondEigenvalue_shearTranslation_le n) + (expect_nonneg fun _ _ ↦ sq_nonneg _) + +-- The lazy graph has the uniform spectral expansion bound on, for example, `ZMod 1000`. +example : (shearTranslation 1000).lazy.spectralExpansion < 1 := + (spectralExpansion_lazy_shearTranslation_le 1000).trans_lt (by norm_num) + +end ComplexityTests.ShearTranslationExpander diff --git a/references.bib b/references.bib index ffd09ecfe..d9e33b33a 100644 --- a/references.bib +++ b/references.bib @@ -800,6 +800,15 @@ @article{BuhrmanFortnowVanMelkebeekTorenvliet2000 doi = {10.1137/S0097539798334736} } +@article{Burger1991, + author = {Burger, Marc}, + title = {Kazhdan Constants for {SL}(3, {Z})}, + journal = {Journal f{\"u}r die reine und angewandte Mathematik}, + volume = {413}, + pages = {36--67}, + year = {1991} +} + @misc{Burghardt2018, title = {Simple {Laws} about {Nonprominent} {Properties} of {Binary} {Relations}}, url = {https://arxiv.org/abs/1806.05036v2}, @@ -1680,6 +1689,17 @@ @article{Gabbay2002 keywords = {Keywords: Abstract syntax; Alpha-conversion; Permutation actions; Set theory; Structural induction} } +@article{GabberGalil1981, + author = {Gabber, Ofer and Galil, Zvi}, + title = {Explicit Constructions of Linear-Sized Superconcentrators}, + journal = {Journal of Computer and System Sciences}, + volume = {22}, + number = {3}, + pages = {407--420}, + year = {1981}, + doi = {10.1016/0022-0000(81)90040-4} +} + @book{GareyJohnson1979, author = {Garey, Michael R. and Johnson, David S.}, title = {Computers and Intractability: A Guide to the Theory of {NP}-Completeness}, @@ -2366,6 +2386,16 @@ @inproceedings{ImpagliazzoWigderson1997 doi = {10.1145/258533.258590} } +@article{JimboMaruoka1987, + author = {Jimbo, Shuji and Maruoka, Akira}, + title = {Expanders Obtained from Affine Transformations}, + journal = {Combinatorica}, + volume = {7}, + number = {4}, + pages = {343--355}, + year = {1987} +} + @article{Johnson1962, author = {Johnson, Selmer M.}, title = {A New Upper Bound for Error-Correcting Codes}, @@ -3021,6 +3051,16 @@ @misc{ Malkin2024 url = {https://www.cs.columbia.edu/~tal/3261/fall24/Handouts/3_Myhill_Nerode.pdf} } +@article{Margulis1973, + author = {Margulis, Grigorii A.}, + title = {Explicit Constructions of Expanders}, + journal = {Problemy Peredachi Informatsii}, + volume = {9}, + number = {4}, + pages = {71--80}, + year = {1973} +} + @incollection{McDiarmid1989, author = {McDiarmid, Colin}, title = {On the Method of Bounded Differences}, From 14714b9a71fd012a55ca5605a15655c7830736a0 Mon Sep 17 00:00:00 2001 From: Christian Reitwiessner Date: Thu, 29 Oct 2026 23:27:56 +0000 Subject: [PATCH 02/13] feat(Probability): retention by pairwise independent hashing (#1444) A point is retained when its hash lies in a target set B. Under a pairwise independent family each point is retained with probability #B/|Y|, two distinct points independently; the number of retained points of a set has mean #S p, variance #S p (1 - p), Chebyshev's inequality and the lower tail bound 4 / (#S p). Co-Authored-By: Claude Opus 5.5 --- Complexity.lean | 1 + .../PairwiseIndependentHash/Retention.lean | 207 ++++++++++++++++++ ComplexityTests/PairwiseRetention.lean | 54 +++++ references.bib | 10 + 4 files changed, 272 insertions(+) create mode 100644 Complexity/Probability/PairwiseIndependentHash/Retention.lean create mode 100644 ComplexityTests/PairwiseRetention.lean diff --git a/Complexity.lean b/Complexity.lean index f59b96f22..3bd2f256c 100644 --- a/Complexity.lean +++ b/Complexity.lean @@ -2911,6 +2911,7 @@ public import Complexity.Probability.PMF.Uniform public import Complexity.Probability.PairwiseIndependent public import Complexity.Probability.PairwiseIndependentHash public import Complexity.Probability.PairwiseIndependentHash.Affine +public import Complexity.Probability.PairwiseIndependentHash.Retention public import Complexity.Probability.PairwiseIndependentHash.Shift public import Complexity.Probability.PairwiseIndependentHash.Toeplitz public import Complexity.Probability.PairwiseIndependentHash.Universal diff --git a/Complexity/Probability/PairwiseIndependentHash/Retention.lean b/Complexity/Probability/PairwiseIndependentHash/Retention.lean new file mode 100644 index 000000000..33feb4034 --- /dev/null +++ b/Complexity/Probability/PairwiseIndependentHash/Retention.lean @@ -0,0 +1,207 @@ +/- +Copyright (c) 2026 Christian Reitwiessner. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Christian Reitwiessner +-/ + +module +-- upstream: candidate + +public import Complexity.Probability.PairwiseIndependentHash +import Complexity.Foundations.Data.Finset.Expect +import Mathlib.Algebra.Order.BigOperators.Expect + +/-! +# Retention by pairwise independent hashing + +Fix a target set `B ⊆ Y` and a pairwise independent family `h i : X → Y`. A point `x` is +*retained* by the seed `i` when its hash `h i x` lies in `B`. Each point is then retained with +probability exactly `p = #B / |Y|`, and the retention events of two distinct points are +independent: both are retained with probability exactly `p ^ 2` +(`IsPairwiseIndependentHash.expect_boole_apply_mem_and_apply_mem`). This is sampling at rate `p` +with pairwise independence, the technique of Chor and Goldreich [ChorGoldreich1989] built on the +hash families of Carter and Wegman [CarterWegman1979], [WegmanCarter1981]. For polynomial or affine +hashing over a finite field with a box `B`, the rate `p` ranges over the ratios of box size to +field size. + +The number `N i = #{x ∈ S | h i x ∈ B}` of retained points of a finite set `S` therefore has mean +`#S p`, second factorial moment `#S (#S - 1) p ^ 2` and variance `#S p (1 - p)`, and Chebyshev's +inequality bounds its deviations. In particular fewer than half of the expected number of points +are retained with probability at most `4 / (#S p)`. For a single target, `B = {y}`, these are the +cell-size moments of `Complexity.Probability.PairwiseIndependentHash`. + +## Main results + +* `Cslib.Probability.IsPairwiseIndependentHash.expect_boole_apply_mem`, + `Cslib.Probability.IsPairwiseIndependentHash.dens_filter_apply_mem`: a point is retained with + probability `#B / |Y|`. +* `Cslib.Probability.IsPairwiseIndependentHash.expect_boole_apply_mem_and_apply_mem`, + `Cslib.Probability.IsPairwiseIndependentHash.dens_filter_apply_mem_and_apply_mem`: two distinct + points are retained independently. +* `Cslib.Probability.IsPairwiseIndependentHash.expect_card_filter_apply_mem`, + `Cslib.Probability.IsPairwiseIndependentHash.expect_card_filter_apply_mem_mul_sub_one`, + `Cslib.Probability.IsPairwiseIndependentHash.expect_card_filter_apply_mem_sub_sq`: the mean, + second factorial moment and variance of the number of retained points. +* `Cslib.Probability.IsPairwiseIndependentHash.dens_le_abs_card_filter_apply_mem_sub_le`: + Chebyshev's inequality for it. +* `Cslib.Probability.IsPairwiseIndependentHash.dens_two_mul_card_filter_apply_mem_lt_le`: fewer + than half of the expected number of points are retained with probability at most `4 / (#S p)`. + +## References + +* [B. Chor, O. Goldreich, *On the power of two-point based sampling*][ChorGoldreich1989] +* [J. L. Carter, M. N. Wegman, *Universal classes of hash functions*][CarterWegman1979] +* [M. N. Wegman, J. L. Carter, *New hash functions and their use in authentication and set + equality*][WegmanCarter1981] +-/ + +public section + +namespace Cslib.Probability.IsPairwiseIndependentHash + +open Finset +open scoped BigOperators + +variable {ι X Y 𝕜 : Type*} [Fintype ι] [Fintype Y] [DecidableEq Y] {h : ι → X → Y} + +/-- **Retention probability**: a point is retained, its hash lying in `B`, with probability +`#B / |Y|`. -/ +theorem expect_boole_apply_mem [Semifield 𝕜] [CharZero 𝕜] (hh : IsPairwiseIndependentHash h) + (x : X) (B : Finset Y) : + 𝔼 i, (if h i x ∈ B then 1 else 0 : 𝕜) = #B / Fintype.card Y := by + have hpt (i : ι) : (if h i x ∈ B then 1 else 0 : 𝕜) = ∑ y ∈ B, if h i x = y then 1 else 0 := + (sum_ite_eq B (h i x) fun _ ↦ (1 : 𝕜)).symm + simp only [hpt] + rw [expect_sum_comm] + simp only [Fintype.expect_boole, hh.dens_filter_apply_eq, NNRat.cast_inv, NNRat.cast_natCast, + sum_const, nsmul_eq_mul, div_eq_mul_inv] + +/-- **Retention probability**: a point is retained, its hash lying in `B`, with probability +`#B / |Y|`. -/ +theorem dens_filter_apply_mem (hh : IsPairwiseIndependentHash h) (x : X) (B : Finset Y) : + dens {i | h i x ∈ B} = #B / Fintype.card Y := by + have := hh.expect_boole_apply_mem (𝕜 := ℚ≥0) x B + rwa [Fintype.expect_boole, NNRat.cast_id] at this + +/-- **Pairwise independent retention**: two distinct points are retained by `B₁` and `B₂` with +probability `#B₁ / |Y| * (#B₂ / |Y|)`. -/ +theorem expect_boole_apply_mem_and_apply_mem [Semifield 𝕜] [CharZero 𝕜] + (hh : IsPairwiseIndependentHash h) {x₁ x₂ : X} (hx : x₁ ≠ x₂) (B₁ B₂ : Finset Y) : + 𝔼 i, (if h i x₁ ∈ B₁ ∧ h i x₂ ∈ B₂ then 1 else 0 : 𝕜) = + #B₁ / Fintype.card Y * (#B₂ / Fintype.card Y) := by + have hpt (i : ι) : (if h i x₁ ∈ B₁ ∧ h i x₂ ∈ B₂ then 1 else 0 : 𝕜) = + ∑ y₁ ∈ B₁, ∑ y₂ ∈ B₂, if h i x₁ = y₁ ∧ h i x₂ = y₂ then 1 else 0 := by + have e₂ : (if h i x₂ ∈ B₂ then 1 else 0 : 𝕜) = + ∑ y₂ ∈ B₂, if h i x₂ = y₂ then 1 else 0 := + (sum_ite_eq B₂ (h i x₂) fun _ ↦ (1 : 𝕜)).symm + rw [ite_and, ← sum_ite_eq B₁ (h i x₁) fun _ ↦ (if h i x₂ ∈ B₂ then 1 else 0 : 𝕜)] + refine sum_congr rfl fun y₁ _ ↦ ?_ + by_cases hy : h i x₁ = y₁ + · simp only [hy, true_and, ite_true] + exact e₂ + · simp [hy] + simp only [hpt] + rw [expect_sum_comm] + simp only [expect_sum_comm, Fintype.expect_boole, hh.dens_filter_apply_eq_and_apply_eq hx, + NNRat.cast_inv, NNRat.cast_pow, NNRat.cast_natCast, sum_const, nsmul_eq_mul] + ring + +/-- **Pairwise independent retention**: two distinct points are retained by `B₁` and `B₂` with +probability `#B₁ / |Y| * (#B₂ / |Y|)`. -/ +theorem dens_filter_apply_mem_and_apply_mem (hh : IsPairwiseIndependentHash h) {x₁ x₂ : X} + (hx : x₁ ≠ x₂) (B₁ B₂ : Finset Y) : + dens {i | h i x₁ ∈ B₁ ∧ h i x₂ ∈ B₂} = #B₁ / Fintype.card Y * (#B₂ / Fintype.card Y) := by + have := hh.expect_boole_apply_mem_and_apply_mem (𝕜 := ℚ≥0) hx B₁ B₂ + rwa [Fintype.expect_boole, NNRat.cast_id] at this + +/-- **The mean number of retained points** of `S` is `#S * (#B / |Y|)`. -/ +theorem expect_card_filter_apply_mem [Semifield 𝕜] [CharZero 𝕜] + (hh : IsPairwiseIndependentHash h) (S : Finset X) (B : Finset Y) : + 𝔼 i, (#{x ∈ S | h i x ∈ B} : 𝕜) = #S * (#B / Fintype.card Y) := by + simp only [card_filter, Nat.cast_sum, Nat.cast_ite, Nat.cast_one, Nat.cast_zero] + rw [expect_sum_comm] + simp only [hh.expect_boole_apply_mem, sum_const, nsmul_eq_mul] + +/-- **The second factorial moment of the number of retained points**: the number of ordered +pairs of distinct retained points of `S` has expectation `#S (#S - 1) (#B / |Y|) ^ 2`. -/ +theorem expect_card_filter_apply_mem_mul_sub_one [Field 𝕜] [CharZero 𝕜] + (hh : IsPairwiseIndependentHash h) (S : Finset X) (B : Finset Y) : + 𝔼 i, (#{x ∈ S | h i x ∈ B} : 𝕜) * (#{x ∈ S | h i x ∈ B} - 1) = + #S * (#S - 1) * (#B / Fintype.card Y) ^ 2 := by + classical + have hcount (i : ι) : (#{x ∈ S | h i x ∈ B} : 𝕜) * (#{x ∈ S | h i x ∈ B} - 1) = + ∑ q ∈ S.offDiag, if h i q.1 ∈ B ∧ h i q.2 ∈ B then 1 else 0 := by + have hoff : {x ∈ S | h i x ∈ B}.offDiag = {q ∈ S.offDiag | h i q.1 ∈ B ∧ h i q.2 ∈ B} := by + ext q + simp only [mem_offDiag, mem_filter] + tauto + rw [sum_boole, ← hoff, offDiag_card, Nat.cast_sub (Nat.le_mul_self _), Nat.cast_mul] + ring + have hpair (q : X × X) (hq : q ∈ S.offDiag) : + 𝔼 i, (if h i q.1 ∈ B ∧ h i q.2 ∈ B then 1 else 0 : 𝕜) = (#B / Fintype.card Y) ^ 2 := by + rw [hh.expect_boole_apply_mem_and_apply_mem (mem_offDiag.1 hq).2.2, sq] + simp only [hcount] + rw [expect_sum_comm, sum_congr rfl hpair, sum_const, nsmul_eq_mul, offDiag_card, + Nat.cast_sub (Nat.le_mul_self _), Nat.cast_mul] + ring + +/-- **The variance of the number of retained points** is `#S p (1 - p)` with `p = #B / |Y|`. -/ +theorem expect_card_filter_apply_mem_sub_sq [Field 𝕜] [CharZero 𝕜] + (hh : IsPairwiseIndependentHash h) (S : Finset X) (B : Finset Y) : + 𝔼 i, ((#{x ∈ S | h i x ∈ B} : 𝕜) - #S * (#B / Fintype.card Y)) ^ 2 = + #S * (#B / Fintype.card Y) * (1 - #B / Fintype.card Y) := by + have hsq (i : ι) : ((#{x ∈ S | h i x ∈ B} : 𝕜) - #S * (#B / Fintype.card Y)) ^ 2 = + (#{x ∈ S | h i x ∈ B} : 𝕜) * (#{x ∈ S | h i x ∈ B} - 1) + + (1 - 2 * (#S * (#B / Fintype.card Y))) * #{x ∈ S | h i x ∈ B} + + (#S * (#B / Fintype.card Y)) ^ 2 := by + ring + rcases isEmpty_or_nonempty ι with hι | hι + · rcases S.eq_empty_or_nonempty with rfl | ⟨x, -⟩ + · simp + rcases B.eq_empty_or_nonempty with rfl | ⟨y, -⟩ + · simp + exact absurd (hh.nonempty x y) (not_nonempty_iff.2 hι) + simp only [hsq, expect_add_distrib, ← mul_expect, hh.expect_card_filter_apply_mem_mul_sub_one, + hh.expect_card_filter_apply_mem, Fintype.expect_const] + ring + +/-- **Chebyshev's inequality for the number of retained points**: it is at distance at least +`ε > 0` from its mean `#S p`, with `p = #B / |Y|`, with probability at most `#S p / ε²`. -/ +theorem dens_le_abs_card_filter_apply_mem_sub_le [Field 𝕜] [LinearOrder 𝕜] + [IsStrictOrderedRing 𝕜] (hh : IsPairwiseIndependentHash h) (S : Finset X) (B : Finset Y) + {ε : 𝕜} (hε : 0 < ε) : + (dens {i | ε ≤ |(#{x ∈ S | h i x ∈ B} : 𝕜) - #S * (#B / Fintype.card Y)|} : 𝕜) ≤ + #S * (#B / Fintype.card Y) / ε ^ 2 := by + have hmarkov := Fintype.mul_dens_filter_le_expect + (f := fun i ↦ ((#{x ∈ S | h i x ∈ B} : 𝕜) - #S * (#B / Fintype.card Y)) ^ 2) + (fun _ ↦ sq_nonneg _) (ε ^ 2) + simp only [sq_le_sq, abs_of_pos hε] at hmarkov + rw [le_div_iff₀ (by positivity), mul_comm] + refine hmarkov.trans ?_ + rw [hh.expect_card_filter_apply_mem_sub_sq] + have hp : (#B : 𝕜) / Fintype.card Y ≥ 0 := by positivity + exact mul_le_of_le_one_right (by positivity) (sub_le_self _ hp) + +/-- **Lower tail of the number of retained points**: fewer than half of the expected number +`#S p`, with `p = #B / |Y|`, are retained with probability at most `4 / (#S p)`. -/ +theorem dens_two_mul_card_filter_apply_mem_lt_le [Field 𝕜] [LinearOrder 𝕜] + [IsStrictOrderedRing 𝕜] (hh : IsPairwiseIndependentHash h) (S : Finset X) (B : Finset Y) + (hpos : 0 < (#S : 𝕜) * (#B / Fintype.card Y)) : + (dens {i | 2 * (#{x ∈ S | h i x ∈ B} : 𝕜) < #S * (#B / Fintype.card Y)} : 𝕜) ≤ + 4 / (#S * (#B / Fintype.card Y)) := by + set μ : 𝕜 := #S * (#B / Fintype.card Y) + have hsub : ({i | 2 * (#{x ∈ S | h i x ∈ B} : 𝕜) < μ} : Finset ι) ⊆ + ({i | μ / 2 ≤ |(#{x ∈ S | h i x ∈ B} : 𝕜) - μ|} : Finset ι) := by + intro i hi + simp only [mem_filter, mem_univ, true_and] at hi ⊢ + rw [abs_sub_comm, abs_of_pos (by linarith)] + linarith + calc (dens {i | 2 * (#{x ∈ S | h i x ∈ B} : 𝕜) < μ} : 𝕜) + ≤ (dens {i | μ / 2 ≤ |(#{x ∈ S | h i x ∈ B} : 𝕜) - μ|} : 𝕜) := by + exact_mod_cast dens_le_dens hsub + _ ≤ μ / (μ / 2) ^ 2 := hh.dens_le_abs_card_filter_apply_mem_sub_le S B (by positivity) + _ = 4 / μ := by + field_simp + ring + +end Cslib.Probability.IsPairwiseIndependentHash diff --git a/ComplexityTests/PairwiseRetention.lean b/ComplexityTests/PairwiseRetention.lean new file mode 100644 index 000000000..bb4a35fe5 --- /dev/null +++ b/ComplexityTests/PairwiseRetention.lean @@ -0,0 +1,54 @@ +/- +Copyright (c) 2026 Christian Reitwiessner. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Christian Reitwiessner +-/ + +import Complexity.Probability.KWiseIndependent.Polynomial +import Complexity.Probability.PairwiseIndependentHash.Retention +import Mathlib.Algebra.Field.ZMod + +/-! +# Retention by polynomial hashing + +Polynomial hashing `x ↦ c₀ + c₁ x` over `𝔽₅`, retaining a point when its hash lies in the box +`{0, 1}`: a point is retained at rate `2 / 5`, as a direct count over the `25` seeds confirms; +two distinct points are retained jointly at rate `4 / 25`; and all five points have `2` retained +on average. +-/ + +namespace ComplexityTests.PairwiseRetention + +open Cslib Cslib.Probability Finset +open scoped BigOperators + +private instance : Fact (Nat.Prime 5) := ⟨Nat.prime_five⟩ + +private theorem hp : + IsPairwiseIndependentHash (polynomialHash : (Fin 2 → ZMod 5) → ZMod 5 → ZMod 5) := + (isKWiseIndependentHash_polynomialHash 2).isPairwiseIndependentHash le_rfl + +-- Each point is retained at rate `2 / 5`. +example (x : ZMod 5) : dens {c : Fin 2 → ZMod 5 | polynomialHash c x ∈ ({0, 1} : Finset _)} = + 2 / 5 := by + rw [hp.dens_filter_apply_mem, show #({0, 1} : Finset (ZMod 5)) = 2 by decide] + norm_num [ZMod.card] + +-- The same rate, counted directly: `10` of the `25` seeds retain the point `3`. +example : #{c : Fin 2 → ZMod 5 | polynomialHash c 3 ∈ ({0, 1} : Finset _)} = 10 := by decide + +-- Two distinct points are both retained at rate `4 / 25`. +example : dens {c : Fin 2 → ZMod 5 | + polynomialHash c 0 ∈ ({0, 1} : Finset _) ∧ polynomialHash c 1 ∈ ({0, 1} : Finset _)} = + 4 / 25 := by + rw [hp.dens_filter_apply_mem_and_apply_mem (by decide), + show #({0, 1} : Finset (ZMod 5)) = 2 by decide] + norm_num [ZMod.card] + +-- Of all five points, `2` are retained on average. +example : 𝔼 c : Fin 2 → ZMod 5, + (#{x ∈ (univ : Finset (ZMod 5)) | polynomialHash c x ∈ ({0, 1} : Finset _)} : ℚ) = 2 := by + rw [hp.expect_card_filter_apply_mem, show #({0, 1} : Finset (ZMod 5)) = 2 by decide] + norm_num [ZMod.card] + +end ComplexityTests.PairwiseRetention diff --git a/references.bib b/references.bib index ffd09ecfe..ec215b3f7 100644 --- a/references.bib +++ b/references.bib @@ -1050,6 +1050,16 @@ @article{ChorGoldreich1988 doi = {10.1137/0217015} } +@article{ChorGoldreich1989, + author = {Chor, Benny and Goldreich, Oded}, + title = {On the Power of Two-Point Based Sampling}, + journal = {Journal of Complexity}, + volume = {5}, + number = {1}, + pages = {96--106}, + year = {1989} +} + @article{ChungGrahamFranklShearer1986, author = {Chung, Fan R. K. and Graham, Ronald L. and Frankl, Peter and Shearer, James B.}, title = {Some Intersection Theorems for Ordered Sets and Graphs}, From 4943d9b0e91fa86788863e3fa7a211187d386748 Mon Sep 17 00:00:00 2001 From: Christian Reitwiessner Date: Thu, 29 Oct 2026 23:57:30 +0000 Subject: [PATCH 03/13] feat(Probability): affine retention channels over a prime field (#1682) Identifiers y : ZMod P are retained when A y + b lies in the box {v | all coordinates < L} of ZMod P ^ H. Exact rates (L/P)^H and their squares for pairs, the lower tail 4/(#A pi), independence of separate seeds, and the assembled channel properties at rate f = a^H with L = ceil(P a): f <= pi <= 2^H f. Co-Authored-By: Claude Opus 5.5 --- Complexity.lean | 1 + .../RetentionChannel.lean | 212 ++++++++++++++++++ ComplexityTests/RetentionChannel.lean | 56 +++++ 3 files changed, 269 insertions(+) create mode 100644 Complexity/Probability/PairwiseIndependentHash/RetentionChannel.lean create mode 100644 ComplexityTests/RetentionChannel.lean diff --git a/Complexity.lean b/Complexity.lean index 3bd2f256c..957459612 100644 --- a/Complexity.lean +++ b/Complexity.lean @@ -2912,6 +2912,7 @@ public import Complexity.Probability.PairwiseIndependent public import Complexity.Probability.PairwiseIndependentHash public import Complexity.Probability.PairwiseIndependentHash.Affine public import Complexity.Probability.PairwiseIndependentHash.Retention +public import Complexity.Probability.PairwiseIndependentHash.RetentionChannel public import Complexity.Probability.PairwiseIndependentHash.Shift public import Complexity.Probability.PairwiseIndependentHash.Toeplitz public import Complexity.Probability.PairwiseIndependentHash.Universal diff --git a/Complexity/Probability/PairwiseIndependentHash/RetentionChannel.lean b/Complexity/Probability/PairwiseIndependentHash/RetentionChannel.lean new file mode 100644 index 000000000..b890a5bad --- /dev/null +++ b/Complexity/Probability/PairwiseIndependentHash/RetentionChannel.lean @@ -0,0 +1,212 @@ +/- +Copyright (c) 2026 Christian Reitwiessner. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Christian Reitwiessner +-/ + +module +-- upstream: candidate + +public import Complexity.Probability.PairwiseIndependentHash.Affine +public import Complexity.Probability.PairwiseIndependentHash.Retention +public import Mathlib.Algebra.Field.ZMod +public import Mathlib.Algebra.Order.Archimedean.Real.Basic +import Mathlib.Data.Fintype.BigOperators + +/-! +# Retention channels over a prime field + +A *retention channel* selects a random set of identifiers at a prescribed rate, with pairwise +independence. Its seed is an affine map `y ↦ A y + b` from `𝔽_P` to `𝔽_P ^ H`, with a uniformly +random matrix `A` and vector `b`. The identifier `y : ZMod P` is *retained* +(`affineRetains P H L s y`) when every coordinate of `A y + b`, read as a number in +`{0, …, P - 1}`, is less than `L`. The target is then the box `retentionBox P H L` with `L ^ H` +points (`card_retentionBox`). By the pairwise independence of affine hashing +(`isPairwiseIndependentHash_affineHash`) and the general retention bounds of +`Complexity.Probability.PairwiseIndependentHash.Retention`, every identifier is retained with +probability exactly `π = (L / P) ^ H`, and two distinct identifiers both with probability `π ^ 2`. +This is sampling by pairwise independent hashing [ChorGoldreich1989] with the hash families of +Carter and Wegman [CarterWegman1979]. + +For a target rate `f = a ^ H` with `1 ≤ P a` and `a ≤ 1`, the side `L = ⌈P a⌉` gives +`f ≤ π ≤ 2 ^ H f` (`affineRetains_rates`). Then the conditional probability that `w` is +retained, given that `y ≠ w` is retained, is at most `2 ^ H f`. A deterministic nonempty set `A` +retains fewer than `#A π / 2` of its identifiers with probability at most `4 / (#A π)`. Two +channels with independent seeds, on the product seed space, give independent events +(`dens_filter_fst_and_snd`). + +These are the channel properties used in Section 4 of the OpenAI preprint *Exact +Derandomization of Logarithmic Space* (2026, unrefereed): there, `c_π f ≤ π_f ≤ C_π f`, +`Pr[Y(w) | Y(y)] ≤ C_pair f`, the lower tail `Pr[∑_{x ∈ A} X(x) < |A| π / 2] ≤ C_var / (|A| π)`, +and the independence of the channels `X` and `Y`. Here the constants are `c_π = 1`, +`C_π = C_pair = 2 ^ H` and `C_var = 4`. The preprint conditions its channels on linearly +independent frames, which changes these constants only by a bounded factor. The frames matter +only for the later averaging walks, so they are not needed here. + +## Main definitions + +* `Cslib.Probability.retentionBox`: the box `{v | ∀ j, (v j).val < L}` in `ZMod P ^ H`. +* `Cslib.Probability.affineRetains`: the identifier `y` is retained by the affine seed `s`. + +## Main results + +* `Cslib.Probability.card_retentionBox`: the box has `L ^ H` points. +* `Cslib.Probability.dens_affineRetains`, `Cslib.Probability.dens_affineRetains_and`: exact + retention probabilities of one identifier and of two distinct ones. +* `Cslib.Probability.dens_two_mul_card_filter_affineRetains_lt_le`: the lower tail of the number + of retained identifiers of a set. +* `Cslib.Probability.dens_filter_fst_and_snd`: events about independent seeds are independent. +* `Cslib.Probability.affineRetains_rates`: the four channel properties at rate `f = a ^ H`. + +## References + +* [B. Chor, O. Goldreich, *On the power of two-point based sampling*][ChorGoldreich1989] +* [J. L. Carter, M. N. Wegman, *Universal classes of hash functions*][CarterWegman1979] +-/ + +public section + +namespace Cslib.Probability + +open Finset +open scoped BigOperators + +/-- **Independence of separate seeds**: on the product of two seed spaces, an event about the +first seed and an event about the second have probability equal to the product of their +probabilities. -/ +theorem dens_filter_fst_and_snd {ι κ : Type*} [Fintype ι] [Fintype κ] (p : ι → Prop) + (q : κ → Prop) [DecidablePred p] [DecidablePred q] : + dens {z : ι × κ | p z.1 ∧ q z.2} = dens {i | p i} * dens {j | q j} := by + rw [dens_eq_card_div_card, dens_eq_card_div_card, dens_eq_card_div_card, + ← univ_product_univ, filter_product, card_product, Fintype.card_prod] + push_cast + rw [mul_div_mul_comm] + +variable (P H L : ℕ) [NeZero P] + +/-- The **retention box** `{v | ∀ j, (v j).val < L}` in `ZMod P ^ H`: every coordinate, read as +a number in `{0, …, P - 1}`, is less than `L`. -/ +def retentionBox : Finset (Fin H → ZMod P) := + Fintype.piFinset fun _ ↦ {a : ZMod P | a.val < L} + +variable {P H L} + +/-- `L` residues of `ZMod P` have representatives less than `L ≤ P`. -/ +private theorem card_filter_val_lt (hL : L ≤ P) : #{a : ZMod P | a.val < L} = L := by + have himage : ({a : ZMod P | a.val < L} : Finset (ZMod P)).image ZMod.val = range L := by + ext k + simp only [mem_image, mem_filter, mem_univ, true_and, mem_range] + refine ⟨fun ⟨a, ha, hak⟩ ↦ hak ▸ ha, fun hk ↦ ⟨k, ?_, ?_⟩⟩ <;> + rw [ZMod.val_cast_of_lt (by omega)] + exact hk + calc #({a : ZMod P | a.val < L} : Finset (ZMod P)) + = #(({a : ZMod P | a.val < L} : Finset (ZMod P)).image ZMod.val) := + (card_image_of_injective _ (ZMod.val_injective P)).symm + _ = L := by rw [himage, card_range] + +/-- The retention box has `L ^ H` points when `L ≤ P`. -/ +theorem card_retentionBox (hL : L ≤ P) : #(retentionBox P H L) = L ^ H := by + rw [retentionBox, Fintype.card_piFinset, prod_const, card_univ, Fintype.card_fin, + card_filter_val_lt hL] + +variable (P H L) + +/-- The identifier `y` is **retained** by the affine seed `s = (A, b)` when `A y + b` lies in the +retention box. -/ +abbrev affineRetains (s : Matrix (Fin H) (Fin 1) (ZMod P) × (Fin H → ZMod P)) (y : ZMod P) : + Prop := + affineHash s (fun _ ↦ y) ∈ retentionBox P H L + +variable {P H L} [Fact P.Prime] + +/-- The affine hash of identifiers is pairwise independent. -/ +private theorem isPairwiseIndependentHash_affineIdentifier : + IsPairwiseIndependentHash fun (s : Matrix (Fin H) (Fin 1) (ZMod P) × (Fin H → ZMod P)) + (y : ZMod P) ↦ affineHash s (fun _ ↦ y) := + isPairwiseIndependentHash_affineHash.comp (e := fun y _ ↦ y) fun _ _ h ↦ congrFun h 0 + +/-- **Retention probability**: every identifier is retained with probability `(L / P) ^ H`. -/ +theorem dens_affineRetains (hL : L ≤ P) (y : ZMod P) : + dens {s | affineRetains P H L s y} = ((L : ℚ≥0) / P) ^ H := by + have h := isPairwiseIndependentHash_affineIdentifier.dens_filter_apply_mem y + (retentionBox P H L) + rw [card_retentionBox hL, Fintype.card_fun, Fintype.card_fin, ZMod.card] at h + unfold affineRetains + rw [h, div_pow] + push_cast + rfl + +/-- **Pairwise independent retention**: two distinct identifiers are both retained with +probability `((L / P) ^ H) ^ 2`. -/ +theorem dens_affineRetains_and (hL : L ≤ P) {w y : ZMod P} (hwy : w ≠ y) : + dens {s | affineRetains P H L s w ∧ affineRetains P H L s y} = + ((L : ℚ≥0) / P) ^ H * ((L : ℚ≥0) / P) ^ H := by + have h := isPairwiseIndependentHash_affineIdentifier.dens_filter_apply_mem_and_apply_mem hwy + (retentionBox P H L) (retentionBox P H L) + rw [card_retentionBox hL, Fintype.card_fun, Fintype.card_fin, ZMod.card] at h + unfold affineRetains + rw [h, div_pow] + push_cast + rfl + +/-- **Lower tail of the retained count**: a set `A` of identifiers retains fewer than half of its +expected number `#A π`, with `π = (L / P) ^ H`, with probability at most `4 / (#A π)`. -/ +theorem dens_two_mul_card_filter_affineRetains_lt_le (hL : L ≤ P) (A : Finset (ZMod P)) + (hpos : 0 < (#A : ℝ) * ((L : ℝ) / P) ^ H) : + (dens {s | 2 * (#{y ∈ A | affineRetains P H L s y} : ℝ) < #A * ((L : ℝ) / P) ^ H} : ℝ) ≤ + 4 / (#A * ((L : ℝ) / P) ^ H) := by + have hrate : ((#(retentionBox P H L) : ℝ) / Fintype.card (Fin H → ZMod P)) = + ((L : ℝ) / P) ^ H := by + rw [card_retentionBox hL, Fintype.card_fun, Fintype.card_fin, ZMod.card, div_pow] + push_cast + rfl + have h := isPairwiseIndependentHash_affineIdentifier.dens_two_mul_card_filter_apply_mem_lt_le + (𝕜 := ℝ) A (retentionBox P H L) (by rwa [hrate]) + rw [hrate] at h + exact h + +/-- **The four channel properties at rate `f = a ^ H`.** Let `1 ≤ P a`, `a ≤ 1` and +`L = ⌈P a⌉`, and write `π = (L / P) ^ H` for the retention probability. Then `L ≤ P`, +`f ≤ π ≤ 2 ^ H f`, two distinct identifiers are both retained with probability at most +`2 ^ H f` times the probability that one of them is, and a nonempty set `A` retains fewer than +`#A π / 2` of its identifiers with probability at most `4 / (#A π)`. Independence of two channels +is `dens_filter_fst_and_snd`. -/ +theorem affineRetains_rates {a : ℝ} (hPa : 1 ≤ P * a) (ha : a ≤ 1) : + let L := ⌈P * a⌉₊ + L ≤ P ∧ a ^ H ≤ ((L : ℝ) / P) ^ H ∧ ((L : ℝ) / P) ^ H ≤ 2 ^ H * a ^ H ∧ + (∀ w y : ZMod P, w ≠ y → + (dens {s | affineRetains P H L s w ∧ affineRetains P H L s y} : ℝ) ≤ + 2 ^ H * a ^ H * dens {s | affineRetains P H L s y}) ∧ + ∀ A : Finset (ZMod P), A.Nonempty → + (dens {s | 2 * (#{y ∈ A | affineRetains P H L s y} : ℝ) < #A * ((L : ℝ) / P) ^ H} : + ℝ) ≤ 4 / (#A * ((L : ℝ) / P) ^ H) := by + intro L + have hP : (0 : ℝ) < P := by exact_mod_cast Nat.pos_of_ne_zero (NeZero.ne P) + have ha0 : 0 < a := by + by_contra h + have := mul_nonpos_of_nonneg_of_nonpos hP.le (not_lt.1 h) + linarith + have hLlo : (P : ℝ) * a ≤ L := Nat.le_ceil _ + have hLhi : (L : ℝ) ≤ 2 * (P * a) := by + have := Nat.ceil_lt_add_one (by positivity : (0 : ℝ) ≤ P * a) + linarith + have hLP : L ≤ P := Nat.ceil_le.2 (by nlinarith) + have hlo : a ≤ (L : ℝ) / P := by + rw [le_div_iff₀ hP] + linarith + have hhi : (L : ℝ) / P ≤ 2 * a := by + rw [div_le_iff₀ hP] + linarith + have hrate_hi : ((L : ℝ) / P) ^ H ≤ 2 ^ H * a ^ H := by + rw [← mul_pow] + exact pow_le_pow_left₀ (by positivity) hhi H + refine ⟨hLP, pow_le_pow_left₀ ha0.le hlo H, hrate_hi, fun w y hwy ↦ ?_, fun A hA ↦ ?_⟩ + · rw [dens_affineRetains_and hLP hwy, dens_affineRetains hLP] + push_cast + exact mul_le_mul_of_nonneg_right hrate_hi (by positivity) + · refine dens_two_mul_card_filter_affineRetains_lt_le hLP A ?_ + have : (0 : ℝ) < #A := by exact_mod_cast hA.card_pos + have : 0 < (L : ℝ) / P := ha0.trans_le hlo + positivity + +end Cslib.Probability diff --git a/ComplexityTests/RetentionChannel.lean b/ComplexityTests/RetentionChannel.lean new file mode 100644 index 000000000..9f278970a --- /dev/null +++ b/ComplexityTests/RetentionChannel.lean @@ -0,0 +1,56 @@ +/- +Copyright (c) 2026 Christian Reitwiessner. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Christian Reitwiessner +-/ + +import Complexity.Probability.PairwiseIndependentHash.RetentionChannel + +/-! +# Retention channels over a prime field + +A retention channel over `𝔽₅` with one coordinate and side `2` retains each identifier at rate +`2 / 5`. A direct count over its `25` seeds confirms the rate. Two independent channels retain two +given identifiers jointly at rate `(2 / 5) ^ 2`. Over `𝔽₇` in two coordinates, at target rate +`f = (1 / 2) ^ 2`, the channel properties hold with side `L = ⌈7 / 2⌉ = 4`. +-/ + +namespace ComplexityTests.RetentionChannel + +open Cslib Cslib.Probability Finset + +private instance : Fact (Nat.Prime 5) := ⟨Nat.prime_five⟩ +private instance : Fact (Nat.Prime 7) := ⟨by decide⟩ + +-- The box `{0, 1}` in `𝔽₅`, and the exact retention rate `2 / 5`. +example : #(retentionBox 5 1 2) = 2 := card_retentionBox (by norm_num) + +example (y : ZMod 5) : dens {s | affineRetains 5 1 2 s y} = 2 / 5 := by + rw [dens_affineRetains (by norm_num)] + norm_num + +-- A direct count: `10` of the `25` seeds `(A, b)` retain the identifier `3`. +example : #{s | affineRetains 5 1 2 s 3} = 10 := by decide + +-- Two independent channels, on the product seed space, retain `3` in the first and `4` in the +-- second with probability `(2 / 5) * (2 / 5)`. +example : dens {z : (Matrix (Fin 1) (Fin 1) (ZMod 5) × (Fin 1 → ZMod 5)) × + (Matrix (Fin 1) (Fin 1) (ZMod 5) × (Fin 1 → ZMod 5)) | + affineRetains 5 1 2 z.1 3 ∧ affineRetains 5 1 2 z.2 4} = 4 / 25 := by + have h := dens_filter_fst_and_snd (fun s ↦ affineRetains 5 1 2 s 3) + (fun s ↦ affineRetains 5 1 2 s 4) + rw [dens_affineRetains (by norm_num), dens_affineRetains (by norm_num)] at h + convert h using 1 + norm_num + +-- At rate `f = (1 / 2) ^ 2` over `𝔽₇`, the side is `L = ⌈7 / 2⌉ = 4`, and the retention rate +-- `(4 / 7) ^ 2` lies within `[f, 4 f]`. +example : (1 / 2 : ℝ) ^ 2 ≤ ((4 : ℝ) / 7) ^ 2 ∧ ((4 : ℝ) / 7) ^ 2 ≤ 2 ^ 2 * (1 / 2 : ℝ) ^ 2 := by + obtain ⟨-, hlo, hhi, -, -⟩ := + affineRetains_rates (P := 7) (H := 2) (a := 1 / 2) (by norm_num) (by norm_num) + have hceil : ⌈((7 : ℕ) : ℝ) * (1 / 2)⌉₊ = 4 := by norm_num [Nat.ceil_eq_iff] + rw [hceil] at hlo hhi + push_cast at hlo hhi + exact ⟨hlo, hhi⟩ + +end ComplexityTests.RetentionChannel From 6553d6d4c7194d0c78ccf25f7d652235965a8056 Mon Sep 17 00:00:00 2001 From: Christian Reitwiessner Date: Fri, 30 Oct 2026 00:03:56 +0000 Subject: [PATCH 04/13] =?UTF-8?q?refactor(Expander):=20share=20the=20shear?= =?UTF-8?q?s=20of=20R=20=C3=97=20R;=20credit=20the=20OpenAI=20preprint=20(?= =?UTF-8?q?#1444)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move Cslib.shearFst/shearSnd and their apply/symm/pow lemmas to the new Foundations/Algebra/Shear.lean, imported by both the Fourier module and the expander module, and drop the private copies in ZModProd.lean. Cite the OpenAI log-space preprint for the Fourier ping-pong idea (7'), adding its bib entry byte-identically to #1676. Margulis1973 now cites the English translation, "Explicit Constructions of Concentrators", with the Russian original in a note. Co-Authored-By: Claude Opus 5.5 --- Complexity.lean | 1 + Complexity/Foundations/Algebra/Shear.lean | 94 +++++++++++++++++++ .../Analysis/Fourier/ZModProd.lean | 23 +---- .../Expander/ShearTranslation.lean | 72 ++------------ references.bib | 18 +++- 5 files changed, 122 insertions(+), 86 deletions(-) create mode 100644 Complexity/Foundations/Algebra/Shear.lean diff --git a/Complexity.lean b/Complexity.lean index f0509049d..8d2ee4953 100644 --- a/Complexity.lean +++ b/Complexity.lean @@ -2278,6 +2278,7 @@ public import Complexity.Crypto.Protocols.SigmaProtocol.SchnorrSignature public import Complexity.Crypto.Protocols.Signature.RandomOracle public import Complexity.Foundations.Algebra.FiniteMagnitude public import Complexity.Foundations.Algebra.GeometricTail +public import Complexity.Foundations.Algebra.Shear public import Complexity.Foundations.Analysis.BernoulliInequality public import Complexity.Foundations.Analysis.Fourier.ZModProd public import Complexity.Foundations.Analysis.HarmonicMean diff --git a/Complexity/Foundations/Algebra/Shear.lean b/Complexity/Foundations/Algebra/Shear.lean new file mode 100644 index 000000000..7edbf52e8 --- /dev/null +++ b/Complexity/Foundations/Algebra/Shear.lean @@ -0,0 +1,94 @@ +/- +Copyright (c) 2026 Christian Reitwiessner. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Christian Reitwiessner +-/ + +module +-- upstream: candidate + +public import Complexity.Init +public import Mathlib.Algebra.Group.End +public import Mathlib.Algebra.Ring.Defs +import Mathlib.Tactic.Ring + +/-! +# Shears of `R × R` + +The shears `(x, y) ↦ (x + k * y, y)` and `(x, y) ↦ (x, y + k * x)` of `R × R` over a commutative +ring, as permutations. The inverse of a shear is the opposite shear, and iterating a shear `m` +times multiplies its parameter by `m`. + +## Main definitions + +* `Cslib.shearFst`, `Cslib.shearSnd`: the shears `(x, y) ↦ (x + k * y, y)` and + `(x, y) ↦ (x, y + k * x)` of `R × R`. + +## Main results + +* `Cslib.shearFst_symm`, `Cslib.shearSnd_symm`: the inverse of a shear is the opposite shear. +* `Cslib.shearFst_pow`, `Cslib.shearSnd_pow`: iterating a shear `m` times multiplies its + parameter by `m`. +-/ + +@[expose] public section + +namespace Cslib + +variable {R : Type*} [CommRing R] + +/-- The shear `(x, y) ↦ (x + k * y, y)` of `R × R`, as a permutation. -/ +def shearFst (k : R) : Equiv.Perm (R × R) where + toFun v := (v.1 + k * v.2, v.2) + invFun v := (v.1 - k * v.2, v.2) + left_inv v := by simp + right_inv v := by simp + +/-- The shear `(x, y) ↦ (x, y + k * x)` of `R × R`, as a permutation. -/ +def shearSnd (k : R) : Equiv.Perm (R × R) where + toFun v := (v.1, v.2 + k * v.1) + invFun v := (v.1, v.2 - k * v.1) + left_inv v := by simp + right_inv v := by simp + +@[simp] +theorem shearFst_apply (k : R) (v : R × R) : shearFst k v = (v.1 + k * v.2, v.2) := + rfl + +@[simp] +theorem shearSnd_apply (k : R) (v : R × R) : shearSnd k v = (v.1, v.2 + k * v.1) := + rfl + +/-- The inverse of a shear is the opposite shear. -/ +theorem shearFst_symm (k : R) : (shearFst k).symm = shearFst (-k) := by + ext v <;> simp [shearFst, sub_eq_add_neg] + +/-- The inverse of a shear is the opposite shear. -/ +theorem shearSnd_symm (k : R) : (shearSnd k).symm = shearSnd (-k) := by + ext v <;> simp [shearSnd, sub_eq_add_neg] + +/-- Iterating a shear multiplies its parameter. -/ +theorem shearFst_pow (k : R) (m : ℕ) : shearFst k ^ m = shearFst (m * k) := by + induction m with + | zero => ext v <;> simp + | succ m ih => + rw [pow_succ', ih] + ext v + · simp only [Equiv.Perm.mul_apply, shearFst_apply] + push_cast + ring + · rfl + +/-- Iterating a shear multiplies its parameter. -/ +theorem shearSnd_pow (k : R) (m : ℕ) : shearSnd k ^ m = shearSnd (m * k) := by + induction m with + | zero => ext v <;> simp + | succ m ih => + rw [pow_succ', ih] + ext v + · rfl + · simp only [Equiv.Perm.mul_apply, shearSnd_apply] + push_cast + ring + +end Cslib diff --git a/Complexity/Foundations/Analysis/Fourier/ZModProd.lean b/Complexity/Foundations/Analysis/Fourier/ZModProd.lean index 03ce150f2..11214c9ca 100644 --- a/Complexity/Foundations/Analysis/Fourier/ZModProd.lean +++ b/Complexity/Foundations/Analysis/Fourier/ZModProd.lean @@ -9,6 +9,7 @@ module public import Complexity.Init public import Mathlib.Analysis.SpecialFunctions.Complex.CircleAddChar +import Complexity.Foundations.Algebra.Shear import Mathlib.Analysis.Complex.Basic import Mathlib.NumberTheory.LegendreSymbol.AddCharacter @@ -114,35 +115,21 @@ theorem dftProd_comp_add (f : ZMod N × ZMod N → ℂ) (t ξ : ZMod N × ZMod N congr 2 ring -/-- The shear `(x, y) ↦ (x + k * y, y)` of `ZMod N × ZMod N`, as a permutation. -/ -private def shearFstEquiv (k : ZMod N) : Equiv.Perm (ZMod N × ZMod N) where - toFun v := (v.1 + k * v.2, v.2) - invFun v := (v.1 - k * v.2, v.2) - left_inv v := by simp - right_inv v := by simp - /-- **The shear `(x, y) ↦ (x + k * y, y)`** acts on frequencies by `(a, b) ↦ (a, b - k * a)`. -/ theorem dftProd_comp_shearFst (f : ZMod N × ZMod N → ℂ) (k : ZMod N) (ξ : ZMod N × ZMod N) : dftProd (fun v ↦ f (v.1 + k * v.2, v.2)) ξ = dftProd f (ξ.1, ξ.2 - k * ξ.1) := by rw [dftProd, dftProd] - refine Fintype.sum_equiv (shearFstEquiv k) _ _ fun v ↦ ?_ - simp only [shearFstEquiv, Equiv.coe_fn_mk] + refine Fintype.sum_equiv (Cslib.shearFst k) _ _ fun v ↦ ?_ + rw [Cslib.shearFst_apply] congr 2 ring -/-- The shear `(x, y) ↦ (x, y + k * x)` of `ZMod N × ZMod N`, as a permutation. -/ -private def shearSndEquiv (k : ZMod N) : Equiv.Perm (ZMod N × ZMod N) where - toFun v := (v.1, v.2 + k * v.1) - invFun v := (v.1, v.2 - k * v.1) - left_inv v := by simp - right_inv v := by simp - /-- **The shear `(x, y) ↦ (x, y + k * x)`** acts on frequencies by `(a, b) ↦ (a - k * b, b)`. -/ theorem dftProd_comp_shearSnd (f : ZMod N × ZMod N → ℂ) (k : ZMod N) (ξ : ZMod N × ZMod N) : dftProd (fun v ↦ f (v.1, v.2 + k * v.1)) ξ = dftProd f (ξ.1 - k * ξ.2, ξ.2) := by rw [dftProd, dftProd] - refine Fintype.sum_equiv (shearSndEquiv k) _ _ fun v ↦ ?_ - simp only [shearSndEquiv, Equiv.coe_fn_mk] + refine Fintype.sum_equiv (Cslib.shearSnd k) _ _ fun v ↦ ?_ + rw [Cslib.shearSnd_apply] congr 2 ring diff --git a/Complexity/Foundations/Combinatorics/Expander/ShearTranslation.lean b/Complexity/Foundations/Combinatorics/Expander/ShearTranslation.lean index c23b98d39..bef483af2 100644 --- a/Complexity/Foundations/Combinatorics/Expander/ShearTranslation.lean +++ b/Complexity/Foundations/Combinatorics/Expander/ShearTranslation.lean @@ -9,6 +9,7 @@ module public import Complexity.Foundations.Combinatorics.Expander.Lazy public import Complexity.Foundations.Combinatorics.Expander.Perm +public import Complexity.Foundations.Algebra.Shear public import Mathlib.Data.ZMod.Basic import Complexity.Foundations.Analysis.Fourier.ZModProd import Mathlib.Algebra.Order.Chebyshev @@ -40,14 +41,16 @@ the frequencies `(a, b)` with `|b| < |a|` to two disjoint sets of frequencies wi and those with `0 < |b|`, `|a| ≤ |b|` to two disjoint sets with `|b| < |a|`. Each class therefore carries at least twice the mass of the other, up to small errors, so both are nearly empty. This is a finite, quantitative argument in the spirit of the proof of the relative property (T) of -`SL₂(ℤ) ⋉ ℤ²` [Burger][Burger1991]. +`SL₂(ℤ) ⋉ ℤ²` [Burger][Burger1991]. The idea of proving a uniform gap for a shear-translation +graph on `ZMod n × ZMod n` by an elementary Fourier ping-pong argument, rather than by property +(T), is taken from the OpenAI preprint on derandomizing logarithmic space [OpenAI2026LogSpace]. +The formulation here is our own: the frequency box, the shears by `±4`, the disjoint-image mass +transfer and the constants differ from the preprint's. The explicit constants are far from optimal; the point is that they do not depend on `n`. ## Main definitions -* `Cslib.shearFst`, `Cslib.shearSnd`: the shears `(x, y) ↦ (x + k * y, y)` and - `(x, y) ↦ (x, y + k * x)` of `R × R`. * `Cslib.RotationMap.shearTranslationMove`: the four moves of the graph. * `Cslib.RotationMap.shearTranslation`: the `8`-regular shear-translation multigraph on `ZMod n × ZMod n`. @@ -63,13 +66,14 @@ The explicit constants are far from optimal; the point is that they do not depen ## References -* [G. A. Margulis, *Explicit constructions of expanders*][Margulis1973] +* [G. A. Margulis, *Explicit constructions of concentrators*][Margulis1973] * [O. Gabber, Z. Galil, *Explicit constructions of linear-sized superconcentrators*][GabberGalil1981] * [S. Jimbo, A. Maruoka, *Expanders obtained from affine transformations*][JimboMaruoka1987] * [M. Burger, *Kazhdan constants for SL(3, ℤ)*][Burger1991] * [S. Hoory, N. Linial, A. Wigderson, *Expander graphs and their applications*][HooryLinialWigderson2006] +* [OpenAI, *Exact derandomization of logarithmic space: L = RL = BPL*][OpenAI2026LogSpace] -/ @[expose] public section @@ -78,66 +82,6 @@ namespace Cslib open Finset -section Shear - -variable {R : Type*} [CommRing R] - -/-- The shear `(x, y) ↦ (x + k * y, y)` of `R × R`, as a permutation. -/ -def shearFst (k : R) : Equiv.Perm (R × R) where - toFun v := (v.1 + k * v.2, v.2) - invFun v := (v.1 - k * v.2, v.2) - left_inv v := by simp - right_inv v := by simp - -/-- The shear `(x, y) ↦ (x, y + k * x)` of `R × R`, as a permutation. -/ -def shearSnd (k : R) : Equiv.Perm (R × R) where - toFun v := (v.1, v.2 + k * v.1) - invFun v := (v.1, v.2 - k * v.1) - left_inv v := by simp - right_inv v := by simp - -@[simp] -theorem shearFst_apply (k : R) (v : R × R) : shearFst k v = (v.1 + k * v.2, v.2) := - rfl - -@[simp] -theorem shearSnd_apply (k : R) (v : R × R) : shearSnd k v = (v.1, v.2 + k * v.1) := - rfl - -/-- The inverse of a shear is the opposite shear. -/ -theorem shearFst_symm (k : R) : (shearFst k).symm = shearFst (-k) := by - ext v <;> simp [shearFst, sub_eq_add_neg] - -/-- The inverse of a shear is the opposite shear. -/ -theorem shearSnd_symm (k : R) : (shearSnd k).symm = shearSnd (-k) := by - ext v <;> simp [shearSnd, sub_eq_add_neg] - -/-- Iterating a shear multiplies its parameter. -/ -theorem shearFst_pow (k : R) (m : ℕ) : shearFst k ^ m = shearFst (m * k) := by - induction m with - | zero => ext v <;> simp - | succ m ih => - rw [pow_succ', ih] - ext v - · simp only [Equiv.Perm.mul_apply, shearFst_apply] - push_cast - ring - · rfl - -/-- Iterating a shear multiplies its parameter. -/ -theorem shearSnd_pow (k : R) (m : ℕ) : shearSnd k ^ m = shearSnd (m * k) := by - induction m with - | zero => ext v <;> simp - | succ m ih => - rw [pow_succ', ih] - ext v - · rfl - · simp only [Equiv.Perm.mul_apply, shearSnd_apply] - push_cast - ring - -end Shear - namespace RotationMap /-- The four moves of the shear-translation graph on `ZMod n × ZMod n`: the shears diff --git a/references.bib b/references.bib index d9e33b33a..7cae42ed4 100644 --- a/references.bib +++ b/references.bib @@ -3053,12 +3053,13 @@ @misc{ Malkin2024 @article{Margulis1973, author = {Margulis, Grigorii A.}, - title = {Explicit Constructions of Expanders}, - journal = {Problemy Peredachi Informatsii}, + title = {Explicit Constructions of Concentrators}, + journal = {Problems of Information Transmission}, volume = {9}, number = {4}, - pages = {71--80}, - year = {1973} + pages = {325--332}, + year = {1973}, + note = {Translated from Problemy Peredachi Informatsii 9(4):71--80, 1973, whose Russian title means ``Explicit constructions of expanders''} } @incollection{McDiarmid1989, @@ -3491,6 +3492,15 @@ @misc{OpenAI2026ETH url = {https://github.com/openai/math/blob/7ef5c0cc5ca4b0e072b7a050fca09ab24bc6fa3a/preprints/The-Exponential-Time-Hypothesis-is-False-October-25-2026/paper.pdf} } +@misc{OpenAI2026LogSpace, + author = {{OpenAI}}, + title = {Exact Derandomization of Logarithmic Space: {L} = {RL} = {BPL}}, + year = {2026}, + howpublished = {Preprint}, + note = {Dated 23 September 2026, not peer reviewed; source revision 7ef5c0cc5ca4b0e072b7a050fca09ab24bc6fa3a}, + url = {https://github.com/openai/math/blob/7ef5c0cc5ca4b0e072b7a050fca09ab24bc6fa3a/preprints/Exact-Derandomization-of-Logarithmic-Space-L-equals-RL-equals-BPL-September-23-2026/paper.pdf} +} + @misc{OpenAI2026RationalHitting, author = {{OpenAI}}, title = {{Rational} matrix hitting lists for noncommutative rational formulas}, From c1e205d1130ab22d0be2331dfe076d579dc71a2c Mon Sep 17 00:00:00 2001 From: Christian Reitwiessner Date: Fri, 30 Oct 2026 00:13:31 +0000 Subject: [PATCH 05/13] docs(Expander): credit the OpenAI Lean development for the Fourier ping-pong (#1444) The preprint's text derives its mixing bound from Shalom's property (T); the elementary route is in OpenAI's AffineSampling.lean at rev 7ef5c0cc (ExactDerandomization.Analysis.Square, ping/squash). Name that file and those declarations, mark the classical sources as background, and align the preprint's reference title with #1676. Co-Authored-By: Claude Opus 5.5 --- .../Expander/ShearTranslation.lean | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/Complexity/Foundations/Combinatorics/Expander/ShearTranslation.lean b/Complexity/Foundations/Combinatorics/Expander/ShearTranslation.lean index bef483af2..3efde6834 100644 --- a/Complexity/Foundations/Combinatorics/Expander/ShearTranslation.lean +++ b/Complexity/Foundations/Combinatorics/Expander/ShearTranslation.lean @@ -41,11 +41,17 @@ the frequencies `(a, b)` with `|b| < |a|` to two disjoint sets of frequencies wi and those with `0 < |b|`, `|a| ≤ |b|` to two disjoint sets with `|b| < |a|`. Each class therefore carries at least twice the mass of the other, up to small errors, so both are nearly empty. This is a finite, quantitative argument in the spirit of the proof of the relative property (T) of -`SL₂(ℤ) ⋉ ℤ²` [Burger][Burger1991]. The idea of proving a uniform gap for a shear-translation -graph on `ZMod n × ZMod n` by an elementary Fourier ping-pong argument, rather than by property -(T), is taken from the OpenAI preprint on derandomizing logarithmic space [OpenAI2026LogSpace]. -The formulation here is our own: the frequency box, the shears by `±4`, the disjoint-image mass -transfer and the constants differ from the preprint's. +`SL₂(ℤ) ⋉ ℤ²` [Burger][Burger1991]. + +The OpenAI preprint on derandomizing logarithmic space [OpenAI2026LogSpace] derives its uniform +mixing bound from Shalom's property (T) results. The elementary route used here, a Fourier +ping-pong on the small frequencies of `ZMod n × ZMod n` instead of property (T), follows the Lean +development accompanying the preprint, the file +[`AffineSampling.lean`](https://github.com/openai/math/blob/7ef5c0cc5ca4b0e072b7a050fca09ab24bc6fa3a/lean/OAI/Computability/Logspace/AffineSampling.lean) +at revision `7ef5c0cc`, namespace `ExactDerandomization.Analysis.Square`, lemmas `ping` and +`squash`. The proof here is an independent formulation: the frequency box, the shears by `±4`, +the disjoint-image mass transfer, the constants and all names differ. The works of Margulis, +Gabber and Galil, Jimbo and Maruoka, Burger and Hoory, Linial and Wigderson are background. The explicit constants are far from optimal; the point is that they do not depend on `n`. @@ -73,7 +79,9 @@ The explicit constants are far from optimal; the point is that they do not depen * [M. Burger, *Kazhdan constants for SL(3, ℤ)*][Burger1991] * [S. Hoory, N. Linial, A. Wigderson, *Expander graphs and their applications*][HooryLinialWigderson2006] -* [OpenAI, *Exact derandomization of logarithmic space: L = RL = BPL*][OpenAI2026LogSpace] +* [OpenAI, *Exact Derandomization of Logarithmic Space: L = RL = BPL*][OpenAI2026LogSpace], + and its Lean development, the file `AffineSampling.lean` linked above (revision `7ef5c0cc`, + `ExactDerandomization.Analysis.Square.ping`, `squash`), for the elementary route -/ @[expose] public section From 53de6a3f649ab48909a0733d9b7699608cffad88 Mon Sep 17 00:00:00 2001 From: Christian Reitwiessner Date: Fri, 30 Oct 2026 00:33:24 +0000 Subject: [PATCH 06/13] feat(Probability): frame-conditioned channels, validated variants and conditional averaging (#1682) Frame-conditioned retention channels over ZMod P with their exact marginal rate, coordinates (F, w) on retention slices, the affine move (F, w) -> (gF, gw + c), validated walk variants with their unique wrap, and conditional variance decay on every slice from a spectral-gap hypothesis on the coordinates. Co-Authored-By: Claude Opus 5.5 --- Complexity.lean | 2 + .../Combinatorics/Expander/Mixing.lean | 14 + .../ConditionalAveraging.lean | 336 ++++++++++++++++++ .../PairwiseIndependentHash/FrameChannel.lean | 231 ++++++++++++ .../RetentionChannel.lean | 6 + ComplexityTests/ConditionalAveraging.lean | 91 +++++ references.bib | 9 + 7 files changed, 689 insertions(+) create mode 100644 Complexity/Probability/PairwiseIndependentHash/ConditionalAveraging.lean create mode 100644 Complexity/Probability/PairwiseIndependentHash/FrameChannel.lean create mode 100644 ComplexityTests/ConditionalAveraging.lean diff --git a/Complexity.lean b/Complexity.lean index 957459612..a8eeb519d 100644 --- a/Complexity.lean +++ b/Complexity.lean @@ -2911,6 +2911,8 @@ public import Complexity.Probability.PMF.Uniform public import Complexity.Probability.PairwiseIndependent public import Complexity.Probability.PairwiseIndependentHash public import Complexity.Probability.PairwiseIndependentHash.Affine +public import Complexity.Probability.PairwiseIndependentHash.ConditionalAveraging +public import Complexity.Probability.PairwiseIndependentHash.FrameChannel public import Complexity.Probability.PairwiseIndependentHash.Retention public import Complexity.Probability.PairwiseIndependentHash.RetentionChannel public import Complexity.Probability.PairwiseIndependentHash.Shift diff --git a/Complexity/Foundations/Combinatorics/Expander/Mixing.lean b/Complexity/Foundations/Combinatorics/Expander/Mixing.lean index f68a740af..dea30246e 100644 --- a/Complexity/Foundations/Combinatorics/Expander/Mixing.lean +++ b/Complexity/Foundations/Combinatorics/Expander/Mixing.lean @@ -48,6 +48,8 @@ says that spectral expanders are edge expanders [Arora and Barak, Section 21.2][ expectations plus the correlation of the centered functions. * `Cslib.RotationMap.sq_expect_mul_walk_pow_sub_le`: the mixing lemma for functions and walks of any length. +* `Cslib.RotationMap.expect_walk_pow_sub_expect_sq_le`: walks of length `t` contract the + variance by `λ(G) ^ (2 t)`. * `Cslib.RotationMap.abs_card_interedges_sub_le`, `Cslib.RotationMap.abs_card_interedges_sub_le_mul_sqrt`: the expander mixing lemma. * `Cslib.RotationMap.le_card_interedges_compl_of_expect_mul_walk_le`, @@ -105,6 +107,18 @@ theorem expect_mul_walk_pow_eq (t : ℕ) (f g : V → ℝ) : Fintype.expect_const] ring +/-- **Variance decay along walks**: a walk of length `t` multiplies the variance of a function, +its second moment about the mean, by at most `λ(G) ^ (2 t)`; the mean is preserved by +`expect_walk_pow`. -/ +theorem expect_walk_pow_sub_expect_sq_le (t : ℕ) (f : V → ℝ) : + 𝔼 v, ((G.walk ^ t) f v - 𝔼 w, f w) ^ 2 ≤ + G.spectralExpansion ^ (2 * t) * 𝔼 v, (f v - 𝔼 w, f w) ^ 2 := by + have hf : (G.walk ^ t) (fun w ↦ f w - 𝔼 u, f u) = fun v ↦ (G.walk ^ t) f v - 𝔼 u, f u := by + rw [show (fun w ↦ f w - 𝔼 u, f u) = f - fun _ ↦ 𝔼 u, f u from rfl, map_sub, walk_pow_const] + rfl + have h := G.expect_walk_pow_sq_le_spectralExpansion_pow_mul (expect_sub_expect f) t + rwa [hf] at h + /-- **The mixing lemma for functions**: the correlation `𝔼 v, f v * (G.walk ^ t) g v` of `f` with `g` along walks of length `t` differs from the product of their expectations by at most `λ(G) ^ t` times their standard deviations. Squared: the square of the difference is at most diff --git a/Complexity/Probability/PairwiseIndependentHash/ConditionalAveraging.lean b/Complexity/Probability/PairwiseIndependentHash/ConditionalAveraging.lean new file mode 100644 index 000000000..04001ee81 --- /dev/null +++ b/Complexity/Probability/PairwiseIndependentHash/ConditionalAveraging.lean @@ -0,0 +1,336 @@ +/- +Copyright (c) 2026 Christian Reitwiessner. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Christian Reitwiessner +-/ + +module +-- upstream: candidate + +public import Complexity.Foundations.Combinatorics.Expander.Mixing +public import Complexity.Foundations.Combinatorics.Expander.Perm +public import Complexity.Foundations.Combinatorics.Expander.Reindex +public import Complexity.Probability.PairwiseIndependentHash.FrameChannel + +/-! +# Conditional averaging on retention slices + +A *retention slice* (`Cslib.Probability.RetentionSlice`) is the set of frame-conditioned channels +`A = (a₀, F)` that retain a fixed identifier `y`; its uniform law is the channel law conditioned on +retaining `y`. In the coordinates `(F, w)` of `sliceEquiv`, with `w ∈ ZMod L ^ H` the value at `y`, +an integer matrix `g` of determinant one and an integer vector `c` act by the **affine move** + +`coordMove g c (F, w) = (g F mod P, g w + c mod L)`. + +Any regular multigraph `G` on the coordinates transports to a walk on every slice +(`sliceGraph`), with the same spectral expansion (`spectralExpansion_sliceGraph`). Hence a single +spectral-gap bound for `G`, independent of `y`, gives **conditional averaging**: on every slice, the +walk of length `t` contracts the conditional variance by `λ(G) ^ (2 t)` +(`expect_walk_pow_sliceGraph_sub_expect_sq_le`). The bound for the walk of the preprint's affine +moves on frames (the frame-lifted gap) is a hypothesis here; later work supplies it. + +**Validated variants.** The move on a slice refers to `y`, but it is realized by permutations of +the full channel space that do not: + +`variantMove L g c z (a₀, F) = (g a₀ + c + L z, g F) mod P`, + +one for each integer *wrap* vector `z`. Each variant is a bijection of all channels. Computing +`x = g w + c` over the integers from the representatives `w` of `A.eval y`, the *wrap test* +`IsValidWrap L g c z (A.eval y)` checks that `x + L z` lies in `{0, …, L - 1} ^ H`. Exactly one +`z` passes, namely `wrap L g c (A.eval y) = -⌊x / L⌋` (`isValidWrap_iff`), and it lies in the +fixed box `|z i| ≤ ∑ j, |g i j| + |c i|` for every side length (`abs_wrap_le`). On a channel +retaining `y`, that variant is the affine move (`variantMove_wrap_eq`). So the sum of the passing +variants over any candidate set of wraps is the move (`sum_ite_isValidWrap`), and the walk of a +family of moves on a slice is the average over moves of these sums +(`walk_sliceGraph_ofPerms_eq`). + +This formalizes ideas of Section 6 of the OpenAI preprint [OpenAI2026LogSpace]: the +coordinates and the action `(F, w) ↦ (MF, Mw + c)` in the proof of Lemma 6.2, and the variants +`A' = MA + (c + Lz) e₁ᵀ (mod P)` with their unique valid wrap `zᵢ = -⌊(Mw + c)ᵢ / L⌋` in the +proof of Lemma 6.3 (items 1–4 for a single step). The preprint's walk uses the elementary +generators of `SL_H(ℤ) ⋉ ℤ^H` and its gap comes from property (T) (Lemma 6.1); here the walk and +its gap are left abstract. Transitivity of the action, the product over several channels, and +`L^s` bounds for `s > 2` are not part of this module. + +## Main definitions + +* `Cslib.Probability.affineSL`: the affine permutation `v ↦ g v + c` of `R ^ n`, for `g` an integer + matrix of determinant one. +* `Cslib.Probability.coordMove`: the affine move on slice coordinates. +* `Cslib.Probability.sliceGraph`: a graph on the coordinates, transported to a retention slice. +* `Cslib.Probability.variantMove`: a variant, a permutation of all channels. +* `Cslib.Probability.IsValidWrap`, `Cslib.Probability.wrap`: the wrap test and its solution. + +## Main results + +* `Cslib.Probability.coordMove_symm`: the inverse move is the move of the inverse. +* `Cslib.Probability.spectralExpansion_sliceGraph`: the transported walk keeps its gap. +* `Cslib.Probability.expect_walk_pow_sliceGraph_sub_expect_sq_le`: conditional averaging. +* `Cslib.Probability.eval_variantMove`: a variant acts affinely on every evaluation. +* `Cslib.Probability.isValidWrap_iff`, `Cslib.Probability.abs_wrap_le`: the valid wrap is unique + and bounded independently of `L` and `P`. +* `Cslib.Probability.variantMove_wrap_eq`: on a slice, the valid variant is the affine move. +* `Cslib.Probability.sum_ite_isValidWrap`, `Cslib.Probability.walk_sliceGraph_ofPerms_eq`: the + sum of the valid variants is the conditional move, and averages to the conditional walk. + +## References + +* [OpenAI, *Exact Derandomization of Logarithmic Space: L = RL = BPL*][OpenAI2026LogSpace] +-/ + +public section + +namespace Cslib.Probability + +open Finset Matrix +open scoped BigOperators + +section Affine + +variable {n : Type*} [Fintype n] [DecidableEq n] (R : Type*) [CommRing R] + +/-- The affine permutation `v ↦ g v + c` of `R ^ n`, for an integer matrix `g` of determinant one +reduced into `R`. -/ +@[expose] def affineSL (g : SpecialLinearGroup n ℤ) (c : n → R) : Equiv.Perm (n → R) := + (SpecialLinearGroup.toLin' (SpecialLinearGroup.map (Int.castRingHom R) g)).toEquiv.trans + (Equiv.addRight c) + +@[simp] +theorem affineSL_apply (g : SpecialLinearGroup n ℤ) (c : n → R) (v : n → R) : + affineSL R g c v = (SpecialLinearGroup.map (Int.castRingHom R) g : Matrix n n R) *ᵥ v + c := + rfl + +end Affine + +variable {P H r L : ℕ} [NeZero P] + +/-- The **affine move** `(F, w) ↦ (g F, g w + c)` on slice coordinates: `g` acts on the frame +modulo `P` and on the box coordinate modulo `L`. -/ +@[expose] def coordMove (g : SpecialLinearGroup (Fin H) ℤ) (c : Fin H → ℤ) : + Equiv.Perm (Frame P H r × (Fin H → ZMod L)) := + (Frame.mapSL g).prodCongr (affineSL (ZMod L) g fun i ↦ (c i : ZMod L)) + +omit [NeZero P] in +/-- The inverse of the move by `(g, c)` is the move by `(g⁻¹, -g⁻¹ c)`. -/ +theorem coordMove_symm (g : SpecialLinearGroup (Fin H) ℤ) (c : Fin H → ℤ) : + (coordMove (P := P) (r := r) (L := L) g c).symm = + coordMove g⁻¹ + (-(((g⁻¹ : SpecialLinearGroup (Fin H) ℤ) : Matrix (Fin H) (Fin H) ℤ) *ᵥ c)) := by + refine Equiv.ext fun p ↦ (coordMove (P := P) (r := r) (L := L) g c).injective ?_ + rw [Equiv.apply_symm_apply] + obtain ⟨F, w⟩ := p + ext j i + · simp only [coordMove, Equiv.prodCongr_apply, Prod.map_fst, Frame.mapSL_apply, mulVec_mulVec, + ← SpecialLinearGroup.coe_mul, ← map_mul, mul_inv_cancel, map_one, SpecialLinearGroup.coe_one, + one_mulVec] + · have hc : (fun i ↦ (((-(((g⁻¹ : SpecialLinearGroup (Fin H) ℤ) : Matrix (Fin H) (Fin H) ℤ) *ᵥ + c)) i : ℤ) : ZMod L)) = -((SpecialLinearGroup.map (Int.castRingHom (ZMod L)) g⁻¹ : + Matrix (Fin H) (Fin H) (ZMod L)) *ᵥ fun i ↦ (c i : ZMod L)) := by + ext i + rw [Pi.neg_apply, Pi.neg_apply, Int.cast_neg, SpecialLinearGroup.map_apply_coe, + RingHom.mapMatrix_apply] + exact congrArg Neg.neg (RingHom.map_mulVec (Int.castRingHom (ZMod L)) _ c i) + simp only [coordMove, Equiv.prodCongr_apply, Prod.map_snd, affineSL_apply, hc, mulVec_add, + mulVec_neg, mulVec_mulVec, ← SpecialLinearGroup.coe_mul, ← map_mul, mul_inv_cancel, map_one, + SpecialLinearGroup.coe_one, one_mulVec] + simp + +variable (L) in +/-- A graph `G` on slice coordinates, transported to the retention slice of `y`. -/ +@[expose] def sliceGraph [NeZero L] (hL : L ≤ P) (y : ZMod P) {D : Type*} + (G : RotationMap (Frame P H r × (Fin H → ZMod L)) D) : + RotationMap (RetentionSlice P H r L y) D := + G.reindex (sliceEquiv hL y).symm + +/-- The walk on a slice has the spectral expansion of the walk on coordinates, for every +identifier `y`. -/ +@[simp] +theorem spectralExpansion_sliceGraph [NeZero L] (hL : L ≤ P) (y : ZMod P) {D : Type*} [Fintype D] + (G : RotationMap (Frame P H r × (Fin H → ZMod L)) D) : + (sliceGraph L hL y G).spectralExpansion = G.spectralExpansion := + G.spectralExpansion_reindex _ + +/-- **Conditional averaging.** Let `G` be any regular multigraph on the slice coordinates, for +example the walk of affine moves, whose spectral expansion is at most `λ`. Then on the retention +slice of every identifier `y`, the walk of length `t` contracts the conditional variance by +`λ ^ (2 t)`, uniformly in `y`; the conditional mean is preserved (`expect_walk_pow`). The bound +`λ` is the hypothesis that the frame-lifted gap must supply. -/ +theorem expect_walk_pow_sliceGraph_sub_expect_sq_le [NeZero L] (hL : L ≤ P) {D : Type*} + [Fintype D] [Nonempty D] (G : RotationMap (Frame P H r × (Fin H → ZMod L)) D) {lam : ℝ} + (hG : G.spectralExpansion ≤ lam) (y : ZMod P) (f : RetentionSlice P H r L y → ℝ) (t : ℕ) : + 𝔼 A, (((sliceGraph L hL y G).walk ^ t) f A - 𝔼 B, f B) ^ 2 ≤ + lam ^ (2 * t) * 𝔼 A, (f A - 𝔼 B, f B) ^ 2 := by + refine ((sliceGraph L hL y G).expect_walk_pow_sub_expect_sq_le t f).trans ?_ + rw [spectralExpansion_sliceGraph] + exact mul_le_mul_of_nonneg_right (pow_le_pow_left₀ G.spectralExpansion_nonneg hG _) + (expect_nonneg fun _ _ ↦ sq_nonneg _) + +/-! ### Validated variants -/ + +variable (L) in +/-- A **validated-walk variant**: the permutation `(a₀, F) ↦ (g a₀ + c + L z, g F)` of all +channels, modulo `P`. It does not depend on any identifier. -/ +@[expose] def variantMove (g : SpecialLinearGroup (Fin H) ℤ) (c z : Fin H → ℤ) : + Equiv.Perm (FrameChannel P H r) := + (affineSL (ZMod P) g fun i ↦ ((c i + L * z i : ℤ) : ZMod P)).prodCongr (Frame.mapSL g) + +omit [NeZero P] in +/-- A variant acts on the value at every identifier by the same affine map. -/ +theorem eval_variantMove (g : SpecialLinearGroup (Fin H) ℤ) (c z : Fin H → ℤ) + (A : FrameChannel P H r) (y : ZMod P) : + (variantMove L g c z A).eval y = + (SpecialLinearGroup.map (Int.castRingHom (ZMod P)) g : Matrix _ _ (ZMod P)) *ᵥ A.eval y + + fun i ↦ ((c i + L * z i : ℤ) : ZMod P) := by + simp only [variantMove, FrameChannel.eval, Equiv.prodCongr_apply, Prod.map_fst, Prod.map_snd, + affineSL_apply, Frame.mapSL_apply, mulVec_add, mulVec_sum, mulVec_smul] + abel + +/-- The integer vector `g w + c`, computed from the representatives `w` of a value. -/ +@[expose] def wrapTarget (g : SpecialLinearGroup (Fin H) ℤ) (c : Fin H → ℤ) (w : Fin H → ZMod P) : + Fin H → ℤ := + (g : Matrix (Fin H) (Fin H) ℤ) *ᵥ (fun j ↦ ((w j).val : ℤ)) + c + +variable (L) in +/-- The **wrap test** for a variant: `g w + c + L z`, computed over the integers from the +representatives `w` of the value, lies in `{0, …, L - 1} ^ H`. -/ +@[expose] def IsValidWrap (g : SpecialLinearGroup (Fin H) ℤ) (c z : Fin H → ℤ) + (w : Fin H → ZMod P) : Prop := + ∀ i, 0 ≤ wrapTarget g c w i + L * z i ∧ wrapTarget g c w i + L * z i < L + +instance (g : SpecialLinearGroup (Fin H) ℤ) (c z : Fin H → ℤ) (w : Fin H → ZMod P) : + Decidable (IsValidWrap L g c z w) := + inferInstanceAs (Decidable (∀ _, _)) + +variable (L) in +/-- The valid wrap `z = -⌊(g w + c) / L⌋`. -/ +@[expose] def wrap (g : SpecialLinearGroup (Fin H) ℤ) (c : Fin H → ℤ) (w : Fin H → ZMod P) : + Fin H → ℤ := + fun i ↦ -(wrapTarget g c w i / L) + +omit [NeZero P] in +/-- **Uniqueness of the valid wrap**: exactly one wrap vector passes the test. -/ +theorem isValidWrap_iff [NeZero L] {g : SpecialLinearGroup (Fin H) ℤ} {c z : Fin H → ℤ} + {w : Fin H → ZMod P} : IsValidWrap L g c z w ↔ z = wrap L g c w := by + have hL : (0 : ℤ) < L := by exact_mod_cast Nat.pos_of_ne_zero (NeZero.ne L) + refine ⟨fun h ↦ funext fun i ↦ ?_, fun h i ↦ ?_⟩ + · have := (Int.ediv_emod_unique hL).2 + ⟨show wrapTarget g c w i + L * z i + L * -z i = wrapTarget g c w i by ring, h i⟩ + simp only [wrap, this.1, neg_neg] + · have hmod := Int.emod_def (wrapTarget g c w i) L + simp only [h, wrap, mul_neg, ← sub_eq_add_neg, ← hmod] + exact ⟨Int.emod_nonneg _ hL.ne', Int.emod_lt_of_pos _ hL⟩ + +/-- **The wrap box**: for a value in the retention box, the valid wrap satisfies +`|z i| ≤ ∑ j, |g i j| + |c i|`, a bound independent of `L` and `P`. So finitely many variants per +move suffice for every side length. -/ +theorem abs_wrap_le [NeZero L] (g : SpecialLinearGroup (Fin H) ℤ) (c : Fin H → ℤ) + {w : Fin H → ZMod P} (hw : w ∈ retentionBox P H L) (i : Fin H) : + |wrap L g c w i| ≤ ∑ j, |g i j| + |c i| := by + have hL : (0 : ℤ) < L := by exact_mod_cast Nat.pos_of_ne_zero (NeZero.ne L) + simp only [wrap, abs_neg] + have hterm (j : Fin H) : |g i j * ((w j).val : ℤ)| ≤ |g i j| * L := by + rw [abs_mul, abs_of_nonneg (Int.natCast_nonneg _)] + have : ((w j).val : ℤ) ≤ L := by exact_mod_cast (mem_retentionBox.1 hw j).le + exact mul_le_mul_of_nonneg_left this (abs_nonneg _) + have hx : |wrapTarget g c w i| ≤ L * (∑ j, |g i j| + |c i|) := by + have h1 : |∑ j, g i j * ((w j).val : ℤ)| ≤ ∑ j, |g i j| * L := + (abs_sum_le_sum_abs _ _).trans (sum_le_sum fun j _ ↦ hterm j) + have h2 : |c i| ≤ |c i| * L := le_mul_of_one_le_right (abs_nonneg _) hL + calc |wrapTarget g c w i| = |∑ j, g i j * ((w j).val : ℤ) + c i| := rfl + _ ≤ |∑ j, g i j * ((w j).val : ℤ)| + |c i| := abs_add_le _ _ + _ ≤ ∑ j, |g i j| * L + |c i| * L := add_le_add h1 h2 + _ = L * (∑ j, |g i j| + |c i|) := by rw [← sum_mul]; ring + generalize wrapTarget g c w i = x at hx ⊢ + generalize ∑ j, |g i j| + |c i| = S at hx ⊢ + have hlo := Int.mul_ediv_self_le (x := x) hL.ne' + have hhi := Int.lt_ediv_add_one_mul_self x hL + rw [abs_le] at hx ⊢ + constructor + · by_contra h + have : x / L + 1 ≤ -S := by omega + nlinarith + · by_contra h + have : S + 1 ≤ x / L := by omega + nlinarith + +/-- **The valid variant is the conditional move.** On a channel retaining `y`, the variant with the +valid wrap maps it to the channel with coordinates `coordMove g c (F, w)`. In particular it +retains `y` again. -/ +theorem variantMove_wrap_eq [NeZero L] (hL : L ≤ P) {y : ZMod P} + (g : SpecialLinearGroup (Fin H) ℤ) (c : Fin H → ℤ) (A : RetentionSlice P H r L y) : + variantMove L g c (wrap L g c (A.1.eval y)) A.1 = + ((sliceEquiv hL y).symm (coordMove g c (sliceEquiv hL y A))).1 := by + refine (FrameChannel.evalEquiv y).injective (Prod.ext (funext fun i ↦ ?_) ?_) + · have hrep : A.1.eval y = fun j ↦ (((A.1.eval y j).val : ℤ) : ZMod P) := by + ext j + simp + have hP : ((SpecialLinearGroup.map (Int.castRingHom (ZMod P)) g : Matrix _ _ (ZMod P)) *ᵥ + A.1.eval y) i = ((((g : Matrix _ _ ℤ) *ᵥ fun j ↦ ((A.1.eval y j).val : ℤ)) i : ℤ) : + ZMod P) := by + conv_lhs => rw [hrep] + rw [SpecialLinearGroup.map_apply_coe, RingHom.mapMatrix_apply] + exact (RingHom.map_mulVec (Int.castRingHom (ZMod P)) _ _ i).symm + have hLmod : (((SpecialLinearGroup.map (Int.castRingHom (ZMod L)) g : Matrix _ _ (ZMod L)) *ᵥ + fun j ↦ (((A.1.eval y j).val : ℕ) : ZMod L)) i + (c i : ZMod L)) = + ((wrapTarget g c (A.1.eval y) i : ℤ) : ZMod L) := by + have hcast : (fun j ↦ (((A.1.eval y j).val : ℕ) : ZMod L)) = + Int.castRingHom (ZMod L) ∘ fun j ↦ ((A.1.eval y j).val : ℤ) := by + ext j + simp + rw [wrapTarget, Pi.add_apply, Int.cast_add, SpecialLinearGroup.map_apply_coe, + RingHom.mapMatrix_apply, hcast] + exact congrArg (· + (c i : ZMod L)) + (RingHom.map_mulVec (Int.castRingHom (ZMod L)) _ _ i).symm + have hval : ((((wrapTarget g c (A.1.eval y) i : ℤ) : ZMod L).val : ℕ) : ZMod P) = + ((wrapTarget g c (A.1.eval y) i % L : ℤ) : ZMod P) := by + rw [← ZMod.val_intCast, Int.cast_natCast] + simp only [FrameChannel.evalEquiv_apply, eval_variantMove, Pi.add_apply, hP, + eval_sliceEquiv_symm, sliceEquiv_apply, coordMove, Equiv.prodCongr_apply, Prod.map_snd, + affineSL_apply, hLmod, hval] + rw [Int.emod_def] + simp only [wrap, wrapTarget, Pi.add_apply] + push_cast + ring + · rfl + +/-- **Exactly one variant survives** (Lemma 6.3, items 3 and 4, for one step). For a channel +retaining `y` and any candidate set `Z` of wraps containing the valid one, the sum over `Z` of +the variants passing the wrap test is the value at the conditional move. -/ +theorem sum_ite_isValidWrap [NeZero L] (hL : L ≤ P) {y : ZMod P} {M : Type*} [AddCommMonoid M] + (g : SpecialLinearGroup (Fin H) ℤ) (c : Fin H → ℤ) (A : RetentionSlice P H r L y) + {Z : Finset (Fin H → ℤ)} (hZ : wrap L g c (A.1.eval y) ∈ Z) (f : FrameChannel P H r → M) : + ∑ z ∈ Z, (if IsValidWrap L g c z (A.1.eval y) then f (variantMove L g c z A.1) else 0) = + f ((sliceEquiv hL y).symm (coordMove g c (sliceEquiv hL y A))).1 := by + simp only [isValidWrap_iff, sum_ite_eq', hZ, ite_true] + rw [variantMove_wrap_eq hL] + +/-- The forward move of a generator `(g, c)` for `b = false`, and its inverse for `b = true`. -/ +@[expose] def signedMove {H : ℕ} (m : SpecialLinearGroup (Fin H) ℤ × (Fin H → ℤ)) (b : Bool) : + SpecialLinearGroup (Fin H) ℤ × (Fin H → ℤ) := + bif b then (m.1⁻¹, -(((m.1⁻¹ : SpecialLinearGroup (Fin H) ℤ) : Matrix (Fin H) (Fin H) ℤ) *ᵥ m.2)) + else m + +/-- **The conditional walk as an average of valid variants.** For a family `σ` of affine +generators, the walk of `ofPerms` of their moves, transported to the slice of `y`, applied to a +function `f` of the channel, is the average over generators and directions of the sums of the +valid variants. -/ +theorem walk_sliceGraph_ofPerms_eq [NeZero L] (hL : L ≤ P) {y : ZMod P} {K : Type*} [Fintype K] + (σ : K → SpecialLinearGroup (Fin H) ℤ × (Fin H → ℤ)) {Z : Finset (Fin H → ℤ)} + (hZ : ∀ k b, ∀ w ∈ retentionBox P H L, + wrap L (signedMove (σ k) b).1 (signedMove (σ k) b).2 w ∈ Z) + (f : FrameChannel P H r → ℝ) (A : RetentionSlice P H r L y) : + (sliceGraph L hL y (RotationMap.ofPerms fun k ↦ coordMove (σ k).1 (σ k).2)).walk + (fun B ↦ f B.1) A = + 𝔼 kb : K × Bool, ∑ z ∈ Z, + (if IsValidWrap L (signedMove (σ kb.1) kb.2).1 (signedMove (σ kb.1) kb.2).2 z (A.1.eval y) + then f (variantMove L (signedMove (σ kb.1) kb.2).1 (signedMove (σ kb.1) kb.2).2 z A.1) + else 0) := by + rw [RotationMap.walk_apply] + refine expect_congr rfl fun ⟨k, b⟩ _ ↦ ?_ + rw [sum_ite_isValidWrap hL _ _ A (hZ k b _ A.2)] + cases b + · rfl + · simp only [sliceGraph, RotationMap.neighbor_reindex, RotationMap.neighbor_ofPerms_true, + Equiv.symm_symm, signedMove, Bool.cond_true, coordMove_symm] + +end Cslib.Probability diff --git a/Complexity/Probability/PairwiseIndependentHash/FrameChannel.lean b/Complexity/Probability/PairwiseIndependentHash/FrameChannel.lean new file mode 100644 index 000000000..c42f9dad8 --- /dev/null +++ b/Complexity/Probability/PairwiseIndependentHash/FrameChannel.lean @@ -0,0 +1,231 @@ +/- +Copyright (c) 2026 Christian Reitwiessner. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Christian Reitwiessner +-/ + +module +-- upstream: candidate + +public import Complexity.Probability.PairwiseIndependentHash.RetentionChannel +public import Mathlib.LinearAlgebra.LinearIndependent.Defs +public import Mathlib.LinearAlgebra.Matrix.SpecialLinearGroup +import Mathlib.LinearAlgebra.StdBasis + +/-! +# Frame-conditioned retention channels and their retention slices + +A *frame* is an ordered linearly independent family `F : Fin r → (Fin H → ZMod P)`. A +*frame-conditioned channel* is a pair `A = (a₀, F)` of a constant column `a₀ : Fin H → ZMod P` +and a frame `F`. It evaluates an identifier `y : ZMod P` as the polynomial + +`A.eval y = a₀ + ∑ j, y ^ (j + 1) • F j`, + +and retains `y` when `A.eval y` lies in the retention box `retentionBox P H L`. Drawing a +uniformly random frame-conditioned channel is drawing a uniformly random `H × (r + 1)` matrix +conditioned on its last `r` columns being linearly independent. + +For a fixed identifier `y`, the map `A ↦ (F, A.eval y)` is a bijection, since `a₀` is recovered +from the value and the frame (`evalEquiv`). Hence the frame and the evaluation are independent, +the evaluation is uniform, and `y` is retained with probability exactly `(L / P) ^ H` for every +`y` and every `r ≤ H` (`dens_eval_mem_retentionBox`), as without frame conditioning. On the +*retention slice* of `y`, the channels retaining `y`, the same bijection gives coordinates +`(F, w)` with `w` in the box `{0, …, L - 1} ^ H`, which we identify with `ZMod L ^ H` +(`sliceEquiv`). Conditional averaging on the slice is done in these coordinates +(`Complexity.Probability.PairwiseIndependentHash.ConditionalAveraging`). + +This follows the rank channels of Section 3 of the OpenAI preprint [OpenAI2026LogSpace] +(channel matrices conditioned on their non-constant columns forming a frame), the exact marginal +in the proof of its Lemma 3.1, and the coordinates `(F, w)` of the proof of its Lemma 6.2. + +## Main definitions + +* `Cslib.Probability.Frame`: ordered linearly independent `r`-tuples in `ZMod P ^ H`. +* `Cslib.Probability.Frame.mapSL`: an integer matrix of determinant one acting on frames. +* `Cslib.Probability.FrameChannel`, `Cslib.Probability.FrameChannel.eval`: frame-conditioned + channels and their evaluation at an identifier. +* `Cslib.Probability.FrameChannel.evalEquiv`: a channel is its value at `y` and its frame. +* `Cslib.Probability.retentionBoxEquiv`: the retention box as `ZMod L ^ H`. +* `Cslib.Probability.RetentionSlice`, `Cslib.Probability.sliceEquiv`: the channels retaining + `y`, and their coordinates `(F, w)`. + +## Main results + +* `Cslib.Probability.dens_eval_mem_retentionBox`: under frame conditioning, every identifier is + retained with probability exactly `(L / P) ^ H`. +* `Cslib.Probability.card_retentionSlice`: the slice has `#frames · L ^ H` channels. + +## References + +* [OpenAI, *Exact Derandomization of Logarithmic Space: L = RL = BPL*][OpenAI2026LogSpace] +-/ + +public section + +namespace Cslib.Probability + +open Finset Matrix +open scoped BigOperators + +variable (P H r : ℕ) + +/-- A **frame**: an ordered linearly independent family of `r` vectors in `ZMod P ^ H`. -/ +abbrev Frame : Type := + {F : Fin r → Fin H → ZMod P // LinearIndependent (ZMod P) F} + +/-- Linear independence of a finite family over `ZMod P` is decided by testing all +coefficient vectors. -/ +instance [NeZero P] : Fintype (Frame P H r) := + haveI : DecidablePred fun F : Fin r → Fin H → ZMod P ↦ LinearIndependent (ZMod P) F := fun F ↦ + decidable_of_iff (∀ g : Fin r → ZMod P, ∑ i, g i • F i = 0 → ∀ i, g i = 0) + Fintype.linearIndependent_iff.symm + Subtype.fintype _ + +variable {P H r} + +/-- For `r ≤ H` the first `r` standard basis vectors form a frame. -/ +theorem Frame.nonempty (hr : r ≤ H) : Nonempty (Frame P H r) := + ⟨⟨Pi.basisFun (ZMod P) (Fin H) ∘ Fin.castLE hr, + (Pi.basisFun (ZMod P) (Fin H)).linearIndependent.comp _ (Fin.castLE_injective hr)⟩⟩ + +/-- An integer matrix of determinant one, reduced modulo `P`, maps frames to frames, column by +column. -/ +@[expose] def Frame.mapSL (g : SpecialLinearGroup (Fin H) ℤ) : Frame P H r ≃ Frame P H r := + let e := SpecialLinearGroup.toLin' (SpecialLinearGroup.map (Int.castRingHom (ZMod P)) g) + Equiv.subtypeEquiv (Equiv.piCongrRight fun _ ↦ e.toEquiv) fun _ ↦ + (e.toLinearMap.linearIndependent_iff e.ker).symm + +@[simp] +theorem Frame.mapSL_apply (g : SpecialLinearGroup (Fin H) ℤ) (F : Frame P H r) (j : Fin r) : + (Frame.mapSL g F).1 j = (SpecialLinearGroup.map (Int.castRingHom (ZMod P)) g : Matrix _ _ _) + *ᵥ F.1 j := + rfl + +variable (P H r) + +/-- A **frame-conditioned channel**: a constant column and a frame. -/ +abbrev FrameChannel : Type := + (Fin H → ZMod P) × Frame P H r + +variable {P H r} + +/-- The value `a₀ + ∑ j, y ^ (j + 1) • F j` of the channel `A = (a₀, F)` at the identifier +`y`. -/ +@[expose] def FrameChannel.eval (A : FrameChannel P H r) (y : ZMod P) : Fin H → ZMod P := + A.1 + ∑ j : Fin r, y ^ (j.val + 1) • A.2.1 j + +/-- **Coordinates of a channel at `y`**: its value at `y` and its frame. The constant column is +recovered as the value minus the frame part. -/ +@[expose] def FrameChannel.evalEquiv (y : ZMod P) : + FrameChannel P H r ≃ (Fin H → ZMod P) × Frame P H r where + toFun A := (A.eval y, A.2) + invFun p := (p.1 - ∑ j : Fin r, y ^ (j.val + 1) • p.2.1 j, p.2) + left_inv A := by simp [FrameChannel.eval] + right_inv p := by simp [FrameChannel.eval] + +@[simp] +theorem FrameChannel.evalEquiv_apply (y : ZMod P) (A : FrameChannel P H r) : + FrameChannel.evalEquiv y A = (A.eval y, A.2) := + rfl + +variable {L : ℕ} [NeZero P] + +/-- **Frame-conditioned retention rate**: for `r ≤ H` and `L ≤ P`, a uniformly random +frame-conditioned channel retains every identifier `y` with probability exactly +`(L / P) ^ H`. -/ +theorem dens_eval_mem_retentionBox (hr : r ≤ H) (hL : L ≤ P) (y : ZMod P) : + dens {A : FrameChannel P H r | A.eval y ∈ retentionBox P H L} = ((L : ℚ≥0) / P) ^ H := by + have := Frame.nonempty (P := P) hr + have hcard : #{A : FrameChannel P H r | A.eval y ∈ retentionBox P H L} = + L ^ H * Fintype.card (Frame P H r) := by + rw [← card_retentionBox (H := H) hL, ← card_univ (α := Frame P H r), ← card_product] + refine card_bij (fun A _ ↦ FrameChannel.evalEquiv y A) (fun A hA ↦ ?_) + (fun _ _ _ _ h ↦ (FrameChannel.evalEquiv y).injective h) fun p hp ↦ ?_ + · simpa using hA + · refine ⟨(FrameChannel.evalEquiv y).symm p, ?_, by simp⟩ + have : ((FrameChannel.evalEquiv y).symm p).eval y = p.1 := by + simp [FrameChannel.evalEquiv, FrameChannel.eval] + simpa [this] using (mem_product.1 hp).1 + have hpos : (0 : ℚ≥0) < Fintype.card (Frame P H r) := by exact_mod_cast Fintype.card_pos + rw [dens, hcard, Fintype.card_prod, Fintype.card_fun, Fintype.card_fin, ZMod.card, div_pow] + push_cast + rw [mul_div_mul_right _ _ hpos.ne'] + +variable (P H r L) + +/-- The **retention slice** of `y`: the frame-conditioned channels retaining `y`. -/ +abbrev RetentionSlice (y : ZMod P) : Type := + {A : FrameChannel P H r // A.eval y ∈ retentionBox P H L} + +variable {P H r L} + +/-- The retention box `{0, …, L - 1} ^ H` in `ZMod P ^ H` is `ZMod L ^ H` for `L ≤ P`, by +reading representatives. -/ +@[expose] def retentionBoxEquiv [NeZero L] (hL : L ≤ P) : + {w : Fin H → ZMod P // w ∈ retentionBox P H L} ≃ (Fin H → ZMod L) where + toFun w i := ((w.1 i).val : ZMod L) + invFun u := ⟨fun i ↦ ((u i).val : ZMod P), by + simp only [mem_retentionBox] + intro i + rw [ZMod.val_cast_of_lt ((ZMod.val_lt _).trans_le hL)] + exact ZMod.val_lt _⟩ + left_inv w := by + have hw := w.2 + simp only [mem_retentionBox] at hw + ext i + simp only + rw [ZMod.val_cast_of_lt (hw i), ZMod.natCast_zmod_val] + right_inv u := by + ext i + simp only + rw [ZMod.val_cast_of_lt ((ZMod.val_lt _).trans_le hL), ZMod.natCast_zmod_val] + +@[simp] +theorem retentionBoxEquiv_apply [NeZero L] (hL : L ≤ P) + (w : {w : Fin H → ZMod P // w ∈ retentionBox P H L}) (i : Fin H) : + retentionBoxEquiv hL w i = ((w.1 i).val : ZMod L) := + rfl + +@[simp] +theorem retentionBoxEquiv_symm_apply [NeZero L] (hL : L ≤ P) (u : Fin H → ZMod L) (i : Fin H) : + ((retentionBoxEquiv hL).symm u).1 i = ((u i).val : ZMod P) := + rfl + +/-- **Coordinates on a retention slice**: a channel retaining `y` is its frame together with its +value at `y`, which ranges over the whole box `ZMod L ^ H`. -/ +@[expose] def sliceEquiv [NeZero L] (hL : L ≤ P) (y : ZMod P) : + RetentionSlice P H r L y ≃ Frame P H r × (Fin H → ZMod L) := + ((FrameChannel.evalEquiv y).subtypeEquiv (p := fun A ↦ A.eval y ∈ retentionBox P H L) + (q := fun p ↦ p.1 ∈ retentionBox P H L) fun _ ↦ Iff.rfl).trans <| + (Equiv.prodSubtypeFstEquivSubtypeProd (p := (· ∈ retentionBox P H L))).trans <| + ((retentionBoxEquiv hL).prodCongr (Equiv.refl _)).trans (Equiv.prodComm _ _) + +@[simp] +theorem sliceEquiv_apply [NeZero L] (hL : L ≤ P) (y : ZMod P) (A : RetentionSlice P H r L y) : + sliceEquiv hL y A = (A.1.2, fun i ↦ ((A.1.eval y i).val : ZMod L)) := + rfl + +/-- The frame of a channel is its frame coordinate on the slice. -/ +@[simp] +theorem sliceEquiv_symm_apply_snd [NeZero L] (hL : L ≤ P) (y : ZMod P) + (p : Frame P H r × (Fin H → ZMod L)) : ((sliceEquiv hL y).symm p).1.2 = p.1 := by + have h := congrArg Prod.fst ((sliceEquiv hL y).apply_symm_apply p) + rwa [sliceEquiv_apply] at h + +/-- The value at `y` of the channel with coordinates `(F, w)` is `w`, read in `ZMod P`. -/ +@[simp] +theorem eval_sliceEquiv_symm [NeZero L] (hL : L ≤ P) (y : ZMod P) + (p : Frame P H r × (Fin H → ZMod L)) (i : Fin H) : + ((sliceEquiv hL y).symm p).1.eval y i = ((p.2 i).val : ZMod P) := by + have h := congrArg (fun q ↦ q.2 i) ((sliceEquiv hL y).apply_symm_apply p) + simp only [sliceEquiv_apply] at h + rw [← h, ZMod.val_cast_of_lt (mem_retentionBox.1 ((sliceEquiv hL y).symm p).2 i), + ZMod.natCast_zmod_val] + +/-- A retention slice has `#frames · L ^ H` channels. -/ +theorem card_retentionSlice [NeZero L] (hL : L ≤ P) (y : ZMod P) : + Fintype.card (RetentionSlice P H r L y) = Fintype.card (Frame P H r) * L ^ H := by + rw [Fintype.card_congr (sliceEquiv hL y), Fintype.card_prod, Fintype.card_fun, + Fintype.card_fin, ZMod.card] + +end Cslib.Probability diff --git a/Complexity/Probability/PairwiseIndependentHash/RetentionChannel.lean b/Complexity/Probability/PairwiseIndependentHash/RetentionChannel.lean index b890a5bad..99d023615 100644 --- a/Complexity/Probability/PairwiseIndependentHash/RetentionChannel.lean +++ b/Complexity/Probability/PairwiseIndependentHash/RetentionChannel.lean @@ -50,6 +50,7 @@ only for the later averaging walks, so they are not needed here. ## Main results +* `Cslib.Probability.mem_retentionBox`: membership in the box, coordinatewise. * `Cslib.Probability.card_retentionBox`: the box has `L ^ H` points. * `Cslib.Probability.dens_affineRetains`, `Cslib.Probability.dens_affineRetains_and`: exact retention probabilities of one identifier and of two distinct ones. @@ -91,6 +92,11 @@ def retentionBox : Finset (Fin H → ZMod P) := variable {P H L} +/-- A vector lies in the retention box when each coordinate has representative less than `L`. -/ +@[simp] +theorem mem_retentionBox {v : Fin H → ZMod P} : v ∈ retentionBox P H L ↔ ∀ j, (v j).val < L := by + simp [retentionBox] + /-- `L` residues of `ZMod P` have representatives less than `L ≤ P`. -/ private theorem card_filter_val_lt (hL : L ≤ P) : #{a : ZMod P | a.val < L} = L := by have himage : ({a : ZMod P | a.val < L} : Finset (ZMod P)).image ZMod.val = range L := by diff --git a/ComplexityTests/ConditionalAveraging.lean b/ComplexityTests/ConditionalAveraging.lean new file mode 100644 index 000000000..72e7b8b5c --- /dev/null +++ b/ComplexityTests/ConditionalAveraging.lean @@ -0,0 +1,91 @@ +/- +Copyright (c) 2026 Christian Reitwiessner. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Christian Reitwiessner +-/ + +import Complexity.Probability.PairwiseIndependentHash.ConditionalAveraging +import Complexity.Foundations.Combinatorics.Expander.AffinePlane + +/-! +# Frame-conditioned channels and conditional averaging + +Frames over `𝔽₃` are counted directly, and a frame-conditioned channel over `𝔽₃` retains an +identifier at rate `2 / 3`, confirmed by a direct count of its six channels. + +Over `𝔽₅` with side `L = 3`, the shear `g = [[1, 1], [0, 1]]` and translation `c = (1, 0)` move +the value `w = (2, 2)` to `g w + c = (5, 2)`. The unique valid wrap is `z = (-1, 0)`, and the +variant it selects is the affine move `(5, 2) mod 3 = (2, 2)`. The wrap `z = 0` fails the integer +test even though its variant also lands in the retention box (`5 mod 5 = 0`): the retention test +alone does not identify the move. + +The conditional-averaging bound is applied to the affine-plane expander over `𝔽₃`, transported +to slice coordinates, which discharges its spectral hypothesis on every slice. +-/ + +namespace ComplexityTests.ConditionalAveraging + +open Cslib Cslib.Probability Finset Matrix +open scoped BigOperators + +private instance : Fact (Nat.Prime 3) := ⟨Nat.prime_three⟩ +private instance : Fact (Nat.Prime 5) := ⟨Nat.prime_five⟩ + +-- The nonzero vectors of `𝔽₃ ^ 2` are its frames of length one. +example : Fintype.card (Frame 3 2 1) = 8 := by decide + +-- Frame conditioning keeps the exact rate: `2 / 3` over `𝔽₃` with side `2`. +example (y : ZMod 3) : dens {A : FrameChannel 3 1 1 | A.eval y ∈ retentionBox 3 1 2} = 2 / 3 := by + rw [dens_eval_mem_retentionBox le_rfl (by norm_num)] + norm_num + +-- A direct count: `4` of the `6` channels retain the identifier `2`. +example : #{A : FrameChannel 3 1 1 | A.eval 2 ∈ retentionBox 3 1 2} = 4 := by decide + +/-- The shear `[[1, 1], [0, 1]]`. -/ +private def shear : SpecialLinearGroup (Fin 2) ℤ := + ⟨!![1, 1; 0, 1], by simp [det_fin_two]⟩ + +/-- A frame-conditioned channel over `𝔽₅` with value `(2, 2)` at `y = 1`. -/ +private def chan : FrameChannel 5 2 1 := + (![1, 2], ⟨![![1, 0]], linearIndependent_unique_iff.2 (by decide)⟩) + +example : chan.eval 1 = ![2, 2] := by decide + +-- The valid wrap is `-⌊(5, 2) / 3⌋ = (-1, 0)`; it passes the integer test, and `0` does not. +example : wrap 3 shear ![1, 0] (chan.eval 1) = ![-1, 0] := by decide +example : IsValidWrap 3 shear ![1, 0] ![-1, 0] (chan.eval 1) := by decide +example : ¬ IsValidWrap 3 shear ![1, 0] 0 (chan.eval 1) := by decide + +-- The valid variant gives the affine move `(5, 2) mod 3 = (2, 2)`. +example : (variantMove 3 shear ![1, 0] ![-1, 0] chan).eval 1 = ![2, 2] := by decide + +-- The wrap `0` also lands in the retention box, at the wrong value `(0, 2)`. +example : (variantMove 3 shear ![1, 0] 0 chan).eval 1 = ![0, 2] := by decide +example : (variantMove 3 shear ![1, 0] 0 chan).eval 1 ∈ retentionBox 5 2 3 := by decide + +-- Wraps of every side length lie in the box `|zᵢ| ≤ ∑ⱼ |gᵢⱼ| + |cᵢ|`. +example : |wrap 3 shear ![1, 0] (chan.eval 1) 0| ≤ 3 := + (abs_wrap_le shear ![1, 0] (by decide) 0).trans (by decide) + +/-- With no frame coordinates, slice coordinates in `𝔽₃ ^ 2` are the affine plane over `𝔽₃`. -/ +private def planeEquiv : Frame 5 2 0 × (Fin 2 → ZMod 3) ≃ ZMod 3 × ZMod 3 := + haveI : Unique (Frame 5 2 0) := + { default := ⟨![], linearIndependent_empty_type⟩ + uniq := fun _ ↦ Subsingleton.elim _ _ } + (Equiv.uniqueProd _ _).trans (finTwoArrowEquiv _) + +-- Conditional averaging with the affine-plane gap `√(1 / 3)`: on the slice of every identifier, +-- `t` steps contract the conditional variance by `(1 / 3) ^ t`. +example (y : ZMod 5) (f : RetentionSlice 5 2 0 3 y → ℝ) (t : ℕ) : + 𝔼 A, (((sliceGraph 3 (by norm_num) y + ((RotationMap.affinePlane (ZMod 3)).reindex planeEquiv.symm)).walk ^ t) f A - + 𝔼 B, f B) ^ 2 ≤ (1 / 3) ^ t * 𝔼 A, (f A - 𝔼 B, f B) ^ 2 := by + have hG : ((RotationMap.affinePlane (ZMod 3)).reindex planeEquiv.symm).spectralExpansion ≤ + Real.sqrt (1 / 3) := by + rw [RotationMap.spectralExpansion_reindex] + simpa using RotationMap.spectralExpansion_affinePlane_le (ZMod 3) + have h := expect_walk_pow_sliceGraph_sub_expect_sq_le (by norm_num) _ hG y f t + rwa [pow_mul, Real.sq_sqrt (by norm_num)] at h + +end ComplexityTests.ConditionalAveraging diff --git a/references.bib b/references.bib index ec215b3f7..652d3cc22 100644 --- a/references.bib +++ b/references.bib @@ -3461,6 +3461,15 @@ @misc{OpenAI2026ETH url = {https://github.com/openai/math/blob/7ef5c0cc5ca4b0e072b7a050fca09ab24bc6fa3a/preprints/The-Exponential-Time-Hypothesis-is-False-October-25-2026/paper.pdf} } +@misc{OpenAI2026LogSpace, + author = {{OpenAI}}, + title = {Exact Derandomization of Logarithmic Space: {L} = {RL} = {BPL}}, + year = {2026}, + howpublished = {Preprint}, + note = {Dated 23 September 2026, not peer reviewed; source revision 7ef5c0cc5ca4b0e072b7a050fca09ab24bc6fa3a}, + url = {https://github.com/openai/math/blob/7ef5c0cc5ca4b0e072b7a050fca09ab24bc6fa3a/preprints/Exact-Derandomization-of-Logarithmic-Space-L-equals-RL-equals-BPL-September-23-2026/paper.pdf} +} + @misc{OpenAI2026RationalHitting, author = {{OpenAI}}, title = {{Rational} matrix hitting lists for noncommutative rational formulas}, From a9e19a53af621145b590444bffda63a695adc5ad Mon Sep 17 00:00:00 2001 From: Christian Reitwiessner Date: Fri, 30 Oct 2026 00:51:23 +0000 Subject: [PATCH 07/13] =?UTF-8?q?feat(Expander):=20Poincar=C3=A9=20inequal?= =?UTF-8?q?ities=20and=20spectral=20gaps=20of=20box=20products=20of=20perm?= =?UTF-8?q?utation=20multigraphs=20(#1682)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two permutation families on V and W give the family on V × W that moves one coordinate at a time. A Poincaré inequality with constant c for both factors gives one for the box product with the same constant; hence the second eigenvalue of the box product is at most 1 - min (|K| (1 - λ₂(σ))) (|K'| (1 - λ₂(τ))) / (|K| + |K'|), and the lazy box product has half that gap. This is the product walk over components of Lemma 6.2 of the OpenAI preprint (gap γ/J for J components). Co-Authored-By: Claude Opus 5.5 --- Complexity.lean | 1 + .../Combinatorics/Expander/BoxProduct.lean | 184 ++++++++++++++++++ ComplexityTests/BoxProductExpander.lean | 72 +++++++ 3 files changed, 257 insertions(+) create mode 100644 Complexity/Foundations/Combinatorics/Expander/BoxProduct.lean create mode 100644 ComplexityTests/BoxProductExpander.lean diff --git a/Complexity.lean b/Complexity.lean index 8d2ee4953..322d1a5e1 100644 --- a/Complexity.lean +++ b/Complexity.lean @@ -2354,6 +2354,7 @@ public import Complexity.Foundations.Combinatorics.Expander.AffineFamily public import Complexity.Foundations.Combinatorics.Expander.AffinePlane public import Complexity.Foundations.Combinatorics.Expander.AffineTower public import Complexity.Foundations.Combinatorics.Expander.Basic +public import Complexity.Foundations.Combinatorics.Expander.BoxProduct public import Complexity.Foundations.Combinatorics.Expander.Cayley public import Complexity.Foundations.Combinatorics.Expander.Cheeger public import Complexity.Foundations.Combinatorics.Expander.Connected diff --git a/Complexity/Foundations/Combinatorics/Expander/BoxProduct.lean b/Complexity/Foundations/Combinatorics/Expander/BoxProduct.lean new file mode 100644 index 000000000..f1f9d97ab --- /dev/null +++ b/Complexity/Foundations/Combinatorics/Expander/BoxProduct.lean @@ -0,0 +1,184 @@ +/- +Copyright (c) 2026 Christian Reitwiessner. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Christian Reitwiessner +-/ + +module +-- upstream: candidate + +public import Complexity.Foundations.Combinatorics.Expander.Lazy +public import Complexity.Foundations.Combinatorics.Expander.Perm +import Complexity.Foundations.Data.Finset.Expect + +/-! +# Box products of permutation multigraphs + +Two families of permutations `σ : K → Equiv.Perm V` and `τ : K' → Equiv.Perm W` give the family +`boxProdPerms σ τ : K ⊕ K' → Equiv.Perm (V × W)` that moves one coordinate at a time: `σ k` on the +first, `τ k'` on the second. Its multigraph `ofPerms (boxProdPerms σ τ)` is the box (Cartesian) +product of the multigraphs of `σ` and `τ`. Its random walk picks a coordinate, with probability +proportional to the number of its permutations, and takes a step there. + +A Poincaré inequality with constant `c` for both families gives one for the product with the same +constant (`mul_expect_sq_le_boxProdPerms`). The proof splits a function of expectation zero on +`V × W` orthogonally into its averages over the fibers `{v} × W` and a part of average zero on every +fiber. The second family controls the fiber part, and the first controls the fiber averages, whose +changes along `σ` are at most the averages of the changes of the function (Jensen). This is the +two-factor case of the tensorization of the spectral gap of product chains: the gap of the product +walk is at least the smaller of the gaps of the factors, weighted by their shares of the degree +(`secondEigenvalue_ofPerms_boxProdPerms_le`). For `J` factors of equal degree and gap `γ`, iterating +gives the gap `γ / J`. This is the walk that the OpenAI preprint on derandomizing logarithmic space +applies to a uniformly selected component of its sampling environment, with gap `γ / J` for `J` +components [OpenAI, proof of Lemma 6.2][OpenAI2026LogSpace]; the statements and proofs here are +ours. + +## Main definitions + +* `Cslib.RotationMap.boxProdPerms`: the permutations of `V × W` that move one coordinate. + +## Main results + +* `Cslib.RotationMap.mul_expect_sq_le_boxProdPerms`: Poincaré inequalities for the two factors give + one for the box product, with the same constant. +* `Cslib.RotationMap.secondEigenvalue_ofPerms_boxProdPerms_le`: the second eigenvalue of the box + product, `λ₂ ≤ 1 - min (|K| (1 - λ₂(σ))) (|K'| (1 - λ₂(τ))) / (|K| + |K'|)`. +* `Cslib.RotationMap.spectralExpansion_lazy_ofPerms_boxProdPerms_le`: the same bound, halved, for + the spectral expansion of the lazy box product. + +## References + +* [OpenAI, *Exact Derandomization of Logarithmic Space: L = RL = BPL*][OpenAI2026LogSpace] +-/ + +public section + +namespace Cslib.RotationMap + +open Finset +open scoped BigOperators + +variable {V W K K' : Type*} + +/-- The permutations of `V × W` that move one coordinate: `σ k` on the first, `τ k'` on the second. +Their multigraph is the box product of the multigraphs of `σ` and `τ`. -/ +@[expose] +def boxProdPerms (σ : K → Equiv.Perm V) (τ : K' → Equiv.Perm W) : K ⊕ K' → Equiv.Perm (V × W) := + Sum.elim (fun k ↦ (σ k).prodCongr (Equiv.refl W)) fun k ↦ (Equiv.refl V).prodCongr (τ k) + +variable (σ : K → Equiv.Perm V) (τ : K' → Equiv.Perm W) + +@[simp] +theorem boxProdPerms_inl (k : K) (p : V × W) : boxProdPerms σ τ (.inl k) p = (σ k p.1, p.2) := rfl + +@[simp] +theorem boxProdPerms_inr (k : K') (p : V × W) : boxProdPerms σ τ (.inr k) p = (p.1, τ k p.2) := rfl + +variable [Fintype V] [Fintype W] [Fintype K] [Fintype K'] + +variable {σ τ} in +/-- **Poincaré inequalities tensorize**: if both families satisfy the Poincaré +inequality `c 𝔼 f² ≤ ∑ k, 𝔼 v, (f (σ k v) - f v) ^ 2` for every function `f` of expectation zero, +then so does their box product, with the same constant. -/ +theorem mul_expect_sq_le_boxProdPerms {c : ℝ} + (hσ : ∀ f : V → ℝ, 𝔼 v, f v = 0 → c * 𝔼 v, f v ^ 2 ≤ ∑ k, 𝔼 v, (f (σ k v) - f v) ^ 2) + (hτ : ∀ g : W → ℝ, 𝔼 w, g w = 0 → c * 𝔼 w, g w ^ 2 ≤ ∑ k, 𝔼 w, (g (τ k w) - g w) ^ 2) + (f : V × W → ℝ) (hf : 𝔼 p, f p = 0) : + c * 𝔼 p, f p ^ 2 ≤ ∑ k, 𝔼 p, (f (boxProdPerms σ τ k p) - f p) ^ 2 := by + rcases isEmpty_or_nonempty W with hW | hW + · simp + -- The fiber averages `g` and the decomposition `𝔼 f² = 𝔼 g² + 𝔼 (f - g)²`. + set g : V → ℝ := fun v ↦ 𝔼 w, f (v, w) with hg + have hsplit : 𝔼 p, f p ^ 2 = 𝔼 v, g v ^ 2 + 𝔼 v, 𝔼 w, (f (v, w) - g v) ^ 2 := by + have h := Fintype.expect_add_sq_of_expect_fiber_eq_zero g + (g := fun p ↦ f p - g p.1) (Fintype.expect_sub_expect_fiber f) + simpa only [add_sub_cancel, Fintype.expect_prod_type, Fintype.expect_const] using h + -- The second family controls the parts of average zero on the fibers. + have hfib (v : V) : + c * 𝔼 w, (f (v, w) - g v) ^ 2 ≤ ∑ k, 𝔼 w, (f (v, τ k w) - f (v, w)) ^ 2 := by + have := hτ (fun w ↦ f (v, w) - g v) (Fintype.expect_sub_expect_fiber f v) + simpa only [sub_sub_sub_cancel_right] using this + -- The first family controls the fiber averages, by Jensen's inequality. + have hg0 : 𝔼 v, g v = 0 := by rw [← Fintype.expect_prod_type]; exact hf + have hjensen (k : K) (v : V) : (g (σ k v) - g v) ^ 2 ≤ 𝔼 w, (f (σ k v, w) - f (v, w)) ^ 2 := by + simpa only [hg, expect_sub_distrib] using + sq_expect_le_expect_sq univ fun w ↦ f (σ k v, w) - f (v, w) + calc c * 𝔼 p, f p ^ 2 + = c * 𝔼 v, g v ^ 2 + 𝔼 v, c * 𝔼 w, (f (v, w) - g v) ^ 2 := by + rw [hsplit, mul_add, mul_expect _ fun v ↦ 𝔼 w, (f (v, w) - g v) ^ 2] + _ ≤ ∑ k, 𝔼 v, (g (σ k v) - g v) ^ 2 + 𝔼 v, ∑ k, 𝔼 w, (f (v, τ k w) - f (v, w)) ^ 2 := + add_le_add (hσ g hg0) (expect_le_expect fun v _ ↦ hfib v) + _ ≤ ∑ k, 𝔼 v, 𝔼 w, (f (σ k v, w) - f (v, w)) ^ 2 + + 𝔼 v, ∑ k, 𝔼 w, (f (v, τ k w) - f (v, w)) ^ 2 := by + gcongr with k _ v + exact hjensen k v + _ = ∑ k, 𝔼 p, (f (boxProdPerms σ τ k p) - f p) ^ 2 := by + rw [Fintype.sum_sum_type, expect_sum_comm] + simp only [boxProdPerms_inl, boxProdPerms_inr, Fintype.expect_prod_type] + +/-- A bound on the second eigenvalue of a permutation multigraph gives a Poincaré inequality for +its permutations, with constant `2 |K| (1 - λ₂)`. -/ +private theorem mul_expect_sq_le_of_secondEigenvalue [Nonempty K] (σ : K → Equiv.Perm V) + (f : V → ℝ) (hf : 𝔼 v, f v = 0) : + 2 * Fintype.card K * (1 - (ofPerms σ).secondEigenvalue) * 𝔼 v, f v ^ 2 ≤ + ∑ k, 𝔼 v, (f (σ k v) - f v) ^ 2 := by + have hK : (0 : ℝ) < 2 * Fintype.card K := by + have := Fintype.card_pos (α := K) + positivity + have h := (ofPerms σ).expect_mul_walk_le_secondEigenvalue_mul hf + rw [expect_mul_walk_ofPerms] at h + have := mul_le_mul_of_nonneg_left h hK.le + rw [mul_sub, mul_div_cancel₀ _ hK.ne'] at this + linarith + +/-- **The spectral gap of a box product**: the second eigenvalue of the box product of two +permutation multigraphs is at most +`1 - min (|K| (1 - λ₂(σ))) (|K'| (1 - λ₂(τ))) / (|K| + |K'|)`. For factors with the same number of +permutations, the gap is at least half the smaller gap of the factors. -/ +theorem secondEigenvalue_ofPerms_boxProdPerms_le [Nonempty K] [Nonempty K'] : + (ofPerms (boxProdPerms σ τ)).secondEigenvalue ≤ + 1 - min (Fintype.card K * (1 - (ofPerms σ).secondEigenvalue)) + (Fintype.card K' * (1 - (ofPerms τ).secondEigenvalue)) / + (Fintype.card K + Fintype.card K') := by + set a : ℝ := Fintype.card K * (1 - (ofPerms σ).secondEigenvalue) + set b : ℝ := Fintype.card K' * (1 - (ofPerms τ).secondEigenvalue) + have hKK : (0 : ℝ) < Fintype.card K + Fintype.card K' := by + have := Fintype.card_pos (α := K) + positivity + rcases subsingleton_or_nontrivial (V × W) with hV | hV + · -- On at most one vertex `λ₂ = 0`, and the bound is nonnegative as `λ₂ ≥ -1` for the factors. + rw [secondEigenvalue_eq_zero_of_subsingleton, sub_nonneg, div_le_one hKK] + have ha2 : a ≤ 2 * Fintype.card K := by + have := (ofPerms σ).neg_one_le_secondEigenvalue + have : (0 : ℝ) ≤ Fintype.card K := Nat.cast_nonneg _ + simp only [a] + nlinarith + have hb2 : b ≤ 2 * Fintype.card K' := by + have := (ofPerms τ).neg_one_le_secondEigenvalue + have : (0 : ℝ) ≤ Fintype.card K' := Nat.cast_nonneg _ + simp only [b] + nlinarith + linarith [min_le_left a b, min_le_right a b] + have h := secondEigenvalue_ofPerms_le (boxProdPerms σ τ) (c := 2 * min a b) fun f hf ↦ + mul_expect_sq_le_boxProdPerms + (fun g hg ↦ (mul_le_mul_of_nonneg_right (by linarith [min_le_left a b]) + (expect_nonneg fun _ _ ↦ sq_nonneg _)).trans (mul_expect_sq_le_of_secondEigenvalue σ g hg)) + (fun g hg ↦ (mul_le_mul_of_nonneg_right (by linarith [min_le_right a b]) + (expect_nonneg fun _ _ ↦ sq_nonneg _)).trans (mul_expect_sq_le_of_secondEigenvalue τ g hg)) + f hf + refine h.trans_eq ?_ + rw [Fintype.card_sum, Nat.cast_add, mul_div_mul_left _ _ two_ne_zero] + +/-- **The lazy box product is an expander** when both factors are: its spectral expansion is at most +`1 - min (|K| (1 - λ₂(σ))) (|K'| (1 - λ₂(τ))) / (2 (|K| + |K'|))`. -/ +theorem spectralExpansion_lazy_ofPerms_boxProdPerms_le [Nonempty K] [Nonempty K'] : + (ofPerms (boxProdPerms σ τ)).lazy.spectralExpansion ≤ + 1 - min (Fintype.card K * (1 - (ofPerms σ).secondEigenvalue)) + (Fintype.card K' * (1 - (ofPerms τ).secondEigenvalue)) / + (2 * (Fintype.card K + Fintype.card K')) := by + have h₁ := (ofPerms (boxProdPerms σ τ)).spectralExpansion_lazy_le_one_add_secondEigenvalue_div_two + have h₂ := secondEigenvalue_ofPerms_boxProdPerms_le σ τ + rw [div_mul_eq_div_div_swap] + linarith + +end Cslib.RotationMap diff --git a/ComplexityTests/BoxProductExpander.lean b/ComplexityTests/BoxProductExpander.lean new file mode 100644 index 000000000..866938cae --- /dev/null +++ b/ComplexityTests/BoxProductExpander.lean @@ -0,0 +1,72 @@ +/- +Copyright (c) 2026 Christian Reitwiessner. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Christian Reitwiessner +-/ + +import Complexity.Foundations.Combinatorics.Expander.BoxProduct +import Complexity.Foundations.Combinatorics.Expander.ShearTranslation + +/-! +# Box products of permutation multigraphs + +Concrete moves of a box product, the Poincaré inequality for the box product of two copies of the +two-point walk, and a uniform spectral gap for the box product of two shear-translation graphs of +unrelated sizes, with every hypothesis discharged. +-/ + +namespace ComplexityTests.BoxProductExpander + +open Cslib Cslib.RotationMap Finset +open scoped BigOperators + +-- A move of the first factor leaves the second coordinate alone, and vice versa. +example : boxProdPerms (shearTranslationMove 5) (shearTranslationMove 3) (.inl 0) + ((1, 2), (2, 2)) = ((3, 2), (2, 2)) := by decide +example : boxProdPerms (shearTranslationMove 5) (shearTranslationMove 3) (.inr 1) + ((1, 2), (2, 2)) = ((1, 2), (2, 1)) := by decide + +/-- The flip of `ZMod 2`. -/ +abbrev flip : Unit → Equiv.Perm (ZMod 2) := fun _ ↦ Equiv.addRight 1 + +/-- The two-point walk satisfies the Poincaré inequality with constant `4`, with equality. -/ +theorem poincare_flip (f : ZMod 2 → ℝ) (hf : 𝔼 v, f v = 0) : + 4 * 𝔼 v, f v ^ 2 ≤ ∑ k, 𝔼 v, (f (flip k v) - f v) ^ 2 := by + have hsum (g : ZMod 2 → ℝ) : ∑ v, g v = g 0 + g 1 := Fin.sum_univ_two g + simp only [Fintype.expect_eq_sum_div_card, ZMod.card, hsum, Fintype.univ_unit, sum_singleton, + flip, Equiv.coe_addRight] at hf ⊢ + have h1 : f 1 = -f 0 := by linarith [(div_eq_zero_iff.1 hf).resolve_right (by norm_num)] + have e1 : (1 : ZMod 2) + 1 = 0 := rfl + rw [zero_add, e1, h1] + nlinarith [sq_nonneg (f 0)] + +/-- The square `ZMod 2 × ZMod 2`, the box product of two edges, inherits the constant `4`. -/ +example (f : ZMod 2 × ZMod 2 → ℝ) (hf : 𝔼 p, f p = 0) : + 4 * 𝔼 p, f p ^ 2 ≤ ∑ k, 𝔼 p, (f (boxProdPerms flip flip k p) - f p) ^ 2 := + mul_expect_sq_le_boxProdPerms poincare_flip poincare_flip f hf + +/-- **A uniform gap for a product of two components**: the lazy box product of the +shear-translation graphs on `ZMod n × ZMod n` and `ZMod m × ZMod m` has spectral expansion at most +`1 - 1 / 16384`, for all `n` and `m`. -/ +example (n m : ℕ) [NeZero n] [NeZero m] : + spectralExpansion + (ofPerms (boxProdPerms (shearTranslationMove n) (shearTranslationMove m))).lazy ≤ + 1 - 1 / 16384 := by + have h := spectralExpansion_lazy_ofPerms_boxProdPerms_le (shearTranslationMove n) + (shearTranslationMove m) + have hn := secondEigenvalue_shearTranslation_le n + have hm := secondEigenvalue_shearTranslation_le m + rw [shearTranslation] at hn hm + simp only [Fintype.card_fin, Nat.cast_ofNat] at h + have hmin : 4 * (1 / 4096 : ℝ) ≤ + min (4 * (1 - (ofPerms (shearTranslationMove n)).secondEigenvalue)) + (4 * (1 - (ofPerms (shearTranslationMove m)).secondEigenvalue)) := + le_min (by linarith) (by linarith) + have : 4 * (1 / 4096 : ℝ) / (2 * (4 + 4)) ≤ + min (4 * (1 - (ofPerms (shearTranslationMove n)).secondEigenvalue)) + (4 * (1 - (ofPerms (shearTranslationMove m)).secondEigenvalue)) / (2 * (4 + 4)) := by + gcongr + norm_num at this ⊢ + linarith + +end ComplexityTests.BoxProductExpander From 40d6f146b4f3a5c872eb23b323ae549501d11684 Mon Sep 17 00:00:00 2001 From: Christian Reitwiessner Date: Fri, 30 Oct 2026 01:02:41 +0000 Subject: [PATCH 08/13] =?UTF-8?q?feat(Expander):=20relative=20Poincar?= =?UTF-8?q?=C3=A9=20inequality=20for=20shears=20and=20translations=20with?= =?UTF-8?q?=20a=20spectator=20(#1682)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From the uniform Poincaré inequality of the shear-translation graph: - on the frequencies: for Φ vanishing at 0, its mass is at most 512 times its changes along the dual unit shears plus its mass weighted by the translation weights ‖e(ξᵢ) - 1‖² (via the bijectivity of dftProd); - with a spectator: when the shears also permute a finite set X and the translations fix it, every function on X × (ZMod n × ZMod n) is within 512 times its total squared change of its fiber averages over ZMod n × ZMod n (complex sums and real averages). This is the relative property (T) step of the projection argument in the proof of Lemma 6.1 of the OpenAI preprint, step (A) of the frame-lifted gap plan on #1682. Co-Authored-By: Claude Opus 5.5 --- Complexity.lean | 1 + .../Expander/RelativeShearTranslation.lean | 351 ++++++++++++++++++ ComplexityTests/RelativeShearTranslation.lean | 47 +++ 3 files changed, 399 insertions(+) create mode 100644 Complexity/Foundations/Combinatorics/Expander/RelativeShearTranslation.lean create mode 100644 ComplexityTests/RelativeShearTranslation.lean diff --git a/Complexity.lean b/Complexity.lean index 8d2ee4953..e2466576e 100644 --- a/Complexity.lean +++ b/Complexity.lean @@ -2374,6 +2374,7 @@ public import Complexity.Foundations.Combinatorics.Expander.Power public import Complexity.Foundations.Combinatorics.Expander.Random public import Complexity.Foundations.Combinatorics.Expander.Reindex public import Complexity.Foundations.Combinatorics.Expander.Reingold +public import Complexity.Foundations.Combinatorics.Expander.RelativeShearTranslation public import Complexity.Foundations.Combinatorics.Expander.Replacement public import Complexity.Foundations.Combinatorics.Expander.ShearTranslation public import Complexity.Foundations.Combinatorics.Expander.SimpleGraph diff --git a/Complexity/Foundations/Combinatorics/Expander/RelativeShearTranslation.lean b/Complexity/Foundations/Combinatorics/Expander/RelativeShearTranslation.lean new file mode 100644 index 000000000..d96c0046b --- /dev/null +++ b/Complexity/Foundations/Combinatorics/Expander/RelativeShearTranslation.lean @@ -0,0 +1,351 @@ +/- +Copyright (c) 2026 Christian Reitwiessner. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Christian Reitwiessner +-/ + +module +-- upstream: candidate + +public import Complexity.Foundations.Analysis.Fourier.ZModProd +public import Complexity.Foundations.Algebra.Shear +public import Complexity.Foundations.Combinatorics.Expander.ShearTranslation +public import Mathlib.Analysis.InnerProductSpace.PiL2 +-- `import all`: the linearity of `ZMod.dftProd` unfolds its body, and the frequency-side +-- inequality reuses the private Parseval identity for translations, `sum_norm_sq_translate`. +import all Complexity.Foundations.Analysis.Fourier.ZModProd +import all Complexity.Foundations.Combinatorics.Expander.ShearTranslation +import Mathlib.LinearAlgebra.FiniteDimensional.Basic + +/-! +# The relative Poincaré inequality for shears and translations + +The Poincaré inequality for the shear-translation graph on `ZMod n × ZMod n` +(`sum_norm_sq_le_shearTranslation`) has two consequences proved here. + +**On the frequencies.** Through the Fourier transform `ZMod.dftProd`, which is a bijection, the +inequality gives one for an arbitrary function `Φ` on the frequencies that vanishes at +`0` (`sum_norm_sq_le_dual_shearTranslation`). The translations become the weights +`‖e (ξ.1) - 1‖ ^ 2` and `‖e (ξ.2) - 1‖ ^ 2`, and the unit shears become the dual shears by `-1`. + +**With a spectator.** Let the shears act on `X × (ZMod n × ZMod n)` together with permutations +`π₁`, `π₂` of a finite set `X`, while the translations leave `X` fixed +(`twistedShearTranslationMove`). Then every function `f` is close to its averages over the fibers +`{x} × (ZMod n × ZMod n)`: their squared distance is at most `512` times the total squared change +of `f` along the four moves (`sum_norm_sq_sub_fiber_le_twistedShearTranslation`, and +`expect_sq_sub_expect_fiber_le_twistedShearTranslation` for real functions and averages). Unlike a +spectral gap, this does not ask the moves to mix `X`: it is a *relative* Poincaré inequality, which +in a representation-theoretic language says that vectors almost invariant under shears and +translations are close to vectors invariant under the translations. The proof transforms `f` in +the second coordinate, `F x = dftProd (f (x, ·))`, and applies the inequality on the frequencies to +`Φ ξ = ‖F · ξ‖` (the `ℓ²` norm over `X`) for `ξ ≠ 0`. The spectator permutations only reindex +this norm, and the reverse triangle inequality bounds the changes of `Φ` by those of `F`. + +This is the step that turns the uniform gap on `ZMod n × ZMod n` into closeness to the vectors +fixed by the translations of one coordinate pair, as in the projection argument of the OpenAI +preprint on derandomizing logarithmic space for its affine walks +[OpenAI, proof of Lemma 6.1][OpenAI2026LogSpace]. The preprint takes it from Shalom's quantitative +relative property (T) of `(SL₂(ℤ) ⋉ ℤ², ℤ²)`; see also [Burger][Burger1991]. The elementary route +through the uniform Fourier gap is credited in the module of `Cslib.RotationMap.shearTranslation`. +The statements and proofs here are ours. + +## Main definitions + +* `Cslib.RotationMap.twistedShearTranslationMove`: the shears and translations of the second + coordinate of `X × (ZMod n × ZMod n)`, with the shears also permuting `X`. + +## Main results + +* `ZMod.dftProd_add`, `ZMod.dftProd_smul`: the transform is linear. +* `ZMod.dftProd_injective`, `ZMod.dftProd_surjective`: the transform is a bijection. +* `ZMod.sum_norm_sq_dftProd_shearFst_sub`, `ZMod.sum_norm_sq_dftProd_shearSnd_sub`: Parseval's + identity for the difference of two functions, one of them sheared. +* `ZMod.dftProd_const_of_ne_zero`: a constant has no nonzero frequencies. +* `Cslib.RotationMap.sum_norm_sq_le_dual_shearTranslation`: the Poincaré inequality on the + frequencies. +* `Cslib.RotationMap.sum_norm_sq_sub_fiber_le_twistedShearTranslation`, + `Cslib.RotationMap.expect_sq_sub_expect_fiber_le_twistedShearTranslation`: the relative + Poincaré inequality with a spectator. + +## References + +* [OpenAI, *Exact Derandomization of Logarithmic Space: L = RL = BPL*][OpenAI2026LogSpace] +* [M. Burger, *Kazhdan constants for SL(3, ℤ)*][Burger1991] +-/ + +public section + +open Finset +open scoped BigOperators + +namespace ZMod + +variable {N : ℕ} [NeZero N] + +/-- The transform is additive. -/ +theorem dftProd_add (f g : ZMod N × ZMod N → ℂ) : dftProd (f + g) = dftProd f + dftProd g := by + ext ξ + simp only [dftProd, Pi.add_apply, mul_add, sum_add_distrib] + +/-- The transform is homogeneous. -/ +theorem dftProd_smul (c : ℂ) (f : ZMod N × ZMod N → ℂ) : dftProd (c • f) = c • dftProd f := by + ext ξ + simp only [dftProd, Pi.smul_apply, smul_eq_mul, mul_sum] + exact sum_congr rfl fun _ _ ↦ by ring + +/-- The transform is injective, by Parseval's identity. -/ +theorem dftProd_injective : Function.Injective (dftProd (N := N)) := by + intro f g h + have hP := sum_norm_sq_dftProd (f - g) + rw [dftProd_sub, h, sub_self] at hP + simp only [Pi.zero_apply, norm_zero, ne_eq, OfNat.ofNat_ne_zero, not_false_eq_true, zero_pow, + sum_const_zero] at hP + have hN : (N : ℝ) ^ 2 ≠ 0 := pow_ne_zero _ (Nat.cast_ne_zero.2 (NeZero.ne N)) + have h0 := (mul_eq_zero.1 hP.symm).resolve_left hN + rw [sum_eq_zero_iff_of_nonneg fun _ _ ↦ by positivity] at h0 + funext v + simpa [sub_eq_zero] using h0 v (mem_univ v) + +/-- The transform as a linear map. -/ +private noncomputable def dftProdLinearMap : + (ZMod N × ZMod N → ℂ) →ₗ[ℂ] (ZMod N × ZMod N → ℂ) where + toFun := dftProd + map_add' := dftProd_add + map_smul' := dftProd_smul + +/-- The transform is surjective: an injective linear endomorphism of a finite-dimensional space. -/ +theorem dftProd_surjective : Function.Surjective (dftProd (N := N)) := + LinearMap.injective_iff_surjective.1 (show Function.Injective dftProdLinearMap from + dftProd_injective (N := N)) + +/-- **A constant has no nonzero frequencies**: Parseval's identity puts all of its mass at `0`. -/ +theorem dftProd_const_of_ne_zero (c : ℂ) {ξ : ZMod N × ZMod N} (hξ : ξ ≠ 0) : + dftProd (fun _ ↦ c) ξ = 0 := by + have hP := sum_norm_sq_dftProd (N := N) fun _ ↦ c + rw [← add_sum_erase _ _ (mem_univ (0 : ZMod N × ZMod N)), dftProd_zero] at hP + simp only [sum_const, card_univ, Fintype.card_prod, ZMod.card, nsmul_eq_mul, norm_mul, + Complex.norm_natCast, Nat.cast_mul] at hP + have h0 : ∑ ζ ∈ univ.erase (0 : ZMod N × ZMod N), ‖dftProd (fun _ ↦ c) ζ‖ ^ 2 = 0 := by linarith + rw [sum_eq_zero_iff_of_nonneg fun _ _ ↦ by positivity] at h0 + simpa using h0 ξ (mem_erase.2 ⟨hξ, mem_univ ξ⟩) + +/-- **Parseval's identity for the difference of two functions along the shear** +`(x, y) ↦ (x + k * y, y)`: it acts on the frequencies by the dual shear `(a, b) ↦ (a, b - k * a)`. +-/ +theorem sum_norm_sq_dftProd_shearFst_sub (f g : ZMod N × ZMod N → ℂ) (k : ZMod N) : + ∑ ξ, ‖dftProd f (Cslib.shearSnd (-k) ξ) - dftProd g ξ‖ ^ 2 = + N ^ 2 * ∑ v, ‖f (Cslib.shearFst k v) - g v‖ ^ 2 := by + rw [← sum_norm_sq_dftProd (fun v ↦ f (Cslib.shearFst k v) - g v)] + refine sum_congr rfl fun ξ _ ↦ ?_ + have : (fun v ↦ f (Cslib.shearFst k v) - g v) = (fun v ↦ f (v.1 + k * v.2, v.2)) - g := rfl + rw [this, dftProd_sub, Pi.sub_apply, dftProd_comp_shearFst, Cslib.shearSnd_apply, neg_mul, + ← sub_eq_add_neg] + +/-- **Parseval's identity for the difference of two functions along the shear** +`(x, y) ↦ (x, y + k * x)`: it acts on the frequencies by the dual shear `(a, b) ↦ (a - k * b, b)`. +-/ +theorem sum_norm_sq_dftProd_shearSnd_sub (f g : ZMod N × ZMod N → ℂ) (k : ZMod N) : + ∑ ξ, ‖dftProd f (Cslib.shearFst (-k) ξ) - dftProd g ξ‖ ^ 2 = + N ^ 2 * ∑ v, ‖f (Cslib.shearSnd k v) - g v‖ ^ 2 := by + rw [← sum_norm_sq_dftProd (fun v ↦ f (Cslib.shearSnd k v) - g v)] + refine sum_congr rfl fun ξ _ ↦ ?_ + have : (fun v ↦ f (Cslib.shearSnd k v) - g v) = (fun v ↦ f (v.1, v.2 + k * v.1)) - g := rfl + rw [this, dftProd_sub, Pi.sub_apply, dftProd_comp_shearSnd, Cslib.shearFst_apply, neg_mul, + ← sub_eq_add_neg] + +end ZMod + +namespace Cslib.RotationMap + +variable {n : ℕ} [NeZero n] + +/-- **The Poincaré inequality for shears and translations, on the frequencies**: a function `Φ` on +`ZMod n × ZMod n` vanishing at `0` has squared norm at most `512` times the sum of its squared +changes along the dual unit shears and of its squared norm weighted by the translation weights +`‖e (ξ.1) - 1‖ ^ 2` and `‖e (ξ.2) - 1‖ ^ 2`, where `e = ZMod.stdAddChar`. -/ +theorem sum_norm_sq_le_dual_shearTranslation (Φ : ZMod n × ZMod n → ℂ) (h0 : Φ 0 = 0) : + ∑ ξ, ‖Φ ξ‖ ^ 2 ≤ 512 * (∑ ξ, ‖Φ (shearSnd (-1) ξ) - Φ ξ‖ ^ 2 + + ∑ ξ, ‖Φ (shearFst (-1) ξ) - Φ ξ‖ ^ 2 + + ∑ ξ, ‖ZMod.stdAddChar ξ.1 - 1‖ ^ 2 * ‖Φ ξ‖ ^ 2 + + ∑ ξ, ‖ZMod.stdAddChar ξ.2 - 1‖ ^ 2 * ‖Φ ξ‖ ^ 2) := by + obtain ⟨f, rfl⟩ := ZMod.dftProd_surjective Φ + have hf : ∑ v, f v = 0 := by rwa [ZMod.dftProd_zero] at h0 + have hP := sum_norm_sq_le_shearTranslation f hf + simp only [Fin.sum_univ_four, shearTranslationMove, Matrix.cons_val_zero, Matrix.cons_val_one, + Matrix.cons_val_two, Matrix.cons_val_three, Matrix.head_cons, Matrix.tail_cons, + Equiv.coe_addRight] at hP + have e₁ := ZMod.sum_norm_sq_dftProd_shearFst_sub f f 1 + have e₂ := ZMod.sum_norm_sq_dftProd_shearSnd_sub f f 1 + have e₃ := sum_norm_sq_translate f (1, 0) + have e₄ := sum_norm_sq_translate f (0, 1) + simp only [mul_one, mul_zero, add_zero, zero_add] at e₃ e₄ + have hM := ZMod.sum_norm_sq_dftProd f + have hn : (0 : ℝ) ≤ (n : ℝ) ^ 2 := by positivity + have := mul_le_mul_of_nonneg_left hP hn + rw [hM, e₁, e₂, e₃, e₄] + linarith + +omit [NeZero n] in +/-- Only the zero vector is sheared to zero. -/ +private theorem shearFst_eq_zero_iff (k : ZMod n) (ξ : ZMod n × ZMod n) : + shearFst k ξ = 0 ↔ ξ = 0 := by + have h0 : shearFst k (0 : ZMod n × ZMod n) = 0 := by simp [shearFst_apply] + exact ⟨fun h ↦ (shearFst k).injective (h.trans h0.symm), fun h ↦ h ▸ h0⟩ + +omit [NeZero n] in +private theorem shearSnd_eq_zero_iff (k : ZMod n) (ξ : ZMod n × ZMod n) : + shearSnd k ξ = 0 ↔ ξ = 0 := by + have h0 : shearSnd k (0 : ZMod n × ZMod n) = 0 := by simp [shearSnd_apply] + exact ⟨fun h ↦ (shearSnd k).injective (h.trans h0.symm), fun h ↦ h ▸ h0⟩ + +variable {X : Type*} + +/-- The shears and translations of the second coordinate of `X × (ZMod n × ZMod n)`, with the +shears also permuting the spectator coordinate: `(x, w) ↦ (π₁ x, shearFst 1 w)`, +`(x, w) ↦ (π₂ x, shearSnd 1 w)`, `(x, w) ↦ (x, w + (1, 0))` and `(x, w) ↦ (x, w + (0, 1))`. -/ +@[expose] +def twistedShearTranslationMove (π₁ π₂ : Equiv.Perm X) (n : ℕ) : + Fin 4 → Equiv.Perm (X × (ZMod n × ZMod n)) := + ![π₁.prodCongr (shearFst 1), π₂.prodCongr (shearSnd 1), + (Equiv.refl X).prodCongr (Equiv.addRight (1, 0)), + (Equiv.refl X).prodCongr (Equiv.addRight (0, 1))] + +/-- The reverse triangle inequality for the `ℓ²` norm of complex functions on a finite set. -/ +private theorem sq_sqrt_sub_sqrt_le [Fintype X] (a b : X → ℂ) : + (√(∑ x, ‖a x‖ ^ 2) - √(∑ x, ‖b x‖ ^ 2)) ^ 2 ≤ ∑ x, ‖a x - b x‖ ^ 2 := by + have h := abs_norm_sub_norm_le (WithLp.toLp 2 a : EuclideanSpace ℂ X) (WithLp.toLp 2 b) + rw [EuclideanSpace.norm_eq, EuclideanSpace.norm_eq, EuclideanSpace.norm_eq] at h + simp only [PiLp.sub_apply] at h + calc _ = |√(∑ x, ‖a x‖ ^ 2) - √(∑ x, ‖b x‖ ^ 2)| ^ 2 := (sq_abs _).symm + _ ≤ √(∑ x, ‖a x - b x‖ ^ 2) ^ 2 := pow_le_pow_left₀ (abs_nonneg _) h 2 + _ = _ := Real.sq_sqrt (sum_nonneg fun _ _ ↦ by positivity) + +variable [Fintype X] + +/-- **The relative Poincaré inequality for shears and translations**, uniformly in `n` and with a +spectator: every complex function `f` on `X × (ZMod n × ZMod n)` is within `512` times its total +squared change along the four moves of its averages over the fibers `{x} × (ZMod n × ZMod n)`. -/ +theorem sum_norm_sq_sub_fiber_le_twistedShearTranslation (π₁ π₂ : Equiv.Perm X) + (f : X × (ZMod n × ZMod n) → ℂ) : + ∑ p, ‖f p - (∑ w, f (p.1, w)) / (n : ℂ) ^ 2‖ ^ 2 ≤ + 512 * ∑ k, ∑ p, ‖f (twistedShearTranslationMove π₁ π₂ n k p) - f p‖ ^ 2 := by + have hn : (0 : ℝ) < (n : ℝ) ^ 2 := by + have : (0 : ℝ) < n := by exact_mod_cast Nat.pos_of_ne_zero (NeZero.ne n) + positivity + have hnC : (n : ℂ) ^ 2 ≠ 0 := pow_ne_zero _ (Nat.cast_ne_zero.2 (NeZero.ne n)) + -- The transforms of the fibers, and of the fibers minus their averages. + set F : X → ZMod n × ZMod n → ℂ := fun x ↦ ZMod.dftProd fun w ↦ f (x, w) with hF + set g : X → ℂ := fun x ↦ (∑ w, f (x, w)) / (n : ℂ) ^ 2 with hg + have hcard : (Fintype.card (ZMod n × ZMod n) : ℂ) = (n : ℂ) ^ 2 := by + simp [Fintype.card_prod, ZMod.card, sq] + have hdft (x : X) (ξ : ZMod n × ZMod n) : + ‖ZMod.dftProd (fun w ↦ f (x, w) - g x) ξ‖ ^ 2 = if ξ = 0 then 0 else ‖F x ξ‖ ^ 2 := by + split_ifs with hξ + · subst hξ + rw [ZMod.dftProd_zero, sum_sub_distrib, sum_const, card_univ, nsmul_eq_mul, hcard] + simp only [hg] + rw [mul_div_cancel₀ _ hnC, sub_self, norm_zero, sq, mul_zero] + · have : (fun w ↦ f (x, w) - g x) = (fun w ↦ f (x, w)) - fun _ ↦ g x := rfl + rw [this, ZMod.dftProd_sub, Pi.sub_apply, ZMod.dftProd_const_of_ne_zero _ hξ, sub_zero] + -- The function on the frequencies: the `ℓ²` norm over `X` of the nonzero frequencies. + set ψ : ZMod n × ZMod n → ℝ := fun ξ ↦ if ξ = 0 then 0 else √(∑ x, ‖F x ξ‖ ^ 2) with hψ + have hψsq (ξ : ZMod n × ZMod n) : + ‖(ψ ξ : ℂ)‖ ^ 2 = ∑ x, if ξ = 0 then 0 else ‖F x ξ‖ ^ 2 := by + rw [Complex.norm_real, Real.norm_eq_abs, sq_abs] + simp only [hψ] + split_ifs + · simp + · exact Real.sq_sqrt (sum_nonneg fun _ _ ↦ by positivity) + have hmain := sum_norm_sq_le_dual_shearTranslation (fun ξ ↦ (ψ ξ : ℂ)) (by simp [hψ]) + -- The mass of `ψ` is that of the fibers minus their averages. + have hL : ∑ ξ, ‖(ψ ξ : ℂ)‖ ^ 2 = + (n : ℝ) ^ 2 * ∑ p, ‖f p - (∑ w, f (p.1, w)) / (n : ℂ) ^ 2‖ ^ 2 := by + calc ∑ ξ, ‖(ψ ξ : ℂ)‖ ^ 2 = ∑ x, ∑ ξ, if ξ = 0 then 0 else ‖F x ξ‖ ^ 2 := by + simp only [hψsq] + exact sum_comm + _ = ∑ x, ∑ ξ, ‖ZMod.dftProd (fun w ↦ f (x, w) - g x) ξ‖ ^ 2 := by simp only [hdft] + _ = ∑ x, (n : ℝ) ^ 2 * ∑ w, ‖f (x, w) - g x‖ ^ 2 := + sum_congr rfl fun x _ ↦ ZMod.sum_norm_sq_dftProd _ + _ = _ := by rw [← mul_sum, Fintype.sum_prod_type] + -- The changes of `ψ` along the dual shears are at most those of `F`. + have hshear (π : Equiv.Perm X) (s : Equiv.Perm (ZMod n × ZMod n)) (hs : ∀ ξ, s ξ = 0 ↔ ξ = 0) + (ξ : ZMod n × ZMod n) : + ‖(ψ (s ξ) : ℂ) - ψ ξ‖ ^ 2 ≤ ∑ x, ‖F (π x) (s ξ) - F x ξ‖ ^ 2 := by + rw [← Complex.ofReal_sub, Complex.norm_real, Real.norm_eq_abs, sq_abs] + by_cases hξ : ξ = 0 + · subst hξ + have h0 : s 0 = 0 := (hs 0).2 rfl + have e : ψ (s 0) - ψ 0 = 0 := by simp only [hψ, h0, ite_true, sub_self] + rw [e, sq, mul_zero] + exact sum_nonneg fun _ _ ↦ by positivity + · have : s ξ ≠ 0 := fun h ↦ hξ ((hs ξ).1 h) + simp only [hψ, this, hξ, ite_false] + rw [← Equiv.sum_comp π fun x ↦ ‖F x (s ξ)‖ ^ 2] + exact sq_sqrt_sub_sqrt_le (fun x ↦ F (π x) (s ξ)) (fun x ↦ F x ξ) + have hS₁ : ∑ ξ, ‖(ψ (shearSnd (-1) ξ) : ℂ) - ψ ξ‖ ^ 2 ≤ + (n : ℝ) ^ 2 * ∑ p, ‖f (twistedShearTranslationMove π₁ π₂ n 0 p) - f p‖ ^ 2 := by + calc _ ≤ ∑ ξ, ∑ x, ‖F (π₁ x) (shearSnd (-1) ξ) - F x ξ‖ ^ 2 := + sum_le_sum fun ξ _ ↦ hshear π₁ _ (shearSnd_eq_zero_iff _) ξ + _ = _ := by + rw [sum_comm, Fintype.sum_prod_type, mul_sum] + refine sum_congr rfl fun x _ ↦ ?_ + exact ZMod.sum_norm_sq_dftProd_shearFst_sub (fun w ↦ f (π₁ x, w)) (fun w ↦ f (x, w)) 1 + have hS₂ : ∑ ξ, ‖(ψ (shearFst (-1) ξ) : ℂ) - ψ ξ‖ ^ 2 ≤ + (n : ℝ) ^ 2 * ∑ p, ‖f (twistedShearTranslationMove π₁ π₂ n 1 p) - f p‖ ^ 2 := by + calc _ ≤ ∑ ξ, ∑ x, ‖F (π₂ x) (shearFst (-1) ξ) - F x ξ‖ ^ 2 := + sum_le_sum fun ξ _ ↦ hshear π₂ _ (shearFst_eq_zero_iff _) ξ + _ = _ := by + rw [sum_comm, Fintype.sum_prod_type, mul_sum] + refine sum_congr rfl fun x _ ↦ ?_ + exact ZMod.sum_norm_sq_dftProd_shearSnd_sub (fun w ↦ f (π₂ x, w)) (fun w ↦ f (x, w)) 1 + -- The translation weights of `ψ` are those of `F`. + have hweight (c : ZMod n × ZMod n → ℝ) (hc : ∀ ξ, 0 ≤ c ξ) : + ∑ ξ, c ξ * ‖(ψ ξ : ℂ)‖ ^ 2 ≤ ∑ x, ∑ ξ, c ξ * ‖F x ξ‖ ^ 2 := by + rw [sum_comm] + refine sum_le_sum fun ξ _ ↦ ?_ + rw [hψsq, mul_sum] + refine sum_le_sum fun x _ ↦ ?_ + split_ifs + · have := hc ξ + simp only [mul_zero] + positivity + · exact le_rfl + have hT₁ : ∑ ξ, ‖ZMod.stdAddChar ξ.1 - 1‖ ^ 2 * ‖(ψ ξ : ℂ)‖ ^ 2 ≤ + (n : ℝ) ^ 2 * ∑ p, ‖f (twistedShearTranslationMove π₁ π₂ n 2 p) - f p‖ ^ 2 := by + refine (hweight _ fun _ ↦ by positivity).trans_eq ?_ + rw [Fintype.sum_prod_type, mul_sum] + refine sum_congr rfl fun x _ ↦ ?_ + have := sum_norm_sq_translate (fun w ↦ f (x, w)) (1, 0) + simp only [mul_one, mul_zero, add_zero] at this + exact this + have hT₂ : ∑ ξ, ‖ZMod.stdAddChar ξ.2 - 1‖ ^ 2 * ‖(ψ ξ : ℂ)‖ ^ 2 ≤ + (n : ℝ) ^ 2 * ∑ p, ‖f (twistedShearTranslationMove π₁ π₂ n 3 p) - f p‖ ^ 2 := by + refine (hweight _ fun _ ↦ by positivity).trans_eq ?_ + rw [Fintype.sum_prod_type, mul_sum] + refine sum_congr rfl fun x _ ↦ ?_ + have := sum_norm_sq_translate (fun w ↦ f (x, w)) (0, 1) + simp only [mul_one, mul_zero, zero_add] at this + exact this + refine le_of_mul_le_mul_left ?_ hn + rw [← hL, Fin.sum_univ_four, mul_left_comm] + linarith + +/-- **The relative Poincaré inequality for shears and translations**, for real functions and +averages: the second moment of `f` about its averages over the fibers `{x} × (ZMod n × ZMod n)` is +at most `512` times the sum of its mean squared changes along the four moves. -/ +theorem expect_sq_sub_expect_fiber_le_twistedShearTranslation (π₁ π₂ : Equiv.Perm X) + (f : X × (ZMod n × ZMod n) → ℝ) : + 𝔼 p, (f p - 𝔼 w, f (p.1, w)) ^ 2 ≤ + 512 * ∑ k, 𝔼 p, (f (twistedShearTranslationMove π₁ π₂ n k p) - f p) ^ 2 := by + have h := sum_norm_sq_sub_fiber_le_twistedShearTranslation π₁ π₂ fun p ↦ (f p : ℂ) + have hfib (x : X) : (∑ w, (f (x, w) : ℂ)) / (n : ℂ) ^ 2 = ((𝔼 w, f (x, w) : ℝ) : ℂ) := by + rw [Fintype.expect_eq_sum_div_card, Fintype.card_prod, ZMod.card] + push_cast + ring + simp only [hfib, ← Complex.ofReal_sub, Complex.norm_real, Real.norm_eq_abs, sq_abs] at h + simp only [Fintype.expect_eq_sum_div_card, ← sum_div] + rw [← mul_div_assoc] + exact div_le_div_of_nonneg_right (by simpa [Fintype.expect_eq_sum_div_card] using h) + (Nat.cast_nonneg _) + +end Cslib.RotationMap diff --git a/ComplexityTests/RelativeShearTranslation.lean b/ComplexityTests/RelativeShearTranslation.lean new file mode 100644 index 000000000..43e7fa54a --- /dev/null +++ b/ComplexityTests/RelativeShearTranslation.lean @@ -0,0 +1,47 @@ +/- +Copyright (c) 2026 Christian Reitwiessner. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Christian Reitwiessner +-/ + +import Complexity.Foundations.Combinatorics.Expander.RelativeShearTranslation + +/-! +# The relative Poincaré inequality for shears and translations + +Concrete moves with a spectator, the transform of a constant, and a client of the relative +Poincaré inequality: a function invariant under the four moves is constant on every fiber +`{x} × (ZMod n × ZMod n)`, for every `n` and every pair of spectator permutations. +-/ + +namespace ComplexityTests.RelativeShearTranslation + +open Cslib Cslib.RotationMap Finset +open scoped BigOperators + +-- The shears move the spectator; the translations do not. +example : twistedShearTranslationMove (Equiv.addRight (1 : ZMod 3)) (Equiv.refl _) 5 0 + (0, (1, 2)) = (1, (3, 2)) := by decide +example : twistedShearTranslationMove (Equiv.addRight (1 : ZMod 3)) (Equiv.refl _) 5 1 + (0, (1, 2)) = (0, (1, 3)) := by decide +example : twistedShearTranslationMove (Equiv.addRight (1 : ZMod 3)) (Equiv.refl _) 5 2 + (2, (4, 2)) = (2, (0, 2)) := by decide + +-- A constant has no nonzero frequencies. +example : ZMod.dftProd (N := 4) (fun _ ↦ (7 : ℂ)) (1, 3) = 0 := + ZMod.dftProd_const_of_ne_zero 7 (by decide) + +/-- **A client**: a real function on `X × (ZMod n × ZMod n)` invariant under the four moves is +constant on every fiber, whatever the spectator permutations. -/ +example {X : Type*} [Fintype X] (n : ℕ) [NeZero n] (π₁ π₂ : Equiv.Perm X) + (f : X × (ZMod n × ZMod n) → ℝ) + (hf : ∀ k p, f (twistedShearTranslationMove π₁ π₂ n k p) = f p) (p : X × (ZMod n × ZMod n)) : + f p = 𝔼 w, f (p.1, w) := by + have h := expect_sq_sub_expect_fiber_le_twistedShearTranslation π₁ π₂ f + simp only [hf, sub_self, ne_eq, OfNat.ofNat_ne_zero, not_false_eq_true, zero_pow, + expect_const_zero, sum_const_zero, mul_zero] at h + have h0 := (Fintype.expect_eq_zero_iff_of_nonneg fun q ↦ sq_nonneg + (f q - 𝔼 w, f (q.1, w))).1 (le_antisymm h (expect_nonneg fun _ _ ↦ sq_nonneg _)) + exact sub_eq_zero.1 (pow_eq_zero_iff two_ne_zero |>.1 (congrFun h0 p)) + +end ComplexityTests.RelativeShearTranslation From 3db1f8fc0c541caf41f9068a34bb0f6b72a2ee0c Mon Sep 17 00:00:00 2001 From: Christian Reitwiessner Date: Fri, 30 Oct 2026 01:09:46 +0000 Subject: [PATCH 09/13] refactor(Expander): move the dftProd lemmas to ZModProd and drop import all; credit AffineSampling.lean (#1682) Review fixes for #1695: - the linearity, bijectivity and constant lemmas for ZMod.dftProd, and the Parseval identities for translations and sheared differences, now live in Foundations/Analysis/Fourier/ZModProd.lean; - ShearTranslation.lean's private Parseval helpers are replaced by these public lemmas (the shear ones are the case f = g); - RelativeShearTranslation.lean no longer uses import all; - the module docstring credits OpenAI's AffineSampling.lean at 7ef5c0cc (square_gap with the external permutations u in changeF; the frame lift slice_frame, frame_gap, slice_gap); our proof is independent. Co-Authored-By: Claude Opus 5.5 --- .../Analysis/Fourier/ZModProd.lean | 90 ++++++++++++++- .../Expander/RelativeShearTranslation.lean | 108 +++--------------- .../Expander/ShearTranslation.lean | 41 +------ 3 files changed, 108 insertions(+), 131 deletions(-) diff --git a/Complexity/Foundations/Analysis/Fourier/ZModProd.lean b/Complexity/Foundations/Analysis/Fourier/ZModProd.lean index 11214c9ca..a50ae059e 100644 --- a/Complexity/Foundations/Analysis/Fourier/ZModProd.lean +++ b/Complexity/Foundations/Analysis/Fourier/ZModProd.lean @@ -9,8 +9,9 @@ module public import Complexity.Init public import Mathlib.Analysis.SpecialFunctions.Complex.CircleAddChar -import Complexity.Foundations.Algebra.Shear +public import Complexity.Foundations.Algebra.Shear import Mathlib.Analysis.Complex.Basic +import Mathlib.LinearAlgebra.FiniteDimensional.Basic import Mathlib.NumberTheory.LegendreSymbol.AddCharacter /-! @@ -38,6 +39,12 @@ multiplies the transform at `ξ` by `e (ξ.1 * t.1 + ξ.2 * t.2)`, and the shear * `ZMod.dftProd_zero`: the transform at the zero frequency is the sum of the values. * `ZMod.dftProd_comp_add`: translation multiplies the transform by a character value. * `ZMod.dftProd_comp_shearFst`, `ZMod.dftProd_comp_shearSnd`: shears permute the frequencies. +* `ZMod.dftProd_add`, `ZMod.dftProd_smul`, `ZMod.dftProd_injective`, `ZMod.dftProd_surjective`: the + transform is a linear bijection. +* `ZMod.dftProd_const_of_ne_zero`: a constant has no nonzero frequencies. +* `ZMod.sum_norm_sq_dftProd_translate`, `ZMod.sum_norm_sq_dftProd_shearFst_sub`, + `ZMod.sum_norm_sq_dftProd_shearSnd_sub`: Parseval's identity for the change along a translation, + and for the difference of two functions, one of them sheared. -/ public section @@ -133,4 +140,85 @@ theorem dftProd_comp_shearSnd (f : ZMod N × ZMod N → ℂ) (k : ZMod N) (ξ : congr 2 ring +/-- The transform is additive. -/ +theorem dftProd_add (f g : ZMod N × ZMod N → ℂ) : dftProd (f + g) = dftProd f + dftProd g := by + ext ξ + simp only [dftProd, Pi.add_apply, mul_add, sum_add_distrib] + +/-- The transform is homogeneous. -/ +theorem dftProd_smul (c : ℂ) (f : ZMod N × ZMod N → ℂ) : dftProd (c • f) = c • dftProd f := by + ext ξ + simp only [dftProd, Pi.smul_apply, smul_eq_mul, mul_sum] + exact sum_congr rfl fun _ _ ↦ by ring + +/-- The transform is injective, by Parseval's identity. -/ +theorem dftProd_injective : Function.Injective (dftProd (N := N)) := by + intro f g h + have hP := sum_norm_sq_dftProd (f - g) + rw [dftProd_sub, h, sub_self] at hP + simp only [Pi.zero_apply, norm_zero, ne_eq, OfNat.ofNat_ne_zero, not_false_eq_true, zero_pow, + sum_const_zero] at hP + have hN : (N : ℝ) ^ 2 ≠ 0 := pow_ne_zero _ (Nat.cast_ne_zero.2 (NeZero.ne N)) + have h0 := (mul_eq_zero.1 hP.symm).resolve_left hN + rw [sum_eq_zero_iff_of_nonneg fun _ _ ↦ by positivity] at h0 + funext v + simpa [sub_eq_zero] using h0 v (mem_univ v) + +/-- The transform as a linear map. -/ +private noncomputable def dftProdLinearMap : + (ZMod N × ZMod N → ℂ) →ₗ[ℂ] (ZMod N × ZMod N → ℂ) where + toFun := dftProd + map_add' := dftProd_add + map_smul' := dftProd_smul + +/-- The transform is surjective: an injective linear endomorphism of a finite-dimensional space. -/ +theorem dftProd_surjective : Function.Surjective (dftProd (N := N)) := + LinearMap.injective_iff_surjective.1 (show Function.Injective dftProdLinearMap from + dftProd_injective (N := N)) + +/-- **A constant has no nonzero frequencies**: Parseval's identity puts all of its mass at `0`. -/ +theorem dftProd_const_of_ne_zero (c : ℂ) {ξ : ZMod N × ZMod N} (hξ : ξ ≠ 0) : + dftProd (fun _ ↦ c) ξ = 0 := by + have hP := sum_norm_sq_dftProd (N := N) fun _ ↦ c + rw [← add_sum_erase _ _ (mem_univ (0 : ZMod N × ZMod N)), dftProd_zero] at hP + simp only [sum_const, card_univ, Fintype.card_prod, ZMod.card, nsmul_eq_mul, norm_mul, + Complex.norm_natCast, Nat.cast_mul] at hP + have h0 : ∑ ζ ∈ univ.erase (0 : ZMod N × ZMod N), ‖dftProd (fun _ ↦ c) ζ‖ ^ 2 = 0 := by linarith + rw [sum_eq_zero_iff_of_nonneg fun _ _ ↦ by positivity] at h0 + simpa using h0 ξ (mem_erase.2 ⟨hξ, mem_univ ξ⟩) + +/-- **Parseval's identity for the change along a translation**: the transform of the change of +`f` along the translation by `t` is the transform of `f` times `e (ξ.1 * t.1 + ξ.2 * t.2) - 1`. -/ +theorem sum_norm_sq_dftProd_translate (f : ZMod N × ZMod N → ℂ) (t : ZMod N × ZMod N) : + ∑ ξ, ‖stdAddChar (ξ.1 * t.1 + ξ.2 * t.2) - 1‖ ^ 2 * ‖dftProd f ξ‖ ^ 2 = + N ^ 2 * ∑ v, ‖f (v + t) - f v‖ ^ 2 := by + rw [← sum_norm_sq_dftProd (fun v ↦ f (v + t) - f v)] + refine sum_congr rfl fun ξ _ ↦ ?_ + have : (fun v ↦ f (v + t) - f v) = (fun v ↦ f (v + t)) - f := rfl + rw [this, dftProd_sub, Pi.sub_apply, dftProd_comp_add, ← sub_one_mul, norm_mul, mul_pow] + +/-- **Parseval's identity for the difference of two functions along the shear** +`(x, y) ↦ (x + k * y, y)`: it acts on the frequencies by the dual shear `(a, b) ↦ (a, b - k * a)`. +-/ +theorem sum_norm_sq_dftProd_shearFst_sub (f g : ZMod N × ZMod N → ℂ) (k : ZMod N) : + ∑ ξ, ‖dftProd f (Cslib.shearSnd (-k) ξ) - dftProd g ξ‖ ^ 2 = + N ^ 2 * ∑ v, ‖f (Cslib.shearFst k v) - g v‖ ^ 2 := by + rw [← sum_norm_sq_dftProd (fun v ↦ f (Cslib.shearFst k v) - g v)] + refine sum_congr rfl fun ξ _ ↦ ?_ + have : (fun v ↦ f (Cslib.shearFst k v) - g v) = (fun v ↦ f (v.1 + k * v.2, v.2)) - g := rfl + rw [this, dftProd_sub, Pi.sub_apply, dftProd_comp_shearFst, Cslib.shearSnd_apply, neg_mul, + ← sub_eq_add_neg] + +/-- **Parseval's identity for the difference of two functions along the shear** +`(x, y) ↦ (x, y + k * x)`: it acts on the frequencies by the dual shear `(a, b) ↦ (a - k * b, b)`. +-/ +theorem sum_norm_sq_dftProd_shearSnd_sub (f g : ZMod N × ZMod N → ℂ) (k : ZMod N) : + ∑ ξ, ‖dftProd f (Cslib.shearFst (-k) ξ) - dftProd g ξ‖ ^ 2 = + N ^ 2 * ∑ v, ‖f (Cslib.shearSnd k v) - g v‖ ^ 2 := by + rw [← sum_norm_sq_dftProd (fun v ↦ f (Cslib.shearSnd k v) - g v)] + refine sum_congr rfl fun ξ _ ↦ ?_ + have : (fun v ↦ f (Cslib.shearSnd k v) - g v) = (fun v ↦ f (v.1, v.2 + k * v.1)) - g := rfl + rw [this, dftProd_sub, Pi.sub_apply, dftProd_comp_shearSnd, Cslib.shearFst_apply, neg_mul, + ← sub_eq_add_neg] + end ZMod diff --git a/Complexity/Foundations/Combinatorics/Expander/RelativeShearTranslation.lean b/Complexity/Foundations/Combinatorics/Expander/RelativeShearTranslation.lean index d96c0046b..700aad5c7 100644 --- a/Complexity/Foundations/Combinatorics/Expander/RelativeShearTranslation.lean +++ b/Complexity/Foundations/Combinatorics/Expander/RelativeShearTranslation.lean @@ -11,11 +11,6 @@ public import Complexity.Foundations.Analysis.Fourier.ZModProd public import Complexity.Foundations.Algebra.Shear public import Complexity.Foundations.Combinatorics.Expander.ShearTranslation public import Mathlib.Analysis.InnerProductSpace.PiL2 --- `import all`: the linearity of `ZMod.dftProd` unfolds its body, and the frequency-side --- inequality reuses the private Parseval identity for translations, `sum_norm_sq_translate`. -import all Complexity.Foundations.Analysis.Fourier.ZModProd -import all Complexity.Foundations.Combinatorics.Expander.ShearTranslation -import Mathlib.LinearAlgebra.FiniteDimensional.Basic /-! # The relative Poincaré inequality for shears and translations @@ -44,10 +39,15 @@ this norm, and the reverse triangle inequality bounds the changes of `Φ` by tho This is the step that turns the uniform gap on `ZMod n × ZMod n` into closeness to the vectors fixed by the translations of one coordinate pair, as in the projection argument of the OpenAI preprint on derandomizing logarithmic space for its affine walks -[OpenAI, proof of Lemma 6.1][OpenAI2026LogSpace]. The preprint takes it from Shalom's quantitative -relative property (T) of `(SL₂(ℤ) ⋉ ℤ², ℤ²)`; see also [Burger][Burger1991]. The elementary route -through the uniform Fourier gap is credited in the module of `Cslib.RotationMap.shearTranslation`. -The statements and proofs here are ours. +[OpenAI, proof of Lemma 6.1][OpenAI2026LogSpace]. The preprint's text takes it from Shalom's +quantitative relative property (T) of `(SL₂(ℤ) ⋉ ℤ², ℤ²)`; see also [Burger][Burger1991]. An +elementary version with external permutations of a spectator, built on a uniform Fourier gap, is +in OpenAI's Lean development, the file +[`AffineSampling.lean`](https://github.com/openai/math/blob/7ef5c0cc5ca4b0e072b7a050fca09ab24bc6fa3a/lean/OAI/Computability/Logspace/AffineSampling.lean) +at revision `7ef5c0cc`: `ExactDerandomization.Analysis.Square.square_gap`, with the external +permutations `u` in `changeF`. The same file lifts it to frames (`slice_frame`, `frame_gap`, +`slice_gap`). The statements and the proof here are independent of that code, which was not +consulted: they are derived from `sum_norm_sq_le_shearTranslation`. ## Main definitions @@ -56,11 +56,6 @@ The statements and proofs here are ours. ## Main results -* `ZMod.dftProd_add`, `ZMod.dftProd_smul`: the transform is linear. -* `ZMod.dftProd_injective`, `ZMod.dftProd_surjective`: the transform is a bijection. -* `ZMod.sum_norm_sq_dftProd_shearFst_sub`, `ZMod.sum_norm_sq_dftProd_shearSnd_sub`: Parseval's - identity for the difference of two functions, one of them sheared. -* `ZMod.dftProd_const_of_ne_zero`: a constant has no nonzero frequencies. * `Cslib.RotationMap.sum_norm_sq_le_dual_shearTranslation`: the Poincaré inequality on the frequencies. * `Cslib.RotationMap.sum_norm_sq_sub_fiber_le_twistedShearTranslation`, @@ -78,83 +73,6 @@ public section open Finset open scoped BigOperators -namespace ZMod - -variable {N : ℕ} [NeZero N] - -/-- The transform is additive. -/ -theorem dftProd_add (f g : ZMod N × ZMod N → ℂ) : dftProd (f + g) = dftProd f + dftProd g := by - ext ξ - simp only [dftProd, Pi.add_apply, mul_add, sum_add_distrib] - -/-- The transform is homogeneous. -/ -theorem dftProd_smul (c : ℂ) (f : ZMod N × ZMod N → ℂ) : dftProd (c • f) = c • dftProd f := by - ext ξ - simp only [dftProd, Pi.smul_apply, smul_eq_mul, mul_sum] - exact sum_congr rfl fun _ _ ↦ by ring - -/-- The transform is injective, by Parseval's identity. -/ -theorem dftProd_injective : Function.Injective (dftProd (N := N)) := by - intro f g h - have hP := sum_norm_sq_dftProd (f - g) - rw [dftProd_sub, h, sub_self] at hP - simp only [Pi.zero_apply, norm_zero, ne_eq, OfNat.ofNat_ne_zero, not_false_eq_true, zero_pow, - sum_const_zero] at hP - have hN : (N : ℝ) ^ 2 ≠ 0 := pow_ne_zero _ (Nat.cast_ne_zero.2 (NeZero.ne N)) - have h0 := (mul_eq_zero.1 hP.symm).resolve_left hN - rw [sum_eq_zero_iff_of_nonneg fun _ _ ↦ by positivity] at h0 - funext v - simpa [sub_eq_zero] using h0 v (mem_univ v) - -/-- The transform as a linear map. -/ -private noncomputable def dftProdLinearMap : - (ZMod N × ZMod N → ℂ) →ₗ[ℂ] (ZMod N × ZMod N → ℂ) where - toFun := dftProd - map_add' := dftProd_add - map_smul' := dftProd_smul - -/-- The transform is surjective: an injective linear endomorphism of a finite-dimensional space. -/ -theorem dftProd_surjective : Function.Surjective (dftProd (N := N)) := - LinearMap.injective_iff_surjective.1 (show Function.Injective dftProdLinearMap from - dftProd_injective (N := N)) - -/-- **A constant has no nonzero frequencies**: Parseval's identity puts all of its mass at `0`. -/ -theorem dftProd_const_of_ne_zero (c : ℂ) {ξ : ZMod N × ZMod N} (hξ : ξ ≠ 0) : - dftProd (fun _ ↦ c) ξ = 0 := by - have hP := sum_norm_sq_dftProd (N := N) fun _ ↦ c - rw [← add_sum_erase _ _ (mem_univ (0 : ZMod N × ZMod N)), dftProd_zero] at hP - simp only [sum_const, card_univ, Fintype.card_prod, ZMod.card, nsmul_eq_mul, norm_mul, - Complex.norm_natCast, Nat.cast_mul] at hP - have h0 : ∑ ζ ∈ univ.erase (0 : ZMod N × ZMod N), ‖dftProd (fun _ ↦ c) ζ‖ ^ 2 = 0 := by linarith - rw [sum_eq_zero_iff_of_nonneg fun _ _ ↦ by positivity] at h0 - simpa using h0 ξ (mem_erase.2 ⟨hξ, mem_univ ξ⟩) - -/-- **Parseval's identity for the difference of two functions along the shear** -`(x, y) ↦ (x + k * y, y)`: it acts on the frequencies by the dual shear `(a, b) ↦ (a, b - k * a)`. --/ -theorem sum_norm_sq_dftProd_shearFst_sub (f g : ZMod N × ZMod N → ℂ) (k : ZMod N) : - ∑ ξ, ‖dftProd f (Cslib.shearSnd (-k) ξ) - dftProd g ξ‖ ^ 2 = - N ^ 2 * ∑ v, ‖f (Cslib.shearFst k v) - g v‖ ^ 2 := by - rw [← sum_norm_sq_dftProd (fun v ↦ f (Cslib.shearFst k v) - g v)] - refine sum_congr rfl fun ξ _ ↦ ?_ - have : (fun v ↦ f (Cslib.shearFst k v) - g v) = (fun v ↦ f (v.1 + k * v.2, v.2)) - g := rfl - rw [this, dftProd_sub, Pi.sub_apply, dftProd_comp_shearFst, Cslib.shearSnd_apply, neg_mul, - ← sub_eq_add_neg] - -/-- **Parseval's identity for the difference of two functions along the shear** -`(x, y) ↦ (x, y + k * x)`: it acts on the frequencies by the dual shear `(a, b) ↦ (a - k * b, b)`. --/ -theorem sum_norm_sq_dftProd_shearSnd_sub (f g : ZMod N × ZMod N → ℂ) (k : ZMod N) : - ∑ ξ, ‖dftProd f (Cslib.shearFst (-k) ξ) - dftProd g ξ‖ ^ 2 = - N ^ 2 * ∑ v, ‖f (Cslib.shearSnd k v) - g v‖ ^ 2 := by - rw [← sum_norm_sq_dftProd (fun v ↦ f (Cslib.shearSnd k v) - g v)] - refine sum_congr rfl fun ξ _ ↦ ?_ - have : (fun v ↦ f (Cslib.shearSnd k v) - g v) = (fun v ↦ f (v.1, v.2 + k * v.1)) - g := rfl - rw [this, dftProd_sub, Pi.sub_apply, dftProd_comp_shearSnd, Cslib.shearFst_apply, neg_mul, - ← sub_eq_add_neg] - -end ZMod - namespace Cslib.RotationMap variable {n : ℕ} [NeZero n] @@ -176,8 +94,8 @@ theorem sum_norm_sq_le_dual_shearTranslation (Φ : ZMod n × ZMod n → ℂ) (h0 Equiv.coe_addRight] at hP have e₁ := ZMod.sum_norm_sq_dftProd_shearFst_sub f f 1 have e₂ := ZMod.sum_norm_sq_dftProd_shearSnd_sub f f 1 - have e₃ := sum_norm_sq_translate f (1, 0) - have e₄ := sum_norm_sq_translate f (0, 1) + have e₃ := ZMod.sum_norm_sq_dftProd_translate f (1, 0) + have e₄ := ZMod.sum_norm_sq_dftProd_translate f (0, 1) simp only [mul_one, mul_zero, add_zero, zero_add] at e₃ e₄ have hM := ZMod.sum_norm_sq_dftProd f have hn : (0 : ℝ) ≤ (n : ℝ) ^ 2 := by positivity @@ -315,7 +233,7 @@ theorem sum_norm_sq_sub_fiber_le_twistedShearTranslation (π₁ π₂ : Equiv.Pe refine (hweight _ fun _ ↦ by positivity).trans_eq ?_ rw [Fintype.sum_prod_type, mul_sum] refine sum_congr rfl fun x _ ↦ ?_ - have := sum_norm_sq_translate (fun w ↦ f (x, w)) (1, 0) + have := ZMod.sum_norm_sq_dftProd_translate (fun w ↦ f (x, w)) (1, 0) simp only [mul_one, mul_zero, add_zero] at this exact this have hT₂ : ∑ ξ, ‖ZMod.stdAddChar ξ.2 - 1‖ ^ 2 * ‖(ψ ξ : ℂ)‖ ^ 2 ≤ @@ -323,7 +241,7 @@ theorem sum_norm_sq_sub_fiber_le_twistedShearTranslation (π₁ π₂ : Equiv.Pe refine (hweight _ fun _ ↦ by positivity).trans_eq ?_ rw [Fintype.sum_prod_type, mul_sum] refine sum_congr rfl fun x _ ↦ ?_ - have := sum_norm_sq_translate (fun w ↦ f (x, w)) (0, 1) + have := ZMod.sum_norm_sq_dftProd_translate (fun w ↦ f (x, w)) (0, 1) simp only [mul_one, mul_zero, zero_add] at this exact this refine le_of_mul_le_mul_left ?_ hn diff --git a/Complexity/Foundations/Combinatorics/Expander/ShearTranslation.lean b/Complexity/Foundations/Combinatorics/Expander/ShearTranslation.lean index 3efde6834..17e725f07 100644 --- a/Complexity/Foundations/Combinatorics/Expander/ShearTranslation.lean +++ b/Complexity/Foundations/Combinatorics/Expander/ShearTranslation.lean @@ -482,36 +482,6 @@ section Gap variable {n : ℕ} [NeZero n] -/-- Parseval's identity for the change of `f` along a translation. -/ -private theorem sum_norm_sq_translate (f : ZMod n × ZMod n → ℂ) (t : ZMod n × ZMod n) : - ∑ ξ, ‖ZMod.stdAddChar (ξ.1 * t.1 + ξ.2 * t.2) - 1‖ ^ 2 * ‖ZMod.dftProd f ξ‖ ^ 2 = - n ^ 2 * ∑ v, ‖f (v + t) - f v‖ ^ 2 := by - rw [← ZMod.sum_norm_sq_dftProd (fun v ↦ f (v + t) - f v)] - refine sum_congr rfl fun ξ _ ↦ ?_ - have : (fun v ↦ f (v + t) - f v) = (fun v ↦ f (v + t)) - f := rfl - rw [this, ZMod.dftProd_sub, Pi.sub_apply, ZMod.dftProd_comp_add, ← sub_one_mul, norm_mul, - mul_pow] - -/-- Parseval's identity for the change of `f` along the shear `(x, y) ↦ (x + k * y, y)`. -/ -private theorem sum_norm_sq_shearFst (f : ZMod n × ZMod n → ℂ) (k : ZMod n) : - ∑ ξ, ‖ZMod.dftProd f (shearSnd (-k) ξ) - ZMod.dftProd f ξ‖ ^ 2 = - n ^ 2 * ∑ v, ‖f (shearFst k v) - f v‖ ^ 2 := by - rw [← ZMod.sum_norm_sq_dftProd (fun v ↦ f (shearFst k v) - f v)] - refine sum_congr rfl fun ξ _ ↦ ?_ - have : (fun v ↦ f (shearFst k v) - f v) = (fun v ↦ f (v.1 + k * v.2, v.2)) - f := rfl - rw [this, ZMod.dftProd_sub, Pi.sub_apply, ZMod.dftProd_comp_shearFst, shearSnd_apply, neg_mul, - ← sub_eq_add_neg] - -/-- Parseval's identity for the change of `f` along the shear `(x, y) ↦ (x, y + k * x)`. -/ -private theorem sum_norm_sq_shearSnd (f : ZMod n × ZMod n → ℂ) (k : ZMod n) : - ∑ ξ, ‖ZMod.dftProd f (shearFst (-k) ξ) - ZMod.dftProd f ξ‖ ^ 2 = - n ^ 2 * ∑ v, ‖f (shearSnd k v) - f v‖ ^ 2 := by - rw [← ZMod.sum_norm_sq_dftProd (fun v ↦ f (shearSnd k v) - f v)] - refine sum_congr rfl fun ξ _ ↦ ?_ - have : (fun v ↦ f (shearSnd k v) - f v) = (fun v ↦ f (v.1, v.2 + k * v.1)) - f := rfl - rw [this, ZMod.dftProd_sub, Pi.sub_apply, ZMod.dftProd_comp_shearSnd, shearFst_apply, neg_mul, - ← sub_eq_add_neg] - /-- The change along the shears by `4` and `-4` is at most `16` times that along the unit shear. -/ private theorem sum_norm_sq_shearFst_four_le (f : ZMod n × ZMod n → ℂ) : @@ -562,7 +532,8 @@ theorem sum_norm_sq_le_shearTranslation (f : ZMod n × ZMod n → ℂ) (hf : ∑ sq_nonneg ‖ZMod.stdAddChar ξ.2 - 1‖] · linarith [one_div_eight_le_norm_stdAddChar_sub_one (not_le.1 hs), sq_nonneg ‖ZMod.stdAddChar ξ.1 - 1‖] - rw [← sum_norm_sq_translate, ← sum_norm_sq_translate, ← sum_add_distrib, mul_sum, sum_filter] + rw [← ZMod.sum_norm_sq_dftProd_translate, ← ZMod.sum_norm_sq_dftProd_translate, + ← sum_add_distrib, mul_sum, sum_filter] refine sum_le_sum fun ξ _ ↦ ?_ have e₁ : ξ.1 * ((1, 0) : ZMod n × ZMod n).1 + ξ.2 * ((1, 0) : ZMod n × ZMod n).2 = ξ.1 := by simp @@ -574,10 +545,10 @@ theorem sum_norm_sq_le_shearTranslation (f : ZMod n × ZMod n → ℂ) (hf : ∑ · have := mul_le_mul_of_nonneg_right (hw ξ hs) (sq_nonneg ‖F ξ‖) linarith -- The dual shears are paid for by the primal shears. - have hD₁ := sum_norm_sq_shearFst f (-4 : ZMod n) - have hD₂ := sum_norm_sq_shearFst f (4 : ZMod n) - have hD₃ := sum_norm_sq_shearSnd f (-4 : ZMod n) - have hD₄ := sum_norm_sq_shearSnd f (4 : ZMod n) + have hD₁ := ZMod.sum_norm_sq_dftProd_shearFst_sub f f (-4 : ZMod n) + have hD₂ := ZMod.sum_norm_sq_dftProd_shearFst_sub f f (4 : ZMod n) + have hD₃ := ZMod.sum_norm_sq_dftProd_shearSnd_sub f f (-4 : ZMod n) + have hD₄ := ZMod.sum_norm_sq_dftProd_shearSnd_sub f f (4 : ZMod n) rw [neg_neg] at hD₁ hD₃ rw [← hF] at hD₁ hD₂ hD₃ hD₄ have e₁ := sum_norm_sq_shearFst_four_le f From 073614394dee338a170f8e56eba57ad2cc557770 Mon Sep 17 00:00:00 2001 From: Christian Reitwiessner Date: Fri, 30 Oct 2026 01:15:49 +0000 Subject: [PATCH 10/13] =?UTF-8?q?feat(Expander):=20Efron=E2=80=93Stein=20a?= =?UTF-8?q?nd=20the=20pair-move=20bound=20on=20Y=20=C3=97=20(Fin=20H=20?= =?UTF-8?q?=E2=86=92=20ZMod=20L)=20(#1682)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Step (B) of the frame-lifted gap plan on #1682: - Fintype.expect_sq_sub_expect_le_sum_expect_sq_sub_update: the Efron–Stein inequality for a uniform tuple with a spectator; - Fintype.expect_sq_sub_expect_update_le: the average over one coordinate is the best approximation by functions not depending on it; - pairShearTranslationMove and expect_sq_sub_expect_le_pairShearTranslation: the second moment of f about its average over w is at most 512 times the sum over i of the Dirichlet form of the elementary shears and unit translations of the pair (i, σ i), using the relative Poincaré inequality of #1695 per pair. Co-Authored-By: Claude Opus 5.5 --- Complexity.lean | 2 + .../Expander/PairShearTranslation.lean | 167 ++++++++++++++++++ .../Foundations/Probability/EfronStein.lean | 141 +++++++++++++++ ComplexityTests/PairShearTranslation.lean | 52 ++++++ 4 files changed, 362 insertions(+) create mode 100644 Complexity/Foundations/Combinatorics/Expander/PairShearTranslation.lean create mode 100644 Complexity/Foundations/Probability/EfronStein.lean create mode 100644 ComplexityTests/PairShearTranslation.lean diff --git a/Complexity.lean b/Complexity.lean index e2466576e..19a2904f6 100644 --- a/Complexity.lean +++ b/Complexity.lean @@ -2369,6 +2369,7 @@ public import Complexity.Foundations.Combinatorics.Expander.Loops public import Complexity.Foundations.Combinatorics.Expander.LowerBound public import Complexity.Foundations.Combinatorics.Expander.Mixing public import Complexity.Foundations.Combinatorics.Expander.Multigraph +public import Complexity.Foundations.Combinatorics.Expander.PairShearTranslation public import Complexity.Foundations.Combinatorics.Expander.Perm public import Complexity.Foundations.Combinatorics.Expander.Power public import Complexity.Foundations.Combinatorics.Expander.Random @@ -2651,6 +2652,7 @@ public import Complexity.Foundations.NumberTheory.SqrtPrimeWindow public import Complexity.Foundations.Order.BooleanSubalgebra public import Complexity.Foundations.Order.Changes public import Complexity.Foundations.Order.UpperLower +public import Complexity.Foundations.Probability.EfronStein 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/Combinatorics/Expander/PairShearTranslation.lean b/Complexity/Foundations/Combinatorics/Expander/PairShearTranslation.lean new file mode 100644 index 000000000..0ab4b088a --- /dev/null +++ b/Complexity/Foundations/Combinatorics/Expander/PairShearTranslation.lean @@ -0,0 +1,167 @@ +/- +Copyright (c) 2026 Christian Reitwiessner. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Christian Reitwiessner +-/ + +module +-- upstream: candidate + +public import Complexity.Foundations.Combinatorics.Expander.RelativeShearTranslation +import Complexity.Foundations.Probability.EfronStein + +/-! +# Shears and translations of coordinate pairs + +Let `Y` be a finite set and consider functions on `Y × (Fin H → ZMod L)`. For a pair `i ≠ j` of +coordinates, the elementary moves are (`pairShearTranslationMove`): the elementary shears +`w ↦ w + w j • e i` and `w ↦ w + w i • e j`, which also act on `Y` by given permutations `ρ`, `ρ'`, +and the unit translations `w ↦ w + e i` and `w ↦ w + e j`. These are the moves of the elementary +matrices of `SL_H(ℤ)` and of the unit translations on a retention slice `Frame P H r × (ZMod L)^H`, +where `ρ` is the action of the same elementary matrix on the frames. + +The second moment of `f` about its average over the whole tuple `w` is at most `512` times the sum, +over the coordinates `i`, of the total squared change of `f` along the moves of a pair `(i, σ i)` +with `σ i ≠ i` (`expect_sq_sub_expect_le_pairShearTranslation`). The proof combines: + +* the Efron–Stein inequality (`Fintype.expect_sq_sub_expect_le_sum_expect_sq_sub_update`), which + reduces the distance from the functions of `y` alone to the distances from the functions not + depending on one coordinate `w i`; +* the best-approximation property of the average over `w i` + (`Fintype.expect_sq_sub_expect_update_le`), which bounds that distance by the distance from the + average over the pair `(w i, w j)`; +* the relative Poincaré inequality with a spectator + (`expect_sq_sub_expect_fiber_le_twistedShearTranslation`), applied to `f` with the pair + `(w i, w j)` resampled and everything else as the spectator + (`expect_sq_sub_expect_update_le_pairShearTranslation`). + +This is the step from the coordinate-pair projections `P_ij` to the projection onto the vectors +fixed by all translations in the OpenAI preprint on derandomizing logarithmic space +[OpenAI, proof of Lemma 6.1][OpenAI2026LogSpace], where the commuting projections are telescoped; +here the Efron–Stein inequality takes the place of the telescoping. The elementary lift of the +relative gap to frames is in OpenAI's Lean development, the file +[`AffineSampling.lean`](https://github.com/openai/math/blob/7ef5c0cc5ca4b0e072b7a050fca09ab24bc6fa3a/lean/OAI/Computability/Logspace/AffineSampling.lean) +at revision `7ef5c0cc` (`slice_frame`, `frame_gap`, `slice_gap`). The statements and the proof here +are independent of that code, which was not consulted. + +## Main definitions + +* `Cslib.RotationMap.pairShearTranslationMove`: the four moves of a coordinate pair. + +## Main results + +* `Cslib.RotationMap.expect_sq_sub_expect_update_le_pairShearTranslation`: one coordinate, from + the moves of a pair containing it. +* `Cslib.RotationMap.expect_sq_sub_expect_le_pairShearTranslation`: all coordinates. + +## References + +* [OpenAI, *Exact Derandomization of Logarithmic Space: L = RL = BPL*][OpenAI2026LogSpace] +-/ + +public section + +open Finset Function +open scoped BigOperators + +namespace Cslib.RotationMap + +variable {Y : Type*} [Fintype Y] {H L : ℕ} + +/-- The four moves of the coordinate pair `(i, j)` on `Y × (Fin H → ZMod L)`: the elementary +shears `w ↦ w + w j • e i` (with `ρ` on `Y`) and `w ↦ w + w i • e j` (with `ρ'` on `Y`), and the +unit translations `w ↦ w + e i` and `w ↦ w + e j`. -/ +@[expose] +def pairShearTranslationMove (ρ ρ' : Equiv.Perm Y) (i j : Fin H) : + Fin 4 → Y × (Fin H → ZMod L) → Y × (Fin H → ZMod L) := + ![fun p ↦ (ρ p.1, update p.2 i (p.2 i + p.2 j)), fun p ↦ (ρ' p.1, update p.2 j (p.2 j + p.2 i)), + fun p ↦ (p.1, update p.2 i (p.2 i + 1)), fun p ↦ (p.1, update p.2 j (p.2 j + 1))] + +/-- Overwriting the coordinates `i` and then `j` of `w`. -/ +private abbrev upd2 (i j : Fin H) (w : Fin H → ZMod L) (a b : ZMod L) : Fin H → ZMod L := + update (update w i a) j b + +omit [Fintype Y] in +private theorem upd2_upd2 (i j : Fin H) (w : Fin H → ZMod L) (a b a' b' : ZMod L) : + upd2 i j (upd2 i j w a b) a' b' = upd2 i j w a' b' := by + funext k + simp only [upd2, update_apply] + split_ifs <;> simp_all + +omit [Fintype Y] in +private theorem update_upd2_fst {i j : Fin H} (hij : i ≠ j) (w : Fin H → ZMod L) (a b c : ZMod L) : + update (upd2 i j w a b) i c = upd2 i j w c b := by + funext k + simp only [upd2, update_apply] + split_ifs <;> simp_all + +omit [Fintype Y] in +private theorem upd2_apply_fst {i j : Fin H} (hij : i ≠ j) (w : Fin H → ZMod L) (a b : ZMod L) : + upd2 i j w a b i = a := by + simp [upd2, hij] + +variable [NeZero L] + +/-- Resampling the pair `(i, j)` of a uniformly random tuple keeps it uniformly random. -/ +private theorem expect_upd2 (i j : Fin H) (Φ : Y × (Fin H → ZMod L) → ℝ) : + 𝔼 q : (Y × (Fin H → ZMod L)) × (ZMod L × ZMod L), Φ (q.1.1, upd2 i j q.1.2 q.2.1 q.2.2) = + 𝔼 p, Φ p := by + rw [Fintype.expect_prod_type, Fintype.expect_prod_type, Fintype.expect_prod_type] + refine expect_congr rfl fun y _ ↦ ?_ + simp only [Fintype.expect_prod_type, upd2] + rw [Fintype.expect_expect_update (fun s ↦ 𝔼 b, Φ (y, update s j b)) i, + Fintype.expect_expect_update (fun s ↦ Φ (y, s)) j] + +/-- **One coordinate, from the moves of a pair containing it**: the second moment of `f` about its +average over `w i` is at most `512` times the total squared change of `f` along the four moves of +the pair `(i, j)`, for `i ≠ j`. -/ +theorem expect_sq_sub_expect_update_le_pairShearTranslation (ρ ρ' : Equiv.Perm Y) {i j : Fin H} + (hij : i ≠ j) (f : Y × (Fin H → ZMod L) → ℝ) : + 𝔼 p, (f p - 𝔼 a, f (p.1, update p.2 i a)) ^ 2 ≤ + 512 * ∑ k, 𝔼 p, (f (pairShearTranslationMove ρ ρ' i j k p) - f p) ^ 2 := by + -- The average over the pair `(w i, w j)`. + set G : Y × (Fin H → ZMod L) → ℝ := fun p ↦ 𝔼 a, 𝔼 b, f (p.1, upd2 i j p.2 a b) with hG + have hGinv (p : Y × (Fin H → ZMod L)) (a b : ZMod L) : G (p.1, upd2 i j p.2 a b) = G p := by + simp only [hG, upd2_upd2] + refine (Fintype.expect_sq_sub_expect_update_le i f G fun p c ↦ ?_).trans ?_ + · have := hGinv p c (update p.2 i c j) + simpa only [upd2, update_eq_self] using this + -- The relative Poincaré inequality, with everything but the pair as the spectator. + set F : (Y × (Fin H → ZMod L)) × (ZMod L × ZMod L) → ℝ := + fun q ↦ f (q.1.1, upd2 i j q.1.2 q.2.1 q.2.2) with hF + have hA := expect_sq_sub_expect_fiber_le_twistedShearTranslation + (ρ.prodCongr (Equiv.refl _)) (ρ'.prodCongr (Equiv.refl _)) F + have hL : 𝔼 q, (F q - 𝔼 v, F (q.1, v)) ^ 2 = 𝔼 p, (f p - G p) ^ 2 := by + rw [← expect_upd2 i j fun p ↦ (f p - G p) ^ 2] + refine expect_congr rfl fun q _ ↦ ?_ + rw [hGinv] + simp only [hF, hG, Fintype.expect_prod_type] + have hR (k : Fin 4) : 𝔼 q, (F (twistedShearTranslationMove (ρ.prodCongr (Equiv.refl _)) + (ρ'.prodCongr (Equiv.refl _)) L k q) - F q) ^ 2 = + 𝔼 p, (f (pairShearTranslationMove ρ ρ' i j k p) - f p) ^ 2 := by + rw [← expect_upd2 i j fun p ↦ (f (pairShearTranslationMove ρ ρ' i j k p) - f p) ^ 2] + refine expect_congr rfl fun q _ ↦ ?_ + obtain ⟨⟨y, w⟩, a, b⟩ := q + fin_cases k <;> + simp [hF, twistedShearTranslationMove, pairShearTranslationMove, shearFst_apply, + shearSnd_apply, upd2_apply_fst hij, update_upd2_fst hij, upd2] + rw [hL] at hA + refine hA.trans_eq ?_ + simp only [hR] + +/-- **All coordinates, from the moves of coordinate pairs**: if `σ i ≠ i` for every coordinate `i`, +the second moment of `f` about its average over the whole tuple is at most `512` times the sum over +`i` of the total squared change of `f` along the four moves of the pair `(i, σ i)`, where `ρ i j` +acts on `Y` with the shear `w ↦ w + w j • e i`. -/ +theorem expect_sq_sub_expect_le_pairShearTranslation {Y : Type} [Fintype Y] + (ρ : Fin H → Fin H → Equiv.Perm Y) (σ : Fin H → Fin H) (hσ : ∀ i, σ i ≠ i) + (f : Y × (Fin H → ZMod L) → ℝ) : + 𝔼 p, (f p - 𝔼 w, f (p.1, w)) ^ 2 ≤ + 512 * ∑ i, ∑ k, 𝔼 p, + (f (pairShearTranslationMove (ρ i (σ i)) (ρ (σ i) i) i (σ i) k p) - f p) ^ 2 := by + refine (Fintype.expect_sq_sub_expect_le_sum_expect_sq_sub_update f).trans ?_ + rw [mul_sum] + exact sum_le_sum fun i _ ↦ + expect_sq_sub_expect_update_le_pairShearTranslation _ _ (hσ i).symm f + +end Cslib.RotationMap diff --git a/Complexity/Foundations/Probability/EfronStein.lean b/Complexity/Foundations/Probability/EfronStein.lean new file mode 100644 index 000000000..05b114c4a --- /dev/null +++ b/Complexity/Foundations/Probability/EfronStein.lean @@ -0,0 +1,141 @@ +/- +Copyright (c) 2026 Christian Reitwiessner. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Christian Reitwiessner +-/ + +module +-- upstream: candidate + +public import Complexity.Foundations.Data.Finset.Expect +import Mathlib.Algebra.BigOperators.Fin +import Mathlib.Algebra.Order.BigOperators.Expect +import Mathlib.Data.Fin.Tuple.Basic + +/-! +# The Efron–Stein inequality for uniform averages + +For a function `f` of a spectator `y` and of a uniformly random tuple `w : Fin n → A`, the second +moment of `f` about its average over `w` is at most the sum, over the coordinates `i`, of the second +moments of `f` about its averages over the single coordinate `w i` +(`Fintype.expect_sq_sub_expect_le_sum_expect_sq_sub_update`): +`𝔼 (f - 𝔼_w f)² ≤ ∑ i, 𝔼 (f - 𝔼_{w i} f)²`. This is the Efron–Stein inequality for the uniform +product measure, with the spectator as an extra fixed coordinate. It reduces the distance of `f` +from the functions of `y` alone to its distances from the functions not depending on one coordinate +at a time. + +The proof is by induction on `n`: split `w = Fin.cons a r`, decompose orthogonally over the fibers +of `(y, a)`, apply the induction hypothesis with the spectator `(y, a)` to the part of average zero +on these fibers, and bound the fiber averages by Jensen's inequality. + +## Main results + +* `Fintype.expect_sq_sub_expect_le_sum_expect_sq_sub_update`: the Efron–Stein inequality. +* `Fintype.expect_sq_sub_expect_update_le`: the average over one coordinate is the best + approximation by functions not depending on it. +-/ + +public section + +open Finset Function +open scoped BigOperators + +namespace Fintype + +/-- The second moment about a constant is the second moment about the average plus the squared +distance of the average from the constant. -/ +private theorem expect_sub_sq_eq {R : Type*} [Fintype R] [Nonempty R] (X : R → ℝ) (c : ℝ) : + 𝔼 r, (X r - c) ^ 2 = 𝔼 r, (X r - 𝔼 s, X s) ^ 2 + (𝔼 s, X s - c) ^ 2 := by + set m := 𝔼 s, X s + have h : 𝔼 r, (X r - m) = 0 := by rw [expect_sub_distrib, Fintype.expect_const, sub_self] + calc 𝔼 r, (X r - c) ^ 2 = 𝔼 r, ((X r - m) ^ 2 + 2 * (m - c) * (X r - m) + (m - c) ^ 2) := + expect_congr rfl fun r _ ↦ by ring + _ = _ := by rw [expect_add_distrib, expect_add_distrib, ← mul_expect, h, mul_zero, add_zero, + Fintype.expect_const] + +/-- **The average over one coordinate is the best approximation** by functions not depending on +that coordinate: if `G` does not change when `w i` is resampled, then the second moment of `f` about +its average over `w i` is at most the second moment of `f - G`. -/ +theorem expect_sq_sub_expect_update_le {ι Y A : Type*} [Fintype ι] [DecidableEq ι] [Fintype Y] + [Fintype A] [Nonempty A] (i : ι) (f G : Y × (ι → A) → ℝ) + (hG : ∀ p c, G (p.1, update p.2 i c) = G p) : + 𝔼 p, (f p - 𝔼 a, f (p.1, update p.2 i a)) ^ 2 ≤ 𝔼 p, (f p - G p) ^ 2 := by + set R : Y × (ι → A) → ℝ := fun p ↦ 𝔼 a, f (p.1, update p.2 i a) with hR + -- The part of `f` of average zero over `w i` is orthogonal to the functions not depending on it. + have horth : 𝔼 p, (f p - R p) * (R p - G p) = 0 := by + rw [Fintype.expect_prod_type] + refine expect_eq_zero fun y _ ↦ ?_ + rw [← Fintype.expect_expect_update _ i] + refine expect_eq_zero fun w _ ↦ ?_ + have h2 (a : A) : G (y, update w i a) = G (y, w) := hG (y, w) a + simp only [hR, update_idem, h2] + rw [← expect_mul, expect_sub_distrib, Fintype.expect_const, sub_self, zero_mul] + calc 𝔼 p, (f p - R p) ^ 2 ≤ 𝔼 p, ((f p - R p) ^ 2 + 2 * ((f p - R p) * (R p - G p)) + + (R p - G p) ^ 2) := by + rw [expect_add_distrib, expect_add_distrib, ← mul_expect, horth, mul_zero, add_zero] + exact le_add_of_nonneg_right (expect_nonneg fun _ _ ↦ sq_nonneg _) + _ = 𝔼 p, (f p - G p) ^ 2 := expect_congr rfl fun p _ ↦ by ring + +universe u + +variable {A : Type u} [Fintype A] [Nonempty A] + +/-- **The Efron–Stein inequality** for a uniformly random tuple `w : Fin n → A` and a spectator +`y`: the second moment of `f` about its average over `w` is at most the sum over the coordinates +`i` of the second moments of `f` about its averages over `w i`. The spectator lives in the +universe of `A`, so that the induction can absorb coordinates into it. -/ +theorem expect_sq_sub_expect_le_sum_expect_sq_sub_update {n : ℕ} {Y : Type u} [Fintype Y] + (f : Y × (Fin n → A) → ℝ) : + 𝔼 p, (f p - 𝔼 w, f (p.1, w)) ^ 2 ≤ ∑ i, 𝔼 p, (f p - 𝔼 a, f (p.1, update p.2 i a)) ^ 2 := by + induction n generalizing Y with + | zero => + have h (p : Y × (Fin 0 → A)) : f p - 𝔼 w, f (p.1, w) = 0 := by + rw [Fintype.expect_unique, sub_eq_zero] + exact congrArg f (Prod.ext rfl (Subsingleton.elim _ _)) + simp only [h] + simp + | succ n ih => + -- Split the tuple into its head `a` and tail `r`. + have hsplit (G : Y × (Fin (n + 1) → A) → ℝ) : + 𝔼 p, G p = 𝔼 y, 𝔼 a, 𝔼 r : Fin n → A, G (y, Fin.cons a r) := by + rw [Fintype.expect_prod_type] + exact expect_congr rfl fun y _ ↦ Fin.expect_univ_cons fun w ↦ G (y, w) + set g : (Y × A) × (Fin n → A) → ℝ := fun q ↦ f (q.1.1, Fin.cons q.1.2 q.2) with hg + have hIH := ih g + have hsplit' (G : (Y × A) × (Fin n → A) → ℝ) : + 𝔼 q, G q = 𝔼 y, 𝔼 a, 𝔼 r, G ((y, a), r) := by + rw [Fintype.expect_prod_type, Fintype.expect_prod_type] + -- The average over the whole tuple, and over its tail. + set h : Y × A → ℝ := fun q ↦ 𝔼 r, g (q, r) with hh + have hM (y : Y) : 𝔼 w, f (y, w) = 𝔼 a, h (y, a) := Fin.expect_univ_cons fun w ↦ f (y, w) + -- Orthogonal decomposition over the fibers of `(y, a)`. + have hLHS : 𝔼 p, (f p - 𝔼 w, f (p.1, w)) ^ 2 = + 𝔼 q, (g q - 𝔼 r, g (q.1, r)) ^ 2 + 𝔼 y, 𝔼 a, (h (y, a) - 𝔼 a', h (y, a')) ^ 2 := by + rw [hsplit, hsplit', ← expect_add_distrib] + refine expect_congr rfl fun y _ ↦ ?_ + rw [← expect_add_distrib] + refine expect_congr rfl fun a _ ↦ ?_ + simp only [hM] + exact expect_sub_sq_eq (fun r ↦ g ((y, a), r)) _ + -- The tail coordinates, by the induction hypothesis. + have htail (i : Fin n) : 𝔼 q, (g q - 𝔼 b, g (q.1, update q.2 i b)) ^ 2 = + 𝔼 p, (f p - 𝔼 b, f (p.1, update p.2 i.succ b)) ^ 2 := by + rw [hsplit, hsplit'] + simp only [hg, Fin.cons_update] + -- The head coordinate, by Jensen's inequality. + have hhead : 𝔼 y, 𝔼 a, (h (y, a) - 𝔼 a', h (y, a')) ^ 2 ≤ + 𝔼 p, (f p - 𝔼 b, f (p.1, update p.2 0 b)) ^ 2 := by + rw [hsplit] + refine expect_le_expect fun y _ ↦ expect_le_expect fun a _ ↦ ?_ + have : h (y, a) - 𝔼 a', h (y, a') = + 𝔼 r, (f (y, Fin.cons a r) - 𝔼 b, f (y, update (Fin.cons a r) 0 b)) := by + simp only [hh, hg, Fin.update_cons_zero, expect_sub_distrib] + rw [expect_comm] + rw [this] + exact sq_expect_le_expect_sq _ _ + rw [hLHS, Fin.sum_univ_succ] + calc _ ≤ ∑ i : Fin n, 𝔼 q, (g q - 𝔼 b, g (q.1, update q.2 i b)) ^ 2 + + 𝔼 p, (f p - 𝔼 b, f (p.1, update p.2 0 b)) ^ 2 := add_le_add hIH hhead + _ = _ := by rw [add_comm]; simp only [htail] + +end Fintype diff --git a/ComplexityTests/PairShearTranslation.lean b/ComplexityTests/PairShearTranslation.lean new file mode 100644 index 000000000..cb28f0927 --- /dev/null +++ b/ComplexityTests/PairShearTranslation.lean @@ -0,0 +1,52 @@ +/- +Copyright (c) 2026 Christian Reitwiessner. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Christian Reitwiessner +-/ + +import Complexity.Foundations.Combinatorics.Expander.PairShearTranslation +import Complexity.Foundations.Probability.EfronStein + +/-! +# Shears and translations of coordinate pairs + +Concrete pair moves on `ZMod 2 × (Fin 3 → ZMod 5)`, an instance of the Efron–Stein inequality, and +a client of the pair bound: a function invariant under the moves of the pairs +`(i, i + 1)` of `Fin 3` depends only on the spectator, for every modulus `L` and every action on +the spectator. +-/ + +namespace ComplexityTests.PairShearTranslation + +open Cslib Cslib.RotationMap Finset Function +open scoped BigOperators + +-- The shear `w ↦ w + w 1 • e 0` acts on the spectator by `ρ`; the translation `w ↦ w + e 2` does +-- not. +example : pairShearTranslationMove (L := 5) (Equiv.addRight (1 : ZMod 2)) (Equiv.refl _) 0 1 0 + (0, ![1, 2, 3]) = (1, ![3, 2, 3]) := by decide +example : pairShearTranslationMove (L := 5) (Equiv.addRight (1 : ZMod 2)) (Equiv.refl _) 2 0 1 + (0, ![1, 2, 4]) = (0, ![0, 2, 4]) := by decide +example : pairShearTranslationMove (L := 5) (Equiv.addRight (1 : ZMod 2)) (Equiv.refl _) 1 2 3 + (0, ![1, 2, 4]) = (0, ![1, 2, 0]) := by decide + +/-- The Efron–Stein inequality instantiates with a trivial spectator and the alphabet `Bool`. -/ +example (f : Unit × (Fin 2 → Bool) → ℝ) : + 𝔼 p, (f p - 𝔼 w, f (p.1, w)) ^ 2 ≤ ∑ i, 𝔼 p, (f p - 𝔼 a, f (p.1, update p.2 i a)) ^ 2 := + Fintype.expect_sq_sub_expect_le_sum_expect_sq_sub_update f + +/-- **A client**: on `Y × (Fin 3 → ZMod L)`, a real function invariant under the moves of the +pairs `(i, i + 1)` depends only on the spectator, whatever the actions `ρ` on `Y`. -/ +example {Y : Type} [Fintype Y] (L : ℕ) [NeZero L] (ρ : Fin 3 → Fin 3 → Equiv.Perm Y) + (f : Y × (Fin 3 → ZMod L) → ℝ) + (hf : ∀ i j k p, f (pairShearTranslationMove (ρ i j) (ρ j i) i j k p) = f p) + (p : Y × (Fin 3 → ZMod L)) : + f p = 𝔼 w, f (p.1, w) := by + have h := expect_sq_sub_expect_le_pairShearTranslation ρ (fun i ↦ i + 1) (by decide) f + simp only [hf, sub_self, ne_eq, OfNat.ofNat_ne_zero, not_false_eq_true, zero_pow, + expect_const_zero, sum_const_zero, mul_zero] at h + have h0 := (Fintype.expect_eq_zero_iff_of_nonneg fun q ↦ sq_nonneg + (f q - 𝔼 w, f (q.1, w))).1 (le_antisymm h (expect_nonneg fun _ _ ↦ sq_nonneg _)) + exact sub_eq_zero.1 (pow_eq_zero_iff two_ne_zero |>.1 (congrFun h0 p)) + +end ComplexityTests.PairShearTranslation From a547de38dc89ede2ccd896a86e6b71cdf36a8bf0 Mon Sep 17 00:00:00 2001 From: Christian Reitwiessner Date: Fri, 30 Oct 2026 01:23:37 +0000 Subject: [PATCH 11/13] =?UTF-8?q?doc(Probability):=20cite=20Efron=E2=80=93?= =?UTF-8?q?Stein=20and=20Steele;=20numeric=20Efron=E2=80=93Stein=20test=20?= =?UTF-8?q?(#1682)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Review fixes for #1699: - references.bib: EfronStein1981 (Ann. Statist. 9(3):586–596) and Steele1986 (Ann. Statist. 14(2):753–758), with DOIs; - EfronStein.lean cites both and gains a References section; - PairShearTranslation.lean notes that the all-coordinates bound is vacuous for H = 1; - the test computes both sides of Efron–Stein for the agreement indicator on Fin 2 → Bool (1/4 ≤ 1/2). Co-Authored-By: Claude Opus 5.5 --- .../Expander/PairShearTranslation.lean | 3 ++- .../Foundations/Probability/EfronStein.lean | 11 ++++++-- ComplexityTests/PairShearTranslation.lean | 26 ++++++++++++++----- references.bib | 22 ++++++++++++++++ 4 files changed, 53 insertions(+), 9 deletions(-) diff --git a/Complexity/Foundations/Combinatorics/Expander/PairShearTranslation.lean b/Complexity/Foundations/Combinatorics/Expander/PairShearTranslation.lean index 0ab4b088a..c438ae30f 100644 --- a/Complexity/Foundations/Combinatorics/Expander/PairShearTranslation.lean +++ b/Complexity/Foundations/Combinatorics/Expander/PairShearTranslation.lean @@ -22,7 +22,8 @@ where `ρ` is the action of the same elementary matrix on the frames. The second moment of `f` about its average over the whole tuple `w` is at most `512` times the sum, over the coordinates `i`, of the total squared change of `f` along the moves of a pair `(i, σ i)` -with `σ i ≠ i` (`expect_sq_sub_expect_le_pairShearTranslation`). The proof combines: +with `σ i ≠ i` (`expect_sq_sub_expect_le_pairShearTranslation`). Such a `σ` exists only when +`H ≠ 1`; for `H = 1` the hypothesis cannot hold, and the bound says nothing. The proof combines: * the Efron–Stein inequality (`Fintype.expect_sq_sub_expect_le_sum_expect_sq_sub_update`), which reduces the distance from the functions of `y` alone to the distances from the functions not diff --git a/Complexity/Foundations/Probability/EfronStein.lean b/Complexity/Foundations/Probability/EfronStein.lean index 05b114c4a..0db7e9bc0 100644 --- a/Complexity/Foundations/Probability/EfronStein.lean +++ b/Complexity/Foundations/Probability/EfronStein.lean @@ -19,8 +19,10 @@ For a function `f` of a spectator `y` and of a uniformly random tuple `w : Fin n moment of `f` about its average over `w` is at most the sum, over the coordinates `i`, of the second moments of `f` about its averages over the single coordinate `w i` (`Fintype.expect_sq_sub_expect_le_sum_expect_sq_sub_update`): -`𝔼 (f - 𝔼_w f)² ≤ ∑ i, 𝔼 (f - 𝔼_{w i} f)²`. This is the Efron–Stein inequality for the uniform -product measure, with the spectator as an extra fixed coordinate. It reduces the distance of `f` +`𝔼 (f - 𝔼_w f)² ≤ ∑ i, 𝔼 (f - 𝔼_{w i} f)²`. This is the Efron–Stein inequality +[Efron and Stein][EfronStein1981] in the general form for functions that need not be symmetric +[Steele][Steele1986], for the uniform product measure and with the spectator as an extra fixed +coordinate. It reduces the distance of `f` from the functions of `y` alone to its distances from the functions not depending on one coordinate at a time. @@ -33,6 +35,11 @@ on these fibers, and bound the fiber averages by Jensen's inequality. * `Fintype.expect_sq_sub_expect_le_sum_expect_sq_sub_update`: the Efron–Stein inequality. * `Fintype.expect_sq_sub_expect_update_le`: the average over one coordinate is the best approximation by functions not depending on it. + +## References + +* [B. Efron, C. Stein, *The Jackknife Estimate of Variance*][EfronStein1981] +* [J. M. Steele, *An Efron-Stein Inequality for Nonsymmetric Statistics*][Steele1986] -/ public section diff --git a/ComplexityTests/PairShearTranslation.lean b/ComplexityTests/PairShearTranslation.lean index cb28f0927..216bc9e72 100644 --- a/ComplexityTests/PairShearTranslation.lean +++ b/ComplexityTests/PairShearTranslation.lean @@ -10,8 +10,8 @@ import Complexity.Foundations.Probability.EfronStein /-! # Shears and translations of coordinate pairs -Concrete pair moves on `ZMod 2 × (Fin 3 → ZMod 5)`, an instance of the Efron–Stein inequality, and -a client of the pair bound: a function invariant under the moves of the pairs +Concrete pair moves on `ZMod 2 × (Fin 3 → ZMod 5)`, a concrete instance of the Efron–Stein +inequality, and a client of the pair bound: a function invariant under the moves of the pairs `(i, i + 1)` of `Fin 3` depends only on the spectator, for every modulus `L` and every action on the spectator. -/ @@ -30,10 +30,24 @@ example : pairShearTranslationMove (L := 5) (Equiv.addRight (1 : ZMod 2)) (Equiv example : pairShearTranslationMove (L := 5) (Equiv.addRight (1 : ZMod 2)) (Equiv.refl _) 1 2 3 (0, ![1, 2, 4]) = (0, ![1, 2, 0]) := by decide -/-- The Efron–Stein inequality instantiates with a trivial spectator and the alphabet `Bool`. -/ -example (f : Unit × (Fin 2 → Bool) → ℝ) : - 𝔼 p, (f p - 𝔼 w, f (p.1, w)) ^ 2 ≤ ∑ i, 𝔼 p, (f p - 𝔼 a, f (p.1, update p.2 i a)) ^ 2 := - Fintype.expect_sq_sub_expect_le_sum_expect_sq_sub_update f +/-- The indicator that the two coordinates of a uniform `w : Fin 2 → Bool` agree. -/ +noncomputable def eqInd (p : Unit × (Fin 2 → Bool)) : ℝ := if p.2 0 = p.2 1 then 1 else 0 + +/-- **Efron–Stein on a concrete function**: the second moment of `eqInd` about its average is +`1 / 4`, and the sum of the single-coordinate terms is `1 / 2`. -/ +example : 𝔼 p, (eqInd p - 𝔼 w, eqInd (p.1, w)) ^ 2 = 1 / 4 ∧ + ∑ i, 𝔼 p, (eqInd p - 𝔼 a, eqInd (p.1, update p.2 i a)) ^ 2 = 1 / 2 := by + constructor + · simp only [Fintype.expect_prod_type, Fin.expect_univ_cons, Fintype.expect_bool, + Fintype.expect_unique] + norm_num [eqInd] + · simp only [Fin.sum_univ_two, Fintype.expect_prod_type, Fin.expect_univ_cons, + Fintype.expect_bool, Fintype.expect_unique] + norm_num [eqInd, update_apply] + +example : 𝔼 p, (eqInd p - 𝔼 w, eqInd (p.1, w)) ^ 2 ≤ + ∑ i, 𝔼 p, (eqInd p - 𝔼 a, eqInd (p.1, update p.2 i a)) ^ 2 := + Fintype.expect_sq_sub_expect_le_sum_expect_sq_sub_update eqInd /-- **A client**: on `Y × (Fin 3 → ZMod L)`, a real function invariant under the moves of the pairs `(i, i + 1)` depends only on the spectator, whatever the actions `ρ` on `Y`. -/ diff --git a/references.bib b/references.bib index 7cae42ed4..213b20d08 100644 --- a/references.bib +++ b/references.bib @@ -1351,6 +1351,17 @@ @inproceedings{DunkelmanKellerShamir2012 doi = {10.1007/978-3-642-29011-4_21} } +@article{EfronStein1981, + author = {Efron, Bradley and Stein, Charles}, + title = {The Jackknife Estimate of Variance}, + journal = {The Annals of Statistics}, + volume = {9}, + number = {3}, + pages = {586--596}, + year = {1981}, + doi = {10.1214/aos/1176345462} +} + @article{EHKV1989, author = {Ehrenfeucht, Andrzej and Haussler, David and Kearns, Michael and Valiant, Leslie}, title = {A General Lower Bound on the Number of Examples Needed for Learning}, @@ -4198,6 +4209,17 @@ @inproceedings{StearnsHartmanisLewis1965 doi = {10.1109/FOCS.1965.11} } +@article{Steele1986, + author = {Steele, J. Michael}, + title = {An {Efron}-{Stein} Inequality for Nonsymmetric Statistics}, + journal = {The Annals of Statistics}, + volume = {14}, + number = {2}, + pages = {753--758}, + year = {1986}, + doi = {10.1214/aos/1176349952} +} + @article{Stockmeyer1976, author = {Stockmeyer, Larry J.}, title = {The Polynomial-Time Hierarchy}, From 0e293465b7b299aaa5ddbe22cbf8199b0238f638 Mon Sep 17 00:00:00 2001 From: Christian Reitwiessner Date: Fri, 30 Oct 2026 01:30:57 +0000 Subject: [PATCH 12/13] =?UTF-8?q?feat(Expander):=20Poincar=C3=A9=20inequal?= =?UTF-8?q?ity=20for=20elementary=20moves=20on=20nonzero=20vectors=20of=20?= =?UTF-8?q?(ZMod=20P)^H=20(#1682)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Step (C) of the frame-lifted gap plan on #1682: for a prime P and H ≥ 3, every real function on (ZMod P)^H is, on the nonzero vectors, within 36864 H² times its total squared change along the elementary moves F ↦ F + F b • e a (a ≠ b) of some constant, uniformly in P. On each fiber {F k = c ≠ 0}, F = c • w off k turns the moves into the elementary shears and unit translations of w, so #1699's pair bound and Efron–Stein (with c as the spectator) make g close to its fiber averages; the fibrations for different k are glued on {F k ≠ 0, F l ≠ 0}, where F k and F l are independent and uniform. Co-Authored-By: Claude Opus 5.5 --- Complexity.lean | 1 + .../Expander/ElementaryMove.lean | 452 ++++++++++++++++++ ComplexityTests/ElementaryMove.lean | 50 ++ 3 files changed, 503 insertions(+) create mode 100644 Complexity/Foundations/Combinatorics/Expander/ElementaryMove.lean create mode 100644 ComplexityTests/ElementaryMove.lean diff --git a/Complexity.lean b/Complexity.lean index 19a2904f6..c1cc2370f 100644 --- a/Complexity.lean +++ b/Complexity.lean @@ -2358,6 +2358,7 @@ public import Complexity.Foundations.Combinatorics.Expander.Cayley public import Complexity.Foundations.Combinatorics.Expander.Cheeger public import Complexity.Foundations.Combinatorics.Expander.Connected public import Complexity.Foundations.Combinatorics.Expander.Contraction +public import Complexity.Foundations.Combinatorics.Expander.ElementaryMove public import Complexity.Foundations.Combinatorics.Expander.Existence public import Complexity.Foundations.Combinatorics.Expander.Family public import Complexity.Foundations.Combinatorics.Expander.Hitting diff --git a/Complexity/Foundations/Combinatorics/Expander/ElementaryMove.lean b/Complexity/Foundations/Combinatorics/Expander/ElementaryMove.lean new file mode 100644 index 000000000..07a2195fc --- /dev/null +++ b/Complexity/Foundations/Combinatorics/Expander/ElementaryMove.lean @@ -0,0 +1,452 @@ +/- +Copyright (c) 2026 Christian Reitwiessner. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Christian Reitwiessner +-/ + +module +-- upstream: candidate + +public import Complexity.Foundations.Combinatorics.Expander.PairShearTranslation +public import Mathlib.Data.ZMod.Basic +import Complexity.Foundations.Probability.EfronStein + +/-! +# Elementary moves on the nonzero vectors of `𝔽_P ^ H` + +The elementary move `elementaryMove a b` adds the coordinate `b` of a vector `F : Fin H → ZMod P` +to its coordinate `a`: it is the action of the elementary matrix `1 + E_ab` of `SL_H(ℤ)`. For a +prime `P` and `H ≥ 3`, these moves mix the nonzero vectors uniformly in `P`: every real function `g` +is close to a constant on the nonzero vectors, with second moment about that constant at most +`36864 H²` times the total squared change of `g` along the elementary moves +(`exists_expect_sq_sub_le_elementaryMove`). These vectors are the frames of length one, the +channel coefficients that the sampling environment moves by left multiplication. + +The proof reduces to the gap of the shear-translation graph on `ZMod P × ZMod P`: + +* **Fibers.** On the vectors with `F k = c ≠ 0`, write `F = c • w` off the coordinate `k`. In + these coordinates the moves `1 + E_ij` with `i, j ≠ k` are the elementary shears of `w`, and the + moves `1 + E_ik` are the unit translations of `w`, since they add `F k = c`. The pair bound + `expect_sq_sub_expect_update_le_pairShearTranslation` and the Efron–Stein inequality therefore + make `g` close to its fiber averages `h_k (F k)` on `{F k ≠ 0}`, with the values `c` as the + spectator. This needs a partner coordinate different from `i` and `k`, hence `H ≥ 3`. +* **Gluing.** On `{F k ≠ 0, F l ≠ 0}` with `k ≠ l`, the coordinates `F k` and `F l` are independent + and uniform, so `h_k (F k) ≈ h_l (F l)` forces both functions to be close to one constant, the + average of `h_0` over the nonzero values. Every nonzero vector has a nonzero coordinate. + +This is the frame part of the averaging walk in the OpenAI preprint on derandomizing logarithmic +space, for frames of length one: the preprint gets it from property (T) of `SL_H(ℤ)` for `H ≥ 3` +[OpenAI, Lemma 6.1][OpenAI2026LogSpace] and the transitivity of the action on frames +[OpenAI, proof of Lemma 6.2][OpenAI2026LogSpace]. An elementary lift of the relative gap to frames +is in OpenAI's Lean development, the file +[`AffineSampling.lean`](https://github.com/openai/math/blob/7ef5c0cc5ca4b0e072b7a050fca09ab24bc6fa3a/lean/OAI/Computability/Logspace/AffineSampling.lean) +at revision `7ef5c0cc` (`slice_frame`, `frame_gap`, `slice_gap`). The statements and the proof +here are independent of that code, which was not consulted. The fiber-and-gluing argument is ours. + +## Main definitions + +* `Cslib.RotationMap.elementaryMove`: the move `F ↦ F + F b • e a`. + +## Main results + +* `Cslib.RotationMap.exists_expect_sq_sub_le_elementaryMove`: the Poincaré inequality for the + elementary moves on the nonzero vectors of `(ZMod P) ^ H`, uniformly in the prime `P`. + +## References + +* [OpenAI, *Exact Derandomization of Logarithmic Space: L = RL = BPL*][OpenAI2026LogSpace] +-/ + +public section + +open Finset Function +open scoped BigOperators + +namespace Cslib.RotationMap + +variable {P H : ℕ} + +/-- The elementary move `F ↦ F + F b • e a`: the action of the elementary matrix `1 + E_ab`. -/ +@[expose] +def elementaryMove (a b : Fin H) (F : Fin H → ZMod P) : Fin H → ZMod P := + update F a (F a + F b) + +variable [Fact P.Prime] + +/-- The indicator of the nonzero elements of `ZMod P`. -/ +private noncomputable def nz (c : ZMod P) : ℝ := if c = 0 then 0 else 1 + +private theorem nz_nonneg (c : ZMod P) : 0 ≤ nz c := by + unfold nz; split_ifs <;> norm_num + +private theorem nz_le_one (c : ZMod P) : nz c ≤ 1 := by + unfold nz; split_ifs <;> norm_num + +private theorem nz_mul_self (c : ZMod P) : nz c * nz c = nz c := by + unfold nz; split_ifs <;> norm_num + +/-- At least half of the elements of `ZMod P` are nonzero. -/ +private theorem half_le_expect_nz : (1 / 2 : ℝ) ≤ 𝔼 c : ZMod P, nz c := by + have h (c : ZMod P) : nz c = 1 - if c = 0 then 1 else 0 := by + unfold nz; split_ifs <;> norm_num + have hP : (2 : ℝ) ≤ P := by exact_mod_cast (Fact.out : P.Prime).two_le + have hsum : (∑ _c : ZMod P, (1 : ℝ)) = P := by simp + simp only [h, expect_sub_distrib, Fintype.expect_eq_sum_div_card, sum_ite_eq', mem_univ, + ite_true, ZMod.card, hsum] + rw [div_self (by positivity)] + have : (1 : ℝ) / P ≤ 1 / 2 := by + rw [div_le_div_iff₀ (by positivity) (by norm_num)] + linarith + linarith + +/-- The weighted second moment about `a` is the weighted second moment about the weighted mean plus +the squared distance of the mean from `a`. -/ +private theorem expect_mul_sq_sub_eq {α : Type*} [Fintype α] (w X : α → ℝ) (a : ℝ) + (hW : 𝔼 x, w x ≠ 0) : + 𝔼 x, w x * (X x - a) ^ 2 = + 𝔼 x, w x * (X x - (𝔼 y, w y * X y) / 𝔼 y, w y) ^ 2 + + (𝔼 x, w x) * ((𝔼 y, w y * X y) / 𝔼 y, w y - a) ^ 2 := by + set W := 𝔼 y, w y + set m := (𝔼 y, w y * X y) / W + have h0 : 𝔼 x, w x * (X x - m) = 0 := by + simp only [mul_sub, expect_sub_distrib, ← expect_mul, m] + field_simp + ring + calc 𝔼 x, w x * (X x - a) ^ 2 + = 𝔼 x, (w x * (X x - m) ^ 2 + 2 * (m - a) * (w x * (X x - m)) + w x * (m - a) ^ 2) := + expect_congr rfl fun x _ ↦ by ring + _ = _ := by + rw [expect_add_distrib, expect_add_distrib, ← mul_expect, h0, mul_zero, add_zero, + ← expect_mul] + +/-- In particular the weighted second moment about `a` is at least the total weight times the +squared distance of the weighted mean from `a`, and at least the weighted second moment about the +weighted mean. -/ +private theorem expect_mul_sq_sub_ge {α : Type*} [Fintype α] (w X : α → ℝ) (a : ℝ) + (hw : ∀ x, 0 ≤ w x) (hW : 𝔼 x, w x ≠ 0) : + (𝔼 x, w x) * ((𝔼 y, w y * X y) / 𝔼 y, w y - a) ^ 2 ≤ 𝔼 x, w x * (X x - a) ^ 2 ∧ + 𝔼 x, w x * (X x - (𝔼 y, w y * X y) / 𝔼 y, w y) ^ 2 ≤ 𝔼 x, w x * (X x - a) ^ 2 := by + rw [expect_mul_sq_sub_eq w X a hW] + have h1 : 0 ≤ 𝔼 x, w x * (X x - (𝔼 y, w y * X y) / 𝔼 y, w y) ^ 2 := + expect_nonneg fun x _ ↦ mul_nonneg (hw x) (sq_nonneg _) + have h2 : 0 ≤ (𝔼 x, w x) * ((𝔼 y, w y * X y) / 𝔼 y, w y - a) ^ 2 := + mul_nonneg (expect_nonneg fun x _ ↦ hw x) (sq_nonneg _) + exact ⟨by linarith, by linarith⟩ + +/-- One coordinate of a uniformly random vector is uniform. -/ +private theorem expect_comp_eval (k : Fin H) (φ : ZMod P → ℝ) : + 𝔼 F : Fin H → ZMod P, φ (F k) = 𝔼 c, φ c := by + calc 𝔼 F : Fin H → ZMod P, φ (F k) = 𝔼 F : Fin H → ZMod P, 𝔼 c, φ (update F k c k) := + (Fintype.expect_expect_update (fun F ↦ φ (F k)) k).symm + _ = 𝔼 c, φ c := by simp only [update_self, Fintype.expect_const] + +/-- Two distinct coordinates of a uniformly random vector are independent and uniform. -/ +private theorem expect_comp_eval_eval {k l : Fin H} (hkl : k ≠ l) (φ : ZMod P → ZMod P → ℝ) : + 𝔼 F : Fin H → ZMod P, φ (F k) (F l) = 𝔼 c, 𝔼 d, φ c d := by + calc 𝔼 F : Fin H → ZMod P, φ (F k) (F l) + = 𝔼 F : Fin H → ZMod P, 𝔼 c, φ (update F k c k) (update F k c l) := + (Fintype.expect_expect_update (fun F ↦ φ (F k) (F l)) k).symm + _ = 𝔼 c, 𝔼 F : Fin H → ZMod P, φ c (F l) := by + simp only [update_self, update_of_ne hkl.symm] + exact expect_comm _ _ _ + _ = _ := expect_congr rfl fun c _ ↦ expect_comp_eval l (φ c) + +/-- Scaling by a nonzero element preserves the uniform average. -/ +private theorem expect_comp_smul {c : ZMod P} (hc : c ≠ 0) (φ : (Fin H → ZMod P) → ℝ) : + 𝔼 w, φ (c • w) = 𝔼 w, φ w := by + let e : (Fin H → ZMod P) ≃ (Fin H → ZMod P) := + ⟨fun w ↦ c • w, fun w ↦ c⁻¹ • w, fun w ↦ by simp [smul_smul, inv_mul_cancel₀ hc], + fun w ↦ by simp [smul_smul, mul_inv_cancel₀ hc]⟩ + exact Fintype.expect_equiv e _ _ fun _ ↦ rfl + +/-- The total squared change of `g` along the elementary moves. -/ +private noncomputable abbrev dir (g : (Fin H → ZMod P) → ℝ) : ℝ := + ∑ a, ∑ b ∈ univ.erase a, 𝔼 F, (g (elementaryMove a b F) - g F) ^ 2 + +private theorem le_dir (g : (Fin H → ZMod P) → ℝ) {a b : Fin H} (hab : b ≠ a) : + 𝔼 F, (g (elementaryMove a b F) - g F) ^ 2 ≤ dir g := + (single_le_sum (f := fun b ↦ 𝔼 F, (g (elementaryMove a b F) - g F) ^ 2) + (fun _ _ ↦ expect_nonneg fun _ _ ↦ sq_nonneg _) (mem_erase.2 ⟨hab, mem_univ b⟩)).trans + (single_le_sum (f := fun a ↦ ∑ b ∈ univ.erase a, 𝔼 F, (g (elementaryMove a b F) - g F) ^ 2) + (fun _ _ ↦ sum_nonneg fun _ _ ↦ expect_nonneg fun _ _ ↦ sq_nonneg _) (mem_univ a)) + +/-- The average of `g` over the vectors with `F k = c`. -/ +private noncomputable abbrev fib (g : (Fin H → ZMod P) → ℝ) (k : Fin H) (c : ZMod P) : ℝ := + 𝔼 F, g (update F k c) + +/-- In the coordinates `F = update (c • w) k c`, an elementary shear of `w` off `k` is an +elementary move of `F`. -/ +private theorem update_smul_shear {i j k : Fin H} (hik : i ≠ k) (hjk : j ≠ k) (c : ZMod P) + (w : Fin H → ZMod P) : + update (c • update w i (w i + w j)) k c = elementaryMove i j (update (c • w) k c) := by + funext t + simp only [elementaryMove, update_apply, Pi.smul_apply, smul_eq_mul] + by_cases htk : t = k + · simp [htk, hik.symm] + · by_cases hti : t = i <;> simp [hti, htk, hik, hjk, mul_add] + +/-- In the coordinates `F = update (c • w) k c`, a unit translation of `w` off `k` is the +elementary move adding `F k = c`. -/ +private theorem update_smul_translate {i k : Fin H} (hik : i ≠ k) (c : ZMod P) + (w : Fin H → ZMod P) : + update (c • update w i (w i + 1)) k c = elementaryMove i k (update (c • w) k c) := by + funext t + simp only [elementaryMove, update_apply, Pi.smul_apply, smul_eq_mul] + by_cases htk : t = k + · simp [htk, hik.symm] + · by_cases hti : t = i <;> simp [hti, htk, hik, mul_add] + +/-- **The fibers**: on `{F k ≠ 0}`, `g` is close to its averages over the fibers `{F k = c}`. -/ +private theorem fiber_bound (hH : 3 ≤ H) (k : Fin H) (g : (Fin H → ZMod P) → ℝ) : + 𝔼 F, nz (F k) * (g F - fib g k (F k)) ^ 2 ≤ 2048 * H * dir g := by + -- A partner `σ i ∉ {i, k}` for every coordinate `i`. + have hσ (i : Fin H) : ∃ j, j ≠ i ∧ j ≠ k := by + by_contra h + push Not at h + have hsub : (univ : Finset (Fin H)) ⊆ {i, k} := fun j _ ↦ by + by_cases hj : j = i + · simp [hj] + · simp [h j hj] + have := (card_le_card hsub).trans (card_insert_le _ _) + simp only [card_univ, Fintype.card_fin, card_singleton] at this + omega + choose σ hσ using hσ + -- Coordinates on the fiber `{F k = c}`: `F = update (c • w) k c`. + set Ψ : ZMod P → (Fin H → ZMod P) → (Fin H → ZMod P) := fun c w ↦ update (c • w) k c with hΨ + set G : ZMod P × (Fin H → ZMod P) → ℝ := fun q ↦ nz q.1 * g (Ψ q.1 q.2) with hG + have hfib {c : ZMod P} (hc : c ≠ 0) (φ : (Fin H → ZMod P) → ℝ) : + 𝔼 w, φ (Ψ c w) = 𝔼 F, φ (update F k c) := + expect_comp_smul hc fun F ↦ φ (update F k c) + -- The left side is the Efron–Stein left side for `G`. + have hL : 𝔼 q, (G q - 𝔼 w, G (q.1, w)) ^ 2 = + 𝔼 F, nz (F k) * (g F - fib g k (F k)) ^ 2 := by + rw [Fintype.expect_prod_type, + ← Fintype.expect_expect_update (fun F ↦ nz (F k) * (g F - fib g k (F k)) ^ 2) k] + simp only [update_self] + conv_rhs => rw [expect_comm] + refine expect_congr rfl fun c _ ↦ ?_ + by_cases hc : c = 0 + · simp [hG, nz, hc] + · have h1 : nz c = 1 := by simp [nz, hc] + simp only [hG, h1, one_mul] + rw [hfib hc g] + exact hfib hc fun F ↦ (g F - 𝔼 F', g (update F' k c)) ^ 2 + -- The coordinate `k` of `w` is not seen. + have hk : 𝔼 q, (G q - 𝔼 a, G (q.1, update q.2 k a)) ^ 2 = 0 := by + have h (q : ZMod P × (Fin H → ZMod P)) (a : ZMod P) : G (q.1, update q.2 k a) = G q := by + have : update (q.1 • update q.2 k a) k q.1 = update (q.1 • q.2) k q.1 := by + funext t + by_cases ht : t = k <;> simp [ht] + simp only [hG, hΨ, this] + simp [h] + -- A move of `w` that is an elementary move of `F` costs at most `dir g`. + have hterm {a b : Fin H} (hab : b ≠ a) + (M : ZMod P × (Fin H → ZMod P) → ZMod P × (Fin H → ZMod P)) (hM₁ : ∀ q, (M q).1 = q.1) + (hM : ∀ c w, Ψ c (M (c, w)).2 = elementaryMove a b (Ψ c w)) : + 𝔼 q, (G (M q) - G q) ^ 2 ≤ dir g := by + refine le_trans ?_ (le_dir g hab) + rw [Fintype.expect_prod_type, + ← Fintype.expect_expect_update (fun F ↦ (g (elementaryMove a b F) - g F) ^ 2) k] + conv_rhs => rw [expect_comm] + refine expect_le_expect fun c _ ↦ ?_ + by_cases hc : c = 0 + · have h0 : nz c = 0 := by simp [nz, hc] + have hz (w : Fin H → ZMod P) : G (M (c, w)) - G (c, w) = 0 := by + simp only [hG, hM₁, h0, zero_mul, sub_self] + simp only [hz] + rw [show (0 : ℝ) ^ 2 = 0 by norm_num, expect_const_zero] + exact expect_nonneg fun _ _ ↦ sq_nonneg _ + · have h1 : nz c = 1 := by simp [nz, hc] + have : ∀ w, G (M (c, w)) - G (c, w) = g (elementaryMove a b (Ψ c w)) - g (Ψ c w) := by + intro w + simp only [hG, hM₁, h1, one_mul, hM] + simp only [this] + exact (hfib hc fun F ↦ (g (elementaryMove a b F) - g F) ^ 2).le + -- The four moves of the pair `(i, σ i)`, for `i ≠ k`. + have hi (i : Fin H) (hik : i ≠ k) : + 𝔼 q, (G q - 𝔼 a, G (q.1, update q.2 i a)) ^ 2 ≤ 2048 * dir g := by + set j := σ i + have hji : j ≠ i := (hσ i).1 + have hjk : j ≠ k := (hσ i).2 + refine (expect_sq_sub_expect_update_le_pairShearTranslation (Equiv.refl _) (Equiv.refl _) + hji.symm G).trans ?_ + rw [Fin.sum_univ_four] + have hmv (m : Fin 4) {a b : Fin H} (hab : b ≠ a) + (hM : ∀ c w, Ψ c (pairShearTranslationMove (Equiv.refl _) (Equiv.refl _) i j m (c, w)).2 = + elementaryMove a b (Ψ c w)) : + 𝔼 q, (G (pairShearTranslationMove (Equiv.refl _) (Equiv.refl _) i j m q) - G q) ^ 2 ≤ + dir g := + hterm hab _ (fun q ↦ by fin_cases m <;> rfl) hM + have e0 := hmv 0 (a := i) (b := j) hji fun c w ↦ update_smul_shear hik hjk c w + have e1 := hmv 1 (a := j) (b := i) hji.symm fun c w ↦ update_smul_shear hjk hik c w + have e2 := hmv 2 (a := i) (b := k) hik.symm fun c w ↦ update_smul_translate hik c w + have e3 := hmv 3 (a := j) (b := k) hjk.symm fun c w ↦ update_smul_translate hjk c w + linarith + -- Efron–Stein, with the coordinate `k` free and the others paired. + have hD : 0 ≤ dir g := + sum_nonneg fun _ _ ↦ sum_nonneg fun _ _ ↦ expect_nonneg fun _ _ ↦ sq_nonneg _ + rw [← hL] + refine (Fintype.expect_sq_sub_expect_le_sum_expect_sq_sub_update G).trans ?_ + calc ∑ i, 𝔼 q, (G q - 𝔼 a, G (q.1, update q.2 i a)) ^ 2 ≤ ∑ _i : Fin H, 2048 * dir g := by + refine sum_le_sum fun i _ ↦ ?_ + by_cases hik : i = k + · subst hik + rw [hk] + positivity + · exact hi i hik + _ = 2048 * H * dir g := by + rw [sum_const, card_univ, Fintype.card_fin, nsmul_eq_mul] + ring + + + +/-- **Gluing two fibrations**: for `k ≠ l`, the fiber averages over `{F k = c}` and `{F l = d}` +differ little on independent nonzero values `c` and `d`. -/ +private theorem expect_nz_nz_sq_le {k l : Fin H} (hkl : k ≠ l) (g : (Fin H → ZMod P) → ℝ) : + 𝔼 c, 𝔼 d, nz c * nz d * (fib g k c - fib g l d) ^ 2 ≤ + 2 * 𝔼 F, nz (F k) * (g F - fib g k (F k)) ^ 2 + + 2 * 𝔼 F, nz (F l) * (g F - fib g l (F l)) ^ 2 := by + rw [← expect_comp_eval_eval hkl fun c d ↦ nz c * nz d * (fib g k c - fib g l d) ^ 2, + mul_expect, mul_expect, ← expect_add_distrib] + refine expect_le_expect fun F _ ↦ ?_ + have h1 := nz_nonneg (F k) + have h2 := nz_nonneg (F l) + have h3 := nz_le_one (F k) + have h4 := nz_le_one (F l) + have hsq : (fib g k (F k) - fib g l (F l)) ^ 2 ≤ + 2 * (g F - fib g k (F k)) ^ 2 + 2 * (g F - fib g l (F l)) ^ 2 := by + nlinarith [sq_nonneg (2 * g F - fib g k (F k) - fib g l (F l))] + have hA := sq_nonneg (g F - fib g k (F k)) + have hB := sq_nonneg (g F - fib g l (F l)) + have hkk : nz (F k) * nz (F l) ≤ nz (F k) := by nlinarith + have hll : nz (F k) * nz (F l) ≤ nz (F l) := by nlinarith + calc nz (F k) * nz (F l) * (fib g k (F k) - fib g l (F l)) ^ 2 + ≤ nz (F k) * nz (F l) * (2 * (g F - fib g k (F k)) ^ 2 + 2 * (g F - fib g l (F l)) ^ 2) := + mul_le_mul_of_nonneg_left hsq (mul_nonneg h1 h2) + _ ≤ 2 * (nz (F k) * (g F - fib g k (F k)) ^ 2) + + 2 * (nz (F l) * (g F - fib g l (F l)) ^ 2) := by + nlinarith [mul_le_mul_of_nonneg_right hkk hA, mul_le_mul_of_nonneg_right hll hB] + +/-- The second moments of the fiber averages about the weighted mean `ȳ` of `fib g l`, on the +nonzero values, are controlled by the gluing term. -/ +private theorem expect_nz_sq_sub_le {k l : Fin H} (g : (Fin H → ZMod P) → ℝ) : + (1 / 2) * 𝔼 c, nz c * (fib g k c - (𝔼 d, nz d * fib g l d) / 𝔼 d : ZMod P, nz d) ^ 2 ≤ + 𝔼 c, 𝔼 d, nz c * nz d * (fib g k c - fib g l d) ^ 2 ∧ + (1 / 2) * 𝔼 d, nz d * (fib g l d - (𝔼 d, nz d * fib g l d) / 𝔼 d : ZMod P, nz d) ^ 2 ≤ + 𝔼 c, 𝔼 d, nz c * nz d * (fib g k c - fib g l d) ^ 2 := by + have hW := half_le_expect_nz (P := P) + have hW0 : 𝔼 d : ZMod P, nz d ≠ 0 := by linarith + set ybar := (𝔼 d, nz d * fib g l d) / 𝔼 d : ZMod P, nz d + set xbar := (𝔼 c, nz c * fib g k c) / 𝔼 c : ZMod P, nz c + constructor + · -- For each `c`, average over `d`. + have hc (c : ZMod P) : + (1 / 2) * (fib g k c - ybar) ^ 2 ≤ 𝔼 d, nz d * (fib g l d - fib g k c) ^ 2 := by + have := (expect_mul_sq_sub_ge nz (fib g l) (fib g k c) nz_nonneg hW0).1 + have h0 := sq_nonneg (fib g k c - ybar) + calc (1 / 2) * (fib g k c - ybar) ^ 2 ≤ (𝔼 d, nz d) * (ybar - fib g k c) ^ 2 := by + rw [show (ybar - fib g k c) ^ 2 = (fib g k c - ybar) ^ 2 by ring] + exact mul_le_mul_of_nonneg_right hW h0 + _ ≤ _ := this + rw [mul_expect] + refine expect_le_expect fun c _ ↦ ?_ + calc 1 / 2 * (nz c * (fib g k c - ybar) ^ 2) = nz c * ((1 / 2) * (fib g k c - ybar) ^ 2) := by + ring + _ ≤ nz c * 𝔼 d, nz d * (fib g l d - fib g k c) ^ 2 := + mul_le_mul_of_nonneg_left (hc c) (nz_nonneg c) + _ = _ := by + rw [mul_expect] + exact expect_congr rfl fun d _ ↦ by ring + · -- For each `d`, average over `c`; then `ybar` beats `xbar`. + have hd (d : ZMod P) : + (1 / 2) * (fib g l d - xbar) ^ 2 ≤ 𝔼 c, nz c * (fib g k c - fib g l d) ^ 2 := by + have := (expect_mul_sq_sub_ge nz (fib g k) (fib g l d) nz_nonneg hW0).1 + have h0 := sq_nonneg (fib g l d - xbar) + calc (1 / 2) * (fib g l d - xbar) ^ 2 ≤ (𝔼 c, nz c) * (xbar - fib g l d) ^ 2 := by + rw [show (xbar - fib g l d) ^ 2 = (fib g l d - xbar) ^ 2 by ring] + exact mul_le_mul_of_nonneg_right hW h0 + _ ≤ _ := this + have hmin := (expect_mul_sq_sub_ge nz (fib g l) xbar nz_nonneg hW0).2 + calc (1 / 2) * 𝔼 d, nz d * (fib g l d - ybar) ^ 2 + ≤ (1 / 2) * 𝔼 d, nz d * (fib g l d - xbar) ^ 2 := + mul_le_mul_of_nonneg_left hmin (by norm_num) + _ ≤ 𝔼 d, 𝔼 c, nz c * nz d * (fib g k c - fib g l d) ^ 2 := by + rw [mul_expect] + refine expect_le_expect fun d _ ↦ ?_ + calc 1 / 2 * (nz d * (fib g l d - xbar) ^ 2) + = nz d * ((1 / 2) * (fib g l d - xbar) ^ 2) := by + ring + _ ≤ nz d * 𝔼 c, nz c * (fib g k c - fib g l d) ^ 2 := + mul_le_mul_of_nonneg_left (hd d) (nz_nonneg d) + _ = _ := by + rw [mul_expect] + exact expect_congr rfl fun c _ ↦ by ring + _ = _ := expect_comm _ _ _ + +/-- **The Poincaré inequality for the elementary moves on the nonzero vectors** of `(ZMod P) ^ H`, +for a prime `P` and `H ≥ 3`, uniformly in `P`: every real function `g` has, about some constant, a +second moment on the nonzero vectors at most `36864 H²` times its total squared change along the +elementary moves `F ↦ F + F b • e a`, `a ≠ b`. -/ +theorem exists_expect_sq_sub_le_elementaryMove (hH : 3 ≤ H) (g : (Fin H → ZMod P) → ℝ) : + ∃ m : ℝ, 𝔼 F, (if F = 0 then 0 else (g F - m) ^ 2) ≤ + 36864 * H ^ 2 * ∑ a, ∑ b ∈ univ.erase a, 𝔼 F, (g (elementaryMove a b F) - g F) ^ 2 := by + have h0 : 0 < H := by omega + set k₀ : Fin H := ⟨0, h0⟩ + set k₁ : Fin H := ⟨1, by omega⟩ + have h01 : k₀ ≠ k₁ := by simp [k₀, k₁, Fin.ext_iff] + set B := 2048 * (H : ℝ) * dir g + have hS (k : Fin H) : 𝔼 F, nz (F k) * (g F - fib g k (F k)) ^ 2 ≤ B := fiber_bound hH k g + have hS0 (k : Fin H) : 0 ≤ 𝔼 F, nz (F k) * (g F - fib g k (F k)) ^ 2 := + expect_nonneg fun F _ ↦ mul_nonneg (nz_nonneg _) (sq_nonneg _) + set ybar := (𝔼 d, nz d * fib g k₀ d) / 𝔼 d : ZMod P, nz d + refine ⟨ybar, ?_⟩ + -- On `{F k ≠ 0}`, `g` is close to `ybar`. + have hT (k : Fin H) : 𝔼 F, nz (F k) * (g F - ybar) ^ 2 ≤ 18 * B := by + have hsplit : 𝔼 F, nz (F k) * (g F - ybar) ^ 2 ≤ + 2 * 𝔼 F, nz (F k) * (g F - fib g k (F k)) ^ 2 + + 2 * 𝔼 c, nz c * (fib g k c - ybar) ^ 2 := by + rw [← expect_comp_eval k fun c ↦ nz c * (fib g k c - ybar) ^ 2, mul_expect, mul_expect, + ← expect_add_distrib] + refine expect_le_expect fun F _ ↦ ?_ + have := nz_nonneg (F k) + nlinarith [sq_nonneg (g F - 2 * fib g k (F k) + ybar), + mul_nonneg this (sq_nonneg (g F - 2 * fib g k (F k) + ybar))] + by_cases hk : k = k₀ + · subst hk + have hQ := expect_nz_nz_sq_le h01.symm g + have hb := (expect_nz_sq_sub_le (k := k₁) (l := k₀) g).2 + have := hS k₀ + have := hS k₁ + have := hS0 k₁ + have := hS0 k₀ + nlinarith + · have hQ := expect_nz_nz_sq_le hk g + have hb := (expect_nz_sq_sub_le (k := k) (l := k₀) g).1 + have := hS k + have := hS k₀ + have := hS0 k + have := hS0 k₀ + nlinarith + -- Every nonzero vector has a nonzero coordinate. + have hpt (F : Fin H → ZMod P) : + (if F = 0 then 0 else (g F - ybar) ^ 2) ≤ ∑ k, nz (F k) * (g F - ybar) ^ 2 := by + split_ifs with hF + · exact sum_nonneg fun k _ ↦ mul_nonneg (nz_nonneg _) (sq_nonneg _) + · obtain ⟨k, hk⟩ : ∃ k, F k ≠ 0 := by + by_contra h + push Not at h + exact hF (funext h) + have h1 : nz (F k) = 1 := by simp [nz, hk] + calc (g F - ybar) ^ 2 = nz (F k) * (g F - ybar) ^ 2 := by rw [h1, one_mul] + _ ≤ _ := single_le_sum (f := fun k ↦ nz (F k) * (g F - ybar) ^ 2) + (fun k _ ↦ mul_nonneg (nz_nonneg _) (sq_nonneg _)) (mem_univ k) + calc 𝔼 F, (if F = 0 then 0 else (g F - ybar) ^ 2) ≤ 𝔼 F, ∑ k, nz (F k) * (g F - ybar) ^ 2 := + expect_le_expect fun F _ ↦ hpt F + _ = ∑ k, 𝔼 F, nz (F k) * (g F - ybar) ^ 2 := expect_sum_comm _ _ _ + _ ≤ ∑ _k : Fin H, 18 * B := sum_le_sum fun k _ ↦ hT k + _ = 36864 * H ^ 2 * dir g := by + rw [sum_const, card_univ, Fintype.card_fin, nsmul_eq_mul] + simp only [B] + ring + +end Cslib.RotationMap diff --git a/ComplexityTests/ElementaryMove.lean b/ComplexityTests/ElementaryMove.lean new file mode 100644 index 000000000..18ec35077 --- /dev/null +++ b/ComplexityTests/ElementaryMove.lean @@ -0,0 +1,50 @@ +/- +Copyright (c) 2026 Christian Reitwiessner. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Christian Reitwiessner +-/ + +import Complexity.Foundations.Combinatorics.Expander.ElementaryMove + +/-! +# Elementary moves on the nonzero vectors of `(ZMod P) ^ H` + +A concrete elementary move, and a client of the Poincaré inequality: for every prime `P`, a real +function on `(ZMod P) ^ 3` invariant under the six elementary moves is constant on the nonzero +vectors. +-/ + +namespace ComplexityTests.ElementaryMove + +open Cslib Cslib.RotationMap Finset +open scoped BigOperators + +-- `F ↦ F + F 2 • e 0` on `(ZMod 5) ^ 3`. +example : elementaryMove (P := 5) 0 2 ![1, 2, 3] = ![4, 2, 3] := by decide +-- It wraps around. +example : elementaryMove (P := 5) 1 0 ![4, 3, 0] = ![4, 2, 0] := by decide + +/-- **A client**: for every prime `P`, a function on `(ZMod P) ^ 3` invariant under the elementary +moves takes one value on all nonzero vectors. -/ +example (P : ℕ) [Fact P.Prime] (g : (Fin 3 → ZMod P) → ℝ) + (hg : ∀ a b F, a ≠ b → g (elementaryMove a b F) = g F) (F F' : Fin 3 → ZMod P) + (hF : F ≠ 0) (hF' : F' ≠ 0) : g F = g F' := by + obtain ⟨m, hm⟩ := exists_expect_sq_sub_le_elementaryMove le_rfl g + have hzero : ∑ a, ∑ b ∈ univ.erase a, 𝔼 F, (g (elementaryMove a b F) - g F) ^ 2 = 0 := + sum_eq_zero fun a _ ↦ sum_eq_zero fun b hb ↦ by + simp [hg a b _ (mem_erase.1 hb).1.symm] + rw [hzero, mul_zero] at hm + have h0 := (Fintype.expect_eq_zero_iff_of_nonneg fun G ↦ by + split_ifs + · exact le_rfl + · exact sq_nonneg (g G - m)).1 (le_antisymm hm (expect_nonneg fun G _ ↦ by + split_ifs + · exact le_rfl + · exact sq_nonneg _)) + have e (G : Fin 3 → ZMod P) (hG : G ≠ 0) : g G = m := by + have := congrFun h0 G + simp only [hG, ite_false, Pi.zero_apply] at this + exact sub_eq_zero.1 (pow_eq_zero_iff two_ne_zero |>.1 this) + rw [e F hF, e F' hF'] + +end ComplexityTests.ElementaryMove From bc81c6ab33076a50ac4b0c25f39fc26888ae39ee Mon Sep 17 00:00:00 2001 From: Christian Reitwiessner Date: Fri, 30 Oct 2026 01:51:20 +0000 Subject: [PATCH 13/13] feat(Probability): uniform spectral gap of the affine walk on slice coordinates (#1682) Step (D) of the frame-lifted gap plan on #1682. Assembles the coordinate-pair bound (#1699) and the Poincare inequality on nonzero vectors (#1703) into a Poincare inequality for the affine moves on Frame P H 1 x (ZMod L)^H, uniform in P and L, and derives the spectral gap 1 - 1/(155648 H^4) of the lazy walk. This discharges the gap hypothesis of #1691's conditional averaging for frames of length one. Adds Matrix.SpecialLinearGroup.map_transvection and transvection_mulVec in Foundations, reusing Mathlib's SpecialLinearGroup.transvection. Co-Authored-By: Claude Opus 5.5 --- Complexity.lean | 2 + .../LinearAlgebra/Matrix/Transvection.lean | 58 +++ .../PairwiseIndependentHash/SliceGap.lean | 415 ++++++++++++++++++ ComplexityTests/SliceGap.lean | 93 ++++ 4 files changed, 568 insertions(+) create mode 100644 Complexity/Foundations/LinearAlgebra/Matrix/Transvection.lean create mode 100644 Complexity/Probability/PairwiseIndependentHash/SliceGap.lean create mode 100644 ComplexityTests/SliceGap.lean diff --git a/Complexity.lean b/Complexity.lean index 083c27d75..170bf924a 100644 --- a/Complexity.lean +++ b/Complexity.lean @@ -2637,6 +2637,7 @@ public import Complexity.Foundations.LinearAlgebra.Matrix.RectPermanent public import Complexity.Foundations.LinearAlgebra.Matrix.SchurComplement public import Complexity.Foundations.LinearAlgebra.Matrix.SubmatrixRobust public import Complexity.Foundations.LinearAlgebra.Matrix.Toeplitz +public import Complexity.Foundations.LinearAlgebra.Matrix.Transvection public import Complexity.Foundations.LinearAlgebra.PivotSpace public import Complexity.Foundations.LinearAlgebra.Rank public import Complexity.Foundations.LinearAlgebra.ReplacementDesign @@ -2924,6 +2925,7 @@ public import Complexity.Probability.PairwiseIndependentHash.FrameChannel public import Complexity.Probability.PairwiseIndependentHash.Retention public import Complexity.Probability.PairwiseIndependentHash.RetentionChannel public import Complexity.Probability.PairwiseIndependentHash.Shift +public import Complexity.Probability.PairwiseIndependentHash.SliceGap public import Complexity.Probability.PairwiseIndependentHash.Toeplitz public import Complexity.Probability.PairwiseIndependentHash.Universal public import Complexity.Probability.Pinsker diff --git a/Complexity/Foundations/LinearAlgebra/Matrix/Transvection.lean b/Complexity/Foundations/LinearAlgebra/Matrix/Transvection.lean new file mode 100644 index 000000000..19d648048 --- /dev/null +++ b/Complexity/Foundations/LinearAlgebra/Matrix/Transvection.lean @@ -0,0 +1,58 @@ +/- +Copyright (c) 2026 Christian Reitwiessner. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Christian Reitwiessner +-/ + +module +-- upstream: candidate + +public import Complexity.Init +public import Mathlib.LinearAlgebra.Matrix.SpecialLinearGroup + +/-! +# Transvections in the special linear group acting on vectors + +Mathlib's `Matrix.SpecialLinearGroup.transvection` is the transvection `1 + c E_ij`, for `i ≠ j`, +as an element of `SL_n(R)`. This file adds two facts about it: a ring homomorphism maps it to the +transvection with the image parameter, and it acts on a vector by adding `c` times the coordinate +`j` to the coordinate `i`. Mathlib computes the action on standard basis vectors only. For `c = 1` +these are the elementary generators of `SL_n(ℤ)`, which act on vectors over every quotient ring +by the elementary moves. + +## Main results + +* `Matrix.SpecialLinearGroup.map_transvection`: a ring homomorphism maps transvections to + transvections. +* `Matrix.SpecialLinearGroup.transvection_mulVec`: a transvection adds `c v j` to `v i`. +-/ + +public section + +namespace Matrix.SpecialLinearGroup + +open Function + +variable {n R : Type*} [Fintype n] [DecidableEq n] [CommRing R] + +/-- A ring homomorphism maps the transvection `1 + c E_ij` to `1 + f c E_ij`. -/ +@[simp] +theorem map_transvection {S : Type*} [CommRing S] (f : R →+* S) {i j : n} (h : i ≠ j) (c : R) : + map f (transvection h c) = transvection h (f c) := by + ext k l + simp only [map_apply_coe, RingHom.mapMatrix_apply, Matrix.map_apply, transvection_coe, + Matrix.add_apply, Matrix.one_apply, Matrix.single_apply] + split_ifs <;> simp + +/-- The transvection `1 + c E_ij` adds `c v j` to the coordinate `i` of `v`. -/ +@[simp] +theorem transvection_mulVec {i j : n} (h : i ≠ j) (c : R) (v : n → R) : + (transvection h c : Matrix n n R) *ᵥ v = update v i (v i + c * v j) := by + rw [transvection_coe, add_mulVec, one_mulVec, single_mulVec] + ext k + by_cases hk : k = i + · subst hk + simp + · simp [hk] + +end Matrix.SpecialLinearGroup diff --git a/Complexity/Probability/PairwiseIndependentHash/SliceGap.lean b/Complexity/Probability/PairwiseIndependentHash/SliceGap.lean new file mode 100644 index 000000000..32f3716df --- /dev/null +++ b/Complexity/Probability/PairwiseIndependentHash/SliceGap.lean @@ -0,0 +1,415 @@ +/- +Copyright (c) 2026 Christian Reitwiessner. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Christian Reitwiessner +-/ + +module +-- upstream: candidate + +public import Complexity.Foundations.Combinatorics.Expander.ElementaryMove +public import Complexity.Foundations.Combinatorics.Expander.Lazy +public import Complexity.Foundations.LinearAlgebra.Matrix.Transvection +public import Complexity.Probability.PairwiseIndependentHash.ConditionalAveraging +import Complexity.Foundations.Combinatorics.Expander.PairShearTranslation +import Complexity.Foundations.Data.Finset.Expect + +/-! +# The spectral gap of the affine walk on slice coordinates + +On the slice coordinates `(F, w) ∈ Frame P H 1 × ZMod L ^ H` of a retention slice +(`Cslib.Probability.sliceEquiv`), the **affine moves** (`affineMove`) are the moves `coordMove` +of the elementary matrices `1 + E_ab` of `SL_H(ℤ)`, `a ≠ b`, and of the unit translations `e_i`: + +`(F, w) ↦ ((1 + E_ab) F, (1 + E_ab) w)`, `(F, w) ↦ (F, w + e_i)`. + +For a prime `P` and `H ≥ 3`, the lazy walk on these `H ^ 2` moves and their inverses has spectral +expansion at most `1 - 1 / (155648 H ^ 4)`, **uniformly in `P` and `L`** +(`spectralExpansion_lazy_ofPerms_affineMove_le`). This is the gap hypothesis of conditional +averaging (`expect_walk_pow_sliceGraph_sub_expect_sq_le`) for frames of length one, which is thereby +discharged (`expect_walk_pow_sliceGraph_affineMove_sub_expect_sq_le`). + +The proof is a Poincaré inequality (`expect_sq_le_affineMove`) assembled from two parts. Write +`g F = 𝔼 w, f (F, w)`, so that `𝔼 f² = 𝔼 g² + 𝔼 (f - g)²` for `f` of mean zero. + +* **The box part.** The coordinate-pair bound `expect_sq_sub_expect_le_pairShearTranslation`, with + the frames as the spectator `Y` and the elementary matrices acting on them, bounds + `𝔼 (f - g)²` by the squared changes of `f` along the affine moves: its pair moves are affine + moves. +* **The frame part.** A frame of length one is a nonzero vector (`Frame.equivNeZero`), on which + `1 + E_ab` acts by the elementary move (`Frame.mapSL_transvection_apply_zero`). So the Poincaré + inequality for the elementary moves on the nonzero vectors of `(ZMod P) ^ H` + (`exists_expect_sq_sub_le_elementaryMove`), whose averages are masked averages over all vectors, + becomes one on the frames (`exists_expect_sq_sub_le_mapSL_transvection`). It bounds `𝔼 g²` by the + squared changes of `g` along the elementary matrices, and by Jensen's inequality these are at + most those of `f` along the affine moves, since an affine move acts on `w` by a bijection. + +The second eigenvalue then follows from `secondEigenvalue_ofPerms_le`, and the lazy walk halves +the gap. + +This is the uniform gap of Lemma 6.1 of the OpenAI preprint on derandomizing logarithmic space +[OpenAI2026LogSpace], for its action on the coordinates `(F, w)` of the proof of its Lemma 6.2, in +the case of frames of length one (`h₀ = 2`). The preprint derives the gap from Shalom's property +(T) of `SL_H(ℤ) ⋉ ℤ^H` and its transitive action. The elementary route, from the uniform +two-dimensional gap through the coordinate pairs to the frames, follows OpenAI's Lean +development, the file +[`AffineSampling.lean`](https://github.com/openai/math/blob/7ef5c0cc5ca4b0e072b7a050fca09ab24bc6fa3a/lean/OAI/Computability/Logspace/AffineSampling.lean) +at revision `7ef5c0cc` (`ExactDerandomization.Analysis.Square.square_gap`, `slice_frame`, +`frame_gap`, `slice_gap`). The statements and the proofs here are independent of that code, which +was not consulted. + +## Main definitions + +* `Cslib.Probability.Frame.equivNeZero`: frames of length one are nonzero vectors. +* `Cslib.Probability.affineGenerator`: the elementary matrices and the unit translations. +* `Cslib.Probability.affineMove`: their moves on slice coordinates. + +## Main results + +* `Cslib.Probability.Frame.card_one`: there are `P ^ H - 1` frames of length one. +* `Cslib.Probability.exists_expect_sq_sub_le_mapSL_transvection`: the Poincaré inequality for the + elementary matrices on frames of length one, uniformly in `P`. +* `Cslib.Probability.expect_sq_le_affineMove`: the Poincaré inequality for the affine moves on + `Frame P H 1 × ZMod L ^ H`, uniformly in `P` and `L`. +* `Cslib.Probability.secondEigenvalue_ofPerms_affineMove_le`, + `Cslib.Probability.spectralExpansion_lazy_ofPerms_affineMove_le`: the uniform spectral gap. +* `Cslib.Probability.expect_walk_pow_sliceGraph_affineMove_sub_expect_sq_le`: conditional + averaging on every retention slice, with the gap hypothesis discharged. + +## References + +* [OpenAI, *Exact Derandomization of Logarithmic Space: L = RL = BPL*][OpenAI2026LogSpace] +-/ + +public section + +namespace Cslib.Probability + +open Finset Function Matrix RotationMap +open scoped BigOperators + +variable {P H L : ℕ} + +/-- The integer matrix `1` acts trivially on frames. -/ +@[simp] +theorem Frame.mapSL_one {r : ℕ} (F : Frame P H r) : Frame.mapSL 1 F = F := + Subtype.ext <| funext fun j ↦ by simp + +/-! ### Frames of length one -/ + +section FrameOne + +variable [Fact P.Prime] + +/-- **A frame of length one is a nonzero vector.** -/ +@[expose] def Frame.equivNeZero : Frame P H 1 ≃ {v : Fin H → ZMod P // v ≠ 0} where + toFun F := ⟨F.1 0, linearIndependent_unique_iff.1 F.2⟩ + invFun v := ⟨fun _ ↦ v.1, linearIndependent_unique_iff.2 v.2⟩ + left_inv F := Subtype.ext <| funext fun i ↦ by rw [Subsingleton.elim i 0] + right_inv _ := rfl + +@[simp] +theorem Frame.equivNeZero_apply (F : Frame P H 1) : (Frame.equivNeZero F).1 = F.1 0 := + rfl + +/-- There are `P ^ H - 1` frames of length one. -/ +theorem Frame.card_one : Fintype.card (Frame P H 1) = P ^ H - 1 := by + rw [Fintype.card_congr Frame.equivNeZero, Fintype.card_subtype_compl, Fintype.card_fun, + Fintype.card_fin, ZMod.card, Fintype.card_unique] + +omit [Fact P.Prime] in +/-- The elementary matrix `1 + E_ab` acts on a frame of length one by the elementary move +`F ↦ F + F b • e a`. -/ +theorem Frame.mapSL_transvection_apply_zero {a b : Fin H} (h : a ≠ b) (F : Frame P H 1) : + (Frame.mapSL (SpecialLinearGroup.transvection h 1) F).1 0 = + RotationMap.elementaryMove a b (F.1 0) := by + rw [Frame.mapSL_apply, SpecialLinearGroup.map_transvection, + SpecialLinearGroup.transvection_mulVec, map_one, one_mul] + rfl + +/-- A sum over the frames of length one is a sum over the nonzero vectors. -/ +theorem Frame.sum_one_eq {M : Type*} [AddCommMonoid M] (Φ : (Fin H → ZMod P) → M) : + ∑ F : Frame P H 1, Φ (F.1 0) = ∑ v, if v = 0 then 0 else Φ v := by + calc ∑ F : Frame P H 1, Φ (F.1 0) = ∑ v : {v : Fin H → ZMod P // v ≠ 0}, Φ v.1 := by + rw [← Equiv.sum_comp Frame.equivNeZero.symm] + rfl + _ = _ := by + rw [← Finset.sum_subtype (univ.filter (· ≠ 0)) (by simp) (fun v ↦ Φ v), sum_filter] + exact sum_congr rfl fun v _ ↦ by split_ifs <;> simp_all + +/-- The masked uniform average over all vectors is a multiple of the average over the frames of +length one. -/ +private theorem expect_ite_eq (Φ : (Fin H → ZMod P) → ℝ) : + 𝔼 v, (if v = 0 then 0 else Φ v) = + (Fintype.card (Frame P H 1) / Fintype.card (Fin H → ZMod P) : ℝ) * + 𝔼 F : Frame P H 1, Φ (F.1 0) := by + rw [Fintype.expect_eq_sum_div_card, Fintype.expect_eq_sum_div_card, ← Frame.sum_one_eq] + rcases isEmpty_or_nonempty (Frame P H 1) with hF | hF + · simp + have hN : (0 : ℝ) < Fintype.card (Frame P H 1) := by exact_mod_cast Fintype.card_pos + field_simp + +/-- The sum over ordered pairs of distinct coordinates. -/ +private theorem sum_sum_erase_eq {M : Type*} [AddCommMonoid M] (ψ : Fin H → Fin H → M) : + ∑ a, ∑ b ∈ univ.erase a, ψ a b = ∑ p : {p : Fin H × Fin H // p.1 ≠ p.2}, ψ p.1.1 p.1.2 := by + rw [← Finset.sum_subtype (univ.filter fun p : Fin H × Fin H ↦ p.1 ≠ p.2) (by simp) + (fun p ↦ ψ p.1 p.2), sum_filter, Fintype.sum_prod_type] + refine sum_congr rfl fun a _ ↦ ?_ + rw [← filter_ne', sum_filter] + exact sum_congr rfl fun b _ ↦ by simp only [ne_comm] + +/-- **The Poincaré inequality for the elementary matrices on frames of length one**, for a prime +`P` and `H ≥ 3`, uniformly in `P`: every real function `g` on the frames has, about some constant, +a second moment at most `36864 H²` times its total squared change along the elementary matrices +`1 + E_ab`, `a ≠ b`. -/ +theorem exists_expect_sq_sub_le_mapSL_transvection (hH : 3 ≤ H) (g : Frame P H 1 → ℝ) : + ∃ m : ℝ, 𝔼 F, (g F - m) ^ 2 ≤ 36864 * H ^ 2 * + ∑ p : {p : Fin H × Fin H // p.1 ≠ p.2}, + 𝔼 F, (g (Frame.mapSL (SpecialLinearGroup.transvection p.2 1) F) - g F) ^ 2 := by + have := Frame.nonempty (P := P) (r := 1) (H := H) (by omega) + -- `g` as a function on all vectors. + set G : (Fin H → ZMod P) → ℝ := fun v ↦ + if h : v = 0 then 0 else g (Frame.equivNeZero.symm ⟨v, h⟩) with hG + have hGF (F : Frame P H 1) : G (F.1 0) = g F := by + have h := (Frame.equivNeZero F).2 + simp only [hG, Frame.equivNeZero_apply] at h ⊢ + simp only [h, dite_false] + exact congrArg g (Frame.equivNeZero.symm_apply_apply F) + obtain ⟨m, hm⟩ := RotationMap.exists_expect_sq_sub_le_elementaryMove hH G + refine ⟨m, ?_⟩ + set c : ℝ := Fintype.card (Frame P H 1) / Fintype.card (Fin H → ZMod P) + have hc : 0 < c := by + have : (0 : ℝ) < Fintype.card (Frame P H 1) := by exact_mod_cast Fintype.card_pos + positivity + have hL : 𝔼 v, (if v = 0 then 0 else (G v - m) ^ 2) = c * 𝔼 F, (g F - m) ^ 2 := by + rw [expect_ite_eq] + simp only [hGF] + rfl + have hR (a b : Fin H) (h : a ≠ b) : + 𝔼 v, (G (RotationMap.elementaryMove a b v) - G v) ^ 2 = + c * 𝔼 F, (g (Frame.mapSL (SpecialLinearGroup.transvection h 1) F) - g F) ^ 2 := by + have h0 (v : Fin H → ZMod P) : (G (RotationMap.elementaryMove a b v) - G v) ^ 2 = + if v = 0 then 0 else (G (RotationMap.elementaryMove a b v) - G v) ^ 2 := by + split_ifs with hv + · subst hv + simp [RotationMap.elementaryMove] + · rfl + rw [expect_congr rfl fun v _ ↦ h0 v, expect_ite_eq] + simp only [← Frame.mapSL_transvection_apply_zero h, hGF] + rfl + rw [hL, sum_sum_erase_eq (fun a b ↦ 𝔼 v, (G (RotationMap.elementaryMove a b v) - G v) ^ 2)] + at hm + have hsum : ∑ p : {p : Fin H × Fin H // p.1 ≠ p.2}, + 𝔼 v, (G (RotationMap.elementaryMove p.1.1 p.1.2 v) - G v) ^ 2 = + c * ∑ p : {p : Fin H × Fin H // p.1 ≠ p.2}, + 𝔼 F, (g (Frame.mapSL (SpecialLinearGroup.transvection p.2 1) F) - g F) ^ 2 := by + rw [mul_sum] + exact sum_congr rfl fun p _ ↦ hR _ _ p.2 + rw [hsum, mul_left_comm] at hm + exact le_of_mul_le_mul_left hm hc + +end FrameOne + +/-! ### The affine moves -/ + +variable (H) in +/-- **The generators of the affine walk**: the elementary matrices `1 + E_ab` for `a ≠ b`, and +the unit translations by `e_i`. -/ +@[expose] def affineGenerator : + {p : Fin H × Fin H // p.1 ≠ p.2} ⊕ Fin H → SpecialLinearGroup (Fin H) ℤ × (Fin H → ℤ) := + Sum.elim (fun p ↦ (SpecialLinearGroup.transvection p.2 1, 0)) fun i ↦ (1, Pi.single i 1) + +variable (P H L) in +/-- **The affine moves on slice coordinates** `(F, w)`: the moves `coordMove` of the generators, +`(F, w) ↦ ((1 + E_ab) F, (1 + E_ab) w)` and `(F, w) ↦ (F, w + e_i)`. -/ +@[expose] def affineMove (r : ℕ) (k : {p : Fin H × Fin H // p.1 ≠ p.2} ⊕ Fin H) : + Equiv.Perm (Frame P H r × (Fin H → ZMod L)) := + coordMove (affineGenerator H k).1 (affineGenerator H k).2 + +@[simp] +theorem affineMove_inl {r : ℕ} (p : {p : Fin H × Fin H // p.1 ≠ p.2}) + (q : Frame P H r × (Fin H → ZMod L)) : + affineMove P H L r (.inl p) q = + (Frame.mapSL (SpecialLinearGroup.transvection p.2 1) q.1, + update q.2 p.1.1 (q.2 p.1.1 + q.2 p.1.2)) := by + simp only [affineMove, affineGenerator, coordMove, Sum.elim_inl, Equiv.prodCongr_apply, + Prod.map, affineSL_apply, SpecialLinearGroup.map_transvection, + SpecialLinearGroup.transvection_mulVec, map_one, one_mul] + exact Prod.ext rfl (funext fun _ ↦ by simp) + +@[simp] +theorem affineMove_inr {r : ℕ} (i : Fin H) (q : Frame P H r × (Fin H → ZMod L)) : + affineMove P H L r (.inr i) q = (q.1, update q.2 i (q.2 i + 1)) := by + obtain ⟨F, w⟩ := q + ext j + · simp [affineMove, affineGenerator, coordMove] + · simp only [affineMove, affineGenerator, coordMove, Sum.elim_inr, Equiv.prodCongr_apply, + Prod.map_snd, affineSL_apply, map_one, SpecialLinearGroup.coe_one, one_mulVec, Pi.add_apply, + update_apply] + split_ifs with h + · subst h + simp + · simp [h] + +/-- There are `H ^ 2` generators: `H (H - 1)` elementary matrices and `H` translations. -/ +theorem card_affineGenerator_index : + Fintype.card ({p : Fin H × Fin H // p.1 ≠ p.2} ⊕ Fin H) = H ^ 2 := by + rw [Fintype.card_sum, Fintype.card_fin, Fintype.card_subtype] + have : (univ.filter fun p : Fin H × Fin H ↦ p.1 ≠ p.2) = (univ : Finset (Fin H)).offDiag := by + ext p + simp + rw [this, offDiag_card, card_univ, Fintype.card_fin] + have : H ≤ H * H := Nat.le_mul_self H + rw [Nat.sub_add_cancel this, sq] + +/-- Averaging over the second coordinate contracts the squared change along a product +permutation. -/ +private theorem sq_expect_sub_expect_le {Y W : Type*} [Fintype W] (π : Equiv.Perm Y) + (τ : Equiv.Perm W) (f : Y × W → ℝ) (y : Y) : + (𝔼 w, f (π y, w) - 𝔼 w, f (y, w)) ^ 2 ≤ 𝔼 w, (f (π.prodCongr τ (y, w)) - f (y, w)) ^ 2 := by + have h : 𝔼 w, f (π y, w) = 𝔼 w, f (π y, τ w) := + (Fintype.expect_equiv τ (fun w ↦ f (π y, τ w)) (fun w ↦ f (π y, w)) fun _ ↦ rfl).symm + rw [h, ← expect_sub_distrib] + exact sq_expect_le_expect_sq univ _ + +/-- **The Poincaré inequality for the affine walk on slice coordinates** `Frame P H 1 × ZMod L ^ H`, +for a prime `P` and `H ≥ 3`, uniformly in `P` and `L`: every real function `f` of mean zero has +second moment at most `38912 H²` times its total squared change along the affine moves. -/ +theorem expect_sq_le_affineMove [Fact P.Prime] [NeZero L] (hH : 3 ≤ H) + (f : Frame P H 1 × (Fin H → ZMod L) → ℝ) (hf : 𝔼 p, f p = 0) : + 𝔼 p, f p ^ 2 ≤ 38912 * H ^ 2 * ∑ k, 𝔼 p, (f (affineMove P H L 1 k p) - f p) ^ 2 := by + have := Frame.nonempty (P := P) (r := 1) (H := H) (by omega) + set D := ∑ k, 𝔼 p, (f (affineMove P H L 1 k p) - f p) ^ 2 + have hD0 : 0 ≤ D := sum_nonneg fun _ _ ↦ expect_nonneg fun _ _ ↦ sq_nonneg _ + have hterm (k) : 𝔼 p, (f (affineMove P H L 1 k p) - f p) ^ 2 ≤ D := + single_le_sum (f := fun k ↦ 𝔼 p, (f (affineMove P H L 1 k p) - f p) ^ 2) + (fun _ _ ↦ expect_nonneg fun _ _ ↦ sq_nonneg _) (mem_univ k) + -- Split `f` into its averages `g` over the box coordinate and the rest. + set g : Frame P H 1 → ℝ := fun F ↦ 𝔼 w, f (F, w) with hg + have hsplit : 𝔼 p, f p ^ 2 = 𝔼 F, g F ^ 2 + 𝔼 p, (f p - 𝔼 w, f (p.1, w)) ^ 2 := by + have h := Fintype.expect_add_sq_of_expect_fiber_eq_zero g + (g := fun p ↦ f p - g p.1) (Fintype.expect_sub_expect_fiber f) + simpa only [add_sub_cancel, Fintype.expect_prod_type, Fintype.expect_const] using h + -- The box part, by the coordinate-pair bound with partners `σ i ≠ i`. + have hH2 : Nontrivial (Fin H) := Fin.nontrivial_iff_two_le.2 (by omega) + choose σ hσ using fun i : Fin H ↦ exists_ne i + let ρ : Fin H → Fin H → Equiv.Perm (Frame P H 1) := fun i j ↦ + if h : i = j then Equiv.refl _ else Frame.mapSL (SpecialLinearGroup.transvection h 1) + have hρ {i j : Fin H} (h : i ≠ j) : + ρ i j = Frame.mapSL (SpecialLinearGroup.transvection h 1) := by + simp [ρ, h] + have hpair (i : Fin H) (k : Fin 4) : + 𝔼 p, (f (RotationMap.pairShearTranslationMove (ρ i (σ i)) (ρ (σ i) i) i (σ i) k p) - + f p) ^ 2 ≤ D := by + have hσi : i ≠ σ i := (hσ i).symm + fin_cases k + · refine le_trans (le_of_eq ?_) (hterm (.inl ⟨(i, σ i), hσi⟩)) + refine expect_congr rfl fun p _ ↦ ?_ + simp [RotationMap.pairShearTranslationMove, hρ hσi] + · refine le_trans (le_of_eq ?_) (hterm (.inl ⟨(σ i, i), hσi.symm⟩)) + refine expect_congr rfl fun p _ ↦ ?_ + simp [RotationMap.pairShearTranslationMove, hρ hσi.symm] + · refine le_trans (le_of_eq ?_) (hterm (.inr i)) + refine expect_congr rfl fun p _ ↦ ?_ + simp [RotationMap.pairShearTranslationMove] + · refine le_trans (le_of_eq ?_) (hterm (.inr (σ i))) + refine expect_congr rfl fun p _ ↦ ?_ + simp [RotationMap.pairShearTranslationMove] + have hbox : 𝔼 p, (f p - 𝔼 w, f (p.1, w)) ^ 2 ≤ 2048 * H * D := by + refine (RotationMap.expect_sq_sub_expect_le_pairShearTranslation ρ σ (fun i ↦ hσ i) f).trans ?_ + calc 512 * ∑ i, ∑ k, 𝔼 p, (f (RotationMap.pairShearTranslationMove (ρ i (σ i)) (ρ (σ i) i) + i (σ i) k p) - f p) ^ 2 ≤ 512 * ∑ _i : Fin H, ∑ _k : Fin 4, D := by + gcongr with i _ k _ + exact hpair i k + _ = 2048 * H * D := by + simp only [sum_const, card_univ, Fintype.card_fin, nsmul_eq_mul] + push_cast + ring + -- The frame part, by the Poincaré inequality on frames and Jensen's inequality. + obtain ⟨m, hm⟩ := exists_expect_sq_sub_le_mapSL_transvection hH g + have hg0 : 𝔼 F, g F = 0 := by rw [← Fintype.expect_prod_type]; exact hf + have hgm : 𝔼 F, g F ^ 2 ≤ 𝔼 F, (g F - m) ^ 2 := by + have : 𝔼 F, (g F - m) ^ 2 = 𝔼 F, g F ^ 2 + m ^ 2 := by + have h1 : 𝔼 F, (g F - m) ^ 2 = 𝔼 F, (g F ^ 2 + m ^ 2) - 2 * m * 𝔼 F, g F := by + rw [mul_expect, ← expect_sub_distrib] + exact expect_congr rfl fun F _ ↦ by ring + rw [h1, hg0, expect_add_distrib, Fintype.expect_const] + ring + rw [this] + nlinarith [sq_nonneg m] + have hframe : ∑ p : {p : Fin H × Fin H // p.1 ≠ p.2}, + 𝔼 F, (g (Frame.mapSL (SpecialLinearGroup.transvection p.2 1) F) - g F) ^ 2 ≤ D := by + calc _ ≤ ∑ p : {p : Fin H × Fin H // p.1 ≠ p.2}, + 𝔼 q, (f (affineMove P H L 1 (.inl p) q) - f q) ^ 2 := by + refine sum_le_sum fun p _ ↦ ?_ + rw [Fintype.expect_prod_type] + exact expect_le_expect fun F _ ↦ sq_expect_sub_expect_le _ _ f F + _ ≤ D := by + refine le_trans ?_ (Fintype.sum_sum_type _).symm.le + exact le_add_of_nonneg_right + (sum_nonneg fun _ _ ↦ expect_nonneg fun _ _ ↦ sq_nonneg _) + have hHD : (H : ℝ) * D ≤ H ^ 2 * D := by + have : (H : ℝ) ≤ H ^ 2 := by + have : (1 : ℝ) ≤ H := by exact_mod_cast (by omega : 1 ≤ H) + nlinarith + exact mul_le_mul_of_nonneg_right this hD0 + have hHsq : (0 : ℝ) ≤ H ^ 2 := sq_nonneg _ + rw [hsplit] + nlinarith [mul_le_mul_of_nonneg_left hframe (by positivity : (0 : ℝ) ≤ 36864 * H ^ 2)] + + +/-- For `H ≥ 2` there are at least two frames of length one. -/ +private theorem nontrivial_frame_one [Fact P.Prime] (hH : 2 ≤ H) : Nontrivial (Frame P H 1) := by + have h0 : (Pi.single ⟨0, by omega⟩ 1 : Fin H → ZMod P) ≠ 0 := by simp + have h1 : (Pi.single ⟨1, by omega⟩ 1 : Fin H → ZMod P) ≠ 0 := by simp + refine ⟨Frame.equivNeZero.symm ⟨_, h0⟩, Frame.equivNeZero.symm ⟨_, h1⟩, fun h ↦ ?_⟩ + have := congrFun (congrArg Subtype.val (Frame.equivNeZero.symm.injective h)) ⟨0, by omega⟩ + simp [Fin.ext_iff] at this + +/-- **The second eigenvalue of the affine walk** on slice coordinates +`Frame P H 1 × ZMod L ^ H` is at most `1 - 1 / (77824 H ^ 4)`, for a prime `P` and `H ≥ 3`, +uniformly in `P` and `L`. -/ +theorem secondEigenvalue_ofPerms_affineMove_le [Fact P.Prime] [NeZero L] (hH : 3 ≤ H) : + (ofPerms (affineMove P H L 1)).secondEigenvalue ≤ 1 - 1 / (77824 * H ^ 4) := by + have := nontrivial_frame_one (P := P) (H := H) (by omega) + have : Nonempty ({p : Fin H × Fin H // p.1 ≠ p.2} ⊕ Fin H) := ⟨.inr ⟨0, by omega⟩⟩ + have hH0 : (0 : ℝ) < H := by exact_mod_cast (by omega : 0 < H) + have h := secondEigenvalue_ofPerms_le (affineMove P H L 1) (c := 1 / (38912 * H ^ 2)) + fun f hf ↦ by + have := expect_sq_le_affineMove hH f hf + rw [one_div_mul_eq_div, div_le_iff₀ (by positivity)] + linarith + refine h.trans_eq ?_ + rw [card_affineGenerator_index] + push_cast + field_simp + ring + +/-- **The spectral gap of the lazy affine walk** on slice coordinates `Frame P H 1 × ZMod L ^ H`: +its spectral expansion is at most `1 - 1 / (155648 H ^ 4)`, for a prime `P` and `H ≥ 3`, +uniformly in `P` and `L`. -/ +theorem spectralExpansion_lazy_ofPerms_affineMove_le [Fact P.Prime] [NeZero L] (hH : 3 ≤ H) : + (ofPerms (affineMove P H L 1)).lazy.spectralExpansion ≤ 1 - 1 / (155648 * H ^ 4) := by + have h₁ := + (ofPerms (affineMove P H L 1)).spectralExpansion_lazy_le_one_add_secondEigenvalue_div_two + have h₂ := secondEigenvalue_ofPerms_affineMove_le (P := P) (L := L) hH + have : 1 / (155648 * (H : ℝ) ^ 4) = (1 / (77824 * H ^ 4)) / 2 := by + rw [div_div] + ring + rw [this] + linarith + +/-- **Conditional averaging with the affine walk**: on the retention slice of every identifier +`y`, `t` steps of the lazy affine walk contract the conditional variance by +`(1 - 1 / (155648 H ^ 4)) ^ (2 t)`, for a prime `P`, `H ≥ 3` and `1 ≤ L ≤ P`, uniformly in `P`, +`L` and `y`. This discharges the gap hypothesis of +`expect_walk_pow_sliceGraph_sub_expect_sq_le` for frames of length one. -/ +theorem expect_walk_pow_sliceGraph_affineMove_sub_expect_sq_le [Fact P.Prime] [NeZero L] + (hH : 3 ≤ H) (hL : L ≤ P) (y : ZMod P) (f : RetentionSlice P H 1 L y → ℝ) (t : ℕ) : + 𝔼 A, (((sliceGraph L hL y (ofPerms (affineMove P H L 1)).lazy).walk ^ t) f A - 𝔼 B, f B) ^ 2 ≤ + (1 - 1 / (155648 * H ^ 4)) ^ (2 * t) * 𝔼 A, (f A - 𝔼 B, f B) ^ 2 := by + have : Nonempty ({p : Fin H × Fin H // p.1 ≠ p.2} ⊕ Fin H) := ⟨.inr ⟨0, by omega⟩⟩ + exact expect_walk_pow_sliceGraph_sub_expect_sq_le hL _ + (spectralExpansion_lazy_ofPerms_affineMove_le hH) y f t + +end Cslib.Probability diff --git a/ComplexityTests/SliceGap.lean b/ComplexityTests/SliceGap.lean new file mode 100644 index 000000000..8f2742814 --- /dev/null +++ b/ComplexityTests/SliceGap.lean @@ -0,0 +1,93 @@ +/- +Copyright (c) 2026 Christian Reitwiessner. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Christian Reitwiessner +-/ + +import Complexity.Foundations.Combinatorics.Expander.BoxProduct +import Complexity.Probability.PairwiseIndependentHash.SliceGap + +/-! +# The spectral gap of the affine walk on slice coordinates + +Concrete affine moves on `Frame 5 3 1 × ZMod 4 ^ 3`, the action of a transvection on a vector, the +count of frames and generators, conditional averaging on the retention slices of `𝔽₅ ^ 3` with the +gap hypothesis discharged, a client deriving that the action is transitive, and the box product of +two affine walks over unrelated fields. +-/ + +namespace ComplexityTests.SliceGap + +open Cslib Cslib.Probability Cslib.RotationMap Finset Matrix +open scoped BigOperators + +instance : Fact (Nat.Prime 5) := ⟨Nat.prime_five⟩ + +-- A transvection adds `c` times one coordinate to another, over any ring. +example : ((SpecialLinearGroup.transvection (show (0 : Fin 3) ≠ 2 by decide) (2 : ℤ) : + Matrix (Fin 3) (Fin 3) ℤ) *ᵥ ![1, 5, -3]) = ![-5, 5, -3] := by + rw [SpecialLinearGroup.transvection_mulVec] + decide + +/-- The frame of length one spanned by `(1, 0, 4)` in `𝔽₅ ^ 3`. -/ +def F : Frame 5 3 1 := Frame.equivNeZero.symm ⟨![1, 0, 4], by decide⟩ + +-- `1 + E_02` adds the coordinate `2` to the coordinate `0`, on the frame modulo `5` and on the box +-- coordinate modulo `4`, wrapping around in both. +example : (affineMove 5 3 4 1 (.inl ⟨(0, 2), by decide⟩) (F, ![3, 1, 2])).1.1 0 = ![0, 0, 4] := by + rw [affineMove_inl, Frame.mapSL_transvection_apply_zero] + decide +example : (affineMove 5 3 4 1 (.inl ⟨(0, 2), by decide⟩) (F, ![3, 1, 2])).2 = ![1, 1, 2] := by + rw [affineMove_inl] + decide +-- A unit translation moves only the box coordinate. +example : affineMove 5 3 4 1 (.inr 0) (F, ![3, 1, 2]) = (F, ![0, 1, 2]) := by + rw [affineMove_inr] + decide + +-- There are `5 ^ 3 - 1 = 124` frames of length one, and `3 ^ 2 = 9` generators. +example : Fintype.card (Frame 5 3 1) = 124 := Frame.card_one +example : Fintype.card ({p : Fin 3 × Fin 3 // p.1 ≠ p.2} ⊕ Fin 3) = 9 := by decide + +/-- **Conditional averaging with every hypothesis discharged**: on the retention slice of every +identifier of `𝔽₅`, with side `3`, `t` steps of the lazy affine walk contract the conditional +variance by `(1 - 1 / 12607488) ^ (2 t)`. -/ +example (y : ZMod 5) (f : RetentionSlice 5 3 1 3 y → ℝ) (t : ℕ) : + 𝔼 A, (((sliceGraph 3 (by norm_num) y (ofPerms (affineMove 5 3 3 1)).lazy).walk ^ t) f A - + 𝔼 B, f B) ^ 2 ≤ (1 - 1 / 12607488) ^ (2 * t) * 𝔼 A, (f A - 𝔼 B, f B) ^ 2 := by + have h := expect_walk_pow_sliceGraph_affineMove_sub_expect_sq_le le_rfl (by norm_num) y f t + norm_num at h ⊢ + exact h + +/-- **Transitivity from the gap**: for every prime `P` and side `L`, a real function on the slice +coordinates `Frame P 3 1 × ZMod L ^ 3` invariant under the affine moves is constant. -/ +example (P L : ℕ) [Fact P.Prime] [NeZero L] (f : Frame P 3 1 × (Fin 3 → ZMod L) → ℝ) + (hf : ∀ k p, f (affineMove P 3 L 1 k p) = f p) (p q : Frame P 3 1 × (Fin 3 → ZMod L)) : + f p = f q := by + have := Frame.nonempty (P := P) (H := 3) (r := 1) (by norm_num) + set f₀ := fun p ↦ f p - 𝔼 q, f q + have h := expect_sq_le_affineMove le_rfl f₀ (by simp [f₀, expect_sub_distrib]) + simp only [f₀, hf, sub_self] at h + norm_num at h + have h0 := (Fintype.expect_eq_zero_iff_of_nonneg fun p ↦ sq_nonneg (f p - 𝔼 q, f q)).1 + (le_antisymm h (expect_nonneg fun _ _ ↦ sq_nonneg _)) + have e (p) : f p = 𝔼 q, f q := sub_eq_zero.1 (pow_eq_zero_iff two_ne_zero |>.1 (congrFun h0 p)) + rw [e p, e q] + +/-- **Two components**: for all primes `P`, `P'` and sides `L`, `L'`, the lazy box product of the +affine walks of two channels has a uniform spectral gap, via `boxProdPerms`. -/ +example (P P' L L' : ℕ) [Fact P.Prime] [Fact P'.Prime] [NeZero L] [NeZero L'] : + (ofPerms (boxProdPerms (affineMove P 3 L 1) (affineMove P' 3 L' 1))).lazy.spectralExpansion ≤ + 1 - 1 / 25214976 := by + have : Nonempty ({p : Fin 3 × Fin 3 // p.1 ≠ p.2} ⊕ Fin 3) := ⟨.inr 0⟩ + refine (spectralExpansion_lazy_ofPerms_boxProdPerms_le _ _).trans ?_ + have h₁ := secondEigenvalue_ofPerms_affineMove_le (P := P) (L := L) le_rfl + have h₂ := secondEigenvalue_ofPerms_affineMove_le (P := P') (L := L') le_rfl + rw [card_affineGenerator_index] + norm_num at h₁ h₂ ⊢ + have : 1 / 700416 ≤ min (9 * (1 - (ofPerms (affineMove P 3 L 1)).secondEigenvalue)) + (9 * (1 - (ofPerms (affineMove P' 3 L' 1)).secondEigenvalue)) := + le_min (by linarith) (by linarith) + linarith + +end ComplexityTests.SliceGap