#include "fmpz.h"
#include "fmpz_vec.h"
#include "n_poly.h"
#include "mpoly.h"
#include "nmod_mpoly.h"
#include "fmpz_mpoly_factor.h"
void fmpz_mpoly_interp_reduce_p(
nmod_mpoly_t Ap,
const nmod_mpoly_ctx_t ctxp,
const fmpz_mpoly_t A,
const fmpz_mpoly_ctx_t ctx)
{
slong i, k, N;
FLINT_ASSERT(Ap->bits == A->bits);
N = mpoly_words_per_exp(A->bits, ctx->minfo);
nmod_mpoly_fit_length(Ap, A->length, ctxp);
k = 0;
for (i = 0; i < A->length; i++)
{
mpoly_monomial_set(Ap->exps + N*k, A->exps + N*i, N);
Ap->coeffs[k] = fmpz_get_nmod(A->coeffs + i, ctxp->mod);
k += (Ap->coeffs[k] != 0);
}
Ap->length = k;
}
void fmpz_mpoly_interp_lift_p(
fmpz_mpoly_t A,
const fmpz_mpoly_ctx_t ctx,
nmod_mpoly_t Ap,
const nmod_mpoly_ctx_t ctxp)
{
slong N = mpoly_words_per_exp(A->bits, ctx->minfo);
FLINT_ASSERT(Ap->bits == A->bits);
fmpz_mpoly_fit_length(A, Ap->length, ctx);
mpoly_copy_monomials(A->exps, Ap->exps, Ap->length, N);
_fmpz_vec_set_nmod_vec(A->coeffs, Ap->coeffs, Ap->length, ctxp->mod);
_fmpz_mpoly_set_length(A, Ap->length, ctx);
}
int fmpz_mpoly_interp_mcrt_p(
flint_bitcnt_t * coeffbits_,
fmpz_mpoly_t H,
const fmpz_mpoly_ctx_t FLINT_UNUSED(ctx),
const fmpz_t m,
const nmod_mpoly_t A,
const nmod_mpoly_ctx_t ctxp)
{
slong i;
#if FLINT_WANT_ASSERT
slong N = mpoly_words_per_exp(A->bits, ctx->minfo);
#endif
int changed = 0;
flint_bitcnt_t coeffbits = 0;
fmpz_t t;
FLINT_ASSERT(H->length == A->length);
FLINT_ASSERT(H->bits == A->bits);
fmpz_init(t);
for (i = 0; i < A->length; i++)
{
FLINT_ASSERT(mpoly_monomial_equal(H->exps + N*i, A->exps + N*i, N));
fmpz_CRT_ui(t, H->coeffs + i, m, A->coeffs[i], ctxp->mod.n, 1);
coeffbits = FLINT_MAX(coeffbits, fmpz_bits(t));
changed |= !fmpz_equal(t, H->coeffs + i);
fmpz_swap(t, H->coeffs + i);
}
fmpz_clear(t);
*coeffbits_ = coeffbits;
return changed;
}
void fmpz_mpoly_interp_reduce_p_mpolyn(
nmod_mpolyn_t E,
const nmod_mpoly_ctx_t pctx,
const fmpz_mpoly_t A,
const fmpz_mpoly_ctx_t ctx)
{
slong N = mpoly_words_per_exp_sp(A->bits, ctx->minfo);
slong offset, shift, k;
ulong mask;
ulong v;
fmpz * Acoeff = A->coeffs;
ulong * Aexp = A->exps;
slong Alen = A->length;
slong Ai;
n_poly_struct * Ecoeff;
ulong * Eexp;
slong Ei;
slong m = ctx->minfo->nvars;
mpoly_gen_offset_shift_sp(&offset, &shift, m - 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++)
{
v = fmpz_get_nmod(Acoeff + Ai, pctx->mod);
k = ((Aexp + N*Ai)[offset] >> shift) & mask;
if (v == 0)
{
continue;
}
if (Ei > 0 && mpoly_monomial_equal_extra(Eexp + N*(Ei - 1),
Aexp + N*Ai, N, offset, -(k << shift)))
{
n_poly_set_coeff(Ecoeff + Ei - 1, k, v);
}
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)
{
nmod_mpolyn_fit_length(E, Ei + 1, pctx);
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_poly_set_coeff(Ecoeff + Ei, k, v);
Ei++;
}
}
E->length = Ei;
}
void fmpz_mpoly_interp_lift_p_mpolyn(
fmpz_mpoly_t A,
const fmpz_mpoly_ctx_t ctx,
const nmod_mpolyn_t B,
const nmod_mpoly_ctx_t pctx)
{
slong N = mpoly_words_per_exp(B->bits, ctx->minfo);
slong offset, shift;
slong vi;
n_poly_struct * Bcoeff = B->coeffs;
ulong * Bexp = B->exps;
slong Blen = B->length;
slong Bi;
fmpz * Acoeff;
ulong * Aexp;
slong Ai;
slong var = ctx->minfo->nvars;
FLINT_ASSERT(var == pctx->minfo->nvars);
fmpz_mpoly_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)
{
fmpz_mpoly_fit_length(A, Ai + (Bcoeff + Bi)->length, ctx);
Acoeff = A->coeffs;
Aexp = A->exps;
}
for (vi = (Bcoeff + Bi)->length - 1; vi >= 0; vi--)
{
if ((Bcoeff + Bi)->coeffs[vi] != 0)
{
mpoly_monomial_set_extra(Aexp + N*Ai, Bexp + N*Bi, N, offset, vi << shift);
fmpz_set_ui_smod(Acoeff + Ai, (Bcoeff + Bi)->coeffs[vi], pctx->mod.n);
Ai++;
}
}
}
A->length = Ai;
}
int fmpz_mpoly_interp_crt_p_mpolyn(
fmpz_mpoly_t F,
fmpz_mpoly_t T,
const fmpz_mpoly_ctx_t ctx,
fmpz_t modulus,
const nmod_mpolyn_t A,
const nmod_mpoly_ctx_t pctx)
{
int changed = 0;
slong N = mpoly_words_per_exp_sp(T->bits, ctx->minfo);
slong offset, shift;
slong vi;
fmpz * Tcoeff;
ulong * Texp;
slong Ti;
n_poly_struct * Acoeff = A->coeffs;
slong Alen = A->length;
ulong * Aexp = A->exps;
slong Ai;
fmpz * Fcoeff = F->coeffs;
slong Flen = F->length;
ulong * Fexp = F->exps;
slong Fi;
fmpz_t zero;
fmpz_init(zero);
FLINT_ASSERT(T->bits == A->bits);
FLINT_ASSERT(F->bits == A->bits);
FLINT_ASSERT(pctx->minfo->nvars == ctx->minfo->nvars);
FLINT_ASSERT(fmpz_mpoly_is_canonical(F, ctx));
FLINT_ASSERT(nmod_mpolyn_is_canonical(A, pctx));
mpoly_gen_offset_shift_sp(&offset, &shift, pctx->minfo->nvars - 1, A->bits, ctx->minfo);
Flen = F->length;
fmpz_mpoly_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)
{
fmpz_mpoly_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))
{
fmpz_CRT_ui(Tcoeff + Ti, Fcoeff + Fi, modulus,
(Acoeff + Ai)->coeffs[vi], pctx->mod.n, 1);
changed |= !fmpz_equal(Tcoeff + Ti, Fcoeff + Fi);
mpoly_monomial_set(Texp + N*Ti, Fexp + N*Fi, N);
Fi++;
do {
vi--;
} while (vi >= 0 && (Acoeff + Ai)->coeffs[vi] == 0);
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)))
{
fmpz_CRT_ui(Tcoeff + Ti, Fcoeff + Fi, modulus, 0, pctx->mod.n, 1);
changed |= !fmpz_equal(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)));
fmpz_CRT_ui(Tcoeff + Ti, zero, modulus, (Acoeff + Ai)->coeffs[vi],
pctx->mod.n, 1);
FLINT_ASSERT(!fmpz_is_zero(Tcoeff + Ti));
changed = 1;
mpoly_monomial_set_extra(Texp + N*Ti, Aexp + N*Ai, N, offset, vi << shift);
do {
vi--;
} while (vi >= 0 && (Acoeff + Ai)->coeffs[vi] == 0);
if (vi < 0)
{
Ai++;
if (Ai < Alen)
vi = n_poly_degree(A->coeffs + Ai);
}
}
FLINT_ASSERT(!fmpz_is_zero(Tcoeff + Ti));
Ti++;
}
T->length = Ti;
if (changed)
{
fmpz_mpoly_swap(F, T, ctx);
}
fmpz_clear(zero);
return changed;
}