Beispiel #1
0
    def __init__(self, eps, m, verbose=False):
        # Compute abscissas and weights

        prec = Float.getdps()

        self.prec = prec
        self.eps = eps
        self.m = m
        self.h = h = Float(1) / 2**m
        self.x = []
        self.w = []

        if (eps, m) in _tscache:
            self.x, self.w = _tscache[(eps, m)]
            return

        if verbose:
            print ("calculating nodes for tanh-sinh quadrature with "
                "epsilon %s and degree %i" % (eps, m))

        Float.store()
        Float.setdps(prec + 10)

        for k in xrange(20 * 2**m + 1):
            x, w = _tsnode(k, h)
            self.x.append(x)
            self.w.append(w)
            diff = abs(self.x[-1] - Float(1))
            if diff <= eps:
                break
            if verbose and m > 6 and k % 300 == 299:
                Float.store(); Float.setdps(5)
                print "  progress", -log(diff, 10) / prec
                Float.revert()

        _tscache[(eps, m)] = self.x, self.w

        Float.revert()
Beispiel #2
0
    def __init__(self, n=None, verbose=False):
        self.n = n
        prec = dps = Float.getdps()
        self.prec = prec

        # Reuse old nodes
        if n in _gausscache:
            cacheddps, xs, ws = _gausscache[n]
            if cacheddps >= dps:
                self.x = [x for x in xs]
                self.w = [w for w in ws]
                return

        if verbose:
            print ("calculating nodes for degree-%i Gauss-Legendre "
                "quadrature..." % n)

        Float.store()
        Float.setdps(2*prec + 5)

        self.x = [None] * n
        self.w = [None] * n

        pf = polyfunc(legendre(n, 'x'), True)

        for k in xrange(n//2 + 1):
            if verbose and k % 4 == 0:
                print "  node", k, "of", n//2
            x, w = _gaussnode(pf, k, n)
            self.x[k] = x
            self.x[n-k-1] = -x
            self.w[k] = self.w[n-k-1] = w

        _gausscache[n] = (dps, self.x, self.w)

        Float.revert()
Beispiel #3
0
def nintegrate(f, a, b, method=0, maxsteps=5000, verbose=False):
    """
    Basic usage
    ===========

    nintegrate(f, a, b) numerically evaluates the integral

           - b
          |    f(x) dx.
         -   a


    The integrand f should be a callable that accepts a Float as input
    and outputs a Float or ComplexFloat; a and b should be Floats,
    numbers that can be converted to Floats, or +/- infinity.

    A simple example:

        >>> Float.setdps(15)
        >>> print nintegrate(lambda x: 2*x**2 - 4*x, 2, 3)
        2.66666666666667

    Calculating the area of a unit circle, with 30 digits:

        >>> Float.setdps(30)
        >>> print nintegrate(lambda x: 4*sqrt(1-x**2), 0, 1)
        3.14159265358979323846264338328

    The integration interval can be infinite or semi-infinite:
    
        >>> Float.setdps(15)
        >>> print nintegrate(lambda x: exp(-x)*sin(x), 0, oo)
        0.5

    Integration methods and accuracy
    ================================

    Nintegrate attempts to obtain a value that is fully accurate within
    the current working precision (i.e., correct to 15 decimal places
    at the default precision level). If nintegrate fails to reach full
    accuracy after a certain number of steps, it prints a warning
    message.

    This message signifies either that the integral is either divergent
    or, if convergent, ill-behaved. It may still be possible to
    evaluate an ill-behaved integral by increasing the 'maxsteps'
    setting, changing the integration method, and/or manually
    transforming the integrand.

    Nintegrate currently supports the following integration methods:

        method = 0  :  Gaussian quadrature (default)
        method = 1  :  tanh-sinh quadrature

    Gaussian quadrature is generally very efficient if the integration
    interval is finite and the integrand is smooth on the entire range
    (including the endpoints). It may fail if the integrand has many
    discontinuities, is highly oscillatory, or possesses integrable
    singularities.

    The tanh-sinh algorithm is often better if the integration interval
    is infinite or if singularities are present at the endpoints;
    especially at very high precision levels. It does not perform well
    if there are singularities between the endpoints or the integrand
    is bumpy or oscillatory.

    It may help to manually transform the integrand, e.g. changing
    variables to remove singularities or breaking up the integration
    interval so that singularities appear only at the endpoints.

    The 'verbose' flag can be set to track the computation's progress.
    """
    dps = Float.getdps()
    Float.store()
    Float.setdps(dps + 3)
    prec = Float.getprec()

    # Transform infinite or semi-infinite interval to a finite interval
    if a == -oo or b == oo:
        g = f
        if a == -oo and b == oo:
            def f(x):
                # make adaptive quadrature work from the left
                x = 1 - x
                return g(x) + g(Float(1)/x)/x**2 + g(-x) + g(Float(-1)/x)/(-x)**2
        elif b == oo:
            aa = Float(a)
            def f(x):
                x = 1 - x
                return g(x + aa) + g(Float(1)/x + aa)/x**2
        elif a == -oo:
            bb = Float(b)
            def f(x):
                x = 1 - x
                return g(-x + bb) + g(Float(-1)/x + bb)/(-x)**2
        a, b = Float(0), Float(1)
    else:
        a, b = Float(a), Float(b)

    eps = Float((1, -prec+4))

    if method == 0:
        degree = int(5 + dps**0.8)
        rule = CompositeGaussLegendre(degree, degree//2, verbose)
    elif method == 1:
        rule = AdaptiveTanhSinh(initial = int(3 + max(0, math.log(prec/30.0, 2))))

    else:
        Float.revert()
        raise ValueError("unknown method")

    s, err, steps = rule.adaptive(f, Float(a), Float(b), eps, steps=0, maxsteps=maxsteps, verbose=verbose)

    Float.revert()

    if not err.ae(0):
        Float.store()
        Float.setdps(1)
        print "Warning: failed to reach full accuracy.", \
            "Estimated magnitude of error: ", str(err)
        Float.revert()

    return +s