Your one-stop shop for numerical integration in Python.
More than 1500 numerical integration schemes for line segments, circles, disks, triangles, quadrilaterals, spheres, balls, tetrahedra, hexahedra, wedges, pyramids, n-spheres, n-balls, n-cubes, n-simplices, and the 1D/2D/3D/nD spaces with weight functions exp(-r) and exp(-r2) for fast integration of real-, complex-, and vector-valued functions.
For example, to numerically integrate any function over any given interval, install quadpy from the Python Package Index with
pip install quadpy
and do
import numpy
import quadpy
def f(x):
return numpy.sin(x) - x
val, err = quadpy.quad(f, 0.0, 6.0)
This is just like scipy with the addition that quadpy handles complex-, vector-, matrix-valued integrands, and lines in spaces of arbitrary dimension.
To integrate over a triangle with Strang's rule of degree 6, do
import numpy
import quadpy
def f(x):
return numpy.sin(x[0]) * numpy.sin(x[1])
triangle = numpy.array([[0.0, 0.0], [1.0, 0.0], [0.7, 0.5]])
val = quadpy.triangle.strang_fix_cowper_09().integrate(f, triangle)
All schemes have
scheme.points
scheme.weights
scheme.degree
scheme.citation
scheme.show()
scheme.integrate(
# ...
)
and many have
scheme.points_symbolic
scheme.weights_symbolic
quadpy is fully vectorized, so if you like to compute the integral of a function on many
domains at once, you can provide them all in one integrate()
call, e.g.,
# shape (3, 5, 2), i.e., (corners, num_triangles, xy_coords)
triangles = numpy.stack([
[[0.0, 0.0], [1.0, 0.0], [0.0, 1.0]],
[[1.2, 0.6], [1.3, 0.7], [1.4, 0.8]],
[[26.0, 31.0], [24.0, 27.0], [33.0, 28]],
[[0.1, 0.3], [0.4, 0.4], [0.7, 0.1]],
[[8.6, 6.0], [9.4, 5.6], [7.5, 7.4]]
], axis=-2)
The same goes for functions with vectorized output, e.g.,
def f(x):
return [numpy.sin(x[0]), numpy.sin(x[1])]
More examples under test/examples_test.py.
Read more about the dimensionality of the input/output arrays in the wiki.
Advanced topics:
- Chebyshev-Gauss (both variants, arbitrary degree)
- Clenshaw-Curtis (after Waldvogel, arbitrary degree)
- Fejér-type-1 (after Waldvogel, arbitrary degree)
- Fejér-type-2 (after Waldvogel, arbitrary degree)
- Gauss-Jacobi
- Gauss-Legendre (via NumPy, arbitrary degree)
- Gauss-Lobatto (arbitrary degree)
- Gauss-Kronrod (after Laurie, arbitrary degree)
- Gauss-Patterson (9 nested schemes up to degree 767)
- Gauss-Radau (arbitrary degree)
- closed Newton-Cotes (arbitrary degree)
- open Newton-Cotes (arbitrary degree)
- tanh-sinh quadrature (see above)
See below for how to generate Gauss formulas for your own weight functions.
Example:
import numpy
import quadpy
scheme = quadpy.line_segment.gauss_patterson(5)
scheme.show()
val = scheme.integrate(lambda x: numpy.exp(x), [0.0, 1.0])
- Generalized Gauss-Laguerre
Example:
import quadpy
scheme = quadpy.e1r.gauss_laguerre(5, alpha=0)
scheme.show()
val = scheme.integrate(lambda x: x**2)
- Gauss-Hermite (via NumPy, arbitrary degree)
- Genz-Keister (1996, 8 nested schemes up to degree 67)
Example:
import quadpy
scheme = quadpy.e1r2.gauss_hermite(5)
scheme.show()
val = scheme.integrate(lambda x: x**2)
- Krylov (1959, arbitrary degree)
Example:
import quadpy
scheme = quadpy.circle.krylov(7)
scheme.show()
val = scheme.integrate(lambda x: numpy.exp(x[0]), [0.0, 0.0], 1.0)
Apart from the classical centroid, vertex, and seven-point schemes we have
- Hammer-Marlowe-Stroud (1956, 5 schemes up to degree 5, also appearing in Hammer-Stroud)
- open and closed Newton-Cotes schemes (1970, after Silvester, arbitrary degree),
- via Stroud (1971):
- Albrecht-Collatz (1958, degree 3)
- conical product scheme (degree 7)
- Franke (1971, 2 schemes of degree 7)
- Strang-Fix/Cowper (1973, 10 schemes up to degree 7),
- Lyness-Jespersen (1975, 21 schemes up to degree 11, two of which are used in TRIEX),
- Lether (1976, degree 2n-2, arbitrary n, not symmetric; reproduced in Rathod-Nagaraja-Venkatesudu, 2007),
- Hillion (1977, 10 schemes up to degree 3),
- Grundmann-Möller (1978, arbitrary degree),
- Laursen-Gellert (1978, 17 schemes up to degree 10),
- CUBTRI (Laurie, 1982, degree 8),
- Dunavant (1985, 20 schemes up to degree 20),
- Cools-Haegemans (1987, degrees 8 and 11),
- Gatermann (1988, degree 7)
- Berntsen-Espelid (1990, 4 schemes of degree 13, the first one being DCUTRI),
- Liu-Vinokur (1998, 13 schemes up to degree 5),
- Griener-Schmid, (1999, 2 schemes of degree 6),
- Walkington (2000, 5 schemes up to degree 5),
- Wandzura-Xiao (2003, 6 schemes up to degree 30),
- Taylor-Wingate-Bos (2005, 5 schemes up to degree 14),
- Zhang-Cui-Liu (2009, 3 schemes up to degree 20),
- Xiao-Gimbutas (2010, 50 schemes up to degree 50),
- Vioreanu-Rokhlin (2014, 20 schemes up to degree 62),
- Williams-Shunn-Jameson (2014, 8 schemes up to degree 12),
- Witherden-Vincent (2015, 19 schemes up to degree 20),
- Papanicolopulos (2016, 27 schemes up to degree 25).
Example:
import quadpy
scheme = quadpy.triangle.xiao_gimbutas_05()
scheme.show()
val = scheme.integrate(lambda x: numpy.exp(x[0]), [[0.0, 0.0], [1.0, 0.0], [0.5, 0.7]])
- Peirce (1957, arbitrary degree)
- via Stroud:
- Radon (1948, degree 5)
- Peirce (1956, 3 schemes up to degree 11)
- Albrecht-Collatz (1958, degree 3)
- Hammer-Stroud (1958, 8 schemes up to degree 15)
- Albrecht (1960, 8 schemes up to degree 17)
- Mysovskih (1964, 3 schemes up to degree 15)
- Rabinowitz-Richter (1969, 6 schemes up to degree 15)
- Lether (1971, arbitrary degree)
- Piessens-Haegemans (1975, 1 scheme of degree 9)
- Haegemans-Piessens (1977, degree 9)
- Cools-Haegemans (1985, 3 schemes up to degree 9)
- Wissmann-Becker (1986, 3 schemes up to degree 8)
- Cools-Kim (2000, 3 schemes up to degree 21)
Example:
import numpy
import quadpy
scheme = quadpy.disk.lether(6)
scheme.show()
val = scheme.integrate(lambda x: numpy.exp(x[0]), [0.0, 0.0], 1.0)
- Hammer-Stroud (1958, 3 schemes up to degree 7)
- via Stroud (1971, 15 schemes up to degree 15):
- Maxwell (1890, degree 7)
- Burnside (1908, degree 5)
- Irwin (1923, 3 schemes up to degree 5)
- Tyler (1953, 3 schemes up to degree 7)
- Albrecht-Collatz (1958, 4 schemes up to degree 5)
- Miller (1960, degree 1)
- Meister (1966, degree 7)
- Phillips (1967, degree 7)
- Rabinowitz-Richter (1969, 6 schemes up to degree 15)
- Franke (1971, 10 schemes up to degree 9)
- Piessens-Haegemans (1975, 2 schemes of degree 9)
- Haegemans-Piessens (1977, degree 7)
- Schmid (1978, 3 schemes up to degree 6)
- Cools-Haegemans (1985, 3 schemes up to degree 13)
- Dunavant (1985, 11 schemes up to degree 19)
- Morrow-Patterson (1985, 2 schemes up to degree 20, single precision)
- Cohen-Gismalla, (1986, 2 schemes up to degree 3, single precision)
- Wissmann-Becker (1986, 6 schemes up to degree 8)
- Cools-Haegemans (1988, 2 schemes up to degree 13)
- Waldron (1994, infinitely many schemes of degree 3)
- Witherden-Vincent (2015, 11 schemes up to degree 21)
- Sommariva (2012, 55 schemes up to degree 55)
- products of line segment schemes
- all formulas from the n-cube
Example:
import numpy
import quadpy
scheme = quadpy.quadrilateral.stroud_c2_7_2()
val = scheme.integrate(
lambda x: numpy.exp(x[0]),
[[[0.0, 0.0], [1.0, 0.0]], [[0.0, 1.0], [1.0, 1.0]]],
)
The points are specified in an array of shape (2, 2, ...) such that arr[0][0]
is the lower left corner, arr[1][1]
the upper right. If your quadrilateral
has its sides aligned with the coordinate axes, you can use the convenience
function
quadpy.quadrilateral.rectangle_points([x0, x1], [y0, y1])
to generate the array.
- via Stroud (1971):
- Stroud-Secrest (1963, 2 schemes up to degree 7)
- Rabinowitz-Richter (1969, 4 schemes up to degree 15)
- a scheme of degree 4
- Haegemans-Piessens (1977, 2 schemes up to degree 9)
Example:
import quadpy
scheme = quadpy.e2r.rabinowitz_richter_5()
scheme.show()
val = scheme.integrate(lambda x: x[0]**2)
- via Stroud (1971):
- Stroud-Secrest (1963, 2 schemes up to degree 7)
- Rabinowitz-Richter (1969, 5 schemes up to degree 15)
- 3 schemes up to degree 7
- Haegemans-Piessens (1977, 2 schemes of degree 9)
Example:
import quadpy
scheme = quadpy.e2r2.rabinowitz_richter_3()
scheme.show()
val = scheme.integrate(lambda x: x[0]**2)
- via Stroud (1971):
- Albrecht-Collatz (1958, 5 schemes up to degree 7)
- McLaren (1963, 10 schemes up to degree 14)
- Lebedev (1976, 34 schemes up to degree 131)
- Bažant-Oh (1986, 3 schemes up to degree 11)
- Heo-Xu (2001, 27 schemes up to degree 39, single-precision)
- Fliege-Maier (2007, 4 schemes up to degree 4, single-precision)
Example:
import numpy
import quadpy
scheme = quadpy.sphere.lebedev_019()
scheme.show()
val = scheme.integrate(lambda x: numpy.exp(x[0]), [0.0, 0.0, 0.0], 1.0)
Integration on the sphere can also be done for function defined in spherical coordinates:
import numpy
import quadpy
scheme = quadpy.sphere.lebedev_019()
val = scheme.integrate_spherical(
lambda azimuthal, polar: numpy.sin(azimuthal)**2 * numpy.sin(polar),
)
- Hammer-Stroud (1958, 6 schemes up to degree 7)
- via: Stroud (1971):
- Ditkin (1948, 3 schemes up to degree 7)
- Mysovskih (1964, degree 7)
- 2 schemes up to degree 14
Example:
import numpy
import quadpy
scheme = quadpy.ball.hammer_stroud_14_3()
scheme.show()
val = scheme.integrate(
lambda x: numpy.exp(x[0]),
[0.0, 0.0, 0.0], 1.0,
)
- Hammer-Marlowe-Stroud (1956, 3 schemes up to degree 3, also appearing in Hammer-Stroud)
- open and closed Newton-Cotes (1970, after Silvester) (arbitrary degree)
- Stroud (1971, degree 7)
- Grundmann-Möller (1978, arbitrary degree),
- Yu (1984, 5 schemes up to degree 6)
- Keast (1986, 10 schemes up to degree 8)
- Beckers-Haegemans (1990, degrees 8 and 9)
- Gatermann (1992, degree 5)
- Liu-Vinokur (1998, 14 schemes up to degree 5)
- Walkington (2000, 6 schemes up to degree 7)
- Zhang-Cui-Liu (2009, 2 schemes up to degree 14)
- Xiao-Gimbutas (2010, 15 schemes up to degree 15)
- Shunn-Ham (2012, 6 schemes up to degree 7)
- Vioreanu-Rokhlin (2014, 10 schemes up to degree 13)
- Williams-Shunn-Jameson (2014, 1 scheme with degree 9)
- Witherden-Vincent (2015, 9 schemes up to degree 10)
Example:
import numpy
import quadpy
scheme = quadpy.tetrahedron.keast_10()
scheme.show()
val = scheme.integrate(
lambda x: numpy.exp(x[0]),
[[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.5, 0.7, 0.0], [0.3, 0.9, 1.0]],
)
- Product schemes derived from line segment schemes
- via: Stroud (1971):
- Sadowsky (1940, degree 5)
- Tyler (1953, 2 schemes up to degree 5)
- Hammer-Wymore (1957, degree 7)
- Albrecht-Collatz (1958, degree 3)
- Hammer-Stroud (1958, 6 schemes up to degree 7)
- Mustard-Lyness-Blatt (1963, 6 schemes up to degree 5)
- Stroud (1967, degree 5)
- Sarma-Stroud (1969, degree 7)
- all formulas from the n-cube
Example:
import numpy
import quadpy
scheme = quadpy.hexahedron.product(quadpy.line_segment.newton_cotes_closed(3))
scheme.show()
val = scheme.integrate(
lambda x: numpy.exp(x[0]),
quadpy.hexahedron.cube_points([0.0, 1.0], [-0.3, 0.4], [1.0, 2.1]),
)
- Felippa (9 schemes up to degree 5)
Example:
import numpy
import quadpy
scheme = quadpy.pyramid.felippa_5()
val = scheme.integrate(
lambda x: numpy.exp(x[0]),
[
[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.5, 0.7, 0.0], [0.3, 0.9, 0.0],
[0.0, 0.1, 1.0],
]
)
- Felippa (6 schemes up to degree 6)
- Kubatko-Yeager-Maggi (21 schemes up to degree 9)
Example:
import numpy
import quadpy
scheme = quadpy.wedge.felippa_3
val = quadpy.wedge.integrate(
lambda x: numpy.exp(x[0]),
[
[[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.5, 0.7, 0.0]],
[[0.0, 0.0, 1.0], [1.0, 0.0, 1.0], [0.5, 0.7, 1.0]],
]
)
- via Stroud (1971):
- Stroud-Secrest (1963, 5 schemes up to degree 7)
Example:
import quadpy
scheme = quadpy.e3r.stroud_secrest_09()
scheme.show()
val = scheme.integrate(lambda x: x[0]**2)
- via Stroud (1971):
- Stroud-Secrest (1963, 7 schemes up to degree 7)
- scheme of degree 14
Example:
import quadpy
scheme = quadpy.e3r2.stroud_secrest_10a()
scheme.show()
val = scheme.integrate(lambda x: x[0]**2)
- via Stroud:
- Lauffer (1955, 5 schemes up to degree 5)
- Hammer-Stroud (1956, 3 schemes up to degree 3)
- Stroud (1964, degree 3)
- Stroud (1966, 7 schemes of degree 3)
- Stroud (1969, degree 5)
- Grundmann-Möller (1978, arbitrary degree)
- Walkington (2000, 5 schemes up to degree 7)
Example:
import numpy
import quadpy
scheme = quadpy.nsimplex.GrundmannMoeller(dim, 3)
dim = 4
val = scheme.integrate(
lambda x: numpy.exp(x[0]),
numpy.array([
[0.0, 0.0, 0.0, 0.0],
[1.0, 2.0, 0.0, 0.0],
[0.0, 1.0, 0.0, 0.0],
[0.0, 3.0, 1.0, 0.0],
[0.0, 0.0, 4.0, 1.0],
])
)
Example:
import numpy
import quadpy
scheme = quadpy.nsphere.dobrodeev_1978(dim)
dim = 4
val = scheme.integrate(lambda x: numpy.exp(x[0]), numpy.zeros(dim), 1.0)
Example:
import numpy
import quadpy
scheme = quadpy.nball.dobrodeev_1970(dim)
dim = 4
val = scheme.integrate(lambda x: numpy.exp(x[0]), numpy.zeros(dim), 1.0)
- Dobrodeev (1970, n >= 5, degree 7)
- via Stroud (1971):
- Ewing (1941, degree 3)
- Tyler (1953, degree 3)
- Stroud (1957, 2 schemes up to degree 3)
- Hammer-Stroud (1958, degree 5)
- Mustard-Lyness-Blatt (1963, degree 5)
- Thacher (1964, degree 2)
- Stroud (1966, 4 schemes of degree 5)
- Phillips (1967, degree 7)
- Stroud (1968, degree 5)
- Dobrodeev (1978, n >= 2, degree 5)
Example:
import numpy
import quadpy
dim = 4
scheme = quadpy.ncube.stroud_cn_3_3(dim)
quadpy.ncube.integrate(
lambda x: numpy.exp(x[0]),
quadpy.ncube.ncube_points(
[0.0, 1.0], [0.1, 0.9], [-1.0, 1.0], [-1.0, -0.5]
)
)
- via Stroud (1971):
- Stroud-Secrest (1963, 4 schemes up to degree 5)
- 2 schemes up to degree 5
Example:
import quadpy
dim = 4
scheme = quadpy.enr.stroud_5_4(dim)
val = scheme.integrate(lambda x: x[0]**2)
- via Stroud (1971):
- Stroud-Secrest (1963, 4 schemes up to degree 5)
- Stroud (1967, 2 schemes of degree 5)
- Stroud (1967, 3 schemes of degree 7)
- Stenger (1971, 6 schemes up to degree 11, varying dimensionality restrictions)
- 5 schemes up to degree 5
Example:
import quadpy
dim = 4
scheme = quadpy.enr2.stroud_5_2(dim)
val = scheme.integrate(lambda x: x[0]**2)
quadpy is available from the Python Package Index, so with
pip install quadpy
you can install.
To run the tests, just check out this repository and type
MPLBACKEND=Agg pytest
This software is published under the GPLv3 license.