Esempio n. 1
0
 def _extrapolate(self, k, q_0, q_1, q_2):
     if k >= 4:
         q_1[k] = dea3(q_0[k - 2], q_0[k - 1], q_0[k])[0]
         q_2[k] = dea3(q_1[k - 2], q_1[k - 1], q_1[k])[0]
     elif k >= 2:
         q_1[k] = dea3(q_0[k - 2], q_0[k - 1], q_0[k])[0]
     #         # Richardson extrapolation
     #         if k >= 4:
     #             q_1[k] = richardson(q_0, k)
     #             q_2[k] = richardson(q_1, k)
     #         elif k >= 2:
     #             q_1[k] = richardson(q_0, k)
     q, err = self._get_best_estimate(k, q_0, q_1, q_2)
     return q, err
Esempio n. 2
0
 def test_dea3_on_trapz_sin(self):
     Ei = self.Ei
     [En, err] = dea3(Ei[0], Ei[1], Ei[2])
     truErr = Ei[:3] - 1.
     assert_allclose(truErr,
                     [-2.00805680e-04, -5.01999079e-05, -1.25498825e-05])
     assert_allclose(En, 1.)
     self.assertLessEqual(err, 0.00021)
Esempio n. 3
0
 def test_dea3_on_trapz_sin(self):
     e_i = self.e_i
     e_n, err = dea3(e_i[0], e_i[1], e_i[2])
     true_err = e_i[:3]-1.
     assert_allclose(true_err,
                     [-2.00805680e-04, -5.01999079e-05, -1.25498825e-05])
     assert_allclose(e_n, 1.)
     self.assertLessEqual(err, 0.00021)
 def test_dea3_on_trapz_sin(self):
     Ei = self.Ei
     [En, err] = dea3(Ei[0], Ei[1], Ei[2])
     truErr = Ei[:3]-1.
     assert_allclose(truErr,
                     [ -2.00805680e-04, -5.01999079e-05, -1.25498825e-05])
     assert_allclose(En,  1.)
     self.assertLessEqual(err, 0.00021)
 def test_dea3_on_trapz_sin(self):
     e_i = self.e_i
     e_n, err = dea3(e_i[0], e_i[1], e_i[2])
     true_err = e_i[:3] - 1.
     assert_allclose(true_err,
                     [-2.00805680e-04, -5.01999079e-05, -1.25498825e-05])
     assert_allclose(e_n, 1.)
     assert err <= 0.00021
Esempio n. 6
0
def _get_best_taylor_coefficients(bs, rs, m):
    extrap = _extrapolate(bs, rs, m)
    mvec = np.arange(m)
    if len(extrap) > 2:
        all_coefs, all_errors = dea3(extrap[:-2], extrap[1:-1], extrap[2:])
        steps = np.atleast_1d(rs[4:])[:, None] * mvec
        coefs, info = _Limit._get_best_estimate(all_coefs, all_errors, steps, (m,))
        errors = info.error_estimate
    else:
        errors = EPS / np.power(rs[2], mvec) * np.maximum(m1, m2)
        coefs = extrap[-1]
    return coefs, errors
Esempio n. 7
0
def _get_best_taylor_coefficients(bs, rs, m, max_m1m2):
    extrap = _extrapolate(bs, rs, m)
    mvec = np.arange(m)
    if len(extrap) > 2:
        all_coefs, all_errors = dea3(extrap[:-2], extrap[1:-1], extrap[2:])
        steps = np.atleast_1d(rs[4:])[:, None] * mvec
        # pylint: disable=protected-access
        coefs, info = _Limit._get_best_estimate(all_coefs, all_errors, steps, (m,))
        errors = info.error_estimate
    else:
        errors = EPS / np.power(rs[2], mvec) * max_m1m2()
        coefs = extrap[-1]
    return coefs, errors
Esempio n. 8
0
 def _wynn_extrapolate(der, steps):
     der, errors = dea3(der[0:-2], der[1:-1], der[2:], symmetric=False)
     return der, errors, steps[2:]
Esempio n. 9
0
 def _wynn_extrapolate(der, steps):
     der, errors = dea3(der[0:-2], der[1:-1], der[2:], symmetric=False)
     return der, errors, steps[2:]
Esempio n. 10
0
def taylor(fun, z0=0, n=1, r=0.0061, num_extrap=3, step_ratio=1.6, **kwds):
    """
    Return Taylor coefficients of complex analytic function using FFT

    Parameters
    ----------
    fun : callable
        function to differentiate
    z0 : real or complex scalar at which to evaluate the derivatives
    n : scalar integer, default 1
        Number of taylor coefficents to compute. Maximum number is 100.
    r : real scalar, default 0.0061
        Initial radius at which to evaluate. For well-behaved functions,
        the computation should be insensitive to the initial radius to within
        about four orders of magnitude.
    num_extrap : scalar integer, default 3
        number of extrapolation steps used in the calculation
    step_ratio : real scalar, default 1.6
        Initial grow/shrinking factor for finding the best radius.
    max_iter : scalar integer, default 30
        Maximum number of iterations
    min_iter : scalar integer, default max_iter // 2
        Minimum number of iterations before the solution may be deemed
        degenerate.  A larger number allows the algorithm to correct a bad
        initial radius.
    full_output : bool, optional
        If `full_output` is False, only the coefficents is returned (default).
        If `full_output` is True, then (coefs, status) is returned

    Returns
    -------
    coefs : ndarray
       array of taylor coefficents
    status: Optional object into which output information is written:
        degenerate: True if the algorithm was unable to bound the error
        iterations: Number of iterations executed
        function_count: Number of function calls
        final_radius: Ending radius of the algorithm
        failed: True if the maximum number of iterations was reached
        error_estimate: approximate bounds of the rounding error.

    This module uses the method of Fornberg to compute the Taylor series
    coefficents of a complex analytic function along with error bounds. The
    method uses a Fast Fourier Transform to invert function evaluations around
    a circle into Taylor series coefficients and uses Richardson Extrapolation
    to improve and bound the estimate. Unlike real-valued finite differences,
    the method searches for a desirable radius and so is reasonably insensitive
    to the initial radius-to within a number of orders of magnitude at least.
    For most cases, the default configuration is likely to succeed.

    Restrictions

    The method uses the coefficients themselves to control the truncation error,
    so the error will not be properly bounded for functions like low-order
    polynomials whose Taylor series coefficients are nearly zero. If the error
    cannot be bounded, degenerate flag will be set to true, and an answer will
    still be computed and returned but should be used with caution.

    Example
    -------

    Compute the first 6 taylor coefficients 1 / (1 - z) expanded round  z0 = 0:
    >>> import numdifftools.fornberg as ndf
    >>> import numpy as np
    >>> c, info = ndf.taylor(lambda x: 1./(1-x), z0=0, n=6, full_output=True)
    >>> np.allclose(c, np.ones(8))
    True
    >>> np.all(info.error_estimate < 1e-9)
    True
    >>> (info.function_count, info.iterations, info.failed) == (144, 18, False)
    True


    References
    ----------
    [1] Fornberg, B. (1981).
        Numerical Differentiation of Analytic Functions.
        ACM Transactions on Mathematical Software (TOMS),
        7(4), 512-526. http://doi.org/10.1145/355972.355979
    """
    max_iter = kwds.get('max_iter', 30)
    min_iter = kwds.get('min_iter', max_iter // 2)
    full_output = kwds.get('full_output', False)
    direction_changes = 0
    rs = []
    bs = []
    previous_direction = None
    degenerate = failed = False
    m = _num_taylor_coefficients(n)
    mvec = np.arange(m)
    # A factor for testing against the targeted geometric progression of
    # FFT coefficients:
    crat = m * (np.exp(np.log(1e-4) / (m - 1))) ** mvec

    # Start iterating. The goal of this loops is to select a circle radius that
    # yields a nice geometric progression of the coefficients (which controls
    # the error), and then to accumulate *three* successive approximations as a
    # function of the circle radius r so that we can perform Richardson
    # Extrapolation and zero out error terms, *greatly* improving the quality
    # of the approximation.

    num_changes = 0
    i = 0
    for i in range(max_iter):
        # print('r = %g' % (r))

        bn = np.fft.fft(fun(_circle(z0, r, m))) / m
        bs.append(bn * np.power(r, -mvec))
        rs.append(r)
        if direction_changes > 1 or degenerate:
            num_changes += 1
            # if len(rs) >= 3:
            if num_changes >= 1 + num_extrap:
                break

        if not degenerate:
            # If not degenerate, check for geometric progression in the fourier
            # transform:
            bnc = bn / crat
            m1 = np.max(np.abs(bnc[:m // 2]))
            m2 = np.max(np.abs(bnc[m // 2:]))
            # If there's an extreme mismatch, then we can consider the
            # geometric progression degenerate, whether one way or the other,
            # and just alternate directions instead of trying to target a
            # specific error bound (not ideal, but not a good reason to fail
            # catastrophically):
            #
            # Note: only consider it degenerate if we've had a chance to steer
            # the radius in the direction at least `min_iter` times:
            degenerate = i > min_iter and (m1 / m2 < 1e-8 or m2 / m1 < 1e-8)

        if degenerate:
            needs_smaller = i % 2 == 0
        else:
            needs_smaller = (m1 != m1 or m2 != m2 or m1 < m2 or
                             _poor_convergence(z0, r, fun, bn, mvec))

        if (previous_direction is not None and
                needs_smaller != previous_direction):
            direction_changes += 1

        if direction_changes > 0:
            # Once we've started changing directions, we've found our range so
            # start taking the square root of the growth factor so that
            # richardson extrapolation is well-behaved:
            step_ratio = np.sqrt(step_ratio)

        if needs_smaller:
            r /= step_ratio
        else:
            r *= step_ratio

        previous_direction = needs_smaller
    else:
        failed = True

    extrap = _extrapolate(bs, rs, m)
    if len(extrap) > 2:
        all_coefs, all_errors = dea3(extrap[:-2], extrap[1:-1], extrap[2:])
        coefs, info = _Limit._get_best_estimate(all_coefs, all_errors,
                                                np.atleast_1d(rs[4:])[:, None]*mvec, (m,))
        errors = info.error_estimate
    else:
        errors = EPS / np.power(rs[2], mvec) * np.maximum(m1, m2)
        coefs = extrap[-1]

    if full_output:
        info = _INFO(errors, degenerate, final_radius=r,
                     function_count=i * m, iterations=i, failed=failed)
        return coefs, info
    return coefs
Esempio n. 11
0
def romberg(fun, a, b, releps=1e-3, abseps=1e-3):
    """
    Numerical integration with the Romberg method

    Parameters
    ----------
    fun : callable
        function to integrate
    a, b : real scalars
        lower and upper integration limits,  respectively.
    releps, abseps : scalar, optional
        requested relative and absolute error, respectively.

    Returns
    -------
    Q : scalar
        value of integral
    abserr : scalar
        estimated absolute error of integral

    ROMBERG approximates the integral of F(X) from A to B
    using Romberg's method of integration.  The function F
    must return a vector of output values if a vector of input values is given.


    Examples
    --------
    >>> import numpy as np
    >>> [q,err] = romberg(np.sqrt,0,10,0,1e-4)
    >>> np.allclose(q, 21.08185107)
    True
    >>> err[0] < 1e-4
    True
    """
    h = b - a
    h_min = 1.0e-9
    # Max size of extrapolation table
    table_limit = max(min(np.round(np.log2(h / h_min)), 30), 3)

    rom = zeros((2, table_limit))

    rom[0, 0] = h * (fun(a) + fun(b)) / 2
    ipower = 1
    f_p = ones(table_limit) * 4

    # q_val1 = 0
    q_val2 = 0.
    q_val4 = rom[0, 0]
    abserr = q_val4
    # epstab = zeros(1,decdigs+7)
    # newflg = 1
    # [res,abserr,epstab,newflg] = dea(newflg,q_val4,abserr,epstab)
    two = 1
    one = 0
    converged = False
    for i in range(1, table_limit):
        h *= 0.5
        u_n5 = np.sum(fun(a + np.arange(1, 2 * ipower, 2) * h)) * h

        #     trapezoidal approximations
        # T2n = 0.5 * (Tn + Un) = 0.5*Tn + u_n5
        rom[two, 0] = 0.5 * rom[one, 0] + u_n5

        f_p[i] = 4 * f_p[i - 1]
        #   Richardson extrapolation
        for k in range(i):
            rom[two, k + 1] = (rom[two, k] + (rom[two, k] - rom[one, k]) /
                               (f_p[k] - 1))

        q_val1 = q_val2
        q_val2 = q_val4
        q_val4 = rom[two, i]

        if 2 <= i:
            res, abserr = dea3(q_val1, q_val2, q_val4)
            # q_val4 = res
            converged = abserr <= max(abseps, releps * abs(res))
            if converged:
                break

        # rom(1,1:i) = rom(2,1:i)
        two = one
        one = (one + 1) % 2
        ipower *= 2
    _assert(converged, "Integral did not converge to the required accuracy!")
    return res, abserr