Tied Parameters Break in Compound Models Due to Name Mangling
- Dominant language
- Python
- Stars
- 5.3k
- Forks
- 2.2k
- Avg merge
- 1d 18h
- Merged PRs (30d)
- 74
Description
### Description
When using astropy.modeling, it’s possible to tie parameters within a custom model using lambda functions, e.g. param2.tied = lambda m: 0.5 * m.param1. This works as expected when the model is standalone.
However, if the same model is added to another (e.g., forming a compound model with model1 + model2), the parameter names are internally renamed (e.g., param1 → model_0_param1), and the original tie function no longer works, because it refers to attributes (m.param1) that no longer exist on the compound model.
### Expected behavior
In complex models with many parameters it would be great to be able to add and remove components without every time adjusting the links.
Is there a way to easily link (tie) parameters keeping the possibility to change the compound model later? Is the lambda approach the only one possible?
### How to Reproduce
```python
import numpy as np
from astropy.modeling import Fittable1DModel, Parameter, models, fitting
# --- Custom model with two tied amplitudes ---
class TwoGaussians(Fittable1DModel):
amp1 = Parameter(default=1.0)
amp2 = Parameter(default=0.5)
mean1 = Parameter(default=0.0)
mean2 = Parameter(default=2.0)
stddev1 = Parameter(default=1.0)
stddev2 = Parameter(default=1.0)
def evaluate(self, x, amp1, amp2, mean1, mean2, stddev1, stddev2):
g1 = amp1 * np.exp(-0.5 * ((x - mean1) / stddev1)**2)
g2 = amp2 * np.exp(-0.5 * ((x - mean2) / stddev2)**2)
return g1 + g2
# Create data
x = np.linspace(-5, 5, 100)
true_model = TwoGaussians(amp1=2.0, amp2=1.0, mean1=0.0, mean2=2.0, stddev1=0.5, stddev2=0.5)
y = true_model(x) + 0.1 * np.random.normal(size=len(x))
# --- First: tied parameters, works! ---
model = TwoGaussians()
model.amp2.tied = lambda m: 0.5 * m.amp1 # Tie works in standalone model
fitter = fitting.LevMarLSQFitter()
fit1 = fitter(model, x, y)
print("Standalone model fit:")
print(f"amp1 = {fit1.amp1.value:.3f}, amp2 = {fit1.amp2.value:.3f} (should be half of amp1)")
# --- Now: Add a constant model, tie breaks ---
compound = model + models.Const1D(amplitude=0.0)
# # Need to reset the tied parameter in the compound model to make it work!
# compound.amp2_0.tied = lambda m: 0.5 * m.amp1_0
try:
fit2 = fitter(compound, x, y)
print("\nCompound model fit:")
print(f"amp1 = {fit2.amp1_0.value:.3f}, amp2 = {fit2.amp2_0.value:.3f}")
except Exception as e:
print("\nCompound model fit failed with error:")
raise e
```
```
Standalone model fit:
amp1 = 1.986, amp2 = 0.993 (should be half of amp1)
Compound model fit failed with error:
Attribute "amp1" not found
```
### Versions
_No response_
Contributor guide
Research direction
Start by running the reproduction in the issue and inspect astropy.modeling's compound-model parameter renaming and tied-parameter handling. Done means a tie defined on a standalone model remains usable after that model is composed, with regression coverage for the shown failure and the existing fitting behavior preserved.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100