I'd like SciPy to solve the following problem for me:
import numpy as np
from numpy import exp, sqrt
import scipy.integrate
import scipy.optimize
def F(x, theta, mu, sigma, r):
#equation 1
def integrand(u):
return u**(r/mu - 1) * exp(sqrt(2*mu / sigma**2) * (x-theta)*u - u**2/2)
return scipy.integrate.quad(integrand, 1e-5, np.inf)[0]
def Prime(f, x, theta, mu, sigma, r, h=1e-5):
# given f, estimates f'(x) using the difference quotient formula
return (f(x+h, theta, mu, sigma, r) - f(x, theta, mu, sigma, r)) / h
def b_star(theta, mu, sigma, r, c):
#equation 2
def func(b):
return F(b, theta, mu, sigma, r) - (b-c)*Prime(F, b, theta, mu, sigma, r)
return scipy.optimize.brentq(func, -2, 3)
b_star(0.573085, 3.213728, 0.5, 0, 0.001) # 0.7714361802263615
This corresponds with the following equations:
,
in which I solve the last equation for b.
This seems to work most of the time; however, in some circumstances the following error occurs:
In: b_star(0.573085,3.213728,0.137655,0,0.001)
Out:
---------------------------------------------------------------------------
OverflowError Traceback (most recent call last)
<ipython-input-164-1aeb31cb3219> in <module>
----> 1 b_star(0.573085,3.213728,0.137655,0,0.001)
<ipython-input-163-14ce7e008b20> in b_star(theta, mu, sigma, r, c)
38 return F(b, theta, mu, sigma, r) - (b-c)*Prime(F, b, theta, mu, sigma, r)
39
---> 40 return so.brentq(func, -2, 3)
41
42 def V(x, theta, mu, sigma, r, c):
/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/scipy/optimize/zeros.py in brentq(f, a, b, args, xtol, rtol, maxiter, full_output, disp)
778 if rtol < _rtol:
779 raise ValueError("rtol too small (%g < %g)" % (rtol, _rtol))
--> 780 r = _zeros._brentq(f, a, b, xtol, rtol, maxiter, args, full_output, disp)
781 return results_c(full_output, r)
782
<ipython-input-163-14ce7e008b20> in func(b)
36
37 def func(b):
---> 38 return F(b, theta, mu, sigma, r) - (b-c)*Prime(F, b, theta, mu, sigma, r)
39
40 return so.brentq(func, -2, 3)
<ipython-input-163-14ce7e008b20> in F(x, theta, mu, sigma, r)
18 def integrand(u):
19 return u**(r/mu - 1) * exp(sqrt(2*mu / sigma**2) * (x-theta)*u - u**2/2)
---> 20 return si.quad(integrand, 1e-5, np.inf)[0]
21
22 def G(x, theta, mu, sigma, r):
/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/scipy/integrate/quadpack.py in quad(func, a, b, args, full_output, epsabs, epsrel, limit, points, weight, wvar, wopts, maxp1, limlst)
339
340 if weight is None:
--> 341 retval = _quad(func, a, b, args, full_output, epsabs, epsrel, limit,
342 points)
343 else:
/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/scipy/integrate/quadpack.py in _quad(func, a, b, args, full_output, epsabs, epsrel, limit, points)
453 return _quadpack._qagse(func,a,b,args,full_output,epsabs,epsrel,limit)
454 else:
--> 455 return _quadpack._qagie(func,bound,infbounds,args,full_output,epsabs,epsrel,limit)
456 else:
457 if infbounds != 0:
<ipython-input-163-14ce7e008b20> in integrand(u)
17 # equation 3.3
18 def integrand(u):
---> 19 return u**(r/mu - 1) * exp(sqrt(2*mu / sigma**2) * (x-theta)*u - u**2/2)
20 return si.quad(integrand, 1e-5, np.inf)[0]
21
OverflowError: math range error
I tried several solutions like using the Decimal package or the gmpy package to allow for bigger floating point numbers, but the output becomes 0.0 in those cases.
I also tried converting the inputs to a np.float128
datatype, but this didn't solve the problem either.
Is there a fix for this?
As @BoarGules notes, the argument to
exp
is too large and the result overflows.Running your code verbatim except for the replacement:
reveals that there is a root near
0.5636522268679528
. This is not bigger thantheta
, but you can check for yourself that it is a root of the provided equation.If you can't tighten the bracket you provide to
brentq
, you can usempmath
to avoid overflow, replacing calls toscipy.integrate.quad
andscipy.optimize.brentq
withmpmath
'squad
andfindroot
.You can also replace your implementation of
Prime
with use ofmpmath
'sdiff
for a more accurate derivative:There are ways of performing this calculation in log-space with SciPy, but the
mpmath
solution is more straightforward.