Skip to content

SO3onS2: fix selective-map rank deficiency for L >= 8; key CUDA graph on input signature - #56

Merged
johmathe merged 1 commit into
mainfrom
johmathe/fix-so3-selective-rank
Oct 14, 2026
Merged

johmathe merged 1 commit into
mainfrom
johmathe/fix-so3-selective-rank

Conversation

@johmathe

Copy link
Copy Markdown
Collaborator

Problem

For a real signal each bispectral entry is a single real number (real if l₁+l₂+l is even, imaginary if odd) and
β_{l₁,l₂,l} = (−1)^{l₁} √((2l+1)/(2l₂+1)) · β_{l₁,l,l₂}.
So the "chain" rows (a, b, l) and "cross" rows (a, l, b) that _proved_linear_bootstrap_block used for l ≥ 8 were the same equation. The per-degree block had real rank ≤ l+1 < 2l+1, and the whole selective invariant was rank-deficient for L ≥ 8 (deficit ⌊(l−6)/2⌋ per degree; 20 dims at L = 15). The map also carried identically-zero entries ((l,l,odd) and odd-parity triples with a repeated index).

Fix

  • _distinct_pair_linear_block(l): 2l+1 rows (a, b, l) over distinct unordered pairs a < b < l, skipping identically-zero triples.
  • Identically-zero entries filtered at every degree; self-coupling fallback restricted to even l ≥ 2 so freed budget is not spent on redundant (l, l, 0).
  • Completeness docstrings now state what is verified numerically (real Jacobian rank (L+1)²−3 for L ≤ 16 in tests; per-degree blocks to l = 100 via the benchmark) vs. what is conjectural (global separation). The "proved" wording is gone.
  • benchmarks/verify_linear_bootstrap.py rewritten as a per-degree real-Jacobian rank check (seed block l ≤ 3 + degree blocks); passes l ≤ 100, σ_min ≈ 5 at every degree.
  • Also: CUDA-graph cache keyed on (shape, dtype, device) instead of batch size (a float64 input no longer replays a float32 graph); sparse CG cache written atomically (tmp + os.replace), EOFError tolerated on load.

Breaking

output_size / layout change for every lmax ≥ 3 (L=3: 15, L=8: 124, L=16: 426 — was 430). The on-disk sparse CG cache self-invalidates. README table updated.

Tests

Closed-form block check; no identically-zero entries; linear rows are distinct equations; whole-invariant Jacobian rank == (L+1)²−3 for L = 4…16 with SVD gap > 1e6 (fails on main for every L ≥ 8); per-degree block rank for l = 4…20; CUDA-graph dtype/shape cache tests (CPU mocks + CUDA parity).

Part of the v0.4.0 stack (D). Note: PR #48 touches the same files and will need a rebase or to be closed.

@codecov

codecov Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 95.59%. Comparing base (b3746db) to head (fb3527a).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main      #56      +/-   ##
==========================================
+ Coverage   95.53%   95.59%   +0.06%     
==========================================
  Files          11       11              
  Lines        2217     2226       +9     
==========================================
+ Hits         2118     2128      +10     
+ Misses         99       98       -1     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

…gnature

The l>=8 "proved linear bootstrap" block used chain rows (a, b, l) together
with cross rows (a, l, b). For a real signal these are the same real
equation up to a constant (beta_{l1,l2,l} = (-1)^{l1} sqrt((2l+1)/(2l2+1))
beta_{l1,l,l2}), so the per-degree block had rank <= l+1 < 2l+1 and the
selective invariant was not generically complete for L >= 8. The block
also kept identically-zero entries ((l,l,odd) and odd-parity triples with a
repeated index) which contribute nothing.

* _distinct_pair_linear_block: 2l+1 rows (a, b, l) with a < b < l over
  distinct unordered pairs, skipping identically-zero triples.
* identically-zero entries filtered at all degrees; self-coupling slots
  restricted to even l >= 2 so freed budget is not spent on (l,l,0).
* output sizes: L=3 15, L=8 124, L=16 426 (was 430). Layout is breaking.
* completeness docstrings now state what is verified numerically (real
  Jacobian rank (L+1)^2-3 for L<=16 in tests; per-degree blocks to l=100
  via benchmarks/verify_linear_bootstrap.py) vs conjectural.
* benchmarks/verify_linear_bootstrap.py rewritten as a per-degree real
  Jacobian rank check (seed block l<=3 plus degree blocks); passes l<=100.
* sparse CG cache written atomically (tmp + os.replace), EOFError tolerated.
* CUDA-graph cache keyed on (shape, dtype, device) rather than batch size:
  a float64 input no longer replays a float32 graph.

Tests: closed-form block check, no-zero-entry and distinct-equation
checks, whole-invariant and per-degree Jacobian rank tests, CUDA graph
dtype/shape cache tests (CPU mocks + CUDA parity).
@johmathe
johmathe force-pushed the johmathe/fix-so3-selective-rank branch from 8e52a31 to fb3527a Compare October 14, 2026 16:44
@johmathe
johmathe merged commit 4ca9966 into main Oct 14, 2026
2 checks passed
@johmathe
johmathe deleted the johmathe/fix-so3-selective-rank branch October 14, 2026 16:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant