Skip to content

feat(autofit): multi-start gradient convergence results contract (phase 2)#1410

Merged
Jammy2211 merged 1 commit into
mainfrom
feature/multistart-gradient-convergence-results-phase-2
Jul 21, 2026
Merged

feat(autofit): multi-start gradient convergence results contract (phase 2)#1410
Jammy2211 merged 1 commit into
mainfrom
feature/multistart-gradient-convergence-results-phase-2

Conversation

@Jammy2211

Copy link
Copy Markdown
Collaborator

Summary

Phase 2 of 2 of the multi-start gradient auto-convergence work (phase 1: PyAutoFit#1407). The results contract: make the auto-convergence outcome inspectable and keep the max-likelihood/aggregator path robust to the variable-length, zero-weight/NaN-diagnostic-row results that early-stopping produces.

API Changes

Additive, plus one shared-Samples correctness fix. Added: converged / stop_reason / convergence / fom_history to the multi-start gradient samples_info; a figure_of_merit_vs_iteration MLE plotter (+ plots_search.yaml toggle) drawing the global-best figure-of-merit trace so the plateau is visible. Fixed: Samples.max_log_likelihood_index / max_log_posterior_index used np.argmax, which selects a NaN sample (argmax([2.5, nan, nan]) == 1) — the multi-start searches write their non-best starts as zero-weight NaN-log-likelihood diagnostic rows, so these returned the wrong index (inconsistent with max_log_likelihood_sample). Now np.nanargmax; only changes results where a NaN was present. No migration.
See full details below.

Test Plan

  • python -m pytest test_autofit/1525 passed, 1 skipped
  • New numpy-only tests: samples_info keys (converged/stop_reason/convergence/fom_history + legacy-search_internal + max_steps cases); variable-length zero-weight/NaN rows never select a NaN row and summarise without IndexError
  • figure_of_merit_vs_iteration renders a PNG with fom_history and no-ops without it
  • Curated smoke autofit_workspace/scripts/searches/mle.py runs end-to-end through the new samples_info path (exit 0)
  • autofit_workspace_test JAX round-trip (converged/stop_reason/trace through the results DB) — workspace follow-up after merge
Full API Changes (for automation & release notes)

Added

  • samples_info on multi-start gradient results now includes: converged: bool, stop_reason ("converged"|"max_steps"|None), convergence ({check_for_convergence, window, rtol, atol, min_steps}), fom_history (list of floats, the global-best figure-of-merit trace, or None for legacy runs).
  • autofit.non_linear.plot.figure_of_merit_vs_iteration(samples, …) — MLE plotter drawing the global-best figure-of-merit vs step; reads samples.samples_info["fom_history"], no-op when absent (LBFGS/Drawer).
  • config/visualize/plots_search.yamlmle.figure_of_merit_vs_iteration toggle (default true). The plot_results gate is default-on and tolerant of a config predating the key, so it never KeyErrors on an MLE fit in an older workspace.

Changed Behaviour

  • Samples.max_log_likelihood_index and Samples.max_log_posterior_index now use np.nanargmax (was np.argmax), so a NaN sample is never selected as the best. This fixes wrong-index selection on any search with NaN samples (the multi-start gradient searches' zero-weight diagnostic rows) and makes the properties consistent with max_log_likelihood_sample. Behaviour is unchanged where no sample is NaN. Fully-NaN sample lists return index 0.

Migration

  • None.

Validation checklist (--auto run — plan was not pre-approved)

  • Effective level: supervised (header: supervised, cap: feature@medium → safe; effective min = supervised)
  • Plan: on the issue (feat(autofit): multi-start gradient convergence results contract (phase 2) #1409), written at start, unmodified since
  • Gate: tests PASS (1525/1 skip; downstream n/a — no API removal) · smoke PASS (searches/mle.py) · review self-CLEAN (incl. the shared-Samples nanargmax fix, full suite green) · Heart RED — two pre-existing/unrelated reasons ("PyAutoFit: 2 commit(s) behind origin", "PyAutoLens: 1 uncommitted source change(s)"), human-waived contemporaneously via AskUserQuestion
  • Human: plan sound in hindsight?
  • Human: diff matches plan (nanargmax fix is in-scope for the zero-weight/NaN edge)?
  • Human: merge, amend, or reject — then log the outcome

Generated by the PyAutoLabs agent workflow.

…ood index

Phase 2 of the multi-start gradient auto-convergence work (phase 1: #1407).

- samples_info now carries converged, stop_reason, the convergence settings, and
  the fom_history trace (JSON-round-trippable) so the auto-convergence outcome is
  inspectable downstream.
- New figure_of_merit_vs_iteration MLE plotter draws the global-best figure-of-
  merit trace so the plateau can be seen; wired into plot_results behind a
  default-on, config-missing-tolerant gate (no-op for LBFGS/Drawer without a
  fom_history).
- Fix Samples.max_log_likelihood_index / max_log_posterior_index to use
  np.nanargmax: plain argmax selected the zero-weight NaN diagnostic rows the
  multi-start searches write, returning the wrong index (inconsistent with
  max_log_likelihood_sample). Only changes results where a NaN was present.
- Aggregator regression tests for variable-length + zero-weight/NaN rows.

Refs #1409.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LSEf7D5urqPgvffKBqzPsF
@Jammy2211 Jammy2211 added the pending-release PR queued for the next release build label Jul 21, 2026
@Jammy2211
Jammy2211 merged commit 5e434d1 into main Jul 21, 2026
5 checks passed
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