Пример #1
0
def do_integral(expr, prec, options):
    func = expr.args[0]
    x, (xlow, xhigh) = expr.args[1][0]
    orig = mp.prec

    oldmaxprec = options.get('maxprec', DEFAULT_MAXPREC)
    options['maxprec'] = min(oldmaxprec, 2 * prec)

    try:
        mp.prec = prec + 5
        xlow = as_mpmath(xlow, prec + 15, options)
        xhigh = as_mpmath(xhigh, prec + 15, options)

        # Integration is like summation, and we can phone home from
        # the integrand function to update accuracy summation style
        # Note that this accuracy is inaccurate, since it fails
        # to account for the variable quadrature weights,
        # but it is better than nothing

        have_part = [False, False]
        max_real_term = [MINUS_INF]
        max_imag_term = [MINUS_INF]

        def f(t):
            re, im, re_acc, im_acc = evalf(func, mp.prec, {'subs': {x: t}})

            have_part[0] = re or have_part[0]
            have_part[1] = im or have_part[1]

            max_real_term[0] = max(max_real_term[0], fastlog(re))
            max_imag_term[0] = max(max_imag_term[0], fastlog(im))

            if im:
                return mpc(re or fzero, im)
            return mpf(re or fzero)

        if options.get('quad') == 'osc':
            A = C.Wild('A', exclude=[x])
            B = C.Wild('B', exclude=[x])
            D = C.Wild('D')
            m = func.match(C.cos(A * x + B) * D)
            if not m:
                m = func.match(C.sin(A * x + B) * D)
            if not m:
                raise ValueError(
                    "An integrand of the form sin(A*x+B)*f(x) "
                    "or cos(A*x+B)*f(x) is required for oscillatory quadrature"
                )
            period = as_mpmath(2 * S.Pi / m[A], prec + 15, options)
            result = quadosc(f, [xlow, xhigh], period=period)
            # XXX: quadosc does not do error detection yet
            quadrature_error = MINUS_INF
        else:
            result, quadrature_error = quadts(f, [xlow, xhigh], error=1)
            quadrature_error = fastlog(quadrature_error._mpf_)

    finally:
        options['maxprec'] = oldmaxprec
        mp.prec = orig

    if have_part[0]:
        re = result.real._mpf_
        if re == fzero:
            re = mpf_shift(fone,
                           min(-prec, -max_real_term[0], -quadrature_error))
            re_acc = -1
        else:
            re_acc = -max(max_real_term[0] - fastlog(re) - prec,
                          quadrature_error)
    else:
        re, re_acc = None, None

    if have_part[1]:
        im = result.imag._mpf_
        if im == fzero:
            im = mpf_shift(fone,
                           min(-prec, -max_imag_term[0], -quadrature_error))
            im_acc = -1
        else:
            im_acc = -max(max_imag_term[0] - fastlog(im) - prec,
                          quadrature_error)
    else:
        im, im_acc = None, None

    result = re, im, re_acc, im_acc
    return result