#include "thread_pool.h"
#include "thread_support.h"
#include "nmod.h"
#include "fmpz.h"
#include "fmpz_vec.h"
#include "fq_nmod.h"
#include "mpoly.h"
#include "fq_zech.h"
#include "fq_zech_poly.h"
#include "n_poly.h"
#include "nmod_mpoly.h"
#include "fq_nmod_mpoly.h"
#include "nmod_mpoly_factor.h"
static void nmod_mpoly_evals(
slong * Atdeg,
n_poly_struct * out,
const int * ignore,
const nmod_mpoly_t A,
ulong * Amin_exp,
ulong * FLINT_UNUSED(Amax_exp),
ulong * Astride,
ulong * alpha,
const nmod_mpoly_ctx_t ctx)
{
slong i, j;
slong nvars = ctx->minfo->nvars;
ulong mask = (-UWORD(1)) >> (FLINT_BITS - A->bits);
slong * offsets, * shifts;
slong N = mpoly_words_per_exp_sp(A->bits, ctx->minfo);
ulong * varexps;
ulong varexp;
slong total_degree, lo, hi;
ulong meval, t;
n_poly_struct * caches;
offsets = FLINT_ARRAY_ALLOC(2*nvars, slong);
shifts = offsets + nvars;
varexps = FLINT_ARRAY_ALLOC(nvars, ulong);
caches = FLINT_ARRAY_ALLOC(3*nvars, n_poly_struct);
for (j = 0; j < nvars; j++)
{
n_poly_zero(out + j);
mpoly_gen_offset_shift_sp(offsets + j, shifts + j, j, A->bits, ctx->minfo);
n_poly_init(caches + 3*j + 0);
n_poly_init(caches + 3*j + 1);
n_poly_init(caches + 3*j + 2);
nmod_pow_cache_start(alpha[j], caches + 3*j + 0,
caches + 3*j + 1, caches + 3*j + 2);
}
total_degree = 0;
for (i = 0; i < A->length; i++)
{
meval = A->coeffs[i];
hi = lo = 0;
for (j = 0; j < nvars; j++)
{
varexp = ((A->exps + N*i)[offsets[j]]>>shifts[j])&mask;
FLINT_ASSERT((Astride[j] == 0 && varexp == Amin_exp[j]) ||
(varexp - Amin_exp[j]) % Astride[j] == 0);
varexps[j] = Astride[j] < 2 ? varexp - Amin_exp[j] :
(varexp - Amin_exp[j])/Astride[j];
add_ssaaaa(hi, lo, hi, lo, 0, varexps[j]);
t = nmod_pow_cache_mulpow_ui(meval, varexps[j], caches + 3*j + 0,
caches + 3*j + 1, caches + 3*j + 2, ctx->mod);
FLINT_ASSERT(t == nmod_mul(meval, nmod_pow_ui(alpha[j], varexps[j],
ctx->mod), ctx->mod));
meval = t;
}
if (hi == 0 && FLINT_SIGN_EXT(lo) == 0 && total_degree >= 0)
total_degree = FLINT_MAX(total_degree, lo);
else
total_degree = -1;
for (j = 0; j < nvars; j++)
{
varexp = varexps[j];
if (ignore[j])
continue;
n_poly_fit_length(out + j, varexp + 1);
while ((ulong) out[j].length <= varexp)
{
out[j].coeffs[out[j].length] = 0;
out[j].length++;
}
t = nmod_pow_cache_mulpow_neg_ui(meval, varexp, caches + 3*j + 0,
caches + 3*j + 1, caches + 3*j + 2, ctx->mod);
FLINT_ASSERT(t == nmod_mul(meval, nmod_pow_ui(nmod_inv(alpha[j],
ctx->mod), varexp, ctx->mod), ctx->mod));
out[j].coeffs[varexp] = nmod_add(out[j].coeffs[varexp], t, ctx->mod);
}
}
*Atdeg = total_degree;
for (j = 0; j < nvars; j++)
_n_poly_normalise(out + j);
for (j = 0; j < 3*nvars; j++)
n_poly_clear(caches + j);
flint_free(offsets);
flint_free(varexps);
flint_free(caches);
}
static void nmod_mpoly_evals_medprime(
slong * Atdeg,
fq_zech_poly_struct * out,
const int * ignore,
const nmod_mpoly_t A,
ulong * Amin_exp,
ulong * FLINT_UNUSED(Amax_exp),
ulong * Astride,
const nmod_mpoly_ctx_t smctx,
const fq_zech_struct * alphas,
const fq_zech_ctx_t medctx)
{
slong i, j;
slong nvars = smctx->minfo->nvars;
ulong mask = (-UWORD(1)) >> (FLINT_BITS - A->bits);
slong * offsets, * shifts;
slong N = mpoly_words_per_exp_sp(A->bits, smctx->minfo);
ulong * varexps;
ulong varexp, lo, hi;
slong total_degree;
fq_zech_t t1, meval;
fq_zech_init(t1, medctx);
fq_zech_init(meval, medctx);
offsets = FLINT_ARRAY_ALLOC(2*nvars, slong);
shifts = offsets + nvars;
varexps = FLINT_ARRAY_ALLOC(nvars, ulong);
for (j = 0; j < nvars; j++)
{
fq_zech_poly_zero(out + j, medctx);
mpoly_gen_offset_shift_sp(offsets + j, shifts + j, j, A->bits,
smctx->minfo);
}
total_degree = 0;
for (i = 0; i < A->length; i++)
{
fq_zech_set_ui(meval, A->coeffs[i], medctx);
lo = hi = 0;
for (j = 0; j < nvars; j++)
{
varexp = ((A->exps + N*i)[offsets[j]]>>shifts[j])&mask;
FLINT_ASSERT((Astride[j] == 0 && varexp == Amin_exp[j]) ||
(varexp - Amin_exp[j]) % Astride[j] == 0);
varexps[j] = Astride[j] < 2 ? varexp - Amin_exp[j] :
(varexp - Amin_exp[j])/Astride[j];
add_ssaaaa(hi, lo, hi, lo, 0, varexps[j]);
fq_zech_pow_ui(t1, alphas + j, varexps[j], medctx);
fq_zech_mul(meval, meval, t1, medctx);
}
if (hi == 0 && FLINT_SIGN_EXT(lo) == 0 && total_degree >= 0)
total_degree = FLINT_MAX((ulong) total_degree, lo);
else
total_degree = -1;
for (j = 0; j < nvars; j++)
{
varexp = varexps[j];
if (ignore[j])
continue;
fq_zech_poly_fit_length(out + j, varexp + 1, medctx);
while ((ulong) out[j].length <= varexp)
{
fq_zech_zero(out[j].coeffs + out[j].length, medctx);
out[j].length++;
}
fq_zech_inv(t1, alphas + j, medctx);
fq_zech_pow_ui(t1, t1, varexp, medctx);
fq_zech_mul(t1, meval, t1, medctx);
fq_zech_add(out[j].coeffs + varexp, out[j].coeffs + varexp, t1, medctx);
}
}
*Atdeg = total_degree;
for (j = 0; j < nvars; j++)
_fq_zech_poly_normalise(out + j, medctx);
flint_free(offsets);
flint_free(varexps);
fq_zech_clear(t1, medctx);
fq_zech_clear(meval, medctx);
}
static void nmod_mpoly_evals_lgprime(
slong * Atdeg,
n_fq_poly_struct * out,
const int * ignore,
const nmod_mpoly_t A,
ulong * Amin_exp,
ulong * FLINT_UNUSED(Amax_exp),
ulong * Astride,
const nmod_mpoly_ctx_t smctx,
const fq_nmod_struct * alpha,
const fq_nmod_ctx_t lgctx)
{
slong d = fq_nmod_ctx_degree(lgctx);
slong i, j;
slong nvars = smctx->minfo->nvars;
ulong mask = (-UWORD(1)) >> (FLINT_BITS - A->bits);
slong * offsets, * shifts;
slong N = mpoly_words_per_exp_sp(A->bits, smctx->minfo);
ulong * varexps;
ulong varexp, lo, hi;
slong total_degree;
n_poly_struct * caches;
ulong * t = FLINT_ARRAY_ALLOC(2*d, ulong);
ulong * meval = t + d;
offsets = FLINT_ARRAY_ALLOC(2*nvars, slong);
shifts = offsets + nvars;
varexps = FLINT_ARRAY_ALLOC(nvars, ulong);
caches = FLINT_ARRAY_ALLOC(3*nvars, n_poly_struct);
for (j = 0; j < nvars; j++)
{
n_fq_poly_zero(out + j);
mpoly_gen_offset_shift_sp(offsets + j, shifts + j, j, A->bits,
smctx->minfo);
n_poly_init(caches + 3*j + 0);
n_poly_init(caches + 3*j + 1);
n_poly_init(caches + 3*j + 2);
n_fq_pow_cache_start_fq_nmod(alpha + j, caches + 3*j + 0,
caches + 3*j + 1, caches + 3*j + 2, lgctx);
}
total_degree = 0;
for (i = 0; i < A->length; i++)
{
_n_fq_set_nmod(meval, A->coeffs[i], d);
hi = lo = 0;
for (j = 0; j < nvars; j++)
{
varexp = ((A->exps + N*i)[offsets[j]]>>shifts[j])&mask;
FLINT_ASSERT((Astride[j] == 0 && varexp == Amin_exp[j]) ||
(varexp - Amin_exp[j]) % Astride[j] == 0);
varexps[j] = Astride[j] < 2 ? varexp - Amin_exp[j] :
(varexp - Amin_exp[j])/Astride[j];
add_ssaaaa(hi, lo, hi, lo, 0, varexps[j]);
n_fq_pow_cache_mulpow_ui(meval, meval, varexps[j], caches + 3*j + 0,
caches + 3*j + 1, caches + 3*j + 2, lgctx);
}
if (hi == 0 && FLINT_SIGN_EXT(lo) == 0 && total_degree >= 0)
total_degree = FLINT_MAX((ulong) total_degree, lo);
else
total_degree = -1;
for (j = 0; j < nvars; j++)
{
varexp = varexps[j];
if (ignore[j])
continue;
n_poly_fit_length(out + j, d*(varexp + 1));
while ((ulong) out[j].length <= varexp)
{
_n_fq_zero(out[j].coeffs + d*out[j].length, d);
out[j].length++;
}
n_fq_pow_cache_mulpow_neg_ui(t, meval, varexp, caches + 3*j + 0,
caches + 3*j + 1, caches + 3*j + 2, lgctx);
n_fq_add(out[j].coeffs + d*varexp, out[j].coeffs + d*varexp, t, lgctx);
}
}
*Atdeg = total_degree;
for (j = 0; j < nvars; j++)
_n_fq_poly_normalise(out + j, d);
for (j = 0; j < 3*nvars; j++)
n_poly_clear(caches + j);
flint_free(offsets);
flint_free(varexps);
flint_free(caches);
flint_free(t);
}
static void _set_estimates(
mpoly_gcd_info_t I,
const nmod_mpoly_t A,
const nmod_mpoly_t B,
const nmod_mpoly_ctx_t ctx)
{
int try_count = 0;
slong nvars = ctx->minfo->nvars;
slong i, j;
n_poly_t Geval;
n_poly_struct * Aevals, * Bevals;
ulong * alpha;
flint_rand_t state;
slong ignore_limit;
int * ignore;
flint_rand_init(state);
ignore = FLINT_ARRAY_ALLOC(nvars, int);
alpha = FLINT_ARRAY_ALLOC(nvars, ulong);
Aevals = FLINT_ARRAY_ALLOC(nvars, n_poly_struct);
Bevals = FLINT_ARRAY_ALLOC(nvars, n_poly_struct);
n_poly_init(Geval);
for (j = 0; j < nvars; j++)
{
n_poly_init(Aevals + j);
n_poly_init(Bevals + j);
}
ignore_limit = (A->length + B->length)/4096;
ignore_limit = FLINT_MAX(WORD(9999), ignore_limit);
I->Gdeflate_deg_bounds_are_nice = 1;
for (j = 0; j < nvars; j++)
{
if (I->Adeflate_deg[j] > ignore_limit ||
I->Bdeflate_deg[j] > ignore_limit)
{
ignore[j] = 1;
I->Gdeflate_deg_bounds_are_nice = 0;
}
else
{
ignore[j] = 0;
}
}
try_again:
if (++try_count > 10)
{
I->Gdeflate_deg_bounds_are_nice = 0;
for (j = 0; j < nvars; j++)
{
I->Gdeflate_deg_bound[j] = FLINT_MIN(I->Adeflate_deg[j],
I->Bdeflate_deg[j]);
I->Gterm_count_est[j] = 1 + I->Gdeflate_deg_bound[j]/2;
}
goto cleanup;
}
for (j = 0; j < nvars; j++)
alpha[j] = n_urandint(state, ctx->mod.n - 1) + 1;
nmod_mpoly_evals(&I->Adeflate_tdeg, Aevals, ignore, A,
I->Amin_exp, I->Amax_exp, I->Gstride, alpha, ctx);
nmod_mpoly_evals(&I->Bdeflate_tdeg, Bevals, ignore, B,
I->Bmin_exp, I->Bmax_exp, I->Gstride, alpha, ctx);
for (j = 0; j < nvars; j++)
{
if (ignore[j])
{
I->Gdeflate_deg_bound[j] = FLINT_MIN(I->Adeflate_deg[j],
I->Bdeflate_deg[j]);
I->Gterm_count_est[j] = 1 + I->Gdeflate_deg_bound[j]/2;
}
else
{
if (I->Adeflate_deg[j] != n_poly_degree(Aevals + j) ||
I->Bdeflate_deg[j] != n_poly_degree(Bevals + j))
{
goto try_again;
}
n_poly_mod_gcd(Geval, Aevals + j, Bevals + j, ctx->mod);
I->Gterm_count_est[j] = 0;
I->Gdeflate_deg_bound[j] = n_poly_degree(Geval);
for (i = I->Gdeflate_deg_bound[j]; i >= 0; i--)
I->Gterm_count_est[j] += (Geval->coeffs[i] != 0);
}
}
cleanup:
n_poly_clear(Geval);
for (j = 0; j < nvars; j++)
{
n_poly_clear(Aevals + j);
n_poly_clear(Bevals + j);
}
flint_free(ignore);
flint_free(alpha);
flint_free(Aevals);
flint_free(Bevals);
flint_rand_clear(state);
return;
}
FLINT_DLL slong _nmod_mpoly_medprime_ignore_limit = WORD(9999);
static void _set_estimates_medprime(
mpoly_gcd_info_t I,
const nmod_mpoly_t A,
const nmod_mpoly_t B,
const nmod_mpoly_ctx_t smctx)
{
slong nvars = smctx->minfo->nvars;
int tries_left = 10;
slong i, j;
fq_zech_poly_t Geval;
fq_zech_poly_struct * Aevals, * Bevals;
fq_zech_struct * alpha;
flint_rand_t state;
slong ignore_limit;
int * ignore;
fq_zech_ctx_t medctx;
slong d, max_degree = n_flog(1000000, smctx->mod.n);
if (max_degree < 2)
return;
flint_rand_init(state);
fq_zech_ctx_init_ui(medctx, smctx->mod.n, 1, "#");
d = n_clog(500, smctx->mod.n);
d = FLINT_MAX(d, 1);
ignore = FLINT_ARRAY_ALLOC(nvars, int);
alpha = FLINT_ARRAY_ALLOC(nvars, fq_zech_struct);
Aevals = FLINT_ARRAY_ALLOC(nvars, fq_zech_poly_struct);
Bevals = FLINT_ARRAY_ALLOC(nvars, fq_zech_poly_struct);
for (j = 0; j < nvars; j++)
{
fq_zech_poly_init(Aevals + j, medctx);
fq_zech_poly_init(Bevals + j, medctx);
fq_zech_init(alpha + j, medctx);
}
fq_zech_poly_init(Geval, medctx);
ignore_limit = (A->length + B->length)/4096;
ignore_limit = FLINT_MAX(_nmod_mpoly_medprime_ignore_limit, ignore_limit);
I->Gdeflate_deg_bounds_are_nice = 1;
for (j = 0; j < nvars; j++)
{
FLINT_ASSERT(I->Gdeflate_deg_bound[j] <= I->Adeflate_deg[j]);
FLINT_ASSERT(I->Gdeflate_deg_bound[j] <= I->Bdeflate_deg[j]);
if (I->Adeflate_deg[j] > ignore_limit ||
I->Bdeflate_deg[j] > ignore_limit)
{
ignore[j] = 1;
I->Gdeflate_deg_bounds_are_nice = 0;
}
else
{
ignore[j] = 0;
}
}
try_again:
tries_left--;
d = FLINT_MIN(d + (tries_left % 2), max_degree);
if (tries_left < 0)
{
I->Gdeflate_deg_bounds_are_nice = 0;
goto cleanup;
}
fq_zech_ctx_clear(medctx);
fq_zech_ctx_init_ui(medctx, smctx->mod.n, d, "#");
for (j = 0; j < nvars; j++)
fq_zech_rand_not_zero(alpha + j, state, medctx);
nmod_mpoly_evals_medprime(&I->Adeflate_tdeg, Aevals, ignore, A,
I->Amin_exp, I->Amax_exp, I->Gstride, smctx, alpha, medctx);
nmod_mpoly_evals_medprime(&I->Bdeflate_tdeg, Bevals, ignore, B,
I->Bmin_exp, I->Bmax_exp, I->Gstride, smctx, alpha, medctx);
for (j = 0; j < nvars; j++)
{
if (!ignore[j])
{
if (I->Adeflate_deg[j] != fq_zech_poly_degree(Aevals + j, medctx) ||
I->Bdeflate_deg[j] != fq_zech_poly_degree(Bevals + j, medctx))
{
goto try_again;
}
fq_zech_poly_gcd(Geval, Aevals + j, Bevals + j, medctx);
I->Gterm_count_est[j] = 0;
I->Gdeflate_deg_bound[j] = FLINT_MIN(I->Gdeflate_deg_bound[j],
fq_zech_poly_degree(Geval, medctx));
for (i = I->Gdeflate_deg_bound[j]; i >= 0; i--)
I->Gterm_count_est[j] += !fq_zech_is_zero(Geval->coeffs + i, medctx);
}
}
cleanup:
fq_zech_poly_clear(Geval, medctx);
for (j = 0; j < nvars; j++)
{
fq_zech_poly_clear(Aevals + j, medctx);
fq_zech_poly_clear(Bevals + j, medctx);
fq_zech_clear(alpha + j, medctx);
}
flint_free(alpha);
flint_free(Aevals);
flint_free(Bevals);
flint_free(ignore);
fq_zech_ctx_clear(medctx);
flint_rand_clear(state);
return;
}
static void _set_estimates_lgprime(
mpoly_gcd_info_t I,
const nmod_mpoly_t A,
const nmod_mpoly_t B,
const nmod_mpoly_ctx_t smctx)
{
slong nvars = smctx->minfo->nvars;
int try_count = 0;
slong i, j;
n_fq_poly_t Geval;
n_fq_poly_struct * Aevals, * Bevals;
fq_nmod_struct * alpha;
flint_rand_t state;
slong ignore_limit;
int * ignore;
fq_nmod_mpoly_ctx_t lgctx;
slong d;
flint_rand_init(state);
d = WORD(20)/(FLINT_BIT_COUNT(smctx->mod.n));
d = FLINT_MAX(WORD(2), d);
fq_nmod_mpoly_ctx_init_deg(lgctx, nvars, ORD_LEX, smctx->mod.n, d);
ignore = FLINT_ARRAY_ALLOC(nvars, int);
alpha = FLINT_ARRAY_ALLOC(nvars, fq_nmod_struct);
Aevals = FLINT_ARRAY_ALLOC(nvars, n_fq_poly_struct);
Bevals = FLINT_ARRAY_ALLOC(nvars, n_fq_poly_struct);
for (j = 0; j < nvars; j++)
{
n_fq_poly_init(Aevals + j);
n_fq_poly_init(Bevals + j);
fq_nmod_init(alpha + j, lgctx->fqctx);
}
n_fq_poly_init(Geval);
ignore_limit = (A->length + B->length)/4096;
ignore_limit = FLINT_MAX(WORD(9999), ignore_limit);
I->Gdeflate_deg_bounds_are_nice = 1;
for (j = 0; j < nvars; j++)
{
FLINT_ASSERT(I->Gdeflate_deg_bound[j] <= I->Adeflate_deg[j]);
FLINT_ASSERT(I->Gdeflate_deg_bound[j] <= I->Bdeflate_deg[j]);
if (I->Adeflate_deg[j] > ignore_limit ||
I->Bdeflate_deg[j] > ignore_limit)
{
ignore[j] = 1;
I->Gdeflate_deg_bounds_are_nice = 0;
}
else
{
ignore[j] = 0;
}
}
try_again:
if (++try_count > 10)
{
I->Gdeflate_deg_bounds_are_nice = 0;
goto cleanup;
}
for (j = 0; j < nvars; j++)
fq_nmod_rand_not_zero(alpha + j, state, lgctx->fqctx);
nmod_mpoly_evals_lgprime(&I->Adeflate_tdeg, Aevals, ignore, A,
I->Amin_exp, I->Amax_exp, I->Gstride, smctx, alpha, lgctx->fqctx);
nmod_mpoly_evals_lgprime(&I->Bdeflate_tdeg, Bevals, ignore, B,
I->Bmin_exp, I->Bmax_exp, I->Gstride, smctx, alpha, lgctx->fqctx);
for (j = 0; j < nvars; j++)
{
if (!ignore[j])
{
if (I->Adeflate_deg[j] != n_fq_poly_degree(Aevals + j) ||
I->Bdeflate_deg[j] != n_fq_poly_degree(Bevals + j))
{
d++;
fq_nmod_mpoly_ctx_change_modulus(lgctx, d);
goto try_again;
}
n_fq_poly_gcd(Geval, Aevals + j, Bevals + j, lgctx->fqctx);
I->Gterm_count_est[j] = 0;
I->Gdeflate_deg_bound[j] = FLINT_MIN(I->Gdeflate_deg_bound[j],
n_fq_poly_degree(Geval));
for (i = I->Gdeflate_deg_bound[j]; i >= 0; i--)
I->Gterm_count_est[j] += !_n_fq_is_zero(Geval->coeffs + d*i, d);
}
}
cleanup:
n_fq_poly_clear(Geval);
for (j = 0; j < nvars; j++)
{
n_fq_poly_clear(Aevals + j);
n_fq_poly_clear(Bevals + j);
fq_nmod_clear(alpha + j, lgctx->fqctx);
}
flint_free(alpha);
flint_free(Aevals);
flint_free(Bevals);
flint_free(ignore);
fq_nmod_mpoly_ctx_clear(lgctx);
flint_rand_clear(state);
return;
}
static void _parallel_set(
nmod_mpoly_t Abar,
nmod_mpoly_t Bbar,
const nmod_mpoly_t A,
const nmod_mpoly_t B,
const nmod_mpoly_ctx_t ctx)
{
if (Abar == B && Bbar == A)
{
FLINT_ASSERT(Abar != NULL && Bbar != NULL);
nmod_mpoly_set(Abar, B, ctx);
nmod_mpoly_set(Bbar, A, ctx);
nmod_mpoly_swap(Abar, Bbar, ctx);
}
else if (Abar == B && Bbar != A)
{
FLINT_ASSERT(Abar != NULL);
if (Bbar != NULL)
nmod_mpoly_set(Bbar, B, ctx);
nmod_mpoly_set(Abar, A, ctx);
}
else
{
if (Abar != NULL)
nmod_mpoly_set(Abar, A, ctx);
if (Bbar != NULL)
nmod_mpoly_set(Bbar, B, ctx);
}
}
static int _do_trivial(
nmod_mpoly_t G,
nmod_mpoly_t Abar,
nmod_mpoly_t Bbar,
const nmod_mpoly_t A,
const nmod_mpoly_t B,
const mpoly_gcd_info_t I,
const nmod_mpoly_ctx_t ctx)
{
_parallel_set(Abar, Bbar, A, B, ctx);
if (Abar != NULL)
mpoly_monomials_shift_right_ui(Abar->exps, Abar->bits, Abar->length,
I->Gmin_exp, ctx->minfo);
if (Bbar != NULL)
mpoly_monomials_shift_right_ui(Bbar->exps, Bbar->bits, Bbar->length,
I->Gmin_exp, ctx->minfo);
nmod_mpoly_fit_length_reset_bits(G, 1, I->Gbits, ctx);
mpoly_set_monomial_ui(G->exps, I->Gmin_exp, I->Gbits, ctx->minfo);
G->coeffs[0] = UWORD(1);
G->length = 1;
return 1;
}
static int _do_monomial_gcd(
nmod_mpoly_t G,
nmod_mpoly_t Abar,
nmod_mpoly_t Bbar,
const nmod_mpoly_t A,
const nmod_mpoly_t B,
const nmod_mpoly_ctx_t ctx)
{
slong i;
flint_bitcnt_t Gbits = FLINT_MIN(A->bits, B->bits);
fmpz * minAfields, * minAdegs, * minBdegs;
TMP_INIT;
FLINT_ASSERT(A->length > 0);
FLINT_ASSERT(B->length == 1);
TMP_START;
minAfields = (fmpz *) TMP_ALLOC(ctx->minfo->nfields*sizeof(fmpz));
for (i = 0; i < ctx->minfo->nfields; i++)
fmpz_init(minAfields + i);
mpoly_min_fields_fmpz(minAfields, A->exps, A->length, A->bits, ctx->minfo);
minAdegs = (fmpz *) TMP_ALLOC(ctx->minfo->nvars*sizeof(fmpz));
for (i = 0; i < ctx->minfo->nvars; i++)
fmpz_init(minAdegs + i);
mpoly_get_monomial_ffmpz_unpacked_ffmpz(minAdegs, minAfields, ctx->minfo);
minBdegs = (fmpz *) TMP_ALLOC(ctx->minfo->nvars*sizeof(fmpz));
for (i = 0; i < ctx->minfo->nvars; i++)
fmpz_init(minBdegs + i);
mpoly_get_monomial_ffmpz(minBdegs, B->exps, B->bits, ctx->minfo);
_fmpz_vec_min_inplace(minBdegs, minAdegs, ctx->minfo->nvars);
_parallel_set(Abar, Bbar, A, B, ctx);
if (Abar != NULL)
mpoly_monomials_shift_right_ffmpz(Abar->exps, Abar->bits, Abar->length,
minBdegs, ctx->minfo);
if (Bbar != NULL)
mpoly_monomials_shift_right_ffmpz(Bbar->exps, Bbar->bits, Bbar->length,
minBdegs, ctx->minfo);
nmod_mpoly_fit_length_reset_bits(G, 1, Gbits, ctx);
mpoly_set_monomial_ffmpz(G->exps, minBdegs, Gbits, ctx->minfo);
G->coeffs[0] = 1;
G->length = 1;
for (i = 0; i < ctx->minfo->nfields; i++)
{
fmpz_clear(minAfields + i);
}
for (i = 0; i < ctx->minfo->nvars; i++)
{
fmpz_clear(minAdegs + i);
fmpz_clear(minBdegs + i);
}
TMP_END;
return 1;
}
static int _try_monomial_cofactors(
nmod_mpoly_t G,
nmod_mpoly_t Abar,
nmod_mpoly_t Bbar,
const nmod_mpoly_t A,
const nmod_mpoly_t B,
const nmod_mpoly_ctx_t ctx)
{
int success;
slong i, j;
slong NA, NG;
slong nvars = ctx->minfo->nvars;
fmpz * Abarexps, * Bbarexps, * Texps;
ulong a0, b0, a0inv;
nmod_mpoly_t T;
flint_bitcnt_t Gbits = FLINT_MIN(A->bits, B->bits);
flint_bitcnt_t Abarbits = A->bits;
flint_bitcnt_t Bbarbits = B->bits;
TMP_INIT;
FLINT_ASSERT(A->length > 0);
FLINT_ASSERT(B->length > 0);
if (A->length != B->length)
return 0;
a0 = A->coeffs[0];
b0 = B->coeffs[0];
for (i = A->length - 1; i > 0; i--)
{
success = (nmod_mul(a0, B->coeffs[i], ctx->mod) ==
nmod_mul(b0, A->coeffs[i], ctx->mod));
if (!success)
goto cleanup;
}
TMP_START;
Abarexps = (fmpz *) TMP_ALLOC(3*nvars*sizeof(fmpz));
Bbarexps = Abarexps + 1*nvars;
Texps = Abarexps + 2*nvars;
for (j = 0; j < nvars; j++)
{
fmpz_init(Abarexps + j);
fmpz_init(Bbarexps + j);
fmpz_init(Texps + j);
}
success = mpoly_monomial_cofactors(Abarexps, Bbarexps, A->exps, A->bits,
B->exps, B->bits, A->length, ctx->minfo);
if (!success)
goto cleanup_tmp;
nmod_mpoly_init3(T, A->length, Gbits, ctx);
NG = mpoly_words_per_exp(Gbits, ctx->minfo);
NA = mpoly_words_per_exp(A->bits, ctx->minfo);
a0inv = nmod_inv(a0, ctx->mod);
T->length = A->length;
for (i = 0; i < A->length; i++)
{
mpoly_get_monomial_ffmpz(Texps, A->exps + NA*i, A->bits, ctx->minfo);
_fmpz_vec_sub(Texps, Texps, Abarexps, nvars);
mpoly_set_monomial_ffmpz(T->exps + NG*i, Texps, Gbits, ctx->minfo);
T->coeffs[i] = nmod_mul(A->coeffs[i], a0inv, ctx->mod);
}
nmod_mpoly_swap(G, T, ctx);
nmod_mpoly_clear(T, ctx);
if (Abar != NULL)
{
nmod_mpoly_fit_length_reset_bits(Abar, 1, Abarbits, ctx);
mpoly_set_monomial_ffmpz(Abar->exps, Abarexps, Abarbits, ctx->minfo);
Abar->coeffs[0] = a0;
_nmod_mpoly_set_length(Abar, 1, ctx);
}
if (Bbar != NULL)
{
nmod_mpoly_fit_length_reset_bits(Bbar, 1, Bbarbits, ctx);
mpoly_set_monomial_ffmpz(Bbar->exps, Bbarexps, Bbarbits, ctx->minfo);
Bbar->coeffs[0] = b0;
_nmod_mpoly_set_length(Bbar, 1, ctx);
}
success = 1;
cleanup_tmp:
for (j = 0; j < nvars; j++)
{
fmpz_clear(Abarexps + j);
fmpz_clear(Bbarexps + j);
fmpz_clear(Texps + j);
}
TMP_END;
cleanup:
return success;
}
static int _do_univar(
nmod_mpoly_t G,
nmod_mpoly_t Abar,
nmod_mpoly_t Bbar,
const nmod_mpoly_t A,
const nmod_mpoly_t B,
slong v_in_both,
const mpoly_gcd_info_t I,
const nmod_mpoly_ctx_t ctx)
{
nmod_poly_t a, b, g, t;
nmod_poly_init_mod(a, ctx->mod);
nmod_poly_init_mod(b, ctx->mod);
nmod_poly_init_mod(g, ctx->mod);
nmod_poly_init_mod(t, ctx->mod);
_nmod_mpoly_to_nmod_poly_deflate(a, A, v_in_both, I->Amin_exp, I->Gstride, ctx);
_nmod_mpoly_to_nmod_poly_deflate(b, B, v_in_both, I->Bmin_exp, I->Gstride, ctx);
nmod_poly_gcd(g, a, b);
_nmod_mpoly_from_nmod_poly_inflate(G, I->Gbits, g, v_in_both,
I->Gmin_exp, I->Gstride, ctx);
if (Abar != NULL)
{
nmod_poly_divexact(t, a, g);
_nmod_mpoly_from_nmod_poly_inflate(Abar, I->Abarbits, t, v_in_both,
I->Abarmin_exp, I->Gstride, ctx);
}
if (Bbar != NULL)
{
nmod_poly_divexact(t, b, g);
_nmod_mpoly_from_nmod_poly_inflate(Bbar, I->Bbarbits, t, v_in_both,
I->Bbarmin_exp, I->Gstride, ctx);
}
nmod_poly_clear(a);
nmod_poly_clear(b);
nmod_poly_clear(g);
nmod_poly_clear(t);
return 1;
}
static int _try_missing_var(
nmod_mpoly_t G, flint_bitcnt_t Gbits,
nmod_mpoly_t Abar,
nmod_mpoly_t Bbar,
slong var,
const nmod_mpoly_t A, ulong Ashift,
const nmod_mpoly_t B, ulong Bshift,
const nmod_mpoly_ctx_t ctx)
{
int success;
nmod_mpoly_univar_t Au;
nmod_mpoly_univar_init(Au, ctx);
#if FLINT_WANT_ASSERT
nmod_mpoly_to_univar(Au, B, var, ctx);
FLINT_ASSERT(Au->length == 1);
#endif
nmod_mpoly_to_univar(Au, A, var, ctx);
nmod_mpoly_univar_fit_length(Au, Au->length + 1, ctx);
nmod_mpoly_set(Au->coeffs + Au->length, B, ctx);
Au->length++;
if (Abar == NULL && Bbar == NULL)
{
success = _nmod_mpoly_vec_content_mpoly(G, Au->coeffs, Au->length, ctx);
if (!success)
goto cleanup;
nmod_mpoly_repack_bits_inplace(G, Gbits, ctx);
_mpoly_gen_shift_left(G->exps, G->bits, G->length,
var, FLINT_MIN(Ashift, Bshift), ctx->minfo);
}
else
{
nmod_mpoly_t tG, tAbar, tBbar;
nmod_mpoly_init(tG, ctx);
nmod_mpoly_init(tAbar, ctx);
nmod_mpoly_init(tBbar, ctx);
success = _nmod_mpoly_vec_content_mpoly(tG, Au->coeffs, Au->length, ctx);
if (!success)
goto cleanup;
nmod_mpoly_repack_bits_inplace(tG, Gbits, ctx);
_mpoly_gen_shift_left(tG->exps, tG->bits, tG->length,
var, FLINT_MIN(Ashift, Bshift), ctx->minfo);
if (Abar != NULL)
{
success = nmod_mpoly_divides(tAbar, A, tG, ctx);
FLINT_ASSERT(success);
}
if (Bbar != NULL)
{
success = nmod_mpoly_divides(tBbar, B, tG, ctx);
FLINT_ASSERT(success);
}
nmod_mpoly_swap(G, tG, ctx);
if (Abar != NULL)
nmod_mpoly_swap(Abar, tAbar, ctx);
if (Bbar != NULL)
nmod_mpoly_swap(Bbar, tBbar, ctx);
nmod_mpoly_clear(tG, ctx);
nmod_mpoly_clear(tAbar, ctx);
nmod_mpoly_clear(tBbar, ctx);
}
success = 1;
cleanup:
nmod_mpoly_univar_clear(Au, ctx);
return success;
}
static int _try_divides(
nmod_mpoly_t G,
nmod_mpoly_t Abar,
nmod_mpoly_t Bbar,
const nmod_mpoly_t A,
const nmod_mpoly_t BB,
const nmod_mpoly_ctx_t ctx)
{
int success = 0;
nmod_mpoly_t Q, B, M;
nmod_mpoly_init(Q, ctx);
nmod_mpoly_init(B, ctx);
nmod_mpoly_init(M, ctx);
nmod_mpoly_term_content(M, BB, ctx);
nmod_mpoly_divides(B, BB, M, ctx);
if (nmod_mpoly_divides(Q, A, B, ctx))
{
_do_monomial_gcd(G, Abar, Bbar, Q, M, ctx);
nmod_mpoly_mul(G, G, B, ctx);
success = 1;
}
nmod_mpoly_clear(Q, ctx);
nmod_mpoly_clear(B, ctx);
nmod_mpoly_clear(M, ctx);
return success;
}
static int _try_zippel(
nmod_mpoly_t G,
nmod_mpoly_t Abar,
nmod_mpoly_t Bbar,
const nmod_mpoly_t A,
const nmod_mpoly_t B,
const mpoly_gcd_info_t I,
const nmod_mpoly_ctx_t ctx)
{
slong m = I->mvars;
int success;
flint_bitcnt_t wbits;
flint_rand_t randstate;
nmod_mpoly_ctx_t uctx;
nmod_mpolyu_t Au, Bu, Gu, Abaru, Bbaru;
nmod_mpoly_t Ac, Bc, Gc, Abarc, Bbarc;
FLINT_ASSERT(A->bits <= FLINT_BITS);
FLINT_ASSERT(B->bits <= FLINT_BITS);
if (!(I->can_use & MPOLY_GCD_USE_ZIPPEL))
return 0;
FLINT_ASSERT(m >= WORD(2));
FLINT_ASSERT(A->length > 0);
FLINT_ASSERT(B->length > 0);
flint_rand_init(randstate);
nmod_mpoly_ctx_init(uctx, m - 1, ORD_LEX, ctx->mod.n);
wbits = FLINT_MAX(A->bits, B->bits);
nmod_mpolyu_init(Au, wbits, uctx);
nmod_mpolyu_init(Bu, wbits, uctx);
nmod_mpolyu_init(Gu, wbits, uctx);
nmod_mpolyu_init(Abaru, wbits, uctx);
nmod_mpolyu_init(Bbaru, wbits, uctx);
nmod_mpoly_init3(Ac, 0, wbits, uctx);
nmod_mpoly_init3(Bc, 0, wbits, uctx);
nmod_mpoly_init3(Gc, 0, wbits, uctx);
nmod_mpoly_init3(Abarc, 0, wbits, uctx);
nmod_mpoly_init3(Bbarc, 0, wbits, uctx);
nmod_mpoly_to_mpolyu_perm_deflate_threaded_pool(Au, uctx, A, ctx,
I->zippel_perm, I->Amin_exp, I->Gstride, NULL, 0);
nmod_mpoly_to_mpolyu_perm_deflate_threaded_pool(Bu, uctx, B, ctx,
I->zippel_perm, I->Bmin_exp, I->Gstride, NULL, 0);
success = nmod_mpolyu_content_mpoly(Ac, Au, uctx) &&
nmod_mpolyu_content_mpoly(Bc, Bu, uctx);
if (!success)
goto cleanup;
nmod_mpolyu_divexact_mpoly_inplace(Au, Ac, uctx);
nmod_mpolyu_divexact_mpoly_inplace(Bu, Bc, uctx);
success = nmod_mpolyu_gcdm_zippel(Gu, Abaru, Bbaru, Au, Bu, uctx, randstate);
if (!success)
goto cleanup;
if (Abar == NULL && Bbar == NULL)
{
success = nmod_mpoly_gcd(Gc, Ac, Bc, uctx);
if (!success)
goto cleanup;
nmod_mpoly_repack_bits_inplace(Gc, wbits, uctx);
nmod_mpolyu_mul_mpoly_inplace(Gu, Gc, uctx);
nmod_mpoly_from_mpolyu_perm_inflate(G, I->Gbits, ctx, Gu, uctx,
I->zippel_perm, I->Gmin_exp, I->Gstride);
}
else
{
success = nmod_mpoly_gcd_cofactors(Gc, Abarc, Bbarc, Ac, Bc, uctx);
if (!success)
goto cleanup;
nmod_mpoly_repack_bits_inplace(Gc, wbits, uctx);
nmod_mpoly_repack_bits_inplace(Abarc, wbits, uctx);
nmod_mpoly_repack_bits_inplace(Bbarc, wbits, uctx);
nmod_mpolyu_mul_mpoly_inplace(Gu, Gc, uctx);
nmod_mpolyu_mul_mpoly_inplace(Abaru, Abarc, uctx);
nmod_mpolyu_mul_mpoly_inplace(Bbaru, Bbarc, uctx);
nmod_mpoly_from_mpolyu_perm_inflate(G, I->Gbits, ctx, Gu, uctx,
I->zippel_perm, I->Gmin_exp, I->Gstride);
if (Abar != NULL)
nmod_mpoly_from_mpolyu_perm_inflate(Abar, I->Abarbits, ctx,
Abaru, uctx, I->zippel_perm, I->Abarmin_exp, I->Gstride);
if (Bbar != NULL)
nmod_mpoly_from_mpolyu_perm_inflate(Bbar, I->Bbarbits, ctx,
Bbaru, uctx, I->zippel_perm, I->Bbarmin_exp, I->Gstride);
}
success = 1;
cleanup:
nmod_mpolyu_clear(Au, uctx);
nmod_mpolyu_clear(Bu, uctx);
nmod_mpolyu_clear(Gu, uctx);
nmod_mpolyu_clear(Abaru, uctx);
nmod_mpolyu_clear(Bbaru, uctx);
nmod_mpoly_clear(Ac, uctx);
nmod_mpoly_clear(Bc, uctx);
nmod_mpoly_clear(Gc, uctx);
nmod_mpoly_clear(Abarc, uctx);
nmod_mpoly_clear(Bbarc, uctx);
nmod_mpoly_ctx_clear(uctx);
flint_rand_clear(randstate);
return success;
}
static int _try_zippel2(
nmod_mpoly_t G,
nmod_mpoly_t Abar,
nmod_mpoly_t Bbar,
const nmod_mpoly_t A,
const nmod_mpoly_t B,
const mpoly_gcd_info_t I,
const nmod_mpoly_ctx_t ctx)
{
slong i, k;
slong m = I->mvars;
int success;
flint_bitcnt_t wbits;
nmod_mpoly_ctx_t lctx;
nmod_mpoly_t Al, Bl, Gl, Abarl, Bbarl;
nmod_mpoly_t Al_lc, Bl_lc, Ac, Bc, Gc, Abarc, Bbarc, Gamma;
slong * tmp, * Gl_degs, * Al_degs, * Bl_degs, * Gamma_degs, * Gguess;
slong max_degree;
FLINT_ASSERT(A->bits <= FLINT_BITS);
FLINT_ASSERT(B->bits <= FLINT_BITS);
FLINT_ASSERT(A->length > 0);
FLINT_ASSERT(B->length > 0);
if (!(I->can_use & MPOLY_GCD_USE_ZIPPEL2))
return 0;
FLINT_ASSERT(m >= 3);
tmp = FLINT_ARRAY_ALLOC(5*m, slong);
Al_degs = tmp + 1*m;
Bl_degs = tmp + 2*m;
Gl_degs = tmp + 3*m;
Gamma_degs = tmp + 4*m;
nmod_mpoly_ctx_init(lctx, m, ORD_LEX, ctx->mod.n);
max_degree = 0;
for (i = 0; i < m; i++)
{
k = I->zippel2_perm[i];
Gl_degs[i] = I->Gdeflate_deg_bound[k];
Al_degs[i] = I->Adeflate_deg[k];
max_degree = FLINT_MAX(max_degree, Al_degs[i]);
Bl_degs[i] = I->Bdeflate_deg[k];
max_degree = FLINT_MAX(max_degree, Bl_degs[i]);
}
wbits = 1 + FLINT_BIT_COUNT(max_degree);
wbits = mpoly_fix_bits(wbits, lctx->minfo);
FLINT_ASSERT(wbits <= FLINT_BITS);
nmod_mpoly_init3(Al, 0, wbits, lctx);
nmod_mpoly_init3(Bl, 0, wbits, lctx);
nmod_mpoly_init3(Gl, 0, wbits, lctx);
nmod_mpoly_init3(Abarl, 0, wbits, lctx);
nmod_mpoly_init3(Bbarl, 0, wbits, lctx);
nmod_mpoly_init3(Ac, 0, wbits, lctx);
nmod_mpoly_init3(Bc, 0, wbits, lctx);
nmod_mpoly_init3(Gc, 0, wbits, lctx);
nmod_mpoly_init3(Abarc, 0, wbits, lctx);
nmod_mpoly_init3(Bbarc, 0, wbits, lctx);
nmod_mpoly_init3(Gamma, 0, wbits, lctx);
nmod_mpoly_init3(Al_lc, 0, wbits, lctx);
nmod_mpoly_init3(Bl_lc, 0, wbits, lctx);
nmod_mpoly_to_mpolyl_perm_deflate(Al, lctx, A, ctx,
I->zippel2_perm, I->Amin_exp, I->Gstride);
nmod_mpoly_to_mpolyl_perm_deflate(Bl, lctx, B, ctx,
I->zippel2_perm, I->Bmin_exp, I->Gstride);
success = nmod_mpolyl_content(Ac, Al, 2, lctx) &&
nmod_mpolyl_content(Bc, Bl, 2, lctx);
if (!success)
goto cleanup;
if (Abar == NULL && Bbar == NULL)
success = nmod_mpoly_gcd(Gc, Ac, Bc, lctx);
else
success = nmod_mpoly_gcd_cofactors(Gc, Abarc, Bbarc, Ac, Bc, lctx);
if (!success)
goto cleanup;
nmod_mpoly_degrees_si(tmp, Ac, lctx);
for (i = 0; i < m; i++)
Al_degs[i] -= tmp[i];
success = nmod_mpoly_divides(Al, Al, Ac, lctx);
FLINT_ASSERT(success);
nmod_mpoly_degrees_si(tmp, Bc, lctx);
for (i = 0; i < m; i++)
Bl_degs[i] -= tmp[i];
success = nmod_mpoly_divides(Bl, Bl, Bc, lctx);
FLINT_ASSERT(success);
nmod_mpoly_degrees_si(tmp, Gc, lctx);
for (i = 0; i < m; i++)
Gl_degs[i] -= tmp[i];
nmod_mpoly_repack_bits_inplace(Al, wbits, lctx);
nmod_mpoly_repack_bits_inplace(Bl, wbits, lctx);
nmod_mpolyl_lead_coeff(Al_lc, Al, 2, lctx);
nmod_mpolyl_lead_coeff(Bl_lc, Bl, 2, lctx);
success = nmod_mpoly_gcd(Gamma, Al_lc, Bl_lc, lctx);
if (!success)
goto cleanup;
nmod_mpoly_repack_bits_inplace(Gamma, wbits, lctx);
nmod_mpoly_degrees_si(Gamma_degs, Gamma, lctx);
Gguess = I->Gdeflate_deg_bounds_are_nice ? Gl_degs : NULL;
success = nmod_mpolyl_gcd_zippel_smprime(Gl, Gguess, Abarl, Bbarl,
Al, Al_degs, Bl, Bl_degs, Gamma, Gamma_degs, lctx);
if (!success)
{
success = nmod_mpolyl_gcd_zippel_lgprime(Gl, Gguess, Abarl, Bbarl,
Al, Al_degs, Bl, Bl_degs, Gamma, Gamma_degs, lctx);
if (!success)
goto cleanup;
}
nmod_mpoly_mul(Gl, Gl, Gc, lctx);
nmod_mpoly_from_mpolyl_perm_inflate(G, I->Gbits, ctx, Gl, lctx,
I->zippel2_perm, I->Gmin_exp, I->Gstride);
if (Abar != NULL)
{
nmod_mpoly_mul(Abarl, Abarl, Abarc, lctx);
nmod_mpoly_from_mpolyl_perm_inflate(Abar, I->Abarbits, ctx, Abarl, lctx,
I->zippel2_perm, I->Abarmin_exp, I->Gstride);
}
if (Bbar != NULL)
{
nmod_mpoly_mul(Bbarl, Bbarl, Bbarc, lctx);
nmod_mpoly_from_mpolyl_perm_inflate(Bbar, I->Bbarbits, ctx, Bbarl, lctx,
I->zippel2_perm, I->Bbarmin_exp, I->Gstride);
}
success = 1;
cleanup:
nmod_mpoly_clear(Al, lctx);
nmod_mpoly_clear(Bl, lctx);
nmod_mpoly_clear(Gl, lctx);
nmod_mpoly_clear(Abarl, lctx);
nmod_mpoly_clear(Bbarl, lctx);
nmod_mpoly_clear(Ac, lctx);
nmod_mpoly_clear(Bc, lctx);
nmod_mpoly_clear(Gc, lctx);
nmod_mpoly_clear(Abarc, lctx);
nmod_mpoly_clear(Bbarc, lctx);
nmod_mpoly_clear(Gamma, lctx);
nmod_mpoly_clear(Al_lc, lctx);
nmod_mpoly_clear(Bl_lc, lctx);
nmod_mpoly_ctx_clear(lctx);
flint_free(tmp);
return success;
}
static int _try_hensel(
nmod_mpoly_t G,
nmod_mpoly_t Abar,
nmod_mpoly_t Bbar,
const nmod_mpoly_t A,
const nmod_mpoly_t B,
const mpoly_gcd_info_t I,
const nmod_mpoly_ctx_t ctx)
{
slong i, k;
slong m = I->mvars;
int success;
flint_bitcnt_t wbits;
nmod_mpoly_ctx_t lctx;
nmod_mpoly_t Al, Bl, Gl, Abarl, Bbarl;
nmod_mpoly_t Ac, Bc, Gc, Abarc, Bbarc;
slong max_deg;
FLINT_ASSERT(A->bits <= FLINT_BITS);
FLINT_ASSERT(B->bits <= FLINT_BITS);
FLINT_ASSERT(A->length > 0);
FLINT_ASSERT(B->length > 0);
if (!(I->can_use & MPOLY_GCD_USE_HENSEL))
return 0;
FLINT_ASSERT(m >= WORD(2));
nmod_mpoly_ctx_init(lctx, m, ORD_LEX, ctx->mod.n);
max_deg = 0;
for (i = 0; i < m; i++)
{
k = I->hensel_perm[i];
max_deg = FLINT_MAX(max_deg, I->Adeflate_deg[k]);
max_deg = FLINT_MAX(max_deg, I->Bdeflate_deg[k]);
}
wbits = 1 + FLINT_BIT_COUNT(max_deg);
wbits = mpoly_fix_bits(wbits, lctx->minfo);
FLINT_ASSERT(wbits <= FLINT_BITS);
nmod_mpoly_init3(Al, 0, wbits, lctx);
nmod_mpoly_init3(Bl, 0, wbits, lctx);
nmod_mpoly_init3(Gl, 0, wbits, lctx);
nmod_mpoly_init3(Abarl, 0, wbits, lctx);
nmod_mpoly_init3(Bbarl, 0, wbits, lctx);
nmod_mpoly_init3(Ac, 0, wbits, lctx);
nmod_mpoly_init3(Bc, 0, wbits, lctx);
nmod_mpoly_init3(Gc, 0, wbits, lctx);
nmod_mpoly_init3(Abarc, 0, wbits, lctx);
nmod_mpoly_init3(Bbarc, 0, wbits, lctx);
nmod_mpoly_to_mpolyl_perm_deflate(Al, lctx, A, ctx,
I->hensel_perm, I->Amin_exp, I->Gstride);
nmod_mpoly_to_mpolyl_perm_deflate(Bl, lctx, B, ctx,
I->hensel_perm, I->Bmin_exp, I->Gstride);
success = nmod_mpolyl_content(Ac, Al, 1, lctx) &&
nmod_mpolyl_content(Bc, Bl, 1, lctx);
if (!success)
goto cleanup;
if (Abar == NULL && Bbar == NULL)
success = nmod_mpoly_gcd(Gc, Ac, Bc, lctx);
else
success = nmod_mpoly_gcd_cofactors(Gc, Abarc, Bbarc, Ac, Bc, lctx);
if (!success)
goto cleanup;
success = nmod_mpoly_divides(Al, Al, Ac, lctx);
FLINT_ASSERT(success);
success = nmod_mpoly_divides(Bl, Bl, Bc, lctx);
FLINT_ASSERT(success);
nmod_mpoly_repack_bits_inplace(Al, wbits, lctx);
nmod_mpoly_repack_bits_inplace(Bl, wbits, lctx);
max_deg = I->Gdeflate_deg_bound[I->hensel_perm[0]];
success = nmod_mpolyl_gcd_hensel_smprime(Gl, max_deg, Abarl, Bbarl, Al, Bl, lctx);
if (!success)
{
success = nmod_mpolyl_gcd_hensel_medprime(Gl, max_deg, Abarl, Bbarl, Al, Bl, lctx);
if (!success)
goto cleanup;
}
nmod_mpoly_mul(Gl, Gl, Gc, lctx);
nmod_mpoly_from_mpolyl_perm_inflate(G, I->Gbits, ctx, Gl, lctx,
I->hensel_perm, I->Gmin_exp, I->Gstride);
if (Abar != NULL)
{
nmod_mpoly_mul(Abarl, Abarl, Abarc, lctx);
nmod_mpoly_from_mpolyl_perm_inflate(Abar, I->Abarbits, ctx, Abarl, lctx,
I->hensel_perm, I->Abarmin_exp, I->Gstride);
}
if (Bbar != NULL)
{
nmod_mpoly_mul(Bbarl, Bbarl, Bbarc, lctx);
nmod_mpoly_from_mpolyl_perm_inflate(Bbar, I->Bbarbits, ctx, Bbarl, lctx,
I->hensel_perm, I->Bbarmin_exp, I->Gstride);
}
success = 1;
cleanup:
nmod_mpoly_clear(Al, lctx);
nmod_mpoly_clear(Bl, lctx);
nmod_mpoly_clear(Gl, lctx);
nmod_mpoly_clear(Abarl, lctx);
nmod_mpoly_clear(Bbarl, lctx);
nmod_mpoly_clear(Ac, lctx);
nmod_mpoly_clear(Bc, lctx);
nmod_mpoly_clear(Gc, lctx);
nmod_mpoly_clear(Abarc, lctx);
nmod_mpoly_clear(Bbarc, lctx);
nmod_mpoly_ctx_clear(lctx);
return success;
}
typedef struct
{
nmod_mpolyn_struct * Pn;
const nmod_mpoly_ctx_struct * nctx;
const nmod_mpoly_struct * P;
const nmod_mpoly_ctx_struct * ctx;
const slong * perm;
const ulong * shift, * stride;
const thread_pool_handle * handles;
slong num_handles;
}
_convertn_arg_struct;
typedef _convertn_arg_struct _convertn_arg_t[1];
static void _worker_convertn(void * varg)
{
_convertn_arg_struct * arg = (_convertn_arg_struct *) varg;
nmod_mpoly_to_mpolyn_perm_deflate_threaded_pool(arg->Pn, arg->nctx, arg->P, arg->ctx,
arg->perm, arg->shift, arg->stride, arg->handles, arg->num_handles);
}
static int _try_brown(
nmod_mpoly_t G,
nmod_mpoly_t Abar,
nmod_mpoly_t Bbar,
const nmod_mpoly_t A,
const nmod_mpoly_t B,
mpoly_gcd_info_t I,
const nmod_mpoly_ctx_t ctx)
{
int success;
slong k, m = I->mvars;
flint_bitcnt_t wbits;
nmod_mpoly_ctx_t nctx;
nmod_mpolyn_t An, Bn, Gn, Abarn, Bbarn;
nmod_poly_stack_t Sp;
slong thread_limit;
thread_pool_handle * handles;
slong num_handles;
if (!(I->can_use & MPOLY_GCD_USE_BROWN))
return 0;
FLINT_ASSERT(m >= 2);
FLINT_ASSERT(A->bits <= FLINT_BITS);
FLINT_ASSERT(B->bits <= FLINT_BITS);
FLINT_ASSERT(A->length > 0);
FLINT_ASSERT(B->length > 0);
wbits = FLINT_MAX(A->bits, B->bits);
nmod_mpoly_ctx_init(nctx, m, ORD_LEX, ctx->mod.n);
nmod_poly_stack_init(Sp, wbits, nctx);
nmod_mpolyn_init(An, wbits, nctx);
nmod_mpolyn_init(Bn, wbits, nctx);
nmod_mpolyn_init(Gn, wbits, nctx);
nmod_mpolyn_init(Abarn, wbits, nctx);
nmod_mpolyn_init(Bbarn, wbits, nctx);
k = I->brown_perm[m - 1];
thread_limit = FLINT_MIN(I->Adeflate_deg[k], I->Bdeflate_deg[k])/8;
thread_limit = FLINT_MIN(thread_limit, (A->length + B->length)/1024);
num_handles = flint_request_threads(&handles, thread_limit);
if (num_handles > 0)
{
slong s = mpoly_divide_threads(num_handles, A->length, B->length);
_convertn_arg_t arg;
FLINT_ASSERT(s >= 0);
FLINT_ASSERT(s < num_handles);
arg->Pn = Bn;
arg->nctx = nctx;
arg->P = B;
arg->ctx = ctx;
arg->perm = I->brown_perm;
arg->shift = I->Bmin_exp;
arg->stride = I->Gstride;
arg->handles = handles + (s + 1);
arg->num_handles = num_handles - (s + 1);
thread_pool_wake(global_thread_pool, handles[s], 0, _worker_convertn, arg);
nmod_mpoly_to_mpolyn_perm_deflate_threaded_pool(An, nctx, A, ctx,
I->brown_perm, I->Amin_exp, I->Gstride, handles + 0, s);
thread_pool_wait(global_thread_pool, handles[s]);
}
else
{
nmod_mpoly_to_mpolyn_perm_deflate_threaded_pool(An, nctx, A, ctx,
I->brown_perm, I->Amin_exp, I->Gstride, NULL, 0);
nmod_mpoly_to_mpolyn_perm_deflate_threaded_pool(Bn, nctx, B, ctx,
I->brown_perm, I->Bmin_exp, I->Gstride, NULL, 0);
}
FLINT_ASSERT(An->bits == wbits);
FLINT_ASSERT(Bn->bits == wbits);
FLINT_ASSERT(An->length > 1);
FLINT_ASSERT(Bn->length > 1);
success = (num_handles > 0)
? nmod_mpolyn_gcd_brown_smprime_threaded_pool(Gn, Abarn, Bbarn, An, Bn,
m - 1, nctx, I, handles, num_handles)
: nmod_mpolyn_gcd_brown_smprime(Gn, Abarn, Bbarn, An, Bn,
m - 1, nctx, I, Sp);
if (!success)
{
nmod_mpoly_to_mpolyn_perm_deflate_threaded_pool(An, nctx, A, ctx,
I->brown_perm, I->Amin_exp, I->Gstride, NULL, 0);
nmod_mpoly_to_mpolyn_perm_deflate_threaded_pool(Bn, nctx, B, ctx,
I->brown_perm, I->Bmin_exp, I->Gstride, NULL, 0);
success = nmod_mpolyn_gcd_brown_lgprime(Gn, Abarn, Bbarn, An, Bn,
m - 1, nctx);
}
if (!success)
goto cleanup;
nmod_mpoly_from_mpolyn_perm_inflate(G, I->Gbits, ctx, Gn, nctx,
I->brown_perm, I->Gmin_exp, I->Gstride);
if (Abar != NULL)
nmod_mpoly_from_mpolyn_perm_inflate(Abar, I->Abarbits, ctx, Abarn, nctx,
I->brown_perm, I->Abarmin_exp, I->Gstride);
if (Bbar != NULL)
nmod_mpoly_from_mpolyn_perm_inflate(Bbar, I->Bbarbits, ctx, Bbarn, nctx,
I->brown_perm, I->Bbarmin_exp, I->Gstride);
success = 1;
cleanup:
flint_give_back_threads(handles, num_handles);
nmod_mpolyn_clear(An, nctx);
nmod_mpolyn_clear(Bn, nctx);
nmod_mpolyn_clear(Gn, nctx);
nmod_mpolyn_clear(Abarn, nctx);
nmod_mpolyn_clear(Bbarn, nctx);
nmod_poly_stack_clear(Sp);
nmod_mpoly_ctx_clear(nctx);
return success;
}
int _nmod_mpoly_gcd_algo_small(
nmod_mpoly_t G,
nmod_mpoly_t Abar,
nmod_mpoly_t Bbar,
const nmod_mpoly_t A,
const nmod_mpoly_t B,
const nmod_mpoly_ctx_t ctx,
unsigned int algo)
{
int success;
flint_bitcnt_t Gbits = FLINT_MIN(A->bits, B->bits);
flint_bitcnt_t Abarbits = A->bits;
flint_bitcnt_t Bbarbits = B->bits;
slong v_in_both;
slong v_in_either;
slong v_in_A_only;
slong v_in_B_only;
slong j;
slong nvars = ctx->minfo->nvars;
mpoly_gcd_info_t I;
#if FLINT_WANT_ASSERT
nmod_mpoly_t T, Asave, Bsave;
#endif
if (A->length == 1)
return _do_monomial_gcd(G, Bbar, Abar, B, A, ctx);
else if (B->length == 1)
return _do_monomial_gcd(G, Abar, Bbar, A, B, ctx);
#if FLINT_WANT_ASSERT
nmod_mpoly_init(T, ctx);
nmod_mpoly_init(Asave, ctx);
nmod_mpoly_init(Bsave, ctx);
nmod_mpoly_set(Asave, A, ctx);
nmod_mpoly_set(Bsave, B, ctx);
#endif
mpoly_gcd_info_init(I, nvars);
I->Gbits = Gbits;
I->Abarbits = Abarbits;
I->Bbarbits = Bbarbits;
mpoly_gcd_info_limits(I->Amax_exp, I->Amin_exp, I->Alead_count,
I->Atail_count, A->exps, A->bits, A->length, ctx->minfo);
mpoly_gcd_info_limits(I->Bmax_exp, I->Bmin_exp, I->Blead_count,
I->Btail_count, B->exps, B->bits, B->length, ctx->minfo);
for (j = 0; j < nvars; j++)
{
if (I->Amax_exp[j] - I->Amin_exp[j] != I->Bmax_exp[j] - I->Bmin_exp[j])
goto skip_monomial_cofactors;
}
if (_try_monomial_cofactors(G, Abar, Bbar, A, B, ctx))
{
goto successful;
}
skip_monomial_cofactors:
mpoly_gcd_info_stride(I->Gstride,
A->exps, A->bits, A->length, I->Amax_exp, I->Amin_exp,
B->exps, B->bits, B->length, I->Bmax_exp, I->Bmin_exp, ctx->minfo);
for (j = 0; j < nvars; j++)
{
ulong t = I->Gstride[j];
if (t == 0)
{
FLINT_ASSERT(I->Amax_exp[j] == I->Amin_exp[j] ||
I->Bmax_exp[j] == I->Bmin_exp[j]);
}
else
{
FLINT_ASSERT((I->Amax_exp[j] - I->Amin_exp[j]) % t == 0);
FLINT_ASSERT((I->Bmax_exp[j] - I->Bmin_exp[j]) % t == 0);
}
I->Adeflate_deg[j] = t == 0 ? 0 : (I->Amax_exp[j] - I->Amin_exp[j])/t;
I->Bdeflate_deg[j] = t == 0 ? 0 : (I->Bmax_exp[j] - I->Bmin_exp[j])/t;
t = FLINT_MIN(I->Amin_exp[j], I->Bmin_exp[j]);
I->Gmin_exp[j] = t;
I->Abarmin_exp[j] = I->Amin_exp[j] - t;
I->Bbarmin_exp[j] = I->Bmin_exp[j] - t;
}
v_in_both = -WORD(1);
for (j = 0; j < nvars; j++)
{
if (I->Amax_exp[j] > I->Amin_exp[j] && I->Bmax_exp[j] > I->Bmin_exp[j])
{
v_in_both = j;
break;
}
}
if (v_in_both == -WORD(1))
{
_do_trivial(G, Abar, Bbar, A, B, I, ctx);
goto successful;
}
FLINT_ASSERT(0 <= v_in_both && v_in_both < nvars);
v_in_either = -WORD(1);
for (j = 0; j < nvars; j++)
{
if (j == v_in_both)
continue;
if (I->Amax_exp[j] > I->Amin_exp[j] || I->Bmax_exp[j] > I->Bmin_exp[j])
{
v_in_either = j;
break;
}
}
if (v_in_either == -WORD(1))
{
_do_univar(G, Abar, Bbar, A, B, v_in_both, I, ctx);
goto successful;
}
v_in_A_only = -WORD(1);
v_in_B_only = -WORD(1);
for (j = 0; j < nvars; j++)
{
if (I->Amax_exp[j] > I->Amin_exp[j] && I->Bmax_exp[j] == I->Bmin_exp[j])
{
v_in_A_only = j;
break;
}
if (I->Bmax_exp[j] > I->Bmin_exp[j] && I->Amax_exp[j] == I->Amin_exp[j])
{
v_in_B_only = j;
break;
}
}
if (v_in_A_only != -WORD(1))
{
success = _try_missing_var(G, I->Gbits, Abar, Bbar, v_in_A_only,
A, I->Amin_exp[v_in_A_only],
B, I->Bmin_exp[v_in_A_only],
ctx);
goto cleanup;
}
if (v_in_B_only != -WORD(1))
{
success = _try_missing_var(G, I->Gbits, Bbar, Abar, v_in_B_only,
B, I->Bmin_exp[v_in_B_only],
A, I->Amin_exp[v_in_B_only],
ctx);
goto cleanup;
}
mpoly_gcd_info_set_perm(I, A->length, B->length, ctx->minfo);
I->Adeflate_tdeg = I->Bdeflate_tdeg = -1;
_set_estimates(I, A, B, ctx);
j = FLINT_MAX(0, 8 - I->mvars);
if (!I->Gdeflate_deg_bounds_are_nice || ctx->mod.n < (ulong) j)
_set_estimates_medprime(I, A, B, ctx);
if (!I->Gdeflate_deg_bounds_are_nice)
_set_estimates_lgprime(I, A, B, ctx);
{
int gcd_is_trivial = 1;
int try_a = I->Gdeflate_deg_bounds_are_nice;
int try_b = I->Gdeflate_deg_bounds_are_nice;
for (j = 0; j < nvars; j++)
{
if (I->Gdeflate_deg_bound[j] != 0)
gcd_is_trivial = 0;
if (I->Adeflate_deg[j] != I->Gdeflate_deg_bound[j])
try_a = 0;
if (I->Bdeflate_deg[j] != I->Gdeflate_deg_bound[j])
try_b = 0;
}
if (gcd_is_trivial)
{
_do_trivial(G, Abar, Bbar, A, B, I, ctx);
goto successful;
}
if (try_a && _try_divides(G, Bbar, Abar, B, A, ctx))
goto successful;
if (try_b && _try_divides(G, Abar, Bbar, A, B, ctx))
goto successful;
}
if (algo == MPOLY_GCD_USE_HENSEL)
{
mpoly_gcd_info_measure_hensel(I, A->length, B->length, ctx->minfo);
success = _try_hensel(G, Abar, Bbar, A, B, I, ctx);
goto cleanup;
}
else if (algo == MPOLY_GCD_USE_BROWN)
{
mpoly_gcd_info_measure_brown(I, A->length, B->length, ctx->minfo);
success = _try_brown(G, Abar, Bbar, A, B, I, ctx);
goto cleanup;
}
else if (algo == MPOLY_GCD_USE_ZIPPEL)
{
mpoly_gcd_info_measure_zippel(I, A->length, B->length, ctx->minfo);
success = _try_zippel(G, Abar, Bbar, A, B, I, ctx);
goto cleanup;
}
else if (I->mvars < 3)
{
mpoly_gcd_info_measure_brown(I, A->length, B->length, ctx->minfo);
mpoly_gcd_info_measure_hensel(I, A->length, B->length, ctx->minfo);
algo &= (MPOLY_GCD_USE_BROWN | MPOLY_GCD_USE_HENSEL);
if (algo == MPOLY_GCD_USE_BROWN)
{
success = _try_brown(G, Abar, Bbar, A, B, I, ctx);
}
else if (algo == MPOLY_GCD_USE_HENSEL)
{
success = _try_hensel(G, Abar, Bbar, A, B, I, ctx);
}
else
{
slong k = I->brown_perm[1];
slong d = FLINT_MAX(I->Adeflate_deg[k], I->Bdeflate_deg[k]);
int deg_is_small = (ulong) d < ctx->mod.n/2;
if (I->Adensity + I->Bdensity > (deg_is_small ? 0.05 : 0.2))
{
success = _try_brown(G, Abar, Bbar, A, B, I, ctx) ||
_try_hensel(G, Abar, Bbar, A, B, I, ctx);
}
else
{
success = _try_hensel(G, Abar, Bbar, A, B, I, ctx) ||
_try_brown(G, Abar, Bbar, A, B, I, ctx);
}
}
goto cleanup;
}
else if (algo == MPOLY_GCD_USE_ZIPPEL2)
{
mpoly_gcd_info_measure_zippel2(I, A->length, B->length, ctx->minfo);
success = _try_zippel2(G, Abar, Bbar, A, B, I, ctx);
goto cleanup;
}
else
{
slong k, d;
int deg_is_small = 1;
double density = I->Adensity + I->Bdensity;
mpoly_gcd_info_measure_hensel(I, A->length, B->length, ctx->minfo);
mpoly_gcd_info_measure_brown(I, A->length, B->length, ctx->minfo);
mpoly_gcd_info_measure_zippel(I, A->length, B->length, ctx->minfo);
mpoly_gcd_info_measure_zippel2(I, A->length, B->length, ctx->minfo);
for (j = 1; j < I->mvars; j++)
{
k = I->brown_perm[j];
d = FLINT_MAX(I->Adeflate_deg[k], I->Bdeflate_deg[k]);
if ((ulong) d > ctx->mod.n/2)
deg_is_small = 0;
}
if (density > 0.08)
{
if (!deg_is_small && _try_hensel(G, Abar, Bbar, A, B, I, ctx))
goto successful;
if (_try_brown(G, Abar, Bbar, A, B, I, ctx))
goto successful;
}
if (I->Adeflate_tdeg > 0 && I->Bdeflate_tdeg > 0)
{
fmpz_t x;
double tdensity;
fmpz_init(x);
fmpz_bin_uiui(x, (ulong)I->Adeflate_tdeg + I->mvars, I->mvars);
tdensity = A->length/fmpz_get_d(x);
fmpz_bin_uiui(x, (ulong)I->Bdeflate_tdeg + I->mvars, I->mvars);
tdensity += B->length/fmpz_get_d(x);
density = FLINT_MAX(density, tdensity);
fmpz_clear(x);
}
if (density > (deg_is_small ? 0.05 : 0.001))
{
if (_try_hensel(G, Abar, Bbar, A, B, I, ctx))
goto successful;
}
k = I->zippel2_perm[1];
k = FLINT_MAX(I->Adeflate_deg[k], I->Bdeflate_deg[k]);
if ((A->length + B->length)/64 < k)
{
if (_try_zippel(G, Abar, Bbar, A, B, I, ctx))
goto successful;
if (_try_zippel2(G, Abar, Bbar, A, B, I, ctx))
goto successful;
}
else
{
if (_try_zippel2(G, Abar, Bbar, A, B, I, ctx))
goto successful;
if (_try_zippel(G, Abar, Bbar, A, B, I, ctx))
goto successful;
}
success = _try_hensel(G, Abar, Bbar, A, B, I, ctx) ||
_try_brown(G, Abar, Bbar, A, B, I, ctx);
goto cleanup;
}
success = 0;
goto cleanup;
successful:
success = 1;
cleanup:
mpoly_gcd_info_clear(I);
if (success)
{
FLINT_ASSERT(G->length > 0);
if (G->coeffs[0] != 1)
{
if (Abar != NULL)
_nmod_vec_scalar_mul_nmod(Abar->coeffs, Abar->coeffs,
Abar->length, G->coeffs[0], ctx->mod);
if (Bbar != NULL)
_nmod_vec_scalar_mul_nmod(Bbar->coeffs, Bbar->coeffs,
Bbar->length, G->coeffs[0], ctx->mod);
_nmod_vec_scalar_mul_nmod(G->coeffs, G->coeffs, G->length,
nmod_inv(G->coeffs[0], ctx->mod), ctx->mod);
}
FLINT_ASSERT(nmod_mpoly_divides(T, Asave, G, ctx));
FLINT_ASSERT(Abar == NULL || nmod_mpoly_equal(T, Abar, ctx));
FLINT_ASSERT(nmod_mpoly_divides(T, Bsave, G, ctx));
FLINT_ASSERT(Bbar == NULL || nmod_mpoly_equal(T, Bbar, ctx));
}
#if FLINT_WANT_ASSERT
nmod_mpoly_clear(T, ctx);
nmod_mpoly_clear(Asave, ctx);
nmod_mpoly_clear(Bsave, ctx);
#endif
return success;
}
static int _nmod_mpoly_gcd_algo_large(
nmod_mpoly_t G,
nmod_mpoly_t Abar,
nmod_mpoly_t Bbar,
const nmod_mpoly_t A,
const nmod_mpoly_t B,
const nmod_mpoly_ctx_t ctx,
unsigned int algo)
{
int success;
slong k;
fmpz * Ashift, * Astride;
fmpz * Bshift, * Bstride;
fmpz * Gshift, * Gstride;
nmod_mpoly_t Anew, Bnew;
const nmod_mpoly_struct * Ause, * Buse;
if (A->length == 1)
return _do_monomial_gcd(G, Bbar, Abar, B, A, ctx);
if (B->length == 1)
return _do_monomial_gcd(G, Abar, Bbar, A, B, ctx);
if (_try_monomial_cofactors(G, Abar, Bbar, A, B, ctx))
return 1;
nmod_mpoly_init(Anew, ctx);
nmod_mpoly_init(Bnew, ctx);
Ause = A;
if (A->bits > FLINT_BITS)
{
if (!nmod_mpoly_repack_bits(Anew, A, FLINT_BITS, ctx))
goto could_not_repack;
Ause = Anew;
}
Buse = B;
if (B->bits > FLINT_BITS)
{
if (!nmod_mpoly_repack_bits(Bnew, B, FLINT_BITS, ctx))
goto could_not_repack;
Buse = Bnew;
}
success = _nmod_mpoly_gcd_algo(G, Abar, Bbar, Ause, Buse, ctx, algo);
goto cleanup;
could_not_repack:
Ashift = _fmpz_vec_init(ctx->minfo->nvars);
Astride = _fmpz_vec_init(ctx->minfo->nvars);
Bshift = _fmpz_vec_init(ctx->minfo->nvars);
Bstride = _fmpz_vec_init(ctx->minfo->nvars);
Gshift = _fmpz_vec_init(ctx->minfo->nvars);
Gstride = _fmpz_vec_init(ctx->minfo->nvars);
nmod_mpoly_deflation(Ashift, Astride, A, ctx);
nmod_mpoly_deflation(Bshift, Bstride, B, ctx);
_fmpz_vec_min(Gshift, Ashift, Bshift, ctx->minfo->nvars);
for (k = 0; k < ctx->minfo->nvars; k++)
fmpz_gcd(Gstride + k, Astride + k, Bstride + k);
nmod_mpoly_deflate(Anew, A, Ashift, Gstride, ctx);
if (Anew->bits > FLINT_BITS)
{
success = nmod_mpoly_repack_bits(Anew, Anew, FLINT_BITS, ctx);
if (!success)
goto deflate_cleanup;
}
nmod_mpoly_deflate(Bnew, B, Bshift, Gstride, ctx);
if (Bnew->bits > FLINT_BITS)
{
success = nmod_mpoly_repack_bits(Bnew, Bnew, FLINT_BITS, ctx);
if (!success)
goto deflate_cleanup;
}
success = _nmod_mpoly_gcd_algo(G, Abar, Bbar, Anew, Bnew, ctx, algo);
if (!success)
goto deflate_cleanup;
for (k = 0; k < ctx->minfo->nvars; k++)
{
fmpz_sub(Ashift + k, Ashift + k, Gshift + k);
fmpz_sub(Bshift + k, Bshift + k, Gshift + k);
FLINT_ASSERT(fmpz_sgn(Ashift + k) >= 0);
FLINT_ASSERT(fmpz_sgn(Bshift + k) >= 0);
}
nmod_mpoly_inflate(G, G, Gshift, Gstride, ctx);
if (Abar != NULL)
nmod_mpoly_inflate(Abar, Abar, Ashift, Gstride, ctx);
if (Bbar != NULL)
nmod_mpoly_inflate(Bbar, Bbar, Bshift, Gstride, ctx);
FLINT_ASSERT(G->length > 0);
if (G->coeffs[0] != 1)
{
if (Abar != NULL)
_nmod_vec_scalar_mul_nmod(Abar->coeffs, Abar->coeffs,
Abar->length, G->coeffs[0], ctx->mod);
if (Bbar != NULL)
_nmod_vec_scalar_mul_nmod(Bbar->coeffs, Bbar->coeffs,
Bbar->length, G->coeffs[0], ctx->mod);
_nmod_vec_scalar_mul_nmod(G->coeffs, G->coeffs, G->length,
nmod_inv(G->coeffs[0], ctx->mod), ctx->mod);
}
deflate_cleanup:
_fmpz_vec_clear(Ashift, ctx->minfo->nvars);
_fmpz_vec_clear(Astride, ctx->minfo->nvars);
_fmpz_vec_clear(Bshift, ctx->minfo->nvars);
_fmpz_vec_clear(Bstride, ctx->minfo->nvars);
_fmpz_vec_clear(Gshift, ctx->minfo->nvars);
_fmpz_vec_clear(Gstride, ctx->minfo->nvars);
cleanup:
nmod_mpoly_clear(Anew, ctx);
nmod_mpoly_clear(Bnew, ctx);
return success;
}
int _nmod_mpoly_gcd_algo(
nmod_mpoly_t G,
nmod_mpoly_t Abar,
nmod_mpoly_t Bbar,
const nmod_mpoly_t A,
const nmod_mpoly_t B,
const nmod_mpoly_ctx_t ctx,
unsigned int algo)
{
FLINT_ASSERT(!nmod_mpoly_is_zero(A, ctx));
FLINT_ASSERT(!nmod_mpoly_is_zero(B, ctx));
if (A->bits <= FLINT_BITS && B->bits <= FLINT_BITS)
return _nmod_mpoly_gcd_algo_small(G, Abar, Bbar, A, B, ctx, algo);
else
return _nmod_mpoly_gcd_algo_large(G, Abar, Bbar, A, B, ctx, algo);
}
int nmod_mpoly_gcd(
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))
{
if (nmod_mpoly_is_zero(B, ctx))
nmod_mpoly_zero(G, ctx);
else
nmod_mpoly_make_monic(G, B, ctx);
return 1;
}
if (nmod_mpoly_is_zero(B, ctx))
{
nmod_mpoly_make_monic(G, A, ctx);
return 1;
}
return _nmod_mpoly_gcd_algo(G, NULL, NULL, A, B, ctx, MPOLY_GCD_USE_ALL);
}