pyerrors.integrate

 1import numpy as np
 2from autograd import jacobian
 3from scipy.integrate import quad as squad
 4
 5from .obs import Obs, derived_observable
 6
 7
 8def quad(func, p, a, b, **kwargs):
 9    '''Performs a (one-dimensional) numeric integration of f(p, x) from a to b.
10
11    The integration is performed using scipy.integrate.quad().
12    All parameters that can be passed to scipy.integrate.quad may also be passed to this function.
13    The output is the same as for scipy.integrate.quad, the first element being an Obs.
14
15    Parameters
16    ----------
17    func : object
18        function to integrate, has to be of the form
19
20        ```python
21        import autograd.numpy as anp
22
23        def func(p, x):
24            return p[0] + p[1] * x + p[2] * anp.sinh(x)
25        ```
26        where x is the integration variable.
27    p : list of floats or Obs
28        parameters of the function func.
29    a: float or Obs
30        Lower limit of integration (use -numpy.inf for -infinity).
31    b: float or Obs
32        Upper limit of integration (use -numpy.inf for -infinity).
33    All parameters of scipy.integrate.quad
34
35    Returns
36    -------
37    y : Obs
38        The integral of func from `a` to `b`.
39    abserr : float
40        An estimate of the absolute error in the result.
41    infodict : dict
42        A dictionary containing additional information.
43        Run scipy.integrate.quad_explain() for more information.
44    message
45        A convergence message.
46    explain
47        Appended only with 'cos' or 'sin' weighting and infinite
48        integration limits, it contains an explanation of the codes in
49        infodict['ierlst']
50    '''
51
52    Np = len(p)
53    isobs = [True if isinstance(pi, Obs) else False for pi in p]
54    pval = np.array([p[i].value if isobs[i] else p[i] for i in range(Np)],)
55    pobs = [p[i] for i in range(Np) if isobs[i]]
56
57    bounds = [a, b]
58    isobs_b = [True if isinstance(bi, Obs) else False for bi in bounds]
59    bval = np.array([bounds[i].value if isobs_b[i] else bounds[i] for i in range(2)])
60    bobs = [bounds[i] for i in range(2) if isobs_b[i]]
61    bsign = [-1, 1]
62
63    ifunc = np.vectorize(lambda x: func(pval, x))
64
65    intpars = squad.__code__.co_varnames[3:3 + len(squad.__defaults__)]
66    ikwargs = {k: kwargs[k] for k in intpars if k in kwargs}
67
68    integration_result = squad(ifunc, bval[0], bval[1], **ikwargs)
69    val = integration_result[0]
70
71    jac = jacobian(func)
72
73    derivint = []
74    for i in range(Np):
75        if isobs[i]:
76            ifunc = np.vectorize(lambda x, i=i: jac(pval, x)[i])
77            derivint.append(squad(ifunc, bounds[0], bounds[1], **ikwargs)[0])
78
79    for i in range(2):
80        if isobs_b[i]:
81            derivint.append(bsign[i] * func(pval, bval[i]))
82
83    if len(derivint) == 0:
84        return integration_result
85
86    res = derived_observable(lambda x, **kwargs: 0 * (x[0] + np.finfo(np.float64).eps) * (pval[0] + np.finfo(np.float64).eps) + val, pobs + bobs, man_grad=derivint)
87
88    return (res, *integration_result[1:])
def quad(func, p, a, b, **kwargs):
 9def quad(func, p, a, b, **kwargs):
10    '''Performs a (one-dimensional) numeric integration of f(p, x) from a to b.
11
12    The integration is performed using scipy.integrate.quad().
13    All parameters that can be passed to scipy.integrate.quad may also be passed to this function.
14    The output is the same as for scipy.integrate.quad, the first element being an Obs.
15
16    Parameters
17    ----------
18    func : object
19        function to integrate, has to be of the form
20
21        ```python
22        import autograd.numpy as anp
23
24        def func(p, x):
25            return p[0] + p[1] * x + p[2] * anp.sinh(x)
26        ```
27        where x is the integration variable.
28    p : list of floats or Obs
29        parameters of the function func.
30    a: float or Obs
31        Lower limit of integration (use -numpy.inf for -infinity).
32    b: float or Obs
33        Upper limit of integration (use -numpy.inf for -infinity).
34    All parameters of scipy.integrate.quad
35
36    Returns
37    -------
38    y : Obs
39        The integral of func from `a` to `b`.
40    abserr : float
41        An estimate of the absolute error in the result.
42    infodict : dict
43        A dictionary containing additional information.
44        Run scipy.integrate.quad_explain() for more information.
45    message
46        A convergence message.
47    explain
48        Appended only with 'cos' or 'sin' weighting and infinite
49        integration limits, it contains an explanation of the codes in
50        infodict['ierlst']
51    '''
52
53    Np = len(p)
54    isobs = [True if isinstance(pi, Obs) else False for pi in p]
55    pval = np.array([p[i].value if isobs[i] else p[i] for i in range(Np)],)
56    pobs = [p[i] for i in range(Np) if isobs[i]]
57
58    bounds = [a, b]
59    isobs_b = [True if isinstance(bi, Obs) else False for bi in bounds]
60    bval = np.array([bounds[i].value if isobs_b[i] else bounds[i] for i in range(2)])
61    bobs = [bounds[i] for i in range(2) if isobs_b[i]]
62    bsign = [-1, 1]
63
64    ifunc = np.vectorize(lambda x: func(pval, x))
65
66    intpars = squad.__code__.co_varnames[3:3 + len(squad.__defaults__)]
67    ikwargs = {k: kwargs[k] for k in intpars if k in kwargs}
68
69    integration_result = squad(ifunc, bval[0], bval[1], **ikwargs)
70    val = integration_result[0]
71
72    jac = jacobian(func)
73
74    derivint = []
75    for i in range(Np):
76        if isobs[i]:
77            ifunc = np.vectorize(lambda x, i=i: jac(pval, x)[i])
78            derivint.append(squad(ifunc, bounds[0], bounds[1], **ikwargs)[0])
79
80    for i in range(2):
81        if isobs_b[i]:
82            derivint.append(bsign[i] * func(pval, bval[i]))
83
84    if len(derivint) == 0:
85        return integration_result
86
87    res = derived_observable(lambda x, **kwargs: 0 * (x[0] + np.finfo(np.float64).eps) * (pval[0] + np.finfo(np.float64).eps) + val, pobs + bobs, man_grad=derivint)
88
89    return (res, *integration_result[1:])

Performs a (one-dimensional) numeric integration of f(p, x) from a to b.

The integration is performed using scipy.integrate.quad(). All parameters that can be passed to scipy.integrate.quad may also be passed to this function. The output is the same as for scipy.integrate.quad, the first element being an Obs.

Parameters
  • func (object): function to integrate, has to be of the form

    import autograd.numpy as anp
    
    def func(p, x):
        return p[0] + p[1] * x + p[2] * anp.sinh(x)
    

    where x is the integration variable.

  • p (list of floats or Obs): parameters of the function func.
  • a (float or Obs): Lower limit of integration (use -numpy.inf for -infinity).
  • b (float or Obs): Upper limit of integration (use -numpy.inf for -infinity).
  • All parameters of scipy.integrate.quad
Returns
  • y (Obs): 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. Run scipy.integrate.quad_explain() for more 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']