#include "nmod.h"
#include "fmpz_mod.h"
#include "nmod_mpoly_factor.h"
#include "fmpz_mod_mpoly_factor.h"
static void _fmpz_mod_mpoly_factor_mul_mpoly_fmpz(
fmpz_mod_mpoly_factor_t f,
fmpz_mod_mpoly_t A,
const fmpz_t e,
const fmpz_mod_mpoly_ctx_t ctx)
{
if (fmpz_mod_mpoly_is_fmpz(A, ctx))
{
FLINT_ASSERT(fmpz_mod_mpoly_is_one(A, ctx));
}
else
{
fmpz_mod_mpoly_factor_append_fmpz_swap(f, A, e, ctx);
}
}
int _fmpz_mod_mpoly_factor_separable(
fmpz_mod_mpoly_factor_t f,
const fmpz_mod_mpoly_t A,
const fmpz_mod_mpoly_ctx_t ctx,
int sep)
{
int success;
slong v, var;
fmpz_t k;
fmpz_mod_mpoly_t U, V, W, G;
FLINT_ASSERT(A->length > 0);
FLINT_ASSERT(fmpz_is_one(A->coeffs + 0));
if (fmpz_abs_fits_ui(fmpz_mod_ctx_modulus(ctx->ffinfo)))
{
nmod_mpoly_ctx_t nctx;
nmod_mpoly_t nA;
nmod_mpoly_factor_t nf;
*nctx->minfo = *ctx->minfo;
nmod_init(&nctx->mod, fmpz_get_ui(fmpz_mod_ctx_modulus(ctx->ffinfo)));
nmod_mpoly_init(nA, nctx);
nmod_mpoly_factor_init(nf, nctx);
_fmpz_mod_mpoly_get_nmod_mpoly(nA, nctx, A, ctx);
success = _nmod_mpoly_factor_separable(nf, nA, nctx, sep);
_fmpz_mod_mpoly_factor_set_nmod_mpoly_factor(f, ctx, nf, nctx);
nmod_mpoly_factor_clear(nf, nctx);
nmod_mpoly_clear(nA, nctx);
return success;
}
fmpz_mod_mpoly_factor_one(f, ctx);
if (!fmpz_mod_mpoly_degrees_fit_si(A, ctx))
return 0;
fmpz_init(k);
fmpz_mod_mpoly_init(U, ctx);
fmpz_mod_mpoly_init(V, ctx);
fmpz_mod_mpoly_init(W, ctx);
fmpz_mod_mpoly_init(G, ctx);
var = -1;
for (v = 0; v < ctx->minfo->nvars; v++)
{
fmpz_mod_mpoly_derivative(U, A, v, ctx);
if (U->length > 0 && (var < 0 || U->length < G->length))
{
var = v;
fmpz_mod_mpoly_swap(V, U, ctx);
}
}
if (var < 0)
{
FLINT_ASSERT(fmpz_mod_mpoly_is_one(A, ctx));
success = 1;
goto cleanup;
}
success = fmpz_mod_mpoly_gcd_cofactors(G, W, V, A, V, ctx);
if (!success)
goto cleanup;
fmpz_one(k);
while (1)
{
fmpz_add_ui(k, k, 1);
if (fmpz_cmp(k, fmpz_mod_ctx_modulus(ctx->ffinfo)) >= 0)
break;
fmpz_sub_ui(k, k, 1);
fmpz_mod_mpoly_derivative(G, W, var, ctx);
fmpz_mod_mpoly_sub(U, V, G, ctx);
if (fmpz_mod_mpoly_is_zero(U, ctx))
break;
success = fmpz_mod_mpoly_gcd_cofactors(G, W, V, W, U, ctx);
if (!success)
goto cleanup;
_fmpz_mod_mpoly_factor_mul_mpoly_fmpz(f, G, k, ctx);
fmpz_add_ui(k, k, 1);
}
_fmpz_mod_mpoly_factor_mul_mpoly_fmpz(f, W, k, ctx);
success = 1;
cleanup:
fmpz_clear(k);
fmpz_mod_mpoly_clear(U, ctx);
fmpz_mod_mpoly_clear(V, ctx);
fmpz_mod_mpoly_clear(W, ctx);
fmpz_mod_mpoly_clear(G, ctx);
return success;
}
int fmpz_mod_mpoly_factor_separable(
fmpz_mod_mpoly_factor_t f,
const fmpz_mod_mpoly_t A,
const fmpz_mod_mpoly_ctx_t ctx,
int sep)
{
int success;
slong i, j;
fmpz_mod_mpoly_factor_t g, t;
if (!fmpz_mod_mpoly_factor_content(f, A, ctx))
return 0;
fmpz_mod_mpoly_factor_init(g, ctx);
fmpz_mod_mpoly_factor_init(t, ctx);
fmpz_swap(g->constant, f->constant);
g->num = 0;
for (j = 0; j < f->num; j++)
{
success = _fmpz_mod_mpoly_factor_separable(t, f->poly + j, ctx, sep);
if (!success)
goto cleanup;
FLINT_ASSERT(fmpz_is_one(t->constant));
fmpz_mod_mpoly_factor_fit_length(g, g->num + t->num, ctx);
for (i = 0; i < t->num; i++)
{
fmpz_mul(g->exp + g->num, t->exp + i, f->exp + j);
fmpz_mod_mpoly_swap(g->poly + g->num, t->poly + i, ctx);
g->num++;
}
}
fmpz_mod_mpoly_factor_swap(f, g, ctx);
success = 1;
cleanup:
fmpz_mod_mpoly_factor_clear(t, ctx);
fmpz_mod_mpoly_factor_clear(g, ctx);
FLINT_ASSERT(!success || fmpz_mod_mpoly_factor_matches(A, f, ctx));
return success;
}
int fmpz_mod_mpoly_factor_squarefree(
fmpz_mod_mpoly_factor_t f,
const fmpz_mod_mpoly_t A,
const fmpz_mod_mpoly_ctx_t ctx)
{
return fmpz_mod_mpoly_factor_separable(f, A, ctx, 0);
}