#include "fmpz.h"
#include "nmod.h"
#include "nmod_vec.h"
#include "nmod_poly.h"
#include "nmod_poly/impl.h"
#include "nmod_mat.h"
#include "gr.h"
#include "gr_vec.h"
#include "gr_mat.h"
#include "gr_poly.h"
#include "gr_generic.h"
static void
_gr_nmod_ctx_write(gr_stream_t out, gr_ctx_t ctx)
{
gr_stream_write(out, "Integers mod ");
gr_stream_write_ui(out, NMOD_CTX(ctx).n);
gr_stream_write(out, " (_gr_nmod)");
}
static truth_t
_gr_nmod_ctx_is_field(const gr_ctx_t ctx)
{
if (NMOD_IS_PRIME(ctx) != T_UNKNOWN)
return NMOD_IS_PRIME(ctx);
return n_is_prime(NMOD_CTX(ctx).n) ? T_TRUE : T_FALSE;
}
static int
_gr_nmod_ctx_set_is_field(gr_ctx_t ctx, truth_t is_field)
{
NMOD_IS_PRIME(ctx) = is_field;
return GR_SUCCESS;
}
static void
_gr_nmod_init(ulong * x, const gr_ctx_t ctx)
{
x[0] = 0;
}
static void
_gr_nmod_clear(ulong * x, const gr_ctx_t ctx)
{
}
static void
_gr_nmod_swap(ulong * x, ulong * y, const gr_ctx_t ctx)
{
ulong t;
t = *x;
*x = *y;
*y = t;
}
static void
_gr_nmod_set_shallow(ulong * res, const ulong * x, const gr_ctx_t ctx)
{
*res = *x;
}
static int
_gr_nmod_randtest(ulong * res, flint_rand_t state, const gr_ctx_t ctx)
{
res[0] = n_randtest(state) % NMOD_CTX(ctx).n;
return GR_SUCCESS;
}
static int
_gr_nmod_write(gr_stream_t out, const ulong * x, const gr_ctx_t ctx)
{
gr_stream_write_ui(out, x[0]);
return GR_SUCCESS;
}
static int
_gr_nmod_zero(ulong * x, const gr_ctx_t ctx)
{
x[0] = 0;
return GR_SUCCESS;
}
static int
_gr_nmod_one(ulong * x, const gr_ctx_t ctx)
{
x[0] = (NMOD_CTX(ctx).n != 1);
return GR_SUCCESS;
}
static int
_gr_nmod_set_si(ulong * res, slong v, const gr_ctx_t ctx)
{
res[0] = nmod_set_si(v, NMOD_CTX(ctx));
return GR_SUCCESS;
}
static int
_gr_nmod_set_ui(ulong * res, ulong v, const gr_ctx_t ctx)
{
res[0] = nmod_set_ui(v, NMOD_CTX(ctx));
return GR_SUCCESS;
}
static int
_gr_nmod_set_fmpz(ulong * res, const fmpz_t v, const gr_ctx_t ctx)
{
nmod_t mod = NMOD_CTX(ctx);
res[0] = fmpz_get_nmod(v, mod);
return GR_SUCCESS;
}
static int
_gr_nmod_get_fmpz(fmpz_t res, const ulong * x, const gr_ctx_t ctx)
{
fmpz_set_ui(res, x[0]);
return GR_SUCCESS;
}
static int
_gr_nmod_inv(ulong * res, const ulong * x, const gr_ctx_t ctx)
{
ulong r, g;
if (x[0] == 1)
{
res[0] = x[0];
return GR_SUCCESS;
}
g = n_gcdinv(&r, x[0], NMOD_CTX(ctx).n);
if (g == 1)
{
res[0] = r;
return GR_SUCCESS;
}
else
{
res[0] = 0;
return GR_DOMAIN;
}
}
#include "fmpz_mod.h"
typedef struct
{
fmpz_mod_ctx_struct ctx;
truth_t is_prime;
}
fmpz_mod_ctx_extended_struct;
#define FMPZ_MOD_CTX(ring_ctx) (&(((fmpz_mod_ctx_extended_struct *)(GR_CTX_DATA_AS_PTR(ring_ctx)))->ctx))
static int
_gr_nmod_set_other(ulong * res, gr_ptr v, gr_ctx_t v_ctx, const gr_ctx_t ctx)
{
if (v_ctx->which_ring == GR_CTX_NMOD)
{
if (NMOD_CTX(ctx).n != NMOD_CTX(v_ctx).n)
return GR_DOMAIN;
*res = *((ulong *) v);
return GR_SUCCESS;
}
if (v_ctx->which_ring == GR_CTX_NMOD_REDC || v_ctx->which_ring == GR_CTX_NMOD_REDC_FAST)
{
if (NMOD_CTX(ctx).n != GR_NMOD_REDC_N(v_ctx))
return GR_DOMAIN;
res[0] = nmod_redc_get_nmod(((ulong *) v)[0], GR_NMOD_REDC_CTX(v_ctx));
return GR_SUCCESS;
}
if (v_ctx->which_ring == GR_CTX_FMPZ_MOD)
{
if (!fmpz_equal_ui(FMPZ_MOD_CTX(v_ctx)->n, NMOD_CTX(ctx).n))
return GR_DOMAIN;
res[0] = fmpz_get_ui(v);
return GR_SUCCESS;
}
if (v_ctx->which_ring == GR_CTX_FMPZ)
{
res[0] = fmpz_get_nmod(v, NMOD_CTX(ctx));
return GR_SUCCESS;
}
if (v_ctx->which_ring == GR_CTX_FMPQ)
{
ulong a, b;
int status;
const fmpq * q = v;
if (fmpz_is_one(fmpq_denref(q)))
{
res[0] = fmpz_get_nmod(fmpq_numref(q), NMOD_CTX(ctx));
}
else
{
b = fmpz_get_nmod(fmpq_denref(q), NMOD_CTX(ctx));
status = _gr_nmod_inv(&b, &b, ctx);
if (status != GR_SUCCESS)
return status;
a = fmpz_get_nmod(fmpq_numref(q), NMOD_CTX(ctx));
res[0] = nmod_mul(a, b, NMOD_CTX(ctx));
}
return GR_SUCCESS;
}
return GR_UNABLE;
}
static truth_t
_gr_nmod_is_zero(const ulong * x, const gr_ctx_t ctx)
{
return (x[0] == 0) ? T_TRUE : T_FALSE;
}
static truth_t
_gr_nmod_is_one(const ulong * x, const gr_ctx_t ctx)
{
return (x[0] == (NMOD_CTX(ctx).n != 1)) ? T_TRUE : T_FALSE;
}
static truth_t
_gr_nmod_is_neg_one(const ulong * x, const gr_ctx_t ctx)
{
return (x[0] == NMOD_CTX(ctx).n - 1) ? T_TRUE : T_FALSE;
}
static truth_t
_gr_nmod_equal(const ulong * x, const ulong * y, const gr_ctx_t ctx)
{
return (x[0] == y[0]) ? T_TRUE : T_FALSE;
}
static int
_gr_nmod_set(ulong * res, const ulong * x, const gr_ctx_t ctx)
{
res[0] = x[0];
return GR_SUCCESS;
}
static int
_gr_nmod_neg(ulong * res, const ulong * x, const gr_ctx_t ctx)
{
res[0] = nmod_neg(x[0], NMOD_CTX(ctx));
return GR_SUCCESS;
}
static int
_gr_nmod_add(ulong * res, const ulong * x, const ulong * y, const gr_ctx_t ctx)
{
res[0] = nmod_add(x[0], y[0], NMOD_CTX(ctx));
return GR_SUCCESS;
}
static int
_gr_nmod_add_ui(ulong * res, const ulong * x, ulong y, const gr_ctx_t ctx)
{
res[0] = nmod_add(x[0], nmod_set_ui(y, NMOD_CTX(ctx)), NMOD_CTX(ctx));
return GR_SUCCESS;
}
static int
_gr_nmod_add_si(ulong * res, const ulong * x, slong y, const gr_ctx_t ctx)
{
res[0] = nmod_add(x[0], nmod_set_si(y, NMOD_CTX(ctx)), NMOD_CTX(ctx));
return GR_SUCCESS;
}
static int
_gr_nmod_sub(ulong * res, const ulong * x, const ulong * y, const gr_ctx_t ctx)
{
res[0] = nmod_sub(x[0], y[0], NMOD_CTX(ctx));
return GR_SUCCESS;
}
static int
_gr_nmod_sub_ui(ulong * res, const ulong * x, ulong y, const gr_ctx_t ctx)
{
res[0] = nmod_sub(x[0], nmod_set_ui(y, NMOD_CTX(ctx)), NMOD_CTX(ctx));
return GR_SUCCESS;
}
static int
_gr_nmod_sub_si(ulong * res, const ulong * x, slong y, const gr_ctx_t ctx)
{
res[0] = nmod_sub(x[0], nmod_set_si(y, NMOD_CTX(ctx)), NMOD_CTX(ctx));
return GR_SUCCESS;
}
static int
_gr_nmod_mul(ulong * res, const ulong * x, const ulong * y, const gr_ctx_t ctx)
{
res[0] = nmod_mul(x[0], y[0], NMOD_CTX(ctx));
return GR_SUCCESS;
}
static int
_gr_nmod_mul_ui(ulong * res, const ulong * x, ulong y, const gr_ctx_t ctx)
{
res[0] = n_mulmod2_preinv(x[0], y, NMOD_CTX(ctx).n, NMOD_CTX(ctx).ninv);
return GR_SUCCESS;
}
static int
_gr_nmod_mul_si(ulong * res, const ulong * x, slong y, const gr_ctx_t ctx)
{
if (y >= 0)
res[0] = n_mulmod2_preinv(x[0], y, NMOD_CTX(ctx).n, NMOD_CTX(ctx).ninv);
else
res[0] = nmod_neg(n_mulmod2_preinv(x[0], -y, NMOD_CTX(ctx).n, NMOD_CTX(ctx).ninv), NMOD_CTX(ctx));
return GR_SUCCESS;
}
static int
_gr_nmod_mul_fmpz(ulong * res, const ulong * x, const fmpz_t y, const gr_ctx_t ctx)
{
if (!COEFF_IS_MPZ(*y))
{
if (*y >= 0)
res[0] = n_mulmod2_preinv(x[0], *y, NMOD_CTX(ctx).n, NMOD_CTX(ctx).ninv);
else
res[0] = nmod_neg(n_mulmod2_preinv(x[0], -*y, NMOD_CTX(ctx).n, NMOD_CTX(ctx).ninv), NMOD_CTX(ctx));
}
else
{
res[0] = nmod_mul(x[0], fmpz_get_nmod(y, NMOD_CTX(ctx)), NMOD_CTX(ctx));
}
return GR_SUCCESS;
}
static int
_gr_nmod_addmul(ulong * res, const ulong * x, const ulong * y, const gr_ctx_t ctx)
{
res[0] = nmod_addmul(res[0], x[0], y[0], NMOD_CTX(ctx));
return GR_SUCCESS;
}
static int
_gr_nmod_submul(ulong * res, const ulong * x, const ulong * y, const gr_ctx_t ctx)
{
res[0] = nmod_addmul(res[0], x[0], nmod_neg(y[0], NMOD_CTX(ctx)), NMOD_CTX(ctx));
return GR_SUCCESS;
}
static int
_gr_nmod_mul_two(ulong * res, const ulong * x, const gr_ctx_t ctx)
{
return _gr_nmod_add(res, x, x, ctx);
}
static int
_gr_nmod_sqr(ulong * res, const ulong * x, const gr_ctx_t ctx)
{
return _gr_nmod_mul(res, x, x, ctx);
}
static int
_gr_nmod_div(ulong * res, const ulong * x, const ulong * y, const gr_ctx_t ctx)
{
ulong t;
int status;
status = _gr_nmod_inv(&t, y, ctx);
if (status == GR_SUCCESS)
_gr_nmod_mul(res, x, &t, ctx);
return status;
}
static int
_gr_nmod_div_si(ulong * res, const ulong * x, slong y, const gr_ctx_t ctx)
{
ulong c = nmod_set_si(y, NMOD_CTX(ctx));
return _gr_nmod_div(res, x, &c, ctx);
}
static int
_gr_nmod_div_ui(ulong * res, const ulong * x, ulong y, const gr_ctx_t ctx)
{
ulong c = nmod_set_ui(y, NMOD_CTX(ctx));
return _gr_nmod_div(res, x, &c, ctx);
}
static int
_gr_nmod_div_fmpz(ulong * res, const ulong * x, const fmpz_t y, const gr_ctx_t ctx)
{
ulong c = fmpz_get_nmod(y, NMOD_CTX(ctx));
return _gr_nmod_div(res, x, &c, ctx);
}
static truth_t
_gr_nmod_is_invertible(const ulong * x, const gr_ctx_t ctx)
{
ulong r, g;
g = n_gcdinv(&r, x[0], NMOD_CTX(ctx).n);
return (g == 1) ? T_TRUE : T_FALSE;
}
static truth_t
_gr_nmod_divides(const ulong * x, const ulong * y, const gr_ctx_t ctx)
{
ulong t;
return nmod_divides(&t, y[0], x[0], NMOD_CTX(ctx)) ? T_TRUE : T_FALSE;
}
static int
_gr_nmod_div_nonunique(ulong * res, const ulong * x, const ulong * y, const gr_ctx_t ctx)
{
ulong t;
int status;
status = _gr_nmod_inv(&t, y, ctx);
if (status == GR_SUCCESS)
{
_gr_nmod_mul(res, x, &t, ctx);
}
else
{
status = nmod_divides(res, *x, *y, NMOD_CTX(ctx)) ? GR_SUCCESS : GR_DOMAIN;
}
return status;
}
static int
_gr_nmod_mul_2exp_si(ulong * res, ulong * x, slong y, const gr_ctx_t ctx)
{
ulong c, m = NMOD_CTX(ctx).n;
if (y >= 0)
{
if ((ulong) y <= NMOD_CTX(ctx).norm)
{
res[0] = nmod_set_ui(x[0] << (ulong) y, NMOD_CTX(ctx));
}
else
{
c = nmod_2_pow_ui(y, NMOD_CTX(ctx));
res[0] = nmod_mul(x[0], c, NMOD_CTX(ctx));
}
}
else
{
if (m == 1)
{
res[0] = 0;
return GR_SUCCESS;
}
if (m % 2 == 0)
return GR_DOMAIN;
c = (m - 1) / 2 + 1;
c = nmod_pow_ui(c, -y, NMOD_CTX(ctx));
res[0] = nmod_mul(x[0], c, NMOD_CTX(ctx));
}
return GR_SUCCESS;
}
static int
_gr_nmod_sqrt(ulong * res, const ulong * x, gr_ctx_t ctx)
{
if (x[0] <= 1)
{
res[0] = x[0];
return GR_SUCCESS;
}
if (gr_ctx_is_field(ctx) != T_TRUE)
return GR_UNABLE;
res[0] = n_sqrtmod(x[0], NMOD_CTX(ctx).n);
if (res[0] == 0)
return GR_DOMAIN;
else
return GR_SUCCESS;
}
static truth_t
_gr_nmod_is_square(const ulong * x, gr_ctx_t ctx)
{
ulong y;
if (x[0] <= 1)
return T_TRUE;
if (gr_ctx_is_field(ctx) != T_TRUE)
return T_UNKNOWN;
y = n_sqrtmod(x[0], NMOD_CTX(ctx).n);
if (y == 0)
return T_FALSE;
else
return T_TRUE;
}
static int
_gr_nmod_pow_ui(ulong * res, const ulong * x, ulong y, const gr_ctx_t ctx)
{
res[0] = nmod_pow_ui(x[0], y, NMOD_CTX(ctx));
return GR_SUCCESS;
}
static int
_gr_nmod_pow_fmpz(ulong * res, const ulong * x, const fmpz_t y, gr_ctx_t ctx)
{
if (fmpz_sgn(y) < 0)
{
return gr_generic_pow_fmpz(res, x, y, ctx);
}
else
{
res[0] = nmod_pow_fmpz(x[0], y, NMOD_CTX(ctx));
return GR_SUCCESS;
}
}
static void
_gr_nmod_vec_init(ulong * res, slong len, gr_ctx_t ctx)
{
slong i;
for (i = 0; i < len; i++)
res[i] = 0;
}
static void
_gr_nmod_vec_clear(ulong * res, slong len, gr_ctx_t ctx)
{
}
static int
_gr_nmod_vec_set(ulong * res, const ulong * vec, slong len, gr_ctx_t ctx)
{
slong i;
for (i = 0; i < len; i++)
res[i] = vec[i];
return GR_SUCCESS;
}
static int
_gr_nmod_vec_normalise(slong * res, const ulong * vec, slong len, gr_ctx_t ctx)
{
while (len > 0 && vec[len - 1] == 0)
len--;
res[0] = len;
return GR_SUCCESS;
}
static slong
_gr_nmod_vec_normalise_weak(const ulong * vec, slong len, gr_ctx_t ctx)
{
while (len > 0 && vec[len - 1] == 0)
len--;
return len;
}
static int
_gr_nmod_vec_neg(ulong * res, const ulong * vec, slong len, gr_ctx_t ctx)
{
slong i;
nmod_t mod = NMOD_CTX(ctx);
for (i = 0; i < len; i++)
res[i] = nmod_neg(vec[i], mod);
return GR_SUCCESS;
}
static int
_gr_nmod_vec_add(ulong * res, const ulong * vec1, const ulong * vec2, slong len, gr_ctx_t ctx)
{
slong i;
nmod_t mod = NMOD_CTX(ctx);
for (i = 0; i < len; i++)
res[i] = nmod_add(vec1[i], vec2[i], mod);
return GR_SUCCESS;
}
static int
_gr_nmod_vec_sub(ulong * res, const ulong * vec1, const ulong * vec2, slong len, gr_ctx_t ctx)
{
slong i;
nmod_t mod = NMOD_CTX(ctx);
for (i = 0; i < len; i++)
res[i] = nmod_sub(vec1[i], vec2[i], mod);
return GR_SUCCESS;
}
static int
_gr_nmod_vec_mul(ulong * res, const ulong * vec1, const ulong * vec2, slong len, gr_ctx_t ctx)
{
slong i;
nmod_t mod = NMOD_CTX(ctx);
for (i = 0; i < len; i++)
res[i] = nmod_mul(vec1[i], vec2[i], mod);
return GR_SUCCESS;
}
static int
_gr_nmod_vec_mul_scalar(ulong * res, const ulong * vec1, slong len, const ulong * c, gr_ctx_t ctx)
{
_nmod_vec_scalar_mul_nmod(res, vec1, len, c[0], NMOD_CTX(ctx));
return GR_SUCCESS;
}
static int
_gr_nmod_scalar_mul_vec(ulong * res, ulong * c, const ulong * vec1, slong len, gr_ctx_t ctx)
{
_nmod_vec_scalar_mul_nmod(res, vec1, len, c[0], NMOD_CTX(ctx));
return GR_SUCCESS;
}
static int
_gr_nmod_vec_mul_scalar_si(ulong * res, const ulong * vec1, slong len, slong c, gr_ctx_t ctx)
{
nmod_t mod = NMOD_CTX(ctx);
_nmod_vec_scalar_mul_nmod(res, vec1, len, nmod_set_si(c, mod), NMOD_CTX(ctx));
return GR_SUCCESS;
}
static int
_gr_nmod_vec_mul_scalar_ui(ulong * res, const ulong * vec1, slong len, ulong c, gr_ctx_t ctx)
{
nmod_t mod = NMOD_CTX(ctx);
_nmod_vec_scalar_mul_nmod(res, vec1, len, nmod_set_ui(c, mod), NMOD_CTX(ctx));
return GR_SUCCESS;
}
static int
_gr_nmod_vec_mul_scalar_fmpz(ulong * res, const ulong * vec1, slong len, const fmpz_t c, gr_ctx_t ctx)
{
nmod_t mod = NMOD_CTX(ctx);
_nmod_vec_scalar_mul_nmod(res, vec1, len, fmpz_get_nmod(c, mod), NMOD_CTX(ctx));
return GR_SUCCESS;
}
static int
_gr_nmod_vec_mul_scalar_2exp_si(ulong * res, const ulong * vec1, slong len, slong c, gr_ctx_t ctx)
{
ulong t[1];
int status = GR_SUCCESS;
if (c == 1)
return _gr_nmod_vec_add(res, vec1, vec1, len, ctx);
status |= _gr_nmod_one(t, ctx);
status |= _gr_nmod_mul_2exp_si(t, t, c, ctx);
status |= _gr_nmod_vec_mul_scalar(res, vec1, len, t, ctx);
return status;
}
static int
_gr_nmod_vec_addmul_scalar(ulong * res, const ulong * vec1, slong len, const ulong * c, gr_ctx_t ctx)
{
nmod_t mod = NMOD_CTX(ctx);
_nmod_vec_scalar_addmul_nmod(res, vec1, len, c[0], mod);
return GR_SUCCESS;
}
static int
_gr_nmod_vec_submul_scalar(ulong * res, const ulong * vec1, slong len, const ulong * c, gr_ctx_t ctx)
{
nmod_t mod = NMOD_CTX(ctx);
_nmod_vec_scalar_addmul_nmod(res, vec1, len, nmod_neg(c[0], mod), mod);
return GR_SUCCESS;
}
static int
_gr_nmod_vec_addmul_scalar_si(ulong * res, const ulong * vec1, slong len, slong c, gr_ctx_t ctx)
{
nmod_t mod = NMOD_CTX(ctx);
_nmod_vec_scalar_addmul_nmod(res, vec1, len, nmod_set_si(c, mod), mod);
return GR_SUCCESS;
}
static int
_gr_nmod_vec_submul_scalar_si(ulong * res, const ulong * vec1, slong len, slong c, gr_ctx_t ctx)
{
nmod_t mod = NMOD_CTX(ctx);
_nmod_vec_scalar_addmul_nmod(res, vec1, len, nmod_neg(nmod_set_si(c, mod), mod), mod);
return GR_SUCCESS;
}
static int
_gr_nmod_vec_sum(ulong * res, const ulong * vec, slong len, gr_ctx_t ctx)
{
ulong hi, lo;
slong i;
nmod_t mod = NMOD_CTX(ctx);
if (len < 10)
{
lo = 0;
for (i = 0; i < len; i++)
lo = nmod_add(lo, vec[i], mod);
}
else
{
umul_ppmm(hi, lo, mod.n, len);
if (hi == 0)
{
lo = vec[0];
for (i = 1; i < len; i++)
lo += vec[i];
NMOD_RED(lo, lo, mod);
}
else
{
lo = vec[0];
hi = 0;
for (i = 1; i < len; i++)
add_ssaaaa(hi, lo, hi, lo, 0, vec[i]);
NMOD2_RED2(lo, hi, lo, mod);
}
}
res[0] = lo;
return GR_SUCCESS;
}
static int
_gr_nmod_vec_product(ulong * res, const ulong * vec, slong len, gr_ctx_t ctx)
{
nmod_t mod = NMOD_CTX(ctx);
if (len <= 2)
{
if (len == 2)
res[0] = nmod_mul(vec[0], vec[1], mod);
else if (len == 1)
res[0] = vec[0];
else
res[0] = (mod.n != 1);
}
else
{
ulong p;
slong i;
if (mod.norm == 0)
{
p = _nmod_mul_fullword(vec[0], vec[1], mod);
for (i = 2; i < len; i++)
p = _nmod_mul_fullword(p, vec[i], mod);
}
else
{
p = nmod_mul(vec[0], vec[1], mod);
for (i = 2; i < len; i++)
p = nmod_mul(p, vec[i], mod);
}
res[0] = p;
}
return GR_SUCCESS;
}
static int
__gr_nmod_vec_dot(ulong * res, const ulong * initial, int subtract, const ulong * vec1, const ulong * vec2, slong len, gr_ctx_t ctx)
{
ulong s;
dot_params_t params;
nmod_t mod;
if (len == 0)
{
if (initial == NULL)
_gr_nmod_zero(res, ctx);
else
_gr_nmod_set(res, initial, ctx);
return GR_SUCCESS;
}
mod = NMOD_CTX(ctx);
params = _nmod_vec_dot_params(len, mod);
s = _nmod_vec_dot(vec1, vec2, len, mod, params);
if (initial == NULL)
{
if (subtract)
s = nmod_neg(s, mod);
}
else
{
if (subtract)
s = nmod_sub(initial[0], s, mod);
else
s = nmod_add(initial[0], s, mod);
}
*res = s;
return GR_SUCCESS;
}
static int
__gr_nmod_vec_dot_rev(ulong * res, const ulong * initial, int subtract, const ulong * vec1, const ulong * vec2, slong len, gr_ctx_t ctx)
{
ulong s;
dot_params_t params;
nmod_t mod;
if (len == 0)
{
if (initial == NULL)
_gr_nmod_zero(res, ctx);
else
_gr_nmod_set(res, initial, ctx);
return GR_SUCCESS;
}
mod = NMOD_CTX(ctx);
params = _nmod_vec_dot_params(len, mod);
s = _nmod_vec_dot_rev(vec1, vec2, len, mod, params);
if (initial == NULL)
{
if (subtract)
s = nmod_neg(s, mod);
}
else
{
if (subtract)
s = nmod_sub(initial[0], s, mod);
else
s = nmod_add(initial[0], s, mod);
}
*res = s;
return GR_SUCCESS;
}
static int
_gr_nmod_vec_reciprocals(ulong * res, slong len, gr_ctx_t ctx)
{
nmod_t mod = NMOD_CTX(ctx);
slong k;
ulong c2;
if (len <= 1)
{
if (len == 1)
res[0] = (mod.n != 1);
return GR_SUCCESS;
}
if (mod.n <= len || mod.n % 2 == 0)
return GR_DOMAIN;
res[0] = 1;
res[1] = c2 = (mod.n - 1) / 2 + 1;;
for (k = 3; k <= len; k += 2)
{
if (n_gcdinv(res + k - 1, k, mod.n) != 1)
return GR_DOMAIN;
}
for (k = 4; k <= len; k += 2)
res[k - 1] = nmod_mul(res[k / 2 - 1], c2, mod);
return GR_SUCCESS;
}
static int
_gr_nmod_poly_mullow(ulong * res,
const ulong * poly1, slong len1,
const ulong * poly2, slong len2, slong n, gr_ctx_t ctx)
{
if (len1 + len2 - 1 == n)
{
if (len1 >= len2)
_nmod_poly_mul(res, poly1, len1, poly2, len2, NMOD_CTX(ctx));
else
_nmod_poly_mul(res, poly2, len2, poly1, len1, NMOD_CTX(ctx));
}
else
{
if (len1 >= len2)
_nmod_poly_mullow(res, poly1, len1, poly2, len2, n, NMOD_CTX(ctx));
else
_nmod_poly_mullow(res, poly2, len2, poly1, len1, n, NMOD_CTX(ctx));
}
return GR_SUCCESS;
}
static int
_gr_nmod_poly_mulmid(ulong * res,
const ulong * poly1, slong len1,
const ulong * poly2, slong len2, slong nlo, slong nhi, gr_ctx_t ctx)
{
_nmod_poly_mulmid(res, poly1, len1, poly2, len2, nlo, nhi, NMOD_CTX(ctx));
return GR_SUCCESS;
}
static int
_gr_nmod_poly_divrem(nn_ptr Q, nn_ptr R, nn_srcptr A, slong lenA,
nn_srcptr B, slong lenB, gr_ctx_t ctx)
{
#if FLINT_BITS == 64 && defined(__AVX2__)
if (lenA - lenB < 80 || lenB < ((NMOD_BITS(NMOD_CTX(ctx)) <= 27) ? 400 : 80))
#else
if (lenA - lenB < 80 || lenB < ((NMOD_BITS(NMOD_CTX(ctx)) <= 27) ? 200 : 80))
#endif
{
ulong invB;
int status;
status = _gr_nmod_inv(&invB, &B[lenB - 1], ctx);
if (status != GR_SUCCESS)
return status;
_nmod_poly_divrem_basecase_preinv1(Q, R, A, lenA, B, lenB, invB, NMOD_CTX(ctx));
return status;
}
else
{
#if FLINT_HAVE_FFT_SMALL
return _gr_poly_divrem_newton(Q, R, A, lenA, B, lenB, ctx);
#else
if (NMOD_BITS(NMOD_CTX(ctx)) >= 16 && lenB >= 1024 && lenA <= 16384)
return _gr_poly_divrem_divconquer(Q, R, A, lenA, B, lenB, 16, ctx);
else
return _gr_poly_divrem_newton(Q, R, A, lenA, B, lenB, ctx);
#endif
}
}
static int
_gr_nmod_poly_divexact(nn_ptr Q, nn_srcptr A, slong lenA, nn_srcptr B, slong lenB, gr_ctx_t ctx)
{
slong lenQ = lenA - lenB + 1;
if (lenB <= 40 || lenQ <= 20)
return _gr_poly_divexact_basecase(Q, A, lenA, B, lenB, ctx);
else if (lenB <= 60 || lenQ <= 60)
return _gr_poly_divexact_basecase_bidirectional(Q, A, lenA, B, lenB, ctx);
else
return _gr_poly_divexact_bidirectional(Q, A, lenA, B, lenB, ctx);
}
#if FLINT_HAVE_FFT_SMALL
static const short inv_series_cutoff_tab[64] = {36, 37, 40, 44, 42, 46, 50, 81, 97,
106, 133, 152, 292, 279, 279, 191, 191, 191, 191, 200, 191, 407, 388, 407, 407,
407, 407, 407, 266, 292, 292, 292, 231, 242, 279, 279, 292, 292, 279, 292,
292, 279, 292, 292, 292, 370, 370, 370, 370, 370, 370, 388, 407, 448,
427, 407, 427, 427, 427, 427, 388, 370, 370, 353, };
#else
static const short inv_series_cutoff_tab[64] = {38, 36, 38, 36, 41, 48, 49, 54, 60,
102, 112, 150, 165, 172, 210, 272, 339, 378, 385, 442, 468, 557, 596,
621, 710, 746, 756, 978, 768, 679, 700, 696, 620, 619, 642, 766, 901,
883, 924, 997, 979, 1028, 1101, 1094, 1152, 1169, 1279, 1311, 1284,
1381, 1418, 1513, 1540, 1598, 1692, 1846, 1883, 1942, 1963, 1803,
1788, 1861, 1881, 1920, };
#endif
static int
_gr_nmod_poly_inv_series_basecase(ulong * res,
const ulong * f, slong flen, slong n, gr_ctx_t ctx)
{
ulong q;
q = f[0];
if (q != 1)
{
if (n_gcdinv(&q, q, NMOD_CTX(ctx).n) != 1)
return GR_DOMAIN;
}
_nmod_poly_inv_series_basecase_preinv1(res, f, flen, n, q, NMOD_CTX(ctx));
return GR_SUCCESS;
}
static int
_gr_nmod_poly_inv_series(ulong * res,
const ulong * f, slong flen, slong n, gr_ctx_t ctx)
{
slong cutoff;
flen = FLINT_MIN(flen, n);
cutoff = inv_series_cutoff_tab[NMOD_BITS(NMOD_CTX(ctx)) - 1];
if (flen < cutoff)
return _gr_poly_inv_series_basecase(res, f, flen, n, ctx);
else
return _gr_poly_inv_series_newton(res, f, flen, n, cutoff, ctx);
}
static int
_gr_nmod_poly_div_series_basecase(ulong * res,
const ulong * f, slong flen, const ulong * g, slong glen, slong n, gr_ctx_t ctx)
{
ulong q;
q = g[0];
if (q != 1)
{
if (n_gcdinv(&q, q, NMOD_CTX(ctx).n) != 1)
return GR_DOMAIN;
}
_nmod_poly_div_series_basecase_preinv1(res, f, flen, g, glen, n, q, NMOD_CTX(ctx));
return GR_SUCCESS;
}
#if FLINT_HAVE_FFT_SMALL
static const short div_series_cutoff_tab[64] = {
85, 81, 85, 89, 106, 145, 166, 182, 210, 337, 321, 321, 306, 321, 321, 306, 321, 321,
321, 306, 626, 597, 597, 597, 597, 597, 597, 597, 370, 388, 388, 407, 321, 321, 321,
321, 321, 337, 321, 337, 321, 321, 337, 321, 337, 427, 427, 448, 427, 427, 448, 448,
470, 470, 470, 470, 470, 470, 493, 470, 427, 470, 448, 448, };
#else
static const short div_series_cutoff_tab[64] = {
64, 64, 63, 65, 77, 84, 140, 158, 197, 208, 276, 243, 348, 358, 450, 560, 585, 692,
749, 787, 864, 922, 914, 1239, 1454, 1424, 1449, 1327, 1115, 1174, 1250, 1282, 961,
981, 1000, 1091, 1138, 1222, 1205, 1374, 1397, 1420, 1446, 1486, 1513, 1763, 1782,
1890, 2047, 2071, 2075, 2271, 2192, 2307, 2407, 2324, 2308, 2958, 3001, 2816,
2747, 2985, 2970, 2871, };
#endif
static int
_gr_nmod_poly_div_series(ulong * res,
const ulong * f, slong flen, const ulong * g, slong glen, slong n, gr_ctx_t ctx)
{
slong cutoff;
flen = FLINT_MIN(flen, n);
glen = FLINT_MIN(glen, n);
cutoff = div_series_cutoff_tab[NMOD_BITS(NMOD_CTX(ctx)) - 1];
if (glen < cutoff)
return _gr_poly_div_series_basecase(res, f, flen, g, glen, n, ctx);
else
return _gr_poly_div_series_newton(res, f, flen, g, glen, n, cutoff, ctx);
}
#if FLINT_HAVE_FFT_SMALL
static const short rsqrt_series_cutoff_tab[64] = {3, 22, 24, 42, 36, 40, 44,
52, 89, 106, 139, 166, 174, 200, 191, 200, 191, 191, 191, 200, 306, 370,
353, 337, 337, 370, 370, 370, 292, 292, 279, 292, 231, 231, 220, 279,
292, 292, 279, 292, 292, 279, 292, 292, 292, 370, 370, 370, 370, 370,
370, 388, 407, 448, 427, 407, 427, 427, 427, 427, 388, 370, 370, 353, };
#else
static const short rsqrt_series_cutoff_tab[64] = {6, 22, 22, 24, 27, 28, 28, 58,
77, 96, 116, 160, 232, 270, 315, 387, 402, 472, 502, 580, 627, 760, 824, 940,
988, 1018, 1155, 1182, 938, 932, 925, 1016, 836, 891, 915, 960, 1038, 1101,
1203, 1236, 1255, 1311, 1386, 1422, 1489, 1592, 1624, 1879, 1828, 2055, 2227,
2369, 2156, 2361, 2415, 2472, 2581, 2719, 2679, 2302, 2199, 2455, 2440, 2356, };
#endif
static int
_gr_nmod_poly_rsqrt_series(ulong * res,
const ulong * f, slong flen, slong n, gr_ctx_t ctx)
{
slong cutoff;
flen = FLINT_MIN(flen, n);
cutoff = rsqrt_series_cutoff_tab[NMOD_BITS(NMOD_CTX(ctx)) - 1];
if (flen < cutoff)
return _gr_poly_rsqrt_series_basecase(res, f, flen, n, ctx);
else
return _gr_poly_rsqrt_series_newton(res, f, flen, n, cutoff, ctx);
}
#if FLINT_HAVE_FFT_SMALL
static const short sqrt_series_cutoff_tab[] = { 32767, 1353, 1353, 919,
1289, 1228, 1491, 1228, 1491, 1289, 1420, 1420, 1228, 1289, 1420,
1353, 1289, 1289, 1353, 4345, 4345, 2423, 2544, 4345, 4562, 2423,
4345, 2671, 1725, 1811, 1725, 3577, 1643, 1643, 1725, 1725, 1725,
3407, 3407, 1725, 1643, 1811, 3407, 3407, 4562, 3755, 3755, 3577,
3577, 4562, 3755, 3942, 3755, 3755, 4562, 4562, 4562, 4562, 3755,
3245, 3245, 2944, 3091, 2423, };
#else
static const short sqrt_series_cutoff_tab[] = { 32767, 632, 732, 928, 1443,
1731, 2364, 2490, 2893, 3173, 5316, 5412, 5727, 6123, 6613, 7290, 7572,
8023, 9114, 9105, 8656, 10645, 11290, 13223, 11507, 15489, 12328, 9338,
9517, 9795, 9596, 13162, 10168, 8013, 9949, 10654, 9932, 12222, 11287,
11623, 11971, 12577, 12207, 13886, 14160, 12200, 13207, 15943, 15320,
14290, 15933, 15463, 14281, 15457, 15302, 17929, 18106, 17058, 14844,
17740, 17916, 18640, 18093, 18638, };
#endif
static int
_gr_nmod_poly_sqrt_series(ulong * res,
const ulong * f, slong flen, slong n, gr_ctx_t ctx)
{
slong cutoff;
flen = FLINT_MIN(flen, n);
cutoff = sqrt_series_cutoff_tab[NMOD_BITS(NMOD_CTX(ctx)) - 1];
if (flen < cutoff)
return _gr_poly_sqrt_series_basecase(res, f, flen, n, ctx);
else
return _gr_poly_sqrt_series_newton(res, f, flen, n, cutoff, ctx);
}
#if FLINT_HAVE_FFT_SMALL
static const short exp_series_mul_cutoff_tab[] = { 470, 470, 470, 470,
470, 470, 470, 470, 470, 266, 266, 231, 279, 292, 292, 266, 266,
254, 266, 266, 448, 470, 470, 448, 448, 470, 493, 470, 337, 321,
427, 321, 292, 292, 292, 292, 292, 292, 279, 292, 292, 292, 279,
279, 292, 448, 448, 427, 448, 448, 448, 448, 448, 448, 427, 448,
427, 448, 448, 448, 353, 407, 407, 353, };
#else
static const short exp_series_mul_cutoff_tab[] = {
4, 4, 6, 12, 18, 38, 56, 57, 97, 121, 144, 145, 187, 228, 216, 286,
315, 426, 505, 547, 620, 631, 649, 781, 931, 810, 950, 1066, 838, 714,
880, 931, 698, 598, 590, 620, 731, 782, 780, 848, 976, 1005, 978, 1006,
1046, 1040, 1203, 1296, 1342, 1327, 1389, 1555, 1568, 1644, 1676, 1725,
1692, 1793, 2014, 1904, 2021, 2086, 2030, 2198,
};
#endif
#if FLINT_HAVE_FFT_SMALL
static const short exp_series_newton_cutoff_tab[64] = { 470, 470, 470,
470, 470, 470, 517, 597, 689, 759, 689, 723, 626, 723, 723, 723,
723, 723, 723, 723, 1289, 1491, 1353, 1353, 1353, 1353, 1353, 1353,
964, 964, 1115, 1115, 835, 876, 876, 919, 876, 919, 919, 876, 919,
876, 835, 919, 919, 1228, 1170, 1289, 1228, 1228, 1353, 1353,
1353, 1228, 1228, 1228, 1289, 1353, 1228, 1170, 1115, 1115, 1170,
1353, };
#else
static const short exp_series_newton_cutoff_tab[64] = {
4, 4, 6, 12, 18, 38, 68, 132, 258, 522, 1033, 1288, 1322, 1494, 1775,
2074, 2404, 2534, 2887, 3017, 3343, 3234, 3550, 4263, 3813, 4534,
5398, 4048, 3381, 3607, 3811, 3724, 2962, 3095, 3268, 3253, 3469, 3664,
4108, 4219, 4043, 4402, 4434, 4377, 4583, 4802, 5030, 5430, 5366, 5407,
5341, 6363, 6415, 6343, 6395, 6444, 6433, 6358, 6939, 6794, 6782, 6837,
6758, 6680,
};
#endif
static int
_gr_nmod_poly_exp_series(ulong * res,
const ulong * f, slong flen, slong n, gr_ctx_t ctx)
{
slong cutoff1, cutoff2;
flen = FLINT_MIN(flen, n);
cutoff1 = exp_series_mul_cutoff_tab[NMOD_BITS(NMOD_CTX(ctx)) - 1];
if (flen < cutoff1)
return _gr_poly_exp_series_basecase(res, f, flen, n, ctx);
cutoff2 = exp_series_newton_cutoff_tab[NMOD_BITS(NMOD_CTX(ctx)) - 1];
if (flen < cutoff2)
return _gr_poly_exp_series_basecase_mul(res, f, flen, n, ctx);
return _gr_poly_exp_series_newton(res, NULL, f, flen, n, cutoff2, ctx);
}
static int
_gr_nmod_roots_gr_poly(gr_vec_t roots, gr_vec_t mult, const gr_poly_t poly, int flags, gr_ctx_t ctx)
{
if (poly->length == 0)
return GR_DOMAIN;
{
gr_poly_t z_poly;
gr_vec_t z_roots;
gr_ctx_t z_ctx;
slong i;
int status = GR_SUCCESS;
fmpz_t t;
fmpz_init(t);
fmpz_set_ui(t, NMOD_CTX(ctx).n);
gr_ctx_init_fmpz_mod(z_ctx, t);
gr_poly_init(z_poly, z_ctx);
gr_vec_init(z_roots, 0, z_ctx);
status |= gr_poly_set_gr_poly_other(z_poly, poly, ctx, z_ctx);
status |= gr_poly_roots(z_roots, mult, z_poly, flags, z_ctx);
if (status == GR_SUCCESS)
{
gr_vec_set_length(roots, z_roots->length, ctx);
for (i = 0; i < z_roots->length; i++)
status |= gr_set_other(gr_vec_entry_ptr(roots, i, ctx), gr_vec_entry_ptr(z_roots, i, z_ctx), z_ctx, ctx);
}
gr_poly_clear(z_poly, z_ctx);
gr_vec_clear(z_roots, z_ctx);
gr_ctx_clear(z_ctx);
fmpz_clear(t);
return status;
}
}
static int
_gr_nmod_mat_mul(gr_mat_t res, const gr_mat_t x, const gr_mat_t y, gr_ctx_t ctx)
{
nmod_mat_t R, X, Y;
nmod_mat_struct *XX, *YY;
R->entries = res->entries;
R->r = res->r;
R->c = res->c;
R->stride = res->stride;
R->mod = NMOD_CTX(ctx);
if (res == x)
{
XX = R;
}
else
{
X->entries = x->entries;
X->r = x->r;
X->c = x->c;
X->stride = x->stride;
X->mod = NMOD_CTX(ctx);
XX = X;
}
if (res == y)
{
YY = R;
}
else if (x == y)
{
YY = XX;
}
else
{
Y->entries = y->entries;
Y->r = y->r;
Y->c = y->c;
Y->stride = y->stride;
Y->mod = NMOD_CTX(ctx);
YY = Y;
}
nmod_mat_mul(R, XX, YY);
return GR_SUCCESS;
}
int __gr_nmod_methods_initialized = 0;
gr_static_method_table __gr_nmod_methods;
gr_method_tab_input __gr_nmod_methods_input[] =
{
{GR_METHOD_CTX_WRITE, (gr_funcptr) _gr_nmod_ctx_write},
{GR_METHOD_CTX_IS_RING, (gr_funcptr) gr_generic_ctx_predicate_true},
{GR_METHOD_CTX_IS_COMMUTATIVE_RING, (gr_funcptr) gr_generic_ctx_predicate_true},
{GR_METHOD_CTX_IS_INTEGRAL_DOMAIN, (gr_funcptr) _gr_nmod_ctx_is_field},
{GR_METHOD_CTX_IS_FIELD, (gr_funcptr) _gr_nmod_ctx_is_field},
{GR_METHOD_CTX_IS_FINITE,
(gr_funcptr) gr_generic_ctx_predicate_true},
{GR_METHOD_CTX_IS_FINITE_CHARACTERISTIC,
(gr_funcptr) gr_generic_ctx_predicate_true},
{GR_METHOD_CTX_IS_EXACT, (gr_funcptr) gr_generic_ctx_predicate_true},
{GR_METHOD_CTX_IS_CANONICAL,
(gr_funcptr) gr_generic_ctx_predicate_true},
{GR_METHOD_CTX_SET_IS_FIELD,(gr_funcptr) _gr_nmod_ctx_set_is_field},
{GR_METHOD_INIT, (gr_funcptr) _gr_nmod_init},
{GR_METHOD_CLEAR, (gr_funcptr) _gr_nmod_clear},
{GR_METHOD_SWAP, (gr_funcptr) _gr_nmod_swap},
{GR_METHOD_SET_SHALLOW, (gr_funcptr) _gr_nmod_set_shallow},
{GR_METHOD_RANDTEST, (gr_funcptr) _gr_nmod_randtest},
{GR_METHOD_WRITE, (gr_funcptr) _gr_nmod_write},
{GR_METHOD_ZERO, (gr_funcptr) _gr_nmod_zero},
{GR_METHOD_ONE, (gr_funcptr) _gr_nmod_one},
{GR_METHOD_IS_ZERO, (gr_funcptr) _gr_nmod_is_zero},
{GR_METHOD_IS_ONE, (gr_funcptr) _gr_nmod_is_one},
{GR_METHOD_IS_NEG_ONE, (gr_funcptr) _gr_nmod_is_neg_one},
{GR_METHOD_EQUAL, (gr_funcptr) _gr_nmod_equal},
{GR_METHOD_SET, (gr_funcptr) _gr_nmod_set},
{GR_METHOD_SET_SI, (gr_funcptr) _gr_nmod_set_si},
{GR_METHOD_SET_UI, (gr_funcptr) _gr_nmod_set_ui},
{GR_METHOD_SET_FMPZ, (gr_funcptr) _gr_nmod_set_fmpz},
{GR_METHOD_SET_OTHER, (gr_funcptr) _gr_nmod_set_other},
{GR_METHOD_GET_FMPZ, (gr_funcptr) _gr_nmod_get_fmpz},
{GR_METHOD_NEG, (gr_funcptr) _gr_nmod_neg},
{GR_METHOD_ADD, (gr_funcptr) _gr_nmod_add},
{GR_METHOD_ADD_SI, (gr_funcptr) _gr_nmod_add_si},
{GR_METHOD_ADD_UI, (gr_funcptr) _gr_nmod_add_ui},
{GR_METHOD_SUB, (gr_funcptr) _gr_nmod_sub},
{GR_METHOD_SUB_SI, (gr_funcptr) _gr_nmod_sub_si},
{GR_METHOD_SUB_UI, (gr_funcptr) _gr_nmod_sub_ui},
{GR_METHOD_MUL, (gr_funcptr) _gr_nmod_mul},
{GR_METHOD_MUL_SI, (gr_funcptr) _gr_nmod_mul_si},
{GR_METHOD_MUL_UI, (gr_funcptr) _gr_nmod_mul_ui},
{GR_METHOD_MUL_FMPZ, (gr_funcptr) _gr_nmod_mul_fmpz},
{GR_METHOD_ADDMUL, (gr_funcptr) _gr_nmod_addmul},
{GR_METHOD_SUBMUL, (gr_funcptr) _gr_nmod_submul},
{GR_METHOD_MUL_TWO, (gr_funcptr) _gr_nmod_mul_two},
{GR_METHOD_MUL_2EXP_SI, (gr_funcptr) _gr_nmod_mul_2exp_si},
{GR_METHOD_SQR, (gr_funcptr) _gr_nmod_sqr},
{GR_METHOD_DIV, (gr_funcptr) _gr_nmod_div},
{GR_METHOD_DIV_SI, (gr_funcptr) _gr_nmod_div_si},
{GR_METHOD_DIV_UI, (gr_funcptr) _gr_nmod_div_ui},
{GR_METHOD_DIV_FMPZ, (gr_funcptr) _gr_nmod_div_fmpz},
{GR_METHOD_DIV_NONUNIQUE, (gr_funcptr) _gr_nmod_div_nonunique},
{GR_METHOD_DIVIDES, (gr_funcptr) _gr_nmod_divides},
{GR_METHOD_IS_INVERTIBLE, (gr_funcptr) _gr_nmod_is_invertible},
{GR_METHOD_INV, (gr_funcptr) _gr_nmod_inv},
{GR_METHOD_POW_UI, (gr_funcptr) _gr_nmod_pow_ui},
{GR_METHOD_POW_FMPZ, (gr_funcptr) _gr_nmod_pow_fmpz},
{GR_METHOD_IS_SQUARE, (gr_funcptr) _gr_nmod_is_square},
{GR_METHOD_SQRT, (gr_funcptr) _gr_nmod_sqrt},
{GR_METHOD_VEC_INIT, (gr_funcptr) _gr_nmod_vec_init},
{GR_METHOD_VEC_CLEAR, (gr_funcptr) _gr_nmod_vec_clear},
{GR_METHOD_VEC_SET, (gr_funcptr) _gr_nmod_vec_set},
{GR_METHOD_VEC_NORMALISE, (gr_funcptr) _gr_nmod_vec_normalise},
{GR_METHOD_VEC_NORMALISE_WEAK, (gr_funcptr) _gr_nmod_vec_normalise_weak},
{GR_METHOD_VEC_NEG, (gr_funcptr) _gr_nmod_vec_neg},
{GR_METHOD_VEC_ADD, (gr_funcptr) _gr_nmod_vec_add},
{GR_METHOD_VEC_SUB, (gr_funcptr) _gr_nmod_vec_sub},
{GR_METHOD_VEC_MUL, (gr_funcptr) _gr_nmod_vec_mul},
{GR_METHOD_VEC_MUL_SCALAR, (gr_funcptr) _gr_nmod_vec_mul_scalar},
{GR_METHOD_VEC_MUL_SCALAR_SI, (gr_funcptr) _gr_nmod_vec_mul_scalar_si},
{GR_METHOD_VEC_MUL_SCALAR_UI, (gr_funcptr) _gr_nmod_vec_mul_scalar_ui},
{GR_METHOD_VEC_MUL_SCALAR_FMPZ, (gr_funcptr) _gr_nmod_vec_mul_scalar_fmpz},
{GR_METHOD_VEC_MUL_SCALAR_2EXP_SI, (gr_funcptr) _gr_nmod_vec_mul_scalar_2exp_si},
{GR_METHOD_SCALAR_MUL_VEC, (gr_funcptr) _gr_nmod_scalar_mul_vec},
{GR_METHOD_VEC_ADDMUL_SCALAR, (gr_funcptr) _gr_nmod_vec_addmul_scalar},
{GR_METHOD_VEC_ADDMUL_SCALAR_SI, (gr_funcptr) _gr_nmod_vec_addmul_scalar_si},
{GR_METHOD_VEC_SUBMUL_SCALAR, (gr_funcptr) _gr_nmod_vec_submul_scalar},
{GR_METHOD_VEC_SUBMUL_SCALAR_SI, (gr_funcptr) _gr_nmod_vec_submul_scalar_si},
{GR_METHOD_VEC_SUB, (gr_funcptr) _gr_nmod_vec_sub},
{GR_METHOD_VEC_SUM, (gr_funcptr) _gr_nmod_vec_sum},
{GR_METHOD_VEC_PRODUCT, (gr_funcptr) _gr_nmod_vec_product},
{GR_METHOD_VEC_DOT, (gr_funcptr) __gr_nmod_vec_dot},
{GR_METHOD_VEC_DOT_REV, (gr_funcptr) __gr_nmod_vec_dot_rev},
{GR_METHOD_VEC_RECIPROCALS, (gr_funcptr) _gr_nmod_vec_reciprocals},
{GR_METHOD_POLY_MULLOW, (gr_funcptr) _gr_nmod_poly_mullow},
{GR_METHOD_POLY_MULMID, (gr_funcptr) _gr_nmod_poly_mulmid},
{GR_METHOD_POLY_DIVREM, (gr_funcptr) _gr_nmod_poly_divrem},
{GR_METHOD_POLY_DIVEXACT, (gr_funcptr) _gr_nmod_poly_divexact},
{GR_METHOD_POLY_INV_SERIES, (gr_funcptr) _gr_nmod_poly_inv_series},
{GR_METHOD_POLY_INV_SERIES_BASECASE, (gr_funcptr) _gr_nmod_poly_inv_series_basecase},
{GR_METHOD_POLY_DIV_SERIES, (gr_funcptr) _gr_nmod_poly_div_series},
{GR_METHOD_POLY_DIV_SERIES_BASECASE, (gr_funcptr) _gr_nmod_poly_div_series_basecase},
{GR_METHOD_POLY_RSQRT_SERIES, (gr_funcptr) _gr_nmod_poly_rsqrt_series},
{GR_METHOD_POLY_SQRT_SERIES, (gr_funcptr) _gr_nmod_poly_sqrt_series},
{GR_METHOD_POLY_EXP_SERIES, (gr_funcptr) _gr_nmod_poly_exp_series},
{GR_METHOD_POLY_ROOTS, (gr_funcptr) _gr_nmod_roots_gr_poly},
{GR_METHOD_MAT_MUL, (gr_funcptr) _gr_nmod_mat_mul},
{0, (gr_funcptr) NULL},
};
int
gr_ctx_init_nmod(gr_ctx_t ctx, ulong n)
{
if (n == 0)
return GR_DOMAIN;
ctx->which_ring = GR_CTX_NMOD;
ctx->sizeof_elem = sizeof(ulong);
ctx->size_limit = WORD_MAX;
NMOD_IS_PRIME(ctx) = T_UNKNOWN;
nmod_init(NMOD_CTX_REF(ctx), n);
ctx->methods = __gr_nmod_methods;
if (!__gr_nmod_methods_initialized)
{
gr_method_tab_init(__gr_nmod_methods, __gr_nmod_methods_input);
__gr_nmod_methods_initialized = 1;
}
return GR_SUCCESS;
}
void
_gr_ctx_init_nmod(gr_ctx_t ctx, void * nmod_t_ref)
{
ctx->which_ring = GR_CTX_NMOD;
ctx->sizeof_elem = sizeof(ulong);
ctx->size_limit = WORD_MAX;
NMOD_IS_PRIME(ctx) = T_UNKNOWN;
*NMOD_CTX_REF(ctx) = ((nmod_t *) nmod_t_ref)[0];
ctx->methods = __gr_nmod_methods;
if (!__gr_nmod_methods_initialized)
{
gr_method_tab_init(__gr_nmod_methods, __gr_nmod_methods_input);
__gr_nmod_methods_initialized = 1;
}
}