I have a lot of data to integrate over and would like to find a way of doing it all with just matrices, and would be willing to compromise on accuracy for a performance boos
vectorize
won't provide help with improving the performance of code that uses quad
. To use quad
, you'll have to call it separately for each component of the value returned by integrate
.
For a vectorized but less accurate approximation, you can use numpy.trapz or scipy.integrate.simps.
Your function definition (at least the one shown in the question) is implemented using numpy functions that all support broadcasting, so given a grid of x
values on [0, 1], you can do this:
In [270]: x = np.linspace(0.0, 1.0, 9).reshape(-1,1)
In [271]: x
Out[271]:
array([[ 0. ],
[ 0.125],
[ 0.25 ],
[ 0.375],
[ 0.5 ],
[ 0.625],
[ 0.75 ],
[ 0.875],
[ 1. ]])
In [272]: integrand(x)
Out[272]:
array([[ 0. , 0. , 0. ],
[ 0.01757812, 0.03515625, 0.05273438],
[ 0.078125 , 0.15625 , 0.234375 ],
[ 0.19335938, 0.38671875, 0.58007812],
[ 0.375 , 0.75 , 1.125 ],
[ 0.63476562, 1.26953125, 1.90429688],
[ 0.984375 , 1.96875 , 2.953125 ],
[ 1.43554688, 2.87109375, 4.30664062],
[ 2. , 4. , 6. ]])
That is, by making x
an array with shape (n, 1), the value returned by integrand(x)
has shape (n, 3)
. There is one column for each value in a
.
You can pass that value to numpy.trapz()
or scipy.integrate.simps()
, using axis=0
, to get the three approximations of the integrals. You'll probably want a finer grid:
In [292]: x = np.linspace(0.0, 1.0, 101).reshape(-1,1)
In [293]: np.trapz(integrand(x), x, axis=0)
Out[293]: array([ 0.583375, 1.16675 , 1.750125])
In [294]: simps(integrand(x), x, axis=0)
Out[294]: array([ 0.58333333, 1.16666667, 1.75 ])
Compare that to repeated calls to quad
:
In [296]: np.array([quad(lambda t: integrand(t)[k], 0, 1)[0] for k in range(len(a))])
Out[296]: array([ 0.58333333, 1.16666667, 1.75 ])
Your function integrate
(which I assume is just an example) is a cubic polynomial, for which Simpson's rule gives the exact result. In general, don't expect simps
to give such an accurate answer.
quadpy (a project of mine) is fully vectorized. Install with
pip install quadpy
and then do
import numpy
import quadpy
def integrand(x):
return [numpy.sin(x), numpy.exp(x)] # ,...
res, err = quadpy.quad(integrand, 0, 1)
print(res)
print(err)
[0.45969769 1.71828183]
[1.30995437e-20 1.14828375e-19]