#include "fq_nmod.h"
#include "n_poly.h"
#include "mpoly.h"
#include "fq_nmod_mpoly.h"
void fq_nmod_mpoly_get_coeff_vars_ui(
fq_nmod_mpoly_t C,
const fq_nmod_mpoly_t A,
const slong * vars,
const ulong * exps,
slong length,
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);
slong i, j;
slong offset, shift;
slong maxoffset, minoffset;
ulong * uexp;
ulong * tmask, * texp;
slong nvars = ctx->minfo->nvars;
ulong * Ccoeffs;
ulong * Cexps;
slong Clen;
TMP_INIT;
if (C == A)
{
fq_nmod_mpoly_t T;
fq_nmod_mpoly_init(T, ctx);
fq_nmod_mpoly_get_coeff_vars_ui(T, A, vars, exps, length, ctx);
fq_nmod_mpoly_swap(T, C, ctx);
fq_nmod_mpoly_clear(T, ctx);
return;
}
TMP_START;
uexp = (ulong *) TMP_ALLOC(nvars*sizeof(ulong));
for (i = 0; i < nvars; i++)
uexp[i] = 0;
for (i = 0; i < length; i++)
uexp[vars[i]] = exps[i];
if (bits < mpoly_exp_bits_required_ui(uexp, ctx->minfo))
{
fq_nmod_mpoly_zero(C, ctx);
goto cleanup;
}
fq_nmod_mpoly_fit_length_reset_bits(C, 4, bits, ctx);
tmask = (ulong *) TMP_ALLOC(N*sizeof(ulong));
texp = (ulong *) TMP_ALLOC(N*sizeof(ulong));
mpoly_monomial_zero(tmask, N);
mpoly_set_monomial_ui(texp, uexp, bits, ctx->minfo);
if (bits <= FLINT_BITS)
{
ulong mask = (-UWORD(1)) >> (FLINT_BITS - bits);
maxoffset = 0;
minoffset = N;
for (i = 0; i < length; i++)
{
mpoly_gen_offset_shift_sp(&offset, &shift, vars[i], bits, ctx->minfo);
tmask[offset] |= mask << shift;
maxoffset = FLINT_MAX(maxoffset, offset);
minoffset = FLINT_MIN(minoffset, offset);
}
FLINT_ASSERT(minoffset < N);
Ccoeffs = C->coeffs;
Cexps = C->exps;
Clen = 0;
for (i = 0; i < A->length; i++)
{
for (j = minoffset; j <= maxoffset; j++)
{
if ((((A->exps + N*i)[j] ^ texp[j]) & tmask[j]) != UWORD(0))
goto continue_outer_sp;
}
_fq_nmod_mpoly_fit_length(&Ccoeffs, &C->coeffs_alloc, d,
&Cexps, &C->exps_alloc, N, Clen + 1);
mpoly_monomial_sub(Cexps + N*Clen, A->exps + N*i, texp, N);
_n_fq_set(Ccoeffs + d*Clen, A->coeffs + d*i, d);
Clen++;
continue_outer_sp:;
}
C->coeffs = Ccoeffs;
C->exps = Cexps;
_fq_nmod_mpoly_set_length(C, Clen, ctx);
}
else
{
slong wpf = A->bits/FLINT_BITS;
maxoffset = 0;
minoffset = N;
for (i = 0; i < length; i++)
{
offset = mpoly_gen_offset_mp(vars[i], A->bits, ctx->minfo);
minoffset = FLINT_MIN(minoffset, offset);
maxoffset = FLINT_MAX(maxoffset, offset + wpf - 1);
for (j = 0; j < wpf; j++)
tmask[offset + j] = -UWORD(1);
}
FLINT_ASSERT(minoffset < N);
Ccoeffs = C->coeffs;
Cexps = C->exps;
Clen = 0;
for (i = 0; i < A->length; i++)
{
for (j = minoffset; j <= maxoffset; j++)
{
if ((((A->exps + N*i)[j] ^ texp[j]) & tmask[j]) != UWORD(0))
goto continue_outer_mp;
}
_fq_nmod_mpoly_fit_length(&Ccoeffs, &C->coeffs_alloc, d,
&Cexps, &C->exps_alloc, N, Clen + 1);
mpoly_monomial_sub_mp(Cexps + N*Clen, A->exps + N*i, texp, N);
_n_fq_set(Ccoeffs + d*Clen, A->coeffs + d*i, d);
Clen++;
continue_outer_mp:;
}
C->coeffs = Ccoeffs;
C->exps = Cexps;
_fq_nmod_mpoly_set_length(C, Clen, ctx);
}
cleanup:
TMP_END;
return;
}