问题
I have a piece of code that I am using scipy.integrate.quad. The limits of integration are minus infinity to infinity. It runs OK, but I would like it faster.
The nature of the problem is that the function being integrated is the product of three functions: (1) one that is narrow (between zero and (2) one that is wide (between, say, 200,000 and 500,000), and (3) one that falls off as 1/abs(x).
I only need accuracy to .1%, if that.
I could do a lot of work and actually determine integration limits that are real numbers so no excess computation gets done; outside the regions of functions 1 and 2 they are both zero, so the 1/x doesn't even come into play there. But it would be a fair amount of error-prone code calculations.
How does this function know how to optimize, and is it pretty good at it, with infinite bounds?
Can I tune it through passing in guidance (like error tolerance)?
Or, would it be worthwhile to try to give it limited integration bounds?
回答1:
quad
uses different algorithms for finite and infinite intervals, but the general idea is the same: the integral is computed using two related methods (for example, 7-point Gauss rule and 15-point Kronrod rule), and the difference between those results provides an estimate for how accurate they are. If the accuracy is low, the interval is bisected and the process repeats for subintervals. A detailed explanation is beyond the scope of a Stack Overflow answer; numerical integration is complicated.
For large or infinite integration bounds, the accuracy and efficiency depend on the algorithm being able to locate the main features of the function. Passing the bounds as -np.inf, np.inf
is risky. For example,
quad(lambda x: np.exp(-(x-20)**2), -np.inf, np.inf)
returns a wrong result (essentially zero instead of 1.77) because it does not notice the bump of the Gaussian function near 20.
On the other hand, arbitrarily imposing a finite interval is questionable in that you give up any control over error (no estimate on what was contained in the infinite tails that you cut off). I suggest the following:
Split the integral into three:
(-np.inf, A)
,(A, B)
, and(B, np.inf)
where, say, A is -1e6 and B is 1e6.For the integral over
(A, B)
, providepoints
parameter, which locates the features ("narrow parts") of the function. For example,quad(lambda x: np.exp(-(x-20)**2), -1e6, 1e6, points=[10, 30])
returns 1.77 as it should.
Adjust
epsabs
(absolute error) andepsrel
(relative error) to within desired accuracy, if you find that the default accuracy is too demanding.
来源:https://stackoverflow.com/questions/49738870/how-does-scipy-integrate-quad-know-when-to-stop