Tying parameters in astropy.modeling

Viewed 540

I am trying to use the Model.tied (or Parameter.tied) attribute in astropy.modelling, but can't seem to figure out how it works. For example, let's say I wanted to create a compound model with two parameters: flux_0 and flux_1. However, I only want flux_0 to be used in fitting: flux_1 should always carry the value 1 - flux_0. (Eventually, I need to extend this functionality so that flux_0 + flux_1 + ... + flux_n = 1.)

I define a model class and a "callable" for the tied attribute like so:

>>> from astropy.modeling import Fittable1DModel, Parameter
>>>
>>> class MyModel(Fittable1DModel):
...     flux = Parameter()
...     @staticmethod
...     def evaluate(x, flux):
...         return flux
...
>>> def tie_fluxes(model):
...     flux_1 = 1 - model.flux_0
...     return flux_1
...
>>> TwoModel = MyModel + MyModel
>>>
>>> TwoModel
<class '__main__.CompoundModel0'>
Name: CompoundModel0
Inputs: ('x',)
Outputs: ('y',)
Fittable parameters: ('flux_0', 'flux_1')
Expression: [0] + [1]
Components:
    [0]: <class '__main__.MyModel'>
    Name: MyModel
    Inputs: ('x',)
    Outputs: ('y',)
    Fittable parameters: ('flux',)

    [1]: <class '__main__.MyModel'>
    Name: MyModel
    Inputs: ('x',)
    Outputs: ('y',)
    Fittable parameters: ('flux',)

Then I inspect the tied attribute. My understanding is that this should be a dictionary (see footnote), but it is not:

>>> TwoModel.tied
<property object at 0x109523958>
>>>
>>> TwoModel.tied['flux_1'] = tie_fluxes
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'property' object does not support item assignment

If I try to set it as a dictionary, it does not update the appropriate Parameter:

>>> TwoModel.tied = {'flux_1': tie_fluxes}
>>>
>>> TwoModel.flux_1.tied
False

But when I try creating an object right off the bat instead of a compound model class (this is not what I want to do in the end), the object's tied attribute is a dictionary. Unfortunately, setting this dictionary still does not produce the desired effect:

>>> TwoSetModel = MyModel(0.2) + MyModel(0.3)
>>>
>>> TwoSetModel
<CompoundModel1(flux_0=0.2, flux_1=0.3)>
>>>
>>> TwoSetModel.tied
{'flux_1': False, 'flux_0': False}
>>>
>>> TwoSetModel.tied['flux_1'] = tie_fluxes
>>>
>>> TwoSetModel
<CompoundModel1(flux_0=0.2, flux_1=0.3)>
>>>
>>> TwoSetModel.flux_1.tied
<function tie_fluxes at 0x102987730>

So in this example, the tied attribute does hold the correct function, but the parameter's value does not update accordingly.

What am I doing wrong here? Am I completely misunderstanding the tied attribute?

(I am using Python 3.5.2 with Astropy 1.3.3 in the above examples)


Footnote:

Running help(TwoModel), I get the following information:

⁝
 |  tied : dict, optional
 |      Dictionary ``{parameter_name: callable}`` of parameters which are
 |      linked to some other parameter. The dictionary values are callables
 |      providing the linking relationship.
 |
 |      Alternatively the `~astropy.modeling.Parameter.tied` property of a
 |      parameter may be used to set the ``tied`` constraint on individual
 |      parameters.
⁝
 |  Examples
 |  --------
 |  >>> from astropy.modeling import models
 |  >>> def tie_center(model):
 |  ...         mean = 50 * model.stddev
 |  ...         return mean
 |  >>> tied_parameters = {'mean': tie_center}
 |
 |  Specify that ``'mean'`` is a tied parameter in one of two ways:
 |
 |  >>> g1 = models.Gaussian1D(amplitude=10, mean=5, stddev=.3,
 |  ...                        tied=tied_parameters)
 |
 |  or
 |
 |  >>> g1 = models.Gaussian1D(amplitude=10, mean=5, stddev=.3)
 |  >>> g1.mean.tied
 |  False
 |  >>> g1.mean.tied = tie_center
 |  >>> g1.mean.tied
 |  <function tie_center at 0x...>
⁝
1 Answers
Related