void fmpq_poly_neg(fmpq_poly_t poly1, const fmpq_poly_t poly2) { if (poly1 == poly2) { _fmpz_vec_neg(poly1->coeffs, poly2->coeffs, poly2->length); } else { fmpq_poly_fit_length(poly1, poly2->length); _fmpz_vec_neg(poly1->coeffs, poly2->coeffs, poly2->length); _fmpq_poly_set_length(poly1, poly2->length); fmpz_set(poly1->den, poly2->den); } }
void _fmpq_poly_canonicalise(fmpz * poly, fmpz_t den, slong len) { if (*den == WORD(1)) return; if (*den == WORD(-1)) { _fmpz_vec_neg(poly, poly, len); fmpz_one(den); } else if (len == 0) { fmpz_one(den); } else { fmpz_t gcd; fmpz_init(gcd); _fmpz_vec_content(gcd, poly, len); if (*gcd != WORD(1)) fmpz_gcd(gcd, gcd, den); if (fmpz_sgn(den) < 0) fmpz_neg(gcd, gcd); if (*gcd != WORD(1)) { _fmpz_vec_scalar_divexact_fmpz(poly, poly, len, gcd); fmpz_divexact(den, den, gcd); } fmpz_clear(gcd); } }
void _fmpq_poly_div(fmpz * Q, fmpz_t q, const fmpz * A, const fmpz_t a, long lenA, const fmpz * B, const fmpz_t b, long lenB) { long lenQ = lenA - lenB + 1; ulong d; const fmpz * lead = B + (lenB - 1); if (lenB == 1) { _fmpq_poly_scalar_div_fmpq(Q, q, A, a, lenA, B, b); return; } /* From pseudo division over Z we have lead^d * A = Q * B + R and thus {A, a} = {b * Q, a * lead^d} * {B, b} + {R, a * lead^d}. */ _fmpz_poly_pseudo_div(Q, &d, A, lenA, B, lenB); /* 1. lead^d == +-1. {Q, q} = {b Q, a} up to sign */ if (d == 0UL || *lead == 1L || *lead == -1L) { fmpz_one(q); _fmpq_poly_scalar_mul_fmpz(Q, q, Q, q, lenQ, b); _fmpq_poly_scalar_div_fmpz(Q, q, Q, q, lenQ, a); if (*lead == -1L && d % 2UL) _fmpz_vec_neg(Q, Q, lenQ); } /* 2. lead^d != +-1. {Q, q} = {b Q, a lead^d} */ else { /* TODO: Improve this. Clearly we do not need to compute den = a lead^d in many cases, but can determine the GCD from lead alone already. */ fmpz_t den; fmpz_init(den); fmpz_pow_ui(den, lead, d); fmpz_mul(den, a, den); fmpz_one(q); _fmpq_poly_scalar_mul_fmpz(Q, q, Q, q, lenQ, b); _fmpq_poly_scalar_div_fmpz(Q, q, Q, q, lenQ, den); fmpz_clear(den); } }
/* Returns 1 if sign * (G, glen) * (Q, qlen) = (P, len), else returns 0. Temp requires space for glen + qlen - 1 coefficients */ int multiplies_out(fmpz * P, long len, const fmpz * Q, long qlen, const fmpz * G, long glen, long sign, fmpz * temp) { int divides = 0; /* multiply out */ if (qlen >= glen) _fmpz_poly_mul(temp, Q, qlen, G, glen); else _fmpz_poly_mul(temp, G, glen, Q, qlen); if (sign < 0L) _fmpz_vec_neg(temp, temp, glen + qlen - 1); /* check if quotient really was exact */ divides = (glen + qlen - 1 == len && _fmpz_vec_equal(temp, P, len)); return divides; }
void _fmpq_poly_scalar_div_si(fmpz * rpoly, fmpz_t rden, const fmpz * poly, const fmpz_t den, long len, long c) { if (c == 1) { if (rpoly != poly) { _fmpz_vec_set(rpoly, poly, len); fmpz_set(rden, den); } } else if (c == -1) { _fmpz_vec_neg(rpoly, poly, len); fmpz_set(rden, den); } else { fmpz_t d, f; fmpz_init(d); fmpz_init(f); fmpz_set_si(f, c); _fmpz_vec_content(d, poly, len); fmpz_gcd(d, d, f); if (c > 0) { _fmpz_vec_scalar_divexact_fmpz(rpoly, poly, len, d); fmpz_mul_si(rden, den, c / fmpz_get_si(d)); } else { ulong q = (- (ulong) c) / fmpz_get_ui(d); fmpz_neg(d, d); _fmpz_vec_scalar_divexact_fmpz(rpoly, poly, len, d); fmpz_mul_ui(rden, den, q); } fmpz_clear(d); fmpz_clear(f); } }
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); }
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); } }
void _fmpq_poly_divrem(fmpz * Q, fmpz_t q, fmpz * R, fmpz_t r, const fmpz * A, const fmpz_t a, slong lenA, const fmpz * B, const fmpz_t b, slong lenB, const fmpz_preinvn_t inv) { slong lenQ = lenA - lenB + 1; slong lenR = lenB - 1; ulong d; const fmpz * lead = B + (lenB - 1); if (lenB == 1) { _fmpq_poly_scalar_div_fmpq(Q, q, A, a, lenA, B, b); fmpz_one(r); return; } /* From pseudo division over Z we have lead^d * A = Q * B + R and thus {A, a} = {b * Q, a * lead^d} * {B, b} + {R, a * lead^d}. */ _fmpz_poly_pseudo_divrem(Q, R, &d, A, lenA, B, lenB, inv); /* Determine the actual length of R */ for ( ; lenR != 0 && fmpz_is_zero(R + (lenR - 1)); lenR--) ; /* 1. lead^d == +-1. {Q, q} = {b Q, a}, {R, r} = {R, a} up to sign */ if (d == UWORD(0) || *lead == WORD(1) || *lead == WORD(-1)) { fmpz_one(q); _fmpq_poly_scalar_mul_fmpz(Q, q, Q, q, lenQ, b); _fmpq_poly_scalar_div_fmpz(Q, q, Q, q, lenQ, a); fmpz_one(r); if (lenR > 0) _fmpq_poly_scalar_div_fmpz(R, r, R, r, lenR, a); if (*lead == WORD(-1) && d % UWORD(2)) { _fmpz_vec_neg(Q, Q, lenQ); _fmpz_vec_neg(R, R, lenR); } } /* 2. lead^d != +-1. {Q, q} = {b Q, a lead^d}, {R, r} = {R, a lead^d} */ else { /* TODO: Improve this. Clearly we do not need to compute den = a lead^d in many cases, but can determine the GCD from lead alone already. */ fmpz_t den; fmpz_init(den); fmpz_pow_ui(den, lead, d); fmpz_mul(den, a, den); fmpz_one(q); _fmpq_poly_scalar_mul_fmpz(Q, q, Q, q, lenQ, b); _fmpq_poly_scalar_div_fmpz(Q, q, Q, q, lenQ, den); fmpz_one(r); if (lenR > 0) _fmpq_poly_scalar_div_fmpz(R, r, R, r, lenR, den); fmpz_clear(den); } }
void _fmpq_poly_scalar_div_mpq(fmpz * rpoly, fmpz_t rden, const fmpz * poly, const fmpz_t den, long len, const fmpz_t r, const fmpz_t s) { fmpz_t gcd1; /* GCD( poly, r ) */ fmpz_t gcd2; /* GCD( s, den ) */ fmpz_init(gcd1); fmpz_init(gcd2); fmpz_set_ui(gcd1, 1); fmpz_set_ui(gcd2, 1); if (*r != 1L) { _fmpz_vec_content(gcd1, poly, len); if (*gcd1 != 1L) fmpz_gcd(gcd1, gcd1, r); } if (*den != 1L && *s != 1L) fmpz_gcd(gcd2, s, den); if (*gcd1 == 1L) { if (*gcd2 == 1L) { _fmpz_vec_scalar_mul_fmpz(rpoly, poly, len, s); fmpz_mul(rden, den, r); } else { fmpz_t s2; fmpz_init(s2); fmpz_divexact(s2, s, gcd2); _fmpz_vec_scalar_mul_fmpz(rpoly, poly, len, s2); fmpz_divexact(rden, den, gcd2); fmpz_mul(rden, rden, r); fmpz_clear(s2); } } else { fmpz_t r2; fmpz_init(r2); fmpz_divexact(r2, r, gcd1); if (*gcd2 == 1L) { _fmpz_vec_scalar_divexact_fmpz(rpoly, poly, len, gcd1); _fmpz_vec_scalar_mul_fmpz(rpoly, rpoly, len, s); fmpz_mul(rden, den, r2); } else { fmpz_t s2; fmpz_init(s2); fmpz_divexact(s2, s, gcd2); _fmpz_vec_scalar_divexact_fmpz(rpoly, poly, len, gcd1); _fmpz_vec_scalar_mul_fmpz(rpoly, rpoly, len, s2); fmpz_divexact(rden, den, gcd2); fmpz_mul(rden, rden, r2); fmpz_clear(s2); } fmpz_clear(r2); } if (_fmpz_vec_is_zero(rpoly, len)) fmpz_set_ui(rden, 1); if (fmpz_sgn(rden) < 0) { _fmpz_vec_neg(rpoly, rpoly, len); fmpz_neg(rden, rden); } fmpz_clear(gcd1); fmpz_clear(gcd2); }
/* 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; }
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; } }
void _fmpz_poly_signature(long * r1, long * r2, fmpz * poly, long len) { fmpz *A, *B, *f, *g, *h, *w; long lenA, lenB; int s, t; if (len <= 2) { *r1 = (len == 2); *r2 = 0; return; } w = _fmpz_vec_init(2 * len + 2); A = w; B = w + len; lenA = len; lenB = lenA - 1; f = w + 2 * len - 1; g = w + 2 * len; h = w + 2 * len + 1; _fmpz_poly_primitive_part(A, poly, lenA); _fmpz_poly_derivative(B, A, lenA); _fmpz_poly_primitive_part(B, B, lenB); fmpz_one(g); fmpz_one(h); s = 1; t = (lenA & 1L) ? -s : s; *r1 = 1; while (1) { long delta = lenA - lenB; int sgnA; _fmpz_poly_pseudo_rem_cohen(A, A, lenA, B, lenB); lenA = lenB; FMPZ_VEC_NORM(A, lenA); if (lenA == 0) { printf("Exception: non-squarefree polynomial detected in fmpz_poly_signature\n"); _fmpz_vec_clear(w, 2 * len + 2); abort(); } if ((fmpz_sgn(B + (lenB - 1)) > 0) || (delta & 1L)) _fmpz_vec_neg(A, A, lenA); sgnA = fmpz_sgn(A + (lenA - 1)); if (sgnA != s) { s = -s; (*r1)--; } if (sgnA != ((lenA & 1L) ? t : -t)) { t = -t; (*r1)++; } if (lenA == 1) { *r2 = ((len - 1) - *r1) / 2; _fmpz_vec_clear(w, 2 * len + 2); return; } else { { fmpz * temp = A; A = B; B = temp; } { long temp = lenA; lenA = lenB; lenB = temp; } if (delta == 1) { fmpz_mul(f, g, h); _fmpz_vec_scalar_divexact_fmpz(B, B, lenB, f); fmpz_set(g, A + (lenA - 1)); fmpz_set(h, g); } else { fmpz_pow_ui(f, h, delta); fmpz_mul(f, f, g); _fmpz_vec_scalar_divexact_fmpz(B, B, lenB, f); fmpz_pow_ui(f, h, delta - 1); fmpz_pow_ui(g, A + (lenA - 1), delta); fmpz_divexact(h, g, f); fmpz_set(g, A + (lenA - 1)); } } } }