scijit.integrate.nquad¶
- scijit.integrate.nquad(func, ranges, args=None, opts=None, full_output=False)¶
Integration over
nvariables.ranges[0]is the INNERMOST integral andranges[-1]the outermost.- Parameters:
- func@njit function
Integrand, in either of two shapes. The scalar shape takes one scalar per axis, innermost first, and then one argument per entry of
args:f(x0, x1, ..., a0, a1). The array shape takes the coordinates as one array and the sameargsafter it,f(x, a0, a1)withx[0]innermost. The shape is resolved when the call compiles, from the function’s arity and from whether it types against a coordinate array.- rangestuple
One entry per axis, innermost first. Each is a
(lo, hi)pair, or a plain@njitcallable RETURNING such a pair. A pair’s members are each a float or a callback. A callback for axisireceives the already-fixed OUTER coordinatesx_{i+1} ... x_{n-1}, innermost of those first, and then theargsentries; or, in the array shape, onecoordsarray holding them outermost first, followed by the same entries. The tuple’s LENGTH sets the nesting depth, so inside@njitit must be a tuple rather than a list or an array.- argstuple, optional
Extra parameters, passed to
funcand to every range callback after their coordinates. Each entry is a real number or an array of real numbers. A value that is not a tuple becomes a one-item tuple.- optsdict, tuple of dicts, or None, optional
Per-axis settings, innermost first, or one dict applied to every axis. An
optsentry isquad()’s own keyword arguments:epsabs,epsrel,limit,points,weight,wvar,wopts,maxp1,limlst,complex_func.woptsis accepted and ignored. A(epsabs, epsrel, limit)triple is accepted in place of a dict.weightandpointspick the QUADPACK routine for their axis, so they are read when the call compiles. Inside@njitthat needs a dict whose values are of MIXED kinds, which is the one numba carries its keys on:{'weight': 'cos', 'wvar': 1.0}works,{'weight': 'cos'}alone does not. A dict holding numbers only needs nothing, since those settings are read at run time.- full_outputbool, optional
Return the diagnostics as a third value. Must be known when the call compiles, since it picks the number of return values.
- Returns:
- valuefloat
The integral.
- abserrfloat
The LARGEST error estimate over every level.
- out_dictdict
Only when
full_output. One key,neval, counting the innermost level’s evaluations.
- Raises:
- TypeError
funcor a limit callback is not a plain@njitfunction; anoptskey is not one of the ten above; anoptspointsis not iterable;funcreturns a complex value.TypingErrorinside@njitfor the first two, which are compile-time questions.- ValueError
rangesis empty; anoptssequence’s length is not the number of ranges; a range entry is not a(lo, hi)pair; anargsentry is not a real number or an array of them; or QUADPACK refuses the settings of some level, which isquad()’s own set of conditions.
See also
scipy.integrate.nquadThe scipy routine this mirrors.
Notes
Prange-safe. Each call works in its own buffer.
An
optsentry is a dict or a triple, where scipy also accepts a callable returning a dict.weightandpointspick the QUADPACK routine for their axis and are read when the call compiles, so a value produced at run time cannot reach them.A per-axis
optscarrying aweightcannot be passed from inside@njit. One dict applied to every axis works, and so does every per-axis spelling whennquadis called from python.An
optssequence of the wrong length raises, and an emptyrangesraisesValueError. scipy validates neither: it indexesoptsfrom the end, so three entries against two ranges uses the last two and drops the first, and an emptyrangesreachesIndexError: list index out of range.A
(lo, hi)pair whose members are individually callbacks, a length-3 sequence of scalars read as one(epsabs, epsrel, limit)triple for every axis, and the array integrand shape are additive. No scipy-shaped call reaches them.An
optsdict whose values are all numbers cannot carrypoints. A dict literal holding a tuple carries it,opts={'points': (0.5,), 'epsabs': 1.49e-8}.complex_funcis accepted only as false. scipy accepts the key and then compares a complexabserragainst an int, socomplex_func=TrueraisesTypeErrorthere for every integrand, real or complex.abserris a float64 on every route. scipy returns the int0on an integral whose range is degenerate.Examples
>>> import numpy as np >>> from numba import njit >>> import scijit.integrate as si >>> @njit ... def f(x0, x1): # scipy's shape, x0 innermost ... return x0 * x1 >>> @njit ... def run(): ... return si.nquad(f, ((0.0, 1.0), (0.0, 2.0))) >>> run() (0.9999999999999999, 1.1102230246251564e-14)
A limit that depends on the axis outside it, and scipy’s other range spelling side by side:
>>> @njit ... def hi0(x1): # axis 0's upper limit ... return 1.0 - x1 >>> @njit ... def rng0(x1): # the same, as one callable ... return 0.0, 1.0 - x1 >>> @njit ... def tri(): ... a = si.nquad(f, ((0.0, hi0), (0.0, 1.0))) ... b = si.nquad(f, (rng0, (0.0, 1.0))) ... return a[0], b[0] >>> tri() (0.04166666666666667, 0.04166666666666667)
Extra parameters travel as scipy’s tuple and reach the integrand and the range callbacks alike:
>>> @njit ... def g(x0, x1, c): ... return c * x0 * x1 >>> @njit ... def lo0(x1, c): ... return 0.0 * c >>> @njit ... def scaled(): ... return si.nquad(g, ((lo0, 1.0), (0.0, 2.0)), (3.0,))[0] >>> scaled() 3.0