Example #1
0
void
_fmpz_poly_pseudo_divrem_cohen(fmpz * Q, fmpz * R, const fmpz * A, 
                               long lenA, const fmpz * B, long lenB)
{
    const fmpz * leadB = B + (lenB - 1);
    long e, lenQ;
    fmpz_t pow;
    
    if (lenB == 1)
    {
        fmpz_init(pow);
        fmpz_pow_ui(pow, leadB, lenA - 1);
        _fmpz_vec_scalar_mul_fmpz(Q, A, lenA, pow);
        _fmpz_vec_zero(R, lenA);
        fmpz_clear(pow);
        return;
    }

    lenQ = lenA - lenB + 1;
    _fmpz_vec_zero(Q, lenQ);
    if (R != A)
        _fmpz_vec_set(R, A, lenA);
    e = lenA - lenB;
    
    /* Unroll the first run of the while loop */
    {
        fmpz_set(Q + (lenQ - 1), R + (lenA - 1));

        _fmpz_vec_scalar_mul_fmpz(R, R, lenA - 1, leadB);
        _fmpz_vec_scalar_submul_fmpz(R + (lenA - lenB), B, lenB - 1, R + (lenA - 1));
        fmpz_zero(R + (lenA - 1));

        for (lenA -= 2; (lenA >= 0) && (R[lenA] == 0L); lenA--) ;
        lenA++;
    }
    while (lenA >= lenB)
    {
        _fmpz_vec_scalar_mul_fmpz(Q, Q, lenQ, leadB);
        fmpz_add(Q + (lenA - lenB), Q + (lenA - lenB), R + (lenA - 1));

        _fmpz_vec_scalar_mul_fmpz(R, R, lenA - 1, leadB);
        _fmpz_vec_scalar_submul_fmpz(R + lenA - lenB, B, lenB - 1, R + (lenA - 1));
        fmpz_zero(R + (lenA - 1));

        for (lenA -= 2; (lenA >= 0) && (R[lenA] == 0L); lenA--) ;
        lenA++;

        e--;
    }

    fmpz_init(pow);
    fmpz_pow_ui(pow, leadB, e);
    _fmpz_vec_scalar_mul_fmpz(Q, Q, lenQ, pow);
    _fmpz_vec_scalar_mul_fmpz(R, R, lenA, pow);
    fmpz_clear(pow);
}
Example #2
0
void _qadic_exp_balanced(fmpz *rop, const fmpz *x, slong v, slong len, 
                         const fmpz *a, const slong *j, slong lena, 
                         const fmpz_t p, slong N, const fmpz_t pN)
{
    const slong d = j[lena - 1];

    fmpz_t pw;
    fmpz *r, *s, *t;
    slong i, w;

    r = _fmpz_vec_init(d);
    s = _fmpz_vec_init(2*d - 1);
    t = _fmpz_vec_init(d);
    fmpz_init(pw);

    fmpz_pow_ui(pw, p, v);
    _fmpz_vec_scalar_mul_fmpz(t, x, len, pw);
    _fmpz_vec_scalar_mod_fmpz(t, t, len, pN);
    _fmpz_vec_zero(t + len, d - len);

    fmpz_set(pw, p);
    fmpz_one(rop + 0);
    _fmpz_vec_zero(rop + 1, d - 1);
    w = 1;

    while (!_fmpz_vec_is_zero(t, d))
    {
        fmpz_mul(pw, pw, pw);

        for (i = 0; i < d; i++)
        {
            fmpz_fdiv_r(r + i, t + i, pw);
            fmpz_sub(t + i, t + i, r + i);
        }

        if (!_fmpz_vec_is_zero(r, d))
        {
            _qadic_exp_bsplit(r, r, w, d, a, j, lena, p, N);
            _fmpz_poly_mul(s, rop, d, r, d);
            _fmpz_poly_reduce(s, 2*d - 1, a, j, lena);
            _fmpz_vec_scalar_mod_fmpz(rop, s, d, pN);
        }

        w *= 2;
    }

    _fmpz_vec_clear(r, d);
    _fmpz_vec_clear(s, 2*d - 1);
    _fmpz_vec_clear(t, d);
    fmpz_clear(pw);
}
Example #3
0
void _fmpz_poly_sqrlow_KS(fmpz * res, const fmpz * poly, long len, long n)
{
    int neg;
    long bits, limbs, loglen, sign = 0;
    mp_limb_t *arr_in, *arr_out;

    FMPZ_VEC_NORM(poly, len);

    if (len == 0)
    {
        _fmpz_vec_zero(res, n);
        return;
    }

    neg = (fmpz_sgn(poly + len - 1) > 0) ? 0 : -1;

    if (n > 2 * len - 1)
    {
        _fmpz_vec_zero(res + 2 * len - 1, n - (2 * len - 1));
        n = 2 * len - 1;
    }

    bits = _fmpz_vec_max_bits(poly, len);
    if (bits < 0)
    {
        sign = 1;
        bits = - bits;
    }

    loglen = FLINT_BIT_COUNT(len);
    bits   = 2 * bits + loglen + sign;
    limbs  = (bits * len - 1) / FLINT_BITS + 1;

    arr_in  = flint_calloc(limbs, sizeof(mp_limb_t));
    arr_out = flint_malloc((2 * limbs) * sizeof(mp_limb_t));

    _fmpz_poly_bit_pack(arr_in, poly, len, bits, neg);

    mpn_sqr(arr_out, arr_in, limbs);

    if (sign)
        _fmpz_poly_bit_unpack(res, n, arr_out, bits, 0);
    else
        _fmpz_poly_bit_unpack_unsigned(res, n, arr_out, bits);

    flint_free(arr_in);
    flint_free(arr_out);
}
Example #4
0
void _fmpq_poly_scalar_mul_fmpz(fmpz * rpoly, fmpz_t rden, 
                                const fmpz * poly, const fmpz_t den, long len,
                                const fmpz_t c)
{
    fmpz_t gcd;  /* GCD( den, c ) */

    if (fmpz_is_zero(c))
    {
        _fmpz_vec_zero(rpoly, len);
        fmpz_one(rden);
        return;
    }

    fmpz_init(gcd);
    fmpz_one(gcd);
    if (*c != 1L)
        fmpz_gcd(gcd, c, den);
    if (*gcd == 1L)
    {
        _fmpz_vec_scalar_mul_fmpz(rpoly, poly, len, c);
        fmpz_set(rden, den);
    }
    else
    {
        fmpz_t c2;
        fmpz_init(c2);
        fmpz_divexact(c2, c, gcd);
        _fmpz_vec_scalar_mul_fmpz(rpoly, poly, len, c2);
        fmpz_divexact(rden, den, gcd);
        fmpz_clear(c2);
    }
    fmpz_clear(gcd);
}
Example #5
0
/* Assumes poly1 and poly2 are not length 0 and len1 >= len2. */
void
_fmpz_poly_mul_karatsuba(fmpz * res, const fmpz * poly1,
                         long len1, const fmpz * poly2, long len2)
{
    fmpz *rev1, *rev2, *out, *temp;
    long length, loglen = 0;

    if (len1 == 1)
    {
        fmpz_mul(res, poly1, poly2);
        return;
    }

    while ((1L << loglen) < len1)
        loglen++;
    length = (1L << loglen);

    rev1 = (fmpz *) flint_calloc(4 * length, sizeof(fmpz *));
    rev2 = rev1 + length;
    out  = rev1 + 2 * length;
    temp = _fmpz_vec_init(2 * length);

    revbin1(rev1, poly1, len1, loglen);
    revbin1(rev2, poly2, len2, loglen);

    _fmpz_poly_mul_kara_recursive(out, rev1, rev2, temp, loglen);

    _fmpz_vec_zero(res, len1 + len2 - 1);
    revbin2(res, out, len1 + len2 - 1, loglen + 1);

    _fmpz_vec_clear(temp, 2 * length);
    flint_free(rev1);
}
Example #6
0
int
fmpq_poly_set_str(fmpq_poly_t poly, const char * str)
{
    int ans;
    long len;

    len = atol(str);
    if (len < 0)
        return -1;
    if (len == 0)
    {
        fmpq_poly_zero(poly);
        return 0;
    }

    fmpq_poly_fit_length(poly, len);
    
    ans = _fmpq_poly_set_str(poly->coeffs, poly->den, str);
    
    if (ans == 0)
    {
        _fmpq_poly_set_length(poly, len);
        _fmpq_poly_normalise(poly);
    }
    else
    {
        _fmpz_vec_zero(poly->coeffs, len);
        fmpz_set_ui(poly->den, 1);
        _fmpq_poly_set_length(poly, 0);
    }
    
    return ans;
}
Example #7
0
void _fmpq_poly_scalar_mul_ui(fmpz * rpoly, fmpz_t rden, 
                              const fmpz * poly, const fmpz_t den, slong len, 
                              ulong c)
{
    fmpz_t gcd;  /* GCD( den, c ) */

    if (c == 0)
    {
        _fmpz_vec_zero(rpoly, len);
        fmpz_one(rden);
        return;
    }

    fmpz_init(gcd);
    fmpz_set_ui(gcd, c);
    fmpz_gcd(gcd, gcd, den);
    if (*gcd == WORD(1))
    {
        _fmpz_vec_scalar_mul_ui(rpoly, poly, len, c);
        fmpz_set(rden, den);
    }
    else
    {
        ulong gcd2 = fmpz_get_ui(gcd);
        ulong c2 = c / gcd2;
        _fmpz_vec_scalar_mul_ui(rpoly, poly, len, c2);
        fmpz_fdiv_q_ui(rden, den, gcd2);
    }
    fmpz_clear(gcd);
}
Example #8
0
void
_fmpq_poly_compose_series_horner(fmpz * res, fmpz_t den, const fmpz * poly1,
        const fmpz_t den1, long len1, const fmpz * poly2,
        const fmpz_t den2, long len2, long n)
{
    if (fmpz_is_one(den2))
    {
        _fmpz_poly_compose_series(res, poly1, len1, poly2, len2, n);
        fmpz_set(den, den1);
        _fmpq_poly_canonicalise(res, den, n);
    }
    else if (n == 1)
    {
        fmpz_set(res, poly1);
        fmpz_set(den, den1);
        _fmpq_poly_canonicalise(res, den, 1);
    }
    else
    {
        long i = len1 - 1;
        long lenr;
        fmpz_t tden;
        fmpz * t = _fmpz_vec_init(n);
        fmpz_init(tden);

        _fmpz_vec_zero(res, n);

        lenr = len2;
        _fmpq_poly_scalar_mul_fmpz(res, den, poly2, den2, len2, poly1 + i);
        _fmpq_poly_scalar_div_fmpz(res, den, res, den, len2, den1);
        i--;

        _fmpq_poly_add(res, den, res, den, len2, poly1 + i, den1, 1);
        _fmpq_poly_canonicalise(res, den, lenr);

        while (i > 0)
        {
            i--;
            if (lenr + len2 - 1 < n)
            {
                _fmpq_poly_mul(t, tden, res, den, lenr, poly2, den2, len2);
                lenr = lenr + len2 - 1;
            }
            else
            {
                _fmpq_poly_mullow(t, tden, res, den, lenr,
                                            poly2, den2, len2, n);
                lenr = n;
            }
            _fmpq_poly_canonicalise(t, tden, lenr);
            _fmpq_poly_add(res, den, t, tden, lenr, poly1 + i, den1, 1);
        }

        _fmpq_poly_canonicalise(res, den, n);

        _fmpz_vec_clear(t, n);
        fmpz_clear(tden);
    }
}
Example #9
0
int
main(void)
{
    int i, result;
    flint_rand_t state;

    printf("is_zero....");
    fflush(stdout);

    flint_randinit(state);

    /* Check zero vector */
    for (i = 0; i < 10000; i++)
    {
        fmpz *a;
        long len = n_randint(state, 100);

        a = _fmpz_vec_init(len);
        _fmpz_vec_randtest(a, state, len, 200);
        _fmpz_vec_zero(a, len);

        result = (_fmpz_vec_is_zero(a, len));
        if (!result)
        {
            printf("FAIL1:\n");
            _fmpz_vec_print(a, len), printf("\n\n");
            abort();
        }

        _fmpz_vec_clear(a, len);
    }

    /* Check non-zero vector */
    for (i = 0; i < 10000; i++)
    {
        fmpz *a;
        long len = n_randint(state, 100) + 1;

        a = _fmpz_vec_init(len);
        _fmpz_vec_randtest(a, state, len, 200);
        fmpz_set_ui(a + (len - 1), 1UL);

        result = (!_fmpz_vec_is_zero(a, len));
        if (!result)
        {
            printf("FAIL2:\n");
            _fmpz_vec_print(a, len), printf("\n\n");
            abort();
        }

        _fmpz_vec_clear(a, len);
    }

    flint_randclear(state);
    _fmpz_cleanup();
    printf("PASS\n");
    return 0;
}
Example #10
0
void 
_fmpq_poly_invsqrt_series(fmpz * rpoly, fmpz_t rden, 
                      const fmpz * poly, const fmpz_t den, long n)
{
    long m;
    fmpz * t, * u;
    fmpz_t tden, uden;

    if (n == 1)
    {
        fmpz_one(rpoly);
        fmpz_one(rden);
        return;
    }

    m = (n + 1) / 2;

    _fmpq_poly_invsqrt_series(rpoly, rden, poly, den, m);

    fmpz_init(tden);
    fmpz_init(uden);
    t = _fmpz_vec_init(n);
    u = _fmpz_vec_init(n);

    _fmpz_vec_zero(rpoly + m, n - m);

    _fmpq_poly_mul(t, tden, rpoly, rden, m, rpoly, rden, m);
    if (2*m - 1 < n)
        fmpz_zero(t + n - 1);

    _fmpq_poly_mullow(u, uden, t, tden, n, rpoly, rden, n, n);
    _fmpq_poly_mullow(t, tden, u, uden, n, poly, den, n, n);
    _fmpz_vec_neg(t + m, t + m, n - m);
    _fmpz_vec_zero(t, m);
    fmpz_mul_ui(tden, tden, 2UL);
    _fmpq_poly_canonicalise(t, tden, n);

    _fmpq_poly_add(rpoly, rden, rpoly, rden, m, t, tden, n);

    fmpz_clear(tden);
    fmpz_clear(uden);
    _fmpz_vec_clear(t, n);
    _fmpz_vec_clear(u, n);
}
Example #11
0
void
fmpz_poly_zero_coeffs(fmpz_poly_t poly, long i, long j)
{
    if (i < 0)
        i = 0;
    if (j > poly->length)
        j = poly->length;

    _fmpz_vec_zero(poly->coeffs, j - i);

    if (j == poly->length)
    {
        _fmpz_poly_set_length(poly, i);
        _fmpz_poly_normalise(poly);
    }
}
Example #12
0
void _qadic_exp(fmpz *rop, const fmpz *op, slong v, slong len, 
                           const fmpz *a, const slong *j, slong lena, 
                           const fmpz_t p, slong N, const fmpz_t pN)
{
    if (N < (WORD(1) << 13) / (slong) fmpz_bits(p))
    {
        _qadic_exp_rectangular(rop, op, v, len, a, j, lena, p, N, pN);
    }
    else
    {
        const slong d = j[lena - 1];

        _qadic_exp_balanced(rop, op, v, len, a, j, lena, p, N, pN);
        _fmpz_vec_zero(rop + d, d - 1);
    }
}
Example #13
0
void
_fmpz_poly_pow_multinomial(fmpz * res, const fmpz * poly, long len, ulong e)
{
    long k, low, rlen;
    fmpz_t d, t;
    fmpz * P;
    
    rlen = (long) e * (len - 1L) + 1L;
    _fmpz_vec_zero(res, rlen);
    
    for (low = 0L; poly[low] == 0L; low++) ;
    if (low == 0L)
    {
        P = (fmpz *) poly;
    }
    else
    {
        P = (fmpz *) poly + low;
        len  -= low;
        res  += (long) e * low;
        rlen -= (long) e * low;
    }
    
    fmpz_init(d);
    fmpz_init(t);
    
    fmpz_pow_ui(res, P, e);
    
    for (k = 1; k < rlen; k++)
    {
        long i, u = -k;
        for (i = 1; i <= FLINT_MIN(k, len - 1); i++)
        {
            fmpz_mul(t, P + i, res + (k - i));
            u += (long) e + 1;
            if (u >= 0)
                fmpz_addmul_ui(res + k, t, (ulong) u);
            else
                fmpz_submul_ui(res + k, t, - ((ulong) u));
        }
        fmpz_add(d, d, P);
        fmpz_divexact(res + k, res + k, d);
    }
    
    fmpz_clear(d);
    fmpz_clear(t);
}
Example #14
0
int dgsl_mp_call_identity(fmpz *rop,  const dgsl_mp_t *self, gmp_randstate_t state) {
  assert(rop); assert(self);

  const long n = fmpz_mat_ncols(self->B);
  mpz_t  tmp_g;  mpz_init(tmp_g);

  _fmpz_vec_zero(rop, n);

  for(long i=0; i<n; i++) {
    self->D[0]->call(tmp_g, self->D[0], state);
    fmpz_set_mpz(rop+i, tmp_g);
  }

  mpz_clear(tmp_g);

  return 0;
}
Example #15
0
void
_fmpz_poly_revert_series_newton(fmpz * Qinv, const fmpz * Q, long n)
{
    if (n <= 2)
    {
        _fmpz_vec_set(Qinv, Q, n);
        return;
    }
    else
    {
        long *a, i, k;
        fmpz *T, *U, *V;

        T = _fmpz_vec_init(n);
        U = _fmpz_vec_init(n);
        V = _fmpz_vec_init(n);

        k = n;
        for (i = 1; (1L << i) < k; i++);
        a = (long *) flint_malloc(i * sizeof(long));
        a[i = 0] = k;
        while (k >= FLINT_REVERSE_NEWTON_CUTOFF)
            a[++i] = (k = (k + 1) / 2);

        _fmpz_poly_revert_series_lagrange(Qinv, Q, k);
        _fmpz_vec_zero(Qinv + k, n - k);

        for (i--; i >= 0; i--)
        {
            k = a[i];
            _fmpz_poly_compose_series(T, Q, k, Qinv, k, k);
            _fmpz_poly_derivative(U, T, k); fmpz_zero(U + k - 1);
            fmpz_zero(T + 1);
            _fmpz_poly_div_series(V, T, U, k);
            _fmpz_poly_derivative(T, Qinv, k);
            _fmpz_poly_mullow(U, V, k, T, k, k);
            _fmpz_vec_sub(Qinv, Qinv, U, k);
        }

        flint_free(a);
        _fmpz_vec_clear(T, n);
        _fmpz_vec_clear(U, n);
        _fmpz_vec_clear(V, n);
    }
}
Example #16
0
static void 
_qadic_exp_bsplit(fmpz *y, const fmpz *x, slong v, slong len, 
                  const fmpz *a, const slong *j, slong lena, 
                  const fmpz_t p, slong N)
{
    const slong d = j[lena - 1];
    const slong n = _padic_exp_bound(v, N, p);

    if (n == 1)
    {
        fmpz_one(y + 0);
        _fmpz_vec_zero(y + 1, d - 1);
    }
    else
    {
        fmpz *P, *T;
        fmpz_t Q, R;
        slong f;

        P = _fmpz_vec_init(2*d - 1);
        T = _fmpz_vec_init(2*d - 1);
        fmpz_init(Q);
        fmpz_init(R);

        _qadic_exp_bsplit_series(P, Q, T, x, len, 1, n, a, j, lena);

        fmpz_add(T + 0, T + 0, Q);  /* (T,Q) := (T,Q) + 1 */

        /* Note exp(x) is a unit so val(T) == val(Q). */
        f = fmpz_remove(Q, Q, p);
        fmpz_pow_ui(R, p, f);
        _fmpz_vec_scalar_divexact_fmpz(T, T, d, R);

        _padic_inv(Q, Q, p, N);
        _fmpz_vec_scalar_mul_fmpz(y, T, d, Q);

        _fmpz_vec_clear(P, 2*d - 1);
        _fmpz_vec_clear(T, 2*d - 1);
        fmpz_clear(Q);
        fmpz_clear(R);
    }
}
Example #17
0
int dgsl_mp_call_inlattice(fmpz *rop,  const dgsl_mp_t *self, gmp_randstate_t state) {
  assert(rop); assert(self);

  const long m = fmpz_mat_nrows(self->B);
  const long n = fmpz_mat_ncols(self->B);
  mpz_t  tmp_g; mpz_init(tmp_g);
  fmpz_t tmp_f; fmpz_init(tmp_f);

  _fmpz_vec_zero(rop, n);

  for(long i=0; i<m; i++) {
    self->D[i]->call(tmp_g, self->D[i], state);
    fmpz_set_mpz(tmp_f, tmp_g);
    _fmpz_vec_scalar_addmul_fmpz(rop, self->B->rows[i], n, tmp_f);
  }
  _fmpz_vec_add(rop, rop, self->c_z, n);

  mpz_clear(tmp_g);
  fmpz_clear(tmp_f);

  return 0;
}
Example #18
0
void
_fmpz_poly_pseudo_divrem_basecase(fmpz * Q, fmpz * R, ulong * d,
                                  const fmpz * A, long lenA, const fmpz * B,
                                  long lenB)
{
    const fmpz * leadB = B + (lenB - 1);
    long iQ = lenA - lenB, iR = lenA - 1;
    fmpz_t rem;

    fmpz_init(rem);

    *d = 0;
    _fmpz_vec_zero(Q, lenA - lenB + 1);
    if (R != A)
        _fmpz_vec_set(R, A, lenA);

    while (iR >= lenB - 1)
    {
        fmpz_fdiv_qr(Q + iQ, rem, R + iR, leadB);
        if (!fmpz_is_zero(rem))
        {
            _fmpz_vec_scalar_mul_fmpz(Q, Q, lenA - lenB + 1, leadB);
            fmpz_set(Q + iQ, R + iR);
            _fmpz_vec_scalar_mul_fmpz(R, R, lenA, leadB);
            (*d)++;
        }

        if (lenB > 1)
            _fmpz_vec_scalar_submul_fmpz(R + (iR - lenB + 1), B, lenB - 1, Q + iQ);

        fmpz_zero(R + iR);

        iR--;
        iQ--;
    }

    fmpz_clear(rem);
}
Example #19
0
void fmpz_poly_ramanujan_tau(fmpz_poly_t res, long n)
{
    long j, k, jv, kv;
    fmpz_t tmp;
    fmpz_poly_fit_length(res, n);
    _fmpz_vec_zero(res->coeffs, n);
    _fmpz_poly_set_length(res, n);
    fmpz_init(tmp);
    for (j = jv = 0; jv < n; jv += ++j)
    {
        fmpz_set_ui(tmp, 2*j+1);
        for (k = kv = 0; jv + kv < n; kv += ++k)
        {
            if ((j+k) & 1)
                fmpz_submul_ui(res->coeffs + jv+kv, tmp, 2*k+1);
            else
                fmpz_addmul_ui(res->coeffs + jv+kv, tmp, 2*k+1);
        }
    }
    fmpz_poly_mullow(res, res, res, n-1);
    fmpz_poly_mullow(res, res, res, n-1);
    fmpz_poly_shift_left(res, res, 1);
    fmpz_clear(tmp);
}
Example #20
0
void
_fmpq_poly_exp_series(fmpz * g, fmpz_t gden,
                        const fmpz * h, const fmpz_t hden, long n)
{
    long m;
    fmpz * t, * u;
    fmpz_t tden, uden;

    if (n < 2)
    {
        fmpz_one(g);
        fmpz_one(gden);
        return;
    }

    m = (n + 1) / 2;
    _fmpq_poly_exp_series(g, gden, h, hden, m);
    _fmpz_vec_zero(g + m, n - m);

    t = _fmpz_vec_init(n);
    u = _fmpz_vec_init(n);
    fmpz_init(tden);
    fmpz_init(uden);

    _fmpq_poly_log_series(t, tden, g, gden, n);
    _fmpq_poly_sub(t, tden, t, tden, n, h, hden, n);
    /* TODO: half of product is redundant! */
    _fmpq_poly_mullow(u, uden, g, gden, n, t, tden, n, n);
    _fmpq_poly_sub(g, gden, g, gden, n, u, uden, n);
    _fmpq_poly_canonicalise(g, gden, n);

    fmpz_clear(tden);
    fmpz_clear(uden);
    _fmpz_vec_clear(t, n);
    _fmpz_vec_clear(u, n);
}
Example #21
0
/* Assumes poly1 and poly2 are not length 0. */
void
_fmpz_poly_mulhigh_classical(fmpz * res, const fmpz * poly1,
                             long len1, const fmpz * poly2, long len2,
                             long start)
{
    _fmpz_vec_zero(res, start);

    if (len1 == 1 && len2 == 1) /* Special case if the length of both inputs is 1 */
    {
        if (start == 0)
            fmpz_mul(res, poly1, poly2);
    }
    else                        /* Ordinary case */
    {
        long i, m, n;

        /* Set res[i] = poly1[i]*poly2[0] */
        if (start < len1)
            _fmpz_vec_scalar_mul_fmpz(res + start, poly1 + start, len1 - start,
                                      poly2);

        /* Set res[i+len1-1] = in1[len1-1]*in2[i] */
        m = FLINT_MAX(len1 - 1, start);
        _fmpz_vec_scalar_mul_fmpz(res + m, poly2 + m - len1 + 1,
                                  len2 - 1 + len1 - m, poly1 + len1 - 1);

        /* out[i+j] += in1[i]*in2[j] */
        m = FLINT_MAX(start, len2 - 1);
        for (i = m - len2 + 1; i < len1 - 1; i++)
        {
            n = FLINT_MAX(i + 1, start);
            _fmpz_vec_scalar_addmul_fmpz(res + n, poly2 + n - i, len2 + i - n,
                                         poly1 + i);
        }
    }
}
Example #22
0
int dgsl_mp_call_coset(fmpz *rop, const dgsl_mp_t *self, gmp_randstate_t state) {
  assert(rop); assert(self);

  const long n = fmpz_mat_ncols(self->B);
  _fmpz_vec_zero(rop, n);

  mpfr_t *c = _mpfr_vec_init(n, mpfr_get_prec(self->sigma));
  _mpfr_vec_set(c, self->c, n, MPFR_RNDN);

  mpfr_t c_prime;
  mpfr_init2(c_prime, mpfr_get_prec(self->sigma));

  mpfr_t tmp;
  mpfr_init2(tmp, mpfr_get_prec(self->sigma));

  mpfr_t sigma_prime;
  mpfr_init2(sigma_prime, mpfr_get_prec(self->sigma));

  mpz_t z;
  mpz_init(z);

  mpfr_t z_mpfr;
  mpfr_init2(z_mpfr, mpfr_get_prec(self->sigma));

  fmpz_t z_fmpz;
  fmpz_init(z_fmpz);

  size_t tau = 3;
  if (ceil(sqrt(log2((double)n))) > tau)
    tau = ceil(sqrt(log2((double)n)));

  mpfr_t *b = _mpfr_vec_init(n, mpfr_get_prec(self->sigma));

  const long m = fmpz_mat_nrows(self->B);
  for(long j=0; j<m; j++) {
    long i = m-j-1;
    _mpfr_vec_dot_product(c_prime, c,                self->G->rows[i], n, MPFR_RNDN);
    _mpfr_vec_dot_product(tmp,     self->G->rows[i], self->G->rows[i], n, MPFR_RNDN);
    mpfr_div(c_prime, c_prime, tmp, MPFR_RNDN);

    mpfr_sqrt(tmp, tmp, MPFR_RNDN);
    mpfr_div(sigma_prime, self->sigma, tmp, MPFR_RNDN);

    assert(mpfr_cmp_d(sigma_prime, 0.0) > 0);
    dgs_disc_gauss_mp_t *D = dgs_disc_gauss_mp_init(sigma_prime, c_prime, tau, DGS_DISC_GAUSS_UNIFORM_ONLINE);
    D->call(z, D, state);
    dgs_disc_gauss_mp_clear(D);

    mpfr_set_z(z_mpfr, z, MPFR_RNDN);
    mpfr_neg(z_mpfr, z_mpfr, MPFR_RNDN);
    _mpfr_vec_set_fmpz_vec(b, self->B->rows[i], n, MPFR_RNDN);
    _mpfr_vec_scalar_addmul_mpfr(c, b, n, z_mpfr, MPFR_RNDN);

    fmpz_set_mpz(z_fmpz, z);
    _fmpz_vec_scalar_addmul_fmpz(rop, self->B->rows[i], n, z_fmpz);
  }

  fmpz_clear(z_fmpz);
  mpfr_clear(z_mpfr);
  mpfr_clear(sigma_prime);
  mpfr_clear(tmp);
  mpfr_clear(c_prime);
  _mpfr_vec_clear(c, n);
  _mpfr_vec_clear(b, n);
  return 0;
}
Example #23
0
void
_fmpq_poly_interpolate_fmpz_vec(fmpz * poly, fmpz_t den,
                                    const fmpz * xs, const fmpz * ys, long n)
{
    fmpz *P, *Q, *w;
    fmpz_t t;

    long i, j;

    /* Constant */
    if (n == 1)
    {
        fmpz_set(poly, ys);
        fmpz_one(den);
        return;
    }

    /* Linear */
    if (n == 2)
    {
        fmpz_sub(den, xs, xs + 1);
        fmpz_sub(poly + 1, ys, ys + 1);
        fmpz_mul(poly, xs, ys + 1);
        fmpz_submul(poly, xs + 1, ys);
        return;
    }

    fmpz_init(t);

    P = _fmpz_vec_init(n + 1);
    Q = _fmpz_vec_init(n);
    w = _fmpz_vec_init(n);

    /* P = (x-x[0])*(x-x[1])*...*(x-x[n-1]) */
    _fmpz_poly_product_roots_fmpz_vec(P, xs, n);

    /* Weights */
    for (i = 0; i < n; i++)
    {
        fmpz_one(w + i);
        for (j = 0; j < n; j++)
        {
            if (i != j)
            {
                fmpz_sub(t, xs + i, xs + j);
                fmpz_mul(w + i, w + i, t);
            }
        }
    }

    _fmpz_vec_zero(poly, n);
    _fmpz_vec_lcm(den, w, n);

    for (i = 0; i < n; i++)
    {
        /* Q = P / (x - x[i]) */
        _fmpz_poly_div_root(Q, P, n + 1, xs + i);

        /* result += Q * weight(i) */
        fmpz_divexact(t, den, w + i);
        fmpz_mul(t, t, ys + i);
        _fmpz_vec_scalar_addmul_fmpz(poly, Q, n, t);
    }

    _fmpz_vec_clear(P, n + 1);
    _fmpz_vec_clear(Q, n);
    _fmpz_vec_clear(w, n);
    fmpz_clear(t);
}
Example #24
0
/* convert to an fmpz poly with a common exponent and coefficients
   at most prec bits, also bounding input error plus rounding error */
void _fmprb_poly_get_fmpz_poly_2exp(fmpr_t error, fmpz_t exp, fmpz  * coeffs,
                            fmprb_srcptr A, long lenA, long prec)
{
    fmpz_t top_exp, bot_exp;
    long shift;
    long i;
    int rounding;

    fmpz_init(top_exp);
    fmpz_init(bot_exp);

    if (!_fmprb_poly_mid_get_hull(bot_exp, top_exp, A, lenA))
    {
        fmpz_zero(exp);
        _fmpz_vec_zero(coeffs, lenA);
        fmpr_zero(error);
        for (i = 0; i < lenA; i++)
        {
            if (fmpr_cmp(fmprb_radref(A + i), error) > 0)
                fmpr_set(error, fmprb_radref(A + i));
        }

        return;   /* no need to clear fmpzs */
    }

    /* only take as much precision as necessary */
    shift = _fmpz_sub_small(top_exp, bot_exp);
    prec = FLINT_MIN(prec, shift);

    fmpz_sub_ui(exp, top_exp, prec);

    /* extract integer polynomial */
    rounding = 0;
    for (i = 0; i < lenA; i++)
        rounding |= fmpr_get_fmpz_fixed_fmpz(coeffs + i,
                        fmprb_midref(A + i), exp);

    fmpr_zero(error);

    /* compute maximum of input errors */
    for (i = 0; i < lenA; i++)
    {
        if (fmpr_cmp(fmprb_radref(A + i), error) > 0)
            fmpr_set(error, fmprb_radref(A + i));
    }

    /* add rounding error */
    if (rounding)
    {
        fmpr_t t;
        fmpr_init(t);

        fmpz_set_ui(fmpr_manref(t), 1UL);
        fmpz_set(fmpr_expref(t), exp);

        fmpr_add(error, error, t, FMPRB_RAD_PREC, FMPR_RND_UP);

        fmpr_clear(t);
    }

    fmpz_clear(top_exp);
}
Example #25
0
void _padic_poly_sub(fmpz *rop, slong *val, slong N, 
                     const fmpz *op1, slong val1, slong len1, slong N1, 
                     const fmpz *op2, slong val2, slong len2, slong N2, 
                     const padic_ctx_t ctx)
{
    const slong len = FLINT_MAX(len1, len2);

    *val = FLINT_MIN(val1, val2);

    if (val1 == val2)
    {
        _fmpz_poly_sub(rop, op1, len1, op2, len2);
        _padic_poly_canonicalise(rop, val, len, ctx->p);
    }
    else
    {
        fmpz_t x;

        fmpz_init(x);
        if (val1 < val2)  /* F := p^g (G - p^{h-g} H) */
        {
            fmpz_pow_ui(x, ctx->p, val2 - val1);

            if (rop == op1)
            {
                _fmpz_vec_zero(rop + len1, len2 - len1);
                _fmpz_vec_scalar_submul_fmpz(rop, op2, len2, x);
            }
            else
            {
                _fmpz_vec_scalar_mul_fmpz(rop, op2, len2, x);
                _fmpz_vec_neg(rop, rop, len2);
                _fmpz_poly_add(rop, op1, len1, rop, len2);
            }
        }
        else  /* F := p^h (p^(g-h) G - H) */
        {
            fmpz_pow_ui(x, ctx->p, val1 - val2);

            if (rop == op2)
            {
                _fmpz_vec_neg(rop, op2, len2);
                _fmpz_vec_zero(rop + len2, len1 - len2);
                _fmpz_vec_scalar_addmul_fmpz(rop, op1, len1, x);
            }
            else
            {
                _fmpz_vec_scalar_mul_fmpz(rop, op1, len1, x);
                _fmpz_poly_sub(rop, rop, len1, op2, len2);
            }
        }
        fmpz_clear(x);
    }

    /* Reduce */
    if (N - *val > 0)
    {
        fmpz_t pow;
        int alloc;

        alloc = _padic_ctx_pow_ui(pow, N - *val, ctx);

        if (N >= N1 && N >= N2)
        {
            slong i;
            for (i = 0; i < len; i++)
                if (fmpz_sgn(rop + i) < 0)
                    fmpz_add(rop + i, rop + i, pow);
        }
        else
        {
            _fmpz_vec_scalar_mod_fmpz(rop, rop, len, pow);
        }

        if (alloc)
            fmpz_clear(pow);
    }
    else
    {
        _fmpz_vec_zero(rop, len);
        *val = 0;
    }
}
Example #26
0
/* Assumes len1 != 0 != len2 */
int
_fmpz_poly_gcd_heuristic(fmpz * res, const fmpz * poly1, long len1, 
                                        const fmpz * poly2, long len2)
{
	ulong bits1, bits2, max_bits, pack_bits, bound_bits, bits_G, bits_Q;
   ulong limbs1, limbs2, limbsg, pack_limbs, qlimbs;
   ulong log_glen, log_length;
   long sign1, sign2, glen, qlen;
	fmpz_t ac, bc, d, gc;
   fmpz * A, * B, * G, * Q, * t;
   mp_ptr array1, array2, arrayg, q, temp;
   int divides;

   fmpz_init(ac);
   fmpz_init(bc);
   fmpz_init(d);
   
	/* compute gcd of content of poly1 and poly2 */
   _fmpz_poly_content(ac, poly1, len1);
   _fmpz_poly_content(bc, poly2, len2);
   fmpz_gcd(d, ac, bc);

   /* special case, one of the polys is a constant */
   if (len2 == 1) /* if len1 == 1 then so does len2 */
   {
      fmpz_set(res, d);

      fmpz_clear(ac);
      fmpz_clear(bc);
	   fmpz_clear(d);

      return 1;
   }
   
   /* divide poly1 and poly2 by their content */
   A = _fmpz_vec_init(len1);
   B = _fmpz_vec_init(len2);
   _fmpz_vec_scalar_divexact_fmpz(A, poly1, len1, ac);
   _fmpz_vec_scalar_divexact_fmpz(B, poly2, len2, bc);
   fmpz_clear(ac);
   fmpz_clear(bc);
	   
	/* special case, one of the polys is length 2 */
   if (len2 == 2) /* if len1 == 2 then so does len2 */
	{
		Q = _fmpz_vec_init(len1 - len2 + 1);
		if (_fmpz_poly_divides(Q, A, len1, B, 2))
      {
		   _fmpz_vec_scalar_mul_fmpz(res, B, 2, d);
         if (fmpz_sgn(res + 1) < 0)
            _fmpz_vec_neg(res, res, 2);
      }
		else  
      {
			fmpz_set(res, d);
         fmpz_zero(res + 1);
      }

		fmpz_clear(d);
		_fmpz_vec_clear(A, len1);
      _fmpz_vec_clear(B, len2);
      _fmpz_vec_clear(Q, len1 - len2 + 1);
      
      return 1;
	}
	
   /* 
      Determine how many bits (pack_bits) to pack into. The bound 
      bound_bits ensures that if G | A and G | B with G primitive 
      then G is the gcd of A and B. The bound is taken from 
      http://arxiv.org/abs/cs/0206032v1
   */
   bits1 = FLINT_ABS(_fmpz_vec_max_bits(A, len1));
	bits2 = FLINT_ABS(_fmpz_vec_max_bits(B, len2));
	max_bits = FLINT_MAX(bits1, bits2);
   			
	bound_bits = FLINT_MIN(bits1, bits2) + 6; 
	pack_bits = FLINT_MAX(bound_bits, max_bits); /* need to pack original polys */
   pack_limbs = (pack_bits - 1)/FLINT_BITS + 1;
   
	if (pack_bits >= 32) /* pack into multiples of limbs if >= 32 bits */
      pack_bits = FLINT_BITS*pack_limbs;
		
   /* allocate space to pack into */
   limbs1 = (pack_bits*len1 - 1)/FLINT_BITS + 1;
   limbs2 = (pack_bits*len2 - 1)/FLINT_BITS + 1;
	array1 = flint_calloc(limbs1, sizeof(mp_limb_t));
   array2 = flint_calloc(limbs2, sizeof(mp_limb_t));
   arrayg = flint_calloc(limbs2, sizeof(mp_limb_t));
   
   /* pack first poly and normalise */
   sign1 = (long) fmpz_sgn(A + len1 - 1);
	_fmpz_poly_bit_pack(array1, A, len1, pack_bits, sign1);
	while (array1[limbs1 - 1] == 0) limbs1--;

   /* pack second poly and normalise */
   sign2 = (long) fmpz_sgn(B + len2 - 1);
   _fmpz_poly_bit_pack(array2, B, len2, pack_bits, sign2);
	while (array2[limbs2 - 1] == 0) limbs2--;
	
	/* compute integer GCD */
   limbsg = mpn_gcd_full(arrayg, array1, limbs1, array2, limbs2);
	
   /* 
      Make space for unpacked gcd. May have one extra coeff due to 
      1 0 -x being packed as 0 -1 -x. 
   */
   glen = FLINT_MIN((limbsg*FLINT_BITS)/pack_bits + 1, len2); 
   G = _fmpz_vec_init(glen);
   
   /* unpack gcd */
   _fmpz_poly_bit_unpack(G, glen, arrayg, pack_bits, 0);
   while (G[glen - 1] == 0) glen--;
   
	/* divide by any content */
   fmpz_init(gc);
	_fmpz_poly_content(gc, G, glen);

   if (!fmpz_is_one(gc)) 
      limbsg = mpn_tdiv_q_fmpz_inplace(arrayg, limbsg, gc);

   /* make space for quotient and remainder of first poly by gcd */
   qlimbs = limbs1 - limbsg + 1;
   qlen = FLINT_MIN(len1, (qlimbs*FLINT_BITS)/pack_bits + 1);
   qlimbs = (qlen*pack_bits - 1)/FLINT_BITS + 1;
   q = flint_calloc(qlimbs, sizeof(mp_limb_t));
   temp = flint_malloc(limbsg*sizeof(mp_limb_t));
   
	divides = 0;

   if (mpn_divides(q, array1, limbs1, arrayg, limbsg, temp)) 
	{
      /* unpack quotient of first poly by gcd */
      Q = _fmpz_vec_init(len1); 
      t = _fmpz_vec_init(len1 + glen);
      _fmpz_poly_bit_unpack(Q, qlen, q, pack_bits, 0);
      while (Q[qlen - 1] == 0) qlen--;
      
      /* divide by content */
      _fmpz_vec_scalar_divexact_fmpz(G, G, glen, gc);
		
      /* check if we really need to multiply out to check for exact quotient */
      bits_G = FLINT_ABS(_fmpz_vec_max_bits(G, glen));
		bits_Q = FLINT_ABS(_fmpz_vec_max_bits(Q, qlen));
		log_glen = FLINT_BIT_COUNT(glen);
		log_length = FLINT_MIN(log_glen, FLINT_BIT_COUNT(qlen));
       
	   divides = (bits_G + bits_Q + log_length < pack_bits);
     
      if (!divides) /* need to multiply out to check exact quotient */
         divides = multiplies_out(A, len1, Q, qlen, G, glen, sign1, t);

		if (divides) /* quotient really was exact */
		{
         mpn_zero(q, qlimbs);
          
         if (mpn_divides(q, array2, limbs2, arrayg, limbsg, temp)) 
	      {
            /* unpack quotient of second poly by gcd */
            qlimbs = limbs2 - limbsg + 1;
            qlen = FLINT_MIN(len2, (qlimbs*FLINT_BITS - 1)/pack_bits + 1);
            _fmpz_poly_bit_unpack(Q, qlen, q, pack_bits, 0);
            while (Q[qlen - 1] == 0) qlen--;
            
            /* check if we really need to multiply out to check for exact quotient */
            bits_Q = FLINT_ABS(_fmpz_vec_max_bits(Q, qlen));
				log_length = FLINT_MIN(log_glen, FLINT_BIT_COUNT(qlen));

				divides = (bits_G + bits_Q + log_length < pack_bits);
		      
            if (!divides) /* we need to multiply out */
               divides = multiplies_out(B, len2, Q, qlen, G, glen, sign1, t);
			} 
		} 

      _fmpz_vec_clear(t, len1 + glen);
      _fmpz_vec_clear(Q, len1);
	}

   flint_free(q); 
	flint_free(temp); 
	flint_free(arrayg); 
	flint_free(array1); 
	flint_free(array2); 
	fmpz_clear(gc); 
	
	_fmpz_vec_clear(A, len1);
	_fmpz_vec_clear(B, len2);
	
   /* we found the gcd, so multiply by content */
   if (divides)
   {
	   _fmpz_vec_zero(res + glen, len2 - glen);
      _fmpz_vec_scalar_mul_fmpz(res, G, glen, d);
   }
		
   fmpz_clear(d);
   _fmpz_vec_clear(G, glen);
		
   return divides;
}
Example #27
0
void
_fmpz_poly_mullow_KS(fmpz * res, const fmpz * poly1, long len1,
                                 const fmpz * poly2, long len2, long n)
{
    int neg1, neg2;
    long limbs1, limbs2, loglen;
    long bits1, bits2, bits;
    mp_limb_t *arr1, *arr2, *arr3;
    long sign = 0;

    FMPZ_VEC_NORM(poly1, len1);
    FMPZ_VEC_NORM(poly2, len2);

    if (!len1 | !len2)
    {
        _fmpz_vec_zero(res, n);
        return;
    }

    neg1 = (fmpz_sgn(poly1 + len1 - 1) > 0) ? 0 : -1;
    neg2 = (fmpz_sgn(poly2 + len2 - 1) > 0) ? 0 : -1;

    if (n > len1 + len2 - 1)
    {
       _fmpz_vec_zero(res + len1 + len2 - 1, n - (len1 + len2 - 1));
       n = len1 + len2 - 1;
    }

    bits1 = _fmpz_vec_max_bits(poly1, len1);
    if (bits1 < 0)
    {
        sign = 1;
        bits1 = -bits1;
    }

    if (poly1 != poly2)
    {
        bits2 = _fmpz_vec_max_bits(poly2, len2);
        if (bits2 < 0)
        {
            sign = 1;
            bits2 = -bits2;
        }
    }
    else
        bits2 = bits1;

    loglen = FLINT_BIT_COUNT(FLINT_MIN(len1, len2));
    bits = bits1 + bits2 + loglen + sign;

    limbs1 = (bits * len1 - 1) / FLINT_BITS + 1;
    limbs2 = (bits * len2 - 1) / FLINT_BITS + 1;

    if (poly1 == poly2)
    {
        arr1 = (mp_ptr) flint_calloc(limbs1, sizeof(mp_limb_t));
        arr2 = arr1;
        _fmpz_poly_bit_pack(arr1, poly1, len1, bits, neg1);
    }
    else
    {
        arr1 = (mp_ptr) flint_calloc(limbs1 + limbs2, sizeof(mp_limb_t));
        arr2 = arr1 + limbs1;
        _fmpz_poly_bit_pack(arr1, poly1, len1, bits, neg1);
        _fmpz_poly_bit_pack(arr2, poly2, len2, bits, neg2);
    }

    arr3 = (mp_ptr) flint_malloc((limbs1 + limbs2) * sizeof(mp_limb_t));

    if (limbs1 == limbs2)
        mpn_mul_n(arr3, arr1, arr2, limbs1);
    else if (limbs1 > limbs2)
        mpn_mul(arr3, arr1, limbs1, arr2, limbs2);
    else
        mpn_mul(arr3, arr2, limbs2, arr1, limbs1);
    
    if (sign)
        _fmpz_poly_bit_unpack(res, n, arr3, bits, neg1 ^ neg2);
    else
        _fmpz_poly_bit_unpack_unsigned(res, n, arr3, bits);

    flint_free(arr1);
    flint_free(arr3);
}
Example #28
0
void 
_fmpq_poly_inv_series_newton(fmpz * Qinv, fmpz_t Qinvden, 
                             const fmpz * Q, const fmpz_t Qden, long n)
{
    if (n == 1)
    {
        if (fmpz_sgn(Q) > 0)
        {
            fmpz_set(Qinv, Qden);
            fmpz_set(Qinvden, Q);
        }
        else
        {
            fmpz_neg(Qinv, Qden);
            fmpz_neg(Qinvden, Q);
        }
    }
    else
    {
        const long alloc = FLINT_MAX(n, 3 * FMPQ_POLY_INV_NEWTON_CUTOFF);
        long *a, i, m;
        fmpz *W, *Wden;

        W = _fmpz_vec_init(alloc + 1);
        Wden = W + alloc;

        for (i = 1; (1L << i) < n; i++) ;

        a = (long *) flint_malloc(i * sizeof(long));
        a[i = 0] = n;
        while (n >= FMPQ_POLY_INV_NEWTON_CUTOFF)
            a[++i] = (n = (n + 1) / 2);

        /* Base case */
        {
            fmpz *rev = W + 2 * FMPQ_POLY_INV_NEWTON_CUTOFF;

            _fmpz_poly_reverse(rev, Q, n, n);
            _fmpz_vec_zero(W, 2*n - 2);
            fmpz_one(W + (2*n - 2));
            fmpz_one(Wden);

            _fmpq_poly_div(Qinv, Qinvden, W, Wden, 2*n - 1, rev, Qden, n);
            _fmpq_poly_canonicalise(Qinv, Qinvden, n);

            _fmpz_poly_reverse(Qinv, Qinv, n, n);
        }

        for (i--; i >= 0; i--)
        {
            m = n;
            n = a[i];

            _fmpz_poly_mullow(W, Q, n, Qinv, m, n);
            fmpz_mul(Wden, Qden, Qinvden);

            _fmpz_poly_mullow(Qinv + m, Qinv, m, W + m, n - m, n - m);
            fmpz_mul(Qinvden, Qinvden, Wden);
            _fmpz_vec_scalar_mul_fmpz(Qinv, Qinv, m, Wden);

            _fmpz_vec_neg(Qinv + m, Qinv + m, n - m);

            _fmpq_poly_canonicalise(Qinv, Qinvden, n);
        }

        _fmpz_vec_clear(W, alloc + 1);
        flint_free(a);
    }
}
Example #29
0
static void 
_qadic_exp_bsplit_series(fmpz *P, fmpz_t Q, fmpz *T, 
                         const fmpz *x, slong len, slong lo, slong hi, 
                         const fmpz *a, const slong *j, slong lena)
{
    const slong d = j[lena - 1];

    if (hi - lo == 1)
    {
        _fmpz_vec_set(P, x, len);
        _fmpz_vec_zero(P + len, 2*d - 1 - len);

        fmpz_set_si(Q, lo);

        _fmpz_vec_set(T, P, 2*d - 1);
    }
    else if (hi - lo == 2)
    {
        _fmpz_poly_sqr(P, x, len);
        _fmpz_vec_zero(P + (2*len - 1), d - (2*len - 1));
        _fmpz_poly_reduce(P, 2*len - 1, a, j, lena);

        fmpz_set_si(Q, lo);
        fmpz_mul_si(Q, Q, lo + 1);

        _fmpz_vec_scalar_mul_si(T, x, len, lo + 1);
        _fmpz_vec_zero(T + len, d - len);
        _fmpz_vec_add(T, T, P, d);
    }
    else
    {
        const slong m = (lo + hi) / 2;

        fmpz *PR, *TR, *W;
        fmpz_t QR;

        PR = _fmpz_vec_init(2*d - 1);
        TR = _fmpz_vec_init(2*d - 1);
        W  = _fmpz_vec_init(2*d - 1);
        fmpz_init(QR);

        _qadic_exp_bsplit_series(P, Q, T, x, len, lo, m, a, j, lena);

        _qadic_exp_bsplit_series(PR, QR, TR, x, len, m, hi, a, j, lena);

        _fmpz_poly_mul(W, TR, d, P, d);
        _fmpz_poly_reduce(W, 2*d - 1, a, j, lena);

        _fmpz_vec_scalar_mul_fmpz(T, T, d, QR);
        _fmpz_vec_add(T, T, W, d);

        _fmpz_poly_mul(W, P, d, PR, d);
        _fmpz_poly_reduce(W, 2*d - 1, a, j, lena);
        _fmpz_vec_swap(P, W, d);

        fmpz_mul(Q, Q, QR);

        _fmpz_vec_clear(PR, 2*d - 1);
        _fmpz_vec_clear(TR, 2*d - 1);
        _fmpz_vec_clear(W,  2*d - 1);
        fmpz_clear(QR);
    }
}