#include "fmpz.h"
#include "mpn_mod.h"
#include "gr.h"
int _mpn_mod_methods_initialized = 0;
gr_static_method_table _mpn_mod_methods;
DIAGNOSTIC_PUSH
DIAGNOSTIC_IGNORE_CAST_FUNCTION_TYPE
gr_method_tab_input _mpn_mod_methods_input[] =
{
{GR_METHOD_CTX_WRITE, (gr_funcptr) mpn_mod_ctx_write},
{GR_METHOD_CTX_CLEAR, (gr_funcptr) mpn_mod_ctx_clear},
{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) mpn_mod_ctx_is_field},
{GR_METHOD_CTX_IS_FIELD, (gr_funcptr) mpn_mod_ctx_is_field},
{GR_METHOD_CTX_IS_UNIQUE_FACTORIZATION_DOMAIN,
(gr_funcptr) mpn_mod_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_false},
{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) mpn_mod_ctx_set_is_field},
{GR_METHOD_INIT, (gr_funcptr) mpn_mod_init},
{GR_METHOD_CLEAR, (gr_funcptr) mpn_mod_clear},
{GR_METHOD_SWAP, (gr_funcptr) mpn_mod_swap},
{GR_METHOD_SET_SHALLOW, (gr_funcptr) mpn_mod_set},
{GR_METHOD_RANDTEST, (gr_funcptr) mpn_mod_randtest},
{GR_METHOD_WRITE, (gr_funcptr) mpn_mod_write},
{GR_METHOD_ZERO, (gr_funcptr) mpn_mod_zero},
{GR_METHOD_ONE, (gr_funcptr) mpn_mod_one},
{GR_METHOD_NEG_ONE, (gr_funcptr) mpn_mod_neg_one},
{GR_METHOD_IS_ZERO, (gr_funcptr) mpn_mod_is_zero},
{GR_METHOD_IS_ONE, (gr_funcptr) mpn_mod_is_one},
{GR_METHOD_IS_NEG_ONE, (gr_funcptr) mpn_mod_is_neg_one},
{GR_METHOD_EQUAL, (gr_funcptr) mpn_mod_equal},
{GR_METHOD_SET, (gr_funcptr) mpn_mod_set},
{GR_METHOD_SET_SI, (gr_funcptr) mpn_mod_set_si},
{GR_METHOD_SET_UI, (gr_funcptr) mpn_mod_set_ui},
{GR_METHOD_SET_FMPZ, (gr_funcptr) mpn_mod_set_fmpz},
{GR_METHOD_SET_OTHER, (gr_funcptr) mpn_mod_set_other},
{GR_METHOD_GET_FMPZ, (gr_funcptr) mpn_mod_get_fmpz},
{GR_METHOD_NEG, (gr_funcptr) mpn_mod_neg},
{GR_METHOD_ADD, (gr_funcptr) mpn_mod_add},
{GR_METHOD_ADD_UI, (gr_funcptr) mpn_mod_add_ui},
{GR_METHOD_ADD_SI, (gr_funcptr) mpn_mod_add_si},
{GR_METHOD_ADD_FMPZ, (gr_funcptr) mpn_mod_add_fmpz},
{GR_METHOD_SUB, (gr_funcptr) mpn_mod_sub},
{GR_METHOD_SUB_UI, (gr_funcptr) mpn_mod_sub_ui},
{GR_METHOD_SUB_SI, (gr_funcptr) mpn_mod_sub_si},
{GR_METHOD_SUB_FMPZ, (gr_funcptr) mpn_mod_sub_fmpz},
{GR_METHOD_MUL, (gr_funcptr) mpn_mod_mul},
{GR_METHOD_MUL_SI, (gr_funcptr) mpn_mod_mul_si},
{GR_METHOD_MUL_UI, (gr_funcptr) mpn_mod_mul_ui},
{GR_METHOD_MUL_FMPZ, (gr_funcptr) mpn_mod_mul_fmpz},
{GR_METHOD_ADDMUL, (gr_funcptr) mpn_mod_addmul},
{GR_METHOD_ADDMUL_SI, (gr_funcptr) mpn_mod_addmul_si},
{GR_METHOD_ADDMUL_UI, (gr_funcptr) mpn_mod_addmul_ui},
{GR_METHOD_ADDMUL_FMPZ, (gr_funcptr) mpn_mod_addmul_fmpz},
{GR_METHOD_SUBMUL, (gr_funcptr) mpn_mod_submul},
{GR_METHOD_SUBMUL_SI, (gr_funcptr) mpn_mod_submul_si},
{GR_METHOD_SUBMUL_UI, (gr_funcptr) mpn_mod_submul_ui},
{GR_METHOD_SUBMUL_FMPZ, (gr_funcptr) mpn_mod_submul_fmpz},
{GR_METHOD_SQR, (gr_funcptr) mpn_mod_sqr},
{GR_METHOD_DIV, (gr_funcptr) mpn_mod_div},
{GR_METHOD_INV, (gr_funcptr) mpn_mod_inv},
{GR_METHOD_VEC_INIT, (gr_funcptr) _mpn_mod_vec_zero},
{GR_METHOD_VEC_CLEAR, (gr_funcptr) _mpn_mod_vec_clear},
{GR_METHOD_VEC_SET, (gr_funcptr) _mpn_mod_vec_set},
{GR_METHOD_VEC_SWAP, (gr_funcptr) _mpn_mod_vec_swap},
{GR_METHOD_VEC_ZERO, (gr_funcptr) _mpn_mod_vec_zero},
{GR_METHOD_VEC_NEG, (gr_funcptr) _mpn_mod_vec_neg},
{GR_METHOD_VEC_ADD, (gr_funcptr) _mpn_mod_vec_add},
{GR_METHOD_VEC_SUB, (gr_funcptr) _mpn_mod_vec_sub},
{GR_METHOD_VEC_MUL, (gr_funcptr) _mpn_mod_vec_mul},
{GR_METHOD_VEC_MUL_SCALAR, (gr_funcptr) _mpn_mod_vec_mul_scalar},
{GR_METHOD_VEC_ADDMUL_SCALAR, (gr_funcptr) _mpn_mod_vec_addmul_scalar},
{GR_METHOD_VEC_SUBMUL_SCALAR, (gr_funcptr) _mpn_mod_vec_submul_scalar},
{GR_METHOD_SCALAR_MUL_VEC, (gr_funcptr) _mpn_mod_scalar_mul_vec},
{GR_METHOD_VEC_DOT, (gr_funcptr) _mpn_mod_vec_dot},
{GR_METHOD_VEC_DOT_REV, (gr_funcptr) _mpn_mod_vec_dot_rev},
{GR_METHOD_POLY_MULLOW, (gr_funcptr) _mpn_mod_poly_mullow},
{GR_METHOD_POLY_MULMID, (gr_funcptr) _mpn_mod_poly_mulmid},
{GR_METHOD_POLY_INV_SERIES, (gr_funcptr) _mpn_mod_poly_inv_series},
{GR_METHOD_POLY_DIV_SERIES, (gr_funcptr) _mpn_mod_poly_div_series},
{GR_METHOD_POLY_DIVREM, (gr_funcptr) _mpn_mod_poly_divrem},
{GR_METHOD_POLY_DIV, (gr_funcptr) _mpn_mod_poly_div},
{GR_METHOD_POLY_GCD, (gr_funcptr) _mpn_mod_poly_gcd},
{GR_METHOD_POLY_XGCD, (gr_funcptr) _mpn_mod_poly_xgcd},
{GR_METHOD_MAT_MUL, (gr_funcptr) mpn_mod_mat_mul},
{GR_METHOD_MAT_NONSINGULAR_SOLVE_TRIL, (gr_funcptr) mpn_mod_mat_nonsingular_solve_tril},
{GR_METHOD_MAT_NONSINGULAR_SOLVE_TRIU, (gr_funcptr) mpn_mod_mat_nonsingular_solve_triu},
{GR_METHOD_MAT_LU, (gr_funcptr) mpn_mod_mat_lu},
{GR_METHOD_MAT_DET, (gr_funcptr) mpn_mod_mat_det},
{GR_METHOD_MAT_CHARPOLY, (gr_funcptr) _mpn_mod_mat_charpoly},
{GR_METHOD_MAT_REDUCE_ROW, (gr_funcptr) mpn_mod_mat_reduce_row},
{0, (gr_funcptr) NULL},
};
DIAGNOSTIC_POP
int
_gr_ctx_init_mpn_mod(gr_ctx_t ctx, nn_srcptr n, slong nlimbs)
{
flint_bitcnt_t norm;
if (nlimbs < MPN_MOD_MIN_LIMBS || nlimbs > MPN_MOD_MAX_LIMBS || n[nlimbs - 1] == 0)
return GR_UNABLE;
ctx->which_ring = GR_CTX_MPN_MOD;
ctx->sizeof_elem = nlimbs * sizeof(ulong);
GR_CTX_DATA_AS_PTR(ctx) = flint_malloc(sizeof(_mpn_mod_ctx_struct));
MPN_MOD_CTX_NLIMBS(ctx) = nlimbs;
flint_mpn_copyi(MPN_MOD_CTX_MODULUS(ctx), n, nlimbs);
MPN_MOD_CTX_NORM(ctx) = norm = flint_clz(n[nlimbs - 1]);
if (norm == 0)
flint_mpn_copyi(MPN_MOD_CTX_MODULUS_NORMED(ctx), n, nlimbs);
else
mpn_lshift(MPN_MOD_CTX_MODULUS_NORMED(ctx), n, nlimbs, norm);
flint_mpn_preinvn(MPN_MOD_CTX_MODULUS_PREINV(ctx), MPN_MOD_CTX_MODULUS_NORMED(ctx), nlimbs);
MPN_MOD_CTX_IS_PRIME(ctx) = T_UNKNOWN;
ctx->size_limit = WORD_MAX;
ctx->methods = _mpn_mod_methods;
if (!_mpn_mod_methods_initialized)
{
gr_method_tab_init(_mpn_mod_methods, _mpn_mod_methods_input);
_mpn_mod_methods_initialized = 1;
}
return GR_SUCCESS;
}
int
gr_ctx_init_mpn_mod(gr_ctx_t ctx, const fmpz_t n)
{
if (fmpz_sgn(n) <= 0)
return GR_DOMAIN;
if (!COEFF_IS_MPZ(*n))
return GR_UNABLE;
return _gr_ctx_init_mpn_mod(ctx, COEFF_TO_PTR(*n)->_mp_d, COEFF_TO_PTR(*n)->_mp_size);
}
static const int
randtest_primes[][2] = {
#if FLINT_BITS == 32
{32, 15},
{64, -59},
#endif
{64, 13},
{128, -159},
{128, 51},
{190, 129},
{192, -237},
{256, 297},
#if FLINT_BITS == 64
{1024, -105},
#endif
};
void
gr_ctx_init_mpn_mod_randtest(gr_ctx_t ctx, flint_rand_t state)
{
fmpz_t n;
fmpz_init(n);
if (n_randint(state, 2))
{
int i = n_randint(state, sizeof(randtest_primes) / (2 * sizeof(int)));
fmpz_ui_pow_ui(n, 2, randtest_primes[i][0]);
fmpz_add_si(n, n, randtest_primes[i][1]);
GR_MUST_SUCCEED(gr_ctx_init_mpn_mod(ctx, n));
GR_MUST_SUCCEED(gr_ctx_set_is_field(ctx, n_randint(state, 2) ? T_TRUE : T_UNKNOWN));
}
else
{
for (;;)
{
fmpz_randtest_not_zero(n, state, FLINT_BITS * MPN_MOD_MAX_LIMBS + 10);
fmpz_abs(n, n);
if (gr_ctx_init_mpn_mod(ctx, n) == GR_SUCCESS)
break;
}
}
fmpz_clear(n);
}