void nmod_poly_factor_cantor_zassenhaus(nmod_poly_factor_t res, const nmod_poly_t f) { nmod_poly_t h, v, g, x; slong i, j, num; nmod_poly_init_preinv(h, f->mod.n, f->mod.ninv); nmod_poly_init_preinv(g, f->mod.n, f->mod.ninv); nmod_poly_init_preinv(v, f->mod.n, f->mod.ninv); nmod_poly_init_preinv(x, f->mod.n, f->mod.ninv); nmod_poly_set_coeff_ui(h, 1, 1); nmod_poly_set_coeff_ui(x, 1, 1); nmod_poly_make_monic(v, f); i = 0; do { i++; nmod_poly_powmod_ui_binexp(h, h, f->mod.n, v); nmod_poly_sub(h, h, x); nmod_poly_gcd(g, h, v); nmod_poly_add(h, h, x); if (g->length != 1) { nmod_poly_make_monic(g, g); num = res->num; nmod_poly_factor_equal_deg(res, g, i); for (j = num; j < res->num; j++) res->exp[j] = nmod_poly_remove(v, res->p + j); } } while (v->length >= 2*i + 3); if (v->length > 1) nmod_poly_factor_insert(res, v, 1); nmod_poly_clear(g); nmod_poly_clear(h); nmod_poly_clear(v); nmod_poly_clear(x); }
void nmod_poly_factor_squarefree(nmod_poly_factor_t res, const nmod_poly_t f) { nmod_poly_t f_d, g, g_1; mp_limb_t p; slong deg, i; if (f->length <= 1) { res->num = 0; return; } if (f->length == 2) { nmod_poly_factor_insert(res, f, 1); return; } p = nmod_poly_modulus(f); deg = nmod_poly_degree(f); /* Step 1, look at f', if it is zero then we are done since f = h(x)^p for some particular h(x), clearly f(x) = sum a_k x^kp, k <= deg(f) */ nmod_poly_init(g_1, p); nmod_poly_init(f_d, p); nmod_poly_init(g, p); nmod_poly_derivative(f_d, f); /* Case 1 */ if (nmod_poly_is_zero(f_d)) { nmod_poly_factor_t new_res; nmod_poly_t h; nmod_poly_init(h, p); for (i = 0; i <= deg / p; i++) /* this will be an integer since f'=0 */ { nmod_poly_set_coeff_ui(h, i, nmod_poly_get_coeff_ui(f, i * p)); } /* Now run square-free on h, and return it to the pth power */ nmod_poly_factor_init(new_res); nmod_poly_factor_squarefree(new_res, h); nmod_poly_factor_pow(new_res, p); nmod_poly_factor_concat(res, new_res); nmod_poly_clear(h); nmod_poly_factor_clear(new_res); } else { nmod_poly_t h, z; nmod_poly_gcd(g, f, f_d); nmod_poly_div(g_1, f, g); i = 1; nmod_poly_init(h, p); nmod_poly_init(z, p); /* Case 2 */ while (!nmod_poly_is_one(g_1)) { nmod_poly_gcd(h, g_1, g); nmod_poly_div(z, g_1, h); /* out <- out.z */ if (z->length > 1) { nmod_poly_factor_insert(res, z, 1); nmod_poly_make_monic(res->p + (res->num - 1), res->p + (res->num - 1)); if (res->num) res->exp[res->num - 1] *= i; } i++; nmod_poly_set(g_1, h); nmod_poly_div(g, g, h); } nmod_poly_clear(h); nmod_poly_clear(z); nmod_poly_make_monic(g, g); if (!nmod_poly_is_one(g)) { /* so now we multiply res with square-free(g^1/p) ^ p */ nmod_poly_t g_p; /* g^(1/p) */ nmod_poly_factor_t new_res_2; nmod_poly_init(g_p, p); for (i = 0; i <= nmod_poly_degree(g) / p; i++) nmod_poly_set_coeff_ui(g_p, i, nmod_poly_get_coeff_ui(g, i*p)); nmod_poly_factor_init(new_res_2); /* square-free(g^(1/p)) */ nmod_poly_factor_squarefree(new_res_2, g_p); nmod_poly_factor_pow(new_res_2, p); nmod_poly_factor_concat(res, new_res_2); nmod_poly_clear(g_p); nmod_poly_factor_clear(new_res_2); } } nmod_poly_clear(g_1); nmod_poly_clear(f_d); nmod_poly_clear(g); }
int main(void) { int i, result; flint_rand_t state; printf("hensel_start_continue_lift...."); fflush(stdout); flint_randinit(state); /* We check that lifting local factors of F yields factors */ for (i = 0; i < 1000; i++) { fmpz_poly_t F, G, H, R; nmod_poly_factor_t f_fac; fmpz_poly_factor_t F_fac; long bits, nbits, n, exp, j, part_exp; long r; fmpz_poly_t *v, *w; long *link; long prev_exp; bits = n_randint(state, 200) + 1; nbits = n_randint(state, FLINT_BITS - 6) + 6; fmpz_poly_init(F); fmpz_poly_init(G); fmpz_poly_init(H); fmpz_poly_init(R); nmod_poly_factor_init(f_fac); fmpz_poly_factor_init(F_fac); n = n_randprime(state, nbits, 0); exp = bits / (FLINT_BIT_COUNT(n) - 1) + 1; part_exp = n_randint(state, exp); /* Produce F as the product of random G and H */ { nmod_poly_t f; nmod_poly_init(f, n); do { do { fmpz_poly_randtest(G, state, n_randint(state, 200) + 2, bits); } while (G->length < 2); fmpz_randtest_not_zero(G->coeffs, state, bits); fmpz_one(fmpz_poly_lead(G)); do { fmpz_poly_randtest(H, state, n_randint(state, 200) + 2, bits); } while (H->length < 2); fmpz_randtest_not_zero(H->coeffs, state, bits); fmpz_one(fmpz_poly_lead(H)); fmpz_poly_mul(F, G, H); fmpz_poly_get_nmod_poly(f, F); } while (!nmod_poly_is_squarefree(f)); fmpz_poly_get_nmod_poly(f, G); nmod_poly_factor_insert(f_fac, f, 1); fmpz_poly_get_nmod_poly(f, H); nmod_poly_factor_insert(f_fac, f, 1); nmod_poly_clear(f); } r = f_fac->num; v = flint_malloc((2*r - 2)*sizeof(fmpz_poly_t)); w = flint_malloc((2*r - 2)*sizeof(fmpz_poly_t)); link = flint_malloc((2*r - 2)*sizeof(long)); for (j = 0; j < 2*r - 2; j++) { fmpz_poly_init(v[j]); fmpz_poly_init(w[j]); } if (part_exp < 1) { _fmpz_poly_hensel_start_lift(F_fac, link, v, w, F, f_fac, exp); } else { fmpz_t nn; fmpz_init_set_ui(nn, n); prev_exp = _fmpz_poly_hensel_start_lift(F_fac, link, v, w, F, f_fac, part_exp); _fmpz_poly_hensel_continue_lift(F_fac, link, v, w, F, prev_exp, part_exp, exp, nn); fmpz_clear(nn); } result = 1; for (j = 0; j < F_fac->num; j++) { fmpz_poly_rem(R, F, F_fac->p + j); result &= (R->length == 0); } for (j = 0; j < 2*r - 2; j++) { fmpz_poly_clear(v[j]); fmpz_poly_clear(w[j]); } flint_free(link); flint_free(v); flint_free(w); if (!result) { printf("FAIL:\n"); printf("bits = %ld, n = %ld, exp = %ld\n", bits, n, exp); fmpz_poly_print(F); printf("\n\n"); fmpz_poly_print(G); printf("\n\n"); fmpz_poly_print(H); printf("\n\n"); fmpz_poly_factor_print(F_fac); printf("\n\n"); abort(); } nmod_poly_factor_clear(f_fac); fmpz_poly_factor_clear(F_fac); fmpz_poly_clear(F); fmpz_poly_clear(H); fmpz_poly_clear(G); fmpz_poly_clear(R); } flint_randclear(state); _fmpz_cleanup(); printf("PASS\n"); return 0; }