#include "longlong.h"
#include "fq_nmod.h"
#include "n_poly.h"
#include "mpoly.h"
#include "nmod_mpoly.h"
#include "fq_nmod_mpoly.h"
static int nmod_mpolyu_gcdm_zippel_bivar(
nmod_mpolyu_t G,
nmod_mpolyu_t Abar,
nmod_mpolyu_t Bbar,
nmod_mpolyu_t A,
nmod_mpolyu_t B,
nmod_mpoly_ctx_t ctx,
flint_rand_t FLINT_UNUSED(randstate))
{
slong var = 0;
slong Alastdeg, Blastdeg;
slong bound;
slong lastdeg;
int success = 0, changed, have_enough;
nmod_mpolyun_t An, Bn, H, Ht;
slong deg;
fq_nmod_mpoly_ctx_t ffctx;
fq_nmod_mpolyu_t Aeval, Beval, Geval;
n_poly_t modulus, gamma, hc;
fq_nmod_t t, geval;
FLINT_ASSERT(G->bits == A->bits);
FLINT_ASSERT(Abar->bits == A->bits);
FLINT_ASSERT(Bbar->bits == A->bits);
FLINT_ASSERT(B->bits == A->bits);
nmod_mpolyun_init(An, A->bits, ctx);
nmod_mpolyun_init(Bn, A->bits, ctx);
nmod_mpolyu_cvtto_mpolyun(An, A, var, ctx);
nmod_mpolyu_cvtto_mpolyun(Bn, B, var, ctx);
FLINT_ASSERT(An->bits == B->bits);
FLINT_ASSERT(An->bits == G->bits);
FLINT_ASSERT(An->length > 0);
FLINT_ASSERT(Bn->length > 0);
FLINT_ASSERT(An->exps[A->length - 1] == 0);
FLINT_ASSERT(Bn->exps[B->length - 1] == 0);
n_poly_init(gamma);
n_poly_mod_gcd(gamma, nmod_mpolyun_leadcoeff_poly(An, ctx),
nmod_mpolyun_leadcoeff_poly(Bn, ctx), ctx->mod);
Alastdeg = nmod_mpolyun_lastdeg(An, ctx);
Blastdeg = nmod_mpolyun_lastdeg(Bn, ctx);
bound = 1 + n_poly_degree(gamma) + FLINT_MIN(Alastdeg, Blastdeg);
n_poly_init(hc);
n_poly_init(modulus);
n_poly_one(modulus);
nmod_mpolyun_init(H, A->bits, ctx);
nmod_mpolyun_init(Ht, A->bits, ctx);
deg = WORD(20)/(FLINT_BIT_COUNT(ctx->mod.n));
deg = FLINT_MAX(WORD(2), deg);
fq_nmod_mpoly_ctx_init_deg(ffctx, ctx->minfo->nvars, ORD_LEX, ctx->mod.n, deg);
fq_nmod_mpolyu_init(Aeval, A->bits, ffctx);
fq_nmod_mpolyu_init(Beval, A->bits, ffctx);
fq_nmod_mpolyu_init(Geval, A->bits, ffctx);
fq_nmod_init(geval, ffctx->fqctx);
fq_nmod_init(t, ffctx->fqctx);
while (1)
{
deg++;
if (deg > 10000)
{
success = 0;
goto finished;
}
fq_nmod_mpolyu_clear(Aeval, ffctx);
fq_nmod_mpolyu_clear(Beval, ffctx);
fq_nmod_mpolyu_clear(Geval, ffctx);
fq_nmod_clear(geval, ffctx->fqctx);
fq_nmod_clear(t, ffctx->fqctx);
fq_nmod_mpoly_ctx_change_modulus(ffctx, deg);
fq_nmod_mpolyu_init(Aeval, A->bits, ffctx);
fq_nmod_mpolyu_init(Beval, A->bits, ffctx);
fq_nmod_mpolyu_init(Geval, A->bits, ffctx);
fq_nmod_init(geval, ffctx->fqctx);
fq_nmod_init(t, ffctx->fqctx);
n_poly_mod_rem(evil_cast_nmod_poly_to_n_poly(geval), gamma,
evil_const_cast_nmod_poly_to_n_poly(ffctx->fqctx->modulus),
ctx->mod);
if (fq_nmod_is_zero(geval, ffctx->fqctx))
goto outer_continue;
nmod_mpolyun_interp_reduce_lg_mpolyu(Aeval, An, ffctx, ctx);
nmod_mpolyun_interp_reduce_lg_mpolyu(Beval, Bn, ffctx, ctx);
if (Aeval->length == 0 || Beval->length == 0)
goto outer_continue;
FLINT_ASSERT(fq_nmod_mpolyu_is_canonical(Aeval, ffctx));
FLINT_ASSERT(fq_nmod_mpolyu_is_canonical(Beval, ffctx));
fq_nmod_mpolyu_gcdp_zippel_univar_no_cofactors(Geval, Aeval, Beval, ffctx);
if (fq_nmod_mpolyu_is_one(Geval, ffctx))
{
nmod_mpolyu_one(G, ctx);
nmod_mpolyu_swap(Abar, A, ctx);
nmod_mpolyu_swap(Bbar, B, ctx);
success = 1;
goto finished;
}
FLINT_ASSERT(Geval->length > 0);
if (n_poly_degree(modulus) > 0)
{
if (Geval->exps[0] > H->exps[0])
{
goto outer_continue;
}
else if (Geval->exps[0] < H->exps[0])
{
n_poly_one(modulus);
}
}
n_fq_get_fq_nmod(t, fq_nmod_mpolyu_leadcoeff(Geval, ffctx), ffctx->fqctx);
fq_nmod_inv(t, t, ffctx->fqctx);
fq_nmod_mul(t, t, geval, ffctx->fqctx);
fq_nmod_mpolyu_scalar_mul_fq_nmod(Geval, t, ffctx);
if (n_poly_degree(modulus) > 0)
{
changed = nmod_mpolyun_interp_crt_lg_mpolyu(&lastdeg, H, Ht,
modulus, ctx, Geval, ffctx);
n_poly_mod_mul(modulus, modulus,
evil_const_cast_nmod_poly_to_n_poly(ffctx->fqctx->modulus),
ctx->mod);
have_enough = n_poly_degree(modulus) >= bound;
if (changed && !have_enough)
{
goto outer_continue;
}
if (!changed || have_enough)
{
nmod_mpolyun_content_last(hc, H, ctx);
nmod_mpolyun_set(Ht, H, ctx);
nmod_mpolyun_divexact_last(Ht, hc, ctx);
nmod_mpolyu_cvtfrom_mpolyun(G, Ht, var, ctx);
if ( nmod_mpolyuu_divides(Abar, A, G, 1, ctx)
&& nmod_mpolyuu_divides(Bbar, B, G, 1, ctx))
{
success = 1;
goto finished;
}
}
if (have_enough)
{
n_poly_one(modulus);
goto outer_continue;
}
}
else
{
nmod_mpolyun_interp_lift_lg_mpolyu(H, ctx, Geval, ffctx);
n_poly_set_nmod_poly(modulus, ffctx->fqctx->modulus);
}
outer_continue:;
}
finished:
n_poly_clear(gamma);
n_poly_clear(hc);
n_poly_clear(modulus);
nmod_mpolyun_clear(An, ctx);
nmod_mpolyun_clear(Bn, ctx);
nmod_mpolyun_clear(H, ctx);
nmod_mpolyun_clear(Ht, ctx);
fq_nmod_clear(geval, ffctx->fqctx);
fq_nmod_clear(t, ffctx->fqctx);
fq_nmod_mpolyu_clear(Aeval, ffctx);
fq_nmod_mpolyu_clear(Beval, ffctx);
fq_nmod_mpolyu_clear(Geval, ffctx);
fq_nmod_mpoly_ctx_clear(ffctx);
return success;
}
int nmod_mpolyu_gcdm_zippel(
nmod_mpolyu_t G,
nmod_mpolyu_t Abar,
nmod_mpolyu_t Bbar,
nmod_mpolyu_t A,
nmod_mpolyu_t B,
nmod_mpoly_ctx_t ctx,
flint_rand_t randstate)
{
slong degbound;
slong bound;
slong Alastdeg, Blastdeg;
slong lastdeg;
int success, changed, have_enough;
nmod_mpolyun_t An, Bn, Hn, Ht;
slong deg;
fq_nmod_mpoly_ctx_t ffctx;
fq_nmod_mpolyu_t Aff, Bff, Gff, Abarff, Bbarff, Gform;
n_poly_t modulus, gamma, hc;
fq_nmod_t t, gammaff;
FLINT_ASSERT(G->bits == A->bits);
FLINT_ASSERT(Abar->bits == A->bits);
FLINT_ASSERT(Bbar->bits == A->bits);
FLINT_ASSERT(B->bits == A->bits);
success = nmod_mpolyu_gcdp_zippel(G, Abar, Bbar, A, B,
ctx->minfo->nvars - 1, ctx, randstate);
if (success)
{
return 1;
}
if (ctx->minfo->nvars == 1)
{
return nmod_mpolyu_gcdm_zippel_bivar(G, Abar, Bbar, A, B, ctx, randstate);
}
FLINT_ASSERT(ctx->minfo->nvars > 1);
n_poly_init(hc);
n_poly_init(modulus);
nmod_mpolyun_init(An, A->bits, ctx);
nmod_mpolyun_init(Bn, A->bits, ctx);
nmod_mpolyu_cvtto_mpolyun(An, A, ctx->minfo->nvars - 1, ctx);
nmod_mpolyu_cvtto_mpolyun(Bn, B, ctx->minfo->nvars - 1, ctx);
FLINT_ASSERT(An->bits == B->bits);
FLINT_ASSERT(An->bits == G->bits);
FLINT_ASSERT(An->length > 0);
FLINT_ASSERT(Bn->length > 0);
FLINT_ASSERT(An->exps[A->length - 1] == 0);
FLINT_ASSERT(Bn->exps[B->length - 1] == 0);
n_poly_init(gamma);
n_poly_mod_gcd(gamma, nmod_mpolyun_leadcoeff_poly(An, ctx),
nmod_mpolyun_leadcoeff_poly(Bn, ctx), ctx->mod);
Alastdeg = nmod_mpolyun_lastdeg(An, ctx);
Blastdeg = nmod_mpolyun_lastdeg(Bn, ctx);
bound = 1 + n_poly_degree(gamma) + FLINT_MIN(Alastdeg, Blastdeg);
degbound = FLINT_MIN(A->exps[0], B->exps[0]);
n_poly_one(modulus);
nmod_mpolyun_init(Hn, A->bits, ctx);
nmod_mpolyun_init(Ht, A->bits, ctx);
deg = WORD(20)/(FLINT_BIT_COUNT(ctx->mod.n));
deg = FLINT_MAX(WORD(2), deg);
fq_nmod_mpoly_ctx_init_deg(ffctx, ctx->minfo->nvars, ORD_LEX, ctx->mod.n, deg);
fq_nmod_mpolyu_init(Aff, A->bits, ffctx);
fq_nmod_mpolyu_init(Bff, A->bits, ffctx);
fq_nmod_mpolyu_init(Gff, A->bits, ffctx);
fq_nmod_mpolyu_init(Abarff, A->bits, ffctx);
fq_nmod_mpolyu_init(Bbarff, A->bits, ffctx);
fq_nmod_mpolyu_init(Gform, A->bits, ffctx);
fq_nmod_init(gammaff, ffctx->fqctx);
fq_nmod_init(t, ffctx->fqctx);
choose_prime_outer:
deg++;
if (deg > 10000)
{
success = 0;
goto finished;
}
fq_nmod_mpolyu_clear(Aff, ffctx);
fq_nmod_mpolyu_clear(Bff, ffctx);
fq_nmod_mpolyu_clear(Gff, ffctx);
fq_nmod_mpolyu_clear(Abarff, ffctx);
fq_nmod_mpolyu_clear(Bbarff, ffctx);
fq_nmod_mpolyu_clear(Gform, ffctx);
fq_nmod_clear(gammaff, ffctx->fqctx);
fq_nmod_clear(t, ffctx->fqctx);
fq_nmod_mpoly_ctx_change_modulus(ffctx, deg);
fq_nmod_mpolyu_init(Aff, A->bits, ffctx);
fq_nmod_mpolyu_init(Bff, A->bits, ffctx);
fq_nmod_mpolyu_init(Gff, A->bits, ffctx);
fq_nmod_mpolyu_init(Abarff, A->bits, ffctx);
fq_nmod_mpolyu_init(Bbarff, A->bits, ffctx);
fq_nmod_mpolyu_init(Gform, A->bits, ffctx);
fq_nmod_init(gammaff, ffctx->fqctx);
fq_nmod_init(t, ffctx->fqctx);
n_poly_mod_rem(evil_cast_nmod_poly_to_n_poly(gammaff), gamma,
evil_const_cast_nmod_poly_to_n_poly(ffctx->fqctx->modulus), ctx->mod);
if (fq_nmod_is_zero(gammaff, ffctx->fqctx))
goto choose_prime_outer;
nmod_mpolyun_interp_reduce_lg_mpolyu(Aff, An, ffctx, ctx);
nmod_mpolyun_interp_reduce_lg_mpolyu(Bff, Bn, ffctx, ctx);
if (Aff->length == 0 || Bff->length == 0)
goto choose_prime_outer;
success = fq_nmod_mpolyu_gcdp_zippel(Gff, Abarff, Bbarff, Aff, Bff,
ctx->minfo->nvars - 2, ffctx, randstate);
if (!success || Gff->exps[0] > (ulong) degbound)
goto choose_prime_outer;
degbound = Gff->exps[0];
if (Gff->length == 1 && Gff->exps[0] == 0)
{
FLINT_ASSERT(fq_nmod_mpoly_is_one(Gff->coeffs + 0, ffctx));
FLINT_ASSERT(!fq_nmod_mpoly_is_zero(Gff->coeffs + 0, ffctx));
nmod_mpolyu_one(G, ctx);
nmod_mpolyu_swap(Abar, A, ctx);
nmod_mpolyu_swap(Bbar, B, ctx);
success = 1;
goto finished;
}
n_fq_get_fq_nmod(t, fq_nmod_mpolyu_leadcoeff(Gff, ffctx), ffctx->fqctx);
fq_nmod_inv(t, t, ffctx->fqctx);
fq_nmod_mul(t, t, gammaff, ffctx->fqctx);
fq_nmod_mpolyu_scalar_mul_fq_nmod(Gff, t, ffctx);
fq_nmod_mpolyu_setform(Gform, Gff, ffctx);
nmod_mpolyun_interp_lift_lg_mpolyu(Hn, ctx, Gff, ffctx);
n_poly_set_nmod_poly(modulus, ffctx->fqctx->modulus);
choose_prime_inner:
deg++;
if (deg > 1000)
{
success = 0;
goto finished;
}
fq_nmod_mpolyu_clear(Aff, ffctx);
fq_nmod_mpolyu_clear(Bff, ffctx);
fq_nmod_mpolyu_clear(Gff, ffctx);
fq_nmod_mpolyu_clear(Abarff, ffctx);
fq_nmod_mpolyu_clear(Bbarff, ffctx);
fq_nmod_clear(gammaff, ffctx->fqctx);
fq_nmod_clear(t, ffctx->fqctx);
fq_nmod_mpoly_ctx_change_modulus(ffctx, deg);
fq_nmod_mpolyu_init(Aff, A->bits, ffctx);
fq_nmod_mpolyu_init(Bff, A->bits, ffctx);
fq_nmod_mpolyu_init(Gff, A->bits, ffctx);
fq_nmod_mpolyu_init(Abarff, A->bits, ffctx);
fq_nmod_mpolyu_init(Bbarff, A->bits, ffctx);
fq_nmod_init(gammaff, ffctx->fqctx);
fq_nmod_init(t, ffctx->fqctx);
n_poly_mod_rem(evil_cast_nmod_poly_to_n_poly(gammaff), gamma,
evil_const_cast_nmod_poly_to_n_poly(ffctx->fqctx->modulus), ctx->mod);
if (fq_nmod_is_zero(gammaff, ffctx->fqctx))
goto choose_prime_inner;
nmod_mpolyun_interp_reduce_lg_mpolyu(Aff, An, ffctx, ctx);
nmod_mpolyun_interp_reduce_lg_mpolyu(Bff, Bn, ffctx, ctx);
if (Aff->length == 0 || Bff->length == 0)
goto choose_prime_inner;
switch (fq_nmod_mpolyu_gcds_zippel(Gff, Aff, Bff, Gform,
ctx->minfo->nvars - 1, ffctx, randstate, °bound))
{
default:
FLINT_ASSERT(0);
case nmod_gcds_form_main_degree_too_high:
case nmod_gcds_form_wrong:
case nmod_gcds_no_solution:
goto choose_prime_outer;
case nmod_gcds_scales_not_found:
case nmod_gcds_eval_point_not_found:
case nmod_gcds_eval_gcd_deg_too_high:
goto choose_prime_inner;
case nmod_gcds_success:
break;
}
n_fq_get_fq_nmod(t, fq_nmod_mpolyu_leadcoeff(Gff, ffctx), ffctx->fqctx);
if (fq_nmod_is_zero(t, ffctx->fqctx))
goto choose_prime_inner;
fq_nmod_inv(t, t, ffctx->fqctx);
fq_nmod_mul(t, t, gammaff, ffctx->fqctx);
fq_nmod_mpolyu_scalar_mul_fq_nmod(Gff, t, ffctx);
changed = nmod_mpolyun_interp_mcrt_lg_mpolyu(&lastdeg, Hn, ctx, modulus, Gff, ffctx);
n_poly_mod_mul(modulus, modulus,
evil_const_cast_nmod_poly_to_n_poly(ffctx->fqctx->modulus), ctx->mod);
have_enough = n_poly_degree(modulus) >= bound;
if (changed && !have_enough)
{
goto choose_prime_inner;
}
if (!changed || have_enough)
{
nmod_mpolyun_content_last(hc, Hn, ctx);
nmod_mpolyun_set(Ht, Hn, ctx);
nmod_mpolyun_divexact_last(Ht, hc, ctx);
nmod_mpolyu_cvtfrom_mpolyun(G, Ht, ctx->minfo->nvars - 1, ctx);
if ( nmod_mpolyuu_divides(Abar, A, G, 1, ctx)
&& nmod_mpolyuu_divides(Bbar, B, G, 1, ctx))
{
success = 1;
goto finished;
}
}
if (have_enough)
{
n_poly_one(modulus);
goto choose_prime_outer;
}
goto choose_prime_inner;
finished:
n_poly_clear(gamma);
n_poly_clear(hc);
n_poly_clear(modulus);
nmod_mpolyun_clear(An, ctx);
nmod_mpolyun_clear(Bn, ctx);
nmod_mpolyun_clear(Hn, ctx);
nmod_mpolyun_clear(Ht, ctx);
fq_nmod_mpolyu_clear(Aff, ffctx);
fq_nmod_mpolyu_clear(Bff, ffctx);
fq_nmod_mpolyu_clear(Gff, ffctx);
fq_nmod_mpolyu_clear(Abarff, ffctx);
fq_nmod_mpolyu_clear(Bbarff, ffctx);
fq_nmod_mpolyu_clear(Gform, ffctx);
fq_nmod_clear(gammaff, ffctx->fqctx);
fq_nmod_clear(t, ffctx->fqctx);
fq_nmod_mpoly_ctx_clear(ffctx);
return success;
}
int nmod_mpoly_gcd_zippel(
nmod_mpoly_t G,
const nmod_mpoly_t A,
const nmod_mpoly_t B,
const nmod_mpoly_ctx_t ctx)
{
if (nmod_mpoly_is_zero(A, ctx) || nmod_mpoly_is_zero(B, ctx))
return nmod_mpoly_gcd(G, A, B, ctx);
return _nmod_mpoly_gcd_algo(G, NULL, NULL, A, B, ctx, MPOLY_GCD_USE_ZIPPEL);
}