Beispiel #1
0
void
_acb_poly_atan_series(acb_ptr g, acb_srcptr h, slong hlen, slong n, slong prec)
{
    acb_t c;
    acb_init(c);

    acb_atan(c, h, prec);

    hlen = FLINT_MIN(hlen, n);

    if (hlen == 1)
    {
        _acb_vec_zero(g + 1, n - 1);
    }
    else
    {
        acb_ptr t, u;
        slong ulen;

        t = _acb_vec_init(n);
        u = _acb_vec_init(n);

        /* atan(h(x)) = integral(h'(x)/(1+h(x)^2)) */
        ulen = FLINT_MIN(n, 2 * hlen - 1);
        _acb_poly_mullow(u, h, hlen, h, hlen, ulen, prec);
        acb_add_ui(u, u, 1, prec);

        _acb_poly_derivative(t, h, hlen, prec);
        _acb_poly_div_series(g, t, hlen - 1, u, ulen, n, prec);
        _acb_poly_integral(g, g, n, prec);

        _acb_vec_clear(t, n);
        _acb_vec_clear(u, n);
    }

    acb_swap(g, c);
    acb_clear(c);
}
Beispiel #2
0
void
_acb_poly_lgamma_series(acb_ptr res, acb_srcptr h, slong hlen, slong len, slong prec)
{
    int reflect;
    slong i, r, n, wp;
    acb_t zr;
    acb_ptr t, u;

    hlen = FLINT_MIN(hlen, len);

    if (hlen == 1)
    {
        acb_lgamma(res, h, prec);
        if (acb_is_finite(res))
            _acb_vec_zero(res + 1, len - 1);
        else
            _acb_vec_indeterminate(res + 1, len - 1);
        return;
    }

    if (len == 2)
    {
        acb_t v;
        acb_init(v);
        acb_set(v, h + 1);
        acb_digamma(res + 1, h, prec);
        acb_lgamma(res, h, prec);
        acb_mul(res + 1, res + 1, v, prec);
        acb_clear(v);
        return;
    }

    /* use real code for real input and output */
    if (_acb_vec_is_real(h, hlen) && arb_is_positive(acb_realref(h)))
    {
        arb_ptr tmp = _arb_vec_init(len);
        for (i = 0; i < hlen; i++)
            arb_set(tmp + i, acb_realref(h + i));
        _arb_poly_lgamma_series(tmp, tmp, hlen, len, prec);
        for (i = 0; i < len; i++)
            acb_set_arb(res + i, tmp + i);
        _arb_vec_clear(tmp, len);
        return;
    }

    wp = prec + FLINT_BIT_COUNT(prec);

    t = _acb_vec_init(len);
    u = _acb_vec_init(len);
    acb_init(zr);

    /* use Stirling series */
    acb_gamma_stirling_choose_param(&reflect, &r, &n, h, 1, 0, wp);

    if (reflect)
    {
        /* log gamma(h+x) = log rf(1-(h+x), r) - log gamma(1-(h+x)+r) - log sin(pi (h+x)) + log(pi) */
        if (r != 0) /* otherwise t = 0 */
        {
            acb_sub_ui(u, h, 1, wp);
            acb_neg(u, u);
            _log_rising_ui_series(t, u, r, len, wp);
            for (i = 1; i < len; i += 2)
                acb_neg(t + i, t + i);
        }

        acb_sub_ui(u, h, 1, wp);
        acb_neg(u, u);
        acb_add_ui(zr, u, r, wp);
        _acb_poly_gamma_stirling_eval(u, zr, n, len, wp);
        for (i = 1; i < len; i += 2)
            acb_neg(u + i, u + i);

        _acb_vec_sub(t, t, u, len, wp);

        /* log(sin) is unstable with large imaginary parts;
           cot_pi is implemented in a numerically stable way */
        acb_set(u, h);
        acb_one(u + 1);
        _acb_poly_cot_pi_series(u, u, 2, len - 1, wp);
        _acb_poly_integral(u, u, len, wp);
        acb_const_pi(u, wp);
        _acb_vec_scalar_mul(u + 1, u + 1, len - 1, u, wp);
        acb_log_sin_pi(u, h, wp);

        _acb_vec_sub(u, t, u, len, wp);

        acb_const_pi(t, wp); /* todo: constant for log pi */
        acb_log(t, t, wp);
        acb_add(u, u, t, wp);
    }
    else
    {
        /* log gamma(x) = log gamma(x+r) - log rf(x,r) */

        acb_add_ui(zr, h, r, wp);
        _acb_poly_gamma_stirling_eval(u, zr, n, len, wp);

        if (r != 0)
        {
            _log_rising_ui_series(t, h, r, len, wp);
            _acb_vec_sub(u, u, t, len, wp);
        }
    }

    /* compose with nonconstant part */
    acb_zero(t);
    _acb_vec_set(t + 1, h + 1, hlen - 1);
    _acb_poly_compose_series(res, u, len, t, hlen, len, prec);

    acb_clear(zr);
    _acb_vec_clear(t, len);
    _acb_vec_clear(u, len);
}
int
acb_calc_integrate_taylor(acb_t res,
    acb_calc_func_t func, void * param,
    const acb_t a, const acb_t b,
    const arf_t inner_radius,
    const arf_t outer_radius,
    long accuracy_goal, long prec)
{
    long num_steps, step, N, bp;
    int result;

    acb_t delta, m, x, y1, y2, sum;
    acb_ptr taylor_poly;
    arf_t err;

    acb_init(delta);
    acb_init(m);
    acb_init(x);
    acb_init(y1);
    acb_init(y2);
    acb_init(sum);
    arf_init(err);

    acb_sub(delta, b, a, prec);

    /* precision used for bounds calculations */
    bp = MAG_BITS;

    /* compute the number of steps */
    {
        arf_t t;
        arf_init(t);
        acb_get_abs_ubound_arf(t, delta, bp);
        arf_div(t, t, inner_radius, bp, ARF_RND_UP);
        arf_mul_2exp_si(t, t, -1);
        num_steps = (long) (arf_get_d(t, ARF_RND_UP) + 1.0);
        /* make sure it's not something absurd */
        num_steps = FLINT_MIN(num_steps, 10 * prec);
        num_steps = FLINT_MAX(num_steps, 1);
        arf_clear(t);
    }

    result = ARB_CALC_SUCCESS;

    acb_zero(sum);

    for (step = 0; step < num_steps; step++)
    {
        /* midpoint of subinterval */
        acb_mul_ui(m, delta, 2 * step + 1, prec);
        acb_div_ui(m, m, 2 * num_steps, prec);
        acb_add(m, m, a, prec);

        if (arb_calc_verbose)
        {
            printf("integration point %ld/%ld: ", 2 * step + 1, 2 * num_steps);
            acb_printd(m, 15); printf("\n");
        }

        /* evaluate at +/- x */
        /* TODO: exactify m, and include error in x? */
        acb_div_ui(x, delta, 2 * num_steps, prec);

        /* compute bounds and number of terms to use */
        {
            arb_t cbound, xbound, rbound;
            arf_t C, D, R, X, T;
            double DD, TT, NN;

            arb_init(cbound);
            arb_init(xbound);
            arb_init(rbound);
            arf_init(C);
            arf_init(D);
            arf_init(R);
            arf_init(X);
            arf_init(T);

            /* R is the outer radius */
            arf_set(R, outer_radius);

            /* X = upper bound for |x| */
            acb_get_abs_ubound_arf(X, x, bp);
            arb_set_arf(xbound, X);

            /* Compute C(m,R). Important subtlety: due to rounding when
               computing m, we will in general be farther than R away from
               the integration path. But since acb_calc_cauchy_bound
               actually integrates over the area traced by a complex
               interval, it will catch any extra singularities (giving
               an infinite bound). */
            arb_set_arf(rbound, outer_radius);
            acb_calc_cauchy_bound(cbound, func, param, m, rbound, 8, bp);
            arf_set_mag(C, arb_radref(cbound));
            arf_add(C, arb_midref(cbound), C, bp, ARF_RND_UP);

            /* Sanity check: we need C < inf and R > X */
            if (arf_is_finite(C) && arf_cmp(R, X) > 0)
            {
                /* Compute upper bound for D = C * R * X / (R - X) */
                arf_mul(D, C, R, bp, ARF_RND_UP);
                arf_mul(D, D, X, bp, ARF_RND_UP);
                arf_sub(T, R, X, bp, ARF_RND_DOWN);
                arf_div(D, D, T, bp, ARF_RND_UP);

                /* Compute upper bound for T = (X / R) */
                arf_div(T, X, R, bp, ARF_RND_UP);

                /* Choose N */
                /* TODO: use arf arithmetic to avoid overflow */
                /* TODO: use relative accuracy (look at |f(m)|?) */
                DD = arf_get_d(D, ARF_RND_UP);
                TT = arf_get_d(T, ARF_RND_UP);
                NN = -(accuracy_goal * 0.69314718055994530942 + log(DD)) / log(TT);
                N = NN + 0.5;
                N = FLINT_MIN(N, 100 * prec);
                N = FLINT_MAX(N, 1);

                /* Tail bound: D / (N + 1) * T^N */
                {
                    mag_t TT;
                    mag_init(TT);
                    arf_get_mag(TT, T);
                    mag_pow_ui(TT, TT, N);
                    arf_set_mag(T, TT);
                    mag_clear(TT);
                }
                arf_mul(D, D, T, bp, ARF_RND_UP);
                arf_div_ui(err, D, N + 1, bp, ARF_RND_UP);
            }
            else
            {
                N = 1;
                arf_pos_inf(err);
                result = ARB_CALC_NO_CONVERGENCE;
            }

            if (arb_calc_verbose)
            {
                printf("N = %ld; bound: ", N); arf_printd(err, 15); printf("\n");
                printf("R: "); arf_printd(R, 15); printf("\n");
                printf("C: "); arf_printd(C, 15); printf("\n");
                printf("X: "); arf_printd(X, 15); printf("\n");
            }

            arb_clear(cbound);
            arb_clear(xbound);
            arb_clear(rbound);
            arf_clear(C);
            arf_clear(D);
            arf_clear(R);
            arf_clear(X);
            arf_clear(T);
        }

        /* evaluate Taylor polynomial */
        taylor_poly = _acb_vec_init(N + 1);
        func(taylor_poly, m, param, N, prec);
        _acb_poly_integral(taylor_poly, taylor_poly, N + 1, prec);
        _acb_poly_evaluate(y2, taylor_poly, N + 1, x, prec);
        acb_neg(x, x);
        _acb_poly_evaluate(y1, taylor_poly, N + 1, x, prec);
        acb_neg(x, x);

        /* add truncation error */
        arb_add_error_arf(acb_realref(y1), err);
        arb_add_error_arf(acb_imagref(y1), err);
        arb_add_error_arf(acb_realref(y2), err);
        arb_add_error_arf(acb_imagref(y2), err);

        acb_add(sum, sum, y2, prec);
        acb_sub(sum, sum, y1, prec);

        if (arb_calc_verbose)
        {
            printf("values:  ");
            acb_printd(y1, 15); printf("  ");
            acb_printd(y2, 15); printf("\n");
        }

        _acb_vec_clear(taylor_poly, N + 1);

        if (result == ARB_CALC_NO_CONVERGENCE)
            break;
    }

    acb_set(res, sum);

    acb_clear(delta);
    acb_clear(m);
    acb_clear(x);
    acb_clear(y1);
    acb_clear(y2);
    acb_clear(sum);
    arf_clear(err);

    return result;
}