scipy.integrate.qmc_quad#

scipy.integrate.qmc_quad(func, a, b, *, n_estimates=8, n_points=1024, qrng=None, log=False)[source]#

Compute an integral in N-dimensions using Quasi-Monte Carlo quadrature.

Parameters:
funccallable

The integrand. Must accept a single argument x, an array which specifies the point(s) at which to evaluate the scalar-valued integrand, and return the value(s) of the integrand. For efficiency, the function should be vectorized to accept an array of shape (d, n_points), where d is the number of variables (i.e. the dimensionality of the function domain) and n_points is the number of quadrature points, and return an array of shape (n_points,), the integrand at each quadrature point.

a, barray-like

One-dimensional arrays specifying the lower and upper integration limits, respectively, of each of the d variables.

n_estimates, n_pointsint, optional

n_estimates (default: 8) statistically independent QMC samples, each of n_points (default: 1024) points, will be generated by qrng. The total number of points at which the integrand func will be evaluated is n_points * n_estimates. See Notes for details.

qrngQMCEngine, optional

An instance of the QMCEngine from which to sample QMC points. The QMCEngine must be initialized to a number of dimensions d corresponding with the number of variables x1, ..., xd passed to func. The provided QMCEngine is used to produce the first integral estimate. If n_estimates is greater than one, additional QMCEngines are spawned from the first (with scrambling enabled, if it is an option.) If a QMCEngine is not provided, the default scipy.stats.qmc.Halton will be initialized with the number of dimensions determine from the length of a.

logboolean, default: False

When set to True, func returns the log of the integrand, and the result object contains the log of the integral.

Returns:
resultobject

A result object with attributes:

integralfloat

The estimate of the integral.

standard_error :

The error estimate. See Notes for interpretation.

Notes

Values of the integrand at each of the n_points points of a QMC sample are used to produce an estimate of the integral. This estimate is drawn from a population of possible estimates of the integral, the value of which we obtain depends on the particular points at which the integral was evaluated. We perform this process n_estimates times, each time evaluating the integrand at different scrambled QMC points, effectively drawing i.i.d. random samples from the population of integral estimates. The sample mean \(m\) of these integral estimates is an unbiased estimator of the true value of the integral, and the standard error of the mean \(s\) of these estimates may be used to generate confidence intervals using the t distribution with n_estimates - 1 degrees of freedom. Perhaps counter-intuitively, increasing n_points while keeping the total number of function evaluation points n_points * n_estimates fixed tends to reduce the actual error, whereas increasing n_estimates tends to decrease the error estimate.

Examples

QMC quadrature is particularly useful for computing integrals in higher dimensions. An example integrand is the probability density function of a multivariate normal distribution.

>>> import numpy as np
>>> from scipy import stats
>>> dim = 8
>>> mean = np.zeros(dim)
>>> cov = np.eye(dim)
>>> def func(x):
...     # `multivariate_normal` expects the _last_ axis to correspond with
...     # the dimensionality of the space, so `x` must be transposed
...     return stats.multivariate_normal.pdf(x.T, mean, cov)

To compute the integral over the unit hypercube:

>>> from scipy.integrate import qmc_quad
>>> a = np.zeros(dim)
>>> b = np.ones(dim)
>>> rng = np.random.default_rng()
>>> qrng = stats.qmc.Halton(d=dim, seed=rng)
>>> n_estimates = 8
>>> res = qmc_quad(func, a, b, n_estimates=n_estimates, qrng=qrng)
>>> res.integral, res.standard_error
(0.00018429555666024108, 1.0389431116001344e-07)

A two-sided, 99% confidence interval for the integral may be estimated as:

>>> t = stats.t(df=n_estimates-1, loc=res.integral,
...             scale=res.standard_error)
>>> t.interval(0.99)
(0.0001839319802536469, 0.00018465913306683527)

Indeed, the value reported by scipy.stats.multivariate_normal is within this range.

>>> stats.multivariate_normal.cdf(b, mean, cov, lower_limit=a)
0.00018430867675187443