Skip to content

fix(hilbert): support offset-centre circular masks#313

Merged
Jammy2211 merged 1 commit into
mainfrom
feature/hilbert-offset-centre-mask
May 15, 2026
Merged

fix(hilbert): support offset-centre circular masks#313
Jammy2211 merged 1 commit into
mainfrom
feature/hilbert-offset-centre-mask

Conversation

@Jammy2211
Copy link
Copy Markdown
Collaborator

Summary

Fixes a user-reported bug where Hilbert image-mesh raised PixelizationException for circular masks with offset centres (e.g. lens systems whose mask centre is not at the field-of-view origin). The bug had two compounding halves: Mask2D.is_circular returned False for genuinely circular offset masks due to pixel-quantization asymmetry, and even if the check were bypassed the Hilbert sampler always probed the image around (0, 0) rather than the mask centre.

API Changes

  • Mask2D.is_circular is now quantization-robust and correctly distinguishes filled discs from annular and square masks (previously annular masks were false-positives).
  • Mask2D.circular_radius derives the radius from the bbox extent. Numerically identical for centred masks.
  • hilbert.image_and_grid_from gains an optional mask_centre=(0.0, 0.0) parameter and translates the Hilbert sample points by it. For masks centred at the origin (every current test/smoke case) this is a no-op.

See full details below.

Test Plan

  • New tests in test_autoarray/mask/test_mask_2d.py cover offset centres (5 parametrised positions), annular masks, square unmasked regions, and circular_radius for offset centres.
  • New test in test_autoarray/inversion/pixelization/image_mesh/test_hilbert.py asserts that the resulting mesh points lie inside the mask's circle for an offset-centre mask.
  • Existing centred-mask Hilbert test returns the same bit-exact mesh point ([-1.02590674, -1.70984456]), confirming Delaunay-Hilbert smoke tests will produce unchanged likelihoods.
  • Full mask suite (72 tests) and full inversion suite (165 tests) pass with no regressions.
Full API Changes (for automation & release notes)

Changed Behaviour

  • Mask2D.is_circular — algorithm rewritten. Now returns True for offset-centre circular masks (was: returned False when centre offset caused pixel-quantization asymmetry). Now returns False for annular masks (was: returned True because central row/column counts were symmetric).
  • Mask2D.circular_radius — computed from the bounding-box extent of the unmasked region (was: from the unmasked-pixel count in a single guessed central row). Numerically identical for centred masks; correct rather than spurious for offset centres.

Changed Signature

  • autoarray.inversion.mesh.image_mesh.hilbert.image_and_grid_from(image, mask, mask_radius, pixel_scales, hilbert_length, mask_centre=(0.0, 0.0)) — new trailing keyword mask_centre, defaults to (0.0, 0.0) so existing callers are unaffected.

Migration

None required. All changes are either additive (new optional kwarg with backward-compatible default) or strictly bug-fix behaviour. Workspaces and tests using centred masks see no numerical change.

🤖 Generated with Claude Code

Previously Hilbert image-mesh raised PixelizationException for offset-centre
circular masks whose centres didn't land on a pixel half-integer, and would
have silently sampled the wrong region of the image for those that slipped
through. This commit fixes both halves of the bug.

- Mask2D.is_circular rewritten to be quantization-robust: bbox square within
  one pixel, geometric centre pixel unmasked, and a reference circular mask
  reconstructed from the inferred centre+radius must match the input within
  rim quantization tolerance. The new predicate correctly accepts offset
  circles and rejects annular and square masks that previously false-passed.
- Mask2D.circular_radius now derives the radius from the bbox extent rather
  than the central row count. Numerically identical for centred masks; correct
  for offset centres.
- hilbert.image_and_grid_from now translates Hilbert sample points by
  mask_centre, so the curve actually probes the masked region of the image.
  For masks centred at the origin (every current test/smoke case) the shift
  is a no-op and likelihoods are bit-identical.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@Jammy2211 Jammy2211 added the pending-release PR queued for the next release build label May 15, 2026
@Jammy2211 Jammy2211 merged commit f484332 into main May 15, 2026
6 checks passed
@Jammy2211 Jammy2211 deleted the feature/hilbert-offset-centre-mask branch May 15, 2026 15:03
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.

1 participant