Search code examples
pythonconstraintscurve-fittingleast-squareslmfit

How can I bound an lmfit parameter based on another parameter such that param1 < 0.5*param2


I have attempted to follow the example given in the documentation of lmfit and produced this:

...
params.add(name="m", value=m_init, min=m_min, max=m_max)
params.add(name="mni_minus_m", value=1, vary=True, min=1e-12)
params.add(name="m_ni", expr='0.5*m + mni_minus_m')  # max value of m_ni is 0.5*m
...

This resides in a function that takes args of m_max, m_min, etc.

As you can probably tell, I'm hoping for m_ni to have its maximum set as half the value of m, but otherwise being freely able to vary anywhere between zero (preferably minimum 0.1) and whatever the maximum is. Setting a min= in the intermediary parameter was suggested in a similar question for reasons of float precision(?)

Unfortunately, it seems this has actually just glued the value of m_ni to 50% of m. This seems to be the case for everything I try to fit with this.

It's entirely possible that this happened because that's just what least-squares has decided it wants to do and this is actually correct syntax, but I'm not sure and would like to verify with anyone more competent than myself.

I'm also wondering how I would set an initial value for m_ni in this scenario, as it's not exactly clear to me.


Solution

  • I haven't used this library but it sounds like you want

    params.add(name="m", value=m_init, min=m_min, max=m_max)
    params.add(name="mni_factor", min=0, max=0.5)
    params.add(name="m_ni", expr='m * mni_factor')
    

    or maybe the last one could be

    params.add(name="m_ni", expr='m * mni_factor if m * mni_factor > 0.1 else 0.1')
    

    to get your 0.1 lower bound, but I'm not sure if that's actually good for optimization behavior :)