Beispiel #1
0
static void
_arb_poly_rising_ui_series_bsplit(arb_ptr res,
    arb_srcptr f, slong flen, ulong a, ulong b,
        slong trunc, slong prec)
{
    flen = FLINT_MIN(flen, trunc);

    if (b - a == 1)
    {
        arb_add_ui(res, f, a, prec);
        _arb_vec_set(res + 1, f + 1, flen - 1);
    }
    else
    {
        arb_ptr L, R;
        slong len1, len2;

        slong m = a + (b - a) / 2;

        len1 = poly_pow_length(flen, m - a, trunc);
        len2 = poly_pow_length(flen, b - m, trunc);

        L = _arb_vec_init(len1 + len2);
        R = L + len1;

        _arb_poly_rising_ui_series_bsplit(L, f, flen, a, m, trunc, prec);
        _arb_poly_rising_ui_series_bsplit(R, f, flen, m, b, trunc, prec);

        _arb_poly_mullow(res, L, len1, R, len2,
            FLINT_MIN(trunc, len1 + len2 - 1), prec);

        _arb_vec_clear(L, len1 + len2);
    }
}
Beispiel #2
0
void
_arb_poly_log1p_series(arb_ptr res, arb_srcptr f, slong flen, slong n, slong prec)
{
    arb_t a;

    flen = FLINT_MIN(flen, n);

    arb_init(a);
    arb_log1p(a, f, prec);

    if (flen == 1)
    {
        _arb_vec_zero(res + 1, n - 1);
    }
    else if (n == 2)
    {
        arb_add_ui(res, f + 0, 1, prec);
        arb_div(res + 1, f + 1, res + 0, prec);
    }
    else if (_arb_vec_is_zero(f + 1, flen - 2))  /* f = a + bx^d */
    {
        slong i, j, d = flen - 1;

        arb_add_ui(res, f + 0, 1, prec);

        for (i = 1, j = d; j < n; j += d, i++)
        {
            if (i == 1)
                arb_div(res + j, f + d, res, prec);
            else
                arb_mul(res + j, res + j - d, res + d, prec);
            _arb_vec_zero(res + j - d + 1, flen - 2);
        }
        _arb_vec_zero(res + j - d + 1, n - (j - d + 1));

        for (i = 2, j = 2 * d; j < n; j += d, i++)
            arb_div_si(res + j, res + j, i % 2 ? i : -i, prec);
    }
    else
    {
        arb_ptr f_diff, f_inv;
        slong alloc;

        alloc = n + flen;
        f_inv = _arb_vec_init(alloc);
        f_diff = f_inv + n;

        arb_add_ui(f_diff, f, 1, prec);
        _arb_vec_set(f_diff + 1, f + 1, flen - 1);
        _arb_poly_inv_series(f_inv, f_diff, flen, n, prec);
        _arb_poly_derivative(f_diff, f, flen, prec);
        _arb_poly_mullow(res, f_inv, n - 1, f_diff, flen - 1, n - 1, prec);
        _arb_poly_integral(res, res, n, prec);

        _arb_vec_clear(f_inv, alloc);
    }

    arb_swap(res, a);
    arb_clear(a);
}
void
_arb_poly_revert_series_lagrange_fast(arb_ptr Qinv, arb_srcptr Q, long Qlen, long n, long prec)
{
    long i, j, k, m;
    arb_ptr R, S, T, tmp;
    arb_t t;

    if (n <= 2)
    {
        if (n >= 1)
            arb_zero(Qinv);
        if (n == 2)
            arb_inv(Qinv + 1, Q + 1, prec);
        return;
    }

    m = n_sqrt(n);

    arb_init(t);
    R = _arb_vec_init((n - 1) * m);
    S = _arb_vec_init(n - 1);
    T = _arb_vec_init(n - 1);

    arb_zero(Qinv);
    arb_inv(Qinv + 1, Q + 1, prec);

    _arb_poly_inv_series(Ri(1), Q + 1, FLINT_MIN(Qlen, n) - 1, n - 1, prec);
    for (i = 2; i <= m; i++)
        _arb_poly_mullow(Ri(i), Ri((i + 1) / 2), n - 1, Ri(i / 2), n - 1, n - 1, prec);

    for (i = 2; i < m; i++)
        arb_div_ui(Qinv + i, Ri(i) + i - 1, i, prec);

    _arb_vec_set(S, Ri(m), n - 1);

    for (i = m; i < n; i += m)
    {
        arb_div_ui(Qinv + i, S + i - 1, i, prec);

        for (j = 1; j < m && i + j < n; j++)
        {
            arb_mul(t, S + 0, Ri(j) + i + j - 1, prec);
            for (k = 1; k <= i + j - 1; k++)
                arb_addmul(t, S + k, Ri(j) + i + j - 1 - k, prec);
            arb_div_ui(Qinv + i + j, t, i + j, prec);
        }

        if (i + 1 < n)
        {
            _arb_poly_mullow(T, S, n - 1, Ri(m), n - 1, n - 1, prec);
            tmp = S; S = T; T = tmp;
        }
    }

    arb_clear(t);
    _arb_vec_clear(R, (n - 1) * m);
    _arb_vec_clear(S, n - 1);
    _arb_vec_clear(T, n - 1);
}
void
_arb_poly_sinh_cosh_series_exponential(arb_ptr s, arb_ptr c,
    const arb_srcptr h, slong hlen, slong len, slong prec)
{
    arb_ptr t, u, v;
    arb_t s0, c0;
    hlen = FLINT_MIN(hlen, len);

    if (hlen == 1)
    {
        arb_sinh_cosh(s, c, h, prec);
        _arb_vec_zero(s + 1, len - 1);
        _arb_vec_zero(c + 1, len - 1);
        return;
    }

    arb_init(s0);
    arb_init(c0);

    t = _arb_vec_init(3 * len);
    u = t + len;
    v = u + len;

    arb_sinh_cosh(s0, c0, h, prec);

    _arb_vec_set(t + 1, h + 1, hlen - 1);
    _arb_poly_exp_series(t, t, len, len, prec);

    /* todo: part of the inverse could be avoided since exp computes
       it internally to half the length */
    _arb_poly_inv_series(u, t, len, len, prec);

    /* hyperbolic sine */
    _arb_vec_sub(s, t, u, len, prec);
    _arb_vec_scalar_mul_2exp_si(s, s, len, -1);

    /* hyperbolic cosine */
    _arb_vec_add(c, t, u, len, prec);
    _arb_vec_scalar_mul_2exp_si(c, c, len, -1);

    /* sinh(h0 + h1) = cosh(h0) sinh(h1) + sinh(h0) cosh(h1)
       cosh(h0 + h1) = cosh(h0) cosh(h1) + sinh(h0) sinh(h1) */
    if (!arb_is_zero(s0))
    {
        _arb_vec_scalar_mul(t, s, len, c0, prec);
        _arb_vec_scalar_mul(u, c, len, s0, prec);
        _arb_vec_scalar_mul(v, s, len, s0, prec);
        _arb_vec_add(s, t, u, len, prec);
        _arb_vec_scalar_mul(t, c, len, c0, prec);
        _arb_vec_add(c, t, v, len, prec);
    }

    _arb_vec_clear(t, 3 * len);

    arb_clear(s0);
    arb_clear(c0);
}
Beispiel #5
0
void
arb_poly_set(arb_poly_t dest, const arb_poly_t src)
{
    slong len = arb_poly_length(src);

    arb_poly_fit_length(dest, len);
    _arb_vec_set(dest->coeffs, src->coeffs, len);
    _arb_poly_set_length(dest, len);
}
Beispiel #6
0
void
_arb_poly_interpolate_newton(arb_ptr poly, arb_srcptr xs,
    arb_srcptr ys, long n, long prec)
{
    if (n == 1)
    {
        arb_set(poly, ys);
    }
    else
    {
        _arb_vec_set(poly, ys, n);
        _interpolate_newton(poly, xs, n, prec);
        while (n > 0 && arb_is_zero(poly + n - 1)) n--;
        _newton_to_monomial(poly, xs, n, prec);
    }
}
Beispiel #7
0
void
cross_site_ws_update_with_edge_rates(cross_site_ws_t w,
        const model_and_data_t m, const arb_struct *edge_rates, slong prec)
{
    w->prec = prec;

    /* update rate mixture */
    rate_mixture_summarize(
            w->rate_mix_prior, w->rate_mix_rates, w->rate_mix_expect,
            m->rate_mixture, prec);

    /* update the equilibrium if necessary, ignoring diagonal entries */
    if (model_and_data_uses_equilibrium(m))
    {
        _arb_vec_rate_matrix_equilibrium(w->equilibrium, m->mat, prec);
    }

    /* update the unscaled rate matrix, and zero the diagonal */
    arb_mat_set(w->rate_matrix, m->mat);
    _arb_mat_zero_diagonal(w->rate_matrix);

    /* update the rate divisor, optionally using the equilibrium */
    _update_rate_divisor(w, m, prec);

    /*
     * Scale the rate matrix according to the rate divisor.
     * Each rate matrix associated with a specific rate category
     * and branch will need to be further scaled.
     */
    arb_mat_scalar_div_arb(w->rate_matrix,
            w->rate_matrix, w->rate_divisor, prec);

    /* update the diagonal of the rate matrix */
    _arb_update_rate_matrix_diagonal(w->rate_matrix, prec);

    /* optionally set edge rates */
    if (edge_rates)
    {
        _arb_vec_set(w->edge_rates, edge_rates, w->edge_count);
    }

    /* update the transition probability matrices */
    _update_transition_matrices(w, prec);
}
void
arb_poly_add_si(arb_poly_t res, const arb_poly_t x, long y, long prec)
{
    long len = x->length;

    if (len == 0)
    {
        arb_poly_set_si(res, y);
    }
    else
    {
        arb_poly_fit_length(res, len);

        arb_add_si(res->coeffs, x->coeffs, y, prec);

        if (res != x)
            _arb_vec_set(res->coeffs + 1, x->coeffs + 1, len - 1);

        _arb_poly_set_length(res, len);
        _arb_poly_normalise(res);
    }
}
Beispiel #9
0
void
_arb_poly_rgamma_series(arb_ptr res, arb_srcptr h, long hlen, long len, long prec)
{
    int reflect;
    long i, rflen, r, n, wp;
    arb_ptr t, u, v;
    arb_struct f[2];

    hlen = FLINT_MIN(hlen, len);
    wp = prec + FLINT_BIT_COUNT(prec);

    t = _arb_vec_init(len);
    u = _arb_vec_init(len);
    v = _arb_vec_init(len);
    arb_init(f);
    arb_init(f + 1);

    /* use zeta values at small integers */
    if (arb_is_int(h) && (arf_cmpabs_ui(arb_midref(h), prec / 2) < 0))
    {
        r = arf_get_si(arb_midref(h), ARF_RND_DOWN);

        _arb_poly_lgamma_series_at_one(u, len, wp);

        _arb_vec_neg(u, u, len);
        _arb_poly_exp_series(t, u, len, len, wp);

        if (r == 1)
        {
            _arb_vec_swap(v, t, len);
        }
        else if (r <= 0)
        {
            arb_set(f, h);
            arb_one(f + 1);
            rflen = FLINT_MIN(len, 2 - r);
            _arb_poly_rising_ui_series(u, f, FLINT_MIN(2, len), 1 - r, rflen, wp);
            _arb_poly_mullow(v, t, len, u, rflen, len, wp);
        }
        else
        {
            arb_one(f);
            arb_one(f + 1);
            rflen = FLINT_MIN(len, r);
            _arb_poly_rising_ui_series(v, f, FLINT_MIN(2, len), r - 1, rflen, wp);

            /* TODO: use div_series? */
            _arb_poly_inv_series(u, v, rflen, len, wp);
            _arb_poly_mullow(v, t, len, u, len, len, wp);
        }
    }
    else
    {
        /* otherwise use Stirling series */
        arb_gamma_stirling_choose_param(&reflect, &r, &n, h, 1, 0, wp);

        /* rgamma(h) = (gamma(1-h+r) sin(pi h)) / (rf(1-h, r) * pi), h = h0 + t*/
        if (reflect)
        {
            /* u = gamma(r+1-h) */
            arb_sub_ui(f, h, r + 1, wp);
            arb_neg(f, f);
            _arb_poly_gamma_stirling_eval(t, f, n, len, wp);
            _arb_poly_exp_series(u, t, len, len, wp);
            for (i = 1; i < len; i += 2)
                arb_neg(u + i, u + i);

            /* v = sin(pi x) */
            arb_const_pi(f + 1, wp);
            arb_mul(f, h, f + 1, wp);
            _arb_poly_sin_series(v, f, 2, len, wp);

            _arb_poly_mullow(t, u, len, v, len, len, wp);

            /* rf(1-h,r) * pi */
            if (r == 0)
            {
                arb_const_pi(u, wp);
                _arb_vec_scalar_div(v, t, len, u, wp);
            }
            else
            {
                arb_sub_ui(f, h, 1, wp);
                arb_neg(f, f);
                arb_set_si(f + 1, -1);
                rflen = FLINT_MIN(len, r + 1);
                _arb_poly_rising_ui_series(v, f, FLINT_MIN(2, len), r, rflen, wp);
                arb_const_pi(u, wp);
                _arb_vec_scalar_mul(v, v, rflen, u, wp);

                /* divide by rising factorial */
                /* TODO: might better to use div_series, when it has a good basecase */
                _arb_poly_inv_series(u, v, rflen, len, wp);
                _arb_poly_mullow(v, t, len, u, len, len, wp);
            }
        }
        else
        {
            /* rgamma(h) = rgamma(h+r) rf(h,r) */
            if (r == 0)
            {
                arb_add_ui(f, h, r, wp);
                _arb_poly_gamma_stirling_eval(t, f, n, len, wp);
                _arb_vec_neg(t, t, len);
                _arb_poly_exp_series(v, t, len, len, wp);
            }
            else
            {
                arb_set(f, h);
                arb_one(f + 1);
                rflen = FLINT_MIN(len, r + 1);
                _arb_poly_rising_ui_series(t, f, FLINT_MIN(2, len), r, rflen, wp);

                arb_add_ui(f, h, r, wp);
                _arb_poly_gamma_stirling_eval(v, f, n, len, wp);
                _arb_vec_neg(v, v, len);
                _arb_poly_exp_series(u, v, len, len, wp);

                _arb_poly_mullow(v, u, len, t, rflen, len, wp);
            }
        }
    }

    /* compose with nonconstant part */
    arb_zero(t);
    _arb_vec_set(t + 1, h + 1, hlen - 1);
    _arb_poly_compose_series(res, v, len, t, hlen, len, prec);

    arb_clear(f);
    arb_clear(f + 1);
    _arb_vec_clear(t, len);
    _arb_vec_clear(u, len);
    _arb_vec_clear(v, len);
}
Beispiel #10
0
void
_arb_poly_exp_series(arb_ptr f, arb_srcptr h, slong hlen, slong n, slong prec)
{
    hlen = FLINT_MIN(hlen, n);

    if (hlen == 1)
    {
        arb_exp(f, h, prec);
        _arb_vec_zero(f + 1, n - 1);
    }
    else if (n == 2)
    {
        arb_exp(f, h, prec);
        arb_mul(f + 1, f, h + 1, prec);  /* safe since hlen >= 2 */
    }
    else if (_arb_vec_is_zero(h + 1, hlen - 2)) /* h = a + bx^d */
    {
        slong i, j, d = hlen - 1;
        arb_t t;
        arb_init(t);
        arb_set(t, h + d);
        arb_exp(f, h, prec);
        for (i = 1, j = d; j < n; j += d, i++)
        {
            arb_mul(f + j, f + j - d, t, prec);
            arb_div_ui(f + j, f + j, i, prec);
            _arb_vec_zero(f + j - d + 1, hlen - 2);
        }
        _arb_vec_zero(f + j - d + 1, n - (j - d + 1));
        arb_clear(t);
    }
    else if (hlen <= arb_poly_newton_exp_cutoff)
    {
        _arb_poly_exp_series_basecase(f, h, hlen, n, prec);
    }
    else
    {
        arb_ptr g, t;
        arb_t u;
        int fix;

        g = _arb_vec_init((n + 1) / 2);
        fix = (hlen < n || h == f || !arb_is_zero(h));

        if (fix)
        {
            t = _arb_vec_init(n);
            _arb_vec_set(t + 1, h + 1, hlen - 1);
        }
        else
            t = (arb_ptr) h;

        arb_init(u);
        arb_exp(u, h, prec);

        _arb_poly_exp_series_newton(f, g, t, n, prec, 0, arb_poly_newton_exp_cutoff);

        if (!arb_is_one(u))
            _arb_vec_scalar_mul(f, f, n, u, prec);

        _arb_vec_clear(g, (n + 1) / 2);
        if (fix)
            _arb_vec_clear(t, n);
        arb_clear(u);
    }
}
void
_arb_poly_zeta_series(arb_ptr res, arb_srcptr h, long hlen, const arb_t a, int deflate, long len, long prec)
{
    long i;
    acb_t cs, ca;
    acb_ptr z;
    arb_ptr t, u;

    if (arb_contains_nonpositive(a))
    {
        _arb_vec_indeterminate(res, len);
        return;
    }

    hlen = FLINT_MIN(hlen, len);

    z = _acb_vec_init(len);
    t = _arb_vec_init(len);
    u = _arb_vec_init(len);
    acb_init(cs);
    acb_init(ca);

    /* use reflection formula */
    if (arf_sgn(arb_midref(h)) < 0 && arb_is_one(a))
    {
        /* zeta(s) = (2*pi)**s * sin(pi*s/2) / pi * gamma(1-s) * zeta(1-s) */
        arb_t pi;
        arb_ptr f, s1, s2, s3, s4;

        arb_init(pi);
        f = _arb_vec_init(2);
        s1 = _arb_vec_init(len);
        s2 = _arb_vec_init(len);
        s3 = _arb_vec_init(len);
        s4 = _arb_vec_init(len);

        arb_const_pi(pi, prec);

        /* s1 = (2*pi)**s */
        arb_mul_2exp_si(pi, pi, 1);
        _arb_poly_pow_cpx(s1, pi, h, len, prec);
        arb_mul_2exp_si(pi, pi, -1);

        /* s2 = sin(pi*s/2) / pi */
        arb_set(f, h);
        arb_one(f + 1);
        arb_mul_2exp_si(f, f, -1);
        arb_mul_2exp_si(f + 1, f + 1, -1);
        _arb_poly_sin_pi_series(s2, f, 2, len, prec);
        _arb_vec_scalar_div(s2, s2, len, pi, prec);

        /* s3 = gamma(1-s) */
        arb_sub_ui(f, h, 1, prec);
        arb_neg(f, f);
        arb_set_si(f + 1, -1);
        _arb_poly_gamma_series(s3, f, 2, len, prec);

        /* s4 = zeta(1-s) */
        arb_sub_ui(f, h, 1, prec);
        arb_neg(f, f);
        acb_set_arb(cs, f);
        acb_one(ca);
        _acb_poly_zeta_cpx_series(z, cs, ca, 0, len, prec);
        for (i = 0; i < len; i++)
            arb_set(s4 + i, acb_realref(z + i));
        for (i = 1; i < len; i += 2)
            arb_neg(s4 + i, s4 + i);

        _arb_poly_mullow(u, s1, len, s2, len, len, prec);
        _arb_poly_mullow(s1, s3, len, s4, len, len, prec);
        _arb_poly_mullow(t, u, len, s1, len, len, prec);

        /* add 1/(1-(s+t)) = 1/(1-s) + t/(1-s)^2 + ... */
        if (deflate)
        {
            arb_sub_ui(u, h, 1, prec);
            arb_neg(u, u);
            arb_inv(u, u, prec);
            for (i = 1; i < len; i++)
                arb_mul(u + i, u + i - 1, u, prec);
            _arb_vec_add(t, t, u, len, prec);
        }

        arb_clear(pi);
        _arb_vec_clear(f, 2);
        _arb_vec_clear(s1, len);
        _arb_vec_clear(s2, len);
        _arb_vec_clear(s3, len);
        _arb_vec_clear(s4, len);
    }
    else
    {
        acb_set_arb(cs, h);
        acb_set_arb(ca, a);
        _acb_poly_zeta_cpx_series(z, cs, ca, deflate, len, prec);
        for (i = 0; i < len; i++)
            arb_set(t + i, acb_realref(z + i));
    }

    /* compose with nonconstant part */
    arb_zero(u);
    _arb_vec_set(u + 1, h + 1, hlen - 1);
    _arb_poly_compose_series(res, t, len, u, hlen, len, prec);

    _acb_vec_clear(z, len);
    _arb_vec_clear(t, len);
    _arb_vec_clear(u, len);
    acb_init(cs);
    acb_init(ca);
}
Beispiel #12
0
void
_arb_poly_lgamma_series(arb_ptr res, arb_srcptr h, slong hlen, slong len, slong prec)
{
    int reflect;
    slong r, n, wp;
    arb_t zr;
    arb_ptr t, u;

    if (!arb_is_positive(h))
    {
        _arb_vec_indeterminate(res, len);
        return;
    }

    hlen = FLINT_MIN(hlen, len);
    wp = prec + FLINT_BIT_COUNT(prec);

    t = _arb_vec_init(len);
    u = _arb_vec_init(len);
    arb_init(zr);

    /* use zeta values at small integers */
    if (arb_is_int(h) && (arf_cmpabs_ui(arb_midref(h), prec / 2) < 0))
    {
        r = arf_get_si(arb_midref(h), ARF_RND_DOWN);

        if (r <= 0)
        {
            _arb_vec_indeterminate(res, len);
            goto cleanup;
        }
        else
        {
            _arb_poly_lgamma_series_at_one(u, len, wp);

            if (r != 1)
            {
                arb_one(zr);
                _log_rising_ui_series(t, zr, r - 1, len, wp);
                _arb_vec_add(u, u, t, len, wp);
            }
        }
    }
    else if (len <= 2)
    {
        arb_lgamma(u, h, wp);
        if (len == 2)
            arb_digamma(u + 1, h, wp);
    }
    else
    {
        /* otherwise use Stirling series */
        arb_gamma_stirling_choose_param(&reflect, &r, &n, h, 0, 0, wp);
        arb_add_ui(zr, h, r, wp);
        _arb_poly_gamma_stirling_eval(u, zr, n, len, wp);

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

    /* compose with nonconstant part */
    arb_zero(t);
    _arb_vec_set(t + 1, h + 1, hlen - 1);
    _arb_poly_compose_series(res, u, len, t, hlen, len, prec);

cleanup:
    arb_clear(zr);
    _arb_vec_clear(t, len);
    _arb_vec_clear(u, len);
}
Beispiel #13
0
void
_arb_poly_evaluate_vec_fast_precomp(arb_ptr vs, arb_srcptr poly,
                                    long plen, arb_ptr * tree, long len, long prec)
{
    long height, i, j, pow, left;
    long tree_height;
    long tlen;
    arb_ptr t, u, swap, pa, pb, pc;

    /* avoid worrying about some degenerate cases */
    if (len < 2 || plen < 2)
    {
        if (len == 1)
        {
            arb_t tmp;
            arb_init(tmp);
            arb_neg(tmp, tree[0] + 0);
            _arb_poly_evaluate(vs + 0, poly, plen, tmp, prec);
            arb_clear(tmp);
        }
        else if (len != 0 && plen == 0)
        {
            _arb_vec_zero(vs, len);
        }
        else if (len != 0 && plen == 1)
        {
            for (i = 0; i < len; i++)
                arb_set(vs + i, poly + 0);
        }
        return;
    }

    t = _arb_vec_init(len);
    u = _arb_vec_init(len);

    left = len;

    /* Initial reduction. We allow the polynomial to be larger
        or smaller than the number of points. */
    height = FLINT_BIT_COUNT(plen - 1) - 1;
    tree_height = FLINT_CLOG2(len);
    while (height >= tree_height)
        height--;
    pow = 1L << height;

    for (i = j = 0; i < len; i += pow, j += (pow + 1))
    {
        tlen = ((i + pow) <= len) ? pow : len % pow;
        _arb_poly_rem(t + i, poly, plen, tree[height] + j, tlen + 1, prec);
    }

    for (i = height - 1; i >= 0; i--)
    {
        pow = 1L << i;
        left = len;
        pa = tree[i];
        pb = t;
        pc = u;

        while (left >= 2 * pow)
        {
            _arb_poly_rem_2(pc, pb, 2 * pow, pa, pow + 1, prec);
            _arb_poly_rem_2(pc + pow, pb, 2 * pow, pa + pow + 1, pow + 1, prec);

            pa += 2 * pow + 2;
            pb += 2 * pow;
            pc += 2 * pow;
            left -= 2 * pow;
        }

        if (left > pow)
        {
            _arb_poly_rem(pc, pb, left, pa, pow + 1, prec);
            _arb_poly_rem(pc + pow, pb, left, pa + pow + 1, left - pow + 1, prec);
        }
        else if (left > 0)
            _arb_vec_set(pc, pb, left);

        swap = t;
        t = u;
        u = swap;
    }

    _arb_vec_set(vs, t, len);
    _arb_vec_clear(t, len);
    _arb_vec_clear(u, len);
}