feat: split rectangular adaptive meshes — Bilinear (rank-CDF) vs RTU (kernel-CDF) - #462
Merged
Merged
Conversation
…(kernel-CDF) Split the rectangular adaptive mesh family into two user-facing variants (PyAutoArray#461): - RectangularBilinearAdaptDensity / RectangularBilinearAdaptImage: the empirical rank-CDF lattice transform (sort + cumsum, no kernel hyperparameters), recovered from the pre-#402 implementation (22b2846^) as create_transforms_rank. O(N log N) on CPU — the fast workspace default, eliminating the O(M_sub x N_data) erf sum that dominates the numba CPU likelihood (55% euclid / 89% hst). - RectangularRTUAdaptDensity / RectangularRTUAdaptImage: pure renames of the kernel-CDF classes (values unchanged) — the advanced option for GPU, JAX gradient samplers and the interferometer sparse path, where they remain the only adaptive rectangular meshes with usable gradients. - RectangularUniform unchanged (now inherits the RTU name). The transform seam is a `transform="rank"|"kernel"` selector threaded through create_transforms dispatch, the adaptive_rectangular_* functions, InterpolatorRectangular and MeshGeometryRectangular, so the geometry's areas/edges always route through the same transform as the mapper. Both transforms share the existing 4-pixel bilinear interpolation. Docstrings encode the guidance split: gradient inference on the Bilinear default needs over_sample_size_pixelization >= 4 (imaging); interferometer gradient work needs RTU (certified in the July gradient audit). Breaking rename — no back-compat aliases; downstream workspaces update in follow-up PRs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WtMqU3JfmyJh8GvB7jT4Et
This was referenced Aug 21, 2026
Merged
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
Splits the rectangular adaptive mesh family into two user-facing variants (part of #461 — library phase; workspace PRs follow once this merges):
RectangularBilinearAdaptDensity/RectangularBilinearAdaptImage— the empirical rank-CDF lattice transform (sort + cumsum, no kernel hyperparameters), recovered from the pre-refactor: consolidate rectangular meshes — kernel takes plain names, retire linear/spline/rotated #402 implementation (22b28463^) ascreate_transforms_rank. O(N log N) on CPU, eliminating the O(M_sub × N_data) erf sum that dominates the numba CPU likelihood (55% of a euclid eval, 89% at hst). Becomes the workspace default in the follow-up PRs.RectangularRTUAdaptDensity/RectangularRTUAdaptImage— pure renames of the current kernel-CDF classes (implementation and likelihood values unchanged). The advanced option for GPU, JAX gradient samplers and the interferometer sparse path, where they remain the only adaptive rectangular meshes with usable gradients. The RTU implementation is deliberately kept forever.RectangularUniformunchanged (now inherits under the RTU name).The seam is a
transform="rank"|"kernel"selector threaded through thecreate_transformsdispatch, theadaptive_rectangular_*functions,InterpolatorRectangularandMeshGeometryRectangular, so the geometry's areas/edges always route through the same transform as the mapper. Both transforms warp the same lattice and share the existing 4-pixel bilinear interpolation.Docstrings encode the guidance split: gradient inference on the Bilinear meshes needs
over_sample_size_pixelization >= 4(imaging — FD-certified in the July gradient audit); at over-sampling 1 the rank-CDF likelihood is exactly piecewise-constant in mass/shear (zero gradients — the reason it was deleted in #402). Interferometer gradient work needs RTU.API Changes
Breaking rename plus two new mesh classes — no back-compat aliases:
RectangularAdaptDensity→RectangularRTUAdaptDensity,RectangularAdaptImage→RectangularRTUAdaptImage(pure renames, kernel-CDF internals and likelihood values untouched).RectangularBilinearAdaptDensity(shape)/RectangularBilinearAdaptImage(shape, weight_power, weight_floor)— rank-CDF adaptive meshes with nobandwidth/n_knotshyperparameters.RectangularUniformunchanged.Downstream workspaces (
autolens_workspace~224 uses,autogalaxy_workspace, HowToLens,autolens_workspace_testpins, prior-config yamls) update in follow-up PRs.See full details below.
Test Plan
python -m pytest test_autoarray/on Python 3.12: 1114 passed; the only 3 failures are the pre-existingtest_transformer.pypynufft failures, reproduced identically on pristinemainin the same environment.transformrejection, Bilinear mesh construction/dispatch/signature, split-regularization guard extended to all five rectangular meshes.xpparity + gradient behaviour: unit tests are NumPy-only by project rule — validated by the parity scripts inautolens_workspace_test/autogalaxy_workspace_testin the workspace follow-up (pins regenerated there).autolens_profilingcells (follow-up, recorded as a versioned result on autolens_profiling#153 / PROGRAMME Phase 14).Full API Changes (for automation & release notes)
Renamed
aa.mesh.RectangularAdaptDensity→aa.mesh.RectangularRTUAdaptDensity(moduleautoarray/inversion/mesh/mesh/rectangular_rtu_adapt_density.py)aa.mesh.RectangularAdaptImage→aa.mesh.RectangularRTUAdaptImage(moduleautoarray/inversion/mesh/mesh/rectangular_rtu_adapt_image.py)Added
aa.mesh.RectangularBilinearAdaptDensity(shape=(3, 3))— rank-CDF density-adaptive rectangular mesh (no kernel hyperparameters).aa.mesh.RectangularBilinearAdaptImage(shape=(3, 3), weight_power=1.0, weight_floor=0.0)— rank-CDF adapt-image-weighted rectangular mesh.create_transforms_rank(traced_points, mesh_weight_map=None, xp=np)inautoarray/inversion/mesh/interpolator/rectangular.py— the recovered empirical rank-CDF transform pair (plus restoredforward_interp/forward_interp_np).Changed Signature
adaptive_rectangular_transformed_grid_from,adaptive_rectangular_areas_from,adaptive_rectangular_mappings_weights_via_interpolation_from: new keywordtransform="kernel"("rank"selects the empirical rank CDF;bandwidth/n_knotsare then unused).InterpolatorRectangular.__init__: new keywordtransform="kernel".AbstractMeshGeometry.__init__/MeshGeometryRectangular: new keywordtransform="kernel"— areas/edges route through the same transform as the mapper.Changed Behaviour
RectangularUniformis untouched.Migration
aa.mesh.RectangularAdaptDensity(shape=(30, 30), bandwidth=1.0)aa.mesh.RectangularRTUAdaptDensity(shape=(30, 30), bandwidth=1.0)aa.mesh.RectangularBilinearAdaptDensity(shape=(30, 30))— gradient users setover_sample_size_pixelization >= 4or stay on RTU; interferometer gradient users stay on RTU.Generated by the PyAutoLabs agent workflow.
Generated by Claude Code