File indexing completed on 2026-11-07 10:15:33
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #ifndef NMOD_VEC_H
0015 #define NMOD_VEC_H
0016
0017 #ifdef NMOD_VEC_INLINES_C
0018 #define NMOD_VEC_INLINE
0019 #else
0020 #define NMOD_VEC_INLINE static inline
0021 #endif
0022
0023 #include "flint.h"
0024 #include "nmod.h" // nmod_mul, nmod_fmma
0025
0026 #ifdef __cplusplus
0027 extern "C" {
0028 #endif
0029
0030 #define NMOD_VEC_NORM(vec, i) \
0031 do { \
0032 while ((i) && vec[(i) - 1] == UWORD(0)) \
0033 (i)--; \
0034 } while (0)
0035
0036 NMOD_VEC_INLINE
0037 nn_ptr _nmod_vec_init(slong len)
0038 {
0039 return (nn_ptr) flint_malloc(len * sizeof(ulong));
0040 }
0041
0042 NMOD_VEC_INLINE
0043 void _nmod_vec_clear(nn_ptr vec)
0044 {
0045 flint_free(vec);
0046 }
0047
0048 void _nmod_vec_randtest(nn_ptr vec, flint_rand_t state, slong len, nmod_t mod);
0049
0050 void _nmod_vec_rand(nn_ptr vec, flint_rand_t state, slong len, nmod_t mod);
0051
0052 NMOD_VEC_INLINE
0053 void _nmod_vec_zero(nn_ptr vec, slong len)
0054 {
0055 slong i;
0056 for (i = 0; i < len; i++)
0057 vec[i] = 0;
0058 }
0059
0060 flint_bitcnt_t _nmod_vec_max_bits(nn_srcptr vec, slong len);
0061
0062 NMOD_VEC_INLINE
0063 void _nmod_vec_set(nn_ptr res, nn_srcptr vec, slong len)
0064 {
0065 slong i;
0066 for (i = 0; i < len; i++)
0067 res[i] = vec[i];
0068 }
0069
0070 NMOD_VEC_INLINE
0071 void _nmod_vec_swap(nn_ptr a, nn_ptr b, slong length)
0072 {
0073 slong i;
0074 for (i = 0; i < length; i++)
0075 {
0076 ulong t = a[i];
0077 a[i] = b[i];
0078 b[i] = t;
0079 }
0080 }
0081
0082 NMOD_VEC_INLINE
0083 int _nmod_vec_equal(nn_srcptr vec, nn_srcptr vec2, slong len)
0084 {
0085 slong i;
0086
0087 for (i = 0; i < len; i++)
0088 if (vec[i] != vec2[i]) return 0;
0089
0090 return 1;
0091 }
0092
0093 NMOD_VEC_INLINE
0094 int _nmod_vec_is_zero(nn_srcptr vec, slong len)
0095 {
0096 slong i;
0097
0098 for (i = 0; i < len; i++)
0099 if (vec[i] != 0) return 0;
0100
0101 return 1;
0102 }
0103
0104
0105 #ifdef FLINT_HAVE_FILE
0106 int _nmod_vec_fprint_pretty(FILE * file, nn_srcptr vec, slong len, nmod_t mod);
0107 int _nmod_vec_fprint(FILE * f, nn_srcptr vec, slong len, nmod_t mod);
0108 #endif
0109
0110 void _nmod_vec_print_pretty(nn_srcptr vec, slong len, nmod_t mod);
0111 int _nmod_vec_print(nn_srcptr vec, slong len, nmod_t mod);
0112
0113
0114 void _nmod_vec_reduce(nn_ptr res, nn_srcptr vec, slong len, nmod_t mod);
0115
0116 void _nmod_vec_add(nn_ptr res, nn_srcptr vec1, nn_srcptr vec2, slong len, nmod_t mod);
0117 void _nmod_vec_sub(nn_ptr res, nn_srcptr vec1, nn_srcptr vec2, slong len, nmod_t mod);
0118 void _nmod_vec_neg(nn_ptr res, nn_srcptr vec, slong len, nmod_t mod);
0119
0120 void _nmod_vec_scalar_mul_nmod(nn_ptr res, nn_srcptr vec, slong len, ulong c, nmod_t mod);
0121 void _nmod_vec_scalar_mul_nmod_redc(nn_ptr res, nn_srcptr vec, slong len, ulong c, nmod_t mod);
0122 void _nmod_vec_scalar_mul_nmod_generic(nn_ptr res, nn_srcptr vec, slong len, ulong c, nmod_t mod);
0123 void _nmod_vec_scalar_mul_nmod_shoup(nn_ptr res, nn_srcptr vec, slong len, ulong c, nmod_t mod);
0124
0125 void _nmod_vec_scalar_addmul_nmod(nn_ptr res, nn_srcptr vec, slong len, ulong c, nmod_t mod);
0126 void _nmod_vec_scalar_addmul_nmod_generic(nn_ptr res, nn_srcptr vec, slong len, ulong c, nmod_t mod);
0127 void _nmod_vec_scalar_addmul_nmod_shoup(nn_ptr res, nn_srcptr vec, slong len, ulong c, nmod_t mod);
0128
0129 #if FLINT_BITS == 64 && defined(__AVX2__)
0130 void _nmod_vec_nored_scalar_addmul_halflimb_avx2(nn_ptr res, nn_srcptr vec, slong len, ulong c);
0131 #endif
0132
0133 NMOD_VEC_INLINE void
0134 _nmod_vec_nored_scalar_addmul_halflimb(nn_ptr res, nn_srcptr vec, slong len, ulong c)
0135 {
0136 #if FLINT_BITS == 64 && defined(__AVX2__)
0137 if (len >= 16)
0138 {
0139 _nmod_vec_nored_scalar_addmul_halflimb_avx2(res, vec, len, c);
0140 return;
0141 }
0142 #endif
0143
0144 slong i;
0145 for (i = 0; i < len; i++)
0146 res[i] += vec[i] * c;
0147 }
0148
0149 void _nmod_vec_nored_scalar_addmul_halflimb(nn_ptr res, nn_srcptr vec, slong len, ulong c);
0150 void _nmod_vec_nored_ll_scalar_addmul_halflimb(nn_ptr res, nn_srcptr vec, slong len, ulong c);
0151 void _nmod_vec_nored_ll_scalar_addmul(nn_ptr res, nn_srcptr vec, slong len, ulong c);
0152 void _nmod_vec_nored_lll_scalar_addmul(nn_ptr res, nn_srcptr vec, slong len, ulong c);
0153
0154
0155 void _nmod_vec_invert(nn_ptr res, nn_srcptr vec, ulong len, nmod_t mod);
0156 void _nmod_vec_invert_naive(nn_ptr res, nn_srcptr vec, ulong len, nmod_t mod);
0157 void _nmod_vec_invert_generic(nn_ptr res, nn_srcptr vec, ulong len, nmod_t mod);
0158 void _nmod_vec_invert_shoup(nn_ptr res, nn_srcptr vec, ulong len, nmod_t mod);
0159
0160
0161
0162
0163 #if (FLINT_BITS == 64)
0164 # define DOT_SPLIT_BITS 56
0165 # define DOT_SPLIT_MASK UWORD(72057594037927935)
0166 #endif
0167
0168 #define _FIXED_LEN_MOD_BOUNDS(fixedlen, onelimb_bnd, twolimb_bnd) \
0169 if (len == fixedlen) \
0170 { \
0171 if (mod.n <= UWORD(onelimb_bnd)) \
0172 { \
0173 dot_params_t params = {_DOT1, UWORD(0)}; \
0174 return params; \
0175 } \
0176 if (mod.n <= UWORD(twolimb_bnd)) \
0177 { \
0178 dot_params_t params = {_DOT2, UWORD(0)}; \
0179 return params; \
0180 } \
0181 dot_params_t params = {_DOT3, UWORD(0)}; \
0182 return params; \
0183 }
0184
0185 FLINT_FORCE_INLINE dot_params_t _nmod_vec_dot_params(ulong len, nmod_t mod)
0186 {
0187 if (len == 0 || mod.n == 1)
0188 {
0189 dot_params_t params = {_DOT0, UWORD(0)};
0190 return params;
0191 }
0192 if ((mod.n & (mod.n - 1)) == 0)
0193 {
0194 dot_params_t params = {_DOT_POW2, UWORD(0)};
0195 return params;
0196 }
0197
0198
0199
0200 if (len <= 11)
0201 {
0202 #if FLINT_BITS == 64
0203
0204 _FIXED_LEN_MOD_BOUNDS(11, 1294981365, 5561902608746059656);
0205 _FIXED_LEN_MOD_BOUNDS(10, 1358187914, 5833372668713515885);
0206 _FIXED_LEN_MOD_BOUNDS( 9, 1431655766, 6148914691236517206);
0207 _FIXED_LEN_MOD_BOUNDS( 8, 1518500250, 6521908912666391107);
0208 _FIXED_LEN_MOD_BOUNDS( 7, 1623345051, 6972213902555716131);
0209 _FIXED_LEN_MOD_BOUNDS( 6, 1753413057, 7530851732716320753);
0210 _FIXED_LEN_MOD_BOUNDS( 5, 1920767767, 8249634742471189718);
0211 _FIXED_LEN_MOD_BOUNDS( 4, 2147483648, 9223372036854775808);
0212 _FIXED_LEN_MOD_BOUNDS( 3, 2479700525, 10650232656628343402);
0213 _FIXED_LEN_MOD_BOUNDS( 2, 3037000500, 13043817825332782213);
0214 #else
0215
0216 _FIXED_LEN_MOD_BOUNDS(11, 19760, 1294981365);
0217 _FIXED_LEN_MOD_BOUNDS(10, 20725, 1358187914);
0218 _FIXED_LEN_MOD_BOUNDS( 9, 21846, 1431655766);
0219 _FIXED_LEN_MOD_BOUNDS( 8, 23171, 1518500250);
0220 _FIXED_LEN_MOD_BOUNDS( 7, 24771, 1623345051);
0221 _FIXED_LEN_MOD_BOUNDS( 6, 26755, 1753413057);
0222 _FIXED_LEN_MOD_BOUNDS( 5, 29309, 1920767767);
0223 _FIXED_LEN_MOD_BOUNDS( 4, 32768, 2147483648);
0224 _FIXED_LEN_MOD_BOUNDS( 3, 37838, 2479700525);
0225 _FIXED_LEN_MOD_BOUNDS( 2, 46341, 3037000500);
0226 #endif
0227
0228 if (mod.n <= (UWORD(1) << FLINT_BITS / 2))
0229 {
0230 dot_params_t params = {_DOT1, UWORD(0)};
0231 return params;
0232 }
0233 dot_params_t params = {_DOT2, UWORD(0)};
0234 return params;
0235 }
0236
0237 if (mod.n <= UWORD(1) << (FLINT_BITS / 2))
0238 {
0239 const ulong t0 = (mod.n - 1) * (mod.n - 1);
0240 ulong u1 = n_mulhi(t0, len);
0241 if (u1 == 0)
0242 {
0243 dot_params_t params = {_DOT1, UWORD(0)};
0244 return params;
0245 }
0246
0247
0248 #if (FLINT_BITS == 64)
0249 if (mod.n <= UWORD(1515531528) && len <= WORD(380368697))
0250 {
0251 ulong pow2_precomp;
0252 NMOD_RED(pow2_precomp, (UWORD(1) << DOT_SPLIT_BITS), mod);
0253 dot_params_t params = {_DOT2_SPLIT, pow2_precomp};
0254 return params;
0255 }
0256 #endif
0257 #if (FLINT_BITS == 64) && defined(__AVX2__)
0258 ulong pow2_precomp;
0259 NMOD_RED(pow2_precomp, (UWORD(1) << DOT_SPLIT_BITS), mod);
0260 dot_params_t params = {_DOT2_HALF, pow2_precomp};
0261 return params;
0262 #else
0263 dot_params_t params = {_DOT2_HALF, UWORD(0)};
0264 return params;
0265 #endif
0266 }
0267
0268
0269
0270 ulong t2, t1, t0, u1;
0271 umul_ppmm(t1, t0, mod.n - 1, mod.n - 1);
0272 umul_ppmm(t2, t1, t1, len);
0273 u1 = n_mulhi(t0, len);
0274 add_ssaaaa(t2, t1, t2, t1, UWORD(0), u1);
0275
0276 if (t2 == 0)
0277 {
0278 dot_params_t params = {_DOT2, UWORD(0)};
0279 return params;
0280 }
0281
0282
0283 #if (FLINT_BITS == 64)
0284 if (mod.n <= UWORD(6521908912666391107))
0285 #else
0286 if (mod.n <= UWORD(1518500250))
0287 #endif
0288 {
0289 dot_params_t params = {_DOT3_ACC, UWORD(0)};
0290 return params;
0291 }
0292
0293 dot_params_t params = {_DOT3, UWORD(0)};
0294 return params;
0295 }
0296
0297 #undef _FIXED_LEN_MOD_BOUNDS
0298
0299 int _nmod_vec_dot_bound_limbs(slong len, nmod_t mod);
0300 int _nmod_vec_dot_bound_limbs_from_params(slong len, nmod_t mod, dot_params_t params);
0301
0302
0303
0304
0305
0306 ulong _nmod_vec_dot_pow2(nn_srcptr vec1, nn_srcptr vec2, slong len, nmod_t mod);
0307 ulong _nmod_vec_dot1(nn_srcptr vec1, nn_srcptr vec2, slong len, nmod_t mod);
0308 ulong _nmod_vec_dot2_half(nn_srcptr vec1, nn_srcptr vec2, slong len, nmod_t mod, ulong pow2_precomp);
0309 ulong _nmod_vec_dot2(nn_srcptr vec1, nn_srcptr vec2, slong len, nmod_t mod);
0310 ulong _nmod_vec_dot3_acc(nn_srcptr vec1, nn_srcptr vec2, slong len, nmod_t mod);
0311 ulong _nmod_vec_dot3(nn_srcptr vec1, nn_srcptr vec2, slong len, nmod_t mod);
0312 #if FLINT_BITS == 64
0313 ulong _nmod_vec_dot2_split(nn_srcptr vec1, nn_srcptr vec2, slong len, nmod_t mod, ulong pow2_precomp);
0314 #endif
0315
0316
0317 ulong _nmod_vec_dot_pow2_rev(nn_srcptr vec1, nn_srcptr vec2, slong len, nmod_t mod);
0318 ulong _nmod_vec_dot1_rev(nn_srcptr vec1, nn_srcptr vec2, slong len, nmod_t mod);
0319 ulong _nmod_vec_dot2_half_rev(nn_srcptr vec1, nn_srcptr vec2, slong len, nmod_t mod);
0320 ulong _nmod_vec_dot2_rev(nn_srcptr vec1, nn_srcptr vec2, slong len, nmod_t mod);
0321 ulong _nmod_vec_dot3_acc_rev(nn_srcptr vec1, nn_srcptr vec2, slong len, nmod_t mod);
0322 ulong _nmod_vec_dot3_rev(nn_srcptr vec1, nn_srcptr vec2, slong len, nmod_t mod);
0323 #if FLINT_BITS == 64
0324 ulong _nmod_vec_dot2_split_rev(nn_srcptr vec1, nn_srcptr vec2, slong len, nmod_t mod, ulong pow2_precomp);
0325 #endif
0326
0327
0328 ulong _nmod_vec_dot_pow2_ptr(nn_srcptr vec1, const nn_ptr * vec2, slong offset, slong len, nmod_t mod);
0329 ulong _nmod_vec_dot1_ptr(nn_srcptr vec1, const nn_ptr * vec2, slong offset, slong len, nmod_t mod);
0330 ulong _nmod_vec_dot2_half_ptr(nn_srcptr vec1, const nn_ptr * vec2, slong offset, slong len, nmod_t mod);
0331 ulong _nmod_vec_dot2_ptr(nn_srcptr vec1, const nn_ptr * vec2, slong offset, slong len, nmod_t mod);
0332 ulong _nmod_vec_dot3_acc_ptr(nn_srcptr vec1, const nn_ptr * vec2, slong offset, slong len, nmod_t mod);
0333 ulong _nmod_vec_dot3_ptr(nn_srcptr vec1, const nn_ptr * vec2, slong offset, slong len, nmod_t mod);
0334 #if FLINT_BITS == 64
0335 ulong _nmod_vec_dot2_split_ptr(nn_srcptr vec1, const nn_ptr * vec2, slong offset, slong len, nmod_t mod, ulong pow2_precomp);
0336 #endif
0337
0338
0339
0340
0341
0342
0343
0344
0345
0346 #define _NMOD_VEC_DOT_SHORT1(fixedlen,expr1,expr2) \
0347 { \
0348 ulong res = (expr1) * (expr2); i++; \
0349 for (slong j = 0; j < fixedlen-1; j++, i++) \
0350 res += (expr1) * (expr2); \
0351 NMOD_RED(res, res, mod); \
0352 return res; \
0353 } \
0354
0355 #define _NMOD_VEC_DOT_SHORT2(fixedlen,expr1,expr2) \
0356 { \
0357 ulong s0, s1, u0, u1; \
0358 umul_ppmm(u1, u0, (expr1), (expr2)); i++; \
0359 for (slong j = 0; j < fixedlen-1; j++, i++) \
0360 { \
0361 umul_ppmm(s1, s0, (expr1), (expr2)); \
0362 add_ssaaaa(u1, u0, u1, u0, s1, s0); \
0363 } \
0364 NMOD2_RED2(s0, u1, u0, mod); \
0365 return s0; \
0366 } \
0367
0368 #define _NMOD_VEC_DOT_SHORT3(fixedlen,expr1,expr2) \
0369 { \
0370 ulong t2 = UWORD(0); \
0371 ulong t1, t0; \
0372 umul_ppmm(t1, t0, (expr1), (expr2)); i++; \
0373 for (slong j = 0; j < fixedlen - 1; j++, i++) \
0374 { \
0375 ulong s0, s1; \
0376 umul_ppmm(s1, s0, (expr1), (expr2)); \
0377 add_sssaaaaaa(t2, t1, t0, \
0378 t2, t1, t0, \
0379 UWORD(0), s1, s0); \
0380 } \
0381 \
0382 NMOD_RED(t2, t2, mod); \
0383 ulong res; \
0384 NMOD_RED3(res, t2, t1, t0, mod); \
0385 return res; \
0386 } \
0387
0388
0389
0390 #define _NMOD_VEC_DOT_SHORT(i, expr1, expr2, len, mod, method) \
0391 { \
0392 if (method == _DOT1 || method == _DOT_POW2) \
0393 { \
0394 if (len == 1) _NMOD_VEC_DOT_SHORT1( 1, expr1, expr2) \
0395 if (len == 2) _NMOD_VEC_DOT_SHORT1( 2, expr1, expr2) \
0396 if (len == 3) _NMOD_VEC_DOT_SHORT1( 3, expr1, expr2) \
0397 if (len == 4) _NMOD_VEC_DOT_SHORT1( 4, expr1, expr2) \
0398 if (len == 5) _NMOD_VEC_DOT_SHORT1( 5, expr1, expr2) \
0399 if (len == 6) _NMOD_VEC_DOT_SHORT1( 6, expr1, expr2) \
0400 if (len == 7) _NMOD_VEC_DOT_SHORT1( 7, expr1, expr2) \
0401 if (len == 8) _NMOD_VEC_DOT_SHORT1( 8, expr1, expr2) \
0402 if (len == 9) _NMOD_VEC_DOT_SHORT1( 9, expr1, expr2) \
0403 if (len == 10) _NMOD_VEC_DOT_SHORT1(10, expr1, expr2) \
0404 _NMOD_VEC_DOT_SHORT1(11, expr1, expr2) \
0405 } \
0406 \
0407 else if (method == _DOT2) \
0408 { \
0409 if (len == 1) return nmod_mul((expr1), (expr2), mod); \
0410 if (len == 2) _NMOD_VEC_DOT_SHORT2( 2, expr1, expr2) \
0411 if (len == 3) _NMOD_VEC_DOT_SHORT2( 3, expr1, expr2) \
0412 if (len == 4) _NMOD_VEC_DOT_SHORT2( 4, expr1, expr2) \
0413 if (len == 5) _NMOD_VEC_DOT_SHORT2( 5, expr1, expr2) \
0414 if (len == 6) _NMOD_VEC_DOT_SHORT2( 6, expr1, expr2) \
0415 if (len == 7) _NMOD_VEC_DOT_SHORT2( 7, expr1, expr2) \
0416 if (len == 8) _NMOD_VEC_DOT_SHORT2( 8, expr1, expr2) \
0417 if (len == 9) _NMOD_VEC_DOT_SHORT2( 9, expr1, expr2) \
0418 if (len == 10) _NMOD_VEC_DOT_SHORT2(10, expr1, expr2) \
0419 _NMOD_VEC_DOT_SHORT2(11, expr1, expr2) \
0420 } \
0421 \
0422 else if (method == _DOT3) \
0423 { \
0424 if (len == 1) return nmod_mul((expr1), (expr2), mod); \
0425 if (len == 2) _NMOD_VEC_DOT_SHORT3( 2, expr1, expr2) \
0426 if (len == 3) _NMOD_VEC_DOT_SHORT3( 3, expr1, expr2) \
0427 if (len == 4) _NMOD_VEC_DOT_SHORT3( 4, expr1, expr2) \
0428 if (len == 5) _NMOD_VEC_DOT_SHORT3( 5, expr1, expr2) \
0429 if (len == 6) _NMOD_VEC_DOT_SHORT3( 6, expr1, expr2) \
0430 if (len == 7) _NMOD_VEC_DOT_SHORT3( 7, expr1, expr2) \
0431 if (len == 8) _NMOD_VEC_DOT_SHORT3( 8, expr1, expr2) \
0432 if (len == 9) _NMOD_VEC_DOT_SHORT3( 9, expr1, expr2) \
0433 if (len == 10) _NMOD_VEC_DOT_SHORT3(10, expr1, expr2) \
0434 _NMOD_VEC_DOT_SHORT3(11, expr1, expr2) \
0435 } \
0436 } while(0); \
0437
0438 FLINT_FORCE_INLINE ulong _nmod_vec_dot(nn_srcptr vec1, nn_srcptr vec2, slong len, nmod_t mod, dot_params_t params)
0439 {
0440 if (len <= 11)
0441 {
0442 if (len == 0) return UWORD(0);
0443 slong i = 0;
0444 _NMOD_VEC_DOT_SHORT(i, vec1[i], vec2[i], len, mod, params.method);
0445 }
0446
0447 if (params.method == _DOT1)
0448 return _nmod_vec_dot1(vec1, vec2, len, mod);
0449
0450 #if FLINT_BITS == 64
0451 if (params.method == _DOT2_SPLIT)
0452 return _nmod_vec_dot2_split(vec1, vec2, len, mod, params.pow2_precomp);
0453 #endif
0454
0455 if (params.method == _DOT2)
0456 return _nmod_vec_dot2(vec1, vec2, len, mod);
0457
0458 if (params.method == _DOT3_ACC)
0459 return _nmod_vec_dot3_acc(vec1, vec2, len, mod);
0460
0461 if (params.method == _DOT3)
0462 return _nmod_vec_dot3(vec1, vec2, len, mod);
0463
0464 if (params.method == _DOT2_HALF)
0465 return _nmod_vec_dot2_half(vec1, vec2, len, mod, params.pow2_precomp);
0466
0467 if (params.method == _DOT_POW2)
0468 {
0469 if (mod.n <= UWORD(1) << (FLINT_BITS / 2))
0470 return _nmod_vec_dot1(vec1, vec2, len, mod);
0471 else
0472 return _nmod_vec_dot_pow2(vec1, vec2, len, mod);
0473 }
0474
0475
0476 return UWORD(0);
0477 }
0478
0479 FLINT_FORCE_INLINE ulong _nmod_vec_dot_rev(nn_srcptr vec1, nn_srcptr vec2, slong len, nmod_t mod, dot_params_t params)
0480 {
0481 if (len <= 11)
0482 {
0483 if (len == 0) return UWORD(0);
0484 slong i = 0;
0485 _NMOD_VEC_DOT_SHORT(i, vec1[i], vec2[len-1-i], len, mod, params.method);
0486 }
0487
0488 if (params.method == _DOT1)
0489 return _nmod_vec_dot1_rev(vec1, vec2, len, mod);
0490
0491 #if FLINT_BITS == 64
0492 if (params.method == _DOT2_SPLIT)
0493 return _nmod_vec_dot2_split_rev(vec1, vec2, len, mod, params.pow2_precomp);
0494 #endif
0495
0496 if (params.method == _DOT2)
0497 return _nmod_vec_dot2_rev(vec1, vec2, len, mod);
0498
0499 if (params.method == _DOT3_ACC)
0500 return _nmod_vec_dot3_acc_rev(vec1, vec2, len, mod);
0501
0502 if (params.method == _DOT3)
0503 return _nmod_vec_dot3_rev(vec1, vec2, len, mod);
0504
0505 if (params.method == _DOT2_HALF)
0506 return _nmod_vec_dot2_half_rev(vec1, vec2, len, mod);
0507
0508 if (params.method == _DOT_POW2)
0509 {
0510 if (mod.n <= UWORD(1) << (FLINT_BITS / 2))
0511 return _nmod_vec_dot1_rev(vec1, vec2, len, mod);
0512 else
0513 return _nmod_vec_dot_pow2_rev(vec1, vec2, len, mod);
0514 }
0515
0516
0517 return UWORD(0);
0518 }
0519
0520 FLINT_FORCE_INLINE ulong _nmod_vec_dot_ptr(nn_srcptr vec1, const nn_ptr * vec2, slong offset, slong len, nmod_t mod, dot_params_t params)
0521 {
0522 if (len <= 11)
0523 {
0524 if (len == 0) return UWORD(0);
0525 slong i = 0;
0526 _NMOD_VEC_DOT_SHORT(i, vec1[i], vec2[i][offset], len, mod, params.method);
0527 }
0528
0529 if (params.method == _DOT1)
0530 return _nmod_vec_dot1_ptr(vec1, vec2, offset, len, mod);
0531
0532 #if FLINT_BITS == 64
0533 if (params.method == _DOT2_SPLIT)
0534 return _nmod_vec_dot2_split_ptr(vec1, vec2, offset, len, mod, params.pow2_precomp);
0535 #endif
0536
0537 if (params.method == _DOT2)
0538 return _nmod_vec_dot2_ptr(vec1, vec2, offset, len, mod);
0539
0540 if (params.method == _DOT3_ACC)
0541 return _nmod_vec_dot3_acc_ptr(vec1, vec2, offset, len, mod);
0542
0543 if (params.method == _DOT3)
0544 return _nmod_vec_dot3_ptr(vec1, vec2, offset, len, mod);
0545
0546 if (params.method == _DOT2_HALF)
0547 return _nmod_vec_dot2_half_ptr(vec1, vec2, offset, len, mod);
0548
0549 if (params.method == _DOT_POW2)
0550 {
0551 if (mod.n <= UWORD(1) << (FLINT_BITS / 2))
0552 return _nmod_vec_dot1_ptr(vec1, vec2, offset, len, mod);
0553 else
0554 return _nmod_vec_dot_pow2_ptr(vec1, vec2, offset, len, mod);
0555 }
0556
0557
0558 return UWORD(0);
0559 }
0560
0561 #undef _NMOD_VEC_DOT_SHORT1
0562 #undef _NMOD_VEC_DOT_SHORT2
0563 #undef _NMOD_VEC_DOT_SHORT3
0564
0565
0566
0567
0568
0569 #define _NMOD_VEC_DOT1(res, i, len, expr1, expr2, mod) \
0570 do \
0571 { \
0572 res = UWORD(0); \
0573 for (i = 0; i < (len); i++) \
0574 res += (expr1) * (expr2); \
0575 NMOD_RED(res, res, mod); \
0576 } while(0);
0577
0578
0579 #if (FLINT_BITS == 64)
0580 #define _NMOD_VEC_DOT2_SPLIT(res, i, len, expr1, expr2, mod, pow2_precomp) \
0581 do \
0582 { \
0583 ulong dp_lo = 0; \
0584 ulong dp_hi = 0; \
0585 \
0586 for (i = 0; i+7 < (len); ) \
0587 { \
0588 dp_lo += (expr1) * (expr2); i++; \
0589 dp_lo += (expr1) * (expr2); i++; \
0590 dp_lo += (expr1) * (expr2); i++; \
0591 dp_lo += (expr1) * (expr2); i++; \
0592 dp_lo += (expr1) * (expr2); i++; \
0593 dp_lo += (expr1) * (expr2); i++; \
0594 dp_lo += (expr1) * (expr2); i++; \
0595 dp_lo += (expr1) * (expr2); i++; \
0596 \
0597 dp_hi += dp_lo >> DOT_SPLIT_BITS; \
0598 dp_lo &= DOT_SPLIT_MASK; \
0599 } \
0600 \
0601 for ( ; i < (len); i++) \
0602 dp_lo += (expr1) * (expr2); \
0603 \
0604 res = pow2_precomp * dp_hi + dp_lo; \
0605 NMOD_RED(res, res, mod); \
0606 } while(0);
0607 #endif
0608
0609
0610
0611
0612 #define _NMOD_VEC_DOT2_HALF(res, i, len, expr1, expr2, mod) \
0613 do \
0614 { \
0615 ulong s0zz = UWORD(0); \
0616 ulong s1zz = UWORD(0); \
0617 for (i = 0; i < (len); i++) \
0618 { \
0619 const ulong prodzz = (expr1) * (expr2); \
0620 add_ssaaaa(s1zz, s0zz, s1zz, s0zz, 0, prodzz); \
0621 } \
0622 NMOD2_RED2(res, s1zz, s0zz, mod); \
0623 } while(0);
0624
0625
0626 #define _NMOD_VEC_DOT2(res, i, len, expr1, expr2, mod) \
0627 do \
0628 { \
0629 ulong u0zz = UWORD(0); \
0630 ulong u1zz = UWORD(0); \
0631 \
0632 for (i = 0; i+7 < (len); ) \
0633 { \
0634 ulong s0zz, s1zz; \
0635 umul_ppmm(s1zz, s0zz, (expr1), (expr2)); \
0636 add_ssaaaa(u1zz, u0zz, u1zz, u0zz, s1zz, s0zz); \
0637 i++; \
0638 umul_ppmm(s1zz, s0zz, (expr1), (expr2)); \
0639 add_ssaaaa(u1zz, u0zz, u1zz, u0zz, s1zz, s0zz); \
0640 i++; \
0641 umul_ppmm(s1zz, s0zz, (expr1), (expr2)); \
0642 add_ssaaaa(u1zz, u0zz, u1zz, u0zz, s1zz, s0zz); \
0643 i++; \
0644 umul_ppmm(s1zz, s0zz, (expr1), (expr2)); \
0645 add_ssaaaa(u1zz, u0zz, u1zz, u0zz, s1zz, s0zz); \
0646 i++; \
0647 umul_ppmm(s1zz, s0zz, (expr1), (expr2)); \
0648 add_ssaaaa(u1zz, u0zz, u1zz, u0zz, s1zz, s0zz); \
0649 i++; \
0650 umul_ppmm(s1zz, s0zz, (expr1), (expr2)); \
0651 add_ssaaaa(u1zz, u0zz, u1zz, u0zz, s1zz, s0zz); \
0652 i++; \
0653 umul_ppmm(s1zz, s0zz, (expr1), (expr2)); \
0654 add_ssaaaa(u1zz, u0zz, u1zz, u0zz, s1zz, s0zz); \
0655 i++; \
0656 umul_ppmm(s1zz, s0zz, (expr1), (expr2)); \
0657 add_ssaaaa(u1zz, u0zz, u1zz, u0zz, s1zz, s0zz); \
0658 i++; \
0659 } \
0660 for ( ; i < (len); i++) \
0661 { \
0662 ulong s0zz, s1zz; \
0663 umul_ppmm(s1zz, s0zz, (expr1), (expr2)); \
0664 add_ssaaaa(u1zz, u0zz, u1zz, u0zz, s1zz, s0zz); \
0665 } \
0666 \
0667 NMOD2_RED2(res, u1zz, u0zz, mod); \
0668 } while(0);
0669
0670
0671
0672 #define _NMOD_VEC_DOT3_ACC(res, i, len, expr1, expr2, mod) \
0673 do \
0674 { \
0675 ulong t2zz = UWORD(0); \
0676 ulong t1zz = UWORD(0); \
0677 ulong t0zz = UWORD(0); \
0678 \
0679 for (i = 0; i+7 < (len); ) \
0680 { \
0681 ulong s0zz, s1zz; \
0682 ulong u0zz = UWORD(0); \
0683 ulong u1zz = UWORD(0); \
0684 umul_ppmm(s1zz, s0zz, (expr1), (expr2)); \
0685 add_ssaaaa(u1zz, u0zz, u1zz, u0zz, s1zz, s0zz); \
0686 i++; \
0687 umul_ppmm(s1zz, s0zz, (expr1), (expr2)); \
0688 add_ssaaaa(u1zz, u0zz, u1zz, u0zz, s1zz, s0zz); \
0689 i++; \
0690 umul_ppmm(s1zz, s0zz, (expr1), (expr2)); \
0691 add_ssaaaa(u1zz, u0zz, u1zz, u0zz, s1zz, s0zz); \
0692 i++; \
0693 umul_ppmm(s1zz, s0zz, (expr1), (expr2)); \
0694 add_ssaaaa(u1zz, u0zz, u1zz, u0zz, s1zz, s0zz); \
0695 i++; \
0696 umul_ppmm(s1zz, s0zz, (expr1), (expr2)); \
0697 add_ssaaaa(u1zz, u0zz, u1zz, u0zz, s1zz, s0zz); \
0698 i++; \
0699 umul_ppmm(s1zz, s0zz, (expr1), (expr2)); \
0700 add_ssaaaa(u1zz, u0zz, u1zz, u0zz, s1zz, s0zz); \
0701 i++; \
0702 umul_ppmm(s1zz, s0zz, (expr1), (expr2)); \
0703 add_ssaaaa(u1zz, u0zz, u1zz, u0zz, s1zz, s0zz); \
0704 i++; \
0705 umul_ppmm(s1zz, s0zz, (expr1), (expr2)); \
0706 add_ssaaaa(u1zz, u0zz, u1zz, u0zz, s1zz, s0zz); \
0707 i++; \
0708 add_sssaaaaaa(t2zz, t1zz, t0zz, \
0709 t2zz, t1zz, t0zz, \
0710 UWORD(0), u1zz, u0zz); \
0711 } \
0712 \
0713 ulong s0zz, s1zz; \
0714 ulong u0zz = UWORD(0); \
0715 ulong u1zz = UWORD(0); \
0716 for ( ; i < (len); i++) \
0717 { \
0718 umul_ppmm(s1zz, s0zz, (expr1), (expr2)); \
0719 add_ssaaaa(u1zz, u0zz, u1zz, u0zz, s1zz, s0zz); \
0720 } \
0721 \
0722 add_sssaaaaaa(t2zz, t1zz, t0zz, \
0723 t2zz, t1zz, t0zz, \
0724 UWORD(0), u1zz, u0zz); \
0725 \
0726 NMOD_RED(t2zz, t2zz, mod); \
0727 NMOD_RED3(res, t2zz, t1zz, t0zz, mod); \
0728 } while(0);
0729
0730
0731
0732 #define _NMOD_VEC_DOT3(res, i, len, expr1, expr2, mod) \
0733 do \
0734 { \
0735 ulong t2zz = UWORD(0); \
0736 ulong t1zz = UWORD(0); \
0737 ulong t0zz = UWORD(0); \
0738 for (i = 0; i < (len); i++) \
0739 { \
0740 ulong s0zz, s1zz; \
0741 umul_ppmm(s1zz, s0zz, (expr1), (expr2)); \
0742 add_sssaaaaaa(t2zz, t1zz, t0zz, \
0743 t2zz, t1zz, t0zz, \
0744 UWORD(0), s1zz, s0zz); \
0745 } \
0746 \
0747 NMOD_RED(t2zz, t2zz, mod); \
0748 NMOD_RED3(res, t2zz, t1zz, t0zz, mod); \
0749 } while(0);
0750
0751
0752
0753
0754 #if (FLINT_BITS == 64)
0755
0756 #define NMOD_VEC_DOT(res, i, len, expr1, expr2, mod, params) \
0757 do \
0758 { \
0759 res = UWORD(0); \
0760 if (params.method == _DOT1 || params.method == _DOT_POW2) \
0761 _NMOD_VEC_DOT1(res, i, len, expr1, expr2, mod) \
0762 else if (params.method == _DOT2_SPLIT) \
0763 _NMOD_VEC_DOT2_SPLIT(res, i, len, expr1, expr2, mod, \
0764 params.pow2_precomp) \
0765 else if (params.method == _DOT2_HALF) \
0766 _NMOD_VEC_DOT2_HALF(res, i, len, expr1, expr2, mod) \
0767 else if (params.method == _DOT2) \
0768 _NMOD_VEC_DOT2(res, i, len, expr1, expr2, mod) \
0769 else if (params.method == _DOT3_ACC) \
0770 _NMOD_VEC_DOT3_ACC(res, i, len, expr1, expr2, mod) \
0771 else if (params.method == _DOT3) \
0772 _NMOD_VEC_DOT3(res, i, len, expr1, expr2, mod) \
0773 } while(0);
0774
0775 #else
0776
0777 #define NMOD_VEC_DOT(res, i, len, expr1, expr2, mod, params) \
0778 do \
0779 { \
0780 res = UWORD(0); \
0781 if (params.method == _DOT1 || params.method == _DOT_POW2) \
0782 _NMOD_VEC_DOT1(res, i, len, expr1, expr2, mod) \
0783 else if (params.method == _DOT2_HALF) \
0784 _NMOD_VEC_DOT2_HALF(res, i, len, expr1, expr2, mod) \
0785 else if (params.method == _DOT2) \
0786 _NMOD_VEC_DOT2(res, i, len, expr1, expr2, mod) \
0787 else if (params.method == _DOT3_ACC) \
0788 _NMOD_VEC_DOT3_ACC(res, i, len, expr1, expr2, mod) \
0789 else if (params.method == _DOT3) \
0790 _NMOD_VEC_DOT3(res, i, len, expr1, expr2, mod) \
0791 } while(0);
0792
0793 #endif
0794
0795
0796
0797 NMOD_VEC_INLINE ulong _nmod_vec_dot_strided(nn_srcptr vec1, slong stride1,
0798 nn_srcptr vec2, slong stride2, slong len, nmod_t mod, dot_params_t params)
0799 {
0800 slong i;
0801 ulong r;
0802 NMOD_VEC_DOT(r, i, len, vec1[i * stride1], vec2[i * stride2], mod, params)
0803 return r;
0804 }
0805
0806 #ifdef __cplusplus
0807 }
0808 #endif
0809
0810 #endif