forked from gap-system/gap
-
Notifications
You must be signed in to change notification settings - Fork 0
/
finfield.h
430 lines (380 loc) · 14.6 KB
/
finfield.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
/****************************************************************************
**
** This file is part of GAP, a system for computational discrete algebra.
**
** Copyright of GAP belongs to its developers, whose names are too numerous
** to list here. Please refer to the COPYRIGHT file for details.
**
** SPDX-License-Identifier: GPL-2.0-or-later
**
** This file declares the functions to compute with elements from small
** finite fields.
**
** Finite fields are an important domain in computational group theory
** because the classical matrix groups are defined over those finite fields.
** The GAP kernel supports elements of finite fields up to some fixed size
** limit stored in MAXSIZE_GF_INTERNAL. To change this limit for 32 resp.
** 64 bit systems, edit `etc/ffgen.c`. Support for fields larger than this
** is implemented by the GAP library.
**
** Elements in small finite fields are represented as immediate objects.
**
** +----------------+-------------+---+
** | <value> | <field> |010|
** +----------------+-------------+---+
**
** The least significant 3 bits of such an immediate object are always 010,
** flagging the object as an object of a small finite field.
**
** The next group of FIELD_BITS_FFE bits represent the small finite field
** where the element lies. They are simply an index into a global table of
** small finite fields, which is constructed at build time.
**
** The most significant VAL_BITS_FFE bits represent the value of the element.
**
** If the value is 0, then the element is the zero from the finite field.
** Otherwise the integer is the logarithm of this element with respect to a
** fixed generator of the multiplicative group of the finite field plus one.
** In the following descriptions we denote this generator always with $z$, it
** is an element of order $o-1$, where $o$ is the order of the finite field.
** Thus 1 corresponds to $z^{1-1} = z^0 = 1$, i.e., the one from the field.
** Likewise 2 corresponds to $z^{2-1} = z^1 = z$, i.e., the root itself.
**
** This representation makes multiplication very easy, we only have to add
** the values and subtract 1 , because $z^{a-1} * z^{b-1} = z^{(a+b-1)-1}$.
** Addition is reduced to * by the formula $z^a + z^b = z^b * (z^{a-b}+1)$.
** This makes it necessary to know the successor $z^a + 1$ of every value.
**
** The finite field bag contains the successor for every nonzero value,
** i.e., 'SUCC_FF(<ff>)[<a>]' is the successor of the element <a>, i.e, it
** is the logarithm of $z^{a-1} + 1$. This list is usually called the
** Zech-Logarithm table. The zeroth entry in the finite field bag is the
** order of the finite field minus one.
*/
#ifndef GAP_FINFIELD_H
#define GAP_FINFIELD_H
#include "common.h"
#include "ffdata.h"
#include "objects.h"
#ifdef HPCGAP
#include "hpc/aobjects.h"
#endif
/****************************************************************************
**
*T FF . . . . . . . . . . . . . . . . . . . . . type of small finite fields
**
** 'FF' is the type used to represent small finite fields.
**
** Small finite fields are represented by an index into a global table.
**
** Depending on the configuration it may be UInt2 or UInt4. The definition
** is in `ffdata.h` and is calculated by `etc/ffgen.c`
*/
GAP_STATIC_ASSERT(NUM_SHORT_FINITE_FIELDS <= (1<<(8*sizeof(FF))),
"NUM_SHORT_FINITE_FIELDS too large for type FF");
GAP_STATIC_ASSERT(FIELD_BITS_FFE + VAL_BITS_FFE + 3 <= 8*sizeof(Obj),
"not enough bits in type Obj to store internal FFEs");
/****************************************************************************
**
*F CHAR_FF(<ff>) . . . . . . . . . . . characteristic of small finite field
**
** 'CHAR_FF' returns the characteristic of the small finite field <ff>.
**
** Note that 'CHAR_FF' is a macro, so do not call it with arguments that
** have side effects.
*/
#define CHAR_FF(ff) (CharFF[ff])
/****************************************************************************
**
*F DEGR_FF(<ff>) . . . . . . . . . . . . . . . degree of small finite field
**
** 'DEGR_FF' returns the degree of the small finite field <ff>.
**
** Note that 'DEGR_FF' is a macro, so do not call it with arguments that
** have side effects.
*/
#define DEGR_FF(ff) (DegrFF[ff])
/****************************************************************************
**
*F SIZE_FF(<ff>) . . . . . . . . . . . . . . . . size of small finite field
**
** 'SIZE_FF' returns the size of the small finite field <ff>.
**
** Note that 'SIZE_FF' is a macro, so do not call it with arguments that
** have side effects.
*/
#define SIZE_FF(ff) (SizeFF[ff])
/****************************************************************************
**
*F SUCC_FF(<ff>) . . . . . . . . . . . successor table of small finite field
**
** 'SUCC_FF' returns a pointer to the successor table of the small finite
** field <ff>.
**
** Note that 'SUCC_FF' is a macro, so do not call it with arguments that
** side effects.
*/
#ifdef HPCGAP
#define SUCC_FF(ff) ((const FFV*)(1+CONST_ADDR_OBJ( ATOMIC_ELM_PLIST( SuccFF, ff ) )))
#else
#define SUCC_FF(ff) ((const FFV*)(1+CONST_ADDR_OBJ( ELM_PLIST( SuccFF, ff ) )))
#endif
extern Obj SuccFF;
/****************************************************************************
**
*T FFV . . . . . . . . type of the values of elements of small finite fields
**
** 'FFV' is the type used to represent the values of elements of small
** finite fields.
**
** Values of elements of small finite fields are represented by the
** logarithm of the element with respect to the root plus one.
**
** Depending on the configuration, this type may be a UInt2 or UInt4.
** This type is actually defined in `ffdata.h` by `etc/ffgen.c`
*/
GAP_STATIC_ASSERT(MAXSIZE_GF_INTERNAL <= (1<<(8*sizeof(FFV))),
"MAXSIZE_GF_INTERNAL too large for type FFV");
GAP_STATIC_ASSERT(sizeof(UInt) >= 2 * sizeof(FFV),
"Overflow possibility in POW_FFV");
/****************************************************************************
**
*F PROD_FFV(<a>,<b>,<f>) . . . . . . . . . . . product of finite field value
**
** 'PROD_FFV' returns the product of the two finite field values <a> and <b>
** from the finite field pointed to by the pointer <f>.
**
** Note that 'PROD_FFV' may only be used if the operands are represented in
** the same finite field. If you want to multiply two elements where one
** lies in a subfield of the other use 'ProdFFEFFE'.
**
** If one of the values is 0 the product is 0.
** If $a+b <= o$ we have $a * b ~ z^{a-1} * z^{b-1} = z^{(a+b-1)-1} ~ a+b-1$
** otherwise we have $a * b ~ z^{(a+b-2)-(o-1)} = z^{(a+b-o)-1} ~ a+b-o$
*/
EXPORT_INLINE FFV PROD_FFV(FFV a, FFV b, const FFV * f)
{
GAP_ASSERT(a <= f[0]);
GAP_ASSERT(b <= f[0]);
if (a == 0 || b == 0)
return 0;
FFV q1 = f[0];
FFV a1 = a - 1;
FFV b1 = q1 - b;
if (a1 <= b1)
return a1 + b;
else
return a1 - b1;
}
/****************************************************************************
**
*F SUM_FFV(<a>,<b>,<f>) . . . . . . . . . . . . sum of finite field values
**
** 'SUM_FFV' returns the sum of the two finite field values <a> and <b> from
** the finite field pointed to by the pointer <f>.
**
** Note that 'SUM_FFV' may only be used if the operands are represented in
** the same finite field. If you want to add two elements where one lies in
** a subfield of the other use 'SumFFEFFE'.
**
** If either operand is 0, the sum is just the other operand.
** If $a <= b$ we have
** $a + b ~ z^{a-1}+z^{b-1} = z^{a-1} * (z^{(b-1)-(a-1)}+1) ~ a * f[b-a+1]$,
** otherwise we have
** $a + b ~ z^{b-1}+z^{a-1} = z^{b-1} * (z^{(a-1)-(b-1)}+1) ~ b * f[a-b+1]$.
*/
EXPORT_INLINE FFV SUM_FFV(FFV a, FFV b, const FFV * f)
{
GAP_ASSERT(a <= f[0]);
GAP_ASSERT(b <= f[0]);
if (a == 0)
return b;
if (b == 0)
return a;
if (b > a) {
FFV t = a;
a = b;
b = t;
}
return PROD_FFV(b, f[a - b + 1], f);
}
/****************************************************************************
**
*F NEG_FFV(<a>,<f>) . . . . . . . . . . . . negative of finite field value
**
** 'NEG_FFV' returns the negative of the finite field value <a> from the
** finite field pointed to by the pointer <f>.
**
** If the characteristic is 2, every element is its own additive inverse.
** Otherwise note that $z^{o-1} = 1 = -1^2$ so $z^{(o-1)/2} = 1^{1/2} = -1$.
** If $a <= (o-1)/2$ we have
** $-a ~ -1 * z^{a-1} = z^{(o-1)/2} * z^{a-1} = z^{a+(o-1)/2-1} ~ a+(o-1)/2$
** otherwise we have
** $-a ~ -1 * z^{a-1} = z^{a+(o-1)/2-1} = z^{a+(o-1)/2-1-(o-1)} ~ a-(o-1)/2$
*/
EXPORT_INLINE FFV NEG_FFV(FFV a, const FFV * f)
{
GAP_ASSERT(a <= f[0]);
UInt q1 = f[0];
if (a == 0)
return 0;
if (q1 % 2)
return a;
if (a <= q1 / 2)
return a + q1 / 2;
else
return a - q1 / 2;
}
/****************************************************************************
**
*F QUO_FFV(<a>,<b>,<f>) . . . . . . . . . . quotient of finite field values
**
** 'QUO_FFV' returns the quotient of the two finite field values <a> and <b>
** from the finite field pointed to by the pointer <f>.
**
** Note that 'QUO_FFV' may only be used if the operands are represented in
** the same finite field. If you want to divide two elements where one lies
** in a subfield of the other use 'QuoFFEFFE'.
**
** A division by 0 is an error, and dividing 0 by a nonzero value gives 0.
** If $0 <= a-b$ we have $a / b ~ z^{a-1} / z^{b-1} = z^{a-b+1-1} ~ a-b+1$,
** otherwise we have $a / b ~ z^{a-b+1-1} = z^{a-b+(o-1)} ~ a-b+o$.
*/
EXPORT_INLINE FFV QUO_FFV(FFV a, FFV b, const FFV * f)
{
GAP_ASSERT(a <= f[0]);
GAP_ASSERT(b <= f[0]);
if (a == 0)
return 0;
if (b <= a)
return a - b + 1;
else
return a + (f[0] - b) + 1;
}
/****************************************************************************
**
*F POW_FFV(<a>,<n>,<f>) . . . . . . . . . . . power of a finite field value
**
** 'POW_FFV' returns the <n>th power of the finite field value <a> from the
** the finite field pointed to by the pointer <f>.
**
** Note that 'POW_FFV' may only be used if the right operand is an integer
** in the range $0..order(f)-1$.
**
** Finally 'POW_FFV' may only be used if the product of two integers of the
** size of 'FFV' does not cause an overflow.
**
** If the finite field element is 0 the power is also 0, otherwise we have
** $a^n ~ (z^{a-1})^n = z^{(a-1)*n} = z^{(a-1)*n % (o-1)} ~ (a-1)*n % (o-1)$
*/
EXPORT_INLINE FFV POW_FFV(FFV a, UInt n, const FFV * f)
{
GAP_ASSERT(a <= f[0]);
GAP_ASSERT(n <= f[0]);
if (!n)
return 1;
if (!a)
return 0;
// Use UInt to avoid overflow in the multiplication
UInt a1 = a - 1;
return ((a1 * n) % f[0]) + 1;
}
/****************************************************************************
**
*F FLD_FFE(<ffe>) . . . . . . . field of an element of a small finite field
**
** 'FLD_FFE' returns the small finite field over which the element <ffe> is
** represented.
**
*/
EXPORT_INLINE FF FLD_FFE(Obj ffe)
{
GAP_ASSERT(IS_FFE(ffe));
return (FF)((UInt)(ffe) >> 3) & ((1 << FIELD_BITS_FFE) - 1);
}
/****************************************************************************
**
*F VAL_FFE(<ffe>) . . . . . . . value of an element of a small finite field
**
** 'VAL_FFE' returns the value of the element <ffe> of a small finite field.
** Thus, if <ffe> is $0_F$, it returns 0; if <ffe> is $1_F$, it returns 1;
** and otherwise if <ffe> is $z^i$, it returns $i+1$.
**
*/
EXPORT_INLINE FFV VAL_FFE(Obj ffe)
{
GAP_ASSERT(IS_FFE(ffe));
return (FFV)((UInt)(ffe) >> (3 + FIELD_BITS_FFE)) &
((1 << VAL_BITS_FFE) - 1);
}
/****************************************************************************
**
*F NEW_FFE(<fld>,<val>) . . . . make a new element of a small finite field
**
** 'NEW_FFE' returns a new element <ffe> of the small finite field <fld>
** with the value <val>.
**
*/
EXPORT_INLINE Obj NEW_FFE(FF fld, FFV val)
{
GAP_ASSERT(val < SIZE_FF(fld));
return (Obj)(((UInt)val << (3 + FIELD_BITS_FFE)) | ((UInt)fld << 3) |
(UInt)0x02);
}
/****************************************************************************
**
*F FiniteField(<p>,<d>) . make the small finite field with <p>^<d> elements
*F FiniteFieldBySize(<q>) . . make the small finite field with <q> elements
**
** 'FiniteField' returns the small finite field with <p>^<d> elements.
** 'FiniteFieldBySize' returns the small finite field with <q> elements.
*/
FF FiniteField(UInt p, UInt d);
FF FiniteFieldBySize(UInt q);
/****************************************************************************
**
*F CommonFF(<f1>,<d1>,<f2>,<d2>) . . . . . . . . . . . . find a common field
**
** 'CommonFF' returns a small finite field that can represent elements of
** degree <d1> from the small finite field <f1> and elements of degree <d2>
** from the small finite field <f2>. Note that this is not guaranteed to be
** the smallest such field. If <f1> and <f2> have different characteristic
** or the smallest common field, is too large, 'CommonFF' returns 0.
*/
FF CommonFF(FF f1, UInt d1, FF f2, UInt d2);
/****************************************************************************
**
*F CharFFE(<ffe>) . . . . . . . . . characteristic of a small finite field
**
** 'CharFFE' returns the characteristic of the small finite field in which
** the element <ffe> lies.
*/
UInt CharFFE(Obj ffe);
/****************************************************************************
**
*F DegreeFFE(<ffe>) . . . . . . . . . . . . degree of a small finite field
**
** 'DegreeFFE' returns the degree of the smallest finite field in which the
** element <ffe> lies.
*/
UInt DegreeFFE(Obj ffe);
/****************************************************************************
**
*F TypeFFE(<ffe>) . . . . . . . . . . type of element of small finite field
**
** 'TypeFFE' returns the type of the element <ffe> of a small finite field.
**
** 'TypeFFE' is the function in 'TypeObjFuncs' for elements in small finite
** fields.
*/
Obj TypeFFE(Obj ffe);
/****************************************************************************
**
*F * * * * * * * * * * * * * initialize module * * * * * * * * * * * * * * *
*/
/****************************************************************************
**
*F InitInfoFinfield() . . . . . . . . . . . . . . . table of init functions
*/
StructInitInfo * InitInfoFinfield ( void );
#endif // GAP_FINFIELD_H