Skip to content

Fix minor numerics: rotation precision, Cn invert pivots, Octa LM acceptance - #57

Merged
johmathe merged 1 commit into
mainfrom
johmathe/fix-minor-numerics
Oct 14, 2026
Merged

johmathe merged 1 commit into
mainfrom
johmathe/fix-minor-numerics

Conversation

@johmathe

Copy link
Copy Markdown
Collaborator

Three small numerical fixes, each TDD'd (test red on main, green here).

rotation.rotate_spherical_function

Interpolates in the input precision instead of casting the float64 sampling grid and signal to float32 before grid_sample. Identity rotation is now exact to 1e-12 in float64 (was ~1e-5). half/bfloat16 are still promoted to float32.

CnonCn.invert

Algorithm 1 divides by every fhat[k], k ≤ n−2, not just fhat[0] and fhat[1]. Documented; a near-zero intermediate pivot now raises ValueError instead of propagating nan, and non-finite β is rejected up front.

OctaonOcta._lm_step

Each damping retry was compared against the loss at the starting point, so a later less-damped retry that beat the start but not the already-accepted step overwrote it (seed 35 in the test: returned residual ~19 above the accepted one). Now compares against the best so far with a per-sample schedule (grow μ until first acceptance, shrink while improving, stop on first stall).

Seeded A/B over 320 random float64 signals: slow-converging (>1e-6) 15 → 5, gross failures 3 → 1, median residual 7e-12 → 3e-16; float32 64/64 clean.

Part of the v0.4.0 stack (E).

…eptance

* rotation.rotate_spherical_function: interpolate in the input precision
  instead of casting the float64 sampling grid and signal to float32 before
  grid_sample (identity rotation is now exact to 1e-12 in float64; half and
  bfloat16 inputs are promoted to float32 as before).
* CnonCn.invert: document that Algorithm 1 divides by every fhat[k], k<=n-2,
  raise ValueError on a near-zero intermediate pivot instead of producing
  nan, and reject non-finite beta up front.
* OctaonOcta._lm_step: compare each damping retry against the best
  candidate so far rather than the starting residual (a less damped retry
  that beat the start but not the accepted step used to overwrite it), and
  use a per-sample schedule (grow mu until first acceptance, shrink while
  improving, stop on first stall).  Seeded A/B over 320 random float64
  signals: slow-converging (>1e-6) 15 -> 5, gross failures 3 -> 1, median
  residual 7e-12 -> 3e-16.

Tests: identity-rotation exactness (float64/float32) and R/R^T roundtrip;
Cn zero-pivot and non-finite-beta errors; LM step never returns a point
worse than the first accepted candidate (seed 35 was a concrete failure).
@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.48%. Comparing base (05e7fdd) to head (ed9bc02).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main      #57      +/-   ##
==========================================
+ Coverage   95.46%   95.48%   +0.01%     
==========================================
  Files          11       11              
  Lines        2227     2236       +9     
==========================================
+ Hits         2126     2135       +9     
  Misses        101      101              

☔ 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.

@johmathe
johmathe merged commit 0744394 into main Oct 14, 2026
4 checks passed
@johmathe
johmathe deleted the johmathe/fix-minor-numerics branch October 14, 2026 16:47
johmathe added a commit that referenced this pull request Oct 14, 2026
* Release v0.4.0

Bump version to 0.4.0 and record the feature-layout changes in the
SO3onS2, DnonDn and SO2onDisk class docstrings (versionchanged notes).

Breaking: output_size / layout changes for SO3onS2 (lmax >= 3), DnonDn
(odd n >= 5) and the default SO2onDisk truncation.

* Raise coverage to ~98.6%: drop dead code, test dense-CG cache and graph wiring

Dead code removed (never reachable from the library):
* _bessel: scalar _jn_scalar/_djn_scalar/_bisect_newton (only tests used
  them; the batch solver is the single root path) and the unreachable
  num_brackets <= 0 branch in compute_all_bessel_roots.
* dn_on_dn: n2d == 0 / n3 == 0 branches (n >= 3 implies n2d >= 1).
* so3_on_s2: empty-slice guard in the power loop of
  _ensure_precomputed_on_device (empty entries are never flagged power).

Bug found by the new tests: _load_or_compute_reduced_cg did not catch
pickle.UnpicklingError, so a corrupt reduced-CG cache file crashed module
construction instead of being recomputed.

New tests: package version fallback; _bessel_jn_multi(()) and order-0
batch roots; _save_cache write failure; triangle-violating sparse CG
entries (empty tables, exact zeros in forward); SO3onS2 dense tables vs
sparse forward (incl. CG power); reduced-CG disk cache compute/load/
corrupt/write-failure paths; lazy sparse gather-table construction; CUDA
graph capture wiring with torch.cuda stream/graph APIs stubbed on CPU.

Remaining uncovered lines are defensive numerical fallbacks in the D_n /
octahedral CG constructions and the CUDA dispatch in SO3onS2.forward.
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