diff --git a/src/finfield.c b/src/finfield.c index 2de6d3e67f..ecc38daad2 100644 --- a/src/finfield.c +++ b/src/finfield.c @@ -8,46 +8,7 @@ *Y (C) 1998 School Math and Comp. Sci., University of St Andrews, Scotland *Y Copyright (C) 2002 The GAP Group ** -** This file contains 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. -** In GAP we support small finite fields with up to 65536 elements, -** larger fields can be realized as polynomial domains over smaller fields. -** -** Elements in small finite fields are represented as immediate objects. -** -** +----------------+-------------+---+ -** | | |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 13 bits represent the small finite field where the element lies. -** They are simply an index into a global table of small finite fields. -** -** The most significant 16 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 desriptions 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 neccessary 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()[]' is the successor of the element , 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. +** The concepts of this kernel module are documented in finfield.h */ #include "finfield.h" @@ -67,14 +28,38 @@ #include "hpc/aobjects.h" #endif -Obj SuccFF; +/**************************************************************************** +** +*V SuccFF . . . . . Tables for finite fields which are computed on demand +*V TypeFF +*V TypeFF0 +** +** SuccFF holds a PLIST of successor lists +** TypeFF holds the types of typical elements of the finite fields +** TypeFF0 holds the types of the zero elements of the finite fields +*/ +Obj SuccFF; Obj TypeFF; Obj TypeFF0; + +/**************************************************************************** +** +*V TYPE_FFE . . . . . kernel copy of GAP function TYPE_FFE +*V TYPE_FFE0 . . . . . kernel copy of GAP function TYPE_FFE0 +*V TYPE_KERNEL_OBJECT .local copy of GAP variable TYPE_KERNEL_OBJECT used to type +** successor bags +*V PrimitiveRootMod . .local copy of GAP function PrimitiveRootMod, used +** when initializing new fields. +** +** These GAP functions are called to compute types of finite field elemnents +*/ + static Obj TYPE_FFE; static Obj TYPE_FFE0; - +static Obj TYPE_KERNEL_OBJECT; +static Obj PrimitiveRootMod; /**************************************************************************** ** @@ -90,13 +75,6 @@ static Obj TYPE_FFE0; #include "finfield_conway.h" - -// used for successor bags -static Obj TYPE_KERNEL_OBJECT; - -// used to call out to GAP -static Obj PrimitiveRootMod; - /**************************************************************************** ** *F lookupPrimePower ( q ) . . . . . .search for a prime power in tables @@ -137,9 +115,11 @@ static FF lookupPrimePower(UInt q) /**************************************************************************** ** -*F FiniteField(

,) . . . make the small finite field with elements +*F FiniteFieldBySize( ) . .make the small finite field with elements +*F FiniteField(

,) . . .make the small finite field with

^ elements ** -** 'FiniteField' returns the small finite field with

^ elements. +** The work is done in the lookup function above, and in FiniteFieldBySize +** where the successor tables are computed. */ FF FiniteFieldBySize ( UInt q) diff --git a/src/finfield.h b/src/finfield.h index ea733b9ab4..c6950fcead 100644 --- a/src/finfield.h +++ b/src/finfield.h @@ -13,8 +13,11 @@ ** ** Finite fields are an important domain in computational group theory ** because the classical matrix groups are defined over those finite fields. -** In GAP we support small finite fields with up to 65536 elements, -** larger fields can be realized as polynomial domains over smaller fields. +** The GAP kernel supports elements of finite fields up to some fixed size +** limit, typically 2^16 on 32 bit systems and 2^24 on 64 bit systems. +** To change the limits, edit etc/ffgen.c. To access the current limits in the +** kernel, use SIZE_LARGEST_INTERNAL_FF, in GAP use MAXSIZE_GF_INTERNAL. +** Larger fields are supported in the library ** ** Elements in small finite fields are represented as immediate objects. ** @@ -25,10 +28,11 @@ ** 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 13 bits represent the small finite field where the element lies. -** They are simply an index into a global table of small finite fields. +** 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 16 bits represent the value of the element. +** 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 @@ -64,10 +68,10 @@ ** ** Small finite fields are represented by an index into a global table. ** -** Since there are only 6542 (prime) + 93 (nonprime) small finite fields, -** the index fits into a 'UInt2' (actually into 13 bits). +** Depending on the configuration it may be UInt2 or UInt4. The definition +** is in `ffdata.h` and is calculated by etc/ffgen.c */ -/* This type is now actually defined in gen/ffdata.h by ffgen*/ + /**************************************************************************** @@ -128,8 +132,8 @@ extern Obj SuccFF; ** 'TYPE_FF' returns the type of elements of the small finite field . ** 'TYPE_FF0' returns the type of the zero of ** -** Note that 'TYPE_FF' is a macro, so do not call it with arguments that -** have side effects. +** Note that 'TYPE_FF' and TypeFF0 are macros, so do not call them +** with arguments that have side effects. */ #define TYPE_FF(ff) (ELM_PLIST( TypeFF, ff )) #define TYPE_FF0(ff) (ELM_PLIST( TypeFF0, ff )) @@ -148,17 +152,9 @@ extern Obj TypeFF0; ** Values of elements of small finite fields are represented by the ** logarithm of the element with respect to the root plus one. ** -** Since small finite fields contain at most 65536 elements, the value fits -** into a 'UInt2'. -** -** It may be possible to change this to 'UInt4' to allow small finite fields -** with more than than 65536 elements. The macros and have been coded in -** such a way that they work without problems. The exception is 'POW_FFV' -** which will only work if the product of integers of type 'FFV' does not -** cause an overflow. And of course the successor table stored for a finite -** field will become quite large for fields with more than 65536 elements. +** Depending on the configuration, this type may be a UInt2 or UInt4. +** This type is actually defined in gen/ffdata.h ffgen */ -/* This type is now actually defined in gen/ffdata.h by ffgen*/ /**************************************************************************** ** @@ -171,11 +167,6 @@ extern Obj TypeFF0; ** the same finite field. If you want to multiply two elements where one ** lies in a subfield of the other use 'ProdFFEFFE'. ** -** Use 'PROD_FFV' only with arguments that are variables or array elements, -** because it is a macro and arguments with side effects will behave strange, -** and because it is a complex macro so most C compilers will be upset by -** complex arguments. Especially do not use 'NEG_FFV(PROD_FFV(a,b,f),f)'. -** ** 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$ @@ -205,11 +196,6 @@ static inline FFV PROD_FFV(FFV a, FFV b, const FFV *f) { ** the same finite field. If you want to add two elements where one lies in ** a subfield of the other use 'SumFFEFFE'. ** -** Use 'SUM_FFV' only with arguments that are variables or array elements, -** because it is a macro and arguments with side effects will behave strange, -** and because it is a complex macro so most C compilers will be upset by -** complex arguments. Especially do not use 'SUM_FFV(a,NEG_FFV(b,f),f)'. -** ** 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]$, @@ -241,11 +227,6 @@ static inline FFV SUM_FFV( FFV a, FFV b, const FFV *f) { ** 'NEG_FFV' returns the negative of the finite field value from the ** finite field pointed to by the pointer . ** -** Use 'NEG_FFV' only with arguments that are variables or array elements, -** because it is a macro and arguments with side effects will behave strange, -** and because it is a complex macro so most C compilers will be upset by -** complex arguments. Especially do not use 'NEG_FFV(PROD_FFV(a,b,f),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 @@ -280,10 +261,6 @@ static inline FFV NEG_FFV( FFV a, const FFV *f) { ** the same finite field. If you want to divide two elements where one lies ** in a subfield of the other use 'QuoFFEFFE'. ** -** Use 'QUO_FFV' only with arguments that are variables or array elements, -** because it is a macro and arguments with side effects will behave strange, -** and because it is a complex macro so most C compilers will be upset by -** complex arguments. Especially do not use 'NEG_FFV(PROD_FFV(a,b,f),f)'. ** ** 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$, @@ -310,21 +287,16 @@ static inline FFV QUO_FFV(FFV a, FFV b, const FFV *f) { ** the finite field pointed to by the pointer . ** ** Note that 'POW_FFV' may only be used if the right operand is an integer -** in the range $0..order(f)-1$. +** in the range $0..order(f)-1$ (tested by an assertion) ** ** Finally 'POW_FFV' may only be used if the product of two integers of the -** size of 'FFV' does not cause an overflow, i.e. only if 'FFV' is -** 'unsigned short'. +** size of 'FFV' does not cause an overflow. This is tested by a compile +** -time assertion. ** -** Note that 'POW_FFV' is a macro, so do not call it with arguments that -** have side effects. ** ** 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)$ ** -** In the first macro one needs to be careful to convert a and n to UInt4. -** Before performing the multiplication, ANSI-C will only convert to Int -** since UInt2 fits into Int. */ static inline FFV POW_FFV(FFV a, UInt n, const FFV *f) { @@ -364,9 +336,11 @@ static inline FF FLD_FFE(Obj ffe) { ** and otherwise if is $z^i$, it returns $i+1$. ** */ -static inline FFV VAL_FFE(Obj ffe) { +static inline FFV VAL_FFE(Obj ffe) +{ GAP_ASSERT(IS_FFE(ffe)); -return (FFV)((UInt)(ffe) >> (3+FIELD_BITS_FFE)) & ((1 << VAL_BITS_FFE)-1); + return (FFV)((UInt)(ffe) >> (3 + FIELD_BITS_FFE)) & + ((1 << VAL_BITS_FFE) - 1); } /**************************************************************************** @@ -378,21 +352,23 @@ return (FFV)((UInt)(ffe) >> (3+FIELD_BITS_FFE)) & ((1 << VAL_BITS_FFE)-1); ** */ -static 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); +static 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(

,) . . . make the small finite field with elements +*F FiniteFieldBySize() . . make the small finite field with elements ** ** 'FiniteField' returns the small finite field with

^ elements. */ -extern FF FiniteField ( - UInt p, - UInt d ); +extern FF FiniteField(UInt p, UInt d); +extern FF FiniteFieldBySize(UInt q); /****************************************************************************