From 5069116529e4070f7261310067b7bf62695031d8 Mon Sep 17 00:00:00 2001 From: 0z5a Date: Wed, 14 Oct 2026 18:23:16 +0200 Subject: [PATCH 01/68] research: restructure manuscript after review and add CPU/evidence CI Restructure the October 13 draft without changing any measured value, acceptance gate, seed or evidence file: - Shorter abstract, explicit contribution list and a terminology table. - Related-work section with five verified additional references (Forward Laplacian, Taylor-mode AD in JAX, Griewank and Walther, NSFnets, Neural Conservation Laws). - TikZ method figure; the two pgfplots plots are now plain TikZ so the PDF builds with pdfLaTeX on a stock TeX Live 2020. - New subsection on what the 2D solve times measure: v relative L2 is the binding gate for all nine methods, and the appendix closure counts include the 4,000 Adam evaluations (2,208-5,259 L-BFGS evaluations). - Diagnosis of the failed C36 acceptance; execution and provenance records moved to an appendix. Also update evidence-index.json for the new tex/pdf hashes, fix the stale "GPU results pending" line in the C36 README, add a naming table to the README, and add a CI workflow that verifies the evidence index, runs the package tests (non-blocking until first green run) and the 19 C36 CPU regression tests. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/cpu-regression.yml | 50 + README.md | 15 +- README.zh-CN.md | 2 +- research/c36-potential-proof/README.md | 6 +- research/manuscript/README.md | 4 +- research/manuscript/evidence-index.json | 19 +- research/manuscript/flashns-summary.zh-CN.md | 4 + research/manuscript/flashns.pdf | Bin 971171 -> 403249 bytes research/manuscript/flashns.tex | 984 +++++++++++-------- scripts/verify_evidence_index.py | 43 + 10 files changed, 679 insertions(+), 448 deletions(-) create mode 100644 .github/workflows/cpu-regression.yml create mode 100644 scripts/verify_evidence_index.py diff --git a/.github/workflows/cpu-regression.yml b/.github/workflows/cpu-regression.yml new file mode 100644 index 0000000..f7e6791 --- /dev/null +++ b/.github/workflows/cpu-regression.yml @@ -0,0 +1,50 @@ +name: CPU regression and evidence hashes + +on: + push: + branches: [main] + pull_request: + +permissions: + contents: read + +jobs: + evidence-hashes: + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: "3.12" + - name: Verify manuscript evidence index + run: python scripts/verify_evidence_index.py + + cpu-tests: + runs-on: ubuntu-latest + timeout-minutes: 45 + env: + PYTHONDONTWRITEBYTECODE: "1" + OMP_NUM_THREADS: "2" + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: "3.12" + - name: Install CPU dependencies + run: | + python -m pip install --upgrade pip + python -m pip install "torch>=2.8,<3" --index-url https://download.pytorch.org/whl/cpu + python -m pip install "numpy>=2,<3" "scipy>=1.14,<2" "sympy>=1.13,<2" "mpmath>=1.3,<2" "pytest>=8,<10" + # Not yet run in this environment; make it blocking after its first green run. + - name: Package CPU tests + continue-on-error: true + run: PYTHONPATH=src python -m pytest -q + - name: C36 CPU regression (19 tests) + working-directory: research/c36-potential-proof + run: > + PYTHONPATH=src python -m unittest -v + test_c36_unpack test_c36_packed + box376.test_coordinate_oracle box376.test_potential_geometry + box376.test_potential_ad_objective box376.test_potential_audit + box376.test_fold_zero_gate diff --git a/README.md b/README.md index 2a8e47d..a46cf58 100644 --- a/README.md +++ b/README.md @@ -78,4 +78,17 @@ The [tested source manifest](docs/tested-source-sha256.json) records the unchang ## Research manuscript -The [October 13 research draft](research/manuscript/README.md) retains the accepted 2D H20 solves and adds the full C36 derivative qualifications, matched H100/CPU timing, and completed 3D training and physical acceptance failures. The new CPU analytic-transpose result is separate from GPU and complete-solver performance. +The [October 14 research draft](research/manuscript/README.md) keeps the accepted 2D H20 solves as the main result and reports the C36 extension (full derivative qualification, matched H100/CPU objective-gradient timing, and the failed 3D training and physical acceptance). It is restructured after an external review; no measured value changed. + +### Naming + +| Name | Where | Meaning | +| --- | --- | --- | +| Q10 / Q20 | paper, code | Complete third-order Taylor state in 2D (10 channels) / 3D (20 channels) | +| GL8 | paper | 2D consumer state: value, gradient, packed Hessian, gradient of the Laplacian (8 channels) | +| C36 | paper, `research/c36-potential-proof` | 3D transient curl-potential consumer state (36 channels) | +| C17 / A24 | `research/c36-potential-proof/src` | Earlier 3D velocity-model contract (17 channels) and its full-spatial-third-order reference (24 channels) | +| B1 | `docs/cuda-*` | Library GEMM plus separate native jet forward/VJP (the library-GEMM jet baseline) | +| U / F | `docs/cuda-*` | Same CUTLASS main loop with a separate VJP (U) or fused dgrad/VJP (F) | +| B1+ / F+ | `docs/cuda-h100-results.md` | B1 / F with a finite Torch/cuBLASLt GEMM plan search | +| G1 / G2 | `docs/validation.md` | SM120 first-layer coordinate-gradient kernel (G1) and its fused VJP/wgrad variant (G2) | diff --git a/README.zh-CN.md b/README.zh-CN.md index 1fcbb22..490af49 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -39,4 +39,4 @@ PYTHONPATH=src uv run pytest -q ## 研究论文 -[2026-10-13 研究稿](research/manuscript/README.md)保留已通过验收的 2D H20 求解实验,并加入完整 C36 导数检查、H100/CPU 配对性能、已完成的 3D 训练与物理验收失败结果。CPU 解析转置加速与 GPU 性能、完整求解器加速分别报告。 +[2026-10-14 研究稿](research/manuscript/README.md)以已通过验收的 2D H20 求解实验为主体,C36 作为三维推广:完整导数检查、H100/CPU 目标与梯度配对吞吐,以及已完成但未通过验收的 3D 训练和物理检验。本版按外部评审意见重新组织结构,没有改动任何实测数值。命名对照见英文 README 的 Naming 表。 diff --git a/research/c36-potential-proof/README.md b/research/c36-potential-proof/README.md index 79afd2c..758bfe3 100644 --- a/research/c36-potential-proof/README.md +++ b/research/c36-potential-proof/README.md @@ -244,8 +244,10 @@ Repeat physical acceptance for seed 361902. The NumPy-only reader reconstructs saved gradient comparisons, family-normalized losses, paired statistics, physical equations and acceptance decisions. It checks observed saved arrays; it does not independently replay every Adam update or reintegrate particle -paths. GPU results for this protocol are pending; no speed, training convergence -or physical acceptance is claimed by these new entry points alone. +paths. The completed H100 training and physical-acceptance results for this +protocol are reported below: both engines finish the frozen budget for both +seeds and all four attempts fail the convergence and physical gates, so no +solve speed or time to accepted accuracy is claimed. The prepared objective now constructs its affine transform and output-scale constants on the device during setup. Its default eager equations are unchanged; diff --git a/research/manuscript/README.md b/research/manuscript/README.md index b1d6a99..63fb94f 100644 --- a/research/manuscript/README.md +++ b/research/manuscript/README.md @@ -1,6 +1,8 @@ # FlashNS research manuscript -[PDF](flashns.pdf) and [editable standalone LaTeX](flashns.tex), updated October 13, 2026. Author and the original accepted 2D H20 experiment are retained from the October 6 release. Equations, tables, bibliography and both original plot datasets are embedded in the source; no external TeX inputs are needed. +[PDF](flashns.pdf) and [editable standalone LaTeX](flashns.tex), updated October 14, 2026. Author and the original accepted 2D H20 experiment are retained from the October 6 release. Equations, tables, bibliography, the method figure and both original plot datasets are embedded in the source; no external TeX inputs are needed. The PDF is built directly with pdfLaTeX (three passes) and needs only standard TeX Live packages: TikZ, booktabs, longtable, hyperref and Latin Modern. + +The October 14 revision restructures the paper after an external review without changing any measured value, gate, seed or evidence file: a shorter abstract, an explicit contribution list, a terminology table, a related-work section with five additional verified references (Forward Laplacian, Taylor-mode AD in JAX, Griewank and Walther, NSFnets, Neural Conservation Laws), a method figure, a paragraph on what the 2D solve times measure, a diagnosis of the failed 3D acceptance, and an appendix that now holds the execution and provenance records. Two clarifications come from the raw protocol rather than new runs: the 2D closure counts include the 4,000 Adam evaluations (every accepted 2D solve stops during L-BFGS after 2,208–5,259 L-BFGS evaluations), and the relative L2 error of v is the binding 2D acceptance criterion for all nine methods. The new C36 section reports complete 4,999-point / 50,692-parameter checks, paired H100 and CPU objective-gradient comparisons, all four frozen-budget training failures, and complete physical acceptance failures. Older H100 packed-gather rows remain about 3% slower than their dense-activation parameter-AD control. The subsequent packed-activation/analytic-transpose CUDA Graph experiments give 1.044582× with eager activation and **1.323962× with compiled activation** (95% paired interval 1.323087–1.324762). Both arms use the same packed forward and compilation choice; the compiled candidate/control means are 164.484/217.771 ms. Both GPU experiments pass 78 numerical comparisons and independent remote/local readers of 156 arrays and 20 timing windows. The separate one-thread CPU result is 1.265×. The older 1,255× native comparison uses a different source and its original recursive cache. No accepted 3D time-to-accuracy improvement is established. diff --git a/research/manuscript/evidence-index.json b/research/manuscript/evidence-index.json index 721aa9a..bd54bd7 100644 --- a/research/manuscript/evidence-index.json +++ b/research/manuscript/evidence-index.json @@ -1,8 +1,9 @@ { - "revision": "2026-10-13", + "revision": "2026-10-14", "derived_from_H20_release_sha256": "60bff9554fe7d89d917b539441f7ee1857f6135aed85d41c0aadab19c75ad0a5", "evidence_snapshot_commit": "37ced2805131fcfaba6f7f89f8b0b1d17e5cef28", - "manuscript_sha256": "28c33f85eacc33b1c35a1473f3afe3248ef4ae5a51cd7cbe73474e7b5d071b08", + "manuscript_sha256": "b75469b61055326391c2aae9b4cd35565fa61d7385c246d9d66d48d52dc7361c", + "previous_manuscript_sha256": "28c33f85eacc33b1c35a1473f3afe3248ef4ae5a51cd7cbe73474e7b5d071b08", "evidence_sha256": { "../c36-potential-proof/protocol-20261012.json": "79dc8bfb5248d0b2ae4069572075f94fc5e888396fdab5c306f4323455ce40c6", "../c36-potential-proof/gpu-objective-full-native-result.json": "a2bd6c3b02e88c6821138c9f7617f31c69ab9d4c164c82c603a2ef6133611e1a", @@ -30,11 +31,12 @@ "C36_physical_acceptance_pass": false, "new_CPU_variant_GPU_qualified": true, "C36_complete_solver_speedup": null, - "pdf_sha256": "4917d95835f3c99be049a5020461784e7dea97280de4e3933c6a1a27d7594cc9", - "pages": 22, - "latex_compilation": "SUCCESS", - "pdf_visual_review": "PASS: all 22 pages on two contact sheets; pages 11, 12 and 18 inspected at full resolution; no clipping or overlap", - "pdf_export": "ReportLab with 300 dpi STIX math images; same standalone LaTeX content", + "pdf_sha256": "feb77fd5757d50fefbefc840c5f33b7893d2c2044e9af2b9f3a637ad1498b879", + "previous_pdf_sha256": "4917d95835f3c99be049a5020461784e7dea97280de4e3933c6a1a27d7594cc9", + "pages": 23, + "latex_compilation": "SUCCESS: pdfLaTeX (TeX Live 2020), three passes, no errors, undefined references or overfull boxes", + "pdf_visual_review": "PASS: Figures 1-3 inspected at 100 dpi after the TikZ conversion; marks, labels and legends render without overlap", + "pdf_export": "pdfLaTeX directly from the standalone source with Latin Modern fonts; plots are plain TikZ (no pgfplots dependency)", "eager_analytic_variant_GPU_qualified": true, "compiled_analytic_variant_GPU_qualified": true, "mathematical_source": "OpenAI Math376; pinned geometry commit adc7f1241b42e322a6451854ab7e4b4c146bf78a; single-box forced-flow instance", @@ -57,5 +59,6 @@ "../c36-potential-proof/compiled-activation-GPU-smoke-result-20261013.json": "bd5576325c844a0a8464ce7590cf9019e4906703fc1771350990d1d656882e56", "../c36-potential-proof/math376-provenance.json": "20aa0b47412606eaf0dbd27b6a4e308254840111e273c9d30d4bbc4237961485" }, - "release_note": "Evidence hashes pin the public copies. Original evidence hashes and release-input hashes retain provenance; private archive locators and site labels were normalized without changing measured arrays, timing values, checks or acceptance outcomes." + "release_note": "Evidence hashes pin the public copies. Original evidence hashes and release-input hashes retain provenance; private archive locators and site labels were normalized without changing measured arrays, timing values, checks or acceptance outcomes.", + "revision_note_20261014": "Restructured per external review: shorter abstract, explicit contributions, terminology table, related work with five verified additional references, method figure, stopping-rule and closure-count clarification, three-dimensional failure diagnosis, and execution records moved to an appendix. No measured value, gate, seed or evidence file changed; evidence_sha256 entries are unchanged." } diff --git a/research/manuscript/flashns-summary.zh-CN.md b/research/manuscript/flashns-summary.zh-CN.md index 014b8e3..7fe412c 100644 --- a/research/manuscript/flashns-summary.zh-CN.md +++ b/research/manuscript/flashns-summary.zh-CN.md @@ -41,4 +41,8 @@ FlashNS 学习向量势和压力,再从学习到的向量势取 curl 得到速 后续 H100 二维补测将复用原 H20 的模型、数据、初始化、训练预算和验收标准;目前尚无新运行结果,不能将 H20 的加速比转用到 H100。 +## 2026-10-14 修订说明 + +本版按外部评审意见重新组织论文结构,没有改动任何实测数值、验收门限、种子或证据文件。两点说明直接来自原始协议,不是新运行:二维表中的 closure 数包含 4,000 次 Adam 评估,所有通过验收的二维求解都在 L-BFGS 阶段停止,L-BFGS 评估为 2,208–5,259 次;九种方法的 v 相对 L2 误差都恰好落在 0.02 门限上,它是二维实际起约束作用的停止条件,报告时间可理解为 v 首次越过门限的时间。三维失败诊断:两种引擎最终 loss 几乎相同,比门限高约 5 倍;三维每次求解只有 438–449 次 L-BFGS 评估,而网络参数多 11 倍;分层验证把 75% 的空间权重放在宽度 η 的面/棱/角过渡层,分层修正压力误差是均匀采样的 6.4–8.7 倍。 + 对应正文:[英文论文及可编辑源文件](README.md)。原始证据和当前范围见 [证据索引](evidence-index.json)。H100 二维补测结果将在完成运行和独立核验后补入。 diff --git a/research/manuscript/flashns.pdf b/research/manuscript/flashns.pdf index df0ed082d6075bc6494fe2e13e1a0ed0031d1a91..8ea5b8d553c2cd1e8679fad4dd6232f963da8606 100644 GIT binary patch literal 403249 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