diff --git a/research/forward-turning-point/README.md b/research/forward-turning-point/README.md new file mode 100644 index 0000000000..3f487ef4f5 --- /dev/null +++ b/research/forward-turning-point/README.md @@ -0,0 +1,100 @@ +# Turning-point asymptotics of the broad forward inverse + +**Claim type:** a formal (semiclassical) derivation of the leading constant, confirmed numerically to +better than 1%. **No new κ, and this is not a proof.** It answers open questions 1–2 of my +[#4408](https://github.com/CrocSwap/integer-mult-bounds/pull/4408). #4408 found that the phase-cell +blocks behind `FORWARD-SMALL-A-AUDIT.md`'s `O(α⁵ρ²θ⁻²e^{aρ/3})` actually grow like `θ^{−1/2}`. It asked +why, and how the constant depends on `α`. The answer is + + ‖K⁻¹‖₂ ≈ e^{a/4} / (2α√π) · θ^{−1/2}, a = πα². + +## Derivation + +The block is `K_{k,i} = α⁻¹G(i − s_k)`, with `G(y) = e^{−b₀y²}`, `b₀ = π/α²`, +`s_k = λk + c` and `θ′ = 1 − λ = θ/(1+θ)`. + +1. **Alternating ansatz.** Try `x_i = (−1)^i u(i)` with `u` slowly varying. By Poisson summation, + `Σ_i (−1)^i u(i)G(i − s)` is dominated by the frequencies `±π`. The next terms are smaller by + `e^{−2π²/b₀}`. To first order in `u′` this gives + + Σ_i (−1)^i u(i) G(i−s) ≈ 2g₀ [cos(πs) u(s) − (π/2b₀) sin(πs) u′(s)], g₀ = √(π/b₀)·e^{−π²/(4b₀)}. + +2. **The turning point.** Write `s_k = k + (c − θ′k)`. Then `cos(πs_k) = (−1)^k cos(π(c − θ′k))`. + This vanishes where `c − θ′k ≡ 1/2`, which is exactly where `β′ = ±1/2`: the zero of the shifted + Gaussian symbol, at a phase-cell edge. With `y` the distance from that point, + + (Kx)_k ≈ (−1)^k · T u, T = A[(πθ′) y − (π/2b₀) ∂_y], A = 2g₀/α. + +3. **The harmonic oscillator.** Write `T = A(π/2b₀)(κy − ∂_y)` with `κ = 2b₀θ′`. Then + `T*T = A²(π/2b₀)²(−∂² + κ²y² + κ)`. Its lowest eigenvalue is `A²(π/2b₀)²·2κ`, because the + harmonic oscillator `−∂² + κ²y²` has ground energy `κ`. So + `σ_min = Aπ√(θ′/b₀)`. Substituting `A` and `b₀ = π/α²` gives the formula above. + +The minimizing vector is the oscillator's Gaussian ground state, of width `(2b₀θ′)^{−1/2}`, +alternating in sign and sitting at the cell edge. In the actual block the turning point lies on the +block's boundary. The numerics match the full-line constant, which means the truncated matrix acts like +a Neumann boundary there. That is observed, not derived. + +## Numerical confirmation + +`verify.py` computes `‖K⁻¹‖₂` by inverse power iteration with sparse LU. It uses the banded block, +dropping entries below `e^{−78}`, on a window of `min(1/θ, 60θ^{−1/2})` coordinates starting at +`β′ = −1/2`: + +| `1/θ` | `α = 3`: ratio to `110.4385·θ^{−1/2}` | `α = 4`: ratio to `20222.76·θ^{−1/2}` | +| --- | --- | --- | +| 400 | 0.97357 | 0.94626 | +| 1,600 | 0.98198 | 0.96333 | +| 6,400 | 0.98981 | 0.97929 | +| 25,600 | 0.99461 | 0.98905 | +| 102,400 | **0.99723** | **0.99438** | + +The ratio tends to 1, and the gap `1 − ratio` roughly halves each time `θ` is quartered, as an +`O(θ^{1/2})` correction should. The verifier also checks two controls: + +- a dense SVD over the whole cell agrees with the sparse iteration at `θ = 1/400`; +- halving the window at `θ = 1/102400` changes the value by less than `10⁻⁶` relative, so the + conditioning is localized at the turning point. + +## Consequence + +At the fine-prime `θ = 1/(4p²)`, with `a ≈ 4 log(16p)`, the true conditioning is + + e^{a/4}/(2α√π) · 2p ≈ 16p²/(α√π) (with e^{a/4} ≈ 16p), + +which is `O(p²/√log p)`. The audit's ceiling is `16p⁴·α⁵·e^{aρ/3}`. At `p = 19` the prediction is +`110.44 · 38 = 4197`, which is close to #4408's measured 4118, against a ceiling of `9.1·10⁹`. The +loss in the ceiling comes from two places: the exponent `a/3` in place of `a/4`, and the reciprocal +gap `θ⁻²` in place of `θ^{−1/2}`. + +## Not covered + +- **A rigorous upper bound.** A proof would need coercivity away from the turning point, plus + control of the boundary layer. +- **The narrow kernel.** For that, see #4402's column gap. +- **Any change to #4100's guards.** The ceiling already sits inside the `p¹⁰` envelope. + +## Reproduce + +```sh +python3.12 -B scripts/research_package.py --package research/forward-turning-point --check-only +python3.12 -B scripts/research_package.py --package research/forward-turning-point +``` + +The verifier prints `PASS_FORWARD_TURNING_POINT` in about 3 seconds. It needs `numpy` and `scipy`. + +## Open next questions + +1. **Can the reduction be made rigorous?** + - *Why it matters:* it would give `‖K⁻¹‖₂ ≤ (1 + o(1))·e^{a/4}/(2α√π)·θ^{−1/2}`. + - *First step:* a Grushin-type reduction near the turning point, plus the accretive symbol bound + of `GAUGEFREE-INTERIORS.md` §3 away from it. + +## Credit + +- The bound is from `FORWARD-SMALL-A-AUDIT.md` (PR1673 lineage). The shifted-symbol picture is from + `GAUGEFREE-INTERIORS.md`. +- The `θ^{−1/2}` observation is my #4408, which answered Matarener's #4356. + +Prepared by Ryanson Jonathan with substantial Claude Code (Claude Opus 5.5) assistance. +Apache-2.0. diff --git a/research/forward-turning-point/SOURCES.json b/research/forward-turning-point/SOURCES.json new file mode 100644 index 0000000000..ec956f87e8 --- /dev/null +++ b/research/forward-turning-point/SOURCES.json @@ -0,0 +1,24 @@ +{ + "schema_version": 1, + "base_commit": "12fa8c5c844be21bfefb38a19503fbd867a11244", + "files": [ + { + "path": "certificates/selected-result.json", + "usage": "provenance", + "git_blob": "b1fea0c94436b236cc2b7d41a7be032811b94c81", + "sha256": "bb2eaa58647b353f88d0aec2eafb9d30df1be53589231b23e12ceef3e4bad129" + }, + { + "path": "docs/research/agent-task-catalog.json", + "usage": "provenance", + "git_blob": "64bfc5af6709ed9811171e0a2108f05e1219cb65", + "sha256": "352a6184713b8843d96fd2c2071eb7aeaa655906b7c51d45ad444912666c8a96" + }, + { + "path": "research/capped-phase-fusion/FORWARD-SMALL-A-AUDIT.md", + "usage": "input", + "git_blob": "0f7f80b3f74d469c2f72f3b9f338d32568b4eae3", + "sha256": "e37aaa30b15671a1dff00676b14572213efaaac99df202dbba5e09f57af487c0" + } + ] +} diff --git a/research/forward-turning-point/TASK.json b/research/forward-turning-point/TASK.json new file mode 100644 index 0000000000..0e4f5d7b77 --- /dev/null +++ b/research/forward-turning-point/TASK.json @@ -0,0 +1,74 @@ +{ + "schema_version": 1, + "task_id": "uniform-transfer-audit", + "priority_revision": 7, + "base_commit": "12fa8c5c844be21bfefb38a19503fbd867a11244", + "original_card": { + "id": "uniform-transfer-audit", + "question": "Does one quantified step of the proposed #4100 all-size construction hold at its actual caller?", + "starting_points": [ + "docs/research/research-family-status.md", + "certificates/selected-result.json", + "research/unconditional-batched-crt/README.md" + ], + "methods": [ + "Prove one missing implication with explicit quantified hypotheses.", + "Find an exact counterexample at the claimed interface boundary." + ], + "acceptance_gate": "Identify the proposition and what would change downstream; do not equate a finite replay with a universal proof.", + "first_step": { + "command": [ + "python3", + "-B", + "scripts/research_baseline.py" + ], + "expected": "PASS_RESEARCH_BASELINE_BINDINGS_ONLY", + "inspect": "Read PROOF.md and AUDIT.md in #4100. Select one distinct obligation: CRT total repair, native/free-algebra lifting, precision/conditioning, or complete fixed-tape cost. This is an author-submitted proof, not an accepted unconditional theorem.", + "scope": "Source-binding orientation only; no scientific replay, theorem acceptance or supplier admission. Budget any heavy replay separately." + }, + "first_experiment": "Check live handoffs; name one proposition, its caller, quantified domain and dependency closure. Independently prove the implication or exhibit a precise gap/counterexample. Prioritize CRT.md total repair or COMPLEX.md free-algebra lift only if unclaimed. Stop at the chosen obligation; do not substitute finite samples or root arithmetic for an all-size proof, or launch the complete package by default.", + "bottleneck_link": "Finite supplier improvements are useful only under the retained transfer obligations.", + "allowed_variations": [ + "One CRT repair, native lift, precision/conditioning or tape-cost proposition, with its exact caller." + ], + "scope_change_triggers": [ + "Replacing a quantified obligation with another finite smoke test.", + "Treating archive intake, an author PASS receipt or a finite composed fixture as discharge of the universal hypotheses." + ], + "overlap_terms": [ + "uniform transfer", + "all-size", + "precision", + "4100", + "unconditional-batched-crt" + ], + "existing_checks": [ + { + "scope": "PR #4100: proposed unconditional construction and finite checks, without independent acceptance.", + "evidence": "research/unconditional-batched-crt/README.md", + "remaining": "Independent proof audit of one caller-bound all-size implication; all other premises remain explicit.", + "status": "author-checked", + "source_commit": "337d04939571a637aeab54a0f58f54fde811663a", + "selected_record_sha256": "bb2eaa58647b353f88d0aec2eafb9d30df1be53589231b23e12ceef3e4bad129" + } + ] + }, + "scope_status": "refined", + "actual_scope": "Answer #4408's open questions: derive and confirm the leading asymptotics ||K^-1||_2 ~ e^(a/4)/(2 alpha sqrt(pi)) theta^(-1/2) of the broad forward phase-cell inverse.", + "scope_change_reason": "Follow-up to #4408, which measured theta^(-1/2) and asked for the mechanism and alpha-dependence.", + "bottleneck_link": "FORWARD-SMALL-A-AUDIT's alpha^5 theta^-2 e^(a rho/3) bound feeds the fine-prime conditioning envelope.", + "budget_minutes": 45, + "stop_rule": "Stop at the formal derivation and numerical confirmation; no rigorous proof attempted.", + "outcome": "completed", + "evidence": "verify.py: ratio to the predicted constant 0.99723 (alpha=3) and 0.99438 (alpha=4) at theta=1/102400 with O(theta^1/2) convergence; dense and localisation controls.", + "author": "Ryanson Jonathan, with Claude Code (Claude Opus 5.5) assistance", + "ai_assistance": "Substantial Claude Code (Claude Opus 5.5) assistance; no independent human review.", + "open_questions": [ + { + "question": "Can the turning-point reduction be made rigorous?", + "why_it_matters": "It would give ||K^-1||_2 <= (1+o(1)) e^(a/4)/(2 alpha sqrt(pi)) theta^(-1/2).", + "first_step": "A Grushin-type reduction near the turning point plus the accretive symbol bound away from it.", + "blocked_by": "None." + } + ] +} diff --git a/research/forward-turning-point/VERIFY.json b/research/forward-turning-point/VERIFY.json new file mode 100644 index 0000000000..7287dd8bff --- /dev/null +++ b/research/forward-turning-point/VERIFY.json @@ -0,0 +1,23 @@ +{ + "schema_version": 1, + "status": "ready", + "python": "3.12", + "requirements": [ + "numpy==1.26.4", + "scipy==1.13.1" + ], + "inputs": [ + "research/capped-phase-fusion/FORWARD-SMALL-A-AUDIT.md" + ], + "commands": [ + { + "argv": [ + "{python}", + "-B", + "{package}/verify.py" + ], + "timeout_seconds": 300, + "checks": "Pinned FORWARD-SMALL-A bound; sparse inverse power iteration of the banded phase-cell block at alpha=3,4 for theta down to 1/102400; ratio to e^(a/4)/(2 alpha sqrt(pi)) theta^(-1/2) within 1% and converging at O(theta^1/2); dense SVD control; localisation control." + } + ] +} diff --git a/research/forward-turning-point/verify.py b/research/forward-turning-point/verify.py new file mode 100644 index 0000000000..15c7dd5066 --- /dev/null +++ b/research/forward-turning-point/verify.py @@ -0,0 +1,97 @@ +#!/usr/bin/env python3 +"""Turning-point asymptotics of the broad forward phase-cell inverse. + +Prediction (README): for K_(k,i) = alpha^-1 exp(-b0 (i - lambda k - c)^2) on a phase cell starting at beta' = -1/2, + + ||K^-1||_2 * sqrt(theta) -> e^(a/4) / (2 alpha sqrt(pi)), a = pi alpha^2, as theta -> 0. + +The verifier builds the banded block (entries farther than 20 from the centre are below e^-78 and dropped; the dropped +part is bounded and reported), computes ||K^-1||_2 by inverse power iteration on K^T K with sparse LU, and checks + * the ratio to the prediction tends to 1: within 1% at theta = 1/102400 for alpha = 3 and 4, monotone over the + last three theta values, with 1 - ratio shrinking by a factor near 2 per factor 4 in theta (O(theta^1/2)); + * agreement with a dense SVD on the full cell at theta = 1/400 (band truncation control); + * localisation: halving the block length (still >= 30 theta^-1/2) changes the value by < 1e-6 relative. +Numerical evidence for a formal derivation; not a proof. Pinned: FORWARD-SMALL-A-AUDIT.md phrase. +Ryanson Jonathan with Claude Code (Claude Opus 5.5) assistance. Apache-2.0. +""" +import json +import math +from pathlib import Path +import sys + +import numpy as np +import scipy.sparse as sp +import scipy.sparse.linalg as spl + +ROOT = Path(__file__).resolve().parents[2] +PHRASE = "`||K^-1|| <= alpha exp(3b/4) c_b^-4/(1-exp(-b rho theta))^2`" +BAND = 20 + + +def need(condition, message): + if not condition: + raise AssertionError(message) + + +def kmat(alpha, theta, n): + rho = 1 + theta + lam, b0, c = 1 / rho, math.pi / alpha ** 2, 0.5 / rho # beta'_0 = -rho c = -1/2 + rows, cols, vals = [], [], [] + for k in range(n): + centre = int(lam * k + c) + i = np.arange(max(0, centre - BAND), min(n, centre + BAND + 2)) + rows.extend([k] * len(i)) + cols.extend(i.tolist()) + vals.extend((np.exp(-b0 * (i - lam * k - c) ** 2) / alpha).tolist()) + return sp.csc_matrix((vals, (rows, cols)), shape=(n, n)) + + +def inv_norm2(K): + lu, luT = spl.splu(K), spl.splu(K.T.tocsc()) + x = np.random.default_rng(0).standard_normal(K.shape[0]) + x /= np.linalg.norm(x) + s = 0.0 + for _ in range(500): + z = luT.solve(lu.solve(x)) + s_new = math.sqrt(np.linalg.norm(z)) + x = z / np.linalg.norm(z) + if abs(s_new - s) < 1e-12 * s_new: + break + s = s_new + return s_new + + +def main(): + text = (ROOT / "research/capped-phase-fusion/FORWARD-SMALL-A-AUDIT.md").read_text(encoding="utf-8") + need(PHRASE in text, "pinned bound") + out = {"status": "PASS_FORWARD_TURNING_POINT", "new_kappa_claimed": False, "alphas": {}} + for alpha in (3, 4): + pred = math.exp(math.pi * alpha ** 2 / 4) / (2 * alpha * math.sqrt(math.pi)) + b0 = math.pi / alpha ** 2 + need(math.exp(-b0 * BAND ** 2) < 1e-20, "dropped band entries negligible") + rows = [] + for inv_th in (400, 1600, 6400, 25600, 102400): + th = 1 / inv_th + n = int(min(inv_th, 60 * math.sqrt(inv_th))) + s = inv_norm2(kmat(alpha, th, n)) + rows.append((inv_th, n, s, s * math.sqrt(th) / pred)) + # dense control on the whole cell + Kd = kmat(alpha, 1 / 400, 400).toarray() + dense = 1 / np.linalg.svd(Kd, compute_uv=False)[-1] + need(abs(dense - rows[0][2]) < 1e-6 * dense, "sparse power iteration matches dense SVD") + # localisation control + half = inv_norm2(kmat(alpha, 1 / 102400, 30 * 320)) + need(abs(half - rows[-1][2]) < 1e-6 * half, "the norm is localised at the turning point") + ratios = [r[3] for r in rows] + need(abs(1 - ratios[-1]) < 0.01, f"alpha={alpha}: within 1% at theta=1/102400") + gaps = [1 - r for r in ratios[-3:]] + need(gaps[0] > gaps[1] > gaps[2] > 0 and all(1.5 < gaps[i] / gaps[i + 1] < 2.6 for i in range(2)), + f"alpha={alpha}: O(theta^1/2) convergence") + out["alphas"][alpha] = {"predicted_constant": f"{pred:.4f}", + "rows": [{"inv_theta": a, "n": b, "inv_norm2": f"{c:.3f}", "ratio": f"{d:.6f}"} + for a, b, c, d in rows]} + print(json.dumps(out, indent=1)) + + +if __name__ == "__main__": + sys.exit(main())