Skip to content

test: re-pin knife-edge positions_threshold pins after the exact grid transform (PyAutoArray#519) #721

Closed

Description

@Jammy2211

Overview

PyAutoLens main is RED (pyauto-heart readiness --json reason PyAutoLens: CI failure). Two tests in test_autolens/analysis/test_result.py pin a point-solver quantity on an exactly mirror-symmetric fixture, and PyAutoArray#519 moved them. Bisected: #519's rotation-matrix rewrite of transform_grid_2d_to_reference_frame (commit f45b30b0) is the sole mover — it made the transform an exact identity at angle 0, so the on-axis deflection is now exactly 0.0 instead of 6.1e-17, the solver hits an exact tie, and the tie-break selects the other branch.

The new values are the more accurate branch (exact transform, exact on-axis zero). Nothing in the library is wrong. This is a test-only re-pin plus a comment recording the sensitivity, opened as a corrective PR so PyAutoLens main goes green again.

Plan

  • Re-pin the four literals in test_autolens/analysis/test_result.py at the existing 1.0e-4 tolerances.
  • Add a short comment above each pin explaining the mirror symmetry, the sub-ULP tie-break, PyAutoArray#519 as the cause, and the 1e-15 flip-back sensitivity.
  • No library change; no tolerance change.
  • Follow-up (filed separately): move the fixture off the symmetry axis so the pin is stable rather than branch-selected.
Detailed implementation plan

Affected Repositories

  • PyAutoLens (primary)

Branch Survey

Repository Current Branch Dirty?
./PyAutoLens main clean (README.md only, unrelated)

Suggested branch: feature/positions-threshold-repin

Implementation Steps

  1. test_autolens/analysis/test_result.py::test__positions_threshold_from — 0.0019501455 → 0.0019534291; 0.0097507278035 → 0.0097671455155. Keep 1.0e-4.
  2. test_autolens/analysis/test_result.py::test__positions_likelihood_from__mass_centre_radial_distance_min — positions[1] (1.00097656e00, -5.63818622e-04) → (1.00097656e00, 5.63818622e-04). positions[0] unchanged. Keep 1.0e-4.
  3. Add the knife-edge comment above each pin.
  4. pytest test_autolens -n 4 -q; ruff check / ruff format --check.

Key Files

  • test_autolens/analysis/test_result.py — the only file changed.

Measurements

quantity pre-#519 post-#519
positions_threshold_from() 0.0019501455607163743 0.0019534291030939357
positions_threshold_from(factor=5.0) 0.009750727803581872 0.009767145515469679
positions[1] (1.0009765625, -5.638186222554754e-04) (1.0009765625, 5.638186222554754e-04)
transform error at angle 0 8.9e-16 0.0 (exact identity)
on-axis alpha_x 6.1e-17 0.0

A 1e-15 nudge of the lens centre in x flips the threshold back to the old value; a 1e-6 nudge moves it by a factor of 86.

Original Prompt

Click to expand starting prompt

Re-pin the knife-edge positions_threshold tests after PyAutoArray#519's exact grid transform

Type: bug
Target: autolens
Repos:

  • @PyAutoLens
    Themes:
  • point-source
  • testing
    Difficulty: small
    Autonomy: supervised
    Priority: high
    Status: draft
    Filed: 2026-09-03

Symptom

PyAutoLens main is RED (pyauto-heart readiness --json reason PyAutoLens: CI failure).
Two tests in test_autolens/analysis/test_result.py fail against the current library mains:

  • test__positions_threshold_from — positions_threshold_from() returns
    0.0019534291030939357, pinned at 0.0019501455607163743; positions_threshold_from(factor=5.0)
    returns 0.009767145515469679, pinned at 0.009750727803581872.
  • test__positions_likelihood_from__mass_centre_radial_distance_min — positions[1] returns
    (1.0009765625, 0.0005638186222554754), pinned at (1.00097656e00, -5.63818622e-04); the x
    component has flipped sign and its magnitude is bit-identical. positions[0] is unchanged at
    (-1.0009765625, 0.0005638186222554754).

Bisect attribution

Bisected across the day's PyAutoArray/PyAutoGalaxy merges with detached scratch worktrees, holding
PyAutoLens fixed:

PyAutoArray PyAutoGalaxy result positions_threshold_from()
main main FAIL 0.0019534291030939357
62feb7eb^ main PASS 0.0019501455607163743
main 50599c2c FAIL —
main 2c729217 FAIL —
main 8d152b15 FAIL —
62feb7eb^ 8d152b15 PASS —

PyAutoArray#519's rotation-matrix rewrite of transform_grid_2d_to_reference_frame (commit
f45b30b0) is the sole mover. The three PyAutoGalaxy merges are bit-neutral.

Accuracy verdict

The fixture is exactly mirror-symmetric: the Isothermal lens centre is (0.1, 0.0), the
SersicSph source is at (0.0, 0.0), ell_comps=(0.0, 0.0) — both lie on x = 0. The new
transform is an exact identity at angle 0 (measured error 0.0; the old polar
cos/sin-of-arctan2 form carried 8.9e-16). Consequently the on-axis deflection alpha_x is now
exactly 0.0 where it was 6.1e-17. The point solver therefore hits an exact tie and its
tie-break selects the other branch, sending both images to the same side of the axis.

The new values are the more accurate branch — they come from an exact transform and an exact
on-axis zero. Nothing in the library is wrong; the pinned quantity is a knife-edge, not a physical
constant.

Knife-edge numbers

Fix

Test-only re-pin. Update the four literals in test_autolens/analysis/test_result.py
(0.0019501455 → 0.0019534291, 0.0097507278035 → 0.0097671455155, positions[1] x sign) at
the existing 1.0e-4 tolerances, and add a comment above each pin recording that the fixture is
exactly mirror-symmetric, that the branch is decided by sub-ULP tie-breaking, that PyAutoArray#519's
exact identity transform selected the other branch, and that a 1e-15 centre nudge flips it back.
No library change.

Follow-up suggestion

File separately: move the fixture off the symmetry axis (a small x offset on the lens centre, or a
non-zero ell_comps) so the pin measures a stable physical quantity rather than a solver
tie-break. As it stands the test will keep re-breaking on any floating-point-level change anywhere
in the transform/deflection chain.

Activity

  1. Jammy2211 commented on Sep 3, 2026

    @Jammy2211
    CollaboratorAuthor

    Bisect

    PyAutoLens held fixed at 6fbab3b52; PyAutoArray/PyAutoGalaxy swapped in detached scratch worktrees. 62feb7eb^ is the commit before PyAutoArray#519's merge; f45b30b0 inside it is the rotation-matrix rewrite of transform_grid_2d_to_reference_frame.

    PyAutoArray PyAutoGalaxy result positions_threshold_from()
    main main FAIL 0.0019534291030939357
    62feb7eb^ main PASS 0.0019501455607163743
    main 50599c2c FAIL —
    main 2c729217 FAIL —
    main 8d152b15 FAIL —
    62feb7eb^ 8d152b15 PASS —

    PyAutoArray#519 is the sole mover: the failure follows PyAutoArray alone and is indifferent to every PyAutoGalaxy merge of the day (50599c2c, 2c729217, 8d152b15 are all bit-neutral).

    Mechanism, measured:

    So the pinned quantity is a solver tie-break, not a physical constant, and the new values are the more accurate branch.

  2. Jammy2211 commented on Sep 3, 2026

    @Jammy2211
    CollaboratorAuthor

    Library PR created — corrective re-pin at PR-open

    PR: #722 (pending-release)

    Test-only. test_autolens/analysis/test_result.py — the four literals re-pinned to the exact-transform branch at the existing 1.0e-4 tolerances, with a comment above each pin recording the mirror symmetry, the sub-ULP tie-break, PyAutoArray#519 as the cause, and the 1e-15 flip-back. No library change.

    Gate evidence on the current library mains (PyAutoArray 7968d671, PyAutoGalaxy a647aa32):

    • pytest test_autolens/analysis/test_result.py -q → 14 passed
    • pytest test_autolens -n 4 -q → 610 passed, 1 xfailed

    Merge first so PyAutoLens main goes green; then /prm.

    Heart is RED and was human-acknowledged for PR-open on 2026-09-03; exact reasons from pyauto-heart readiness --json: "PyAutoLens: CI failure" (this PR is the human-authorized corrective PR for that reason); "release validation FAILED (stage integrate)"; "PyAutoArray: open PR 11d old". Never merge without the human.


    Generated by Claude Code

  3. Jammy2211 commented on Sep 3, 2026

    @Jammy2211
    CollaboratorAuthor

    Shipped

    PR #722 — MERGED (c6c2a06a9), test-only.

    Cause. PyAutoArray#519 (f45b30b0) made the grid transform an exact identity at angle 0 — the
    rotation that previously left an 8.9e-16 residual now returns the input bit-for-bit. On the symmetry
    axis the deflection is therefore exactly 0.0 rather than a denormal, and the position solver's
    tie-break picks the other branch. The two test_result.py pins moved by that flip, and by nothing else:

    • positions_threshold_from() 0.0019501455607 → 0.0019534291031 (+1.7e-3 relative)
    • positions[1].x — sign flip with bit-identical magnitude

    Evidence. A 6-cell bisect matrix across the candidate commits isolates PyAutoArray#519 f45b30b0;
    PyAutoGalaxy #599/#602/#603 are bit-neutral. It is a genuine knife edge: a 1e-15 x-nudge of the fixture
    flips the branch back, and a 1e-6 nudge moves the threshold by ×86. A pre-existing Isothermal.axis_ratio()
    clip at 0.99999 gives a 1.7e-6 bias against IsothermalSph — real, but unrelated to this move.

    test_autolens: 610 passed, 1 xfailed.

    Follow-up filed: move the fixture off the symmetry axis so the pin stops sitting on a tie-break
    (PyAutoMind draft/bug/autolens/positions_threshold_fixture_off_axis.md).

    Record: PyAutoMind complete/2026/09/positions-threshold-repin.md. PyAutoLens is pending-release.

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