Beispiel #1
0
/* Differential equation for F(a,b,c,y+z):

   (y+z)(y-1+z) F''(z) + ((y+z)(a+b+1) - c) F'(z) + a b F(z) = 0

   Coefficients in the Taylor series are bounded by

       A * binomial(N+k, k) * nu^k

   using the Cauchy-Kovalevskaya majorant method.
   See J. van der Hoeven, "Fast evaluation of holonomic functions near
   and in regular singularities"
*/
static void
bound(mag_t A, mag_t nu, mag_t N,
    const acb_t a, const acb_t b, const acb_t c, const acb_t y,
    const acb_t f0, const acb_t f1)
{
    mag_t M0, M1, t, u;
    acb_t d;

    acb_init(d);
    mag_init(M0);
    mag_init(M1);
    mag_init(t);
    mag_init(u);

    /* nu = max(1/|y-1|, 1/|y|) = 1/min(|y-1|, |y|) */
    acb_get_mag_lower(t, y);
    acb_sub_ui(d, y, 1, MAG_BITS);
    acb_get_mag_lower(u, d);
    mag_min(t, t, u);
    mag_one(u);
    mag_div(nu, u, t);

    /* M0 = 2 nu |ab| */
    acb_get_mag(t, a);
    acb_get_mag(u, b);
    mag_mul(M0, t, u);
    mag_mul(M0, M0, nu);
    mag_mul_2exp_si(M0, M0, 1);

    /* M1 = 2 nu |(a+b+1)y-c| + 2|a+b+1| */
    acb_add(d, a, b, MAG_BITS);
    acb_add_ui(d, d, 1, MAG_BITS);
    acb_get_mag(t, d);
    acb_mul(d, d, y, MAG_BITS);
    acb_sub(d, d, c, MAG_BITS);
    acb_get_mag(u, d);
    mag_mul(u, u, nu);
    mag_add(M1, t, u);
    mag_mul_2exp_si(M1, M1, 1);

    /* N = max(sqrt(2 M0), 2 M1) / nu */
    mag_mul_2exp_si(M0, M0, 1);
    mag_sqrt(M0, M0);
    mag_mul_2exp_si(M1, M1, 1);
    mag_max(N, M0, M1);
    mag_div(N, N, nu);

    /* A = max(|f0|, |f1| / (nu (N+1)) */
    acb_get_mag(t, f0);
    acb_get_mag(u, f1);
    mag_div(u, u, nu);
    mag_div(u, u, N);  /* upper bound for dividing by N+1 */
    mag_max(A, t, u);

    acb_clear(d);
    mag_clear(M0);
    mag_clear(M1);
    mag_clear(t);
    mag_clear(u);
}
void
acb_get_mag(mag_t u, const acb_t z)
{
    if (arb_is_zero(acb_imagref(z)))
    {
        arb_get_mag(u, acb_realref(z));
    }
    else if (arb_is_zero(acb_realref(z)))
    {
        arb_get_mag(u, acb_imagref(z));
    }
    else
    {
        mag_t v;
        mag_init(v);

        arb_get_mag(u, acb_realref(z));
        arb_get_mag(v, acb_imagref(z));

        mag_mul(u, u, u);
        mag_addmul(u, v, v);
        mag_sqrt(u, u);

        mag_clear(v);
    }
}
Beispiel #3
0
void
mag_root(mag_t y, const mag_t x, ulong n)
{
    if (n == 0)
    {
        mag_inf(y);
    }
    else if (n == 1 || mag_is_special(x))
    {
        mag_set(y, x);
    }
    else if (n == 2)
    {
        mag_sqrt(y, x);
    }
    else if (n == 4)
    {
        mag_sqrt(y, x);
        mag_sqrt(y, y);
    }
    else
    {
        fmpz_t e, f;

        fmpz_init_set_ui(e, MAG_BITS);
        fmpz_init(f);

        /* We evaluate exp(log(1+2^(kn)x)/n) 2^-k where k is chosen
           so that 2^(kn) x ~= 2^30. TODO: this rewriting is probably
           unnecessary with the new exp/log functions. */
        fmpz_sub(e, e, MAG_EXPREF(x));
        fmpz_cdiv_q_ui(e, e, n);
        fmpz_mul_ui(f, e, n);
        mag_mul_2exp_fmpz(y, x, f);
        mag_log1p(y, y);
        mag_div_ui(y, y, n);
        mag_exp(y, y);
        fmpz_neg(e, e);
        mag_mul_2exp_fmpz(y, y, e);

        fmpz_clear(e);
        fmpz_clear(f);
    }
}
void
acb_rising_ui_get_mag(mag_t bound, const acb_t s, ulong n)
{
    if (n == 0)
    {
        mag_one(bound);
        return;
    }

    if (n == 1)
    {
        acb_get_mag(bound, s);
        return;
    }

    if (!acb_is_finite(s))
    {
        mag_inf(bound);
        return;
    }

    if (arf_sgn(arb_midref(acb_realref(s))) >= 0)
    {
        acb_rising_get_mag2_right(bound, acb_realref(s), acb_imagref(s), n);
    }
    else
    {
        arb_t a;
        long k;
        mag_t bound2, t, u;

        arb_init(a);
        mag_init(bound2);
        mag_init(t);
        mag_init(u);

        arb_get_mag(u, acb_imagref(s));
        mag_mul(u, u, u);
        mag_one(bound);

        for (k = 0; k < n; k++)
        {
            arb_add_ui(a, acb_realref(s), k, MAG_BITS);

            if (arf_sgn(arb_midref(a)) >= 0)
            {
                acb_rising_get_mag2_right(bound2, a, acb_imagref(s), n - k);
                mag_mul(bound, bound, bound2);
                break;
            }
            else
            {
                arb_get_mag(t, a);
                mag_mul(t, t, t);
                mag_add(t, t, u);
                mag_mul(bound, bound, t);
            }
        }

        arb_clear(a);
        mag_clear(bound2);
        mag_clear(t);
        mag_clear(u);
    }

    mag_sqrt(bound, bound);
}