| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305 |
- # Author: Travis Oliphant 2001
- # Author: Nathan Woods 2013 (nquad &c)
- import sys
- import warnings
- from functools import partial
- from . import _quadpack
- import numpy as np
- from scipy._lib._array_api import xp_capabilities
- __all__ = ["quad", "dblquad", "tplquad", "nquad", "IntegrationWarning"]
- class IntegrationWarning(UserWarning):
- """
- Warning on issues during integration.
- """
- pass
- @xp_capabilities(np_only=True)
- def quad(func, a, b, args=(), full_output=0, epsabs=1.49e-8, epsrel=1.49e-8,
- limit=50, points=None, weight=None, wvar=None, wopts=None, maxp1=50,
- limlst=50, complex_func=False):
- """
- Compute a definite integral.
- Integrate func from `a` to `b` (possibly infinite interval) using a
- technique from the Fortran library QUADPACK.
- Parameters
- ----------
- func : {function, scipy.LowLevelCallable}
- A Python function or method to integrate. If `func` takes many
- arguments, it is integrated along the axis corresponding to the
- first argument.
- If the user desires improved integration performance, then `f` may
- be a `scipy.LowLevelCallable` with one of the signatures::
- double func(double x)
- double func(double x, void *user_data)
- double func(int n, double *xx)
- double func(int n, double *xx, void *user_data)
- The ``user_data`` is the data contained in the `scipy.LowLevelCallable`.
- In the call forms with ``xx``, ``n`` is the length of the ``xx``
- array which contains ``xx[0] == x`` and the rest of the items are
- numbers contained in the ``args`` argument of quad.
- In addition, certain ctypes call signatures are supported for
- backward compatibility, but those should not be used in new code.
- a : float
- Lower limit of integration (use -numpy.inf for -infinity).
- b : float
- Upper limit of integration (use numpy.inf for +infinity).
- args : tuple, optional
- Extra arguments to pass to `func`.
- full_output : int, optional
- Non-zero to return a dictionary of integration information.
- If non-zero, warning messages are also suppressed and the
- message is appended to the output tuple.
- complex_func : bool, optional
- Indicate if the function's (`func`) return type is real
- (``complex_func=False``: default) or complex (``complex_func=True``).
- In both cases, the function's argument is real.
- If full_output is also non-zero, the `infodict`, `message`, and
- `explain` for the real and complex components are returned in
- a dictionary with keys "real output" and "imag output".
- Returns
- -------
- y : float
- The integral of func from `a` to `b`.
- abserr : float
- An estimate of the absolute error in the result.
- infodict : dict
- A dictionary containing additional information.
- message
- A convergence message.
- explain
- Appended only with 'cos' or 'sin' weighting and infinite
- integration limits, it contains an explanation of the codes in
- infodict['ierlst']
- Other Parameters
- ----------------
- epsabs : float or int, optional
- Absolute error tolerance. Default is 1.49e-8. `quad` tries to obtain
- an accuracy of ``abs(i-result) <= max(epsabs, epsrel*abs(i))``
- where ``i`` = integral of `func` from `a` to `b`, and ``result`` is the
- numerical approximation. See `epsrel` below.
- epsrel : float or int, optional
- Relative error tolerance. Default is 1.49e-8.
- If ``epsabs <= 0``, `epsrel` must be greater than both 5e-29
- and ``50 * (machine epsilon)``. See `epsabs` above.
- limit : float or int, optional
- An upper bound on the number of subintervals used in the adaptive
- algorithm.
- points : (sequence of floats,ints), optional
- A sequence of break points in the bounded integration interval
- where local difficulties of the integrand may occur (e.g.,
- singularities, discontinuities). The sequence does not have
- to be sorted. Note that this option cannot be used in conjunction
- with ``weight``.
- weight : float or int, optional
- String indicating weighting function. Full explanation for this
- and the remaining arguments can be found below.
- wvar : optional
- Variables for use with weighting functions.
- wopts : optional
- Optional input for reusing Chebyshev moments.
- maxp1 : float or int, optional
- An upper bound on the number of Chebyshev moments.
- limlst : int, optional
- Upper bound on the number of cycles (>=3) for use with a sinusoidal
- weighting and an infinite end-point.
- See Also
- --------
- dblquad : double integral
- tplquad : triple integral
- nquad : n-dimensional integrals (uses `quad` recursively)
- fixed_quad : fixed-order Gaussian quadrature
- simpson : integrator for sampled data
- romb : integrator for sampled data
- scipy.special : for coefficients and roots of orthogonal polynomials
- Notes
- -----
- For valid results, the integral must converge; behavior for divergent
- integrals is not guaranteed.
- **Extra information for quad() inputs and outputs**
- If full_output is non-zero, then the third output argument
- (infodict) is a dictionary with entries as tabulated below. For
- infinite limits, the range is transformed to (0,1) and the
- optional outputs are given with respect to this transformed range.
- Let M be the input argument limit and let K be infodict['last'].
- The entries are:
- 'neval'
- The number of function evaluations.
- 'last'
- The number, K, of subintervals produced in the subdivision process.
- 'alist'
- A rank-1 array of length M, the first K elements of which are the
- left end points of the subintervals in the partition of the
- integration range.
- 'blist'
- A rank-1 array of length M, the first K elements of which are the
- right end points of the subintervals.
- 'rlist'
- A rank-1 array of length M, the first K elements of which are the
- integral approximations on the subintervals.
- 'elist'
- A rank-1 array of length M, the first K elements of which are the
- moduli of the absolute error estimates on the subintervals.
- 'iord'
- A rank-1 integer array of length M, the first L elements of
- which are pointers to the error estimates over the subintervals
- with ``L=K`` if ``K<=M/2+2`` or ``L=M+1-K`` otherwise. Let I be the
- sequence ``infodict['iord']`` and let E be the sequence
- ``infodict['elist']``. Then ``E[I[1]], ..., E[I[L]]`` forms a
- decreasing sequence.
- If the input argument points is provided (i.e., it is not None),
- the following additional outputs are placed in the output
- dictionary. Assume the points sequence is of length P.
- 'pts'
- A rank-1 array of length P+2 containing the integration limits
- and the break points of the intervals in ascending order.
- This is an array giving the subintervals over which integration
- will occur.
- 'level'
- A rank-1 integer array of length M (=limit), containing the
- subdivision levels of the subintervals, i.e., if (aa,bb) is a
- subinterval of ``(pts[1], pts[2])`` where ``pts[0]`` and ``pts[2]``
- are adjacent elements of ``infodict['pts']``, then (aa,bb) has level l
- if ``|bb-aa| = |pts[2]-pts[1]| * 2**(-l)``.
- 'ndin'
- A rank-1 integer array of length P+2. After the first integration
- over the intervals (pts[1], pts[2]), the error estimates over some
- of the intervals may have been increased artificially in order to
- put their subdivision forward. This array has ones in slots
- corresponding to the subintervals for which this happens.
- **Weighting the integrand**
- The input variables, *weight* and *wvar*, are used to weight the
- integrand by a select list of functions. Different integration
- methods are used to compute the integral with these weighting
- functions, and these do not support specifying break points. The
- possible values of weight and the corresponding weighting functions are.
- ========== =================================== =====================
- ``weight`` Weight function used ``wvar``
- ========== =================================== =====================
- 'cos' cos(w*x) wvar = w
- 'sin' sin(w*x) wvar = w
- 'alg' g(x) = ((x-a)**alpha)*((b-x)**beta) wvar = (alpha, beta)
- 'alg-loga' g(x)*log(x-a) wvar = (alpha, beta)
- 'alg-logb' g(x)*log(b-x) wvar = (alpha, beta)
- 'alg-log' g(x)*log(x-a)*log(b-x) wvar = (alpha, beta)
- 'cauchy' 1/(x-c) wvar = c
- ========== =================================== =====================
- wvar holds the parameter w, (alpha, beta), or c depending on the weight
- selected. In these expressions, a and b are the integration limits.
- For the 'cos' and 'sin' weighting, additional inputs and outputs are
- available.
- For weighted integrals with finite integration limits, the integration
- is performed using a Clenshaw-Curtis method, which uses Chebyshev moments.
- For repeated calculations, these moments are saved in the output dictionary:
- 'momcom'
- The maximum level of Chebyshev moments that have been computed,
- i.e., if ``M_c`` is ``infodict['momcom']`` then the moments have been
- computed for intervals of length ``|b-a| * 2**(-l)``,
- ``l=0,1,...,M_c``.
- 'nnlog'
- A rank-1 integer array of length M(=limit), containing the
- subdivision levels of the subintervals, i.e., an element of this
- array is equal to l if the corresponding subinterval is
- ``|b-a|* 2**(-l)``.
- 'chebmo'
- A rank-2 array of shape (25, maxp1) containing the computed
- Chebyshev moments. These can be passed on to an integration
- over the same interval by passing this array as the second
- element of the sequence wopts and passing infodict['momcom'] as
- the first element.
- If one of the integration limits is infinite, then a Fourier integral is
- computed (assuming w neq 0). If full_output is 1 and a numerical error
- is encountered, besides the error message attached to the output tuple,
- a dictionary is also appended to the output tuple which translates the
- error codes in the array ``info['ierlst']`` to English messages. The
- output information dictionary contains the following entries instead of
- 'last', 'alist', 'blist', 'rlist', and 'elist':
- 'lst'
- The number of subintervals needed for the integration (call it ``K_f``).
- 'rslst'
- A rank-1 array of length M_f=limlst, whose first ``K_f`` elements
- contain the integral contribution over the interval
- ``(a+(k-1)c, a+kc)`` where ``c = (2*floor(|w|) + 1) * pi / |w|``
- and ``k=1,2,...,K_f``.
- 'erlst'
- A rank-1 array of length ``M_f`` containing the error estimate
- corresponding to the interval in the same position in
- ``infodict['rslist']``.
- 'ierlst'
- A rank-1 integer array of length ``M_f`` containing an error flag
- corresponding to the interval in the same position in
- ``infodict['rslist']``. See the explanation dictionary (last entry
- in the output tuple) for the meaning of the codes.
- **Details of QUADPACK level routines**
- `quad` calls routines from the FORTRAN library QUADPACK. This section
- provides details on the conditions for each routine to be called and a
- short description of each routine. The routine called depends on
- `weight`, `points` and the integration limits `a` and `b`.
- ================ ============== ========== =====================
- QUADPACK routine `weight` `points` infinite bounds
- ================ ============== ========== =====================
- qagse None No No
- qagie None No Yes
- qagpe None Yes No
- qawoe 'sin', 'cos' No No
- qawfe 'sin', 'cos' No either `a` or `b`
- qawse 'alg*' No No
- qawce 'cauchy' No No
- ================ ============== ========== =====================
- The following provides a short description from [1]_ for each
- routine.
- qagse
- is an integrator based on globally adaptive interval
- subdivision in connection with extrapolation, which will
- eliminate the effects of integrand singularities of
- several types. The integration is performed using a 21-point Gauss-Kronrod
- quadrature within each subinterval.
- qagie
- handles integration over infinite intervals. The infinite range is
- mapped onto a finite interval and subsequently the same strategy as
- in ``QAGS`` is applied.
- qagpe
- serves the same purposes as QAGS, but also allows the
- user to provide explicit information about the location
- and type of trouble-spots i.e. the abscissae of internal
- singularities, discontinuities and other difficulties of
- the integrand function.
- qawoe
- is an integrator for the evaluation of
- :math:`\\int^b_a \\cos(\\omega x)f(x)dx` or
- :math:`\\int^b_a \\sin(\\omega x)f(x)dx`
- over a finite interval [a,b], where :math:`\\omega` and :math:`f`
- are specified by the user. The rule evaluation component is based
- on the modified Clenshaw-Curtis technique
- An adaptive subdivision scheme is used in connection
- with an extrapolation procedure, which is a modification
- of that in ``QAGS`` and allows the algorithm to deal with
- singularities in :math:`f(x)`.
- qawfe
- calculates the Fourier transform
- :math:`\\int^\\infty_a \\cos(\\omega x)f(x)dx` or
- :math:`\\int^\\infty_a \\sin(\\omega x)f(x)dx`
- for user-provided :math:`\\omega` and :math:`f`. The procedure of
- ``QAWO`` is applied on successive finite intervals, and convergence
- acceleration by means of the :math:`\\varepsilon`-algorithm is applied
- to the series of integral approximations.
- qawse
- approximate :math:`\\int^b_a w(x)f(x)dx`, with :math:`a < b` where
- :math:`w(x) = (x-a)^{\\alpha}(b-x)^{\\beta}v(x)` with
- :math:`\\alpha,\\beta > -1`, where :math:`v(x)` may be one of the
- following functions: :math:`1`, :math:`\\log(x-a)`, :math:`\\log(b-x)`,
- :math:`\\log(x-a)\\log(b-x)`.
- The user specifies :math:`\\alpha`, :math:`\\beta` and the type of the
- function :math:`v`. A globally adaptive subdivision strategy is
- applied, with modified Clenshaw-Curtis integration on those
- subintervals which contain `a` or `b`.
- qawce
- compute :math:`\\int^b_a f(x) / (x-c)dx` where the integral must be
- interpreted as a Cauchy principal value integral, for user specified
- :math:`c` and :math:`f`. The strategy is globally adaptive. Modified
- Clenshaw-Curtis integration is used on those intervals containing the
- point :math:`x = c`.
- **Integration of Complex Function of a Real Variable**
- A complex valued function, :math:`f`, of a real variable can be written as
- :math:`f = g + ih`. Similarly, the integral of :math:`f` can be
- written as
- .. math::
- \\int_a^b f(x) dx = \\int_a^b g(x) dx + i\\int_a^b h(x) dx
- assuming that the integrals of :math:`g` and :math:`h` exist
- over the interval :math:`[a,b]` [2]_. Therefore, ``quad`` integrates
- complex-valued functions by integrating the real and imaginary components
- separately.
- References
- ----------
- .. [1] Piessens, Robert; de Doncker-Kapenga, Elise;
- Überhuber, Christoph W.; Kahaner, David (1983).
- QUADPACK: A subroutine package for automatic integration.
- Springer-Verlag.
- ISBN 978-3-540-12553-2.
- .. [2] McCullough, Thomas; Phillips, Keith (1973).
- Foundations of Analysis in the Complex Plane.
- Holt Rinehart Winston.
- ISBN 0-03-086370-8
- Examples
- --------
- Calculate :math:`\\int^4_0 x^2 dx` and compare with an analytic result
- >>> from scipy import integrate
- >>> import numpy as np
- >>> x2 = lambda x: x**2
- >>> integrate.quad(x2, 0, 4)
- (21.333333333333332, 2.3684757858670003e-13)
- >>> print(4**3 / 3.) # analytical result
- 21.3333333333
- Calculate :math:`\\int^\\infty_0 e^{-x} dx`
- >>> invexp = lambda x: np.exp(-x)
- >>> integrate.quad(invexp, 0, np.inf)
- (1.0, 5.842605999138044e-11)
- Calculate :math:`\\int^1_0 a x \\,dx` for :math:`a = 1, 3`
- >>> f = lambda x, a: a*x
- >>> y, err = integrate.quad(f, 0, 1, args=(1,))
- >>> y
- 0.5
- >>> y, err = integrate.quad(f, 0, 1, args=(3,))
- >>> y
- 1.5
- Calculate :math:`\\int^1_0 x^2 + y^2 dx` with ctypes, holding
- y parameter as 1::
- testlib.c =>
- double func(int n, double args[n]){
- return args[0]*args[0] + args[1]*args[1];}
- compile to library testlib.*
- ::
- from scipy import integrate
- import ctypes
- lib = ctypes.CDLL('/home/.../testlib.*') #use absolute path
- lib.func.restype = ctypes.c_double
- lib.func.argtypes = (ctypes.c_int,ctypes.c_double)
- integrate.quad(lib.func,0,1,(1))
- #(1.3333333333333333, 1.4802973661668752e-14)
- print((1.0**3/3.0 + 1.0) - (0.0**3/3.0 + 0.0)) #Analytic result
- # 1.3333333333333333
- Be aware that pulse shapes and other sharp features as compared to the
- size of the integration interval may not be integrated correctly using
- this method. A simplified example of this limitation is integrating a
- y-axis reflected step function with many zero values within the integrals
- bounds.
- >>> y = lambda x: 1 if x<=0 else 0
- >>> integrate.quad(y, -1, 1)
- (1.0, 1.1102230246251565e-14)
- >>> integrate.quad(y, -1, 100)
- (1.0000000002199108, 1.0189464580163188e-08)
- >>> integrate.quad(y, -1, 10000)
- (0.0, 0.0)
- """
- if not isinstance(args, tuple):
- args = (args,)
- # Shortcut for empty interval, also works for improper integrals.
- if a == b:
- if full_output == 0:
- return (0., 0.)
- else:
- infodict = {"neval": 0, "last": 0,
- "alist": np.full(limit, np.nan, dtype=np.float64),
- "blist": np.full(limit, np.nan, dtype=np.float64),
- "rlist": np.zeros(limit, dtype=np.float64),
- "elist": np.zeros(limit, dtype=np.float64),
- "iord" : np.zeros(limit, dtype=np.int32)}
- if complex_func:
- return (0.+0.j, 0.+0.j, {"real": infodict, "imag": infodict})
- else:
- return (0., 0., infodict)
- # check the limits of integration: \int_a^b, expect a < b
- flip, a, b = b < a, min(a, b), max(a, b)
- if complex_func:
- def imfunc(x, *args):
- return func(x, *args).imag
- def refunc(x, *args):
- return func(x, *args).real
- re_retval = quad(refunc, a, b, args, full_output, epsabs,
- epsrel, limit, points, weight, wvar, wopts,
- maxp1, limlst, complex_func=False)
- im_retval = quad(imfunc, a, b, args, full_output, epsabs,
- epsrel, limit, points, weight, wvar, wopts,
- maxp1, limlst, complex_func=False)
- integral = re_retval[0] + 1j*im_retval[0]
- error_estimate = re_retval[1] + 1j*im_retval[1]
- retval = integral, error_estimate
- if full_output:
- msgexp = {}
- msgexp["real"] = re_retval[2:]
- msgexp["imag"] = im_retval[2:]
- retval = retval + (msgexp,)
- return retval
- if weight is None:
- retval = _quad(func, a, b, args, full_output, epsabs, epsrel, limit,
- points)
- else:
- if points is not None:
- msg = ("Break points cannot be specified when using weighted integrand.\n"
- "Continuing, ignoring specified points.")
- warnings.warn(msg, IntegrationWarning, stacklevel=2)
- retval = _quad_weight(func, a, b, args, full_output, epsabs, epsrel,
- limlst, limit, maxp1, weight, wvar, wopts)
- if flip:
- retval = (-retval[0],) + retval[1:]
- ier = retval[-1]
- if ier == 0:
- return retval[:-1]
- msgs = {80: "A Python error occurred possibly while calling the function.",
- 1: f"The maximum number of subdivisions ({limit}) has been achieved.\n "
- f"If increasing the limit yields no improvement it is advised to "
- f"analyze \n the integrand in order to determine the difficulties. "
- f"If the position of a \n local difficulty can be determined "
- f"(singularity, discontinuity) one will \n probably gain from "
- f"splitting up the interval and calling the integrator \n on the "
- f"subranges. Perhaps a special-purpose integrator should be used.",
- 2: "The occurrence of roundoff error is detected, which prevents \n "
- "the requested tolerance from being achieved. "
- "The error may be \n underestimated.",
- 3: "Extremely bad integrand behavior occurs at some points of the\n "
- "integration interval.",
- 4: "The algorithm does not converge. Roundoff error is detected\n "
- "in the extrapolation table. It is assumed that the requested "
- "tolerance\n cannot be achieved, and that the returned result "
- "(if full_output = 1) is \n the best which can be obtained.",
- 5: "The integral is probably divergent, or slowly convergent.",
- 6: "The input is invalid.",
- 7: "Abnormal termination of the routine. The estimates for result\n "
- "and error are less reliable. It is assumed that the requested "
- "accuracy\n has not been achieved.",
- 'unknown': "Unknown error."}
- if weight in ['cos','sin'] and (b == np.inf or a == -np.inf):
- msgs[1] = (
- "The maximum number of cycles allowed has been achieved., e.e.\n of "
- "subintervals (a+(k-1)c, a+kc) where c = (2*int(abs(omega)+1))\n "
- "*pi/abs(omega), for k = 1, 2, ..., lst. "
- "One can allow more cycles by increasing the value of limlst. "
- "Look at info['ierlst'] with full_output=1."
- )
- msgs[4] = (
- "The extrapolation table constructed for convergence acceleration\n of "
- "the series formed by the integral contributions over the cycles, \n does "
- "not converge to within the requested accuracy. "
- "Look at \n info['ierlst'] with full_output=1."
- )
- msgs[7] = (
- "Bad integrand behavior occurs within one or more of the cycles.\n "
- "Location and type of the difficulty involved can be determined from \n "
- "the vector info['ierlist'] obtained with full_output=1."
- )
- explain = {1: "The maximum number of subdivisions (= limit) has been \n "
- "achieved on this cycle.",
- 2: "The occurrence of roundoff error is detected and prevents\n "
- "the tolerance imposed on this cycle from being achieved.",
- 3: "Extremely bad integrand behavior occurs at some points of\n "
- "this cycle.",
- 4: "The integral over this cycle does not converge (to within the "
- "required accuracy) due to roundoff in the extrapolation "
- "procedure invoked on this cycle. It is assumed that the result "
- "on this interval is the best which can be obtained.",
- 5: "The integral over this cycle is probably divergent or "
- "slowly convergent."}
- try:
- msg = msgs[ier]
- except KeyError:
- msg = msgs['unknown']
- if ier in [1,2,3,4,5,7]:
- if full_output:
- if weight in ['cos', 'sin'] and (b == np.inf or a == -np.inf):
- return retval[:-1] + (msg, explain)
- else:
- return retval[:-1] + (msg,)
- else:
- warnings.warn(msg, IntegrationWarning, stacklevel=2)
- return retval[:-1]
- elif ier == 6: # Forensic decision tree when QUADPACK throws ier=6
- if epsabs <= 0: # Small error tolerance - applies to all methods
- if epsrel < max(50 * sys.float_info.epsilon, 5e-29):
- msg = ("If 'epsabs'<=0, 'epsrel' must be greater than both"
- " 5e-29 and 50*(machine epsilon).")
- elif weight in ['sin', 'cos'] and (abs(a) + abs(b) == np.inf):
- msg = ("Sine or cosine weighted integrals with infinite domain"
- " must have 'epsabs'>0.")
- elif weight is None:
- if points is None: # QAGSE/QAGIE
- msg = ("Invalid 'limit' argument. There must be"
- " at least one subinterval")
- else: # QAGPE
- if not (min(a, b) <= min(points) <= max(points) <= max(a, b)):
- msg = ("All break points in 'points' must lie within the"
- " integration limits.")
- elif len(points) >= limit:
- msg = (f"Number of break points ({len(points):d}) "
- f"must be less than subinterval limit ({limit:d})")
- else:
- if maxp1 < 1:
- msg = "Chebyshev moment limit maxp1 must be >=1."
- elif weight in ('cos', 'sin') and abs(a+b) == np.inf: # QAWFE
- msg = "Cycle limit limlst must be >=3."
- elif weight.startswith('alg'): # QAWSE
- if min(wvar) < -1:
- msg = "wvar parameters (alpha, beta) must both be >= -1."
- if b < a:
- msg = "Integration limits a, b must satistfy a<b."
- elif weight == 'cauchy' and wvar in (a, b):
- msg = ("Parameter 'wvar' must not equal"
- " integration limits 'a' or 'b'.")
- raise ValueError(msg)
- def _quad(func,a,b,args,full_output,epsabs,epsrel,limit,points):
- infbounds = 0
- if (b != np.inf and a != -np.inf):
- pass # standard integration
- elif (b == np.inf and a != -np.inf):
- infbounds = 1
- bound = a
- elif (b == np.inf and a == -np.inf):
- infbounds = 2
- bound = 0 # ignored
- elif (b != np.inf and a == -np.inf):
- infbounds = -1
- bound = b
- else:
- raise RuntimeError("Infinity comparisons don't work for you.")
- if points is None:
- if infbounds == 0:
- return _quadpack._qagse(func,a,b,args,full_output,epsabs,epsrel,limit)
- else:
- return _quadpack._qagie(func, bound, infbounds, args, full_output,
- epsabs, epsrel, limit)
- else:
- if infbounds != 0:
- raise ValueError("Infinity inputs cannot be used with break points.")
- else:
- #Duplicates force function evaluation at singular points
- the_points = np.unique(points)
- the_points = the_points[a < the_points]
- the_points = the_points[the_points < b]
- the_points = np.concatenate((the_points, (0., 0.)))
- return _quadpack._qagpe(func, a, b, the_points, args, full_output,
- epsabs, epsrel, limit)
- def _quad_weight(func, a, b, args, full_output, epsabs, epsrel,
- limlst, limit, maxp1,weight, wvar, wopts):
- if weight not in ['cos','sin','alg','alg-loga','alg-logb','alg-log','cauchy']:
- raise ValueError(f"{weight} not a recognized weighting function.")
- strdict = {'cos':1,'sin':2,'alg':1,'alg-loga':2,'alg-logb':3,'alg-log':4}
- if weight in ['cos','sin']:
- integr = strdict[weight]
- if (b != np.inf and a != -np.inf): # finite limits
- if wopts is None: # no precomputed Chebyshev moments
- return _quadpack._qawoe(func, a, b, wvar, integr, args, full_output,
- epsabs, epsrel, limit, maxp1,1)
- else: # precomputed Chebyshev moments
- momcom = wopts[0]
- chebcom = wopts[1]
- return _quadpack._qawoe(func, a, b, wvar, integr, args,
- full_output,epsabs, epsrel, limit, maxp1, 2,
- momcom, chebcom)
- elif (b == np.inf and a != -np.inf):
- return _quadpack._qawfe(func, a, wvar, integr, args, full_output,
- epsabs, limlst, limit, maxp1)
- elif (b != np.inf and a == -np.inf): # remap function and interval
- if weight == 'cos':
- def thefunc(x,*myargs):
- y = -x
- func = myargs[0]
- myargs = (y,) + myargs[1:]
- return func(*myargs)
- else:
- def thefunc(x,*myargs):
- y = -x
- func = myargs[0]
- myargs = (y,) + myargs[1:]
- return -func(*myargs)
- args = (func,) + args
- return _quadpack._qawfe(thefunc, -b, wvar, integr, args,
- full_output, epsabs, limlst, limit, maxp1)
- else:
- raise ValueError("Cannot integrate with this weight from -Inf to +Inf.")
- else:
- if a in [-np.inf, np.inf] or b in [-np.inf, np.inf]:
- message = "Cannot integrate with this weight over an infinite interval."
- raise ValueError(message)
- if weight.startswith('alg'):
- integr = strdict[weight]
- return _quadpack._qawse(func, a, b, wvar, integr, args,
- full_output, epsabs, epsrel, limit)
- else: # weight == 'cauchy'
- return _quadpack._qawce(func, a, b, wvar, args, full_output,
- epsabs, epsrel, limit)
- @xp_capabilities(np_only=True)
- def dblquad(func, a, b, gfun, hfun, args=(), epsabs=1.49e-8, epsrel=1.49e-8):
- """
- Compute a double integral.
- Return the double (definite) integral of ``func(y, x)`` from ``x = a..b``
- and ``y = gfun(x)..hfun(x)``.
- Parameters
- ----------
- func : callable
- A Python function or method of at least two variables: y must be the
- first argument and x the second argument.
- a, b : float
- The limits of integration in x: `a` < `b`
- gfun : callable or float
- The lower boundary curve in y which is a function taking a single
- floating point argument (x) and returning a floating point result
- or a float indicating a constant boundary curve.
- hfun : callable or float
- The upper boundary curve in y (same requirements as `gfun`).
- args : sequence, optional
- Extra arguments to pass to `func`.
- epsabs : float, optional
- Absolute tolerance passed directly to the inner 1-D quadrature
- integration. Default is 1.49e-8. ``dblquad`` tries to obtain
- an accuracy of ``abs(i-result) <= max(epsabs, epsrel*abs(i))``
- where ``i`` = inner integral of ``func(y, x)`` from ``gfun(x)``
- to ``hfun(x)``, and ``result`` is the numerical approximation.
- See `epsrel` below.
- epsrel : float, optional
- Relative tolerance of the inner 1-D integrals. Default is 1.49e-8.
- If ``epsabs <= 0``, `epsrel` must be greater than both 5e-29
- and ``50 * (machine epsilon)``. See `epsabs` above.
- Returns
- -------
- y : float
- The resultant integral.
- abserr : float
- An estimate of the error.
- See Also
- --------
- quad : single integral
- tplquad : triple integral
- nquad : N-dimensional integrals
- fixed_quad : fixed-order Gaussian quadrature
- simpson : integrator for sampled data
- romb : integrator for sampled data
- scipy.special : for coefficients and roots of orthogonal polynomials
- Notes
- -----
- For valid results, the integral must converge; behavior for divergent
- integrals is not guaranteed.
- **Details of QUADPACK level routines**
- `quad` calls routines from the FORTRAN library QUADPACK. This section
- provides details on the conditions for each routine to be called and a
- short description of each routine. For each level of integration, ``qagse``
- is used for finite limits or ``qagie`` is used if either limit (or both!)
- are infinite. The following provides a short description from [1]_ for each
- routine.
- qagse
- is an integrator based on globally adaptive interval
- subdivision in connection with extrapolation, which will
- eliminate the effects of integrand singularities of
- several types. The integration is is performed using a 21-point Gauss-Kronrod
- quadrature within each subinterval.
- qagie
- handles integration over infinite intervals. The infinite range is
- mapped onto a finite interval and subsequently the same strategy as
- in ``QAGS`` is applied.
- References
- ----------
- .. [1] Piessens, Robert; de Doncker-Kapenga, Elise;
- Überhuber, Christoph W.; Kahaner, David (1983).
- QUADPACK: A subroutine package for automatic integration.
- Springer-Verlag.
- ISBN 978-3-540-12553-2.
- Examples
- --------
- Compute the double integral of ``x * y**2`` over the box
- ``x`` ranging from 0 to 2 and ``y`` ranging from 0 to 1.
- That is, :math:`\\int^{x=2}_{x=0} \\int^{y=1}_{y=0} x y^2 \\,dy \\,dx`.
- >>> import numpy as np
- >>> from scipy import integrate
- >>> f = lambda y, x: x*y**2
- >>> integrate.dblquad(f, 0, 2, 0, 1)
- (0.6666666666666667, 7.401486830834377e-15)
- Calculate :math:`\\int^{x=\\pi/4}_{x=0} \\int^{y=\\cos(x)}_{y=\\sin(x)} 1
- \\,dy \\,dx`.
- >>> f = lambda y, x: 1
- >>> integrate.dblquad(f, 0, np.pi/4, np.sin, np.cos)
- (0.41421356237309503, 1.1083280054755938e-14)
- Calculate :math:`\\int^{x=1}_{x=0} \\int^{y=2-x}_{y=x} a x y \\,dy \\,dx`
- for :math:`a=1, 3`.
- >>> f = lambda y, x, a: a*x*y
- >>> integrate.dblquad(f, 0, 1, lambda x: x, lambda x: 2-x, args=(1,))
- (0.33333333333333337, 5.551115123125783e-15)
- >>> integrate.dblquad(f, 0, 1, lambda x: x, lambda x: 2-x, args=(3,))
- (0.9999999999999999, 1.6653345369377348e-14)
- Compute the two-dimensional Gaussian Integral, which is the integral of the
- Gaussian function :math:`f(x,y) = e^{-(x^{2} + y^{2})}`, over
- :math:`(-\\infty,+\\infty)`. That is, compute the integral
- :math:`\\iint^{+\\infty}_{-\\infty} e^{-(x^{2} + y^{2})} \\,dy\\,dx`.
- >>> f = lambda x, y: np.exp(-(x ** 2 + y ** 2))
- >>> integrate.dblquad(f, -np.inf, np.inf, -np.inf, np.inf)
- (3.141592653589777, 2.5173086737433208e-08)
- """
- def temp_ranges(*args):
- return [gfun(args[0]) if callable(gfun) else gfun,
- hfun(args[0]) if callable(hfun) else hfun]
- return nquad(func, [temp_ranges, [a, b]], args=args,
- opts={"epsabs": epsabs, "epsrel": epsrel})
- @xp_capabilities(np_only=True)
- def tplquad(func, a, b, gfun, hfun, qfun, rfun, args=(), epsabs=1.49e-8,
- epsrel=1.49e-8):
- """
- Compute a triple (definite) integral.
- Return the triple integral of ``func(z, y, x)`` from ``x = a..b``,
- ``y = gfun(x)..hfun(x)``, and ``z = qfun(x,y)..rfun(x,y)``.
- Parameters
- ----------
- func : function
- A Python function or method of at least three variables in the
- order (z, y, x).
- a, b : float
- The limits of integration in x: `a` < `b`
- gfun : function or float
- The lower boundary curve in y which is a function taking a single
- floating point argument (x) and returning a floating point result
- or a float indicating a constant boundary curve.
- hfun : function or float
- The upper boundary curve in y (same requirements as `gfun`).
- qfun : function or float
- The lower boundary surface in z. It must be a function that takes
- two floats in the order (x, y) and returns a float or a float
- indicating a constant boundary surface.
- rfun : function or float
- The upper boundary surface in z. (Same requirements as `qfun`.)
- args : tuple, optional
- Extra arguments to pass to `func`.
- epsabs : float, optional
- Absolute tolerance passed directly to the innermost 1-D quadrature
- integration. Default is 1.49e-8.
- epsrel : float, optional
- Relative tolerance of the innermost 1-D integrals. Default is 1.49e-8.
- Returns
- -------
- y : float
- The resultant integral.
- abserr : float
- An estimate of the error.
- See Also
- --------
- quad : Adaptive quadrature using QUADPACK
- fixed_quad : Fixed-order Gaussian quadrature
- dblquad : Double integrals
- nquad : N-dimensional integrals
- romb : Integrators for sampled data
- simpson : Integrators for sampled data
- scipy.special : For coefficients and roots of orthogonal polynomials
- Notes
- -----
- For valid results, the integral must converge; behavior for divergent
- integrals is not guaranteed.
- **Details of QUADPACK level routines**
- `quad` calls routines from the FORTRAN library QUADPACK. This section
- provides details on the conditions for each routine to be called and a
- short description of each routine. For each level of integration, ``qagse``
- is used for finite limits or ``qagie`` is used, if either limit (or both!)
- are infinite. The following provides a short description from [1]_ for each
- routine.
- qagse
- is an integrator based on globally adaptive interval
- subdivision in connection with extrapolation, which will
- eliminate the effects of integrand singularities of
- several types. The integration is is performed using a 21-point Gauss-Kronrod
- quadrature within each subinterval.
- qagie
- handles integration over infinite intervals. The infinite range is
- mapped onto a finite interval and subsequently the same strategy as
- in ``QAGS`` is applied.
- References
- ----------
- .. [1] Piessens, Robert; de Doncker-Kapenga, Elise;
- Überhuber, Christoph W.; Kahaner, David (1983).
- QUADPACK: A subroutine package for automatic integration.
- Springer-Verlag.
- ISBN 978-3-540-12553-2.
- Examples
- --------
- Compute the triple integral of ``x * y * z``, over ``x`` ranging
- from 1 to 2, ``y`` ranging from 2 to 3, ``z`` ranging from 0 to 1.
- That is, :math:`\\int^{x=2}_{x=1} \\int^{y=3}_{y=2} \\int^{z=1}_{z=0} x y z
- \\,dz \\,dy \\,dx`.
- >>> import numpy as np
- >>> from scipy import integrate
- >>> f = lambda z, y, x: x*y*z
- >>> integrate.tplquad(f, 1, 2, 2, 3, 0, 1)
- (1.8749999999999998, 3.3246447942574074e-14)
- Calculate :math:`\\int^{x=1}_{x=0} \\int^{y=1-2x}_{y=0}
- \\int^{z=1-x-2y}_{z=0} x y z \\,dz \\,dy \\,dx`.
- Note: `qfun`/`rfun` takes arguments in the order (x, y), even though ``f``
- takes arguments in the order (z, y, x).
- >>> f = lambda z, y, x: x*y*z
- >>> integrate.tplquad(f, 0, 1, 0, lambda x: 1-2*x, 0, lambda x, y: 1-x-2*y)
- (0.05416666666666668, 2.1774196738157757e-14)
- Calculate :math:`\\int^{x=1}_{x=0} \\int^{y=1}_{y=0} \\int^{z=1}_{z=0}
- a x y z \\,dz \\,dy \\,dx` for :math:`a=1, 3`.
- >>> f = lambda z, y, x, a: a*x*y*z
- >>> integrate.tplquad(f, 0, 1, 0, 1, 0, 1, args=(1,))
- (0.125, 5.527033708952211e-15)
- >>> integrate.tplquad(f, 0, 1, 0, 1, 0, 1, args=(3,))
- (0.375, 1.6581101126856635e-14)
- Compute the three-dimensional Gaussian Integral, which is the integral of
- the Gaussian function :math:`f(x,y,z) = e^{-(x^{2} + y^{2} + z^{2})}`, over
- :math:`(-\\infty,+\\infty)`. That is, compute the integral
- :math:`\\iiint^{+\\infty}_{-\\infty} e^{-(x^{2} + y^{2} + z^{2})} \\,dz
- \\,dy\\,dx`.
- >>> f = lambda x, y, z: np.exp(-(x ** 2 + y ** 2 + z ** 2))
- >>> integrate.tplquad(f, -np.inf, np.inf, -np.inf, np.inf, -np.inf, np.inf)
- (5.568327996830833, 4.4619078828029765e-08)
- """
- # f(z, y, x)
- # qfun/rfun(x, y)
- # gfun/hfun(x)
- # nquad will hand (y, x, t0, ...) to ranges0
- # nquad will hand (x, t0, ...) to ranges1
- # Only qfun / rfun is different API...
- def ranges0(*args):
- return [qfun(args[1], args[0]) if callable(qfun) else qfun,
- rfun(args[1], args[0]) if callable(rfun) else rfun]
- def ranges1(*args):
- return [gfun(args[0]) if callable(gfun) else gfun,
- hfun(args[0]) if callable(hfun) else hfun]
- ranges = [ranges0, ranges1, [a, b]]
- return nquad(func, ranges, args=args,
- opts={"epsabs": epsabs, "epsrel": epsrel})
- @xp_capabilities(np_only=True)
- def nquad(func, ranges, args=None, opts=None, full_output=False):
- r"""
- Integration over multiple variables.
- Wraps `quad` to enable integration over multiple variables.
- Various options allow improved integration of discontinuous functions, as
- well as the use of weighted integration, and generally finer control of the
- integration process.
- Parameters
- ----------
- func : {callable, scipy.LowLevelCallable}
- The function to be integrated. Has arguments of ``x0, ..., xn``,
- ``t0, ..., tm``, where integration is carried out over ``x0, ..., xn``,
- which must be floats. Where ``t0, ..., tm`` are extra arguments
- passed in args.
- Function signature should be ``func(x0, x1, ..., xn, t0, t1, ..., tm)``.
- Integration is carried out in order. That is, integration over ``x0``
- is the innermost integral, and ``xn`` is the outermost.
- If the user desires improved integration performance, then `f` may
- be a `scipy.LowLevelCallable` with one of the signatures::
- double func(int n, double *xx)
- double func(int n, double *xx, void *user_data)
- where ``n`` is the number of variables and args. The ``xx`` array
- contains the coordinates and extra arguments. ``user_data`` is the data
- contained in the `scipy.LowLevelCallable`.
- ranges : iterable object
- Each element of ranges may be either a sequence of 2 numbers, or else
- a callable that returns such a sequence. ``ranges[0]`` corresponds to
- integration over x0, and so on. If an element of ranges is a callable,
- then it will be called with all of the integration arguments available,
- as well as any parametric arguments. e.g., if
- ``func = f(x0, x1, x2, t0, t1)``, then ``ranges[0]`` may be defined as
- either ``(a, b)`` or else as ``(a, b) = range0(x1, x2, t0, t1)``.
- args : iterable object, optional
- Additional arguments ``t0, ..., tn``, required by ``func``, ``ranges``,
- and ``opts``.
- opts : iterable object or dict, optional
- Options to be passed to `quad`. May be empty, a dict, or
- a sequence of dicts or functions that return a dict. If empty, the
- default options from scipy.integrate.quad are used. If a dict, the same
- options are used for all levels of integraion. If a sequence, then each
- element of the sequence corresponds to a particular integration. e.g.,
- ``opts[0]`` corresponds to integration over ``x0``, and so on. If a
- callable, the signature must be the same as for ``ranges``. The
- available options together with their default values are:
- - epsabs = 1.49e-08
- - epsrel = 1.49e-08
- - limit = 50
- - points = None
- - weight = None
- - wvar = None
- - wopts = None
- For more information on these options, see `quad`.
- full_output : bool, optional
- Partial implementation of ``full_output`` from scipy.integrate.quad.
- The number of integrand function evaluations ``neval`` can be obtained
- by setting ``full_output=True`` when calling nquad.
- Returns
- -------
- result : float
- The result of the integration.
- abserr : float
- The maximum of the estimates of the absolute error in the various
- integration results.
- out_dict : dict, optional
- A dict containing additional information on the integration.
- See Also
- --------
- quad : 1-D numerical integration
- dblquad, tplquad : double and triple integrals
- fixed_quad : fixed-order Gaussian quadrature
- Notes
- -----
- For valid results, the integral must converge; behavior for divergent
- integrals is not guaranteed.
- **Details of QUADPACK level routines**
- `nquad` calls routines from the FORTRAN library QUADPACK. This section
- provides details on the conditions for each routine to be called and a
- short description of each routine. The routine called depends on
- `weight`, `points` and the integration limits `a` and `b`.
- ================ ============== ========== =====================
- QUADPACK routine `weight` `points` infinite bounds
- ================ ============== ========== =====================
- qagse None No No
- qagie None No Yes
- qagpe None Yes No
- qawoe 'sin', 'cos' No No
- qawfe 'sin', 'cos' No either `a` or `b`
- qawse 'alg*' No No
- qawce 'cauchy' No No
- ================ ============== ========== =====================
- The following provides a short description from [1]_ for each
- routine.
- qagse
- is an integrator based on globally adaptive interval
- subdivision in connection with extrapolation, which will
- eliminate the effects of integrand singularities of
- several types. The integration is is performed using a 21-point Gauss-Kronrod
- quadrature within each subinterval.
- qagie
- handles integration over infinite intervals. The infinite range is
- mapped onto a finite interval and subsequently the same strategy as
- in ``QAGS`` is applied.
- qagpe
- serves the same purposes as QAGS, but also allows the
- user to provide explicit information about the location
- and type of trouble-spots i.e. the abscissae of internal
- singularities, discontinuities and other difficulties of
- the integrand function.
- qawoe
- is an integrator for the evaluation of
- :math:`\int^b_a \cos(\omega x)f(x)dx` or
- :math:`\int^b_a \sin(\omega x)f(x)dx`
- over a finite interval [a,b], where :math:`\omega` and :math:`f`
- are specified by the user. The rule evaluation component is based
- on the modified Clenshaw-Curtis technique
- An adaptive subdivision scheme is used in connection
- with an extrapolation procedure, which is a modification
- of that in ``QAGS`` and allows the algorithm to deal with
- singularities in :math:`f(x)`.
- qawfe
- calculates the Fourier transform
- :math:`\int^\infty_a \cos(\omega x)f(x)dx` or
- :math:`\int^\infty_a \sin(\omega x)f(x)dx`
- for user-provided :math:`\omega` and :math:`f`. The procedure of
- ``QAWO`` is applied on successive finite intervals, and convergence
- acceleration by means of the :math:`\varepsilon`-algorithm is applied
- to the series of integral approximations.
- qawse
- approximate :math:`\int^b_a w(x)f(x)dx`, with :math:`a < b` where
- :math:`w(x) = (x-a)^{\alpha}(b-x)^{\beta}v(x)` with
- :math:`\alpha,\beta > -1`, where :math:`v(x)` may be one of the
- following functions: :math:`1`, :math:`\log(x-a)`, :math:`\log(b-x)`,
- :math:`\log(x-a)\log(b-x)`.
- The user specifies :math:`\alpha`, :math:`\beta` and the type of the
- function :math:`v`. A globally adaptive subdivision strategy is
- applied, with modified Clenshaw-Curtis integration on those
- subintervals which contain `a` or `b`.
- qawce
- compute :math:`\int^b_a f(x) / (x-c)dx` where the integral must be
- interpreted as a Cauchy principal value integral, for user specified
- :math:`c` and :math:`f`. The strategy is globally adaptive. Modified
- Clenshaw-Curtis integration is used on those intervals containing the
- point :math:`x = c`.
- References
- ----------
- .. [1] Piessens, Robert; de Doncker-Kapenga, Elise;
- Überhuber, Christoph W.; Kahaner, David (1983).
- QUADPACK: A subroutine package for automatic integration.
- Springer-Verlag.
- ISBN 978-3-540-12553-2.
- Examples
- --------
- Calculate
- .. math::
- \int^{1}_{-0.15} \int^{0.8}_{0.13} \int^{1}_{-1} \int^{1}_{0}
- f(x_0, x_1, x_2, x_3) \,dx_0 \,dx_1 \,dx_2 \,dx_3 ,
- where
- .. math::
- f(x_0, x_1, x_2, x_3) = \begin{cases}
- x_0^2+x_1 x_2-x_3^3+ \sin{x_0}+1 & (x_0-0.2 x_3-0.5-0.25 x_1 > 0) \\
- x_0^2+x_1 x_2-x_3^3+ \sin{x_0}+0 & (x_0-0.2 x_3-0.5-0.25 x_1 \leq 0)
- \end{cases} .
- >>> import numpy as np
- >>> from scipy import integrate
- >>> func = lambda x0,x1,x2,x3 : x0**2 + x1*x2 - x3**3 + np.sin(x0) + (
- ... 1 if (x0-.2*x3-.5-.25*x1>0) else 0)
- >>> def opts0(*args, **kwargs):
- ... return {'points':[0.2*args[2] + 0.5 + 0.25*args[0]]}
- >>> integrate.nquad(func, [[0,1], [-1,1], [.13,.8], [-.15,1]],
- ... opts=[opts0,{},{},{}], full_output=True)
- (1.5267454070738633, 2.9437360001402324e-14, {'neval': 388962})
- Calculate
- .. math::
- \int^{t_0+t_1+1}_{t_0+t_1-1}
- \int^{x_2+t_0^2 t_1^3+1}_{x_2+t_0^2 t_1^3-1}
- \int^{t_0 x_1+t_1 x_2+1}_{t_0 x_1+t_1 x_2-1}
- f(x_0,x_1, x_2,t_0,t_1)
- \,dx_0 \,dx_1 \,dx_2,
- where
- .. math::
- f(x_0, x_1, x_2, t_0, t_1) = \begin{cases}
- x_0 x_2^2 + \sin{x_1}+2 & (x_0+t_1 x_1-t_0 > 0) \\
- x_0 x_2^2 +\sin{x_1}+1 & (x_0+t_1 x_1-t_0 \leq 0)
- \end{cases}
- and :math:`(t_0, t_1) = (0, 1)` .
- >>> def func2(x0, x1, x2, t0, t1):
- ... return x0*x2**2 + np.sin(x1) + 1 + (1 if x0+t1*x1-t0>0 else 0)
- >>> def lim0(x1, x2, t0, t1):
- ... return [t0*x1 + t1*x2 - 1, t0*x1 + t1*x2 + 1]
- >>> def lim1(x2, t0, t1):
- ... return [x2 + t0**2*t1**3 - 1, x2 + t0**2*t1**3 + 1]
- >>> def lim2(t0, t1):
- ... return [t0 + t1 - 1, t0 + t1 + 1]
- >>> def opts0(x1, x2, t0, t1):
- ... return {'points' : [t0 - t1*x1]}
- >>> def opts1(x2, t0, t1):
- ... return {}
- >>> def opts2(t0, t1):
- ... return {}
- >>> integrate.nquad(func2, [lim0, lim1, lim2], args=(0,1),
- ... opts=[opts0, opts1, opts2])
- (36.099919226771625, 1.8546948553373528e-07)
- """
- depth = len(ranges)
- ranges = [rng if callable(rng) else _RangeFunc(rng) for rng in ranges]
- if args is None:
- args = ()
- if opts is None:
- opts = [dict([])] * depth
- if isinstance(opts, dict):
- opts = [_OptFunc(opts)] * depth
- else:
- opts = [opt if callable(opt) else _OptFunc(opt) for opt in opts]
- return _NQuad(func, ranges, opts, full_output).integrate(*args)
- class _RangeFunc:
- def __init__(self, range_):
- self.range_ = range_
- def __call__(self, *args):
- """Return stored value.
- *args needed because range_ can be float or func, and is called with
- variable number of parameters.
- """
- return self.range_
- class _OptFunc:
- def __init__(self, opt):
- self.opt = opt
- def __call__(self, *args):
- """Return stored dict."""
- return self.opt
- class _NQuad:
- def __init__(self, func, ranges, opts, full_output):
- self.abserr = 0
- self.func = func
- self.ranges = ranges
- self.opts = opts
- self.maxdepth = len(ranges)
- self.full_output = full_output
- if self.full_output:
- self.out_dict = {'neval': 0}
- def integrate(self, *args, **kwargs):
- depth = kwargs.pop('depth', 0)
- if kwargs:
- raise ValueError('unexpected kwargs')
- # Get the integration range and options for this depth.
- ind = -(depth + 1)
- fn_range = self.ranges[ind]
- low, high = fn_range(*args)
- fn_opt = self.opts[ind]
- opt = dict(fn_opt(*args))
- if 'points' in opt:
- opt['points'] = [x for x in opt['points'] if low <= x <= high]
- if depth + 1 == self.maxdepth:
- f = self.func
- else:
- f = partial(self.integrate, depth=depth+1)
- quad_r = quad(f, low, high, args=args, full_output=self.full_output,
- **opt)
- value = quad_r[0]
- abserr = quad_r[1]
- if self.full_output:
- infodict = quad_r[2]
- # The 'neval' parameter in full_output returns the total
- # number of times the integrand function was evaluated.
- # Therefore, only the innermost integration loop counts.
- if depth + 1 == self.maxdepth:
- self.out_dict['neval'] += infodict['neval']
- self.abserr = max(self.abserr, abserr)
- if depth > 0:
- return value
- else:
- # Final result of N-D integration with error
- if self.full_output:
- return value, self.abserr, self.out_dict
- else:
- return value, self.abserr
|