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, j, result = 1; fmpz_t t; flint_rand_t state; flint_randinit(state); printf("derivative...."); fflush(stdout); fmpz_init(t); /* Check derivative by hand */ for (i = 0; i < 10000; i++) { nmod_poly_t a, b; mp_limb_t n = n_randtest_not_zero(state); nmod_poly_init(a, n); nmod_poly_init(b, n); nmod_poly_randtest(a, state, n_randint(state, 100)); nmod_poly_derivative(b, a); if (a->length <= 1) result = (b->length == 0); else { for (j = 1; j < a->length; j++) { fmpz_set_ui(t, nmod_poly_get_coeff_ui(a, j)); fmpz_mul_ui(t, t, j); fmpz_mod_ui(t, t, n); result &= (fmpz_get_ui(t) == nmod_poly_get_coeff_ui(b, j - 1)); } } if (!result) { printf("FAIL:\n"); printf("a->length = %ld, n = %lu\n", a->length, a->mod.n); nmod_poly_print(a), printf("\n\n"); nmod_poly_print(b), printf("\n\n"); abort(); } nmod_poly_clear(a); nmod_poly_clear(b); } fmpz_clear(t); /* Check aliasing */ for (i = 0; i < 10000; i++) { nmod_poly_t a, b; mp_limb_t n = n_randtest_not_zero(state); nmod_poly_init(a, n); nmod_poly_init(b, n); nmod_poly_randtest(a, state, n_randint(state, 100)); nmod_poly_derivative(b, a); nmod_poly_derivative(a, a); result = nmod_poly_equal(a, b); if (!result) { printf("FAIL:\n"); printf("a->length = %ld, n = %lu\n", a->length, a->mod.n); nmod_poly_print(a), printf("\n\n"); nmod_poly_print(b), printf("\n\n"); abort(); } nmod_poly_clear(a); nmod_poly_clear(b); } flint_randclear(state); _fmpz_cleanup(); printf("PASS\n"); return 0; }