void F_mpz_mod_poly_realloc(F_mpz_mod_poly_t poly, const ulong alloc) { if (!alloc) // alloc == 0, clear up { F_mpz_mod_poly_clear(poly); poly->coeffs = NULL; poly->alloc = 0; poly->length = 0; return; } if (poly->alloc) // realloc { F_mpz_mod_poly_truncate(poly, alloc); poly->coeffs = (F_mpz *) flint_heap_realloc(poly->coeffs, alloc); if (alloc > poly->alloc) F_mpn_clear(poly->coeffs + poly->alloc, alloc - poly->alloc); } else // nothing allocated already so do it now { poly->coeffs = (mp_limb_t*) flint_heap_alloc(alloc); F_mpn_clear(poly->coeffs, alloc); } poly->alloc = alloc; }
void F_mpz_mod_poly_divrem_divconquer(F_mpz_mod_poly_t Q, F_mpz_mod_poly_t R, const F_mpz_mod_poly_t A, const F_mpz_mod_poly_t B) { F_mpz_mod_poly_t QB; F_mpz_mod_poly_init(QB, Q->P); F_mpz_mod_poly_div_divconquer_recursive(Q, QB, A, B); F_mpz_mod_poly_fit_length(R, A->length); _F_mpz_mod_poly_sub(R, A, QB); _F_mpz_mod_poly_normalise(R); F_mpz_mod_poly_clear(QB); }
void F_mpz_mod_poly_mul_trunc_left(F_mpz_mod_poly_t res, const F_mpz_mod_poly_t poly1, const F_mpz_mod_poly_t poly2, ulong trunc) { if ((poly1->length == 0) || (poly2->length == 0) || (poly1->length + poly2->length <= trunc + 1)) // special case if either poly is zero { F_mpz_mod_poly_zero(res); return; } if ((poly1 == res) || (poly2 == res)) // aliased inputs { F_mpz_mod_poly_t output; // create temporary F_mpz_mod_poly_init2(output, res->P, poly1->length + poly2->length - 1); if (poly1->length >= poly2->length) _F_mpz_mod_poly_mul_trunc_left(output, poly1, poly2, trunc); else _F_mpz_mod_poly_mul_trunc_left(output, poly2, poly1, trunc); F_mpz_mod_poly_swap(output, res); // swap temporary with real output F_mpz_mod_poly_clear(output); } else // ordinary case { F_mpz_mod_poly_fit_length(res, poly1->length + poly2->length - 1); if (poly1->length >= poly2->length) _F_mpz_mod_poly_mul_trunc_left(res, poly1, poly2, trunc); else _F_mpz_mod_poly_mul_trunc_left(res, poly2, poly1, trunc); } }
void F_mpz_mod_poly_div_divconquer_recursive(F_mpz_mod_poly_t Q, F_mpz_mod_poly_t BQ, const F_mpz_mod_poly_t A, const F_mpz_mod_poly_t B) { if (A->length < B->length) { F_mpz_mod_poly_zero(Q); F_mpz_mod_poly_zero(BQ); return; } // A->length is now >= B->length ulong crossover = 16; if (A->length - B->length + 1 <= crossover) { /* Use the classical algorithm to compute the quotient and remainder, then use A - R to compute BQ */ F_mpz_mod_poly_t Rb; F_mpz_mod_poly_init(Rb, B->P); F_mpz_mod_poly_divrem_basecase(Q, Rb, A, B); F_mpz_mod_poly_fit_length(BQ, A->length); F_mpz_mod_poly_sub(BQ, A, Rb); F_mpz_mod_poly_clear(Rb); return; } F_mpz_mod_poly_t d1, d2, d3, d4, p1, q1, q2, dq1, dq2, d1q1, d2q1, d2q2, d1q2, t, temp; ulong n1 = (B->length + 1)/2; ulong n2 = B->length - n1; /* We let B = d1*x^n2 + d2 */ _F_mpz_mod_poly_attach_shift(d1, B, n2); _F_mpz_mod_poly_attach_truncate(d2, B, n2); _F_mpz_mod_poly_attach_shift(d3, B, n1); _F_mpz_mod_poly_attach_truncate(d4, B, n1); if (A->length < 2*B->length - 1) { /* Convert unbalanced division into a 2*q - 1 by q division */ F_mpz_mod_poly_t t_A, t_B, t_B2; ulong q = A->length - B->length + 1; ulong q2 = B->length - q; _F_mpz_mod_poly_attach_shift(t_A, A, A->length - 2*q + 1); _F_mpz_mod_poly_attach_shift(t_B, B, q2); _F_mpz_mod_poly_attach_truncate(t_B2, B, q2); F_mpz_mod_poly_init(d1q1, B->P); F_mpz_mod_poly_div_divconquer_recursive(Q, d1q1, t_A, t_B); /* Compute d2q1 = Q*t_B2 It is of length q2*q terms */ F_mpz_mod_poly_init(d2q1, B->P); F_mpz_mod_poly_mul(d2q1, Q, t_B2); /* Compute BQ = d1q1*x^n1 + d2q1 It has length at most n1+n2-1 */ F_mpz_mod_poly_fit_length(BQ, FLINT_MAX(d1q1->length + B->length - q, d2q1->length)); F_mpz_mod_poly_left_shift(BQ, d1q1, B->length - q); F_mpz_mod_poly_clear(d1q1); _F_mpz_mod_poly_add(BQ, BQ, d2q1); F_mpz_mod_poly_clear(d2q1); return; } if (A->length > 2*B->length - 1) { // We shift A right until it is length 2*B->length -1 // We call this polynomial p1 ulong shift = A->length - 2*B->length + 1; _F_mpz_mod_poly_attach_shift(p1, A, shift); /* Set q1 to p1 div B This is a 2*B->length-1 by B->length division so q1 ends up being at most length B->length d1q1 = d1*q1 is length at most 2*B->length-1 */ F_mpz_mod_poly_init(d1q1, B->P); F_mpz_mod_poly_init(q1, Q->P); F_mpz_mod_poly_div_divconquer_recursive(q1, d1q1, p1, B); /* Compute dq1 = d1*q1*x^shift dq1 is then of length at most A->length dq1 is normalised since d1q1 was */ F_mpz_mod_poly_init(dq1, B->P); F_mpz_mod_poly_fit_length(dq1, d1q1->length + shift); F_mpz_mod_poly_left_shift(dq1, d1q1, shift); F_mpz_mod_poly_clear(d1q1); /* Compute t = A - dq1 The first B->length coefficients cancel if the division is exact, leaving A->length - B->length significant terms otherwise we truncate at this length */ F_mpz_mod_poly_init(t, A->P); F_mpz_mod_poly_sub(t, A, dq1); F_mpz_mod_poly_truncate(t, A->length - B->length); /* Compute q2 = t div B It is a smaller division than the original since t->length <= A->length-B->length */ F_mpz_mod_poly_init(q2, Q->P); F_mpz_mod_poly_init(dq2, Q->P); F_mpz_mod_poly_div_divconquer_recursive(q2, dq2, t, B); F_mpz_mod_poly_clear(t); /* Write out Q = q1*x^shift + q2 Q has length at most B->length+shift Note q2 has length at most shift since at most it is an A->length-B->length by B->length division */ F_mpz_mod_poly_fit_length(Q, FLINT_MAX(q1->length + shift, q2->length)); F_mpz_mod_poly_left_shift(Q, q1, shift); F_mpz_mod_poly_clear(q1); F_mpz_mod_poly_add(Q, Q, q2); F_mpz_mod_poly_clear(q2); /* Write out BQ = dq1 + dq2 */ F_mpz_mod_poly_fit_length(BQ, FLINT_MAX(dq1->length, dq2->length)); F_mpz_mod_poly_add(BQ, dq1, dq2); F_mpz_mod_poly_clear(dq1); F_mpz_mod_poly_clear(dq2); return; } // n2 + B->length - 1 < A->length <= n1 + n2 + B->length - 1 /* We let A = a1*x^(n1+2*n2-1) + a2*x^(n1+n2-1) + a3 where a1 is length at most n1 (and at least 1), a2 is length n2 and a3 is length n1+n2-1 We set p1 = a1*x^(n1-1)+ other terms, so it has length at most 2*n1-1 */ _F_mpz_mod_poly_attach_shift(p1, A, 2*n2); /* Set q1 to p1 div d1 This is at most a 2*n1-1 by n1 division so q1 ends up being at most length n1 d1q1 = d1*q1 is length at most 2*n1-1 */ F_mpz_mod_poly_init(d1q1, B->P); F_mpz_mod_poly_init(q1, B->P); F_mpz_mod_poly_div_divconquer_recursive(q1, d1q1, p1, d1); /* Compute d2q1 = d2*q1 which ends up being at most length n1+n2-1 */ F_mpz_mod_poly_init(d2q1, B->P); F_mpz_mod_poly_mul(d2q1, d2, q1); /* Compute dq1 = d1*q1*x^n2 + d2*q1 dq1 is then of length at most 2*n1+n2-1 */ F_mpz_mod_poly_init2(dq1, B->P, FLINT_MAX(d1q1->length + n2, d2q1->length)); F_mpz_mod_poly_left_shift(dq1, d1q1, n2); F_mpz_mod_poly_clear(d1q1); _F_mpz_mod_poly_add(dq1, dq1, d2q1); F_mpz_mod_poly_clear(d2q1); /* Compute t = p1*x^(n1+n2-1) + p2*x^(n1-1) - dq1 which has length at most 2*n1+n2-1, but we are not interested in up to the first n1 coefficients, so it has effective length at most n1+n2-1 */ F_mpz_mod_poly_init2(t, A->P, FLINT_MAX(A->length-n2, dq1->length)); F_mpz_mod_poly_right_shift(t, A, n2); _F_mpz_mod_poly_sub(t, t, dq1); F_mpz_mod_poly_truncate(t, B->length - 1); /* Compute q2 = t div d1 It is at most an n1+n2-1 by n1 division, so the length of q2 will be at most n2 Also compute d1q2 of length at most n1+n2-1 */ F_mpz_mod_poly_init(d1q2, B->P); F_mpz_mod_poly_init(q2, Q->P); F_mpz_mod_poly_div_divconquer_recursive(q2, d1q2, t, d1); F_mpz_mod_poly_clear(t); /* Compute d2q2 = d2*q2 which is of length at most n1+n2-1 */ F_mpz_mod_poly_init(d2q2, A->P); F_mpz_mod_poly_mul(d2q2, d2, q2); /* Compute dq2 = d1*q2*x^n2 + d2q2 which is of length at most n1+2*n2-1 */ F_mpz_mod_poly_init2(dq2, A->P, FLINT_MAX(d1q2->length+n2, d2q2->length)); F_mpz_mod_poly_left_shift(dq2, d1q2, n2); F_mpz_mod_poly_clear(d1q2); _F_mpz_mod_poly_add(dq2, dq2, d2q2); F_mpz_mod_poly_clear(d2q2); /* Write out Q = q1*x^n2 + q2 Q has length at most n1+n2 */ F_mpz_mod_poly_fit_length(Q, FLINT_MAX(q1->length+n2, q2->length)); F_mpz_mod_poly_left_shift(Q, q1, n2); F_mpz_mod_poly_clear(q1); _F_mpz_mod_poly_add(Q, Q, q2); F_mpz_mod_poly_clear(q2); /* Write out BQ = dq1*x^n2 + dq2 BQ has length at most 2*(n1+n2)-1 */ F_mpz_mod_poly_fit_length(BQ, FLINT_MAX(n2 + dq1->length, dq2->length)); F_mpz_mod_poly_left_shift(BQ, dq1, n2); _F_mpz_mod_poly_add(BQ, BQ, dq2); F_mpz_mod_poly_clear(dq2); F_mpz_mod_poly_clear(dq1); }
void F_mpz_mod_poly_divrem_basecase(F_mpz_mod_poly_t Q, F_mpz_mod_poly_t R, const F_mpz_mod_poly_t A, const F_mpz_mod_poly_t B) { if (B->length == 0) { printf("Error: Divide by zero\n"); abort(); } if (A->length < B->length) { F_mpz_mod_poly_set(R, A); F_mpz_mod_poly_zero(Q); return; } F_mpz_t lead_inv; F_mpz_init(lead_inv); F_mpz_invert(lead_inv, B->coeffs + B->length - 1, B->P); F_mpz * coeff_Q; F_mpz_mod_poly_t qB; F_mpz_mod_poly_init2(qB, B->P, B->length); F_mpz_mod_poly_t Bm1; _F_mpz_mod_poly_attach_truncate(Bm1, B, B->length - 1); long coeff = A->length - 1; F_mpz_mod_poly_set(R, A); if (A->length >= B->length) { F_mpz_mod_poly_fit_length(Q, A->length - B->length + 1); _F_mpz_mod_poly_set_length(Q, A->length - B->length + 1); } else F_mpz_mod_poly_zero(Q); coeff_Q = Q->coeffs - B->length + 1; while (coeff >= (long) B->length - 1) { while ((coeff >= (long) B->length - 1) && (F_mpz_is_zero(R->coeffs + coeff))) { F_mpz_zero(coeff_Q + coeff); coeff--; } if (coeff >= (long) B->length - 1) { F_mpz_mulmod2(coeff_Q + coeff, R->coeffs + coeff, lead_inv, B->P); F_mpz_mod_poly_scalar_mul(qB, Bm1, coeff_Q + coeff); F_mpz_mod_poly_t R_sub; F_mpz_init(R_sub->P); F_mpz_set(R_sub->P, B->P); R_sub->coeffs = R->coeffs + coeff - B->length + 1; R_sub->length = B->length - 1; _F_mpz_mod_poly_sub(R_sub, R_sub, qB); F_mpz_clear(R_sub->P); coeff--; } } _F_mpz_mod_poly_set_length(R, B->length - 1); _F_mpz_mod_poly_normalise(R); F_mpz_mod_poly_clear(qB); F_mpz_clear(lead_inv); }
void F_mpz_mod_poly_gcd_euclidean(F_mpz_mod_poly_t res, F_mpz_mod_poly_t poly1, F_mpz_mod_poly_t poly2) { F_mpz_mod_poly_t R, A, B; F_mpz_poly_t r; int steps = 0; if (poly1->length == 0) { if (poly2->length == 0) F_mpz_mod_poly_zero(res); else F_mpz_mod_poly_make_monic(res, poly2); return; } if (poly2->length == 0) { F_mpz_mod_poly_make_monic(res, poly1); return; } if ((poly1->length == 1) || (poly2->length == 1)) { _F_mpz_poly_attach_F_mpz_mod_poly(r, res); F_mpz_poly_set_coeff_ui(r, 0, 1L); _F_mpz_mod_poly_attach_F_mpz_poly(res, r); _F_mpz_mod_poly_normalise(res); return; } F_mpz_t P; F_mpz_init(P); F_mpz_set(P, poly1->P); F_mpz_mod_poly_init(R, P); if (poly1->length > poly2->length) { _F_mpz_mod_poly_attach(A, poly1); _F_mpz_mod_poly_attach(B, poly2); } else { _F_mpz_mod_poly_attach(A, poly2); _F_mpz_mod_poly_attach(B, poly1); } F_mpz_mod_poly_rem(R, A, B); F_mpz_mod_poly_swap(A, B); F_mpz_mod_poly_swap(B, R); F_mpz_mod_poly_init(R, P); if (B->length > 1) { F_mpz_mod_poly_rem(R, A, B); F_mpz_mod_poly_swap(A, B); F_mpz_mod_poly_swap(B, R); F_mpz_mod_poly_init(R, P); steps = 1; } while (B->length > 1) { F_mpz_mod_poly_rem(A, A, B); F_mpz_mod_poly_swap(A, B); } if (B->length == 1) { _F_mpz_poly_attach_F_mpz_mod_poly(r, res); F_mpz_poly_set_coeff_ui(r, 0, 1L); _F_mpz_mod_poly_attach_F_mpz_poly(res, r); res->length = 1; } else F_mpz_mod_poly_make_monic(res, A); if (steps) { F_mpz_mod_poly_clear(A); } F_mpz_mod_poly_clear(B); F_mpz_mod_poly_clear(R); }