Skip to content

perf: back off the fnnls warm-start memo on scattered evaluation streams - #615

Merged
Jammy2211 merged 1 commit into
mainfrom
feature/nnls-memo-scattered-backoff
Oct 7, 2026
Merged

Jammy2211 merged 1 commit into
mainfrom
feature/nnls-memo-scattered-backoff

Conversation

@Jammy2211

Copy link
Copy Markdown
Collaborator

Summary

The fnnls passive-set warm-start memo judges a seed only after the seeded solve has run, so on a scattered (iid) evaluation stream every other solve paid for a bad seed (autolens_profiling#332: ALMA Delaunay solve 2.17x slower with the memo on).

This adds a per-key exponential back-off in nnls_memo: after 2 consecutive seeded-solve fallbacks, the next 1, 2, 4, ... (cap 32) would-be-seeded solves start dense (still refreshing the entry). Each backed-off dense solve also checks, for free, whether the seed it skipped would have passed the guard; if so the remaining skips are cancelled, so a stream that turns local regains the memo after one solve. An accepted real seed resets the streak. A local walk never falls back twice in a row, so its path and every reconstruction are unchanged. No config keys or tolerances change.

Local witness (n=576, solver-only, min of 3, 3 seeds, 64 solves): iid on/off 1.49x -> 1.17x; walk 0.18x -> 0.18x; iid->walk phase recovery 0.69x.

Closes #613

API Changes

None to the public modelling API — internal solver behaviour only. Adds a new warm_start_backoff key to the positive-only solver stats dict and a nnls_memo.memo_clear() helper that clears memo entries and back-off state together (harnesses that clear _nnls_passive_set_memo directly now leave back-off state behind; see Downstream notes).
See full details below.

Test Plan

  • Full PyAutoArray suite after rebase onto main: pytest test_autoarray/ — 1975 passed, 4 xfailed
  • New test_autoarray/inversion/inversion/test_nnls_memo.py (back-off schedule, streak reset, shadow-check recovery, local walk unchanged)
  • Real Nautilus-replay witness — NOT a merge gate (human decision); tracked as a follow-up on perf: back off the fnnls warm-start memo on scattered evaluation streams #613

Readiness (Heart)

Heart verdict YELLOW, acknowledged by the human for this ship. Reasons verbatim from pyauto-heart readiness --json:

  • autogalaxy_workspace: open PR 7d old
  • autolens_workspace: open PR 7d old
  • euclid_strong_lens_modeling_pipeline: open PR 7d old
  • release validation stale: source moved since rehearsal (PyAutoNerves)

Downstream notes

  • No workspace script references the changed symbols (workspace impact: none, option iii).
  • autolens_profiling harnesses (fixed_light_numba.py, delaunay_numba_nnls_iterations.py, fixed_light_numpy_solvers.py, fixed_light_s4b_checks.py) clear nnls_memo._nnls_passive_set_memo directly; they should switch to nnls_memo.memo_clear() so back-off state does not leak between rows. _production_config.py prose cites nnls_memo.py:63, which shifts with this PR (cosmetic). Follow-up noted on perf: back off the fnnls warm-start memo on scattered evaluation streams #613.
Full API Changes (for automation & release notes)

Added

  • autoarray.inversion.inversion.nnls_memo.memo_clear() — clears passive-set entries and back-off state together
  • nnls_memo.BackoffState, nnls_memo.backoff_should_skip(key), backoff_record_fallback(key), backoff_end_skip(key), backoff_record_accept(key), seed_error_fraction(seed_passive_set, passive_set, n) — internal back-off helpers
  • stats["warm_start_backoff"] — new key in the stats dict filled by reconstruction_positive_only_from (True when the memo seed was skipped by back-off)

Changed Behaviour

  • reconstruction_positive_only_from (memo on): after 2 consecutive seed fallbacks for a key, the next 1, 2, 4, ... (cap 32) would-be-seeded solves start dense; reconstructions are unchanged (dense and seeded starts converge to the same NNLS solution), only the start/iteration path differs.

Generated by the PyAutoLabs agent workflow.

🤖 Generated with Claude Code

The passive-set memo's fallback guard judges a seed only after the seeded
solve has run, so on a scattered (iid) stream every other solve paid for a
bad seed (autolens_profiling#332: alma Delaunay solve 2.17x slower memo-on).

Add a per-key back-off in nnls_memo: after 2 consecutive seeded-solve
fallbacks the next 1, 2, 4, ... (cap 32) would-be-seeded solves start dense
(still refreshing the entry). Each backed-off dense solve also checks, for
free, whether the seed it skipped would have passed the guard against it
(symmetric difference with the final passive set == warm_start_errors); if
so the remaining skips are cancelled, so a stream that turns local regains
the memo after one solve. An accepted real seed resets the streak. A local
walk never falls back twice in a row, so its path and every reconstruction
are unchanged. New stats key warm_start_backoff; memo_clear() clears entries
and back-off state together. No config keys or tolerances change.

Local witness (n=576, solver-only, min of 3, 3 seeds, 64 solves): iid
on/off 1.49x -> 1.17x; walk 0.18x -> 0.18x; iid->walk phase recovery 0.69x.

Refs #613

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S11WE9oj7Mvkfhc4EPBnyN
@Jammy2211 Jammy2211 added the pending-release PR queued for the next release build label Oct 7, 2026
@Jammy2211
Jammy2211 merged commit 58bdda0 into main Oct 7, 2026
3 checks passed
@Jammy2211
Jammy2211 deleted the feature/nnls-memo-scattered-backoff branch October 7, 2026 06:43
@Jammy2211 Jammy2211 removed the pending-release PR queued for the next release build label Oct 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

perf: back off the fnnls warm-start memo on scattered evaluation streams

1 participant