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
Split the rectangular adaptive mesh family into two user-facing variants: Bilinear (RectangularBilinearAdaptDensity / RectangularBilinearAdaptImage), a resurrected empirical rank-CDF lattice transform that is fast on CPU, and RTU (RectangularRTUAdaptDensity / RectangularRTUAdaptImage), pure renames of the current kernel-CDF classes. The RTU kernel-CDF transform dominates the numba CPU likelihood (55% of a euclid eval, 89% at hst; O(M_sub × N_data) erf sum), so the conceptually simpler rank-CDF variant becomes the workspace default while RTU is documented as the advanced option (GPU / gradient samplers / interferometer). Resolves option (2) of the Phase 14 default-mesh decision (autolens_profiling PROGRAMME Phase 14 / autolens_profiling#153).
Plan
Resurrect the empirical rank-CDF adaptive transform (sort + cumsum) deleted in the July mesh consolidation and pair it with the existing 4-pixel bilinear interpolation as RectangularBilinearAdaptDensity / RectangularBilinearAdaptImage.
Pure-rename the current kernel-CDF classes to RectangularRTUAdaptDensity / RectangularRTUAdaptImage — implementation and likelihood values unchanged; the RTU implementation is never deleted (it is the only certified gradient mesh on the interferometer sparse path).
RectangularUniform stays as-is.
Update exports, configs and unit tests; PR release notes carry an ## API Changes heading (breaking rename).
Docs must state: gradient inference on the Bilinear default needs over_sample_size_pixelization >= 4 (imaging); interferometer gradient work needs RTU.
Workspace follow-up (separate PRs once the library API lands): default examples switch to Bilinear; RTU documented separately as the advanced option, folding in the queued Enzi-citation docs draft; prior-config yamls added/renamed; _test likelihood pins regenerated for Bilinear scripts (overwrite) while RTU pin scripts survive as pure renames; update autolens_profiling#153 / PROGRAMME Phase 14 with the decision.
Detailed implementation plan
Work Classification
Both (library first — workspace PRs follow once the PyAutoArray API lands).
Workspace repos are not checked out in this session; the workspace phase attaches them after the library PR merges. Local-dev worktree root (created by /start_library when resumed locally): ~/Code/PyAutoLabs-wt/rectangular-bilinear-rtu-mesh-split/.
Recover the empirical rank-CDF transform from the pre-consolidation tree — git show 22b28463^:autoarray/inversion/mesh/interpolator/rectangular.py (create_transforms with argsort/take_along_axis/cumsum, plus its forward_interp/reverse_interp jax+numpy pairs). Do not reinvent it. Add it to autoarray/inversion/mesh/interpolator/rectangular.py alongside the kernel-CDF create_transforms, selectable by the interpolator (e.g. a transform="rank"|"kernel" seam threaded through adaptive_rectangular_transformed_grid_from, adaptive_rectangular_areas_from, adaptive_rectangular_mappings_weights_via_interpolation_from and InterpolatorRectangular).
New mesh classes RectangularBilinearAdaptDensity / RectangularBilinearAdaptImage in autoarray/inversion/mesh/mesh/ — mirror the current RectangularAdaptDensity / RectangularAdaptImage shape (overlay grid, mesh_weight_map_from, interpolator_from) but with the rank-CDF transform and nobandwidth/n_knots hyperparameters (that simplicity is the point of the split).
Pure-rename RectangularAdaptDensity → RectangularRTUAdaptDensity and RectangularAdaptImage → RectangularRTUAdaptImage (kernel-CDF internals untouched). Update autoarray/inversion/mesh/mesh/__init__.py and top-level autoarray/__init__.py exports. No back-compat aliases — the rename is intentionally breaking, recorded under ## API Changes.
Docstrings encode the guidance split: Bilinear = fast CPU default, piecewise-constant likelihood at over_sample_size_pixelization=1 (gradients exactly zero — gradient users set os_pix>=4 or use RTU); RTU = smooth C-inf transform, correct gradients in every configuration incl. the interferometer sparse path, recommended on GPU (cite Enzi et al. arXiv:2606.30620).
Tests: recover/adapt the relevant deleted empirical-CDF unit tests from 22b28463^ (test_autoarray/inversion/pixelization/...), keep the existing rectangular tests running against the renamed RTU classes, add Bilinear cases to the interpolator + mesh test_rectangular.py files.
Grep for any config/registry references to the old class names inside PyAutoArray (e.g. autoarray/config, JSON/dict serialization of mesh classes) and update.
Run the mesh/pixelization test suite; open the library PR with ## API Changes release notes.
Workspace follow-up (separate PRs, after library merge)
autolens_workspace (~224 uses), autogalaxy_workspace, HowToLens (~42): default examples → RectangularBilinearAdaptDensity; RTU documented as the recommended advanced option (GPU / gradient samplers / interferometer), folding in PyAutoMind draft/docs/workspaces/rectangular_mesh_enzi_citation_examples.md (retire that draft when folded in).
Prior configs: add mesh/rectangular_bilinear_adapt_*.yaml; rename RTU yamls to the new class names (autoconf lowercases keys).
autolens_workspace_test: RTU pin scripts survive as pure renames (values unchanged); add/switch default-mesh scripts to Bilinear and regenerate pins, overwriting (pre-consolidation historical values are not reusable — over-sampling configs changed since: 3b4156e, 602ffce).
Measure the Bilinear classes in the existing autolens_profiling cells (scripts/imaging/likelihood_runtime/pixelization_numba.py etc.), record a versioned result, and update autolens_profiling#153 / PROGRAMME Phase 14 with the decision.
autoarray/inversion/mesh/mesh/rectangular_adapt_density.py / rectangular_adapt_image.py — current kernel-CDF mesh classes → renamed RTU classes; templates for the new Bilinear classes.
Certified in the July gradient audit (autolens_workspace_developer/jax_profiling/gradient/README.md): at os_pix=1 the rank-CDF likelihood is exactly piecewise-constant in mass/shear (zero gradients — the reason it was deleted); at os_pix=4 full FD sweeps validate both adaptive meshes (AdaptImage <=~1% production shape, AdaptDensity <=~3%). The interferometer sparse path has no over-sampling, so Bilinear is permanently gradient-dead there — RTU (or RectangularUniform) must remain the interferometer gradient mesh. Sampler-level mesh-family ranking is already PROGRAMME Phase 5 — not duplicated here.
Original Prompt
Click to expand starting prompt
Rectangular mesh split: Bilinear (fast CPU default) vs RTU (advanced/GPU)
Type: feature
Target: autoarray
Repos:
@PyAutoArray
@autolens_workspace
@autogalaxy_workspace
@autolens_workspace_test
Difficulty: medium
Autonomy: supervised
Priority: high
Original request (verbatim, 2026-08-21)
Ok, I think we want RectangularBilinearAdaptDensity (workspace default)
RectangularBilinearAdaptImage, RectangularRTUAdaptDensity and
RectangularRTUAdaptImage. Confirm RectangularBilinearAdaptDensity is CPU fast
and gradient robust. Thsi will prob means we need to again updated all _test
workspace likelihood values in certain scripts, see if history has them but
over write if not (and keep RTU files somewhere)? make prompt to hand off to
mobile
Preceding context (same conversation): the RTU kernel-CDF transform dominates
the numba CPU likelihood (55% of a euclid eval, 89% at hst; O(M_sub x N_data)
erf sum), making the workspace-default rectangular mesh slow on CPU and on the
interferometer path. Proposal: a simpler/faster rectangular mesh becomes the
workspace default; RTU is documented separately as the recommended option for
advanced modeling, especially on GPU. This subsumes option (2) of the Phase 14
default-mesh decision (autolens_profiling PROGRAMME.md Phase 14, issue
autolens_profiling#153) — resolve/update that issue as part of this work.
Grounding (verified 2026-08-21, this session)
Current classes (PyAutoArray autoarray/inversion/mesh/mesh/__init__.py): RectangularAdaptDensity / RectangularAdaptImage (RTU kernel-CDF,
Enzi et al. arXiv:2606.30620) and RectangularUniform (plain uniform
lattice + bilinear, no transform). There is no bare Rectangular.
Naming caveat: BOTH the RTU meshes and every historical adaptive variant
use the same 4-pixel bilinear interpolation on the warped lattice
(interpolator/rectangular.py:435-442). What "Bilinear vs RTU" actually
distinguishes is the lattice transform: the resurrect candidate is the empirical rank-CDF adaptive transform (sort + cumsum), deleted in
PyAutoArray 22b28463 (refactor: consolidate rectangular meshes — kernel takes plain names, retire linear/spline/rotated #402, 2026-07-23, -3738 lines) when kernel-CDF took
the plain names. Recover its implementation from that commit
(create_transforms with argsort/cumsum) — do NOT reinvent it.
CPU fast: YES. The rank-CDF transform is O(N log N) sort/cumsum and
eliminates the erf sum that is 55-89% of the numba CPU eval (post-perf: windowed numba fast path for the kernel-CDF forward transform #458 the
RTU eval is euclid 1.17 s / hst 10.1 s on a 4-core container). Measure the
new class in the existing autolens_profiling cells
(scripts/imaging/likelihood_runtime/pixelization_numba.py etc.) and record
a versioned result.
Gradient robust: CONDITIONALLY. Certified evidence from the July
gradient audit (autolens_workspace_developer/jax_profiling/gradient/README.md):
os_pix=1 (the current default): rank-CDF likelihood is exactly
piecewise-constant in mass/shear — gradients exactly zero. Unusable.
over_sample_size_pixelization=4: full FD sweeps validate both adaptive
meshes — AdaptImage production shape <=~1% on mass, AdaptDensity <=~3%.
Acceptable for most JAX gradient samplers.
Interferometer sparse path: no over-sampling exists — the staircase with
no escape hatch. RTU (and RectangularUniform) are the only certified
gradient meshes there.
So docs MUST say: gradient inference on the Bilinear default needs
os_pix>=4 (imaging); interferometer gradient work needs RTU. Sampler-level
mesh-family ranking is already PROGRAMME Phase 5 — do not duplicate it here.
Alternative implementation considered: interpolated-kernel-CDF forward
(K=8192 -> dlnL <= +4e-3, 18-55x on the step, measured in feature/triangle array typing #151/feature/revert to float #153 work).
Rejected for the Bilinear pair (it is still RTU with a bandwidth
hyperparameter, defeating "conceptually simple"); it remains feature/revert to float #153's lever
for making RTU itself faster on CPU.
Goal
PyAutoArray: four adaptive classes — RectangularBilinearAdaptDensity (resurrected rank-CDF transform +
bilinear) and RectangularBilinearAdaptImage; RectangularRTUAdaptDensity / RectangularRTUAdaptImage (pure renames of
the current kernel-CDF classes, values unchanged). RectangularUniform
stays as-is (library-test baseline; certified interferometer gradient
mesh). Never delete the RTU implementation. Breaking rename → release
notes need the ## API Changes heading.
Workspaces (autolens_workspace ~224 uses, autogalaxy_workspace,
HowToLens ~42): default examples switch to RectangularBilinearAdaptDensity; RTU documented separately as the
recommended advanced option (GPU / gradient samplers / interferometer),
folding in the queued Enzi-citation docs draft
(draft/docs/workspaces/rectangular_mesh_enzi_citation_examples.md).
Prior configs: add mesh/rectangular_bilinear_adapt_*.yaml, rename the
RTU yamls to match the new class names (autoconf lowercases keys).
_test workspace: likelihood pin scripts
(scripts/{imaging,multi_dataset,interferometer}/jax_likelihood/rectangular*.py
and siblings) — keep RTU pin scripts alive under the renamed classes
(values unchanged by a pure rename), add/switch default-mesh scripts to
Bilinear and regenerate pins, overwriting. History does hold
pre-consolidation (empirical-CDF era) values but under older paths/configs
(over-sampling changed since: 3b4156e, 602ffce) — not reusable.
Update autolens_profiling#153 / PROGRAMME Phase 14 with the decision.
Library first, workspace follow-up once the API lands (standard both-routing).
Overview
Split the rectangular adaptive mesh family into two user-facing variants: Bilinear (
RectangularBilinearAdaptDensity/RectangularBilinearAdaptImage), a resurrected empirical rank-CDF lattice transform that is fast on CPU, and RTU (RectangularRTUAdaptDensity/RectangularRTUAdaptImage), pure renames of the current kernel-CDF classes. The RTU kernel-CDF transform dominates the numba CPU likelihood (55% of a euclid eval, 89% at hst; O(M_sub × N_data) erf sum), so the conceptually simpler rank-CDF variant becomes the workspace default while RTU is documented as the advanced option (GPU / gradient samplers / interferometer). Resolves option (2) of the Phase 14 default-mesh decision (autolens_profiling PROGRAMME Phase 14 / autolens_profiling#153).Plan
RectangularBilinearAdaptDensity/RectangularBilinearAdaptImage.RectangularRTUAdaptDensity/RectangularRTUAdaptImage— implementation and likelihood values unchanged; the RTU implementation is never deleted (it is the only certified gradient mesh on the interferometer sparse path).RectangularUniformstays as-is.## API Changesheading (breaking rename).over_sample_size_pixelization >= 4(imaging); interferometer gradient work needs RTU._testlikelihood pins regenerated for Bilinear scripts (overwrite) while RTU pin scripts survive as pure renames; update autolens_profiling#153 / PROGRAMME Phase 14 with the decision.Detailed implementation plan
Work Classification
Both (library first — workspace PRs follow once the PyAutoArray API lands).
Affected Repositories
Branch Survey
Workspace repos are not checked out in this session; the workspace phase attaches them after the library PR merges. Local-dev worktree root (created by
/start_librarywhen resumed locally):~/Code/PyAutoLabs-wt/rectangular-bilinear-rtu-mesh-split/.Suggested branch:
feature/rectangular-bilinear-rtu-mesh-splitImplementation Steps (library phase, PyAutoArray)
git show 22b28463^:autoarray/inversion/mesh/interpolator/rectangular.py(create_transformswithargsort/take_along_axis/cumsum, plus itsforward_interp/reverse_interpjax+numpy pairs). Do not reinvent it. Add it toautoarray/inversion/mesh/interpolator/rectangular.pyalongside the kernel-CDFcreate_transforms, selectable by the interpolator (e.g. atransform="rank"|"kernel"seam threaded throughadaptive_rectangular_transformed_grid_from,adaptive_rectangular_areas_from,adaptive_rectangular_mappings_weights_via_interpolation_fromandInterpolatorRectangular).RectangularBilinearAdaptDensity/RectangularBilinearAdaptImageinautoarray/inversion/mesh/mesh/— mirror the currentRectangularAdaptDensity/RectangularAdaptImageshape (overlay grid,mesh_weight_map_from,interpolator_from) but with the rank-CDF transform and nobandwidth/n_knotshyperparameters (that simplicity is the point of the split).RectangularAdaptDensity→RectangularRTUAdaptDensityandRectangularAdaptImage→RectangularRTUAdaptImage(kernel-CDF internals untouched). Updateautoarray/inversion/mesh/mesh/__init__.pyand top-levelautoarray/__init__.pyexports. No back-compat aliases — the rename is intentionally breaking, recorded under## API Changes.over_sample_size_pixelization=1(gradients exactly zero — gradient users set os_pix>=4 or use RTU); RTU = smooth C-inf transform, correct gradients in every configuration incl. the interferometer sparse path, recommended on GPU (cite Enzi et al. arXiv:2606.30620).22b28463^(test_autoarray/inversion/pixelization/...), keep the existing rectangular tests running against the renamed RTU classes, add Bilinear cases to the interpolator + meshtest_rectangular.pyfiles.autoarray/config, JSON/dict serialization of mesh classes) and update.## API Changesrelease notes.Workspace follow-up (separate PRs, after library merge)
autolens_workspace(~224 uses),autogalaxy_workspace, HowToLens (~42): default examples →RectangularBilinearAdaptDensity; RTU documented as the recommended advanced option (GPU / gradient samplers / interferometer), folding inPyAutoMind draft/docs/workspaces/rectangular_mesh_enzi_citation_examples.md(retire that draft when folded in).mesh/rectangular_bilinear_adapt_*.yaml; rename RTU yamls to the new class names (autoconf lowercases keys).autolens_workspace_test: RTU pin scripts survive as pure renames (values unchanged); add/switch default-mesh scripts to Bilinear and regenerate pins, overwriting (pre-consolidation historical values are not reusable — over-sampling configs changed since:3b4156e,602ffce).scripts/imaging/likelihood_runtime/pixelization_numba.pyetc.), record a versioned result, and update autolens_profiling#153 / PROGRAMME Phase 14 with the decision.Key Files
autoarray/inversion/mesh/interpolator/rectangular.py— kernel-CDFcreate_transformstoday; gains the resurrected rank-CDF variant + selection seam.autoarray/inversion/mesh/mesh/rectangular_adapt_density.py/rectangular_adapt_image.py— current kernel-CDF mesh classes → renamed RTU classes; templates for the new Bilinear classes.autoarray/inversion/mesh/mesh/__init__.py,autoarray/__init__.py— exports.test_autoarray/inversion/pixelization/interpolator/test_rectangular.py,test_autoarray/inversion/pixelization/mesh/test_rectangular.py— test homes.22b28463^(pre-consolidation tree; deletion commit refactor: consolidate rectangular meshes — kernel takes plain names, retire linear/spline/rotated #402, 2026-07-23).Gradient evidence (why the split is safe)
Certified in the July gradient audit (
autolens_workspace_developer/jax_profiling/gradient/README.md): at os_pix=1 the rank-CDF likelihood is exactly piecewise-constant in mass/shear (zero gradients — the reason it was deleted); at os_pix=4 full FD sweeps validate both adaptive meshes (AdaptImage <=~1% production shape, AdaptDensity <=~3%). The interferometer sparse path has no over-sampling, so Bilinear is permanently gradient-dead there — RTU (or RectangularUniform) must remain the interferometer gradient mesh. Sampler-level mesh-family ranking is already PROGRAMME Phase 5 — not duplicated here.Original Prompt
Click to expand starting prompt
Rectangular mesh split: Bilinear (fast CPU default) vs RTU (advanced/GPU)
Type: feature
Target: autoarray
Repos:
Difficulty: medium
Autonomy: supervised
Priority: high
Original request (verbatim, 2026-08-21)
Preceding context (same conversation): the RTU kernel-CDF transform dominates
the numba CPU likelihood (55% of a euclid eval, 89% at hst; O(M_sub x N_data)
erf sum), making the workspace-default rectangular mesh slow on CPU and on the
interferometer path. Proposal: a simpler/faster rectangular mesh becomes the
workspace default; RTU is documented separately as the recommended option for
advanced modeling, especially on GPU. This subsumes option (2) of the Phase 14
default-mesh decision (
autolens_profilingPROGRAMME.md Phase 14, issueautolens_profiling#153) — resolve/update that issue as part of this work.
Grounding (verified 2026-08-21, this session)
PyAutoArray autoarray/inversion/mesh/mesh/__init__.py):RectangularAdaptDensity/RectangularAdaptImage(RTU kernel-CDF,Enzi et al. arXiv:2606.30620) and
RectangularUniform(plain uniformlattice + bilinear, no transform). There is no bare
Rectangular.use the same 4-pixel bilinear interpolation on the warped lattice
(
interpolator/rectangular.py:435-442). What "Bilinear vs RTU" actuallydistinguishes is the lattice transform: the resurrect candidate is the
empirical rank-CDF adaptive transform (sort + cumsum), deleted in
PyAutoArray
22b28463(refactor: consolidate rectangular meshes — kernel takes plain names, retire linear/spline/rotated #402, 2026-07-23, -3738 lines) when kernel-CDF tookthe plain names. Recover its implementation from that commit
(
create_transformswithargsort/cumsum) — do NOT reinvent it.eliminates the erf sum that is 55-89% of the numba CPU eval (post-perf: windowed numba fast path for the kernel-CDF forward transform #458 the
RTU eval is euclid 1.17 s / hst 10.1 s on a 4-core container). Measure the
new class in the existing
autolens_profilingcells(
scripts/imaging/likelihood_runtime/pixelization_numba.pyetc.) and recorda versioned result.
gradient audit (
autolens_workspace_developer/jax_profiling/gradient/README.md):piecewise-constant in mass/shear — gradients exactly zero. Unusable.
meshes — AdaptImage production shape <=~1% on mass, AdaptDensity <=~3%.
Acceptable for most JAX gradient samplers.
no escape hatch. RTU (and RectangularUniform) are the only certified
gradient meshes there.
So docs MUST say: gradient inference on the Bilinear default needs
os_pix>=4 (imaging); interferometer gradient work needs RTU. Sampler-level
mesh-family ranking is already PROGRAMME Phase 5 — do not duplicate it here.
(K=8192 -> dlnL <= +4e-3, 18-55x on the step, measured in feature/triangle array typing #151/feature/revert to float #153 work).
Rejected for the Bilinear pair (it is still RTU with a bandwidth
hyperparameter, defeating "conceptually simple"); it remains feature/revert to float #153's lever
for making RTU itself faster on CPU.
Goal
RectangularBilinearAdaptDensity(resurrected rank-CDF transform +bilinear) and
RectangularBilinearAdaptImage;RectangularRTUAdaptDensity/RectangularRTUAdaptImage(pure renames ofthe current kernel-CDF classes, values unchanged).
RectangularUniformstays as-is (library-test baseline; certified interferometer gradient
mesh). Never delete the RTU implementation. Breaking rename → release
notes need the
## API Changesheading.autolens_workspace~224 uses,autogalaxy_workspace,HowToLens ~42): default examples switch to
RectangularBilinearAdaptDensity; RTU documented separately as therecommended advanced option (GPU / gradient samplers / interferometer),
folding in the queued Enzi-citation docs draft
(
draft/docs/workspaces/rectangular_mesh_enzi_citation_examples.md).Prior configs: add
mesh/rectangular_bilinear_adapt_*.yaml, rename theRTU yamls to match the new class names (autoconf lowercases keys).
(
scripts/{imaging,multi_dataset,interferometer}/jax_likelihood/rectangular*.pyand siblings) — keep RTU pin scripts alive under the renamed classes
(values unchanged by a pure rename), add/switch default-mesh scripts to
Bilinear and regenerate pins, overwriting. History does hold
pre-consolidation (empirical-CDF era) values but under older paths/configs
(over-sampling changed since:
3b4156e,602ffce) — not reusable.Library first, workspace follow-up once the API lands (standard both-routing).