void _fmpz_poly_hensel_lift_without_inverse(fmpz *G, fmpz *H, const fmpz *f, long lenF, const fmpz *g, long lenG, const fmpz *h, long lenH, const fmpz *a, long lenA, const fmpz *b, long lenB, const fmpz_t p, const fmpz_t p1) { const fmpz one[1] = {1l}; const long lenM = FLINT_MAX(lenG, lenH); const long lenE = FLINT_MAX(lenG + lenB - 2, lenH + lenA - 2); const long lenD = FLINT_MAX(lenE, lenF); fmpz *C, *D, *E, *M; C = _fmpz_vec_init(lenF + lenD + lenE + lenM); D = C + lenF; E = D + lenD; M = E + lenE; if (lenG >= lenH) _fmpz_poly_mul(C, g,lenG, h, lenH); else _fmpz_poly_mul(C, h, lenH, g, lenG); _fmpz_vec_sub(C, f, C, lenF); _fmpz_vec_scalar_divexact_fmpz(D, C, lenF, p); _fmpz_vec_scalar_mod_fmpz(C, D, lenF, p1); lift(G, g, lenG, b, lenB); lift(H, h, lenH, a, lenA); _fmpz_vec_clear(C, lenF + lenD + lenE + lenM); }
/* 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 _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); }
void _gamma_rf_bsplit(fmpz * A, ulong a, ulong b) { ulong n = b - a; if (n == 0) { fmpz_one(A); } else if (n < 8) { ulong j, k; fmpz_set_ui(A, a); fmpz_one(A + 1); for (j = 1; j < n; j++) { fmpz_one(A + j + 1); for (k = j; k > 0; k--) { fmpz_mul_ui(A + k, A + k, a + j); fmpz_add(A + k, A + k, A + k - 1); } fmpz_mul_ui(A, A, a + j); } } else { ulong m = a + (b - a) / 2; ulong w = m - a; ulong v = b - m; fmpz *t, *A1, *A2; t = _fmpz_vec_init(w + v + 2); A1 = t; A2 = A1 + w + 1; _gamma_rf_bsplit(A1, a, m); _gamma_rf_bsplit(A2, m, b); _fmpz_poly_mul(A, A2, v + 1, A1, w + 1); _fmpz_vec_clear(t, w + v + 2); } }
/* Balanced product of linear factors (x+alpha_i) using fixed-point arithmetic with prec bits */ static void balanced_product(fmpz * c, fmpz * alpha, slong len, slong prec) { if (len == 1) { fmpz_one(c + 1); fmpz_mul_2exp(c + 1, c + 1, prec); fmpz_set(c, alpha); } else if (len == 2) { fmpz_mul(c, alpha, alpha + 1); fmpz_fdiv_q_2exp(c, c, prec); fmpz_add(c + 1, alpha, alpha + 1); fmpz_one(c + 2); fmpz_mul_2exp(c + 2, c + 2, prec); } else { fmpz *L, *R; slong i, m; m = len / 2; L = _fmpz_vec_init(len + 2); R = L + m + 1; balanced_product(L, alpha, m, prec); balanced_product(R, alpha + m, len - m, prec); _fmpz_poly_mul(c, R, len - m + 1, L, m + 1); for (i = 0; i < len + 1; i++) fmpz_fdiv_q_2exp(c + i, c + i, prec); _fmpz_vec_clear(L, len + 2); } }
void _fmpz_poly_compose_divconquer(fmpz * res, const fmpz * poly1, long len1, const fmpz * poly2, long len2) { long i, j, k, n; long *hlen, alloc, powlen; fmpz *v, **h, *pow, *temp; if (len1 == 1) { fmpz_set(res, poly1); return; } if (len2 == 1) { _fmpz_poly_evaluate_fmpz(res, poly1, len1, poly2); return; } if (len1 == 2) { _fmpz_poly_compose_horner(res, poly1, len1, poly2, len2); return; } /* Initialisation */ hlen = (long *) malloc(((len1 + 1) / 2) * sizeof(long)); for (k = 1; (2 << k) < len1; k++) ; hlen[0] = hlen[1] = ((1 << k) - 1) * (len2 - 1) + 1; for (i = k - 1; i > 0; i--) { long hi = (len1 + (1 << i) - 1) / (1 << i); for (n = (hi + 1) / 2; n < hi; n++) hlen[n] = ((1 << i) - 1) * (len2 - 1) + 1; } powlen = (1 << k) * (len2 - 1) + 1; alloc = 0; for (i = 0; i < (len1 + 1) / 2; i++) alloc += hlen[i]; v = _fmpz_vec_init(alloc + 2 * powlen); h = (fmpz **) malloc(((len1 + 1) / 2) * sizeof(fmpz *)); h[0] = v; for (i = 0; i < (len1 - 1) / 2; i++) { h[i + 1] = h[i] + hlen[i]; hlen[i] = 0; } hlen[(len1 - 1) / 2] = 0; pow = v + alloc; temp = pow + powlen; /* Let's start the actual work */ for (i = 0, j = 0; i < len1 / 2; i++, j += 2) { if (poly1[j + 1] != 0L) { _fmpz_vec_scalar_mul_fmpz(h[i], poly2, len2, poly1 + j + 1); fmpz_add(h[i], h[i], poly1 + j); hlen[i] = len2; } else if (poly1[j] != 0L) { fmpz_set(h[i], poly1 + j); hlen[i] = 1; } } if ((len1 & 1L)) { if (poly1[j] != 0L) { fmpz_set(h[i], poly1 + j); hlen[i] = 1; } } _fmpz_poly_mul(pow, poly2, len2, poly2, len2); powlen = 2 * len2 - 1; for (n = (len1 + 1) / 2; n > 2; n = (n + 1) / 2) { if (hlen[1] > 0) { long templen = powlen + hlen[1] - 1; _fmpz_poly_mul(temp, pow, powlen, h[1], hlen[1]); _fmpz_poly_add(h[0], temp, templen, h[0], hlen[0]); hlen[0] = FLINT_MAX(hlen[0], templen); } for (i = 1; i < n / 2; i++) { if (hlen[2*i + 1] > 0) { _fmpz_poly_mul(h[i], pow, powlen, h[2*i + 1], hlen[2*i + 1]); hlen[i] = hlen[2*i + 1] + powlen - 1; } else hlen[i] = 0; _fmpz_poly_add(h[i], h[i], hlen[i], h[2*i], hlen[2*i]); hlen[i] = FLINT_MAX(hlen[i], hlen[2*i]); } if ((n & 1L)) { _fmpz_vec_set(h[i], h[2*i], hlen[2*i]); hlen[i] = hlen[2*i]; } _fmpz_poly_mul(temp, pow, powlen, pow, powlen); powlen += powlen - 1; { fmpz * t = pow; pow = temp; temp = t; } } _fmpz_poly_mul(res, pow, powlen, h[1], hlen[1]); _fmpz_vec_add(res, res, h[0], hlen[0]); _fmpz_vec_clear(v, alloc + 2 * powlen); free(h); free(hlen); }
void frob(const mpoly_t P, const ctx_t ctxFracQt, const qadic_t t1, const qadic_ctx_t Qq, prec_t *prec, const prec_t *prec_in, int verbose) { const padic_ctx_struct *Qp = &Qq->pctx; const fmpz *p = Qp->p; const long a = qadic_ctx_degree(Qq); const long n = P->n - 1; const long d = mpoly_degree(P, -1, ctxFracQt); const long b = gmc_basis_size(n, d); long i, j, k; /* Diagonal fibre */ padic_mat_t F0; /* Gauss--Manin Connection */ mat_t M; mon_t *bR, *bC; fmpz_poly_t r; /* Local solution */ fmpz_poly_mat_t C, Cinv; long vC, vCinv; /* Frobenius */ fmpz_poly_mat_t F; long vF; fmpz_poly_mat_t F1; long vF1; fmpz_poly_t cp; clock_t c0, c1; double c; if (verbose) { printf("Input:\n"); printf(" P = "), mpoly_print(P, ctxFracQt), printf("\n"); printf(" p = "), fmpz_print(p), printf("\n"); printf(" t1 = "), qadic_print_pretty(t1, Qq), printf("\n"); printf("\n"); fflush(stdout); } /* Step 1 {M, r} *********************************************************/ c0 = clock(); mat_init(M, b, b, ctxFracQt); fmpz_poly_init(r); gmc_compute(M, &bR, &bC, P, ctxFracQt); { fmpz_poly_t t; fmpz_poly_init(t); fmpz_poly_set_ui(r, 1); for (i = 0; i < M->m; i++) for (j = 0; j < M->n; j++) { fmpz_poly_lcm(t, r, fmpz_poly_q_denref( (fmpz_poly_q_struct *) mat_entry(M, i, j, ctxFracQt))); fmpz_poly_swap(r, t); } fmpz_poly_clear(t); } c1 = clock(); c = (double) (c1 - c0) / CLOCKS_PER_SEC; if (verbose) { printf("Gauss-Manin connection:\n"); printf(" r(t) = "), fmpz_poly_print_pretty(r, "t"), printf("\n"); printf(" Time = %f\n", c); printf("\n"); fflush(stdout); } { qadic_t t; qadic_init2(t, 1); fmpz_poly_evaluate_qadic(t, r, t1, Qq); if (qadic_is_zero(t)) { printf("Exception (deformation_frob).\n"); printf("The resultant r evaluates to zero (mod p) at t1.\n"); abort(); } qadic_clear(t); } /* Precisions ************************************************************/ if (prec_in != NULL) { *prec = *prec_in; } else { deformation_precisions(prec, p, a, n, d, fmpz_poly_degree(r)); } if (verbose) { printf("Precisions:\n"); printf(" N0 = %ld\n", prec->N0); printf(" N1 = %ld\n", prec->N1); printf(" N2 = %ld\n", prec->N2); printf(" N3 = %ld\n", prec->N3); printf(" N3i = %ld\n", prec->N3i); printf(" N3w = %ld\n", prec->N3w); printf(" N3iw = %ld\n", prec->N3iw); printf(" N4 = %ld\n", prec->N4); printf(" m = %ld\n", prec->m); printf(" K = %ld\n", prec->K); printf(" r = %ld\n", prec->r); printf(" s = %ld\n", prec->s); printf("\n"); fflush(stdout); } /* Initialisation ********************************************************/ padic_mat_init2(F0, b, b, prec->N4); fmpz_poly_mat_init(C, b, b); fmpz_poly_mat_init(Cinv, b, b); fmpz_poly_mat_init(F, b, b); vF = 0; fmpz_poly_mat_init(F1, b, b); vF1 = 0; fmpz_poly_init(cp); /* Step 2 {F0} ***********************************************************/ { padic_ctx_t pctx_F0; fmpz *t; padic_ctx_init(pctx_F0, p, FLINT_MIN(prec->N4 - 10, 0), prec->N4, PADIC_VAL_UNIT); t = _fmpz_vec_init(n + 1); c0 = clock(); mpoly_diagonal_fibre(t, P, ctxFracQt); diagfrob(F0, t, n, d, prec->N4, pctx_F0, 0); padic_mat_transpose(F0, F0); c1 = clock(); c = (double) (c1 - c0) / CLOCKS_PER_SEC; if (verbose) { printf("Diagonal fibre:\n"); printf(" P(0) = {"), _fmpz_vec_print(t, n + 1), printf("}\n"); printf(" Time = %f\n", c); printf("\n"); fflush(stdout); } _fmpz_vec_clear(t, n + 1); padic_ctx_clear(pctx_F0); } /* Step 3 {C, Cinv} ******************************************************/ /* Compute C as a matrix over Z_p[[t]]. A is the same but as a series of matrices over Z_p. Mt is the matrix -M^t, and Cinv is C^{-1}^t, the local solution of the differential equation replacing M by Mt. */ c0 = clock(); { const long K = prec->K; padic_mat_struct *A; gmde_solve(&A, K, p, prec->N3, prec->N3w, M, ctxFracQt); gmde_convert_soln(C, &vC, A, K, p); for(i = 0; i < K; i++) padic_mat_clear(A + i); free(A); } c1 = clock(); c = (double) (c1 - c0) / CLOCKS_PER_SEC; if (verbose) { printf("Local solution:\n"); printf(" Time for C = %f\n", c); fflush(stdout); } c0 = clock(); { const long K = (prec->K + (*p) - 1) / (*p); mat_t Mt; padic_mat_struct *Ainv; mat_init(Mt, b, b, ctxFracQt); mat_transpose(Mt, M, ctxFracQt); mat_neg(Mt, Mt, ctxFracQt); gmde_solve(&Ainv, K, p, prec->N3i, prec->N3iw, Mt, ctxFracQt); gmde_convert_soln(Cinv, &vCinv, Ainv, K, p); fmpz_poly_mat_transpose(Cinv, Cinv); fmpz_poly_mat_compose_pow(Cinv, Cinv, *p); for(i = 0; i < K; i++) padic_mat_clear(Ainv + i); free(Ainv); mat_clear(Mt, ctxFracQt); } c1 = clock(); c = (double) (c1 - c0) / CLOCKS_PER_SEC; if (verbose) { printf(" Time for C^{-1} = %f\n", c); printf("\n"); fflush(stdout); } /* Step 4 {F(t) := C(t) F(0) C(t^p)^{-1}} ********************************/ /* Computes the product C(t) F(0) C(t^p)^{-1} modulo (p^{N_2}, t^K). This is done by first computing the unit part of the product exactly over the integers modulo t^K. */ c0 = clock(); { fmpz_t pN; fmpz_poly_mat_t T; fmpz_init(pN); fmpz_poly_mat_init(T, b, b); for (i = 0; i < b; i++) { /* Find the unique k s.t. F0(i,k) is non-zero */ for (k = 0; k < b; k++) if (!fmpz_is_zero(padic_mat_entry(F0, i, k))) break; if (k == b) { printf("Exception (frob). F0 is singular.\n\n"); abort(); } for (j = 0; j < b; j++) { fmpz_poly_scalar_mul_fmpz(fmpz_poly_mat_entry(T, i, j), fmpz_poly_mat_entry(Cinv, k, j), padic_mat_entry(F0, i, k)); } } fmpz_poly_mat_mul(F, C, T); fmpz_poly_mat_truncate(F, prec->K); vF = vC + padic_mat_val(F0) + vCinv; /* Canonicalise (F, vF) */ { long v = fmpz_poly_mat_ord_p(F, p); if (v == LONG_MAX) { printf("ERROR (deformation_frob). F(t) == 0.\n"); abort(); } else if (v > 0) { fmpz_pow_ui(pN, p, v); fmpz_poly_mat_scalar_divexact_fmpz(F, F, pN); vF = vF + v; } } /* Reduce (F, vF) modulo p^{N2} */ fmpz_pow_ui(pN, p, prec->N2 - vF); fmpz_poly_mat_scalar_mod_fmpz(F, F, pN); fmpz_clear(pN); fmpz_poly_mat_clear(T); } c1 = clock(); c = (double) (c1 - c0) / CLOCKS_PER_SEC; if (verbose) { printf("Matrix for F(t):\n"); printf(" Time = %f\n", c); printf("\n"); fflush(stdout); } /* Step 5 {G = r(t)^m F(t)} **********************************************/ c0 = clock(); { fmpz_t pN; fmpz_poly_t t; fmpz_init(pN); fmpz_poly_init(t); fmpz_pow_ui(pN, p, prec->N2 - vF); /* Compute r(t)^m mod p^{N2-vF} */ if (prec->denR == NULL) { fmpz_mod_poly_t _t; fmpz_mod_poly_init(_t, pN); fmpz_mod_poly_set_fmpz_poly(_t, r); fmpz_mod_poly_pow(_t, _t, prec->m); fmpz_mod_poly_get_fmpz_poly(t, _t); fmpz_mod_poly_clear(_t); } else { /* TODO: We don't really need a copy */ fmpz_poly_set(t, prec->denR); } fmpz_poly_mat_scalar_mul_fmpz_poly(F, F, t); fmpz_poly_mat_scalar_mod_fmpz(F, F, pN); /* TODO: This should not be necessary? */ fmpz_poly_mat_truncate(F, prec->K); fmpz_clear(pN); fmpz_poly_clear(t); } c1 = clock(); c = (double) (c1 - c0) / CLOCKS_PER_SEC; if (verbose) { printf("Analytic continuation:\n"); printf(" Time = %f\n", c); printf("\n"); fflush(stdout); } /* Steps 6 and 7 *********************************************************/ if (a == 1) { /* Step 6 {F(1) = r(t_1)^{-m} G(t_1)} ********************************/ c0 = clock(); { const long N = prec->N2 - vF; fmpz_t f, g, t, pN; fmpz_init(f); fmpz_init(g); fmpz_init(t); fmpz_init(pN); fmpz_pow_ui(pN, p, N); /* f := \hat{t_1}, g := r(\hat{t_1})^{-m} */ _padic_teichmuller(f, t1->coeffs + 0, p, N); if (prec->denR == NULL) { _fmpz_mod_poly_evaluate_fmpz(g, r->coeffs, r->length, f, pN); fmpz_powm_ui(t, g, prec->m, pN); } else { _fmpz_mod_poly_evaluate_fmpz(t, prec->denR->coeffs, prec->denR->length, f, pN); } _padic_inv(g, t, p, N); /* F1 := g G(\hat{t_1}) */ for (i = 0; i < b; i++) for (j = 0; j < b; j++) { const fmpz_poly_struct *poly = fmpz_poly_mat_entry(F, i, j); const long len = poly->length; if (len == 0) { fmpz_poly_zero(fmpz_poly_mat_entry(F1, i, j)); } else { fmpz_poly_fit_length(fmpz_poly_mat_entry(F1, i, j), 1); _fmpz_mod_poly_evaluate_fmpz(t, poly->coeffs, len, f, pN); fmpz_mul(fmpz_poly_mat_entry(F1, i, j)->coeffs + 0, g, t); fmpz_mod(fmpz_poly_mat_entry(F1, i, j)->coeffs + 0, fmpz_poly_mat_entry(F1, i, j)->coeffs + 0, pN); _fmpz_poly_set_length(fmpz_poly_mat_entry(F1, i, j), 1); _fmpz_poly_normalise(fmpz_poly_mat_entry(F1, i, j)); } } vF1 = vF; fmpz_poly_mat_canonicalise(F1, &vF1, p); fmpz_clear(f); fmpz_clear(g); fmpz_clear(t); fmpz_clear(pN); } c1 = clock(); c = (double) (c1 - c0) / CLOCKS_PER_SEC; if (verbose) { printf("Evaluation:\n"); printf(" Time = %f\n", c); printf("\n"); fflush(stdout); } } else { /* Step 6 {F(1) = r(t_1)^{-m} G(t_1)} ********************************/ c0 = clock(); { const long N = prec->N2 - vF; fmpz_t pN; fmpz *f, *g, *t; fmpz_init(pN); f = _fmpz_vec_init(a); g = _fmpz_vec_init(2 * a - 1); t = _fmpz_vec_init(2 * a - 1); fmpz_pow_ui(pN, p, N); /* f := \hat{t_1}, g := r(\hat{t_1})^{-m} */ _qadic_teichmuller(f, t1->coeffs, t1->length, Qq->a, Qq->j, Qq->len, p, N); if (prec->denR == NULL) { fmpz_t e; fmpz_init_set_ui(e, prec->m); _fmpz_mod_poly_compose_smod(g, r->coeffs, r->length, f, a, Qq->a, Qq->j, Qq->len, pN); _qadic_pow(t, g, a, e, Qq->a, Qq->j, Qq->len, pN); fmpz_clear(e); } else { _fmpz_mod_poly_reduce(prec->denR->coeffs, prec->denR->length, Qq->a, Qq->j, Qq->len, pN); _fmpz_poly_normalise(prec->denR); _fmpz_mod_poly_compose_smod(t, prec->denR->coeffs, prec->denR->length, f, a, Qq->a, Qq->j, Qq->len, pN); } _qadic_inv(g, t, a, Qq->a, Qq->j, Qq->len, p, N); /* F1 := g G(\hat{t_1}) */ for (i = 0; i < b; i++) for (j = 0; j < b; j++) { const fmpz_poly_struct *poly = fmpz_poly_mat_entry(F, i, j); const long len = poly->length; fmpz_poly_struct *poly2 = fmpz_poly_mat_entry(F1, i, j); if (len == 0) { fmpz_poly_zero(poly2); } else { _fmpz_mod_poly_compose_smod(t, poly->coeffs, len, f, a, Qq->a, Qq->j, Qq->len, pN); fmpz_poly_fit_length(poly2, 2 * a - 1); _fmpz_poly_mul(poly2->coeffs, g, a, t, a); _fmpz_mod_poly_reduce(poly2->coeffs, 2 * a - 1, Qq->a, Qq->j, Qq->len, pN); _fmpz_poly_set_length(poly2, a); _fmpz_poly_normalise(poly2); } } /* Now the matrix for p^{-1} F_p at t=t_1 is (F1, vF1). */ vF1 = vF; fmpz_poly_mat_canonicalise(F1, &vF1, p); fmpz_clear(pN); _fmpz_vec_clear(f, a); _fmpz_vec_clear(g, 2 * a - 1); _fmpz_vec_clear(t, 2 * a - 1); } c1 = clock(); c = (double) (c1 - c0) / CLOCKS_PER_SEC; if (verbose) { printf("Evaluation:\n"); printf(" Time = %f\n", c); printf("\n"); fflush(stdout); } /* Step 7 {Norm} *****************************************************/ /* Computes the matrix for $q^{-1} F_q$ at $t = t_1$ as the product $F \sigma(F) \dotsm \sigma^{a-1}(F)$ up appropriate transpositions because our convention of columns vs rows is the opposite of that used by Gerkmann. Note that, in any case, transpositions do not affect the characteristic polynomial. */ c0 = clock(); { const long N = prec->N1 - a * vF1; fmpz_t pN; fmpz_poly_mat_t T; fmpz_init(pN); fmpz_poly_mat_init(T, b, b); fmpz_pow_ui(pN, p, N); fmpz_poly_mat_frobenius(T, F1, 1, p, N, Qq); _qadic_mat_mul(F1, F1, T, pN, Qq); for (i = 2; i < a; i++) { fmpz_poly_mat_frobenius(T, T, 1, p, N, Qq); _qadic_mat_mul(F1, F1, T, pN, Qq); } vF1 = a * vF1; fmpz_poly_mat_canonicalise(F1, &vF1, p); fmpz_clear(pN); fmpz_poly_mat_clear(T); } c1 = clock(); c = (double) (c1 - c0) / CLOCKS_PER_SEC; if (verbose) { printf("Norm:\n"); printf(" Time = %f\n", c); printf("\n"); fflush(stdout); } } /* Step 8 {Reverse characteristic polynomial} ****************************/ c0 = clock(); deformation_revcharpoly(cp, F1, vF1, n, d, prec->N0, prec->r, prec->s, Qq); c1 = clock(); c = (double) (c1 - c0) / CLOCKS_PER_SEC; if (verbose) { printf("Reverse characteristic polynomial:\n"); printf(" p(T) = "), fmpz_poly_print_pretty(cp, "T"), printf("\n"); printf(" Time = %f\n", c); printf("\n"); fflush(stdout); } /* Clean up **************************************************************/ padic_mat_clear(F0); mat_clear(M, ctxFracQt); free(bR); free(bC); fmpz_poly_clear(r); fmpz_poly_mat_clear(C); fmpz_poly_mat_clear(Cinv); fmpz_poly_mat_clear(F); fmpz_poly_mat_clear(F1); fmpz_poly_clear(cp); }
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); } }
void _fmpz_mod_poly_mul(fmpz *res, const fmpz *poly1, slong len1, const fmpz *poly2, slong len2, const fmpz_t p) { _fmpz_poly_mul(res, poly1, len1, poly2, len2); _fmpz_vec_scalar_mod_fmpz(res, res, len1 + len2 - 1, p); }
int main(void) { int i, result; flint_rand_t state; printf("mul...."); fflush(stdout); flint_randinit(state); /* Check aliasing of a and b */ for (i = 0; i < 2000; i++) { fmpz_poly_t a, b, c; fmpz_poly_init(a); fmpz_poly_init(b); fmpz_poly_init(c); fmpz_poly_randtest(b, state, n_randint(state, 50), 500); fmpz_poly_randtest(c, state, n_randint(state, 50), 500); fmpz_poly_mul(a, b, c); fmpz_poly_mul(b, b, c); result = (fmpz_poly_equal(a, b)); if (!result) { printf("FAIL:\n"); fmpz_poly_print(a), printf("\n\n"); fmpz_poly_print(b), printf("\n\n"); abort(); } fmpz_poly_clear(a); fmpz_poly_clear(b); fmpz_poly_clear(c); } /* Check aliasing of a and c */ for (i = 0; i < 2000; i++) { fmpz_poly_t a, b, c; fmpz_poly_init(a); fmpz_poly_init(b); fmpz_poly_init(c); fmpz_poly_randtest(b, state, n_randint(state, 50), 500); fmpz_poly_randtest(c, state, n_randint(state, 50), 500); fmpz_poly_mul(a, b, c); fmpz_poly_mul(c, b, c); result = (fmpz_poly_equal(a, c)); if (!result) { printf("FAIL:\n"); fmpz_poly_print(a), printf("\n\n"); fmpz_poly_print(c), printf("\n\n"); abort(); } fmpz_poly_clear(a); fmpz_poly_clear(b); fmpz_poly_clear(c); } /* Check (b*c)+(b*d) = b*(c+d) */ for (i = 0; i < 2000; i++) { fmpz_poly_t a1, a2, b, c, d; fmpz_poly_init(a1); fmpz_poly_init(a2); fmpz_poly_init(b); fmpz_poly_init(c); fmpz_poly_init(d); fmpz_poly_randtest(b, state, n_randint(state, 100), 500); fmpz_poly_randtest(c, state, n_randint(state, 100), 500); fmpz_poly_randtest(d, state, n_randint(state, 100), 500); fmpz_poly_mul(a1, b, c); fmpz_poly_mul(a2, b, d); fmpz_poly_add(a1, a1, a2); fmpz_poly_add(c, c, d); fmpz_poly_mul(a2, b, c); result = (fmpz_poly_equal(a1, a2)); if (!result) { printf("FAIL:\n"); fmpz_poly_print(a1), printf("\n\n"); fmpz_poly_print(a2), printf("\n\n"); abort(); } fmpz_poly_clear(a1); fmpz_poly_clear(a2); fmpz_poly_clear(b); fmpz_poly_clear(c); fmpz_poly_clear(d); } /* Check _fmpz_poly_mul directly */ for (i = 0; i < 2000; i++) { long len1, len2; fmpz_poly_t a, b, out1, out2; len1 = n_randint(state, 100) + 1; len2 = n_randint(state, 100) + 1; fmpz_poly_init(a); fmpz_poly_init(b); fmpz_poly_init(out1); fmpz_poly_init(out2); fmpz_poly_randtest(a, state, len1, 200); fmpz_poly_randtest(b, state, len2, 200); fmpz_poly_mul(out1, a, b); fmpz_poly_fit_length(a, a->alloc + n_randint(state, 10)); fmpz_poly_fit_length(b, b->alloc + n_randint(state, 10)); a->length = a->alloc; b->length = b->alloc; fmpz_poly_fit_length(out2, a->length + b->length - 1); if (a->length >= b->length) _fmpz_poly_mul(out2->coeffs, a->coeffs, a->length, b->coeffs, b->length); else _fmpz_poly_mul(out2->coeffs, b->coeffs, b->length, a->coeffs, a->length); _fmpz_poly_set_length(out2, a->length + b->length - 1); _fmpz_poly_normalise(out2); result = (fmpz_poly_equal(out1, out2)); if (!result) { printf("FAIL:\n"); fmpz_poly_print(out1), printf("\n\n"); fmpz_poly_print(out2), printf("\n\n"); abort(); } fmpz_poly_clear(a); fmpz_poly_clear(b); fmpz_poly_clear(out1); fmpz_poly_clear(out2); } flint_randclear(state); _fmpz_cleanup(); printf("PASS\n"); return 0; }
static void __fmpz_poly_divrem_divconquer(fmpz * Q, fmpz * R, const fmpz * A, long lenA, const fmpz * B, long lenB) { if (lenA < 2 * lenB - 1) { /* Convert unbalanced division into a 2 n1 - 1 by n1 division */ const long n1 = lenA - lenB + 1; const long n2 = lenB - n1; const fmpz * p1 = A + n2; const fmpz * d1 = B + n2; const fmpz * d2 = B; fmpz * W = _fmpz_vec_init((2 * n1 - 1) + lenB - 1); fmpz * d1q1 = R + n2; fmpz * d2q1 = W + (2 * n1 - 1); _fmpz_poly_divrem_divconquer_recursive(Q, d1q1, W, p1, d1, n1); /* Compute d2q1 = Q d2, of length lenB - 1 */ if (n1 >= n2) _fmpz_poly_mul(d2q1, Q, n1, d2, n2); else _fmpz_poly_mul(d2q1, d2, n2, Q, n1); /* Compute BQ = d1q1 * x^n1 + d2q1, of length lenB - 1; then compute R = A - BQ */ _fmpz_vec_swap(R, d2q1, n2); _fmpz_vec_add(R + n2, R + n2, d2q1 + n2, n1 - 1); _fmpz_vec_sub(R, A, R, lenA); _fmpz_vec_clear(W, (2 * n1 - 1) + lenB - 1); } else if (lenA > 2 * lenB - 1) { /* We shift A right until it is of length 2 lenB - 1, call this p1 */ const long shift = lenA - 2 * lenB + 1; const fmpz * p1 = A + shift; fmpz * q1 = Q + shift; fmpz * q2 = Q; fmpz * W = R + lenA; fmpz * d1q1 = W + (2 * lenB - 1); /* XXX: In this case, we expect R to be of length lenA + 2 * (2 * lenB - 1) and A to be modifiable */ /* Set q1 to p1 div B, a 2 lenB - 1 by lenB division, so q1 ends up being of length lenB; set d1q1 = d1 * q1 of length 2 lenB - 1 */ _fmpz_poly_divrem_divconquer_recursive(q1, d1q1, W, p1, B, lenB); /* We have dq1 = d1 * q1 * x^shift, of length lenA Compute R = A - dq1; the first lenB coeffs represent remainder terms (zero if division is exact), leaving lenA - lenB significant terms which we use in the division */ _fmpz_vec_sub((fmpz *) A + shift, A + shift, d1q1, lenB - 1); /* Compute q2 = trunc(R) div B; it is a smaller division than the original since len(trunc(R)) = lenA - lenB */ __fmpz_poly_divrem_divconquer(q2, R, A, lenA - lenB, B, lenB); _fmpz_vec_sub(R + lenA - lenB, A + lenA - lenB, d1q1 + lenB - 1, lenB); /* We have Q = q1 * x^shift + q2; Q has length lenB + shift; note q2 has length shift since the above division is lenA - lenB by lenB We've also written the remainder in place */ } else /* lenA = 2 * lenB - 1 */ { fmpz * W = _fmpz_vec_init(lenA); _fmpz_poly_divrem_divconquer_recursive(Q, R, W, A, B, lenB); _fmpz_vec_sub(R, A, R, lenA); _fmpz_vec_clear(W, lenA); } }