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 triangle, install quadpy from the Python Package Index with
pip3 install quadpy --user
and 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)
This uses Strang's rule of degree 6.
All schemese 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_3a()
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
pip3 install quadpy --user
you can install.
To run the tests, just check out this repository and type
MPLBACKEND=Agg pytest
quadpy is published under the MIT license.