#include "fq_nmod.h"
#include "n_poly.h"
#include "fq_nmod_poly.h"
#include "mpoly.h"
#include "nmod_mpoly.h"
#include "fq_nmod_mpoly.h"
static void _n_poly_mul_n_fq(
n_poly_t a,
const n_poly_t b,
const ulong * c,
const fq_nmod_ctx_t ctx)
{
slong d = fq_nmod_ctx_degree(ctx);
n_poly_t C;
C->coeffs = (ulong *) c;
C->length = d;
C->alloc = d;
_n_poly_normalise(C);
n_poly_mod_mul(a, b, C, ctx->mod);
}
void nmod_mpolyn_interp_reduce_lg_poly(
fq_nmod_poly_t E,
const fq_nmod_ctx_t fqctx,
const nmod_mpolyn_t A,
const nmod_mpoly_ctx_t ctx)
{
fq_nmod_t v;
slong Ai, Alen, k;
n_poly_struct * Acoeff;
ulong * Aexp;
slong N, off, shift;
N = mpoly_words_per_exp_sp(A->bits, ctx->minfo);
mpoly_gen_offset_shift_sp(&off, &shift, 0, A->bits, ctx->minfo);
fq_nmod_init(v, fqctx);
Acoeff = A->coeffs;
Aexp = A->exps;
Alen = A->length;
fq_nmod_poly_zero(E, fqctx);
for (Ai = 0; Ai < Alen; Ai++)
{
k = (Aexp + N*Ai)[off] >> shift;
n_poly_mod_rem(evil_cast_nmod_poly_to_n_poly(v), Acoeff + Ai,
evil_const_cast_nmod_poly_to_n_poly(fqctx->modulus), ctx->mod);
fq_nmod_poly_set_coeff(E, k, v, fqctx);
}
fq_nmod_clear(v, fqctx);
}
void nmod_mpolyn_interp_lift_lg_poly(
slong * lastdeg_,
nmod_mpolyn_t A,
const nmod_mpoly_ctx_t ctx,
const fq_nmod_poly_t B,
const fq_nmod_ctx_t fqctx)
{
slong Bexp;
slong Blen = fq_nmod_poly_length(B, fqctx);
fq_nmod_struct * Bcoeff = B->coeffs;
n_poly_struct * Acoeff;
ulong * Aexp;
slong Ai;
slong lastdeg = -WORD(1);
slong N, off, shift;
N = mpoly_words_per_exp_sp(A->bits, ctx->minfo);
mpoly_gen_offset_shift_sp(&off, &shift, 0, A->bits, ctx->minfo);
nmod_mpolyn_fit_length(A, Blen, ctx);
Acoeff = A->coeffs;
Aexp = A->exps;
Ai = 0;
for (Bexp = Blen - 1; Bexp >= 0; Bexp--)
{
if (!fq_nmod_is_zero(Bcoeff + Bexp, fqctx))
{
FLINT_ASSERT(Ai < A->alloc);
n_poly_set_nmod_poly(Acoeff + Ai, Bcoeff + Bexp);
lastdeg = FLINT_MAX(lastdeg, n_poly_degree(Acoeff + Ai));
mpoly_monomial_zero(Aexp + N*Ai, N);
(Aexp + N*Ai)[off] = Bexp << shift;
Ai++;
}
}
A->length = Ai;
*lastdeg_ = lastdeg;
}
int nmod_mpolyn_interp_crt_lg_poly(
slong * lastdeg_,
nmod_mpolyn_t F,
nmod_mpolyn_t T,
n_poly_t modulus,
const nmod_mpoly_ctx_t ctx,
fq_nmod_poly_t A,
const fq_nmod_ctx_t fqctx)
{
int changed = 0;
slong lastdeg = -WORD(1);
fq_nmod_t u, v;
n_poly_t w;
slong Fi, Ti, Aexp;
fq_nmod_struct * Acoeff = A->coeffs;
slong Flen = F->length;
n_poly_struct * Fcoeffs = F->coeffs;
ulong * Fexps = F->exps;
n_poly_struct * Tcoeffs;
ulong * Texps;
fq_nmod_t inv_m_eval;
slong N, off, shift;
FLINT_ASSERT(T->bits == F->bits);
N = mpoly_words_per_exp_sp(F->bits, ctx->minfo);
mpoly_gen_offset_shift_sp(&off, &shift, 0, F->bits, ctx->minfo);
fq_nmod_init(inv_m_eval, fqctx);
n_poly_mod_rem(evil_cast_nmod_poly_to_n_poly(inv_m_eval), modulus,
evil_const_cast_nmod_poly_to_n_poly(fqctx->modulus), ctx->mod);
fq_nmod_inv(inv_m_eval, inv_m_eval, fqctx);
Fi = 0;
fq_nmod_init(u, fqctx);
fq_nmod_init(v, fqctx);
n_poly_init(w);
Aexp = fq_nmod_poly_degree(A, fqctx);
nmod_mpolyn_fit_length(T, Flen + Aexp + 1, ctx);
Tcoeffs = T->coeffs;
Texps = T->exps;
Ti = 0;
while (Fi < Flen || Aexp >= 0)
{
FLINT_ASSERT(Ti < T->alloc);
if (Fi < Flen)
{
FLINT_ASSERT(!n_poly_is_zero(Fcoeffs + Fi));
FLINT_ASSERT(n_poly_degree(Fcoeffs + Fi) < n_poly_degree(modulus));
}
if (Aexp >= 0)
{
FLINT_ASSERT(!fq_nmod_is_zero(Acoeff + Aexp, fqctx));
}
mpoly_monomial_zero(Texps + N*Ti, N);
if (Fi < Flen && Aexp >= 0 && ((Fexps + N*Fi)[off]>>shift) == (ulong) Aexp)
{
n_poly_mod_rem(evil_cast_nmod_poly_to_n_poly(u), Fcoeffs + Fi,
evil_const_cast_nmod_poly_to_n_poly(fqctx->modulus), ctx->mod);
fq_nmod_sub(v, Acoeff + Aexp, u, fqctx);
if (!fq_nmod_is_zero(v, fqctx))
{
changed = 1;
fq_nmod_mul(u, v, inv_m_eval, fqctx);
n_poly_mod_mul(w, modulus, evil_cast_nmod_poly_to_n_poly(u), ctx->mod);
n_poly_mod_add(Tcoeffs + Ti, Fcoeffs + Fi, w, ctx->mod);
}
else
{
n_poly_set(Tcoeffs + Ti, Fcoeffs + Fi);
}
(Texps + N*Ti)[off] = (Fexps + N*Fi)[off];
Fi++;
do {
Aexp--;
} while (Aexp >= 0 && fq_nmod_is_zero(Acoeff + Aexp, fqctx));
}
else if (Fi < Flen && (Aexp < 0 || ((Fexps + N*Fi)[off]>>shift) > (ulong) Aexp))
{
n_poly_mod_rem(evil_cast_nmod_poly_to_n_poly(v), Fcoeffs + Fi,
evil_const_cast_nmod_poly_to_n_poly(fqctx->modulus), ctx->mod);
if (!fq_nmod_is_zero(v, fqctx))
{
changed = 1;
fq_nmod_mul(u, v, inv_m_eval, fqctx);
n_poly_mod_mul(w, evil_const_cast_nmod_poly_to_n_poly(u), modulus, ctx->mod);
n_poly_mod_sub(Tcoeffs + Ti, Fcoeffs + Fi, w, ctx->mod);
}
else
{
n_poly_set(Tcoeffs + Ti, Fcoeffs + Fi);
}
(Texps + N*Ti)[off] = (Fexps + N*Fi)[off];
Fi++;
}
else if (Aexp >= 0 && (Fi >= Flen || ((Fexps + N*Fi)[off]>>shift) < (ulong) Aexp))
{
changed = 1;
fq_nmod_mul(u, Acoeff + Aexp, inv_m_eval, fqctx);
n_poly_mod_mul(Tcoeffs + Ti, modulus,
evil_const_cast_nmod_poly_to_n_poly(u), ctx->mod);
(Texps + N*Ti)[off] = Aexp << shift;
do {
Aexp--;
} while (Aexp >= 0 && fq_nmod_is_zero(Acoeff + Aexp, fqctx));
}
else
{
FLINT_ASSERT(0);
}
FLINT_ASSERT(!n_poly_is_zero(Tcoeffs + Ti));
lastdeg = FLINT_MAX(lastdeg, n_poly_degree(Tcoeffs + Ti));
Ti++;
}
T->length = Ti;
if (changed)
{
nmod_mpolyn_swap(T, F);
}
fq_nmod_clear(u, fqctx);
fq_nmod_clear(v, fqctx);
n_poly_clear(w);
fq_nmod_clear(inv_m_eval, fqctx);
*lastdeg_ = lastdeg;
return changed;
}
void nmod_mpolyn_interp_lift_lg_bpoly(
slong * lastdeg_,
nmod_mpolyn_t F,
const nmod_mpoly_ctx_t smctx,
n_fq_bpoly_t A,
const fq_nmod_mpoly_ctx_t lgctx)
{
slong lgd = fq_nmod_ctx_degree(lgctx->fqctx);
slong N = mpoly_words_per_exp_sp(F->bits, smctx->minfo);
slong i, j, Fi;
slong lastdeg = -WORD(1);
slong off0, shift0, off1, shift1;
mpoly_gen_offset_shift_sp(&off0, &shift0, 0, F->bits, smctx->minfo);
mpoly_gen_offset_shift_sp(&off1, &shift1, 1, F->bits, smctx->minfo);
Fi = 0;
for (i = A->length - 1; i >= 0; i--)
{
n_fq_poly_struct * Ai = A->coeffs + i;
for (j = Ai->length - 1; j >= 0; j--)
{
if (_n_fq_is_zero(Ai->coeffs + lgd*j, lgd))
continue;
nmod_mpolyn_fit_length(F, Fi + 1, smctx);
mpoly_monomial_zero(F->exps + N*Fi, N);
(F->exps + N*Fi)[off0] += (i << shift0);
(F->exps + N*Fi)[off1] += (j << shift1);
n_fq_get_n_poly(F->coeffs + Fi, Ai->coeffs + lgd*j, lgctx->fqctx);
lastdeg = FLINT_MAX(lastdeg, n_poly_degree(F->coeffs + Fi));
Fi++;
}
}
F->length = Fi;
*lastdeg_ = lastdeg;
}
int nmod_mpolyn_interp_crt_lg_bpoly(
slong * lastdeg,
nmod_mpolyn_t F,
nmod_mpolyn_t T,
n_fq_poly_t modulus,
const nmod_mpoly_ctx_t smctx,
n_fq_bpoly_t A,
const fq_nmod_mpoly_ctx_t lgctx)
{
slong lgd = fq_nmod_ctx_degree(lgctx->fqctx);
int changed = 0;
slong N = mpoly_words_per_exp(T->bits, smctx->minfo);
slong off0, shift0, off1, shift1;
n_fq_poly_struct * Acoeffs = A->coeffs;
slong Fi, Ti, Ai, ai;
slong Flen = F->length;
ulong * Fexps = F->exps;
n_poly_struct * Fcoeffs = F->coeffs;
ulong * Texps = T->exps;
n_poly_struct * Tcoeffs = T->coeffs;
ulong * u = FLINT_ARRAY_ALLOC(3*lgd, ulong);
ulong * v = u + lgd;
ulong * inv_m_eval = v + lgd;
ulong Fexpi, mask;
mask = (-UWORD(1)) >> (FLINT_BITS - F->bits);
mpoly_gen_offset_shift_sp(&off0, &shift0, 0, F->bits, smctx->minfo);
mpoly_gen_offset_shift_sp(&off1, &shift1, 1, F->bits, smctx->minfo);
_n_fq_set_n_poly(u, modulus->coeffs, modulus->length, lgctx->fqctx);
n_fq_inv(inv_m_eval, u, lgctx->fqctx);
FLINT_ASSERT(nmod_mpolyn_is_canonical(F, smctx));
FLINT_ASSERT(n_fq_bpoly_is_canonical(A, lgctx->fqctx));
FLINT_ASSERT(T->bits == F->bits);
*lastdeg = -1;
Ti = Fi = 0;
Ai = A->length - 1;
ai = (Ai < 0) ? 0 : n_fq_poly_degree(Acoeffs + Ai);
while (Fi < Flen || Ai >= 0)
{
if (Ti >= T->alloc)
{
slong extra = FLINT_MAX(Flen - Fi, Ai);
nmod_mpolyn_fit_length(T, Ti + extra + 1, smctx);
Tcoeffs = T->coeffs;
Texps = T->exps;
}
if (Fi < Flen)
{
Fexpi = pack_exp2(((Fexps + N*Fi)[off0]>>shift0)&mask,
((Fexps + N*Fi)[off1]>>shift1)&mask);
}
else
{
Fexpi = 0;
}
if (Fi < Flen && Ai >= 0 && Fexpi == pack_exp2(Ai, ai))
{
mpoly_monomial_set(Texps + N*Ti, Fexps + N*Fi, N);
_n_fq_set_n_poly(u, Fcoeffs[Fi].coeffs, Fcoeffs[Fi].length, lgctx->fqctx);
n_fq_sub(v, Acoeffs[Ai].coeffs + lgd*ai, u, lgctx->fqctx);
if (!_n_fq_is_zero(v, lgd))
{
changed = 1;
n_fq_mul(u, v, inv_m_eval, lgctx->fqctx);
_n_poly_mul_n_fq(Tcoeffs + Ti, modulus, u, lgctx->fqctx);
n_poly_mod_add(Tcoeffs + Ti, Tcoeffs + Ti, Fcoeffs + Fi, smctx->mod);
}
else
{
n_poly_set(Tcoeffs + Ti, Fcoeffs + Fi);
}
Fi++;
do {
ai--;
} while (ai >= 0 && _n_fq_is_zero(Acoeffs[Ai].coeffs + lgd*ai, lgd));
if (ai < 0)
{
do {
Ai--;
} while (Ai >= 0 && Acoeffs[Ai].length == 0);
if (Ai >= 0)
ai = n_fq_poly_degree(Acoeffs + Ai);
}
}
else if (Fi < Flen && (Ai < 0 || Fexpi > pack_exp2(Ai, ai)))
{
mpoly_monomial_set(Texps + N*Ti, Fexps + N*Fi, N);
_n_fq_set_n_poly(v, Fcoeffs[Fi].coeffs, Fcoeffs[Fi].length, lgctx->fqctx);
if (!_n_fq_is_zero(v, lgd))
{
changed = 1;
n_fq_mul(u, v, inv_m_eval, lgctx->fqctx);
_n_poly_mul_n_fq(Tcoeffs + Ti, modulus, u, lgctx->fqctx);
n_poly_mod_sub(Tcoeffs + Ti, Fcoeffs + Fi, Tcoeffs + Ti, smctx->mod);
}
else
{
n_poly_set(Tcoeffs + Ti, Fcoeffs + Fi);
}
Fi++;
}
else
{
FLINT_ASSERT(Ai >= 0 && (Fi >= Flen || Fexpi < pack_exp2(Ai, ai)));
mpoly_monomial_zero(Texps + N*Ti, N);
(Texps + N*Ti)[off0] += (Ai << shift0);
(Texps + N*Ti)[off1] += (ai << shift1);
changed = 1;
n_fq_mul(u, Acoeffs[Ai].coeffs + lgd*ai, inv_m_eval, lgctx->fqctx);
_n_poly_mul_n_fq(Tcoeffs + Ti, modulus, u, lgctx->fqctx);
do {
ai--;
} while (ai >= 0 && _n_fq_is_zero(Acoeffs[Ai].coeffs + lgd*ai, lgd));
if (ai < 0)
{
do {
Ai--;
} while (Ai >= 0 && Acoeffs[Ai].length == 0);
if (Ai >= 0)
ai = n_fq_poly_degree(Acoeffs + Ai);
}
}
FLINT_ASSERT(!n_poly_is_zero(Tcoeffs + Ti));
*lastdeg = FLINT_MAX(*lastdeg, n_poly_degree(Tcoeffs + Ti));
Ti++;
}
T->length = Ti;
if (changed)
nmod_mpolyn_swap(T, F);
FLINT_ASSERT(nmod_mpolyn_is_canonical(F, smctx));
flint_free(u);
return changed;
}
void nmod_mpolyn_interp_reduce_lg_mpolyn(
fq_nmod_mpolyn_t E,
fq_nmod_mpoly_ctx_t ectx,
nmod_mpolyn_t A,
slong var,
const nmod_mpoly_ctx_t ctx)
{
slong N = mpoly_words_per_exp_sp(A->bits, ctx->minfo);
slong offset, shift, k;
ulong mask;
fq_nmod_t v;
n_poly_struct * Acoeff = A->coeffs;
ulong * Aexp = A->exps;
slong Alen = A->length;
slong Ai;
n_poly_struct * Ecoeff;
ulong * Eexp;
slong Ei;
fq_nmod_init(v, ectx->fqctx);
FLINT_ASSERT(var > 0);
mpoly_gen_offset_shift_sp(&offset, &shift, var - 1, A->bits, ctx->minfo);
mask = (-UWORD(1)) >> (FLINT_BITS - A->bits);
Ecoeff = E->coeffs;
Eexp = E->exps;
Ei = 0;
for (Ai = 0; Ai < Alen; Ai++)
{
n_poly_mod_rem(evil_cast_nmod_poly_to_n_poly(v), Acoeff + Ai,
evil_const_cast_nmod_poly_to_n_poly(ectx->fqctx->modulus), ctx->mod);
k = ((Aexp + N*Ai)[offset] >> shift) & mask;
if (fq_nmod_is_zero(v, ectx->fqctx))
{
continue;
}
if (Ei > 0 && mpoly_monomial_equal_extra(Eexp + N*(Ei - 1), Aexp + N*Ai, N, offset, -(k << shift)))
{
n_fq_poly_set_coeff_fq_nmod(Ecoeff + Ei - 1, k, v, ectx->fqctx);
}
else
{
FLINT_ASSERT(Ei == 0 || mpoly_monomial_gt_nomask_extra(Eexp + N*(Ei - 1), Aexp + N*Ai, N, offset, -(k << shift)));
if (Ei >= E->alloc)
{
fq_nmod_mpolyn_fit_length(E, Ei + 1, ectx);
Ecoeff = E->coeffs;
Eexp = E->exps;
}
mpoly_monomial_set_extra(Eexp + N*Ei, Aexp + N*Ai, N, offset, -(k << shift));
n_poly_zero(Ecoeff + Ei);
n_fq_poly_set_coeff_fq_nmod(Ecoeff + Ei, k, v, ectx->fqctx);
Ei++;
}
}
E->length = Ei;
fq_nmod_clear(v, ectx->fqctx);
}
void nmod_mpolyn_interp_lift_lg_mpolyn(
slong * lastdeg_,
nmod_mpolyn_t A,
slong var,
const nmod_mpoly_ctx_t ctx,
fq_nmod_mpolyn_t B,
const fq_nmod_mpoly_ctx_t ectx)
{
slong d = fq_nmod_ctx_degree(ectx->fqctx);
slong N = mpoly_words_per_exp_sp(B->bits, ctx->minfo);
slong offset, shift;
slong vi;
n_fq_poly_struct * Bcoeff = B->coeffs;
ulong * Bexp = B->exps;
slong Blen = B->length;
slong Bi;
n_poly_struct * Acoeff;
ulong * Aexp;
slong Ai;
slong lastdeg = -WORD(1);
FLINT_ASSERT(A->bits == B->bits);
nmod_mpolyn_fit_length(A, Blen, ctx);
Acoeff = A->coeffs;
Aexp = A->exps;
mpoly_gen_offset_shift_sp(&offset, &shift, var - 1, A->bits, ctx->minfo);
Ai = 0;
for (Bi = 0; Bi < Blen; Bi++)
{
if (Ai + (Bcoeff + Bi)->length >= A->alloc)
{
nmod_mpolyn_fit_length(A, Ai + (Bcoeff + Bi)->length, ctx);
Acoeff = A->coeffs;
Aexp = A->exps;
}
for (vi = (Bcoeff + Bi)->length - 1; vi >= 0; vi--)
{
if (!_n_fq_is_zero((Bcoeff + Bi)->coeffs + d*vi, d))
{
mpoly_monomial_set_extra(Aexp + N*Ai, Bexp + N*Bi, N, offset, vi << shift);
n_fq_get_n_poly(Acoeff + Ai, (Bcoeff + Bi)->coeffs + d*vi, ectx->fqctx);
lastdeg = FLINT_MAX(lastdeg, n_poly_degree(Acoeff + Ai));
Ai++;
}
}
}
A->length = Ai;
*lastdeg_ = lastdeg;
}
int nmod_mpolyn_interp_crt_lg_mpolyn(
slong * lastdeg_,
nmod_mpolyn_t F,
nmod_mpolyn_t T,
n_poly_t modulus,
slong var,
const nmod_mpoly_ctx_t ctx,
fq_nmod_mpolyn_t A,
const fq_nmod_mpoly_ctx_t ectx)
{
slong d = fq_nmod_ctx_degree(ectx->fqctx);
int changed = 0;
slong N = mpoly_words_per_exp_sp(A->bits, ctx->minfo);
slong offset, shift;
slong lastdeg = -WORD(1);
slong vi;
fq_nmod_t u, v;
n_poly_t w;
n_poly_struct * Tcoeff;
ulong * Texp;
slong Ti;
n_fq_poly_struct * Acoeff = A->coeffs;
slong Alen = A->length;
ulong * Aexp = A->exps;
slong Ai;
n_poly_struct * Fcoeff = F->coeffs;
slong Flen = F->length;
ulong * Fexp = F->exps;
slong Fi;
fq_nmod_t inv_m_eval;
fq_nmod_t at;
fq_nmod_init(inv_m_eval, ectx->fqctx);
n_poly_mod_rem(evil_cast_nmod_poly_to_n_poly(inv_m_eval), modulus,
evil_const_cast_nmod_poly_to_n_poly(ectx->fqctx->modulus), ctx->mod);
fq_nmod_inv(inv_m_eval, inv_m_eval, ectx->fqctx);
fq_nmod_init(at, ectx->fqctx);
fq_nmod_init(u, ectx->fqctx);
fq_nmod_init(v, ectx->fqctx);
n_poly_init(w);
FLINT_ASSERT(var > 0);
FLINT_ASSERT(T->bits == A->bits);
FLINT_ASSERT(F->bits == A->bits);
mpoly_gen_offset_shift_sp(&offset, &shift, var - 1, A->bits, ctx->minfo);
Flen = F->length;
nmod_mpolyn_fit_length(T, FLINT_MAX(Flen, Alen), ctx);
Tcoeff = T->coeffs;
Texp = T->exps;
Ti = 0;
Fi = Ai = vi = 0;
if (Ai < Alen)
{
vi = n_poly_degree(A->coeffs + Ai);
}
while (Fi < Flen || Ai < Alen)
{
if (Ti >= T->alloc)
{
nmod_mpolyn_fit_length(T, Ti + FLINT_MAX(Flen - Fi, Alen - Ai), ctx);
Tcoeff = T->coeffs;
Texp = T->exps;
}
if (Fi < Flen && Ai < Alen && mpoly_monomial_equal_extra(Fexp + N*Fi, Aexp + N*Ai, N, offset, vi << shift))
{
n_poly_mod_rem(evil_cast_nmod_poly_to_n_poly(u), Fcoeff + Fi,
evil_const_cast_nmod_poly_to_n_poly(ectx->fqctx->modulus), ctx->mod);
n_fq_get_fq_nmod(at, Acoeff[Ai].coeffs + d*vi, ectx->fqctx);
fq_nmod_sub(v, at, u, ectx->fqctx);
if (!fq_nmod_is_zero(v, ectx->fqctx))
{
changed = 1;
fq_nmod_mul(u, v, inv_m_eval, ectx->fqctx);
n_poly_mod_mul(w, modulus,
evil_const_cast_nmod_poly_to_n_poly(u), ctx->mod);
n_poly_mod_add(Tcoeff + Ti, Fcoeff + Fi, w, ctx->mod);
}
else
{
n_poly_set(Tcoeff + Ti, Fcoeff + Fi);
}
mpoly_monomial_set(Texp + N*Ti, Fexp + N*Fi, N);
Fi++;
do {
vi--;
} while (vi >= 0 && _n_fq_is_zero(Acoeff[Ai].coeffs + d*vi, d));
if (vi < 0)
{
Ai++;
if (Ai < Alen)
{
vi = n_poly_degree(A->coeffs + Ai);
}
}
}
else if (Fi < Flen && (Ai >= Alen || mpoly_monomial_gt_nomask_extra(Fexp + N*Fi, Aexp + N*Ai, N, offset, vi << shift)))
{
n_poly_mod_rem(evil_cast_nmod_poly_to_n_poly(v), Fcoeff + Fi,
evil_const_cast_nmod_poly_to_n_poly(ectx->fqctx->modulus), ctx->mod);
if (!fq_nmod_is_zero(v, ectx->fqctx))
{
changed = 1;
fq_nmod_mul(u, v, inv_m_eval, ectx->fqctx);
n_poly_mod_mul(w, evil_const_cast_nmod_poly_to_n_poly(u),
modulus, ctx->mod);
n_poly_mod_sub(Tcoeff + Ti, Fcoeff + Fi, w, ctx->mod);
}
else
{
n_poly_set(Tcoeff + Ti, Fcoeff + Fi);
}
mpoly_monomial_set(Texp + N*Ti, Fexp + N*Fi, N);
Fi++;
}
else
{
FLINT_ASSERT(Ai < Alen && (Fi >= Flen || mpoly_monomial_lt_nomask_extra(Fexp + N*Fi, Aexp + N*Ai, N, offset, vi << shift)));
changed = 1;
n_fq_get_fq_nmod(at, Acoeff[Ai].coeffs + d*vi, ectx->fqctx);
fq_nmod_mul(u, at, inv_m_eval, ectx->fqctx);
n_poly_mod_mul(Tcoeff + Ti, evil_const_cast_nmod_poly_to_n_poly(u),
modulus, ctx->mod);
mpoly_monomial_set_extra(Texp + N*Ti, Aexp + N*Ai, N, offset, vi << shift);
do {
vi--;
} while (vi >= 0 && _n_fq_is_zero(Acoeff[Ai].coeffs + d*vi, d));
if (vi < 0)
{
Ai++;
if (Ai < Alen)
{
vi = n_poly_degree(A->coeffs + Ai);
}
}
}
FLINT_ASSERT(!n_poly_is_zero(Tcoeff + Ti));
lastdeg = FLINT_MAX(lastdeg, n_poly_degree(Tcoeff + Ti));
Ti++;
}
T->length = Ti;
if (changed)
{
nmod_mpolyn_swap(T, F);
}
fq_nmod_clear(inv_m_eval, ectx->fqctx);
fq_nmod_clear(u, ectx->fqctx);
fq_nmod_clear(v, ectx->fqctx);
fq_nmod_clear(at, ectx->fqctx);
n_poly_clear(w);
FLINT_ASSERT(nmod_mpolyn_is_canonical(F, ctx));
*lastdeg_ = lastdeg;
return changed;
}
void nmod_mpolyn_interp_reduce_lg_mpoly(
fq_nmod_mpoly_t A,
nmod_mpolyn_t B,
const fq_nmod_mpoly_ctx_t ffctx,
const nmod_mpoly_ctx_t ctx)
{
slong d = fq_nmod_ctx_degree(ffctx->fqctx);
slong N = N = mpoly_words_per_exp(B->bits, ctx->minfo);
slong i, Alen;
FLINT_ASSERT(A->bits == B->bits);
FLINT_ASSERT(B->bits <= FLINT_BITS);
FLINT_ASSERT(ctx->minfo->ord == ORD_LEX);
FLINT_ASSERT(ffctx->minfo->ord == ORD_LEX);
FLINT_ASSERT(ffctx->minfo->nvars == ctx->minfo->nvars);
Alen = 0;
fq_nmod_mpoly_fit_length(A, B->length, ffctx);
for (i = 0; i < B->length; i++)
{
mpoly_monomial_set(A->exps + N*Alen, B->exps + N*i, N);
if (B->coeffs[i].length > d)
{
_nmod_poly_rem(A->coeffs + d*Alen, B->coeffs[i].coeffs,
B->coeffs[i].length, ffctx->fqctx->modulus->coeffs, d + 1,
fq_nmod_ctx_mod(ffctx->fqctx));
}
else
{
_n_fq_set_n_poly(A->coeffs + d*Alen, B->coeffs[i].coeffs,
B->coeffs[i].length, ffctx->fqctx);
}
Alen += !_n_fq_is_zero(A->coeffs + d*Alen, d);
}
A->length = Alen;
}
void nmod_mpolyun_interp_reduce_lg_mpolyu(
fq_nmod_mpolyu_t A,
nmod_mpolyun_t B,
const fq_nmod_mpoly_ctx_t ffctx,
const nmod_mpoly_ctx_t ctx)
{
slong i, k, Blen;
fq_nmod_mpoly_struct * Acoeff;
nmod_mpolyn_struct * Bcoeff;
ulong * Aexp, * Bexp;
Blen = B->length;
fq_nmod_mpolyu_fit_length(A, Blen, ffctx);
Acoeff = A->coeffs;
Bcoeff = B->coeffs;
Aexp = A->exps;
Bexp = B->exps;
k = 0;
for (i = 0; i < Blen; i++)
{
nmod_mpolyn_interp_reduce_lg_mpoly(Acoeff + k, Bcoeff + i, ffctx, ctx);
Aexp[k] = Bexp[i];
k += !fq_nmod_mpoly_is_zero(Acoeff + k, ffctx);
}
A->length = k;
}
void nmod_mpolyn_interp_lift_lg_mpoly(
nmod_mpolyn_t A,
const nmod_mpoly_ctx_t ctx,
fq_nmod_mpoly_t Ap,
const fq_nmod_mpoly_ctx_t ctxp)
{
slong d = fq_nmod_ctx_degree(ctxp->fqctx);
slong i, N;
FLINT_ASSERT(Ap->bits == A->bits);
nmod_mpolyn_fit_length(A, Ap->length, ctx);
N = mpoly_words_per_exp(A->bits, ctx->minfo);
for (i = 0; i < Ap->length; i++)
{
mpoly_monomial_set(A->exps + N*i, Ap->exps + N*i, N);
n_fq_get_n_poly(A->coeffs + i, Ap->coeffs + d*i, ctxp->fqctx);
}
A->length = Ap->length;
}
void nmod_mpolyun_interp_lift_lg_mpolyu(
nmod_mpolyun_t A,
const nmod_mpoly_ctx_t ctx,
fq_nmod_mpolyu_t Ap,
const fq_nmod_mpoly_ctx_t ctxp)
{
slong i;
FLINT_ASSERT(Ap->bits == A->bits);
nmod_mpolyun_fit_length(A, Ap->length, ctx);
for (i = 0; i < Ap->length; i++)
{
A->exps[i] = Ap->exps[i];
nmod_mpolyn_interp_lift_lg_mpoly(A->coeffs + i, ctx, Ap->coeffs + i, ctxp);
}
A->length = Ap->length;
}
static int nmod_mpolyn_interp_crt_lg_mpoly(
slong * lastdeg,
nmod_mpolyn_t F,
nmod_mpolyn_t T,
n_poly_t m,
const nmod_mpoly_ctx_t ctx,
fq_nmod_mpoly_t A,
fq_nmod_t inv_m_eval,
const fq_nmod_mpoly_ctx_t ffctx)
{
slong d = fq_nmod_ctx_degree(ffctx->fqctx);
int changed = 0;
slong i, j, k;
slong N;
fq_nmod_t u, v;
n_poly_t w;
flint_bitcnt_t bits = A->bits;
slong Flen = F->length, Alen = A->length;
ulong * Fexp = F->exps, * Aexp = A->exps;
ulong * Texp;
ulong * Acoeff = A->coeffs;
n_poly_struct * Fcoeff = F->coeffs;
n_poly_struct * Tcoeff;
fq_nmod_t at;
FLINT_ASSERT(F->bits == bits);
FLINT_ASSERT(ctx->minfo->ord == ORD_LEX);
fq_nmod_init(u, ffctx->fqctx);
fq_nmod_init(v, ffctx->fqctx);
n_poly_init(w);
fq_nmod_init(at, ffctx->fqctx);
nmod_mpolyn_fit_length(T, Flen + Alen, ctx);
Texp = T->exps;
Tcoeff = T->coeffs;
N = mpoly_words_per_exp(bits, ctx->minfo);
i = j = k = 0;
while (i < Flen || j < Alen)
{
if (i < Flen && (j >= Alen
|| mpoly_monomial_gt_nomask(Fexp + N*i, Aexp + N*j, N)))
{
FLINT_ASSERT(!n_poly_is_zero(Fcoeff + i));
FLINT_ASSERT(n_poly_degree(Fcoeff + i) < n_poly_degree(m));
n_poly_mod_rem(evil_cast_nmod_poly_to_n_poly(v), Fcoeff + i,
evil_const_cast_nmod_poly_to_n_poly(ffctx->fqctx->modulus), ctx->mod);
if (!fq_nmod_is_zero(v, ffctx->fqctx))
{
changed = 1;
fq_nmod_mul(u, v, inv_m_eval, ffctx->fqctx);
n_poly_mod_mul(w, evil_const_cast_nmod_poly_to_n_poly(u),
m, ctx->mod);
n_poly_mod_sub(Tcoeff + k, Fcoeff + i, w, ctx->mod);
} else {
n_poly_set(Tcoeff + k, Fcoeff + i);
}
FLINT_ASSERT(!n_poly_is_zero(Tcoeff + k));
*lastdeg = FLINT_MAX(*lastdeg, n_poly_degree(Tcoeff + k));
mpoly_monomial_set(Texp + N*k, Fexp + N*i, N);
k++;
i++;
}
else if (j < Alen && (i >= Flen
|| mpoly_monomial_lt_nomask(Fexp + N*i, Aexp + N*j, N)))
{
if (!_n_fq_is_zero(Acoeff + d*j, d))
{
changed = 1;
n_fq_get_fq_nmod(at, Acoeff + d*j, ffctx->fqctx);
fq_nmod_mul(u, at, inv_m_eval, ffctx->fqctx);
n_poly_mod_mul(Tcoeff + k, m,
evil_const_cast_nmod_poly_to_n_poly(u), ctx->mod);
*lastdeg = FLINT_MAX(*lastdeg, n_poly_degree(Tcoeff + k));
mpoly_monomial_set(Texp + N*k, Aexp + N*j, N);
k++;
}
j++;
}
else if (i < Flen && j < Alen
&& mpoly_monomial_equal(Fexp + N*i, Aexp + N*j, N))
{
FLINT_ASSERT(!n_poly_is_zero(Fcoeff + i));
FLINT_ASSERT(n_poly_degree(Fcoeff + i) < n_poly_degree(m));
n_poly_mod_rem(evil_cast_nmod_poly_to_n_poly(u), Fcoeff + i,
evil_const_cast_nmod_poly_to_n_poly(ffctx->fqctx->modulus), ctx->mod);
n_fq_get_fq_nmod(at, Acoeff + d*j, ffctx->fqctx);
fq_nmod_sub(v, at, u, ffctx->fqctx);
if (!fq_nmod_is_zero(v, ffctx->fqctx))
{
changed = 1;
fq_nmod_mul(u, v, inv_m_eval, ffctx->fqctx);
n_poly_mod_mul(w, m, evil_const_cast_nmod_poly_to_n_poly(u), ctx->mod);
n_poly_mod_add(Tcoeff + k, Fcoeff + i, w, ctx->mod);
} else {
n_poly_set(Tcoeff + k, Fcoeff + i);
}
FLINT_ASSERT(!n_poly_is_zero(Tcoeff + k));
*lastdeg = FLINT_MAX(*lastdeg, n_poly_degree(Tcoeff + k));
mpoly_monomial_set(Texp + N*k, Aexp + N*j, N);
k++;
i++;
j++;
}
else
{
FLINT_ASSERT(0);
}
}
nmod_mpolyn_set_length(T, k, ctx);
if (changed)
{
nmod_mpolyn_swap(T, F);
}
fq_nmod_clear(u, ffctx->fqctx);
fq_nmod_clear(v, ffctx->fqctx);
n_poly_clear(w);
fq_nmod_clear(at, ffctx->fqctx);
return changed;
}
int nmod_mpolyun_interp_crt_lg_mpolyu(
slong * lastdeg,
nmod_mpolyun_t F,
nmod_mpolyun_t T,
n_poly_t m,
const nmod_mpoly_ctx_t ctx,
fq_nmod_mpolyu_t A,
const fq_nmod_mpoly_ctx_t ffctx)
{
int changed = 0;
slong i, j, k;
ulong * Texp;
ulong * Fexp;
ulong * Aexp;
slong Flen;
slong Alen;
nmod_mpolyn_t S;
nmod_mpolyn_struct * Tcoeff;
nmod_mpolyn_struct * Fcoeff;
fq_nmod_mpoly_struct * Acoeff;
fq_nmod_mpoly_t zero;
fq_nmod_t inv_m_eval;
*lastdeg = -WORD(1);
FLINT_ASSERT(F->bits == T->bits);
FLINT_ASSERT(T->bits == A->bits);
nmod_mpolyn_init(S, F->bits, ctx);
Flen = F->length;
Alen = A->length;
nmod_mpolyun_fit_length(T, Flen + Alen, ctx);
Tcoeff = T->coeffs;
Fcoeff = F->coeffs;
Acoeff = A->coeffs;
Texp = T->exps;
Fexp = F->exps;
Aexp = A->exps;
fq_nmod_mpoly_init(zero, ffctx);
fq_nmod_mpoly_fit_length_reset_bits(zero, 0, A->bits, ffctx);
fq_nmod_init(inv_m_eval, ffctx->fqctx);
n_poly_mod_rem(evil_cast_nmod_poly_to_n_poly(inv_m_eval), m,
evil_const_cast_nmod_poly_to_n_poly(ffctx->fqctx->modulus), ctx->mod);
fq_nmod_inv(inv_m_eval, inv_m_eval, ffctx->fqctx);
i = j = k = 0;
while (i < Flen || j < Alen)
{
if (i < Flen && (j >= Alen || Fexp[i] > Aexp[j]))
{
nmod_mpolyn_set(Tcoeff + k, Fcoeff + i, ctx);
changed |= nmod_mpolyn_interp_crt_lg_mpoly(lastdeg, Tcoeff + k,
S, m, ctx, zero, inv_m_eval, ffctx);
Texp[k] = Fexp[i];
k++;
i++;
}
else if (j < Alen && (i >= Flen || Aexp[j] > Fexp[i]))
{
nmod_mpolyn_zero(Tcoeff + k, ctx);
changed |= nmod_mpolyn_interp_crt_lg_mpoly(lastdeg, Tcoeff + k,
S, m, ctx, Acoeff + j, inv_m_eval, ffctx);
Texp[k] = Aexp[j];
k++;
j++;
}
else if (i < Flen && j < Alen && (Fexp[i] == Aexp[j]))
{
nmod_mpolyn_set(Tcoeff + k, Fcoeff + i, ctx);
changed |= nmod_mpolyn_interp_crt_lg_mpoly(lastdeg, Tcoeff + k,
S, m, ctx, Acoeff + j, inv_m_eval, ffctx);
Texp[k] = Aexp[j];
FLINT_ASSERT(!nmod_mpolyn_is_zero(Tcoeff + k, ctx));
k++;
i++;
j++;
}
else
{
FLINT_ASSERT(0);
}
}
T->length = k;
if (changed)
{
nmod_mpolyun_swap(T, F);
}
fq_nmod_clear(inv_m_eval, ffctx->fqctx);
nmod_mpolyn_clear(S, ctx);
fq_nmod_mpoly_clear(zero, ffctx);
return changed;
}
int nmod_mpolyn_interp_mcrt_lg_mpoly(
slong * lastdeg_,
nmod_mpolyn_t H,
const nmod_mpoly_ctx_t smctx,
const n_poly_t m,
const ulong * inv_m_eval,
fq_nmod_mpoly_t A,
const fq_nmod_mpoly_ctx_t lgctx)
{
slong lastdeg = *lastdeg_;
slong i, lgd = fq_nmod_ctx_degree(lgctx->fqctx);
#if FLINT_WANT_ASSERT
slong N = mpoly_words_per_exp(A->bits, smctx->minfo);
#endif
int changed = 0;
ulong * u = FLINT_ARRAY_ALLOC(lgd, ulong);
n_poly_t w;
n_poly_init(w);
FLINT_ASSERT(H->length == A->length);
FLINT_ASSERT(H->bits == A->bits);
for (i = 0; i < A->length; i++)
{
FLINT_ASSERT(mpoly_monomial_equal(H->exps + N*i, A->exps + N*i, N));
_n_fq_set_n_poly(u, H->coeffs[i].coeffs, H->coeffs[i].length, lgctx->fqctx);
n_fq_sub(u, A->coeffs + lgd*i, u, lgctx->fqctx);
if (!_n_fq_is_zero(u, lgd))
{
changed = 1;
n_fq_mul(u, u, inv_m_eval, lgctx->fqctx);
_n_poly_mul_n_fq(w, m, u, lgctx->fqctx);
n_poly_mod_add(H->coeffs + i, H->coeffs + i, w, smctx->mod);
}
lastdeg = FLINT_MAX(lastdeg, n_poly_degree(H->coeffs + i));
FLINT_ASSERT(n_poly_degree(H->coeffs + i) < n_poly_degree(m) +
nmod_poly_degree(lgctx->fqctx->modulus));
}
*lastdeg_ = lastdeg;
flint_free(u);
n_poly_clear(w);
return changed;
}
static int nmod_mpolyn_CRT_fq_nmod_mpoly(
slong * lastdeg,
nmod_mpolyn_t H,
const nmod_mpoly_ctx_t ctx,
n_poly_t m,
fq_nmod_t inv_m_eval,
fq_nmod_mpoly_t A,
const fq_nmod_mpoly_ctx_t ctxp)
{
slong d = fq_nmod_ctx_degree(ctxp->fqctx);
slong i;
#if FLINT_WANT_ASSERT
slong N;
#endif
int changed = 0;
fq_nmod_t u, v, at;
n_poly_t w;
fq_nmod_init(u, ctxp->fqctx);
fq_nmod_init(v, ctxp->fqctx);
fq_nmod_init(at, ctxp->fqctx);
n_poly_init(w);
FLINT_ASSERT(H->length == A->length);
FLINT_ASSERT(H->bits == A->bits);
#if FLINT_WANT_ASSERT
N = mpoly_words_per_exp(A->bits, ctx->minfo);
#endif
for (i = 0; i < A->length; i++)
{
FLINT_ASSERT(mpoly_monomial_equal(H->exps + N*i, A->exps + N*i, N));
n_poly_mod_rem(evil_cast_nmod_poly_to_n_poly(u), H->coeffs + i,
evil_const_cast_nmod_poly_to_n_poly(ctxp->fqctx->modulus), ctx->mod);
n_fq_get_fq_nmod(at, A->coeffs + d*i, ctxp->fqctx);
fq_nmod_sub(v, at, u, ctxp->fqctx);
if (!fq_nmod_is_zero(v, ctxp->fqctx))
{
changed = 1;
fq_nmod_mul(u, v, inv_m_eval, ctxp->fqctx);
n_poly_mod_mul(w, evil_const_cast_nmod_poly_to_n_poly(u), m, ctx->mod);
n_poly_mod_add(H->coeffs + i, H->coeffs + i, w, ctx->mod);
}
*lastdeg = FLINT_MAX(*lastdeg, n_poly_degree(H->coeffs + i));
FLINT_ASSERT(n_poly_degree(H->coeffs + i) < n_poly_degree(m) +
nmod_poly_degree(ctxp->fqctx->modulus));
}
fq_nmod_clear(u, ctxp->fqctx);
fq_nmod_clear(v, ctxp->fqctx);
fq_nmod_clear(at, ctxp->fqctx);
n_poly_clear(w);
return changed;
}
int nmod_mpolyun_interp_mcrt_lg_mpolyu(
slong * lastdeg,
nmod_mpolyun_t H,
const nmod_mpoly_ctx_t ctx,
n_poly_t m,
fq_nmod_mpolyu_t A,
const fq_nmod_mpoly_ctx_t ctxp)
{
slong i;
int changed = 0;
fq_nmod_t inv_m_eval;
*lastdeg = -WORD(1);
fq_nmod_init(inv_m_eval, ctxp->fqctx);
n_poly_mod_rem(evil_cast_nmod_poly_to_n_poly(inv_m_eval), m,
evil_const_cast_nmod_poly_to_n_poly(ctxp->fqctx->modulus), ctx->mod);
fq_nmod_inv(inv_m_eval, inv_m_eval, ctxp->fqctx);
FLINT_ASSERT(H->bits == A->bits);
FLINT_ASSERT(H->length == A->length);
for (i = 0; i < A->length; i++)
{
FLINT_ASSERT(H->exps[i] == A->exps[i]);
changed |= nmod_mpolyn_CRT_fq_nmod_mpoly(lastdeg, H->coeffs + i, ctx, m,
inv_m_eval, A->coeffs + i, ctxp);
}
H->length = A->length;
fq_nmod_clear(inv_m_eval, ctxp->fqctx);
return changed;
}
void fq_nmod_mpolyn_interp_reduce_sm_poly(
fq_nmod_poly_t E,
const fq_nmod_mpolyn_t A,
const fq_nmod_t alpha,
const fq_nmod_mpoly_ctx_t ctx)
{
fq_nmod_t v;
slong Ai, Alen, k;
n_poly_struct * Acoeff;
ulong * Aexp;
slong N, off, shift;
N = mpoly_words_per_exp_sp(A->bits, ctx->minfo);
mpoly_gen_offset_shift_sp(&off, &shift, 0, A->bits, ctx->minfo);
fq_nmod_init(v, ctx->fqctx);
Acoeff = A->coeffs;
Aexp = A->exps;
Alen = A->length;
Ai = 0;
fq_nmod_poly_zero(E, ctx->fqctx);
for (Ai = 0; Ai < Alen; Ai++)
{
n_fq_poly_evaluate_fq_nmod(v, Acoeff + Ai, alpha, ctx->fqctx);
k = (Aexp + N*Ai)[off] >> shift;
fq_nmod_poly_set_coeff(E, k, v, ctx->fqctx);
}
fq_nmod_clear(v, ctx->fqctx);
}
void fq_nmod_mpolyn_interp_lift_sm_poly(
fq_nmod_mpolyn_t A,
const fq_nmod_poly_t B,
const fq_nmod_mpoly_ctx_t ctx)
{
slong Bi;
slong Blen = fq_nmod_poly_length(B, ctx->fqctx);
fq_nmod_struct * Bcoeff = B->coeffs;
n_poly_struct * Acoeff;
ulong * Aexp;
slong Ai;
slong N, off, shift;
N = mpoly_words_per_exp_sp(A->bits, ctx->minfo);
mpoly_gen_offset_shift_sp(&off, &shift, 0, A->bits, ctx->minfo);
fq_nmod_mpolyn_fit_length(A, Blen, ctx);
Acoeff = A->coeffs;
Aexp = A->exps;
Ai = 0;
for (Bi = Blen - 1; Bi >= 0; Bi--)
{
if (!fq_nmod_is_zero(Bcoeff + Bi, ctx->fqctx))
{
FLINT_ASSERT(Ai < A->alloc);
n_fq_poly_set_fq_nmod(Acoeff + Ai, Bcoeff + Bi, ctx->fqctx);
mpoly_monomial_zero(Aexp + N*Ai, N);
(Aexp + N*Ai)[off] = Bi << shift;
Ai++;
}
}
A->length = Ai;
}
int fq_nmod_mpolyn_interp_crt_sm_poly(
slong * lastdeg_,
fq_nmod_mpolyn_t F,
fq_nmod_mpolyn_t T,
const fq_nmod_poly_t A,
const fq_nmod_poly_t modulus,
const fq_nmod_t alpha,
const fq_nmod_mpoly_ctx_t ctx)
{
int changed = 0;
slong lastdeg = -WORD(1);
fq_nmod_t u, v;
slong Fi, Ti, Ai;
fq_nmod_struct * Acoeff = A->coeffs;
slong Flen = F->length;
n_poly_struct * Fcoeffs = F->coeffs;
ulong * Fexps = F->exps;
n_poly_struct * Tcoeffs;
ulong * Texps;
fq_nmod_poly_t tp;
slong N, off, shift;
n_poly_t tpt;
N = mpoly_words_per_exp_sp(F->bits, ctx->minfo);
mpoly_gen_offset_shift_sp(&off, &shift, 0, F->bits, ctx->minfo);
Fi = 0;
Ai = fq_nmod_poly_degree(A, ctx->fqctx);
fq_nmod_init(u, ctx->fqctx);
fq_nmod_init(v, ctx->fqctx);
fq_nmod_poly_init(tp, ctx->fqctx);
n_poly_init(tpt);
fq_nmod_mpolyn_fit_length(T, Flen + Ai + 1, ctx);
Tcoeffs = T->coeffs;
Texps = T->exps;
Ti = 0;
while (Fi < Flen || Ai >= 0)
{
FLINT_ASSERT(Ti < T->alloc);
if (Fi < Flen)
{
FLINT_ASSERT(!n_poly_is_zero(Fcoeffs + Fi));
FLINT_ASSERT(n_poly_degree(Fcoeffs + Fi) < fq_nmod_poly_degree(modulus, ctx->fqctx));
}
if (Ai >= 0)
{
FLINT_ASSERT(!fq_nmod_is_zero(Acoeff + Ai, ctx->fqctx));
}
mpoly_monomial_zero(Texps + N*Ti, N);
if (Fi < Flen && Ai >= 0 && ((Fexps + N*Fi)[off]>>shift) == (ulong) Ai)
{
n_fq_poly_evaluate_fq_nmod(u, Fcoeffs + Fi, alpha, ctx->fqctx);
fq_nmod_sub(v, Acoeff + Ai, u, ctx->fqctx);
if (!fq_nmod_is_zero(v, ctx->fqctx))
{
changed = 1;
fq_nmod_poly_scalar_mul_fq_nmod(tp, modulus, v, ctx->fqctx);
n_fq_poly_set_fq_nmod_poly(tpt, tp, ctx->fqctx);
n_fq_poly_add(Tcoeffs + Ti, Fcoeffs + Fi, tpt, ctx->fqctx);
}
else
{
n_fq_poly_set(Tcoeffs + Ti, Fcoeffs + Fi, ctx->fqctx);
}
(Texps + N*Ti)[off] = Ai << shift;
Fi++;
do {
Ai--;
} while (Ai >= 0 && fq_nmod_is_zero(Acoeff + Ai, ctx->fqctx));
}
else if (Fi < Flen && (Ai < 0 || ((Fexps + N*Fi)[off]>>shift) > (ulong) Ai))
{
n_fq_poly_evaluate_fq_nmod(v, Fcoeffs + Fi, alpha, ctx->fqctx);
if (!fq_nmod_is_zero(v, ctx->fqctx))
{
changed = 1;
fq_nmod_poly_scalar_mul_fq_nmod(tp, modulus, v, ctx->fqctx);
n_fq_poly_set_fq_nmod_poly(tpt, tp, ctx->fqctx);
n_fq_poly_sub(Tcoeffs + Ti, Fcoeffs + Fi, tpt, ctx->fqctx);
}
else
{
n_fq_poly_set(Tcoeffs + Ti, Fcoeffs + Fi, ctx->fqctx);
}
(Texps + N*Ti)[off] = (Fexps + N*Fi)[off];
Fi++;
}
else if (Ai >= 0 && (Fi >= Flen || ((Fexps + N*Fi)[off]>>shift) < (ulong) Ai))
{
changed = 1;
fq_nmod_poly_scalar_mul_fq_nmod(tp, modulus, Acoeff + Ai, ctx->fqctx);
n_fq_poly_set_fq_nmod_poly(Tcoeffs + Ti, tp, ctx->fqctx);
(Texps + N*Ti)[off] = Ai << shift;
do {
Ai--;
} while (Ai >= 0 && fq_nmod_is_zero(Acoeff + Ai, ctx->fqctx));
}
else
{
FLINT_ASSERT(0);
}
FLINT_ASSERT(!n_poly_is_zero(Tcoeffs + Ti));
lastdeg = FLINT_MAX(lastdeg, n_poly_degree(Tcoeffs + Ti));
Ti++;
}
T->length = Ti;
fq_nmod_clear(u, ctx->fqctx);
fq_nmod_clear(v, ctx->fqctx);
fq_nmod_poly_clear(tp, ctx->fqctx);
n_poly_clear(tpt);
if (changed)
{
fq_nmod_mpolyn_swap(T, F);
}
*lastdeg_ = lastdeg;
return changed;
}
void fq_nmod_mpolyn_interp_lift_sm_bpoly(
fq_nmod_mpolyn_t F,
n_fq_bpoly_t A,
const fq_nmod_mpoly_ctx_t ctx)
{
slong d = fq_nmod_ctx_degree(ctx->fqctx);
slong N = mpoly_words_per_exp_sp(F->bits, ctx->minfo);
slong i, j, Fi;
slong off0, shift0, off1, shift1;
mpoly_gen_offset_shift_sp(&off0, &shift0, 0, F->bits, ctx->minfo);
mpoly_gen_offset_shift_sp(&off1, &shift1, 1, F->bits, ctx->minfo);
Fi = 0;
for (i = A->length - 1; i >= 0; i--)
{
n_fq_poly_struct * Ai = A->coeffs + i;
for (j = Ai->length - 1; j >= 0; j--)
{
if (_n_fq_is_zero(Ai->coeffs + d*j, d))
continue;
fq_nmod_mpolyn_fit_length(F, Fi + 1, ctx);
mpoly_monomial_zero(F->exps + N*Fi, N);
(F->exps + N*Fi)[off0] += (i << shift0);
(F->exps + N*Fi)[off1] += (j << shift1);
n_fq_poly_set_n_fq(F->coeffs + Fi, Ai->coeffs + d*j, ctx->fqctx);
Fi++;
}
}
F->length = Fi;
}
int fq_nmod_mpolyn_interp_crt_sm_bpoly(
slong * lastdeg,
fq_nmod_mpolyn_t F,
fq_nmod_mpolyn_t T,
const n_fq_bpoly_t A,
const n_fq_poly_t modulus,
n_fq_poly_t alphapow,
const fq_nmod_mpoly_ctx_t ctx)
{
int changed = 0;
slong d = fq_nmod_ctx_degree(ctx->fqctx);
slong N = mpoly_words_per_exp(F->bits, ctx->minfo);
slong off0, shift0, off1, shift1;
n_poly_struct * Acoeffs = A->coeffs;
slong Fi, Ti, Ai, ai;
slong Flen = F->length;
ulong * Fexps = F->exps;
n_fq_poly_struct * Fcoeffs = F->coeffs;
ulong * Texps = T->exps;
n_fq_poly_struct * Tcoeffs = T->coeffs;
ulong * v = FLINT_ARRAY_ALLOC(d, ulong);
ulong Fexpi, mask;
FLINT_ASSERT(fq_nmod_mpolyn_is_canonical(F, ctx));
FLINT_ASSERT(n_fq_bpoly_is_canonical(A, ctx->fqctx));
mask = (-UWORD(1)) >> (FLINT_BITS - F->bits);
mpoly_gen_offset_shift_sp(&off0, &shift0, 0, F->bits, ctx->minfo);
mpoly_gen_offset_shift_sp(&off1, &shift1, 1, F->bits, ctx->minfo);
FLINT_ASSERT(T->bits == F->bits);
*lastdeg = -1;
Ti = Fi = 0;
Ai = A->length - 1;
ai = (Ai < 0) ? 0 : n_poly_degree(Acoeffs + Ai);
while (Fi < Flen || Ai >= 0)
{
if (Ti >= T->alloc)
{
slong extra = FLINT_MAX(Flen - Fi, Ai);
fq_nmod_mpolyn_fit_length(T, Ti + extra + 1, ctx);
Tcoeffs = T->coeffs;
Texps = T->exps;
}
if (Fi < Flen)
Fexpi = pack_exp2(((Fexps + N*Fi)[off0]>>shift0)&mask,
((Fexps + N*Fi)[off1]>>shift1)&mask);
else
Fexpi = 0;
if (Fi < Flen && Ai >= 0 && Fexpi == pack_exp2(Ai, ai))
{
mpoly_monomial_set(Texps + N*Ti, Fexps + N*Fi, N);
n_fq_poly_eval_pow(v, Fcoeffs + Fi, alphapow, ctx->fqctx);
n_fq_sub(v, Acoeffs[Ai].coeffs + d*ai, v, ctx->fqctx);
if (!_n_fq_is_zero(v, d))
{
changed = 1;
n_fq_poly_scalar_addmul_n_fq(Tcoeffs + Ti,
Fcoeffs + Fi, modulus, v, ctx->fqctx);
}
else
{
n_fq_poly_set(Tcoeffs + Ti, Fcoeffs + Fi, ctx->fqctx);
}
Fi++;
do {
ai--;
} while (ai >= 0 && _n_fq_is_zero(Acoeffs[Ai].coeffs + d*ai, d));
if (ai < 0)
{
do {
Ai--;
} while (Ai >= 0 && Acoeffs[Ai].length == 0);
if (Ai >= 0)
ai = n_fq_poly_degree(Acoeffs + Ai);
}
}
else if (Ai >= 0 && (Fi >= Flen || Fexpi < pack_exp2(Ai, ai)))
{
mpoly_monomial_zero(Texps + N*Ti, N);
(Texps + N*Ti)[off0] += (Ai << shift0);
(Texps + N*Ti)[off1] += (ai << shift1);
changed = 1;
n_fq_poly_scalar_mul_n_fq(Tcoeffs + Ti, modulus,
Acoeffs[Ai].coeffs + d*ai, ctx->fqctx);
do {
ai--;
} while (ai >= 0 && _n_fq_is_zero(Acoeffs[Ai].coeffs + d*ai, d));
if (ai < 0)
{
do {
Ai--;
} while (Ai >= 0 && Acoeffs[Ai].length == 0);
if (Ai >= 0)
ai = n_fq_poly_degree(Acoeffs + Ai);
}
}
else
{
FLINT_ASSERT(Fi < Flen && (Ai < 0 || Fexpi > pack_exp2(Ai, ai)));
mpoly_monomial_set(Texps + N*Ti, Fexps + N*Fi, N);
n_fq_poly_eval_pow(v, Fcoeffs + Fi, alphapow, ctx->fqctx);
if (!_n_fq_is_zero(v, d))
{
changed = 1;
_n_fq_neg(v, v, d, ctx->fqctx->mod);
n_fq_poly_scalar_addmul_n_fq(Tcoeffs + Ti,
Fcoeffs + Fi, modulus, v, ctx->fqctx);
}
else
{
n_fq_poly_set(Tcoeffs + Ti, Fcoeffs + Fi, ctx->fqctx);
}
Fi++;
}
FLINT_ASSERT(!n_fq_poly_is_zero(Tcoeffs + Ti));
*lastdeg = FLINT_MAX(*lastdeg, n_fq_poly_degree(Tcoeffs + Ti));
Ti++;
}
T->length = Ti;
if (changed)
fq_nmod_mpolyn_swap(T, F);
flint_free(v);
return changed;
}
void fq_nmod_mpolyn_interp_reduce_sm_mpolyn(
fq_nmod_mpolyn_t E,
fq_nmod_mpolyn_t A,
slong var,
fq_nmod_t alpha,
const fq_nmod_mpoly_ctx_t ctx)
{
slong N = mpoly_words_per_exp_sp(A->bits, ctx->minfo);
slong offset, shift, k;
ulong mask;
fq_nmod_t v;
n_poly_struct * Acoeff = A->coeffs;
ulong * Aexp = A->exps;
slong Alen = A->length;
slong Ai;
n_poly_struct * Ecoeff;
ulong * Eexp;
slong Ei;
fq_nmod_init(v, ctx->fqctx);
FLINT_ASSERT(var > 0);
mpoly_gen_offset_shift_sp(&offset, &shift, var - 1, A->bits, ctx->minfo);
mask = (-UWORD(1)) >> (FLINT_BITS - A->bits);
Ecoeff = E->coeffs;
Eexp = E->exps;
Ei = 0;
for (Ai = 0; Ai < Alen; Ai++)
{
n_fq_poly_evaluate_fq_nmod(v, Acoeff + Ai, alpha, ctx->fqctx);
k = ((Aexp + N*Ai)[offset] >> shift) & mask;
if (fq_nmod_is_zero(v, ctx->fqctx))
{
continue;
}
if (Ei > 0 && mpoly_monomial_equal_extra(Eexp + N*(Ei - 1), Aexp + N*Ai, N, offset, -(k << shift)))
{
n_fq_poly_set_coeff_fq_nmod(Ecoeff + Ei - 1, k, v, ctx->fqctx);
}
else
{
FLINT_ASSERT(Ei == 0 || mpoly_monomial_gt_nomask_extra(Eexp + N*(Ei - 1), Aexp + N*Ai, N, offset, -(k << shift)));
if (Ei >= E->alloc)
{
fq_nmod_mpolyn_fit_length(E, Ei + 1, ctx);
Ecoeff = E->coeffs;
Eexp = E->exps;
}
mpoly_monomial_set_extra(Eexp + N*Ei, Aexp + N*Ai, N, offset, -(k << shift));
n_poly_zero(Ecoeff + Ei);
n_fq_poly_set_coeff_fq_nmod(Ecoeff + Ei, k, v, ctx->fqctx);
Ei++;
}
}
E->length = Ei;
fq_nmod_clear(v, ctx->fqctx);
}
void fq_nmod_mpolyn_interp_lift_sm_mpolyn(
fq_nmod_mpolyn_t A,
fq_nmod_mpolyn_t B,
slong var,
const fq_nmod_mpoly_ctx_t ctx)
{
slong d = fq_nmod_ctx_degree(ctx->fqctx);
slong N = mpoly_words_per_exp_sp(B->bits, ctx->minfo);
slong offset, shift;
slong vi;
n_fq_poly_struct * Bcoeff = B->coeffs;
ulong * Bexp = B->exps;
slong Blen = B->length;
slong Bi;
n_fq_poly_struct * Acoeff;
ulong * Aexp;
slong Ai;
fq_nmod_mpolyn_fit_length(A, Blen, ctx);
Acoeff = A->coeffs;
Aexp = A->exps;
mpoly_gen_offset_shift_sp(&offset, &shift, var - 1, A->bits, ctx->minfo);
Ai = 0;
for (Bi = 0; Bi < Blen; Bi++)
{
if (Ai + (Bcoeff + Bi)->length >= A->alloc)
{
fq_nmod_mpolyn_fit_length(A, Ai + (Bcoeff + Bi)->length, ctx);
Acoeff = A->coeffs;
Aexp = A->exps;
}
for (vi = (Bcoeff + Bi)->length - 1; vi >= 0; vi--)
{
if (!_n_fq_is_zero(Bcoeff[Bi].coeffs + d*vi, d))
{
mpoly_monomial_set_extra(Aexp + N*Ai, Bexp + N*Bi, N, offset, vi << shift);
n_fq_poly_zero(Acoeff + Ai);
n_fq_poly_set_coeff_n_fq(Acoeff + Ai, 0, Bcoeff[Bi].coeffs + d*vi, ctx->fqctx);
Ai++;
}
}
}
A->length = Ai;
}
int fq_nmod_mpolyn_interp_mcrt_sm_mpoly(
slong * lastdeg_,
fq_nmod_mpolyn_t F,
fq_nmod_mpoly_t A,
const n_fq_poly_t modulus,
n_fq_poly_t alphapow,
const fq_nmod_mpoly_ctx_t ctx)
{
slong d = fq_nmod_ctx_degree(ctx->fqctx);
#if FLINT_WANT_ASSERT
slong N = mpoly_words_per_exp(A->bits, ctx->minfo);
#endif
slong lastdeg = *lastdeg_;
int changed = 0;
ulong * v = FLINT_ARRAY_ALLOC(d, ulong);
slong i, Alen = A->length;
ulong * Acoeffs = A->coeffs;
n_fq_poly_struct * Fcoeffs = F->coeffs;
FLINT_ASSERT(F->bits == A->bits);
FLINT_ASSERT(ctx->minfo->ord == ORD_LEX);
FLINT_ASSERT(F->length == Alen);
for (i = 0; i < Alen; i++)
{
FLINT_ASSERT(mpoly_monomial_equal(F->exps + N*i, A->exps + N*i, N));
FLINT_ASSERT(!n_fq_poly_is_zero(Fcoeffs + i));
FLINT_ASSERT(n_fq_poly_degree(Fcoeffs + i) < n_fq_poly_degree(modulus));
n_fq_poly_eval_pow(v, Fcoeffs + i, alphapow, ctx->fqctx);
n_fq_sub(v, Acoeffs + d*i, v, ctx->fqctx);
if (!_n_fq_is_zero(v, d))
{
changed = 1;
n_fq_poly_scalar_addmul_n_fq(Fcoeffs + i, Fcoeffs + i,
modulus, v, ctx->fqctx);
}
FLINT_ASSERT(!n_fq_poly_is_zero(Fcoeffs + i));
lastdeg = FLINT_MAX(lastdeg, n_fq_poly_degree(Fcoeffs + i));
}
flint_free(v);
*lastdeg_ = lastdeg;
return changed;
}
int fq_nmod_mpolyn_interp_crt_sm_mpolyn(
slong * lastdeg_,
fq_nmod_mpolyn_t F,
fq_nmod_mpolyn_t T,
fq_nmod_mpolyn_t A,
slong var,
fq_nmod_poly_t modulus,
const fq_nmod_t alpha,
const fq_nmod_mpoly_ctx_t ctx)
{
slong d = fq_nmod_ctx_degree(ctx->fqctx);
int changed = 0;
slong N = mpoly_words_per_exp_sp(A->bits, ctx->minfo);
slong lastdeg = -WORD(1);
slong offset, shift;
slong vi;
fq_nmod_t v, at;
fq_nmod_poly_t tp;
n_fq_poly_t tpt;
n_fq_poly_struct * Tcoeff;
ulong * Texp;
slong Ti;
n_fq_poly_struct * Acoeff = A->coeffs;
slong Alen = A->length;
ulong * Aexp = A->exps;
slong Ai;
n_fq_poly_struct * Fcoeff = F->coeffs;
slong Flen = F->length;
ulong * Fexp = F->exps;
slong Fi;
fq_nmod_poly_init(tp, ctx->fqctx);
fq_nmod_init(v, ctx->fqctx);
fq_nmod_init(at, ctx->fqctx);
n_fq_poly_init(tpt);
FLINT_ASSERT(var > 0);
FLINT_ASSERT(T->bits == A->bits);
FLINT_ASSERT(F->bits == A->bits);
mpoly_gen_offset_shift_sp(&offset, &shift, var - 1, A->bits, ctx->minfo);
Flen = F->length;
fq_nmod_mpolyn_fit_length(T, FLINT_MAX(Flen, Alen), ctx);
Tcoeff = T->coeffs;
Texp = T->exps;
Ti = 0;
Fi = Ai = vi = 0;
if (Ai < Alen)
{
vi = n_fq_poly_degree(A->coeffs + Ai);
}
while (Fi < Flen || Ai < Alen)
{
if (Ti >= T->alloc)
{
fq_nmod_mpolyn_fit_length(T, Ti + FLINT_MAX(Flen - Fi, Alen - Ai), ctx);
Tcoeff = T->coeffs;
Texp = T->exps;
}
if (Ai < Alen)
{
FLINT_ASSERT(!_n_fq_is_zero(Acoeff[Ai].coeffs + d*vi, d));
}
if (Fi < Flen && Ai < Alen && mpoly_monomial_equal_extra(Fexp + N*Fi, Aexp + N*Ai, N, offset, vi << shift))
{
n_fq_poly_evaluate_fq_nmod(v, Fcoeff + Fi, alpha, ctx->fqctx);
n_fq_get_fq_nmod(at, Acoeff[Ai].coeffs + d*vi, ctx->fqctx);
fq_nmod_sub(v, at, v, ctx->fqctx);
if (!fq_nmod_is_zero(v, ctx->fqctx))
{
changed = 1;
fq_nmod_poly_scalar_mul_fq_nmod(tp, modulus, v, ctx->fqctx);
n_fq_poly_set_fq_nmod_poly(tpt, tp, ctx->fqctx);
n_fq_poly_add(Tcoeff + Ti, Fcoeff + Fi, tpt, ctx->fqctx);
}
else
{
n_fq_poly_set(Tcoeff + Ti, Fcoeff + Fi, ctx->fqctx);
}
mpoly_monomial_set(Texp + N*Ti, Fexp + N*Fi, N);
Fi++;
do {
vi--;
} while (vi >= 0 && _n_fq_is_zero(Acoeff[Ai].coeffs + d*vi, d));
if (vi < 0)
{
Ai++;
if (Ai < Alen)
{
vi = n_fq_poly_degree(A->coeffs + Ai);
}
}
}
else if (Fi < Flen && (Ai >= Alen || mpoly_monomial_gt_nomask_extra(Fexp + N*Fi, Aexp + N*Ai, N, offset, vi << shift)))
{
n_fq_poly_evaluate_fq_nmod(v, Fcoeff + Fi, alpha, ctx->fqctx);
if (!fq_nmod_is_zero(v, ctx->fqctx))
{
changed = 1;
fq_nmod_poly_scalar_mul_fq_nmod(tp, modulus, v, ctx->fqctx);
n_fq_poly_set_fq_nmod_poly(tpt, tp, ctx->fqctx);
n_fq_poly_sub(Tcoeff + Ti, Fcoeff + Fi, tpt, ctx->fqctx);
}
else
{
n_fq_poly_set(Tcoeff + Ti, Fcoeff + Fi, ctx->fqctx);
}
mpoly_monomial_set(Texp + N*Ti, Fexp + N*Fi, N);
Fi++;
}
else
{
FLINT_ASSERT(Ai < Alen && (Fi >= Flen || mpoly_monomial_lt_nomask_extra(Fexp + N*Fi, Aexp + N*Ai, N, offset, vi << shift)));
changed = 1;
n_fq_get_fq_nmod(at, Acoeff[Ai].coeffs + d*vi, ctx->fqctx);
fq_nmod_poly_scalar_mul_fq_nmod(tp, modulus, at, ctx->fqctx);
n_fq_poly_set_fq_nmod_poly(Tcoeff + Ti, tp, ctx->fqctx);
mpoly_monomial_set_extra(Texp + N*Ti, Aexp + N*Ai, N, offset, vi << shift);
do {
vi--;
} while (vi >= 0 && _n_fq_is_zero(Acoeff[Ai].coeffs + d*vi, d));
if (vi < 0)
{
Ai++;
if (Ai < Alen)
{
vi = n_fq_poly_degree(A->coeffs + Ai);
}
}
}
FLINT_ASSERT(!n_fq_poly_is_zero(Tcoeff + Ti));
lastdeg = FLINT_MAX(lastdeg, n_fq_poly_degree(Tcoeff + Ti));
Ti++;
}
T->length = Ti;
if (changed)
{
fq_nmod_mpolyn_swap(T, F);
}
fq_nmod_poly_clear(tp, ctx->fqctx);
fq_nmod_clear(v, ctx->fqctx);
fq_nmod_clear(at, ctx->fqctx);
n_fq_poly_clear(tpt);
FLINT_ASSERT(fq_nmod_mpolyn_is_canonical(F, ctx));
*lastdeg_ = lastdeg;
return changed;
}
void fq_nmod_mpolyn_interp_reduce_lg_poly(
fq_nmod_poly_t E,
const fq_nmod_mpoly_ctx_t ectx,
fq_nmod_mpolyn_t A,
const fq_nmod_mpoly_ctx_t ctx,
const bad_fq_nmod_embed_t emb)
{
fq_nmod_t v;
slong Ai, Alen, k;
n_fq_poly_struct * Acoeff;
ulong * Aexp;
slong N, off, shift;
N = mpoly_words_per_exp_sp(A->bits, ctx->minfo);
mpoly_gen_offset_shift_sp(&off, &shift, 0, A->bits, ctx->minfo);
fq_nmod_init(v, ectx->fqctx);
Acoeff = A->coeffs;
Aexp = A->exps;
Alen = A->length;
fq_nmod_poly_zero(E, ectx->fqctx);
for (Ai = 0; Ai < Alen; Ai++)
{
k = (Aexp + N*Ai)[off] >> shift;
bad_fq_nmod_embed_n_fq_sm_to_fq_nmod_lg(v, Acoeff + Ai, emb);
fq_nmod_poly_set_coeff(E, k, v, ectx->fqctx);
}
fq_nmod_clear(v, ectx->fqctx);
}
void fq_nmod_mpolyn_interp_lift_lg_poly(
slong * lastdeg_,
fq_nmod_mpolyn_t A,
const fq_nmod_mpoly_ctx_t ctx,
fq_nmod_poly_t B,
const fq_nmod_mpoly_ctx_t ectx,
const bad_fq_nmod_embed_t emb)
{
slong Bexp;
slong Blen = fq_nmod_poly_length(B, ectx->fqctx);
fq_nmod_struct * Bcoeff = B->coeffs;
n_fq_poly_struct * Acoeff;
ulong * Aexp;
slong Ai;
slong lastdeg = -WORD(1);
slong N, off, shift;
N = mpoly_words_per_exp_sp(A->bits, ctx->minfo);
mpoly_gen_offset_shift_sp(&off, &shift, 0, A->bits, ctx->minfo);
fq_nmod_mpolyn_fit_length(A, Blen, ctx);
Acoeff = A->coeffs;
Aexp = A->exps;
Ai = 0;
for (Bexp = Blen - 1; Bexp >= 0; Bexp--)
{
if (!fq_nmod_is_zero(Bcoeff + Bexp, ectx->fqctx))
{
FLINT_ASSERT(Ai < A->alloc);
bad_fq_nmod_embed_fq_nmod_lg_to_n_fq_sm(Acoeff + Ai, Bcoeff + Bexp, emb);
FLINT_ASSERT(!n_fq_poly_is_zero(Acoeff + Ai));
lastdeg = FLINT_MAX(lastdeg, n_fq_poly_degree(Acoeff + Ai));
mpoly_monomial_zero(Aexp + N*Ai, N);
(Aexp + N*Ai)[off] = Bexp << shift;
Ai++;
}
}
A->length = Ai;
*lastdeg_ = lastdeg;
}
int fq_nmod_mpolyn_interp_crt_lg_poly(
slong * lastdeg_,
fq_nmod_mpolyn_t F,
fq_nmod_mpolyn_t T,
fq_nmod_poly_t modulus,
const fq_nmod_mpoly_ctx_t ctx,
fq_nmod_poly_t A,
const fq_nmod_mpoly_ctx_t ectx,
const bad_fq_nmod_embed_t emb)
{
int changed = 0;
slong lastdeg = -WORD(1);
fq_nmod_t u, v;
fq_nmod_poly_t u_sm, w;
n_fq_poly_t wt;
slong Fi, Ti, Aexp;
fq_nmod_struct * Acoeff = A->coeffs;
slong Flen = F->length;
n_fq_poly_struct * Fcoeff = F->coeffs;
ulong * Fexp = F->exps;
n_fq_poly_struct * Tcoeff;
ulong * Texp;
fq_nmod_poly_t tp;
fq_nmod_t inv_m_eval;
slong N, off, shift;
FLINT_ASSERT(T->bits == F->bits);
N = mpoly_words_per_exp_sp(F->bits, ctx->minfo);
mpoly_gen_offset_shift_sp(&off, &shift, 0, F->bits, ctx->minfo);
fq_nmod_init(inv_m_eval, ectx->fqctx);
bad_fq_nmod_embed_sm_to_lg(inv_m_eval, modulus, emb);
fq_nmod_inv(inv_m_eval, inv_m_eval, ectx->fqctx);
fq_nmod_init(u, ectx->fqctx);
fq_nmod_init(v, ectx->fqctx);
fq_nmod_poly_init(u_sm, ctx->fqctx);
fq_nmod_poly_init(w, ctx->fqctx);
n_fq_poly_init(wt);
Fi = 0;
Aexp = fq_nmod_poly_degree(A, ectx->fqctx);
fq_nmod_poly_init(tp, ctx->fqctx);
fq_nmod_mpolyn_fit_length(T, Flen + Aexp + 1, ctx);
Tcoeff = T->coeffs;
Texp = T->exps;
Ti = 0;
while (Fi < Flen || Aexp >= 0)
{
FLINT_ASSERT(Ti < T->alloc);
if (Fi < Flen)
{
FLINT_ASSERT(!n_fq_poly_is_zero(Fcoeff + Fi));
FLINT_ASSERT(n_fq_poly_degree(Fcoeff + Fi) < fq_nmod_poly_degree(modulus, ctx->fqctx));
}
if (Aexp >= 0)
{
FLINT_ASSERT(!fq_nmod_is_zero(Acoeff + Aexp, ectx->fqctx));
}
mpoly_monomial_zero(Texp + N*Ti, N);
if (Fi < Flen && Aexp >= 0 && ((Fexp + N*Fi)[off]>>shift) == (ulong) Aexp)
{
bad_fq_nmod_embed_n_fq_sm_to_fq_nmod_lg(u, Fcoeff + Fi, emb);
fq_nmod_sub(v, Acoeff + Aexp, u, ectx->fqctx);
if (!fq_nmod_is_zero(v, ectx->fqctx))
{
changed = 1;
fq_nmod_mul(u, v, inv_m_eval, ectx->fqctx);
bad_fq_nmod_embed_lg_to_sm(u_sm, u, emb);
fq_nmod_poly_mul(w, modulus, u_sm, ctx->fqctx);
n_fq_poly_set_fq_nmod_poly(wt, w, ctx->fqctx);
n_fq_poly_add(Tcoeff + Ti, Fcoeff + Fi, wt, ctx->fqctx);
}
else
{
n_fq_poly_set(Tcoeff + Ti, Fcoeff + Fi, ctx->fqctx);
}
(Texp + N*Ti)[off] = (Fexp + N*Fi)[off];
Fi++;
do {
Aexp--;
} while (Aexp >= 0 && fq_nmod_is_zero(Acoeff + Aexp, ectx->fqctx));
}
else if (Fi < Flen && (Aexp < 0 || ((Fexp + N*Fi)[off]>>shift) > (ulong) Aexp))
{
bad_fq_nmod_embed_n_fq_sm_to_fq_nmod_lg(v, Fcoeff + Fi, emb);
if (!fq_nmod_is_zero(v, ectx->fqctx))
{
changed = 1;
fq_nmod_mul(u, v, inv_m_eval, ectx->fqctx);
bad_fq_nmod_embed_lg_to_sm(u_sm, u, emb);
fq_nmod_poly_mul(w, u_sm, modulus, ctx->fqctx);
n_fq_poly_set_fq_nmod_poly(wt, w, ctx->fqctx);
n_fq_poly_add(Tcoeff + Ti, Fcoeff + Fi, wt, ctx->fqctx);
}
else
{
n_fq_poly_set(Tcoeff + Ti, Fcoeff + Fi, ctx->fqctx);
}
(Texp + N*Ti)[off] = (Fexp + N*Fi)[off];
Fi++;
}
else if (Aexp >= 0 && (Fi >= Flen || ((Fexp + N*Fi)[off]>>shift) < (ulong) Aexp))
{
changed = 1;
fq_nmod_mul(u, Acoeff + Aexp, inv_m_eval, ectx->fqctx);
bad_fq_nmod_embed_lg_to_sm(u_sm, u, emb);
fq_nmod_poly_mul(w, modulus, u_sm, ctx->fqctx);
n_fq_poly_set_fq_nmod_poly(Tcoeff + Ti, w, ctx->fqctx);
(Texp + N*Ti)[off] = Aexp << shift;
do {
Aexp--;
} while (Aexp >= 0 && fq_nmod_is_zero(Acoeff + Aexp, ectx->fqctx));
}
else
{
FLINT_ASSERT(0);
}
FLINT_ASSERT(!n_fq_poly_is_zero(Tcoeff + Ti));
lastdeg = FLINT_MAX(lastdeg, n_fq_poly_degree(Tcoeff + Ti));
Ti++;
}
T->length = Ti;
if (changed)
{
fq_nmod_mpolyn_swap(T, F);
}
fq_nmod_clear(u, ectx->fqctx);
fq_nmod_clear(v, ectx->fqctx);
fq_nmod_poly_clear(u_sm, ctx->fqctx);
fq_nmod_poly_clear(w, ctx->fqctx);
n_fq_poly_clear(wt);
fq_nmod_clear(inv_m_eval, ectx->fqctx);
*lastdeg_ = lastdeg;
return changed;
}
void fq_nmod_mpolyn_interp_lift_lg_bpoly(
slong * lastdeg_,
fq_nmod_mpolyn_t F,
const fq_nmod_mpoly_ctx_t smctx,
n_fq_bpoly_t A,
const fq_nmod_mpoly_ctx_t lgctx,
const bad_fq_nmod_embed_t emb)
{
slong lgd = fq_nmod_ctx_degree(lgctx->fqctx);
slong N = mpoly_words_per_exp_sp(F->bits, smctx->minfo);
slong i, j, Fi;
slong lastdeg = -WORD(1);
slong off0, shift0, off1, shift1;
mpoly_gen_offset_shift_sp(&off0, &shift0, 0, F->bits, smctx->minfo);
mpoly_gen_offset_shift_sp(&off1, &shift1, 1, F->bits, smctx->minfo);
Fi = 0;
for (i = A->length - 1; i >= 0; i--)
{
n_fq_poly_struct * Ai = A->coeffs + i;
for (j = Ai->length - 1; j >= 0; j--)
{
if (_n_fq_is_zero(Ai->coeffs + lgd*j, lgd))
continue;
fq_nmod_mpolyn_fit_length(F, Fi + 1, smctx);
mpoly_monomial_zero(F->exps + N*Fi, N);
(F->exps + N*Fi)[off0] += (i << shift0);
(F->exps + N*Fi)[off1] += (j << shift1);
bad_n_fq_embed_lg_to_sm(F->coeffs + Fi, Ai->coeffs + lgd*j, emb);
lastdeg = FLINT_MAX(lastdeg, n_fq_poly_degree(F->coeffs + Fi));
Fi++;
}
}
F->length = Fi;
*lastdeg_ = lastdeg;
}
int fq_nmod_mpolyn_interp_crt_lg_bpoly(
slong * lastdeg,
fq_nmod_mpolyn_t F,
fq_nmod_mpolyn_t T,
n_fq_poly_t modulus,
const fq_nmod_mpoly_ctx_t smctx,
n_fq_bpoly_t A,
const fq_nmod_mpoly_ctx_t lgctx,
const bad_fq_nmod_embed_t emb)
{
slong lgd = fq_nmod_ctx_degree(lgctx->fqctx);
int changed = 0;
slong N = mpoly_words_per_exp(T->bits, smctx->minfo);
slong off0, shift0, off1, shift1;
n_fq_poly_struct * Acoeffs = A->coeffs;
slong Fi, Ti, Ai, ai;
slong Flen = F->length;
ulong * Fexps = F->exps;
n_fq_poly_struct * Fcoeffs = F->coeffs;
ulong * Texps = T->exps;
n_fq_poly_struct * Tcoeffs = T->coeffs;
ulong * u = FLINT_ARRAY_ALLOC(3*lgd, ulong);
ulong * v = u + lgd;
ulong * inv_m_eval = v + lgd;
n_fq_poly_t u_sm;
ulong Fexpi, mask;
mask = (-UWORD(1)) >> (FLINT_BITS - F->bits);
mpoly_gen_offset_shift_sp(&off0, &shift0, 0, F->bits, smctx->minfo);
mpoly_gen_offset_shift_sp(&off1, &shift1, 1, F->bits, smctx->minfo);
n_fq_poly_init(u_sm);
bad_n_fq_embed_sm_to_lg(u, modulus, emb);
n_fq_inv(inv_m_eval, u, lgctx->fqctx);
FLINT_ASSERT(fq_nmod_mpolyn_is_canonical(F, smctx));
FLINT_ASSERT(n_fq_bpoly_is_canonical(A, lgctx->fqctx));
FLINT_ASSERT(T->bits == F->bits);
*lastdeg = -1;
Ti = Fi = 0;
Ai = A->length - 1;
ai = (Ai < 0) ? 0 : n_fq_poly_degree(Acoeffs + Ai);
while (Fi < Flen || Ai >= 0)
{
if (Ti >= T->alloc)
{
slong extra = FLINT_MAX(Flen - Fi, Ai);
fq_nmod_mpolyn_fit_length(T, Ti + extra + 1, smctx);
Tcoeffs = T->coeffs;
Texps = T->exps;
}
if (Fi < Flen)
{
Fexpi = pack_exp2(((Fexps + N*Fi)[off0]>>shift0)&mask,
((Fexps + N*Fi)[off1]>>shift1)&mask);
}
else
{
Fexpi = 0;
}
if (Fi < Flen && Ai >= 0 && Fexpi == pack_exp2(Ai, ai))
{
mpoly_monomial_set(Texps + N*Ti, Fexps + N*Fi, N);
bad_n_fq_embed_sm_to_lg(u, Fcoeffs + Fi, emb);
n_fq_sub(v, Acoeffs[Ai].coeffs + lgd*ai, u, lgctx->fqctx);
if (!_n_fq_is_zero(v, lgd))
{
changed = 1;
n_fq_mul(u, v, inv_m_eval, lgctx->fqctx);
bad_n_fq_embed_lg_to_sm(u_sm, u, emb);
n_fq_poly_mul(Tcoeffs + Ti, modulus, u_sm, smctx->fqctx);
n_fq_poly_add(Tcoeffs + Ti, Tcoeffs + Ti, Fcoeffs + Fi, smctx->fqctx);
}
else
{
n_fq_poly_set(Tcoeffs + Ti, Fcoeffs + Fi, smctx->fqctx);
}
Fi++;
do {
ai--;
} while (ai >= 0 && _n_fq_is_zero(Acoeffs[Ai].coeffs + lgd*ai, lgd));
if (ai < 0)
{
do {
Ai--;
} while (Ai >= 0 && Acoeffs[Ai].length == 0);
if (Ai >= 0)
ai = n_fq_poly_degree(Acoeffs + Ai);
}
}
else if (Fi < Flen && (Ai < 0 || Fexpi > pack_exp2(Ai, ai)))
{
mpoly_monomial_set(Texps + N*Ti, Fexps + N*Fi, N);
bad_n_fq_embed_sm_to_lg(v, Fcoeffs + Fi, emb);
if (!_n_fq_is_zero(v, lgd))
{
changed = 1;
n_fq_mul(u, v, inv_m_eval, lgctx->fqctx);
bad_n_fq_embed_lg_to_sm(u_sm, u, emb);
n_fq_poly_mul(Tcoeffs + Ti, modulus, u_sm, smctx->fqctx);
n_fq_poly_sub(Tcoeffs + Ti, Fcoeffs + Fi, Tcoeffs + Ti, smctx->fqctx);
}
else
{
n_fq_poly_set(Tcoeffs + Ti, Fcoeffs + Fi, smctx->fqctx);
}
Fi++;
}
else
{
FLINT_ASSERT(Ai >= 0 && (Fi >= Flen || Fexpi < pack_exp2(Ai, ai)));
mpoly_monomial_zero(Texps + N*Ti, N);
(Texps + N*Ti)[off0] += (Ai << shift0);
(Texps + N*Ti)[off1] += (ai << shift1);
changed = 1;
n_fq_mul(u, Acoeffs[Ai].coeffs + lgd*ai, inv_m_eval, lgctx->fqctx);
bad_n_fq_embed_lg_to_sm(u_sm, u, emb);
n_fq_poly_mul(Tcoeffs + Ti, modulus, u_sm, smctx->fqctx);
do {
ai--;
} while (ai >= 0 && _n_fq_is_zero(Acoeffs[Ai].coeffs + lgd*ai, lgd));
if (ai < 0)
{
do {
Ai--;
} while (Ai >= 0 && Acoeffs[Ai].length == 0);
if (Ai >= 0)
ai = n_fq_poly_degree(Acoeffs + Ai);
}
}
FLINT_ASSERT(!n_fq_poly_is_zero(Tcoeffs + Ti));
*lastdeg = FLINT_MAX(*lastdeg, n_fq_poly_degree(Tcoeffs + Ti));
Ti++;
}
T->length = Ti;
if (changed)
fq_nmod_mpolyn_swap(T, F);
FLINT_ASSERT(fq_nmod_mpolyn_is_canonical(F, smctx));
n_fq_poly_clear(u_sm);
flint_free(u);
return changed;
}
void fq_nmod_mpolyn_interp_reduce_lg_mpolyn(
fq_nmod_mpolyn_t E,
const fq_nmod_mpoly_ctx_t ectx,
fq_nmod_mpolyn_t A,
slong var,
const fq_nmod_mpoly_ctx_t ctx,
const bad_fq_nmod_embed_t emb)
{
slong N = mpoly_words_per_exp_sp(A->bits, ctx->minfo);
slong offset, shift, k;
ulong mask;
fq_nmod_t v;
n_fq_poly_struct * Acoeff = A->coeffs;
ulong * Aexp = A->exps;
slong Alen = A->length;
slong Ai;
n_fq_poly_struct * Ecoeff;
ulong * Eexp;
slong Ei;
fq_nmod_init(v, ectx->fqctx);
FLINT_ASSERT(var > 0);
mpoly_gen_offset_shift_sp(&offset, &shift, var - 1, A->bits, ctx->minfo);
mask = (-UWORD(1)) >> (FLINT_BITS - A->bits);
Ecoeff = E->coeffs;
Eexp = E->exps;
Ei = 0;
for (Ai = 0; Ai < Alen; Ai++)
{
bad_fq_nmod_embed_n_fq_sm_to_fq_nmod_lg(v, Acoeff + Ai, emb);
k = ((Aexp + N*Ai)[offset] >> shift) & mask;
if (fq_nmod_is_zero(v, ectx->fqctx))
{
continue;
}
if (Ei > 0 && mpoly_monomial_equal_extra(Eexp + N*(Ei - 1), Aexp + N*Ai, N, offset, -(k << shift)))
{
n_fq_poly_set_coeff_fq_nmod(Ecoeff + Ei - 1, k, v, ectx->fqctx);
}
else
{
FLINT_ASSERT(Ei == 0 || mpoly_monomial_gt_nomask_extra(Eexp + N*(Ei - 1), Aexp + N*Ai, N, offset, -(k << shift)));
if (Ei >= E->alloc)
{
fq_nmod_mpolyn_fit_length(E, Ei + 1, ectx);
Ecoeff = E->coeffs;
Eexp = E->exps;
}
mpoly_monomial_set_extra(Eexp + N*Ei, Aexp + N*Ai, N, offset, -(k << shift));
n_fq_poly_zero(Ecoeff + Ei);
n_fq_poly_set_coeff_fq_nmod(Ecoeff + Ei, k, v, ectx->fqctx);
Ei++;
}
}
E->length = Ei;
fq_nmod_clear(v, ectx->fqctx);
}
void fq_nmod_mpolyn_interp_lift_lg_mpolyn(
slong * lastdeg_,
fq_nmod_mpolyn_t A,
slong var,
const fq_nmod_mpoly_ctx_t ctx,
fq_nmod_mpolyn_t B,
const fq_nmod_mpoly_ctx_t ectx,
const bad_fq_nmod_embed_t emb)
{
slong lgd = fq_nmod_ctx_degree(ectx->fqctx);
slong N = mpoly_words_per_exp_sp(B->bits, ctx->minfo);
slong offset, shift;
slong vi;
n_fq_poly_struct * Bcoeff = B->coeffs;
ulong * Bexp = B->exps;
slong Blen = B->length;
slong Bi;
n_fq_poly_struct * Acoeff;
ulong * Aexp;
slong Ai;
slong lastdeg = -WORD(1);
FLINT_ASSERT(A->bits == B->bits);
fq_nmod_mpolyn_fit_length(A, Blen, ctx);
Acoeff = A->coeffs;
Aexp = A->exps;
mpoly_gen_offset_shift_sp(&offset, &shift, var - 1, A->bits, ctx->minfo);
Ai = 0;
for (Bi = 0; Bi < Blen; Bi++)
{
if (Ai + Bcoeff[Bi].length >= A->alloc)
{
fq_nmod_mpolyn_fit_length(A, Ai + Bcoeff[Bi].length, ctx);
Acoeff = A->coeffs;
Aexp = A->exps;
}
for (vi = Bcoeff[Bi].length - 1; vi >= 0; vi--)
{
if (_n_fq_is_zero(Bcoeff[Bi].coeffs + lgd*vi, lgd))
continue;
mpoly_monomial_set_extra(Aexp + N*Ai, Bexp + N*Bi, N, offset, vi << shift);
bad_n_fq_embed_lg_to_sm(Acoeff + Ai, Bcoeff[Bi].coeffs + lgd*vi, emb);
FLINT_ASSERT(!n_fq_poly_is_zero(Acoeff + Ai));
lastdeg = FLINT_MAX(lastdeg, n_fq_poly_degree(Acoeff + Ai));
Ai++;
}
}
A->length = Ai;
*lastdeg_ = lastdeg;
}
int fq_nmod_mpolyn_interp_crt_lg_mpolyn(
slong * lastdeg_,
fq_nmod_mpolyn_t F,
fq_nmod_mpolyn_t T,
fq_nmod_poly_t modulus,
slong var,
const fq_nmod_mpoly_ctx_t ctx,
fq_nmod_mpolyn_t A,
const fq_nmod_mpoly_ctx_t ectx,
const bad_fq_nmod_embed_t emb)
{
slong lgd = fq_nmod_ctx_degree(ectx->fqctx);
int changed = 0;
slong N = mpoly_words_per_exp_sp(A->bits, ctx->minfo);
slong offset, shift;
slong lastdeg = -WORD(1);
slong vi;
fq_nmod_t u, v;
fq_nmod_poly_t u_sm, w;
fq_nmod_t inv_m_eval;
fq_nmod_t at;
n_fq_poly_t wt;
n_fq_poly_struct * Tcoeff;
ulong * Texp;
slong Ti;
n_fq_poly_struct * Acoeff = A->coeffs;
slong Alen = A->length;
ulong * Aexp = A->exps;
slong Ai;
n_fq_poly_struct * Fcoeff = F->coeffs;
slong Flen = F->length;
ulong * Fexp = F->exps;
slong Fi;
fq_nmod_init(inv_m_eval, ectx->fqctx);
bad_fq_nmod_embed_sm_to_lg(inv_m_eval, modulus, emb);
fq_nmod_inv(inv_m_eval, inv_m_eval, ectx->fqctx);
fq_nmod_init(u, ectx->fqctx);
fq_nmod_init(v, ectx->fqctx);
fq_nmod_poly_init(u_sm, ctx->fqctx);
fq_nmod_poly_init(w, ctx->fqctx);
fq_nmod_init(at, ectx->fqctx);
n_fq_poly_init(wt);
FLINT_ASSERT(var > 0);
FLINT_ASSERT(T->bits == A->bits);
FLINT_ASSERT(F->bits == A->bits);
mpoly_gen_offset_shift_sp(&offset, &shift, var - 1, A->bits, ctx->minfo);
Flen = F->length;
fq_nmod_mpolyn_fit_length(T, FLINT_MAX(Flen, Alen), ctx);
Tcoeff = T->coeffs;
Texp = T->exps;
Ti = 0;
Fi = Ai = vi = 0;
if (Ai < Alen)
{
vi = n_fq_poly_degree(A->coeffs + Ai);
}
while (Fi < Flen || Ai < Alen)
{
if (Ti >= T->alloc)
{
fq_nmod_mpolyn_fit_length(T, Ti + FLINT_MAX(Flen - Fi, Alen - Ai), ctx);
Tcoeff = T->coeffs;
Texp = T->exps;
}
if (Fi < Flen && Ai < Alen && mpoly_monomial_equal_extra(Fexp + N*Fi, Aexp + N*Ai, N, offset, vi << shift))
{
bad_fq_nmod_embed_n_fq_sm_to_fq_nmod_lg(u, Fcoeff + Fi, emb);
n_fq_get_fq_nmod(at, Acoeff[Ai].coeffs + lgd*vi, ectx->fqctx);
fq_nmod_sub(v, at, u, ectx->fqctx);
if (!fq_nmod_is_zero(v, ectx->fqctx))
{
changed = 1;
fq_nmod_mul(u, v, inv_m_eval, ectx->fqctx);
bad_fq_nmod_embed_lg_to_sm(u_sm, u, emb);
fq_nmod_poly_mul(w, modulus, u_sm, ctx->fqctx);
n_fq_poly_set_fq_nmod_poly(wt, w, ctx->fqctx);
n_fq_poly_add(Tcoeff + Ti, Fcoeff + Fi, wt, ctx->fqctx);
}
else
{
n_fq_poly_set(Tcoeff + Ti, Fcoeff + Fi, ctx->fqctx);
}
mpoly_monomial_set(Texp + N*Ti, Fexp + N*Fi, N);
Fi++;
do {
vi--;
} while (vi >= 0 && _n_fq_is_zero(Acoeff[Ai].coeffs + lgd*vi, lgd));
if (vi < 0)
{
Ai++;
if (Ai < Alen)
{
vi = n_fq_poly_degree(A->coeffs + Ai);
}
}
}
else if (Fi < Flen && (Ai >= Alen || mpoly_monomial_gt_nomask_extra(Fexp + N*Fi, Aexp + N*Ai, N, offset, vi << shift)))
{
bad_fq_nmod_embed_n_fq_sm_to_fq_nmod_lg(v, Fcoeff + Fi, emb);
if (!fq_nmod_is_zero(v, ectx->fqctx))
{
changed = 1;
fq_nmod_mul(u, v, inv_m_eval, ectx->fqctx);
bad_fq_nmod_embed_lg_to_sm(u_sm, u, emb);
fq_nmod_poly_mul(w, u_sm, modulus, ctx->fqctx);
n_fq_poly_set_fq_nmod_poly(wt, w, ctx->fqctx);
n_fq_poly_sub(Tcoeff + Ti, Fcoeff + Fi, wt, ctx->fqctx);
}
else
{
n_fq_poly_set(Tcoeff + Ti, Fcoeff + Fi, ctx->fqctx);
}
mpoly_monomial_set(Texp + N*Ti, Fexp + N*Fi, N);
Fi++;
}
else
{
FLINT_ASSERT(Ai < Alen && (Fi >= Flen || mpoly_monomial_lt_nomask_extra(Fexp + N*Fi, Aexp + N*Ai, N, offset, vi << shift)));
changed = 1;
n_fq_get_fq_nmod(at, Acoeff[Ai].coeffs + lgd*vi, ectx->fqctx);
fq_nmod_mul(u, at, inv_m_eval, ectx->fqctx);
bad_fq_nmod_embed_lg_to_sm(u_sm, u, emb);
fq_nmod_poly_mul(w, modulus, u_sm, ctx->fqctx);
n_fq_poly_set_fq_nmod_poly(Tcoeff + Ti, w, ctx->fqctx);
mpoly_monomial_set_extra(Texp + N*Ti, Aexp + N*Ai, N, offset, vi << shift);
do {
vi--;
} while (vi >= 0 && _n_fq_is_zero(Acoeff[Ai].coeffs + lgd*vi, lgd));
if (vi < 0)
{
Ai++;
if (Ai < Alen)
{
vi = n_fq_poly_degree(A->coeffs + Ai);
}
}
}
FLINT_ASSERT(!n_fq_poly_is_zero(Tcoeff + Ti));
lastdeg = FLINT_MAX(lastdeg, n_fq_poly_degree(Tcoeff + Ti));
Ti++;
}
T->length = Ti;
if (changed)
{
fq_nmod_mpolyn_swap(T, F);
}
fq_nmod_clear(inv_m_eval, ectx->fqctx);
fq_nmod_clear(u, ectx->fqctx);
fq_nmod_clear(v, ectx->fqctx);
fq_nmod_poly_clear(u_sm, ctx->fqctx);
fq_nmod_poly_clear(w, ctx->fqctx);
fq_nmod_clear(at, ectx->fqctx);
n_fq_poly_clear(wt);
FLINT_ASSERT(fq_nmod_mpolyn_is_canonical(F, ctx));
*lastdeg_ = lastdeg;
return changed;
}
static void fq_nmod_mpolyn_interp_reduce_sm_mpoly(
fq_nmod_mpoly_t B,
fq_nmod_mpolyn_t A,
fq_nmod_t alpha,
const fq_nmod_mpoly_ctx_t ctx)
{
slong d = fq_nmod_ctx_degree(ctx->fqctx);
slong i, k, N;
fq_nmod_t bt;
FLINT_ASSERT(B->bits == A->bits);
fq_nmod_init(bt, ctx->fqctx);
fq_nmod_mpoly_fit_length(B, A->length, ctx);
N = mpoly_words_per_exp(A->bits, ctx->minfo);
k = 0;
for (i = 0; i < A->length; i++)
{
mpoly_monomial_set(B->exps + N*k, A->exps + N*i, N);
n_fq_poly_evaluate_fq_nmod(bt, A->coeffs + i, alpha, ctx->fqctx);
n_fq_set_fq_nmod(B->coeffs + d*k, bt, ctx->fqctx);
k += !_n_fq_is_zero(B->coeffs + d*k, d);
}
B->length = k;
fq_nmod_clear(bt, ctx->fqctx);
}
void fq_nmod_mpolyun_interp_reduce_sm_mpolyu(
fq_nmod_mpolyu_t B,
fq_nmod_mpolyun_t A,
fq_nmod_t alpha,
const fq_nmod_mpoly_ctx_t ctx)
{
slong i, k;
FLINT_ASSERT(B->bits == A->bits);
fq_nmod_mpolyu_fit_length(B, A->length, ctx);
k = 0;
for (i = 0; i < A->length; i++)
{
B->exps[k] = A->exps[i];
fq_nmod_mpolyn_interp_reduce_sm_mpoly(B->coeffs + k, A->coeffs + i, alpha, ctx);
k += !fq_nmod_mpoly_is_zero(B->coeffs + k, ctx);
}
B->length = k;
}
void fq_nmod_mpolyn_interp_lift_sm_mpoly(
fq_nmod_mpolyn_t A,
const fq_nmod_mpoly_t B,
const fq_nmod_mpoly_ctx_t ctx)
{
slong d = fq_nmod_ctx_degree(ctx->fqctx);
slong i;
slong N;
n_fq_poly_struct * Acoeff;
ulong * Bcoeff;
ulong * Aexp, * Bexp;
slong Blen;
fq_nmod_mpolyn_fit_bits(A, B->bits, ctx);
A->bits = B->bits;
Blen = B->length;
fq_nmod_mpolyn_fit_length(A, Blen, ctx);
Acoeff = A->coeffs;
Bcoeff = B->coeffs;
Aexp = A->exps;
Bexp = B->exps;
N = mpoly_words_per_exp(B->bits, ctx->minfo);
for (i = 0; i < Blen; i++)
{
n_fq_poly_set_n_fq(Acoeff + i, Bcoeff + d*i, ctx->fqctx);
mpoly_monomial_set(Aexp + N*i, Bexp + N*i, N);
}
A->length = Blen;
}
void fq_nmod_mpolyun_interp_lift_sm_mpolyu(
fq_nmod_mpolyun_t A,
const fq_nmod_mpolyu_t B,
const fq_nmod_mpoly_ctx_t ctx)
{
slong i;
FLINT_ASSERT(A->bits == B->bits);
fq_nmod_mpolyun_fit_length(A, B->length, ctx);
for (i = 0; i < B->length; i++)
{
A->exps[i] = B->exps[i];
fq_nmod_mpolyn_interp_lift_sm_mpoly(A->coeffs + i, B->coeffs + i, ctx);
FLINT_ASSERT((A->coeffs + i)->bits == B->bits);
}
A->length = B->length;
}
static int fq_nmod_mpolyn_interp_crt_sm_mpoly(
slong * lastdeg,
fq_nmod_mpolyn_t F,
fq_nmod_mpolyn_t T,
fq_nmod_mpoly_t A,
fq_nmod_poly_t modulus,
fq_nmod_t alpha,
const fq_nmod_mpoly_ctx_t ctx)
{
slong d = fq_nmod_ctx_degree(ctx->fqctx);
flint_bitcnt_t bits = A->bits;
slong N = mpoly_words_per_exp(bits, ctx->minfo);
int changed = 0;
slong i, j, k;
fq_nmod_t v;
slong Flen = F->length, Alen = A->length;
ulong * Fexp = F->exps, * Aexp = A->exps;
ulong * Texp;
ulong * Acoeff = A->coeffs;
n_fq_poly_struct * Fcoeff = F->coeffs;
n_fq_poly_struct * Tcoeff;
fq_nmod_poly_t tp;
n_fq_poly_t tpt;
fq_nmod_t at;
FLINT_ASSERT(F->bits == bits);
FLINT_ASSERT(ctx->minfo->ord == ORD_LEX);
fq_nmod_init(v, ctx->fqctx);
fq_nmod_poly_init(tp, ctx->fqctx);
n_fq_poly_init(tpt);
fq_nmod_init(at, ctx->fqctx);
fq_nmod_mpolyn_fit_length(T, Flen + Alen, ctx);
Texp = T->exps;
Tcoeff = T->coeffs;
i = j = k = 0;
while (i < Flen || j < Alen)
{
if (i < Flen && (j >= Alen
|| mpoly_monomial_gt_nomask(Fexp + N*i, Aexp + N*j, N)))
{
FLINT_ASSERT(!n_fq_poly_is_zero(Fcoeff + i));
FLINT_ASSERT(n_fq_poly_degree(Fcoeff + i) < fq_nmod_poly_degree(modulus, ctx->fqctx));
n_fq_poly_evaluate_fq_nmod(v, Fcoeff + i, alpha, ctx->fqctx);
if (!fq_nmod_is_zero(v, ctx->fqctx))
{
changed = 1;
fq_nmod_poly_scalar_mul_fq_nmod(tp, modulus, v, ctx->fqctx);
n_fq_poly_set_fq_nmod_poly(tpt, tp, ctx->fqctx);
n_fq_poly_sub(Tcoeff + k, Fcoeff + i, tpt, ctx->fqctx);
}
else
{
n_fq_poly_set(Tcoeff + k, Fcoeff + i, ctx->fqctx);
}
FLINT_ASSERT(!n_fq_poly_is_zero(Tcoeff + k));
lastdeg[0] = FLINT_MAX(lastdeg[0], n_fq_poly_degree(Tcoeff + k));
mpoly_monomial_set(Texp + N*k, Fexp + N*i, N);
k++;
i++;
}
else if (j < Alen && (i >= Flen
|| mpoly_monomial_lt_nomask(Fexp + N*i, Aexp + N*j, N)))
{
if (!_n_fq_is_zero(Acoeff + d*j, d))
{
changed = 1;
n_fq_get_fq_nmod(at, Acoeff + d*j, ctx->fqctx);
fq_nmod_poly_scalar_mul_fq_nmod(tp, modulus, at, ctx->fqctx);
n_fq_poly_set_fq_nmod_poly(Tcoeff + k, tp, ctx->fqctx);
FLINT_ASSERT(!n_fq_poly_is_zero(Tcoeff + k));
lastdeg[0] = FLINT_MAX(lastdeg[0], n_fq_poly_degree(Tcoeff + k));
mpoly_monomial_set(Texp + N*k, Aexp + N*j, N);
k++;
}
j++;
}
else if (i < Flen && j < Alen
&& mpoly_monomial_equal(Fexp + N*i, Aexp + N*j, N))
{
FLINT_ASSERT(!n_fq_poly_is_zero(Fcoeff + i));
FLINT_ASSERT(n_fq_poly_degree(Fcoeff + i) < fq_nmod_poly_degree(modulus, ctx->fqctx));
n_fq_poly_evaluate_fq_nmod(v, Fcoeff + i, alpha, ctx->fqctx);
n_fq_get_fq_nmod(at, Acoeff + d*j, ctx->fqctx);
fq_nmod_sub(v, at, v, ctx->fqctx);
if (!fq_nmod_is_zero(v, ctx->fqctx))
{
changed = 1;
fq_nmod_poly_scalar_mul_fq_nmod(tp, modulus, v, ctx->fqctx);
n_fq_poly_set_fq_nmod_poly(tpt, tp, ctx->fqctx);
n_fq_poly_add(Tcoeff + k, Fcoeff + i, tpt, ctx->fqctx);
}
else
{
n_fq_poly_set(Tcoeff + k, Fcoeff + i, ctx->fqctx);
}
FLINT_ASSERT(!n_fq_poly_is_zero(Tcoeff + k));
lastdeg[0] = FLINT_MAX(lastdeg[0], n_fq_poly_degree(Tcoeff + k));
mpoly_monomial_set(Texp + N*k, Aexp + N*j, N);
k++;
i++;
j++;
}
else
{
FLINT_ASSERT(0);
}
}
T->length = k;
if (changed)
{
fq_nmod_mpolyn_swap(T, F);
}
fq_nmod_poly_clear(tp, ctx->fqctx);
fq_nmod_clear(v, ctx->fqctx);
n_fq_poly_clear(tpt);
fq_nmod_clear(at, ctx->fqctx);
return changed;
}
int fq_nmod_mpolyun_interp_crt_sm_mpolyu(
slong * lastdeg,
fq_nmod_mpolyun_t F,
fq_nmod_mpolyun_t T,
fq_nmod_mpolyu_t A,
fq_nmod_poly_t modulus,
fq_nmod_t alpha,
const fq_nmod_mpoly_ctx_t ctx)
{
int changed = 0;
slong i, j, k;
ulong * Texp;
ulong * Fexp;
ulong * Aexp;
slong Flen;
slong Alen;
fq_nmod_mpolyn_t S;
fq_nmod_mpolyn_struct * Tcoeff;
fq_nmod_mpolyn_struct * Fcoeff;
fq_nmod_mpoly_struct * Acoeff;
fq_nmod_mpoly_t zero;
lastdeg[0] = -WORD(1);
FLINT_ASSERT(F->bits == T->bits);
FLINT_ASSERT(T->bits == A->bits);
fq_nmod_mpolyn_init(S, F->bits, ctx);
Flen = F->length;
Alen = A->length;
fq_nmod_mpolyun_fit_length(T, Flen + Alen, ctx);
Tcoeff = T->coeffs;
Fcoeff = F->coeffs;
Acoeff = A->coeffs;
Texp = T->exps;
Fexp = F->exps;
Aexp = A->exps;
fq_nmod_mpoly_init(zero, ctx);
fq_nmod_mpoly_fit_length_reset_bits(zero, 0, A->bits, ctx);
i = j = k = 0;
while (i < Flen || j < Alen)
{
if (i < Flen && (j >= Alen || Fexp[i] > Aexp[j]))
{
fq_nmod_mpolyn_set(Tcoeff + k, Fcoeff + i, ctx);
changed |= fq_nmod_mpolyn_interp_crt_sm_mpoly(lastdeg, Tcoeff + k, S, zero, modulus, alpha, ctx);
Texp[k] = Fexp[i];
k++;
i++;
}
else if (j < Alen && (i >= Flen || Aexp[j] > Fexp[i]))
{
fq_nmod_mpolyn_zero(Tcoeff + k, ctx);
changed |= fq_nmod_mpolyn_interp_crt_sm_mpoly(lastdeg, Tcoeff + k, S, Acoeff + j, modulus, alpha, ctx);
Texp[k] = Aexp[j];
k++;
j++;
}
else if (i < Flen && j < Alen && (Fexp[i] == Aexp[j]))
{
fq_nmod_mpolyn_set(Tcoeff + k, Fcoeff + i, ctx);
changed |= fq_nmod_mpolyn_interp_crt_sm_mpoly(lastdeg, Tcoeff + k, S, Acoeff + j, modulus, alpha, ctx);
Texp[k] = Aexp[j];
FLINT_ASSERT(!fq_nmod_mpolyn_is_zero(Tcoeff + k, ctx));
k++;
i++;
j++;
} else
{
FLINT_ASSERT(0);
}
}
T->length = k;
if (changed)
{
fq_nmod_mpolyun_swap(T, F);
}
fq_nmod_mpolyn_clear(S, ctx);
fq_nmod_mpoly_clear(zero, ctx);
return changed;
}
void fq_nmod_mpolyn_interp_reduce_lg_mpoly(
fq_nmod_mpoly_t A,
fq_nmod_mpolyn_t B,
const fq_nmod_mpoly_ctx_t ectx,
const fq_nmod_mpoly_ctx_t ctx,
const bad_fq_nmod_embed_t emb)
{
slong lgd = fq_nmod_ctx_degree(ectx->fqctx);
slong N = mpoly_words_per_exp_sp(B->bits, ctx->minfo);
slong i, k;
FLINT_ASSERT(A->bits == B->bits);
FLINT_ASSERT(B->bits <= FLINT_BITS);
FLINT_ASSERT(ctx->minfo->ord == ORD_LEX);
FLINT_ASSERT(ectx->minfo->ord == ORD_LEX);
FLINT_ASSERT(ectx->minfo->nvars == ctx->minfo->nvars);
k = 0;
for (i = 0; i < B->length; i++)
{
fq_nmod_mpoly_fit_length(A, k + 1, ectx);
mpoly_monomial_set(A->exps + N*k, B->exps + N*i, N);
bad_n_fq_embed_sm_to_lg(A->coeffs + lgd*k, B->coeffs + i, emb);
k += !_n_fq_is_zero(A->coeffs + lgd*k, lgd);
}
_fq_nmod_mpoly_set_length(A, k, ectx);
}
void fq_nmod_mpolyun_interp_reduce_lg_mpolyu(
fq_nmod_mpolyu_t A,
fq_nmod_mpolyun_t B,
const fq_nmod_mpoly_ctx_t ectx,
const fq_nmod_mpoly_ctx_t ctx,
const bad_fq_nmod_embed_t emb)
{
slong i, k, Blen;
fq_nmod_mpoly_struct * Acoeff;
fq_nmod_mpolyn_struct * Bcoeff;
ulong * Aexp, * Bexp;
Blen = B->length;
fq_nmod_mpolyu_fit_length(A, Blen, ectx);
Acoeff = A->coeffs;
Bcoeff = B->coeffs;
Aexp = A->exps;
Bexp = B->exps;
k = 0;
for (i = 0; i < Blen; i++)
{
fq_nmod_mpolyn_interp_reduce_lg_mpoly(Acoeff + k, Bcoeff + i, ectx, ctx, emb);
Aexp[k] = Bexp[i];
k += !fq_nmod_mpoly_is_zero(Acoeff + k, ectx);
}
A->length = k;
}
void fq_nmod_mpolyn_interp_lift_lg_mpoly(
fq_nmod_mpolyn_t A,
const fq_nmod_mpoly_ctx_t ctx,
fq_nmod_mpoly_t B,
const fq_nmod_mpoly_ctx_t ectx,
const bad_fq_nmod_embed_t emb)
{
slong lgd = fq_nmod_ctx_degree(ectx->fqctx);
slong N = mpoly_words_per_exp(A->bits, ctx->minfo);
slong i;
FLINT_ASSERT(B->bits == A->bits);
fq_nmod_mpolyn_fit_length(A, B->length, ctx);
for (i = 0; i < B->length; i++)
{
mpoly_monomial_set(A->exps + N*i, B->exps + N*i, N);
bad_n_fq_embed_lg_to_sm(A->coeffs + i, B->coeffs + lgd*i, emb);
FLINT_ASSERT(!n_fq_poly_is_zero(A->coeffs + i));
}
A->length = B->length;
}
void fq_nmod_mpolyun_interp_lift_lg_mpolyu(
fq_nmod_mpolyun_t A,
const fq_nmod_mpoly_ctx_t ctx,
fq_nmod_mpolyu_t B,
const fq_nmod_mpoly_ctx_t ectx,
const bad_fq_nmod_embed_t emb)
{
slong i;
FLINT_ASSERT(B->bits == A->bits);
fq_nmod_mpolyun_fit_length(A, B->length, ctx);
for (i = 0; i < B->length; i++)
{
A->exps[i] = B->exps[i];
fq_nmod_mpolyn_interp_lift_lg_mpoly(A->coeffs + i, ctx, B->coeffs + i, ectx, emb);
FLINT_ASSERT(!fq_nmod_mpolyn_is_zero(A->coeffs + i, ctx));
}
A->length = B->length;
}
static int fq_nmod_mpolyn_interp_crt_lg_mpoly(
slong * lastdeg,
fq_nmod_mpolyn_t F,
fq_nmod_mpolyn_t T,
fq_nmod_poly_t m,
const fq_nmod_mpoly_ctx_t ctx,
fq_nmod_mpoly_t A,
fq_nmod_t inv_m_eval,
const fq_nmod_mpoly_ctx_t ectx,
const bad_fq_nmod_embed_t emb)
{
slong lgd = fq_nmod_ctx_degree(ectx->fqctx);
int changed = 0;
slong i, j, k;
slong N;
fq_nmod_t u, v;
fq_nmod_poly_t u_sm, w;
flint_bitcnt_t bits = A->bits;
slong Flen = F->length, Alen = A->length;
ulong * Fexp = F->exps, * Aexp = A->exps;
ulong * Texp;
ulong * Acoeff = A->coeffs;
n_fq_poly_struct * Fcoeff = F->coeffs;
n_fq_poly_struct * Tcoeff;
fq_nmod_t at;
n_fq_poly_t wt;
FLINT_ASSERT(bits <= FLINT_BITS);
FLINT_ASSERT(F->bits == bits);
FLINT_ASSERT(ctx->minfo->ord == ORD_LEX);
fq_nmod_init(u, ectx->fqctx);
fq_nmod_init(v, ectx->fqctx);
fq_nmod_poly_init(u_sm, ctx->fqctx);
fq_nmod_poly_init(w, ctx->fqctx);
n_fq_poly_init(wt);
fq_nmod_init(at, ectx->fqctx);
fq_nmod_mpolyn_fit_length(T, Flen + Alen, ctx);
Texp = T->exps;
Tcoeff = T->coeffs;
N = mpoly_words_per_exp(bits, ctx->minfo);
i = j = k = 0;
while (i < Flen || j < Alen)
{
if (i < Flen && (j >= Alen
|| mpoly_monomial_gt_nomask(Fexp + N*i, Aexp + N*j, N)))
{
FLINT_ASSERT(!n_fq_poly_is_zero(Fcoeff + i));
FLINT_ASSERT(n_fq_poly_degree(Fcoeff + i) < fq_nmod_poly_degree(m, ctx->fqctx));
bad_fq_nmod_embed_n_fq_sm_to_fq_nmod_lg(v, Fcoeff + i, emb);
if (!fq_nmod_is_zero(v, ectx->fqctx))
{
changed = 1;
fq_nmod_mul(u, v, inv_m_eval, ectx->fqctx);
bad_fq_nmod_embed_lg_to_sm(u_sm, u, emb);
fq_nmod_poly_mul(w, u_sm, m, ctx->fqctx);
n_fq_poly_set_fq_nmod_poly(wt, w, ctx->fqctx);
n_fq_poly_sub(Tcoeff + k, Fcoeff + i, wt, ctx->fqctx);
}
else
{
n_fq_poly_set(Tcoeff + k, Fcoeff + i, ctx->fqctx);
}
FLINT_ASSERT(!n_fq_poly_is_zero(Tcoeff + k));
lastdeg[0] = FLINT_MAX(lastdeg[0], n_fq_poly_degree(Tcoeff + k));
mpoly_monomial_set(Texp + N*k, Fexp + N*i, N);
k++;
i++;
}
else if (j < Alen && (i >= Flen
|| mpoly_monomial_lt_nomask(Fexp + N*i, Aexp + N*j, N)))
{
if (!_n_fq_is_zero(Acoeff + lgd*j, lgd))
{
changed = 1;
n_fq_get_fq_nmod(at, Acoeff + lgd*j, ectx->fqctx);
fq_nmod_mul(u, at, inv_m_eval, ectx->fqctx);
bad_fq_nmod_embed_lg_to_sm(u_sm, u, emb);
fq_nmod_poly_mul(w, m, u_sm, ctx->fqctx);
n_fq_poly_set_fq_nmod_poly(Tcoeff + k, w, ctx->fqctx);
FLINT_ASSERT(!n_fq_poly_is_zero(Tcoeff + k));
lastdeg[0] = FLINT_MAX(lastdeg[0], n_fq_poly_degree(Tcoeff + k));
mpoly_monomial_set(Texp + N*k, Aexp + N*j, N);
k++;
}
j++;
}
else if (i < Flen && j < Alen
&& mpoly_monomial_equal(Fexp + N*i, Aexp + N*j, N))
{
FLINT_ASSERT(!n_fq_poly_is_zero(Fcoeff + i));
FLINT_ASSERT(n_fq_poly_degree(Fcoeff + i) < fq_nmod_poly_degree(m, ctx->fqctx));
bad_fq_nmod_embed_n_fq_sm_to_fq_nmod_lg(u, Fcoeff + i, emb);
n_fq_get_fq_nmod(at, Acoeff + lgd*j, ectx->fqctx);
fq_nmod_sub(v, at, u, ectx->fqctx);
if (!fq_nmod_is_zero(v, ectx->fqctx))
{
changed = 1;
fq_nmod_mul(u, v, inv_m_eval, ectx->fqctx);
bad_fq_nmod_embed_lg_to_sm(u_sm, u, emb);
fq_nmod_poly_mul(w, m, u_sm, ctx->fqctx);
n_fq_poly_set_fq_nmod_poly(wt, w, ctx->fqctx);
n_fq_poly_add(Tcoeff + k, Fcoeff + i, wt, ctx->fqctx);
}
else
{
n_fq_poly_set(Tcoeff + k, Fcoeff + i, ctx->fqctx);
}
FLINT_ASSERT(!n_fq_poly_is_zero(Tcoeff + k));
lastdeg[0] = FLINT_MAX(lastdeg[0], n_fq_poly_degree(Tcoeff + k));
mpoly_monomial_set(Texp + N*k, Aexp + N*j, N);
k++;
i++;
j++;
}
else
{
FLINT_ASSERT(0);
}
}
T->length = k;
if (changed)
{
fq_nmod_mpolyn_swap(T, F);
}
fq_nmod_clear(u, ectx->fqctx);
fq_nmod_clear(v, ectx->fqctx);
fq_nmod_poly_clear(u_sm, ctx->fqctx);
fq_nmod_poly_clear(w, ctx->fqctx);
n_fq_poly_clear(wt);
fq_nmod_clear(at, ectx->fqctx);
return changed;
}
int fq_nmod_mpolyun_interp_crt_lg_mpolyu(
slong * lastdeg,
fq_nmod_mpolyun_t F,
fq_nmod_mpolyun_t T,
fq_nmod_poly_t m,
const fq_nmod_mpoly_ctx_t ctx,
fq_nmod_mpolyu_t A,
const fq_nmod_mpoly_ctx_t ectx,
const bad_fq_nmod_embed_t emb)
{
int changed = 0;
slong i, j, k;
ulong * Texp;
ulong * Fexp;
ulong * Aexp;
slong Flen;
slong Alen;
fq_nmod_mpolyn_t S;
fq_nmod_mpolyn_struct * Tcoeff;
fq_nmod_mpolyn_struct * Fcoeff;
fq_nmod_mpoly_struct * Acoeff;
fq_nmod_mpoly_t zero;
fq_nmod_t inv_m_eval;
lastdeg[0] = -WORD(1);
FLINT_ASSERT(F->bits == T->bits);
FLINT_ASSERT(T->bits == A->bits);
fq_nmod_mpolyn_init(S, F->bits, ctx);
Flen = F->length;
Alen = A->length;
fq_nmod_mpolyun_fit_length(T, Flen + Alen, ctx);
Tcoeff = T->coeffs;
Fcoeff = F->coeffs;
Acoeff = A->coeffs;
Texp = T->exps;
Fexp = F->exps;
Aexp = A->exps;
fq_nmod_mpoly_init(zero, ectx);
fq_nmod_mpoly_fit_length_reset_bits(zero, 0, A->bits, ectx);
fq_nmod_init(inv_m_eval, ectx->fqctx);
bad_fq_nmod_embed_sm_to_lg(inv_m_eval, m, emb);
fq_nmod_inv(inv_m_eval, inv_m_eval, ectx->fqctx);
i = j = k = 0;
while (i < Flen || j < Alen)
{
if (i < Flen && (j >= Alen || Fexp[i] > Aexp[j]))
{
fq_nmod_mpolyn_set(Tcoeff + k, Fcoeff + i, ctx);
changed |= fq_nmod_mpolyn_interp_crt_lg_mpoly(lastdeg, Tcoeff + k,
S, m, ctx, zero, inv_m_eval, ectx, emb);
Texp[k] = Fexp[i];
FLINT_ASSERT(!fq_nmod_mpolyn_is_zero(Tcoeff + k, ctx));
k++;
i++;
}
else if (j < Alen && (i >= Flen || Aexp[j] > Fexp[i]))
{
fq_nmod_mpolyn_zero(Tcoeff + k, ctx);
changed |= fq_nmod_mpolyn_interp_crt_lg_mpoly(lastdeg, Tcoeff + k,
S, m, ctx, Acoeff + j, inv_m_eval, ectx, emb);
Texp[k] = Aexp[j];
FLINT_ASSERT(!fq_nmod_mpolyn_is_zero(Tcoeff + k, ctx));
k++;
j++;
}
else if (i < Flen && j < Alen && (Fexp[i] == Aexp[j]))
{
fq_nmod_mpolyn_set(Tcoeff + k, Fcoeff + i, ctx);
changed |= fq_nmod_mpolyn_interp_crt_lg_mpoly(lastdeg, Tcoeff + k,
S, m, ctx, Acoeff + j, inv_m_eval, ectx, emb);
Texp[k] = Aexp[j];
FLINT_ASSERT(!fq_nmod_mpolyn_is_zero(Tcoeff + k, ctx));
k++;
i++;
j++;
}
else
{
FLINT_ASSERT(0);
}
}
T->length = k;
if (changed)
{
fq_nmod_mpolyun_swap(T, F);
}
fq_nmod_clear(inv_m_eval, ectx->fqctx);
fq_nmod_mpolyn_clear(S, ctx);
fq_nmod_mpoly_clear(zero, ectx);
return changed;
}
static int fq_nmod_mpolyn_interp_mcrt_lg_mpoly(
slong * lastdeg,
fq_nmod_mpolyn_t H,
const fq_nmod_mpoly_ctx_t ctx,
fq_nmod_poly_t m,
fq_nmod_t inv_m_eval,
fq_nmod_mpoly_t A,
const fq_nmod_mpoly_ctx_t ectx,
const bad_fq_nmod_embed_t emb)
{
slong lgd = fq_nmod_ctx_degree(ectx->fqctx);
slong i;
#if FLINT_WANT_ASSERT
slong N = mpoly_words_per_exp(A->bits, ctx->minfo);
#endif
int changed = 0;
fq_nmod_t u, v, at;
fq_nmod_poly_t w, u_sm;
n_fq_poly_t wt;
fq_nmod_init(u, ectx->fqctx);
fq_nmod_init(v, ectx->fqctx);
fq_nmod_poly_init(w, ctx->fqctx);
n_fq_poly_init(wt);
fq_nmod_poly_init(u_sm, ctx->fqctx);
fq_nmod_init(at, ectx->fqctx);
FLINT_ASSERT(H->length == A->length);
FLINT_ASSERT(H->bits == A->bits);
for (i = 0; i < A->length; i++)
{
FLINT_ASSERT(mpoly_monomial_equal(H->exps + N*i, A->exps + N*i, N));
bad_fq_nmod_embed_n_fq_sm_to_fq_nmod_lg(u, H->coeffs + i, emb);
n_fq_get_fq_nmod(at, A->coeffs + lgd*i, ectx->fqctx);
fq_nmod_sub(v, at, u, ectx->fqctx);
if (!fq_nmod_is_zero(v, ectx->fqctx))
{
changed = 1;
fq_nmod_mul(u, v, inv_m_eval, ectx->fqctx);
bad_fq_nmod_embed_lg_to_sm(u_sm, u, emb);
fq_nmod_poly_mul(w, u_sm, m, ctx->fqctx);
n_fq_poly_set_fq_nmod_poly(wt, w, ctx->fqctx);
n_fq_poly_add(H->coeffs + i, H->coeffs + i, wt, ctx->fqctx);
}
*lastdeg = FLINT_MAX(*lastdeg, n_fq_poly_degree(H->coeffs + i));
FLINT_ASSERT(n_fq_poly_degree(H->coeffs + i)
< fq_nmod_poly_degree(m, ctx->fqctx)
+ fq_nmod_poly_degree(emb->h, ctx->fqctx));
}
fq_nmod_clear(u, ectx->fqctx);
fq_nmod_clear(v, ectx->fqctx);
fq_nmod_poly_clear(w, ctx->fqctx);
n_fq_poly_clear(wt);
fq_nmod_poly_clear(u_sm, ctx->fqctx);
fq_nmod_clear(at, ectx->fqctx);
return changed;
}
int fq_nmod_mpolyun_interp_mcrt_lg_mpolyu(
slong * lastdeg,
fq_nmod_mpolyun_t H,
const fq_nmod_mpoly_ctx_t ctx,
fq_nmod_poly_t m,
fq_nmod_mpolyu_t A,
const fq_nmod_mpoly_ctx_t ectx,
bad_fq_nmod_embed_t emb)
{
slong i;
int changed = 0;
fq_nmod_t inv_m_eval;
*lastdeg = -WORD(1);
fq_nmod_init(inv_m_eval, ectx->fqctx);
bad_fq_nmod_embed_sm_to_lg(inv_m_eval, m, emb);
fq_nmod_inv(inv_m_eval, inv_m_eval, ectx->fqctx);
FLINT_ASSERT(H->bits == A->bits);
FLINT_ASSERT(H->length == A->length);
for (i = 0; i < A->length; i++)
{
FLINT_ASSERT(H->exps[i] == A->exps[i]);
changed |= fq_nmod_mpolyn_interp_mcrt_lg_mpoly(lastdeg, H->coeffs + i,
ctx, m, inv_m_eval, A->coeffs + i, ectx, emb);
}
H->length = A->length;
fq_nmod_clear(inv_m_eval, ectx->fqctx);
return changed;
}