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?
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With