Skip to content

fix: single-image recovery blind to inf-padded JAX solver output #771

Closed

Description

@Jammy2211

Overview

Result.image_plane_multiple_image_positions in autolens/analysis/result.py triggers the inward-walk single-image recovery when multiple_images.shape[0] <= 1. Under a JAX-backed analysis (xp=jnp) the point solver returns a static-shape array padded with (inf, inf) rows (remove_infinities defaults to xp is np since #759), so the shape test is never true and recovery can never fire. Since PyAutoLens#765 (discussion https://github.com/orgs/PyAutoLabs/discussions/30) a 1-image JAX solve then raises PositionsException at PositionsLH construction, so JAX SLaM chains could error where they used to run. Padded rows are also written into the cached files/multiple_image_positions.json.

Plan

  • Count finite solver rows (not array length) before deciding whether the single-image recovery runs.
  • When two or more finite images exist, return only the finite rows, so downstream consumers and the cached JSON are clean.
  • Apply the same finite-row count inside the inward-walk recovery loop.
  • Unit tests: padded 1-image array triggers recovery; padded 2-image array returns exactly the 2 finite rows; unpadded numpy output unchanged. Witness: padded-1-image test fails on main, passes with the fix.
Detailed implementation plan

Affected Repositories

  • PyAutoLens (primary)

Branch Survey

Repository Current Branch Dirty?
./PyAutoLens main clean

Suggested branch: feature/padded-single-image-recovery

Implementation Steps

  1. In autolens/analysis/result.py image_plane_multiple_image_positions (the if multiple_images.shape[0] <= 1: block), compute finite = np.isfinite(np.asarray(multiple_images)).all(axis=1); if finite.sum() <= 1 call image_plane_multiple_image_positions_for_single_image_from(); else return aa.Grid2DIrregular(values=np.asarray(multiple_images)[finite]). Keep the zero-images comment accurate and extend it to explain inf padding.
  2. In image_plane_multiple_image_positions_for_single_image_from, apply the same finite-row count to the multiple_images.shape[0] > 1 test and return only finite rows.
  3. Tests in test_autolens/analysis/test_result.py: monkeypatch PointSolver.solve to return (a) 1 finite row + inf rows → recovery helper called; (b) 2 finite rows + inf rows → exactly the 2 finite rows; (c) unpadded 2-row numpy array → unchanged.
  4. Witness: run test (a) on unfixed source (fails) and with the fix (passes).
  5. Run python -m pytest test_autolens/analysis -q and the full test_autolens suite.

Key Files

  • autolens/analysis/result.py — image_plane_multiple_image_positions, image_plane_multiple_image_positions_for_single_image_from
  • test_autolens/analysis/test_result.py — new tests

Pin risk: none for finite inputs (numpy solver output contains no non-finite rows, so the filter is the identity).

Links: PyAutoLens#765, https://github.com/orgs/PyAutoLabs/discussions/30

Original Prompt

Click to expand starting prompt

PyAutoLens: single-image recovery in Result.image_plane_multiple_image_positions_from is blind to inf-padded JAX solver output

Type: bug
Target: PyAutoLens
Repos:

  • PyAutoLens
    Difficulty: medium
    Autonomy: safe
    Priority: normal
    Memory: wiki/galaxies/sources/massive-ellipticals.md; wiki/lensing/sources/dark-matter-substructure.md; wiki/galaxies/sources/light-profile-fitting.md
    Status: formalised
    Consequence: judge
    Witness: a new test in test_autolens feeding image_plane_multiple_image_positions_from a 1-image array padded with inf rows fails on main and passes with the fix
    Review-minutes: 20
    Unattended: ready

PyAutoLens: single-image recovery in Result.image_plane_multiple_image_positions_from is blind to inf-padded JAX solver output.

Found while reviewing community PR PyAutoLens#765 (@samlange04, discussion https://github.com/orgs/PyAutoLabs/discussions/23 sibling report #30). In autolens/analysis/result.py (around line 138) the inward-walk recovery for a single-image solve tests multiple_images.shape[0] <= 1. With a JAX-backed analysis the point solver (xp=jnp, remove_infinities defaults to xp is np since #759) returns a static-shape array padded with (inf, inf) rows (20 rows), so the shape test is always false and the recovery can never fire under JAX. After #765 (which drops non-finite rows at PositionsLH construction and raises PositionsException when fewer than 2 finite rows remain) a 1-image JAX solve now raises at construction instead of silently scoring zero penalty. Fail-loud is better than silent zero, but SLaM chains on JAX could start erroring where they used to run.

Fix: count finite rows (np.isfinite(...).all(axis=1).sum()) before the <= 1 check, or strip non-finite rows before it, so the recovery path triggers for padded output exactly as it does for the numpy solver. Add a unit test feeding a padded 1-image array and asserting the recovery path runs (and a 2-image padded array does not). Not yet reproduced with a real 1-image JAX solve; severity unknown. Check that the cached files/multiple_image_positions.json written from padded positions still round-trips.

Activity

  1. Jammy2211 commented on Oct 7, 2026

    @Jammy2211
    CollaboratorAuthor

    Library PR created: #772. Finite-row count in both the top-level solve and the inward walk; witness: 3 of 4 new tests fail on main, all pass with the fix; test_autolens/analysis 101 passed, full test_autolens 831 passed / 1 xfailed. No public API change, no workspace impact; pin risk none for finite (NumPy) inputs. Awaiting human /prm.

  2. Jammy2211 commented on Oct 7, 2026

    @Jammy2211
    CollaboratorAuthor

    Shipped: merged in #772 as 384e86e (pending release). Closing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions