Macaulay2 Engine
Loading...
Searching...
No Matches
aring-zzp-flint.hpp
Go to the documentation of this file.
1// Copyright 2013 Michael E. Stillman
2
3#ifndef _aring_zzp_flint_hpp_
4#define _aring_zzp_flint_hpp_
5
42
43#include "interface/random.h"
44#include "aring.hpp"
45#include "buffer.hpp"
46#include "ringelem.hpp"
47#include "exceptions.hpp" // for division_by_zero_error
48
49class RingMap;
50
51// The following needs to be included before any flint files are included.
52#include <M2/gc-include.h>
53
54#pragma GCC diagnostic push
55#pragma GCC diagnostic ignored "-Wconversion"
56#include <flint/flint.h> // for fmpz_t, nmod_t, flint_rand_t
57#include <flint/fmpz.h> // for fmpz_clear, fmpz_fdiv_ui, fmpz_init
58#ifdef HAVE_FLINT_NMOD_H
59 #include <flint/nmod.h> // for nmod_neg, nmod_add, nmod_div, nmod_mul
60#endif
61#pragma GCC diagnostic pop
62
63namespace M2 {
79class ARingZZpFlint : public SimpleARing<ARingZZpFlint>
80{
81 // Integers mod p, implemented as
82 // residues in 0..p-1, where
83 // p is a word length in size.
84 // the largest p is the largest prime < 2^64
85
86 public:
87 static const RingID ringID = ring_ZZpFlint;
88 typedef mp_limb_t ElementType; // most of the time an unsigned long.
90 typedef std::vector<elem> ElementContainerType;
91
92 ARingZZpFlint(size_t prime);
93
95
96 nmod_t flintModulus() const { return mModulus; }
97 // ring informational
98 size_t characteristic() const { return mCharac; }
99 size_t cardinality() const { return mCharac; }
100 unsigned int computeHashValue(const elem &a) const
101 {
102 return static_cast<unsigned int>(a);
103 }
104
105 long coerceToLongInteger(const elem &f) const
106 {
107 long result = f;
108 if (result > characteristic() / 2) result -= characteristic();
109 return result;
110 }
111
112 void getGenerator(elem &gen) const { gen = mGenerator; }
113 long discreteLog(const elem &a) const; // returns -1 if a is 0
114
115 void text_out(buffer &o) const;
116
118 // ElementType informational ////
120
121 bool is_unit(ElementType f) const { return f != 0; }
122 bool is_zero(ElementType f) const { return f == 0; }
123 bool is_equal(ElementType f, ElementType g) const { return f == g; }
125 {
126 if (f > g) return -1;
127 if (f < g) return 1;
128 return 0;
129 }
130
131 // 'init', 'init_set' functions
132
133 void init(ElementType &result) const { result = 0; }
135 static void clear(ElementType &result) { (void) result; }
136
137 void set(ElementType &result, ElementType a) const { result = a; }
138 void set_zero(ElementType &result) const { result = 0; }
139 void set_from_long(ElementType &result, long a) const
140 {
141 // printf("called deprecated and inefficient
142 // ARingZZpFlint::set_from_long\n");
143 fmpz_t b;
144 fmpz_init(b);
145 fmpz_set_si(b, a);
146 result = fmpz_fdiv_ui(b, mCharac);
147 fmpz_clear(b);
148 }
149
150 void set_var(ElementType &result, int v) const
151 {
152 (void) v;
153 result = 1;
154 }
155
156 void set_from_mpz(ElementType &result, mpz_srcptr a) const
157 {
158 result = mpz_fdiv_ui(a, mCharac);
159 }
160
161 bool set_from_mpq(ElementType &result, mpq_srcptr a) const
162 {
163 ElementType n, d;
164 set_from_mpz(n, mpq_numref(a));
165 set_from_mpz(d, mpq_denref(a));
166 if (is_zero(d)) return false;
167 divide(result, n, d);
168 return true;
169 }
170
172 {
173 (void) result;
174 (void) a;
175 return false;
176 }
177
178 // arithmetic
180 {
181 result = nmod_neg(a, mModulus);
182 }
183
185 {
186 if (is_zero(a)) throw exc::division_by_zero_error();
187
188 result = n_invmod(a, mCharac);
189 }
190
192 {
193 result = nmod_add(a, b, mModulus);
194 }
195
197 {
198 result = nmod_sub(a, b, mModulus);
199 }
200
202 ElementType a,
203 ElementType b) const
204 {
205 ElementType a1 = nmod_neg(a, mModulus);
206
207 // the code below was an attempt to prevent flint from calling the
208 // version of the general multiply code if the product of the two flint
209 // integers always fits in a single limb. Speedup was not significant in testing.
210
211 //if (mModulus.norm >= FLINT_BITS/2) /* addmul will fit in a limb */
212 //{
213 // mp_limb_t ab_hi, ab_lo;
214 // umul_ppmm(ab_hi, ab_lo, a1, b); // a_hi is not needed in this case
215 // ab_lo = nmod_add(result, ab_lo, mModulus);
216 // NMOD_RED(result,ab_lo,mModulus);
217 //}
218 //else // product does not fit in a single limb
219
220 NMOD_ADDMUL(result, a1, b, mModulus);
221 }
222
224 {
225 result = nmod_mul(a, b, mModulus);
226 }
227
229 {
230 if (b == 0)
232 result = nmod_div(a, b, mModulus);
233 }
234
235 void power(ElementType &result, ElementType a, long n) const
236 {
237 if (a != 0)
238 {
239 result = n_powmod2_preinv(a, n, mModulus.n, mModulus.ninv);
240 }
241 else
242 {
243 // case a == 0
244 if (n < 0) throw exc::division_by_zero_error();
245 if (n == 0) return set_from_long(result, 1);
246 if (n > 0) return set_zero(result);
247 }
248 }
249
250 void power_mpz(ElementType &result, ElementType a, mpz_srcptr n) const
251 {
252 if (a != 0)
253 {
254 unsigned long nbar = mpz_fdiv_ui(n, mCharac - 1);
255 result = n_powmod2_ui_preinv(a, nbar, mModulus.n, mModulus.ninv);
256 }
257 else
258 {
259 // case a == 0
260 if (mpz_sgn(n) == 0)
262 else if (mpz_sgn(n) > 0)
264 else
266 }
267 }
268
269 void swap(ElementType &a, ElementType &b) const
270 {
271 ElementType tmp = a;
272 a = b;
273 b = tmp;
274 }
275
276 void elem_text_out(buffer &o,
277 ElementType a,
278 bool p_one = true,
279 bool p_plus = false,
280 bool p_parens = false) const;
281
283 ElementType b,
284 ElementType &x,
285 ElementType &y) const
286 // returns x,y s.y. x*a + y*b == 0.
287 // if possible, x is set to 1.
288 // no need to consider the case a==0 or b==0.
289 {
290 assert(a != 0);
291 assert(b != 0);
292 x = 1;
293 divide(y, a, b);
294 negate(y, y);
295 }
296
298#if 0
299 {
300 fmpz a;
301 fmpz_init(&a);
302 fmpz_randm(&a, mRandomState, mFmpzCharac);
303 result = fmpz_get_ui(&a);
304 fmpz_clear(&a);
305 }
306#endif
307 void eval(const RingMap *map,
308 const ElementType f,
309 int first_var,
310 ring_elem &result) const;
311
313 // to/from ringelem ////////
315
317 {
318 assert(sizeof(mp_limb_t) <= sizeof(long));
319 result = ring_elem(static_cast<long>(a));
320 }
321
323 {
324 result = static_cast<mp_limb_t>(a.get_long());
325 }
326
328 {
329 return static_cast<mp_limb_t>(a.get_long());
330 }
331
332 private:
333 nmod_t mModulus;
334 size_t mCharac; // not needed, as it is in mModulus
335 mutable flint_rand_t mRandomState;
337 mp_limb_t mGenerator; // do we need to compute this eagerly?
338};
339};
340
341#endif
342
343// Local Variables:
344// compile-command: "make -C $M2BUILDDIR/Macaulay2/e "
345// indent-tabs-mode: nil
346// End:
Shared base of the aring framework (namespace M2) that unifies the engine's coefficient rings.
Append-only GC-backed byte buffer used throughout the engine for text output.
long coerceToLongInteger(const elem &f) const
void set(ElementType &result, ElementType a) const
void power_mpz(ElementType &result, ElementType a, mpz_srcptr n) const
void elem_text_out(buffer &o, ElementType a, bool p_one=true, bool p_plus=false, bool p_parens=false) const
void init_set(ElementType &result, ElementType a) const
void to_ring_elem(ring_elem &result, const ElementType &a) const
static const RingID ringID
bool is_unit(ElementType f) const
static void clear(ElementType &result)
void mult(ElementType &result, ElementType a, ElementType b) const
void set_from_mpz(ElementType &result, mpz_srcptr a) const
void set_zero(ElementType &result) const
std::vector< elem > ElementContainerType
void swap(ElementType &a, ElementType &b) const
void add(ElementType &result, ElementType a, ElementType b) const
ElementType from_ring_elem_const(const ring_elem &a) const
void invert(ElementType &result, ElementType a) const
int compare_elems(ElementType f, ElementType g) const
void set_from_long(ElementType &result, long a) const
void negate(ElementType &result, ElementType a) const
void divide(ElementType &result, ElementType a, ElementType b) const
void power(ElementType &result, ElementType a, long n) const
bool set_from_mpq(ElementType &result, mpq_srcptr a) const
unsigned int computeHashValue(const elem &a) const
void subtract_multiple(ElementType &result, ElementType a, ElementType b) const
flint_rand_t mRandomState
void getGenerator(elem &gen) const
void eval(const RingMap *map, const ElementType f, int first_var, ring_elem &result) const
bool is_zero(ElementType f) const
void from_ring_elem(ElementType &result, const ring_elem &a) const
void init(ElementType &result) const
ARingZZpFlint(size_t prime)
size_t characteristic() const
size_t cardinality() const
long discreteLog(const elem &a) const
bool is_equal(ElementType f, ElementType g) const
void syzygy(ElementType a, ElementType b, ElementType &x, ElementType &y) const
void random(ElementType &result) const
bool set_from_BigReal(ElementType &result, gmp_RR a) const
void text_out(buffer &o) const
void set_var(ElementType &result, int v) const
nmod_t flintModulus() const
void subtract(ElementType &result, ElementType a, ElementType b) const
A base class for simple ARings.
Definition aring.hpp:147
Engine-side ring homomorphism: stores, for each source-ring variable, the target-ring element it maps...
Definition ringmap.hpp:60
namespace exc — internal C++ exception types and the TRY / CATCH macro pair.
RingID
Definition aring.hpp:75
@ ring_ZZpFlint
Definition aring.hpp:83
VALGRIND_MAKE_MEM_DEFINED & result(result)
mpfr_srcptr gmp_RR
Definition m2-types.h:148
Definition aring-CC.cpp:3
volatile int x
unsigned long rawRandomULong(unsigned long max)
Definition random.cpp:39
Engine-boundary C API for the engine's PRNG and rational / real / complex random draws.
ring_elem — the universal value type carried by every Ring* in the engine.
long get_long() const
Definition ringelem.hpp:125