/* Copyright (C) 2010 William Hart This file is part of FLINT. FLINT is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #ifndef NMOD_VEC_H #define NMOD_VEC_H #ifdef NMOD_VEC_INLINES_C #define NMOD_VEC_INLINE FLINT_DLL #else #define NMOD_VEC_INLINE static __inline__ #endif #undef ulong #define ulong ulongxx /* interferes with system includes */ #include #undef ulong #include #define ulong mp_limb_t #include "longlong.h" #include "ulong_extras.h" #include "flint.h" #ifdef __cplusplus extern "C" { #endif typedef struct { mp_limb_t n; mp_limb_t ninv; flint_bitcnt_t norm; } nmod_t; #define NMOD_VEC_NORM(vec, i) \ do { \ while ((i) && vec[(i) - 1] == UWORD(0)) \ (i)--; \ } while (0) #define NMOD_RED2(r, a_hi, a_lo, mod) \ do { \ mp_limb_t q0xx, q1xx, r1xx; \ const mp_limb_t u1xx = ((a_hi)<<(mod).norm) + r_shift((a_lo), FLINT_BITS - (mod).norm); \ const mp_limb_t u0xx = ((a_lo)<<(mod).norm); \ const mp_limb_t nxx = ((mod).n<<(mod).norm); \ umul_ppmm(q1xx, q0xx, (mod).ninv, u1xx); \ add_ssaaaa(q1xx, q0xx, q1xx, q0xx, u1xx, u0xx); \ r1xx = (u0xx - (q1xx + 1)*nxx); \ if (r1xx > q0xx) r1xx += nxx; \ if (r1xx < nxx) r = (r1xx>>(mod).norm); \ else r = ((r1xx - nxx)>>(mod).norm); \ } while (0) #define NMOD_RED(r, a, mod) \ do { \ NMOD_RED2(r, 0, a, mod); \ } while (0) #define NMOD2_RED2(r, a_hi, a_lo, mod) \ do { \ mp_limb_t v_hi; \ NMOD_RED(v_hi, a_hi, mod); \ NMOD_RED2(r, v_hi, a_lo, mod); \ } while (0) #define NMOD_RED3(r, a_hi, a_me, a_lo, mod) \ do { \ mp_limb_t v_hi; \ NMOD_RED2(v_hi, a_hi, a_me, mod); \ NMOD_RED2(r, v_hi, a_lo, mod); \ } while (0) #define NMOD_ADDMUL(r, a, b, mod) \ do { \ mp_limb_t a_hi, a_lo; \ umul_ppmm(a_hi, a_lo, a, b); \ add_ssaaaa(a_hi, a_lo, a_hi, a_lo, (mp_limb_t) 0, r); \ NMOD_RED2(r, a_hi, a_lo, mod); \ } while (0) NMOD_VEC_INLINE mp_limb_t _nmod_add(mp_limb_t a, mp_limb_t b, nmod_t mod) { const mp_limb_t sum = a + b; return sum - mod.n + ((((mp_limb_signed_t)(sum - mod.n))>>(FLINT_BITS - 1)) & mod.n); } NMOD_VEC_INLINE mp_limb_t _nmod_sub(mp_limb_t a, mp_limb_t b, nmod_t mod) { const mp_limb_t diff = a - b; return ((((mp_limb_signed_t)diff)>>(FLINT_BITS - 1)) & mod.n) + diff; } NMOD_VEC_INLINE mp_limb_t nmod_add(mp_limb_t a, mp_limb_t b, nmod_t mod) { const mp_limb_t neg = mod.n - a; if (neg > b) return a + b; else return b - neg; } NMOD_VEC_INLINE mp_limb_t nmod_sub(mp_limb_t a, mp_limb_t b, nmod_t mod) { const mp_limb_t diff = a - b; if (a < b) return mod.n + diff; else return diff; } NMOD_VEC_INLINE mp_limb_t nmod_neg(mp_limb_t a, nmod_t mod) { if (a) return mod.n - a; else return 0; } NMOD_VEC_INLINE mp_limb_t nmod_mul(mp_limb_t a, mp_limb_t b, nmod_t mod) { mp_limb_t res, hi, lo; umul_ppmm(hi, lo, a, b); NMOD_RED2(res, hi, lo, mod); return res; } NMOD_VEC_INLINE mp_limb_t nmod_addmul(mp_limb_t a, mp_limb_t b, mp_limb_t c, nmod_t mod) { NMOD_ADDMUL(a, b, c, mod); return a; } NMOD_VEC_INLINE mp_limb_t nmod_inv(mp_limb_t a, nmod_t mod) { return n_invmod(a, mod.n); } NMOD_VEC_INLINE mp_limb_t nmod_div(mp_limb_t a, mp_limb_t b, nmod_t mod) { b = n_invmod(b, mod.n); return n_mulmod2_preinv(a, b, mod.n, mod.ninv); } NMOD_VEC_INLINE mp_limb_t nmod_pow_ui(mp_limb_t a, ulong exp, nmod_t mod) { return n_powmod2_ui_preinv(a, exp, mod.n, mod.ninv); } /* This function is in fmpz.h FMPZ_INLINE mp_limb_t nmod_pow_fmpz(mp_limb_t a, const fmpz_t exp, nmod_t mod) */ NMOD_VEC_INLINE void nmod_init(nmod_t * mod, mp_limb_t n) { mod->n = n; mod->ninv = n_preinvert_limb(n); count_leading_zeros(mod->norm, n); } NMOD_VEC_INLINE mp_ptr _nmod_vec_init(slong len) { return (mp_ptr) flint_malloc(len * sizeof(mp_limb_t)); } NMOD_VEC_INLINE void _nmod_vec_clear(mp_ptr vec) { flint_free(vec); } FLINT_DLL void _nmod_vec_randtest(mp_ptr vec, flint_rand_t state, slong len, nmod_t mod); NMOD_VEC_INLINE void _nmod_vec_zero(mp_ptr vec, slong len) { flint_mpn_zero(vec, len); } FLINT_DLL flint_bitcnt_t _nmod_vec_max_bits(mp_srcptr vec, slong len); NMOD_VEC_INLINE void _nmod_vec_set(mp_ptr res, mp_srcptr vec, slong len) { flint_mpn_copyi(res, vec, len); } NMOD_VEC_INLINE void _nmod_vec_swap(mp_ptr a, mp_ptr b, slong length) { slong i; for (i = 0; i < length; i++) { mp_limb_t t = a[i]; a[i] = b[i]; b[i] = t; } } NMOD_VEC_INLINE int _nmod_vec_equal(mp_srcptr vec, mp_srcptr vec2, slong len) { slong i; for (i = 0; i < len; i++) if (vec[i] != vec2[i]) return 0; return 1; } NMOD_VEC_INLINE int _nmod_vec_is_zero(mp_srcptr vec, slong len) { slong i; for (i = 0; i < len; i++) if (vec[i] != 0) return 0; return 1; } FLINT_DLL void _nmod_vec_reduce(mp_ptr res, mp_srcptr vec, slong len, nmod_t mod); FLINT_DLL void _nmod_vec_add(mp_ptr res, mp_srcptr vec1, mp_srcptr vec2, slong len, nmod_t mod); FLINT_DLL void _nmod_vec_sub(mp_ptr res, mp_srcptr vec1, mp_srcptr vec2, slong len, nmod_t mod); FLINT_DLL void _nmod_vec_neg(mp_ptr res, mp_srcptr vec, slong len, nmod_t mod); FLINT_DLL void _nmod_vec_scalar_mul_nmod(mp_ptr res, mp_srcptr vec, slong len, mp_limb_t c, nmod_t mod); FLINT_DLL void _nmod_vec_scalar_mul_nmod_shoup(mp_ptr res, mp_srcptr vec, slong len, mp_limb_t c, nmod_t mod); FLINT_DLL void _nmod_vec_scalar_addmul_nmod(mp_ptr res, mp_srcptr vec, slong len, mp_limb_t c, nmod_t mod); FLINT_DLL int _nmod_vec_dot_bound_limbs(slong len, nmod_t mod); #define NMOD_VEC_DOT(res, i, len, expr1, expr2, mod, nlimbs) \ do \ { \ mp_limb_t s0, s1, s2, t0, t1; \ s0 = s1 = s2 = UWORD(0); \ switch (nlimbs) \ { \ case 1: \ for (i = 0; i < (len); i++) \ { \ s0 += (expr1) * (expr2); \ } \ NMOD_RED(s0, s0, mod); \ break; \ case 2: \ if (mod.n <= (UWORD(1) << (FLINT_BITS / 2))) \ { \ for (i = 0; i < (len); i++) \ { \ t0 = (expr1) * (expr2); \ add_ssaaaa(s1, s0, s1, s0, 0, t0); \ } \ } \ else if ((len) < 8) \ { \ for (i = 0; i < len; i++) \ { \ umul_ppmm(t1, t0, (expr1), (expr2)); \ add_ssaaaa(s1, s0, s1, s0, t1, t0); \ } \ } \ else \ { \ mp_limb_t v0, v1, u0, u1; \ i = 0; \ if ((len) & 1) \ umul_ppmm(v1, v0, (expr1), (expr2)); \ else \ v0 = v1 = 0; \ for (i = (len) & 1; i < (len); i++) \ { \ umul_ppmm(t1, t0, (expr1), (expr2)); \ add_ssaaaa(s1, s0, s1, s0, t1, t0); \ i++; \ umul_ppmm(u1, u0, (expr1), (expr2)); \ add_ssaaaa(v1, v0, v1, v0, u1, u0); \ } \ add_ssaaaa(s1, s0, s1, s0, v1, v0); \ } \ NMOD2_RED2(s0, s1, s0, mod); \ break; \ default: \ for (i = 0; i < (len); i++) \ { \ umul_ppmm(t1, t0, (expr1), (expr2)); \ add_sssaaaaaa(s2, s1, s0, s2, s1, s0, 0, t1, t0); \ } \ NMOD_RED(s2, s2, mod); \ NMOD_RED3(s0, s2, s1, s0, mod); \ break; \ } \ res = s0; \ } while (0); FLINT_DLL mp_limb_t _nmod_vec_dot(mp_srcptr vec1, mp_srcptr vec2, slong len, nmod_t mod, int nlimbs); FLINT_DLL mp_limb_t _nmod_vec_dot_rev(mp_srcptr vec1, mp_srcptr vec2, slong len, nmod_t mod, int nlimbs); FLINT_DLL mp_limb_t _nmod_vec_dot_ptr(mp_srcptr vec1, const mp_ptr * vec2, slong offset, slong len, nmod_t mod, int nlimbs); /* discrete logs a la Pohlig - Hellman ***************************************/ typedef struct { mp_limb_t gammapow; ulong cm; } nmod_discrete_log_pohlig_hellman_table_entry_struct; typedef struct { slong exp; ulong prime; mp_limb_t gamma; mp_limb_t gammainv; mp_limb_t startingbeta; ulong co; ulong startinge; ulong idem; ulong cbound; ulong dbound; nmod_discrete_log_pohlig_hellman_table_entry_struct * table; /* length cbound */ } nmod_discrete_log_pohlig_hellman_entry_struct; typedef struct { nmod_t mod; /* p is mod.n */ mp_limb_t alpha; /* p.r. of p */ mp_limb_t alphainv; slong num_factors; /* factors of p - 1*/ nmod_discrete_log_pohlig_hellman_entry_struct * entries; } nmod_discrete_log_pohlig_hellman_struct; typedef nmod_discrete_log_pohlig_hellman_struct nmod_discrete_log_pohlig_hellman_t[1]; FLINT_DLL void nmod_discrete_log_pohlig_hellman_init( nmod_discrete_log_pohlig_hellman_t L); FLINT_DLL void nmod_discrete_log_pohlig_hellman_clear( nmod_discrete_log_pohlig_hellman_t L); FLINT_DLL double nmod_discrete_log_pohlig_hellman_precompute_prime( nmod_discrete_log_pohlig_hellman_t L, mp_limb_t p); FLINT_DLL ulong nmod_discrete_log_pohlig_hellman_run( const nmod_discrete_log_pohlig_hellman_t L, mp_limb_t y); NMOD_VEC_INLINE mp_limb_t nmod_discrete_log_pohlig_hellman_primitive_root( const nmod_discrete_log_pohlig_hellman_t L) { return L->alpha; } #ifdef __cplusplus } #endif #endif