potential: backend-correct ttensor eigenvalues + zvc_range no-solution guard#984
Conversation
…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 Report✅ All modified and coverable lines are covered by tests. 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. 🚀 New features to boost your workflow:
|
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>
All-backend test status (jax / torch)Commit Green is achieved via the checked-in xfail-ledger ( Overall: jax: 1057 passed · 265 xfail · 725 deferred | torch: 764 passed · 1279 xfail · 1 deferred Ledger size: 2357 entries (jax=284, torch=2073).
Per-shard counts
|
What
Burndown PR-5 (
Potential.pyonly). Two galpy-source backend fixes that complete the jaxtest_potentialburndown (these were the last 2 jax xfails):ttensor(class method + module function):jax.numpy.linalg.eigvalsreturns a complex array for the symmetric tidal tensor (numpy returns real), breaking the host-sidenumpy.fabs. Takexp.real(...)on the non-numpy branch only (noteigvalsh— that would change numpy's LAPACK routine/ordering).zvc_rangebackend branch: replicate the numpy path's no-solution[nan,nan]guard viaxp.whereong(RLz)>0. The nan branch usesxp.full_like(RLz, nan)(a true constant), notRLz*nan— the latter NaN-poisonsd(zvc_range)/dLzthrough the eagerxp.whereVJP (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 jaxtest_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