You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The positive-only inversion solve (fnnls_cholesky) dominates the numba CPU Delaunay likelihood — ~74% of a euclid-resolution evaluation on the production campaign fiducial (Delaunay + Hilbert-1250, PyAutoLabs/autolens_profiling#151). Profiling showed the cost is implementation, not linear algebra: ~150 Bro–Jong active-set iterations, each rebuilding the ~1300² Cholesky factor via np.insert/np.delete (two O(n²) copies per change) and re-copying/finite-scanning it inside scipy's solve_triangular/cho_solve. This task makes the solver maintain its factor in one preallocated buffer with copy-free numba triangular solves — same mathematics, a fraction of the memory traffic.
Plan
Hold the factor in the top-left k×k corner of a preallocated buffer, grown/shrunk in place as the active set changes (no np.insert/np.delete).
Replace the per-iteration scipy solve_triangular/cho_solve calls with numba kernels that read the buffer's upper triangle directly (no copies, no per-call finite scans).
Keep the existing numba Givens up/down-date kernels (proven bitwise-stable on strided views) and the out-of-place functions for reference and tests.
Validate against the pinned autolens_profiling delaunay_numba cells and the full test suite.
autoarray/util/cholesky_funcs.py: add cholinsertlast_inplace / choldeleteindexes_inplace (buffer-view variants of the existing out-of-place functions) and the numba kernels _solve_upper_transposed_buffer (row-oriented forward substitution for U^T y = b) and _cho_solve_buffer (full (U^T U) s = b solve).
autoarray/util/fnnls.py: allocate U_buffer = np.zeros((n, n)) once per solve; thread (U_buffer, k_active) through the outer loop and fix_constraint_cholesky in place of the reallocated U.
test_autoarray/util/test_cholesky_inplace.py: cross-implementation agreement at 1e-13, exact factor-property checks (U'U = active submatrix), scipy.optimize.nnls cross-checks, warm-start = cold-start.
Key Files
autoarray/util/fnnls.py — the Bro–Jong active-set loop
test_autoarray/: 1026 passed; the only failures are 3 pre-existing pynufft transformer tests that fail identically on stock main in this environment.
Results are not bitwise identical to the old path (LAPACK picks layout-dependent but equally valid kernels; the old implementation already mixed layouts between its own iterations) — equivalence is enforced at 1e-13 in the new tests.
Original Prompt
Click to expand starting prompt
PyAutoMind draft/feature/autoarray/numba_cpu_likelihood_positive_only_solver_speedup.md — "Numba CPU likelihood: positive-only solver speed-up (the Delaunay ~74% euclid lever)". Candidate directions in win/effort order: (1) in-place factor buffer [this issue], (2) block pivoting, (3) cross-evaluation warm starts, (4) BLAS-thread guidance. Full context and the instrumented probe table live in the prompt file and the PyAutoLabs/autolens_profiling#151 findings trail.
Overview
The positive-only inversion solve (
fnnls_cholesky) dominates the numba CPU Delaunay likelihood — ~74% of a euclid-resolution evaluation on the production campaign fiducial (Delaunay + Hilbert-1250, PyAutoLabs/autolens_profiling#151). Profiling showed the cost is implementation, not linear algebra: ~150 Bro–Jong active-set iterations, each rebuilding the ~1300² Cholesky factor vianp.insert/np.delete(two O(n²) copies per change) and re-copying/finite-scanning it inside scipy'ssolve_triangular/cho_solve. This task makes the solver maintain its factor in one preallocated buffer with copy-free numba triangular solves — same mathematics, a fraction of the memory traffic.Plan
np.insert/np.delete).solve_triangular/cho_solvecalls with numba kernels that read the buffer's upper triangle directly (no copies, no per-call finite scans).Detailed implementation plan
Affected Repositories
Branch Survey
Suggested branch:
feature/fnnls-inplace-cholesky-bufferImplementation Steps
autoarray/util/cholesky_funcs.py: addcholinsertlast_inplace/choldeleteindexes_inplace(buffer-view variants of the existing out-of-place functions) and the numba kernels_solve_upper_transposed_buffer(row-oriented forward substitution for U^T y = b) and_cho_solve_buffer(full (U^T U) s = b solve).autoarray/util/fnnls.py: allocateU_buffer = np.zeros((n, n))once per solve; thread(U_buffer, k_active)through the outer loop andfix_constraint_choleskyin place of the reallocatedU.test_autoarray/util/test_cholesky_inplace.py: cross-implementation agreement at 1e-13, exact factor-property checks (U'U = active submatrix),scipy.optimize.nnlscross-checks, warm-start = cold-start.Key Files
autoarray/util/fnnls.py— the Bro–Jong active-set loopautoarray/util/cholesky_funcs.py— factor update + solve kernelsautoarray/inversion/inversion/inversion_util.py—reconstruction_positive_only_from(caller; unchanged)Results (validated 2026-08-20, 4-core cloud container)
test_autoarray/: 1026 passed; the only failures are 3 pre-existing pynufft transformer tests that fail identically on stockmainin this environment.Original Prompt
Click to expand starting prompt
PyAutoMind
draft/feature/autoarray/numba_cpu_likelihood_positive_only_solver_speedup.md— "Numba CPU likelihood: positive-only solver speed-up (the Delaunay ~74% euclid lever)". Candidate directions in win/effort order: (1) in-place factor buffer [this issue], (2) block pivoting, (3) cross-evaluation warm starts, (4) BLAS-thread guidance. Full context and the instrumented probe table live in the prompt file and the PyAutoLabs/autolens_profiling#151 findings trail.