Skip to content

modeling: tied expressions that depend on other tied parameters see stale values during fitting #20710

Open

Description

@tepickering

Description

When a tied expression refers to another tied parameter,
fitter_to_model_params_array (used by all the non-linear fitters) evaluates it
with the value of that parameter from the previous call, rather than the value
that was just computed.

In the tied-parameter loop each new value is written into the local
parameters array and then model._array_to_parameters() is called:

https://github.com/astropy/astropy/blob/dbbf2acd6d/astropy/modeling/fitting.py#L2226-L2238

_array_to_parameters() re-reads model._parameters, which is not the local
array (the model.parameters setter copies into it), so the new tied value
never reaches the model before the next tied expression is evaluated. The
comment there ("To handle multiple tied constraints, model parameters need to
be updated after each iteration") suggests this was meant to work.

As a result, during fitting the objective function evaluated at a given set of
free parameters depends on the previous evaluation. Fits generally still end up
satisfying the tie, since the lag disappears once the free parameters stop
changing, but the function seen by the optimizer, and its finite-difference or
analytic Jacobian, are not consistent with each other.

Expected behavior

Tied values should be applied in order, so that a tied expression sees the
updated values of tied parameters that precede it in model.param_names.
A single call of fitter_to_model_params should give the same result as two.

How to Reproduce

from astropy.modeling import fitting, models

model = models.Gaussian1D(3, 1.0, 0.5) + models.Gaussian1D(1, 2.0, 0.5)
model.amplitude_1.tied = lambda m: 2 * m.amplitude_0
# mean_1 depends on amplitude_1, which is itself tied
model.mean_1.tied = lambda m: m.mean_0 + 0.1 * m.amplitude_1

free, _, _ = fitting.model_to_fit_params(model)
fitting.fitter_to_model_params(model, free)
print(model.amplitude_1.value, model.mean_1.value)  # expected 6.0 1.6
fitting.fitter_to_model_params(model, free)
print(model.amplitude_1.value, model.mean_1.value)

Output:

6.0 1.1
6.0 1.6

A likely fix is to assign the updated array back to the model
(model.parameters = parameters) instead of calling
model._array_to_parameters(), but since that changes what the fitters see I
thought it best to report it separately. Found while working on #20664 (the fix
there is consistent with the current behavior and does not depend on this).

Versions

platform.platform() = 'Linux-7.3.0-5-cachyos-x86_64-with-glibc2.44'
platform.python_version() = '3.13.16'

astropy              main @ dbbf2acd6d
numpy                2.5.4
scipy                1.18.1
pyerfa               2.0.1.5

AI disclosure: this report was drafted with the help of Claude Code (Claude Opus 5.5), which also found the bug while working on #20664; I have checked the reproduction and the analysis.

Activity

  1. Onkar-Raskar commented on Oct 26, 2026

    @Onkar-Raskar
    Contributor

    @tepickering , I would like to work on issue, i have reproduced it locally.

    Image
  2. Onkar-Raskar commented on Oct 27, 2026

    @Onkar-Raskar
    Contributor

    @tepickering , can you review my pr and let me know if any changes required.

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions