Macaulay2 Engine
Loading...
Searching...
No Matches
GF.cpp
Go to the documentation of this file.
1// Copyright 1995 Michael E. Stillman
2
3/*
4Note from MES to MES, 27 Jan 2012
5We could have a class which mediates between _originalR and this ring.
6
7
8class GFTranslator
9// needs to be able to find a "good" minimal polynomial for (p,n).
10// needs to be able to tell if a specific polynomial is "good" (i.e. is
11// needs to be able to find a primitive element mod a poly f(x).
12{
13public:
14 GFTranslator(); // What input?
15
16 const PolyRing &ring() const;
17 ring_elem minimalPolynomial();
18 ring_elem primitiveElement();
19
20 ring_elem fromLog(int exp); // allow negative exponents too?
21 int discreteLog(ring_elem a); // return the value r s.t. primitiveRoot^r == a.
22
23 createTables();
24private:
25
26};
27 */
28
29#include "ZZ.hpp"
30#include "GF.hpp"
31#include "text-io.hpp"
32#include "monoid.hpp"
33#include "ringmap.hpp"
34#include "poly.hpp"
35#include "interrupted.hpp"
36
37#include "aring-m2-gf.hpp"
38
40{
41 // set the GF ring tables. Returns false if there is an error.
42 _primitive_element = prim;
44 initialize_ring(_originalR->characteristic(),
46
48
49 int i, j;
50
51 if (_originalR->n_quotients() != 1)
52 {
54 "rawGaloisField expected an element of a quotient ring of the form "
55 "ZZ/p[x]/(f)");
56 }
57 ring_elem f = _originalR->quotient_element(0);
58 Nterm *t = f;
59 int n = _originalR->getMonoid()->primary_degree(t->monom);
60
61 Q_ = static_cast<int>(characteristic());
62 for (i = 1; i < n; i++) Q_ *= static_cast<int>(characteristic());
63
64 Qexp_ = n;
65 Q1_ = Q_ - 1;
66 _ZERO = 0;
67 _ONE = Q1_;
68 _MINUS_ONE = (characteristic() == 2 ? _ONE : Q1_ / 2);
69
70 // Get ready to create the 'one_table'
71 VECTOR(ring_elem) polys;
72 polys.push_back(_originalR->from_long(0));
73 ring_elem primelem = prim->get_value();
74 polys.push_back(_originalR->copy(primelem));
75
76 ring_elem oneR = _originalR->one();
77
78 _x_exponent = -1;
79 ring_elem x = _originalR->var(0);
80 if (_originalR->is_equal(primelem, x)) _x_exponent = 1;
81 for (i = 2; i < Q_; i++)
82 {
83 ring_elem g = _originalR->mult(polys[i - 1], primelem);
84 polys.push_back(g);
85 if (_originalR->is_equal(g, oneR)) break;
86 if (_originalR->is_equal(g, x)) _x_exponent = i;
87 }
88
89 if (polys.size() != Q_)
90 {
91 throw exc::engine_error("GF: primitive element expected");
92 }
93
94 assert(_x_exponent >= 0);
95
96 // Set 'one_table'.
98 _one_table[0] = Q_ - 1;
99 for (i = 1; i <= Q_ - 1; i++)
100 {
101 if (system_interrupted()) return false;
102 ring_elem f1 = _originalR->add(polys[i], oneR);
103 for (j = 1; j <= Q_ - 1; j++)
104 if (_originalR->is_equal(f1, polys[j])) break;
105 _one_table[i] = j;
106 }
107
108 // Create the Z/P ---> GF(Q) inclusion map
110 int a = _ONE;
112 for (i = 1; i < characteristic(); i++)
113 {
114 _from_int_table[i] = a;
115 a = _one_table[a];
116 }
117
118 zeroV = from_long(0);
119 oneV = from_long(1);
120 minus_oneV = from_long(-1);
121
122 return true;
123}
124
128{
129 GF *result = new GF;
130 if (!result->initialize_GF(prim)) return nullptr;
131
132 return result;
133}
134
135void GF::text_out(buffer &o) const { o << "GF(" << Q_ << ")"; }
137{
138 const Ring *R = _originalR->getAmbientRing();
139 ring_elem f = R->copy(_originalR->quotient_element(0));
140 return RingElement::make_raw(R, f);
141}
142
144{
145 ring_elem a = ring_elem(1); // this is the primitive generator
146 return RingElement::make_raw(this, a);
147}
148
150{
153 _originalR->power(_primitive_element->get_value(), a.get_int()));
154}
155
157// takes an element of this ring, and returns an element of _originalR->XXX()
158{
159 return _originalR->power(_primitive_element->get_value(), a.get_int());
160}
161
163{
164 if (a.get_int() == _ZERO) return -1;
165 if (a.get_int() == Q1_) return 0;
166 return a.get_int();
167}
168
169static inline int modulus_add(int a, int b, int p)
170{
171 int t = a + b;
172 return (t <= p ? t : t - p);
173}
174
175static inline int modulus_sub(int a, int b, int p)
176{
177 int t = a - b;
178 return (t <= 0 ? t + p : t);
179}
180
182{
183 int exp = rawRandomInt((int32_t)Q_);
184 return ring_elem(exp);
185}
186
188 const ring_elem a,
189 bool p_one,
190 bool p_plus,
191 bool p_parens) const
192{
193 if (a.get_int() == _ZERO)
194 {
195 o << "0";
196 return;
197 }
198 ring_elem h = _originalR->power(_primitive_element->get_value(), a.get_int());
199 _originalR->elem_text_out(o, h, p_one, p_plus, p_parens);
200 _originalR->remove(h);
201}
202
203ring_elem GF::eval(const RingMap *map, const ring_elem f, int first_var) const
204{
205 return map->get_ring()->power(map->elem(first_var), f.get_int());
206}
207
209{
210 long m1 = n % characteristic();
211 if (m1 < 0) m1 += characteristic();
212 int m = static_cast<int>(m1);
213 m = _from_int_table[m];
214 return ring_elem(m);
215}
216
217ring_elem GF::from_int(mpz_srcptr n) const
218{
219 mpz_t result;
220 mpz_init(result);
221 mpz_mod_ui(result, n, characteristic());
222 long m1 = mpz_get_si(result);
223 mpz_clear(result);
224 if (m1 < 0) m1 += characteristic();
225 int m = static_cast<int>(m1);
226 m = _from_int_table[m];
227 return ring_elem(m);
228}
229
230bool GF::from_rational(mpq_srcptr q, ring_elem &result) const
231{
232 // a will be an element of ZZ/p
233 ring_elem a;
234 bool ok1 = _originalR->getCoefficients()->from_rational(q, a);
235 if (not ok1) return false;
236 std::pair<bool, long> b =
237 _originalR->getCoefficients()->coerceToLongInteger(a);
238 if (b.first)
239 {
240 result = GF::from_long(b.second);
241 return true;
242 }
243 return false;
244}
245
246ring_elem GF::var(int v) const
247{
248 if (v == 0) return _x_exponent;
249 return _ZERO;
250}
251bool GF::promote(const Ring *Rf, const ring_elem f, ring_elem &result) const
252{
253 // Rf = Z/p[x]/F(x) ---> GF(p,n)
254 // promotion: need to be able to know the value of 'x'.
255 // lift: need to compute (primite_element)^e
256
257 if (Rf != _originalR) return false;
258
259 const Ring *K = _originalR->getCoefficients();
260
261 result = from_long(0);
262 int exp[1];
263 for (Nterm& t : f)
264 {
265 std::pair<bool, long> b = K->coerceToLongInteger(t.coeff);
266 assert(b.first);
267 ring_elem coef = from_long(b.second);
268 _originalR->getMonoid()->to_expvector(t.monom, exp);
269 // exp[0] is the variable we want. Notice that since the ring is a
270 // quotient,
271 // this degree is < n (where Q_ = P^n).
272 ring_elem g = power(_x_exponent, exp[0]);
273 g = mult(g, coef);
274 result = ring_elem(internal_add(result.get_int(), g.get_int()));
275 }
276 return true;
277}
278
279bool GF::lift(const Ring *Rg, const ring_elem f, ring_elem &result) const
280{
281 // Rg = Z/p[x]/F(x) ---> GF(p,n)
282 // promotion: need to be able to know the value of 'x'.
283 // lift: need to compute (primite_element)^e
284
285 if (Rg != _originalR) return false;
286
287 int e = f.get_int();
288 if (e == _ZERO)
289 result = _originalR->from_long(0);
290 else if (e == _ONE)
291 result = _originalR->from_long(1);
292 else
293 result = _originalR->power(_primitive_element->get_value(), e);
294
295 return true;
296}
297
298bool GF::is_unit(const ring_elem f) const { return (f.get_int() != _ZERO); }
299bool GF::is_zero(const ring_elem f) const { return (f.get_int() == _ZERO); }
300bool GF::is_equal(const ring_elem f, const ring_elem g) const
301{
302 return f.get_int() == g.get_int();
303}
304
305int GF::compare_elems(const ring_elem f, const ring_elem g) const
306{
307 int cmp = f.get_int() - g.get_int();
308 if (cmp < 0) return -1;
309 if (cmp == 0) return 0;
310 return 1;
311}
312
313ring_elem GF::copy(const ring_elem f) const { return f; }
314
316{
317 // nothing needed to remove.
318}
319
320int GF::internal_negate(int f) const
321{
322 if (f == _ZERO) return _ZERO;
323 return f = modulus_add(f, _MINUS_ONE, Q1_);
324}
325
326int GF::internal_add(int a, int b) const
327{
328 if (b == _ZERO) return a;
329 if (a == _ZERO) return b;
330
331 int n = a - b;
332 if (n > 0)
333 {
334 if (n == _MINUS_ONE) return _ZERO;
335 return modulus_add(b, _one_table[n], Q1_);
336 }
337 else if (n < 0)
338 {
339 if (-n == _MINUS_ONE) return _ZERO;
340 return modulus_add(a, _one_table[-n], Q1_);
341 }
342 else
343 {
344 if (characteristic() == 2) return _ZERO;
345 return modulus_add(a, _one_table[_ONE], Q1_);
346 }
347}
348
349int GF::internal_subtract(int f, int g) const
350{
351 if (g == _ZERO) return f;
352 if (f == g) return _ZERO;
353 int g1 = modulus_add(g, _MINUS_ONE, Q1_); // f = -g
354 return internal_add(f, g1);
355}
356
358{
359 return ring_elem(internal_negate(f.get_int()));
360}
361
362ring_elem GF::add(const ring_elem f, const ring_elem g) const
363{
364 return ring_elem(internal_add(f.get_int(), g.get_int()));
365}
366
368{
369 return ring_elem(internal_subtract(f.get_int(), g.get_int()));
370}
371
372ring_elem GF::mult(const ring_elem f, const ring_elem g) const
373{
374 if (f.get_int() == _ZERO || g.get_int() == _ZERO) return ring_elem(_ZERO);
375 return ring_elem(modulus_add(f.get_int(), g.get_int(), Q1_));
376}
377
378ring_elem GF::power(const ring_elem f, int n) const
379{
380 if (f.get_int() != _ZERO)
381 {
382 int m = (f.get_int() * n) % Q1_;
383 if (m <= 0) m += Q1_;
384 return ring_elem(m);
385 }
386 else
387 {
388 // f == 0 element.
389 if (n == 0)
390 return ring_elem(_ONE);
391 else if (n > 0)
392 return ring_elem(_ZERO);
393 else
395 }
396}
397ring_elem GF::power(const ring_elem f, mpz_srcptr n) const
398{
399 if (f.get_int() != _ZERO)
400 {
401 int exp = RingZZ::mod_ui(n, Q1_);
402 int m = (f.get_int() * exp) % Q1_; // WARNING TODO: possible overflow! Check!
403 if (m <= 0) m += Q1_;
404 return ring_elem(m);
405 }
406 else
407 {
408 if (mpz_sgn(n) == 0)
409 return ring_elem(_ONE);
410 else if (mpz_sgn(n) > 0)
411 return ring_elem(_ZERO);
412 else
414 }
415}
416
418{
419 if (f.get_int() == _ZERO)
421 if (f.get_int() == _ONE) return ring_elem(_ONE);
422 return ring_elem(Q1_ - f.get_int());
423}
424
426{
427 if (g.get_int() == _ZERO)
429 if (f.get_int() == _ZERO) return ring_elem(_ZERO);
430 return modulus_sub(f.get_int(), g.get_int(), Q1_);
431}
432
434 const ring_elem b,
435 ring_elem &x,
436 ring_elem &y) const
437{
438 x = GF::from_long(1);
439 y = GF::divide(a, b);
441}
442
443// Local Variables:
444// compile-command: "make -C $M2BUILDDIR/Macaulay2/e "
445// indent-tabs-mode: nil
446// End:
static int modulus_add(int a, int b, int p)
Definition GF.cpp:169
static int modulus_sub(int a, int b, int p)
Definition GF.cpp:175
Legacy Ring-based Galois field with explicit Zech-style lookup tables.
Legacy RingZZ — a Ring-derived integer ring backed by GMP mpz_t.
M2::ARingGFM2 — native engine Galois field, no FLINT dependency.
ring_elem get_rep(ring_elem f) const
Definition GF.cpp:156
virtual ring_elem invert(const ring_elem f) const
Definition GF.cpp:417
virtual bool from_rational(mpq_srcptr q, ring_elem &result) const
Definition GF.cpp:230
virtual ~GF()
Definition GF.cpp:126
virtual bool is_equal(const ring_elem f, const ring_elem g) const
Definition GF.cpp:300
int internal_add(int f, int g) const
Definition GF.cpp:326
virtual ring_elem eval(const RingMap *map, const ring_elem f, int first_var) const
Definition GF.cpp:203
int _x_exponent
Definition GF.hpp:67
virtual void syzygy(const ring_elem a, const ring_elem b, ring_elem &x, ring_elem &y) const
Definition GF.cpp:433
int * _one_table
Definition GF.hpp:76
virtual void text_out(buffer &o) const
Definition GF.cpp:135
virtual ring_elem subtract(const ring_elem f, const ring_elem g) const
Definition GF.cpp:367
const RingElement * _primitive_element
Definition GF.hpp:66
bool initialize_GF(const RingElement *prim)
Definition GF.cpp:39
virtual int compare_elems(const ring_elem f, const ring_elem g) const
Definition GF.cpp:305
virtual void elem_text_out(buffer &o, const ring_elem f, bool p_one=true, bool p_plus=false, bool p_parens=false) const
Definition GF.cpp:187
int internal_subtract(int f, int g) const
Definition GF.cpp:349
virtual const RingElement * getGenerator() const
Definition GF.cpp:143
int internal_negate(int f) const
Definition GF.cpp:320
int _MINUS_ONE
Definition GF.hpp:74
int * _from_int_table
Definition GF.hpp:77
virtual ring_elem copy(const ring_elem f) const
Definition GF.cpp:313
virtual bool promote(const Ring *R, const ring_elem f, ring_elem &result) const
Definition GF.cpp:251
int Q_
Definition GF.hpp:69
virtual ring_elem from_int(mpz_srcptr n) const
Definition GF.cpp:217
int Qexp_
Definition GF.hpp:70
virtual void remove(ring_elem &f) const
Definition GF.cpp:315
virtual ring_elem var(int v) const
Definition GF.cpp:246
virtual bool is_zero(const ring_elem f) const
Definition GF.cpp:299
virtual bool lift(const Ring *R, const ring_elem f, ring_elem &result) const
Definition GF.cpp:279
virtual ring_elem random() const
Definition GF.cpp:181
int Q1_
Definition GF.hpp:71
virtual ring_elem add(const ring_elem f, const ring_elem g) const
Definition GF.cpp:362
const PolynomialRing * _originalR
Definition GF.hpp:64
virtual ring_elem from_long(long n) const
Definition GF.cpp:208
virtual ring_elem power(const ring_elem f, mpz_srcptr n) const
Exponentiation. This is the default function, if a class doesn't define this.
Definition GF.cpp:397
static GF * create(const RingElement *prim)
Definition GF.cpp:127
GF()
Definition GF.cpp:125
virtual const RingElement * getRepresentation(const ring_elem &a) const
Definition GF.cpp:149
int discrete_log(ring_elem a) const
Definition GF.cpp:162
virtual ring_elem negate(const ring_elem f) const
Definition GF.cpp:357
int _ONE
Definition GF.hpp:73
virtual ring_elem mult(const ring_elem f, const ring_elem g) const
Definition GF.cpp:372
virtual bool is_unit(const ring_elem f) const
Definition GF.cpp:298
int _ZERO
Definition GF.hpp:72
virtual ring_elem divide(const ring_elem f, const ring_elem g) const
Definition GF.cpp:425
const RingElement * getMinimalPolynomial() const
Definition GF.cpp:136
static const PolyRing * get_trivial_poly_ring()
Definition poly.cpp:35
virtual std::pair< bool, long > coerceToLongInteger(ring_elem a) const
Definition ring.cpp:236
ring_elem minus_oneV
Definition ring.hpp:131
void initialize_ring(long charac, const PolynomialRing *DR=nullptr, const std::vector< int > &heft_vec={})
Definition ring.cpp:30
virtual const PolynomialRing * cast_to_PolynomialRing() const
Definition ring.hpp:243
long characteristic() const
Definition ring.hpp:159
virtual ring_elem copy(const ring_elem f) const =0
ring_elem oneV
Definition ring.hpp:130
bool declare_field()
Definition ring.cpp:69
virtual ring_elem power(const ring_elem f, mpz_srcptr n) const
Exponentiation. This is the default function, if a class doesn't define this.
Definition ring.cpp:109
ring_elem zeroV
Definition ring.hpp:129
Ring()
Definition ring.hpp:136
ring_elem get_value() const
Definition relem.hpp:79
static RingElement * make_raw(const Ring *R, ring_elem f)
Definition relem.cpp:20
const Ring * get_ring() const
Definition relem.hpp:81
Front-end-visible "ring element" value: an engine ring_elem paired with the Ring* that gives it meani...
Definition relem.hpp:67
const ring_elem elem(int i) const
Definition ringmap.hpp:114
const Ring * get_ring() const
Definition ringmap.hpp:111
Engine-side ring homomorphism: stores, for each source-ring variable, the target-ring element it maps...
Definition ringmap.hpp:60
static unsigned int mod_ui(mpz_srcptr n, unsigned int p)
Definition ZZ.cpp:55
int p
bool system_interrupted()
system_interrupted() — thread-safe polling predicate for Ctrl+C handling.
VALGRIND_MAKE_MEM_DEFINED & result(result)
Monoid — variable count, naming, grading, and monomial order of a polynomial ring.
#define VECTOR(T)
Definition newdelete.hpp:78
#define newarray_atomic(T, len)
Definition newdelete.hpp:91
volatile int x
Concrete commutative PolyRing — standard polynomial ring inheriting from PolyRingFlat.
int32_t rawRandomInt(int32_t max)
Definition random.cpp:44
RingMap — engine representation of a ring homomorphism.
int monom[1]
Definition ringelem.hpp:160
Singly linked-list node carrying one term of a polynomial-ring element.
Definition ringelem.hpp:156
Text-formatting helpers layered on buffer: bignum print, line wrapping, M2_gbTrace-gated emit.
int get_int() const
Definition ringelem.hpp:124