Ejemplo n.º 1
0
void
_arb_poly_mullow_block(arb_ptr z, arb_srcptr x, slong xlen,
                       arb_srcptr y, slong ylen, slong n, slong prec)
{
    slong xmlen, xrlen, ymlen, yrlen, i;
    fmpz *xz, *yz, *zz;
    fmpz *xe, *ye;
    slong *xblocks, *yblocks;
    int squaring;
    fmpz_t scale, t;

    xlen = FLINT_MIN(xlen, n);
    ylen = FLINT_MIN(ylen, n);

    squaring = (x == y) && (xlen == ylen);

    /* Strip trailing zeros */
    xmlen = xrlen = xlen;
    while (xmlen > 0 && arf_is_zero(arb_midref(x + xmlen - 1))) xmlen--;
    while (xrlen > 0 && mag_is_zero(arb_radref(x + xrlen - 1))) xrlen--;

    if (squaring)
    {
        ymlen = xmlen;
        yrlen = xrlen;
    }
    else
    {
        ymlen = yrlen = ylen;
        while (ymlen > 0 && arf_is_zero(arb_midref(y + ymlen - 1))) ymlen--;
        while (yrlen > 0 && mag_is_zero(arb_radref(y + yrlen - 1))) yrlen--;
    }

    /* We don't know how to deal with infinities or NaNs */
    if (!_arb_vec_is_finite(x, xlen) ||
            (!squaring && !_arb_vec_is_finite(y, ylen)))
    {
        _arb_poly_mullow_classical(z, x, xlen, y, ylen, n, prec);
        return;
    }

    xlen = FLINT_MAX(xmlen, xrlen);
    ylen = FLINT_MAX(ymlen, yrlen);

    /* Start with the zero polynomial */
    _arb_vec_zero(z, n);

    /* Nothing to do */
    if (xlen == 0 || ylen == 0)
        return;

    n = FLINT_MIN(n, xlen + ylen - 1);

    fmpz_init(scale);
    fmpz_init(t);
    xz = _fmpz_vec_init(xlen);
    yz = _fmpz_vec_init(ylen);
    zz = _fmpz_vec_init(n);
    xe = _fmpz_vec_init(xlen);
    ye = _fmpz_vec_init(ylen);
    xblocks = flint_malloc(sizeof(slong) * (xlen + 1));
    yblocks = flint_malloc(sizeof(slong) * (ylen + 1));

    _arb_poly_get_scale(scale, x, xlen, y, ylen);

    /* Error propagation */
    /* (xm + xr)*(ym + yr) = (xm*ym) + (xr*ym + xm*yr + xr*yr)
                           = (xm*ym) + (xm*yr + xr*(ym + yr))  */
    if (xrlen != 0 || yrlen != 0)
    {
        mag_ptr tmp;
        double *xdbl, *ydbl;

        tmp = _mag_vec_init(FLINT_MAX(xlen, ylen));
        xdbl = flint_malloc(sizeof(double) * xlen);
        ydbl = flint_malloc(sizeof(double) * ylen);

        /* (xm + xr)^2 = (xm*ym) + (xr^2 + 2 xm xr)
                       = (xm*ym) + xr*(2 xm + xr)    */
        if (squaring)
        {
            _mag_vec_get_fmpz_2exp_blocks(xz, xdbl, xe, xblocks, scale, x, NULL, xrlen);

            for (i = 0; i < xlen; i++)
            {
                arf_get_mag(tmp + i, arb_midref(x + i));
                mag_mul_2exp_si(tmp + i, tmp + i, 1);
                mag_add(tmp + i, tmp + i, arb_radref(x + i));
            }

            _mag_vec_get_fmpz_2exp_blocks(yz, ydbl, ye, yblocks, scale, NULL, tmp, xlen);
            _arb_poly_addmullow_rad(z, zz, xz, xdbl, xe, xblocks, xrlen, yz, ydbl, ye, yblocks, xlen, n);
        }
        else if (yrlen == 0)
        {
            /* xr * |ym| */
            _mag_vec_get_fmpz_2exp_blocks(xz, xdbl, xe, xblocks, scale, x, NULL, xrlen);

            for (i = 0; i < ymlen; i++)
                arf_get_mag(tmp + i, arb_midref(y + i));

            _mag_vec_get_fmpz_2exp_blocks(yz, ydbl, ye, yblocks, scale, NULL, tmp, ymlen);
            _arb_poly_addmullow_rad(z, zz, xz, xdbl, xe, xblocks, xrlen, yz, ydbl, ye, yblocks, ymlen, n);
        }
        else
        {
            /* |xm| * yr */
            for (i = 0; i < xmlen; i++)
                arf_get_mag(tmp + i, arb_midref(x + i));

            _mag_vec_get_fmpz_2exp_blocks(xz, xdbl, xe, xblocks, scale, NULL, tmp, xmlen);
            _mag_vec_get_fmpz_2exp_blocks(yz, ydbl, ye, yblocks, scale, y, NULL, yrlen);
            _arb_poly_addmullow_rad(z, zz, xz, xdbl, xe, xblocks, xmlen, yz, ydbl, ye, yblocks, yrlen, n);

            /* xr*(|ym| + yr) */
            if (xrlen != 0)
            {
                _mag_vec_get_fmpz_2exp_blocks(xz, xdbl, xe, xblocks, scale, x, NULL, xrlen);

                for (i = 0; i < ylen; i++)
                    arb_get_mag(tmp + i, y + i);

                _mag_vec_get_fmpz_2exp_blocks(yz, ydbl, ye, yblocks, scale, NULL, tmp, ylen);
                _arb_poly_addmullow_rad(z, zz, xz, xdbl, xe, xblocks, xrlen, yz, ydbl, ye, yblocks, ylen, n);
            }
        }

        _mag_vec_clear(tmp, FLINT_MAX(xlen, ylen));
        flint_free(xdbl);
        flint_free(ydbl);
    }

    /* multiply midpoints */
    if (xmlen != 0 && ymlen != 0)
    {
        _arb_vec_get_fmpz_2exp_blocks(xz, xe, xblocks, scale, x, xmlen, prec);

        if (squaring)
        {
            _arb_poly_addmullow_block(z, zz, xz, xe, xblocks, xmlen, xz, xe, xblocks, xmlen, n, prec, 1);
        }
        else
        {
            _arb_vec_get_fmpz_2exp_blocks(yz, ye, yblocks, scale, y, ymlen, prec);
            _arb_poly_addmullow_block(z, zz, xz, xe, xblocks, xmlen, yz, ye, yblocks, ymlen, n, prec, 0);
        }
    }

    /* Unscale. */
    if (!fmpz_is_zero(scale))
    {
        fmpz_zero(t);
        for (i = 0; i < n; i++)
        {
            arb_mul_2exp_fmpz(z + i, z + i, t);
            fmpz_add(t, t, scale);
        }
    }

    _fmpz_vec_clear(xz, xlen);
    _fmpz_vec_clear(yz, ylen);
    _fmpz_vec_clear(zz, n);
    _fmpz_vec_clear(xe, xlen);
    _fmpz_vec_clear(ye, ylen);
    flint_free(xblocks);
    flint_free(yblocks);
    fmpz_clear(scale);
    fmpz_clear(t);
}
Ejemplo n.º 2
0
void
acb_hypgeom_pfq_series_direct(acb_poly_t res,
    const acb_poly_struct * a, long p,
    const acb_poly_struct * b, long q,
    const acb_poly_t z, int regularized,
    long n, long len, long prec)
{
    acb_poly_t s, t, err;
    arb_poly_t C, T;
    long i;
    int is_real;
    int terminating;

    /* default algorithm to choose number of terms */
    if (n < 0)
    {
        n = acb_hypgeom_pfq_series_choose_n(a, p, b, q, z, len, prec);
    }

    terminating = 0;

    /* check if it terminates due to a root of the numerator */
    for (i = 0; i < p; i++)
    {
        if (acb_poly_length(a + i) == 0 && n > 0)
        {
            terminating = 1;
        }
        else if (acb_poly_length(a + i) == 1)
        {
            acb_srcptr c = acb_poly_get_coeff_ptr(a + i, 0);

            if (acb_is_int(c) && arb_is_negative(acb_realref(c)) &&
                arf_cmpabs_ui(arb_midref(acb_realref(c)), n) < 0)
            {
                terminating = 1;
            }
        }
    }

    /* check if it terminates (to order n) due to z */
    /* the following tests could be made stronger... */
    if (z->length == 0 && n >= 1)
    {
        terminating = 1;
    }
    else if (!terminating && z->length > 0 && acb_is_zero(z->coeffs) && n >= len)
    {
        if (regularized)
        {
            terminating = 1;
        }
        else
        {
            terminating = 1;

            for (i = 0; i < q; i++)
            {
                acb_srcptr c = acb_poly_get_coeff_ptr(b + i, 0);

                if (!arb_is_positive(acb_realref(c)) && acb_contains_int(c))
                    terminating = 0;
            }
        }
    }

    acb_poly_init(s);
    acb_poly_init(t);
    acb_poly_init(err);
    arb_poly_init(C);
    arb_poly_init(T);

    acb_hypgeom_pfq_series_sum_forward(s, t, a, p, b, q, z, regularized, n, len, prec);

    if (!terminating)
    {
        is_real = acb_poly_is_real(z);
        for (i = 0; i < p; i++)
            is_real = is_real && acb_poly_is_real(a + i);
        for (i = 0; i < q; i++)
            is_real = is_real && acb_poly_is_real(b + i);

        acb_poly_majorant(T, t, MAG_BITS);
        acb_hypgeom_pfq_series_bound_factor(C, a, p, b, q, z, n, len, MAG_BITS);

        if (!_arb_vec_is_finite(T->coeffs, T->length) ||
            !_arb_vec_is_finite(C->coeffs, C->length))
        {
            arb_poly_fit_length(T, len);
            _arb_vec_indeterminate(T->coeffs, len);
            _arb_poly_set_length(T, len);
        }
        else
        {
            arb_poly_mullow(T, T, C, len, MAG_BITS);
        }

        /* create polynomial of errors */
        acb_poly_fit_length(err, len);

        for (i = 0; i < FLINT_MIN(len, T->length); i++)
        {
            arb_add_error(acb_realref(err->coeffs + i), T->coeffs + i);
            if (!is_real)
                arb_add_error(acb_imagref(err->coeffs + i), T->coeffs + i);
        }

        _acb_poly_set_length(err, len);
        _acb_poly_normalise(err);

        acb_poly_add(s, s, err, prec);
    }

    acb_poly_set(res, s);

    acb_poly_clear(s);
    acb_poly_clear(t);
    acb_poly_clear(err);
    arb_poly_clear(C);
    arb_poly_clear(T);
}