Skip to content

feat: __solved_parameters__ protocol for model figures + Model cls fix (PyAutoLens#736) - #1615

Merged
Jammy2211 merged 1 commit into
mainfrom
feature/model-figures-lens
Sep 11, 2026
Merged

Jammy2211 merged 1 commit into
mainfrom
feature/model-figures-lens

Conversation

@Jammy2211

Copy link
Copy Markdown
Collaborator

Summary

Phase 3 of the model-figures epic, PyAutoFit half (PyAutoLens#736; phases 1–2: #1606, #1614). PyAutoFit cannot know which lens parameters a fit solves rather than samples, and solved_paths= could only re-tag rows that already exist — a linear light profile has no intensity slot at all. This PR adds a class-declared protocol: a class sets __solved_parameters__ = ("intensity",) and graph_spec appends a solved row for each declared name that is not a slot (re-tagging it when it is), with provenance solved-by-fit and in_model_info=False. No lens class name appears in PyAutoFit; PyAutoGalaxy and PyAutoArray declare the attribute on LightProfileLinear, PointSolved and Pixelization in the sibling PRs. Because the per-search model.png calls ModelPlotter(model) bare, it inherits the semantics automatically.

Also: solved_paths= is now additive (an unmatched path is synthesised on its owner, never silently ignored); rule R7 drops af.Model(cls) for any int/float subclass so a free Redshift renders as an ordinary pill on its galaxy card; the presentation shows name · solved and a footer N parameters solved during fitting; counts["solved"] added.

Bug fix found on the way: Model.constructor_argument_names filtered only self, so for a class with a custom __new__(cls, …) (autogalaxy.Redshift(float)) cls leaked in as a parameter and af.Model(Redshift) overwrote its own .cls with a ConfigException. The bound first argument is now dropped whether it is self or cls.

API Changes

Added the __solved_parameters__ class-attribute protocol consumed by af.GraphSpec / af.ModelPlotter; solved_paths= became additive; af.Model of an int/float subclass is a row on its owner in the figure; af.Model(cls) with a custom __new__ no longer mis-parses cls as a parameter. No symbol removed or renamed. See full details below.

Test Plan

  • test_autofit/graph_spec 66 passed (14 new in test_solved.py), test_autofit/model_figure 80 passed (4 new), test_autofit/non_linear/paths/test_model_figure_output.py 9 passed — serial.
  • Full test_autofit 2732 passed / 2 skipped; black + pyflakes clean.
  • Verified in the task worktree against the real autogalaxy.Redshift: af.Model(ag.Redshift).cls is ag.Redshift, config prior resolves, instance_from_prior_medians().redshift == 1.5.
  • CI: lib-tests 3.12 / 3.13 / no-jax, docs.
Full API Changes (for automation & release notes)

Added

  • Protocol: a class attribute __solved_parameters__: tuple[str, ...] on any modelled class; af.GraphSpec.from_model appends a solved row (provenance solved-by-fit, in_model_info=False) per declared name that is not a slot and re-tags a declared name that is.
  • Provenance.kind value solved-by-fit.
  • GraphSpec.counts["solved"] (solved scalars on the uncollapsed tree).
  • Presentation: name · solved pill text; footer phrase N parameter(s) solved during fitting.

Changed Behaviour

  • GraphSpec.from_model(..., solved_paths=): an entry matching no row is synthesised as a solved row on its owner node (root when the owner is not a component) instead of being ignored.
  • Rule R7 (Model(int)/Model(float) is a row on its owner) now applies to any int/float subclass (e.g. autogalaxy.Redshift).
  • Model.constructor_argument_names drops the bound first argument whether it is self or cls — fixes af.Model of a class with a custom __new__.

Migration

  • None. Downstream libraries opt in by declaring __solved_parameters__ on their classes (PyAutoArray / PyAutoGalaxy sibling PRs).

Generated by the PyAutoLabs agent workflow.

🤖 Generated with Claude Code

https://claude.ai/code/session_0178yLU9v19GtACcRPFggjGa

Model figures phase 3. A class can now declare the quantities a fit solves
for it -- `__solved_parameters__ = ("intensity",)` -- and graph_spec adds
them as `solved` rows (provenance `solved-by-fit`, absent from model.info)
without PyAutoFit knowing the class. `solved_paths=` is additive too: an
entry matching no row is synthesised on its owner instead of being ignored.
Rule R7 now drops `af.Model(cls)` for any int/float subclass, so a free
`Redshift` is a pill on its galaxy card rather than a one-pill child card.
The presentation shows `name · solved` pills and counts them in the footer.

Also fixes `Model.constructor_argument_names` leaking the bound `cls`
argument of a custom `__new__` into the parameter list, which made
`af.Model(Redshift)` overwrite its own `cls` with a ConfigException.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0178yLU9v19GtACcRPFggjGa
@Jammy2211 Jammy2211 added the pending-release PR queued for the next release build label Sep 11, 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.

1 participant