Skip to content

potential: backend-correct ttensor eigenvalues + zvc_range no-solution guard#984

Merged
jobovy merged 2 commits into
feat/backendsfrom
backend/potential-ttensor-zvc
Jun 20, 2026
Merged

potential: backend-correct ttensor eigenvalues + zvc_range no-solution guard#984
jobovy merged 2 commits into
feat/backendsfrom
backend/potential-ttensor-zvc

Conversation

@jobovy

@jobovy jobovy commented Jun 20, 2026

Copy link
Copy Markdown
Owner

What

Burndown PR-5 (Potential.py only). Two galpy-source backend fixes that complete the jax test_potential burndown (these were the last 2 jax xfails):

  • ttensor (class method + module function): jax.numpy.linalg.eigvals returns a complex array for the symmetric tidal tensor (numpy returns real), breaking the host-side numpy.fabs. Take xp.real(...) on the non-numpy branch only (not eigvalsh — that would change numpy's LAPACK routine/ordering).
  • zvc_range backend branch: replicate the numpy path's no-solution [nan,nan] guard via xp.where on g(RLz)>0. The nan branch uses xp.full_like(RLz, nan) (a true constant), not RLz*nan — the latter NaN-poisons d(zvc_range)/dLz through the eager xp.where VJP (caught by adversarial review; FD-verified the gradient is now correct: AD=FD=1.3554).

Byte-identity + review

numpy branch untouched and bit-identical (eigenvalues + zvc results verified via .tobytes()). Fixes jax test_ttensor + test_zvc_range_undefined. Adversarially reviewed (caught + fixed the AD-poisoning blocker; no-solution branch verified crash-free; condition fidelity confirmed). The torch counterparts need a separate test-side wrap / the central coercion and stay ledgered.

🤖 Generated with Claude Code

…n guard

Two galpy-source backend fixes (numpy path byte-identical, guarded on
xp is not numpy / is_backend_array), completing the jax test_potential burndown:

* ttensor (class method + module function): jax.numpy.linalg.eigvals returns a
  COMPLEX array for the symmetric tidal tensor (numpy returns real), so the
  host-side numpy.fabs over the result raised. Take xp.real(...) of the
  eigenvalues on the non-numpy branch only (NOT eigvalsh -- that would change
  the numpy LAPACK routine/ordering); numpy branch unchanged, eigenvalues
  bit-identical.
* zvc_range backend branch: replicate the numpy path's no-solution NaN guard,
  returning a stacked [nan, nan] via xp.where on the no-real-roots condition
  g(RLz) > 0 (mirroring the numpy test Phi + Lz^2/2R^2 > E). The no-solution
  branch uses xp.full_like(RLz, nan), NOT RLz * nan: eager xp.where evaluates
  both branches and its VJP multiplies the unselected branch's cotangent, so
  RLz * nan would NaN-poison d{Rmin,Rmax}/dLz in the ordinary has-solution case
  (verified: AD now matches finite-difference, 1.3554 for d zvc[0]/dLz). numpy
  branch untouched.

Fixes jax test_ttensor and test_zvc_range_undefined (verified pass). The torch
counterparts need a separate test-side numpy.asarray wrap / the central scalar
coercion and stay ledgered for now.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
@codecov

codecov Bot commented Jun 20, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.93%. Comparing base (fcad3f7) to head (f9f107e).

Additional details and impacted files
@@              Coverage Diff               @@
##           feat/backends     #984   +/-   ##
==============================================
  Coverage          99.93%   99.93%           
==============================================
  Files                253      253           
  Lines              39803    39809    +6     
  Branches             839      840    +1     
==============================================
+ Hits               39778    39784    +6     
  Misses                25       25           

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

PR-5 added xp.real(xp.linalg.eigvals(tij)) to ttensor (method + module
function) on the non-numpy branch. Add a torch ttensor(eigenval=True) test (the
module only had a jax one) asserting the eigenvalues are REAL (not complex) and
match the numpy reference -- directly validating the fix and giving the patch
line a robust second cover in the coverage shard.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jun 20, 2026

Copy link
Copy Markdown
Contributor

All-backend test status (jax / torch)

Commit a17b559d98e29fb30b33e31911d3696803e64d71

Green is achieved via the checked-in xfail-ledger (tests/backend_xfail.txt, applied xfail(strict=False)), so the metric to watch is the shrinking xfail count (burndown), not a raw pass count. A FAIL/ERR is an un-ledgered regression (reds the run). Because the ledger is non-strict, a now-passing ledgered test is a plain pass here (no per-push XPASS); burndown candidates -- in both directions -- are surfaced by the scheduled regen run, which rewrites the ledger from real outcomes. deferred is a separate burndown: tests skipped because they are unrunnable under the backend until the port is vectorized (see tests/backend_slow_skip.txt), e.g. the jax spherical-DF sampling/quadrature tests pending the Track F DF migration.

Overall: jax: 1057 passed · 265 xfail · 725 deferred | torch: 764 passed · 1279 xfail · 1 deferred

Ledger size: 2357 entries (jax=284, torch=2073).

Test shard jax torch
actionAngle ✅ 112 pass · 89 xfail ✅ 26 pass · 175 xfail
sphericaldf ✅ 164 pass · 26 xfail · 28 deferred ✅ 8 pass · 210 xfail
conversion + util + misc ✅ 86 pass · 5 xfail · 1 deferred ✅ 41 pass · 51 xfail
potential + scf + multipole — (no result) — (no result)
quantity + coords ✅ 287 pass · 49 xfail ✅ 189 pass · 147 xfail
orbit (energy/Jacobi + from_name) ✅ 0 pass · 0 xfail · 115 deferred ✅ 53 pass · 62 xfail
orbit + orbits (main) ✅ 0 pass · 0 xfail · 578 deferred ✅ 189 pass · 386 xfail
evolveddiskdf ✅ 35 pass · 0 xfail ✅ 32 pass · 3 xfail
jeans + dynamfric ✅ 17 pass · 2 xfail · 2 deferred ✅ 7 pass · 13 xfail · 1 deferred
qdf + pv2qdf + streamgapdf_impulse + noninertial ✅ 57 pass · 75 xfail · 1 deferred ✅ 14 pass · 119 xfail
streamgapdf ✅ 28 pass · 2 xfail ✅ 27 pass · 3 xfail
diskdf ✅ 129 pass · 0 xfail ✅ 112 pass · 17 xfail
streamdf + streamspraydf + streamTrack ✅ 142 pass · 17 xfail ✅ 66 pass · 93 xfail
Per-shard counts
Test shard backend pass xfail deferred XPASS fail error
actionAngle jax 112 89 0 0 0 0
actionAngle torch 26 175 0 0 0 0
sphericaldf jax 164 26 28 0 0 0
sphericaldf torch 8 210 0 0 0 0
conversion + util + misc jax 86 5 1 0 0 0
conversion + util + misc torch 41 51 0 0 0 0
potential + scf + multipole jax
potential + scf + multipole torch
quantity + coords jax 287 49 0 0 0 0
quantity + coords torch 189 147 0 0 0 0
orbit (energy/Jacobi + from_name) jax 0 0 115 0 0 0
orbit (energy/Jacobi + from_name) torch 53 62 0 0 0 0
orbit + orbits (main) jax 0 0 578 0 0 0
orbit + orbits (main) torch 189 386 0 0 0 0
evolveddiskdf jax 35 0 0 0 0 0
evolveddiskdf torch 32 3 0 0 0 0
jeans + dynamfric jax 17 2 2 0 0 0
jeans + dynamfric torch 7 13 1 0 0 0
qdf + pv2qdf + streamgapdf_impulse + noninertial jax 57 75 1 0 0 0
qdf + pv2qdf + streamgapdf_impulse + noninertial torch 14 119 0 0 0 0
streamgapdf jax 28 2 0 0 0 0
streamgapdf torch 27 3 0 0 0 0
diskdf jax 129 0 0 0 0 0
diskdf torch 112 17 0 0 0 0
streamdf + streamspraydf + streamTrack jax 142 17 0 0 0 0
streamdf + streamspraydf + streamTrack torch 66 93 0 0 0 0

@jobovy jobovy merged commit 92cb802 into feat/backends Jun 20, 2026
146 checks passed
@jobovy jobovy deleted the backend/potential-ttensor-zvc branch June 20, 2026 12:14
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