Skip to content

feat: split rectangular adaptive meshes — Bilinear (rank-CDF) vs RTU (kernel-CDF) - #462

Merged
Jammy2211 merged 1 commit into
mainfrom
feature/rectangular-bilinear-rtu-mesh-split
Aug 21, 2026
Merged

feat: split rectangular adaptive meshes — Bilinear (rank-CDF) vs RTU (kernel-CDF)#462
Jammy2211 merged 1 commit into
mainfrom
feature/rectangular-bilinear-rtu-mesh-split

Conversation

@Jammy2211

Copy link
Copy Markdown
Collaborator

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^) as create_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.
  • RectangularUniform unchanged (now inherits under the RTU name).

The seam is a transform="rank"|"kernel" selector threaded through the 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 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:

  • RectangularAdaptDensityRectangularRTUAdaptDensity, RectangularAdaptImageRectangularRTUAdaptImage (pure renames, kernel-CDF internals and likelihood values untouched).
  • New RectangularBilinearAdaptDensity(shape) / RectangularBilinearAdaptImage(shape, weight_power, weight_floor) — rank-CDF adaptive meshes with no bandwidth/n_knots hyperparameters.
  • RectangularUniform unchanged.

Downstream workspaces (autolens_workspace ~224 uses, autogalaxy_workspace, HowToLens, autolens_workspace_test pins, prior-config yamls) update in follow-up PRs.
See full details below.

Test Plan

  • Full suite python -m pytest test_autoarray/ on Python 3.12: 1114 passed; the only 3 failures are the pre-existing test_transformer.py pynufft failures, reproduced identically on pristine main in the same environment.
  • New unit tests: rank-CDF transform exactness at the traced points (ranks / weighted cumsum), monotonicity/bounds, exact round-trip, mappings/weights normalization, area telescoping to the bounding box, density adaptivity, invalid-transform rejection, Bilinear mesh construction/dispatch/signature, split-regularization guard extended to all five rectangular meshes.
  • JAX/xp parity + gradient behaviour: unit tests are NumPy-only by project rule — validated by the parity scripts in autolens_workspace_test/autogalaxy_workspace_test in the workspace follow-up (pins regenerated there).
  • CPU speed-up measured in the existing autolens_profiling cells (follow-up, recorded as a versioned result on autolens_profiling#153 / PROGRAMME Phase 14).
Full API Changes (for automation & release notes)

Renamed

  • aa.mesh.RectangularAdaptDensityaa.mesh.RectangularRTUAdaptDensity (module autoarray/inversion/mesh/mesh/rectangular_rtu_adapt_density.py)
  • aa.mesh.RectangularAdaptImageaa.mesh.RectangularRTUAdaptImage (module autoarray/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) in autoarray/inversion/mesh/interpolator/rectangular.py — the recovered empirical rank-CDF transform pair (plus restored forward_interp / forward_interp_np).

Changed Signature

  • adaptive_rectangular_transformed_grid_from, adaptive_rectangular_areas_from, adaptive_rectangular_mappings_weights_via_interpolation_from: new keyword transform="kernel" ("rank" selects the empirical rank CDF; bandwidth/n_knots are then unused).
  • InterpolatorRectangular.__init__: new keyword transform="kernel".
  • AbstractMeshGeometry.__init__ / MeshGeometryRectangular: new keyword transform="kernel" — areas/edges route through the same transform as the mapper.

Changed Behaviour

  • None for existing classes: the RTU meshes are pure renames (likelihood values unchanged); RectangularUniform is untouched.

Migration

  • Before: aa.mesh.RectangularAdaptDensity(shape=(30, 30), bandwidth=1.0)
  • After (same behaviour): aa.mesh.RectangularRTUAdaptDensity(shape=(30, 30), bandwidth=1.0)
  • After (fast CPU default): aa.mesh.RectangularBilinearAdaptDensity(shape=(30, 30)) — gradient users set over_sample_size_pixelization >= 4 or stay on RTU; interferometer gradient users stay on RTU.

Generated by the PyAutoLabs agent workflow.


Generated by Claude Code

…(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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pending-release PR queued for the next release build

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants