Repository navigation
feat: AdaptPower regularization — power input + factor-2 scatter fix #511
Description
Overview
The Adapt regularization family puts its coefficient into the regularization matrix at the fourth power (adapt.py:45-47 squares, then adapt.py:84 / regularization_util.py:257,334 square again), while Constant squares exactly once. Both carry the identical LogUniform(1e-6, 1e6) prior, so the adaptive schemes explore a λ⁴ smoothing range and go numerically non-positive-definite from c ≈ 1e4 instead of Constant's c ≈ 1e6. That is the mechanism behind the likelihood-overflow flood diagnosed on RAL pilot 341908_5 (slam_source_pix_nn): fp64 Cholesky returned finite garbage, Nautilus accepted log_l up to 3e+303, and a 6-hour GPU run never terminated.
A second asymmetry sits in the same builder: weighted_regularization_matrix_from scatters every mesh edge in both directions, so Adapt(inner=outer=c) is exactly 2 × Constant(c) — contradicting its own docstring. (Verified on main: Adapt diag 4.00000001 vs Constant diag 2.00000001, ratio 2.0 on every entry, 4-connected 3×3 mesh.)
This task adds corrected sibling classes and leaves the legacy classes byte-for-byte, so stored identifiers, output/ directories and aggregator reloads all stay valid.
Plan
- Give
adapt_regularization_weights_fromapowerkeyword defaulting to2.0— the legacy numerics, untouched. - Add a single-scatter matrix builder beside the existing one (numpy + JAX), which is the weighted graph Laplacian and reduces exactly to
Constantfor uniform weights. - Add four new sibling classes —
AdaptPower,AdaptSplitPower,AdaptSplitZerothPower,MaternAdaptPowerKernel— each takingpower: float = 1.0(effective coefficient exponent2 · power), so the default matchesConstant's λ² convention andpower=2.0reproduces the legacy classes exactly. - Export them through
aa.reg→ag.reg/al.reg. - Copy the PyAutoGalaxy prior yamls for the new classes, declaring
poweras aConstantprior soaf.Modelnever samples it; mirror into the PyAutoLens test config. - Test the exact equalities (
AdaptPower(c) == Constant(c),AdaptSplitPower(c) == ConstantSplit(c),power=2.0 == legacy), numpy/JAX parity, and that theaf.Modelidentifier differs from the legacy class. - Document the λ⁴ legacy and the factor-2 scatter on the old docstrings; document the λ² convention and the
c_new = c_old ** 2migration on the new ones.
Detailed implementation plan
Affected Repositories
- PyAutoArray (primary) — new classes, new util, tests, docstrings
- PyAutoGalaxy — prior yamls,
docs/api/pixelization.rst, one composition test - PyAutoLens —
test_autolens/config/priors/regularization.yamlmirror,docs/api/pixelization.rst, one composition test
Branch Survey
| Repository | Current Branch | Dirty? |
|---|---|---|
| ./PyAutoArray | main | clean |
| ./PyAutoGalaxy | main | clean |
| ./PyAutoLens | main | clean |
worktree_check_conflict reports PyAutoGalaxy + PyAutoLens claimed by lenscalc-adaptive-hessian-step. Its file sets (autogalaxy/operate/lens_calc.py, test_autogalaxy/operate/test_deflections.py, test_autolens/lens/test_multi_plane_cross_validation.py) are disjoint from this task's, so a parallel worktree is taken (own index, own branch) rather than a fold.
Suggested branch: feature/adapt-linear-regularization
Implementation Steps
-
autoarray/inversion/regularization/adapt.pyadapt_regularization_weights_from(inner_coefficient, outer_coefficient, pixel_signals, power=2.0)→(...) ** power. Default 2.0 = existing behaviour, bit-identical.- New
weighted_regularization_matrix_single_scatter_from(regularization_weights, neighbors, xp=np): builds the weighted graph Laplacian with edge weight0.5 * (w_i**2 + w_j**2), scattering each ordered neighbour pair once (mat[i,i] += w_ij,mat[i,j] -= w_ij), plus the same1e-8diagonal floor. Symmetric, PSD (row sums zero), and exactlyConstant's matrix when the weights are uniform. numpy and JAX branches, as the existing builder. - Docstring notes on
Adapt: λ⁴ legacy convention; the factor-2 scatter (Adapt(inner=outer=1)is2 × Constant(1), not equal to it); preferAdaptPower.
-
New modules (one class each, so the prior yaml filename matches the module —
JSONPriorConfigkeys config by module path):adapt_power.py→class AdaptPower(Adapt)—power: float = 1.0; overridesregularization_weights_from(passespower) andregularization_matrix_from(single-scatter builder).adapt_split_power.py→class AdaptSplitPower(AdaptSplit)—power; overridesregularization_weights_fromonly (the split builder is shared withConstantSplitand already scatters once).adapt_split_zeroth_power.py→class AdaptSplitZerothPower(AdaptSplitZeroth)— same, zeroth leg unchanged (BrightnessZerothis already single-square).matern_adapt_power_kernel.py→class MaternAdaptPowerKernel(MaternAdaptKernel)— same.
-
autoarray/inversion/regularization/__init__.py: export all four.aa.regis the module itself, andag.reg/al.regarefrom autoarray.inversion import regularization as reg, so the chain propagates with no downstream edit. -
PyAutoGalaxy
autogalaxy/config/priors/regularization/{adapt_power,adapt_split_power,adapt_split_zeroth_power,matern_adapt_power_kernel}.yaml— copies of the legacy files with the class key renamed andpower: {type: Constant, value: 1.0}added. PyAutoLenstest_autolens/config/priors/regularization.yaml— mirror entries. -
Tests
test_autoarray/inversion/regularizations/test_adapt_power.py:AdaptPower(inner=outer=c)matrix==Constant(c)matrix;AdaptPower(power=2.0)==Adapt; weights unsquared atpower=1.0; numpy/JAX parity of the new builder.test_adapt_split_power.py/test_adapt_split_zeroth_power.py/test_matern_adapt_power_kernel.py:AdaptSplitPower(inner=outer=c)==ConstantSplit(c);power=2.0reproduces the legacy class; numpy/JAX parity of the split path.af.Modelcomposition + identifier divergence from the legacy class.- PyAutoGalaxy + PyAutoLens: one
af.Model(al.reg.AdaptSplitPower)composition test each (proves the prior config resolves).
-
Docs:
docs/api/pixelization.rstautosummary in PyAutoGalaxy and PyAutoLens gainsAdaptPower/AdaptSplitPower.
Key Files
autoarray/inversion/regularization/adapt.py—powerkeyword + the single-scatter builderautoarray/inversion/regularization/{adapt_split,adapt_split_zeroth,matern_adapt_kernel}.py— docstring notes onlyautoarray/inversion/regularization/__init__.py— exportsautogalaxy/config/priors/regularization/*.yaml,test_autolens/config/priors/regularization.yaml
Trade-offs
- New modules, not same-module siblings.
autonerves.json_prior.configkeys prior config bycls.__module__ + cls.__name__and matches the config dict path built from the yaml filename, so aadapt_power.yamlonly resolves for a class living inadapt_power.py. Same-module classes would silently fall back to the legacyAdaptconfig via thefamily()base-class walk and leave the new yaml an orphan. - The factor-2 fix is only in the new class. Halving
weighted_regularization_matrix_fromin place would silently change the effective regularization of everyAdaptfit ever run. Filed as documentation-only:PyAutoMind/draft/bug/autoarray/adapt_scatter_factor_two.md. poweris aConstantprior, not a free parameter. It is a convention switch, not something to sample; leaving it free would let a search wander between λ² and λ⁴ mid-fit.
Original Prompt
Click to expand starting prompt
do the 5 things above listed and make sure we have some SMC runs going soon
Rung 2 of the approved plan "Overflow-flood fix wave + SMC on the A100" (task A3), as amended 2026-08-29 by the human: "maximal changes, power as an input". Full prompt: PyAutoMind/active/adapt_linear_regularization.md.
Generated by the PyAutoLabs agent workflow.
Activity
Jammy2211 commentedon Aug 29, 2026
Library PR Created
Three PRs, library-first:
b91b332f9d283da43e4623927Merge order matters: PyAutoGalaxy and PyAutoLens CI check out the PyAutoArray
mainbranch, so both stay red onAttributeError: ... AdaptPoweruntil #512 merges. Merge #512 first, then re-run CI on the other two.What shipped
Four sibling classes —
AdaptPower,AdaptSplitPower,AdaptSplitZerothPower,MaternAdaptPowerKernel— each takingpower: float = 1.0(effective coefficient exponent2 * power). The legacyAdaptfamily and its util functions are byte-for-byte unchanged.Both defects are fixed in the new classes, not just the λ⁴ one:
powerargument.power=2.0restores the legacy scaling.weighted_regularization_matrix_single_scatter_from— a weighted graph Laplacian with edge weight0.5*(w_i² + w_j²), symmetric and PSD.The two exact equalities now hold and are asserted in tests:
AdaptPower(inner=outer=c)==Constant(c)(max abs diff ≤ 1.4e-14 overc ∈ {0.5, 2.0, 7.0})AdaptSplitPower(inner=outer=c)==ConstantSplit(c)(bit-identical)powerships as aConstantprior so a search never samples it.Verification
test_autoarray/test_autogalaxy/test_autolens/test_autoarray/inversion/regularizations/Existing pins untouched — the legacy numerics are unchanged, which the new characterisation test
test__legacy_adapt_is_twice_constant__documents_the_scatter_asymmetrylocks in.Mind
draft/bug/autoarray/PROBE_adapt_double_square_coefficient.md— answered and retired intocomplete/2026/08/probe-adapt-double-square-coefficient.md.draft/bug/autoarray/adapt_scatter_factor_two.md— filed as a note (documented property of the legacy classes, fixed in the*Powerones), not an open bug.draft/feature/autoarray/adapt_linear_default_flip.md— filed as the deferred, breaking decision to make the*Powerclasses the defaults.Not merged — merge stays human.
Jammy2211 commentedon Aug 29, 2026
CI update: all three PRs are green.
The earlier "downstream will be red" note was wrong: PyAutoHeart's
lib-tests.ymlclones each dependency library at the matching branch if it exists, and all three PRs share the branch name, so the downstream runs tested against the PyAutoArray branch. Merge order is still library-first (#512 → #592 → #716) somainnever referencesAdaptPowerbefore it exists.Jammy2211 commentedon Aug 29, 2026
Shipped
Merged as PyAutoArray #512 (302d5df) with PyAutoGalaxy #592 (2ee44d507, prior yamls) and PyAutoLens #716 (af514d179, test config). New
AdaptPower,AdaptSplitPower,AdaptSplitZerothPower,MaternAdaptPowerKernelwithpower=1.0(2.0 reproduces legacy exactly) and the single-scatter Laplacian soAdaptPower(c) == Constant(c); legacy classes untouched. Suites: Array 1358 / Galaxy 1152 / Lens 572.feat: test prior config + docs for the AdaptPower regularization sibl…