Cubature (cubature
)¶
There is one function that embodies all functionalities offered by Cubature.
One of the nice things about Cubature is that you can perform multi-dimensional integrations at once, which can be achieved by defining:
ndim
xmin
xmax
There are two types of refinement in the integration methods, both necessary to achieve a desired integration error threshold:
h
additional integration points are addedp
the order of the integration polynomials is increased
It allows the evaluation of vectorized functions, making it convenient to take
advantage of NumPy’s speed (see examples with vectorized=True
).
See the detailed description below on how to use a vector valued fuction (function that returs an array) or a scalar function.
- cubature.cubature(func, ndim, fdim, xmin, xmax, args=(), kwargs={}, abserr=1e-08, relerr=1e-08, norm=0, maxEval=0, adaptive='h', vectorized=False)[source]¶
Numerical-integration using the cubature method.
- Parameters:
- funccallable
- If
vectorized=False
the callable must have the form: f(x_array, *args, **kwargs)
where:
x_array
in an array containing thendim
variablesbeing integrated
args
is a tuple containing any other arguments required by the functionkwargs
is a dict containing any keyword arguments required by the functionthe function must return a 1-D
np.ndarray
objectexample 1, vector valued function:
fdim = 3 def func(x_array, *args, **kwargs): # note that here ndim=2 (2 variables) x, y = x_array return np.array([x**2-y**2, x*y, x*y**2])
example 2, scalar function:
fdim = 1 def func(x_array, *args, **kwargs): # note that here ndim=2 (2 variables) x, y = x_array return x**2-y**2
- If
vectorized=True
the function must have the form: f(x_array, *args, **kwargs)
where:
x_array
hasshape=(npt, ndim)
args
is a tuple containing any other arguments required by the functionkwargs
is a dict containing any keyword arguments required by the functionexample 1, vector valued function:
# function that returns a vector with 3 values fdim = 3 def func(x_array, *args, **kwargs): # note that here ndim=2 (2 variables) x = x_array[:, 0] y = x_array[:, 1] npt = x_array.shape[0] out = np.zeros((npt, fdim)) out[:, 0] = x**2 - y**2 out[:, 1] = x*y out[:, 2] = x*y**2 return out
example 2, scalar function:
fdim = 1 def func(x_array, *args, **kwargs): # note that here ndim=3 (3 variables) x = x_array[:, 0] y = x_array[:, 1] z = x_array[:, 2] return x**2 + y**2 + z**2
The results from both vectorized and non-vectorized examples above should be the same, but the vectorized implementation is much faster since it will take advantage of NumPy’s vectorization capabilities.
- If
- ndiminteger
Number dimensions or number of variables being integrated.
- fdiminteger
Length of the output vector given by
func
. It should be1
if the function returns a scalar.- xmin, xmaxarray-like
These are 1-D arrays with the minimum and maximum integration limits for each variable being integrated. In cubature, if you are using
vectorized=True
, it is also possible to have one integration limit per value in the vector-valued function.If
vectorized=False
:xmin, xmax
are vectors with the integration limits for each of thendim
dimensions, thus we must assert thatxmin.shape[0] == ndim
.
If
vectorized=True
:xmin, xmax
are vectors with the integration limits for each of thendim
dimensions. Withvectorized=True
it is possible to use one integration limit per value in the vector-valued function. In this case, we must assert thatxmin.shape[0] == ndim*fdim
. Here, the limits are read in the orderxmin[i*ndim + j]
, meaning the j-th dimension of the i-th element of the vector-valued function.
- argstuple or list, optional
Contains the extra arguments required by
func
.- kwargsdict-like, optional
Contains the extra keyword arguments passed to
func
.- adaptivestring, optional
The adaptive scheme used along the adaptive integration:
‘h’ means ‘h-adaptive’, where the domain is partitioned
‘p’ means ‘p-adaptive’, where the order of the integration rule is increased
The ‘p-adaptive’ scheme is often better for smoth functions in low dimensions.
- abserrdouble, optional
Integration stops when estimated absolute error is below this threshold
- relerrdouble, optional
Integration stops when estimated error in integral value is below this threshold
- norminteger, optional
Specifies the norm that is used to measure the error and determine convergence properties (irrelevant for single-valued functions). The
norm
argument takes one of the values:- 0 for ERROR_INDIVIDUAL: convergence is achieved only when each
integrand individually satisfies the requested error tolerances;
- 1 for ERROR_PAIRED: like ERROR_INDIVIDUAL, except that the
integrands are grouped into consecutive pairs, with the error tolerance applied in a L2 sense to each pair. This option is mainly useful for integrating vectors of complex numbers, where each consecutive pair of real integrans is the real and imaginary parts of a single complex integrand, and you only care about the error in the complex plane rather than the error in the real and imaginary parts separately;
2 for ERROR_L2;
3 for ERROR_L1;
4 for ERROR_LINF,
the absolute error is measured as |e| and the relative error as |err|/|val|, where |...| is the L1, L2, or L-infinity norm, respectively. (|x| in the L1 norm is the sum of the absolute values of the components, in the L2 norm is the root mean square of the components, and in the L-infinity norm is the maximum absolute value of the components).
- maxEvalinteger, optional
The maximum number of function evaluations.
- vectorizedboolean, optional
If
vectorized=True
the integration points are passed to the integrand function as an array of points, allowing parallel evaluation of different points.
- Returns:
- valnumpy.ndarray
The 1-D array of length
fdim
with the computed integral values- errnumpy.ndarray
The 1-D array of length
fdim
with the estimated errors. For smooth functions this estimate is usually conservative (see the results from thetest_cubature.py
script.
Notes
The supplied function must return a 1-D
np.ndarray
object, even for single-valued functions
References
Examples
>>> # Volume of a sphere: >>> import numpy as np >>> from cubature import cubature
>>> def integrand_sphere(x_array, *args): >>> r, theta, phi = x_array >>> return np.array([r**2*sin(phi)])
>>> ndim = 3 >>> fdim = 1 >>> radius = 1. >>> xmin = np.array([0, 0, 0]) >>> xmax = np.array([radius, 2*pi, pi]) >>> val, err = cubature(integrand_sphere, ndim, fdim, xmin, xmax)
More Examples¶
import numpy as np
from numpy import pi, sin
from cubature import cubature
def integrand_brick(x_array):
return 1.
def integrand_sphere(x_array):
r, theta, phi = x_array
return r**2*sin(phi)
def integrand_ellipsoid(x_array, a, b, c):
rho, phi, theta = x_array
return a*b*c*rho**2*sin(theta)
def integrand_ellipsoid_v(x_array, a, b, c):
rho = np.array(x_array[:, 0])
phi = np.array(x_array[:, 1])
theta = np.array(x_array[:, 2])
return a*b*c*rho**2*sin(theta)
def exact_brick(a, b, c):
return a*b*c
def exact_sphere(r):
return 4./3*pi*r**3
def exact_ellipsoid(a,b,c):
return 4./3*pi*a*b*c
if __name__ == '__main__':
# brick
print('_________________')
print('')
print('Brick')
a, b, c = 1., 2., 3.
xmin = np.zeros((3,), dtype=float)
xmax = np.array([a, b, c], dtype=float)
val, err = cubature(integrand_brick, 3, 1, xmin, xmax)
print('Approximated: {0}'.format(val))
print('Exact: {0}'.format(exact_brick(a,b,c)))
# sphere
print('_________________')
print('')
print('Sphere')
radius = 1.
xmin = np.array([0, 0, 0], np.float64)
xmax = np.array([radius, 2*pi, pi], np.float64)
val, err = cubature(integrand_sphere, 3, 1, xmin, xmax)
print('Approximated: {0}'.format(val))
print('Exact: {0}'.format(exact_sphere(radius)))
# ellipsoid
print('_________________')
print('')
print('Ellipsoid')
a, b, c = 1., 2., 3.
xmin = np.array([0, 0, 0], np.float64)
xmax = np.array([1., 2*pi, pi], np.float64)
val, err = cubature(integrand_ellipsoid, 3, 1, xmin, xmax, args=(a,b,c))
print('Approximated: {0}'.format(val))
print('Exact: {0}'.format(exact_ellipsoid(a,b,c)))
print('_________________')
# ellipsoid vectorized
print('_________________')
print('')
print('Ellipsoid Vectorized')
a, b, c = 1., 2., 3.
xmin = np.array([0, 0, 0], np.float64)
xmax = np.array([1., 2*pi, pi], np.float64)
val, err = cubature(integrand_ellipsoid_v, 3, 1, xmin, xmax, args=(a,b,c),
vectorized=True)
print('Approximated: {0}'.format(val))
print('Exact: {0}'.format(exact_ellipsoid(a,b,c)))
print('_________________')
import numpy as np
from numpy import pi, sin
from cubature import cubature
def integrand_rectangle(x_array):
return 1.
def integrand_rectangle_v(x_array):
return np.ones_like(x_array[:, 0])
def integrand_circle(x_array):
return x_array[0]
def integrand_circle_v(x_array):
return x_array[:, 0]
def exact_rectangle(a, b):
return a*b
def exact_circle(r):
return pi*r**2
if __name__ == '__main__':
# rectangle
print('_________________')
print('')
print('Rectangle')
a, b = 3, 5
xmin = [0, 0]
xmax = [a, b]
val, err = cubature(integrand_rectangle, 2, 1, xmin, xmax)
print('Approximated: {0}'.format(val))
print('Exact: {0}'.format(exact_rectangle(a, b)))
# rectangle (vectorized)
print('_________________')
print('')
print('Rectangle (vectorized)')
a, b = 3, 5
xmin = [0, 0]
xmax = [a, b]
val, err = cubature(integrand_rectangle_v, 2, 1, xmin, xmax, vectorized=True)
print('Approximated: {0}'.format(val))
print('Exact: {0}'.format(exact_rectangle(a, b)))
# circle
print('_________________')
print('')
print('Circle')
r = 3.
xmin = [0, 0]
xmax = [r, 2*pi]
val, err = cubature(integrand_circle, 2, 1, xmin, xmax)
print('Approximated: {0}'.format(val))
print('Exact: {0}'.format(exact_circle(r)))
print('_________________')
# circle (vectorized)
print('_________________')
print('')
print('Circle (vectorized)')
r = 3.
xmin = [0, 0]
xmax = [r, 2*pi]
val, err = cubature(integrand_circle_v, 2, 1, xmin, xmax, vectorized=True)
print('Approximated: {0}'.format(val))
print('Exact: {0}'.format(exact_circle(r)))
print('_________________')