Fitting with entangled constraints

20 views
Skip to first unread message

Raphael Moreau (Kharkai)

unread,
Sep 9, 2024, 1:55:54 PM9/9/24
to lmfit-py
Hello,

I am trying to fit a signal with a combination of signatures following something like this:
y(x) = a * A(x) + b * B(x) + c * C(x) with the specific constraints of having b to 0 if c is not, and similarly having c to 0 if b is not, meaning that if contribution of B is 'used' then C is not and vice versa.

My very first question is: is such a problem actually have solution (from a mathematical point of view) or it it not possible ?

My code is the following and (obviously) it doesn't work, where I was trying to used literal constraints capabilities through 'expr':
A = np.array(whatever)
B = np.array(whatever)
B = np.array(whatever)
def fnc(x, a, b, c, K):
   vector = np.vectorize(np.int_)
   y = a * A[vector(x)] + b * B[vector(x)] + c * B[vector(x)] + K
   return y
model = Model(fnc, prefix='model_')

params = Parameters()
params.add('coeff_a', value=0.0, min=0.0)

params.add('coeff_b', value=0.0, min=0.0, expr='vary = False if c > 0.0 ')
params.add('coeff_c', value=0.0, min=0.0, expr='vary = False if b > 0.0 ')
params.add('B', value=0.0, min=0.0, max=1.0)

out = model.fit(data_to_fit[x1:x2], params, x=np.arange(x1, x2, 1))

What should I change to solve such a question? Is the approach using the 'expr' parameter correct and I simply didn't wrote it correctly, or should a different approach be used ?

I am rather new to this kind of problematic so apologies if my question is poorely formulated or if it is a trivial question, thanks in advance from France.

Best regards,
Raphael



Matt Newville

unread,
Sep 11, 2024, 10:42:10 PM9/11/24
to lmfi...@googlegroups.com
Hi Raphael,

On Mon, Sep 9, 2024 at 10:55 AM Raphael Moreau (Kharkai) <raph...@gmail.com> wrote:
Hello,

I am trying to fit a signal with a combination of signatures following something like this:
y(x) = a * A(x) + b * B(x) + c * C(x) with the specific constraints of having b to 0 if c is not, and similarly having c to 0 if b is not, meaning that if contribution of B is 'used' then C is not and vice versa.

My very first question is: is such a problem actually have solution (from a mathematical point of view) or it it not possible ?

I think the answer might be "no", or at least "not easily".  One difficulty is that "is 0" and "is not 0" does not mention the order of magnitude.  That is, 1.e-100 is kind of infinitely far from zero.   The fit doesn't know if b=1.e-6 is miniscule or enormous - does that count as zero?

Another challenge is that using b or c as discrete values such as
     if b < 1.e-8:
          y = a * A(x) + c * C(x) + K
     else:    
          y = a * A(x) + b * B(x) + K

may not work well either, as the derivative is for `b` and `c` will have sharp transitions.  

Using a sigmoidal function that smoothly transitions from 0 to 1 over some range of value, might work, such as
    from scipy.special import erf
    def fnc(x, a, b, c, K):
            y_c  = c * C(x)
            y_b = b * B(x)
            b0 = 1.e-8                    # what you expect "0" to mean ....not sure what this should be!
            ramp = erf((b-b0 )/b0)  #  you may want to scale this to set "how wide" the transition from -1 to 1 is. 
            return a * A(x) + K + y_b * (1+ramp)/2.0  + y_c * (1-ramp)/2.0


That will turn b*B(x) and c*C(x) on and off slowly and might work better,  


>  params.add('coeff_b', value=0.0, min=0.0, expr='vary = False if c > 0.0 ')

That expression won't work: expressions need to give a floating point value.


> def fnc(x, a, b, c, K):
>   vector = np.vectorize(np.int_)
>   y = a * A[vector(x)] + b * B[vector(x)] + c * B[vector(x)] + K
>   return y

I don't understand the use of `np.vectorize` here.  What are you trying to do?   I strongly encourage you to just use plain numpy arrays.

 --Matt 
Reply all
Reply to author
Forward
0 new messages