Python scipy.optimize: Using fsolve with multiple first guesses

23,829

Doing this might make you miss something important, but, to silence the warning message you could use warnings.filterwarnings:

import warnings
warnings.filterwarnings('ignore', 'The iteration is not making good progress')
import math
from scipy.optimize import fsolve
import numpy as np
def p(s, l, k, q):
    p = q * np.maximum(s - k, 0.0)
    return (p + math.copysign(l, -q)) * math.fabs(q) * 100.0

x0 = fsolve(p, np.arange(33.86, 50.86, 1.0),
            args=(1.42, 41.0, -1.0), xtol=1e-06, maxfev=500)
print(x0)

In fact, p(x0, 1.42, 41.0, -1) is not close to zero, so fsolve is correctly warning you that it failed to find a solution.


PS. When you say

fsolve(p, np.arange(33.86, 50.86, 1.0),...)

you are telling fsolve that your initial guess for s is the numpy array np.arange(33.86, 50.86, 1.0). The whole array is being passed in to p at once.

Notice that np.arange(33.86, 50.86, 1.0) has length 17 and so does x0. That is because fsolve thinks it is looking for an array of length 17 that solves p.

I think perhaps you meant s to be a float? In that case, you can only pass in one float value for your initial guess:

fsolve(p, 41.0, args = (1.42, 41.0, -1.0), xtol=1e-06, maxfev=500)

For example,

import math
import scipy.optimize as optimize
import numpy as np

def p(s, l, k, q):
    p = q * np.maximum(s - k, 0.0)
    return (p + math.copysign(l, -q)) * math.fabs(q) * 100.0

args = (1.42, 41.0, -1.0)
result = optimize.fsolve(p, 41.0, args=args, xtol=1e-06, maxfev=500)
print(result)

yields

[ 42.42]

fsolve does a decent job of zeroing-in on the root if the initial guess is >= 41.0 (the value of k) but fails when the initial guess is < 41.0.

My guess is that this is due to np.maximum not changing for many guesses for s. So fsolve does not know whether to increase or decrease s and is apt to guess wrong and move s farther and farther from the root.

Share:
23,829
Jason Strimpel
Author by

Jason Strimpel

Passionate technologist and experienced leader. My super power is found at the intersection of engineering, sales and leadership.

Updated on September 17, 2020

Comments

  • Jason Strimpel
    Jason Strimpel over 3 years

    Scipy version 0.10.0

    Consider the following:

    >>> import math
    >>> from scipy.optimize import fsolve
    >>> import numpy as np
    >>> def p(s, l, k, q):
        p = q * np.maximum(s - k, 0.0)
        return (p + math.copysign(l, -q)) * math.fabs(q) * 100.0
    
    >>> x0 = fsolve(p, np.arange(33.86, 50.86, 1.0), args=(1.42, 41.0, -1.0), xtol=1e-06, maxfev=500)
    Warning (from warnings module):
      File "C:\Python27\lib\site-packages\scipy\optimize\minpack.py", line 152
        warnings.warn(msg, RuntimeWarning)
    RuntimeWarning: The iteration is not making good progress, as measured by the 
       improvement from the last ten iterations.
    >>> print x0
    [ -4.87169392e+05  -4.87168392e+05  -4.87167392e+05  -4.87166392e+05
      -4.87165392e+05  -4.87164392e+05  -4.87163392e+05  -4.87162392e+05
       4.24200000e+01   4.24200000e+01   4.24200000e+01   4.24200000e+01
       4.24200000e+01   4.24200000e+01   4.24200000e+01   4.24200000e+01
       4.24200000e+01]
    

    First question is how one might suppress the warning message that's being returned?

    Second, why might this error be generated in the first place (other than the obvious, that the iteration is not making good progress :) )?

    Finally, the root of this function is 42.42 (which is found). Why is fzero returning -4.87e+05 as well?