#include "fmpz.h"
#include "gr_vec.h"
#include "gr_poly.h"
int
gr_poly_factor_squarefree(gr_ptr c, gr_vec_t fac, gr_vec_t exp, const gr_poly_t F, gr_ctx_t ctx)
{
gr_poly_t f, d, t1;
gr_poly_t v, w, s;
slong i;
int status = GR_SUCCESS;
fmpz_t e;
gr_ctx_t poly_ctx, fmpz_ctx;
if (gr_ctx_is_finite_characteristic(ctx) != T_FALSE)
return GR_UNABLE;
gr_ctx_init_gr_poly(poly_ctx, ctx);
gr_ctx_init_fmpz(fmpz_ctx);
if (F->length == 0)
{
status |= gr_zero(c, ctx);
gr_vec_set_length(fac, 0, poly_ctx);
gr_vec_set_length(exp, 0, fmpz_ctx);
gr_ctx_clear(poly_ctx);
gr_ctx_clear(fmpz_ctx);
return GR_SUCCESS;
}
status |= gr_poly_get_coeff_scalar(c, F, F->length - 1, ctx);
if (gr_is_zero(c, ctx) != T_FALSE)
{
gr_ctx_clear(poly_ctx);
gr_ctx_clear(fmpz_ctx);
return GR_UNABLE;
}
if (F->length == 1)
{
gr_vec_set_length(fac, 0, poly_ctx);
gr_vec_set_length(exp, 0, fmpz_ctx);
gr_ctx_clear(poly_ctx);
gr_ctx_clear(fmpz_ctx);
return GR_SUCCESS;
}
fmpz_init(e);
gr_poly_init(f, ctx);
gr_poly_init(d, ctx);
gr_poly_init(t1, ctx);
gr_poly_init(v, ctx);
gr_poly_init(w, ctx);
gr_poly_init(s, ctx);
status |= gr_poly_make_monic(f, F, ctx);
status |= gr_poly_derivative(t1, f, ctx);
status |= gr_poly_gcd(d, f, t1, ctx);
if (status != GR_SUCCESS)
{
status = GR_UNABLE;
goto cleanup;
}
gr_vec_set_length(fac, 0, ctx);
gr_vec_set_length(exp, 0, ctx);
if (d->length == 1)
{
status |= gr_vec_append(fac, f, poly_ctx);
fmpz_one(e);
status |= gr_vec_append(exp, e, fmpz_ctx);
}
else
{
status |= gr_poly_divrem(v, s, f, d, ctx);
status |= gr_poly_divrem(w, s, t1, d, ctx);
if (status != GR_SUCCESS)
goto cleanup;
for (i = 1; ; i++)
{
status |= gr_poly_derivative(t1, v, ctx);
status |= gr_poly_sub(s, w, t1, ctx);
if (s->length != 0 && gr_is_zero(gr_poly_coeff_ptr(s, s->length - 1, ctx), ctx) != T_FALSE)
{
status = GR_UNABLE;
goto cleanup;
}
if (s->length == 0)
{
if (v->length > 1)
{
status |= gr_vec_append(fac, v, poly_ctx);
fmpz_set_ui(e, i);
status |= gr_vec_append(exp, e, fmpz_ctx);
}
break;
}
status |= gr_poly_gcd(d, v, s, ctx);
if (status != GR_SUCCESS)
goto cleanup;
status |= gr_poly_divrem(v, t1, v, d, ctx);
status |= gr_poly_divrem(w, t1, s, d, ctx);
if (status != GR_SUCCESS)
goto cleanup;
if (d->length > 1)
{
status |= gr_vec_append(fac, d, poly_ctx);
fmpz_set_ui(e, i);
status |= gr_vec_append(exp, e, fmpz_ctx);
}
}
}
cleanup:
gr_poly_clear(f, ctx);
gr_poly_clear(d, ctx);
gr_poly_clear(t1, ctx);
gr_poly_clear(v, ctx);
gr_poly_clear(w, ctx);
gr_poly_clear(s, ctx);
fmpz_clear(e);
gr_ctx_clear(poly_ctx);
gr_ctx_clear(fmpz_ctx);
return status;
}