From 888918d31bf556a04215a38559542b30a557bc44 Mon Sep 17 00:00:00 2001 From: Samuel Giuseppe Schlesinger Date: Thu, 29 Oct 2026 15:10:19 -0400 Subject: [PATCH 01/25] chore(deps): track CSLib main and Lean rc2 Advance CSLib to 8a8ad748 and synchronize Mathlib, the documentation generator, Verso, and all three lockfiles with Lean v4.36.0-rc2. Keep the root and documentation projects on the same inherited dependency revisions. --- docbuild/lake-manifest.json | 34 +++++++++++++++++----------------- docbuild/lakefile.toml | 2 +- guide/lake-manifest.json | 30 +++++++++++++++--------------- guide/lakefile.toml | 2 +- lake-manifest.json | 26 +++++++++++++------------- lakefile.toml | 2 +- lean-toolchain | 2 +- 7 files changed, 49 insertions(+), 49 deletions(-) diff --git a/docbuild/lake-manifest.json b/docbuild/lake-manifest.json index 3609d26b5..a1f5e4692 100644 --- a/docbuild/lake-manifest.json +++ b/docbuild/lake-manifest.json @@ -5,10 +5,10 @@ "type": "git", "subDir": null, "scope": "leanprover", - "rev": "0656b7ebd305f089c8d6bd8684a0797f19414cc2", + "rev": "20afd4ddabd2ef38ffb1a8b930ee0f375e3f75e8", "name": "«doc-gen4»", "manifestFile": "lake-manifest.json", - "inputRev": "v4.36.0-rc1", + "inputRev": "v4.36.0-rc2", "inherited": false, "configFile": "lakefile.lean"}, {"type": "path", @@ -23,7 +23,7 @@ "type": "git", "subDir": null, "scope": "", - "rev": "e1faac1842cb10b3a68c644643b6e3568766343c", + "rev": "f582e4bc64d6f43e6e711f89b09567d2088fab8d", "name": "leansqlite", "manifestFile": "lake-manifest.json", "inputRev": "main", @@ -33,7 +33,7 @@ "type": "git", "subDir": null, "scope": "", - "rev": "34d2efffcb6dc8d5f3537cf6a7f88bfaa999ec49", + "rev": "c09cb1e4f1e6e1c231a1175a12b681b075054a1b", "name": "Cli", "manifestFile": "lake-manifest.json", "inputRev": "main", @@ -43,7 +43,7 @@ "type": "git", "subDir": null, "scope": "", - "rev": "a24bcde05a7971144ba0c0b5b1d60c3a0f0bc4af", + "rev": "91ece4f8d8f93aac566e247874f6b27b57249f1b", "name": "UnicodeBasic", "manifestFile": "lake-manifest.json", "inputRev": "main", @@ -53,7 +53,7 @@ "type": "git", "subDir": null, "scope": "", - "rev": "78f28e27259a4b2f5a8199800334cebd92730f3d", + "rev": "cdf8963f8b4c9a5593c5aaa9fa4f2759f8dec1c1", "name": "BibtexQuery", "manifestFile": "lake-manifest.json", "inputRev": "master", @@ -73,27 +73,27 @@ "type": "git", "subDir": null, "scope": "", - "rev": "f4a472560f78c59bbedd795fe041ec507f7d0582", + "rev": "8a8ad7489cdccb007ad7279bfb9d03bbda2229ad", "name": "cslib", "manifestFile": "lake-manifest.json", - "inputRev": "f4a472560f78c59bbedd795fe041ec507f7d0582", + "inputRev": "8a8ad7489cdccb007ad7279bfb9d03bbda2229ad", "inherited": true, "configFile": "lakefile.toml"}, {"url": "https://github.com/leanprover-community/mathlib4", "type": "git", "subDir": null, "scope": "leanprover-community", - "rev": "625d8914199bc567cca9b91f90e8e5afafa5ae51", + "rev": "9d581dfff2e41de989072ea63abf3daf69311520", "name": "mathlib", "manifestFile": "lake-manifest.json", - "inputRev": "v4.36.0-rc1", + "inputRev": "v4.36.0-rc2", "inherited": true, "configFile": "lakefile.lean"}, {"url": "https://github.com/leanprover-community/plausible", "type": "git", "subDir": null, "scope": "leanprover-community", - "rev": "c2d7840c65673533e15b499f25beecdc6227f7d8", + "rev": "129d1ba9a16bc0660f46c79e9fb041ef5d5d80de", "name": "plausible", "manifestFile": "lake-manifest.json", "inputRev": "main", @@ -103,7 +103,7 @@ "type": "git", "subDir": null, "scope": "leanprover-community", - "rev": "9d39f9bb0c30aa2f6200808805ff16e6ce950890", + "rev": "c61286b7b63cbfd563b28e11e81d0a18233a044a", "name": "LeanSearchClient", "manifestFile": "lake-manifest.json", "inputRev": "main", @@ -113,7 +113,7 @@ "type": "git", "subDir": null, "scope": "leanprover-community", - "rev": "b3cc36c295aa5e3e3c0197b09a6556298e710447", + "rev": "b8cc5dd0a36233b88a6ed5a7dbf1207d09338c60", "name": "importGraph", "manifestFile": "lake-manifest.json", "inputRev": "main", @@ -123,7 +123,7 @@ "type": "git", "subDir": null, "scope": "leanprover-community", - "rev": "17137fad38a2cc782ff00b323a13c3a991d085ab", + "rev": "16259c0d07d61ee37d999d05b5cf96338b8daa11", "name": "proofwidgets", "manifestFile": "lake-manifest.json", "inputRev": "main", @@ -133,7 +133,7 @@ "type": "git", "subDir": null, "scope": "leanprover-community", - "rev": "cbdde3aa2665915fb286c48bcd4cdf885c629511", + "rev": "7d11bfa88558f8d3d90afdf6bd877ed70001498d", "name": "aesop", "manifestFile": "lake-manifest.json", "inputRev": "master", @@ -143,7 +143,7 @@ "type": "git", "subDir": null, "scope": "leanprover-community", - "rev": "6d26f8bb4b2bb78f929ad160feac508866821316", + "rev": "b0256621cb88178e9ad932a53633077b3029e621", "name": "Qq", "manifestFile": "lake-manifest.json", "inputRev": "master", @@ -153,7 +153,7 @@ "type": "git", "subDir": null, "scope": "leanprover-community", - "rev": "4453b52d2468f4c346a8711d728c0742e7483c9b", + "rev": "d4c39b228d4a06f3b00748c2c445a7b9f056a6e3", "name": "batteries", "manifestFile": "lake-manifest.json", "inputRev": "main", diff --git a/docbuild/lakefile.toml b/docbuild/lakefile.toml index ed4689727..b9c4092df 100644 --- a/docbuild/lakefile.toml +++ b/docbuild/lakefile.toml @@ -12,4 +12,4 @@ path = ".." [[require]] scope = "leanprover" name = "doc-gen4" -rev = "v4.36.0-rc1" +rev = "v4.36.0-rc2" diff --git a/guide/lake-manifest.json b/guide/lake-manifest.json index b8da10f21..3f19786a0 100644 --- a/guide/lake-manifest.json +++ b/guide/lake-manifest.json @@ -5,10 +5,10 @@ "type": "git", "subDir": null, "scope": "", - "rev": "f7a4dc6867f8df27778b2b320763ec9e3b7be070", + "rev": "71a2035b44e7f54a797ce799fd1b03cdd3a44684", "name": "verso", "manifestFile": "lake-manifest.json", - "inputRev": "v4.36.0-rc1", + "inputRev": "v4.36.0-rc2", "inherited": false, "configFile": "lakefile.lean"}, {"type": "path", @@ -23,7 +23,7 @@ "type": "git", "subDir": null, "scope": "", - "rev": "34d2efffcb6dc8d5f3537cf6a7f88bfaa999ec49", + "rev": "c09cb1e4f1e6e1c231a1175a12b681b075054a1b", "name": "Cli", "manifestFile": "lake-manifest.json", "inputRev": "main", @@ -33,7 +33,7 @@ "type": "git", "subDir": null, "scope": "", - "rev": "d22e76ef3d2a925132315af902ea432233b4a44a", + "rev": "758bff3509b8e90ca82e37aa5de81de3c9e70fc0", "name": "illuminate", "manifestFile": "lake-manifest.json", "inputRev": "main", @@ -43,7 +43,7 @@ "type": "git", "subDir": null, "scope": "", - "rev": "c2d7840c65673533e15b499f25beecdc6227f7d8", + "rev": "129d1ba9a16bc0660f46c79e9fb041ef5d5d80de", "name": "plausible", "manifestFile": "lake-manifest.json", "inputRev": "main", @@ -73,27 +73,27 @@ "type": "git", "subDir": null, "scope": "", - "rev": "f4a472560f78c59bbedd795fe041ec507f7d0582", + "rev": "8a8ad7489cdccb007ad7279bfb9d03bbda2229ad", "name": "cslib", "manifestFile": "lake-manifest.json", - "inputRev": "f4a472560f78c59bbedd795fe041ec507f7d0582", + "inputRev": "8a8ad7489cdccb007ad7279bfb9d03bbda2229ad", "inherited": true, "configFile": "lakefile.toml"}, {"url": "https://github.com/leanprover-community/mathlib4", "type": "git", "subDir": null, "scope": "leanprover-community", - "rev": "625d8914199bc567cca9b91f90e8e5afafa5ae51", + "rev": "9d581dfff2e41de989072ea63abf3daf69311520", "name": "mathlib", "manifestFile": "lake-manifest.json", - "inputRev": "v4.36.0-rc1", + "inputRev": "v4.36.0-rc2", "inherited": true, "configFile": "lakefile.lean"}, {"url": "https://github.com/leanprover-community/LeanSearchClient", "type": "git", "subDir": null, "scope": "leanprover-community", - "rev": "9d39f9bb0c30aa2f6200808805ff16e6ce950890", + "rev": "c61286b7b63cbfd563b28e11e81d0a18233a044a", "name": "LeanSearchClient", "manifestFile": "lake-manifest.json", "inputRev": "main", @@ -103,7 +103,7 @@ "type": "git", "subDir": null, "scope": "leanprover-community", - "rev": "b3cc36c295aa5e3e3c0197b09a6556298e710447", + "rev": "b8cc5dd0a36233b88a6ed5a7dbf1207d09338c60", "name": "importGraph", "manifestFile": "lake-manifest.json", "inputRev": "main", @@ -113,7 +113,7 @@ "type": "git", "subDir": null, "scope": "leanprover-community", - "rev": "17137fad38a2cc782ff00b323a13c3a991d085ab", + "rev": "16259c0d07d61ee37d999d05b5cf96338b8daa11", "name": "proofwidgets", "manifestFile": "lake-manifest.json", "inputRev": "main", @@ -123,7 +123,7 @@ "type": "git", "subDir": null, "scope": "leanprover-community", - "rev": "cbdde3aa2665915fb286c48bcd4cdf885c629511", + "rev": "7d11bfa88558f8d3d90afdf6bd877ed70001498d", "name": "aesop", "manifestFile": "lake-manifest.json", "inputRev": "master", @@ -133,7 +133,7 @@ "type": "git", "subDir": null, "scope": "leanprover-community", - "rev": "6d26f8bb4b2bb78f929ad160feac508866821316", + "rev": "b0256621cb88178e9ad932a53633077b3029e621", "name": "Qq", "manifestFile": "lake-manifest.json", "inputRev": "master", @@ -143,7 +143,7 @@ "type": "git", "subDir": null, "scope": "leanprover-community", - "rev": "4453b52d2468f4c346a8711d728c0742e7483c9b", + "rev": "d4c39b228d4a06f3b00748c2c445a7b9f056a6e3", "name": "batteries", "manifestFile": "lake-manifest.json", "inputRev": "main", diff --git a/guide/lakefile.toml b/guide/lakefile.toml index fb7601692..f62d2a91a 100644 --- a/guide/lakefile.toml +++ b/guide/lakefile.toml @@ -21,7 +21,7 @@ path = ".." [[require]] name = "verso" git = "https://github.com/leanprover/verso" -rev = "v4.36.0-rc1" +rev = "v4.36.0-rc2" [[lean_lib]] name = "ComplexityGuide" diff --git a/lake-manifest.json b/lake-manifest.json index a4892b4fc..a2c1eaffd 100644 --- a/lake-manifest.json +++ b/lake-manifest.json @@ -5,27 +5,27 @@ "type": "git", "subDir": null, "scope": "", - "rev": "f4a472560f78c59bbedd795fe041ec507f7d0582", + "rev": "8a8ad7489cdccb007ad7279bfb9d03bbda2229ad", "name": "cslib", "manifestFile": "lake-manifest.json", - "inputRev": "f4a472560f78c59bbedd795fe041ec507f7d0582", + "inputRev": "8a8ad7489cdccb007ad7279bfb9d03bbda2229ad", "inherited": false, "configFile": "lakefile.toml"}, {"url": "https://github.com/leanprover-community/mathlib4", "type": "git", "subDir": null, "scope": "leanprover-community", - "rev": "625d8914199bc567cca9b91f90e8e5afafa5ae51", + "rev": "9d581dfff2e41de989072ea63abf3daf69311520", "name": "mathlib", "manifestFile": "lake-manifest.json", - "inputRev": "v4.36.0-rc1", + "inputRev": "v4.36.0-rc2", "inherited": true, "configFile": "lakefile.lean"}, {"url": "https://github.com/leanprover-community/plausible", "type": "git", "subDir": null, "scope": "leanprover-community", - "rev": "c2d7840c65673533e15b499f25beecdc6227f7d8", + "rev": "129d1ba9a16bc0660f46c79e9fb041ef5d5d80de", "name": "plausible", "manifestFile": "lake-manifest.json", "inputRev": "main", @@ -35,7 +35,7 @@ "type": "git", "subDir": null, "scope": "leanprover-community", - "rev": "9d39f9bb0c30aa2f6200808805ff16e6ce950890", + "rev": "c61286b7b63cbfd563b28e11e81d0a18233a044a", "name": "LeanSearchClient", "manifestFile": "lake-manifest.json", "inputRev": "main", @@ -45,7 +45,7 @@ "type": "git", "subDir": null, "scope": "leanprover-community", - "rev": "b3cc36c295aa5e3e3c0197b09a6556298e710447", + "rev": "b8cc5dd0a36233b88a6ed5a7dbf1207d09338c60", "name": "importGraph", "manifestFile": "lake-manifest.json", "inputRev": "main", @@ -55,7 +55,7 @@ "type": "git", "subDir": null, "scope": "leanprover-community", - "rev": "17137fad38a2cc782ff00b323a13c3a991d085ab", + "rev": "16259c0d07d61ee37d999d05b5cf96338b8daa11", "name": "proofwidgets", "manifestFile": "lake-manifest.json", "inputRev": "main", @@ -65,7 +65,7 @@ "type": "git", "subDir": null, "scope": "leanprover-community", - "rev": "cbdde3aa2665915fb286c48bcd4cdf885c629511", + "rev": "7d11bfa88558f8d3d90afdf6bd877ed70001498d", "name": "aesop", "manifestFile": "lake-manifest.json", "inputRev": "master", @@ -75,7 +75,7 @@ "type": "git", "subDir": null, "scope": "leanprover-community", - "rev": "6d26f8bb4b2bb78f929ad160feac508866821316", + "rev": "b0256621cb88178e9ad932a53633077b3029e621", "name": "Qq", "manifestFile": "lake-manifest.json", "inputRev": "master", @@ -85,7 +85,7 @@ "type": "git", "subDir": null, "scope": "leanprover-community", - "rev": "4453b52d2468f4c346a8711d728c0742e7483c9b", + "rev": "d4c39b228d4a06f3b00748c2c445a7b9f056a6e3", "name": "batteries", "manifestFile": "lake-manifest.json", "inputRev": "main", @@ -95,10 +95,10 @@ "type": "git", "subDir": null, "scope": "leanprover", - "rev": "34d2efffcb6dc8d5f3537cf6a7f88bfaa999ec49", + "rev": "c09cb1e4f1e6e1c231a1175a12b681b075054a1b", "name": "Cli", "manifestFile": "lake-manifest.json", - "inputRev": "v4.36.0-rc1", + "inputRev": "v4.36.0-rc2", "inherited": true, "configFile": "lakefile.toml"}], "name": "complexitylib", diff --git a/lakefile.toml b/lakefile.toml index ce7b8cd77..00f09a874 100644 --- a/lakefile.toml +++ b/lakefile.toml @@ -33,7 +33,7 @@ autoImplicit = false [[require]] name = "cslib" git = "https://github.com/leanprover/cslib" -rev = "f4a472560f78c59bbedd795fe041ec507f7d0582" +rev = "8a8ad7489cdccb007ad7279bfb9d03bbda2229ad" [[lean_lib]] name = "Complexity" diff --git a/lean-toolchain b/lean-toolchain index 2afd38716..0fc433692 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:v4.36.0-rc1 +leanprover/lean4:v4.36.0-rc2 From 9a1b75416b7723a073411f0ee9a7d2ccfdd49ec9 Mon Sep 17 00:00:00 2001 From: Samuel Giuseppe Schlesinger Date: Thu, 29 Oct 2026 15:10:24 -0400 Subject: [PATCH 02/25] refactor(probability): use generic infinite-sum lemmas Replace 187 deprecated ENNReal wrapper uses across 55 proof files with their generic counterparts. The exact mapping is: - ENNReal.tsum_le_tsum -> tsum_le_tsum (94) - ENNReal.tsum_add -> tsum_add (54) - ENNReal.tsum_eq_zero -> tsum_eq_zero_iff (14) - ENNReal.summable -> CompleteLattice.summable (6) - ENNReal.tsum_comm -> tsum_comm (6) - ENNReal.tsum_prod' -> tsum_prod' (5) - ENNReal.le_tsum -> le_tsum (5) - ENNReal.tsum_eq_add_tsum_ite -> tsum_eq_add_tsum_ite (2) - ENNReal.tsum_sigma -> tsum_sigma (1) The old wrappers invoke these same theorems specialized to ENNReal. All five le_tsum calls already pass the function by name. No statements or definitions change. --- .../Algorithms/WordRAM/Karger/FastCut.lean | 2 +- .../Algorithms/WordRAM/Karger/Graph.lean | 6 +-- .../Algorithms/WordRAM/KargerMinCut.lean | 2 +- .../Algorithms/WordRAM/KargerStein.lean | 6 +-- .../Computability/Complexity/Classes/IP.lean | 2 +- .../Classes/IP/GraphNonIsomorphism.lean | 2 +- .../Complexity/Classes/IP/Guessing.lean | 6 +-- .../Complexity/Classes/IP/OptimalProver.lean | 8 ++-- .../Complexity/Classes/IP/Repetition.lean | 6 +-- .../LogSpace/Randomized/Amplification.lean | 2 +- .../Complexity/Classes/MIP/OptimalProver.lean | 4 +- .../Complexity/FineGrained/PPSZ/Basic.lean | 2 +- .../Complexity/FineGrained/PPZ.lean | 2 +- .../Computability/Interactive/Plain.lean | 4 +- .../Computability/Kolmogorov/AverageCase.lean | 4 +- .../Computability/PCP/TwoProverGame.lean | 2 +- .../WordRAM/Randomized/Expected.lean | 12 ++--- .../CramerShoup/ProjectiveHash.lean | 4 +- .../Computational/CramerShoup/Scheme.lean | 2 +- .../Crypto/Computational/DiffieHellman.lean | 16 +++---- .../Computational/DiffieHellman/Order.lean | 4 +- .../Encryption/Authenticated.lean | 14 +++--- .../Encryption/EncryptThenMAC.lean | 8 ++-- .../Crypto/Computational/GMW/Soundness.lean | 6 +-- Complexity/Crypto/Computational/MAC.lean | 8 ++-- .../Computational/NaorReingold/Security.lean | 10 ++-- .../Computational/OneWay/LiuPassConverse.lean | 2 +- .../Computational/OneWayToSignature.lean | 6 +-- .../Crypto/Computational/PRGToOneWay.lean | 2 +- .../Computational/PedersenCommitment.lean | 8 ++-- .../Pseudoentropy/MaskedExtraction.lean | 2 +- Complexity/Crypto/Game.lean | 20 ++++---- Complexity/Crypto/Game/UntilBad.lean | 16 +++---- Complexity/Crypto/Primitives/PRG/NextBit.lean | 4 +- .../Crypto/Protocols/Cipher/EvenMansour.lean | 6 +-- .../Crypto/Protocols/Cipher/LubyRackoff.lean | 48 +++++++++---------- .../Crypto/Protocols/MAC/CarterWegman.lean | 16 +++---- .../Protocols/SigmaProtocol/FiatShamir.lean | 6 +-- .../Probabilistic/BoundedUniform.lean | 6 +-- .../Languages/Probabilistic/Expect.lean | 8 ++-- .../Probabilistic/Oracle/Interaction.lean | 2 +- .../Probabilistic/RandomPermutation.lean | 8 ++-- .../Languages/Probabilistic/UntilBad.lean | 10 ++-- .../Languages/Probabilistic/Vector.lean | 2 +- Complexity/Probability/Conditioning.lean | 6 +-- .../Probability/CorrelatedSampling.lean | 2 +- Complexity/Probability/Forking.lean | 2 +- Complexity/Probability/IID.lean | 2 +- Complexity/Probability/MinEntropy.lean | 2 +- Complexity/Probability/Minimax.lean | 4 +- Complexity/Probability/PMF/Bind.lean | 14 +++--- Complexity/Probability/PMF/Event.lean | 16 +++---- Complexity/Probability/PMF/Map.lean | 2 +- .../ProductConditioning/SideInformation.lean | 2 +- Complexity/Probability/RejectionSampling.lean | 4 +- 55 files changed, 186 insertions(+), 186 deletions(-) diff --git a/Complexity/Algorithms/WordRAM/Karger/FastCut.lean b/Complexity/Algorithms/WordRAM/Karger/FastCut.lean index a216c2ae8..30a2afa92 100644 --- a/Complexity/Algorithms/WordRAM/Karger/FastCut.lean +++ b/Complexity/Algorithms/WordRAM/Karger/FastCut.lean @@ -658,7 +658,7 @@ theorem two_branch_hit_prob_ge {α β γ : Type} (m₁ : ProbComp α) (m₂ : α have ha : a ∈ m₁.support := (ProbComp.support_eval m₁) ▸ ha_eval have ha_hit : a ∈ hit₁ := not_not.mp ha_not_miss rw [PMF.toOuterMeasure_map_apply, PMF.toOuterMeasure_apply] - refine ENNReal.tsum_eq_zero.mpr fun b => ?_ + refine tsum_eq_zero_iff.mpr fun b => ?_ by_cases hb_eval : b ∈ (m₂ a).eval.support · have hb : b ∈ (m₂ a).support := (ProbComp.support_eval (m₂ a)) ▸ hb_eval have hmem : f a b ∈ hit := hprop₁ a ha ha_hit b hb diff --git a/Complexity/Algorithms/WordRAM/Karger/Graph.lean b/Complexity/Algorithms/WordRAM/Karger/Graph.lean index 9afa1d805..c03da4013 100644 --- a/Complexity/Algorithms/WordRAM/Karger/Graph.lean +++ b/Complexity/Algorithms/WordRAM/Karger/Graph.lean @@ -1107,7 +1107,7 @@ theorem toOuterMeasure_bind_ge_mul_ennreal {α β : Type*} (p : PMF α) (kernel s₁ * s₂ ≤ p.toOuterMeasure pre * s₂ := mul_le_mul_of_nonneg_right hp zero_le _ ≤ (p.bind kernel).toOuterMeasure event := by rw [PMF.toOuterMeasure_bind_apply, PMF.toOuterMeasure_apply, ← ENNReal.tsum_mul_right] - refine ENNReal.tsum_le_tsum fun a => ?_ + refine tsum_le_tsum fun a => ?_ by_cases ha : a ∈ pre · simp only [Set.indicator_of_mem ha] by_cases hs : a ∈ p.support @@ -1131,7 +1131,7 @@ theorem toOuterMeasure_bind_le_mul_ennreal {α β : Type*} (p : PMF α) (kernel (p.bind kernel).toOuterMeasure failure ≤ p.toOuterMeasure stillFailing * q₂ := by rw [PMF.toOuterMeasure_bind_apply, PMF.toOuterMeasure_apply, ← ENNReal.tsum_mul_right] - refine ENNReal.tsum_le_tsum fun a => ?_ + refine tsum_le_tsum fun a => ?_ by_cases hs : a ∈ p.support · by_cases ha : a ∈ stillFailing · simp only [Set.indicator_of_mem ha] @@ -1146,7 +1146,7 @@ valid on arbitrary types without measurability hypotheses. -/ theorem toOuterMeasure_add_compl_ennreal {α : Type*} (p : PMF α) (s : Set α) : p.toOuterMeasure s + p.toOuterMeasure sᶜ = 1 := by classical - rw [PMF.toOuterMeasure_apply, PMF.toOuterMeasure_apply, ← ENNReal.tsum_add] + rw [PMF.toOuterMeasure_apply, PMF.toOuterMeasure_apply, ← tsum_add] have hpt : (fun x => s.indicator p x + sᶜ.indicator p x) = p := by ext x by_cases hx : x ∈ s <;> simp [hx] diff --git a/Complexity/Algorithms/WordRAM/KargerMinCut.lean b/Complexity/Algorithms/WordRAM/KargerMinCut.lean index b3ef003a5..c07c84a3c 100644 --- a/Complexity/Algorithms/WordRAM/KargerMinCut.lean +++ b/Complexity/Algorithms/WordRAM/KargerMinCut.lean @@ -1181,7 +1181,7 @@ theorem ampLoop_spec {w sb n R : ℕ} {W : Fin n → Fin n → ℕ} {mem₀ : obtain ⟨m_r, hm_r, _, hsup_r, _⟩ := hnext z₁ hz₁ rw [hml_def, hm_r.codeComp_eq, PMF.toOuterMeasure_map_apply, PMF.toOuterMeasure_apply] - convert ENNReal.tsum_eq_zero.mpr _ + convert tsum_eq_zero_iff.mpr _ intro z₂ by_cases hz₂_eval : z₂ ∈ m_r.eval.support · have hz₂ : z₂ ∈ m_r.support := (ProbComp.support_eval m_r) ▸ hz₂_eval diff --git a/Complexity/Algorithms/WordRAM/KargerStein.lean b/Complexity/Algorithms/WordRAM/KargerStein.lean index 92368fc36..5a2a42a1a 100644 --- a/Complexity/Algorithms/WordRAM/KargerStein.lean +++ b/Complexity/Algorithms/WordRAM/KargerStein.lean @@ -168,7 +168,7 @@ private theorem toOuterMeasure_mono_support {α : Type} (m : ProbComp α) {S T : m.eval.toOuterMeasure S ≤ m.eval.toOuterMeasure T := by classical rw [PMF.toOuterMeasure_apply, PMF.toOuterMeasure_apply] - refine ENNReal.tsum_le_tsum fun a => ?_ + refine tsum_le_tsum fun a => ?_ by_cases ha : a ∈ S · simp only [Set.indicator_of_mem ha] by_cases hs : a ∈ m.support @@ -2684,7 +2684,7 @@ theorem fastCutNode_spec {n w : ℕ} {W₀ : Fin n → Fin n → ℕ} have hcompl0 : (ms2_fn z₂.1).eval.toOuterMeasure {zs | zs.1.regs retVal = minCut W₀}ᶜ = 0 := by rw [PMF.toOuterMeasure_apply] - refine ENNReal.tsum_eq_zero.mpr fun zs => ?_ + refine tsum_eq_zero_iff.mpr fun zs => ?_ by_cases hzs_ev : zs ∈ (ms2_fn z₂.1).eval.support · have hzs : zs ∈ (ms2_fn z₂.1).support := (ProbComp.support_eval (ms2_fn z₂.1)) ▸ hzs_ev @@ -3679,7 +3679,7 @@ theorem fastCutAmpLoop_spec {w sb n R : ℕ} {W : Fin n → Fin n → ℕ} {mem have hbv₁ : z₁.1.regs bestVal = minCut W := not_not.mp hhit obtain ⟨m_r, hm_r, _, hsup_r, _⟩ := hnext z₁ hz₁ rw [hml_def, hm_r.codeComp_eq, PMF.toOuterMeasure_map_apply, PMF.toOuterMeasure_apply] - refine ENNReal.tsum_eq_zero.mpr fun z₂ => ?_ + refine tsum_eq_zero_iff.mpr fun z₂ => ?_ by_cases hz₂_eval : z₂ ∈ m_r.eval.support · have hz₂ : z₂ ∈ m_r.support := (ProbComp.support_eval m_r) ▸ hz₂_eval have hbv₂ : z₂.1.regs bestVal = minCut W := diff --git a/Complexity/Computability/Complexity/Classes/IP.lean b/Complexity/Computability/Complexity/Classes/IP.lean index d2c73a5bc..d583e0f90 100644 --- a/Complexity/Computability/Complexity/Classes/IP.lean +++ b/Complexity/Computability/Complexity/Classes/IP.lean @@ -148,7 +148,7 @@ theorem acceptProb_eq_acceptProbWith (verifier : WordOracleComp Operation Bool) /-- The acceptance probability sums the masses of the accepting outcomes over final states. -/ theorem acceptProb_eq_tsum (verifier : WordOracleComp Operation Bool) (P : Prover Operation) : acceptProb verifier P = ∑' s, P.run verifier P.init (true, s) := by - rw [acceptProb, PMF.map_apply, ENNReal.tsum_prod', tsum_bool] + rw [acceptProb, PMF.map_apply, tsum_prod', tsum_bool] simp /-- Private coins drawn before any message average the acceptance probabilities of the diff --git a/Complexity/Computability/Complexity/Classes/IP/GraphNonIsomorphism.lean b/Complexity/Computability/Complexity/Classes/IP/GraphNonIsomorphism.lean index dfce7de33..659f372bf 100644 --- a/Complexity/Computability/Complexity/Classes/IP/GraphNonIsomorphism.lean +++ b/Complexity/Computability/Complexity/Classes/IP/GraphNonIsomorphism.lean @@ -413,7 +413,7 @@ private theorem card_filter_not_injective_div_le (n : ℕ) : private theorem tsum_map_mul {β γ : Type*} (μ : PMF β) (m : β → γ) (f : γ → ENNReal) : ∑' c, μ.map m c * f c = ∑' b, μ b * f (m b) := by simp only [PMF.map_apply, ENNReal.tsum_mul_right.symm] - rw [ENNReal.tsum_comm] + rw [tsum_comm] refine tsum_congr fun b => ?_ rw [tsum_eq_single (m b)] · simp diff --git a/Complexity/Computability/Complexity/Classes/IP/Guessing.lean b/Complexity/Computability/Complexity/Classes/IP/Guessing.lean index 6eaedc8da..02e8929d3 100644 --- a/Complexity/Computability/Complexity/Classes/IP/Guessing.lean +++ b/Complexity/Computability/Complexity/Classes/IP/Guessing.lean @@ -77,8 +77,8 @@ noncomputable def Prover.guessProb (P : Prover Unit) (s : P.State) (m : List Boo theorem Prover.guessProb_add_le_one (P : Prover Unit) (s : P.State) (m : List Bool) : P.guessProb s m false + P.guessProb s m true ≤ 1 := by simp only [Prover.guessProb, PMF.map_apply] - rw [← ENNReal.tsum_add, ← PMF.tsum_coe ((P.respond ((), m)).run s)] - refine ENNReal.tsum_le_tsum fun y => ?_ + rw [← tsum_add, ← PMF.tsum_coe ((P.respond ((), m)).run s)] + refine tsum_le_tsum fun y => ?_ by_cases h : List.take 1 y.1 = [false] · simp [h] · by_cases h' : List.take 1 y.1 = [true] <;> simp [h, h'] @@ -120,7 +120,7 @@ theorem acceptProb_guessingRound_le {message : Bool → ProbComp (List Bool)} { exact hclose _ fun m => PMF.coe_le_one _ _ _ = ∑' m, ProbComp.eval (message false) m * (P.guessProb P.init m false + P.guessProb P.init m true) + δ := by - rw [← add_assoc, ← ENNReal.tsum_add] + rw [← add_assoc, ← tsum_add] simp only [mul_add] _ ≤ 1 + δ := by gcongr diff --git a/Complexity/Computability/Complexity/Classes/IP/OptimalProver.lean b/Complexity/Computability/Complexity/Classes/IP/OptimalProver.lean index 3ad366c14..7fd4eec66 100644 --- a/Complexity/Computability/Complexity/Classes/IP/OptimalProver.lean +++ b/Complexity/Computability/Complexity/Classes/IP/OptimalProver.lean @@ -304,7 +304,7 @@ private theorem sum_acceptFrom_after_le (hF : IsBounded F D L) (P : Prover Unit) lia rw [Finset.sum_eq_zero fun m _ => ?_, add_zero] · split_ifs <;> simp - · refine ENNReal.tsum_eq_zero.mpr fun ys => ?_ + · refine tsum_eq_zero_iff.mpr fun ys => ?_ rw [after_append] unfold outcome at hnil rcases hah : after (F r) h with _ | ⟨b⟩ | ⟨q, next⟩ @@ -320,12 +320,12 @@ private theorem sum_acceptFrom_after_le (hF : IsBounded F D L) (P : Prover Unit) exact (Finset.sum_congr rfl fun r _ => by split_ifs <;> simp).le rw [Finset.sum_comm] refine Finset.sum_le_sum fun m _ => ?_ - rw [← Summable.tsum_finsetSum fun r _ => ENNReal.summable] + rw [← Summable.tsum_finsetSum fun r _ => CompleteLattice.summable] calc ∑' ys : List Bool × P.State, ∑ r, (P.respond ((), m)).run s ys * acceptFrom P ys.2 (after (F r) (h ++ [(m, ys.1)])) ≤ ∑' ys : List Bool × P.State, (P.respond ((), m)).run s ys * ((BitString.shortWords L).sup fun y => value F L n (h ++ [(m, y)]) : ℕ) := by - refine ENNReal.tsum_le_tsum fun ys => ?_ + refine tsum_le_tsum fun ys => ?_ rw [← Finset.mul_sum] refine mul_le_mul_right ?_ _ refine (ih (h ++ [(m, ys.1)]) (by @@ -395,7 +395,7 @@ private theorem sum_acceptFrom_optimalProver_after (hF : IsBounded F D L) (n : lia rw [Finset.sum_eq_zero fun m _ => ?_, add_zero] · split_ifs <;> simp - · refine ENNReal.tsum_eq_zero.mpr fun ys => ?_ + · refine tsum_eq_zero_iff.mpr fun ys => ?_ rw [after_append] unfold outcome at hnil rcases hah : after (F r) h with _ | ⟨b⟩ | ⟨q, next⟩ diff --git a/Complexity/Computability/Complexity/Classes/IP/Repetition.lean b/Complexity/Computability/Complexity/Classes/IP/Repetition.lean index 66023d528..77f8fb503 100644 --- a/Complexity/Computability/Complexity/Classes/IP/Repetition.lean +++ b/Complexity/Computability/Complexity/Classes/IP/Repetition.lean @@ -64,7 +64,7 @@ private theorem acceptProb_bind_ite (P : Prover Operation) acceptProb (do let ok ← round; if ok then rest else pure false) P = ∑' s, P.run round P.init (true, s) * acceptProb rest { P with init := s } := by simp only [acceptProb, Prover.run_bind, PMF.map_bind] - rw [PMF.bind_apply, ENNReal.tsum_prod', tsum_bool] + rw [PMF.bind_apply, tsum_prod', tsum_bool] simp only [Bool.false_eq_true, Bool.true_eq_false, ↓reduceIte, Prover.run_pure, PMF.pure_map, PMF.pure_apply, mul_zero, tsum_zero, zero_add] rfl @@ -81,7 +81,7 @@ theorem acceptProb_sequentialRepeat_le {round : WordOracleComp Operation Bool} { calc ∑' s, P.run round P.init (true, s) * acceptProb (sequentialRepeat k round) { P with init := s } ≤ ∑' s, P.run round P.init (true, s) * ε ^ k := - ENNReal.tsum_le_tsum fun s => mul_le_mul' le_rfl (ih _) + tsum_le_tsum fun s => mul_le_mul' le_rfl (ih _) _ = (∑' s, P.run round P.init (true, s)) * ε ^ k := ENNReal.tsum_mul_right _ ≤ ε * ε ^ k := by gcongr @@ -103,7 +103,7 @@ theorem le_acceptProb_sequentialRepeat {round : WordOracleComp Operation Bool} { gcongr exact (h s).trans_eq (acceptProb_eq_tsum round _) _ = ∑' s', P.run round s (true, s') * c ^ k := ENNReal.tsum_mul_right.symm - _ ≤ _ := ENNReal.tsum_le_tsum fun s' => mul_le_mul' le_rfl (ih s') + _ ≤ _ := tsum_le_tsum fun s' => mul_le_mul' le_rfl (ih s') /-- A constant number of sequential runs of a strict oracle PPT verifier is strict oracle PPT. -/ theorem isOraclePPTOn_sequentialRepeat [DecidableEq Operation] [Finite Operation] diff --git a/Complexity/Computability/Complexity/Classes/LogSpace/Randomized/Amplification.lean b/Complexity/Computability/Complexity/Classes/LogSpace/Randomized/Amplification.lean index 1c3606355..56fd01273 100644 --- a/Complexity/Computability/Complexity/Classes/LogSpace/Randomized/Amplification.lean +++ b/Complexity/Computability/Complexity/Classes/LogSpace/Randomized/Amplification.lean @@ -126,7 +126,7 @@ theorem eval_runClosed_orElse_apply (h₁ : first.toNTM.RunsInTime input t₁) exact congrArg _ (PMF.pure_apply_self _) · rw [add_zero] _ = q + ProbComp.eval (first.runClosed t₁ input) [true] * (1 - q) := by - rw [ENNReal.tsum_add, ENNReal.tsum_mul_right, PMF.tsum_coe, one_mul, tsum_ite_eq] + rw [tsum_add, ENNReal.tsum_mul_right, PMF.tsum_coe, one_mul, tsum_ite_eq] /-- **Rejections multiply under `orElse`.** Counted on coin strings, the probability that `first.orElse second` does not accept is the product of the probabilities that `first` and diff --git a/Complexity/Computability/Complexity/Classes/MIP/OptimalProver.lean b/Complexity/Computability/Complexity/Classes/MIP/OptimalProver.lean index ebf6834a9..0f1a57869 100644 --- a/Complexity/Computability/Complexity/Classes/MIP/OptimalProver.lean +++ b/Complexity/Computability/Complexity/Classes/MIP/OptimalProver.lean @@ -581,7 +581,7 @@ private theorem tsum_mul_le_bestOfList (μ : PMF α) (g : α → ℝ≥0∞) (de ∑' x, μ x * g x ≤ g (bestOfList g default l) := by calc ∑' x, μ x * g x ≤ ∑' x, μ x * g (bestOfList g default l) := by - refine ENNReal.tsum_le_tsum fun x => ?_ + refine tsum_le_tsum fun x => ?_ by_cases hx : x ∈ μ.support · exact mul_le_mul_right (le_bestOfList g default l (hsupp x hx)) (μ x) · rw [PMF.mem_support_iff, not_not] at hx @@ -618,7 +618,7 @@ theorem exists_deterministic_prover_family [Finite ι] [DecidableEq ι] {γ : Ty rw [run_eq_bind_piPresample (hF c) P (fun _ => d) (fun _ => le_rfl) (Prover.independent P).init, PMF.bind_apply] simp only [hc, ← ENNReal.tsum_mul_left] - rw [← Summable.tsum_finsetSum fun _ _ => ENNReal.summable] + rw [← Summable.tsum_finsetSum fun _ _ => CompleteLattice.summable] refine tsum_congr fun f => ?_ rw [Finset.mul_sum] exact Finset.sum_congr rfl fun c _ => by rw [mul_left_comm] diff --git a/Complexity/Computability/Complexity/FineGrained/PPSZ/Basic.lean b/Complexity/Computability/Complexity/FineGrained/PPSZ/Basic.lean index e47a1f654..a73035873 100644 --- a/Complexity/Computability/Complexity/FineGrained/PPSZ/Basic.lean +++ b/Complexity/Computability/Complexity/FineGrained/PPSZ/Basic.lean @@ -276,7 +276,7 @@ theorem ppz_round_apply_le {φ : CNF (Fin n)} {w : ℕ} (hw : 1 ≤ w) {σ : Fin (hσ : φ.eval σ = true) : PPZ.round φ (fun x => some (σ x)) ≤ round φ w (fun x => some (σ x)) := by rw [PPZ.round, round, PPZ.roundWith, PPZ.roundWith, PMF.bind_apply, PMF.bind_apply] - refine ENNReal.tsum_le_tsum fun π => mul_le_mul_right ?_ _ + refine tsum_le_tsum fun π => mul_le_mul_right ?_ _ rw [← PPZ.restrict_prefixSet_self σ π] rw [PPZ.runWith_apply_restrict (O := PPZ.forced φ) (fun _ hτ _ _ h => PPZ.forced_eq hσ hτ h) π le_rfl, PPZ.runWith_apply_restrict (O := implied φ w) (fun _ hτ _ _ h => implied_eq hσ hτ h) π diff --git a/Complexity/Computability/Complexity/FineGrained/PPZ.lean b/Complexity/Computability/Complexity/FineGrained/PPZ.lean index 29084952a..a7c4fa2c3 100644 --- a/Complexity/Computability/Complexity/FineGrained/PPZ.lean +++ b/Complexity/Computability/Complexity/FineGrained/PPZ.lean @@ -458,7 +458,7 @@ theorem runWith_apply_restrict {O : (Fin n → Option Bool) → Fin n → Option by_cases hsupp : τ ∈ (runWith O π i).support · rw [PMF.map_apply] convert mul_zero _ - refine ENNReal.tsum_eq_zero.mpr fun b => ite_eq_right fun e => hτ ?_ + refine tsum_eq_zero_iff.mpr fun b => ite_eq_right fun e => hτ ?_ funext y by_cases hy : y = x · subst hy diff --git a/Complexity/Computability/Interactive/Plain.lean b/Complexity/Computability/Interactive/Plain.lean index 23a157b84..822083780 100644 --- a/Complexity/Computability/Interactive/Plain.lean +++ b/Complexity/Computability/Interactive/Plain.lean @@ -201,9 +201,9 @@ private theorem rbrFrom_le : ∀ (s : Spec) (smp : PerChallenge ProbComp s) st' calc ∑' c, ProbComp.eval smp.1 c * _ ≤ ∑' c, ProbComp.eval smp.1 c * (A.indicator 1 c + PerChallenge.sum s ε.2) := - ENNReal.tsum_le_tsum fun c => by gcongr; exact hinner c + tsum_le_tsum fun c => by gcongr; exact hinner c _ = (ProbComp.eval smp.1).toOuterMeasure A + PerChallenge.sum s ε.2 := by - simp only [mul_add, ENNReal.tsum_add, ENNReal.tsum_mul_right, PMF.tsum_coe, one_mul, + simp only [mul_add, tsum_add, ENNReal.tsum_mul_right, PMF.tsum_coe, one_mul, PMF.toOuterMeasure_apply] congr 1 refine tsum_congr fun c => ?_ diff --git a/Complexity/Computability/Kolmogorov/AverageCase.lean b/Complexity/Computability/Kolmogorov/AverageCase.lean index 0ead74cf0..86083ba86 100644 --- a/Complexity/Computability/Kolmogorov/AverageCase.lean +++ b/Complexity/Computability/Kolmogorov/AverageCase.lean @@ -277,7 +277,7 @@ private theorem pmf_map_true_le_one_sub_of_imp_false {α : Type*} (q : PMF α) ( ((q.map P) true).toReal ≤ 1 - ((q.map Q) true).toReal := by have hle : (q.map P) true ≤ (q.map Q) false := by rw [PMF.map_apply, PMF.map_apply] - refine ENNReal.tsum_le_tsum fun v => ?_ + refine tsum_le_tsum fun v => ?_ by_cases hp : P v = true · have hq : Q v = false := hdisj v hp simp [hp, hq] @@ -292,7 +292,7 @@ private theorem pmf_map_true_le_of_imp_true {α : Type*} (q : PMF α) (P Q : α ((q.map P) true).toReal ≤ ((q.map Q) true).toReal := by apply ENNReal.toReal_mono (PMF.apply_ne_top _ _) rw [PMF.map_apply, PMF.map_apply] - refine ENNReal.tsum_le_tsum fun v => ?_ + refine tsum_le_tsum fun v => ?_ by_cases hp : P v = true · have hq : Q v = true := himp v hp simp [hp, hq] diff --git a/Complexity/Computability/PCP/TwoProverGame.lean b/Complexity/Computability/PCP/TwoProverGame.lean index d918d1eba..e742d8fc8 100644 --- a/Complexity/Computability/PCP/TwoProverGame.lean +++ b/Complexity/Computability/PCP/TwoProverGame.lean @@ -117,7 +117,7 @@ theorem winProb_shared_le_value [Nonempty A] [Nonempty B] {R : Type*} (ρ : PMF exact ENNReal.ofReal_le_ofReal (G.winProb_le_value (fun x => ha x r) (fun y => hb y r)) calc ∑' r, ρ r * (G.questions.map fun q => (q, ha q.1 r, hb q.2 r)).toOuterMeasure {z | G.accepts z.1.1 z.1.2 z.2.1 z.2.2} - ≤ ∑' r, ρ r * ENNReal.ofReal G.value := ENNReal.tsum_le_tsum fun r => by gcongr; exact hr r + ≤ ∑' r, ρ r * ENNReal.ofReal G.value := tsum_le_tsum fun r => by gcongr; exact hr r _ = ENNReal.ofReal G.value := by rw [ENNReal.tsum_mul_right, ρ.tsum_coe, one_mul] end Finite diff --git a/Complexity/Computability/WordRAM/Randomized/Expected.lean b/Complexity/Computability/WordRAM/Randomized/Expected.lean index 7d9e1844a..4f1881163 100644 --- a/Complexity/Computability/WordRAM/Randomized/Expected.lean +++ b/Complexity/Computability/WordRAM/Randomized/Expected.lean @@ -117,7 +117,7 @@ theorem evalRand_haltedSet_mono (w : ℕ) (p : Program B r) (s : State r) : rw [evalRand, runRand_add w p T 1, ProbComp.eval_bind] simp only [evalRand, runRand_succ, runRand_zero, bind_pure] rw [hstep, PMF.toOuterMeasure_bind_apply, PMF.toOuterMeasure_apply] - refine ENNReal.tsum_le_tsum fun cfg => ?_ + refine tsum_le_tsum fun cfg => ?_ by_cases hcfg : cfg ∈ RandCfg.haltedSet r · have hmem := hcfg obtain ⟨v, d, rfl⟩ := hcfg @@ -139,7 +139,7 @@ theorem RandHaltsWithin.almostSurelyHalts {w T : ℕ} {p : Program B r} {s : Sta exact hnot (h cfg hmem) have hsum : (evalRand w p T s).toOuterMeasure (RandCfg.haltedSet r) + (evalRand w p T s).toOuterMeasure (RandCfg.haltedSet r)ᶜ = 1 := by - rw [PMF.toOuterMeasure_apply, PMF.toOuterMeasure_apply, ← ENNReal.tsum_add] + rw [PMF.toOuterMeasure_apply, PMF.toOuterMeasure_apply, ← tsum_add] convert (evalRand w p T s).tsum_coe using 1 congr 1 funext cfg @@ -172,7 +172,7 @@ theorem expectedStepsFrom_faulted (w : ℕ) (p : Program B r) : private theorem tsum_nat_eq_zero_add (g : ℕ → ℝ≥0∞) : ∑' t : ℕ, g t = g 0 + ∑' t : ℕ, g (t + 1) := by - rw [ENNReal.tsum_eq_add_tsum_ite (f := g) 0] + rw [tsum_eq_add_tsum_ite (f := g) 0] congr 1 have hsh := Function.Injective.tsum_eq Nat.succ_injective (f := fun t => if t = 0 then 0 else g t) fun t ht => by @@ -199,7 +199,7 @@ theorem expectedStepsFrom_running (w : ℕ) (p : Program B r) (s : State r) : intro t rw [runRand_succ, ProbComp.eval_bind, PMF.toOuterMeasure_bind_apply] simp only [hsucc] - rw [ENNReal.tsum_comm] + rw [tsum_comm] simp only [ProbComp.expect, expectedStepsFrom, ENNReal.tsum_mul_left] /-- Under `RandFaultFree`, every horizon partitions probability `1` between `.running` and @@ -208,7 +208,7 @@ theorem RandFaultFree.running_add_halted_eq_one {w : ℕ} {p : Program B r} {s : (hf : RandFaultFree w p s) (t : ℕ) : (evalRand w p t s).toOuterMeasure {cfg | ∃ u, cfg = .running u} + (evalRand w p t s).toOuterMeasure (RandCfg.haltedSet r) = 1 := by - rw [PMF.toOuterMeasure_apply, PMF.toOuterMeasure_apply, ← ENNReal.tsum_add] + rw [PMF.toOuterMeasure_apply, PMF.toOuterMeasure_apply, ← tsum_add] convert (evalRand w p t s).tsum_coe using 1 congr 1 funext cfg @@ -242,7 +242,7 @@ theorem AlmostSurelyHalts.of_expectedTime_ne_top {w : ℕ} {p : Program B r} {s have hinf : (⊤ : ℝ≥0∞) ≤ expectedTime w p s := by calc (⊤ : ℝ≥0∞) = ∑' _ : ℕ, (1 - supH) := (ENNReal.tsum_const_eq_top_of_ne_zero hpos.ne').symm - _ ≤ expectedTime w p s := ENNReal.tsum_le_tsum hle_run + _ ≤ expectedTime w p s := tsum_le_tsum hle_run exact htop (top_unique hinf) /-- Under `RandHaltsWithin w p s T`, the active-configuration tail sum vanishes from `T` onward and diff --git a/Complexity/Crypto/Computational/CramerShoup/ProjectiveHash.lean b/Complexity/Crypto/Computational/CramerShoup/ProjectiveHash.lean index 09e298a66..c52fe95e6 100644 --- a/Complexity/Crypto/Computational/CramerShoup/ProjectiveHash.lean +++ b/Complexity/Crypto/Computational/CramerShoup/ProjectiveHash.lean @@ -555,8 +555,8 @@ theorem uniform_projHash2_fiber_any_le (d : F.Desc) [DecidableEq (F.Carrier d)] have hor : (μ.map (fun τ₂ => (q :: qs).any (fun q' => hit q' τ₂))) true ≤ (μ.map (hit q)) true + (μ.map (fun τ₂ => qs.any (fun q' => hit q' τ₂))) true := by - simp only [List.any_cons, PMF.map_apply, ← ENNReal.tsum_add] - refine ENNReal.tsum_le_tsum fun τ₂ => ?_ + simp only [List.any_cons, PMF.map_apply, ← tsum_add] + refine tsum_le_tsum fun τ₂ => ?_ cases hit q τ₂ <;> cases qs.any (fun q' => hit q' τ₂) <;> simp have hsingle : (μ.map (hit q)) true = (F.order d : ℝ≥0∞)⁻¹ := by have heq : diff --git a/Complexity/Crypto/Computational/CramerShoup/Scheme.lean b/Complexity/Crypto/Computational/CramerShoup/Scheme.lean index 58a4a0937..0e6744c8c 100644 --- a/Complexity/Crypto/Computational/CramerShoup/Scheme.lean +++ b/Complexity/Crypto/Computational/CramerShoup/Scheme.lean @@ -1008,7 +1008,7 @@ private theorem tsum_and_isCramerShoupBadDH_le rw [hpre, Bool.true_and, ← hvElem, ← hwElem, encodeProjHash2_encode, he_equiv τ] rw [hbad_eq] cases cond <;> cases F.encode d (e_equiv τ • F.generator d) == parts.2.2.2 <;> simp - exact (ENNReal.tsum_le_tsum fun τ => + exact (tsum_le_tsum fun τ => mul_le_mul_of_nonneg_left (hle τ) zero_le).trans (F.tsum_uniform_smul_generator_eq e_equiv parts.2.2.2) · simp only [Bool.not_eq_true] at hpre diff --git a/Complexity/Crypto/Computational/DiffieHellman.lean b/Complexity/Crypto/Computational/DiffieHellman.lean index 00a002fc8..2f8a35c45 100644 --- a/Complexity/Crypto/Computational/DiffieHellman.lean +++ b/Complexity/Crypto/Computational/DiffieHellman.lean @@ -173,14 +173,14 @@ theorem succProbability_discreteLogGame_le_cdhGame (setup : ℕ → PMF F.Desc) simp only [discreteLogGame, cdhGame, dlToCDHAdversary, ProbComp.eval_bind, ProbComp.eval_pure, PMF.monad_bind_eq_bind, PMF.monad_pure_eq_pure, PMF.bind_bind, PMF.pure_bind] rw [PMF.bind_apply, PMF.bind_apply] - refine ENNReal.tsum_le_tsum fun d => mul_le_mul_of_nonneg_left ?_ zero_le + refine tsum_le_tsum fun d => mul_le_mul_of_nonneg_left ?_ zero_le rw [PMF.bind_apply, PMF.bind_apply] - refine ENNReal.tsum_le_tsum fun α => mul_le_mul_of_nonneg_left ?_ zero_le + refine tsum_le_tsum fun α => mul_le_mul_of_nonneg_left ?_ zero_le rw [← PMF.bind_const (PMF.uniformOfFintype (ZMod (F.order d))) ((ProbComp.eval (adversary n (d, F.encode d (α • F.generator d)))).bind _)] rw [PMF.bind_apply, PMF.bind_apply] - refine ENNReal.tsum_le_tsum fun β => mul_le_mul_of_nonneg_left ?_ zero_le - refine ENNReal.tsum_le_tsum fun guess => mul_le_mul_of_nonneg_left ?_ zero_le + refine tsum_le_tsum fun β => mul_le_mul_of_nonneg_left ?_ zero_le + refine tsum_le_tsum fun guess => mul_le_mul_of_nonneg_left ?_ zero_le by_cases hα : (ofBits guess : ZMod (F.order d)) = α · simp only [hα, F.smul_encode, smul_smul, decide_true, le_rfl] · simp only [hα, decide_false, PMF.pure_apply, Bool.true_eq_false, ↓reduceIte, zero_le] @@ -301,7 +301,7 @@ theorem ddhIdealGame_cdhToDDHDistinguisher_true_le (setup : ℕ → PMF F.Desc) fun guess => PMF.pure (decide (guess = F.encode d (γ • F.generator d)))) true ≤ ∑' d, setup n d * (m : ℝ≥0∞)⁻¹ := by - refine ENNReal.tsum_le_tsum fun d => ?_ + refine tsum_le_tsum fun d => ?_ by_cases hd : d ∈ (setup n).support · refine mul_le_mul_of_nonneg_left ?_ zero_le have hord : (F.order d : ℝ≥0∞)⁻¹ ≤ (m : ℝ≥0∞)⁻¹ := @@ -315,8 +315,8 @@ theorem ddhIdealGame_cdhToDDHDistinguisher_true_le (setup : ℕ → PMF F.Desc) PMF.pure (decide (guess = F.encode d (γ • F.generator d)))) true ≤ ∑' α, PMF.uniformOfFintype (ZMod (F.order d)) α * ∑' β, PMF.uniformOfFintype (ZMod (F.order d)) β * (m : ℝ≥0∞)⁻¹ := by - refine ENNReal.tsum_le_tsum fun α => mul_le_mul_of_nonneg_left ?_ zero_le - refine ENNReal.tsum_le_tsum fun β => mul_le_mul_of_nonneg_left ?_ zero_le + refine tsum_le_tsum fun α => mul_le_mul_of_nonneg_left ?_ zero_le + refine tsum_le_tsum fun β => mul_le_mul_of_nonneg_left ?_ zero_le rw [PMF.bind_comm, PMF.bind_apply] calc ∑' guess, ProbComp.eval (adversary n (d, F.encode d (α • F.generator d), F.encode d (β • F.generator d))) guess * @@ -325,7 +325,7 @@ theorem ddhIdealGame_cdhToDDHDistinguisher_true_le (setup : ℕ → PMF F.Desc) ≤ ∑' guess, ProbComp.eval (adversary n (d, F.encode d (α • F.generator d), F.encode d (β • F.generator d))) guess * (m : ℝ≥0∞)⁻¹ := by - refine ENNReal.tsum_le_tsum fun guess => + refine tsum_le_tsum fun guess => mul_le_mul_of_nonneg_left ((F.uniform_decide_eq_encode_le d guess).trans hord) zero_le _ = (m : ℝ≥0∞)⁻¹ := by rw [ENNReal.tsum_mul_right, PMF.tsum_coe, one_mul] diff --git a/Complexity/Crypto/Computational/DiffieHellman/Order.lean b/Complexity/Crypto/Computational/DiffieHellman/Order.lean index b0a3dbafa..478cd484b 100644 --- a/Complexity/Crypto/Computational/DiffieHellman/Order.lean +++ b/Complexity/Crypto/Computational/DiffieHellman/Order.lean @@ -138,7 +138,7 @@ private theorem expected_inv_order_le_two_mul_advantage_ddh (F : PrimeOrderGroup (((F.order d - 1 : ℕ) : ℝ≥0∞) * ((F.order d : ℝ≥0∞)⁻¹ * (F.order d : ℝ≥0∞)⁻¹))) := by dsimp only [ddhRealGame, ddhZeroDistinguisher] simp only [ProbComp.eval_pure, PMF.monad_bind_eq_bind, PMF.bind_apply] - rw [← ENNReal.tsum_add] + rw [← tsum_add] refine tsum_congr fun d => ?_ have hstep : (∑' α, PMF.uniformOfFintype (ZMod (F.order d)) α * @@ -164,7 +164,7 @@ private theorem expected_inv_order_le_two_mul_advantage_ddh (F : PrimeOrderGroup 2 * ∑' d, setup n d * (((F.order d - 1 : ℕ) : ℝ≥0∞) * ((F.order d : ℝ≥0∞)⁻¹ * (F.order d : ℝ≥0∞)⁻¹)) := by rw [← ENNReal.tsum_mul_left] - refine ENNReal.tsum_le_tsum fun d => ?_ + refine tsum_le_tsum fun d => ?_ rw [← mul_assoc, mul_comm (2 : ℝ≥0∞) (setup n d), mul_assoc] refine mul_le_mul_of_nonneg_left ?_ zero_le have hq2 : 2 ≤ F.order d := (F.prime_order d).two_le diff --git a/Complexity/Crypto/Computational/Encryption/Authenticated.lean b/Complexity/Crypto/Computational/Encryption/Authenticated.lean index a177011ae..951e29dce 100644 --- a/Complexity/Crypto/Computational/Encryption/Authenticated.lean +++ b/Complexity/Crypto/Computational/Encryption/Authenticated.lean @@ -1662,7 +1662,7 @@ private theorem ennreal_tsum_finsetSum {α β : Type*} induction s using Finset.induction_on with | empty => simp | insert b s hb ih => - simp only [Finset.sum_insert hb, ENNReal.tsum_add, ih] + simp only [Finset.sum_insert hb, tsum_add, ih] private theorem eval_ccaRejectWithBadOracle_false (E : SymmetricCipher) (n : ℕ) (k : List Bool) (bit : Bool) (request : Bool × List Bool) (queried : List (List Bool)) : @@ -1761,7 +1761,7 @@ private theorem bad_ccaRejectWithBad_le_sum_ciCombined {α : Type} (E : Symmetri (fun x => PMF.pure (!x.2.2.contains x.2.1.2.2 && (E.decrypt n k x.2.1.2.2).isSome)) true := - ENNReal.tsum_le_tsum fun a => mul_le_mul_of_nonneg_left (ih a queried) zero_le + tsum_le_tsum fun a => mul_le_mul_of_nonneg_left (ih a queried) zero_le _ = _ := by simp only [Finset.mul_sum] rw [ennreal_tsum_finsetSum] @@ -1818,7 +1818,7 @@ private theorem bad_ccaRejectWithBad_le_sum_ciCombined {α : Type} (E : Symmetri PMF.pure (!x.2.2.contains x.2.1.2.2 && (E.decrypt n k x.2.1.2.2).isSome)) true := - ENNReal.tsum_le_tsum fun ct => + tsum_le_tsum fun ct => mul_le_mul_of_nonneg_left (ih ct (ct :: queried)) zero_le _ = _ := by simp only [Finset.mul_sum] @@ -1993,8 +1993,8 @@ private theorem advantage_ccaGame_ccaRejectGame_le_sum (E : SymmetricCipher) (ct ProbOracleComp.eval_run_interpret, hrejEq] exact PMF.bind_apply _ _ _ have hle1 : pCCA ≤ pRej + pSum := by - rw [hCCA_eq, hRej_eq, hsum_eq, ← ENNReal.tsum_add] - refine ENNReal.tsum_le_tsum fun k => ?_ + rw [hCCA_eq, hRej_eq, hsum_eq, ← tsum_add] + refine tsum_le_tsum fun k => ?_ rw [← mul_add] by_cases hk : k ∈ (ProbComp.eval (E.keyGen n)).support · refine mul_le_mul_of_nonneg_left ?_ zero_le @@ -2007,8 +2007,8 @@ private theorem advantage_ccaGame_ccaRejectGame_le_sum (E : SymmetricCipher) (ct rw [eval_ciGame_ccaToCIAtIndexAdversary_key E ctBound j bit adversary n k hk hctBound] · rw [(PMF.apply_eq_zero_iff _ _).mpr hk, zero_mul, zero_mul] have hle2 : pRej ≤ pCCA + pSum := by - rw [hCCA_eq, hRej_eq, hsum_eq, ← ENNReal.tsum_add] - refine ENNReal.tsum_le_tsum fun k => ?_ + rw [hCCA_eq, hRej_eq, hsum_eq, ← tsum_add] + refine tsum_le_tsum fun k => ?_ rw [← mul_add] by_cases hk : k ∈ (ProbComp.eval (E.keyGen n)).support · refine mul_le_mul_of_nonneg_left ?_ zero_le diff --git a/Complexity/Crypto/Computational/Encryption/EncryptThenMAC.lean b/Complexity/Crypto/Computational/Encryption/EncryptThenMAC.lean index d8d240fb8..e33925650 100644 --- a/Complexity/Crypto/Computational/Encryption/EncryptThenMAC.lean +++ b/Complexity/Crypto/Computational/Encryption/EncryptThenMAC.lean @@ -1629,7 +1629,7 @@ private theorem step_bad_prfCipherForgetfulWithBadOracle_le (n : ℕ) (bit : Boo {x | x.2.2 = true} ≤ ∑' r, (BitString.uniformList n) r * {r : List Bool | (cache.lookup r).isSome}.indicator 1 r := by - refine ENNReal.tsum_le_tsum fun r => mul_le_mul_of_nonneg_left ?_ zero_le + refine tsum_le_tsum fun r => mul_le_mul_of_nonneg_left ?_ zero_le by_cases hr : (cache.lookup r).isSome = true · rw [Set.indicator_of_mem (show r ∈ {r : List Bool | (cache.lookup r).isSome} from hr), Pi.one_apply] @@ -1697,7 +1697,7 @@ private theorem bad_prfCipherForgetfulWithBadOracle_le {α : Type} (n : ℕ) (bi (cont y.1)).run y.2).toOuterMeasure {x | x.2.2 = true} ≤ ∑' y, ProbOracleComp.handler (fun m => StateT.lift (ProbComp.unifOracle m)) (prfCipherForgetfulWithBadOracle n bit) (Sum.inl m) (cache, false) y * B := by - refine ENNReal.tsum_le_tsum fun y => ?_ + refine tsum_le_tsum fun y => ?_ by_cases hy : y ∈ (ProbOracleComp.handler (fun m => StateT.lift (ProbComp.unifOracle m)) (prfCipherForgetfulWithBadOracle n bit) (Sum.inl m) (cache, false)).support @@ -1749,10 +1749,10 @@ private theorem bad_prfCipherForgetfulWithBadOracle_le {α : Type} (n : ℕ) (bi ≤ ∑' y, prfCipherForgetfulWithBadOracle n bit request (cache, false) y * ({x : List Bool × (List (List Bool × List Bool) × Bool) | x.2.2 = true}.indicator 1 y + K) := - ENNReal.tsum_le_tsum hterm + tsum_le_tsum hterm _ = (prfCipherForgetfulWithBadOracle n bit request (cache, false)).toOuterMeasure {x | x.2.2 = true} + K := by - simp only [mul_add, ENNReal.tsum_add, ENNReal.tsum_mul_right, PMF.tsum_coe, + simp only [mul_add, tsum_add, ENNReal.tsum_mul_right, PMF.tsum_coe, one_mul, PMF.toOuterMeasure_apply] congr 1 refine tsum_congr fun y => ?_ diff --git a/Complexity/Crypto/Computational/GMW/Soundness.lean b/Complexity/Crypto/Computational/GMW/Soundness.lean index 7841dd8ec..99dcd2c2f 100644 --- a/Complexity/Crypto/Computational/GMW/Soundness.lean +++ b/Complexity/Crypto/Computational/GMW/Soundness.lean @@ -562,7 +562,7 @@ theorem acceptProb_gmwVerifier_le {α : Type} {generator : List Bool → List Bo P.init x * ProbOracleComp.acceptProbWith P.respond (step2 r x.1) x.2 ≤ ∑' x, ProbOracleComp.runWith P.respond (List.take (K * m) <$> ProbOracleComp.query ((), r)) P.init x * (1 / 8) := - ENNReal.tsum_le_tsum fun x => mul_le_mul_right (hstep2_le r x.1 x.2 hbind) _ + tsum_le_tsum fun x => mul_le_mul_right (hstep2_le r x.1 x.2 hbind) _ _ = (∑' x, ProbOracleComp.runWith P.respond (List.take (K * m) <$> ProbOracleComp.query ((), r)) P.init x) * (1 / 8) := ENNReal.tsum_mul_right @@ -591,9 +591,9 @@ theorem acceptProb_gmwVerifier_le {α : Type} {generator : List Bool → List Bo calc ∑' r, BitString.uniformList m r * acceptProb (step1 r) P ≤ ∑' r, (({r | ¬ NaorBinding generator s r}.indicator (BitString.uniformList m) r) + - BitString.uniformList m r * (1 / 8)) := ENNReal.tsum_le_tsum hterm_le + BitString.uniformList m r * (1 / 8)) := tsum_le_tsum hterm_le _ = (∑' r, {r | ¬ NaorBinding generator s r}.indicator (BitString.uniformList m) r) + - ∑' r, BitString.uniformList m r * (1 / 8) := ENNReal.tsum_add + ∑' r, BitString.uniformList m r * (1 / 8) := tsum_add _ = naorBindingProb generator length s + 1 / 8 := by rw [← PMF.toOuterMeasure_apply, ENNReal.tsum_mul_right, PMF.tsum_coe, one_mul] rfl diff --git a/Complexity/Crypto/Computational/MAC.lean b/Complexity/Crypto/Computational/MAC.lean index 5b35fad27..5d8f4e36f 100644 --- a/Complexity/Crypto/Computational/MAC.lean +++ b/Complexity/Crypto/Computational/MAC.lean @@ -797,7 +797,7 @@ private theorem pmf_bind_pure_bool_le {α : Type} (p : PMF α) (f g : α → Boo (p.bind (fun a => PMF.pure (f a))) true ≤ (p.bind (fun a => PMF.pure (g a))) true := by rw [PMF.bind_apply, PMF.bind_apply] - refine ENNReal.tsum_le_tsum fun a => ?_ + refine tsum_le_tsum fun a => ?_ by_cases ha : a ∈ p.support · refine mul_le_mul_of_nonneg_left ?_ zero_le cases hf : f a @@ -816,7 +816,7 @@ theorem succProbability_eufCmaGame_le_sufCmaGame (M : MACScheme) simp only [Game.succProbability, sufCmaGame, ProbComp.eval_bind, ProbComp.eval_pure] refine ENNReal.toNNReal_mono (PMF.apply_ne_top _ true) ?_ rw [PMF.bind_apply, PMF.bind_apply] - refine ENNReal.tsum_le_tsum fun sk => ?_ + refine tsum_le_tsum fun sk => ?_ refine mul_le_mul_of_nonneg_left (pmf_bind_pure_bool_le _ _ _ fun out _ hout => ?_) zero_le simp only [Bool.and_eq_true, Bool.not_eq_true'] at hout ⊢ refine ⟨⟨hout.1.1, ?_⟩, hout.2⟩ @@ -1450,7 +1450,7 @@ theorem succProbability_prfIdealGame_macToPrfDistinguisher_le (adversary : Forge zero_le] have htotal : (phase1.bind phase2) true ≤ (1 : ℝ≥0∞) / 2 ^ n := by rw [PMF.bind_apply] - refine (ENNReal.tsum_le_tsum fun a => ?_).trans + refine (tsum_le_tsum fun a => ?_).trans (PMF.tsum_mul_le_of_forall_le phase1 fun _ => le_rfl) by_cases ha : a ∈ phase1.support · exact mul_le_mul_right (hstep_bound a ha) _ @@ -2012,7 +2012,7 @@ theorem succProbability_eufCmaGame_le_sufCmaGame (M : NonceMACScheme) simp only [Game.succProbability, eufCmaGame, sufCmaGame, ProbComp.eval_bind, ProbComp.eval_pure] refine ENNReal.toNNReal_mono (PMF.apply_ne_top _ true) ?_ rw [PMF.bind_apply, PMF.bind_apply] - refine ENNReal.tsum_le_tsum fun sk => ?_ + refine tsum_le_tsum fun sk => ?_ refine mul_le_mul_of_nonneg_left (MACScheme.pmf_bind_pure_bool_le _ _ _ fun out _ hout => ?_) zero_le simp only [Bool.and_eq_true, Bool.not_eq_true'] at hout ⊢ diff --git a/Complexity/Crypto/Computational/NaorReingold/Security.lean b/Complexity/Crypto/Computational/NaorReingold/Security.lean index ad05595ed..bcc1e4022 100644 --- a/Complexity/Crypto/Computational/NaorReingold/Security.lean +++ b/Complexity/Crypto/Computational/NaorReingold/Security.lean @@ -2995,7 +2995,7 @@ theorem DDH.negligible_naorReingoldHashedGame_const {F : PrimeOrderGroupFamily} refine ne_of_lt (lt_of_le_of_lt ?_ ENNReal.one_lt_top) calc (∑' d, setup n d * (F.order d : ℝ≥0∞)⁻¹) ≤ ∑' d, setup n d * 1 := by - refine ENNReal.tsum_le_tsum fun d => mul_le_mul_of_nonneg_left ?_ (by positivity) + refine tsum_le_tsum fun d => mul_le_mul_of_nonneg_left ?_ (by positivity) exact ENNReal.inv_le_one.mpr (by exact_mod_cast (F.prime_order d).pos) _ = 1 := by simp [(setup n).tsum_coe] have hε_pos : 0 < ε n := by @@ -3007,7 +3007,7 @@ theorem DDH.negligible_naorReingoldHashedGame_const {F : PrimeOrderGroupFamily} ENNReal.mul_pos hd₀_ne hord_ne exact ENNReal.toNNReal_pos (ne_of_gt (lt_of_lt_of_le hterm_pos - (ENNReal.le_tsum (f := fun d => setup n d * (F.order d : ℝ≥0∞)⁻¹) d₀))) + (le_tsum (f := fun d => setup n d * (F.order d : ℝ≥0∞)⁻¹) d₀))) hexp_top let τ : ℝ≥0 := NNReal.sqrt (ε n) have hτ_pos : 0 < τ := NNReal.sqrt_pos.mpr hε_pos @@ -3079,7 +3079,7 @@ theorem DDH.negligible_naorReingoldHashedGame_const {F : PrimeOrderGroupFamily} have hsum_err : (∑' d, setup n d * errTerm d) = ((lhlBound n : ℝ≥0) : ℝ≥0∞) := by dsimp only [errTerm, lhlBound] - simp_rw [mul_add, ENNReal.tsum_add, ← mul_assoc] + simp_rw [mul_add, tsum_add, ← mul_assoc] rw [ENNReal.tsum_mul_right, ENNReal.tsum_mul_right, (setup n).tsum_coe, one_mul, ENNReal.coe_add] congr 1 @@ -3095,8 +3095,8 @@ theorem DDH.negligible_naorReingoldHashedGame_const {F : PrimeOrderGroupFamily} (hfg : ∀ d ∈ (setup n).support, f d true ≤ g d true + ((Game.advantage (g1 d) (g2 d) : ℝ≥0) : ℝ≥0∞)) : ((setup n).bind f) true ≤ ((setup n).bind g) true + ((lhlBound n : ℝ≥0) : ℝ≥0∞) := by - rw [← hsum_err, PMF.bind_apply, PMF.bind_apply, ← ENNReal.tsum_add] - refine ENNReal.tsum_le_tsum fun d => ?_ + rw [← hsum_err, PMF.bind_apply, PMF.bind_apply, ← tsum_add] + refine tsum_le_tsum fun d => ?_ by_cases hd : d ∈ (setup n).support · rw [← mul_add] exact mul_le_mul_of_nonneg_left ((hfg d hd).trans (add_le_add le_rfl (hpoint d hd))) diff --git a/Complexity/Crypto/Computational/OneWay/LiuPassConverse.lean b/Complexity/Crypto/Computational/OneWay/LiuPassConverse.lean index 3c997b6a5..2350d6382 100644 --- a/Complexity/Crypto/Computational/OneWay/LiuPassConverse.lean +++ b/Complexity/Crypto/Computational/OneWay/LiuPassConverse.lean @@ -610,7 +610,7 @@ private theorem heuristic_fail_mul_le_family_fail {t : ℕ → ℕ} (ht : ∀ n, rw [hfailA_eq] dsimp only [failH] rw [PMF.map_apply, PMF.map_apply] - refine ENNReal.tsum_le_tsum fun coins => ?_ + refine tsum_le_tsum fun coins => ?_ split_ifs with h1 h2 · rfl · exfalso diff --git a/Complexity/Crypto/Computational/OneWayToSignature.lean b/Complexity/Crypto/Computational/OneWayToSignature.lean index ce784ba7d..a3cc11acb 100644 --- a/Complexity/Crypto/Computational/OneWayToSignature.lean +++ b/Complexity/Crypto/Computational/OneWayToSignature.lean @@ -663,7 +663,7 @@ private theorem map_bool_apply_true {α : Type*} (p : PMF α) (P : α → Bool) private theorem ennreal_tsum_finsetSum {α ι : Type*} (s : Finset ι) (g : ι → α → ℝ≥0∞) : (∑' a, ∑ i ∈ s, g i a) = ∑ i ∈ s, ∑' a, g i a := - Summable.tsum_finsetSum fun _ _ => ENNReal.summable + Summable.tsum_finsetSum fun _ _ => CompleteLattice.summable /-- **Lamport's one-time signature theorem**: for any one-way function `f`, `lamportScheme f` is existentially unforgeable under one-time adaptive chosen-message attack (`OneTimeEUFCMA`). -/ @@ -817,7 +817,7 @@ theorem OneWay.oneTimeEUFCMA_lamport {f : List Bool → List Bool} (hf : OneWay ≤ ∑' out, ∑ j : Fin (dyadicSize (2 * n)), if j.val < 2 * n then runWith (pkOf w) (dummySkOf w j.val) out * (if invWin w j.val out then 1 else 0) - else 0 := ENNReal.tsum_le_tsum (hpointwise w hw) + else 0 := tsum_le_tsum (hpointwise w hw) _ = ∑ j : Fin (dyadicSize (2 * n)), ∑' out, if j.val < 2 * n then runWith (pkOf w) (dummySkOf w j.val) out * (if invWin w j.val out then 1 else 0) @@ -845,7 +845,7 @@ theorem OneWay.oneTimeEUFCMA_lamport {f : List Bool → List Bool} (hf : OneWay if j.val < 2 * n then ((runWith (pkOf w) (dummySkOf w j.val)).map (invWin w j.val)) true else 0 := by - refine ENNReal.tsum_le_tsum fun w => ?_ + refine tsum_le_tsum fun w => ?_ by_cases hw : w ∈ μ.support · exact mul_le_mul_right (hw_sum w hw) (μ w) · simp [(PMF.apply_eq_zero_iff μ w).mpr hw] diff --git a/Complexity/Crypto/Computational/PRGToOneWay.lean b/Complexity/Crypto/Computational/PRGToOneWay.lean index 1fb8c7c47..70e7f7aea 100644 --- a/Complexity/Crypto/Computational/PRGToOneWay.lean +++ b/Complexity/Crypto/Computational/PRGToOneWay.lean @@ -107,7 +107,7 @@ theorem succProbability_uniformList_test_le {generator : List Bool → List Bool split_ifs with hr · exact PMF.coe_le_one _ _ simp only [test, ProbComp.eval_bind, ProbComp.eval_pure, PMF.bind_apply, PMF.pure_apply] - refine le_of_eq (ENNReal.tsum_eq_zero.2 fun x => ?_) + refine le_of_eq (tsum_eq_zero_iff.2 fun x => ?_) have hne : generator x ≠ List.ofFn r := fun hx => hr <| mem_image.2 ⟨x, hP x (by rw [← hlen x, hx, List.length_ofFn]), hx⟩ simp [hne] diff --git a/Complexity/Crypto/Computational/PedersenCommitment.lean b/Complexity/Crypto/Computational/PedersenCommitment.lean index e77853f5a..09842b79b 100644 --- a/Complexity/Crypto/Computational/PedersenCommitment.lean +++ b/Complexity/Crypto/Computational/PedersenCommitment.lean @@ -405,11 +405,11 @@ theorem pedersenHidingGame_apply_true_le (setup : ℕ → PMF F.Desc) ≤ ∑' α, (PMF.uniformOfFintype (ZMod (F.order d)) α * F.pedersenScheme.hidingForKey ⟨d, α • F.generator d⟩ adversary b₂ n true + if α = 0 then (F.order d : ℝ≥0∞)⁻¹ else 0) := - ENNReal.tsum_le_tsum hα + tsum_le_tsum hα _ = (∑' α, PMF.uniformOfFintype (ZMod (F.order d)) α * F.pedersenScheme.hidingForKey ⟨d, α • F.generator d⟩ adversary b₂ n true) + (F.order d : ℝ≥0∞)⁻¹ := by - rw [ENNReal.tsum_add, tsum_ite_eq] + rw [tsum_add, tsum_ite_eq] _ ≤ (∑' α, PMF.uniformOfFintype (ZMod (F.order d)) α * F.pedersenScheme.hidingForKey ⟨d, α • F.generator d⟩ adversary b₂ n true) + (m : ℝ≥0∞)⁻¹ := add_le_add le_rfl hord @@ -423,7 +423,7 @@ theorem pedersenHidingGame_apply_true_le (setup : ℕ → PMF F.Desc) (((PMF.uniformOfFintype (ZMod (F.order d))).bind fun α => F.pedersenScheme.hidingForKey ⟨d, α • F.generator d⟩ adversary b₂ n) true + (m : ℝ≥0∞)⁻¹) := by - refine ENNReal.tsum_le_tsum fun d => ?_ + refine tsum_le_tsum fun d => ?_ by_cases hd : d ∈ (setup n).support · exact mul_le_mul_of_nonneg_left (hd_bound d hd) zero_le · have hd0 : setup n d = 0 := by rwa [PMF.mem_support_iff, not_not] at hd @@ -432,7 +432,7 @@ theorem pedersenHidingGame_apply_true_le (setup : ℕ → PMF F.Desc) ((PMF.uniformOfFintype (ZMod (F.order d))).bind fun α => F.pedersenScheme.hidingForKey ⟨d, α • F.generator d⟩ adversary b₂ n) true) + (m : ℝ≥0∞)⁻¹ := by - simp only [mul_add, ENNReal.tsum_add, ENNReal.tsum_mul_right, (setup n).tsum_coe, one_mul] + simp only [mul_add, tsum_add, ENNReal.tsum_mul_right, (setup n).tsum_coe, one_mul] /-- **Unconditional hiding bound for Pedersen commitments**: when every supported group at parameter `n` has order at least `m > 0`, any (even computationally unbounded) diff --git a/Complexity/Crypto/Computational/Pseudoentropy/MaskedExtraction.lean b/Complexity/Crypto/Computational/Pseudoentropy/MaskedExtraction.lean index 9a46827f4..ffd5f9b0b 100644 --- a/Complexity/Crypto/Computational/Pseudoentropy/MaskedExtraction.lean +++ b/Complexity/Crypto/Computational/Pseudoentropy/MaskedExtraction.lean @@ -109,7 +109,7 @@ theorem maskedSample_mass_ge {α β : Type} (source : ProbComp α) rw [← ENNReal.toReal_mul] apply ENNReal.toReal_mono (PMF.apply_ne_top _ _) rw [PMF.bind_apply] - exact ENNReal.le_tsum (f := fun x => ProbComp.eval source x * + exact le_tsum (f := fun x => ProbComp.eval source x * ((ProbComp.eval (maskBit (mask x) (truth x))).map (observe x, ·)) (observe value, bit)) value exact (mul_le_mul (hsource value hvalue) (hbitMass.trans hmap) diff --git a/Complexity/Crypto/Game.lean b/Complexity/Crypto/Game.lean index e289aabc6..4f37d2714 100644 --- a/Complexity/Crypto/Game.lean +++ b/Complexity/Crypto/Game.lean @@ -295,16 +295,16 @@ theorem advantage_bind_le {α : Type*} (d : PMF α) (game1 game2 : α → Game) rw [PMF.bind_apply, PMF.bind_apply] calc ∑' a, d a * game1 a true ≤ ∑' a, d a * (game2 a true + ENNReal.ofReal ε) := - ENNReal.tsum_le_tsum fun a => mul_le_mul_of_nonneg_left (h1 a) zero_le + tsum_le_tsum fun a => mul_le_mul_of_nonneg_left (h1 a) zero_le _ = (∑' a, d a * game2 a true) + ENNReal.ofReal ε := by - simp only [mul_add, ENNReal.tsum_add, ENNReal.tsum_mul_right, d.tsum_coe, one_mul] + simp only [mul_add, tsum_add, ENNReal.tsum_mul_right, d.tsum_coe, one_mul] have hsum2 : (d.bind game2) true ≤ (d.bind game1) true + ENNReal.ofReal ε := by rw [PMF.bind_apply, PMF.bind_apply] calc ∑' a, d a * game2 a true ≤ ∑' a, d a * (game1 a true + ENNReal.ofReal ε) := - ENNReal.tsum_le_tsum fun a => mul_le_mul_of_nonneg_left (h2 a) zero_le + tsum_le_tsum fun a => mul_le_mul_of_nonneg_left (h2 a) zero_le _ = (∑' a, d a * game1 a true) + ENNReal.ofReal ε := by - simp only [mul_add, ENNReal.tsum_add, ENNReal.tsum_mul_right, d.tsum_coe, one_mul] + simp only [mul_add, tsum_add, ENNReal.tsum_mul_right, d.tsum_coe, one_mul] have hadv := advantage_le_of_apply_le ENNReal.ofReal_ne_top hsum1 hsum2 rwa [ENNReal.toReal_ofReal hε0] at hadv @@ -324,8 +324,8 @@ theorem advantage_bind_uniformOfFintype_of_ne_le {α : Type*} [Fintype α] [None have hle₁ : ((PMF.uniformOfFintype α).bind g) true ≤ p true + (Fintype.card α : ℝ≥0∞)⁻¹ := by rw [← PMF.bind_const (PMF.uniformOfFintype α) p, ← hsingle, PMF.bind_apply, PMF.bind_apply, - PMF.bind_apply, ← ENNReal.tsum_add] - refine ENNReal.tsum_le_tsum fun a => ?_ + PMF.bind_apply, ← tsum_add] + refine tsum_le_tsum fun a => ?_ rw [← mul_add] refine mul_le_mul_of_nonneg_left ?_ zero_le by_cases ha : a = a₀ @@ -335,8 +335,8 @@ theorem advantage_bind_uniformOfFintype_of_ne_le {α : Type*} [Fintype α] [None have hle₂ : p true ≤ ((PMF.uniformOfFintype α).bind g) true + (Fintype.card α : ℝ≥0∞)⁻¹ := by nth_rw 1 [← PMF.bind_const (PMF.uniformOfFintype α) p] - rw [← hsingle, PMF.bind_apply, PMF.bind_apply, PMF.bind_apply, ← ENNReal.tsum_add] - refine ENNReal.tsum_le_tsum fun a => ?_ + rw [← hsingle, PMF.bind_apply, PMF.bind_apply, PMF.bind_apply, ← tsum_add] + refine tsum_le_tsum fun a => ?_ rw [← mul_add] refine mul_le_mul_of_nonneg_left ?_ zero_le by_cases ha : a = a₀ @@ -363,8 +363,8 @@ theorem bind_apply_le_add_bind_apply {β : Type*} (μ : PMF β) (μ.bind game2) b ≤ (μ.bind game1) b + (μ.bind err) b := by have h1 (f g : β → Game) (hle : ∀ x, f x b ≤ g x b + err x b) : (μ.bind f) b ≤ (μ.bind g) b + (μ.bind err) b := by - simp only [PMF.bind_apply, ← ENNReal.tsum_add, ← mul_add] - exact ENNReal.tsum_le_tsum fun x => mul_le_mul_of_nonneg_left (hle x) zero_le + simp only [PMF.bind_apply, ← tsum_add, ← mul_add] + exact tsum_le_tsum fun x => mul_le_mul_of_nonneg_left (hle x) zero_le exact ⟨h1 game1 game2 fun x => (h x).1, h1 game2 game1 fun x => (h x).2⟩ /-- Averaging pointwise acceptance-probability bounds `game1 x true ≤ game2 x true + err x true` diff --git a/Complexity/Crypto/Game/UntilBad.lean b/Complexity/Crypto/Game/UntilBad.lean index 52f3c2892..f80d1e46d 100644 --- a/Complexity/Crypto/Game/UntilBad.lean +++ b/Complexity/Crypto/Game/UntilBad.lean @@ -164,9 +164,9 @@ theorem runStatelessOracle_bind_le {T α : Type} (μ : PMF T) (∑' x, PMF.uniformOfFintype (Fin (m + 1)) x * g x) + (Q : ℝ≥0∞) * δ := by calc ∑' x, PMF.uniformOfFintype (Fin (m + 1)) x * f x ≤ ∑' x, PMF.uniformOfFintype (Fin (m + 1)) x * (g x + (Q : ℝ≥0∞) * δ) := - ENNReal.tsum_le_tsum fun x => mul_le_mul_of_nonneg_left (hle x) zero_le + tsum_le_tsum fun x => mul_le_mul_of_nonneg_left (hle x) zero_le _ = (∑' x, PMF.uniformOfFintype (Fin (m + 1)) x * g x) + (Q : ℝ≥0∞) * δ := by - simp only [mul_add, ENNReal.tsum_add, ENNReal.tsum_mul_right, PMF.tsum_coe, one_mul] + simp only [mul_add, tsum_add, ENNReal.tsum_mul_right, PMF.tsum_coe, one_mul] exact ⟨hsum _ _ (fun x => (ih x).1), hsum _ _ (fun x => (ih x).2)⟩ · simp only [Sum.elim_inr] have hinr₁ : @@ -184,13 +184,13 @@ theorem runStatelessOracle_bind_le {T α : Type} (μ : PMF T) simp only [PMF.bind_apply] calc ∑' τ, μ τ * f τ b ≤ ∑' τ, (μ τ * g τ b + μ τ * if isBad τ req.2 then 1 else 0) := by - refine ENNReal.tsum_le_tsum fun τ => ?_ + refine tsum_le_tsum fun τ => ?_ by_cases hb : isBad τ req.2 = true · simp only [hb, ↓reduceIte, mul_one] exact le_add_of_le_right (mul_le_of_le_one_right zero_le (PMF.coe_le_one _ _)) · simp only [Bool.not_eq_true] at hb rw [hfg τ hb]; simp [hb] - _ = (∑' τ, μ τ * g τ b) + ∑' τ, μ τ * if isBad τ req.2 then 1 else 0 := ENNReal.tsum_add + _ = (∑' τ, μ τ * g τ b) + ∑' τ, μ τ * if isBad τ req.2 then 1 else 0 := tsum_add _ ≤ (∑' τ, μ τ * g τ b) + δ := add_le_add le_rfl (hbad req.2) have hstep1 := hstep (fun τ => runStatelessOracle (o₁ τ) (k (o₁ τ req.2)) (next τ)) @@ -372,20 +372,20 @@ theorem runStatelessOracle_le_runFinderOracle {α : Type} ≤ ∑' x, PMF.uniformOfFintype (Fin (m + 1)) x * (runStatelessOracle o₂ (k x) next b + runFinderOracle o₂ isBad extract (k x) none isGood true) := - ENNReal.tsum_le_tsum fun x => mul_le_mul_of_nonneg_left (ih x).1 zero_le + tsum_le_tsum fun x => mul_le_mul_of_nonneg_left (ih x).1 zero_le _ = (∑' x, PMF.uniformOfFintype (Fin (m + 1)) x * runStatelessOracle o₂ (k x) next b) + ∑' x, PMF.uniformOfFintype (Fin (m + 1)) x * runFinderOracle o₂ isBad extract (k x) none isGood true := by - simp only [mul_add, ENNReal.tsum_add] + simp only [mul_add, tsum_add] · calc ∑' x, PMF.uniformOfFintype (Fin (m + 1)) x * runStatelessOracle o₂ (k x) next b ≤ ∑' x, PMF.uniformOfFintype (Fin (m + 1)) x * (runStatelessOracle o₁ (k x) next b + runFinderOracle o₂ isBad extract (k x) none isGood true) := - ENNReal.tsum_le_tsum fun x => mul_le_mul_of_nonneg_left (ih x).2 zero_le + tsum_le_tsum fun x => mul_le_mul_of_nonneg_left (ih x).2 zero_le _ = (∑' x, PMF.uniformOfFintype (Fin (m + 1)) x * runStatelessOracle o₁ (k x) next b) + ∑' x, PMF.uniformOfFintype (Fin (m + 1)) x * runFinderOracle o₂ isBad extract (k x) none isGood true := by - simp only [mul_add, ENNReal.tsum_add] + simp only [mul_add, tsum_add] · rw [runStatelessOracle_query_inr, runStatelessOracle_query_inr, runFinderOracle_query_inr] by_cases hb : isBad req.2 = true · simp only [hb, ↓reduceIte] diff --git a/Complexity/Crypto/Primitives/PRG/NextBit.lean b/Complexity/Crypto/Primitives/PRG/NextBit.lean index 886b68555..76fe10070 100644 --- a/Complexity/Crypto/Primitives/PRG/NextBit.lean +++ b/Complexity/Crypto/Primitives/PRG/NextBit.lean @@ -121,9 +121,9 @@ private theorem bind_apply_add_of_forall {α β : Type*} (μ : PMF α) {f g h : {c : ℝ≥0∞} (hfg : ∀ x, f x b + g x b = h x b + c) : μ.bind f b + μ.bind g b = μ.bind h b + c := by simp only [PMF.bind_apply] - rw [← ENNReal.tsum_add] + rw [← tsum_add] simp_rw [← mul_add, hfg, mul_add] - rw [ENNReal.tsum_add, ENNReal.tsum_mul_right, μ.tsum_coe, one_mul] + rw [tsum_add, ENNReal.tsum_mul_right, μ.tsum_coe, one_mul] /-- **The distinguisher/predictor lemma** [Boneh and Shoup, Lemma 3.5][BonehShoup2023]. Draw `x` from `μ`. The guess `guessOfDistinguisher (d x)` equals `target x` with probability `1 / 2`, plus diff --git a/Complexity/Crypto/Protocols/Cipher/EvenMansour.lean b/Complexity/Crypto/Protocols/Cipher/EvenMansour.lean index b88c043a5..ca41828a6 100644 --- a/Complexity/Crypto/Protocols/Cipher/EvenMansour.lean +++ b/Complexity/Crypto/Protocols/Cipher/EvenMansour.lean @@ -1955,7 +1955,7 @@ private theorem idealGame_apply_le_realGame_add_of_keyDist (keyDist : PMF (G × calc (∑' res : Bool × (Cache G × Cache G), M_ideal res * keyDist.toOuterMeasure {k | isBadEvenMansourKey res.2.1 res.2.2 k = true}) ≤ ∑' res : Bool × (Cache G × Cache G), M_ideal res * ε := by - refine ENNReal.tsum_le_tsum fun res => ?_ + refine tsum_le_tsum fun res => ?_ by_cases hmem : res ∈ M_ideal.support · refine mul_le_mul_of_nonneg_left (hbad_le res.2.1 res.2.2 ?_ ?_) zero_le · simpa using length_fst_idealLazyHandler_le hcall.1 hmem @@ -1968,14 +1968,14 @@ private theorem idealGame_apply_le_realGame_add_of_keyDist (keyDist : PMF (G × ≤ ∑' k : G × G, keyDist k * ((((OracleComp.interpret (realLazyHandler k) program).run []).map Prod.fst) b + M_ideal.toOuterMeasure {res | isBadEvenMansourKey res.2.1 res.2.2 k = true}) := - ENNReal.tsum_le_tsum fun k => mul_le_mul_of_nonneg_left (hpoint k) zero_le + tsum_le_tsum fun k => mul_le_mul_of_nonneg_left (hpoint k) zero_le _ = (∑' k : G × G, keyDist k * (((OracleComp.interpret (realLazyHandler k) program).run []).map Prod.fst) b) + (∑' k : G × G, keyDist k * M_ideal.toOuterMeasure {res | isBadEvenMansourKey res.2.1 res.2.2 k = true}) := by - simp_rw [mul_add, ENNReal.tsum_add] + simp_rw [mul_add, tsum_add] _ ≤ _ := add_le_add le_rfl hsum_bad private theorem advantage_le_of_forall_bool_le {g₁ g₂ : Game} {ε : ℝ≥0∞} (hε : ε ≠ ⊤) diff --git a/Complexity/Crypto/Protocols/Cipher/LubyRackoff.lean b/Complexity/Crypto/Protocols/Cipher/LubyRackoff.lean index ac6f10219..a46a9a06e 100644 --- a/Complexity/Crypto/Protocols/Cipher/LubyRackoff.lean +++ b/Complexity/Crypto/Protocols/Cipher/LubyRackoff.lean @@ -1013,7 +1013,7 @@ private theorem tsum_seed_toOuterMeasure_hasCollision_le {seed₁ : PMF K₁} {h ∑' x, idealRun x * ∑' k₁, ({k₁ : K₁ | hasUCollision (h₁ k₁) x.2 = true}.indicator seed₁ k₁) := by simp only [← ENNReal.tsum_mul_left] - rw [ENNReal.tsum_comm] + rw [tsum_comm] refine tsum_congr fun x => tsum_congr fun k₁ => ?_ by_cases hx : hasUCollision (h₁ k₁) x.2 = true · rw [Set.indicator_of_mem hx, Set.indicator_of_mem hx, mul_comm] @@ -1022,7 +1022,7 @@ private theorem tsum_seed_toOuterMeasure_hasCollision_le {seed₁ : PMF K₁} {h calc ∑' x, idealRun x * ∑' k₁, ({k₁ : K₁ | hasUCollision (h₁ k₁) x.2 = true}.indicator seed₁ k₁) ≤ ∑' x, idealRun x * (Q.choose 2 * ε) := by - refine ENNReal.tsum_le_tsum fun x => ?_ + refine tsum_le_tsum fun x => ?_ by_cases hmem : x ∈ idealRun.support · refine mul_le_mul_of_nonneg_left ?_ zero_le rw [← PMF.toOuterMeasure_apply] @@ -1045,10 +1045,10 @@ private theorem tsum_seed_toOuterMeasure_hasCollision_le {seed₁ : PMF K₁} {h ≤ ∑' k₁, seed₁ k₁ * (idealRun.toOuterMeasure {x | hasUCollision (h₁ k₁) x.2 = true} + idealRun.toOuterMeasure {x | hasVCollision x.2 = true}) := - ENNReal.tsum_le_tsum fun k₁ => mul_le_mul_of_nonneg_left (hsplit k₁) zero_le + tsum_le_tsum fun k₁ => mul_le_mul_of_nonneg_left (hsplit k₁) zero_le _ = (∑' k₁, seed₁ k₁ * idealRun.toOuterMeasure {x | hasUCollision (h₁ k₁) x.2 = true}) + (∑' k₁, seed₁ k₁ * idealRun.toOuterMeasure {x | hasVCollision x.2 = true}) := by - simp only [mul_add, ENNReal.tsum_add] + simp only [mul_add, tsum_add] _ ≤ Q.choose 2 * ε + Q.choose 2 * (Fintype.card G : ℝ≥0∞)⁻¹ := add_le_add hu hv /-- For every fixed `f₁`, the acceptance probability of `feistel3FixedGame f₁ program` and @@ -1092,13 +1092,13 @@ theorem feistel3HashIdealGame_apply_le {seed₁ : PMF K₁} {h₁ : K₁ → G ≤ ∑' k₁, seed₁ k₁ * (randomFunctionGame program b + ((OracleComp.interpret (memoize (fun _ : G × G => PMF.uniformOfFintype (G × G))) program).run []).toOuterMeasure {x | hasCollision (h₁ k₁) x.2 = true}) := - ENNReal.tsum_le_tsum fun k₁ => + tsum_le_tsum fun k₁ => mul_le_mul_of_nonneg_left (feistel3FixedGame_apply_le (h₁ k₁) program b) zero_le _ = randomFunctionGame program b + ∑' k₁, seed₁ k₁ * ((OracleComp.interpret (memoize (fun _ : G × G => PMF.uniformOfFintype (G × G))) program).run []).toOuterMeasure {x | hasCollision (h₁ k₁) x.2 = true} := by - simp only [mul_add, ENNReal.tsum_add, ENNReal.tsum_mul_right, seed₁.tsum_coe, one_mul] + simp only [mul_add, tsum_add, ENNReal.tsum_mul_right, seed₁.tsum_coe, one_mul] _ ≤ randomFunctionGame program b + (Q.choose 2 * ε + Q.choose 2 * (Fintype.card G : ℝ≥0∞)⁻¹) := add_le_add le_rfl (tsum_seed_toOuterMeasure_hasCollision_le hh₁ hQ) @@ -1120,14 +1120,14 @@ theorem randomFunctionGame_apply_le_feistel3HashIdealGame {seed₁ : PMF K₁} { ≤ ∑' k₁, seed₁ k₁ * (feistel3FixedGame (h₁ k₁) program b + ((OracleComp.interpret (memoize (fun _ : G × G => PMF.uniformOfFintype (G × G))) program).run []).toOuterMeasure {x | hasCollision (h₁ k₁) x.2 = true}) := - ENNReal.tsum_le_tsum fun k₁ => + tsum_le_tsum fun k₁ => mul_le_mul_of_nonneg_left (randomFunctionGame_apply_le_feistel3FixedGame (h₁ k₁) program b) zero_le _ = (∑' k₁, seed₁ k₁ * feistel3FixedGame (h₁ k₁) program b) + ∑' k₁, seed₁ k₁ * ((OracleComp.interpret (memoize (fun _ : G × G => PMF.uniformOfFintype (G × G))) program).run []).toOuterMeasure {x | hasCollision (h₁ k₁) x.2 = true} := by - simp only [mul_add, ENNReal.tsum_add] + simp only [mul_add, tsum_add] _ ≤ (∑' k₁, seed₁ k₁ * feistel3FixedGame (h₁ k₁) program b) + (Q.choose 2 * ε + Q.choose 2 * (Fintype.card G : ℝ≥0∞)⁻¹) := add_le_add le_rfl (tsum_seed_toOuterMeasure_hasCollision_le hh₁ hQ) @@ -1619,7 +1619,7 @@ theorem le_idealStrongGame_feistel3CCAAttack_false {l₀ l₁ l₂ r₀ : G} _ ≤ ∑' π : Equiv.Perm (G × G), PMF.uniformOfFintype (Equiv.Perm (G × G)) π * OracleComp.interpret (feistelStrongOracle π) (feistel3CCAAttack l₀ l₁ r₀) false := - ENNReal.le_tsum (f := fun π : Equiv.Perm (G × G) => + le_tsum (f := fun π : Equiv.Perm (G × G) => PMF.uniformOfFintype (Equiv.Perm (G × G)) π * OracleComp.interpret (feistelStrongOracle π) (feistel3CCAAttack l₀ l₁ r₀) false) π₀ @@ -1875,9 +1875,9 @@ theorem idealStrongGame_feistel3CCAAttack_true_le {l₀ l₁ : G} (r₀ : G) (h0 (fun x => decide (-vw₀.1 + x.1.2 = -vw₁.1 + r₀))) true ≤ ∑' vw₁, ((PMF.uniformOfFintype (G × G)) vw₁ * (Fintype.card G : ℝ≥0∞)⁻¹ + ({q₃} : Set (G × G)).indicator (PMF.uniformOfFintype (G × G)) vw₁) := - ENNReal.tsum_le_tsum hvw₁ + tsum_le_tsum hvw₁ _ = (Fintype.card G : ℝ≥0∞)⁻¹ + (Fintype.card (G × G) : ℝ≥0∞)⁻¹ := by - rw [ENNReal.tsum_add, ENNReal.tsum_mul_right, PMF.tsum_coe, one_mul, + rw [tsum_add, ENNReal.tsum_mul_right, PMF.tsum_coe, one_mul, ← PMF.toOuterMeasure_apply, PMF.toOuterMeasure_apply_singleton, PMF.uniformOfFintype_apply] calc ∑' vw₀, (PMF.uniformOfFintype (G × G)) vw₀ * @@ -1888,7 +1888,7 @@ theorem idealStrongGame_feistel3CCAAttack_true_le {l₀ l₁ : G} (r₀ : G) (h0 (fun x => decide (-vw₀.1 + x.1.2 = -vw₁.1 + r₀))) true ≤ ∑' vw₀, (PMF.uniformOfFintype (G × G)) vw₀ * ((Fintype.card G : ℝ≥0∞)⁻¹ + (Fintype.card (G × G) : ℝ≥0∞)⁻¹) := - ENNReal.tsum_le_tsum fun vw₀ => mul_le_mul_of_nonneg_left (hvw₀ vw₀) zero_le + tsum_le_tsum fun vw₀ => mul_le_mul_of_nonneg_left (hvw₀ vw₀) zero_le _ = (Fintype.card G : ℝ≥0∞)⁻¹ + (Fintype.card (G × G) : ℝ≥0∞)⁻¹ := by rw [ENNReal.tsum_mul_right, PMF.tsum_coe, one_mul] have hchoose : ((Nat.choose 3 2 : ℕ) : ℝ≥0∞) = 3 := rfl @@ -3043,7 +3043,7 @@ private theorem tsum_toOuterMeasure_of_pointwise_le {α β : Type} (μ : PMF α) (∑' a, μ a * ∑' y, {y | P a y}.indicator d y) = ∑' y, d y * ∑' a, {a | P a y}.indicator μ a := by simp only [← ENNReal.tsum_mul_left] - rw [ENNReal.tsum_comm] + rw [tsum_comm] refine tsum_congr fun y => tsum_congr fun a => ?_ by_cases h : P a y · rw [Set.indicator_of_mem h, Set.indicator_of_mem h, mul_comm] @@ -3051,7 +3051,7 @@ private theorem tsum_toOuterMeasure_of_pointwise_le {α β : Type} (μ : PMF α) rw [hcomm] calc ∑' y, d y * ∑' a, {a | P a y}.indicator μ a ≤ ∑' y, d y * M := - ENNReal.tsum_le_tsum fun y => mul_le_mul_of_nonneg_left (by + tsum_le_tsum fun y => mul_le_mul_of_nonneg_left (by rw [← PMF.toOuterMeasure_apply] exact hM y) zero_le _ = M := by rw [ENNReal.tsum_mul_right, d.tsum_coe, one_mul] @@ -3155,14 +3155,14 @@ private theorem tsum_uniform_toOuterMeasure_hasCollision4_le d.toOuterMeasure {x | IsGoodCache4 Q x.2 ∧ hasVCollision4 f₄ x.2 = true} + (Q.choose 2 : ℝ≥0∞) * (Fintype.card (G × G) : ℝ≥0∞)⁻¹) := - ENNReal.tsum_le_tsum fun f₄ => + tsum_le_tsum fun f₄ => mul_le_mul_of_nonneg_left (toOuterMeasure_hasCollision4_le f₁ f₄ hQ) zero_le _ = d.toOuterMeasure {x | IsGoodCache4 Q x.2 ∧ hasUCollision f₁ x.2 = true} + (∑' f₄, unif f₄ * d.toOuterMeasure {x | IsGoodCache4 Q x.2 ∧ hasVCollision4 f₄ x.2 = true}) + (Q.choose 2 : ℝ≥0∞) * (Fintype.card (G × G) : ℝ≥0∞)⁻¹ := by - simp only [mul_add, ENNReal.tsum_add, ENNReal.tsum_mul_right, unif.tsum_coe, one_mul] + simp only [mul_add, tsum_add, ENNReal.tsum_mul_right, unif.tsum_coe, one_mul] _ ≤ _ := add_le_add (add_le_add le_rfl (tsum_uniform_toOuterMeasure_hasVCollision4_le d Q)) le_rfl calc ∑' f₁, unif f₁ * ∑' f₄, unif f₄ * d.toOuterMeasure {x | hasCollision4 f₁ f₄ x.2 = true} @@ -3171,12 +3171,12 @@ private theorem tsum_uniform_toOuterMeasure_hasCollision4_le {x | IsGoodCache4 Q x.2 ∧ hasUCollision f₁ x.2 = true} + Q.choose 2 * (Fintype.card G : ℝ≥0∞)⁻¹ + (Q.choose 2 : ℝ≥0∞) * (Fintype.card (G × G) : ℝ≥0∞)⁻¹) := - ENNReal.tsum_le_tsum fun f₁ => mul_le_mul_of_nonneg_left (hinner f₁) zero_le + tsum_le_tsum fun f₁ => mul_le_mul_of_nonneg_left (hinner f₁) zero_le _ = (∑' f₁, unif f₁ * d.toOuterMeasure {x | IsGoodCache4 Q x.2 ∧ hasUCollision f₁ x.2 = true}) + Q.choose 2 * (Fintype.card G : ℝ≥0∞)⁻¹ + (Q.choose 2 : ℝ≥0∞) * (Fintype.card (G × G) : ℝ≥0∞)⁻¹ := by - simp only [mul_add, ENNReal.tsum_add, ENNReal.tsum_mul_right, unif.tsum_coe, one_mul] + simp only [mul_add, tsum_add, ENNReal.tsum_mul_right, unif.tsum_coe, one_mul] _ ≤ Q.choose 2 * (Fintype.card G : ℝ≥0∞)⁻¹ + Q.choose 2 * (Fintype.card G : ℝ≥0∞)⁻¹ + (Q.choose 2 : ℝ≥0∞) * (Fintype.card (G × G) : ℝ≥0∞)⁻¹ := @@ -3253,13 +3253,13 @@ theorem feistel4StrongRandomRoundsGame_apply_le (forgetVal + ((OracleComp.interpret RandomPermutation.forgetfulAnswer prog).run []).toOuterMeasure {x | hasCollision4 f₁ f₄ x.2 = true}) := - ENNReal.tsum_le_tsum fun f₁ => mul_le_mul_of_nonneg_left - (ENNReal.tsum_le_tsum fun f₄ => mul_le_mul_of_nonneg_left + tsum_le_tsum fun f₁ => mul_le_mul_of_nonneg_left + (tsum_le_tsum fun f₄ => mul_le_mul_of_nonneg_left (feistel4StrongFixedGame_apply_le f₁ f₄ program b) zero_le) zero_le _ = forgetVal + ∑' f₁, unif f₁ * ∑' f₄, unif f₄ * ((OracleComp.interpret RandomPermutation.forgetfulAnswer prog).run []).toOuterMeasure {x | hasCollision4 f₁ f₄ x.2 = true} := by - simp only [mul_add, ENNReal.tsum_add, ENNReal.tsum_mul_right, unif.tsum_coe, one_mul] + simp only [mul_add, tsum_add, ENNReal.tsum_mul_right, unif.tsum_coe, one_mul] _ ≤ _ := add_le_add le_rfl (tsum_uniform_toOuterMeasure_hasCollision4_le hQ') have hperm := RandomPermutation.forgetfulAnswer_bind_apply_le_uniformPerm hQ' PMF.pure b simp only [Probability.PMF.monad_bind_eq_bind, PMF.bind_pure] at hperm @@ -3303,14 +3303,14 @@ theorem idealStrongGame_apply_le_feistel4StrongRandomRoundsGame (feistel4StrongFixedGame f₁ f₄ program b + ((OracleComp.interpret RandomPermutation.forgetfulAnswer prog).run []).toOuterMeasure {x | hasCollision4 f₁ f₄ x.2 = true}) := - ENNReal.tsum_le_tsum fun f₁ => mul_le_mul_of_nonneg_left - (ENNReal.tsum_le_tsum fun f₄ => mul_le_mul_of_nonneg_left + tsum_le_tsum fun f₁ => mul_le_mul_of_nonneg_left + (tsum_le_tsum fun f₄ => mul_le_mul_of_nonneg_left (forgetfulAnswer_apply_le_feistel4StrongFixedGame f₁ f₄ program b) zero_le) zero_le _ = (∑' f₁, unif f₁ * ∑' f₄, unif f₄ * feistel4StrongFixedGame f₁ f₄ program b) + ∑' f₁, unif f₁ * ∑' f₄, unif f₄ * ((OracleComp.interpret RandomPermutation.forgetfulAnswer prog).run []).toOuterMeasure {x | hasCollision4 f₁ f₄ x.2 = true} := by - simp only [mul_add, ENNReal.tsum_add] + simp only [mul_add, tsum_add] _ ≤ _ := add_le_add le_rfl (tsum_uniform_toOuterMeasure_hasCollision4_le hQ') have hperm := RandomPermutation.uniformPerm_bind_apply_le_forgetful hQ' PMF.pure b simp only [Probability.PMF.monad_bind_eq_bind, PMF.bind_pure] at hperm diff --git a/Complexity/Crypto/Protocols/MAC/CarterWegman.lean b/Complexity/Crypto/Protocols/MAC/CarterWegman.lean index dd32115b4..4b4f2bb30 100644 --- a/Complexity/Crypto/Protocols/MAC/CarterWegman.lean +++ b/Complexity/Crypto/Protocols/MAC/CarterWegman.lean @@ -3802,10 +3802,10 @@ theorem randomNonceSimHandler_not_nodup_le {α : Type} [Fintype N] [Nonempty N] PMF.pure (!decide (res.2.map (fun e => e.1.2)).Nodup)) true ≤ ∑' x, PMF.uniformOfFintype N x * ((PMF.pure (decide (x ∈ tr.map (fun e => e.1.2)))) true + B) := - ENNReal.tsum_le_tsum fun x => mul_le_mul_of_nonneg_left (hx_bound x) zero_le + tsum_le_tsum fun x => mul_le_mul_of_nonneg_left (hx_bound x) zero_le _ = ((PMF.uniformOfFintype N).bind fun x => PMF.pure (decide (x ∈ tr.map (fun e => e.1.2)))) true + B := by - simp only [mul_add, ENNReal.tsum_add, ENNReal.tsum_mul_right, + simp only [mul_add, tsum_add, ENNReal.tsum_mul_right, (PMF.uniformOfFintype N).tsum_coe, one_mul, PMF.bind_apply] _ ≤ (tr.length : ℝ≥0∞) / Fintype.card N + B := add_le_add hmem_le le_rfl _ = ((∑ i ∈ Finset.range (Q + 1), (tr.length + i) : ℕ) : ℝ≥0∞) / Fintype.card N := by @@ -4029,11 +4029,11 @@ theorem randomNonceStrongGame_le_sum_add_max {seed : PMF K} {hash : K → M → ≤ ∑' res, simPMF res * ((PMF.pure (!decide (res.2.map (fun e => e.1.2)).Nodup)) true + max ε (Fintype.card Y : ℝ≥0∞)⁻¹) := - ENNReal.tsum_le_tsum fun res => mul_le_mul_of_nonneg_left (hpoint res) zero_le + tsum_le_tsum fun res => mul_le_mul_of_nonneg_left (hpoint res) zero_le _ = (simPMF.bind fun res => PMF.pure (!decide (res.2.map (fun e => e.1.2)).Nodup)) true + max ε (Fintype.card Y : ℝ≥0∞)⁻¹ := by - simp only [mul_add, ENNReal.tsum_add, ENNReal.tsum_mul_right, simPMF.tsum_coe, one_mul, + simp only [mul_add, tsum_add, ENNReal.tsum_mul_right, simPMF.tsum_coe, one_mul, PMF.bind_apply] _ ≤ ((∑ i ∈ Finset.range Q, i : ℕ) : ℝ≥0∞) / Fintype.card N + max ε (Fintype.card Y : ℝ≥0∞)⁻¹ := by @@ -4485,10 +4485,10 @@ theorem probOracleComp_randomNonceSimHandler_not_nodup_le {α : Type} PMF.pure (!decide (res.2.map (fun e => e.1.2)).Nodup)) true ≤ ∑' x, PMF.uniformOfFintype N x * ((PMF.pure (decide (x ∈ tr.map (fun e => e.1.2)))) true + B) := - ENNReal.tsum_le_tsum fun x => mul_le_mul_of_nonneg_left (hx_bound x) zero_le + tsum_le_tsum fun x => mul_le_mul_of_nonneg_left (hx_bound x) zero_le _ = ((PMF.uniformOfFintype N).bind fun x => PMF.pure (decide (x ∈ tr.map (fun e => e.1.2)))) true + B := by - simp only [mul_add, ENNReal.tsum_add, ENNReal.tsum_mul_right, + simp only [mul_add, tsum_add, ENNReal.tsum_mul_right, (PMF.uniformOfFintype N).tsum_coe, one_mul, PMF.bind_apply] _ ≤ (tr.length : ℝ≥0∞) / Fintype.card N + B := add_le_add hmem_le le_rfl _ = ((∑ i ∈ Finset.range (Q + 1), (tr.length + i) : ℕ) : ℝ≥0∞) / Fintype.card N := by @@ -4610,11 +4610,11 @@ theorem seed_uniform_probOracleComp_checkRandomNonceSUF_le {α : Type} ≤ ∑' res, simPMF res * ((PMF.pure (!decide (res.2.map (fun e => e.1.2)).Nodup)) true + max ε (Fintype.card Y : ℝ≥0∞)⁻¹) := - ENNReal.tsum_le_tsum fun res => mul_le_mul_of_nonneg_left (hpoint res) zero_le + tsum_le_tsum fun res => mul_le_mul_of_nonneg_left (hpoint res) zero_le _ = (simPMF.bind fun res => PMF.pure (!decide (res.2.map (fun e => e.1.2)).Nodup)) true + max ε (Fintype.card Y : ℝ≥0∞)⁻¹ := by - simp only [mul_add, ENNReal.tsum_add, ENNReal.tsum_mul_right, simPMF.tsum_coe, one_mul, + simp only [mul_add, tsum_add, ENNReal.tsum_mul_right, simPMF.tsum_coe, one_mul, PMF.bind_apply] _ ≤ ((∑ i ∈ Finset.range Q, i : ℕ) : ℝ≥0∞) / Fintype.card N + max ε (Fintype.card Y : ℝ≥0∞)⁻¹ := by diff --git a/Complexity/Crypto/Protocols/SigmaProtocol/FiatShamir.lean b/Complexity/Crypto/Protocols/SigmaProtocol/FiatShamir.lean index 2075b932a..39a83a0cb 100644 --- a/Complexity/Crypto/Protocols/SigmaProtocol/FiatShamir.lean +++ b/Complexity/Crypto/Protocols/SigmaProtocol/FiatShamir.lean @@ -391,7 +391,7 @@ private theorem toOuterMeasure_flag_le (P : SigmaProtocol X Y T C Z) (key : X × {x | x.2.2 = true} ≤ ∑' ts, (P.commit key.1 key.2) ts * {ts : T × P.State | (st.1.1.lookup (m, ts.1)).isSome}.indicator 1 ts := by - refine ENNReal.tsum_le_tsum fun ts => mul_le_mul_of_nonneg_left ?_ zero_le + refine tsum_le_tsum fun ts => mul_le_mul_of_nonneg_left ?_ zero_le by_cases hts : (st.1.1.lookup (m, ts.1)).isSome · rw [Set.indicator_of_mem (show ts ∈ {ts : T × P.State | (st.1.1.lookup (m, ts.1)).isSome} from hts), Pi.one_apply] @@ -828,12 +828,12 @@ private theorem bind_apply_le_add {α β : Type} {μ : PMF α} {f g : α → PMF (μ.bind f) b ≤ (μ.bind g) b + K := by simp only [PMF.bind_apply] calc ∑' a, μ a * f a b ≤ ∑' a, μ a * (g a b + K) := by - refine ENNReal.tsum_le_tsum fun a => ?_ + refine tsum_le_tsum fun a => ?_ by_cases ha : a ∈ μ.support · exact mul_le_mul_of_nonneg_left (h a ha) zero_le · rw [(PMF.apply_eq_zero_iff _ _).mpr ha, zero_mul, zero_mul] _ = ∑' a, μ a * g a b + K := by - simp only [mul_add, ENNReal.tsum_add, ENNReal.tsum_mul_right, PMF.tsum_coe, one_mul] + simp only [mul_add, tsum_add, ENNReal.tsum_mul_right, PMF.tsum_coe, one_mul] omit [DecidableEq C] in /-- **The game hops** for one key and one choice of the forger's coins: the experiment wins at diff --git a/Complexity/Languages/Probabilistic/BoundedUniform.lean b/Complexity/Languages/Probabilistic/BoundedUniform.lean index 6fa41f00f..a4166310d 100644 --- a/Complexity/Languages/Probabilistic/BoundedUniform.lean +++ b/Complexity/Languages/Probabilistic/BoundedUniform.lean @@ -187,7 +187,7 @@ private theorem retry_some (bound value : ℕ) (next : PMF (Option ℕ)) : simp [hib, hiv] change (∑' i, μ i * (if i < bound then PMF.pure (some i) else next) (some value)) = _ simp_rw [hterm] - rw [ENNReal.tsum_add] + rw [tsum_add] simp only [tsum_ite_eq] rw [show μ bound = (intervalFailure bound : ℝ≥0∞) from eval_sampleBoundedIndex_sentinel bound] by_cases hv : value < bound @@ -342,7 +342,7 @@ private theorem uniformFin_nat_apply (bound value : ℕ) [NeZero bound] : · intro i hi have : value ≠ i.val := fun h => hi (Fin.ext h.symm) simp [this] - · rw [ENNReal.tsum_eq_zero.mpr] + · rw [tsum_eq_zero_iff.mpr] · simp [hv] · intro i have : value ≠ i.val := by omega @@ -364,7 +364,7 @@ theorem eval_sampleUniformInterval_some_eq (bound attempts value : ℕ) [NeZero private theorem tsum_option_eq {α : Type} (f : Option α → ℝ≥0∞) : ∑' x, f x = f none + ∑' x, f (some x) := by rw [← (Equiv.optionEquivSumPUnit.{0, 0} α).symm.tsum_eq f] - rw [ENNReal.summable.tsum_sum ENNReal.summable] + rw [CompleteLattice.summable.tsum_sum CompleteLattice.summable] simp [add_comm] private theorem optional_map_density {α β : Type} (μ : PMF (Option α)) (ν : PMF α) diff --git a/Complexity/Languages/Probabilistic/Expect.lean b/Complexity/Languages/Probabilistic/Expect.lean index 3785b103e..6b22d82f8 100644 --- a/Complexity/Languages/Probabilistic/Expect.lean +++ b/Complexity/Languages/Probabilistic/Expect.lean @@ -70,7 +70,7 @@ theorem expect_zero (m : ProbComp α) : expect m (fun _ => 0) = 0 := theorem expect_add (m : ProbComp α) (f g : α → ℝ≥0∞) : expect m (fun a => f a + g a) = expect m f + expect m g := by - simp only [expect, mul_add, ENNReal.tsum_add] + simp only [expect, mul_add, tsum_add] theorem expect_mul_left (m : ProbComp α) (c : ℝ≥0∞) (f : α → ℝ≥0∞) : expect m (fun a => c * f a) = c * expect m f := by @@ -86,7 +86,7 @@ theorem expect_mul_right (m : ProbComp α) (f : α → ℝ≥0∞) (c : ℝ≥0 theorem expect_bind (m : ProbComp α) (k : α → ProbComp β) (f : β → ℝ≥0∞) : expect (m >>= k) f = expect m (fun a => expect (k a) f) := by simp only [expect, eval_bind, PMF.bind_apply, ← ENNReal.tsum_mul_right] - rw [ENNReal.tsum_comm] + rw [tsum_comm] congr 1 funext a simp only [mul_assoc, ENNReal.tsum_mul_left] @@ -107,7 +107,7 @@ theorem expect_congr_on_support {m : ProbComp α} {f g : α → ℝ≥0∞} theorem expect_mono_on_support {m : ProbComp α} {f g : α → ℝ≥0∞} (h : ∀ a ∈ m.support, f a ≤ g a) : expect m f ≤ expect m g := by - refine ENNReal.tsum_le_tsum fun a => ?_ + refine tsum_le_tsum fun a => ?_ by_cases ha : a ∈ m.support · exact mul_le_mul_right (h a ha) _ · have hzero : (eval m) a = 0 := (PMF.apply_eq_zero_iff (eval m) a).mpr (by @@ -129,7 +129,7 @@ theorem expect_eq_top_of_mem_support {m : ProbComp α} {f : α → ℝ≥0∞} { refine top_unique ?_ calc (⊤ : ℝ≥0∞) = (eval m) a * f a := by rw [hf, ENNReal.mul_top hpos] - _ ≤ expect m f := ENNReal.le_tsum (f := fun b => (eval m) b * f b) a + _ ≤ expect m f := le_tsum (f := fun b => (eval m) b * f b) a theorem expect_unifFin (n : ℕ) (f : Fin (n + 1) → ℝ≥0∞) : expect (unifFin n) f = (∑ k : Fin (n + 1), f k) / (n + 1 : ℝ≥0∞) := by diff --git a/Complexity/Languages/Probabilistic/Oracle/Interaction.lean b/Complexity/Languages/Probabilistic/Oracle/Interaction.lean index 6aa1215f3..d822a739c 100644 --- a/Complexity/Languages/Probabilistic/Oracle/Interaction.lean +++ b/Complexity/Languages/Probabilistic/Oracle/Interaction.lean @@ -168,7 +168,7 @@ theorem acceptProbWith_bind_ite_le (program : ProbOracleComp spec Bool) acceptProbWith oracle program s := by conv_rhs => rw [← bind_pure program, acceptProbWith_bind] rw [acceptProbWith_bind] - refine ENNReal.tsum_le_tsum fun x => mul_le_mul_right ?_ _ + refine tsum_le_tsum fun x => mul_le_mul_right ?_ _ cases x.1 · simp only [Bool.false_eq_true, ↓reduceIte, le_refl] · simp only [↓reduceIte, acceptProbWith_pure] diff --git a/Complexity/Languages/Probabilistic/RandomPermutation.lean b/Complexity/Languages/Probabilistic/RandomPermutation.lean index f8b175e6d..153ac0a84 100644 --- a/Complexity/Languages/Probabilistic/RandomPermutation.lean +++ b/Complexity/Languages/Probabilistic/RandomPermutation.lean @@ -1175,9 +1175,9 @@ theorem toOuterMeasure_bad_choose_two_le {ι σ β : Type} {spec : ι → Type} calc ∑' y, (handler q s) y * ((OracleComp.interpret handler (cont y.1)).run y.2).toOuterMeasure {x | bad x.2} ≤ ∑' y, (handler q s) y * ({x : spec q × σ | bad x.2}.indicator 1 y + K) := - ENNReal.tsum_le_tsum hterm + tsum_le_tsum hterm _ = (handler q s).toOuterMeasure {x | bad x.2} + K := by - simp only [mul_add, ENNReal.tsum_add, ENNReal.tsum_mul_right, PMF.tsum_coe, one_mul, + simp only [mul_add, tsum_add, ENNReal.tsum_mul_right, PMF.tsum_coe, one_mul, PMF.toOuterMeasure_apply] congr 1 refine tsum_congr fun y => ?_ @@ -1413,8 +1413,8 @@ theorem toOuterMeasure_forgetfulAnswer_le_pairwise_and_length_le_add {β : Type} {x | (x.2.Pairwise (fun a b => a.1 ≠ b.1) ∧ x.2.Pairwise (fun a b => a.2 ≠ b.2) ∧ x.2.length ≤ Q) ∧ P x.2}) + q.toOuterMeasure {x | x.2.2 = true} - simp only [PMF.toOuterMeasure_apply, ← ENNReal.tsum_add] - refine ENNReal.tsum_le_tsum fun ⟨a, c, b⟩ => ?_ + simp only [PMF.toOuterMeasure_apply, ← tsum_add] + refine tsum_le_tsum fun ⟨a, c, b⟩ => ?_ by_cases hmem : (a, (c, b)) ∈ q.support · by_cases hP : P c · cases b with diff --git a/Complexity/Languages/Probabilistic/UntilBad.lean b/Complexity/Languages/Probabilistic/UntilBad.lean index 7bcd7e202..ac26422b6 100644 --- a/Complexity/Languages/Probabilistic/UntilBad.lean +++ b/Complexity/Languages/Probabilistic/UntilBad.lean @@ -129,8 +129,8 @@ theorem bind_apply_le (h : IdenticalUntilBad first second bad) (program : Oracle ((interpret first program).run s).toOuterMeasure {x | bad x.2} := by classical simp only [PMF.bind_apply, PMF.toOuterMeasure_apply] - rw [← ENNReal.tsum_add] - refine ENNReal.tsum_le_tsum fun x => ?_ + rw [← tsum_add] + refine tsum_le_tsum fun x => ?_ by_cases hx : bad x.2 · have hbad : x ∈ {x : α × σ | bad x.2} := hx rw [Set.indicator_of_mem hbad] @@ -153,7 +153,7 @@ private theorem toOuterMeasure_bad_add_good (p : PMF (α × σ)) : p.toOuterMeasure {x | bad x.2} + p.toOuterMeasure {x | ¬bad x.2} = 1 := by classical simp only [PMF.toOuterMeasure_apply] - rw [← ENNReal.tsum_add, ← p.tsum_coe] + rw [← tsum_add, ← p.tsum_coe] refine tsum_congr fun x => ?_ by_cases hx : bad x.2 · rw [Set.indicator_of_mem (show x ∈ {x : α × σ | bad x.2} from hx), @@ -244,9 +244,9 @@ theorem toOuterMeasure_bad_le {handler : (q : ι) → StateT σ PMF (spec q)} {b calc ∑' y, (handler q s) y * ((interpret handler (cont y.1)).run y.2).toOuterMeasure {x | bad x.2} ≤ ∑' y, (handler q s) y * ({x : spec q × σ | bad x.2}.indicator 1 y + K) := - ENNReal.tsum_le_tsum hterm + tsum_le_tsum hterm _ = (handler q s).toOuterMeasure {x | bad x.2} + K := by - simp only [mul_add, ENNReal.tsum_add, ENNReal.tsum_mul_right, PMF.tsum_coe, one_mul, + simp only [mul_add, tsum_add, ENNReal.tsum_mul_right, PMF.tsum_coe, one_mul, PMF.toOuterMeasure_apply] congr 1 refine tsum_congr fun y => ?_ diff --git a/Complexity/Languages/Probabilistic/Vector.lean b/Complexity/Languages/Probabilistic/Vector.lean index 5e43aaaa5..4f3e7ead7 100644 --- a/Complexity/Languages/Probabilistic/Vector.lean +++ b/Complexity/Languages/Probabilistic/Vector.lean @@ -274,7 +274,7 @@ theorem eval_pi {m : ℕ} {α : Fin m → Type} [∀ i, Finite (α i)] funext i simpa using (congrFun hEq (Fin.succ i)).symm · intro a ha - simp only [mul_eq_zero, ENNReal.tsum_eq_zero] + simp only [mul_eq_zero, tsum_eq_zero_iff] right intro b rw [ite_eq_right] diff --git a/Complexity/Probability/Conditioning.lean b/Complexity/Probability/Conditioning.lean index faca6d699..340e70ef4 100644 --- a/Complexity/Probability/Conditioning.lean +++ b/Complexity/Probability/Conditioning.lean @@ -48,7 +48,7 @@ variable {α β : Type*} theorem map_fst_apply (joint : PMF (α × β)) (a : α) : (joint.map Prod.fst) a = ∑' b, joint (a, b) := by classical - rw [PMF.map_apply, ENNReal.tsum_prod'] + rw [PMF.map_apply, tsum_prod'] rw [tsum_eq_single a] · simp · intro x hx @@ -72,9 +72,9 @@ theorem conditionalSnd_apply (joint : PMF (α × β)) (a : α) conditionalSnd joint a b = joint (a, b) / (joint.map Prod.fst) a := by classical have hpost : a ∈ (joint.bind (fun pair => PMF.pure pair.1)).support := ha - simp only [conditionalSnd, hpost, dite_true, PMF.map_apply, ENNReal.tsum_prod', + simp only [conditionalSnd, hpost, dite_true, PMF.map_apply, tsum_prod', posteriorDist_apply, bind_pair_apply, PMF.pure_apply] - simp [ENNReal.tsum_prod', div_eq_mul_inv] + simp [tsum_prod', div_eq_mul_inv] /-- Multiplying by the marginal recovers the joint mass, also at zero-probability observations. -/ theorem marginal_mul_conditionalSnd (joint : PMF (α × β)) (a : α) (b : β) : diff --git a/Complexity/Probability/CorrelatedSampling.lean b/Complexity/Probability/CorrelatedSampling.lean index 5e9f61775..ae9ebd647 100644 --- a/Complexity/Probability/CorrelatedSampling.lean +++ b/Complexity/Probability/CorrelatedSampling.lean @@ -171,7 +171,7 @@ theorem map_firstIn_weightedOrderAux (w : Ω → ℝ≥0) : rcases o with _ | c · rw [PMF.bind_apply, PMF.map_apply] simp only [reduceCtorEq, ite_false, tsum_zero] - refine ENNReal.tsum_eq_zero.mpr fun a => ?_ + refine tsum_eq_zero_iff.mpr fun a => ?_ split_ifs <;> simp [PMF.map_apply] rw [PMF.bind_apply, tsum_fintype, hrhs] set du := weightedDraw w U hU0 diff --git a/Complexity/Probability/Forking.lean b/Complexity/Probability/Forking.lean index 960ea5e2e..b13827992 100644 --- a/Complexity/Probability/Forking.lean +++ b/Complexity/Probability/Forking.lean @@ -215,7 +215,7 @@ private theorem bind_match_apply {X : Type} (μ : PMF X) (index : X → Option ( | some j => decide (event j x))) true = ∑ j, (μ.bind fun x => PMF.pure (decide (index x = some j ∧ event j x))) true := by simp only [PMF.bind_apply, PMF.pure_apply] - rw [← Summable.tsum_finsetSum fun _ _ => ENNReal.summable] + rw [← Summable.tsum_finsetSum fun _ _ => CompleteLattice.summable] refine tsum_congr fun x => ?_ rw [← Finset.mul_sum] congr 1 diff --git a/Complexity/Probability/IID.lean b/Complexity/Probability/IID.lean index 74388f5b5..0a600cf4a 100644 --- a/Complexity/Probability/IID.lean +++ b/Complexity/Probability/IID.lean @@ -73,7 +73,7 @@ noncomputable def iid (μ : PMF α) : (k : ℕ) → PMF (Fin k → α) intro h exact absurd (by rw [h, Fin.tail_cons]) hw · intro a ha - rw [PMF.map_apply, ENNReal.tsum_eq_zero.mpr, mul_zero] + rw [PMF.map_apply, tsum_eq_zero_iff.mpr, mul_zero] intro w simp only [ite_eq_right_iff] intro h diff --git a/Complexity/Probability/MinEntropy.lean b/Complexity/Probability/MinEntropy.lean index 15120ffd6..29fd28b12 100644 --- a/Complexity/Probability/MinEntropy.lean +++ b/Complexity/Probability/MinEntropy.lean @@ -183,7 +183,7 @@ theorem le_minEntropy_bind (μ : PMF β) (f : β → PMF α) {k : ℝ} apply ENNReal.toReal_le_of_le_ofReal hk calc μ.bind f a = ∑' b, μ b * f b a := PMF.bind_apply μ f a - _ ≤ ∑' b, μ b * ENNReal.ofReal (2 ^ (-k)) := ENNReal.tsum_le_tsum hcomponent + _ ≤ ∑' b, μ b * ENNReal.ofReal (2 ^ (-k)) := tsum_le_tsum hcomponent _ = ENNReal.ofReal (2 ^ (-k)) := by rw [ENNReal.tsum_mul_right, μ.tsum_coe, one_mul] /-! ### Weak random sources -/ diff --git a/Complexity/Probability/Minimax.lean b/Complexity/Probability/Minimax.lean index e34129b86..ba395a192 100644 --- a/Complexity/Probability/Minimax.lean +++ b/Complexity/Probability/Minimax.lean @@ -213,10 +213,10 @@ theorem exists_mem_support_tsum_mul_le (μ : PMF α) (ν : PMF β) (loss : α calc ∑' a, μ a * ∑' b, ν b * loss a b = ∑' b, ν b * ∑' a, μ a * loss a b := by simp only [← ENNReal.tsum_mul_left] - rw [ENNReal.tsum_comm] + rw [tsum_comm] exact tsum_congr fun b => tsum_congr fun a => by ring _ ≤ ∑' b, ν b * ε := by - refine ENNReal.tsum_le_tsum fun b => ?_ + refine tsum_le_tsum fun b => ?_ by_cases hb : b ∈ ν.support · gcongr exact h b hb diff --git a/Complexity/Probability/PMF/Bind.lean b/Complexity/Probability/PMF/Bind.lean index fcdd9502b..c3b9858bc 100644 --- a/Complexity/Probability/PMF/Bind.lean +++ b/Complexity/Probability/PMF/Bind.lean @@ -53,7 +53,7 @@ theorem bind_sigma_apply {β : α → Type*} (p : PMF α) (f : (a : α) → PMF (p.bind (fun a => (f a).map (Sigma.mk a))) ⟨a, b⟩ = p a * f a b := by classical simp only [PMF.bind_apply, PMF.map_apply, ← ENNReal.tsum_mul_left, mul_ite, mul_zero] - rw [← ENNReal.tsum_sigma] + rw [← tsum_sigma] simp /-- A continuation only needs to agree on outcomes the preceding distribution can produce. -/ @@ -76,7 +76,7 @@ theorem le_bind_apply_on_support (μ : PMF α) {f : α → PMF β} {b : β} {c : (h : ∀ a ∈ μ.support, c ≤ f a b) : c ≤ μ.bind f b := by rw [PMF.bind_apply] calc c = ∑' a, μ a * c := by rw [ENNReal.tsum_mul_right, μ.tsum_coe, one_mul] - _ ≤ ∑' a, μ a * f a b := ENNReal.tsum_le_tsum fun a => by + _ ≤ ∑' a, μ a * f a b := tsum_le_tsum fun a => by by_cases ha : a ∈ μ.support · exact mul_le_mul_right (h a ha) _ · simp [(PMF.apply_eq_zero_iff μ a).2 ha] @@ -87,7 +87,7 @@ theorem bind_apply_le_on_support (μ : PMF α) {f : α → PMF β} {b : β} {c : (h : ∀ a ∈ μ.support, f a b ≤ c) : μ.bind f b ≤ c := by rw [PMF.bind_apply] calc ∑' a, μ a * f a b - _ ≤ ∑' a, μ a * c := ENNReal.tsum_le_tsum fun a => by + _ ≤ ∑' a, μ a * c := tsum_le_tsum fun a => by by_cases ha : a ∈ μ.support · exact mul_le_mul_right (h a ha) _ · simp [(PMF.apply_eq_zero_iff μ a).2 ha] @@ -98,7 +98,7 @@ probability in the whole experiment. The sample spaces may be infinite. -/ theorem bind_apply_mono_on_support (μ : PMF α) {f g : α → PMF β} (b : β) (h : ∀ a ∈ μ.support, f a b ≤ g a b) : μ.bind f b ≤ μ.bind g b := by simp only [PMF.bind_apply] - apply ENNReal.tsum_le_tsum + apply tsum_le_tsum intro a by_cases ha : a ∈ μ.support · exact mul_le_mul_right (h a ha) _ @@ -117,7 +117,7 @@ theorem exists_bind_apply_le [Finite α] (μ : PMF α) (f : α → PMF β) (b : /-- An average of values at most `B` is at most `B`. -/ theorem tsum_mul_le_of_forall_le (μ : PMF α) {f : α → ℝ≥0∞} {B : ℝ≥0∞} (h : ∀ a, f a ≤ B) : ∑' a, μ a * f a ≤ B := - calc ∑' a, μ a * f a ≤ ∑' a, μ a * B := ENNReal.tsum_le_tsum fun a => mul_le_mul_right (h a) _ + calc ∑' a, μ a * f a ≤ ∑' a, μ a * B := tsum_le_tsum fun a => mul_le_mul_right (h a) _ _ = B := by rw [ENNReal.tsum_mul_right, μ.tsum_coe, one_mul] /-- Values at most `1` on a finite set `T` and at most `B` elsewhere average to at most @@ -126,9 +126,9 @@ theorem tsum_mul_le_card_mul_add [DecidableEq α] (μ : PMF α) {ε : ℝ≥0∞ (T : Finset α) {f : α → ℝ≥0∞} {B : ℝ≥0∞} (h : ∀ a, f a ≤ (if a ∈ T then 1 else 0) + B) : ∑' a, μ a * f a ≤ T.card * ε + B := by calc ∑' a, μ a * f a ≤ ∑' a, (μ a * (if a ∈ T then 1 else 0) + μ a * B) := - ENNReal.tsum_le_tsum fun a => (mul_le_mul_right (h a) _).trans_eq (mul_add _ _ _) + tsum_le_tsum fun a => (mul_le_mul_right (h a) _).trans_eq (mul_add _ _ _) _ = ∑ a ∈ T, μ a + B := by - rw [ENNReal.tsum_add, ENNReal.tsum_mul_right, μ.tsum_coe, one_mul, + rw [tsum_add, ENNReal.tsum_mul_right, μ.tsum_coe, one_mul, tsum_eq_sum (s := T) fun a ha => by simp only [ha, ↓reduceIte, mul_zero]] congr 1 exact Finset.sum_congr rfl fun a ha => by simp only [ha, ↓reduceIte, mul_one] diff --git a/Complexity/Probability/PMF/Event.lean b/Complexity/Probability/PMF/Event.lean index ce673d7ce..16a45d6e8 100644 --- a/Complexity/Probability/PMF/Event.lean +++ b/Complexity/Probability/PMF/Event.lean @@ -73,7 +73,7 @@ theorem toOuterMeasure_ne_top (p : PMF α) (event : Set α) : p.toOuterMeasure e /-- An event has probability at most one. -/ theorem toOuterMeasure_le_one (p : PMF α) (event : Set α) : p.toOuterMeasure event ≤ 1 := by rw [PMF.toOuterMeasure_apply, ← p.tsum_coe] - exact ENNReal.tsum_le_tsum (fun a => Set.indicator_apply_le (fun _ => le_rfl)) + exact tsum_le_tsum (fun a => Set.indicator_apply_le (fun _ => le_rfl)) /-- The event that `f a` deviates from `m` by at least `ε` is covered by the upper tail `m + ε ≤ f a` and the lower tail `f a ≤ m - ε`. -/ @@ -111,7 +111,7 @@ theorem toOuterMeasure_apply_toReal [Fintype α] (p : PMF α) (event : Set α) : theorem toOuterMeasure_toReal_add_compl (p : PMF α) (event : Set α) : (p.toOuterMeasure event).toReal + (p.toOuterMeasure eventᶜ).toReal = 1 := by have h : p.toOuterMeasure event + p.toOuterMeasure eventᶜ = 1 := by - rw [PMF.toOuterMeasure_apply, PMF.toOuterMeasure_apply, ← ENNReal.tsum_add] + rw [PMF.toOuterMeasure_apply, PMF.toOuterMeasure_apply, ← tsum_add] convert p.tsum_coe using 1 congr 1 funext a @@ -154,7 +154,7 @@ theorem toOuterMeasure_bind_failure_le (p : PMF α) (kernel : α → PMF β) rw [PMF.toOuterMeasure_bind_apply, PMF.toOuterMeasure_apply] calc _ ≤ ∑' a, ((preᶜ).indicator p a + p a * error) := by - apply ENNReal.tsum_le_tsum + apply tsum_le_tsum intro a by_cases ha : a ∈ pre · simp only [Set.indicator_of_notMem (show a ∉ preᶜ by simpa), zero_add] @@ -165,7 +165,7 @@ theorem toOuterMeasure_bind_failure_le (p : PMF α) (kernel : α → PMF β) · simp only [Set.indicator_of_mem (show a ∈ preᶜ from ha)] exact (mul_le_mul_of_nonneg_left (toOuterMeasure_le_one (kernel a) failure) zero_le).trans (by simp) - _ = _ := by rw [ENNReal.tsum_add, ENNReal.tsum_mul_right, p.tsum_coe, one_mul] + _ = _ := by rw [tsum_add, ENNReal.tsum_mul_right, p.tsum_coe, one_mul] /-- The real-valued error rule for a randomized continuation. -/ theorem toOuterMeasure_bind_failure_toReal_le (p : PMF α) (kernel : α → PMF β) @@ -193,7 +193,7 @@ theorem toOuterMeasure_bind_ge_mul (p : PMF α) (kernel : α → PMF β) classical have hle : p.toOuterMeasure pre * ENNReal.ofReal s₂ ≤ (p.bind kernel).toOuterMeasure event := by rw [PMF.toOuterMeasure_bind_apply, PMF.toOuterMeasure_apply, ← ENNReal.tsum_mul_right] - refine ENNReal.tsum_le_tsum fun a => ?_ + refine tsum_le_tsum fun a => ?_ by_cases ha : a ∈ pre · simp only [Set.indicator_of_mem ha] by_cases hs : a ∈ p.support @@ -242,7 +242,7 @@ theorem map_true_mono (p : PMF α) {E F : α → Bool} (h : ∀ a ∈ p.support, E a = true → F a = true) : (p.map E) true ≤ (p.map F) true := by rw [PMF.map_apply, PMF.map_apply] - refine ENNReal.tsum_le_tsum fun a => ?_ + refine tsum_le_tsum fun a => ?_ by_cases ha : a ∈ p.support · by_cases hE : true = E a · simp [← hE, h a ha hE.symm] @@ -253,8 +253,8 @@ theorem map_true_mono (p : PMF α) {E F : α → Bool} theorem map_true_le_add (p : PMF α) {E A B : α → Bool} (h : ∀ a ∈ p.support, E a = true → A a = true ∨ B a = true) : (p.map E) true ≤ (p.map A) true + (p.map B) true := by - rw [PMF.map_apply, PMF.map_apply, PMF.map_apply, ← ENNReal.tsum_add] - refine ENNReal.tsum_le_tsum fun a => ?_ + rw [PMF.map_apply, PMF.map_apply, PMF.map_apply, ← tsum_add] + refine tsum_le_tsum fun a => ?_ by_cases ha : a ∈ p.support · by_cases hE : true = E a · rcases h a ha hE.symm with hA | hB diff --git a/Complexity/Probability/PMF/Map.lean b/Complexity/Probability/PMF/Map.lean index eed796d9b..4aad0a45d 100644 --- a/Complexity/Probability/PMF/Map.lean +++ b/Complexity/Probability/PMF/Map.lean @@ -40,7 +40,7 @@ variable {α β : Type*} theorem le_map_apply (p : PMF α) (f : α → β) (a : α) : p a ≤ (p.map f) (f a) := by classical rw [PMF.map_apply] - simpa using ENNReal.le_tsum (f := fun x => if f a = f x then p x else 0) a + simpa using le_tsum (f := fun x => if f a = f x then p x else 0) a /-- Relabeling a distribution by an equivalence preserves each corresponding point mass. -/ theorem map_equiv_apply (p : PMF α) (e : α ≃ β) (b : β) : diff --git a/Complexity/Probability/ProductConditioning/SideInformation.lean b/Complexity/Probability/ProductConditioning/SideInformation.lean index 316b7c63c..11c12f8fe 100644 --- a/Complexity/Probability/ProductConditioning/SideInformation.lean +++ b/Complexity/Probability/ProductConditioning/SideInformation.lean @@ -186,7 +186,7 @@ theorem sideJoint_apply (μ : PMF T) (J : T → PMF ((∀ i, β i) × V)) (t : T exact hx (Prod.ext (congrArg Prod.snd h).symm (congrArg (·.2) (congrArg Prod.fst h)).symm) · intro t' ht' rw [PMF.map_apply] - refine mul_eq_zero_of_right _ (ENNReal.tsum_eq_zero.mpr fun x => ite_eq_right fun h => ?_) + refine mul_eq_zero_of_right _ (tsum_eq_zero_iff.mpr fun x => ite_eq_right fun h => ?_) exact absurd (congrArg (·.1) (congrArg Prod.fst h)) (Ne.symm ht') /-- The pairs `(u, v)` that complete `(t, v)` to an outcome in `W`. -/ diff --git a/Complexity/Probability/RejectionSampling.lean b/Complexity/Probability/RejectionSampling.lean index d317c0d2f..83b85bf82 100644 --- a/Complexity/Probability/RejectionSampling.lean +++ b/Complexity/Probability/RejectionSampling.lean @@ -144,7 +144,7 @@ theorem shiftReject_apply_some (hv : ∀ z ∈ S, z - v ∈ B) (z : α) : · intro y hy have hyz : y + v ≠ z := fun h => hy (eq_sub_of_add_eq h) split_ifs <;> simp_all [eq_comm] - · refine ENNReal.tsum_eq_zero.mpr fun y => ?_ + · refine tsum_eq_zero_iff.mpr fun y => ?_ split_ifs with h₁ h₂ <;> simp_all /-- **Rejection sampling, aborts.** Under the same hypothesis, the sampler aborts with @@ -156,7 +156,7 @@ theorem shiftReject_apply_none (hv : ∀ z ∈ S, z - v ∈ B) : rw [tsum_eq_sum (s := S) fun z hz => by simp [hz], Finset.sum_ite_mem, Finset.inter_self, Finset.sum_const, nsmul_eq_mul, div_eq_mul_inv] have htotal := (shiftReject B S hB v).tsum_coe - rw [ENNReal.tsum_eq_add_tsum_ite none, ← (Option.some_injective α).tsum_eq] at htotal + rw [tsum_eq_add_tsum_ite none, ← (Option.some_injective α).tsum_eq] at htotal · simp only [reduceCtorEq, ite_false, hsome] at htotal exact ENNReal.eq_sub_of_add_eq (ENNReal.div_ne_top (ENNReal.natCast_ne_top _) (by simpa using hB.ne_empty)) htotal From d7dcd7985e43c0678127230df389fa8ea3e3ea61 Mon Sep 17 00:00:00 2001 From: Samuel Giuseppe Schlesinger Date: Thu, 29 Oct 2026 15:21:52 -0400 Subject: [PATCH 03/25] fix(build): adapt proofs to the rc2 Mathlib API Qualify newly protected matrix and finite-sum lemmas, publicly import the relocated Matrix.Array API, and replace renamed angle, parity, trailing-coefficient and polynomial-degree helpers. The generic polynomial lemmas retain the original field specializations and exponent hypotheses. No theorem statement or definition body changes. Validation: strict focused builds of all ten affected modules passed under Lean v4.36.0-rc2. Source comparison against d6ccb24f shows all Lean edits are inside theorem proofs except the required Bird import. --- Complexity/Computability/Circuit/Bird.lean | 1 + Complexity/Computability/Circuit/Quantum/Basic.lean | 4 ++-- Complexity/Computability/Circuit/Rational/Wronskian.lean | 2 +- .../Foundations/BooleanAnalysis/LowDegree/Addition.lean | 2 +- .../Foundations/BooleanAnalysis/SparseEquations.lean | 2 +- .../FieldTheory/Finite/LinearizedPolynomial.lean | 6 +++--- Complexity/Foundations/LinearAlgebra/Matrix/ListProd.lean | 4 ++-- Complexity/Foundations/LinearAlgebra/Matrix/Rank.lean | 2 +- .../Foundations/LinearAlgebra/Matrix/SubmatrixRobust.lean | 8 ++++---- Complexity/Foundations/Probability/Gaussian/Sheppard.lean | 2 +- 10 files changed, 17 insertions(+), 16 deletions(-) diff --git a/Complexity/Computability/Circuit/Bird.lean b/Complexity/Computability/Circuit/Bird.lean index 62b11531b..a39c61ae9 100644 --- a/Complexity/Computability/Circuit/Bird.lean +++ b/Complexity/Computability/Circuit/Bird.lean @@ -8,6 +8,7 @@ module -- upstream: candidate public import Complexity.Init +public import Mathlib.LinearAlgebra.Matrix.Array public import Mathlib.LinearAlgebra.Matrix.Determinant.Bird.Defs public import Mathlib.LinearAlgebra.Matrix.Determinant.Basic import Mathlib.Algebra.Order.BigOperators.Group.LocallyFinite diff --git a/Complexity/Computability/Circuit/Quantum/Basic.lean b/Complexity/Computability/Circuit/Quantum/Basic.lean index 7797874a4..c9265f0f4 100644 --- a/Complexity/Computability/Circuit/Quantum/Basic.lean +++ b/Complexity/Computability/Circuit/Quantum/Basic.lean @@ -172,7 +172,7 @@ theorem place_apply (A : Fin k ↪ Fin n) (U : unitaryGroup (Fin k → Bool) ℂ (place A U : Matrix _ _ ℂ) y x = if ∀ j, (¬∃ i, A i = j) → y j = x j then (U : Matrix _ _ ℂ) (y ∘ A) (x ∘ A) else 0 := by simp only [place, MonoidHom.coe_mk, OneHom.coe_mk, submatrix_apply, kroneckerMap_apply, - splitEquiv_apply_fst, splitEquiv_apply_snd, one_apply, funext_iff, Subtype.forall] + splitEquiv_apply_fst, splitEquiv_apply_snd, Matrix.one_apply, funext_iff, Subtype.forall] split_ifs <;> simp namespace PlacedGate @@ -281,7 +281,7 @@ theorem hadamardMatrix_mem_unitaryGroup : hadamardMatrix ∈ unitaryGroup Bool rw [mem_unitaryGroup_iff] ext b c cases b <;> cases c <;> - simp [hadamardMatrix, mul_apply, star_eq_conjTranspose, Complex.conj_ofReal, h2, h1] + simp [hadamardMatrix, Matrix.mul_apply, star_eq_conjTranspose, Complex.conj_ofReal, h2, h1] theorem star_hadamardMatrix : star hadamardMatrix = hadamardMatrix := by ext b c diff --git a/Complexity/Computability/Circuit/Rational/Wronskian.lean b/Complexity/Computability/Circuit/Rational/Wronskian.lean index f2ce76817..138a37718 100644 --- a/Complexity/Computability/Circuit/Rational/Wronskian.lean +++ b/Complexity/Computability/Circuit/Rational/Wronskian.lean @@ -148,7 +148,7 @@ lemma wronskian_order_of_distinct_orders {K : Type*} [Field K] [CharZero K] Matrix.det_mul_row (fun j => (f j).trailingCoeff) (Matrix.of fun i j : Fin h => ((f j).natTrailingDegree.descFactorial i.val : K))] exact mul_ne_zero (Finset.prod_ne_zero_iff.mpr fun j _ => - trailingCoeff_nonzero_iff_nonzero.mpr (hf j)) (det_descFactorial_ne_zero _ hd) + trailingCoeff_ne_zero.mpr (hf j)) (det_descFactorial_ne_zero _ hd) have hB0 : B.det ≠ 0 := fun hz => by simp [hz] at hBc have hA0 : A.det ≠ 0 := hdet ▸ mul_ne_zero (pow_ne_zero _ X_ne_zero) hB0 have hscale : A.det = X ^ (∑ i : Fin h, i.val) * wronskianFamily f := by diff --git a/Complexity/Foundations/BooleanAnalysis/LowDegree/Addition.lean b/Complexity/Foundations/BooleanAnalysis/LowDegree/Addition.lean index 905b6c11a..271991b3b 100644 --- a/Complexity/Foundations/BooleanAnalysis/LowDegree/Addition.lean +++ b/Complexity/Foundations/BooleanAnalysis/LowDegree/Addition.lean @@ -82,7 +82,7 @@ theorem hasSliceDecomposition_add (p q : ℕ) : have hexpand : (fun x y : ι → Bool => monomial K S.1 (x + y)) = ∑ T ∈ S.1.powerset, (fun x y => monomial K T x * monomial K (S.1 \ T) y) := by funext x y - simp only [sum_apply, monomial_add] + simp only [Finset.sum_apply, monomial_add] rw [hexpand] apply (sliceSpace (lowDegree K ι p) (lowDegree K ι q)).sum_mem intro T hT diff --git a/Complexity/Foundations/BooleanAnalysis/SparseEquations.lean b/Complexity/Foundations/BooleanAnalysis/SparseEquations.lean index d9daca94e..d1bc719e3 100644 --- a/Complexity/Foundations/BooleanAnalysis/SparseEquations.lean +++ b/Complexity/Foundations/BooleanAnalysis/SparseEquations.lean @@ -143,7 +143,7 @@ is even. -/ theorem monomialSum_zmod_two_eq_zero_iff_even (𝓜 : Finset (Finset ι)) (x : ι → Bool) : monomialSum (ZMod 2) 𝓜 x = 0 ↔ Even (monomialSum ℤ 𝓜 x) := by rw [monomialSum_eq_card_filter (ZMod 2), monomialSum_eq_card_filter ℤ, - ZMod.natCast_eq_zero_iff_even, Int.even_coe_nat] + ZMod.natCast_eq_zero_iff_even, Int.even_natCast] /-- An assignment `x : ι → Bool` is a common zero of the family `{P i}_{i ∈ I}` over `𝔽₂` if every equation `P i` (`i ∈ I`) evaluates to `0` in `ZMod 2` at `x`. -/ diff --git a/Complexity/Foundations/FieldTheory/Finite/LinearizedPolynomial.lean b/Complexity/Foundations/FieldTheory/Finite/LinearizedPolynomial.lean index 09309146e..a27032be5 100644 --- a/Complexity/Foundations/FieldTheory/Finite/LinearizedPolynomial.lean +++ b/Complexity/Foundations/FieldTheory/Finite/LinearizedPolynomial.lean @@ -252,7 +252,7 @@ private theorem comp_eq_X_pow_card_sub_X [Fintype F] {P Q : F[X]} ⟨by rw [natDegree_comp, hdeg], hQm.comp hPm hPdeg⟩ have hX : IsMonicOfDegree (X ^ Fintype.card F - X : F[X]) (Fintype.card F) := by rw [isMonicOfDegree_iff] - refine ⟨(FiniteField.X_pow_card_sub_X_natDegree_eq F hq1).le, ?_⟩ + refine ⟨(natDegree_X_pow_sub_X (R := F) hq1).le, ?_⟩ have h1 : (1 : ℕ) ≠ Fintype.card F := hq1.ne simp [coeff_X, h1] rw [← sub_eq_zero] @@ -410,10 +410,10 @@ theorem exists_subfield_card_le [Finite F] {n k : ℕ} (hn : finrank (ZMod 2) F have h1 : 1 < 2 ^ k := Nat.one_lt_two_pow hk0.ne' have hcard : Fintype.card F = 2 ^ n := by rw [Module.card_eq_pow_finrank (K := ZMod 2) (V := F), ZMod.card, hn] - refine FiniteField.X_pow_card_sub_X_ne_zero F h1 + refine X_pow_sub_X_ne_zero (R := F) h1 (eq_zero_of_natDegree_lt_card_of_eval_eq_zero _ (f := id) Function.injective_id (fun x => by simp [hall x]) ?_) - rw [FiniteField.X_pow_card_sub_X_natDegree_eq F h1, hcard] + rw [natDegree_X_pow_sub_X (R := F) h1, hcard] exact Nat.pow_lt_pow_right (by norm_num) hkn · by_cases hW : ∃ y₀ ∈ W, y₀ ≠ 0 · obtain ⟨y₀, hy₀W, hy₀⟩ := hW diff --git a/Complexity/Foundations/LinearAlgebra/Matrix/ListProd.lean b/Complexity/Foundations/LinearAlgebra/Matrix/ListProd.lean index 11579b762..50ea8c7ef 100644 --- a/Complexity/Foundations/LinearAlgebra/Matrix/ListProd.lean +++ b/Complexity/Foundations/LinearAlgebra/Matrix/ListProd.lean @@ -38,7 +38,7 @@ theorem list_prod_ofFn_apply : ∀ {d : ℕ} (M : Fin d → Matrix ι ι R) (a b if p 0 = a ∧ p (Fin.last d) = b then ∏ i : Fin d, M i (p i.castSucc) (p i.succ) else 0 | 0, M, a, b => by rw [← (Equiv.funUnique (Fin 1) ι).symm.sum_comp] - simp only [List.ofFn_zero, List.prod_nil, one_apply, Finset.univ_eq_empty, + simp only [List.ofFn_zero, List.prod_nil, Matrix.one_apply, Finset.univ_eq_empty, Finset.prod_empty, Equiv.funUnique_symm_apply, Fin.last_zero, uniqueElim_const] by_cases hab : a = b · subst hab @@ -51,7 +51,7 @@ theorem list_prod_ofFn_apply : ∀ {d : ℕ} (M : Fin d → Matrix ι ι R) (a b have hL : (List.ofFn M).prod a b = ∑ q : Fin (d + 1) → ι, if q (Fin.last d) = b then M 0 a (q 0) * ∏ i : Fin d, M i.succ (q i.castSucc) (q i.succ) else 0 := by - rw [List.ofFn_succ, List.prod_cons, mul_apply] + rw [List.ofFn_succ, List.prod_cons, Matrix.mul_apply] simp only [list_prod_ofFn_apply (fun i => M i.succ), Finset.mul_sum, mul_ite, mul_zero] rw [Finset.sum_comm] refine Finset.sum_congr rfl fun q _ => ?_ diff --git a/Complexity/Foundations/LinearAlgebra/Matrix/Rank.lean b/Complexity/Foundations/LinearAlgebra/Matrix/Rank.lean index 04e6d3604..de84069b6 100644 --- a/Complexity/Foundations/LinearAlgebra/Matrix/Rank.lean +++ b/Complexity/Foundations/LinearAlgebra/Matrix/Rank.lean @@ -87,7 +87,7 @@ theorem exists_eq_mul_rank (A : Matrix m n K) : (b.sum_repr (col j)) simp only [Submodule.coe_sum, Submodule.coe_smul, Finset.sum_apply, Pi.smul_apply, smul_eq_mul] at h - simpa [mul_apply, col, mul_comm] using h.symm + simpa [Matrix.mul_apply, col, mul_comm] using h.symm /-- The natural rank of a finite matrix agrees with the cardinal rank of its linear map. -/ theorem natCast_rank_eq_rank_toLin' [DecidableEq n] (M : Matrix m n K) : diff --git a/Complexity/Foundations/LinearAlgebra/Matrix/SubmatrixRobust.lean b/Complexity/Foundations/LinearAlgebra/Matrix/SubmatrixRobust.lean index 16c25ab37..7d6f58267 100644 --- a/Complexity/Foundations/LinearAlgebra/Matrix/SubmatrixRobust.lean +++ b/Complexity/Foundations/LinearAlgebra/Matrix/SubmatrixRobust.lean @@ -340,17 +340,17 @@ theorem add_blockRank_le_cutRank_add_transpose [Finite ι] (hfg.symm.mono inter_subset_right inter_subset_right) (fun i hi j hj hj' => by have hjY : j ∉ Y := fun h => hj' ⟨hj, h⟩ - simp only [add_apply, transpose_apply, hMY i j hjY, hMY j i (hnotY i hi.2), add_zero]) + simp only [Matrix.add_apply, transpose_apply, hMY i j hjY, hMY j i (hnotY i hi.2), add_zero]) (fun i hi j hj hj' => by have hjX : j ∉ X := fun h => hj' ⟨hj, h⟩ - simp only [add_apply, transpose_apply, hMX i j (hnotX i hi.2), hMX j i hjX, add_zero]) + simp only [Matrix.add_apply, transpose_apply, hMX i j (hnotX i hi.2), hMX j i hjX, add_zero]) have hb₁ : R.blockRank (f ⁻¹' U) (g ⁻¹' Uᶜ) ≤ (M + Mᵀ).blockRank (U ∩ X) Uᶜ := by calc R.blockRank (f ⁻¹' U) (g ⁻¹' Uᶜ) = M.blockRank (U ∩ X) (Uᶜ ∩ Y) := by rw [← hMR, M.blockRank_submatrix hf hg, image_preimage_eq_inter_range, image_preimage_eq_inter_range] _ = (M + Mᵀ).blockRank (U ∩ X) (Uᶜ ∩ Y) := blockRank_congr fun i hi j _ => by - simp only [add_apply, transpose_apply, hMY j i (hnotY i hi.2), add_zero] + simp only [Matrix.add_apply, transpose_apply, hMY j i (hnotY i hi.2), add_zero] _ ≤ (M + Mᵀ).blockRank (U ∩ X) Uᶜ := blockRank_mono_right _ _ inter_subset_left have hb₂ : R.blockRank (f ⁻¹' Uᶜ) (g ⁻¹' U) ≤ (M + Mᵀ).blockRank (U ∩ Y) Uᶜ := by calc R.blockRank (f ⁻¹' Uᶜ) (g ⁻¹' U) @@ -359,7 +359,7 @@ theorem add_blockRank_le_cutRank_add_transpose [Finite ι] image_preimage_eq_inter_range] _ = Mᵀ.blockRank (U ∩ Y) (Uᶜ ∩ X) := (M.blockRank_transpose _ _).symm _ = (M + Mᵀ).blockRank (U ∩ Y) (Uᶜ ∩ X) := blockRank_congr fun i hi j _ => by - simp only [add_apply, transpose_apply, hMX i j (hnotX i hi.2), zero_add] + simp only [Matrix.add_apply, transpose_apply, hMX i j (hnotX i hi.2), zero_add] _ ≤ (M + Mᵀ).blockRank (U ∩ Y) Uᶜ := blockRank_mono_right _ _ inter_subset_left unfold cutRank omega diff --git a/Complexity/Foundations/Probability/Gaussian/Sheppard.lean b/Complexity/Foundations/Probability/Gaussian/Sheppard.lean index e3c419ba0..e18ca8f6d 100644 --- a/Complexity/Foundations/Probability/Gaussian/Sheppard.lean +++ b/Complexity/Foundations/Probability/Gaussian/Sheppard.lean @@ -308,7 +308,7 @@ theorem measureReal_stdGaussian_mem_uIoc_le_angle {u v : E} (huv : ‖u‖ = ‖ simp only [hu, hv, inner_zero_left, uIoc_of_le le_rfl, Ioc_self, mem_empty_iff_false, ofPred_false, measureReal_empty] exact div_nonneg (InnerProductGeometry.angle_nonneg _ _) pi_pos.le - · rw [eq_neg_of_add_eq_zero_right hne, InnerProductGeometry.angle_self_neg_of_nonzero hu, + · rw [eq_neg_of_add_eq_zero_right hne, InnerProductGeometry.angle_self_neg_of_ne_zero hu, div_self pi_ne_zero] exact measureReal_le_one · rw [InnerProductGeometry.angle_eq_two_mul_arctan huv hne] From f5a70cb9826c88744c1dfbc560340d3efebbfb04 Mon Sep 17 00:00:00 2001 From: Samuel Giuseppe Schlesinger Date: Thu, 29 Oct 2026 15:26:19 -0400 Subject: [PATCH 04/25] test(quantum): qualify the protected matrix lemma Preserve the existing non-unitary matrix counterexample under rc2 Mathlib by explicitly selecting Matrix.mul_apply, as in the library proof repairs. --- ComplexityTests/QuantumCircuit.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ComplexityTests/QuantumCircuit.lean b/ComplexityTests/QuantumCircuit.lean index a440e1a4b..cca9dbe2c 100644 --- a/ComplexityTests/QuantumCircuit.lean +++ b/ComplexityTests/QuantumCircuit.lean @@ -158,7 +158,7 @@ example : ¬Circuit.IsOver {⟨3, Gate.toffoli⟩} [h₀] := fun h => example : !![(1 : ℂ), 1; 0, 1] ∉ unitaryGroup (Fin 2) ℂ := by intro h have := congrFun (congrFun (mem_unitaryGroup_iff.mp h) 0) 0 - simp [mul_apply, Fin.sum_univ_two, star_eq_conjTranspose] at this + simp [Matrix.mul_apply, Fin.sum_univ_two, star_eq_conjTranspose] at this -- A two-qubit gate cannot be placed on a one-qubit register: the wires must be distinct. example : IsEmpty (Fin 2 ↪ Fin 1) := From bb3e910dfc197e46f4b11e0c666b6546a075b7c8 Mon Sep 17 00:00:00 2001 From: Samuel Giuseppe Schlesinger Date: Thu, 29 Oct 2026 15:46:20 -0400 Subject: [PATCH 05/25] fix(build): normalize goals before proof automation Use expected-type-directed refinement for the generic zero-sum lemma and expose the determinant variable-count function before fun_prop. Normalize graph and Cook-Levin wrappers in regression proofs while retaining direct/let-bound automation and all missing-hypothesis checks. Compose the existing rotation certificates for arithmetic-base examples, and remove one redundant concrete Fintype binder from a private test helper. Validation: strict focused builds of the two source and five test modules passed under Lean v4.36.0-rc2. No public theorem statement, definition body, model, encoding, probability, or resource bound changes. No heartbeat or fun_prop compatibility option was introduced. --- Complexity/Algorithms/WordRAM/KargerMinCut.lean | 2 +- .../Computability/Circuit/Arithmetic/Determinant.lean | 4 +++- ComplexityTests/ExpanderContraction.lean | 3 ++- ComplexityTests/ExpanderFamily.lean | 1 + ComplexityTests/ExplicitExpanders.lean | 8 ++++++-- ComplexityTests/Iteration/SparseDisplacement.lean | 2 +- ComplexityTests/MultiTapePolyTime.lean | 1 + 7 files changed, 15 insertions(+), 6 deletions(-) diff --git a/Complexity/Algorithms/WordRAM/KargerMinCut.lean b/Complexity/Algorithms/WordRAM/KargerMinCut.lean index c07c84a3c..5cf511394 100644 --- a/Complexity/Algorithms/WordRAM/KargerMinCut.lean +++ b/Complexity/Algorithms/WordRAM/KargerMinCut.lean @@ -1181,7 +1181,7 @@ theorem ampLoop_spec {w sb n R : ℕ} {W : Fin n → Fin n → ℕ} {mem₀ : obtain ⟨m_r, hm_r, _, hsup_r, _⟩ := hnext z₁ hz₁ rw [hml_def, hm_r.codeComp_eq, PMF.toOuterMeasure_map_apply, PMF.toOuterMeasure_apply] - convert tsum_eq_zero_iff.mpr _ + refine tsum_eq_zero_iff.mpr ?_ intro z₂ by_cases hz₂_eval : z₂ ∈ m_r.eval.support · have hz₂ : z₂ ∈ m_r.support := (ProbComp.support_eval m_r) ▸ hz₂_eval diff --git a/Complexity/Computability/Circuit/Arithmetic/Determinant.lean b/Complexity/Computability/Circuit/Arithmetic/Determinant.lean index 1f231b4cf..01cf49231 100644 --- a/Complexity/Computability/Circuit/Arithmetic/Determinant.lean +++ b/Complexity/Computability/Circuit/Arithmetic/Determinant.lean @@ -272,7 +272,9 @@ generic determinants has `n * n` variables, degree at most `n` and arithmetic ci `3 * n ^ 4 + 4` gates. -/ theorem detFamily_mem_VP : detFamily K ∈ VP K := by choose c hc hsize using exists_circuit_det (K := K) - refine ⟨⟨by fun_prop, PolynomiallyBounded.id.mono_of_le fun n => + refine ⟨⟨?_, PolynomiallyBounded.id.mono_of_le fun n => totalDegree_det_genericMatrix_le n⟩, c, PolynomiallyBounded.mono_of_le (by fun_prop) hsize, hc⟩ + change PolynomiallyBounded (fun n : ℕ => n * n) + fun_prop end Cslib.Circuits.Arithmetic diff --git a/ComplexityTests/ExpanderContraction.lean b/ComplexityTests/ExpanderContraction.lean index ac59474d9..1bd9d7150 100644 --- a/ComplexityTests/ExpanderContraction.lean +++ b/ComplexityTests/ExpanderContraction.lean @@ -68,7 +68,7 @@ example : ComputableInPolyTime threeVertices.rot have hg : ComputableInPolyTime completeFive.rot (encPair (encFinEnum (Fin 5)) (encFinEnum (Fin 5))) (encPair (encFinEnum (Fin 5)) (encFinEnum (Fin 5))) := .of_finite _ - fun_prop [threeVertices, RotationMap.contractFin] + exact ComputableInPolyTime.rotationMap_contract he hd hg example {V W I D : Type} (G : RotationMap V D) (encode : V → W × I) (decode : W × I → Option V) (hinv : Function.IsPartialInv encode decode) @@ -80,6 +80,7 @@ example {V W I D : Type} (G : RotationMap V D) (encode : V → W × I) (fun p : (W × (I × D)) × Bool => ((RotationMap.contract encode decode hinv G).rot p.1, !p.2)) (encPair (encPair ew (encPair ei ed)) encBool) (encPair (encPair ew (encPair ei ed)) encBool) := by + dsimp only [RotationMap.contract, RotationMap.contractRot, RotationMap.contractDart] fail_if_success (clear he; fun_prop) fail_if_success (clear hd; fun_prop) fail_if_success (clear hg; fun_prop) diff --git a/ComplexityTests/ExpanderFamily.lean b/ComplexityTests/ExpanderFamily.lean index 0dd5ac6e9..51163712e 100644 --- a/ComplexityTests/ExpanderFamily.lean +++ b/ComplexityTests/ExpanderFamily.lean @@ -96,6 +96,7 @@ example {V W D : Type} (G : RotationMap V D) (e : V ≃ W) let next := (G.reindex e).rot p.1 (next, !p.2)) (encPair (encPair ew ed) encBool) (encPair (encPair ew ed) encBool) := by + dsimp only [RotationMap.reindex, RotationMap.reindexRot] fail_if_success (clear hf; fun_prop) fail_if_success (clear hb; fun_prop) fail_if_success (clear hg; fun_prop) diff --git a/ComplexityTests/ExplicitExpanders.lean b/ComplexityTests/ExplicitExpanders.lean index a912aabc8..c8d706921 100644 --- a/ComplexityTests/ExplicitExpanders.lean +++ b/ComplexityTests/ExplicitExpanders.lean @@ -64,7 +64,8 @@ example {K : Type} [Field K] (encode : K ↪ List Bool) ComputableInPolyTime (RotationMap.affinePlaneTowerBase K).rot (encPair (baseEncoding encode) (planeEncoding encode)) (encPair (baseEncoding encode) (planeEncoding encode)) := by - fun_prop [RotationMap.affinePlaneTowerBase] + have hplane := ComputableInPolyTime.rotationMap_affinePlane hmul hsub + exact ((hplane.rotationMap_tensor hplane).rotationMap_zigzag hplane).rotationMap_zigzag hplane -- Only the fixed field operations use the finite-domain theorem; graph products compose them. example (encode : ZMod 257 ↪ List Bool) : @@ -75,7 +76,8 @@ example (encode : ZMod 257 ↪ List Bool) : (planeEncoding encode) encode := .of_finite _ have hsub : ComputableInPolyTime (fun p : ZMod 257 × ZMod 257 => p.1 - p.2) (planeEncoding encode) encode := .of_finite _ - fun_prop [RotationMap.affinePlaneTowerBase] + have hplane := ComputableInPolyTime.rotationMap_affinePlane hmul hsub + exact ((hplane.rotationMap_tensor hplane).rotationMap_zigzag hplane).rotationMap_zigzag hplane -- Equivalent direct and let-bound spellings, with a supplied rotation on an arbitrary type. example {V D E : Type} (G : RotationMap V D) (H : RotationMap D E) @@ -86,6 +88,7 @@ example {V D E : Type} (G : RotationMap V D) (H : RotationMap D E) (fun p : ((V × D) × (E × E)) × Bool => ((G.zigzag H).rot p.1, !p.2)) (encPair (encPair (encPair vertex label) (encPair small small)) encBool) (encPair (encPair (encPair vertex label) (encPair small small)) encBool) := by + dsimp only [RotationMap.zigzag, RotationMap.zigzagRot] fail_if_success (clear hG; fun_prop) fail_if_success (clear hH; fun_prop) fun_prop @@ -100,6 +103,7 @@ example {V D E : Type} (G : RotationMap V D) (H : RotationMap D E) (next, !p.2)) (encPair (encPair (encPair vertex label) (encPair small small)) encBool) (encPair (encPair (encPair vertex label) (encPair small small)) encBool) := by + dsimp only [RotationMap.zigzag, RotationMap.zigzagRot] fun_prop end ComplexityTests.ExplicitExpanders diff --git a/ComplexityTests/Iteration/SparseDisplacement.lean b/ComplexityTests/Iteration/SparseDisplacement.lean index 634e74f09..fbe746f4f 100644 --- a/ComplexityTests/Iteration/SparseDisplacement.lean +++ b/ComplexityTests/Iteration/SparseDisplacement.lean @@ -34,7 +34,7 @@ example : private def editedCounter : Equiv.Perm (BitVec 2) := (Equiv.swap 0 1).trans (Equiv.addRight 1) -private theorem editedCounter_disagreement [Fintype (BitVec 2)] : +private theorem editedCounter_disagreement : disagreement editedCounter (fun x => x + 1) = {0, 1} := by ext x simp only [mem_disagreement, Finset.mem_insert, Finset.mem_singleton] diff --git a/ComplexityTests/MultiTapePolyTime.lean b/ComplexityTests/MultiTapePolyTime.lean index 2042aace5..8fde4c4a0 100644 --- a/ComplexityTests/MultiTapePolyTime.lean +++ b/ComplexityTests/MultiTapePolyTime.lean @@ -139,6 +139,7 @@ example {α : Type} (enc : α ↪ List Bool) (p : Polynomial ℕ) (c d : ℕ) : ComputableTidilyInPolyTime (fun a => List.range (Cslib.Complexity.CookLevin.parameters p c d enc a).2.2) enc (encList encUnary) := by + dsimp only [Cslib.Complexity.CookLevin.parameters] fun_prop private def finish (move : SignType) (symbol : Bool) : Turing.MultiTapeTM 0 Bool Unit := From 7085d68db489c129c39d3795fb25b3683fded7d7 Mon Sep 17 00:00:00 2001 From: Christian Reitwiessner Date: Thu, 29 Oct 2026 22:56:13 +0000 Subject: [PATCH 06/25] feat(Foundations): correction factorization and reward transport for transition matrices Pure linear algebra for the correction-and-copy hierarchy (#1444 Phase 2, ideas 2 and 4 of #474), following the OpenAI preprint (2026-09-23), Section 4: the factorization 1 - (C - E + EC) = (1 + E)(1 - C), the corrected inverse, copy splitting intertwined with its projection, and the reward transport identity with the stage error bound. Co-Authored-By: Claude Opus 5.5 --- Complexity.lean | 1 + .../Matrix/CorrectionHierarchy.lean | 461 ++++++++++++++++++ ComplexityTests/CorrectionHierarchy.lean | 122 +++++ references.bib | 9 + 4 files changed, 593 insertions(+) create mode 100644 Complexity/Foundations/LinearAlgebra/Matrix/CorrectionHierarchy.lean create mode 100644 ComplexityTests/CorrectionHierarchy.lean diff --git a/Complexity.lean b/Complexity.lean index f59b96f22..c0e4b8629 100644 --- a/Complexity.lean +++ b/Complexity.lean @@ -2620,6 +2620,7 @@ public import Complexity.Foundations.LinearAlgebra.ExchangeReplacement public import Complexity.Foundations.LinearAlgebra.ImageSparsification public import Complexity.Foundations.LinearAlgebra.Interpolation public import Complexity.Foundations.LinearAlgebra.KernelVector +public import Complexity.Foundations.LinearAlgebra.Matrix.CorrectionHierarchy public import Complexity.Foundations.LinearAlgebra.Matrix.CutRank public import Complexity.Foundations.LinearAlgebra.Matrix.Kronecker public import Complexity.Foundations.LinearAlgebra.Matrix.Lindsey diff --git a/Complexity/Foundations/LinearAlgebra/Matrix/CorrectionHierarchy.lean b/Complexity/Foundations/LinearAlgebra/Matrix/CorrectionHierarchy.lean new file mode 100644 index 000000000..606c43617 --- /dev/null +++ b/Complexity/Foundations/LinearAlgebra/Matrix/CorrectionHierarchy.lean @@ -0,0 +1,461 @@ +/- +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.Block +public import Mathlib.LinearAlgebra.Matrix.NonsingularInverse +import Mathlib.Algebra.Order.BigOperators.Group.Finset +import Mathlib.Tactic.NoncommRing + +/-! +# Corrections, copies and reward transport for transition matrices + +Let `C` be the transition matrix of a finite Markov chain that may stop (its rows sum to at most +one), and let `e` be a reward collected when it stops. The expected reward `p` from each state +solves `(1 - C) p = e`; when `C` is nilpotent, `p = (1 - C)⁻¹ e`. For the time-layered +configuration graph of a randomized machine, `p` is the vector of acceptance probabilities. + +This file develops the exact algebra of a hierarchy that shrinks the entries of `C` while keeping +`p` recoverable, following the OpenAI preprint (2026-09-23), Section 4, idea 2 and the deterministic +part of idea 4 in issue #474 [OpenAI2026LogSpace]. The estimates that choose the corrections and +the copies (factorial truncation, detectors) are not part of this file. + +* **Correction.** For any matrix `E`, the *corrected* matrix `D = C - E + E C` satisfies + `1 - D = (1 + E) (1 - C)` (`one_add_mul_one_sub_eq_one_sub`, a ring identity). So the same `p` + solves `(1 - D) p = (1 + E) e` (`Matrix.one_sub_correction_mulVec`): the correction moves + transition weight into the reward `e + E e`. When `1 + E` is invertible, for example when `E` is + strictly upper triangular, `(1 - D)⁻¹ (e + E e) = (1 - C)⁻¹ e` + (`Matrix.inv_one_sub_correction_mulVec`). If `E ≥ 0` and the rows of `C` sum to at most one, + the rows of `D` sum to at most as much (`Matrix.correction_mulVec_one_le`). +* **Copies.** A vertex `x` is replaced by copies `(x, i)`, weighted by `r i x`, and an entry + `D x y` is split among the copies of `y` in proportions `s x y j` (`Matrix.copySplit`). + If the weighted proportions sum to one on the support of `D`, the projection + `Matrix.copyWeight r` intertwines the two matrices: `copySplit r s D * copyWeight r = + copyWeight r * D` (`Matrix.copySplit_mul_copyWeight`). +* **Reward transport.** Iterating, a sequence of stages with transition matrices `C l`, + corrections `E l` and projections `P l` satisfying `C (l + 1) * P l = P l * D l` carries the + cumulative projection `Matrix.copyProjection` and the transported reward + `Matrix.rewardTransport`, with `C l * Pc l = Pc l - B l * (1 - C 0)` + (`Matrix.mul_copyProjection`). Hence the stage-`l` reward `W l = B l e` equals + `Pc l p - C l Pc l p` (`Matrix.rewardTransport_mulVec`). At a vertex `z l` reached from `z 0` + by primary copies only, the transported reward underestimates `p (z 0)` by at most the row + sum of `C l` (`Matrix.sub_rewardTransport_mulVec_mem_Icc`), so by at most `|A l| * ε l` when + the entries of `C l` are at most `ε l` and its nonzero columns lie in `A l` + (`Matrix.sub_rewardTransport_mulVec_le_card_mul`). With the paper's per-stage rates (entries + shrink by `2 ^ (c + 1)`, active columns at most double) this is the stage bound + `0 ≤ p (z 0) - W l (z l) ≤ n / 2 ^ (c l)` (`Matrix.sub_rewardTransport_mulVec_le_pow`). + +## Main definitions + +* `Matrix.IsStrictUpperTriangular`: entries vanish unless the row index is below the column index. +* `Matrix.copySplit`, `Matrix.copyWeight`: a copy step and its weighted projection. +* `Matrix.copyProjection`, `Matrix.rewardTransport`: cumulative projections and rewards of a + sequence of stages. + +## Main results + +* `one_add_mul_one_sub_eq_one_sub`: `(1 + e) (1 - c) = 1 - (c - e + e c)` in any ring. +* `Matrix.one_sub_correction_mulVec`, `Matrix.inv_one_sub_correction_mulVec`: the expected reward + of `C` is the expected corrected reward of `C - E + E C`. +* `Matrix.IsStrictUpperTriangular.det_one_add`: `det (1 + E) = 1` for strictly upper triangular + `E`. +* `Matrix.correction_mulVec_one_le`: corrections keep matrices substochastic. +* `Matrix.copySplit_mul_copyWeight`: a copy step intertwines with its projection. +* `Matrix.mul_copyProjection`, `Matrix.rewardTransport_mulVec`: the reward transport identity. +* `Matrix.sub_rewardTransport_mulVec_mem_Icc`, `Matrix.sub_rewardTransport_mulVec_le_card_mul`, + `Matrix.sub_rewardTransport_mulVec_le_pow`: the transported reward is a lower bound with error + controlled by the last transition matrix. + +## References + +* [OpenAI, *Exact Derandomization of Logarithmic Space: L = RL = BPL*][OpenAI2026LogSpace], + Section 4 (preprint, not peer reviewed) +-/ + +public section + +open Finset + +/-- **The correction factorization.** In any ring, correcting `c` by `e` to `c - e + e * c` +factors `1 - (c - e + e * c)` as `(1 + e) * (1 - c)` [OpenAI2026LogSpace, Section 4]. -/ +theorem one_add_mul_one_sub_eq_one_sub {R : Type*} [Ring R] (c e : R) : + (1 + e) * (1 - c) = 1 - (c - e + e * c) := by + noncomm_ring + +namespace Matrix + +section Triangular + +variable {V R : Type*} + +/-- A square matrix is *strictly upper triangular* when its entry at `(i, j)` vanishes unless +`i < j`. For the time-layered transition matrices of a machine, ordered by time, this says that +every transition moves strictly forward. -/ +def IsStrictUpperTriangular [LT V] [Zero R] (M : Matrix V V R) : Prop := + ∀ ⦃i j⦄, ¬ i < j → M i j = 0 + +namespace IsStrictUpperTriangular + +variable [Preorder V] {M N : Matrix V V R} + +/-- A strictly upper triangular matrix is upper triangular. -/ +theorem isUpperTriangular [Zero R] (h : M.IsStrictUpperTriangular) : M.IsUpperTriangular := + fun _ _ hji => h (lt_asymm hji) + +theorem add [AddZeroClass R] (hM : M.IsStrictUpperTriangular) (hN : N.IsStrictUpperTriangular) : + (M + N).IsStrictUpperTriangular := fun i j hij => by + simp only [add_apply, hM hij, hN hij, add_zero] + +theorem neg [SubtractionMonoid R] (hM : M.IsStrictUpperTriangular) : + (-M).IsStrictUpperTriangular := fun i j hij => by + simp only [neg_apply, hM hij, neg_zero] + +theorem sub [SubtractionMonoid R] (hM : M.IsStrictUpperTriangular) + (hN : N.IsStrictUpperTriangular) : (M - N).IsStrictUpperTriangular := fun i j hij => by + simp only [sub_apply, hM hij, hN hij, sub_zero] + +theorem mul [Fintype V] [NonUnitalNonAssocSemiring R] (hM : M.IsStrictUpperTriangular) + (hN : N.IsStrictUpperTriangular) : (M * N).IsStrictUpperTriangular := fun i j hij => by + refine Finset.sum_eq_zero fun k _ => ?_ + change M i k * N k j = 0 + by_cases hik : i < k + · rw [hN fun hkj => hij (hik.trans hkj), mul_zero] + · rw [hM hik, zero_mul] + +/-- `1 + E` has determinant one when `E` is strictly upper triangular. -/ +theorem det_one_add {V : Type*} [Fintype V] [DecidableEq V] [LinearOrder V] [CommRing R] + {E : Matrix V V R} (h : E.IsStrictUpperTriangular) : (1 + E).det = 1 := by + have hT : (1 + E).IsUpperTriangular := fun i j (hji : j < i) => by + rw [add_apply, one_apply_ne (ne_of_lt hji).symm, h.isUpperTriangular hji, add_zero] + rw [det_of_isUpperTriangular hT] + exact Finset.prod_eq_one fun i _ => by rw [add_apply, one_apply_eq, h (lt_irrefl i), add_zero] + +end IsStrictUpperTriangular + +end Triangular + +section Correction + +variable {V R : Type*} [Fintype V] + +/-- **Corrections preserve the expected reward.** Correcting `C` to `C - E + E * C` turns the +equation `(1 - C) p = e` into `(1 - D) p = (1 + E) e` for the same `p`: the weight removed from +the transitions reappears in the reward [OpenAI2026LogSpace, Section 4]. -/ +theorem one_sub_correction_mulVec [DecidableEq V] [Ring R] (C E : Matrix V V R) (p : V → R) : + (1 - (C - E + E * C)) *ᵥ p = (1 + E) *ᵥ ((1 - C) *ᵥ p) := by + rw [mulVec_mulVec, one_add_mul_one_sub_eq_one_sub] + +/-- **The corrected inverse.** When `1 + E` is invertible, the expected reward +`(1 - C)⁻¹ e` of `C` equals the expected reward of the corrected matrix `C - E + E * C` with the +corrected reward `e + E e`. -/ +theorem inv_one_sub_correction_mulVec [DecidableEq V] [CommRing R] {C E : Matrix V V R} + (hE : IsUnit (1 + E).det) (e : V → R) : + (1 - (C - E + E * C))⁻¹ *ᵥ (e + E *ᵥ e) = (1 - C)⁻¹ *ᵥ e := by + have h : (1 - (C - E + E * C))⁻¹ * (1 + E) = (1 - C)⁻¹ := by + rw [← one_add_mul_one_sub_eq_one_sub, mul_inv_rev, + nonsing_inv_mul_cancel_right (1 + E) (1 - C)⁻¹ hE] + rw [← h, ← mulVec_mulVec, add_mulVec, one_mulVec] + +/-- The corrected inverse for a strictly upper triangular correction. -/ +theorem IsStrictUpperTriangular.inv_one_sub_correction_mulVec [DecidableEq V] [LinearOrder V] + [CommRing R] {C E : Matrix V V R} (hE : E.IsStrictUpperTriangular) (e : V → R) : + (1 - (C - E + E * C))⁻¹ *ᵥ (e + E *ᵥ e) = (1 - C)⁻¹ *ᵥ e := + Matrix.inv_one_sub_correction_mulVec (by rw [hE.det_one_add]; exact isUnit_one) e + +/-- The row sums of a corrected matrix: `(C - E + E C) 1 = C 1 - E (1 - C 1)`. -/ +theorem correction_mulVec_one [Ring R] (C E : Matrix V V R) : + (C - E + E * C) *ᵥ 1 = C *ᵥ 1 - E *ᵥ (1 - C *ᵥ 1) := by + rw [add_mulVec, sub_mulVec, ← mulVec_mulVec, mulVec_sub] + abel + +/-- An entrywise nonnegative matrix maps nonnegative vectors to nonnegative vectors. -/ +theorem mulVec_nonneg {m n : Type*} [Fintype n] [Semiring R] [PartialOrder R] [IsOrderedRing R] + {M : Matrix m n R} (hM : ∀ i j, 0 ≤ M i j) {v : n → R} (hv : 0 ≤ v) : 0 ≤ M *ᵥ v := + fun i => Finset.sum_nonneg fun j _ => mul_nonneg (hM i j) (hv j) + +/-- An entrywise nonnegative matrix whose rows sum to at most one maps vectors with entries at +most one to vectors with entries at most one. -/ +theorem mulVec_le_one {m n : Type*} [Fintype n] [Semiring R] [PartialOrder R] [IsOrderedRing R] + {M : Matrix m n R} (hM : ∀ i j, 0 ≤ M i j) (hM1 : M *ᵥ 1 ≤ 1) {v : n → R} + (hv : v ≤ 1) : + M *ᵥ v ≤ 1 := fun i => + le_trans (Finset.sum_le_sum fun j _ => mul_le_mul_of_nonneg_left (hv j) (hM i j)) (hM1 i) + +/-- **Corrections keep rows substochastic.** If `E ≥ 0` and the rows of `C` sum to at most one, +then each row of `C - E + E C` sums to at most the corresponding row of `C`. -/ +theorem correction_mulVec_one_le [Ring R] [PartialOrder R] [IsOrderedRing R] + {C E : Matrix V V R} (hE : ∀ i j, 0 ≤ E i j) (hC : C *ᵥ 1 ≤ 1) : + (C - E + E * C) *ᵥ 1 ≤ C *ᵥ 1 := by + rw [correction_mulVec_one] + exact sub_le_self _ (mulVec_nonneg hE (sub_nonneg.mpr hC)) + +end Correction + +section Copy + +variable {V ι R : Type*} + +/-- **A copy step.** Each vertex `x` gets copies `(x, i)` with row weights `r i x`, and the entry +`D x y` is split among the copies `(y, j)` of its target in proportions `s x y j`. In the +preprint the proportions depend only on the size of `D x y`, and the copies beyond a primary one +are activated only at targets where the correction was suppressed +[OpenAI2026LogSpace, Section 4.4]. -/ +@[expose] def copySplit [Mul R] (r : ι → V → R) (s : V → V → ι → R) (D : Matrix V V R) : + Matrix (V × ι) (V × ι) R := + of fun a b => r a.2 a.1 * D a.1 b.1 * s a.1 b.1 b.2 + +/-- The *copy projection* from copies to their parents, weighted by `r`: the copy `(x, i)` maps +to `x` with weight `r i x`. -/ +@[expose] def copyWeight [DecidableEq V] [Zero R] (r : ι → V → R) : Matrix (V × ι) V R := + of fun a z => if a.1 = z then r a.2 a.1 else 0 + +@[simp] +theorem copyWeight_mulVec [Fintype V] [DecidableEq V] [NonUnitalNonAssocSemiring R] + (r : ι → V → R) (v : V → R) (a : V × ι) : + (copyWeight r *ᵥ v) a = r a.2 a.1 * v a.1 := by + simp [copyWeight, mulVec, dotProduct, ite_mul] + +/-- A copy with weight one projects to its parent exactly. -/ +theorem copyWeight_apply_of_eq_one [DecidableEq V] [Semiring R] {r : ι → V → R} {x : V} + {i : ι} (h : r i x = 1) (w : V) : copyWeight r (x, i) w = if w = x then 1 else 0 := by + simp [copyWeight, h, eq_comm] + +/-- **Copies intertwine with their projection.** If, on every nonzero entry `D x y`, the +proportions `s x y j` weighted by `r j y` sum to one, then splitting `D` into copies and +projecting back agrees with projecting first: `copySplit r s D * copyWeight r = +copyWeight r * D` [OpenAI2026LogSpace, Proposition 4.5]. -/ +theorem copySplit_mul_copyWeight [Fintype V] [DecidableEq V] [Fintype ι] [Semiring R] + {r : ι → V → R} {s : V → V → ι → R} {D : Matrix V V R} + (hs : ∀ x y, D x y ≠ 0 → ∑ j, s x y j * r j y = 1) : + copySplit r s D * copyWeight r = copyWeight r * D := by + ext ⟨x, i⟩ z + have hL : (copySplit r s D * copyWeight r) (x, i) z = r i x * D x z * ∑ j, s x z j * r j z := by + rw [mul_apply, Fintype.sum_prod_type, Fintype.sum_eq_single z fun y hy => ?_, Finset.mul_sum] + · simp [copySplit, copyWeight, mul_assoc] + · simp [copyWeight, hy] + have hR : (copyWeight r * D) (x, i) z = r i x * D x z := by + rw [mul_apply, Fintype.sum_eq_single x fun y hy => ?_] + · simp [copyWeight] + · simp [copyWeight, Ne.symm hy] + rw [hL, hR] + by_cases hD : D x z = 0 + · simp [hD] + · rw [hs x z hD, mul_one] + +theorem copySplit_nonneg [Semiring R] [PartialOrder R] [IsOrderedRing R] {r : ι → V → R} + {s : V → V → ι → R} {D : Matrix V V R} (hr : ∀ i x, 0 ≤ r i x) + (hs : ∀ x y j, 0 ≤ s x y j) (hD : ∀ x y, 0 ≤ D x y) (a b : V × ι) : + 0 ≤ copySplit r s D a b := + mul_nonneg (mul_nonneg (hr _ _) (hD _ _)) (hs _ _ _) + +/-- **Copies keep rows substochastic** when the weights are at most one and the proportions of +each entry sum to at most one. -/ +theorem copySplit_mulVec_one_le [Fintype V] [Fintype ι] [Semiring R] [PartialOrder R] + [IsOrderedRing R] {r : ι → V → R} {s : V → V → ι → R} {D : Matrix V V R} + (hr0 : ∀ i x, 0 ≤ r i x) (hr1 : ∀ i x, r i x ≤ 1) (hs1 : ∀ x y, ∑ j, s x y j ≤ 1) + (hD0 : ∀ x y, 0 ≤ D x y) (hD1 : D *ᵥ 1 ≤ 1) : copySplit r s D *ᵥ 1 ≤ 1 := by + rintro ⟨x, i⟩ + have hrow : ∑ b : V × ι, copySplit r s D (x, i) b ≤ r i x * ∑ y, D x y := by + rw [Fintype.sum_prod_type, Finset.mul_sum] + refine Finset.sum_le_sum fun y _ => ?_ + simp only [copySplit, of_apply, ← Finset.mul_sum] + exact mul_le_of_le_one_right (mul_nonneg (hr0 i x) (hD0 x y)) (hs1 x y) + have hDx : ∑ y, D x y ≤ 1 := by simpa [mulVec, dotProduct] using hD1 x + simpa [mulVec, dotProduct] using + (hrow.trans (mul_le_of_le_one_right (hr0 i x) hDx)).trans (hr1 i x) + +end Copy + +section Hierarchy + +variable {V : ℕ → Type*} [∀ l, Fintype (V l)] [∀ l, DecidableEq (V l)] {R : Type*} + +/-- **The cumulative projection** of a sequence of stages with projections +`P l : Matrix (V (l + 1)) (V l) R`: the product `P (l - 1) * ⋯ * P 0`, from stage `l` to +stage `0`. -/ +@[expose] def copyProjection [Semiring R] (P : ∀ l, Matrix (V (l + 1)) (V l) R) : + ∀ l, Matrix (V l) (V 0) R + | 0 => 1 + | l + 1 => P l * copyProjection P l + +/-- **The transported reward matrix** of a sequence of stages with projections `P l` and +corrections `E l`: `B (l + 1) = P l * (1 + E l) * B l`, starting from `B 0 = 1`. Applied to the +initial reward `e`, it gives the stage-`l` reward `B l e`. -/ +@[expose] def rewardTransport [Semiring R] (P : ∀ l, Matrix (V (l + 1)) (V l) R) + (E : ∀ l, Matrix (V l) (V l) R) : ∀ l, Matrix (V l) (V 0) R + | 0 => 1 + | l + 1 => P l * (1 + E l) * rewardTransport P E l + +variable {C E : ∀ l, Matrix (V l) (V l) R} {P : ∀ l, Matrix (V (l + 1)) (V l) R} + +/-- **The reward transport identity.** If each stage's transition matrix intertwines with the +corrected matrix of the previous stage, `C (l + 1) * P l = P l * (C l - E l + E l * C l)`, then +`C l * Pc l = Pc l - B l * (1 - C 0)` for the cumulative projection `Pc` and the transported +reward matrix `B` [OpenAI2026LogSpace, Proposition 4.7]. -/ +theorem mul_copyProjection [Ring R] + (h : ∀ l, C (l + 1) * P l = P l * (C l - E l + E l * C l)) (l : ℕ) : + C l * copyProjection P l = copyProjection P l - rewardTransport P E l * (1 - C 0) := by + induction l with + | zero => simp [copyProjection, rewardTransport] + | succ l ih => + have hD : C l - E l + E l * C l = 1 - (1 + E l) * (1 - C l) := by + rw [one_add_mul_one_sub_eq_one_sub, sub_sub_cancel] + have hB : (1 - C l) * copyProjection P l = rewardTransport P E l * (1 - C 0) := by + rw [Matrix.sub_mul, Matrix.one_mul, ih, sub_sub_cancel] + calc C (l + 1) * copyProjection P (l + 1) + = P l * (C l - E l + E l * C l) * copyProjection P l := by + rw [copyProjection, ← Matrix.mul_assoc, h] + _ = P l * copyProjection P l - P l * (1 + E l) * ((1 - C l) * copyProjection P l) := by + rw [hD] + simp only [Matrix.mul_sub, Matrix.sub_mul, Matrix.mul_one, Matrix.one_mul, + Matrix.mul_assoc] + _ = copyProjection P (l + 1) - rewardTransport P E (l + 1) * (1 - C 0) := by + rw [hB] + simp only [copyProjection, rewardTransport, Matrix.mul_assoc] + +/-- **The transported reward.** If `p` solves `(1 - C 0) p = e`, the stage-`l` reward is +`B l e = Pc l p - C l (Pc l p)`: the projected solution minus what the remaining transitions +still carry [OpenAI2026LogSpace, Proposition 4.7]. -/ +theorem rewardTransport_mulVec [Ring R] + (h : ∀ l, C (l + 1) * P l = P l * (C l - E l + E l * C l)) {p e : V 0 → R} + (hp : (1 - C 0) *ᵥ p = e) (l : ℕ) : + rewardTransport P E l *ᵥ e = + copyProjection P l *ᵥ p - C l *ᵥ (copyProjection P l *ᵥ p) := by + rw [mulVec_mulVec, mul_copyProjection h, sub_mulVec, ← mulVec_mulVec, hp, sub_sub_cancel] + +/-- The stage rewards are updated by adding the correction's contribution and projecting: +`W (l + 1) = P l (W l + E l W l)`. -/ +theorem rewardTransport_succ_mulVec [Semiring R] (e : V 0 → R) (l : ℕ) : + rewardTransport P E (l + 1) *ᵥ e = + P l *ᵥ (rewardTransport P E l *ᵥ e + E l *ᵥ (rewardTransport P E l *ᵥ e)) := by + rw [rewardTransport, ← mulVec_mulVec, ← mulVec_mulVec, add_mulVec, one_mulVec] + +/-- Along *primary copies* `z l`, whose rows of `P l` are unit vectors, the cumulative projection +reads off the original coordinate. -/ +theorem copyProjection_mulVec_primary [Semiring R] {z : ∀ l, V l} + (hz : ∀ l w, P l (z (l + 1)) w = if w = z l then 1 else 0) (p : V 0 → R) (l : ℕ) : + (copyProjection P l *ᵥ p) (z l) = p (z 0) := by + induction l with + | zero => simp [copyProjection] + | succ l ih => + rw [copyProjection, ← mulVec_mulVec] + simp [mulVec, dotProduct, hz, ite_mul, ← ih] + +section Order + +variable [Ring R] [PartialOrder R] [IsOrderedRing R] + +private theorem one_apply_nonneg {n : Type*} [DecidableEq n] (i j : n) : + (0 : R) ≤ (1 : Matrix n n R) i j := by + rw [one_apply]; split_ifs <;> simp + +private theorem mul_nonneg_entries {m n o : Type*} [Fintype n] {A : Matrix m n R} + {B : Matrix n o R} (hA : ∀ i j, 0 ≤ A i j) (hB : ∀ i j, 0 ≤ B i j) (i : m) (k : o) : + 0 ≤ (A * B) i k := + Finset.sum_nonneg fun j _ => mul_nonneg (hA i j) (hB j k) + +theorem copyProjection_nonneg (hP : ∀ l i j, 0 ≤ P l i j) (l : ℕ) : + ∀ i j, 0 ≤ copyProjection P l i j := by + induction l with + | zero => exact one_apply_nonneg + | succ l ih => exact mul_nonneg_entries (hP l) ih + +/-- The cumulative projection of substochastic projections is substochastic. -/ +theorem copyProjection_mulVec_one_le (hP : ∀ l i j, 0 ≤ P l i j) (hP1 : ∀ l, P l *ᵥ 1 ≤ 1) + (l : ℕ) : copyProjection P l *ᵥ 1 ≤ 1 := by + induction l with + | zero => simp [copyProjection] + | succ l ih => + rw [copyProjection, ← mulVec_mulVec] + exact mulVec_le_one (hP l) (hP1 l) ih + +theorem rewardTransport_nonneg (hP : ∀ l i j, 0 ≤ P l i j) (hE : ∀ l i j, 0 ≤ E l i j) + (l : ℕ) : ∀ i j, 0 ≤ rewardTransport P E l i j := by + induction l with + | zero => exact one_apply_nonneg + | succ l ih => + exact mul_nonneg_entries (mul_nonneg_entries (hP l) + (fun i j => add_nonneg (one_apply_nonneg i j) (hE l i j))) ih + +variable (hP : ∀ l i j, 0 ≤ P l i j) (hP1 : ∀ l, P l *ᵥ 1 ≤ 1) + (hC : ∀ l i j, 0 ≤ C l i j) (hstep : ∀ l, C (l + 1) * P l = P l * (C l - E l + E l * C l)) + {p e : V 0 → R} + (hp : (1 - C 0) *ᵥ p = e) (hp0 : 0 ≤ p) (hp1 : p ≤ 1) +include hP hP1 hC hstep hp hp0 hp1 + +/-- The stage rewards are bounded by the projected solution, hence by one. -/ +theorem rewardTransport_mulVec_le (l : ℕ) : + rewardTransport P E l *ᵥ e ≤ copyProjection P l *ᵥ p ∧ + copyProjection P l *ᵥ p ≤ 1 := by + have hPc0 : 0 ≤ copyProjection P l *ᵥ p := mulVec_nonneg (copyProjection_nonneg hP l) hp0 + refine ⟨?_, mulVec_le_one (copyProjection_nonneg hP l) + (copyProjection_mulVec_one_le hP hP1 l) hp1⟩ + rw [rewardTransport_mulVec hstep hp] + exact sub_le_self _ (mulVec_nonneg (hC l) hPc0) + +/-- **The stage error.** Along primary copies `z l`, the stage-`l` reward underestimates the +solution at `z 0` by at most the row sum of `C l` at `z l` +[OpenAI2026LogSpace, Proposition 4.7]. -/ +theorem sub_rewardTransport_mulVec_mem_Icc {z : ∀ l, V l} + (hz : ∀ l w, P l (z (l + 1)) w = if w = z l then 1 else 0) (l : ℕ) : + p (z 0) - (rewardTransport P E l *ᵥ e) (z l) ∈ Set.Icc 0 (∑ y, C l (z l) y) := by + have hPc0 : 0 ≤ copyProjection P l *ᵥ p := mulVec_nonneg (copyProjection_nonneg hP l) hp0 + have hPc1 : copyProjection P l *ᵥ p ≤ 1 := + (rewardTransport_mulVec_le hP hP1 hC hstep hp hp0 hp1 l).2 + rw [rewardTransport_mulVec hstep hp, Pi.sub_apply, copyProjection_mulVec_primary hz, + sub_sub_cancel] + exact ⟨mulVec_nonneg (hC l) hPc0 _, Finset.sum_le_sum fun y _ => + mul_le_of_le_one_right (hC l _ y) (hPc1 y)⟩ + +/-- **The stage error, by counting.** If the entries of `C l` are at most `ε` and its nonzero +columns lie in `A`, the stage-`l` reward along primary copies underestimates the solution by at +most `|A| ε`. -/ +theorem sub_rewardTransport_mulVec_le_card_mul {z : ∀ l, V l} + (hz : ∀ l w, P l (z (l + 1)) w = if w = z l then 1 else 0) (l : ℕ) {ε : R} + (hε : ∀ x y, C l x y ≤ ε) {A : Finset (V l)} (hA : ∀ x y, C l x y ≠ 0 → y ∈ A) : + p (z 0) - (rewardTransport P E l *ᵥ e) (z l) ≤ A.card • ε := by + refine (sub_rewardTransport_mulVec_mem_Icc hP hP1 hC hstep hp hp0 hp1 hz l).2.trans ?_ + rw [← Finset.sum_subset (Finset.subset_univ A) fun y _ hy => by_contra fun h => hy (hA _ y h)] + exact Finset.sum_le_card_nsmul _ _ _ fun y _ => hε _ y + +end Order + +/-- **The stage bound.** If the entries of `C l` are at most `(2 ^ (c + 1))⁻¹ ^ l` and its +nonzero columns lie in a set of at most `2 ^ l * n` vertices, then along primary copies +`0 ≤ p (z 0) - W l (z l) ≤ n * (2 ^ c)⁻¹ ^ l`. With `n` the number of vertices of stage `0`, +this is the preprint's bound `|V₀| 2 ^ (-(H - 1) l)` for `H = c + 1` +[OpenAI2026LogSpace, Proposition 4.7]. -/ +theorem sub_rewardTransport_mulVec_le_pow [Field R] [LinearOrder R] [IsStrictOrderedRing R] + (hP : ∀ l i j, 0 ≤ P l i j) (hP1 : ∀ l, P l *ᵥ 1 ≤ 1) (hC : ∀ l i j, 0 ≤ C l i j) + (hstep : ∀ l, C (l + 1) * P l = P l * (C l - E l + E l * C l)) {p e : V 0 → R} + (hp : (1 - C 0) *ᵥ p = e) (hp0 : 0 ≤ p) (hp1 : p ≤ 1) {z : ∀ l, V l} + (hz : ∀ l w, P l (z (l + 1)) w = if w = z l then 1 else 0) {c n : ℕ} + (hε : ∀ l x y, C l x y ≤ ((2 : R) ^ (c + 1))⁻¹ ^ l) (A : ∀ l, Finset (V l)) + (hA : ∀ l x y, C l x y ≠ 0 → y ∈ A l) (hAn : ∀ l, (A l).card ≤ 2 ^ l * n) + (l : ℕ) : + 0 ≤ p (z 0) - (rewardTransport P E l *ᵥ e) (z l) ∧ + p (z 0) - (rewardTransport P E l *ᵥ e) (z l) ≤ n * ((2 : R) ^ c)⁻¹ ^ l := by + refine ⟨(sub_rewardTransport_mulVec_mem_Icc hP hP1 hC hstep hp hp0 hp1 hz l).1, ?_⟩ + refine (sub_rewardTransport_mulVec_le_card_mul hP hP1 hC hstep hp hp0 hp1 hz l (hε l) + (hA l)).trans ?_ + rw [nsmul_eq_mul] + calc ((A l).card : R) * ((2 : R) ^ (c + 1))⁻¹ ^ l + ≤ (2 ^ l * n : ℕ) * ((2 : R) ^ (c + 1))⁻¹ ^ l := + mul_le_mul_of_nonneg_right (by exact_mod_cast hAn l) + (pow_nonneg (inv_nonneg.mpr (pow_nonneg zero_le_two _)) _) + _ = n * ((2 : R) ^ c)⁻¹ ^ l := by + have h2 : (2 : R) ^ l ≠ 0 := pow_ne_zero _ two_ne_zero + push_cast + rw [pow_succ, mul_inv, mul_pow, inv_pow (2 : R), mul_comm ((2 : R) ^ l), mul_assoc, + ← mul_assoc ((2 : R) ^ l), mul_comm ((2 : R) ^ l), mul_assoc _ ((2 : R) ^ l), + mul_inv_cancel₀ h2, mul_one] + +end Hierarchy + +end Matrix diff --git a/ComplexityTests/CorrectionHierarchy.lean b/ComplexityTests/CorrectionHierarchy.lean new file mode 100644 index 000000000..03ad463c2 --- /dev/null +++ b/ComplexityTests/CorrectionHierarchy.lean @@ -0,0 +1,122 @@ +/- +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.LinearAlgebra.Matrix.CorrectionHierarchy + +/-! +# Tests for corrections, copies and reward transport +-/ + +namespace ComplexityTests.CorrectionHierarchy + +open Matrix + +/-- A walk on three time layers: from `0` to `1` and from `1` to `2`, each with probability +`1 / 2`; it stops otherwise. -/ +private def C : Matrix (Fin 3) (Fin 3) ℚ := !![0, 1 / 2, 0; 0, 0, 1 / 2; 0, 0, 0] + +/-- The reward is collected at `2`. -/ +private def e : Fin 3 → ℚ := ![0, 0, 1] + +/-- The expected rewards: `1 / 4` from `0`, `1 / 2` from `1`. -/ +private def p : Fin 3 → ℚ := ![1 / 4, 1 / 2, 1] + +private theorem one_sub_C_mulVec_p : (1 - C) *ᵥ p = e := by + ext i; fin_cases i <;> norm_num [C, p, e, mulVec, dotProduct, Fin.sum_univ_three, one_apply] + +/-- The correction removes the second transition. -/ +private def E : Matrix (Fin 3) (Fin 3) ℚ := !![0, 0, 0; 0, 0, 1 / 2; 0, 0, 0] + +private theorem E_strict : E.IsStrictUpperTriangular := by + intro i j h + fin_cases i <;> fin_cases j <;> simp_all [E] + +-- The corrected matrix keeps only the first transition. +example : C - E + E * C = !![0, 1 / 2, 0; 0, 0, 0; 0, 0, 0] := by + ext i j; fin_cases i <;> fin_cases j <;> simp [C, E] + +-- The removed weight `1 / 2` reappears as a reward at `1`, and `p` still solves the corrected +-- equation. +example : (1 - (C - E + E * C)) *ᵥ p = ![0, 1 / 2, 1] := by + rw [one_sub_correction_mulVec, one_sub_C_mulVec_p] + ext i; fin_cases i <;> simp [E, e, mulVec, dotProduct, Fin.sum_univ_three, one_apply] + +private theorem inv_one_sub_C : (1 - C)⁻¹ = 1 + C + C * C := + inv_eq_left_inv <| by + ext i j; fin_cases i <;> fin_cases j <;> + simp [C, mul_apply, Fin.sum_univ_three, one_apply] + +-- The acceptance probabilities of the corrected walk with the corrected reward are those of +-- the original walk: `1 / 4` from `0`. +example : ((1 - (C - E + E * C))⁻¹ *ᵥ (e + E *ᵥ e)) 0 = 1 / 4 := by + rw [E_strict.inv_one_sub_correction_mulVec, inv_one_sub_C] + simp [C, e, mulVec, dotProduct, Fin.sum_univ_three, one_apply] + norm_num + +-- Corrections keep the rows substochastic. +example : (C - E + E * C) *ᵥ 1 ≤ C *ᵥ 1 := + correction_mulVec_one_le (fun i j => by fin_cases i <;> fin_cases j <;> simp [E]) fun i => by + fin_cases i <;> simp [C, mulVec, dotProduct, Fin.sum_univ_three] <;> norm_num + +/-! ### Copies -/ + +/-- Both copies of every vertex are active. -/ +private def r : Fin 2 → Fin 3 → ℚ := fun _ _ => 1 + +/-- Every entry is split evenly between the two copies of its target. -/ +private def s : Fin 3 → Fin 3 → Fin 2 → ℚ := fun _ _ _ => 1 / 2 + +-- Splitting halves the entries and intertwines with the copy projection. +example : copySplit r s C ((0 : Fin 3), (0 : Fin 2)) ((1 : Fin 3), (1 : Fin 2)) = 1 / 4 := by + norm_num [copySplit, r, s, C] + +example : copySplit r s C * copyWeight r = copyWeight r * C := + copySplit_mul_copyWeight fun _ _ _ => by simp [r, s] + +example : copySplit r s C *ᵥ 1 ≤ 1 := + copySplit_mulVec_one_le (fun _ _ => by simp [r]) (fun _ _ => le_rfl) + (fun _ _ => by simp [s]) + (fun i j => by fin_cases i <;> fin_cases j <;> simp [C]) + fun i => by fin_cases i <;> norm_num [C, mulVec, dotProduct, Fin.sum_univ_three] + +/-! ### Reward transport + +A one-step hierarchy: the correction `C + C ^ 2` removes every transition of `C`, since +`C ^ 3 = 0`, so the stage-`1` matrix is zero and the stage-`1` reward is exact. -/ + +private def Cs (l : ℕ) : Matrix (Fin 3) (Fin 3) ℚ := if l = 0 then C else 0 + +private def Es (l : ℕ) : Matrix (Fin 3) (Fin 3) ℚ := if l = 0 then C + C * C else 0 + +private def Ps (_ : ℕ) : Matrix (Fin 3) (Fin 3) ℚ := 1 + +private theorem C_cube : C * C * C = 0 := by + ext i j; fin_cases i <;> fin_cases j <;> simp [C, mul_apply, Fin.sum_univ_three] + +private theorem hstep (l : ℕ) : Cs (l + 1) * Ps l = Ps l * (Cs l - Es l + Es l * Cs l) := by + rcases l with _ | l + · simp only [Cs, Es, Ps, ↓reduceIte, Nat.add_one_ne_zero, Matrix.zero_mul, Matrix.one_mul] + rw [← C_cube]; noncomm_ring + · simp [Cs, Es, Ps] + +private theorem nonneg_C : ∀ i j, 0 ≤ C i j := by + intro i j; fin_cases i <;> fin_cases j <;> simp [C] + +-- From `0`, the stage-`1` reward equals the acceptance probability `1 / 4`: the error bound is +-- the row sum of the zero matrix. +example : (rewardTransport (V := fun _ => Fin 3) Ps Es 1 *ᵥ e) 0 = 1 / 4 := by + have h := sub_rewardTransport_mulVec_mem_Icc (V := fun _ => Fin 3) (C := Cs) (E := Es) + (P := Ps) (z := fun _ => 0) (fun _ i j => by simp [Ps, one_apply]; split_ifs <;> simp) + (fun _ => by simp [Ps]) (fun l i j => by unfold Cs; split_ifs <;> simp [nonneg_C]) + hstep (p := p) (e := e) (by simpa [Cs] using one_sub_C_mulVec_p) + (fun i => by fin_cases i <;> norm_num [p]) + (fun i => by fin_cases i <;> norm_num [p]) + (fun _ w => by simp [Ps, one_apply, eq_comm]) 1 + have hp0 : p 0 = 1 / 4 := rfl + simp only [Cs, Nat.add_one_ne_zero, ↓reduceIte, Matrix.zero_apply, Finset.sum_const_zero, + Set.mem_Icc] at h + linarith [h.1, h.2] + +end ComplexityTests.CorrectionHierarchy diff --git a/references.bib b/references.bib index ffd09ecfe..39e270d93 100644 --- a/references.bib +++ b/references.bib @@ -3451,6 +3451,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 832f9390cd08ee432c7d3a14ae70d623b647fd80 Mon Sep 17 00:00:00 2001 From: Christian Reitwiessner Date: Thu, 29 Oct 2026 23:05:28 +0000 Subject: [PATCH 07/25] fix(Foundations): expose IsStrictUpperTriangular so importers can apply it Co-Authored-By: Claude Opus 5.5 --- .../Foundations/LinearAlgebra/Matrix/CorrectionHierarchy.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Complexity/Foundations/LinearAlgebra/Matrix/CorrectionHierarchy.lean b/Complexity/Foundations/LinearAlgebra/Matrix/CorrectionHierarchy.lean index 606c43617..4ded7fdbb 100644 --- a/Complexity/Foundations/LinearAlgebra/Matrix/CorrectionHierarchy.lean +++ b/Complexity/Foundations/LinearAlgebra/Matrix/CorrectionHierarchy.lean @@ -97,7 +97,7 @@ variable {V R : Type*} /-- A square matrix is *strictly upper triangular* when its entry at `(i, j)` vanishes unless `i < j`. For the time-layered transition matrices of a machine, ordered by time, this says that every transition moves strictly forward. -/ -def IsStrictUpperTriangular [LT V] [Zero R] (M : Matrix V V R) : Prop := +@[expose] def IsStrictUpperTriangular [LT V] [Zero R] (M : Matrix V V R) : Prop := ∀ ⦃i j⦄, ¬ i < j → M i j = 0 namespace IsStrictUpperTriangular From 1fbc2671b8dbcee6119dbd9f79b4a36b2bf4b52a Mon Sep 17 00:00:00 2001 From: Christian Reitwiessner Date: Thu, 29 Oct 2026 23:15:03 +0000 Subject: [PATCH 08/25] fix(Foundations): separate row-sum control from nonnegativity; add reward lower bound Review of #1676: correction_mulVec_one_le only shows that row sums do not grow, so its docstring, the module summary and the test comment no longer call it substochasticity. Add rewardTransport_mulVec_nonneg, the lower half of (4.30), under nonnegative projections, corrections and reward. Co-Authored-By: Claude Opus 5.5 --- .../Matrix/CorrectionHierarchy.lean | 24 ++++++++++++++----- ComplexityTests/CorrectionHierarchy.lean | 12 +++++++++- 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/Complexity/Foundations/LinearAlgebra/Matrix/CorrectionHierarchy.lean b/Complexity/Foundations/LinearAlgebra/Matrix/CorrectionHierarchy.lean index 4ded7fdbb..2420fb961 100644 --- a/Complexity/Foundations/LinearAlgebra/Matrix/CorrectionHierarchy.lean +++ b/Complexity/Foundations/LinearAlgebra/Matrix/CorrectionHierarchy.lean @@ -65,9 +65,11 @@ the copies (factorial truncation, detectors) are not part of this file. of `C` is the expected corrected reward of `C - E + E C`. * `Matrix.IsStrictUpperTriangular.det_one_add`: `det (1 + E) = 1` for strictly upper triangular `E`. -* `Matrix.correction_mulVec_one_le`: corrections keep matrices substochastic. +* `Matrix.correction_mulVec_one_le`: nonnegative corrections do not increase row sums. * `Matrix.copySplit_mul_copyWeight`: a copy step intertwines with its projection. * `Matrix.mul_copyProjection`, `Matrix.rewardTransport_mulVec`: the reward transport identity. +* `Matrix.rewardTransport_mulVec_nonneg`, `Matrix.rewardTransport_mulVec_le`: the stage rewards + lie between `0` and the projected solution. * `Matrix.sub_rewardTransport_mulVec_mem_Icc`, `Matrix.sub_rewardTransport_mulVec_le_card_mul`, `Matrix.sub_rewardTransport_mulVec_le_pow`: the transported reward is a lower bound with error controlled by the last transition matrix. @@ -187,8 +189,10 @@ theorem mulVec_le_one {m n : Type*} [Fintype n] [Semiring R] [PartialOrder R] [I M *ᵥ v ≤ 1 := fun i => le_trans (Finset.sum_le_sum fun j _ => mul_le_mul_of_nonneg_left (hv j) (hM i j)) (hM1 i) -/-- **Corrections keep rows substochastic.** If `E ≥ 0` and the rows of `C` sum to at most one, -then each row of `C - E + E C` sums to at most the corresponding row of `C`. -/ +/-- **Corrections do not increase row sums.** If `E ≥ 0` and the rows of `C` sum to at most one, +then each row of `C - E + E C` sums to at most the corresponding row of `C`. This says nothing +about the signs of the entries of `C - E + E C`; their nonnegativity depends on how `E` is +chosen [OpenAI2026LogSpace, Lemma 4.4]. -/ theorem correction_mulVec_one_le [Ring R] [PartialOrder R] [IsOrderedRing R] {C E : Matrix V V R} (hE : ∀ i j, 0 ≤ E i j) (hC : C *ᵥ 1 ≤ 1) : (C - E + E * C) *ᵥ 1 ≤ C *ᵥ 1 := by @@ -254,8 +258,9 @@ theorem copySplit_nonneg [Semiring R] [PartialOrder R] [IsOrderedRing R] {r : ι 0 ≤ copySplit r s D a b := mul_nonneg (mul_nonneg (hr _ _) (hD _ _)) (hs _ _ _) -/-- **Copies keep rows substochastic** when the weights are at most one and the proportions of -each entry sum to at most one. -/ +/-- **Copies keep row sums at most one** when the weights lie in `[0, 1]`, `D` is nonnegative +with row sums at most one, and the proportions of each entry sum to at most one. Together with +`Matrix.copySplit_nonneg` this makes the copy step substochastic. -/ theorem copySplit_mulVec_one_le [Fintype V] [Fintype ι] [Semiring R] [PartialOrder R] [IsOrderedRing R] {r : ι → V → R} {s : V → V → ι → R} {D : Matrix V V R} (hr0 : ∀ i x, 0 ≤ r i x) (hr1 : ∀ i x, r i x ≤ 1) (hs1 : ∀ x y, ∑ j, s x y j ≤ 1) @@ -383,13 +388,20 @@ theorem rewardTransport_nonneg (hP : ∀ l i j, 0 ≤ P l i j) (hE : ∀ l i j, exact mul_nonneg_entries (mul_nonneg_entries (hP l) (fun i j => add_nonneg (one_apply_nonneg i j) (hE l i j))) ih +/-- The stage rewards are nonnegative when the projections, the corrections and the initial reward +are [OpenAI2026LogSpace, Proposition 4.7]. -/ +theorem rewardTransport_mulVec_nonneg (hP : ∀ l i j, 0 ≤ P l i j) (hE : ∀ l i j, 0 ≤ E l i j) + {e : V 0 → R} (he : 0 ≤ e) (l : ℕ) : 0 ≤ rewardTransport P E l *ᵥ e := + mulVec_nonneg (rewardTransport_nonneg hP hE l) he + variable (hP : ∀ l i j, 0 ≤ P l i j) (hP1 : ∀ l, P l *ᵥ 1 ≤ 1) (hC : ∀ l i j, 0 ≤ C l i j) (hstep : ∀ l, C (l + 1) * P l = P l * (C l - E l + E l * C l)) {p e : V 0 → R} (hp : (1 - C 0) *ᵥ p = e) (hp0 : 0 ≤ p) (hp1 : p ≤ 1) include hP hP1 hC hstep hp hp0 hp1 -/-- The stage rewards are bounded by the projected solution, hence by one. -/ +/-- The stage rewards are bounded by the projected solution, hence by one. For the lower bound +see `Matrix.rewardTransport_mulVec_nonneg`. -/ theorem rewardTransport_mulVec_le (l : ℕ) : rewardTransport P E l *ᵥ e ≤ copyProjection P l *ᵥ p ∧ copyProjection P l *ᵥ p ≤ 1 := by diff --git a/ComplexityTests/CorrectionHierarchy.lean b/ComplexityTests/CorrectionHierarchy.lean index 03ad463c2..c6bb668e6 100644 --- a/ComplexityTests/CorrectionHierarchy.lean +++ b/ComplexityTests/CorrectionHierarchy.lean @@ -55,7 +55,7 @@ example : ((1 - (C - E + E * C))⁻¹ *ᵥ (e + E *ᵥ e)) 0 = 1 / 4 := by simp [C, e, mulVec, dotProduct, Fin.sum_univ_three, one_apply] norm_num --- Corrections keep the rows substochastic. +-- A nonnegative correction does not increase the row sums. example : (C - E + E * C) *ᵥ 1 ≤ C *ᵥ 1 := correction_mulVec_one_le (fun i j => by fin_cases i <;> fin_cases j <;> simp [E]) fun i => by fin_cases i <;> simp [C, mulVec, dotProduct, Fin.sum_univ_three] <;> norm_num @@ -119,4 +119,14 @@ example : (rewardTransport (V := fun _ => Fin 3) Ps Es 1 *ᵥ e) 0 = 1 / 4 := by Set.mem_Icc] at h linarith [h.1, h.2] +-- The transported rewards are nonnegative. +example : 0 ≤ rewardTransport (V := fun _ => Fin 3) Ps Es 1 *ᵥ e := + rewardTransport_mulVec_nonneg (V := fun _ => Fin 3) + (fun _ i j => by simp only [Ps, one_apply]; split_ifs <;> simp) + (fun l i j => by + unfold Es; split_ifs + · fin_cases i <;> fin_cases j <;> norm_num [C, mul_apply, Fin.sum_univ_three] + · simp) + (fun i => by fin_cases i <;> simp [e]) 1 + end ComplexityTests.CorrectionHierarchy From b5cc0590faa36fabf897783af15a6384793707f6 Mon Sep 17 00:00:00 2001 From: Christian Reitwiessner Date: Thu, 29 Oct 2026 23:05:40 +0000 Subject: [PATCH 09/25] feat(Foundations): factorial truncation of cutoff corrections Second slice of #1444 Phase 2 (idea 3 of #474), following the OpenAI preprint (2026-09-23), Lemma 4.1 and Lemma 4.4: the cutoff correction recursion E = phi((C + EC)) on a strictly upper triangular C has a unique fixed point, its iterates increase towards it, and after k iterations the error is at most f e^(1/theta) (L/theta)^k / k!, independently of the size of the matrix. The corrected matrix of a finite iterate is nonnegative and small in fully corrected columns. Co-Authored-By: Claude Opus 5.5 --- Complexity.lean | 1 + .../Matrix/FactorialTruncation.lean | 483 ++++++++++++++++++ ComplexityTests/FactorialTruncation.lean | 93 ++++ 3 files changed, 577 insertions(+) create mode 100644 Complexity/Foundations/LinearAlgebra/Matrix/FactorialTruncation.lean create mode 100644 ComplexityTests/FactorialTruncation.lean diff --git a/Complexity.lean b/Complexity.lean index c0e4b8629..b1c2b3181 100644 --- a/Complexity.lean +++ b/Complexity.lean @@ -2622,6 +2622,7 @@ public import Complexity.Foundations.LinearAlgebra.Interpolation public import Complexity.Foundations.LinearAlgebra.KernelVector public import Complexity.Foundations.LinearAlgebra.Matrix.CorrectionHierarchy public import Complexity.Foundations.LinearAlgebra.Matrix.CutRank +public import Complexity.Foundations.LinearAlgebra.Matrix.FactorialTruncation public import Complexity.Foundations.LinearAlgebra.Matrix.Kronecker public import Complexity.Foundations.LinearAlgebra.Matrix.Lindsey public import Complexity.Foundations.LinearAlgebra.Matrix.ListProd diff --git a/Complexity/Foundations/LinearAlgebra/Matrix/FactorialTruncation.lean b/Complexity/Foundations/LinearAlgebra/Matrix/FactorialTruncation.lean new file mode 100644 index 000000000..ad9fe5b9c --- /dev/null +++ b/Complexity/Foundations/LinearAlgebra/Matrix/FactorialTruncation.lean @@ -0,0 +1,483 @@ +/- +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.LinearAlgebra.Matrix.CorrectionHierarchy +public import Mathlib.Analysis.SpecialFunctions.Exp +import Mathlib.Algebra.Ring.GeomSum +import Mathlib.Data.Nat.Choose.Bounds +import Mathlib.Topology.Algebra.Order.Floor + +/-! +# Factorial truncation of cutoff corrections + +Let `C` be a strictly upper triangular transition matrix with nonnegative entries at most `f` +and rows summing to at most one. A *cutoff correction* chooses the correction `E` of +`Matrix.one_sub_correction_mulVec` entrywise from the corrected input, +`E x y = φ y ((C + E C) x y)`, where each cutoff `φ y` is monotone, `L`-Lipschitz and leaves at +least `θ f` behind: `0 ≤ φ y t ≤ max (t - θ f) 0`. In the OpenAI preprint (2026-09-23), idea 3 in +issue #474, `φ y t = f Q (t / f) g y` for a smooth ramp `Q` and a column multiplier `g` +[OpenAI2026LogSpace, Section 4.1]. + +The equation is a recursion along the order of the columns, so it has exactly one solution +`Matrix.cutoffCorrectionFix φ C`, reached by iterating `Matrix.cutoffCorrection φ C` from zero +`card V` times (`Matrix.cutoffCorrection_fix`, `Matrix.eq_cutoffCorrectionFix`). The point of +the estimate is that far fewer iterations suffice, independently of the size of `V`: after `k` +iterations every entry is within `f e^(1 / θ) (L / θ)^k / k!` of the fixed point +(`Matrix.cutoffCorrectionFix_sub_iter_le`). + +The proof counts chains. In a fixed row, every positive entry of the fixed point leaves a residual +at least `θ f`, and the residuals of a row sum to at most one, so the row has at most `1 / (θ f)` +positive entries. Unrolling the recursion `k` times along that row expresses the error as a sum +over increasing chains of `k` of these entries, each weighted by at most `(L f)^k`; there are at +most `binomial (1 / (θ f), k) ≤ (θ f)^(-k) / k!` of them. + +For the finite correction `E = E k`, the corrected matrix `C - E + E C` is nonnegative +(`Matrix.cutoffCorrection_residual_nonneg`), and in a column whose cutoff leaves at most `θ₂ f` +behind its entries are at most `θ₂ f` plus the truncation error +(`Matrix.cutoffCorrection_residual_le`). Since `x ^ k / k!` tends to zero, a number of iterations +depending only on `θ`, `L` and the target accuracy suffices (`Matrix.exists_factorial_bound_le`). + +## Main definitions + +* `Matrix.cutoffCorrection`: one step `F ↦ φ y ((C + F C) x y)` of the recursion. +* `Matrix.cutoffCorrectionIter`: its `k`-th iterate from zero. +* `Matrix.cutoffCorrectionFix`: its unique fixed point. + +## Main results + +* `Matrix.cutoffCorrection_fix`, `Matrix.eq_cutoffCorrectionFix`: existence and uniqueness of the + fixed point, for strictly upper triangular `C`. +* `Matrix.cutoffCorrectionIter_le_fix`: the iterates increase towards the fixed point. +* `Matrix.cutoffCorrectionFix_sub_iter_le`: **factorial truncation**, the bound + `E* - E k ≤ f e^(1 / θ) (L / θ)^k / k!`. +* `Matrix.cutoffCorrection_residual_nonneg`, `Matrix.cutoffCorrection_residual_le`: the corrected + matrix of a finite iterate is nonnegative, with small entries in fully corrected columns. +* `Matrix.exists_factorial_bound_le`: a uniform number of iterations reaches any accuracy. + +## References + +* [OpenAI, *Exact Derandomization of Logarithmic Space: L = RL = BPL*][OpenAI2026LogSpace], + Lemma 4.1 and Lemma 4.4 (preprint, not peer reviewed). The estimate is of Picard type: compare + the factorial bound for Picard iterates of Lipschitz ODEs. +-/ + +public section + +open Finset + +namespace Matrix + +variable {V R : Type*} [Fintype V] + +section Recursion + +variable [NonUnitalNonAssocSemiring R] + +/-- **One step of the cutoff correction recursion**: the matrix with entry +`φ y ((C + F C) x y)` at `(x, y)`. -/ +@[expose] def cutoffCorrection (φ : V → R → R) (C F : Matrix V V R) : Matrix V V R := + of fun x y => φ y ((C + F * C) x y) + +/-- The `k`-th iterate of `Matrix.cutoffCorrection φ C` from the zero matrix. -/ +@[expose] def cutoffCorrectionIter (φ : V → R → R) (C : Matrix V V R) (k : ℕ) : Matrix V V R := + (cutoffCorrection φ C)^[k] 0 + +/-- The *cutoff correction* of `C`: the iterate after `card V` steps, which is the unique fixed +point of `Matrix.cutoffCorrection φ C` when `C` is strictly upper triangular. -/ +@[expose] def cutoffCorrectionFix (φ : V → R → R) (C : Matrix V V R) : Matrix V V R := + cutoffCorrectionIter φ C (Fintype.card V) + +variable {φ : V → R → R} {C : Matrix V V R} + +theorem cutoffCorrectionIter_succ (k : ℕ) : + cutoffCorrectionIter φ C (k + 1) = cutoffCorrection φ C (cutoffCorrectionIter φ C k) := + Function.iterate_succ_apply' _ _ _ + +variable [LinearOrder V] + +/-- The entry `(x, y)` of a correction step depends only on the entries `(x, z)` with `z < y`. -/ +private theorem cutoffCorrection_congr (hC : C.IsStrictUpperTriangular) {F G : Matrix V V R} + {x y : V} (h : ∀ z < y, F x z = G x z) : + cutoffCorrection φ C F x y = cutoffCorrection φ C G x y := by + simp only [cutoffCorrection, of_apply, add_apply, mul_apply] + congr 2 + refine Finset.sum_congr rfl fun z _ => ?_ + by_cases hz : z < y + · rw [h z hz] + · rw [hC hz, mul_zero, mul_zero] + +private theorem card_filter_lt_lt {y z : V} (hzy : z < y) : + #{w | w < z} < #{w | w < y} := + Finset.card_lt_card <| Finset.ssubset_iff_of_subset + (fun w hw => by simp only [mem_filter, mem_univ, true_and] at hw ⊢; exact hw.trans hzy) + |>.mpr ⟨z, by simpa using hzy, by simp⟩ + +/-- The iterates are stationary at `(x, y)` from the `(#{z | z < y} + 1)`-th on. -/ +private theorem cutoffCorrectionIter_succ_apply (hC : C.IsStrictUpperTriangular) (k : ℕ) : + ∀ x y : V, #{z | z < y} < k → + cutoffCorrectionIter φ C (k + 1) x y = cutoffCorrectionIter φ C k x y := by + induction k with + | zero => intro x y h; exact absurd h (Nat.not_lt_zero _) + | succ k ih => + intro x y h + rw [cutoffCorrectionIter_succ (k := k + 1)] + conv_rhs => rw [cutoffCorrectionIter_succ] + exact cutoffCorrection_congr hC fun z hz => + ih x z ((card_filter_lt_lt hz).trans_le (Nat.lt_succ_iff.mp h)) + +/-- **Existence of the cutoff correction**: `Matrix.cutoffCorrectionFix φ C` is a fixed point of +the recursion when `C` is strictly upper triangular [OpenAI2026LogSpace, Lemma 4.1]. -/ +theorem cutoffCorrection_fix (hC : C.IsStrictUpperTriangular) : + cutoffCorrection φ C (cutoffCorrectionFix φ C) = cutoffCorrectionFix φ C := by + ext x y + rw [cutoffCorrectionFix, ← cutoffCorrectionIter_succ] + refine cutoffCorrectionIter_succ_apply hC _ x y (Finset.card_lt_card ?_) + exact Finset.ssubset_iff_of_subset (Finset.subset_univ _) |>.mpr ⟨y, mem_univ _, by simp⟩ + +/-- **Uniqueness of the cutoff correction**: every fixed point of the recursion is +`Matrix.cutoffCorrectionFix φ C` when `C` is strictly upper triangular +[OpenAI2026LogSpace, Lemma 4.1]. -/ +theorem eq_cutoffCorrectionFix (hC : C.IsStrictUpperTriangular) {F : Matrix V V R} + (hF : cutoffCorrection φ C F = F) : F = cutoffCorrectionFix φ C := by + ext x y + induction y using WellFoundedLT.induction with + | ind y ih => + rw [← hF, ← cutoffCorrection_fix hC] + exact cutoffCorrection_congr hC ih + +end Recursion + +section Bounds + +variable [LinearOrder V] {φ : V → ℝ → ℝ} {C : Matrix V V ℝ} {f θ L : ℝ} + +omit [Fintype V] in +/-- Counting increasing chains by rank: summing a nonnegative `g` of the rank within `S` over the +members of `S` below `y` is at most summing `g` over the ranks below the rank of `y`. -/ +private theorem sum_rank_le (S : Finset V) (y : V) {g : ℕ → ℝ} (hg : ∀ j, 0 ≤ g j) : + ∑ z ∈ S.filter (· < y), g #(S.filter (· < z)) ≤ + ∑ j ∈ range #(S.filter (· < y)), g j := by + have hlt : ∀ {a b : V}, a ∈ S → a < b → #(S.filter (· < a)) < #(S.filter (· < b)) := + fun {a b} ha hab => Finset.card_lt_card <| Finset.ssubset_iff_of_subset + (fun w hw => by simp only [mem_filter] at hw ⊢; exact ⟨hw.1, hw.2.trans hab⟩) + |>.mpr ⟨a, by simp [ha, hab], by simp⟩ + have hinj : Set.InjOn (fun z => #(S.filter (· < z))) (S.filter (· < y) : Set V) := by + intro a ha b hb hab + simp only [coe_filter, Set.mem_ofPred_eq] at ha hb + by_contra hne + rcases lt_or_gt_of_ne hne with h | h + · exact (hlt ha.1 h).ne hab + · exact (hlt hb.1 h).ne hab.symm + rw [← Finset.sum_image (f := g) hinj] + refine Finset.sum_le_sum_of_subset_of_nonneg (fun j hj => ?_) fun j _ _ => hg j + obtain ⟨z, hz, rfl⟩ := Finset.mem_image.mp hj + simp only [mem_filter] at hz + exact Finset.mem_range.mpr (hlt hz.1 hz.2) + +/-- The hockey-stick identity `∑ j < n, (j choose k) = n choose (k + 1)`. -/ +private theorem sum_range_choose_eq (n k : ℕ) : + ∑ j ∈ range n, (j.choose k : ℝ) = (n.choose (k + 1) : ℝ) := by + induction n with + | zero => simp + | succ n ih => rw [sum_range_succ, ih, Nat.choose_succ_succ', Nat.cast_add, add_comm] + +variable (hC : C.IsStrictUpperTriangular) (hC0 : ∀ x y, 0 ≤ C x y) (hCf : ∀ x y, C x y ≤ f) + (hC1 : C *ᵥ 1 ≤ 1) (hφ0 : ∀ y t, 0 ≤ φ y t) (hφθ : ∀ y t, φ y t ≤ max (t - θ * f) 0) + (hφm : ∀ y, Monotone (φ y)) (hφL : ∀ y s t, s ≤ t → φ y t - φ y s ≤ L * (t - s)) + +section Monotone + +omit [LinearOrder V] in +include hC0 hφm in +private theorem cutoffCorrection_mono {F G : Matrix V V ℝ} (hFG : ∀ x y, F x y ≤ G x y) + (x y : V) : cutoffCorrection φ C F x y ≤ cutoffCorrection φ C G x y := by + refine hφm y ?_ + simp only [add_apply, mul_apply] + exact add_le_add_right (Finset.sum_le_sum fun z _ => + mul_le_mul_of_nonneg_right (hFG x z) (hC0 z y)) _ + +omit [LinearOrder V] in +include hφ0 in +theorem cutoffCorrectionIter_nonneg (k : ℕ) (x y : V) : 0 ≤ cutoffCorrectionIter φ C k x y := by + cases k with + | zero => simp [cutoffCorrectionIter] + | succ k => rw [cutoffCorrectionIter_succ]; exact hφ0 _ _ + +omit [LinearOrder V] in +include hC0 hφ0 hφm in +/-- The iterates increase. -/ +theorem cutoffCorrectionIter_le_succ (k : ℕ) (x y : V) : + cutoffCorrectionIter φ C k x y ≤ cutoffCorrectionIter φ C (k + 1) x y := by + induction k generalizing x y with + | zero => exact cutoffCorrectionIter_nonneg hφ0 1 x y + | succ k ih => + rw [cutoffCorrectionIter_succ, cutoffCorrectionIter_succ (k := k + 1)] + exact cutoffCorrection_mono hC0 hφm ih x y + +include hC hC0 hφ0 hφm in +/-- **The iterates increase towards the fixed point** [OpenAI2026LogSpace, Lemma 4.1]. -/ +theorem cutoffCorrectionIter_le_fix (k : ℕ) (x y : V) : + cutoffCorrectionIter φ C k x y ≤ cutoffCorrectionFix φ C x y := by + induction k generalizing x y with + | zero => exact cutoffCorrectionIter_nonneg hφ0 _ x y + | succ k ih => + rw [cutoffCorrectionIter_succ, ← cutoffCorrection_fix hC] + exact cutoffCorrection_mono hC0 hφm ih x y + +end Monotone + +omit [LinearOrder V] in +/-- The input `(C + F C) x y` of a correction step is nonnegative. -/ +private theorem correctionInput_nonneg (hC0 : ∀ x y, 0 ≤ C x y) {F : Matrix V V ℝ} + (hF : ∀ x y, 0 ≤ F x y) (x y : V) : 0 ≤ (C + F * C) x y := + add_nonneg (hC0 x y) (Finset.sum_nonneg fun z _ => mul_nonneg (hF x z) (hC0 z y)) + +omit [Fintype V] [LinearOrder V] in +include hφθ in +/-- A cutoff never exceeds its nonnegative input. -/ +private theorem cutoff_le_self (hθf : 0 ≤ θ * f) (y : V) {t : ℝ} (ht : 0 ≤ t) : φ y t ≤ t := + (hφθ y t).trans (max_le (by linarith) ht) + +omit [Fintype V] [LinearOrder V] in +include hφθ in +/-- A positive cutoff leaves at least `θ f` behind. -/ +private theorem le_sub_cutoff_of_pos (y : V) {t : ℝ} (h : 0 < φ y t) : θ * f ≤ t - φ y t := by + have h1 := hφθ y t + have h2 : 0 < t - θ * f := by + by_contra hneg + rw [max_eq_right (by linarith)] at h1 + linarith + rw [max_eq_left h2.le] at h1 + linarith + +include hC in +private theorem fix_apply (x y : V) : + cutoffCorrectionFix φ C x y = φ y ((C + cutoffCorrectionFix φ C * C) x y) := by + conv_lhs => rw [← cutoffCorrection_fix hC] + rfl + +section Row + +variable (x : V) + +/-- The positive entries of row `x` of the fixed point. -/ +private noncomputable abbrev support : Finset V := {z | cutoffCorrectionFix φ C x z ≠ 0} + +include hC hC0 hC1 hφ0 hφθ in +/-- In each row, the fixed point has at most `1 / (θ f)` positive entries: each leaves a +residual at least `θ f`, and the residuals of a row sum to at most one. -/ +private theorem card_support_mul_le (hθf : 0 ≤ θ * f) : + (#(support (φ := φ) (C := C) x) : ℝ) * (θ * f) ≤ 1 := by + set E := cutoffCorrectionFix φ C + have hE0 : ∀ i j, 0 ≤ E i j := cutoffCorrectionIter_nonneg hφ0 _ + have hEfix : ∀ y, E x y = φ y ((C + E * C) x y) := fix_apply hC x + have hres : ∀ y, (C - E + E * C) x y = (C + E * C) x y - E x y := fun y => by + simp only [add_apply, sub_apply]; ring + have hres0 : ∀ y, 0 ≤ (C - E + E * C) x y := fun y => by + rw [hres, hEfix y, sub_nonneg] + exact cutoff_le_self hφθ hθf y (correctionInput_nonneg hC0 hE0 x y) + have hrow : ∑ y, (C - E + E * C) x y ≤ 1 := by + simpa [mulVec, dotProduct] using (correction_mulVec_one_le hE0 hC1 x).trans (hC1 x) + calc (#(support (φ := φ) (C := C) x) : ℝ) * (θ * f) + = ∑ y ∈ support (φ := φ) (C := C) x, θ * f := by rw [sum_const, nsmul_eq_mul] + _ ≤ ∑ y ∈ support (φ := φ) (C := C) x, (C - E + E * C) x y := by + refine Finset.sum_le_sum fun y hy => ?_ + have hpos : 0 < φ y ((C + E * C) x y) := by + rw [← hEfix y] + exact lt_of_le_of_ne (hE0 x y) (Ne.symm (by simpa using hy)) + rw [hres, hEfix y] + exact le_sub_cutoff_of_pos hφθ y hpos + _ ≤ ∑ y, (C - E + E * C) x y := + Finset.sum_le_sum_of_subset_of_nonneg (subset_univ _) fun y _ _ => hres0 y + _ ≤ 1 := hrow + +/-- A sum `∑ z, F x z * C z y` only sees the members of `support x` below `y`, when `F` vanishes +outside the support. -/ +private theorem sum_mul_eq_sum_support (hC : C.IsStrictUpperTriangular) {F : Matrix V V ℝ} + (hF : ∀ z, cutoffCorrectionFix φ C x z = 0 → F x z = 0) (y : V) : + ∑ z, F x z * C z y = ∑ z ∈ (support (φ := φ) (C := C) x).filter (· < y), F x z * C z y := by + refine (Finset.sum_subset (subset_univ _) fun z _ hz => ?_).symm + simp only [mem_filter, mem_univ, true_and, not_and_or, not_not] at hz + rcases hz with hz | hz + · rw [hF z hz, zero_mul] + · rw [hC hz, mul_zero] + +include hC hC0 hCf hφ0 hφθ in +/-- The entries of the fixed point grow at most geometrically along the support of a row. -/ +private theorem fix_le_pow (hf : 0 ≤ f) (hθf : 0 ≤ θ * f) (y : V) : + cutoffCorrectionFix φ C x y ≤ + f * (1 + f) ^ #((support (φ := φ) (C := C) x).filter (· < y)) := by + set E := cutoffCorrectionFix φ C + have hE0 : ∀ i j, 0 ≤ E i j := cutoffCorrectionIter_nonneg hφ0 _ + induction y using WellFoundedLT.induction with + | ind y ih => + set S := support (φ := φ) (C := C) x + have hEfix : E x y = φ y ((C + E * C) x y) := fix_apply hC x y + have hsum : ∑ z, E x z * C z y = ∑ z ∈ S.filter (· < y), E x z * C z y := + sum_mul_eq_sum_support x hC (fun _ h => h) y + calc E x y ≤ (C + E * C) x y := by + rw [hEfix]; exact cutoff_le_self hφθ hθf y (correctionInput_nonneg hC0 hE0 x y) + _ = C x y + ∑ z ∈ S.filter (· < y), E x z * C z y := by + rw [add_apply, mul_apply, hsum] + _ ≤ f + ∑ z ∈ S.filter (· < y), f * (1 + f) ^ #(S.filter (· < z)) * f := by + refine add_le_add (hCf x y) (Finset.sum_le_sum fun z hz => ?_) + exact mul_le_mul (ih z (mem_filter.mp hz).2) (hCf z y) (hC0 z y) (by positivity) + _ = f + f * f * ∑ z ∈ S.filter (· < y), (1 + f) ^ #(S.filter (· < z)) := by + rw [Finset.mul_sum]; congr 1; exact Finset.sum_congr rfl fun z _ => by ring + _ ≤ f + f * f * ∑ j ∈ range #(S.filter (· < y)), (1 + f) ^ j := by + gcongr + exact sum_rank_le S y fun j => by positivity + _ = f * (1 + f) ^ #(S.filter (· < y)) := by + have := geom_sum_mul_add f #(S.filter (· < y)) + rw [add_comm f 1] at this + linear_combination f * this + +include hC hC0 hCf hφ0 hφθ hφm hφL in +/-- The iteration error along a row is bounded by counting increasing chains in its support. -/ +private theorem fix_sub_iter_le_choose (hf : 0 ≤ f) (hθf : 0 ≤ θ * f) (hL : 0 ≤ L) (k : ℕ) + (y : V) : cutoffCorrectionFix φ C x y - cutoffCorrectionIter φ C k x y ≤ + f * (1 + f) ^ #(support (φ := φ) (C := C) x) * (L * f) ^ k * + (#((support (φ := φ) (C := C) x).filter (· < y))).choose k := by + set E := cutoffCorrectionFix φ C + set S := support (φ := φ) (C := C) x + have hE0 : ∀ i j, 0 ≤ E i j := cutoffCorrectionIter_nonneg hφ0 _ + have hM : ∀ y, E x y ≤ f * (1 + f) ^ #S := fun y => + (fix_le_pow hC hC0 hCf hφ0 hφθ x hf hθf y).trans <| mul_le_mul_of_nonneg_left + (pow_le_pow_right₀ (by linarith) (card_le_card (filter_subset _ _))) hf + induction k generalizing y with + | zero => + simpa using (sub_le_self _ (cutoffCorrectionIter_nonneg hφ0 0 x y)).trans (hM y) + | succ k ih => + set F := cutoffCorrectionIter φ C k + have hFE : ∀ z, F x z ≤ E x z := cutoffCorrectionIter_le_fix hC hC0 hφ0 hφm k x + have hEfix : E x y = φ y ((C + E * C) x y) := fix_apply hC x y + have hsum : ∑ z, (E - F) x z * C z y = ∑ z ∈ S.filter (· < y), (E - F) x z * C z y := + sum_mul_eq_sum_support x hC (fun z hz => by + change E x z = 0 at hz + rw [sub_apply, hz, sub_eq_zero] + exact le_antisymm (cutoffCorrectionIter_nonneg (C := C) hφ0 k x z) (hz ▸ hFE z)) y + have hdiff : (C + E * C) x y - (C + F * C) x y = ∑ z, (E - F) x z * C z y := by + simp only [add_apply, mul_apply, sub_apply, sub_mul, Finset.sum_sub_distrib]; ring + have hle : (C + F * C) x y ≤ (C + E * C) x y := by + rw [← sub_nonneg, hdiff] + exact Finset.sum_nonneg fun z _ => mul_nonneg (by rw [sub_apply, sub_nonneg]; exact hFE z) + (hC0 z y) + calc E x y - cutoffCorrectionIter φ C (k + 1) x y + = φ y ((C + E * C) x y) - φ y ((C + F * C) x y) := by + rw [hEfix, cutoffCorrectionIter_succ]; rfl + _ ≤ L * ∑ z ∈ S.filter (· < y), (E - F) x z * C z y := by + rw [← hsum, ← hdiff] + exact hφL y _ _ hle + _ ≤ L * ∑ z ∈ S.filter (· < y), + f * (1 + f) ^ #S * (L * f) ^ k * (#(S.filter (· < z))).choose k * f := by + refine mul_le_mul_of_nonneg_left (Finset.sum_le_sum fun z _ => ?_) hL + rw [sub_apply] + exact mul_le_mul (ih z) (hCf z y) (hC0 z y) (by positivity) + _ = f * (1 + f) ^ #S * (L * f) ^ (k + 1) * + ∑ z ∈ S.filter (· < y), ((#(S.filter (· < z))).choose k : ℝ) := by + rw [Finset.mul_sum, Finset.mul_sum] + exact Finset.sum_congr rfl fun z _ => by ring + _ ≤ f * (1 + f) ^ #S * (L * f) ^ (k + 1) * + ∑ j ∈ range #(S.filter (· < y)), (j.choose k : ℝ) := by + gcongr + exact sum_rank_le S y (g := fun j => (j.choose k : ℝ)) fun j => by positivity + _ = f * (1 + f) ^ #S * (L * f) ^ (k + 1) * (#(S.filter (· < y))).choose (k + 1) := by + rw [sum_range_choose_eq] + +end Row + +include hC hC0 hCf hC1 hφ0 hφθ hφm hφL in +/-- **Factorial truncation.** After `k` iterations of the cutoff correction recursion, every entry +is within `f e^(1 / θ) (L / θ)^k / k!` of the fixed point, uniformly in the size of `V` +[OpenAI2026LogSpace, Lemma 4.1]. -/ +theorem cutoffCorrectionFix_sub_iter_le (hf : 0 < f) (hθ : 0 < θ) (hL : 0 ≤ L) (k : ℕ) + (x y : V) : cutoffCorrectionFix φ C x y - cutoffCorrectionIter φ C k x y ≤ + f * Real.exp (1 / θ) * (L / θ) ^ k / k.factorial := by + have hθf : 0 ≤ θ * f := by positivity + set S := support (φ := φ) (C := C) x + set m := #S + have hm : (m : ℝ) * f ≤ 1 / θ := by + rw [le_div_iff₀ hθ] + nlinarith [card_support_mul_le hC hC0 hC1 hφ0 hφθ x hθf] + have hr : #(S.filter (· < y)) ≤ m := card_le_card (filter_subset _ _) + refine (fix_sub_iter_le_choose hC hC0 hCf hφ0 hφθ hφm hφL x hf.le hθf hL k y).trans ?_ + have hexp : (1 + f) ^ m ≤ Real.exp (1 / θ) := by + calc (1 + f) ^ m ≤ Real.exp f ^ m := by + gcongr; linarith [Real.add_one_le_exp f] + _ = Real.exp (m * f) := by rw [← Real.exp_nat_mul] + _ ≤ Real.exp (1 / θ) := Real.exp_le_exp.mpr hm + have hchoose : ((#(S.filter (· < y))).choose k : ℝ) ≤ (m : ℝ) ^ k / k.factorial := + (Nat.choose_le_pow_div k _).trans (by gcongr) + have hLf : (L * f) ^ k * ((m : ℝ) ^ k / k.factorial) ≤ (L / θ) ^ k / k.factorial := by + rw [← mul_div_assoc, ← mul_pow] + gcongr + calc L * f * m = L * (m * f) := by ring + _ ≤ L * (1 / θ) := by gcongr + _ = L / θ := by ring + calc f * (1 + f) ^ m * (L * f) ^ k * ((#(S.filter (· < y))).choose k : ℝ) + ≤ f * Real.exp (1 / θ) * ((L * f) ^ k * ((m : ℝ) ^ k / k.factorial)) := by + rw [mul_assoc (f * (1 + f) ^ m)] + gcongr + _ ≤ f * Real.exp (1 / θ) * ((L / θ) ^ k / k.factorial) := by gcongr + _ = f * Real.exp (1 / θ) * (L / θ) ^ k / k.factorial := by ring + +omit [LinearOrder V] in +include hC0 hφ0 hφθ hφm in +/-- **The corrected matrix of a finite iterate is nonnegative.** -/ +theorem cutoffCorrection_residual_nonneg (hθf : 0 ≤ θ * f) (k : ℕ) (x y : V) : + 0 ≤ (C - cutoffCorrectionIter φ C k + cutoffCorrectionIter φ C k * C) x y := by + cases k with + | zero => simpa [cutoffCorrectionIter] using hC0 x y + | succ k => + have hF0 := cutoffCorrectionIter_nonneg (C := C) hφ0 k + have hstep : cutoffCorrectionIter φ C (k + 1) x y = + φ y ((C + cutoffCorrectionIter φ C k * C) x y) := by + rw [cutoffCorrectionIter_succ]; rfl + have hcut := cutoff_le_self hφθ hθf y (correctionInput_nonneg hC0 hF0 x y) + have hgrow : (cutoffCorrectionIter φ C k * C) x y ≤ + (cutoffCorrectionIter φ C (k + 1) * C) x y := + Finset.sum_le_sum fun z _ => mul_le_mul_of_nonneg_right + (cutoffCorrectionIter_le_succ hC0 hφ0 hφm k x z) (hC0 z y) + rw [← hstep, add_apply] at hcut + rw [add_apply, sub_apply] + linarith + +include hC hC0 hCf hC1 hφ0 hφθ hφm hφL in +/-- **Fully corrected columns have small residuals.** If the cutoff of column `y` leaves at most +`θ₂ f` behind, the corrected matrix of the `k`-th iterate has entries at most +`θ₂ f + f e^(1 / θ) (L / θ)^k / k!` in that column [OpenAI2026LogSpace, Lemma 4.4]. -/ +theorem cutoffCorrection_residual_le (hf : 0 < f) (hθ : 0 < θ) (hL : 0 ≤ L) {θ₂ : ℝ} {y : V} + (hgood : ∀ t, t - θ₂ * f ≤ φ y t) (k : ℕ) (x : V) : + (C - cutoffCorrectionIter φ C k + cutoffCorrectionIter φ C k * C) x y ≤ + θ₂ * f + f * Real.exp (1 / θ) * (L / θ) ^ k / k.factorial := by + set E := cutoffCorrectionFix φ C + set F := cutoffCorrectionIter φ C k + have hEfix : E x y = φ y ((C + E * C) x y) := fix_apply hC x y + have hΔ := cutoffCorrectionFix_sub_iter_le hC hC0 hCf hC1 hφ0 hφθ hφm hφL hf hθ hL k x y + have hΔC : (F * C) x y ≤ (E * C) x y := + Finset.sum_le_sum fun z _ => mul_le_mul_of_nonneg_right + (cutoffCorrectionIter_le_fix hC hC0 hφ0 hφm k x z) (hC0 z y) + have hT := hgood ((C + E * C) x y) + rw [← hEfix] at hT + simp only [add_apply, sub_apply] at hT hΔC ⊢ + linarith + +/-- **A constant number of iterations suffices**: for every accuracy `δ > 0` there is `k`, depending +only on `θ`, `L` and `δ`, with `e^(1 / θ) (L / θ)^k / k! ≤ δ` [OpenAI2026LogSpace, Lemma 4.1]. -/ +theorem exists_factorial_bound_le (θ L : ℝ) {δ : ℝ} (hδ : 0 < δ) : + ∃ k : ℕ, Real.exp (1 / θ) * (L / θ) ^ k / k.factorial ≤ δ := by + have h := (FloorSemiring.tendsto_pow_div_factorial_atTop (L / θ)).const_mul + (Real.exp (1 / θ)) + rw [mul_zero] at h + obtain ⟨k, hk⟩ := (h.eventually (gt_mem_nhds hδ)).exists + exact ⟨k, by rw [mul_div_assoc]; exact hk.le⟩ + +end Bounds + +end Matrix diff --git a/ComplexityTests/FactorialTruncation.lean b/ComplexityTests/FactorialTruncation.lean new file mode 100644 index 000000000..1a9743119 --- /dev/null +++ b/ComplexityTests/FactorialTruncation.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.LinearAlgebra.Matrix.FactorialTruncation + +/-! +# Tests for factorial truncation of cutoff corrections +-/ + +namespace ComplexityTests.FactorialTruncation + +open Matrix + +/-- A walk on three time layers: from `0` to `1` and from `1` to `2`, each with probability +`1 / 2`. Its entries are at most `f = 1 / 2`. -/ +private noncomputable def C : Matrix (Fin 3) (Fin 3) ℝ := !![0, 1 / 2, 0; 0, 0, 1 / 2; 0, 0, 0] + +/-- The hard cutoff `t ↦ max (t - θ f) 0` with `θ = 1 / 4`, `f = 1 / 2`: it leaves exactly `1 / 8` +behind. It is monotone and `1`-Lipschitz. -/ +private noncomputable def φ : Fin 3 → ℝ → ℝ := fun _ t => max (t - 1 / 8) 0 + +private theorem hC : C.IsStrictUpperTriangular := by + intro i j h; fin_cases i <;> fin_cases j <;> simp_all [C] + +private theorem hC0 : ∀ x y, 0 ≤ C x y := by + intro x y; fin_cases x <;> fin_cases y <;> norm_num [C] + +private theorem hCf : ∀ x y, C x y ≤ 1 / 2 := by + intro x y; fin_cases x <;> fin_cases y <;> norm_num [C] + +private theorem hC1 : C *ᵥ 1 ≤ 1 := by + intro x; fin_cases x <;> norm_num [C, mulVec, dotProduct, Fin.sum_univ_three] + +private theorem hφ0 : ∀ y t, 0 ≤ φ y t := fun _ _ => le_max_right _ _ + +private theorem hφθ : ∀ y t, φ y t ≤ max (t - 1 / 4 * (1 / 2)) 0 := fun _ t => by + norm_num [φ] + +private theorem hφm : ∀ y, Monotone (φ y) := fun _ _ _ h => max_le_max (by linarith) le_rfl + +private theorem hφL : ∀ y s t, s ≤ t → φ y t - φ y s ≤ 1 * (t - s) := fun _ s t _ => by + simp only [φ, one_mul] + have := le_max_left (s - 1 / 8) 0 + have := le_max_right (s - 1 / 8) 0 + have : max (t - 1 / 8) 0 ≤ max (s - 1 / 8) 0 + (t - s) := max_le (by linarith) (by linarith) + linarith + +/-- The cutoff correction of `C`, computed by hand: `φ (1 / 2) = 3 / 8` on both transitions, +and `φ (3 / 8 * 1 / 2) = 1 / 16` on the corrected two-step entry. -/ +private noncomputable def Estar : Matrix (Fin 3) (Fin 3) ℝ := + !![0, 3 / 8, 1 / 16; 0, 0, 3 / 8; 0, 0, 0] + +-- `Estar` solves the recursion, so it is the cutoff correction. +private theorem Estar_eq : Estar = cutoffCorrectionFix φ C := by + refine eq_cutoffCorrectionFix hC ?_ + ext x y + fin_cases x <;> fin_cases y <;> + norm_num [cutoffCorrection, φ, C, Estar, mul_apply, Fin.sum_univ_three] + +-- One iteration from zero misses the two-step entry entirely. +example : cutoffCorrectionIter φ C 1 0 2 = 0 := by + norm_num [cutoffCorrectionIter, cutoffCorrection, φ, C] + +-- The truncation error after one iteration, `1 / 16`, is within the factorial bound. +example : cutoffCorrectionFix φ C 0 2 - cutoffCorrectionIter φ C 1 0 2 ≤ + 1 / 2 * Real.exp (1 / (1 / 4)) * (1 / (1 / 4)) ^ 1 / (Nat.factorial 1) := + cutoffCorrectionFix_sub_iter_le hC hC0 hCf hC1 hφ0 hφθ hφm hφL (by norm_num) (by norm_num) + (by norm_num) 1 0 2 + +-- After two iterations the iterate has reached the fixed point at `(0, 2)`. +example : cutoffCorrectionIter φ C 2 0 2 = cutoffCorrectionFix φ C 0 2 := by + rw [← Estar_eq] + norm_num [cutoffCorrectionIter, cutoffCorrection, φ, C, Estar, mul_apply, Fin.sum_univ_three] + +-- The corrected matrix of every iterate is nonnegative, and the hard cutoff leaves at most +-- `θ f = 1 / 8` behind in every column. +example (k : ℕ) (x y : Fin 3) : + 0 ≤ (C - cutoffCorrectionIter φ C k + cutoffCorrectionIter φ C k * C) x y := + cutoffCorrection_residual_nonneg hC0 hφ0 hφθ hφm (by norm_num) k x y + +example (k : ℕ) (x y : Fin 3) : + (C - cutoffCorrectionIter φ C k + cutoffCorrectionIter φ C k * C) x y ≤ + 1 / 4 * (1 / 2) + 1 / 2 * Real.exp (1 / (1 / 4)) * (1 / (1 / 4)) ^ k / k.factorial := + cutoffCorrection_residual_le hC hC0 hCf hC1 hφ0 hφθ hφm hφL (by norm_num) (by norm_num) + (by norm_num) (fun t => by norm_num [φ]) k x + +-- A fixed number of iterations gets within `1 / 100` of the factorial bound's limit. +example : ∃ k : ℕ, Real.exp (1 / (1 / 4)) * (1 / (1 / 4)) ^ k / k.factorial ≤ 1 / 100 := + exists_factorial_bound_le _ _ (by norm_num) + +end ComplexityTests.FactorialTruncation From 6e0388d538b591a63b9a59ef5a4337638b31242e Mon Sep 17 00:00:00 2001 From: Christian Reitwiessner Date: Thu, 29 Oct 2026 23:17:18 +0000 Subject: [PATCH 10/25] refactor(Foundations): use Nat.sum_Icc_choose for the hockey-stick step Review nit on #1677: drop the private hockey-stick lemma. Co-Authored-By: Claude Opus 5.5 --- .../Matrix/FactorialTruncation.lean | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/Complexity/Foundations/LinearAlgebra/Matrix/FactorialTruncation.lean b/Complexity/Foundations/LinearAlgebra/Matrix/FactorialTruncation.lean index ad9fe5b9c..d9e81c1ed 100644 --- a/Complexity/Foundations/LinearAlgebra/Matrix/FactorialTruncation.lean +++ b/Complexity/Foundations/LinearAlgebra/Matrix/FactorialTruncation.lean @@ -180,13 +180,6 @@ private theorem sum_rank_le (S : Finset V) (y : V) {g : ℕ → ℝ} (hg : ∀ j simp only [mem_filter] at hz exact Finset.mem_range.mpr (hlt hz.1 hz.2) -/-- The hockey-stick identity `∑ j < n, (j choose k) = n choose (k + 1)`. -/ -private theorem sum_range_choose_eq (n k : ℕ) : - ∑ j ∈ range n, (j.choose k : ℝ) = (n.choose (k + 1) : ℝ) := by - induction n with - | zero => simp - | succ n ih => rw [sum_range_succ, ih, Nat.choose_succ_succ', Nat.cast_add, add_comm] - variable (hC : C.IsStrictUpperTriangular) (hC0 : ∀ x y, 0 ≤ C x y) (hCf : ∀ x y, C x y ≤ f) (hC1 : C *ᵥ 1 ≤ 1) (hφ0 : ∀ y t, 0 ≤ φ y t) (hφθ : ∀ y t, φ y t ≤ max (t - θ * f) 0) (hφm : ∀ y, Monotone (φ y)) (hφL : ∀ y s t, s ≤ t → φ y t - φ y s ≤ L * (t - s)) @@ -388,7 +381,15 @@ private theorem fix_sub_iter_le_choose (hf : 0 ≤ f) (hθf : 0 ≤ θ * f) (hL gcongr exact sum_rank_le S y (g := fun j => (j.choose k : ℝ)) fun j => by positivity _ = f * (1 + f) ^ #S * (L * f) ^ (k + 1) * (#(S.filter (· < y))).choose (k + 1) := by - rw [sum_range_choose_eq] + -- the hockey-stick identity `∑ j ∈ Icc k n, j.choose k = (n + 1).choose (k + 1)` + congr 1 + rcases hn : #(S.filter (· < y)) with _ | n + · simp + · rw [← Nat.sum_Icc_choose, Nat.cast_sum] + refine (Finset.sum_subset (fun j hj => ?_) fun j hj hjn => ?_).symm + · simp only [mem_Icc, mem_range] at hj ⊢; omega + · simp only [mem_Icc, mem_range, not_and_or, not_le] at hj hjn + rw [Nat.choose_eq_zero_of_lt (by omega), Nat.cast_zero] end Row From 8b3f5725d8ca58892463e9848898ea86e29fdc2a Mon Sep 17 00:00:00 2001 From: Christian Reitwiessner Date: Thu, 29 Oct 2026 23:26:24 +0000 Subject: [PATCH 11/25] doc(Foundations): count chains with the integer support size Review of #1677: the module docstring now bounds the chain count by m.choose k for the actual support size m, as the proof does. Co-Authored-By: Claude Opus 5.5 --- .../LinearAlgebra/Matrix/FactorialTruncation.lean | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Complexity/Foundations/LinearAlgebra/Matrix/FactorialTruncation.lean b/Complexity/Foundations/LinearAlgebra/Matrix/FactorialTruncation.lean index d9e81c1ed..f94a429ae 100644 --- a/Complexity/Foundations/LinearAlgebra/Matrix/FactorialTruncation.lean +++ b/Complexity/Foundations/LinearAlgebra/Matrix/FactorialTruncation.lean @@ -32,10 +32,10 @@ iterations every entry is within `f e^(1 / θ) (L / θ)^k / k!` of the fixed poi (`Matrix.cutoffCorrectionFix_sub_iter_le`). The proof counts chains. In a fixed row, every positive entry of the fixed point leaves a residual -at least `θ f`, and the residuals of a row sum to at most one, so the row has at most `1 / (θ f)` -positive entries. Unrolling the recursion `k` times along that row expresses the error as a sum -over increasing chains of `k` of these entries, each weighted by at most `(L f)^k`; there are at -most `binomial (1 / (θ f), k) ≤ (θ f)^(-k) / k!` of them. +at least `θ f`, and the residuals of a row sum to at most one, so the number `m` of positive +entries in the row satisfies `m θ f ≤ 1`. Unrolling the recursion `k` times along that row +expresses the error as a sum over increasing chains of `k` of these entries, each weighted by at +most `(L f)^k`; there are at most `m.choose k ≤ m^k / k! ≤ (θ f)^(-k) / k!` of them. For the finite correction `E = E k`, the corrected matrix `C - E + E C` is nonnegative (`Matrix.cutoffCorrection_residual_nonneg`), and in a column whose cutoff leaves at most `θ₂ f` From 14714b9a71fd012a55ca5605a15655c7830736a0 Mon Sep 17 00:00:00 2001 From: Christian Reitwiessner Date: Thu, 29 Oct 2026 23:27:56 +0000 Subject: [PATCH 12/25] 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 7fd99bc4ccd4c39d1421d17fe606d092133b5074 Mon Sep 17 00:00:00 2001 From: Christian Reitwiessner Date: Thu, 29 Oct 2026 23:25:02 +0000 Subject: [PATCH 13/25] feat(Foundations): one stage of the correction-and-copy hierarchy Third slice of #1679 (Phase 2 of #1444, ideas 3 and 4 of #474), following the OpenAI preprint (2026-09-23), Lemma 4.2, Lemma 4.4 and Proposition 4.5: row-sum, entry, domination and support bounds for cutoff corrections; the copy step with explicit split fractions, its density and active-copy bounds; incidence counting; and the one-stage rates that feed the stage bound, given an abstract detector interface. Co-Authored-By: Claude Opus 5.5 --- Complexity.lean | 1 + .../LinearAlgebra/Matrix/CopyStage.lean | 533 ++++++++++++++++++ ComplexityTests/CopyStage.lean | 137 +++++ 3 files changed, 671 insertions(+) create mode 100644 Complexity/Foundations/LinearAlgebra/Matrix/CopyStage.lean create mode 100644 ComplexityTests/CopyStage.lean diff --git a/Complexity.lean b/Complexity.lean index b1c2b3181..2a5c4feb0 100644 --- a/Complexity.lean +++ b/Complexity.lean @@ -2620,6 +2620,7 @@ public import Complexity.Foundations.LinearAlgebra.ExchangeReplacement public import Complexity.Foundations.LinearAlgebra.ImageSparsification public import Complexity.Foundations.LinearAlgebra.Interpolation public import Complexity.Foundations.LinearAlgebra.KernelVector +public import Complexity.Foundations.LinearAlgebra.Matrix.CopyStage public import Complexity.Foundations.LinearAlgebra.Matrix.CorrectionHierarchy public import Complexity.Foundations.LinearAlgebra.Matrix.CutRank public import Complexity.Foundations.LinearAlgebra.Matrix.FactorialTruncation diff --git a/Complexity/Foundations/LinearAlgebra/Matrix/CopyStage.lean b/Complexity/Foundations/LinearAlgebra/Matrix/CopyStage.lean new file mode 100644 index 000000000..4fd044ed2 --- /dev/null +++ b/Complexity/Foundations/LinearAlgebra/Matrix/CopyStage.lean @@ -0,0 +1,533 @@ +/- +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.LinearAlgebra.Matrix.FactorialTruncation +import Mathlib.Algebra.BigOperators.Fin + +/-! +# One stage of the correction-and-copy hierarchy + +One stage of the hierarchy of the OpenAI preprint (2026-09-23), Section 4, ideas 3 and 4 in issue +#474 [OpenAI2026LogSpace], takes a transition matrix `C` with entries at most `f`, corrects it to +`D = C - E + E C` with a finite cutoff correction `E` (`Matrix.cutoffCorrectionIter`), and splits +the remaining large entries of `D` among copies of their targets (`Matrix.copyStage`). This file +proves the deterministic bounds of such a stage. The result `C⁺` has entries at most `f / q`, and +its support lies in a set at most twice as large as the support of `C` +(`Matrix.copyStage_rates`). These are exactly the per-stage hypotheses of the stage bound +`Matrix.sub_rewardTransport_mulVec_le_pow`; `Matrix.sub_rewardTransport_mulVec_le_of_rates` +iterates them. + +The choice of which columns are corrected and which vertices get active copies comes from the +preprint's *detectors*, which are probabilistic. Here it is an interface: copy weights `r` with +`r 0 = 1`, and a finite set `O` of *overloaded* vertices, such that + +* only overloaded vertices have active extra copies: `r j x ≠ 0 → x ∈ O` for `j ≠ 0`; +* every column is either *fully corrected*, `t - θ₂ f ≤ φ y t` for all `t`, or overloaded with all + its copies active; +* `m |O| ≤ |A|`, where `m + 1` is the number of copies and `A` covers the support of `C`. + +The last condition follows from incidence counting (`Matrix.card_mul_le_of_incidences`): if every +overloaded column has many large entries in one of a few substochastic matrices, as the detectors +guarantee for the pilot inputs, then there are few overloaded columns. + +The corrected matrix also satisfies the remaining bounds of Lemma 4.4 of the preprint. Its entries +are at most `(k + 1) f` (`Matrix.cutoffCorrection_residual_le_mul`). It dominates its unsigned +constituents, `θ / (2 (k + 1)) (C + E + E C) ≤ D` (`Matrix.cutoffCorrection_residual_dominates`), +which lets the three terms of `D` be estimated separately. Its support stays within that of `C` +(`Matrix.cutoffCorrection_residual_mem`). + +## Main definitions + +* `Matrix.copyFraction`: the proportions in which an entry is split among `m + 1` copies. +* `Matrix.copyStage`: the copy step `Matrix.copySplit` with these proportions. +* `Matrix.copyCover`: the copies that can be active, given a cover of the parents. + +## Main results + +* `Matrix.cutoffCorrectionIter_sum_le`, `Matrix.cutoffCorrectionIter_le_mul`: row sums and + entries of the iterates. +* `Matrix.cutoffCorrection_residual_le_mul`, `Matrix.cutoffCorrection_residual_dominates`, + `Matrix.cutoffCorrection_residual_mem`: entry bound, domination and support of the residual. +* `Matrix.copyStage_mul_copyWeight`, `Matrix.copyStage_nonneg`, `Matrix.copyStage_mulVec_one_le`, + `Matrix.copyStage_le`, `Matrix.copyStage_mem_copyCover`, `Matrix.card_copyCover_le`: the copy + step intertwines with its projection, is substochastic, has small entries and few active + copies. +* `Matrix.card_mul_le_of_incidences`: incidence counting. +* `Matrix.copyStage_rates`: the one-stage density and active-count bounds. +* `Matrix.sub_rewardTransport_mulVec_le_of_rates`: the stage bound from per-stage rates. + +## References + +* [OpenAI, *Exact Derandomization of Logarithmic Space: L = RL = BPL*][OpenAI2026LogSpace], + Lemma 4.2, Lemma 4.4, Proposition 4.5 and Proposition 4.7 (preprint, not peer reviewed) +-/ + +public section + +open Finset + +namespace Matrix + +/-! ### Residual bounds for cutoff corrections -/ + +section Residual + +variable {V : Type*} [Fintype V] {φ : V → ℝ → ℝ} {C : Matrix V V ℝ} {f θ : ℝ} + +variable (hC0 : ∀ x y, 0 ≤ C x y) (hφ0 : ∀ y t, 0 ≤ φ y t) + (hφθ : ∀ y t, φ y t ≤ max (t - θ * f) 0) (hθf : 0 ≤ θ * f) + +omit [Fintype V] in +include hφθ hθf in +private theorem cutoff_le_self' (y : V) {t : ℝ} (ht : 0 ≤ t) : φ y t ≤ t := + (hφθ y t).trans (max_le (by linarith) ht) + +omit [Fintype V] in +include hφ0 hφθ hθf in +private theorem cutoff_zero (y : V) : φ y 0 = 0 := + le_antisymm ((hφθ y 0).trans (max_le (by linarith) le_rfl)) (hφ0 y 0) + +include hC0 hφ0 hφθ hθf in +private theorem iter_succ_le_input (k : ℕ) (x y : V) : + cutoffCorrectionIter φ C (k + 1) x y ≤ (C + cutoffCorrectionIter φ C k * C) x y := by + rw [cutoffCorrectionIter_succ] + exact cutoff_le_self' hφθ hθf y <| add_nonneg (hC0 x y) <| Finset.sum_nonneg fun z _ => + mul_nonneg (cutoffCorrectionIter_nonneg hφ0 k x z) (hC0 z y) + +include hC0 hφ0 hφθ hθf in +/-- **Row sums of the iterates**: the `k`-th iterate of a cutoff correction of a substochastic +`C` has row sums at most `k` [OpenAI2026LogSpace, Lemma 4.2]. -/ +theorem cutoffCorrectionIter_sum_le (hC1 : C *ᵥ 1 ≤ 1) (k : ℕ) (x : V) : + ∑ y, cutoffCorrectionIter φ C k x y ≤ k := by + have hrow : ∀ z, ∑ y, C z y ≤ 1 := fun z => by simpa [mulVec, dotProduct] using hC1 z + induction k with + | zero => simp [cutoffCorrectionIter] + | succ k ih => + set F := cutoffCorrectionIter φ C k + calc ∑ y, cutoffCorrectionIter φ C (k + 1) x y ≤ ∑ y, (C + F * C) x y := + Finset.sum_le_sum fun y _ => iter_succ_le_input hC0 hφ0 hφθ hθf k x y + _ = ∑ y, C x y + ∑ z, F x z * ∑ y, C z y := by + simp only [add_apply, mul_apply, Finset.sum_add_distrib, Finset.mul_sum] + rw [Finset.sum_comm] + _ ≤ 1 + ∑ z, F x z * 1 := add_le_add (hrow x) (Finset.sum_le_sum fun z _ => + mul_le_mul_of_nonneg_left (hrow z) (cutoffCorrectionIter_nonneg hφ0 k x z)) + _ ≤ (k + 1 : ℕ) := by simp only [mul_one]; push_cast; linarith + +include hC0 hφ0 hφθ hθf in +/-- The input `(C + E_k C) x y` of the `(k + 1)`-th step is at most `(k + 1) f`. -/ +private theorem input_le (hCf : ∀ x y, C x y ≤ f) (hf : 0 ≤ f) (hC1 : C *ᵥ 1 ≤ 1) (k : ℕ) + (x y : V) : (C + cutoffCorrectionIter φ C k * C) x y ≤ (k + 1) * f := by + have hsum := cutoffCorrectionIter_sum_le hC0 hφ0 hφθ hθf hC1 k x + calc (C + cutoffCorrectionIter φ C k * C) x y + = C x y + ∑ z, cutoffCorrectionIter φ C k x z * C z y := rfl + _ ≤ f + ∑ z, cutoffCorrectionIter φ C k x z * f := add_le_add (hCf x y) + (Finset.sum_le_sum fun z _ => + mul_le_mul_of_nonneg_left (hCf z y) (cutoffCorrectionIter_nonneg hφ0 k x z)) + _ ≤ (k + 1) * f := by rw [← Finset.sum_mul]; nlinarith + +include hC0 hφ0 hφθ hθf in +/-- **Entries of the iterates**: the `k`-th iterate has entries at most `k f` +[OpenAI2026LogSpace, Lemma 4.2]. -/ +theorem cutoffCorrectionIter_le_mul (hCf : ∀ x y, C x y ≤ f) (hf : 0 ≤ f) (hC1 : C *ᵥ 1 ≤ 1) + (k : ℕ) (x y : V) : cutoffCorrectionIter φ C k x y ≤ k * f := by + cases k with + | zero => simp [cutoffCorrectionIter] + | succ k => + push_cast + exact (iter_succ_le_input hC0 hφ0 hφθ hθf k x y).trans + (input_le hC0 hφ0 hφθ hθf hCf hf hC1 k x y) + +include hC0 hφ0 hφθ hθf in +/-- **The residual entry bound**: `C - E_k + E_k C` has entries at most `(k + 1) f` +[OpenAI2026LogSpace, Lemma 4.4]. -/ +theorem cutoffCorrection_residual_le_mul (hCf : ∀ x y, C x y ≤ f) (hf : 0 ≤ f) + (hC1 : C *ᵥ 1 ≤ 1) (k : ℕ) (x y : V) : + (C - cutoffCorrectionIter φ C k + cutoffCorrectionIter φ C k * C) x y ≤ (k + 1) * f := by + have h := input_le hC0 hφ0 hφθ hθf hCf hf hC1 k x y + have h0 := cutoffCorrectionIter_nonneg (C := C) hφ0 k x y + simp only [add_apply, sub_apply] at h ⊢ + linarith + +include hC0 hφ0 hφθ hθf in +/-- **Domination of the unsigned terms**: for `θ ≤ 1`, the residual of the `(k + 1)`-th iterate +dominates a fixed multiple of the sum of its unsigned constituents, +`θ / (2 (k + 1)) (C + E + E C) ≤ C - E + E C` [OpenAI2026LogSpace, Lemma 4.4]. -/ +theorem cutoffCorrection_residual_dominates (hCf : ∀ x y, C x y ≤ f) (hf : 0 ≤ f) + (hC1 : C *ᵥ 1 ≤ 1) (hφm : ∀ y, Monotone (φ y)) (hθ0 : 0 ≤ θ) (hθ1 : θ ≤ 1) (k : ℕ) + (x y : V) : + θ / (2 * (k + 1)) * (C + cutoffCorrectionIter φ C (k + 1) + + cutoffCorrectionIter φ C (k + 1) * C) x y ≤ + (C - cutoffCorrectionIter φ C (k + 1) + cutoffCorrectionIter φ C (k + 1) * C) x y := by + have hk : (0 : ℝ) < k + 1 := by positivity + have ha0 : 0 ≤ (C + cutoffCorrectionIter φ C k * C) x y := + add_nonneg (hC0 x y) (Finset.sum_nonneg fun z _ => + mul_nonneg (cutoffCorrectionIter_nonneg hφ0 k x z) (hC0 z y)) + have ha := input_le hC0 hφ0 hφθ hθf hCf hf hC1 k x y + have hEa : cutoffCorrectionIter φ C (k + 1) x y = + φ y ((C + cutoffCorrectionIter φ C k * C) x y) := by + rw [cutoffCorrectionIter_succ]; rfl + have he0 := cutoffCorrectionIter_nonneg (C := C) hφ0 (k + 1) x y + have hea := iter_succ_le_input hC0 hφ0 hφθ hθf k x y + have hFE : (cutoffCorrectionIter φ C k * C) x y ≤ (cutoffCorrectionIter φ C (k + 1) * C) x y := + Finset.sum_le_sum fun z _ => + mul_le_mul_of_nonneg_right (cutoffCorrectionIter_le_succ hC0 hφ0 hφm k x z) (hC0 z y) + have hθa := hφθ y ((C + cutoffCorrectionIter φ C k * C) x y) + rw [← hEa] at hθa + set F := cutoffCorrectionIter φ C k + set E := cutoffCorrectionIter φ C (k + 1) + set a := (C + F * C) x y + set t := θ / (k + 1) + have ht0 : 0 ≤ t := by positivity + have ht1 : t ≤ 1 := by rw [div_le_one hk]; linarith + have hmin : t * a ≤ a - E x y := by + rcases le_or_gt 0 (a - θ * f) with h | h + · have he : E x y ≤ a - θ * f := by rw [max_eq_left h] at hθa; exact hθa + have : t * a ≤ θ * f := by + calc t * a ≤ t * ((k + 1) * f) := mul_le_mul_of_nonneg_left ha ht0 + _ = θ * f := by simp only [t]; field_simp + linarith + · have he : E x y ≤ 0 := by rw [max_eq_right h.le] at hθa; exact hθa + nlinarith + have hcoef : θ / (2 * (k + 1)) = t / 2 := by simp only [t]; field_simp + have h1 : t / 2 * E x y ≤ t / 2 * a := mul_le_mul_of_nonneg_left hea (by positivity) + have h2 : t / 2 * ((E * C) x y - (F * C) x y) ≤ (E * C) x y - (F * C) x y := + mul_le_of_le_one_left (by linarith) (by linarith) + have hadef : a = C x y + (F * C) x y := rfl + rw [hcoef] + simp only [add_apply, sub_apply] + nlinarith + +variable {A : Finset V} + +include hφ0 hφθ hθf in +/-- The iterates are supported within any set `A` covering the support of `C`. -/ +theorem cutoffCorrectionIter_mem (hA : ∀ x y, C x y ≠ 0 → x ∈ A ∧ y ∈ A) (k : ℕ) (x y : V) + (h : cutoffCorrectionIter φ C k x y ≠ 0) : x ∈ A ∧ y ∈ A := by + induction k generalizing x y with + | zero => simp [cutoffCorrectionIter] at h + | succ k ih => + by_contra hxy + apply h + have hCxy : C x y = 0 := by + by_contra h'; exact hxy (hA x y h') + have hin : (C + cutoffCorrectionIter φ C k * C) x y = 0 := by + simp only [add_apply, mul_apply, hCxy, zero_add] + refine Finset.sum_eq_zero fun z _ => ?_ + by_cases hE : cutoffCorrectionIter φ C k x z = 0 + · rw [hE, zero_mul] + by_cases hCz : C z y = 0 + · rw [hCz, mul_zero] + exact absurd ⟨(ih x z hE).1, (hA z y hCz).2⟩ hxy + rw [cutoffCorrectionIter_succ] + change φ y ((C + cutoffCorrectionIter φ C k * C) x y) = 0 + rw [hin, cutoff_zero hφ0 hφθ hθf] + +include hφ0 hφθ hθf in +/-- **The residual stays within the support of `C`** [OpenAI2026LogSpace, Lemma 4.4]. -/ +theorem cutoffCorrection_residual_mem (hA : ∀ x y, C x y ≠ 0 → x ∈ A ∧ y ∈ A) (k : ℕ) + (x y : V) + (h : (C - cutoffCorrectionIter φ C k + cutoffCorrectionIter φ C k * C) x y ≠ 0) : + x ∈ A ∧ y ∈ A := by + by_contra hxy + apply h + have hE : ∀ u v, cutoffCorrectionIter φ C k u v ≠ 0 → u ∈ A ∧ v ∈ A := + cutoffCorrectionIter_mem hφ0 hφθ hθf hA k + have hCxy : C x y = 0 := by by_contra h'; exact hxy (hA x y h') + have hExy : cutoffCorrectionIter φ C k x y = 0 := by by_contra h'; exact hxy (hE x y h') + simp only [add_apply, sub_apply, mul_apply, hCxy, hExy, sub_zero, zero_add] + refine Finset.sum_eq_zero fun z _ => ?_ + by_cases hEz : cutoffCorrectionIter φ C k x z = 0 + · rw [hEz, zero_mul] + by_cases hCz : C z y = 0 + · rw [hCz, mul_zero] + exact absurd ⟨(hE x z hEz).1, (hA z y hCz).2⟩ hxy + +end Residual + +/-! ### Copy fractions -/ + +section Fraction + +/-- **Copy fractions** for `m + 1` copies, driven by a cutoff `χ` with values in `[0, 1]`: the +primary copy `0` receives `1 - m / (m + 1) χ t`, every other copy `χ t / (m + 1)`. Small entries +(`χ t = 0`) stay with the primary copy; large ones (`χ t = 1`) are split evenly +[OpenAI2026LogSpace, (4.21)]. -/ +@[expose] noncomputable def copyFraction (χ : ℝ → ℝ) (m : ℕ) (t : ℝ) (j : Fin (m + 1)) : ℝ := + if j = 0 then 1 - m / (m + 1) * χ t else χ t / (m + 1) + +variable {χ : ℝ → ℝ} {m : ℕ} {t : ℝ} + +theorem sum_copyFraction (χ : ℝ → ℝ) (m : ℕ) (t : ℝ) : ∑ j, copyFraction χ m t j = 1 := by + rw [Fin.sum_univ_succ] + simp only [copyFraction, Fin.succ_ne_zero, ↓reduceIte, Finset.sum_const, card_univ, + Fintype.card_fin, nsmul_eq_mul] + field_simp + ring + +theorem copyFraction_nonneg (h0 : 0 ≤ χ t) (h1 : χ t ≤ 1) (j : Fin (m + 1)) : + 0 ≤ copyFraction χ m t j := by + have hm : (m : ℝ) / (m + 1) ≤ 1 := by rw [div_le_one (by positivity)]; linarith + unfold copyFraction + split_ifs + · nlinarith [mul_le_mul hm h1 h0 zero_le_one] + · positivity + +theorem copyFraction_le_one (h0 : 0 ≤ χ t) (h1 : χ t ≤ 1) (j : Fin (m + 1)) : + copyFraction χ m t j ≤ 1 := by + unfold copyFraction + split_ifs + · have : 0 ≤ (m : ℝ) / (m + 1) * χ t := by positivity + linarith + · rw [div_le_one (by positivity)]; linarith + +theorem copyFraction_of_eq_zero (h : χ t = 0) (j : Fin (m + 1)) : + copyFraction χ m t j = if j = 0 then 1 else 0 := by + simp [copyFraction, h] + +theorem copyFraction_of_eq_one (h : χ t = 1) (j : Fin (m + 1)) : + copyFraction χ m t j = 1 / (m + 1) := by + unfold copyFraction + split_ifs + · rw [h]; field_simp; ring + · rw [h] + +end Fraction + +/-! ### The copy step -/ + +section Stage + +variable {V : Type*} {m : ℕ} {χ : ℝ → ℝ} {τ₀ τ₁ : ℝ} {r : Fin (m + 1) → V → ℝ} + {D : Matrix V V ℝ} + +/-- **The copy step** of the hierarchy: `Matrix.copySplit` with the proportions +`Matrix.copyFraction χ m (D x y)` [OpenAI2026LogSpace, (4.23)]. -/ +@[expose] noncomputable def copyStage (χ : ℝ → ℝ) (m : ℕ) (r : Fin (m + 1) → V → ℝ) + (D : Matrix V V ℝ) : Matrix (V × Fin (m + 1)) (V × Fin (m + 1)) ℝ := + copySplit r (fun x y => copyFraction χ m (D x y)) D + +/-- The copies that can be active: the primary copies of a cover `A` of the parents, and all +copies of the overloaded vertices `O`. -/ +@[expose] def copyCover [DecidableEq V] (A O : Finset V) : Finset (V × Fin (m + 1)) := + A ×ˢ {0} ∪ O ×ˢ univ.erase 0 + +theorem card_copyCover_le [DecidableEq V] (A O : Finset V) : + #(copyCover (m := m) A O) ≤ #A + m * #O := by + refine (card_union_le _ _).trans ?_ + rw [card_product, card_product, card_singleton, card_erase_of_mem (mem_univ _), card_univ, + Fintype.card_fin, mul_one, Nat.add_sub_cancel, mul_comm] + +/-- **The copy step intertwines with its projection** when the primary weight is one and every +large entry `τ₀ < D x y` has all copies of its target active [OpenAI2026LogSpace, (4.26)]. -/ +theorem copyStage_mul_copyWeight [Fintype V] [DecidableEq V] (hr0 : ∀ x, r 0 x = 1) + (hχ₀ : ∀ t, t ≤ τ₀ → χ t = 0) + (hbig : ∀ x y, τ₀ < D x y → ∀ j, r j y = 1) : + copyStage χ m r D * copyWeight r = copyWeight r * D := by + refine copySplit_mul_copyWeight fun x y _ => ?_ + rcases le_or_gt (D x y) τ₀ with h | h + · rw [Fin.sum_univ_succ] + simp [copyFraction_of_eq_zero (hχ₀ _ h), Fin.succ_ne_zero, hr0] + · simp only [hbig x y h, mul_one] + exact sum_copyFraction χ m (D x y) + +theorem copyStage_nonneg (hr : ∀ j x, 0 ≤ r j x) (hD : ∀ x y, 0 ≤ D x y) + (hχ0 : ∀ t, 0 ≤ χ t) (hχ1 : ∀ t, χ t ≤ 1) (a b : V × Fin (m + 1)) : + 0 ≤ copyStage χ m r D a b := + copySplit_nonneg hr (fun _ _ j => copyFraction_nonneg (hχ0 _) (hχ1 _) j) hD a b + +/-- The copy step is substochastic when `D` is and the weights lie in `[0, 1]`. -/ +theorem copyStage_mulVec_one_le [Fintype V] (hr0 : ∀ j x, 0 ≤ r j x) (hr1 : ∀ j x, r j x ≤ 1) + (hD0 : ∀ x y, 0 ≤ D x y) (hD1 : D *ᵥ 1 ≤ 1) : copyStage χ m r D *ᵥ 1 ≤ 1 := + copySplit_mulVec_one_le hr0 hr1 (fun x y => (sum_copyFraction χ m (D x y)).le) hD0 hD1 + +/-- **The density bound**: if the entries of `D` are at most `K`, the cutoff is one from `τ₁` +on, `τ₁ ≤ b` and `K / (m + 1) ≤ b`, the copy step has entries at most `b` +[OpenAI2026LogSpace, Proposition 4.5]. -/ +theorem copyStage_le (hr0 : ∀ j x, 0 ≤ r j x) (hr1 : ∀ j x, r j x ≤ 1) + (hD0 : ∀ x y, 0 ≤ D x y) {K b : ℝ} (hDK : ∀ x y, D x y ≤ K) (hχ0 : ∀ t, 0 ≤ χ t) + (hχ1 : ∀ t, χ t ≤ 1) (hχ₁ : ∀ t, τ₁ ≤ t → χ t = 1) (hτ₁ : τ₁ ≤ b) + (hK : K / (m + 1) ≤ b) (a c : V × Fin (m + 1)) : copyStage χ m r D a c ≤ b := by + simp only [copyStage, copySplit, of_apply] + have hrD : r a.2 a.1 * D a.1 c.1 ≤ D a.1 c.1 := + mul_le_of_le_one_left (hD0 _ _) (hr1 _ _) + have hrD0 : 0 ≤ r a.2 a.1 * D a.1 c.1 := mul_nonneg (hr0 _ _) (hD0 _ _) + rcases lt_or_ge (D a.1 c.1) τ₁ with h | h + · calc r a.2 a.1 * D a.1 c.1 * copyFraction χ m (D a.1 c.1) c.2 + ≤ r a.2 a.1 * D a.1 c.1 := + mul_le_of_le_one_right hrD0 (copyFraction_le_one (hχ0 _) (hχ1 _) _) + _ ≤ b := by linarith + · rw [copyFraction_of_eq_one (hχ₁ _ h)] + calc r a.2 a.1 * D a.1 c.1 * (1 / (m + 1)) ≤ K * (1 / (m + 1)) := + mul_le_mul_of_nonneg_right (hrD.trans (hDK _ _)) (by positivity) + _ ≤ b := by rw [mul_one_div]; exact hK + +/-- **Active copies**: if `A` covers the support of `D`, extra copies of `x` are active only for +overloaded `x`, and large entries have overloaded targets, then the copy step is supported in +`Matrix.copyCover A O` [OpenAI2026LogSpace, Proposition 4.5]. -/ +theorem copyStage_mem_copyCover [DecidableEq V] {A O : Finset V} + (hA : ∀ x y, D x y ≠ 0 → x ∈ A ∧ y ∈ A) + (hrO : ∀ j x, j ≠ 0 → r j x ≠ 0 → x ∈ O) (hχ₀ : ∀ t, t ≤ τ₀ → χ t = 0) + (hcolO : ∀ x y, τ₀ < D x y → y ∈ O) (a b : V × Fin (m + 1)) + (h : copyStage χ m r D a b ≠ 0) : a ∈ copyCover A O ∧ b ∈ copyCover A O := by + obtain ⟨⟨x, i⟩, ⟨y, j⟩⟩ := (⟨a, b⟩ : _ × _) + simp only [copyStage, copySplit, of_apply, ne_eq, mul_eq_zero, not_or] at h + obtain ⟨⟨hr, hD⟩, hs⟩ := h + have hxy := hA _ _ hD + simp only [copyCover, mem_union, mem_product, mem_singleton, mem_erase, mem_univ, and_true] + constructor + · by_cases hi : a.2 = 0 + · exact Or.inl ⟨hxy.1, hi⟩ + · exact Or.inr ⟨hrO _ _ hi hr, hi⟩ + · by_cases hj : b.2 = 0 + · exact Or.inl ⟨hxy.2, hj⟩ + · refine Or.inr ⟨hcolO a.1 b.1 ?_, hj⟩ + by_contra hle + exact hs (by simp [copyFraction_of_eq_zero (hχ₀ _ (not_lt.mp hle)), hj]) + +end Stage + +/-! ### Incidence counting -/ + +/-- **Incidence counting.** Let `G i` be nonnegative matrices whose rows sum to at most `s i` and +vanish outside `A`. If each vertex of `O` is the target of at least `N` entries larger than `δ` +in one of the `G i`, then `|O| N δ ≤ |A| ∑ s i`. With the pilot inputs of the preprint as `G i`, +this bounds the number of overloaded columns [OpenAI2026LogSpace, Proposition 4.5]. -/ +theorem card_mul_le_of_incidences {V : Type*} [Fintype V] {k : ℕ} + (G : Fin k → Matrix V V ℝ) (hG0 : ∀ i x y, 0 ≤ G i x y) (s : Fin k → ℝ) + (hGs : ∀ i x, ∑ y, G i x y ≤ s i) (A : Finset V) (hGA : ∀ i x y, G i x y ≠ 0 → x ∈ A) + {δ : ℝ} (hδ : 0 < δ) (O : Finset V) {N : ℕ} + (hO : ∀ y ∈ O, ∃ i, N ≤ #{x | δ < G i x y}) : + (#O * N : ℝ) * δ ≤ #A * ∑ i, s i := by + classical + -- the indicator of a large entry, scaled by `δ`, is at most the entry + have hind : ∀ i x y, (if δ < G i x y then δ else 0) ≤ G i x y := fun i x y => by + split_ifs with h + · exact h.le + · exact hG0 i x y + have hcount : ∀ i y, (#{x | δ < G i x y} : ℝ) * δ = ∑ x, if δ < G i x y then δ else 0 := + fun i y => by rw [Finset.sum_ite, Finset.sum_const_zero, add_zero, Finset.sum_const, + nsmul_eq_mul] + have hrowA : ∀ i x, (∑ y, if δ < G i x y then δ else 0) ≤ if x ∈ A then s i else 0 := by + intro i x + split_ifs with hx + · exact (Finset.sum_le_sum fun y _ => hind i x y).trans (hGs i x) + · refine le_of_eq (Finset.sum_eq_zero fun y _ => ?_) + have : G i x y = 0 := by by_contra h; exact hx (hGA i x y h) + simp [this, not_lt.mpr hδ.le] + calc (#O * N : ℝ) * δ = ∑ y ∈ O, (N : ℝ) * δ := by + rw [Finset.sum_const, nsmul_eq_mul, mul_assoc] + _ ≤ ∑ y ∈ O, ∑ i, ∑ x, if δ < G i x y then δ else 0 := by + refine Finset.sum_le_sum fun y hy => ?_ + obtain ⟨i, hi⟩ := hO y hy + calc (N : ℝ) * δ ≤ (#{x | δ < G i x y} : ℝ) * δ := + mul_le_mul_of_nonneg_right (by exact_mod_cast hi) hδ.le + _ = ∑ x, if δ < G i x y then δ else 0 := hcount i y + _ ≤ ∑ i, ∑ x, if δ < G i x y then δ else 0 := + Finset.single_le_sum (f := fun i => ∑ x, if δ < G i x y then δ else 0) + (fun i _ => Finset.sum_nonneg fun x _ => by split_ifs <;> linarith) (mem_univ i) + _ ≤ ∑ y, ∑ i, ∑ x, if δ < G i x y then δ else 0 := + Finset.sum_le_sum_of_subset_of_nonneg (subset_univ O) fun y _ _ => + Finset.sum_nonneg fun i _ => Finset.sum_nonneg fun x _ => by split_ifs <;> linarith + _ = ∑ i, ∑ x, ∑ y, if δ < G i x y then δ else 0 := by + rw [Finset.sum_comm] + exact Finset.sum_congr rfl fun i _ => Finset.sum_comm + _ ≤ ∑ i, ∑ x, if x ∈ A then s i else 0 := + Finset.sum_le_sum fun i _ => Finset.sum_le_sum fun x _ => hrowA i x + _ = #A * ∑ i, s i := by + simp only [Finset.sum_ite_mem, univ_inter, Finset.sum_const, nsmul_eq_mul] + rw [Finset.mul_sum] + +/-! ### One stage -/ + +section Rates + +variable {V : Type*} [Fintype V] [DecidableEq V] [LinearOrder V] {φ : V → ℝ → ℝ} + {C : Matrix V V ℝ} {f θ L : ℝ} {m : ℕ} {χ : ℝ → ℝ} {τ₀ τ₁ : ℝ} {r : Fin (m + 1) → V → ℝ} + +/-- **One stage of the hierarchy.** Correct `C` by the `k`-th cutoff iterate and split the residual +`D` by `Matrix.copyStage`. Suppose every column is either fully corrected (its cutoff leaves at most +`θ₂ f`) or overloaded with all copies active, the truncation error keeps fully corrected entries +at most `τ₀`, the cutoff `χ` is `0` up to `τ₀` and `1` from `τ₁ ≤ f / q`, there are enough copies +(`(k + 1) f / (m + 1) ≤ f / q`), and `m |O| ≤ |A|` for a cover `A` of the support of `C`. Then +the copy step has entries at most `f / q`, intertwines with its projection, and is supported in a +set of at most `2 |A|` copies [OpenAI2026LogSpace, Proposition 4.5]. -/ +theorem copyStage_rates (hC : C.IsStrictUpperTriangular) (hC0 : ∀ x y, 0 ≤ C x y) + (hCf : ∀ x y, C x y ≤ f) (hC1 : C *ᵥ 1 ≤ 1) (hφ0 : ∀ y t, 0 ≤ φ y t) + (hφθ : ∀ y t, φ y t ≤ max (t - θ * f) 0) (hφm : ∀ y, Monotone (φ y)) + (hφL : ∀ y s t, s ≤ t → φ y t - φ y s ≤ L * (t - s)) (hf : 0 < f) (hθ : 0 < θ) + (hL : 0 ≤ L) (k : ℕ) {A O : Finset V} (hA : ∀ x y, C x y ≠ 0 → x ∈ A ∧ y ∈ A) + (hr0 : ∀ x, r 0 x = 1) (hr01 : ∀ j x, 0 ≤ r j x ∧ r j x ≤ 1) + (hrO : ∀ j x, j ≠ 0 → r j x ≠ 0 → x ∈ O) {θ₂ : ℝ} + (hcol : ∀ y, (∀ t, t - θ₂ * f ≤ φ y t) ∨ ((∀ j, r j y = 1) ∧ y ∈ O)) + (hτ₀ : θ₂ * f + f * Real.exp (1 / θ) * (L / θ) ^ k / k.factorial ≤ τ₀) + (hχ0 : ∀ t, 0 ≤ χ t) (hχ1 : ∀ t, χ t ≤ 1) (hχ₀ : ∀ t, t ≤ τ₀ → χ t = 0) + (hχ₁ : ∀ t, τ₁ ≤ t → χ t = 1) {q : ℝ} (hτ₁ : τ₁ ≤ f / q) + (hK : (k + 1) * f / (m + 1) ≤ f / q) (hO : m * #O ≤ #A) : + let D := C - cutoffCorrectionIter φ C k + cutoffCorrectionIter φ C k * C + (∀ a b, copyStage χ m r D a b ≤ f / q) ∧ + copyStage χ m r D * copyWeight r = copyWeight r * D ∧ + (∀ a b, copyStage χ m r D a b ≠ 0 → + a ∈ copyCover A O ∧ b ∈ copyCover A O) ∧ + #(copyCover (m := m) A O) ≤ 2 * #A := by + intro D + have hθf : 0 ≤ θ * f := by positivity + have hD0 : ∀ x y, 0 ≤ D x y := cutoffCorrection_residual_nonneg hC0 hφ0 hφθ hφm hθf k + have hbig : ∀ x y, τ₀ < D x y → (∀ j, r j y = 1) ∧ y ∈ O := fun x y h => by + rcases hcol y with hgood | hcopy + · have := cutoffCorrection_residual_le hC hC0 hCf hC1 hφ0 hφθ hφm hφL hf hθ hL hgood k x + exact absurd (this.trans hτ₀) (not_le.mpr h) + · exact hcopy + refine ⟨copyStage_le (fun j x => (hr01 j x).1) (fun j x => (hr01 j x).2) hD0 + (cutoffCorrection_residual_le_mul hC0 hφ0 hφθ hθf hCf hf.le hC1 k) hχ0 hχ1 hχ₁ hτ₁ hK, + copyStage_mul_copyWeight hr0 hχ₀ fun x y h => (hbig x y h).1, + copyStage_mem_copyCover (cutoffCorrection_residual_mem hφ0 hφθ hθf hA k) hrO hχ₀ + fun x y h => (hbig x y h).2, ?_⟩ + exact (card_copyCover_le A O).trans (by omega) + +end Rates + +/-! ### Iterating the stages -/ + +section Hierarchy + +variable {V : ℕ → Type*} [∀ l, Fintype (V l)] [∀ l, DecidableEq (V l)] + {C E : ∀ l, Matrix (V l) (V l) ℝ} {P : ∀ l, Matrix (V (l + 1)) (V l) ℝ} + +/-- **The stage bound from per-stage rates.** If the entries of `C 0` are at most one, each stage +divides the entry bound by `q = 2 ^ (c + 1)`, and each stage at most doubles a cover of the +support, then along primary copies `0 ≤ p (z 0) - W l (z l) ≤ n * (2 ^ c)⁻¹ ^ l`, where `n` +bounds the initial cover. `Matrix.copyStage_rates` provides the per-stage rates +[OpenAI2026LogSpace, Proposition 4.7]. -/ +theorem sub_rewardTransport_mulVec_le_of_rates (hP : ∀ l i j, 0 ≤ P l i j) + (hP1 : ∀ l, P l *ᵥ 1 ≤ 1) (hC : ∀ l i j, 0 ≤ C l i j) + (hstep : ∀ l, C (l + 1) * P l = P l * (C l - E l + E l * C l)) {p e : V 0 → ℝ} + (hp : (1 - C 0) *ᵥ p = e) (hp0 : 0 ≤ p) (hp1 : p ≤ 1) {z : ∀ l, V l} + (hz : ∀ l w, P l (z (l + 1)) w = if w = z l then 1 else 0) {c n : ℕ} + (hε0 : ∀ x y, C 0 x y ≤ 1) + (hεs : ∀ l, (∀ x y, C l x y ≤ ((2 : ℝ) ^ (c + 1))⁻¹ ^ l) → + ∀ x y, C (l + 1) x y ≤ ((2 : ℝ) ^ (c + 1))⁻¹ ^ (l + 1)) + (A : ∀ l, Finset (V l)) (hA : ∀ l x y, C l x y ≠ 0 → y ∈ A l) (hA0 : #(A 0) ≤ n) + (hAs : ∀ l, #(A (l + 1)) ≤ 2 * #(A l)) (l : ℕ) : + 0 ≤ p (z 0) - (rewardTransport P E l *ᵥ e) (z l) ∧ + p (z 0) - (rewardTransport P E l *ᵥ e) (z l) ≤ n * ((2 : ℝ) ^ c)⁻¹ ^ l := by + have hε : ∀ l x y, C l x y ≤ ((2 : ℝ) ^ (c + 1))⁻¹ ^ l := by + intro l + induction l with + | zero => simpa using hε0 + | succ l ih => exact hεs l ih + have hAn : ∀ l, #(A l) ≤ 2 ^ l * n := by + intro l + induction l with + | zero => simpa using hA0 + | succ l ih => rw [pow_succ]; linarith [hAs l] + exact sub_rewardTransport_mulVec_le_pow hP hP1 hC hstep hp hp0 hp1 hz hε A hA hAn l + +end Hierarchy + +end Matrix diff --git a/ComplexityTests/CopyStage.lean b/ComplexityTests/CopyStage.lean new file mode 100644 index 000000000..0b65b9f50 --- /dev/null +++ b/ComplexityTests/CopyStage.lean @@ -0,0 +1,137 @@ +/- +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.LinearAlgebra.Matrix.CopyStage + +/-! +# Tests for one stage of the correction-and-copy hierarchy +-/ + +namespace ComplexityTests.CopyStage + +open Finset Matrix + +/-- A walk on three time layers: from `0` to `1` and from `1` to `2`, each with probability +`1 / 2`. Its entries are at most `f = 1 / 2`. -/ +private noncomputable def C : Matrix (Fin 3) (Fin 3) ℝ := !![0, 1 / 2, 0; 0, 0, 1 / 2; 0, 0, 0] + +/-- The hard cutoff `t ↦ max (t - θ f) 0` with `θ = 1 / 4`, `f = 1 / 2`. -/ +private noncomputable def φ : Fin 3 → ℝ → ℝ := fun _ t => max (t - 1 / 8) 0 + +private theorem hC : C.IsStrictUpperTriangular := by + intro i j h; fin_cases i <;> fin_cases j <;> simp_all [C] + +private theorem hC0 : ∀ x y, 0 ≤ C x y := by + intro x y; fin_cases x <;> fin_cases y <;> norm_num [C] + +private theorem hCf : ∀ x y, C x y ≤ 1 / 2 := by + intro x y; fin_cases x <;> fin_cases y <;> norm_num [C] + +private theorem hC1 : C *ᵥ 1 ≤ 1 := by + intro x; fin_cases x <;> norm_num [C, mulVec, dotProduct, Fin.sum_univ_three] + +private theorem hφ0 : ∀ y t, 0 ≤ φ y t := fun _ _ => le_max_right _ _ + +private theorem hφθ : ∀ y t, φ y t ≤ max (t - 1 / 4 * (1 / 2)) 0 := fun _ t => by + norm_num [φ] + +private theorem hφm : ∀ y, Monotone (φ y) := fun _ _ _ h => max_le_max (by linarith) le_rfl + +private theorem hφL : ∀ y s t, s ≤ t → φ y t - φ y s ≤ 1 * (t - s) := fun _ s t _ => by + simp only [φ, one_mul] + have := le_max_left (s - 1 / 8) 0 + have := le_max_right (s - 1 / 8) 0 + have : max (t - 1 / 8) 0 ≤ max (s - 1 / 8) 0 + (t - s) := max_le (by linarith) (by linarith) + linarith + +/-! ### Residual bounds -/ + +-- One iteration corrects each transition to `1 / 8`, so the row sums are at most one. +example (x : Fin 3) : ∑ y, cutoffCorrectionIter φ C 1 x y ≤ 1 := by + exact_mod_cast cutoffCorrectionIter_sum_le hC0 hφ0 hφθ (by norm_num) hC1 1 x + +example (k : ℕ) (x y : Fin 3) : + (C - cutoffCorrectionIter φ C k + cutoffCorrectionIter φ C k * C) x y ≤ (k + 1) * (1 / 2) := + cutoffCorrection_residual_le_mul hC0 hφ0 hφθ (by norm_num) hCf (by norm_num) hC1 k x y + +-- The residual of the first iterate dominates `θ / 2 = 1 / 8` times its unsigned terms. +example (x y : Fin 3) : + 1 / 4 / (2 * ((0 : ℕ) + 1)) * (C + cutoffCorrectionIter φ C 1 + + cutoffCorrectionIter φ C 1 * C) x y ≤ + (C - cutoffCorrectionIter φ C 1 + cutoffCorrectionIter φ C 1 * C) x y := + cutoffCorrection_residual_dominates hC0 hφ0 hφθ (by norm_num) hCf (by norm_num) hC1 hφm + (by norm_num) (by norm_num) 0 x y + +/-! ### Copy fractions -/ + +/-- A ramp from `0` at `t ≤ 0` to `1` at `t ≥ 1 / 4`. -/ +private noncomputable def χ (t : ℝ) : ℝ := min (max (4 * t) 0) 1 + +private theorem χ0 : ∀ t, 0 ≤ χ t := fun _ => le_min (le_max_right _ _) zero_le_one +private theorem χ1 : ∀ t, χ t ≤ 1 := fun _ => min_le_right _ _ +private theorem χ₀ : ∀ t, t ≤ 0 → χ t = 0 := fun t h => by + simp only [χ]; rw [max_eq_right (by linarith)]; norm_num +private theorem χ₁ : ∀ t, 1 / 4 ≤ t → χ t = 1 := fun t h => by + simp only [χ]; rw [max_eq_left (by linarith)]; exact min_eq_right (by linarith) + +-- A large entry is split evenly between two copies; a small one stays with the primary copy. +example : copyFraction χ 1 (1 / 2) 1 = 1 / 2 := by + rw [copyFraction_of_eq_one (χ₁ _ (by norm_num))]; norm_num + +example (j : Fin 2) : copyFraction χ 1 0 j = if j = 0 then 1 else 0 := + copyFraction_of_eq_zero (χ₀ 0 le_rfl) j + +/-! ### One stage + +Without correction (`k = 0`, so `D = C`) and with every vertex overloaded and both of its copies +active, the stage halves the entries `1 / 2` of `C` and at most doubles the support. -/ + +private def r : Fin 2 → Fin 3 → ℝ := fun _ _ => 1 + +-- The split entry from the primary copy of `0` to the second copy of `1` is `1 / 4`. +example : copyStage χ 1 r (C - cutoffCorrectionIter φ C 0 + cutoffCorrectionIter φ C 0 * C) + ((0 : Fin 3), (0 : Fin 2)) ((1 : Fin 3), (1 : Fin 2)) = 1 / 4 := by + simp only [copyStage, copySplit, of_apply, cutoffCorrectionIter, Function.iterate_zero, id, + sub_zero, Matrix.zero_mul, add_zero] + rw [copyFraction_of_eq_one (χ₁ _ (by norm_num [C]))] + norm_num [r, C] + +private theorem stage : + let D := C - cutoffCorrectionIter φ C 0 + cutoffCorrectionIter φ C 0 * C + (∀ a b, copyStage χ 1 r D a b ≤ 1 / 2 / 2) ∧ + copyStage χ 1 r D * copyWeight r = copyWeight r * D ∧ + (∀ a b, copyStage χ 1 r D a b ≠ 0 → a ∈ copyCover univ univ ∧ b ∈ copyCover univ univ) ∧ + #(copyCover (m := 1) (univ : Finset (Fin 3)) univ) ≤ 2 * #(univ : Finset (Fin 3)) := + copyStage_rates (m := 1) (q := 2) (L := 1) (θ := 1 / 4) hC hC0 hCf hC1 + hφ0 hφθ hφm hφL (by norm_num) (by norm_num) (by norm_num) 0 + (fun _ _ _ => ⟨mem_univ _, mem_univ _⟩) (fun _ => rfl) + (fun _ _ => by norm_num [r]) (fun _ _ _ _ => mem_univ _) + (θ₂ := -(Real.exp (1 / (1 / 4)) * (1 / (1 / 4)) ^ 0 / Nat.factorial 0)) + (fun _ => Or.inr ⟨fun _ => rfl, mem_univ _⟩) (τ₀ := 0) (le_of_eq (by ring)) χ0 χ1 χ₀ + (τ₁ := 1 / 4) χ₁ (by norm_num) (by norm_num) (by simp) + +-- Every entry of the stage is at most `f / q = 1 / 4`, and at most `6` copies are active. +example : ∀ a b, copyStage χ 1 r (C - cutoffCorrectionIter φ C 0 + + cutoffCorrectionIter φ C 0 * C) a b ≤ 1 / 2 / 2 := stage.1 + +example : #(copyCover (m := 1) (univ : Finset (Fin 3)) univ) ≤ 6 := stage.2.2.2 + +/-! ### Incidence counting -/ + +-- In the walk, both targets `1` and `2` have an entry `1 / 2 > 1 / 4`, so +-- `2 · 1 · (1 / 4) ≤ |rows| · 1` with the two nonzero rows `{0, 1}`. +example : + ((#({1, 2} : Finset (Fin 3)) * 1 : ℕ) : ℝ) * (1 / 4) ≤ #({0, 1} : Finset (Fin 3)) * 1 := by + have h := card_mul_le_of_incidences (k := 1) (fun _ => C) (fun _ => hC0) (fun _ => 1) + (fun _ x => by fin_cases x <;> norm_num [C, Fin.sum_univ_three]) {0, 1} + (fun _ x y hxy => by fin_cases x <;> fin_cases y <;> simp_all [C]) (δ := 1 / 4) + (by norm_num) {1, 2} (N := 1) (fun y hy => ⟨0, by + simp only [mem_insert, mem_singleton] at hy + rcases hy with rfl | rfl + · exact card_pos.mpr ⟨0, by norm_num [C]⟩ + · exact card_pos.mpr ⟨1, by norm_num [C]⟩⟩) + simpa using h + +end ComplexityTests.CopyStage From 4943d9b0e91fa86788863e3fa7a211187d386748 Mon Sep 17 00:00:00 2001 From: Christian Reitwiessner Date: Thu, 29 Oct 2026 23:57:30 +0000 Subject: [PATCH 14/25] 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 ea663cedbea1caf5e23e6f38b36fed48ed46dda8 Mon Sep 17 00:00:00 2001 From: Christian Reitwiessner Date: Fri, 30 Oct 2026 00:04:51 +0000 Subject: [PATCH 15/25] fix(Foundations): qualify Matrix apply lemmas for the rc2 Mathlib API Under rc2 the root-namespace add_apply/neg_apply/sub_apply/mul_apply/one_apply no longer apply to matrices; use the Matrix.* versions in CorrectionHierarchy and its test, as #1653 does elsewhere. Co-Authored-By: Claude Opus 5.5 --- .../Matrix/CorrectionHierarchy.lean | 18 ++++++++++-------- ComplexityTests/CorrectionHierarchy.lean | 19 ++++++++++--------- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/Complexity/Foundations/LinearAlgebra/Matrix/CorrectionHierarchy.lean b/Complexity/Foundations/LinearAlgebra/Matrix/CorrectionHierarchy.lean index 2420fb961..ec5c5825e 100644 --- a/Complexity/Foundations/LinearAlgebra/Matrix/CorrectionHierarchy.lean +++ b/Complexity/Foundations/LinearAlgebra/Matrix/CorrectionHierarchy.lean @@ -112,15 +112,15 @@ theorem isUpperTriangular [Zero R] (h : M.IsStrictUpperTriangular) : M.IsUpperTr theorem add [AddZeroClass R] (hM : M.IsStrictUpperTriangular) (hN : N.IsStrictUpperTriangular) : (M + N).IsStrictUpperTriangular := fun i j hij => by - simp only [add_apply, hM hij, hN hij, add_zero] + simp only [Matrix.add_apply, hM hij, hN hij, add_zero] theorem neg [SubtractionMonoid R] (hM : M.IsStrictUpperTriangular) : (-M).IsStrictUpperTriangular := fun i j hij => by - simp only [neg_apply, hM hij, neg_zero] + simp only [Matrix.neg_apply, hM hij, neg_zero] theorem sub [SubtractionMonoid R] (hM : M.IsStrictUpperTriangular) (hN : N.IsStrictUpperTriangular) : (M - N).IsStrictUpperTriangular := fun i j hij => by - simp only [sub_apply, hM hij, hN hij, sub_zero] + simp only [Matrix.sub_apply, hM hij, hN hij, sub_zero] theorem mul [Fintype V] [NonUnitalNonAssocSemiring R] (hM : M.IsStrictUpperTriangular) (hN : N.IsStrictUpperTriangular) : (M * N).IsStrictUpperTriangular := fun i j hij => by @@ -134,9 +134,10 @@ theorem mul [Fintype V] [NonUnitalNonAssocSemiring R] (hM : M.IsStrictUpperTrian theorem det_one_add {V : Type*} [Fintype V] [DecidableEq V] [LinearOrder V] [CommRing R] {E : Matrix V V R} (h : E.IsStrictUpperTriangular) : (1 + E).det = 1 := by have hT : (1 + E).IsUpperTriangular := fun i j (hji : j < i) => by - rw [add_apply, one_apply_ne (ne_of_lt hji).symm, h.isUpperTriangular hji, add_zero] + rw [Matrix.add_apply, one_apply_ne (ne_of_lt hji).symm, h.isUpperTriangular hji, add_zero] rw [det_of_isUpperTriangular hT] - exact Finset.prod_eq_one fun i _ => by rw [add_apply, one_apply_eq, h (lt_irrefl i), add_zero] + exact Finset.prod_eq_one fun i _ => by + rw [Matrix.add_apply, one_apply_eq, h (lt_irrefl i), add_zero] end IsStrictUpperTriangular @@ -240,11 +241,12 @@ theorem copySplit_mul_copyWeight [Fintype V] [DecidableEq V] [Fintype ι] [Semir copySplit r s D * copyWeight r = copyWeight r * D := by ext ⟨x, i⟩ z have hL : (copySplit r s D * copyWeight r) (x, i) z = r i x * D x z * ∑ j, s x z j * r j z := by - rw [mul_apply, Fintype.sum_prod_type, Fintype.sum_eq_single z fun y hy => ?_, Finset.mul_sum] + rw [Matrix.mul_apply, Fintype.sum_prod_type, Fintype.sum_eq_single z fun y hy => ?_, + Finset.mul_sum] · simp [copySplit, copyWeight, mul_assoc] · simp [copyWeight, hy] have hR : (copyWeight r * D) (x, i) z = r i x * D x z := by - rw [mul_apply, Fintype.sum_eq_single x fun y hy => ?_] + rw [Matrix.mul_apply, Fintype.sum_eq_single x fun y hy => ?_] · simp [copyWeight] · simp [copyWeight, Ne.symm hy] rw [hL, hR] @@ -358,7 +360,7 @@ variable [Ring R] [PartialOrder R] [IsOrderedRing R] private theorem one_apply_nonneg {n : Type*} [DecidableEq n] (i j : n) : (0 : R) ≤ (1 : Matrix n n R) i j := by - rw [one_apply]; split_ifs <;> simp + rw [Matrix.one_apply]; split_ifs <;> simp private theorem mul_nonneg_entries {m n o : Type*} [Fintype n] {A : Matrix m n R} {B : Matrix n o R} (hA : ∀ i j, 0 ≤ A i j) (hB : ∀ i j, 0 ≤ B i j) (i : m) (k : o) : diff --git a/ComplexityTests/CorrectionHierarchy.lean b/ComplexityTests/CorrectionHierarchy.lean index c6bb668e6..1564bdc7a 100644 --- a/ComplexityTests/CorrectionHierarchy.lean +++ b/ComplexityTests/CorrectionHierarchy.lean @@ -24,7 +24,8 @@ private def e : Fin 3 → ℚ := ![0, 0, 1] private def p : Fin 3 → ℚ := ![1 / 4, 1 / 2, 1] private theorem one_sub_C_mulVec_p : (1 - C) *ᵥ p = e := by - ext i; fin_cases i <;> norm_num [C, p, e, mulVec, dotProduct, Fin.sum_univ_three, one_apply] + ext i; fin_cases i <;> + norm_num [C, p, e, mulVec, dotProduct, Fin.sum_univ_three, Matrix.one_apply] /-- The correction removes the second transition. -/ private def E : Matrix (Fin 3) (Fin 3) ℚ := !![0, 0, 0; 0, 0, 1 / 2; 0, 0, 0] @@ -41,18 +42,18 @@ example : C - E + E * C = !![0, 1 / 2, 0; 0, 0, 0; 0, 0, 0] := by -- equation. example : (1 - (C - E + E * C)) *ᵥ p = ![0, 1 / 2, 1] := by rw [one_sub_correction_mulVec, one_sub_C_mulVec_p] - ext i; fin_cases i <;> simp [E, e, mulVec, dotProduct, Fin.sum_univ_three, one_apply] + ext i; fin_cases i <;> simp [E, e, mulVec, dotProduct, Fin.sum_univ_three, Matrix.one_apply] private theorem inv_one_sub_C : (1 - C)⁻¹ = 1 + C + C * C := inv_eq_left_inv <| by ext i j; fin_cases i <;> fin_cases j <;> - simp [C, mul_apply, Fin.sum_univ_three, one_apply] + simp [C, Matrix.mul_apply, Fin.sum_univ_three, Matrix.one_apply] -- The acceptance probabilities of the corrected walk with the corrected reward are those of -- the original walk: `1 / 4` from `0`. example : ((1 - (C - E + E * C))⁻¹ *ᵥ (e + E *ᵥ e)) 0 = 1 / 4 := by rw [E_strict.inv_one_sub_correction_mulVec, inv_one_sub_C] - simp [C, e, mulVec, dotProduct, Fin.sum_univ_three, one_apply] + simp [C, e, mulVec, dotProduct, Fin.sum_univ_three, Matrix.one_apply] norm_num -- A nonnegative correction does not increase the row sums. @@ -93,7 +94,7 @@ private def Es (l : ℕ) : Matrix (Fin 3) (Fin 3) ℚ := if l = 0 then C + C * C private def Ps (_ : ℕ) : Matrix (Fin 3) (Fin 3) ℚ := 1 private theorem C_cube : C * C * C = 0 := by - ext i j; fin_cases i <;> fin_cases j <;> simp [C, mul_apply, Fin.sum_univ_three] + ext i j; fin_cases i <;> fin_cases j <;> simp [C, Matrix.mul_apply, Fin.sum_univ_three] private theorem hstep (l : ℕ) : Cs (l + 1) * Ps l = Ps l * (Cs l - Es l + Es l * Cs l) := by rcases l with _ | l @@ -108,12 +109,12 @@ private theorem nonneg_C : ∀ i j, 0 ≤ C i j := by -- the row sum of the zero matrix. example : (rewardTransport (V := fun _ => Fin 3) Ps Es 1 *ᵥ e) 0 = 1 / 4 := by have h := sub_rewardTransport_mulVec_mem_Icc (V := fun _ => Fin 3) (C := Cs) (E := Es) - (P := Ps) (z := fun _ => 0) (fun _ i j => by simp [Ps, one_apply]; split_ifs <;> simp) + (P := Ps) (z := fun _ => 0) (fun _ i j => by simp [Ps, Matrix.one_apply]; split_ifs <;> simp) (fun _ => by simp [Ps]) (fun l i j => by unfold Cs; split_ifs <;> simp [nonneg_C]) hstep (p := p) (e := e) (by simpa [Cs] using one_sub_C_mulVec_p) (fun i => by fin_cases i <;> norm_num [p]) (fun i => by fin_cases i <;> norm_num [p]) - (fun _ w => by simp [Ps, one_apply, eq_comm]) 1 + (fun _ w => by simp [Ps, Matrix.one_apply, eq_comm]) 1 have hp0 : p 0 = 1 / 4 := rfl simp only [Cs, Nat.add_one_ne_zero, ↓reduceIte, Matrix.zero_apply, Finset.sum_const_zero, Set.mem_Icc] at h @@ -122,10 +123,10 @@ example : (rewardTransport (V := fun _ => Fin 3) Ps Es 1 *ᵥ e) 0 = 1 / 4 := by -- The transported rewards are nonnegative. example : 0 ≤ rewardTransport (V := fun _ => Fin 3) Ps Es 1 *ᵥ e := rewardTransport_mulVec_nonneg (V := fun _ => Fin 3) - (fun _ i j => by simp only [Ps, one_apply]; split_ifs <;> simp) + (fun _ i j => by simp only [Ps, Matrix.one_apply]; split_ifs <;> simp) (fun l i j => by unfold Es; split_ifs - · fin_cases i <;> fin_cases j <;> norm_num [C, mul_apply, Fin.sum_univ_three] + · fin_cases i <;> fin_cases j <;> norm_num [C, Matrix.mul_apply, Fin.sum_univ_three] · simp) (fun i => by fin_cases i <;> simp [e]) 1 From ed3268e11cabe302fe7a7ffe7263d38df994663a Mon Sep 17 00:00:00 2001 From: Christian Reitwiessner Date: Fri, 30 Oct 2026 00:10:43 +0000 Subject: [PATCH 16/25] feat(Foundations): copy stages preserve strict upper triangularity MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add cutoffCorrectionIter_isStrictUpperTriangular, cutoffCorrection_residual_isStrictUpperTriangular and copyStage_isStrictUpperTriangular (for the lexicographic order on Lex (V × Fin (m + 1))), so a stage's output can feed the next stage. Correct two descriptions: the pilot inputs have bounded row sums, not necessarily at most one, and copyStage_mulVec_one_le preserves the row-sum bound, with nonnegativity from copyStage_nonneg. Co-Authored-By: Claude Opus 5.5 --- .../LinearAlgebra/Matrix/CopyStage.lean | 53 +++++++++++++++++-- ComplexityTests/CopyStage.lean | 17 ++++++ 2 files changed, 67 insertions(+), 3 deletions(-) diff --git a/Complexity/Foundations/LinearAlgebra/Matrix/CopyStage.lean b/Complexity/Foundations/LinearAlgebra/Matrix/CopyStage.lean index 4fd044ed2..f261da8d2 100644 --- a/Complexity/Foundations/LinearAlgebra/Matrix/CopyStage.lean +++ b/Complexity/Foundations/LinearAlgebra/Matrix/CopyStage.lean @@ -23,6 +23,14 @@ its support lies in a set at most twice as large as the support of `C` `Matrix.sub_rewardTransport_mulVec_le_pow`; `Matrix.sub_rewardTransport_mulVec_le_of_rates` iterates them. +Stages can be chained. If `C` is strictly upper triangular, so is the residual `D` +(`Matrix.cutoffCorrection_residual_isStrictUpperTriangular`), and the copy step is strictly upper +triangular for the lexicographic order on the copies `Lex (V × Fin (m + 1))`, which is linearly +ordered (`Matrix.copyStage_isStrictUpperTriangular`). Its rows sum to at most one +(`Matrix.copyStage_mulVec_one_le` with `Matrix.correction_mulVec_one_le`) and its entries are +nonnegative under the cutoff assumptions `0 ≤ χ ≤ 1` (`Matrix.copyStage_nonneg` with +`Matrix.cutoffCorrection_residual_nonneg`), so it satisfies the input hypotheses of the next stage. + The choice of which columns are corrected and which vertices get active copies comes from the preprint's *detectors*, which are probabilistic. Here it is an interface: copy weights `r` with `r 0 = 1`, and a finite set `O` of *overloaded* vertices, such that @@ -33,8 +41,9 @@ preprint's *detectors*, which are probabilistic. Here it is an interface: copy w * `m |O| ≤ |A|`, where `m + 1` is the number of copies and `A` covers the support of `C`. The last condition follows from incidence counting (`Matrix.card_mul_le_of_incidences`): if every -overloaded column has many large entries in one of a few substochastic matrices, as the detectors -guarantee for the pilot inputs, then there are few overloaded columns. +overloaded column has many large entries in one of a few matrices with the stated row-sum bounds, +as the detectors guarantee for the pilot inputs, then there are few overloaded columns. The pilot +inputs have bounded row sums, not necessarily at most one [OpenAI2026LogSpace, Lemma 4.2]. The corrected matrix also satisfies the remaining bounds of Lemma 4.4 of the preprint. Its entries are at most `(k + 1) f` (`Matrix.cutoffCorrection_residual_le_mul`). It dominates its unsigned @@ -58,6 +67,9 @@ which lets the three terms of `D` be estimated separately. Its support stays wit `Matrix.copyStage_le`, `Matrix.copyStage_mem_copyCover`, `Matrix.card_copyCover_le`: the copy step intertwines with its projection, is substochastic, has small entries and few active copies. +* `Matrix.cutoffCorrection_residual_isStrictUpperTriangular`, + `Matrix.copyStage_isStrictUpperTriangular`: a stage maps strictly upper triangular matrices to + strictly upper triangular ones, for the lexicographic order on the copies. * `Matrix.card_mul_le_of_incidences`: incidence counting. * `Matrix.copyStage_rates`: the one-stage density and active-count bounds. * `Matrix.sub_rewardTransport_mulVec_le_of_rates`: the stage bound from per-stage rates. @@ -248,6 +260,28 @@ theorem cutoffCorrection_residual_mem (hA : ∀ x y, C x y ≠ 0 → x ∈ A ∧ · rw [hCz, mul_zero] exact absurd ⟨(hE x z hEz).1, (hA z y hCz).2⟩ hxy +include hφ0 hφθ hθf in +/-- The iterates of the cutoff correction of a strictly upper triangular matrix are strictly upper +triangular. -/ +theorem cutoffCorrectionIter_isStrictUpperTriangular [Preorder V] + (hC : C.IsStrictUpperTriangular) (k : ℕ) : + (cutoffCorrectionIter φ C k).IsStrictUpperTriangular := by + induction k with + | zero => intro x y _; simp [cutoffCorrectionIter] + | succ k ih => + intro x y hxy + rw [cutoffCorrectionIter_succ] + change φ y ((C + cutoffCorrectionIter φ C k * C) x y) = 0 + rw [(hC.add (ih.mul hC)) hxy, cutoff_zero hφ0 hφθ hθf] + +include hφ0 hφθ hθf in +/-- **The residual of a strictly upper triangular matrix is strictly upper triangular.** -/ +theorem cutoffCorrection_residual_isStrictUpperTriangular [Preorder V] + (hC : C.IsStrictUpperTriangular) (k : ℕ) : + (C - cutoffCorrectionIter φ C k + cutoffCorrectionIter φ C k * C).IsStrictUpperTriangular := + have hE := cutoffCorrectionIter_isStrictUpperTriangular hφ0 hφθ hθf hC k + (hC.sub hE).add (hE.mul hC) + end Residual /-! ### Copy fractions -/ @@ -317,6 +351,16 @@ copies of the overloaded vertices `O`. -/ @[expose] def copyCover [DecidableEq V] (A O : Finset V) : Finset (V × Fin (m + 1)) := A ×ˢ {0} ∪ O ×ˢ univ.erase 0 +/-- **The copy step stays strictly upper triangular** for the lexicographic order on the copies: +`(x, i)` comes before `(y, j)` when `x < y`, or `x = y` and `i < j`. Indexed by +`Lex (V × Fin (m + 1))`, which is linearly ordered when `V` is, the copy step can be the input of +the next stage. -/ +theorem copyStage_isStrictUpperTriangular [Preorder V] (hD : D.IsStrictUpperTriangular) : + ((copyStage χ m r D).submatrix ofLex ofLex).IsStrictUpperTriangular := by + intro a b hab + simp only [submatrix_apply, copyStage, copySplit, of_apply] + rw [hD fun h => hab (Prod.Lex.lt_iff.2 (Or.inl h)), mul_zero, zero_mul] + theorem card_copyCover_le [DecidableEq V] (A O : Finset V) : #(copyCover (m := m) A O) ≤ #A + m * #O := by refine (card_union_le _ _).trans ?_ @@ -341,7 +385,10 @@ theorem copyStage_nonneg (hr : ∀ j x, 0 ≤ r j x) (hD : ∀ x y, 0 ≤ D x y) 0 ≤ copyStage χ m r D a b := copySplit_nonneg hr (fun _ _ j => copyFraction_nonneg (hχ0 _) (hχ1 _) j) hD a b -/-- The copy step is substochastic when `D` is and the weights lie in `[0, 1]`. -/ +/-- **The copy step preserves the row-sum upper bound**: its rows sum to at most one when `D` is +nonnegative with rows summing to at most one and the weights lie in `[0, 1]`. Substochasticity +also needs nonnegative entries, which `Matrix.copyStage_nonneg` gives under the additional +cutoff assumptions `0 ≤ χ ≤ 1`. -/ theorem copyStage_mulVec_one_le [Fintype V] (hr0 : ∀ j x, 0 ≤ r j x) (hr1 : ∀ j x, r j x ≤ 1) (hD0 : ∀ x y, 0 ≤ D x y) (hD1 : D *ᵥ 1 ≤ 1) : copyStage χ m r D *ᵥ 1 ≤ 1 := copySplit_mulVec_one_le hr0 hr1 (fun x y => (sum_copyFraction χ m (D x y)).le) hD0 hD1 diff --git a/ComplexityTests/CopyStage.lean b/ComplexityTests/CopyStage.lean index 0b65b9f50..fd97008fd 100644 --- a/ComplexityTests/CopyStage.lean +++ b/ComplexityTests/CopyStage.lean @@ -118,6 +118,23 @@ example : ∀ a b, copyStage χ 1 r (C - cutoffCorrectionIter φ C 0 + example : #(copyCover (m := 1) (univ : Finset (Fin 3)) univ) ≤ 6 := stage.2.2.2 +/-! ### Chaining stages -/ + +-- The stage output, indexed by the lexicographically ordered copies, is again strictly upper +-- triangular, so it can be the input `C` of the next stage. +example : ((copyStage χ 1 r (C - cutoffCorrectionIter φ C 0 + + cutoffCorrectionIter φ C 0 * C)).submatrix ofLex ofLex).IsStrictUpperTriangular := + copyStage_isStrictUpperTriangular + (cutoffCorrection_residual_isStrictUpperTriangular hφ0 hφθ (by norm_num) hC 0) + +-- Concretely, the copy `(1, 1)` of the middle vertex comes after both copies of vertex `0`, so +-- the entries from it back to them vanish. +example (i : Fin 2) : (copyStage χ 1 r (C - cutoffCorrectionIter φ C 0 + + cutoffCorrectionIter φ C 0 * C)) (1, 1) (0, i) = 0 := + copyStage_isStrictUpperTriangular (V := Fin 3) + (cutoffCorrection_residual_isStrictUpperTriangular hφ0 hφθ (by norm_num) hC 0) + (i := toLex (1, 1)) (j := toLex (0, i)) (by simp [Prod.Lex.lt_iff]) + /-! ### Incidence counting -/ -- In the walk, both targets `1` and `2` have an entry `1 / 2 > 1 / 4`, so From 19cf8a82f0390c89261196084d1838f498523e73 Mon Sep 17 00:00:00 2001 From: Christian Reitwiessner Date: Fri, 30 Oct 2026 00:10:59 +0000 Subject: [PATCH 17/25] fix(Foundations): qualify Matrix apply lemmas in FactorialTruncation for rc2 Under rc2 the root-namespace add_apply/sub_apply/mul_apply no longer apply to matrices; use the Matrix.* versions in FactorialTruncation and its test, rewrapping lines that crossed 100 columns. Co-Authored-By: Claude Opus 5.5 --- .../Matrix/FactorialTruncation.lean | 26 ++++++++++--------- ComplexityTests/FactorialTruncation.lean | 5 ++-- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/Complexity/Foundations/LinearAlgebra/Matrix/FactorialTruncation.lean b/Complexity/Foundations/LinearAlgebra/Matrix/FactorialTruncation.lean index f94a429ae..856f41393 100644 --- a/Complexity/Foundations/LinearAlgebra/Matrix/FactorialTruncation.lean +++ b/Complexity/Foundations/LinearAlgebra/Matrix/FactorialTruncation.lean @@ -105,7 +105,7 @@ variable [LinearOrder V] private theorem cutoffCorrection_congr (hC : C.IsStrictUpperTriangular) {F G : Matrix V V R} {x y : V} (h : ∀ z < y, F x z = G x z) : cutoffCorrection φ C F x y = cutoffCorrection φ C G x y := by - simp only [cutoffCorrection, of_apply, add_apply, mul_apply] + simp only [cutoffCorrection, of_apply, Matrix.add_apply, Matrix.mul_apply] congr 2 refine Finset.sum_congr rfl fun z _ => ?_ by_cases hz : z < y @@ -191,7 +191,7 @@ include hC0 hφm in private theorem cutoffCorrection_mono {F G : Matrix V V ℝ} (hFG : ∀ x y, F x y ≤ G x y) (x y : V) : cutoffCorrection φ C F x y ≤ cutoffCorrection φ C G x y := by refine hφm y ?_ - simp only [add_apply, mul_apply] + simp only [Matrix.add_apply, Matrix.mul_apply] exact add_le_add_right (Finset.sum_le_sum fun z _ => mul_le_mul_of_nonneg_right (hFG x z) (hC0 z y)) _ @@ -271,7 +271,7 @@ private theorem card_support_mul_le (hθf : 0 ≤ θ * f) : have hE0 : ∀ i j, 0 ≤ E i j := cutoffCorrectionIter_nonneg hφ0 _ have hEfix : ∀ y, E x y = φ y ((C + E * C) x y) := fix_apply hC x have hres : ∀ y, (C - E + E * C) x y = (C + E * C) x y - E x y := fun y => by - simp only [add_apply, sub_apply]; ring + simp only [Matrix.add_apply, Matrix.sub_apply]; ring have hres0 : ∀ y, 0 ≤ (C - E + E * C) x y := fun y => by rw [hres, hEfix y, sub_nonneg] exact cutoff_le_self hφθ hθf y (correctionInput_nonneg hC0 hE0 x y) @@ -317,7 +317,7 @@ private theorem fix_le_pow (hf : 0 ≤ f) (hθf : 0 ≤ θ * f) (y : V) : calc E x y ≤ (C + E * C) x y := by rw [hEfix]; exact cutoff_le_self hφθ hθf y (correctionInput_nonneg hC0 hE0 x y) _ = C x y + ∑ z ∈ S.filter (· < y), E x z * C z y := by - rw [add_apply, mul_apply, hsum] + rw [Matrix.add_apply, Matrix.mul_apply, hsum] _ ≤ f + ∑ z ∈ S.filter (· < y), f * (1 + f) ^ #(S.filter (· < z)) * f := by refine add_le_add (hCf x y) (Finset.sum_le_sum fun z hz => ?_) exact mul_le_mul (ih z (mem_filter.mp hz).2) (hCf z y) (hC0 z y) (by positivity) @@ -353,14 +353,16 @@ private theorem fix_sub_iter_le_choose (hf : 0 ≤ f) (hθf : 0 ≤ θ * f) (hL have hsum : ∑ z, (E - F) x z * C z y = ∑ z ∈ S.filter (· < y), (E - F) x z * C z y := sum_mul_eq_sum_support x hC (fun z hz => by change E x z = 0 at hz - rw [sub_apply, hz, sub_eq_zero] + rw [Matrix.sub_apply, hz, sub_eq_zero] exact le_antisymm (cutoffCorrectionIter_nonneg (C := C) hφ0 k x z) (hz ▸ hFE z)) y have hdiff : (C + E * C) x y - (C + F * C) x y = ∑ z, (E - F) x z * C z y := by - simp only [add_apply, mul_apply, sub_apply, sub_mul, Finset.sum_sub_distrib]; ring + simp only [Matrix.add_apply, Matrix.mul_apply, Matrix.sub_apply, sub_mul, + Finset.sum_sub_distrib] + ring have hle : (C + F * C) x y ≤ (C + E * C) x y := by rw [← sub_nonneg, hdiff] - exact Finset.sum_nonneg fun z _ => mul_nonneg (by rw [sub_apply, sub_nonneg]; exact hFE z) - (hC0 z y) + exact Finset.sum_nonneg fun z _ => + mul_nonneg (by rw [Matrix.sub_apply, sub_nonneg]; exact hFE z) (hC0 z y) calc E x y - cutoffCorrectionIter φ C (k + 1) x y = φ y ((C + E * C) x y) - φ y ((C + F * C) x y) := by rw [hEfix, cutoffCorrectionIter_succ]; rfl @@ -370,7 +372,7 @@ private theorem fix_sub_iter_le_choose (hf : 0 ≤ f) (hθf : 0 ≤ θ * f) (hL _ ≤ L * ∑ z ∈ S.filter (· < y), f * (1 + f) ^ #S * (L * f) ^ k * (#(S.filter (· < z))).choose k * f := by refine mul_le_mul_of_nonneg_left (Finset.sum_le_sum fun z _ => ?_) hL - rw [sub_apply] + rw [Matrix.sub_apply] exact mul_le_mul (ih z) (hCf z y) (hC0 z y) (by positivity) _ = f * (1 + f) ^ #S * (L * f) ^ (k + 1) * ∑ z ∈ S.filter (· < y), ((#(S.filter (· < z))).choose k : ℝ) := by @@ -445,8 +447,8 @@ theorem cutoffCorrection_residual_nonneg (hθf : 0 ≤ θ * f) (k : ℕ) (x y : (cutoffCorrectionIter φ C (k + 1) * C) x y := Finset.sum_le_sum fun z _ => mul_le_mul_of_nonneg_right (cutoffCorrectionIter_le_succ hC0 hφ0 hφm k x z) (hC0 z y) - rw [← hstep, add_apply] at hcut - rw [add_apply, sub_apply] + rw [← hstep, Matrix.add_apply] at hcut + rw [Matrix.add_apply, Matrix.sub_apply] linarith include hC hC0 hCf hC1 hφ0 hφθ hφm hφL in @@ -466,7 +468,7 @@ theorem cutoffCorrection_residual_le (hf : 0 < f) (hθ : 0 < θ) (hL : 0 ≤ L) (cutoffCorrectionIter_le_fix hC hC0 hφ0 hφm k x z) (hC0 z y) have hT := hgood ((C + E * C) x y) rw [← hEfix] at hT - simp only [add_apply, sub_apply] at hT hΔC ⊢ + simp only [Matrix.add_apply, Matrix.sub_apply] at hT hΔC ⊢ linarith /-- **A constant number of iterations suffices**: for every accuracy `δ > 0` there is `k`, depending diff --git a/ComplexityTests/FactorialTruncation.lean b/ComplexityTests/FactorialTruncation.lean index 1a9743119..18bd60c9a 100644 --- a/ComplexityTests/FactorialTruncation.lean +++ b/ComplexityTests/FactorialTruncation.lean @@ -57,7 +57,7 @@ private theorem Estar_eq : Estar = cutoffCorrectionFix φ C := by refine eq_cutoffCorrectionFix hC ?_ ext x y fin_cases x <;> fin_cases y <;> - norm_num [cutoffCorrection, φ, C, Estar, mul_apply, Fin.sum_univ_three] + norm_num [cutoffCorrection, φ, C, Estar, Matrix.mul_apply, Fin.sum_univ_three] -- One iteration from zero misses the two-step entry entirely. example : cutoffCorrectionIter φ C 1 0 2 = 0 := by @@ -72,7 +72,8 @@ example : cutoffCorrectionFix φ C 0 2 - cutoffCorrectionIter φ C 1 0 2 ≤ -- After two iterations the iterate has reached the fixed point at `(0, 2)`. example : cutoffCorrectionIter φ C 2 0 2 = cutoffCorrectionFix φ C 0 2 := by rw [← Estar_eq] - norm_num [cutoffCorrectionIter, cutoffCorrection, φ, C, Estar, mul_apply, Fin.sum_univ_three] + norm_num [cutoffCorrectionIter, cutoffCorrection, φ, C, Estar, Matrix.mul_apply, + Fin.sum_univ_three] -- The corrected matrix of every iterate is nonnegative, and the hard cutoff leaves at most -- `θ f = 1 / 8` behind in every column. From 35dd78f4d9eed6f507e19309c4af8cebc5c791e7 Mon Sep 17 00:00:00 2001 From: Christian Reitwiessner Date: Fri, 30 Oct 2026 00:20:21 +0000 Subject: [PATCH 18/25] refactor(Foundations): general copySplit_isStrictUpperTriangular beside copySplit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit State the preservation lemma for arbitrary weights and proportions in CorrectionHierarchy.lean, for the lexicographic order on Lex (V × ι), and derive copyStage_isStrictUpperTriangular from it. Co-Authored-By: Claude Opus 5.5 --- .../LinearAlgebra/Matrix/CopyStage.lean | 10 ++++------ .../LinearAlgebra/Matrix/CorrectionHierarchy.lean | 14 ++++++++++++++ 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/Complexity/Foundations/LinearAlgebra/Matrix/CopyStage.lean b/Complexity/Foundations/LinearAlgebra/Matrix/CopyStage.lean index f261da8d2..aaad7308f 100644 --- a/Complexity/Foundations/LinearAlgebra/Matrix/CopyStage.lean +++ b/Complexity/Foundations/LinearAlgebra/Matrix/CopyStage.lean @@ -354,12 +354,10 @@ copies of the overloaded vertices `O`. -/ /-- **The copy step stays strictly upper triangular** for the lexicographic order on the copies: `(x, i)` comes before `(y, j)` when `x < y`, or `x = y` and `i < j`. Indexed by `Lex (V × Fin (m + 1))`, which is linearly ordered when `V` is, the copy step can be the input of -the next stage. -/ -theorem copyStage_isStrictUpperTriangular [Preorder V] (hD : D.IsStrictUpperTriangular) : - ((copyStage χ m r D).submatrix ofLex ofLex).IsStrictUpperTriangular := by - intro a b hab - simp only [submatrix_apply, copyStage, copySplit, of_apply] - rw [hD fun h => hab (Prod.Lex.lt_iff.2 (Or.inl h)), mul_zero, zero_mul] +the next stage (`Matrix.copySplit_isStrictUpperTriangular`). -/ +theorem copyStage_isStrictUpperTriangular [LT V] (hD : D.IsStrictUpperTriangular) : + ((copyStage χ m r D).submatrix ofLex ofLex).IsStrictUpperTriangular := + copySplit_isStrictUpperTriangular hD theorem card_copyCover_le [DecidableEq V] (A O : Finset V) : #(copyCover (m := m) A O) ≤ #A + m * #O := by diff --git a/Complexity/Foundations/LinearAlgebra/Matrix/CorrectionHierarchy.lean b/Complexity/Foundations/LinearAlgebra/Matrix/CorrectionHierarchy.lean index 2420fb961..07f8e44b7 100644 --- a/Complexity/Foundations/LinearAlgebra/Matrix/CorrectionHierarchy.lean +++ b/Complexity/Foundations/LinearAlgebra/Matrix/CorrectionHierarchy.lean @@ -67,6 +67,8 @@ the copies (factorial truncation, detectors) are not part of this file. `E`. * `Matrix.correction_mulVec_one_le`: nonnegative corrections do not increase row sums. * `Matrix.copySplit_mul_copyWeight`: a copy step intertwines with its projection. +* `Matrix.copySplit_isStrictUpperTriangular`: a copy step stays strictly upper triangular for the + lexicographic order on the copies. * `Matrix.mul_copyProjection`, `Matrix.rewardTransport_mulVec`: the reward transport identity. * `Matrix.rewardTransport_mulVec_nonneg`, `Matrix.rewardTransport_mulVec_le`: the stage rewards lie between `0` and the projected solution. @@ -258,6 +260,18 @@ theorem copySplit_nonneg [Semiring R] [PartialOrder R] [IsOrderedRing R] {r : ι 0 ≤ copySplit r s D a b := mul_nonneg (mul_nonneg (hr _ _) (hD _ _)) (hs _ _ _) +/-- **Copies stay strictly upper triangular** for the lexicographic order on the copies: `(x, i)` +comes before `(y, j)` when `x < y`, or `x = y` and `i < j`. Indexed by `Lex (V × ι)`, which is +linearly ordered when `V` and `ι` are, a copy step of a strictly upper triangular matrix can be +corrected and copied again. Only the order of the parents matters: an entry from `(x, i)` to +`(y, j)` vanishes unless `x < y`. -/ +theorem copySplit_isStrictUpperTriangular [LT V] [LT ι] [MulZeroClass R] {r : ι → V → R} + {s : V → V → ι → R} {D : Matrix V V R} (hD : D.IsStrictUpperTriangular) : + ((copySplit r s D).submatrix ofLex ofLex).IsStrictUpperTriangular := by + intro a b hab + simp only [submatrix_apply, copySplit, of_apply] + rw [hD fun h => hab (Prod.Lex.lt_iff.2 (Or.inl h)), mul_zero, zero_mul] + /-- **Copies keep row sums at most one** when the weights lie in `[0, 1]`, `D` is nonnegative with row sums at most one, and the proportions of each entry sum to at most one. Together with `Matrix.copySplit_nonneg` this makes the copy step substochastic. -/ From 53de6a3f649ab48909a0733d9b7699608cffad88 Mon Sep 17 00:00:00 2001 From: Christian Reitwiessner Date: Fri, 30 Oct 2026 00:33:24 +0000 Subject: [PATCH 19/25] 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 f1303d90f2b557e87bcb16959dc2ba517631af8e Mon Sep 17 00:00:00 2001 From: Christian Reitwiessner Date: Fri, 30 Oct 2026 01:08:54 +0000 Subject: [PATCH 20/25] feat(Foundations): pilot with step-dependent multipliers and probabilistic column detectors Phase 2 slice 4 of #1444 (tracked in #1679): the pilot of Lemma 4.2 with step-dependent multipliers, the column detector of Lemma 4.3 over an abstract retention-channel interface, and one stage of the hierarchy whose multipliers, copy weights and overloaded set come from the detector, discharging the detector interface of copyStage_rates. Co-Authored-By: Claude Opus 5.5 --- Complexity.lean | 4 + .../Foundations/Data/Finset/KthLargest.lean | 116 +++++ .../LinearAlgebra/Matrix/PilotCorrection.lean | 331 ++++++++++++ .../Probability/ColumnDetector.lean | 469 ++++++++++++++++++ .../Probability/DetectedStage.lean | 295 +++++++++++ ComplexityTests/Detectors.lean | 215 ++++++++ ComplexityTests/KthLargest.lean | 53 ++ 7 files changed, 1483 insertions(+) create mode 100644 Complexity/Foundations/Data/Finset/KthLargest.lean create mode 100644 Complexity/Foundations/LinearAlgebra/Matrix/PilotCorrection.lean create mode 100644 Complexity/Foundations/Probability/ColumnDetector.lean create mode 100644 Complexity/Foundations/Probability/DetectedStage.lean create mode 100644 ComplexityTests/Detectors.lean create mode 100644 ComplexityTests/KthLargest.lean diff --git a/Complexity.lean b/Complexity.lean index 2a5c4feb0..28144e01a 100644 --- a/Complexity.lean +++ b/Complexity.lean @@ -2497,6 +2497,7 @@ public import Complexity.Foundations.Data.Fin.Tuple public import Complexity.Foundations.Data.Finset.Average public import Complexity.Foundations.Data.Finset.Expect public import Complexity.Foundations.Data.Finset.Finpartition +public import Complexity.Foundations.Data.Finset.KthLargest public import Complexity.Foundations.Data.Finset.Markov public import Complexity.Foundations.Data.Finset.OrderGlue public import Complexity.Foundations.Data.Finset.OrderedFilter @@ -2628,6 +2629,7 @@ public import Complexity.Foundations.LinearAlgebra.Matrix.Kronecker public import Complexity.Foundations.LinearAlgebra.Matrix.Lindsey public import Complexity.Foundations.LinearAlgebra.Matrix.ListProd public import Complexity.Foundations.LinearAlgebra.Matrix.Moore +public import Complexity.Foundations.LinearAlgebra.Matrix.PilotCorrection public import Complexity.Foundations.LinearAlgebra.Matrix.Rank public import Complexity.Foundations.LinearAlgebra.Matrix.RectPermanent public import Complexity.Foundations.LinearAlgebra.Matrix.SchurComplement @@ -2650,6 +2652,8 @@ 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.ColumnDetector +public import Complexity.Foundations.Probability.DetectedStage public import Complexity.Foundations.Probability.Gaussian.Multivariate public import Complexity.Foundations.Probability.Gaussian.Real public import Complexity.Foundations.Probability.Gaussian.Sheppard diff --git a/Complexity/Foundations/Data/Finset/KthLargest.lean b/Complexity/Foundations/Data/Finset/KthLargest.lean new file mode 100644 index 000000000..b1198aef3 --- /dev/null +++ b/Complexity/Foundations/Data/Finset/KthLargest.lean @@ -0,0 +1,116 @@ +/- +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.Data.Finset.Max + +/-! +# The `k`-th largest value, padded with zeros + +`Finset.kthLargest k s h` is the `k`-th largest member of the multiset of values `h x`, `x ∈ s`, +padded with infinitely many zeros. It is the largest value `h x` that is reached or exceeded by at +least `k` of the values, or `0` if that is larger. So it is nonnegative, and it is `0` when fewer +than `k` of the values are positive. This is the order statistic `rank_k` of the detectors in the +OpenAI preprint [OpenAI2026LogSpace, Section 4.2]. + +It is characterized by threshold counts: for `0 < k` and `0 ≤ t`, the `k`-th largest value exceeds +`t` exactly when at least `k` values exceed `t` (`Finset.lt_kthLargest_iff`), and for `0 < t` it +is at least `t` exactly when at least `k` values are at least `t` (`Finset.le_kthLargest_iff`). + +## Main definitions + +* `Finset.kthLargest`: the `k`-th largest value, padded with zeros. + +## Main results + +* `Finset.kthLargest_nonneg`, `Finset.kthLargest_le`: bounds. +* `Finset.lt_kthLargest_iff`, `Finset.le_kthLargest_iff`: the threshold characterizations. + +## References + +* [OpenAI, *Exact Derandomization of Logarithmic Space: L = RL = BPL*][OpenAI2026LogSpace], + Section 4.2 (preprint, not peer reviewed) +-/ + +public section + +namespace Finset + +variable {α R : Type*} [LinearOrder R] [Zero R] + +/-- The **`k`-th largest value** of `h` on `s`, padded with zeros: the largest value `h x`, +`x ∈ s`, that at least `k` values `h w`, `w ∈ s`, reach or exceed, or `0` if that is larger. -/ +@[expose] def kthLargest (k : ℕ) (s : Finset α) (h : α → R) : R := + (insert 0 ((s.filter fun x => k ≤ #{w ∈ s | h x ≤ h w}).image h)).max' (insert_nonempty _ _) + +variable {k : ℕ} {s : Finset α} {h : α → R} {t : R} + +theorem kthLargest_nonneg : 0 ≤ kthLargest k s h := + le_max' _ _ (mem_insert_self _ _) + +/-- The `k`-th largest value is at most any nonnegative upper bound of the values. -/ +theorem kthLargest_le (ht : 0 ≤ t) (hh : ∀ x ∈ s, h x ≤ t) : kthLargest k s h ≤ t := by + refine max'_le _ _ _ fun a ha => ?_ + rcases mem_insert.mp ha with rfl | ha + · exact ht + · obtain ⟨x, hx, rfl⟩ := mem_image.mp ha + exact hh x (mem_filter.mp hx).1 + +/-- A value of `s` reached or exceeded by at least `k` values is at most the `k`-th largest. -/ +private theorem le_kthLargest_of_le_card {x : α} (hx : x ∈ s) + (hk : k ≤ #{w ∈ s | h x ≤ h w}) : h x ≤ kthLargest k s h := + le_max' _ _ (mem_insert_of_mem (mem_image_of_mem h (mem_filter.mpr ⟨hx, hk⟩))) + +omit [Zero R] in +/-- If at least `k > 0` values satisfy a threshold condition, so does the smallest of them, which +is reached or exceeded by all of them. -/ +private theorem exists_le_card (hk : 0 < k) (p : R → Prop) [DecidablePred p] + (hp : k ≤ #{x ∈ s | p (h x)}) : + ∃ x ∈ s, p (h x) ∧ k ≤ #{w ∈ s | h x ≤ h w} := by + have hne : ({x ∈ s | p (h x)} : Finset α).Nonempty := card_pos.mp (hk.trans_le hp) + obtain ⟨x, hx, hmin⟩ := exists_min_image _ h hne + obtain ⟨hxs, hpx⟩ := mem_filter.mp hx + refine ⟨x, hxs, hpx, hp.trans (card_le_card fun w hw => ?_)⟩ + exact mem_filter.mpr ⟨(mem_filter.mp hw).1, hmin w hw⟩ + +/-- **The `k`-th largest value exceeds `t ≥ 0`** exactly when at least `k > 0` values do. -/ +theorem lt_kthLargest_iff (hk : 0 < k) (ht : 0 ≤ t) : + t < kthLargest k s h ↔ k ≤ #{x ∈ s | t < h x} := by + constructor + · intro hlt + obtain ⟨a, ha, hta⟩ : ∃ a ∈ _, t < a := ⟨_, max'_mem _ _, hlt⟩ + rcases mem_insert.mp ha with rfl | ha + · exact absurd ht (not_le.mpr hta) + obtain ⟨x, hx, rfl⟩ := mem_image.mp ha + obtain ⟨-, hkx⟩ := mem_filter.mp hx + exact hkx.trans (card_le_card fun w hw => by + obtain ⟨hws, hxw⟩ := mem_filter.mp hw + exact mem_filter.mpr ⟨hws, hta.trans_le hxw⟩) + · intro hcard + obtain ⟨x, hxs, htx, hkx⟩ := exists_le_card hk (t < ·) hcard + exact htx.trans_le (le_kthLargest_of_le_card hxs hkx) + +/-- **The `k`-th largest value is at least `t > 0`** exactly when at least `k > 0` values are. -/ +theorem le_kthLargest_iff (hk : 0 < k) (ht : 0 < t) : + t ≤ kthLargest k s h ↔ k ≤ #{x ∈ s | t ≤ h x} := by + constructor + · intro hle + obtain ⟨a, ha, hta⟩ : ∃ a ∈ _, t ≤ a := ⟨_, max'_mem _ _, hle⟩ + rcases mem_insert.mp ha with rfl | ha + · exact absurd ht (not_lt.mpr hta) + obtain ⟨x, hx, rfl⟩ := mem_image.mp ha + obtain ⟨-, hkx⟩ := mem_filter.mp hx + exact hkx.trans (card_le_card fun w hw => by + obtain ⟨hws, hxw⟩ := mem_filter.mp hw + exact mem_filter.mpr ⟨hws, hta.trans hxw⟩) + · intro hcard + obtain ⟨x, hxs, htx, hkx⟩ := exists_le_card hk (t ≤ ·) hcard + exact htx.trans (le_kthLargest_of_le_card hxs hkx) + +end Finset diff --git a/Complexity/Foundations/LinearAlgebra/Matrix/PilotCorrection.lean b/Complexity/Foundations/LinearAlgebra/Matrix/PilotCorrection.lean new file mode 100644 index 000000000..a6aa6efe3 --- /dev/null +++ b/Complexity/Foundations/LinearAlgebra/Matrix/PilotCorrection.lean @@ -0,0 +1,331 @@ +/- +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.LinearAlgebra.Matrix.FactorialTruncation + +/-! +# The pilot correction with step-dependent multipliers + +In the correction-and-copy hierarchy of the OpenAI preprint (2026-09-23), Section 4.2, idea 3 in +issue #474 [OpenAI2026LogSpace], the column multiplier of the cutoff correction is chosen by a +*pilot*: a run of the correction recursion in which the multiplier may decrease from step to +step. At step `i + 1` the pilot forms its input `G = C + Ê_i C`, evaluates a column number +`U G y` on it (in the preprint a detector, see `Complexity.Foundations.Probability.ColumnDetector`), +takes the running maximum `M_(i+1) = M_i ⊔ U G`, and sets +`Ê_(i+1) x y = c (G x y) * γ (M_(i+1) y)` for a base cutoff `c` and a nonincreasing `γ` +(`Matrix.pilotCorrection`, `Matrix.pilotMax`, `Matrix.pilotInput`). The actual correction then +runs the fixed-multiplier recursion `Matrix.cutoffCorrectionIter` with the final multiplier +`γ (M_k y)`. + +All bounds of [OpenAI2026LogSpace, Lemma 4.2] hold for any sequence of corrections that starts at +zero and stays between zero and its input, `0 ≤ F (i + 1) ≤ C + F i C` +(`Matrix.IsCorrectionSeq`). Both the pilot (`Matrix.isCorrectionSeq_pilotCorrection`) and the +fixed-multiplier recursion (`Matrix.isCorrectionSeq_cutoffCorrectionIter`) are of this form. For +a substochastic `C` with entries at most `f`, the `i`-th correction and the input of step `i + 1` +have row sums at most `i` and `i + 1` and entries at most `i f` and `(i + 1) f`; they are +supported within any cover of the support of `C`, and strictly upper triangular when `C` is. +Since the running maximum only grows and `γ` is nonincreasing, the actual correction and its inputs +are bounded by those of the pilot (`Matrix.cutoffCorrectionIter_le_pilotCorrection`). + +## Main definitions + +* `Matrix.IsCorrectionSeq`: corrections starting at zero and dominated by their inputs. +* `Matrix.pilotCorrection`, `Matrix.pilotMax`, `Matrix.pilotInput`: the pilot. + +## Main results + +* `Matrix.IsCorrectionSeq.sum_le`, `Matrix.IsCorrectionSeq.sum_input_le`, + `Matrix.IsCorrectionSeq.le_mul`, `Matrix.IsCorrectionSeq.input_le_mul`: row-sum and entry + bounds. +* `Matrix.IsCorrectionSeq.mem`, `Matrix.IsCorrectionSeq.input_mem`: supports. +* `Matrix.IsCorrectionSeq.isStrictUpperTriangular`, + `Matrix.IsCorrectionSeq.input_isStrictUpperTriangular`: strict forwardness. +* `Matrix.isCorrectionSeq_cutoffCorrectionIter`, `Matrix.isCorrectionSeq_pilotCorrection`: the + actual correction and the pilot are correction sequences. +* `Matrix.cutoffCorrectionIter_le_of_isCorrectionSeq`: comparison with a dominating sequence. +* `Matrix.pilotMax_mono`, `Matrix.exists_lt_pilotInput_of_lt_pilotMax`: the running maximum. +* `Matrix.cutoffCorrectionIter_le_pilotCorrection`: the actual correction is at most the pilot. + +## References + +* [OpenAI, *Exact Derandomization of Logarithmic Space: L = RL = BPL*][OpenAI2026LogSpace], + Section 4.2 and Lemma 4.2 (preprint, not peer reviewed) +-/ + +public section + +open Finset + +namespace Matrix + +variable {V : Type*} [Fintype V] {F : ℕ → Matrix V V ℝ} {f : ℝ} + +/-- `F` is a **correction sequence** for `C`: it starts at zero, and each correction lies between +zero and its input, `0 ≤ F (i + 1) ≤ C + F i * C` entrywise. The pilot of the preprint, with +step-dependent multipliers, and the actual correction, with a fixed multiplier, are both of this +form [OpenAI2026LogSpace, Lemma 4.2]. -/ +structure IsCorrectionSeq (C : Matrix V V ℝ) (F : ℕ → Matrix V V ℝ) : Prop where + zero : F 0 = 0 + nonneg_succ : ∀ i x y, 0 ≤ F (i + 1) x y + le_input : ∀ i x y, F (i + 1) x y ≤ (C + F i * C) x y + +section Sequence + +variable {C : Matrix V V ℝ} + +namespace IsCorrectionSeq + +variable (hF : IsCorrectionSeq C F) +include hF + +theorem nonneg (i : ℕ) (x y : V) : 0 ≤ F i x y := by + cases i with + | zero => simp [hF.zero] + | succ i => exact hF.nonneg_succ i x y + +theorem input_nonneg (hC0 : ∀ x y, 0 ≤ C x y) (i : ℕ) (x y : V) : 0 ≤ (C + F i * C) x y := + add_nonneg (hC0 x y) (sum_nonneg fun z _ => mul_nonneg (hF.nonneg i x z) (hC0 z y)) + +/-- **Row sums of the corrections**: the `i`-th correction of a substochastic `C` has row sums at +most `i`, and the input of step `i + 1` at most `i + 1` [OpenAI2026LogSpace, Lemma 4.2]. -/ +theorem sum_input_le (hC1 : C *ᵥ 1 ≤ 1) : + ∀ i x, ∑ y, (C + F i * C) x y ≤ i + 1 ∧ ∑ y, F i x y ≤ i := by + have hrow : ∀ z, ∑ y, C z y ≤ 1 := fun z => by simpa [mulVec, dotProduct] using hC1 z + have hinput : ∀ i x, ∑ y, F i x y ≤ i → ∑ y, (C + F i * C) x y ≤ i + 1 := fun i x hi => by + calc ∑ y, (C + F i * C) x y = ∑ y, C x y + ∑ z, F i x z * ∑ y, C z y := by + simp only [add_apply, mul_apply, sum_add_distrib, mul_sum] + rw [sum_comm] + _ ≤ 1 + ∑ z, F i x z * 1 := add_le_add (hrow x) (sum_le_sum fun z _ => + mul_le_mul_of_nonneg_left (hrow z) (hF.nonneg i x z)) + _ ≤ i + 1 := by simp only [mul_one]; linarith + intro i + induction i with + | zero => intro x; simpa [hF.zero] using hinput 0 x (by simp [hF.zero]) + | succ i ih => + intro x + have hsum : ∑ y, F (i + 1) x y ≤ (i + 1 : ℕ) := by + push_cast + exact (sum_le_sum fun y _ => hF.le_input i x y).trans (ih x).1 + exact ⟨hinput _ x hsum, hsum⟩ + +theorem sum_le (hC1 : C *ᵥ 1 ≤ 1) (i : ℕ) (x : V) : ∑ y, F i x y ≤ i := + (hF.sum_input_le hC1 i x).2 + +/-- **Entries of the inputs**: the input of step `i + 1` has entries at most `(i + 1) f` +[OpenAI2026LogSpace, Lemma 4.2]. -/ +theorem input_le_mul (hCf : ∀ x y, C x y ≤ f) (hf : 0 ≤ f) (hC1 : C *ᵥ 1 ≤ 1) (i : ℕ) + (x y : V) : (C + F i * C) x y ≤ (i + 1) * f := by + have hsum := hF.sum_le hC1 i x + calc (C + F i * C) x y = C x y + ∑ z, F i x z * C z y := rfl + _ ≤ f + ∑ z, F i x z * f := add_le_add (hCf x y) + (sum_le_sum fun z _ => mul_le_mul_of_nonneg_left (hCf z y) (hF.nonneg i x z)) + _ ≤ (i + 1) * f := by rw [← sum_mul]; nlinarith + +/-- **Entries of the corrections**: the `i`-th correction has entries at most `i f` +[OpenAI2026LogSpace, Lemma 4.2]. -/ +theorem le_mul (hCf : ∀ x y, C x y ≤ f) (hf : 0 ≤ f) (hC1 : C *ᵥ 1 ≤ 1) (i : ℕ) (x y : V) : + F i x y ≤ i * f := by + cases i with + | zero => simp [hF.zero] + | succ i => + push_cast + exact (hF.le_input i x y).trans (hF.input_le_mul hCf hf hC1 i x y) + +variable {A : Finset V} + +/-- The corrections and the inputs are supported within any set `A` covering the support of `C` +[OpenAI2026LogSpace, Lemma 4.2]. -/ +theorem input_mem_and_mem (hA : ∀ x y, C x y ≠ 0 → x ∈ A ∧ y ∈ A) : + ∀ i x y, ((C + F i * C) x y ≠ 0 → x ∈ A ∧ y ∈ A) ∧ (F i x y ≠ 0 → x ∈ A ∧ y ∈ A) := by + have hinput : ∀ i, (∀ x y, F i x y ≠ 0 → x ∈ A ∧ y ∈ A) → + ∀ x y, (C + F i * C) x y ≠ 0 → x ∈ A ∧ y ∈ A := fun i hi x y h => by + by_contra hxy + apply h + have hCxy : C x y = 0 := by by_contra h'; exact hxy (hA x y h') + simp only [add_apply, mul_apply, hCxy, zero_add] + refine sum_eq_zero fun z _ => ?_ + by_cases hE : F i x z = 0 + · rw [hE, zero_mul] + by_cases hCz : C z y = 0 + · rw [hCz, mul_zero] + exact absurd ⟨(hi x z hE).1, (hA z y hCz).2⟩ hxy + intro i + induction i with + | zero => + have h0 : ∀ x y, F 0 x y ≠ 0 → x ∈ A ∧ y ∈ A := fun x y h => by simp [hF.zero] at h + exact fun x y => ⟨hinput 0 h0 x y, h0 x y⟩ + | succ i ih => + have hi : ∀ x y, F (i + 1) x y ≠ 0 → x ∈ A ∧ y ∈ A := fun x y h => + (ih x y).1 fun h' => h (le_antisymm (h' ▸ hF.le_input i x y) (hF.nonneg_succ i x y)) + exact fun x y => ⟨hinput _ hi x y, hi x y⟩ + +theorem mem (hA : ∀ x y, C x y ≠ 0 → x ∈ A ∧ y ∈ A) (i : ℕ) (x y : V) (h : F i x y ≠ 0) : + x ∈ A ∧ y ∈ A := + (hF.input_mem_and_mem hA i x y).2 h + +theorem input_mem (hA : ∀ x y, C x y ≠ 0 → x ∈ A ∧ y ∈ A) (i : ℕ) (x y : V) + (h : (C + F i * C) x y ≠ 0) : x ∈ A ∧ y ∈ A := + (hF.input_mem_and_mem hA i x y).1 h + +/-- The corrections of a strictly upper triangular `C` are strictly upper triangular +[OpenAI2026LogSpace, Lemma 4.2]. -/ +theorem isStrictUpperTriangular [Preorder V] (hC : C.IsStrictUpperTriangular) (i : ℕ) : + (F i).IsStrictUpperTriangular := by + induction i with + | zero => intro x y _; simp [hF.zero] + | succ i ih => + intro x y hxy + have h := hF.le_input i x y + rw [(hC.add (ih.mul hC)) hxy] at h + exact le_antisymm h (hF.nonneg_succ i x y) + +theorem input_isStrictUpperTriangular [Preorder V] (hC : C.IsStrictUpperTriangular) (i : ℕ) : + (C + F i * C).IsStrictUpperTriangular := + hC.add ((hF.isStrictUpperTriangular hC i).mul hC) + +end IsCorrectionSeq + +/-- The fixed-multiplier recursion `Matrix.cutoffCorrectionIter` is a correction sequence when +the cutoffs satisfy `0 ≤ φ y t ≤ max (t - θ f) 0` with `0 ≤ θ f`. -/ +theorem isCorrectionSeq_cutoffCorrectionIter {φ : V → ℝ → ℝ} {θ : ℝ} (hC0 : ∀ x y, 0 ≤ C x y) + (hφ0 : ∀ y t, 0 ≤ φ y t) (hφθ : ∀ y t, φ y t ≤ max (t - θ * f) 0) (hθf : 0 ≤ θ * f) : + IsCorrectionSeq C (cutoffCorrectionIter φ C) where + zero := rfl + nonneg_succ i x y := cutoffCorrectionIter_nonneg hφ0 (i + 1) x y + le_input i x y := by + rw [cutoffCorrectionIter_succ] + refine (hφθ y _).trans (max_le (by linarith) ?_) + exact add_nonneg (hC0 x y) (sum_nonneg fun z _ => + mul_nonneg (cutoffCorrectionIter_nonneg hφ0 i x z) (hC0 z y)) + +/-- **Comparison with a dominating sequence**: if the cutoffs `φ y` are monotone and the first +`k` steps of `F` dominate the cutoffs of their own inputs, then the first `k` iterates of the +fixed-multiplier recursion, and their inputs, are at most those of `F` +[OpenAI2026LogSpace, Lemma 4.2]. -/ +theorem cutoffCorrectionIter_le_of_isCorrectionSeq {φ : V → ℝ → ℝ} (hC0 : ∀ x y, 0 ≤ C x y) + (hφm : ∀ y, Monotone (φ y)) {k : ℕ} + (hφF : ∀ i < k, ∀ x y, φ y ((C + F i * C) x y) ≤ F (i + 1) x y) (hF : IsCorrectionSeq C F) : + ∀ i ≤ k, ∀ x y, cutoffCorrectionIter φ C i x y ≤ F i x y ∧ + (C + cutoffCorrectionIter φ C i * C) x y ≤ (C + F i * C) x y := by + have hinput : ∀ i, (∀ x y, cutoffCorrectionIter φ C i x y ≤ F i x y) → + ∀ x y, (C + cutoffCorrectionIter φ C i * C) x y ≤ (C + F i * C) x y := + fun i hi x y => add_le_add_right (sum_le_sum fun z _ => + mul_le_mul_of_nonneg_right (hi x z) (hC0 z y)) _ + intro i + induction i with + | zero => + have h0 : ∀ x y, cutoffCorrectionIter φ C 0 x y ≤ F 0 x y := fun x y => by + simp [cutoffCorrectionIter, hF.zero] + exact fun _ x y => ⟨h0 x y, hinput 0 h0 x y⟩ + | succ i ih => + intro hik + have hi : ∀ x y, cutoffCorrectionIter φ C (i + 1) x y ≤ F (i + 1) x y := fun x y => by + rw [cutoffCorrectionIter_succ] + exact (hφm y ((ih (by omega) x y).2)).trans (hφF i (by omega) x y) + exact fun x y => ⟨hi x y, hinput _ hi x y⟩ + +end Sequence + +/-! ### The pilot -/ + +section Pilot + +variable (c γ : ℝ → ℝ) (U : Matrix V V ℝ → V → ℝ) (C : Matrix V V ℝ) + +/-- The **pilot** as a pair of the current correction and the running maximum of the column +numbers. Step `i + 1` forms the input `G = C + Ê_i C`, updates the running maximum to +`M_(i+1) = M_i ⊔ U G`, and sets `Ê_(i+1) x y = c (G x y) * γ (M_(i+1) y)` +[OpenAI2026LogSpace, (4.10)–(4.13)]. -/ +noncomputable def pilot : ℕ → Matrix V V ℝ × (V → ℝ) + | 0 => (0, 0) + | i + 1 => + let G := C + (pilot i).1 * C + let M := (pilot i).2 ⊔ U G + (of fun x y => c (G x y) * γ (M y), M) + +/-- The `i`-th pilot correction `Ê_i`. -/ +noncomputable def pilotCorrection (i : ℕ) : Matrix V V ℝ := (pilot c γ U C i).1 + +/-- The input `G = C + Ê_i C` of pilot step `i + 1`; the preprint's `G_(i+1)`. -/ +@[expose] noncomputable def pilotInput (i : ℕ) : Matrix V V ℝ := C + pilotCorrection c γ U C i * C + +/-- The running maximum `M_i = max (0, U G_1, …, U G_i)` of the column numbers after `i` pilot +steps. The pilot multiplier of step `i` is `γ (M_i y)`. -/ +noncomputable def pilotMax (i : ℕ) : V → ℝ := (pilot c γ U C i).2 + +variable {c γ U C} + +@[simp] theorem pilotCorrection_zero : pilotCorrection c γ U C 0 = 0 := by rfl + +@[simp] theorem pilotMax_zero : pilotMax c γ U C 0 = 0 := by rfl + +theorem pilotMax_succ (i : ℕ) : + pilotMax c γ U C (i + 1) = pilotMax c γ U C i ⊔ U (pilotInput c γ U C i) := by rfl + +theorem pilotCorrection_succ_apply (i : ℕ) (x y : V) : + pilotCorrection c γ U C (i + 1) x y = + c (pilotInput c γ U C i x y) * γ (pilotMax c γ U C (i + 1) y) := by rfl + +/-- The running maximum grows. -/ +theorem pilotMax_mono {i j : ℕ} (hij : i ≤ j) (y : V) : + pilotMax c γ U C i y ≤ pilotMax c γ U C j y := by + induction hij with + | refl => exact le_rfl + | step _ ih => exact ih.trans (by rw [pilotMax_succ]; exact le_sup_left) + +/-- If the running maximum after `k` steps exceeds `a ≥ 0`, some column number `U G_(i+1)`, +`i < k`, does. -/ +theorem exists_lt_pilotInput_of_lt_pilotMax {a : ℝ} (ha : 0 ≤ a) {k : ℕ} {y : V} + (h : a < pilotMax c γ U C k y) : ∃ i < k, a < U (pilotInput c γ U C i) y := by + induction k with + | zero => exact absurd h (not_lt.mpr ha) + | succ k ih => + rw [pilotMax_succ, Pi.sup_apply, lt_sup_iff] at h + rcases h with h | h + · obtain ⟨i, hi, hU⟩ := ih h + exact ⟨i, by omega, hU⟩ + · exact ⟨k, by omega, h⟩ + +/-- **The pilot is a correction sequence** when the base cutoff satisfies `0 ≤ c t ≤ t` for +`t ≥ 0` and the multipliers lie in `[0, 1]` [OpenAI2026LogSpace, Lemma 4.2]. -/ +theorem isCorrectionSeq_pilotCorrection (hC0 : ∀ x y, 0 ≤ C x y) (hc0 : ∀ t, 0 ≤ c t) + (hct : ∀ t, 0 ≤ t → c t ≤ t) (hγ0 : ∀ t, 0 ≤ γ t) (hγ1 : ∀ t, γ t ≤ 1) : + IsCorrectionSeq C (pilotCorrection c γ U C) := by + have hnonneg : ∀ i x y, 0 ≤ pilotCorrection c γ U C (i + 1) x y := fun i x y => by + rw [pilotCorrection_succ_apply]; exact mul_nonneg (hc0 _) (hγ0 _) + have hall : ∀ i x y, 0 ≤ pilotCorrection c γ U C i x y := fun i x y => by + cases i with + | zero => simp + | succ i => exact hnonneg i x y + refine ⟨rfl, hnonneg, fun i x y => ?_⟩ + rw [pilotCorrection_succ_apply] + have hG : 0 ≤ pilotInput c γ U C i x y := + add_nonneg (hC0 x y) (sum_nonneg fun z _ => mul_nonneg (hall i x z) (hC0 z y)) + exact (mul_le_of_le_one_right (hc0 _) (hγ1 _)).trans (hct _ hG) + +/-- **The actual correction is at most the pilot.** Run the fixed-multiplier recursion with the +cutoffs `φ y t = c t * γ (M_k y)`, the final pilot multiplier. For a monotone nonnegative `c` and +a nonincreasing `γ`, its first `k` iterates and their inputs are at most the pilot corrections and +pilot inputs [OpenAI2026LogSpace, Lemma 4.2]. -/ +theorem cutoffCorrectionIter_le_pilotCorrection (hC0 : ∀ x y, 0 ≤ C x y) (hc0 : ∀ t, 0 ≤ c t) + (hct : ∀ t, 0 ≤ t → c t ≤ t) (hcm : Monotone c) (hγ0 : ∀ t, 0 ≤ γ t) (hγ1 : ∀ t, γ t ≤ 1) + (hγm : Antitone γ) {k i : ℕ} (hik : i ≤ k) (x y : V) : + cutoffCorrectionIter (fun y t => c t * γ (pilotMax c γ U C k y)) C i x y ≤ + pilotCorrection c γ U C i x y ∧ + (C + cutoffCorrectionIter (fun y t => c t * γ (pilotMax c γ U C k y)) C i * C) x y ≤ + pilotInput c γ U C i x y := by + refine cutoffCorrectionIter_le_of_isCorrectionSeq hC0 + (fun y => hcm.mul_const (hγ0 _)) (fun j hj x y => ?_) + (isCorrectionSeq_pilotCorrection hC0 hc0 hct hγ0 hγ1) i hik x y + rw [pilotCorrection_succ_apply] + exact mul_le_mul_of_nonneg_left (hγm (pilotMax_mono (by omega) y)) (hc0 _) + +end Pilot + +end Matrix diff --git a/Complexity/Foundations/Probability/ColumnDetector.lean b/Complexity/Foundations/Probability/ColumnDetector.lean new file mode 100644 index 000000000..5756f4530 --- /dev/null +++ b/Complexity/Foundations/Probability/ColumnDetector.lean @@ -0,0 +1,469 @@ +/- +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.KthLargest +public import Mathlib.Algebra.BigOperators.Expect +public import Mathlib.Data.Finset.Density +public import Mathlib.LinearAlgebra.Matrix.Defs +public import Mathlib.Basic.Real.Basic +import Complexity.Foundations.Data.Finset.Markov +import Mathlib.Algebra.Order.BigOperators.Expect +import Mathlib.Algebra.BigOperators.Field +import Mathlib.Algebra.BigOperators.Ring.Finset +import Mathlib.Tactic.FieldSimp +import Mathlib.Tactic.Linarith +import Mathlib.Tactic.Positivity + +/-! +# Column detectors from retention channels + +A *column detector* decides, with true expectations over random retained sets, whether a column +of a nonnegative matrix `G` has many substantial entries. It is the detector of the OpenAI preprint +(2026-09-23), Section 4.2, idea 3 in issue #474 [OpenAI2026LogSpace], which chooses the column +multipliers of the correction-and-copy hierarchy. + +**Channels.** Two *retention channels* `X : ι → V → Prop` and `Y : κ → V → Prop` select random +sets of vertices from independent uniform seeds `s : ι` and `t : κ`; independence is built in, +since the seed space is the product `ι × κ`. `Cslib.Probability.RetentionChannels` records the +properties that the detector uses, at rate `f` [OpenAI2026LogSpace, (4.8), (4.9)]: + +* every vertex is retained with the same probability `π`, with `c_π f ≤ π ≤ C_π f`; +* for `w ≠ y`, `Pr[Y(w) ∧ Y(y)] ≤ C_pair f Pr[Y(y)]`; +* a nonempty set `A` retains fewer than `|A| π / 2` members of `X` with probability at most + `C_var / (|A| π)`. + +**The detector.** For a draw `T` of the terminal channel `Y`, the *row gate* of row `x` is +`ρ (rank_K {G x w / f : w ∈ T})` (`Matrix.rowGate`); it is one unless `K` retained entries of the +row exceed `η f`. For a draw `S` of the start channel `X`, the *trial* at column `y` is +`rank_J {ϕ (G x y / f) * gate x : x ∈ S}` (`Matrix.detectorTrial`), where `rank_j` is the `j`-th +largest value padded with zeros (`Finset.kthLargest`). The *detector number* `U y` is the +expectation of the trial over both channels, conditioned on `Y(y)` (`Matrix.columnDetector`). + +**The detector lemma** [OpenAI2026LogSpace, Lemma 4.3]. Let `ϕ` be zero through `δ₀` and one from +`δ₁`, and `ρ` one through `η > 0`, both with values in `[0, 1]`. + +1. If the rows of `G ≥ 0` sum to at most `k`, the gate rank satisfies `K ≥ 160 (1 + C_pair k / η)`, + and `R` satisfies `c_π R ≥ max (4 J, 40 C_var)`, then a column with more than `R / f` entries + at least `δ₁ f` has `U y ≥ 19 / 20` (`Matrix.le_columnDetector`). +2. If `U y > 1 / 4`, the column has more than `J / (4 C_π f)` entries above `δ₀ f` + (`Matrix.lt_card_of_lt_columnDetector`). + +Each statement uses only the hypotheses it needs; for instance the second needs neither the +row-sum bound nor the row gates' threshold. + +The first statement uses no independence between the row gates of different rows; it combines +Markov's inequality for the gate failures with the lower tail of the start channel. + +## Main definitions + +* `Cslib.Probability.RetentionChannels`: the channel properties used by the detector. +* `Matrix.rowGate`, `Matrix.detectorTrial`, `Matrix.columnDetector`: the detector. + +## Main results + +* `Matrix.columnDetector_nonneg`, `Matrix.columnDetector_le_one`: detector numbers lie in `[0, 1]`. +* `Matrix.le_columnDetector`: columns with many large entries are detected. +* `Matrix.lt_card_of_lt_columnDetector`: detected columns have many substantial entries. + +## References + +* [OpenAI, *Exact Derandomization of Logarithmic Space: L = RL = BPL*][OpenAI2026LogSpace], + Section 4.2 and Lemma 4.3 (preprint, not peer reviewed) +-/ + +public section + +open Finset +open scoped BigOperators + +namespace Cslib.Probability + +/-- **Retention channels** `X` and `Y` at rate `f`, with independent uniform seeds `s : ι` and +`t : κ`: every vertex is retained by either channel with the same probability `π`, +`c_π f ≤ π ≤ C_π f`; two distinct vertices `w ≠ y` are both retained by `Y` with probability at +most `C_pair f` times that of `y`; and a nonempty set `A` retains fewer than `|A| π / 2` members +of `X` with probability at most `C_var / (|A| π)`. These are the properties +[OpenAI2026LogSpace, (4.8), (4.9)] that the detectors use. -/ +structure RetentionChannels {V ι κ : Type*} [Fintype ι] [Fintype κ] (X : ι → V → Prop) + (Y : κ → V → Prop) [∀ s v, Decidable (X s v)] [∀ t v, Decidable (Y t v)] + (f π cπ Cπ Cpair Cvar : ℝ) : Prop where + dens_X : ∀ v, (dens {s | X s v} : ℝ) = π + dens_Y : ∀ v, (dens {t | Y t v} : ℝ) = π + lower : cπ * f ≤ π + upper : π ≤ Cπ * f + pair : ∀ w y, w ≠ y → (dens {t | Y t w ∧ Y t y} : ℝ) ≤ Cpair * f * dens {t | Y t y} + tail : ∀ A : Finset V, A.Nonempty → + (dens {s | 2 * (#{x ∈ A | X s x} : ℝ) < #A * π} : ℝ) ≤ Cvar / (#A * π) + +end Cslib.Probability + +namespace Matrix + +open Cslib.Probability + +variable {V ι κ : Type*} [Fintype V] [Fintype ι] [Fintype κ] + +section Definitions + +/-- The **row gate** of row `x` for a draw `T` of the terminal channel: +`ρ (rank_K {G x w / f : w ∈ T})` [OpenAI2026LogSpace, (4.11)]. -/ +@[expose] noncomputable def rowGate (ρ : ℝ → ℝ) (K : ℕ) (f : ℝ) (G : Matrix V V ℝ) + (T : Finset V) (x : V) : ℝ := + ρ (kthLargest K T fun w => G x w / f) + +/-- A **detector trial** at column `y`, for draws `S` of the start channel and `T` of the terminal +channel: `rank_J {ϕ (G x y / f) * rowGate x : x ∈ S}` [OpenAI2026LogSpace, (4.12)]. -/ +@[expose] noncomputable def detectorTrial (ϕ ρ : ℝ → ℝ) (J K : ℕ) (f : ℝ) (G : Matrix V V ℝ) + (S T : Finset V) (y : V) : ℝ := + kthLargest J S fun x => ϕ (G x y / f) * rowGate ρ K f G T x + +/-- The **detector number** of column `y`: the expectation of the detector trial over the seeds of +both channels, conditioned on `Y(y)` [OpenAI2026LogSpace, (4.12)]. -/ +@[expose] noncomputable def columnDetector (X : ι → V → Prop) (Y : κ → V → Prop) + [∀ s v, Decidable (X s v)] [∀ t v, Decidable (Y t v)] (ϕ ρ : ℝ → ℝ) (J K : ℕ) (f : ℝ) + (G : Matrix V V ℝ) (y : V) : ℝ := + 𝔼 s, 𝔼 t ∈ {t | Y t y}, detectorTrial ϕ ρ J K f G {x | X s x} {w | Y t w} y + +end Definitions + +variable {X : ι → V → Prop} {Y : κ → V → Prop} [∀ s v, Decidable (X s v)] + [∀ t v, Decidable (Y t v)] {ϕ ρ : ℝ → ℝ} {J K : ℕ} {f : ℝ} {G : Matrix V V ℝ} {y : V} + +private theorem dens_cast {α : Type*} [Fintype α] (s : Finset α) : + ((dens s : ℚ≥0) : ℝ) = #s / Fintype.card α := by + rw [dens_eq_card_div_card]; push_cast; rfl + +private theorem columnDetector_eq_sum : + columnDetector X Y ϕ ρ J K f G y = + (∑ s, ∑ t ∈ {t | Y t y}, detectorTrial ϕ ρ J K f G {x | X s x} {w | Y t w} y) / + (Fintype.card ι * #({t | Y t y} : Finset κ)) := by + rw [columnDetector, Fintype.expect_eq_sum_div_card] + simp only [expect_eq_sum_div_card] + rw [← Finset.sum_div, div_div, mul_comm (#({t | Y t y} : Finset κ) : ℝ)] + +omit [Fintype V] in +theorem detectorTrial_nonneg {S T : Finset V} : 0 ≤ detectorTrial ϕ ρ J K f G S T y := + kthLargest_nonneg + +omit [Fintype V] in +theorem detectorTrial_le_one (hϕ0 : ∀ t, 0 ≤ ϕ t) (hϕ1 : ∀ t, ϕ t ≤ 1) + (hρ1 : ∀ t, ρ t ≤ 1) {S T : Finset V} : detectorTrial ϕ ρ J K f G S T y ≤ 1 := + kthLargest_le zero_le_one fun _ _ => + (mul_le_mul_of_nonneg_left (hρ1 _) (hϕ0 _)).trans (by rw [mul_one]; exact hϕ1 _) + +theorem columnDetector_nonneg : 0 ≤ columnDetector X Y ϕ ρ J K f G y := by + rw [columnDetector] + exact expect_nonneg fun _ _ => expect_nonneg fun _ _ => detectorTrial_nonneg + +theorem columnDetector_le_one (hϕ0 : ∀ t, 0 ≤ ϕ t) (hϕ1 : ∀ t, ϕ t ≤ 1) + (hρ1 : ∀ t, ρ t ≤ 1) : columnDetector X Y ϕ ρ J K f G y ≤ 1 := by + rw [columnDetector_eq_sum] + refine div_le_one_of_le₀ ?_ (by positivity) + calc ∑ s, ∑ t ∈ {t | Y t y}, detectorTrial ϕ ρ J K f G {x | X s x} {w | Y t w} y + ≤ ∑ _s : ι, ∑ _t ∈ ({t | Y t y} : Finset κ), (1 : ℝ) := + sum_le_sum fun _ _ => sum_le_sum fun _ _ => detectorTrial_le_one hϕ0 hϕ1 hρ1 + _ = Fintype.card ι * #({t | Y t y} : Finset κ) := by + simp only [sum_const, card_univ, nsmul_eq_mul, mul_one] + +variable {π cπ Cπ Cpair Cvar : ℝ} + +omit [Fintype V] in +private theorem card_X (hch : RetentionChannels X Y f π cπ Cπ Cpair Cvar) (v : V) : + (#({s | X s v} : Finset ι) : ℝ) = π * Fintype.card ι := by + have h := hch.dens_X v + rw [dens_cast] at h + rcases (Fintype.card ι).eq_zero_or_pos with h0 | h0 + · have : (#({s | X s v} : Finset ι)) = 0 := Nat.eq_zero_of_le_zero + (h0 ▸ card_le_univ _) + simp [this, h0] + · rw [← h]; field_simp + +/-- **Detected columns have many substantial entries** [OpenAI2026LogSpace, Lemma 4.3 (2)]: if +`ϕ` vanishes through `δ₀` and the detector number of column `y` exceeds `1 / 4`, more than +`J / (4 C_π f)` entries of the column exceed `δ₀ f`. -/ +theorem lt_card_of_lt_columnDetector (hch : RetentionChannels X Y f π cπ Cπ Cpair Cvar) + (hf : 0 < f) (hϕ0 : ∀ t, 0 ≤ ϕ t) (hϕ1 : ∀ t, ϕ t ≤ 1) {δ₀ : ℝ} + (hϕδ : ∀ t, t ≤ δ₀ → ϕ t = 0) (hρ1 : ∀ t, ρ t ≤ 1) (hJ : 0 < J) + (hU : 1 / 4 < columnDetector X Y ϕ ρ J K f G y) : + J / (4 * Cπ * f) < #({x | δ₀ * f < G x y} : Finset V) := by + set A0 : Finset V := {x | δ₀ * f < G x y} + set T : Finset κ := {t | Y t y} + have hJr : (0 : ℝ) < J := by exact_mod_cast hJ + -- a trial is at most the number of retained substantial entries over `J` + have htrial : ∀ s t, detectorTrial ϕ ρ J K f G {x | X s x} {w | Y t w} y ≤ + (#{x ∈ A0 | X s x} : ℝ) / J := by + intro s t + rcases le_or_gt (detectorTrial ϕ ρ J K f G {x | X s x} {w | Y t w} y) 0 with h | h + · exact h.trans (by positivity) + have hcard := (lt_kthLargest_iff hJ le_rfl).mp h + have hsub : ({x ∈ ({x | X s x} : Finset V) | + 0 < ϕ (G x y / f) * rowGate ρ K f G {w | Y t w} x}) ⊆ {x ∈ A0 | X s x} := by + intro x hx + simp only [mem_filter, mem_univ, true_and, A0] at hx ⊢ + refine ⟨?_, hx.1⟩ + by_contra hle + have : G x y / f ≤ δ₀ := by rw [div_le_iff₀ hf]; linarith + rw [hϕδ _ this, zero_mul] at hx + exact lt_irrefl _ hx.2 + have hJle : (J : ℝ) ≤ #{x ∈ A0 | X s x} := by exact_mod_cast hcard.trans (card_le_card hsub) + rw [le_div_iff₀ hJr] + calc detectorTrial ϕ ρ J K f G {x | X s x} {w | Y t w} y * J ≤ 1 * J := + mul_le_mul_of_nonneg_right (detectorTrial_le_one hϕ0 hϕ1 hρ1) hJr.le + _ ≤ _ := by rw [one_mul]; exact hJle + -- summing over the start seeds counts each substantial entry with its retention probability + have hsumX : ∑ s, (#{x ∈ A0 | X s x} : ℝ) = #A0 * (π * Fintype.card ι) := by + simp only [natCast_card_filter] + rw [sum_comm] + simp only [← natCast_card_filter, card_X hch, sum_const, nsmul_eq_mul] + have hT : 0 < #T := by + rw [card_pos] + by_contra hT + rw [not_nonempty_iff_eq_empty] at hT + have : columnDetector X Y ϕ ρ J K f G y = 0 := by + rw [columnDetector_eq_sum]; simp [T, hT] + linarith + have hι : 0 < Fintype.card ι := by + rw [Fintype.card_pos_iff] + by_contra hι + rw [not_nonempty_iff] at hι + have : columnDetector X Y ϕ ρ J K f G y = 0 := by + rw [columnDetector_eq_sum]; simp + linarith + have hTr : (0 : ℝ) < #T := by exact_mod_cast hT + have hιr : (0 : ℝ) < Fintype.card ι := by exact_mod_cast hι + have hUle : columnDetector X Y ϕ ρ J K f G y ≤ #A0 * π / J := by + rw [columnDetector_eq_sum, div_le_div_iff₀ (by positivity) hJr] + calc (∑ s, ∑ t ∈ T, detectorTrial ϕ ρ J K f G {x | X s x} {w | Y t w} y) * J + ≤ (∑ s, ∑ _t ∈ T, (#{x ∈ A0 | X s x} : ℝ) / J) * J := + mul_le_mul_of_nonneg_right + (sum_le_sum fun s _ => sum_le_sum fun t _ => htrial s t) hJr.le + _ = #T * ∑ s, (#{x ∈ A0 | X s x} : ℝ) := by + simp only [sum_const, nsmul_eq_mul, Finset.mul_sum, Finset.sum_mul] + exact sum_congr rfl fun s _ => by field_simp + _ = #A0 * π * (Fintype.card ι * #T) := by rw [hsumX]; ring + have hπ : 0 < π := by + by_contra hπ + have : #A0 * π / J ≤ 0 := + div_nonpos_of_nonpos_of_nonneg (mul_nonpos_of_nonneg_of_nonpos (by positivity) + (not_lt.mp hπ)) hJr.le + linarith + have hCπ : 0 < Cπ * f := hπ.trans_le hch.upper + have h1 : J / 4 < #A0 * π := by + have := hU.trans_le hUle + rw [lt_div_iff₀ hJr] at this + linarith + rw [div_lt_iff₀ (by nlinarith)] + calc (J : ℝ) = J / 4 * 4 := by ring + _ < #A0 * π * 4 := by linarith + _ ≤ #A0 * (Cπ * f) * 4 := by gcongr; exact hch.upper + _ = #A0 * (4 * Cπ * f) := by ring + +omit [Fintype V] in +private theorem card_pos_of_dens {α : Type*} [Fintype α] {s : Finset α} {π : ℝ} (hπ : 0 < π) + (h : (dens s : ℝ) = π) : 0 < Fintype.card α ∧ 0 < #s := by + rw [dens_cast] at h + rcases (Fintype.card α).eq_zero_or_pos with h0 | h0 + · simp [h0] at h; linarith + refine ⟨h0, Nat.pos_of_ne_zero fun hs => ?_⟩ + simp [hs] at h; linarith + +/-- **Columns with many large entries are detected** [OpenAI2026LogSpace, Lemma 4.3 (1)]. Let the +rows of `G ≥ 0` sum to at most `k`, let `ϕ` be one from `δ₁`, let `ρ ≤ 1` be one through `η > 0`, +let the gate rank satisfy `K ≥ 160 (1 + C_pair k / η)`, and let `c_π R ≥ 4 J` and +`c_π R ≥ 40 C_var`. If more than `R / f` entries of column `y` are at least `δ₁ f`, its detector +number is at least `19 / 20`. -/ +theorem le_columnDetector (hch : RetentionChannels X Y f π cπ Cπ Cpair Cvar) (hf : 0 < f) + (hcπ : 0 < cπ) (hCpair : 0 ≤ Cpair) {δ₁ : ℝ} (hϕδ : ∀ t, δ₁ ≤ t → ϕ t = 1) + (hρ1 : ∀ t, ρ t ≤ 1) {η : ℝ} (hη : 0 < η) + (hρη : ∀ t, t ≤ η → ρ t = 1) (hG0 : ∀ x w, 0 ≤ G x w) {k : ℝ} + (hGk : ∀ x, ∑ w, G x w ≤ k) (hK : 160 * (1 + Cpair * k / η) ≤ K) (hJ : 0 < J) {R : ℝ} + (hRJ : 4 * J ≤ cπ * R) (hRvar : 40 * Cvar ≤ cπ * R) + (hy : R / f < #({x | δ₁ * f ≤ G x y} : Finset V)) : + 19 / 20 ≤ columnDetector X Y ϕ ρ J K f G y := by + classical + set A : Finset V := {x | δ₁ * f ≤ G x y} + set T : Finset κ := {t | Y t y} + set D : ℝ := 1 + Cpair * k / η + set gate : κ → V → ℝ := fun t x => rowGate ρ K f G {w | Y t w} x + have hπ : 0 < π := (mul_pos hcπ hf).trans_le hch.lower + have hJr : (0 : ℝ) < J := by exact_mod_cast hJ + have hnπ : cπ * R < #A * π := by + have h1 : R < #A * f := by rwa [div_lt_iff₀ hf] at hy + calc cπ * R < cπ * (#A * f) := mul_lt_mul_of_pos_left h1 hcπ + _ = #A * (cπ * f) := by ring + _ ≤ #A * π := mul_le_mul_of_nonneg_left hch.lower (by positivity) + have hnπ0 : 0 < (#A : ℝ) * π := by linarith + have hA : A.Nonempty := by + rw [← card_pos, ← Nat.cast_pos (α := ℝ)] + exact pos_of_mul_pos_left hnπ0 hπ.le + obtain ⟨hι, -⟩ := card_pos_of_dens hπ (hch.dens_X y) + obtain ⟨hκ, hT⟩ := card_pos_of_dens hπ (hch.dens_Y y) + have hκr : (0 : ℝ) < Fintype.card κ := by exact_mod_cast hκ + have hιr : (0 : ℝ) < Fintype.card ι := by exact_mod_cast hι + have hTr : (0 : ℝ) < #T := by exact_mod_cast hT + have hD : 1 ≤ D := by + have : 0 ≤ Cpair * k / η := by + have hk : 0 ≤ k := (sum_nonneg fun w _ => hG0 y w).trans (hGk y) + positivity + linarith + have hKpos : 0 < K := by + have : (0 : ℝ) < K := by linarith + exact_mod_cast this + -- Markov's inequality for the row gates: each row fails its gate on few terminal draws + have hgate : ∀ x, (#{t ∈ T | gate t x < 1} : ℝ) * K ≤ #T * D := by + intro x + set W : Finset V := {w | η * f < G x w} + have hW : (#W : ℝ) * (η * f) ≤ k := + (card_filter_mul_le_sum univ _ (fun w => G x w) (fun w _ => hG0 x w) + fun _ _ hw => hw.le).trans (hGk x) + have hbadK : ∀ t ∈ T, gate t x < 1 → (K : ℝ) ≤ #{w ∈ W | Y t w} := by + intro t _ ht + have hlt : η < kthLargest K {w | Y t w} (fun w => G x w / f) := by + by_contra hle + have h1 := hρη _ (not_lt.mp hle) + simp only [gate, rowGate] at ht + rw [h1] at ht + exact lt_irrefl _ ht + have hcard := (lt_kthLargest_iff hKpos hη.le).mp hlt + have hsub : ({w ∈ ({w | Y t w} : Finset V) | η < G x w / f} : Finset V) ⊆ + {w ∈ W | Y t w} := fun w hw => by + simp only [mem_filter, mem_univ, true_and, W] at hw ⊢ + exact ⟨by rw [lt_div_iff₀ hf] at hw; exact hw.2, hw.1⟩ + exact_mod_cast hcard.trans (card_le_card hsub) + have hMarkov : (#{t ∈ T | gate t x < 1} : ℝ) * K ≤ ∑ t ∈ T, (#{w ∈ W | Y t w} : ℝ) := + card_filter_mul_le_sum T _ _ (fun _ _ => by positivity) hbadK + have hswap : ∑ t ∈ T, (#{w ∈ W | Y t w} : ℝ) = ∑ w ∈ W, (#{t ∈ T | Y t w} : ℝ) := by + simp only [natCast_card_filter] + exact sum_comm + have hterm : ∀ w ∈ W, (#{t ∈ T | Y t w} : ℝ) ≤ (if y = w then (#T : ℝ) else 0) + + Cpair * f * #T := by + intro w _ + have hle : (#{t ∈ T | Y t w} : ℝ) ≤ #T := by exact_mod_cast card_filter_le _ _ + by_cases hwy : y = w + · simp only [hwy, ↓reduceIte] + have : 0 ≤ Cpair * f * #T := by positivity + linarith + · simp only [hwy, ↓reduceIte, zero_add] + have hp := hch.pair w y (Ne.symm hwy) + rw [dens_cast, dens_cast, ← mul_div_assoc, div_le_div_iff_of_pos_right hκr] at hp + have hset : ({t ∈ T | Y t w} : Finset κ) = ({t | Y t w ∧ Y t y} : Finset κ) := by + ext t; simp only [T, mem_filter, mem_univ, true_and]; tauto + rw [hset] + exact hp + have hWf : (#W : ℝ) * f ≤ k / η := by + rw [le_div_iff₀ hη]; linarith + calc (#{t ∈ T | gate t x < 1} : ℝ) * K + ≤ ∑ w ∈ W, ((if y = w then (#T : ℝ) else 0) + Cpair * f * #T) := + hMarkov.trans (hswap ▸ sum_le_sum hterm) + _ = (if y ∈ W then (#T : ℝ) else 0) + #W * (Cpair * f * #T) := by + rw [sum_add_distrib, sum_ite_eq, sum_const, nsmul_eq_mul] + _ ≤ #T + #T * Cpair * (#W * f) := by + have : (if y ∈ W then (#T : ℝ) else 0) ≤ #T := by split_ifs <;> [exact le_rfl; positivity] + nlinarith + _ ≤ #T + #T * Cpair * (k / η) := by gcongr + _ = #T * D := by simp only [D]; ring + -- the expected number of retained large rows that fail their gate + set N : ι → ℝ := fun s => #{x ∈ A | X s x} + set L : ι → κ → ℝ := fun s t => #{x ∈ A | X s x ∧ gate t x < 1} + have hL0 : ∀ s t, 0 ≤ L s t := fun _ _ => by positivity + have hsumL : ∑ s, ∑ t ∈ T, L s t ≤ #A * π * Fintype.card ι * (#T * D / K) := by + have heq : ∑ s, ∑ t ∈ T, L s t = + ∑ x ∈ A, (#{s | X s x} : ℝ) * #{t ∈ T | gate t x < 1} := by + have h1 : ∀ s t, L s t = ∑ x ∈ A, + (if X s x then (1 : ℝ) else 0) * (if gate t x < 1 then 1 else 0) := fun s t => by + simp only [L, natCast_card_filter, ite_zero_mul_ite_zero, mul_one] + simp only [h1, natCast_card_filter, sum_mul_sum] + exact (sum_congr rfl fun s _ => sum_comm).trans sum_comm + rw [heq] + have hKr : (0 : ℝ) < K := by exact_mod_cast hKpos + calc ∑ x ∈ A, (#{s | X s x} : ℝ) * #{t ∈ T | gate t x < 1} + ≤ ∑ _x ∈ A, π * Fintype.card ι * (#T * D / K) := by + refine sum_le_sum fun x _ => ?_ + rw [card_X hch] + exact mul_le_mul_of_nonneg_left (by rw [le_div_iff₀ hKr]; exact hgate x) + (by positivity) + _ = #A * π * Fintype.card ι * (#T * D / K) := by + rw [sum_const, nsmul_eq_mul]; ring + -- outside two bad events, at least `J` retained large rows pass their gates + have hgood : ∀ s t, ¬ 2 * N s < #A * π → ¬ #A * π < 4 * L s t → + 1 ≤ detectorTrial ϕ ρ J K f G {x | X s x} {w | Y t w} y := by + intro s t h1 h2 + push Not at h1 h2 + have hsplit : N s = L s t + #{x ∈ A | X s x ∧ ¬ gate t x < 1} := by + simp only [N, L, natCast_card_filter, ← sum_add_distrib] + refine sum_congr rfl fun x _ => ?_ + by_cases hX : X s x <;> by_cases hg : gate t x < 1 <;> simp [hX, hg] + have hJle : (J : ℝ) ≤ #{x ∈ A | X s x ∧ ¬ gate t x < 1} := by + have : 4 * (J : ℝ) < #A * π := hRJ.trans_lt hnπ + linarith + refine (le_kthLargest_iff hJ one_pos).mpr ?_ + refine Nat.cast_le.mp (hJle.trans ?_) + refine Nat.cast_le.mpr (card_le_card fun x hx => ?_) + simp only [mem_filter, mem_univ, true_and, A] at hx ⊢ + refine ⟨hx.2.1, ?_⟩ + have hϕx : ϕ (G x y / f) = 1 := hϕδ _ (by rw [le_div_iff₀ hf]; exact hx.1) + have hgx : gate t x = 1 := le_antisymm (hρ1 _) (not_lt.mp hx.2.2) + simp only [gate] at hgx + rw [hϕx, hgx, one_mul] + -- sum the pointwise bound `trial ≥ 1 - [bad start draw] - [many gate failures]` + set b1 : ι → ℝ := fun s => if 2 * N s < #A * π then 1 else 0 + set b2 : ι → κ → ℝ := fun s t => if #A * π < 4 * L s t then 1 else 0 + have hpoint : ∀ s t, 1 - b1 s - b2 s t ≤ + detectorTrial ϕ ρ J K f G {x | X s x} {w | Y t w} y := by + intro s t + have h0 : 0 ≤ detectorTrial ϕ ρ J K f G {x | X s x} {w | Y t w} y := detectorTrial_nonneg + by_cases h1 : 2 * N s < #A * π + · have : 0 ≤ b2 s t := by simp only [b2]; split_ifs <;> norm_num + simp only [b1, h1, ↓reduceIte] + linarith + by_cases h2 : #A * π < 4 * L s t + · simp only [b1, b2, h1, h2, ↓reduceIte] + linarith + · simp only [b1, b2, h1, h2, ↓reduceIte, sub_zero] + exact hgood s t h1 h2 + have hb1 : ∑ s, b1 s ≤ Cvar / (#A * π) * Fintype.card ι := by + have ht := hch.tail A hA + rw [dens_cast, div_le_iff₀ hιr] at ht + simp only [b1, N] + rw [sum_boole] + exact ht + have hb2 : ∑ s, ∑ t ∈ T, b2 s t ≤ 4 / (#A * π) * ∑ s, ∑ t ∈ T, L s t := by + rw [mul_sum] + refine sum_le_sum fun s _ => ?_ + rw [mul_sum] + refine sum_le_sum fun t _ => ?_ + simp only [b2] + split_ifs with h + · rw [div_mul_eq_mul_div, le_div_iff₀ hnπ0]; linarith + · have := hL0 s t; positivity + have hvar : Cvar / (#A * π) ≤ 1 / 40 := by + rw [div_le_div_iff₀ hnπ0 (by norm_num)]; linarith + have hgatebound : 4 / (#A * π) * (#A * π * Fintype.card ι * (#T * D / K)) ≤ + Fintype.card ι * #T / 40 := by + have hKr : (0 : ℝ) < K := by exact_mod_cast hKpos + have : 4 / (#A * π) * (#A * π * Fintype.card ι * (#T * D / K)) = + 4 * D / K * (Fintype.card ι * #T) := by + field_simp + rw [this, div_eq_mul_one_div (Fintype.card ι * (#T : ℝ)) 40, mul_comm _ (1 / 40 : ℝ)] + refine mul_le_mul_of_nonneg_right ?_ (by positivity) + rw [div_le_iff₀ hKr]; linarith + rw [columnDetector_eq_sum, le_div_iff₀ (by positivity)] + have h4 : 0 ≤ 4 / (#A * π) := by positivity + calc 19 / 20 * (Fintype.card ι * #T : ℝ) + ≤ Fintype.card ι * #T - #T * (Cvar / (#A * π) * Fintype.card ι) - + 4 / (#A * π) * (#A * π * Fintype.card ι * (#T * D / K)) := by + nlinarith [mul_le_mul_of_nonneg_left hvar (by positivity : (0 : ℝ) ≤ #T * Fintype.card ι)] + _ ≤ Fintype.card ι * #T - #T * ∑ s, b1 s - ∑ s, ∑ t ∈ T, b2 s t := by + nlinarith [mul_le_mul_of_nonneg_left hb1 hTr.le, mul_le_mul_of_nonneg_left hsumL h4] + _ = ∑ s, ∑ t ∈ T, (1 - b1 s - b2 s t) := by + simp only [sum_sub_distrib, sum_const, nsmul_eq_mul, card_univ, mul_one] + rw [← mul_sum] + _ ≤ _ := sum_le_sum fun s _ => sum_le_sum fun t _ => hpoint s t + +end Matrix diff --git a/Complexity/Foundations/Probability/DetectedStage.lean b/Complexity/Foundations/Probability/DetectedStage.lean new file mode 100644 index 000000000..ab425a36c --- /dev/null +++ b/Complexity/Foundations/Probability/DetectedStage.lean @@ -0,0 +1,295 @@ +/- +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.LinearAlgebra.Matrix.CopyStage +public import Complexity.Foundations.LinearAlgebra.Matrix.PilotCorrection +public import Complexity.Foundations.Probability.ColumnDetector +import Mathlib.Algebra.BigOperators.Fin +import Mathlib.Algebra.Order.Floor.Semiring + +/-! +# One stage of the hierarchy with detector-chosen multipliers + +This file closes the detector interface of `Matrix.copyStage_rates` +[OpenAI2026LogSpace, Section 4.2, Proposition 4.5]. One stage of the correction-and-copy hierarchy +runs the pilot (`Matrix.pilotMax`) with the column detector +`Matrix.columnDetector X Y ϕ ρ J K f` as its column number, for retention channels `X`, `Y` +satisfying `Cslib.Probability.RetentionChannels`. Let `M = M_k` be the final running maximum of the +detector numbers. Then + +* the column multiplier of the actual correction is `γ (M y)`, so the cutoffs are + `φ y t = c t * γ (M y)` for the base cutoff `c t = f Q (t / f)`; +* the copy weights are `r 0 x = 1` and `r j x = κ (M x)` for `j ≠ 0` + (`Matrix.detectorWeight`) [OpenAI2026LogSpace, (4.22)]; +* the overloaded vertices are `O = {x | 1 / 4 < M x}` (`Matrix.overloaded`). + +Since `γ` is one through `1 / 2` and `κ` is zero through `1 / 4` and one from `1 / 2`, every +column is either fully corrected or overloaded with all copies active, and only overloaded vertices +have active extra copies. The detector lemma (`Matrix.lt_card_of_lt_columnDetector`) gives each +overloaded column more than `J / (4 C_π f)` entries above `δ₀ f` in some pilot input, and +incidence counting over the pilot inputs, whose rows sum to at most `1, …, k`, gives +`m |O| ≤ |A|` once `2 C_π m k (k + 1) ≤ δ₀ J` [OpenAI2026LogSpace, (4.24)]. So the stage has the +density, intertwining and active-count conclusions of `Matrix.copyStage_rates` +(`Matrix.detectedStage_rates`), with only the channel properties and deterministic constant +conditions as hypotheses. + +The pilot also bounds the column counts of the corrected columns +[OpenAI2026LogSpace, Lemma 4.3 (3)]: if the pilot multiplier of a column is positive, its pilot +inputs have at most `R / f` entries at least `δ₁ f` (`Matrix.card_le_of_pilot_pos`), and so do +the inputs of the actual correction when the final multiplier is positive +(`Matrix.card_le_of_multiplier_pos`). + +## Main definitions + +* `Matrix.detectorWeight`: the copy weights `r` from the running maximum. +* `Matrix.overloaded`: the overloaded vertices. + +## Main results + +* `Matrix.card_overloaded_le`: the incidence bound `m |O| ≤ |A|`. +* `Matrix.detectedStage_rates`: one stage with detector-chosen multipliers and copies. +* `Matrix.card_le_of_pilot_pos`, `Matrix.card_le_of_multiplier_pos`: column counts of corrected + columns. + +## References + +* [OpenAI, *Exact Derandomization of Logarithmic Space: L = RL = BPL*][OpenAI2026LogSpace], + Section 4.2, Lemma 4.3 and Proposition 4.5 (preprint, not peer reviewed) +-/ + +public section + +open Finset Cslib.Probability + +namespace Matrix + +section Definitions + +variable {V : Type*} + +/-- The **copy weights** from the running maximum `M` of the detector numbers: the primary copy +has weight one, every other copy of `x` weight `κ (M x)` [OpenAI2026LogSpace, (4.22)]. -/ +@[expose] noncomputable def detectorWeight {m : ℕ} (κ : ℝ → ℝ) (M : V → ℝ) (j : Fin (m + 1)) + (x : V) : ℝ := + if j = 0 then 1 else κ (M x) + +/-- The **overloaded** vertices: those whose running maximum of detector numbers exceeds `1 / 4` +[OpenAI2026LogSpace, Proposition 4.5]. -/ +@[expose] noncomputable def overloaded [Fintype V] (M : V → ℝ) : Finset V := + {x | 1 / 4 < M x} + +end Definitions + +variable {V ι ι' : Type*} [Fintype V] [Fintype ι] [Fintype ι'] {X : ι → V → Prop} + {Y : ι' → V → Prop} [∀ s v, Decidable (X s v)] [∀ t v, Decidable (Y t v)] {ϕ ρ : ℝ → ℝ} + {J K : ℕ} {f π cπ Cπ Cpair Cvar : ℝ} {c γ : ℝ → ℝ} {C : Matrix V V ℝ} + +private theorem sum_fin_succ_cast (k : ℕ) : ∑ i : Fin k, ((i : ℝ) + 1) = k * (k + 1) / 2 := by + rw [Fin.sum_univ_eq_sum_range (fun i => (i : ℝ) + 1)] + induction k with + | zero => simp + | succ k ih => rw [sum_range_succ, ih]; push_cast; ring + +/-- **Few overloaded vertices** [OpenAI2026LogSpace, Proposition 4.5]: after `k` pilot steps with +the column detector, if `A` covers the support of `C` and `2 C_π m k (k + 1) ≤ δ₀ J`, then +`m |O| ≤ |A|`. Each overloaded column has more than `J / (4 C_π f)` entries above `δ₀ f` in some +pilot input, and the pilot inputs have row sums at most `1, …, k`. -/ +theorem card_overloaded_le (hch : RetentionChannels X Y f π cπ Cπ Cpair Cvar) (hf : 0 < f) + (hCπ : 0 < Cπ) (hϕ0 : ∀ t, 0 ≤ ϕ t) (hϕ1 : ∀ t, ϕ t ≤ 1) {δ₀ : ℝ} (hδ₀ : 0 < δ₀) + (hϕδ : ∀ t, t ≤ δ₀ → ϕ t = 0) (hρ1 : ∀ t, ρ t ≤ 1) (hJ : 0 < J) (hC0 : ∀ x y, 0 ≤ C x y) + (hC1 : C *ᵥ 1 ≤ 1) {A : Finset V} (hA : ∀ x y, C x y ≠ 0 → x ∈ A ∧ y ∈ A) + (hc0 : ∀ t, 0 ≤ c t) (hct : ∀ t, 0 ≤ t → c t ≤ t) (hγ0 : ∀ t, 0 ≤ γ t) + (hγ1 : ∀ t, γ t ≤ 1) {k m : ℕ} (hJm : 2 * Cπ * m * k * (k + 1) ≤ δ₀ * J) : + m * #(overloaded (pilotMax c γ (columnDetector X Y ϕ ρ J K f) C k)) ≤ #A := by + set U := columnDetector X Y ϕ ρ J K f + set O := overloaded (pilotMax c γ U C k) + have hseq := isCorrectionSeq_pilotCorrection (U := U) hC0 hc0 hct hγ0 hγ1 + -- every overloaded column has many substantial entries in some pilot input + have hinc : ∀ y ∈ O, ∃ i : Fin k, J / (4 * Cπ * f) < + #({x | δ₀ * f < pilotInput c γ U C i x y} : Finset V) := by + intro y hy + simp only [O, overloaded, mem_filter, mem_univ, true_and] at hy + obtain ⟨i, hi, hU⟩ := exists_lt_pilotInput_of_lt_pilotMax (by norm_num) hy + exact ⟨⟨i, hi⟩, lt_card_of_lt_columnDetector hch hf hϕ0 hϕ1 hϕδ hρ1 hJ hU⟩ + rcases O.eq_empty_or_nonempty with hO | hO + · rw [hO, card_empty, mul_zero]; exact Nat.zero_le _ + have hk : 0 < k := by + obtain ⟨y, hy⟩ := hO + obtain ⟨⟨i, hi⟩, -⟩ := hinc y hy + omega + set N := ⌊J / (4 * Cπ * f)⌋₊ + 1 + have hN : ∀ y ∈ O, ∃ i : Fin k, N ≤ #({x | δ₀ * f < pilotInput c γ U C i x y} : Finset V) := by + intro y hy + obtain ⟨i, hi⟩ := hinc y hy + exact ⟨i, Nat.succ_le_of_lt ((Nat.floor_lt (by positivity)).mpr hi)⟩ + have hcount := card_mul_le_of_incidences (fun i : Fin k => pilotInput c γ U C i) + (fun i x y => hseq.input_nonneg hC0 i x y) (fun i => (i : ℝ) + 1) + (fun i x => (hseq.sum_input_le hC1 i x).1) A + (fun i x y h => (hseq.input_mem hA i x y h).1) (mul_pos hδ₀ hf) O hN + rw [sum_fin_succ_cast] at hcount + have hNJ : J / (4 * Cπ * f) < N := by + simp only [N]; push_cast; exact Nat.lt_floor_add_one _ + have hJN : (J : ℝ) * δ₀ < 4 * Cπ * N * δ₀ * f := by + rw [div_lt_iff₀ (by positivity)] at hNJ + nlinarith + have hkpos : (0 : ℝ) < k * (k + 1) := by + have : (0 : ℝ) < k := by exact_mod_cast hk + positivity + -- `#O N δ₀ f ≤ #A k (k + 1) / 2` and `2 C_π m k (k + 1) ≤ δ₀ J < 4 C_π N δ₀ f` + have key : (m : ℝ) * #O * (2 * Cπ * k * (k + 1)) ≤ #A * (2 * Cπ * k * (k + 1)) := by + have h1 : (m : ℝ) * #O * (2 * Cπ * k * (k + 1)) ≤ #O * (δ₀ * J) := by + have := mul_le_mul_of_nonneg_left hJm (Nat.cast_nonneg (α := ℝ) #O) + nlinarith + have h2 : (#O : ℝ) * (δ₀ * J) ≤ #O * (4 * Cπ * N * δ₀ * f) := + mul_le_mul_of_nonneg_left (by nlinarith) (Nat.cast_nonneg _) + have h3 : (#O : ℝ) * (4 * Cπ * N * δ₀ * f) ≤ #A * (2 * Cπ * k * (k + 1)) := by + have := mul_le_mul_of_nonneg_left hcount (by positivity : (0 : ℝ) ≤ 4 * Cπ) + nlinarith + linarith + have : (m : ℝ) * #O ≤ #A := le_of_mul_le_mul_right key (by positivity) + exact_mod_cast this + +/-- **Corrected pilot columns have few large entries** [OpenAI2026LogSpace, Lemma 4.3 (3)]. Under +the hypotheses of `Matrix.le_columnDetector` with row-sum bound `k`, if `γ` vanishes from `4 / 5` +on and the pilot multiplier `γ (M_(i+1) y)` of step `i + 1 ≤ k` is positive, then the pilot input +of that step has at most `R / f` entries at least `δ₁ f` in column `y`. -/ +theorem card_le_of_pilot_pos (hch : RetentionChannels X Y f π cπ Cπ Cpair Cvar) (hf : 0 < f) + (hcπ : 0 < cπ) (hCpair : 0 ≤ Cpair) {δ₁ : ℝ} (hϕδ : ∀ t, δ₁ ≤ t → ϕ t = 1) + (hρ1 : ∀ t, ρ t ≤ 1) {η : ℝ} (hη : 0 < η) (hρη : ∀ t, t ≤ η → ρ t = 1) + (hC0 : ∀ x y, 0 ≤ C x y) (hC1 : C *ᵥ 1 ≤ 1) (hc0 : ∀ t, 0 ≤ c t) + (hct : ∀ t, 0 ≤ t → c t ≤ t) (hγ0 : ∀ t, 0 ≤ γ t) (hγ1 : ∀ t, γ t ≤ 1) + (hγ45 : ∀ t, 4 / 5 ≤ t → γ t = 0) {k : ℕ} (hK : 160 * (1 + Cpair * k / η) ≤ K) + (hJ : 0 < J) {R : ℝ} (hRJ : 4 * J ≤ cπ * R) (hRvar : 40 * Cvar ≤ cπ * R) {i : ℕ} + (hi : i < k) {y : V} + (hpos : 0 < γ (pilotMax c γ (columnDetector X Y ϕ ρ J K f) C (i + 1) y)) : + (#({x | δ₁ * f ≤ pilotInput c γ (columnDetector X Y ϕ ρ J K f) C i x y} : Finset V) : ℝ) ≤ + R / f := by + set U := columnDetector X Y ϕ ρ J K f + have hseq := isCorrectionSeq_pilotCorrection (U := U) hC0 hc0 hct hγ0 hγ1 + by_contra hlt + have hrow : ∀ x, ∑ w, pilotInput c γ U C i x w ≤ (k : ℝ) := fun x => by + have := (hseq.sum_input_le hC1 i x).1 + have hik : (i : ℝ) + 1 ≤ k := by exact_mod_cast hi + exact this.trans hik + have hU : 19 / 20 ≤ U (pilotInput c γ U C i) y := + le_columnDetector hch hf hcπ hCpair hϕδ hρ1 hη hρη (hseq.input_nonneg hC0 i) hrow hK hJ hRJ + hRvar (not_le.mp hlt) + have hM : 4 / 5 ≤ pilotMax c γ U C (i + 1) y := by + rw [pilotMax_succ, Pi.sup_apply] + exact le_sup_of_le_right (by linarith) + rw [hγ45 _ hM] at hpos + exact lt_irrefl _ hpos + +/-- **Corrected columns have few large entries** [OpenAI2026LogSpace, Lemma 4.3 (3)]: if the +final multiplier `γ (M_k y)` is positive, then for every `i < k` the input of step `i + 1` of the +actual correction, with cutoffs `c t * γ (M_k y)`, has at most `R / f` entries at least `δ₁ f` in +column `y`. -/ +theorem card_le_of_multiplier_pos (hch : RetentionChannels X Y f π cπ Cπ Cpair Cvar) + (hf : 0 < f) (hcπ : 0 < cπ) (hCpair : 0 ≤ Cpair) {δ₁ : ℝ} (hϕδ : ∀ t, δ₁ ≤ t → ϕ t = 1) + (hρ1 : ∀ t, ρ t ≤ 1) {η : ℝ} (hη : 0 < η) (hρη : ∀ t, t ≤ η → ρ t = 1) + (hC0 : ∀ x y, 0 ≤ C x y) (hC1 : C *ᵥ 1 ≤ 1) (hc0 : ∀ t, 0 ≤ c t) + (hct : ∀ t, 0 ≤ t → c t ≤ t) (hcm : Monotone c) (hγ0 : ∀ t, 0 ≤ γ t) (hγ1 : ∀ t, γ t ≤ 1) + (hγm : Antitone γ) (hγ45 : ∀ t, 4 / 5 ≤ t → γ t = 0) {k : ℕ} + (hK : 160 * (1 + Cpair * k / η) ≤ K) (hJ : 0 < J) {R : ℝ} (hRJ : 4 * J ≤ cπ * R) + (hRvar : 40 * Cvar ≤ cπ * R) {y : V} + (hpos : 0 < γ (pilotMax c γ (columnDetector X Y ϕ ρ J K f) C k y)) {i : ℕ} (hi : i < k) : + let M := pilotMax c γ (columnDetector X Y ϕ ρ J K f) C k + (#({x | δ₁ * f ≤ (C + cutoffCorrectionIter (fun y t => c t * γ (M y)) C i * C) x y} : + Finset V) : ℝ) ≤ R / f := by + intro M + set U := columnDetector X Y ϕ ρ J K f + have hstep : 0 < γ (pilotMax c γ U C (i + 1) y) := + hpos.trans_le (hγm (pilotMax_mono (by omega) y)) + refine le_trans ?_ (card_le_of_pilot_pos hch hf hcπ hCpair hϕδ hρ1 hη hρη hC0 hC1 hc0 hct + hγ0 hγ1 hγ45 hK hJ hRJ hRvar hi hstep) + refine Nat.cast_le.mpr (card_le_card fun x hx => ?_) + simp only [mem_filter, mem_univ, true_and] at hx ⊢ + exact hx.trans (cutoffCorrectionIter_le_pilotCorrection hC0 hc0 hct hcm hγ0 hγ1 hγm + hi.le x y).2 + +variable [DecidableEq V] [LinearOrder V] {θ L θ₂ : ℝ} {κ χ : ℝ → ℝ} {τ₀ τ₁ q : ℝ} + +/-- **One stage with detector-chosen multipliers and copies** +[OpenAI2026LogSpace, Proposition 4.5]. Run `k` pilot steps with the column detector, let `M` be +the final running maximum, correct `C` by `k` steps of the cutoffs `φ y t = c t * γ (M y)`, and +split the residual `D` with the copy weights `Matrix.detectorWeight κ M` and the overloaded set +`Matrix.overloaded M`. If the base cutoff satisfies the hypotheses of the factorial truncation +together with `t - θ₂ f ≤ c t`, `γ` is nonincreasing and one through `1 / 2`, `κ` is zero through +`1 / 4` and one from `1 / 2`, `2 C_π m k (k + 1) ≤ δ₀ J`, and the copy constants are chosen as in +`Matrix.copyStage_rates`, then the copy step has entries at most `f / q`, intertwines with its +projection, and is supported in at most `2 |A|` copies. -/ +theorem detectedStage_rates (hch : RetentionChannels X Y f π cπ Cπ Cpair Cvar) + (hC : C.IsStrictUpperTriangular) (hC0 : ∀ x y, 0 ≤ C x y) (hCf : ∀ x y, C x y ≤ f) + (hC1 : C *ᵥ 1 ≤ 1) {A : Finset V} (hA : ∀ x y, C x y ≠ 0 → x ∈ A ∧ y ∈ A) (hf : 0 < f) + (hc0 : ∀ t, 0 ≤ c t) (hcθ : ∀ t, c t ≤ max (t - θ * f) 0) (hcm : Monotone c) + (hcL : ∀ s t, s ≤ t → c t - c s ≤ L * (t - s)) (hcθ₂ : ∀ t, t - θ₂ * f ≤ c t) (hθ : 0 < θ) + (hL : 0 ≤ L) (hγ0 : ∀ t, 0 ≤ γ t) (hγ1 : ∀ t, γ t ≤ 1) (hγhalf : ∀ t, t ≤ 1 / 2 → γ t = 1) + (hκ0 : ∀ t, 0 ≤ κ t) (hκ1 : ∀ t, κ t ≤ 1) (hκq : ∀ t, t ≤ 1 / 4 → κ t = 0) + (hκhalf : ∀ t, 1 / 2 < t → κ t = 1) (hCπ : 0 < Cπ) (hϕ0 : ∀ t, 0 ≤ ϕ t) + (hϕ1 : ∀ t, ϕ t ≤ 1) {δ₀ : ℝ} (hδ₀ : 0 < δ₀) (hϕδ : ∀ t, t ≤ δ₀ → ϕ t = 0) + (hρ1 : ∀ t, ρ t ≤ 1) (hJ : 0 < J) {k m : ℕ} (hJm : 2 * Cπ * m * k * (k + 1) ≤ δ₀ * J) + (hτ₀ : θ₂ * f + f * Real.exp (1 / θ) * (L / θ) ^ k / k.factorial ≤ τ₀) + (hχ0 : ∀ t, 0 ≤ χ t) (hχ1 : ∀ t, χ t ≤ 1) (hχ₀ : ∀ t, t ≤ τ₀ → χ t = 0) + (hχ₁ : ∀ t, τ₁ ≤ t → χ t = 1) (hτ₁ : τ₁ ≤ f / q) (hcopies : (k + 1) * f / (m + 1) ≤ f / q) : + let M := pilotMax c γ (columnDetector X Y ϕ ρ J K f) C k + let E := cutoffCorrectionIter (fun y t => c t * γ (M y)) C k + let D := C - E + E * C + (∀ a b, copyStage χ m (detectorWeight κ M) D a b ≤ f / q) ∧ + copyStage χ m (detectorWeight κ M) D * copyWeight (detectorWeight κ M) = + copyWeight (detectorWeight κ M) * D ∧ + (∀ a b, copyStage χ m (detectorWeight κ M) D a b ≠ 0 → + a ∈ copyCover A (overloaded M) ∧ b ∈ copyCover A (overloaded M)) ∧ + #(copyCover (m := m) A (overloaded M)) ≤ 2 * #A := by + intro M E D + have hct : ∀ t, 0 ≤ t → c t ≤ t := fun t ht => + (hcθ t).trans (max_le (by nlinarith [mul_pos hθ hf]) ht) + have hO := card_overloaded_le (K := K) (k := k) (m := m) hch hf hCπ hϕ0 hϕ1 hδ₀ hϕδ hρ1 hJ hC0 + hC1 hA hc0 hct hγ0 hγ1 hJm + refine copyStage_rates (φ := fun y t => c t * γ (M y)) (θ := θ) (L := L) (m := m) (χ := χ) + (τ₀ := τ₀) (τ₁ := τ₁) (r := detectorWeight κ M) (A := A) (O := overloaded M) (θ₂ := θ₂) + (q := q) hC hC0 hCf hC1 + (fun y t => mul_nonneg (hc0 t) (hγ0 _)) + (fun y t => (mul_le_of_le_one_right (hc0 t) (hγ1 _)).trans (hcθ t)) + (fun y => hcm.mul_const (hγ0 _)) + (fun y s t hst => ?_) hf hθ hL k hA (fun x => by simp [detectorWeight]) + (fun j x => ?_) (fun j x hj hr => ?_) (fun y => ?_) hτ₀ hχ0 hχ1 hχ₀ hχ₁ hτ₁ hcopies hO + · -- the cutoffs are `L`-Lipschitz + have hmono : 0 ≤ c t - c s := sub_nonneg.mpr (hcm hst) + calc c t * γ (M y) - c s * γ (M y) = γ (M y) * (c t - c s) := by ring + _ ≤ 1 * (c t - c s) := mul_le_mul_of_nonneg_right (hγ1 _) hmono + _ ≤ L * (t - s) := by rw [one_mul]; exact hcL s t hst + · -- the weights lie in `[0, 1]` + unfold detectorWeight + split_ifs + · exact ⟨zero_le_one, le_rfl⟩ + · exact ⟨hκ0 _, hκ1 _⟩ + · -- only overloaded vertices have active extra copies + simp only [detectorWeight, hj, ↓reduceIte] at hr + simp only [overloaded, mem_filter, mem_univ, true_and] + by_contra hle + exact hr (hκq _ (not_lt.mp hle)) + · -- every column is fully corrected or overloaded with all copies active + by_cases hg : γ (M y) = 1 + · left + intro t + simp only [hg, mul_one] + exact hcθ₂ t + · right + have hhalf : 1 / 2 < M y := by + by_contra hle + exact hg (hγhalf _ (not_lt.mp hle)) + refine ⟨fun j => ?_, ?_⟩ + · unfold detectorWeight + split_ifs + · rfl + · exact hκhalf _ hhalf + · simp only [overloaded, mem_filter, mem_univ, true_and] + linarith + +end Matrix diff --git a/ComplexityTests/Detectors.lean b/ComplexityTests/Detectors.lean new file mode 100644 index 000000000..fc8731cde --- /dev/null +++ b/ComplexityTests/Detectors.lean @@ -0,0 +1,215 @@ +/- +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.Probability.DetectedStage +import Mathlib.Analysis.SpecialFunctions.Exponential +import Mathlib.Analysis.Complex.ExponentialBounds +import Mathlib.Tactic.FinCases + +/-! +# Tests for the pilot, the column detectors and a detected stage +-/ + +namespace ComplexityTests.Detectors + +open Finset Matrix Cslib.Probability + +/-! ### Channels that retain every vertex -/ + +/-- A channel with one seed that retains every vertex. -/ +private abbrev all {V : Type*} : Unit → V → Prop := fun _ _ => True + +/-- Channels that retain everything satisfy the channel interface at every rate `f ∈ (0, 1]`, with +`c_π = 1`, `C_π = C_pair = 1 / f` and `C_var = 0`. -/ +private theorem retentionChannels_all {V : Type*} {f : ℝ} (hf : 0 < f) (hf1 : f ≤ 1) : + RetentionChannels (all (V := V)) all f 1 1 (1 / f) (1 / f) 0 where + dens_X _ := by simp [all] + dens_Y _ := by simp [all] + lower := by simpa using hf1 + upper := by rw [one_div_mul_cancel hf.ne'] + pair _ _ _ := by simp [all, hf.ne'] + tail A _ := by + have : ({s | 2 * (#{x ∈ A | all s x} : ℝ) < #A * 1} : Finset Unit) = ∅ := by + ext s + simp only [all, filter_true, mul_one, mem_filter, mem_univ, true_and, notMem_empty, + iff_false, not_lt] + linarith [(Nat.cast_nonneg (α := ℝ) #A)] + rw [this] + simp + +/-! ### Step cutoffs -/ + +/-- The step `0` through `a`, `1` above. -/ +private noncomputable def up (a t : ℝ) : ℝ := if t ≤ a then 0 else 1 + +/-- The step `1` through `a`, `0` above. -/ +private noncomputable def down (a t : ℝ) : ℝ := if t ≤ a then 1 else 0 + +private theorem up_nonneg (a t : ℝ) : 0 ≤ up a t := by unfold up; split_ifs <;> norm_num +private theorem up_le_one (a t : ℝ) : up a t ≤ 1 := by unfold up; split_ifs <;> norm_num +private theorem up_of_le {a t : ℝ} (h : t ≤ a) : up a t = 0 := by simp only [up, h, ↓reduceIte] +private theorem up_of_lt {a t : ℝ} (h : a < t) : up a t = 1 := by + simp only [up, not_le.mpr h, ↓reduceIte] +private theorem down_nonneg (a t : ℝ) : 0 ≤ down a t := by unfold down; split_ifs <;> norm_num +private theorem down_le_one (a t : ℝ) : down a t ≤ 1 := by unfold down; split_ifs <;> norm_num +private theorem down_of_le {a t : ℝ} (h : t ≤ a) : down a t = 1 := by + simp only [down, h, ↓reduceIte] +private theorem down_antitone (a : ℝ) : Antitone (down a) := fun s t hst => by + unfold down; split_ifs with h1 h2 <;> first | exact absurd (hst.trans h1) h2 | norm_num + +/-! ### The detector lemma on a concrete column -/ + +/-- Rows `0, …, 4` each have one entry `1 / 5`, in column `5`. -/ +private noncomputable def G : Matrix (Fin 6) (Fin 6) ℝ := + of fun x y => if y = 5 ∧ x ≠ 5 then 1 / 5 else 0 + +private theorem G0 : ∀ x w, 0 ≤ G x w := by + intro x w; simp only [G, of_apply]; split_ifs <;> norm_num + +private theorem G_row : ∀ x, ∑ w, G x w ≤ (1 : ℝ) := by + intro x; fin_cases x <;> simp [G] <;> norm_num + +-- Column `5` has five entries `1 / 5 ≥ δ₁ f` with `f = 1` and `δ₁ = 1 / 6`, more than +-- `R / f = 4`, so its detector number is at least `19 / 20`. The score is the step at `1 / 10`, +-- the gate the step at `η = 1 / 2`, and the gate rank `K = 480 ≥ 160 (1 + 1 / (1 / 2))`. +example : 19 / 20 ≤ columnDetector all all (up (1 / 10)) (down (1 / 2)) 1 480 1 G 5 := by + have hcount : (4 : ℝ) / 1 < #(univ.filter fun x => 1 / 6 * 1 ≤ G x 5) := by + have hsub : (univ.erase 5 : Finset (Fin 6)) ⊆ univ.filter fun x => 1 / 6 * 1 ≤ G x 5 := + fun x hx => by + have hx5 : x ≠ 5 := ne_of_mem_erase hx + simp only [mem_filter, mem_univ, true_and, G, of_apply, hx5, ne_eq, not_false_eq_true, + ↓reduceIte] + norm_num + have := card_le_card hsub + rw [card_erase_of_mem (mem_univ _), card_univ, Fintype.card_fin] at this + have : (5 : ℝ) ≤ #(univ.filter fun x => 1 / 6 * 1 ≤ G x 5) := by exact_mod_cast this + linarith + exact le_columnDetector (J := 1) (K := 480) (G := G) (R := 4) + (retentionChannels_all (V := Fin 6) one_pos le_rfl) one_pos one_pos (by norm_num) + (δ₁ := 1 / 6) (fun t ht => up_of_lt (by linarith)) (down_le_one _) + (by norm_num : (0 : ℝ) < 1 / 2) (fun t ht => down_of_le ht) G0 G_row (by norm_num) + one_pos (by norm_num) (by norm_num) hcount + +-- An empty column has no substantial entries, so its detector number is at most `1 / 4`. +example : columnDetector all all (up (1 / 10)) (down (1 / 2)) 1 480 1 G 0 ≤ 1 / 4 := by + refine not_lt.mp fun h => ?_ + have := lt_card_of_lt_columnDetector (J := 1) (K := 480) (G := G) + (retentionChannels_all (V := Fin 6) one_pos le_rfl) one_pos (up_nonneg _) (up_le_one _) + (fun t ht => up_of_le ht) (down_le_one _) one_pos h + have hempty : (univ.filter fun x => 1 / 10 * 1 < G x 0) = ∅ := by + ext x; simp only [G, of_apply, Fin.reduceEq, false_and, ↓reduceIte, mem_filter, mem_univ, + true_and, notMem_empty, iff_false, not_lt]; norm_num + rw [hempty, card_empty, Nat.cast_zero] at this + norm_num at this + +/-! ### A stage of the hierarchy with detector-chosen multipliers -/ + +/-- A walk on three time layers: from `0` to `1` and from `1` to `2`, each with probability +`f = 1 / 2`. -/ +private noncomputable def C : Matrix (Fin 3) (Fin 3) ℝ := !![0, 1 / 2, 0; 0, 0, 1 / 2; 0, 0, 0] + +private theorem hC : C.IsStrictUpperTriangular := by + intro i j h; fin_cases i <;> fin_cases j <;> simp_all [C] + +private theorem hC0 : ∀ x y, 0 ≤ C x y := by + intro x y; fin_cases x <;> fin_cases y <;> norm_num [C] + +private theorem hCf : ∀ x y, C x y ≤ 1 / 2 := by + intro x y; fin_cases x <;> fin_cases y <;> norm_num [C] + +private theorem hC1 : C *ᵥ 1 ≤ 1 := by + intro x; fin_cases x <;> norm_num [C, mulVec, dotProduct, Fin.sum_univ_three] + +/-- The hard base cutoff `t ↦ max (t - θ f) 0` with `θ = 1 / 4`, `f = 1 / 2`. -/ +private noncomputable def c (t : ℝ) : ℝ := max (t - 1 / 8) 0 + +private theorem hcL : ∀ s t, s ≤ t → c t - c s ≤ 1 * (t - s) := fun s t _ => by + simp only [c, one_mul] + have := le_max_left (s - 1 / 8) 0 + have := le_max_right (s - 1 / 8) 0 + have : max (t - 1 / 8) 0 ≤ max (s - 1 / 8) 0 + (t - s) := max_le (by linarith) (by linarith) + linarith + +private theorem c_nonneg (t : ℝ) : 0 ≤ c t := le_max_right _ _ +private theorem c_le (t : ℝ) (ht : 0 ≤ t) : c t ≤ t := max_le (by linarith) ht +private theorem c_mono : Monotone c := fun _ _ h => max_le_max (by linarith) le_rfl + +/-! ### The pilot -/ + +/-- A column number that flags column `2`, whatever the input. -/ +private noncomputable def flag2 : Matrix (Fin 3) (Fin 3) ℝ → Fin 3 → ℝ := + fun _ y => if y = 2 then 1 else 0 + +-- After one pilot step the running maximum flags column `2`, which loses its multiplier. +example : pilotMax c (down (1 / 2)) flag2 C 1 2 = 1 := by + rw [pilotMax_succ]; norm_num [flag2] + +-- Column `1` is corrected, `Ê₁ (0, 1) = c (1 / 2) = 3 / 8`; column `2` is not. +example : pilotCorrection c (down (1 / 2)) flag2 C 1 0 1 = 3 / 8 := by + rw [pilotCorrection_succ_apply, pilotMax_succ] + norm_num [pilotInput, flag2, c, C, down] + +example : pilotCorrection c (down (1 / 2)) flag2 C 1 1 2 = 0 := by + rw [pilotCorrection_succ_apply, pilotMax_succ] + norm_num [flag2, down] + +-- The pilot corrections have row sums at most the step count. +example (x : Fin 3) : ∑ y, pilotCorrection c (down (1 / 2)) flag2 C 2 x y ≤ 2 := by + exact_mod_cast (isCorrectionSeq_pilotCorrection hC0 c_nonneg c_le (down_nonneg _) + (down_le_one _)).sum_le hC1 2 x + +-- The actual correction with the final multiplier stays below the pilot. +example (x y : Fin 3) : + cutoffCorrectionIter (fun y t => c t * down (1 / 2) (pilotMax c (down (1 / 2)) flag2 C 2 y)) + C 1 x y ≤ pilotCorrection c (down (1 / 2)) flag2 C 1 x y := + (cutoffCorrectionIter_le_pilotCorrection hC0 c_nonneg c_le c_mono (down_nonneg _) + (down_le_one _) (down_antitone _) (by norm_num : 1 ≤ 2) x y).1 + +/-! ### One stage -/ + +/-- `e ^ 4 · 4 ^ 15 / 15! ≤ 1 / 8`: fifteen iterations make the truncation error small. -/ +private theorem factorial_bound : + (1 / 2 : ℝ) * Real.exp (1 / (1 / 4)) * (1 / (1 / 4)) ^ 15 / (Nat.factorial 15) ≤ 1 / 16 := by + have he : Real.exp 4 ≤ 55 := by + have h1 : Real.exp 4 = Real.exp 1 ^ 4 := by rw [← Real.exp_nat_mul]; norm_num + rw [h1] + calc Real.exp 1 ^ 4 ≤ 2.7182818286 ^ 4 := + pow_le_pow_left₀ (Real.exp_pos 1).le Real.exp_one_lt_d9.le 4 + _ ≤ 55 := by norm_num + norm_num [Nat.factorial] + nlinarith + +-- One stage with `k = 15` pilot and correction steps, `m + 1 = 32` copies, the full-retention +-- channels at rate `f = 1 / 2`, the detector score `up (1 / 10)` with `δ₀ = 1 / 10` and rank +-- `J = 297600 ≥ 2 C_π m k (k + 1) / δ₀`: the copies have entries at most `f / q = 1 / 4`, +-- intertwine with their projection, and at most `2 · 3` of them are active. +example : + let M := pilotMax c (down (1 / 2)) (columnDetector all all (up (1 / 10)) (down (1 / 2)) 297600 + 1 (1 / 2)) C 15 + let E := cutoffCorrectionIter (fun y t => c t * down (1 / 2) (M y)) C 15 + let D := C - E + E * C + (∀ a b, copyStage (up (3 / 16)) 31 (detectorWeight (up (1 / 4)) M) D a b ≤ 1 / 2 / 2) ∧ + copyStage (up (3 / 16)) 31 (detectorWeight (up (1 / 4)) M) D * + copyWeight (detectorWeight (up (1 / 4)) M) = + copyWeight (detectorWeight (up (1 / 4)) M) * D ∧ + (∀ a b, copyStage (up (3 / 16)) 31 (detectorWeight (up (1 / 4)) M) D a b ≠ 0 → + a ∈ copyCover univ (overloaded M) ∧ b ∈ copyCover univ (overloaded M)) ∧ + #(copyCover (m := 31) (univ : Finset (Fin 3)) (overloaded M)) ≤ + 2 * #(univ : Finset (Fin 3)) := + detectedStage_rates (X := all) (Y := all) (ϕ := up (1 / 10)) (ρ := down (1 / 2)) (J := 297600) + (K := 1) (f := 1 / 2) (c := c) (γ := down (1 / 2)) (C := C) (A := univ) (κ := up (1 / 4)) + (χ := up (3 / 16)) (q := 2) (k := 15) (m := 31) (θ := 1 / 4) (L := 1) (θ₂ := 1 / 4) + (τ₀ := 3 / 16) (τ₁ := 1 / 4) (δ₀ := 1 / 10) + (retentionChannels_all (V := Fin 3) (by norm_num) (by norm_num)) hC hC0 hCf hC1 + (fun _ _ _ => ⟨mem_univ _, mem_univ _⟩) (by norm_num) c_nonneg + (fun t => le_of_eq (by norm_num [c])) c_mono hcL + (fun t => by norm_num [c]) (by norm_num) zero_le_one (down_nonneg _) (down_le_one _) + (fun t ht => down_of_le ht) (up_nonneg _) (up_le_one _) (fun t ht => up_of_le ht) + (fun t ht => up_of_lt (by linarith)) (by norm_num) (up_nonneg _) (up_le_one _) (by norm_num) + (fun t ht => up_of_le ht) (down_le_one _) (by norm_num) (by norm_num) + (by linarith [factorial_bound]) (up_nonneg _) (up_le_one _) (fun t ht => up_of_le ht) + (fun t ht => up_of_lt (by linarith)) (by norm_num) (by norm_num) + +end ComplexityTests.Detectors diff --git a/ComplexityTests/KthLargest.lean b/ComplexityTests/KthLargest.lean new file mode 100644 index 000000000..7dac815a7 --- /dev/null +++ b/ComplexityTests/KthLargest.lean @@ -0,0 +1,53 @@ +/- +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.Data.Finset.KthLargest +import Mathlib.Algebra.Order.Ring.Rat +import Mathlib.Data.Fin.VecNotation +import Mathlib.Data.Fintype.Basic +import Mathlib.Tactic.FinCases +import Mathlib.Tactic.NormNum + +/-! +# Tests for the `k`-th largest value +-/ + +namespace ComplexityTests.KthLargest + +open Finset + +/-- The values `3, 1, 2, 0`. -/ +private def h : Fin 4 → ℚ := ![3, 1, 2, 0] + +private theorem filter_two_lt : (univ.filter fun x => (2 : ℚ) < h x) = {0} := by + decide + +private theorem filter_two_le : (univ.filter fun x => (2 : ℚ) ≤ h x) = {0, 2} := by + decide + +private theorem filter_zero_lt : (univ.filter fun x => (0 : ℚ) < h x) = {0, 1, 2} := by + decide + +-- The second largest of `3, 1, 2, 0` is `2`: two values are at least `2`, one exceeds it. +example : kthLargest 2 univ h = 2 := by + refine le_antisymm (not_lt.mp fun hlt => ?_) ?_ + · have := (lt_kthLargest_iff (by norm_num) (by norm_num)).mp hlt + rw [filter_two_lt, card_singleton] at this + omega + · rw [le_kthLargest_iff (by norm_num) (by norm_num), filter_two_le] + rfl + +-- Only three values are positive, so the padded fourth largest is `0`. +example : kthLargest 4 univ h = 0 := by + refine le_antisymm (not_lt.mp fun hlt => ?_) kthLargest_nonneg + have := (lt_kthLargest_iff (by norm_num) le_rfl).mp hlt + rw [filter_zero_lt] at this + exact absurd this (by decide) + +-- Values above a nonnegative bound bound the order statistic. +example (k : ℕ) : kthLargest k univ h ≤ 3 := + kthLargest_le (by norm_num) fun x _ => by fin_cases x <;> norm_num [h] + +end ComplexityTests.KthLargest From 80b604b4b2d9f650f1c5442bd133025c2e998f00 Mon Sep 17 00:00:00 2001 From: Christian Reitwiessner Date: Fri, 30 Oct 2026 01:08:54 +0000 Subject: [PATCH 21/25] refactor(Foundations): derive fixed-multiplier iterate bounds from IsCorrectionSeq The row-sum, entry and input bounds of cutoffCorrectionIter in CopyStage are the fixed-multiplier case of the correction-sequence bounds; reuse them instead of re-proving. Statements are unchanged. Co-Authored-By: Claude Opus 5.5 --- .../LinearAlgebra/Matrix/CopyStage.lean | 58 ++++--------------- 1 file changed, 10 insertions(+), 48 deletions(-) diff --git a/Complexity/Foundations/LinearAlgebra/Matrix/CopyStage.lean b/Complexity/Foundations/LinearAlgebra/Matrix/CopyStage.lean index aaad7308f..d61617c73 100644 --- a/Complexity/Foundations/LinearAlgebra/Matrix/CopyStage.lean +++ b/Complexity/Foundations/LinearAlgebra/Matrix/CopyStage.lean @@ -8,6 +8,7 @@ module -- upstream: candidate public import Complexity.Foundations.LinearAlgebra.Matrix.FactorialTruncation +import Complexity.Foundations.LinearAlgebra.Matrix.PilotCorrection import Mathlib.Algebra.BigOperators.Fin /-! @@ -95,65 +96,24 @@ variable {V : Type*} [Fintype V] {φ : V → ℝ → ℝ} {C : Matrix V V ℝ} { variable (hC0 : ∀ x y, 0 ≤ C x y) (hφ0 : ∀ y t, 0 ≤ φ y t) (hφθ : ∀ y t, φ y t ≤ max (t - θ * f) 0) (hθf : 0 ≤ θ * f) -omit [Fintype V] in -include hφθ hθf in -private theorem cutoff_le_self' (y : V) {t : ℝ} (ht : 0 ≤ t) : φ y t ≤ t := - (hφθ y t).trans (max_le (by linarith) ht) - omit [Fintype V] in include hφ0 hφθ hθf in private theorem cutoff_zero (y : V) : φ y 0 = 0 := le_antisymm ((hφθ y 0).trans (max_le (by linarith) le_rfl)) (hφ0 y 0) -include hC0 hφ0 hφθ hθf in -private theorem iter_succ_le_input (k : ℕ) (x y : V) : - cutoffCorrectionIter φ C (k + 1) x y ≤ (C + cutoffCorrectionIter φ C k * C) x y := by - rw [cutoffCorrectionIter_succ] - exact cutoff_le_self' hφθ hθf y <| add_nonneg (hC0 x y) <| Finset.sum_nonneg fun z _ => - mul_nonneg (cutoffCorrectionIter_nonneg hφ0 k x z) (hC0 z y) - include hC0 hφ0 hφθ hθf in /-- **Row sums of the iterates**: the `k`-th iterate of a cutoff correction of a substochastic `C` has row sums at most `k` [OpenAI2026LogSpace, Lemma 4.2]. -/ theorem cutoffCorrectionIter_sum_le (hC1 : C *ᵥ 1 ≤ 1) (k : ℕ) (x : V) : - ∑ y, cutoffCorrectionIter φ C k x y ≤ k := by - have hrow : ∀ z, ∑ y, C z y ≤ 1 := fun z => by simpa [mulVec, dotProduct] using hC1 z - induction k with - | zero => simp [cutoffCorrectionIter] - | succ k ih => - set F := cutoffCorrectionIter φ C k - calc ∑ y, cutoffCorrectionIter φ C (k + 1) x y ≤ ∑ y, (C + F * C) x y := - Finset.sum_le_sum fun y _ => iter_succ_le_input hC0 hφ0 hφθ hθf k x y - _ = ∑ y, C x y + ∑ z, F x z * ∑ y, C z y := by - simp only [add_apply, mul_apply, Finset.sum_add_distrib, Finset.mul_sum] - rw [Finset.sum_comm] - _ ≤ 1 + ∑ z, F x z * 1 := add_le_add (hrow x) (Finset.sum_le_sum fun z _ => - mul_le_mul_of_nonneg_left (hrow z) (cutoffCorrectionIter_nonneg hφ0 k x z)) - _ ≤ (k + 1 : ℕ) := by simp only [mul_one]; push_cast; linarith - -include hC0 hφ0 hφθ hθf in -/-- The input `(C + E_k C) x y` of the `(k + 1)`-th step is at most `(k + 1) f`. -/ -private theorem input_le (hCf : ∀ x y, C x y ≤ f) (hf : 0 ≤ f) (hC1 : C *ᵥ 1 ≤ 1) (k : ℕ) - (x y : V) : (C + cutoffCorrectionIter φ C k * C) x y ≤ (k + 1) * f := by - have hsum := cutoffCorrectionIter_sum_le hC0 hφ0 hφθ hθf hC1 k x - calc (C + cutoffCorrectionIter φ C k * C) x y - = C x y + ∑ z, cutoffCorrectionIter φ C k x z * C z y := rfl - _ ≤ f + ∑ z, cutoffCorrectionIter φ C k x z * f := add_le_add (hCf x y) - (Finset.sum_le_sum fun z _ => - mul_le_mul_of_nonneg_left (hCf z y) (cutoffCorrectionIter_nonneg hφ0 k x z)) - _ ≤ (k + 1) * f := by rw [← Finset.sum_mul]; nlinarith + ∑ y, cutoffCorrectionIter φ C k x y ≤ k := + (isCorrectionSeq_cutoffCorrectionIter hC0 hφ0 hφθ hθf).sum_le hC1 k x include hC0 hφ0 hφθ hθf in /-- **Entries of the iterates**: the `k`-th iterate has entries at most `k f` [OpenAI2026LogSpace, Lemma 4.2]. -/ theorem cutoffCorrectionIter_le_mul (hCf : ∀ x y, C x y ≤ f) (hf : 0 ≤ f) (hC1 : C *ᵥ 1 ≤ 1) - (k : ℕ) (x y : V) : cutoffCorrectionIter φ C k x y ≤ k * f := by - cases k with - | zero => simp [cutoffCorrectionIter] - | succ k => - push_cast - exact (iter_succ_le_input hC0 hφ0 hφθ hθf k x y).trans - (input_le hC0 hφ0 hφθ hθf hCf hf hC1 k x y) + (k : ℕ) (x y : V) : cutoffCorrectionIter φ C k x y ≤ k * f := + (isCorrectionSeq_cutoffCorrectionIter hC0 hφ0 hφθ hθf).le_mul hCf hf hC1 k x y include hC0 hφ0 hφθ hθf in /-- **The residual entry bound**: `C - E_k + E_k C` has entries at most `(k + 1) f` @@ -161,7 +121,8 @@ include hC0 hφ0 hφθ hθf in theorem cutoffCorrection_residual_le_mul (hCf : ∀ x y, C x y ≤ f) (hf : 0 ≤ f) (hC1 : C *ᵥ 1 ≤ 1) (k : ℕ) (x y : V) : (C - cutoffCorrectionIter φ C k + cutoffCorrectionIter φ C k * C) x y ≤ (k + 1) * f := by - have h := input_le hC0 hφ0 hφθ hθf hCf hf hC1 k x y + have h := (isCorrectionSeq_cutoffCorrectionIter hC0 hφ0 hφθ hθf).input_le_mul hCf hf hC1 k + x y have h0 := cutoffCorrectionIter_nonneg (C := C) hφ0 k x y simp only [add_apply, sub_apply] at h ⊢ linarith @@ -180,12 +141,13 @@ theorem cutoffCorrection_residual_dominates (hCf : ∀ x y, C x y ≤ f) (hf : 0 have ha0 : 0 ≤ (C + cutoffCorrectionIter φ C k * C) x y := add_nonneg (hC0 x y) (Finset.sum_nonneg fun z _ => mul_nonneg (cutoffCorrectionIter_nonneg hφ0 k x z) (hC0 z y)) - have ha := input_le hC0 hφ0 hφθ hθf hCf hf hC1 k x y + have ha := (isCorrectionSeq_cutoffCorrectionIter hC0 hφ0 hφθ hθf).input_le_mul hCf hf hC1 k + x y have hEa : cutoffCorrectionIter φ C (k + 1) x y = φ y ((C + cutoffCorrectionIter φ C k * C) x y) := by rw [cutoffCorrectionIter_succ]; rfl have he0 := cutoffCorrectionIter_nonneg (C := C) hφ0 (k + 1) x y - have hea := iter_succ_le_input hC0 hφ0 hφθ hθf k x y + have hea := (isCorrectionSeq_cutoffCorrectionIter hC0 hφ0 hφθ hθf).le_input k x y have hFE : (cutoffCorrectionIter φ C k * C) x y ≤ (cutoffCorrectionIter φ C (k + 1) * C) x y := Finset.sum_le_sum fun z _ => mul_le_mul_of_nonneg_right (cutoffCorrectionIter_le_succ hC0 hφ0 hφm k x z) (hC0 z y) From 0fd3e72a85ca7c97e9a56a4ef02de0155f002e94 Mon Sep 17 00:00:00 2001 From: Christian Reitwiessner Date: Fri, 30 Oct 2026 01:12:51 +0000 Subject: [PATCH 22/25] feat(Probability): affine retention channels satisfy the detector interface Instantiate RetentionChannels (#1696) with the affine channels of #1688 at rate a^H, with c_pi = 1, C_pi = C_pair = 2^H and C_var = 4. Co-Authored-By: Claude Opus 5.5 --- Complexity.lean | 1 + .../DetectorChannels.lean | 66 +++++++++++++++++++ ComplexityTests/DetectorChannels.lean | 43 ++++++++++++ 3 files changed, 110 insertions(+) create mode 100644 Complexity/Probability/PairwiseIndependentHash/DetectorChannels.lean create mode 100644 ComplexityTests/DetectorChannels.lean diff --git a/Complexity.lean b/Complexity.lean index b6aec3207..bc7a47aa1 100644 --- a/Complexity.lean +++ b/Complexity.lean @@ -2918,6 +2918,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.DetectorChannels public import Complexity.Probability.PairwiseIndependentHash.Retention public import Complexity.Probability.PairwiseIndependentHash.RetentionChannel public import Complexity.Probability.PairwiseIndependentHash.Shift diff --git a/Complexity/Probability/PairwiseIndependentHash/DetectorChannels.lean b/Complexity/Probability/PairwiseIndependentHash/DetectorChannels.lean new file mode 100644 index 000000000..ec1343a5e --- /dev/null +++ b/Complexity/Probability/PairwiseIndependentHash/DetectorChannels.lean @@ -0,0 +1,66 @@ +/- +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.Probability.ColumnDetector +public import Complexity.Probability.PairwiseIndependentHash.RetentionChannel + +/-! +# Affine retention channels satisfy the detector interface + +The affine retention channels over `𝔽_P` (`Cslib.Probability.affineRetains`) satisfy the channel +interface `Cslib.Probability.RetentionChannels` of the column detectors, with the constants +`c_π = 1`, `C_π = C_pair = 2 ^ H` and `C_var = 4`. Vertices are identified with field elements +through an injective identifier map `ident : V → ZMod P`, and both channels use the affine seed +space; their independence comes from the product of the two seed spaces. So the detector lemma +(`Matrix.le_columnDetector`, `Matrix.lt_card_of_lt_columnDetector`) and the detected stage +(`Matrix.detectedStage_rates`) hold for these channels at rate `f = a ^ H`, where +`1 ≤ P a` and `a ≤ 1` [OpenAI2026LogSpace, (4.8), (4.9)]. + +## Main results + +* `Cslib.Probability.retentionChannels_affineRetains`: the affine channels at rate `a ^ H`. + +## References + +* [OpenAI, *Exact Derandomization of Logarithmic Space: L = RL = BPL*][OpenAI2026LogSpace], + Section 4.2 (preprint, not peer reviewed) +-/ + +public section + +open Finset + +namespace Cslib.Probability + +variable {V : Type*} {P H : ℕ} [Fact P.Prime] + +/-- **Affine retention channels satisfy the detector interface.** Let `ident : V → ZMod P` be +injective, `1 ≤ P a` and `a ≤ 1`, and `L = ⌈P a⌉`. Retaining `v` when the affine seed retains +`ident v`, for each of two channels, gives retention channels at rate `f = a ^ H` with retention +probability `π = (L / P) ^ H` and constants `c_π = 1`, `C_π = C_pair = 2 ^ H`, `C_var = 4`. -/ +theorem retentionChannels_affineRetains {ident : V → ZMod P} (hident : Function.Injective ident) + {a : ℝ} (hPa : 1 ≤ P * a) (ha : a ≤ 1) : + RetentionChannels (fun s v => affineRetains P H ⌈P * a⌉₊ s (ident v)) + (fun s v => affineRetains P H ⌈P * a⌉₊ s (ident v)) (a ^ H) + ((((⌈P * a⌉₊ : ℕ) : ℝ) / P) ^ H) 1 (2 ^ H) (2 ^ H) 4 := by + obtain ⟨hL, hlow, hup, hpair, htail⟩ := affineRetains_rates (H := H) hPa ha + have hdens : ∀ v, (dens {s | affineRetains P H ⌈P * a⌉₊ s (ident v)} : ℝ) = + (((⌈P * a⌉₊ : ℕ) : ℝ) / P) ^ H := fun v => by + rw [dens_affineRetains hL]; push_cast; rfl + refine ⟨hdens, hdens, by rw [one_mul]; exact hlow, hup, fun w y hwy => ?_, fun A hA => ?_⟩ + · exact hpair _ _ (hident.ne hwy) + · have hcard : #(A.image ident) = #A := card_image_of_injective A hident + have hfilter : ∀ s, #{x ∈ A | affineRetains P H ⌈P * a⌉₊ s (ident x)} = + #{y ∈ A.image ident | affineRetains P H ⌈P * a⌉₊ s y} := fun s => by + rw [filter_image, card_image_of_injective _ hident] + have := htail (A.image ident) (hA.image ident) + simp only [hcard, ← hfilter] at this + exact this + +end Cslib.Probability diff --git a/ComplexityTests/DetectorChannels.lean b/ComplexityTests/DetectorChannels.lean new file mode 100644 index 000000000..a00f4d873 --- /dev/null +++ b/ComplexityTests/DetectorChannels.lean @@ -0,0 +1,43 @@ +/- +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.DetectorChannels +import Mathlib.Tactic.NormNum.Prime + +/-! +# Tests for affine channels in the column detector +-/ + +namespace ComplexityTests.DetectorChannels + +open Finset Matrix Cslib.Probability + +private instance : Fact (Nat.Prime 5) := ⟨by norm_num⟩ + +/-- The affine channels on `𝔽₅` with `H = 2` and `a = 1 / 2`: rate `f = 1 / 4`, side +`L = ⌈5 / 2⌉ = 3`, retention probability `(3 / 5) ^ 2`. -/ +private theorem channels : + RetentionChannels (fun s (v : ZMod 5) => affineRetains 5 2 ⌈(5 : ℕ) * (1 / 2 : ℝ)⌉₊ s (id v)) + (fun s (v : ZMod 5) => affineRetains 5 2 ⌈(5 : ℕ) * (1 / 2 : ℝ)⌉₊ s (id v)) ((1 / 2) ^ 2) + ((((⌈(5 : ℕ) * (1 / 2 : ℝ)⌉₊ : ℕ) : ℝ) / (5 : ℕ)) ^ 2) 1 (2 ^ 2) (2 ^ 2) 4 := + retentionChannels_affineRetains Function.injective_id (by norm_num) (by norm_num) + +-- With detector rank `J = 20`, the threshold `J / (4 C_π f) = 20 / (4 · 4 · (1 / 4)) = 5` is the +-- whole vertex set, so on `𝔽₅` no column is ever flagged, whatever the matrix. +example (G : Matrix (ZMod 5) (ZMod 5) ℝ) (y : ZMod 5) : + columnDetector (fun s (v : ZMod 5) => affineRetains 5 2 ⌈(5 : ℕ) * (1 / 2 : ℝ)⌉₊ s (id v)) + (fun s (v : ZMod 5) => affineRetains 5 2 ⌈(5 : ℕ) * (1 / 2 : ℝ)⌉₊ s (id v)) + (fun t => min (max t 0) 1) (fun _ => 1) 20 1 ((1 / 2) ^ 2) G y ≤ 1 / 4 := by + refine not_lt.mp fun h => ?_ + have := lt_card_of_lt_columnDetector channels (by norm_num) + (fun t => le_min (le_max_right _ _) zero_le_one) (fun t => min_le_right _ _) (δ₀ := 0) + (fun t ht => by rw [max_eq_right ht, min_eq_left zero_le_one]) (fun _ => le_rfl) + (by norm_num) h + have hcard : (#({x | 0 * (1 / 2) ^ 2 < G x y} : Finset (ZMod 5)) : ℝ) ≤ 5 := by + exact_mod_cast (card_le_univ _).trans (by simp) + norm_num at this hcard + linarith + +end ComplexityTests.DetectorChannels From 34406a084312428fd65108771467fbc7086f9c3f Mon Sep 17 00:00:00 2001 From: Christian Reitwiessner Date: Fri, 30 Oct 2026 02:28:47 +0000 Subject: [PATCH 23/25] fix(Foundations): qualify Matrix apply lemmas in CopyStage and PilotCorrection for rc2 Under rc2 the root-namespace add_apply/sub_apply/mul_apply no longer apply to matrices; use the Matrix.* versions, as rc2-refresh/1676 and /1677 do for the lower modules of this stack. Proof-only; no statement changes. Co-Authored-By: Claude Opus 5.5 --- .../Foundations/LinearAlgebra/Matrix/CopyStage.lean | 8 ++++---- .../Foundations/LinearAlgebra/Matrix/PilotCorrection.lean | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Complexity/Foundations/LinearAlgebra/Matrix/CopyStage.lean b/Complexity/Foundations/LinearAlgebra/Matrix/CopyStage.lean index d61617c73..9ee05d128 100644 --- a/Complexity/Foundations/LinearAlgebra/Matrix/CopyStage.lean +++ b/Complexity/Foundations/LinearAlgebra/Matrix/CopyStage.lean @@ -124,7 +124,7 @@ theorem cutoffCorrection_residual_le_mul (hCf : ∀ x y, C x y ≤ f) (hf : 0 have h := (isCorrectionSeq_cutoffCorrectionIter hC0 hφ0 hφθ hθf).input_le_mul hCf hf hC1 k x y have h0 := cutoffCorrectionIter_nonneg (C := C) hφ0 k x y - simp only [add_apply, sub_apply] at h ⊢ + simp only [Matrix.add_apply, Matrix.sub_apply] at h ⊢ linarith include hC0 hφ0 hφθ hθf in @@ -174,7 +174,7 @@ theorem cutoffCorrection_residual_dominates (hCf : ∀ x y, C x y ≤ f) (hf : 0 mul_le_of_le_one_left (by linarith) (by linarith) have hadef : a = C x y + (F * C) x y := rfl rw [hcoef] - simp only [add_apply, sub_apply] + simp only [Matrix.add_apply, Matrix.sub_apply] nlinarith variable {A : Finset V} @@ -191,7 +191,7 @@ theorem cutoffCorrectionIter_mem (hA : ∀ x y, C x y ≠ 0 → x ∈ A ∧ y have hCxy : C x y = 0 := by by_contra h'; exact hxy (hA x y h') have hin : (C + cutoffCorrectionIter φ C k * C) x y = 0 := by - simp only [add_apply, mul_apply, hCxy, zero_add] + simp only [Matrix.add_apply, Matrix.mul_apply, hCxy, zero_add] refine Finset.sum_eq_zero fun z _ => ?_ by_cases hE : cutoffCorrectionIter φ C k x z = 0 · rw [hE, zero_mul] @@ -214,7 +214,7 @@ theorem cutoffCorrection_residual_mem (hA : ∀ x y, C x y ≠ 0 → x ∈ A ∧ cutoffCorrectionIter_mem hφ0 hφθ hθf hA k have hCxy : C x y = 0 := by by_contra h'; exact hxy (hA x y h') have hExy : cutoffCorrectionIter φ C k x y = 0 := by by_contra h'; exact hxy (hE x y h') - simp only [add_apply, sub_apply, mul_apply, hCxy, hExy, sub_zero, zero_add] + simp only [Matrix.add_apply, Matrix.sub_apply, Matrix.mul_apply, hCxy, hExy, sub_zero, zero_add] refine Finset.sum_eq_zero fun z _ => ?_ by_cases hEz : cutoffCorrectionIter φ C k x z = 0 · rw [hEz, zero_mul] diff --git a/Complexity/Foundations/LinearAlgebra/Matrix/PilotCorrection.lean b/Complexity/Foundations/LinearAlgebra/Matrix/PilotCorrection.lean index a6aa6efe3..d9373a6d8 100644 --- a/Complexity/Foundations/LinearAlgebra/Matrix/PilotCorrection.lean +++ b/Complexity/Foundations/LinearAlgebra/Matrix/PilotCorrection.lean @@ -99,7 +99,7 @@ theorem sum_input_le (hC1 : C *ᵥ 1 ≤ 1) : have hrow : ∀ z, ∑ y, C z y ≤ 1 := fun z => by simpa [mulVec, dotProduct] using hC1 z have hinput : ∀ i x, ∑ y, F i x y ≤ i → ∑ y, (C + F i * C) x y ≤ i + 1 := fun i x hi => by calc ∑ y, (C + F i * C) x y = ∑ y, C x y + ∑ z, F i x z * ∑ y, C z y := by - simp only [add_apply, mul_apply, sum_add_distrib, mul_sum] + simp only [Matrix.add_apply, Matrix.mul_apply, sum_add_distrib, mul_sum] rw [sum_comm] _ ≤ 1 + ∑ z, F i x z * 1 := add_le_add (hrow x) (sum_le_sum fun z _ => mul_le_mul_of_nonneg_left (hrow z) (hF.nonneg i x z)) @@ -148,7 +148,7 @@ theorem input_mem_and_mem (hA : ∀ x y, C x y ≠ 0 → x ∈ A ∧ y ∈ A) : by_contra hxy apply h have hCxy : C x y = 0 := by by_contra h'; exact hxy (hA x y h') - simp only [add_apply, mul_apply, hCxy, zero_add] + simp only [Matrix.add_apply, Matrix.mul_apply, hCxy, zero_add] refine sum_eq_zero fun z _ => ?_ by_cases hE : F i x z = 0 · rw [hE, zero_mul] From e6b85378cab8203315c44bece13f456b566685cb Mon Sep 17 00:00:00 2001 From: Christian Reitwiessner Date: Fri, 30 Oct 2026 02:29:20 +0000 Subject: [PATCH 24/25] feat(Probability): pair and tail estimates for frame-conditioned retention channels Lemma 3.1, items 2-3, of the OpenAI preprint for frame-conditioned channels: the frame density q_fr (with 1/2 <= q_fr for r < H, via Mathlib's card_linearIndependent), pairwise independence of the unrestricted polynomial channel, the transfer bound dens_frame <= dens / q_fr, the pair bound and the Chebyshev lower tail, and the detector-interface instance retentionChannels_frameRetains (constants 2^H / q_fr and 4 / q_fr, or 2^(H+1) and 8 for r < H). Co-Authored-By: Claude Opus 5.5 --- Complexity.lean | 3 +- .../FrameRetention.lean | 355 ++++++++++++++++++ ComplexityTests/FrameRetention.lean | 101 +++++ 3 files changed, 458 insertions(+), 1 deletion(-) create mode 100644 Complexity/Probability/PairwiseIndependentHash/FrameRetention.lean create mode 100644 ComplexityTests/FrameRetention.lean diff --git a/Complexity.lean b/Complexity.lean index 2d38b53fd..1e4753357 100644 --- a/Complexity.lean +++ b/Complexity.lean @@ -2918,9 +2918,10 @@ 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.DetectorChannels public import Complexity.Probability.PairwiseIndependentHash.ConditionalAveraging +public import Complexity.Probability.PairwiseIndependentHash.DetectorChannels public import Complexity.Probability.PairwiseIndependentHash.FrameChannel +public import Complexity.Probability.PairwiseIndependentHash.FrameRetention public import Complexity.Probability.PairwiseIndependentHash.Retention public import Complexity.Probability.PairwiseIndependentHash.RetentionChannel public import Complexity.Probability.PairwiseIndependentHash.Shift diff --git a/Complexity/Probability/PairwiseIndependentHash/FrameRetention.lean b/Complexity/Probability/PairwiseIndependentHash/FrameRetention.lean new file mode 100644 index 000000000..736755dd5 --- /dev/null +++ b/Complexity/Probability/PairwiseIndependentHash/FrameRetention.lean @@ -0,0 +1,355 @@ +/- +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.Probability.ColumnDetector +public import Complexity.Probability.PairwiseIndependentHash.FrameChannel +import Complexity.Probability.PairwiseIndependentHash.Shift +import Mathlib.LinearAlgebra.Matrix.GeneralLinearGroup.Card + +/-! +# Retention estimates for frame-conditioned channels + +A frame-conditioned channel `A = (a₀, F)` (`Cslib.Probability.FrameChannel`) is a uniformly random +polynomial channel `y ↦ a₀ + ∑ j, y ^ (j + 1) • M j` conditioned on its coefficient columns `M` +forming a frame, i.e. being linearly independent. Its single evaluations have the exact +retention probability `(L / P) ^ H` (`dens_eval_mem_retentionBox`). Here we prove the pair and +lower-tail estimates, following the proof of Lemma 3.1 of the OpenAI preprint +[OpenAI2026LogSpace, Lemma 3.1 and its proof, pp. 9–10]: + +* The *frame density* `q_fr = #frames / #matrices` (`frameDensity`) is + `∏_{i < r} (1 - P ^ i / P ^ H)` (`frameDensity_eq_prod`), by Mathlib's count of linearly + independent families, and it is at least `1 / 2` for `r < H` (`one_div_two_le_frameDensity`). +* Without the frame condition, the polynomial channel (`polyChannelEval`) is a pairwise + independent hash family as soon as it has a non-constant column (`r ≥ 1`): + `isPairwiseIndependentHash_polyChannelEval`. +* Conditioning on the frame increases the probability of any event by at most the factor + `1 / q_fr` (`dens_frameChannel_le`). + +Together these give the pair bound `π₁ π₂ / q_fr` for two distinct identifiers +(`dens_eval_mem_and_eval_mem_le`) and the Chebyshev lower tail `4 / (#A π q_fr)` +(`dens_two_mul_card_filter_eval_mem_lt_le`). So frame-conditioned channels satisfy the detector +interface `Cslib.Probability.RetentionChannels` with constants `c_π = 1`, `C_π = 2 ^ H`, +`C_pair = 2 ^ H / q_fr` and `C_var = 4 / q_fr` (`retentionChannels_frameRetains`), and for +`r < H` with the constants `2 ^ (H + 1)` and `8`, which depend on `H` only +(`retentionChannels_frameRetains_of_lt`). + +## Main definitions + +* `Cslib.Probability.frameDensity`: the probability `q_fr` that a uniformly random family of `r` + vectors in `ZMod P ^ H` is a frame. +* `Cslib.Probability.polyChannelEval`: the value of a polynomial channel with unrestricted + coefficient columns. +* `Cslib.Probability.frameRetains`: a frame-conditioned channel retains an identifier. + +## Main results + +* `Cslib.Probability.card_frame`: there are `∏_{i < r} (P ^ H - P ^ i)` frames. +* `Cslib.Probability.frameDensity_eq_prod`, `Cslib.Probability.frameDensity_pos`, + `Cslib.Probability.one_div_two_le_frameDensity`: the frame density and its bounds. +* `Cslib.Probability.isPairwiseIndependentHash_polyChannelEval`: unrestricted polynomial channels + are pairwise independent. +* `Cslib.Probability.dens_frameChannel_le`: the transfer from unrestricted to frame-conditioned + channels. +* `Cslib.Probability.dens_eval_mem_and_eval_mem_le`: the pair bound. +* `Cslib.Probability.dens_two_mul_card_filter_eval_mem_lt_le`: the lower tail. +* `Cslib.Probability.retentionChannels_frameRetains`, + `Cslib.Probability.retentionChannels_frameRetains_of_lt`: frame-conditioned channels satisfy the + detector interface. + +## References + +* [OpenAI, *Exact Derandomization of Logarithmic Space: L = RL = BPL*][OpenAI2026LogSpace], + Lemma 3.1 (preprint, not peer reviewed) +-/ + +public section + +namespace Cslib.Probability + +open Finset + +variable {P H r : ℕ} + +section Density + +variable (P H r) in +/-- The **frame density** `q_fr`: the probability that a uniformly random family of `r` vectors +in `ZMod P ^ H` is a frame [OpenAI2026LogSpace, proof of Lemma 3.1]. -/ +noncomputable def frameDensity [NeZero P] : ℝ := + Fintype.card (Frame P H r) / Fintype.card (Fin r → Fin H → ZMod P) + +/-- The frame density is nonnegative. -/ +theorem frameDensity_nonneg [NeZero P] : 0 ≤ frameDensity P H r := by + rw [frameDensity] + positivity + +variable [Fact P.Prime] + +/-- **Counting frames**: for `r ≤ H` there are `∏_{i < r} (P ^ H - P ^ i)` frames of length `r` +in `ZMod P ^ H`. -/ +theorem card_frame (hr : r ≤ H) : + Fintype.card (Frame P H r) = ∏ i : Fin r, (P ^ H - P ^ (i : ℕ)) := by + rw [← Nat.card_eq_fintype_card] + have h := card_linearIndependent (K := ZMod P) (V := Fin H → ZMod P) (k := r) + (by rwa [Module.finrank_fintype_fun_eq_card, Fintype.card_fin]) + rwa [Module.finrank_fintype_fun_eq_card, Fintype.card_fin, ZMod.card] at h + +/-- The frame density is `∏_{i < r} (1 - P ^ i / P ^ H)` for `r ≤ H`. -/ +theorem frameDensity_eq_prod (hr : r ≤ H) : + frameDensity P H r = ∏ i : Fin r, (1 - (P : ℝ) ^ (i : ℕ) / P ^ H) := by + have hP : (P : ℝ) ^ H ≠ 0 := pow_ne_zero _ (Nat.cast_ne_zero.2 (Fact.out : P.Prime).ne_zero) + have hle (i : Fin r) : P ^ (i : ℕ) ≤ P ^ H := + Nat.pow_le_pow_right (Fact.out : P.Prime).pos (by omega) + rw [frameDensity, card_frame hr] + simp only [Fintype.card_fun, Fintype.card_fin, ZMod.card, Nat.cast_prod, Nat.cast_pow] + rw [← Fin.prod_const r ((P : ℝ) ^ H), ← prod_div_distrib] + refine prod_congr rfl fun i _ ↦ ?_ + rw [Nat.cast_sub (hle i), one_sub_div hP] + push_cast + rfl + +/-- `1 - P ^ r / P ^ H ≤ ∏_{i < r} (1 - P ^ i / P ^ H)` for `r ≤ H` and `P ≥ 2`. Each step +uses `(1 - u) ^ 2 ≥ 1 - P u`. -/ +private theorem one_sub_le_prod_one_sub {p : ℝ} (hp : 2 ≤ p) {H : ℕ} : + ∀ r ≤ H, 1 - p ^ r / p ^ H ≤ ∏ i : Fin r, (1 - p ^ (i : ℕ) / p ^ H) + | 0, _ => by + rw [Fin.prod_univ_zero, pow_zero, sub_le_self_iff] + positivity + | r + 1, hr => by + rw [Fin.prod_univ_castSucc, Fin.val_last] + simp only [Fin.val_castSucc] + have ih := one_sub_le_prod_one_sub hp (H := H) r (by omega) + have hu0 : 0 ≤ p ^ r / p ^ H := by positivity + have hu1 : p ^ r / p ^ H ≤ 1 := + div_le_one_of_le₀ (pow_le_pow_right₀ (by linarith) (show r ≤ H by omega)) (by positivity) + calc 1 - p ^ (r + 1) / p ^ H = 1 - p * (p ^ r / p ^ H) := by rw [pow_succ]; ring + _ ≤ (1 - p ^ r / p ^ H) * (1 - p ^ r / p ^ H) := by nlinarith + _ ≤ _ := mul_le_mul_of_nonneg_right ih (by linarith) + +/-- For `r < H`, at least half of all families of `r` vectors in `ZMod P ^ H` are frames. -/ +theorem one_div_two_le_frameDensity (hr : r < H) : 1 / 2 ≤ frameDensity P H r := by + have hp : (2 : ℝ) ≤ P := by exact_mod_cast (Fact.out : P.Prime).two_le + have hpos : (0 : ℝ) < P ^ H := by positivity + have hr' : (P : ℝ) ^ r * P ≤ P ^ H := by + rw [← pow_succ] + exact pow_le_pow_right₀ (by linarith) hr + have hfrac : (P : ℝ) ^ r / P ^ H ≤ 1 / 2 := by + rw [div_le_iff₀ hpos] + nlinarith [pow_pos (by linarith : (0 : ℝ) < P) r] + rw [frameDensity_eq_prod hr.le] + linarith [one_sub_le_prod_one_sub hp r hr.le] + +/-- For `r ≤ H` the frame density is positive. -/ +theorem frameDensity_pos (hr : r ≤ H) : 0 < frameDensity P H r := by + have := Frame.nonempty (P := P) hr + rw [frameDensity] + exact div_pos (by exact_mod_cast Fintype.card_pos) (by exact_mod_cast Fintype.card_pos) + +end Density + +section Unrestricted + +/-- The value `∑ j, y ^ (j + 1) • M j + a₀` at `y` of the polynomial channel with unrestricted +coefficient columns `M` and constant column `a₀`, for the seed `s = (M, a₀)`. -/ +def polyChannelEval (s : (Fin r → Fin H → ZMod P) × (Fin H → ZMod P)) (y : ZMod P) : + Fin H → ZMod P := + ∑ j : Fin r, y ^ (j.val + 1) • s.1 j + s.2 + +/-- A frame-conditioned channel evaluates as the unrestricted polynomial channel with the same +columns. -/ +theorem FrameChannel.eval_eq_polyChannelEval (A : FrameChannel P H r) (y : ZMod P) : + A.eval y = polyChannelEval (A.2.1, A.1) y := + add_comm _ _ + +/-- The coefficient part `M ↦ (y ↦ ∑ j, y ^ (j + 1) • M j)` of a polynomial channel, as an +additive map. -/ +private def polyCoeffHom : (Fin r → Fin H → ZMod P) →+ (ZMod P → Fin H → ZMod P) where + toFun M y := ∑ j : Fin r, y ^ (j.val + 1) • M j + map_zero' := by + funext y + simp + map_add' M N := by + funext y + simp [smul_add, sum_add_distrib] + +variable [Fact P.Prime] + +/-- **Unrestricted polynomial channels are pairwise independent**: with at least one +non-constant column, the values of a uniformly random polynomial channel at two distinct +identifiers are independent and uniform [OpenAI2026LogSpace, proof of Lemma 3.1]. The difference +of the values at `x₁ ≠ x₂` takes every value already through the first column, since +`x₁ - x₂` is invertible. -/ +theorem isPairwiseIndependentHash_polyChannelEval (hr : 0 < r) : + IsPairwiseIndependentHash (polyChannelEval (P := P) (H := H) (r := r)) := by + refine isPairwiseIndependentHash_add_of_surjective (polyCoeffHom (P := P) (H := H) (r := r)) + fun x₁ x₂ hx c ↦ ?_ + have hne : x₁ - x₂ ≠ 0 := sub_ne_zero.2 hx + refine ⟨Pi.single ⟨0, hr⟩ ((x₁ - x₂)⁻¹ • c), ?_⟩ + simp only [polyCoeffHom, AddMonoidHom.coe_mk, ZeroHom.coe_mk] + rw [Fintype.sum_eq_single ⟨0, hr⟩ fun j hj ↦ by rw [Pi.single_eq_of_ne hj, smul_zero], + Fintype.sum_eq_single ⟨0, hr⟩ fun j hj ↦ by rw [Pi.single_eq_of_ne hj, smul_zero], + Pi.single_eq_same, ← sub_smul, smul_smul, zero_add, pow_one, pow_one, + mul_inv_cancel₀ hne, one_smul] + +end Unrestricted + +section Transfer + +variable [NeZero P] + +/-- **Transfer to frame conditioning**: an event about the seed `(M, a₀)` of a polynomial channel +has, under frame conditioning, at most its unrestricted probability divided by the frame density +`q_fr` [OpenAI2026LogSpace, proof of Lemma 3.1]. -/ +theorem dens_frameChannel_le (E : (Fin r → Fin H → ZMod P) × (Fin H → ZMod P) → Prop) + [DecidablePred E] : + (dens {A : FrameChannel P H r | E (A.2.1, A.1)} : ℝ) ≤ dens {s | E s} / frameDensity P H r := by + have hinj : #{A : FrameChannel P H r | E (A.2.1, A.1)} ≤ #{s | E s} := + card_le_card_of_injOn (fun A ↦ (A.2.1, A.1)) (fun A hA ↦ by simpa using hA) + fun A _ B _ h ↦ by + simp only [Prod.mk.injEq] at h + exact Prod.ext h.2 (Subtype.ext h.1) + have hQ : (0 : ℝ) < Fintype.card (Fin r → Fin H → ZMod P) := by exact_mod_cast Fintype.card_pos + rw [dens_eq_card_div_card, dens_eq_card_div_card, frameDensity, Fintype.card_prod, + Fintype.card_prod] + push_cast + rw [div_div_div_eq, mul_comm (#{s | E s} : ℝ), mul_assoc, mul_div_mul_left _ _ hQ.ne', + mul_comm (Fintype.card (Fin H → ZMod P) : ℝ)] + exact div_le_div_of_nonneg_right (by exact_mod_cast hinj) (by positivity) + +variable [Fact P.Prime] {L L₁ L₂ : ℕ} + +/-- **Pair bound under frame conditioning**: for distinct identifiers `w ≠ y` and sides +`L₁, L₂ ≤ P`, a frame-conditioned channel with `r ≥ 1` retains `w` in the box of side `L₁` and `y` +in the box of side `L₂` with probability at most `(L₁ / P) ^ H (L₂ / P) ^ H / q_fr` +[OpenAI2026LogSpace, proof of Lemma 3.1, item 2]. -/ +theorem dens_eval_mem_and_eval_mem_le (hr : 0 < r) (hL₁ : L₁ ≤ P) (hL₂ : L₂ ≤ P) {w y : ZMod P} + (hwy : w ≠ y) : + (dens {A : FrameChannel P H r | + A.eval w ∈ retentionBox P H L₁ ∧ A.eval y ∈ retentionBox P H L₂} : ℝ) ≤ + ((L₁ : ℝ) / P) ^ H * ((L₂ : ℝ) / P) ^ H / frameDensity P H r := by + have h := dens_frameChannel_le (P := P) (H := H) (r := r) + fun s ↦ polyChannelEval s w ∈ retentionBox P H L₁ ∧ polyChannelEval s y ∈ retentionBox P H L₂ + simp only [← FrameChannel.eval_eq_polyChannelEval] at h + rw [(isPairwiseIndependentHash_polyChannelEval hr).dens_filter_apply_mem_and_apply_mem hwy, + card_retentionBox hL₁, card_retentionBox hL₂, Fintype.card_fun, Fintype.card_fin, + ZMod.card] at h + push_cast at h + rw [div_pow, div_pow] + convert h using 1 + rw [dens_eq_card_div_card] + push_cast + rfl + +/-- **Lower tail under frame conditioning**: for `r ≥ 1`, `L ≤ P` and `π = (L / P) ^ H`, a +frame-conditioned channel retains fewer than `#A π / 2` identifiers of `A` with probability at +most `4 / (#A π) / q_fr` [OpenAI2026LogSpace, proof of Lemma 3.1, item 3]. -/ +theorem dens_two_mul_card_filter_eval_mem_lt_le (hr : 0 < r) (hL : L ≤ P) (A : Finset (ZMod P)) + (hpos : 0 < (#A : ℝ) * ((L : ℝ) / P) ^ H) : + (dens {s : FrameChannel P H r | + 2 * (#{y ∈ A | s.eval y ∈ retentionBox P H L} : ℝ) < #A * ((L : ℝ) / P) ^ H} : ℝ) ≤ + 4 / (#A * ((L : ℝ) / P) ^ H) / frameDensity P H r := 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 ht := (isPairwiseIndependentHash_polyChannelEval (H := H) hr + ).dens_two_mul_card_filter_apply_mem_lt_le (𝕜 := ℝ) A (retentionBox P H L) (by rwa [hrate]) + rw [hrate] at ht + have h := dens_frameChannel_le (P := P) (H := H) (r := r) + fun s ↦ 2 * (#{y ∈ A | polyChannelEval s y ∈ retentionBox P H L} : ℝ) < + #A * ((L : ℝ) / P) ^ H + simp only [← FrameChannel.eval_eq_polyChannelEval] at h + exact h.trans (div_le_div_of_nonneg_right ht (frameDensity_nonneg)) + +end Transfer + +section Interface + +variable (P H) in +/-- The identifier `y` is **retained** by the frame-conditioned channel `s` when its value +`s.eval y` lies in the retention box of side `L`. -/ +abbrev frameRetains [NeZero P] (L : ℕ) (s : FrameChannel P H r) (y : ZMod P) : Prop := + s.eval y ∈ retentionBox P H L + +/-- A positive rate `a` from `1 ≤ P a`. -/ +private theorem pos_of_one_le_mul {P a : ℝ} (hP : 0 ≤ P) (hPa : 1 ≤ P * a) : 0 < a := by + by_contra h + nlinarith [mul_nonpos_of_nonneg_of_nonpos hP (not_lt.1 h)] + +variable {V : Type*} [Fact P.Prime] + +/-- **Frame-conditioned channels satisfy the detector interface.** Let `ident : V → ZMod P` be +injective, `1 ≤ r ≤ H`, `1 ≤ P a`, `a ≤ 1` and `L = ⌈P a⌉`. Retaining `v` when a uniformly random +frame-conditioned channel retains `ident v`, for each of two channels, gives retention channels at +rate `f = a ^ H` with retention probability `π = (L / P) ^ H` and constants `c_π = 1`, +`C_π = 2 ^ H`, `C_pair = 2 ^ H / q_fr` and `C_var = 4 / q_fr`, where `q_fr` is the frame +density [OpenAI2026LogSpace, Lemma 3.1, items 1–3]. -/ +theorem retentionChannels_frameRetains {ident : V → ZMod P} (hident : Function.Injective ident) + (hr0 : 0 < r) (hr : r ≤ H) {a : ℝ} (hPa : 1 ≤ P * a) (ha : a ≤ 1) : + RetentionChannels (fun (s : FrameChannel P H r) v ↦ frameRetains P H ⌈P * a⌉₊ s (ident v)) + (fun (s : FrameChannel P H r) v ↦ frameRetains P H ⌈P * a⌉₊ s (ident v)) (a ^ H) + ((((⌈P * a⌉₊ : ℕ) : ℝ) / P) ^ H) 1 (2 ^ H) (2 ^ H / frameDensity P H r) + (4 / frameDensity P H r) := by + obtain ⟨hL, hlow, hup, -, -⟩ := affineRetains_rates (P := P) (H := H) hPa ha + set π : ℝ := (((⌈P * a⌉₊ : ℕ) : ℝ) / P) ^ H + have hq := frameDensity_pos (P := P) hr + have hπ : 0 < π := (pow_pos (pos_of_one_le_mul (Nat.cast_nonneg P) hPa) H).trans_le hlow + have hdens : ∀ v, (dens {s : FrameChannel P H r | frameRetains P H ⌈P * a⌉₊ s (ident v)} : ℝ) = + π := fun v ↦ by + rw [dens_eval_mem_retentionBox hr hL] + push_cast + rfl + refine ⟨hdens, hdens, by rw [one_mul]; exact hlow, hup, fun w y hwy ↦ ?_, fun A hA ↦ ?_⟩ + · refine (dens_eval_mem_and_eval_mem_le hr0 hL hL (hident.ne hwy)).trans ?_ + rw [hdens, div_mul_eq_mul_div, div_mul_eq_mul_div, div_le_div_iff_of_pos_right hq] + exact mul_le_mul_of_nonneg_right hup hπ.le + · have hcard : #(A.image ident) = #A := card_image_of_injective A hident + have hfilter : ∀ s : FrameChannel P H r, + #{x ∈ A | s.eval (ident x) ∈ retentionBox P H ⌈P * a⌉₊} = + #{y ∈ A.image ident | s.eval y ∈ retentionBox P H ⌈P * a⌉₊} := fun s ↦ by + rw [filter_image, card_image_of_injective _ hident] + have hpos : 0 < (#(A.image ident) : ℝ) * π := + mul_pos (by exact_mod_cast (hA.image ident).card_pos) hπ + have := dens_two_mul_card_filter_eval_mem_lt_le hr0 hL (A.image ident) hpos + simp only [hcard, ← hfilter] at this + rwa [div_right_comm] at this + +/-- **Frame-conditioned channels with constants depending only on `H`.** For `1 ≤ r < H`, the +frame density is at least `1 / 2`, so the channels of `retentionChannels_frameRetains` satisfy the +detector interface with `c_π = 1`, `C_π = 2 ^ H`, `C_pair = 2 ^ (H + 1)` and `C_var = 8` +[OpenAI2026LogSpace, Lemma 3.1, items 1–3]. -/ +theorem retentionChannels_frameRetains_of_lt {ident : V → ZMod P} + (hident : Function.Injective ident) (hr0 : 0 < r) (hr : r < H) {a : ℝ} (hPa : 1 ≤ P * a) + (ha : a ≤ 1) : + RetentionChannels (fun (s : FrameChannel P H r) v ↦ frameRetains P H ⌈P * a⌉₊ s (ident v)) + (fun (s : FrameChannel P H r) v ↦ frameRetains P H ⌈P * a⌉₊ s (ident v)) (a ^ H) + ((((⌈P * a⌉₊ : ℕ) : ℝ) / P) ^ H) 1 (2 ^ H) (2 ^ (H + 1)) 8 := by + have h := retentionChannels_frameRetains hident hr0 hr.le hPa ha + have hq := one_div_two_le_frameDensity (P := P) hr + have hq0 : 0 < frameDensity P H r := by linarith + have hpair : 2 ^ H / frameDensity P H r ≤ 2 ^ (H + 1) := by + rw [div_le_iff₀ hq0, pow_succ] + nlinarith [pow_pos (by norm_num : (0 : ℝ) < 2) H] + have hvar : 4 / frameDensity P H r ≤ 8 := by + rw [div_le_iff₀ hq0] + linarith + refine ⟨h.dens_X, h.dens_Y, h.lower, h.upper, fun w y hwy ↦ (h.pair w y hwy).trans ?_, + fun A hA ↦ (h.tail A hA).trans ?_⟩ + · have := pos_of_one_le_mul (Nat.cast_nonneg P) hPa + gcongr + · have : 0 < (((⌈P * a⌉₊ : ℕ) : ℝ) / P) ^ H := by + have := pos_of_one_le_mul (Nat.cast_nonneg P) hPa + exact (by positivity : (0 : ℝ) < 1 * a ^ H).trans_le h.lower + have := mul_pos (by exact_mod_cast hA.card_pos : (0 : ℝ) < #A) this + gcongr + +end Interface + +end Cslib.Probability diff --git a/ComplexityTests/FrameRetention.lean b/ComplexityTests/FrameRetention.lean new file mode 100644 index 000000000..793e0390b --- /dev/null +++ b/ComplexityTests/FrameRetention.lean @@ -0,0 +1,101 @@ +/- +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.FrameRetention +import Mathlib.Tactic.NormNum.Prime + +/-! +# Tests for frame-conditioned retention estimates + +The frame density is evaluated on small cases. Over `𝔽₃` with `H = r = 1`, frame conditioning +breaks pairwise independence: two identifiers are retained jointly with probability `1 / 3`, +not `(2 / 3) ^ 2`, but within the pair bound `(2 / 3) ^ 2 / q_fr = 2 / 3`. Finally the +frame-conditioned channels over `𝔽₅` drive the column detector. +-/ + +namespace ComplexityTests.FrameRetention + +open Finset Matrix Cslib.Probability + +private instance : Fact (Nat.Prime 3) := ⟨by norm_num⟩ +private instance : Fact (Nat.Prime 5) := ⟨by norm_num⟩ + +-- Eight of the nine vectors of `𝔽₃ ^ 2` are frames of length one. +example : frameDensity 3 2 1 = 8 / 9 := by + rw [frameDensity_eq_prod (by norm_num)] + norm_num + +-- `(9 - 1) (9 - 3) = 48` of the `81` pairs of vectors in `𝔽₃ ^ 2` are frames. +example : Fintype.card (Frame 3 2 2) = 48 := by + rw [card_frame le_rfl] + decide + +-- Over `𝔽₃` with `H = 1`, the nonzero scalars are the frames: `q_fr = 2 / 3`. +private theorem frameDensity_three : frameDensity 3 1 1 = 2 / 3 := by + rw [frameDensity_eq_prod le_rfl] + norm_num + +-- For `r < H`, the frame density is at least `1 / 2`, uniformly in the field. +example : 1 / 2 ≤ frameDensity 5 3 2 := one_div_two_le_frameDensity (by norm_num) + +-- Under frame conditioning, only `a₀ = 0, F = 1` and `a₀ = 1, F = 2` retain both `0` and `1` in +-- the box `{0, 1}`: two of the six channels. +private theorem card_both : + #{A : FrameChannel 3 1 1 | A.eval 0 ∈ retentionBox 3 1 2 ∧ A.eval 1 ∈ retentionBox 3 1 2} = + 2 := by + decide + +-- So the joint probability is `1 / 3`, which differs from `(2 / 3) ^ 2`: frame-conditioned +-- channels are not pairwise independent. +example : + dens {A : FrameChannel 3 1 1 | A.eval 0 ∈ retentionBox 3 1 2 ∧ A.eval 1 ∈ retentionBox 3 1 2} = + 1 / 3 ∧ (1 / 3 : ℚ≥0) ≠ (2 / 3) ^ 2 := by + refine ⟨?_, by norm_num⟩ + have hcard : Fintype.card (FrameChannel 3 1 1) = 6 := by decide + rw [dens, card_both, hcard] + norm_num + +-- The pair bound `(2 / 3) ^ 2 / q_fr = 2 / 3` covers it. +example : + (dens {A : FrameChannel 3 1 1 | + A.eval 0 ∈ retentionBox 3 1 2 ∧ A.eval 1 ∈ retentionBox 3 1 2} : ℝ) ≤ 2 / 3 := by + have h := dens_eval_mem_and_eval_mem_le (P := 3) (H := 1) (r := 1) (L₁ := 2) (L₂ := 2) + (by norm_num) (by norm_num) (by norm_num) (w := 0) (y := 1) (by decide) + rw [frameDensity_three] at h + norm_num at h + exact h + +/-- Frame-conditioned channels on `𝔽₅` with `H = 2`, `r = 1` and `a = 1 / 2`: rate `f = 1 / 4`, +side `L = ⌈5 / 2⌉ = 3`, retention probability `(3 / 5) ^ 2`, and constants `C_pair = C_var = 8`. -/ +private theorem channels : + RetentionChannels + (fun (s : FrameChannel 5 2 1) (v : ZMod 5) ↦ + frameRetains 5 2 ⌈(5 : ℕ) * (1 / 2 : ℝ)⌉₊ s (id v)) + (fun (s : FrameChannel 5 2 1) (v : ZMod 5) ↦ + frameRetains 5 2 ⌈(5 : ℕ) * (1 / 2 : ℝ)⌉₊ s (id v)) ((1 / 2) ^ 2) + ((((⌈(5 : ℕ) * (1 / 2 : ℝ)⌉₊ : ℕ) : ℝ) / (5 : ℕ)) ^ 2) 1 (2 ^ 2) (2 ^ (2 + 1)) 8 := + retentionChannels_frameRetains_of_lt Function.injective_id (by norm_num) (by norm_num) + (by norm_num) (by norm_num) + +-- With detector rank `J = 20`, the threshold `J / (4 C_π f) = 5` is the whole vertex set, so on +-- `𝔽₅` the frame-conditioned detector never flags a column, whatever the matrix. +example (G : Matrix (ZMod 5) (ZMod 5) ℝ) (y : ZMod 5) : + columnDetector + (fun (s : FrameChannel 5 2 1) (v : ZMod 5) ↦ + frameRetains 5 2 ⌈(5 : ℕ) * (1 / 2 : ℝ)⌉₊ s (id v)) + (fun (s : FrameChannel 5 2 1) (v : ZMod 5) ↦ + frameRetains 5 2 ⌈(5 : ℕ) * (1 / 2 : ℝ)⌉₊ s (id v)) + (fun t ↦ min (max t 0) 1) (fun _ ↦ 1) 20 1 ((1 / 2) ^ 2) G y ≤ 1 / 4 := by + refine not_lt.mp fun h ↦ ?_ + have := lt_card_of_lt_columnDetector channels (by norm_num) + (fun t ↦ le_min (le_max_right _ _) zero_le_one) (fun t ↦ min_le_right _ _) (δ₀ := 0) + (fun t ht ↦ by rw [max_eq_right ht, min_eq_left zero_le_one]) (fun _ ↦ le_rfl) + (by norm_num) h + have hcard : (#({x | 0 * (1 / 2) ^ 2 < G x y} : Finset (ZMod 5)) : ℝ) ≤ 5 := by + exact_mod_cast (card_le_univ _).trans (by simp) + norm_num at this hcard + linarith + +end ComplexityTests.FrameRetention From 915171329b2560084440f987fe8c274bbbfb7380 Mon Sep 17 00:00:00 2001 From: Christian Reitwiessner Date: Fri, 30 Oct 2026 02:28:47 +0000 Subject: [PATCH 25/25] fix(Foundations): qualify Matrix apply lemmas in CopyStage and PilotCorrection for rc2 Under rc2 the root-namespace add_apply/sub_apply/mul_apply no longer apply to matrices; use the Matrix.* versions, as rc2-refresh/1676 and /1677 do for the lower modules of this stack. Proof-only; no statement changes. Co-Authored-By: Claude Opus 5.5 (cherry picked from commit 34406a084312428fd65108771467fbc7086f9c3f) --- .../Foundations/LinearAlgebra/Matrix/CopyStage.lean | 8 ++++---- .../Foundations/LinearAlgebra/Matrix/PilotCorrection.lean | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Complexity/Foundations/LinearAlgebra/Matrix/CopyStage.lean b/Complexity/Foundations/LinearAlgebra/Matrix/CopyStage.lean index d61617c73..9ee05d128 100644 --- a/Complexity/Foundations/LinearAlgebra/Matrix/CopyStage.lean +++ b/Complexity/Foundations/LinearAlgebra/Matrix/CopyStage.lean @@ -124,7 +124,7 @@ theorem cutoffCorrection_residual_le_mul (hCf : ∀ x y, C x y ≤ f) (hf : 0 have h := (isCorrectionSeq_cutoffCorrectionIter hC0 hφ0 hφθ hθf).input_le_mul hCf hf hC1 k x y have h0 := cutoffCorrectionIter_nonneg (C := C) hφ0 k x y - simp only [add_apply, sub_apply] at h ⊢ + simp only [Matrix.add_apply, Matrix.sub_apply] at h ⊢ linarith include hC0 hφ0 hφθ hθf in @@ -174,7 +174,7 @@ theorem cutoffCorrection_residual_dominates (hCf : ∀ x y, C x y ≤ f) (hf : 0 mul_le_of_le_one_left (by linarith) (by linarith) have hadef : a = C x y + (F * C) x y := rfl rw [hcoef] - simp only [add_apply, sub_apply] + simp only [Matrix.add_apply, Matrix.sub_apply] nlinarith variable {A : Finset V} @@ -191,7 +191,7 @@ theorem cutoffCorrectionIter_mem (hA : ∀ x y, C x y ≠ 0 → x ∈ A ∧ y have hCxy : C x y = 0 := by by_contra h'; exact hxy (hA x y h') have hin : (C + cutoffCorrectionIter φ C k * C) x y = 0 := by - simp only [add_apply, mul_apply, hCxy, zero_add] + simp only [Matrix.add_apply, Matrix.mul_apply, hCxy, zero_add] refine Finset.sum_eq_zero fun z _ => ?_ by_cases hE : cutoffCorrectionIter φ C k x z = 0 · rw [hE, zero_mul] @@ -214,7 +214,7 @@ theorem cutoffCorrection_residual_mem (hA : ∀ x y, C x y ≠ 0 → x ∈ A ∧ cutoffCorrectionIter_mem hφ0 hφθ hθf hA k have hCxy : C x y = 0 := by by_contra h'; exact hxy (hA x y h') have hExy : cutoffCorrectionIter φ C k x y = 0 := by by_contra h'; exact hxy (hE x y h') - simp only [add_apply, sub_apply, mul_apply, hCxy, hExy, sub_zero, zero_add] + simp only [Matrix.add_apply, Matrix.sub_apply, Matrix.mul_apply, hCxy, hExy, sub_zero, zero_add] refine Finset.sum_eq_zero fun z _ => ?_ by_cases hEz : cutoffCorrectionIter φ C k x z = 0 · rw [hEz, zero_mul] diff --git a/Complexity/Foundations/LinearAlgebra/Matrix/PilotCorrection.lean b/Complexity/Foundations/LinearAlgebra/Matrix/PilotCorrection.lean index a6aa6efe3..d9373a6d8 100644 --- a/Complexity/Foundations/LinearAlgebra/Matrix/PilotCorrection.lean +++ b/Complexity/Foundations/LinearAlgebra/Matrix/PilotCorrection.lean @@ -99,7 +99,7 @@ theorem sum_input_le (hC1 : C *ᵥ 1 ≤ 1) : have hrow : ∀ z, ∑ y, C z y ≤ 1 := fun z => by simpa [mulVec, dotProduct] using hC1 z have hinput : ∀ i x, ∑ y, F i x y ≤ i → ∑ y, (C + F i * C) x y ≤ i + 1 := fun i x hi => by calc ∑ y, (C + F i * C) x y = ∑ y, C x y + ∑ z, F i x z * ∑ y, C z y := by - simp only [add_apply, mul_apply, sum_add_distrib, mul_sum] + simp only [Matrix.add_apply, Matrix.mul_apply, sum_add_distrib, mul_sum] rw [sum_comm] _ ≤ 1 + ∑ z, F i x z * 1 := add_le_add (hrow x) (sum_le_sum fun z _ => mul_le_mul_of_nonneg_left (hrow z) (hF.nonneg i x z)) @@ -148,7 +148,7 @@ theorem input_mem_and_mem (hA : ∀ x y, C x y ≠ 0 → x ∈ A ∧ y ∈ A) : by_contra hxy apply h have hCxy : C x y = 0 := by by_contra h'; exact hxy (hA x y h') - simp only [add_apply, mul_apply, hCxy, zero_add] + simp only [Matrix.add_apply, Matrix.mul_apply, hCxy, zero_add] refine sum_eq_zero fun z _ => ?_ by_cases hE : F i x z = 0 · rw [hE, zero_mul]