#include "fmpz_mod.h"
#include "mpoly.h"
#include "fmpz_mod_mpoly_factor.h"
#if 0#endif
void fmpz_mod_polyu1n_interp_reduce_2sm_poly(
fmpz_mod_poly_t E,
fmpz_mod_poly_t F,
const fmpz_mod_polyun_t A,
fmpz_mod_poly_t alphapow,
const fmpz_mod_ctx_t ctx)
{
slong i;
fmpz_t u, v;
fmpz_init(u);
fmpz_init(v);
fmpz_mod_poly_zero(E, ctx);
fmpz_mod_poly_zero(F, ctx);
for (i = 0; i < A->length; i++)
{
fmpz_mod_poly_eval2_pow(u, v, A->coeffs + i, alphapow, ctx);
fmpz_mod_poly_set_coeff_fmpz(E, A->exps[i], u, ctx);
fmpz_mod_poly_set_coeff_fmpz(F, A->exps[i], v, ctx);
}
fmpz_clear(u);
fmpz_clear(v);
}
void fmpz_mod_polyu1n_interp_lift_2sm_poly(
slong * lastdeg,
fmpz_mod_polyun_t F,
const fmpz_mod_poly_t A,
const fmpz_mod_poly_t B,
const fmpz_t alpha,
const fmpz_mod_ctx_t ctx)
{
slong lastlen = 0;
fmpz_t u, v, d0, d1, Avalue, Bvalue;
slong Fi, Aexp, Bexp;
const fmpz * Acoeff = A->coeffs;
const fmpz * Bcoeff = B->coeffs;
fmpz_mod_poly_struct * Fcoeffs;
ulong * Fexps;
slong e;
fmpz_init(u);
fmpz_init(v);
fmpz_init(d0);
fmpz_init(d1);
fmpz_init(Avalue);
fmpz_init(Bvalue);
Aexp = _fmpz_mod_poly_degree(A);
Bexp = _fmpz_mod_poly_degree(B);
fmpz_mod_polyun_fit_length(F, FLINT_MAX(Aexp, Bexp) + 1, ctx);
Fcoeffs = F->coeffs;
Fexps = F->exps;
fmpz_set_ui(d0, 2);
fmpz_mod_inv(d0, d0, ctx);
fmpz_mod_add(d1, alpha, alpha, ctx);
fmpz_mod_inv(d1, d1, ctx);
Fi = 0;
while (Aexp >= 0 || Bexp >= 0)
{
e = Aexp;
fmpz_zero(Avalue);
fmpz_zero(Bvalue);
if (Aexp == Bexp)
{
fmpz_set(Avalue, Acoeff + Aexp);
fmpz_set(Bvalue, Bcoeff + Bexp);
}
else if (Aexp > Bexp)
{
fmpz_set(Avalue, Acoeff + Aexp);
}
else
{
FLINT_ASSERT(Bexp > Aexp);
e = Bexp;
fmpz_set(Bvalue, Bcoeff + Bexp);
}
FLINT_ASSERT(!fmpz_is_zero(Avalue) || !fmpz_is_zero(Bvalue));
fmpz_mod_add(u, Avalue, Bvalue, ctx);
fmpz_mod_sub(v, Avalue, Bvalue, ctx);
fmpz_mod_mul(u, u, d0, ctx);
fmpz_mod_mul(v, v, d1, ctx);
FLINT_ASSERT(Fi < F->alloc);
Fexps[Fi] = e;
FLINT_ASSERT(!fmpz_is_zero(u) || !fmpz_is_zero(v));
fmpz_mod_poly_fit_length(Fcoeffs + Fi, 2, ctx);
fmpz_set(Fcoeffs[Fi].coeffs + 0, u);
fmpz_set(Fcoeffs[Fi].coeffs + 1, v);
Fcoeffs[Fi].length = 1 + !fmpz_is_zero(v);
lastlen = FLINT_MAX(lastlen, Fcoeffs[Fi].length);
Fi++;
if (e == Aexp)
{
do {
Aexp--;
} while (Aexp >= 0 && fmpz_is_zero(Acoeff + Aexp));
}
if (e == Bexp)
{
do {
Bexp--;
} while (Bexp >= 0 && fmpz_is_zero(Bcoeff + Bexp));
}
}
F->length = Fi;
fmpz_clear(u);
fmpz_clear(v);
fmpz_clear(d0);
fmpz_clear(d1);
fmpz_clear(Avalue);
fmpz_clear(Bvalue);
*lastdeg = lastlen - 1;
return;
}
int fmpz_mod_polyu1n_interp_crt_2sm_poly(
slong * lastdeg,
fmpz_mod_polyun_t F,
fmpz_mod_polyun_t T,
const fmpz_mod_poly_t A,
const fmpz_mod_poly_t B,
const fmpz_mod_poly_t modulus,
fmpz_mod_poly_t alphapow,
const fmpz_mod_ctx_t ctx)
{
int changed = 0, Finc;
slong lastlen = 0;
fmpz_mod_poly_struct * Fvalue;
fmpz_t u, v, FvalueA, FvalueB;
slong Fi, Ti, Aexp, Bexp, e, fexp;
const fmpz * Acoeff = A->coeffs;
const fmpz * Bcoeff = B->coeffs;
slong Flen = F->length;
fmpz_mod_poly_struct * Fcoeffs = F->coeffs;
ulong * Fexps = F->exps;
fmpz_mod_poly_struct * Tcoeffs;
ulong * Texps;
fmpz_mod_poly_t zero;
zero->alloc = 0;
zero->length = 0;
zero->coeffs = NULL;
fmpz_init(u);
fmpz_init(v);
fmpz_init(FvalueA);
fmpz_init(FvalueB);
Fi = 0;
Aexp = _fmpz_mod_poly_degree(A);
Bexp = _fmpz_mod_poly_degree(B);
fmpz_mod_polyun_fit_length(T, Flen + FLINT_MAX(Aexp, Bexp) + 1, ctx);
Tcoeffs = T->coeffs;
Texps = T->exps;
Ti = 0;
#if FLINT_WANT_ASSERT
fmpz_mod_poly_evaluate_fmpz(u, modulus, alphapow->coeffs + 1, ctx);
fmpz_mod_mul(u, u, alphapow->coeffs + 1, ctx);
fmpz_mod_add(u, u, u, ctx);
FLINT_ASSERT(fmpz_is_one(u));
fmpz_mod_neg(v, alphapow->coeffs + 1, ctx);
fmpz_mod_poly_evaluate_fmpz(u, modulus, v, ctx);
fmpz_mod_mul(u, u, alphapow->coeffs + 1, ctx);
fmpz_mod_add(u, u, u, ctx);
FLINT_ASSERT(fmpz_is_one(u));
#endif
while (Fi < Flen || Aexp >= 0 || Bexp >= 0)
{
FLINT_ASSERT(Ti < T->alloc);
fexp = e = -WORD(1);
if (Fi < Flen)
{
fexp = e = Fexps[Fi];
FLINT_ASSERT(!fmpz_mod_poly_is_zero(Fcoeffs + Fi, ctx));
FLINT_ASSERT(_fmpz_mod_poly_degree(Fcoeffs + Fi) < _fmpz_mod_poly_degree(modulus));
}
if (Aexp >= 0)
{
e = FLINT_MAX(e, Aexp);
FLINT_ASSERT(!fmpz_is_zero(Acoeff + Aexp));
}
if (Bexp >= 0)
{
e = FLINT_MAX(e, Bexp);
FLINT_ASSERT(!fmpz_is_zero(Bcoeff + Bexp));
}
FLINT_ASSERT(e >= 0);
Texps[Ti] = e;
Fvalue = zero;
fmpz_zero(FvalueA);
fmpz_zero(FvalueB);
Finc = 0;
if (Fi < Flen && e == fexp)
{
Finc = 1;
Fvalue = Fcoeffs + Fi;
fmpz_mod_poly_eval2_pow(FvalueA, FvalueB, Fcoeffs + Fi, alphapow, ctx);
}
if (e == Aexp)
{
fmpz_mod_sub(FvalueA, FvalueA, Acoeff + Aexp, ctx);
}
if (e == Bexp)
{
fmpz_mod_sub(FvalueB, FvalueB, Bcoeff + Bexp, ctx);
}
fmpz_mod_sub(u, FvalueB, FvalueA, ctx);
fmpz_mod_add(v, FvalueB, FvalueA, ctx);
fmpz_mod_mul(v, v, alphapow->coeffs + 1, ctx);
fmpz_mod_neg(v, v, ctx);
changed |= !fmpz_is_zero(u) || !fmpz_is_zero(v);
fmpz_mod_poly_addmul_linear(Tcoeffs + Ti, Fvalue, modulus, u, v, ctx);
FLINT_ASSERT(Tcoeffs[Ti].length > 0);
lastlen = FLINT_MAX(lastlen, Tcoeffs[Ti].length);
Ti++;
Fi += Finc;
if (e == Aexp)
{
do {
Aexp--;
} while (Aexp >= 0 && fmpz_is_zero(Acoeff + Aexp));
}
if (e == Bexp)
{
do {
Bexp--;
} while (Bexp >= 0 && fmpz_is_zero(Bcoeff + Bexp));
}
}
T->length = Ti;
fmpz_clear(u);
fmpz_clear(v);
fmpz_clear(FvalueA);
fmpz_clear(FvalueB);
if (changed)
fmpz_mod_polyun_swap(T, F);
*lastdeg = lastlen - 1;
return changed;
}
void fmpz_mod_mpolyn_interp_reduce_sm_poly(
fmpz_mod_poly_t E,
const fmpz_mod_mpolyn_t A,
const fmpz_t alpha,
const fmpz_mod_mpoly_ctx_t ctx)
{
fmpz_t v;
slong Ai, Alen, k;
fmpz_mod_poly_struct * Acoeff;
ulong * Aexp;
slong N, off, shift;
fmpz_init(v);
N = mpoly_words_per_exp_sp(A->bits, ctx->minfo);
mpoly_gen_offset_shift_sp(&off, &shift, 0, A->bits, ctx->minfo);
Acoeff = A->coeffs;
Aexp = A->exps;
Alen = A->length;
Ai = 0;
fmpz_mod_poly_zero(E, ctx->ffinfo);
for (Ai = 0; Ai < Alen; Ai++)
{
fmpz_mod_poly_evaluate_fmpz(v, Acoeff + Ai, alpha, ctx->ffinfo);
k = (Aexp + N*Ai)[off] >> shift;
fmpz_mod_poly_set_coeff_fmpz(E, k, v, ctx->ffinfo);
}
fmpz_clear(v);
}
void fmpz_mod_mpolyn_interp_lift_sm_poly(
fmpz_mod_mpolyn_t A,
const fmpz_mod_poly_t B,
const fmpz_mod_mpoly_ctx_t ctx)
{
slong Bi;
slong Blen = fmpz_mod_poly_length(B, ctx->ffinfo);
fmpz * Bcoeff = B->coeffs;
fmpz_mod_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);
fmpz_mod_mpolyn_fit_length(A, Blen, ctx);
Acoeff = A->coeffs;
Aexp = A->exps;
Ai = 0;
for (Bi = Blen - 1; Bi >= 0; Bi--)
{
if (!fmpz_is_zero(Bcoeff + Bi))
{
FLINT_ASSERT(Ai < A->alloc);
fmpz_mod_poly_set_fmpz(Acoeff + Ai, Bcoeff + Bi, ctx->ffinfo);
mpoly_monomial_zero(Aexp + N*Ai, N);
(Aexp + N*Ai)[off] = Bi << shift;
Ai++;
}
}
A->length = Ai;
}
int fmpz_mod_mpolyn_interp_crt_sm_poly(
slong * lastdeg_,
fmpz_mod_mpolyn_t F,
fmpz_mod_mpolyn_t T,
const fmpz_mod_poly_t A,
const fmpz_mod_poly_t modulus,
const fmpz_t alpha,
const fmpz_mod_mpoly_ctx_t ctx)
{
int changed = 0;
slong lastdeg = -WORD(1);
fmpz_t u, v;
slong Fi, Ti, Ai;
fmpz * Acoeff = A->coeffs;
slong Flen = F->length;
fmpz_mod_poly_struct * Fcoeff = F->coeffs;
ulong * Fexp = F->exps;
fmpz_mod_poly_struct * Tcoeff;
ulong * Texp;
fmpz_mod_poly_t tp;
slong N, off, shift;
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 = fmpz_mod_poly_degree(A, ctx->ffinfo);
fmpz_init(u);
fmpz_init(v);
fmpz_mod_poly_init(tp, ctx->ffinfo);
fmpz_mod_mpolyn_fit_length(T, Flen + Ai + 1, ctx);
Tcoeff = T->coeffs;
Texp = T->exps;
Ti = 0;
while (Fi < Flen || Ai >= 0)
{
FLINT_ASSERT(Ti < T->alloc);
if (Fi < Flen)
{
FLINT_ASSERT(!fmpz_mod_poly_is_zero(Fcoeff + Fi, ctx->ffinfo));
FLINT_ASSERT(fmpz_mod_poly_degree(Fcoeff + Fi, ctx->ffinfo) <
fmpz_mod_poly_degree(modulus, ctx->ffinfo));
}
if (Ai >= 0)
{
FLINT_ASSERT(!fmpz_is_zero(Acoeff + Ai));
}
mpoly_monomial_zero(Texp + N*Ti, N);
if (Fi < Flen && Ai >= 0 && ((Fexp + N*Fi)[off]>>shift) == (ulong) Ai)
{
fmpz_mod_poly_evaluate_fmpz(u, Fcoeff + Fi, alpha, ctx->ffinfo);
fmpz_mod_sub(v, Acoeff + Ai, u, ctx->ffinfo);
if (!fmpz_is_zero(v))
{
changed = 1;
fmpz_mod_poly_scalar_mul_fmpz(tp, modulus, v, ctx->ffinfo);
fmpz_mod_poly_add(Tcoeff + Ti, Fcoeff + Fi, tp, ctx->ffinfo);
}
else
{
fmpz_mod_poly_set(Tcoeff + Ti, Fcoeff + Fi, ctx->ffinfo);
}
(Texp + N*Ti)[off] = Ai << shift;
Fi++;
do {
Ai--;
} while (Ai >= 0 && fmpz_is_zero(Acoeff + Ai));
}
else if (Fi < Flen && (Ai < 0 || ((Fexp + N*Fi)[off]>>shift) > (ulong) Ai))
{
fmpz_mod_poly_evaluate_fmpz(v, Fcoeff + Fi, alpha, ctx->ffinfo);
if (!fmpz_is_zero(v))
{
changed = 1;
fmpz_mod_poly_scalar_mul_fmpz(tp, modulus, v, ctx->ffinfo);
fmpz_mod_poly_sub(Tcoeff + Ti, Fcoeff + Fi, tp, ctx->ffinfo);
}
else
{
fmpz_mod_poly_set(Tcoeff + Ti, Fcoeff + Fi, ctx->ffinfo);
}
(Texp + N*Ti)[off] = (Fexp + N*Fi)[off];
Fi++;
}
else if (Ai >= 0 && (Fi >= Flen || ((Fexp + N*Fi)[off]>>shift) < (ulong) Ai))
{
changed = 1;
fmpz_mod_poly_scalar_mul_fmpz(Tcoeff + Ti, modulus, Acoeff + Ai, ctx->ffinfo);
(Texp + N*Ti)[off] = Ai << shift;
do {
Ai--;
} while (Ai >= 0 && fmpz_is_zero(Acoeff + Ai));
}
else
{
FLINT_ASSERT(0);
}
FLINT_ASSERT(!fmpz_mod_poly_is_zero(Tcoeff + Ti, ctx->ffinfo));
lastdeg = FLINT_MAX(lastdeg, fmpz_mod_poly_degree(Tcoeff + Ti, ctx->ffinfo));
Ti++;
}
T->length = Ti;
fmpz_clear(u);
fmpz_clear(v);
fmpz_mod_poly_clear(tp, ctx->ffinfo);
if (changed)
{
fmpz_mod_mpolyn_swap(T, F, ctx);
}
*lastdeg_ = lastdeg;
return changed;
}
void fmpz_mod_mpolyn_interp_reduce_2sm_mpolyn(
fmpz_mod_mpolyn_t E,
fmpz_mod_mpolyn_t F,
fmpz_mod_mpolyn_t A,
slong var,
fmpz_mod_poly_t alphapow,
const fmpz_mod_mpoly_ctx_t ctx)
{
slong N = mpoly_words_per_exp(A->bits, ctx->minfo);
slong offset, shift, k;
ulong mask;
fmpz_t e, f;
fmpz_mod_poly_struct * Acoeff = A->coeffs;
ulong * Aexp = A->exps;
slong Alen = A->length;
slong Ai;
fmpz_mod_poly_struct * Ecoeff;
ulong * Eexp;
slong Ei;
fmpz_mod_poly_struct * Fcoeff;
ulong * Fexp;
slong Fi;
fmpz_init(e);
fmpz_init(f);
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;
Fcoeff = F->coeffs;
Fexp = F->exps;
Fi = 0;
for (Ai = 0; Ai < Alen; Ai++)
{
fmpz_mod_poly_eval2_pow(e, f, Acoeff + Ai, alphapow, ctx->ffinfo);
k = ((Aexp + N*Ai)[offset] >> shift) & mask;
if (!fmpz_is_zero(e))
{
if (Ei > 0 && mpoly_monomial_equal_extra(Eexp + N*(Ei - 1), Aexp + N*Ai, N, offset, -(k << shift)))
{
fmpz_mod_poly_set_coeff_fmpz(Ecoeff + Ei - 1, k, e, ctx->ffinfo);
}
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)
{
fmpz_mod_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));
fmpz_mod_poly_zero(Ecoeff + Ei, ctx->ffinfo);
fmpz_mod_poly_set_coeff_fmpz(Ecoeff + Ei, k, e, ctx->ffinfo);
Ei++;
}
}
if (!fmpz_is_zero(f))
{
if (Fi > 0 && mpoly_monomial_equal_extra(Fexp + N*(Fi - 1), Aexp + N*Ai, N, offset, -(k << shift)))
{
fmpz_mod_poly_set_coeff_fmpz(Fcoeff + Fi - 1, k, f, ctx->ffinfo);
}
else
{
FLINT_ASSERT(Fi == 0 || mpoly_monomial_gt_nomask_extra(Fexp + N*(Fi - 1), Aexp + N*Ai, N, offset, -(k << shift)));
if (Fi >= F->alloc)
{
fmpz_mod_mpolyn_fit_length(F, Fi + 1, ctx);
Fcoeff = F->coeffs;
Fexp = F->exps;
}
mpoly_monomial_set_extra(Fexp + N*Fi, Aexp + N*Ai, N, offset, -(k << shift));
fmpz_mod_poly_zero(Fcoeff + Fi, ctx->ffinfo);
fmpz_mod_poly_set_coeff_fmpz(Fcoeff + Fi, k, f, ctx->ffinfo);
Fi++;
}
}
}
E->length = Ei;
F->length = Fi;
fmpz_clear(e);
fmpz_clear(f);
}
void fmpz_mod_mpolyn_interp_lift_2sm_mpolyn(
slong * lastdeg,
fmpz_mod_mpolyn_t T,
fmpz_mod_mpolyn_t A,
fmpz_mod_mpolyn_t B,
slong var,
const fmpz_t alpha,
const fmpz_mod_mpoly_ctx_t ctx)
{
slong lastlen = 0;
slong N = mpoly_words_per_exp_sp(A->bits, ctx->minfo);
slong offset, shift;
fmpz_mod_poly_struct * Tcoeff;
ulong * Texp;
slong Ti;
fmpz_mod_poly_struct * Acoeff = A->coeffs;
slong Alen = A->length;
ulong * Aexp = A->exps;
slong Ai, ai;
fmpz_mod_poly_struct * Bcoeff = B->coeffs;
slong Blen = B->length;
ulong * Bexp = B->exps;
slong Bi, bi;
fmpz zero0 = 0;
fmpz * Avalue, * Bvalue;
fmpz_t u, v, FvalueA, FvalueB;
int cmp;
fmpz_t d0;
fmpz_init(d0);
fmpz_mod_add(d0, alpha, alpha, ctx->ffinfo);
fmpz_mod_inv(d0, d0, ctx->ffinfo);
fmpz_init(u);
fmpz_init(v);
fmpz_init(FvalueA);
fmpz_init(FvalueB);
FLINT_ASSERT(var > 0);
FLINT_ASSERT(T->bits == A->bits);
mpoly_gen_offset_shift_sp(&offset, &shift, var - 1, A->bits, ctx->minfo);
fmpz_mod_mpolyn_fit_length(T, FLINT_MAX(Alen, Blen), ctx);
Tcoeff = T->coeffs;
Texp = T->exps;
Ti = Ai = Bi = 0;
ai = (Ai >= Alen) ? 0 : A->coeffs[Ai].length - 1;
bi = (Bi >= Blen) ? 0 : B->coeffs[Bi].length - 1;
while (Ai < Alen || Bi < Blen)
{
if (Ti >= T->alloc)
{
slong extra = FLINT_MAX(Alen - Ai, Blen - Bi);
fmpz_mod_mpolyn_fit_length(T, Ti + extra + 1, ctx);
Tcoeff = T->coeffs;
Texp = T->exps;
}
FLINT_ASSERT(Ai >= Alen || !fmpz_is_zero((Acoeff + Ai)->coeffs + ai));
FLINT_ASSERT(Bi >= Blen || !fmpz_is_zero((Bcoeff + Bi)->coeffs + bi));
Avalue = &zero0;
if (Ai < Alen)
{
Avalue = (Acoeff + Ai)->coeffs + ai;
mpoly_monomial_set_extra(Texp + N*Ti,
Aexp + N*Ai, N, offset, ai << shift);
}
Bvalue = &zero0;
if (Bi < Blen)
{
cmp = (Avalue == &zero0) ? -1 : mpoly_monomial_cmp_nomask_extra(
Texp + N*Ti, Bexp + N*Bi, N, offset, bi << shift);
if (cmp <= 0)
{
Bvalue = (Bcoeff + Bi)->coeffs + bi;
}
if (cmp < 0)
{
Avalue = &zero0;
mpoly_monomial_set_extra(Texp + N*Ti,
Bexp + N*Bi, N, offset, bi << shift);
}
}
fmpz_mod_neg(FvalueA, Avalue, ctx->ffinfo);
fmpz_mod_neg(FvalueB, Bvalue, ctx->ffinfo);
fmpz_mod_sub(u, FvalueB, FvalueA, ctx->ffinfo);
fmpz_mod_add(v, FvalueB, FvalueA, ctx->ffinfo);
fmpz_mod_mul(v, alpha, v, ctx->ffinfo);
fmpz_mod_neg(v, v, ctx->ffinfo);
FLINT_ASSERT(!fmpz_is_zero(u) || !fmpz_is_zero(v));
fmpz_mod_poly_zero(Tcoeff + Ti, ctx->ffinfo);
fmpz_mod_mul(u, u, d0, ctx->ffinfo);
fmpz_mod_mul(v, v, d0, ctx->ffinfo);
fmpz_mod_poly_set_coeff_fmpz(Tcoeff + Ti, 0, v, ctx->ffinfo);
fmpz_mod_poly_set_coeff_fmpz(Tcoeff + Ti, 1, u, ctx->ffinfo);
if (Avalue != &zero0)
{
do {
ai--;
} while (ai >= 0 && fmpz_is_zero((Acoeff + Ai)->coeffs + ai));
if (ai < 0)
{
Ai++;
if (Ai < Alen)
ai = A->coeffs[Ai].length - 1;
}
}
if (Bvalue != &zero0)
{
do {
bi--;
} while (bi >= 0 && fmpz_is_zero((Bcoeff + Bi)->coeffs + bi));
if (bi < 0)
{
Bi++;
if (Bi < Blen)
bi = B->coeffs[Bi].length - 1;
}
}
FLINT_ASSERT(!fmpz_mod_poly_is_zero(Tcoeff + Ti, ctx->ffinfo));
lastlen = FLINT_MAX(lastlen, Tcoeff[Ti].length);
Ti++;
}
T->length = Ti;
*lastdeg = lastlen - 1;
FLINT_ASSERT(fmpz_mod_mpolyn_is_canonical(T, ctx));
fmpz_clear(d0);
fmpz_clear(u);
fmpz_clear(v);
fmpz_clear(FvalueA);
fmpz_clear(FvalueB);
return;
}
int fmpz_mod_mpolyn_interp_crt_2sm_mpolyn(
slong * lastdeg,
fmpz_mod_mpolyn_t F,
fmpz_mod_mpolyn_t T,
fmpz_mod_mpolyn_t A,
fmpz_mod_mpolyn_t B,
slong var,
fmpz_mod_poly_t modulus,
fmpz_mod_poly_t alphapow,
const fmpz_mod_mpoly_ctx_t ctx)
{
slong lastlen = 0;
int changed = 0;
slong N = mpoly_words_per_exp_sp(A->bits, ctx->minfo);
slong offset, shift;
fmpz_mod_poly_t zero;
fmpz zero0 = 0;
fmpz_mod_poly_struct * Tcoeff;
ulong * Texp;
slong Ti;
fmpz_mod_poly_struct * Fcoeff = F->coeffs;
slong Flen = F->length;
ulong * Fexp = F->exps;
slong Fi;
fmpz_mod_poly_struct * Acoeff = A->coeffs;
slong Alen = A->length;
ulong * Aexp = A->exps;
slong Ai, ai;
fmpz_mod_poly_struct * Bcoeff = B->coeffs;
slong Blen = B->length;
ulong * Bexp = B->exps;
slong Bi, bi;
fmpz_mod_poly_struct * Fvalue;
fmpz * Avalue, * Bvalue;
fmpz_t u, v, FvalueA, FvalueB;
int texp_set, cmp;
FLINT_ASSERT(fmpz_mod_poly_degree(modulus, ctx->ffinfo) > 0);
zero->coeffs = NULL;
zero->alloc = 0;
zero->length = 0;
fmpz_init(u);
fmpz_init(v);
fmpz_init(FvalueA);
fmpz_init(FvalueB);
#if FLINT_WANT_ASSERT
fmpz_mod_poly_evaluate_fmpz(u, modulus, alphapow->coeffs + 1, ctx->ffinfo);
fmpz_mod_mul(u, u, alphapow->coeffs + 1, ctx->ffinfo);
fmpz_mod_add(u, u, u, ctx->ffinfo);
FLINT_ASSERT(fmpz_is_one(u));
fmpz_mod_neg(v, alphapow->coeffs + 1, ctx->ffinfo);
fmpz_mod_poly_evaluate_fmpz(u, modulus, v, ctx->ffinfo);
fmpz_mod_mul(u, u, alphapow->coeffs + 1, ctx->ffinfo);
fmpz_mod_add(u, u, u, ctx->ffinfo);
FLINT_ASSERT(fmpz_is_one(u));
#endif
FLINT_ASSERT(fmpz_mod_mpolyn_is_canonical(A, ctx));
FLINT_ASSERT(fmpz_mod_mpolyn_is_canonical(B, ctx));
FLINT_ASSERT(fmpz_mod_mpolyn_is_canonical(F, ctx));
FLINT_ASSERT(var > 0);
FLINT_ASSERT(T->bits == A->bits);
FLINT_ASSERT(F->bits == A->bits);
FLINT_ASSERT(A->bits <= FLINT_BITS);
mpoly_gen_offset_shift_sp(&offset, &shift, var - 1, A->bits, ctx->minfo);
Flen = F->length;
fmpz_mod_mpolyn_fit_length(T, FLINT_MAX(Flen, Alen), ctx);
Tcoeff = T->coeffs;
Texp = T->exps;
Ti = Fi = Ai = Bi = 0;
ai = (Ai >= Alen) ? 0 : A->coeffs[Ai].length - 1;
bi = (Bi >= Blen) ? 0 : B->coeffs[Bi].length - 1;
while (Fi < Flen || Ai < Alen || Bi < Blen)
{
if (Ti >= T->alloc)
{
slong extra = Flen - Fi;
extra = FLINT_MAX(extra, Alen - Ai);
extra = FLINT_MAX(extra, Blen - Bi);
fmpz_mod_mpolyn_fit_length(T, Ti + extra + 1, ctx);
Tcoeff = T->coeffs;
Texp = T->exps;
}
FLINT_ASSERT(Fi >= Flen || (Fcoeff + Fi)->length != 0);
FLINT_ASSERT(Ai >= Alen || !fmpz_is_zero((Acoeff + Ai)->coeffs + ai));
FLINT_ASSERT(Bi >= Blen || !fmpz_is_zero((Bcoeff + Bi)->coeffs + bi));
Fvalue = zero;
texp_set = 0;
if (Fi < Flen)
{
Fvalue = Fcoeff + Fi;
texp_set = 1;
mpoly_monomial_set(Texp + N*Ti, Fexp + N*Fi, N);
}
Avalue = &zero0;
if (Ai < Alen)
{
cmp = (!texp_set) ? -1
: mpoly_monomial_cmp_nomask_extra(Texp + N*Ti,
Aexp + N*Ai, N, offset, ai << shift);
if (cmp <= 0)
{
Avalue = (Acoeff + Ai)->coeffs + ai;
}
if (cmp < 0)
{
Fvalue = zero;
texp_set = 1;
mpoly_monomial_set_extra(Texp + N*Ti,
Aexp + N*Ai, N, offset, ai << shift);
}
}
Bvalue = &zero0;
if (Bi < Blen)
{
cmp = (!texp_set) ? -1 : mpoly_monomial_cmp_nomask_extra(
Texp + N*Ti, Bexp + N*Bi, N, offset, bi << shift);
if (cmp <= 0)
{
Bvalue = (Bcoeff + Bi)->coeffs + bi;
}
if (cmp < 0)
{
Fvalue = zero;
Avalue = &zero0;
texp_set = 1;
mpoly_monomial_set_extra(Texp + N*Ti,
Bexp + N*Bi, N, offset, bi << shift);
}
}
FLINT_ASSERT(texp_set);
fmpz_mod_poly_eval2_pow(FvalueA, FvalueB, Fvalue, alphapow, ctx->ffinfo);
fmpz_mod_sub(FvalueA, FvalueA, Avalue, ctx->ffinfo);
fmpz_mod_sub(FvalueB, FvalueB, Bvalue, ctx->ffinfo);
fmpz_mod_sub(u, FvalueB, FvalueA, ctx->ffinfo);
fmpz_mod_add(v, FvalueB, FvalueA, ctx->ffinfo);
fmpz_mod_mul(v, alphapow->coeffs + 1, v, ctx->ffinfo);
fmpz_mod_neg(v, v, ctx->ffinfo);
changed |= !fmpz_is_zero(u) || !fmpz_is_zero(v);
fmpz_mod_poly_addmul_linear(Tcoeff + Ti, Fvalue, modulus, u, v, ctx->ffinfo);
Fi += (Fvalue != zero);
if (Avalue != &zero0)
{
do {
ai--;
} while (ai >= 0 && fmpz_is_zero((Acoeff + Ai)->coeffs + ai));
if (ai < 0)
{
Ai++;
if (Ai < Alen)
ai = A->coeffs[Ai].length - 1;
}
}
if (Bvalue != &zero0)
{
do {
bi--;
} while (bi >= 0 && fmpz_is_zero((Bcoeff + Bi)->coeffs + bi));
if (bi < 0)
{
Bi++;
if (Bi < Blen)
bi = B->coeffs[Bi].length - 1;
}
}
FLINT_ASSERT(!fmpz_mod_poly_is_zero(Tcoeff + Ti, ctx->ffinfo));
lastlen = FLINT_MAX(lastlen, Tcoeff[Ti].length);
Ti++;
}
T->length = Ti;
*lastdeg = lastlen - 1;
if (changed)
fmpz_mod_mpolyn_swap(T, F, ctx);
fmpz_clear(u);
fmpz_clear(v);
fmpz_clear(FvalueA);
fmpz_clear(FvalueB);
FLINT_ASSERT(fmpz_mod_mpolyn_is_canonical(F, ctx));
return changed;
}
void fmpz_mod_mpolyn_interp_lift_sm_mpoly(
fmpz_mod_mpolyn_t A,
const fmpz_mod_mpoly_t B,
const fmpz_mod_mpoly_ctx_t ctx)
{
slong i, N;
fmpz_mod_poly_struct * Acoeff;
const fmpz * Bcoeff;
ulong * Aexp, * Bexp;
slong Blen;
FLINT_ASSERT(A->bits == B->bits);
Blen = B->length;
fmpz_mod_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++)
{
fmpz_mod_poly_set_fmpz(Acoeff + i, Bcoeff + i, ctx->ffinfo);
mpoly_monomial_set(Aexp + N*i, Bexp + N*i, N);
}
A->length = Blen;
}
int fmpz_mod_mpolyn_interp_crt_sm_mpoly(
slong * lastdeg,
fmpz_mod_mpolyn_t F,
fmpz_mod_mpolyn_t T,
fmpz_mod_mpoly_t A,
fmpz_mod_poly_t modulus,
fmpz_mod_poly_t alphapow,
const fmpz_mod_mpoly_ctx_t ctx)
{
slong lastlen = 0;
int changed = 0;
slong i, j, k;
flint_bitcnt_t bits = A->bits;
slong N = mpoly_words_per_exp(bits, ctx->minfo);
slong Flen = F->length, Alen = A->length;
ulong * Fexp = F->exps, * Aexp = A->exps;
ulong * Texp;
fmpz * Acoeff = A->coeffs;
fmpz_mod_poly_struct * Fcoeff = F->coeffs;
fmpz_mod_poly_struct * Tcoeff;
fmpz_t v;
FLINT_ASSERT(F->bits == bits);
FLINT_ASSERT(ctx->minfo->ord == ORD_LEX);
fmpz_mod_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(!fmpz_mod_poly_is_zero(Fcoeff + i, ctx->ffinfo));
FLINT_ASSERT(fmpz_mod_poly_degree(Fcoeff + i, ctx->ffinfo) <
fmpz_mod_poly_degree(modulus, ctx->ffinfo));
fmpz_mod_poly_eval_pow(v, Fcoeff + i, alphapow, ctx->ffinfo);
if (!fmpz_is_zero(v))
{
changed = 1;
fmpz_mod_neg(v, v, ctx->ffinfo);
fmpz_mod_poly_scalar_addmul_fmpz_mod(Tcoeff + k,
Fcoeff + i, modulus, v, ctx->ffinfo);
}
else
{
fmpz_mod_poly_set(Tcoeff + k, Fcoeff + i, ctx->ffinfo);
}
FLINT_ASSERT(!fmpz_mod_poly_is_zero(Tcoeff + k, ctx->ffinfo));
lastlen = FLINT_MAX(lastlen, Tcoeff[k].length);
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)))
{
FLINT_ASSERT(!fmpz_is_zero(Acoeff + j));
changed = 1;
fmpz_mod_poly_scalar_mul_fmpz(Tcoeff + k, modulus, Acoeff + j, ctx->ffinfo);
lastlen = FLINT_MAX(lastlen, Tcoeff[k].length);
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(!fmpz_mod_poly_is_zero(Fcoeff + i, ctx->ffinfo));
FLINT_ASSERT(fmpz_mod_poly_degree(Fcoeff + i, ctx->ffinfo) <
fmpz_mod_poly_degree(modulus, ctx->ffinfo));
fmpz_mod_poly_eval_pow(v, Fcoeff + i, alphapow, ctx->ffinfo);
fmpz_mod_sub(v, Acoeff + j, v, ctx->ffinfo);
if (!fmpz_is_zero(v))
{
changed = 1;
fmpz_mod_poly_scalar_addmul_fmpz_mod(Tcoeff + k,
Fcoeff + i, modulus, v, ctx->ffinfo);
}
else
{
fmpz_mod_poly_set(Tcoeff + k, Fcoeff + i, ctx->ffinfo);
}
FLINT_ASSERT(!fmpz_mod_poly_is_zero(Tcoeff + k, ctx->ffinfo));
lastlen = FLINT_MAX(lastlen, Tcoeff[k].length);
mpoly_monomial_set(Texp + N*k, Aexp + N*j, N);
k++;
i++;
j++;
}
else
{
FLINT_ASSERT(0);
}
}
T->length = k;
*lastdeg = lastlen - 1;
if (changed)
fmpz_mod_mpolyn_swap(T, F, ctx);
return changed;
}
int fmpz_mod_mpolyn_interp_mcrt_sm_mpoly(
slong * lastdeg,
fmpz_mod_mpolyn_t F,
const fmpz_mod_mpoly_t A,
const fmpz_mod_poly_t modulus,
fmpz_mod_poly_t alphapow,
const fmpz_mod_mpoly_ctx_t ctx)
{
slong lastlen = 0;
int changed = 0;
slong i;
fmpz_t v;
fmpz * Acoeff = A->coeffs;
slong Flen = F->length;
FLINT_ASSERT(Flen == A->length);
fmpz_init(v);
for (i = 0; i < Flen; i++)
{
fmpz_mod_poly_eval_pow(v, F->coeffs + i, alphapow, ctx->ffinfo);
fmpz_mod_sub(v, Acoeff + i, v, ctx->ffinfo);
if (!fmpz_is_zero(v))
{
changed = 1;
fmpz_mod_poly_scalar_addmul_fmpz_mod(F->coeffs + i,
F->coeffs + i, modulus, v, ctx->ffinfo);
}
lastlen = FLINT_MAX(lastlen, F->coeffs[i].length);
}
fmpz_clear(v);
*lastdeg = lastlen - 1;
return changed;
}