#include "fq_nmod.h"
#include "fq_nmod_poly.h"
#include "n_poly.h"
#include "mpoly.h"
#include "fq_nmod_mpoly.h"
static int fq_nmod_mpolyu_gcdm_zippel_bivar(
fq_nmod_mpolyu_t G,
fq_nmod_mpolyu_t Abar,
fq_nmod_mpolyu_t Bbar,
fq_nmod_mpolyu_t A,
fq_nmod_mpolyu_t B,
fq_nmod_mpoly_ctx_t ctx,
flint_rand_t randstate)
{
slong var = 0;
slong Alastdeg, Blastdeg;
slong bound;
slong lastdeg;
int success = 0, changed, have_enough;
fq_nmod_mpolyun_t An, Bn, H, Ht;
fq_nmod_poly_t modulus, gamma, hc, tmp1, tmp2;
bad_fq_nmod_mpoly_embed_chooser_t embc;
bad_fq_nmod_embed_struct * cur_emb;
fq_nmod_mpoly_ctx_t ectx;
fq_nmod_mpolyu_t Aeval, Beval, Geval;
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);
fq_nmod_mpolyun_init(An, A->bits, ctx);
fq_nmod_mpolyun_init(Bn, A->bits, ctx);
fq_nmod_mpolyu_cvtto_mpolyun(An, A, var, ctx);
fq_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);
fq_nmod_poly_init(tmp1, ctx->fqctx);
fq_nmod_poly_init(tmp2, ctx->fqctx);
fq_nmod_poly_init(gamma, ctx->fqctx);
n_fq_poly_get_fq_nmod_poly(tmp1, fq_nmod_mpolyun_leadcoeff_poly(An, ctx), ctx->fqctx);
n_fq_poly_get_fq_nmod_poly(tmp2, fq_nmod_mpolyun_leadcoeff_poly(Bn, ctx), ctx->fqctx);
fq_nmod_poly_gcd(gamma, tmp1, tmp2, ctx->fqctx);
Alastdeg = fq_nmod_mpolyun_lastdeg(An, ctx);
Blastdeg = fq_nmod_mpolyun_lastdeg(Bn, ctx);
bound = 1 + fq_nmod_poly_degree(gamma, ctx->fqctx)
+ FLINT_MIN(Alastdeg, Blastdeg);
fq_nmod_poly_init(hc, ctx->fqctx);
fq_nmod_poly_init(modulus, ctx->fqctx);
fq_nmod_poly_one(modulus, ctx->fqctx);
fq_nmod_mpolyun_init(H, A->bits, ctx);
fq_nmod_mpolyun_init(Ht, A->bits, ctx);
cur_emb = bad_fq_nmod_mpoly_embed_chooser_init(embc, ectx, ctx, randstate);
fq_nmod_mpolyu_init(Aeval, A->bits, ectx);
fq_nmod_mpolyu_init(Beval, A->bits, ectx);
fq_nmod_mpolyu_init(Geval, A->bits, ectx);
fq_nmod_init(geval, ectx->fqctx);
fq_nmod_init(t, ectx->fqctx);
goto have_prime;
choose_prime_outer:
cur_emb = bad_fq_nmod_mpoly_embed_chooser_next(embc, ectx, ctx, randstate);
if (cur_emb == NULL)
{
success = 0;
goto finished;
}
have_prime:
FLINT_ASSERT(cur_emb != NULL);
bad_fq_nmod_embed_sm_to_lg(geval, gamma, cur_emb);
if (fq_nmod_is_zero(geval, ectx->fqctx))
goto choose_prime_outer;
fq_nmod_mpolyun_interp_reduce_lg_mpolyu(Aeval, An, ectx, ctx, cur_emb);
fq_nmod_mpolyun_interp_reduce_lg_mpolyu(Beval, Bn, ectx, ctx, cur_emb);
if (Aeval->length == 0 || Beval->length == 0)
goto choose_prime_outer;
FLINT_ASSERT(fq_nmod_mpolyu_is_canonical(Aeval, ectx));
FLINT_ASSERT(fq_nmod_mpolyu_is_canonical(Beval, ectx));
fq_nmod_mpolyu_gcdp_zippel_univar_no_cofactors(Geval, Aeval, Beval, ectx);
if (fq_nmod_mpolyu_is_one(Geval, ectx))
{
fq_nmod_mpolyu_one(G, ctx);
fq_nmod_mpolyu_swap(Abar, A, ctx);
fq_nmod_mpolyu_swap(Bbar, B, ctx);
success = 1;
goto finished;
}
FLINT_ASSERT(Geval->length > 0);
if (fq_nmod_poly_degree(modulus, ctx->fqctx) > 0)
{
if (Geval->exps[0] > H->exps[0])
{
goto choose_prime_outer;
}
else if (Geval->exps[0] < H->exps[0])
{
fq_nmod_poly_one(modulus, ctx->fqctx);
}
}
n_fq_get_fq_nmod(t, fq_nmod_mpolyu_leadcoeff(Geval, ectx), ectx->fqctx);
fq_nmod_inv(t, t, ectx->fqctx);
fq_nmod_mul(t, t, geval, ectx->fqctx);
fq_nmod_mpolyu_scalar_mul_fq_nmod(Geval, t, ectx);
if (fq_nmod_poly_degree(modulus, ctx->fqctx) > 0)
{
changed = fq_nmod_mpolyun_interp_crt_lg_mpolyu(&lastdeg,
H, Ht, modulus, ctx, Geval, ectx, cur_emb);
fq_nmod_poly_mul(modulus, modulus, cur_emb->h, ctx->fqctx);
have_enough = fq_nmod_poly_degree(modulus, ctx->fqctx) >= bound;
if (changed && !have_enough)
{
goto choose_prime_outer;
}
if (!changed || have_enough)
{
fq_nmod_mpolyun_content_poly(hc, H, ctx);
fq_nmod_mpolyun_divexact_poly(Ht, H, hc, ctx);
fq_nmod_mpolyu_cvtfrom_mpolyun(G, Ht, var, ctx);
if ( fq_nmod_mpolyuu_divides(Abar, A, G, 1, ctx)
&& fq_nmod_mpolyuu_divides(Bbar, B, G, 1, ctx))
{
success = 1;
goto finished;
}
}
if (have_enough)
{
fq_nmod_poly_one(modulus, ctx->fqctx);
goto choose_prime_outer;
}
}
else
{
fq_nmod_mpolyun_interp_lift_lg_mpolyu(H, ctx, Geval, ectx, cur_emb);
fq_nmod_poly_set(modulus, cur_emb->h, ctx->fqctx);
}
goto choose_prime_outer;
finished:
fq_nmod_poly_clear(tmp1, ctx->fqctx);
fq_nmod_poly_clear(tmp2, ctx->fqctx);
fq_nmod_poly_clear(gamma, ctx->fqctx);
fq_nmod_poly_clear(hc, ctx->fqctx);
fq_nmod_poly_clear(modulus, ctx->fqctx);
fq_nmod_mpolyun_clear(An, ctx);
fq_nmod_mpolyun_clear(Bn, ctx);
fq_nmod_mpolyun_clear(H, ctx);
fq_nmod_mpolyun_clear(Ht, ctx);
fq_nmod_mpolyu_clear(Aeval, ectx);
fq_nmod_mpolyu_clear(Beval, ectx);
fq_nmod_mpolyu_clear(Geval, ectx);
fq_nmod_clear(geval, ectx->fqctx);
fq_nmod_clear(t, ectx->fqctx);
bad_fq_nmod_mpoly_embed_chooser_clear(embc, ectx, ctx, randstate);
return success;
}
int fq_nmod_mpolyu_gcdm_zippel(
fq_nmod_mpolyu_t G,
fq_nmod_mpolyu_t Abar,
fq_nmod_mpolyu_t Bbar,
fq_nmod_mpolyu_t A,
fq_nmod_mpolyu_t B,
fq_nmod_mpoly_ctx_t ctx,
flint_rand_t randstate)
{
ulong degbound;
slong bound;
slong Alastdeg, Blastdeg;
slong lastdeg;
int success, changed, have_enough;
fq_nmod_mpolyun_t An, Bn, Hn, Ht;
fq_nmod_poly_t modulus, gamma, hc, tmp1, tmp2;
bad_fq_nmod_mpoly_embed_chooser_t embc;
bad_fq_nmod_embed_struct * cur_emb;
fq_nmod_mpoly_ctx_t ectx;
fq_nmod_mpolyu_t Aeval, Beval, Geval, Abareval, Bbareval, Gform;
fq_nmod_t t, gammaeval;
FLINT_ASSERT(G->bits == A->bits);
FLINT_ASSERT(B->bits == A->bits);
success = fq_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 fq_nmod_mpolyu_gcdm_zippel_bivar(G, Abar, Bbar, A, B,
ctx, randstate);
}
FLINT_ASSERT(ctx->minfo->nvars > 1);
fq_nmod_poly_init(hc, ctx->fqctx);
fq_nmod_poly_init(modulus, ctx->fqctx);
fq_nmod_mpolyun_init(An, A->bits, ctx);
fq_nmod_mpolyun_init(Bn, A->bits, ctx);
fq_nmod_mpolyu_cvtto_mpolyun(An, A, ctx->minfo->nvars - 1, ctx);
fq_nmod_mpolyu_cvtto_mpolyun(Bn, B, ctx->minfo->nvars - 1, ctx);
FLINT_ASSERT(An->bits == A->bits);
FLINT_ASSERT(Bn->bits == A->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);
fq_nmod_poly_init(tmp1, ctx->fqctx);
fq_nmod_poly_init(tmp2, ctx->fqctx);
fq_nmod_poly_init(gamma, ctx->fqctx);
n_fq_poly_get_fq_nmod_poly(tmp1, fq_nmod_mpolyun_leadcoeff_poly(An, ctx), ctx->fqctx);
n_fq_poly_get_fq_nmod_poly(tmp2, fq_nmod_mpolyun_leadcoeff_poly(Bn, ctx), ctx->fqctx);
fq_nmod_poly_gcd(gamma, tmp1, tmp2, ctx->fqctx);
Alastdeg = fq_nmod_mpolyun_lastdeg(An, ctx);
Blastdeg = fq_nmod_mpolyun_lastdeg(Bn, ctx);
bound = 1 + fq_nmod_poly_degree(gamma, ctx->fqctx)
+ FLINT_MIN(Alastdeg, Blastdeg);
degbound = FLINT_MIN(A->exps[0], B->exps[0]);
fq_nmod_poly_one(modulus, ctx->fqctx);
fq_nmod_mpolyun_init(Hn, A->bits, ctx);
fq_nmod_mpolyun_init(Ht, A->bits, ctx);
cur_emb = bad_fq_nmod_mpoly_embed_chooser_init(embc, ectx, ctx, randstate);
fq_nmod_mpolyu_init(Aeval, A->bits, ectx);
fq_nmod_mpolyu_init(Beval, A->bits, ectx);
fq_nmod_mpolyu_init(Geval, A->bits, ectx);
fq_nmod_mpolyu_init(Abareval, A->bits, ectx);
fq_nmod_mpolyu_init(Bbareval, A->bits, ectx);
fq_nmod_mpolyu_init(Gform, A->bits, ectx);
fq_nmod_init(gammaeval, ectx->fqctx);
fq_nmod_init(t, ectx->fqctx);
goto have_prime;
choose_prime_outer:
cur_emb = bad_fq_nmod_mpoly_embed_chooser_next(embc, ectx, ctx, randstate);
if (cur_emb == NULL)
{
success = 0;
goto finished;
}
have_prime:
FLINT_ASSERT(cur_emb != NULL);
bad_fq_nmod_embed_sm_to_lg(gammaeval, gamma, cur_emb);
if (fq_nmod_is_zero(gammaeval, ectx->fqctx))
{
goto choose_prime_outer;
}
fq_nmod_mpolyun_interp_reduce_lg_mpolyu(Aeval, An, ectx, ctx, cur_emb);
fq_nmod_mpolyun_interp_reduce_lg_mpolyu(Beval, Bn, ectx, ctx, cur_emb);
if (Aeval->length == 0 || Beval->length == 0)
goto choose_prime_outer;
FLINT_ASSERT(fq_nmod_mpolyu_is_canonical(Aeval, ectx));
FLINT_ASSERT(fq_nmod_mpolyu_is_canonical(Beval, ectx));
success = fq_nmod_mpolyu_gcdp_zippel(Geval, Abareval, Bbareval, Aeval, Beval,
ctx->minfo->nvars - 2, ectx, randstate);
FLINT_ASSERT(!success || Geval->length > 0);
if (!success || Geval->exps[0] > degbound)
goto choose_prime_outer;
degbound = Geval->exps[0];
if (Geval->length == 1 && Geval->exps[0] == 0)
{
FLINT_ASSERT(fq_nmod_mpoly_is_one(Geval->coeffs + 0, ectx));
FLINT_ASSERT(!fq_nmod_mpoly_is_zero(Geval->coeffs + 0, ectx));
fq_nmod_mpolyu_one(G, ctx);
fq_nmod_mpolyu_swap(Abar, A, ctx);
fq_nmod_mpolyu_swap(Bbar, B, ctx);
success = 1;
goto finished;
}
n_fq_get_fq_nmod(t, fq_nmod_mpolyu_leadcoeff(Geval, ectx), ectx->fqctx);
fq_nmod_inv(t, t, ectx->fqctx);
fq_nmod_mul(t, t, gammaeval, ectx->fqctx);
fq_nmod_mpolyu_scalar_mul_fq_nmod(Geval, t, ectx);
fq_nmod_mpolyu_setform(Gform, Geval, ectx);
fq_nmod_mpolyun_interp_lift_lg_mpolyu(Hn, ctx, Geval, ectx, cur_emb);
fq_nmod_poly_set(modulus, cur_emb->h, ctx->fqctx);
choose_prime_inner:
cur_emb = bad_fq_nmod_mpoly_embed_chooser_next(embc, ectx, ctx, randstate);
if (cur_emb == NULL)
{
success = 0;
goto finished;
}
bad_fq_nmod_embed_sm_to_lg(gammaeval, gamma, cur_emb);
if (fq_nmod_is_zero(gammaeval, ectx->fqctx))
goto choose_prime_inner;
fq_nmod_mpolyun_interp_reduce_lg_mpolyu(Aeval, An, ectx, ctx, cur_emb);
fq_nmod_mpolyun_interp_reduce_lg_mpolyu(Beval, Bn, ectx, ctx, cur_emb);
if (Aeval->length == 0 || Beval->length == 0)
goto choose_prime_inner;
switch (fq_nmod_mpolyu_gcds_zippel(Geval, Aeval, Beval, Gform,
ctx->minfo->nvars - 1, ectx, randstate, (slong *) °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(Geval, ectx), ectx->fqctx);
if (fq_nmod_is_zero(t, ectx->fqctx))
{
goto choose_prime_inner;
}
fq_nmod_inv(t, t, ectx->fqctx);
fq_nmod_mul(t, t, gammaeval, ectx->fqctx);
fq_nmod_mpolyu_scalar_mul_fq_nmod(Geval, t, ectx);
changed = fq_nmod_mpolyun_interp_mcrt_lg_mpolyu(&lastdeg, Hn, ctx, modulus, Geval, ectx, cur_emb);
fq_nmod_poly_mul(modulus, modulus, cur_emb->h, ctx->fqctx);
have_enough = fq_nmod_poly_degree(modulus, ctx->fqctx) >= bound;
if (changed && !have_enough)
{
goto choose_prime_inner;
}
if (!changed || have_enough)
{
fq_nmod_mpolyun_content_poly(hc, Hn, ctx);
fq_nmod_mpolyun_divexact_poly(Ht, Hn, hc, ctx);
fq_nmod_mpolyu_cvtfrom_mpolyun(G, Ht, ctx->minfo->nvars - 1, ctx);
if ( fq_nmod_mpolyuu_divides(Abar, A, G, 1, ctx)
&& fq_nmod_mpolyuu_divides(Bbar, B, G, 1, ctx))
{
success = 1;
goto finished;
}
}
if (have_enough)
{
fq_nmod_poly_one(modulus, ctx->fqctx);
goto choose_prime_outer;
}
goto choose_prime_inner;
finished:
fq_nmod_poly_clear(tmp1, ctx->fqctx);
fq_nmod_poly_clear(tmp2, ctx->fqctx);
fq_nmod_poly_clear(gamma, ctx->fqctx);
fq_nmod_poly_clear(hc, ctx->fqctx);
fq_nmod_poly_clear(modulus, ctx->fqctx);
fq_nmod_mpolyun_clear(An, ctx);
fq_nmod_mpolyun_clear(Bn, ctx);
fq_nmod_mpolyun_clear(Hn, ctx);
fq_nmod_mpolyun_clear(Ht, ctx);
fq_nmod_mpolyu_clear(Aeval, ectx);
fq_nmod_mpolyu_clear(Beval, ectx);
fq_nmod_mpolyu_clear(Geval, ectx);
fq_nmod_mpolyu_clear(Abareval, ectx);
fq_nmod_mpolyu_clear(Bbareval, ectx);
fq_nmod_mpolyu_clear(Gform, ectx);
fq_nmod_clear(gammaeval, ectx->fqctx);
fq_nmod_clear(t, ectx->fqctx);
bad_fq_nmod_mpoly_embed_chooser_clear(embc, ectx, ctx, randstate);
return success;
}
int fq_nmod_mpoly_gcd_zippel(
fq_nmod_mpoly_t G,
const fq_nmod_mpoly_t A,
const fq_nmod_mpoly_t B,
const fq_nmod_mpoly_ctx_t ctx)
{
if (fq_nmod_mpoly_is_zero(A, ctx) || fq_nmod_mpoly_is_zero(B, ctx))
return fq_nmod_mpoly_gcd(G, A, B, ctx);
return _fq_nmod_mpoly_gcd_algo(G, NULL, NULL, A, B, ctx, MPOLY_GCD_USE_ZIPPEL);
}