Macaulay2 Engine
Loading...
Searching...
No Matches
aring-gf-flint.hpp
Go to the documentation of this file.
1// Copyright 2014 Michael E. Stillman
2
3#ifndef _aring_gf_flint_hpp_
4#define _aring_gf_flint_hpp_
5
42
43#include <vector>
44
45// The following needs to be included before any flint files are included.
46#include <M2/gc-include.h>
47
48// includes gmp.h, which is required for FLINT functions that use GMP
49#include <M2/math-include.h>
50
51#pragma GCC diagnostic push
52#pragma GCC diagnostic ignored "-Wconversion"
53#include <flint/flint.h> // for flint_rand_t, fmpz_t, ulong
54#include <flint/fmpz.h> // for fmpz_clear_readonly, fmpz_init_set_...
55#include <flint/fq_nmod.h> // for fq_nmod_clear, fq_nmod_init, fq_nmod_c...
56#include <flint/fq_zech.h> // for fq_zech_clear, fq_zech_ctx_clear, fq_z...
57#include <flint/nmod_poly.h> // for nmod_poly_set_coeff_ui, nmod_poly_clear
58#pragma GCC diagnostic pop
59
60#include "interface/random.h"
61#include "aring.hpp"
62#include "buffer.hpp"
63#include "ringelem.hpp"
64#include "exceptions.hpp" // for exc::division_by_zero_error
65
66class PolynomialRing;
67class RingElement;
68
69namespace M2 {
70
90{
91 public:
93 typedef fq_zech_struct ElementType;
95 typedef std::vector<elem> ElementContainerType;
96
103 class Element : public ElementImpl<ElementType>
104 {
105 public:
106 Element() = delete;
108 {
109 // figure out how to move the value without the context
110 fq_zech_init2(&mValue, mContext);
111 fq_zech_set(&mValue, &other.mValue, mContext);
112 }
113 explicit Element(const ARingGFFlint& R) : mContext(R.mContext)
114 {
115 fq_zech_init2(&mValue, mContext);
116 }
118 {
120 }
121 ~Element() { fq_zech_clear(&mValue, mContext); }
122
123 private:
124 const fq_zech_ctx_struct* mContext;
125 };
126
139 {
140 const fq_zech_ctx_struct* mContext;
141 const size_t mSize;
142 std::unique_ptr<ElementType[]> mData;
143
144 public:
145 ElementArray(const ARingGFFlint& R, size_t size)
146 : mContext(R.mContext), mSize(size), mData(new ElementType[size])
147 {
148 for (size_t i = 0; i < mSize; i++) fq_zech_init2(&mData[i], mContext);
149 }
151 {
152 for (size_t i = 0; i < mSize; i++) fq_zech_clear(&mData[i], mContext);
153 }
154 ElementType& operator[](size_t idx) { return mData[idx]; }
155 const ElementType& operator[](size_t idx) const { return mData[idx]; }
156 ElementType *data() { return mData.get(); }
157 const ElementType *data() const { return mData.get(); }
158 };
159
160 ARingGFFlint(const PolynomialRing& R, const ring_elem a);
161
163
164 const fq_zech_ctx_struct* flintContext() const { return mContext; }
165 long characteristic() const { return mCharacteristic; }
166 long dimension() const { return mDimension; }
167 const PolynomialRing& originalRing() const { return mOriginalRing; }
168 void getGenerator(ElementType& result_gen) const;
169
170 void text_out(buffer& o) const;
171
172 private:
173 fq_zech_ctx_t mContext;
174 fq_nmod_ctx_t mBigContext;
175
176 const PolynomialRing& mOriginalRing; // This is a quotient ring k[a]/f(a).
177 const RingElement* mPrimitiveElement; // element in the original ring
178 ulong*
179 mPPowers; // array 0..mDimension of powers of mCharacteristic (mod 2^64)
182 mutable flint_rand_t mRandomState;
183
185 mutable bool mGeneratorComputed;
186
190
191 public:
192 unsigned int computeHashValue(const elem& a) const
193 {
194 return static_cast<unsigned int>(a.value);
195 }
196
198 {
199 // we only use this data type for GF's smaller than 32 bits, since
200 // this class creates lookup tables that are way too big otherwise.
201 result = ring_elem(static_cast<int>(a.value));
202 }
203
205 {
206 result.value = a.get_int();
207 }
208
210 {
211 return {.value = static_cast<mp_limb_t>(a.get_int())};
212 }
213
214 bool is_unit(const ElementType& f) const { return not is_zero(f); }
215 bool is_zero(const ElementType& f) const
216 {
217 return fq_zech_is_zero(&f, mContext);
218 }
219 bool is_equal(const ElementType& f, const ElementType& g) const
220 {
221 return fq_zech_equal(&f, &g, mContext);
222 }
223
224 int compare_elems(const ElementType& f, const ElementType& g) const;
225
226 void copy(ElementType& result, const ElementType& a) const
227 {
228 fq_zech_set(&result, &a, mContext);
229 }
230 void init(ElementType& result) const { fq_zech_init2(&result, mContext); }
231 void init_set(ElementType& result, const ElementType& a) const
232 {
233 init(result);
234 copy(result, a);
235 }
236 void set(ElementType& result, const ElementType& a) const { copy(result, a); }
237 void set_zero(ElementType& result) const { fq_zech_zero(&result, mContext); }
238 void clear(ElementType& result) const { fq_zech_clear(&result, mContext); }
239 void set_from_long(ElementType& result, long a) const
240 {
241 long a1 = a % characteristic();
242 if (a1 < 0) a1 += characteristic();
243 fq_zech_set_ui(&result, a1, mContext);
244 }
245
246 void set_var(ElementType& result, int v) const
247 {
248 if (v != 0) set_from_long(result, 1);
249 std::vector<long> poly = {0, 1};
251 // printf("variable is %lu\n", result.value);
252 }
253
254 void set_from_mpz(ElementType& result, mpz_srcptr a) const
255 {
256 int b = static_cast<int>(mpz_fdiv_ui(a, characteristic()));
258 }
259
260 bool set_from_mpq(ElementType& result, mpq_srcptr a) const
261 {
262 ElementType n, d;
263 init(n);
264 init(d);
265 set_from_mpz(n, mpq_numref(a));
266 set_from_mpz(d, mpq_denref(a));
267 if (is_zero(d)) return false;
268 divide(result, n, d);
269 return true;
270 }
271
273 {
274 (void) result;
275 (void) a;
276 return false;
277 }
278
279 void negate(ElementType& result, const ElementType& a) const
280 {
281 fq_zech_neg(&result, &a, mContext);
282 }
283
284 void invert(ElementType& result, const ElementType& a) const
285 {
286 if (is_zero(a))
288 else fq_zech_inv(&result, &a, mContext);
289 }
290
292 const ElementType& a,
293 const ElementType& b) const
294 {
295 fq_zech_add(&result, &a, &b, mContext);
296 // printf("zech add %lu + %lu = %lu\n", a.value, b.value, result.value);
297 }
298
300 const ElementType& a,
301 const ElementType& b) const
302 {
303 fq_zech_sub(&result, &a, &b, mContext);
304 }
305
307 const ElementType& a,
308 const ElementType& b) const
309 {
310 ElementType c;
311 init(c);
312 mult(c, a, b);
314 clear(c);
315 }
316
318 const ElementType& a,
319 const ElementType& b) const
320 {
321 fq_zech_mul(&result, &a, &b, mContext);
322 }
323
325 const ElementType& a,
326 const ElementType& b) const
327 {
328 // We need to handle the case when result is a, or b.
329 // This is why we use the temporary value 'c'.
330 ElementType c;
331 init(c);
332#if 0
333 printf("entering divide\n");
334 printf(" a = ");
335 fq_zech_print_pretty(&a, mContext);
336 printf("\n b = ");
337 fq_zech_print_pretty(&b, mContext);
338#endif
339 invert(c, b);
340#if 0
341 printf("\n 1/b = ");
342 fq_zech_print_pretty(&c, mContext);
343#endif
344 mult(result, c, a);
345#if 0
346 printf("\n a/b = ");
347 fq_zech_print_pretty(&result, mContext);
348 printf("\n");
349#endif
350 clear(c);
351 }
352
353 void power(ElementType& result, const ElementType& a, int n) const
354 {
355 if (n < 0)
356 {
357 invert(result, a);
358 fq_zech_pow_ui(&result, &result, -n, mContext);
359 }
360 else
361 fq_zech_pow_ui(&result, &a, n, mContext);
362 }
363
364 void power_mpz(ElementType& result, const ElementType& a, mpz_srcptr n) const
365 {
366 if (mpz_sgn(n) < 0)
367 invert(result, a);
368 else
369 copy(result, a);
370
371 mpz_t abs_n;
372 mpz_init(abs_n);
373 mpz_abs(abs_n, n);
374
375 fmpz_t fn;
376 fmpz_init_set_readonly(fn, abs_n);
377 fq_zech_pow(&result, &result, fn, mContext);
378 fmpz_clear_readonly(fn);
379 mpz_clear(abs_n);
380 }
381
382 void swap(ElementType& a, ElementType& b) const
383 {
384 fq_zech_swap(&a, &b, mContext);
385 }
386
387 void elem_text_out(buffer& o,
388 const ElementType& a,
389 bool p_one = true,
390 bool p_plus = false,
391 bool p_parens = false) const;
392
393 void syzygy(const ElementType& a,
394 const ElementType& b,
395 ElementType& x,
396 ElementType& y) const
397 // returns x,y s.y. x*a + y*b == 0.
398 // if possible, x is set to 1.
399 // no need to consider the case a==0 or b==0.
400 {
401 assert(not is_zero(a));
402 assert(not is_zero(b));
403 set_from_long(x, 1);
404 divide(y, a, b);
405 negate(y, y);
406 }
407
409 {
410 std::vector<long> poly;
411 for (int i = 0; i < dimension(); ++i)
412 poly.push_back(rawRandomULong(characteristic()));
414 // fq_zech_randtest(&result, mRandomState, mContext);
415 }
416
417 void fromSmallIntegerCoefficients(ElementType& result,
418 const std::vector<long>& poly) const;
419
420 void getSmallIntegerCoefficients(const ElementType& a,
421 std::vector<long>& poly) const;
422
423 bool promote(const Ring* Rf, const ring_elem f, ElementType& result) const;
424
425 void lift_to_original_ring(ring_elem& result, const ElementType& f) const;
426 // GF specific routine, used in getRepresentation
427
428 bool lift(const Ring* Rg, const ElementType& f, ring_elem& result) const;
429
430 // map : this --> target(map)
431 // primelem --> map->elem(first_var)
432 // evaluate map(f)
433 void eval(const RingMap* map,
434 const ElementType& f,
435 int first_var,
436 ring_elem& result) const;
437};
438};
439
440#endif
441// Local Variables:
442// compile-command: "make -C $M2BUILDDIR/Macaulay2/e "
443// indent-tabs-mode: nil
444// 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.
const fq_zech_ctx_struct * mContext
Element(const ARingGFFlint &R, const ElementType &value)
Element(const ARingGFFlint &R)
const fq_zech_ctx_struct * mContext
const ElementType & operator[](size_t idx) const
ElementType & operator[](size_t idx)
ElementArray(const ARingGFFlint &R, size_t size)
const ElementType * data() const
std::unique_ptr< ElementType[]> mData
const fq_zech_ctx_struct * flintContext() const
void getGenerator(ElementType &result_gen) const
void getSmallIntegerCoefficients(const ElementType &a, std::vector< long > &poly) const
void text_out(buffer &o) const
void init_set(ElementType &result, const ElementType &a) const
void divide(ElementType &result, const ElementType &a, const ElementType &b) const
fq_zech_struct ElementType
void negate(ElementType &result, const ElementType &a) const
void init(ElementType &result) const
void to_ring_elem(ring_elem &result, const ElementType &a) const
void mult(ElementType &result, const ElementType &a, const ElementType &b) const
unsigned int computeHashValue(const elem &a) const
Arithmetic functions ///////.
void copy(ElementType &result, const ElementType &a) const
void clear(ElementType &result) const
std::vector< elem > ElementContainerType
ElementType from_ring_elem_const(const ring_elem &a) const
bool promote(const Ring *Rf, const ring_elem f, ElementType &result) const
ARingGFFlint(const PolynomialRing &R, const ring_elem a)
void elem_text_out(buffer &o, const ElementType &a, bool p_one=true, bool p_plus=false, bool p_parens=false) const
void add(ElementType &result, const ElementType &a, const ElementType &b) const
void subtract_multiple(ElementType &result, const ElementType &a, const ElementType &b) const
void eval(const RingMap *map, const ElementType &f, int first_var, ring_elem &result) const
long dimension() const
fq_nmod_ctx_t mBigContext
void set_var(ElementType &result, int v) const
void set_zero(ElementType &result) const
void syzygy(const ElementType &a, const ElementType &b, ElementType &x, ElementType &y) const
bool set_from_BigReal(ElementType &result, gmp_RR a) const
flint_rand_t mRandomState
static const RingID ringID
bool is_zero(const ElementType &f) const
void set(ElementType &result, const ElementType &a) const
bool is_unit(const ElementType &f) const
void from_ring_elem(ElementType &result, const ring_elem &a) const
const RingElement * mPrimitiveElement
void power_mpz(ElementType &result, const ElementType &a, mpz_srcptr n) const
void power(ElementType &result, const ElementType &a, int n) const
void set_from_mpz(ElementType &result, mpz_srcptr a) const
fq_zech_ctx_t mContext
const PolynomialRing & originalRing() const
void set_from_long(ElementType &result, long a) const
int compare_elems(const ElementType &f, const ElementType &g) const
void swap(ElementType &a, ElementType &b) const
void lift_to_original_ring(ring_elem &result, const ElementType &f) const
long characteristic() const
ElementType mCachedGenerator
void fromSmallIntegerCoefficients(ElementType &result, const std::vector< long > &poly) const
void subtract(ElementType &result, const ElementType &a, const ElementType &b) const
const PolynomialRing & mOriginalRing
bool is_equal(const ElementType &f, const ElementType &g) const
bool lift(const Ring *Rg, const ElementType &f, ring_elem &result) const
void invert(ElementType &result, const ElementType &a) const
bool set_from_mpq(ElementType &result, mpq_srcptr a) const
void random(ElementType &result) const
const ElementType & value() const
Definition aring.hpp:132
ElementImpl()=default
ElementType mValue
Definition aring.hpp:119
Abstract base for the engine's polynomial-ring hierarchy.
Definition polyring.hpp:96
Front-end-visible "ring element" value: an engine ring_elem paired with the Ring* that gives it meani...
Definition relem.hpp:67
xxx xxx xxx
Definition ring.hpp:102
Engine-side ring homomorphism: stores, for each source-ring variable, the target-ring element it maps...
Definition ringmap.hpp:60
unsigned long int ulong
Definition comb.cpp:7
namespace exc — internal C++ exception types and the TRY / CATCH macro pair.
RingID
Definition aring.hpp:75
@ ring_GFFlintZech
Definition aring.hpp:86
OrigFn fn
Definition m2-mem.cpp:273
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.
int get_int() const
Definition ringelem.hpp:124