Repository navigation
perf: reuse one Cholesky factor of F+H for the solve and the log det - #634
Merged
Merged
Conversation
On the NumPy backend with use_positive_only_solver=False, a likelihood call factorized the same SPD matrix F + H twice: np.linalg.solve (LU) for the reconstruction and np.linalg.cholesky for log_det_curvature_reg_matrix_term. A new cached_property `_curvature_reg_matrix_cho_factor` computes one scipy.linalg.cho_factor (a copy; curvature_reg_matrix is not overwritten). `reconstruction` solves with cho_solve, and the log det reads 2 * sum(log(diag(L))) off the same factor when every linear object is regularized. The factor is None (unchanged routes) on JAX, with the positive-only solver, under log_det_method="slogdet", on LinAlgError, or when its diagonal is not finite. An indefinite-but-nonsingular F + H is therefore still solved by the LU and still makes the log det raise (or return 0.0 in test mode), and a singular one still makes the solve raise (or return its test-mode dummy). Tests pin all of these against the two-factorization values. Closes #633 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 15, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
On the NumPy backend with
use_positive_only_solver=False, every likelihood call factorized the same SPD matrixF + Htwice:np.linalg.solve(LU) forreconstruction, thennp.linalg.choleskyforlog_det_curvature_reg_matrix_term. A newcached_property_curvature_reg_matrix_cho_factorcomputes onescipy.linalg.cho_factor, which serves both.reconstructionsolves withcho_solve. The log det is2 * sum(log(diag(L)))from the same factor, used when every linear object is regularized. The factor is built on a copy, socurvature_reg_matrixis never overwritten.The factor is
None, and the code takes exactly the old routes, in these cases: the JAX backend, the positive-only solver,log_det_method="slogdet", aLinAlgError(scipy's class is numpy's), or a non-finite factor diagonal. Failure behaviour is therefore unchanged:F + His still solved by the LU, and the dense Cholesky log det still raises it (or returns 0.0 in test mode).F + Hstill makes the solve raise (or return its test-mode dummy).Campaign: PyAutoLabs/PyAutoPulse#62 (task
interferometer_large_mask_aris).Closes #633
API Changes
None; the changes are internal only. The new
_curvature_reg_matrix_cho_factoris private. The positive-negative NumPy reconstruction now comes from a Cholesky solve rather than an LU. It agrees with the LU to round-off on well-conditioned systems. On ill-conditioned ones it agrees to within the system's conditioning, and is more accurate there (see Witness).Witness (laptop, single-threaded, Aris SPT2319-55 125×125 interferometer, Delaunay + AdaptSplit, numba route,
use_positive_only_solver=False)Pass condition: ≥15% at 1,405 and ≥35% at 2,947.
curvature_matrixnoise on a shared machine (227 → 254 ms and 339 → 445 ms between legs with no code change).fom_rest(78 / 122 / 544 ms) is a second dense Cholesky:log_det_curvature_reg_matrix_termis a plain property, sofigure_of_meritre-ran it after the breakdown's own tick.Reconstruction clause ("unchanged to 1e-10 relative") is not met at 2,947 vertices, and cannot be met there. At the witness vector, cond(F + H) = 7.67e14, so eps·cond ≈ 0.17. Measured against a longdouble-residual, iteratively refined reference:
So the 1.6e-3 change sits inside the conditioning bound, and the new solve is closer to the true solution. The independent reviewer reproduced these numbers. The log det is bit-identical and logL agrees to 1.1e-11 relative. At 1,405 vertices the clause holds (5.2e-14). The reviewer suggests rewording the Witness to "within conditioning (eps·cond); log det bit-identical; logL within 1e-10 relative". Flagged for the human merge decision.
Test Plan
test_autoarray/inversion/inversion/test_positive_negative_shared_cholesky.py(10 tests):cho_factorcall and no mutation ofF + H;slogdetunchanged, no factor;jaxthat raises ImportError.pytest test_autoarray -x -q: 2065 passed, 4 xfailedpytest test_autogalaxy -x -q(worktree source): 1357 passedpytest test_autolens -x -q(worktree source): 832 passed, 1 xfailedpyauto-heart smoke, all workspaces, worktree source): 165/165 passed, 0 failed (autofit 8 scripts + 2 notebooks, autogalaxy 14+2, autolens 41+2, autolens_test 37, euclid 9, howtolens 50); autocti/autocti_test not run (smoke env build failed locally: arcticpy needs libgsl-dev, same as PyAutoArray#632)Full API Changes (for automation & release notes)
Added
AbstractInversion._curvature_reg_matrix_cho_factor(privatecached_property):scipy.linalg.cho_factortuple ofcurvature_reg_matrix, orNone.Changed Behaviour
AbstractInversion.reconstruction(NumPy, positive-negative,log_det_method="cholesky"):cho_solvewith the shared factor in place ofnp.linalg.solve; falls back to the unchanged LU when the factor isNone.AbstractInversion.log_det_curvature_reg_matrix_term(same gate, all linear objects regularized): read off the shared factor; it does not evaluate the reconstruction.(n, n)array per inversion (~70 MB at n ≈ 3,000), documented in the docstring.Validation checklist (--auto run — plan was not pre-approved)
Heart RED development override
Heart was RED at launch and at ship (
Heart: RED — Release RED; monitoring RED · 10/100 · 415 unresolved; reasons as listed on #633 / PyAutoArray#626).pyauto-heart readiness --jsonat ship time reportedstale("release validation stale: source moved since rehearsal (PyAutoFit)"). The live human authorized the development-only override in session 3e3dea38: AskUserQuestion "L1 now under override (Recommended)", 2026-10-15 late. It permits commit, push and PR-open. Merge is a separate human/prm. This PR stops at PR-open; no auto-merge.Generated by the PyAutoLabs agent workflow.
🤖 Generated with Claude Code