Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
| Download
GAP 4.8.9 installation with standard packages -- copy to your CoCalc project to get it
Project: cocalc-sagemath-dev-slelievre
Views: 418346/****************************************************************************1**2*W finfield.c GAP source Werner Nickel3*W & Martin Schönert4**5**6*Y Copyright (C) 1996, Lehrstuhl D für Mathematik, RWTH Aachen, Germany7*Y (C) 1998 School Math and Comp. Sci., University of St Andrews, Scotland8*Y Copyright (C) 2002 The GAP Group9**10** This file contains the functions to compute with elements from small11** finite fields.12**13** Finite fields are an important domain in computational group theory14** because the classical matrix groups are defined over those finite fields.15** In GAP we support small finite fields with up to 65536 elements,16** larger fields can be realized as polynomial domains over smaller fields.17**18** Elements in small finite fields are represented as immediate objects.19**20** +----------------+-------------+---+21** | <value> | <field> |010|22** +----------------+-------------+---+23**24** The least significant 3 bits of such an immediate object are always 010,25** flagging the object as an object of a small finite field.26**27** The next 13 bits represent the small finite field where the element lies.28** They are simply an index into a global table of small finite fields.29**30** The most significant 16 bits represent the value of the element.31**32** If the value is 0, then the element is the zero from the finite field.33** Otherwise the integer is the logarithm of this element with respect to a34** fixed generator of the multiplicative group of the finite field plus one.35** In the following desriptions we denote this generator always with $z$, it36** is an element of order $o-1$, where $o$ is the order of the finite field.37** Thus 1 corresponds to $z^{1-1} = z^0 = 1$, i.e., the one from the field.38** Likewise 2 corresponds to $z^{2-1} = z^1 = z$, i.e., the root itself.39**40** This representation makes multiplication very easy, we only have to add41** the values and subtract 1 , because $z^{a-1} * z^{b-1} = z^{(a+b-1)-1}$.42** Addition is reduced to * by the formula $z^a + z^b = z^b * (z^{a-b}+1)$.43** This makes it neccessary to know the successor $z^a + 1$ of every value.44**45** The finite field bag contains the successor for every nonzero value,46** i.e., 'SUCC_FF(<ff>)[<a>]' is the successor of the element <a>, i.e, it47** is the logarithm of $z^{a-1} + 1$. This list is usually called the48** Zech-Logarithm table. The zeroth entry in the finite field bag is the49** order of the finite field minus one.50*/51#include "system.h" /* Ints, UInts */525354#include "gasman.h" /* garbage collector */55#include "objects.h" /* objects */56#include "scanner.h" /* scanner */5758#include "gap.h" /* error handling, initialisation */5960#include "gvars.h" /* global variables */6162#include "calls.h" /* generic call mechanism */63#include "opers.h" /* generic operations */6465#include "ariths.h" /* basic arithmetic */6667#include "bool.h" /* booleans */6869#include "integer.h" /* integers */7071#include "finfield.h" /* finite fields and ff elements */7273#include "records.h" /* generic records */74#include "precord.h" /* plain records */7576#include "lists.h" /* generic lists */77#include "plist.h" /* plain lists */78#include "string.h" /* strings */7980#include "code.h" /* coder */81#include "aobjects.h" /* atomic access to plists */82#include "thread.h" /* threads */83#include "tls.h" /* thread-local storage */8485#include "ffdata.h" /* pre-computed finite field data */868788/****************************************************************************89**9091*T FF . . . . . . . . . . . . . . . . . . . . . type of small finite fields92**93** 'FF' is the type used to represent small finite fields.94**95** Small finite fields are represented by an index into a global table.96**97** Since there are only 6542 (prime) + 93 (nonprime) small finite fields,98** the index fits into a 'UInt2' (actually into 13 bits).99**100** 'FF' is defined in the declaration part of this package as follows101**102typedef UInt2 FF;103*/104105106/****************************************************************************107**108*F CHAR_FF(<ff>) . . . . . . . . . . . characteristic of small finite field109**110** 'CHAR_FF' returns the characteristic of the small finite field <ff>.111**112** Note that 'CHAR_FF' is a macro, so do not call it with arguments that113** have side effects.114**115** 'CHAR_FF' is defined in the declaration part of this package as follows116**117#define CHAR_FF(ff) INT_INTOBJ( ELM_PLIST( CharFF, ff ) )118*/119Obj CharFF;120121122/****************************************************************************123**124*F DEGR_FF(<ff>) . . . . . . . . . . . . . . . degree of small finite field125**126** 'DEGR_FF' returns the degree of the small finite field <ff>.127**128** Note that 'DEGR_FF' is a macro, so do not call it with arguments that129** have side effects.130**131** 'DEGR_FF' is defined in the declaration part of this package as follows132**133#define DEGR_FF(ff) INT_INTOBJ( ELM_PLIST( DegrFF, ff ) )134*/135Obj DegrFF;136137138/****************************************************************************139**140*F SIZE_FF(<ff>) . . . . . . . . . . . . . . . . size of small finite field141**142** 'SIZE_FF' returns the size of the small finite field <ff>.143**144** Note that 'SIZE_FF' is a macro, so do not call it with arguments that145** have side effects.146**147** 'SIZE_FF' is defined in the declaration part of this package as follows148**149#define SIZE_FF(ff) (*SUCC_FF(ff)+1)150*/151152153/****************************************************************************154**155*F SUCC_FF(<ff>) . . . . . . . . . . . successor table of small finite field156**157** 'SUCC_FF' returns a pointer to the successor table of the small finite158** field <ff>.159**160** Note that 'SUCC_FF' is a macro, so do not call it with arguments that161** side effects.162**163** 'SUCC_FF' is defined in the declaration part of this package as follows164**165#define SUCC_FF(ff) ((FFV*)ADDR_OBJ( ELM_PLIST( SuccFF, ff ) ))166*/167Obj SuccFF;168169170/****************************************************************************171**172*F TYPE_FF(<ff>) . . . . . . . . . . . . . . . type of a small finite field173**174** 'TYPE_FF' returns the type of elements of the small finite field <ff>.175**176** Note that 'TYPE_FF' is a macro, so do not call it with arguments that177** have side effects.178**179** 'TYPE_FF' is defined in the declaration part of this package as follows180**181#define TYPE_FF(ff) (ELM_PLIST( TypeFF, ff ))182*/183Obj TypeFF;184Obj TypeFF0;185186Obj TYPE_FFE;187Obj TYPE_FFE0;188189190/****************************************************************************191**192*T FFV . . . . . . . . type of the values of elements of small finite fields193**194** 'FFV' is the type used to represent the values of elements of small195** finite fields.196**197** Values of elements of small finite fields are represented by the198** logarithm of the element with respect to the root plus one.199**200** Since small finite fields contain at most 65536 elements, the value fits201** into a 'UInt2'.202**203** It may be possible to change this to 'UInt4' to allow small finite fields204** with more than than 65536 elements. The macros and have been coded in205** such a way that they work without problems. The exception is 'POW_FFV'206** which will only work if the product of integers of type 'FFV' does not207** cause an overflow. And of course the successor table stored for a finite208** field will become quite large for fields with more than 65536 elements.209**210** 'FFV' is defined in the declaration part of this package as follows211**212typedef UInt2 FFV;213*/214215216/****************************************************************************217**218*F SUM_FFV(<a>,<b>,<f>) . . . . . . . . . . . . sum of finite field values219**220** 'SUM_FFV' returns the sum of the two finite field values <a> and <b> from221** the finite field pointed to by the pointer <f>.222**223** Note that 'SUM_FFV' may only be used if the operands are represented in224** the same finite field. If you want to add two elements where one lies in225** a subfield of the other use 'SumFFEFFE'.226**227** Use 'SUM_FFV' only with arguments that are variables or array elements,228** because it is a macro and arguments with side effects will behave strange,229** and because it is a complex macro so most C compilers will be upset by230** complex arguments. Especially do not use 'SUM_FFV(a,NEG_FFV(b,f),f)'.231**232** If either operand is 0, the sum is just the other operand.233** If $a <= b$ we have234** $a + b ~ z^{a-1}+z^{b-1} = z^{a-1} * (z^{(b-1)-(a-1)}+1) ~ a * f[b-a+1]$,235** otherwise we have236** $a + b ~ z^{b-1}+z^{a-1} = z^{b-1} * (z^{(a-1)-(b-1)}+1) ~ b * f[a-b+1]$.237**238** 'SUM_FFV' is defined in the declaration part of this package as follows239**240#define SUM2_FFV(a,b,f) PROD_FFV( a, (f)[(b)-(a)+1], f )241#define SUM1_FFV(a,b,f) ( (a)<=(b) ? SUM2_FFV(a,b,f) : SUM2_FFV(b,a,f) )242#define SUM_FFV(a,b,f) ( (a)==0 || (b)==0 ? (a)+(b) : SUM1_FFV(a,b,f) )243*/244245246/****************************************************************************247**248*F NEG_FFV(<a>,<f>) . . . . . . . . . . . . negative of finite field value249**250** 'NEG_FFV' returns the negative of the finite field value <a> from the251** finite field pointed to by the pointer <f>.252**253** Use 'NEG_FFV' only with arguments that are variables or array elements,254** because it is a macro and arguments with side effects will behave strange,255** and because it is a complex macro so most C compilers will be upset by256** complex arguments. Especially do not use 'NEG_FFV(PROD_FFV(a,b,f),f)'.257**258** If the characteristic is 2, every element is its own additive inverse.259** Otherwise note that $z^{o-1} = 1 = -1^2$ so $z^{(o-1)/2} = 1^{1/2} = -1$.260** If $a <= (o-1)/2$ we have261** $-a ~ -1 * z^{a-1} = z^{(o-1)/2} * z^{a-1} = z^{a+(o-1)/2-1} ~ a+(o-1)/2$262** otherwise we have263** $-a ~ -1 * z^{a-1} = z^{a+(o-1)/2-1} = z^{a+(o-1)/2-1-(o-1)} ~ a-(o-1)/2$264**265** 'NEG_FFV' is defined in the declaration part of this package as follows266**267#define NEG2_FFV(a,f) ( (a)<=*(f)/2 ? (a)+*(f)/2 : (a)-*(f)/2 )268#define NEG1_FFV(a,f) ( *(f)%2==1 ? (a) : NEG2_FFV(a,f) )269#define NEG_FFV(a,f) ( (a)==0 ? 0 : NEG1_FFV(a,f) )270*/271272273/****************************************************************************274**275*F PROD_FFV(<a>,<b>,<f>) . . . . . . . . . . . product of finite field value276**277** 'PROD_FFV' returns the product of the two finite field values <a> and <b>278** from the finite field pointed to by the pointer <f>.279**280** Note that 'PROD_FFV' may only be used if the operands are represented in281** the same finite field. If you want to multiply two elements where one282** lies in a subfield of the other use 'ProdFFEFFE'.283**284** Use 'PROD_FFV' only with arguments that are variables or array elements,285** because it is a macro and arguments with side effects will behave strange,286** and because it is a complex macro so most C compilers will be upset by287** complex arguments. Especially do not use 'NEG_FFV(PROD_FFV(a,b,f),f)'.288**289** If one of the values is 0 the product is 0.290** If $a+b <= o$ we have $a * b ~ z^{a-1} * z^{b-1} = z^{(a+b-1)-1} ~ a+b-1$291** otherwise we have $a * b ~ z^{(a+b-2)-(o-1)} = z^{(a+b-o)-1} ~ a+b-o$292**293** 'PROD_FF' is defined in the declaration part of this package as follows294**295#define PROD1_FFV(a,b,f) ( (a)-1<=*(f)-(b) ? (a)-1+(b) : (a)-1-(*(f)-(b)) )296#define PROD_FFV(a,b,f) ( (a)==0 || (b)==0 ? 0 : PROD1_FFV(a,b,f) )297*/298299300/****************************************************************************301**302*F QUO_FFV(<a>,<b>,<f>) . . . . . . . . . . quotient of finite field values303**304** 'QUO_FFV' returns the quotient of the two finite field values <a> and <b>305** from the finite field pointed to by the pointer <f>.306**307** Note that 'QUO_FFV' may only be used if the operands are represented in308** the same finite field. If you want to divide two elements where one lies309** in a subfield of the other use 'QuoFFEFFE'.310**311** Use 'QUO_FFV' only with arguments that are variables or array elements,312** because it is a macro and arguments with side effects will behave strange,313** and because it is a complex macro so most C compilers will be upset by314** complex arguments. Especially do not use 'NEG_FFV(PROD_FFV(a,b,f),f)'.315**316** A division by 0 is an error, and dividing 0 by a nonzero value gives 0.317** If $0 <= a-b$ we have $a / b ~ z^{a-1} / z^{b-1} = z^{a-b+1-1} ~ a-b+1$,318** otherwise we have $a / b ~ z^{a-b+1-1} = z^{a-b+(o-1)} ~ a-b+o$.319**320** 'QUO_FFV' is defined in the declaration part of this package as follows321**322#define QUO1_FFV(a,b,f) ( (b)<=(a) ? (a)-(b)+1 : *(f)-(b)+1+(a) )323#define QUO_FFV(a,b,f) ( (a)==0 ? 0 : QUO1_FFV(a,b,f) )324*/325326327/****************************************************************************328**329*F POW_FFV(<a>,<n>,<f>) . . . . . . . . . . . power of a finite field value330**331** 'POW_FFV' returns the <n>th power of the finite field value <a> from the332** the finite field pointed to by the pointer <f>.333**334** Note that 'POW_FFV' may only be used if the right operand is an integer335** in the range $0..order(f)-1$.336**337** Finally 'POW_FFV' may only be used if the product of two integers of the338** size of 'FFV' does not cause an overflow, i.e. only if 'FFV' is339** 'unsigned short'.340**341** Note that 'POW_FFV' is a macro, so do not call it with arguments that342** have side effects. For optimal performance put the operands in registers343** before calling 'POW_FFV'.344**345** If the finite field element is 0 the power is also 0, otherwise we have346** $a^n ~ (z^{a-1})^n = z^{(a-1)*n} = z^{(a-1)*n % (o-1)} ~ (a-1)*n % (o-1)$347**348** 'POW_FFV' is defined in the declaration part of this package as follows349**350#define POW1_FFV(a,n,f) ( (((a)-1) * (n)) % *(f) + 1 )351#define POW_FFV(a,n,f) ( (n)==0 ? 1 : ( (a)==0 ? 0 : POW1_FFV(a,n,f) ) )352*/353354355/****************************************************************************356**357*F FLD_FFE(<ffe>) . . . . . . . field of an element of a small finite field358**359** 'FLD_FFE' returns the small finite field over which the element <ffe> is360** represented.361**362** Note that 'FLD_FFE' is a macro, so do not call it with arguments that363** have side effects.364**365** 'FLD_FFE' is defined in the declaration part of this package as follows366**367#define FLD_FFE(ffe) ((((UInt)(ffe)) & 0xFFFF) >> 3)368*/369370371/****************************************************************************372**373*F VAL_FFE(<ffe>) . . . . . . . value of an element of a small finite field374**375** 'VAL_FFE' returns the value of the element <ffe> of a small finite field.376** Thus, if <ffe> is $0_F$, it returns 0; if <ffe> is $1_F$, it returns 1;377** and otherwise if <ffe> is $z^i$, it returns $i+1$.378**379** Note that 'VAL_FFE' is a macro, so do not call it with arguments that380** have side effects.381**382** 'VAL_FFE' is defined in the declaration part of this package as follows383**384#define VAL_FFE(ffe) (((UInt)(ffe)) >> 16)385*/386387388/****************************************************************************389**390*F NEW_FFE(<fld>,<val>) . . . . make a new element of a small finite field391**392** 'NEW_FFE' returns a new element <ffe> of the small finite field <fld>393** with the value <val>.394**395** Note that 'NEW_FFE' is a macro, so do not call it with arguments that396** have side effects.397**398** 'NEW_FFE' is defined in the declaration part of this package as follows399**400#define NEW_FFE(fld,val) ((Obj)(((val) << 16) + ((fld) << 3) + 0x02))401*/402403404/****************************************************************************405**406*V PolsFF . . . . . . . . . . list of Conway polynomials for finite fields407**408** 'PolsFF' is a list of Conway polynomials for finite fields. The even409** entries are the proper prime powers, odd entries are the corresponding410** conway polynomials.411*/412unsigned long PolsFF [] = {4134, 1+2,4148, 1+2,41516, 1+2,41632, 1 +4,41764, 1+2 +8+16,418128, 1+2,419256, 1 +4+8+16,420512, 1 +16,4211024, 1+2+4+8 +32+64,4222048, 1 +4,4234096, 1+2 +8 +32+64+128,4248192, 1+2 +8+16,42516384, 1 +8 +32 +128,42632768, 1 +4 +16+32,42765536, 1 +4+8 +32,4289, 2 +2*3,42927, 1 +2*3,43081, 2 +2*27,431243, 1 +2*3,432729, 2 +2*3 +1*9 +2*81,4332187, 1 +2*9,4346561, 2 +2*3 +2*9 +1*81 +2*243,43519683, 1 +1*3 +2*9 +2*27,43659049, 2 +1*3 +2*81 +2*243 +2*729,43725, 2 +4*5,438125, 3 +3*5,439625, 2 +4*5 +4*25,4403125, 3 +4*5,44115625, 2 +1*25 +4*125 +1*625,44249, 3 +6*7,443343, 4 +6*49,4442401, 3 +4*7 +5*49,44516807, 4 +1*7,446121, 2 + 7*11,4471331, 9 + 2*11,44814641, 2 +10*11 +8*121,449169, 2 +12*13,4502197, 11 + 2*13,45128561, 2 +12*13 +3*169,452289, 3 +16*17,4534913, 14 + 1*17,454361, 2 +18*19,4556859, 17 + 4*19,456529, 5 +21*23,45712167, 18 + 2*23,458841, 2 +24*29,45924389, 27 + 2*29,460961, 3 +29*31,46129791, 28 + 1*31,4621369, 2 +33*37,46350653, 35 + 6*37,4641681, 6 + 38* 41,4651849, 3 + 42* 43,4662209, 5 + 45* 47,4672809, 2 + 49* 53,4683481, 2 + 58* 59,4693721, 2 + 60* 61,4704489, 2 + 63* 67,4715041, 7 + 69* 71,4725329, 5 + 70* 73,4736241, 3 + 78* 79,4746889, 2 + 82* 83,4757921, 3 + 82* 89,4769409, 5 + 96* 97,47710201, 2 + 97*101,47810609, 5 +102*103,47911449, 2 +103*107,48011881, 6 +108*109,48112769, 3 +101*113,48216129, 3 +126*127,48317161, 2 +127*131,48418769, 3 +131*137,48519321, 2 +138*139,48622201, 2 +145*149,48722801, 6 +149*151,48824649, 5 +152*157,48926569, 2 +159*163,49027889, 5 +166*167,49129929, 2 +169*173,49232041, 2 +172*179,49332761, 2 +177*181,49436481, 19 +190*191,49537249, 5 +192*193,49638809, 2 +192*197,49739601, 3 +193*199,49844521, 2 +207*211,49949729, 3 +221*223,50051529, 2 +220*227,50152441, 6 +228*229,50254289, 3 +232*233,50357121, 7 +237*239,50458081, 7 +238*241,50563001, 6 +242*251,506};507508509/****************************************************************************510**511*F FiniteField(<p>,<d>) . . . make the small finite field with <q> elements512**513** 'FiniteField' returns the small finite field with <p>^<d> elements.514*/515FF FiniteField (516UInt p,517UInt d )518{519FF ff; /* finite field, result */520Obj bag1, bag2; /* successor table bags */521FFV * succ; /* successor table */522FFV * indx; /* index table */523UInt q; /* size of finite field */524UInt poly; /* Conway polynomial of extension */525UInt i, l, f, n, e; /* loop variables */526527/* search through the finite field table */528for ( ff = 1; ff <= LEN_PLIST(SuccFF); ff++ ) {529if ( CHAR_FF(ff) == p && DEGR_FF(ff) == d ) {530return ff;531}532}533534/* check whether we can build such a finite field */535if ( ( 2 <= p && 17 <= d) || ( 3 <= p && 11 <= d)536|| ( 5 <= p && 7 <= d) || ( 7 <= p && 6 <= d)537|| ( 11 <= p && 5 <= d) || ( 17 <= p && 4 <= d)538|| ( 41 <= p && 3 <= d) || (257 <= p && 2 <= d) ) {539return 0;540}541542/* allocate a bag for the finite field and one for a temporary */543q = 1;544for ( i = 1; i <= d; i++ ) q *= p;545bag1 = NewBag( T_PERM2, q * sizeof(FFV) );546bag2 = NewBag( T_PERM2, q * sizeof(FFV) );547indx = (FFV*)ADDR_OBJ( bag1 );548succ = (FFV*)ADDR_OBJ( bag2 );549550/* if q is a prime find the smallest primitive root $e$, use $x - e$ */551/*N 1990/02/04 mschoene this is likely to explode if 'FFV' is 'UInt4' */552/*N 1990/02/04 mschoene there are few dumber ways to find prim. roots */553if ( d == 1 ) {554for ( e = 1, i = 1; i != p-1; ++e ) {555for ( f = e, i = 1; f != 1; ++i )556f = (f * e) % p;557}558poly = p-(e-1);559}560561/* otherwise look up the polynomial used to construct this field */562else {563for ( i = 0; PolsFF[i] != q; i += 2 ) ;564poly = PolsFF[i+1];565}566567/* construct 'indx' such that 'e = x^(indx[e]-1) % poly' for every e */568/*N 1990/02/04 mschoene this is likely to explode if 'FFV' is 'UInt4' */569indx[ 0 ] = 0;570for ( e = 1, n = 0; n < q-1; ++n ) {571indx[ e ] = n + 1;572/* e =p*e mod poly =x*e mod poly =x*x^n mod poly =x^{n+1} mod poly */573if ( p != 2 ) {574f = p * (e % (q/p)); l = ((p-1) * (e / (q/p))) % p; e = 0;575for ( i = 1; i < q; i *= p )576e = e + i * ((f/i + l * (poly/i)) % p);577}578else {579if ( 2*e & q ) e = 2*e ^ poly ^ q;580else e = 2*e;581}582}583584/* construct 'succ' such that 'x^(n-1)+1 = x^(succ[n]-1)' for every n */585succ[ 0 ] = q-1;586for ( e = 1, f = p-1; e < q; e++ ) {587if ( e < f ) {588succ[ indx[e] ] = indx[ e+1 ];589}590else {591succ[ indx[e] ] = indx[ e+1-p ];592f += p;593}594}595596/* enter the finite field in the tables */597ASS_LIST( CharFF, ff, INTOBJ_INT(p) );598ASS_LIST( DegrFF, ff, INTOBJ_INT(d) );599ASS_LIST( SuccFF, ff, bag2 );600CHANGED_BAG(SuccFF);601bag1 = CALL_1ARGS( TYPE_FFE, INTOBJ_INT(p) );602ASS_LIST( TypeFF, ff, bag1 );603CHANGED_BAG(TypeFF);604bag1 = CALL_1ARGS( TYPE_FFE0, INTOBJ_INT(p) );605ASS_LIST( TypeFF0, ff, bag1 );606CHANGED_BAG(TypeFF0);607608/* return the finite field */609return ff;610}611612613/****************************************************************************614**615*F CommonFF(<f1>,<d1>,<f2>,<d2>) . . . . . . . . . . . . find a common field616**617** 'CommonFF' returns a small finite field that can represent elements of618** degree <d1> from the small finite field <f1> and elements of degree <d2>619** from the small finite field <f2>. Note that this is not guaranteed to be620** the smallest such field. If <f1> and <f2> have different characteristic621** or the smallest common field, is too large, 'CommonFF' returns 0.622*/623FF CommonFF (624FF f1,625UInt d1,626FF f2,627UInt d2 )628{629UInt p; /* characteristic */630UInt d; /* degree */631632/* trivial case first */633if ( f1 == f2 ) {634return f1;635}636637/* get and check the characteristics */638p = CHAR_FF( f1 );639if ( p != CHAR_FF( f2 ) ) {640return 0;641}642643/* check whether one of the fields will do */644if ( DEGR_FF(f1) % d2 == 0 ) {645return f1;646}647if ( DEGR_FF(f2) % d1 == 0 ) {648return f2;649}650651/* compute the neccessary degree */652d = d1;653while ( d % d2 != 0 ) {654d += d1;655}656657/* try to build the field */658return FiniteField( p, d );659}660661662/****************************************************************************663**664*F CharFFE(<ffe>) . . . . . . . . . characteristic of a small finite field665**666** 'CharFFE' returns the characteristic of the small finite field in which667** the element <ffe> lies.668*/669UInt CharFFE (670Obj ffe )671{672return CHAR_FF( FLD_FFE(ffe) );673}674675Obj FuncCHAR_FFE_DEFAULT (676Obj self,677Obj ffe )678{679return INTOBJ_INT( CHAR_FF( FLD_FFE(ffe) ) );680}681682683/****************************************************************************684**685*F DegreeFFE(<ffe>) . . . . . . . . . . . . degree of a small finite field686**687** 'DegreeFFE' returns the degree of the smallest finite field in which the688** element <ffe> lies.689*/690UInt DegreeFFE (691Obj ffe )692{693UInt d; /* degree, result */694FFV val; /* value of element */695FF fld; /* field of element */696UInt q; /* size of field */697UInt p; /* char. of field */698UInt m; /* size of minimal field */699700/* get the value, the field, the size, and the characteristic */701val = VAL_FFE( ffe );702fld = FLD_FFE( ffe );703q = SIZE_FF( fld );704p = CHAR_FF( fld );705706/* the zero element has a degree of one */707if ( val == 0 ) {708return 1L;709}710711/* compute the degree */712m = p;713d = 1;714while ( (q-1) % (m-1) != 0 || (val-1) % ((q-1)/(m-1)) != 0 ) {715m *= p;716d += 1;717}718719/* return the degree */720return d;721}722723Obj FunDEGREE_FFE_DEFAULT (724Obj self,725Obj ffe )726{727return INTOBJ_INT( DegreeFFE( ffe ) );728}729730731/****************************************************************************732**733*F TypeFFE(<ffe>) . . . . . . . . . . type of element of small finite field734**735** 'TypeFFE' returns the type of the element <ffe> of a small finite field.736**737** 'TypeFFE' is the function in 'TypeObjFuncs' for elements in small finite738** fields.739*/740Obj TypeFFE (741Obj ffe )742{743if (VAL_FFE(ffe) == 0)744return TYPE_FF0( FLD_FFE( ffe ) );745else746return TYPE_FF( FLD_FFE( ffe ) );747}748749750/****************************************************************************751**752*F EqFFE(<opL>,<opR>) . . . . . . . test if finite field elements are equal753**754** 'EqFFE' returns 'True' if the two finite field elements <opL> and <opR>755** are equal and 'False' othwise.756**757** This is complicated because it must account for the following situation.758** Suppose 'a' is 'Z(3)', 'b' is 'Z(3^2)^4' and finally 'c' is 'Z(3^3)^13'.759** Mathematically 'a' is equal to 'b', so we want 'a = b' to be 'true' and760** since 'a' is represented over a subfield of 'b' this is no big problem.761** Again 'a' is equal to 'c', and again we want 'a = c' to be 'true' and762** again this is no problem since 'a' is represented over a subfield of 'c'.763** Since '=' ought to be transitive we also want 'b = c' to be 'true' and764** this is a problem, because they are represented over incompatible fields.765*/766Int EqFFE (767Obj opL,768Obj opR )769{770FFV vL, vR; /* value of left and right */771FF fL, fR; /* field of left and right */772UInt pL, pR; /* char. of left and right */773UInt qL, qR; /* size of left and right */774UInt mL, mR; /* size of minimal field */775776/* get the values and the fields over which they are represented */777vL = VAL_FFE( opL );778vR = VAL_FFE( opR );779fL = FLD_FFE( opL );780fR = FLD_FFE( opR );781782/* if the elements are represented over the same field, it is easy */783if ( fL == fR ) {784return (vL == vR);785}786787/* elements in fields of different characteristic are different too */788pL = CHAR_FF( fL );789pR = CHAR_FF( fR );790if ( pL != pR ) {791return 0L;792}793794/* the zero element is not equal to any other element */795if ( vL == 0 || vR == 0 ) {796return (vL == 0 && vR == 0);797}798799/* compute the sizes of the minimal fields in which the elements lie */800qL = SIZE_FF( fL );801mL = pL;802while ( (qL-1) % (mL-1) != 0 || (vL-1) % ((qL-1)/(mL-1)) != 0 ) mL *= pL;803qR = SIZE_FF( fR );804mR = pR;805while ( (qR-1) % (mR-1) != 0 || (vR-1) % ((qR-1)/(mR-1)) != 0 ) mR *= pR;806807/* elements in different fields are different too */808if ( mL != mR ) {809return 0L;810}811812/* otherwise compare the elements in the common minimal field */813return ((vL-1)/((qL-1)/(mL-1)) == (vR-1)/((qR-1)/(mR-1)));814}815816817/****************************************************************************818**819*F LtFFE(<opL>,<opR>) . . . . . . test if finite field elements is smaller820**821** 'LtFFEFFE' returns 'True' if the finite field element <opL> is strictly822** less than the finite field element <opR> and 'False' otherwise.823*/824Int LtFFE (825Obj opL,826Obj opR )827{828FFV vL, vR; /* value of left and right */829FF fL, fR; /* field of left and right */830UInt pL, pR; /* char. of left and right */831UInt qL, qR; /* size of left and right */832UInt mL, mR; /* size of minimal field */833834/* get the values and the fields over which they are represented */835vL = VAL_FFE( opL );836vR = VAL_FFE( opR );837fL = FLD_FFE( opL );838fR = FLD_FFE( opR );839840/* elements in fields of different characteristic are not comparable */841pL = CHAR_FF( fL );842pR = CHAR_FF( fR );843if ( pL != pR ) {844return (DoOperation2Args( LtOper, opL, opR ) == True);845}846847/* the zero element is smaller than any other element */848if ( vL == 0 || vR == 0 ) {849return (vL == 0 && vR != 0);850}851852/* compute the sizes of the minimal fields in which the elements lie */853qL = SIZE_FF( fL );854mL = pL;855while ( (qL-1) % (mL-1) != 0 || (vL-1) % ((qL-1)/(mL-1)) != 0 ) mL *= pL;856qR = SIZE_FF( fR );857mR = pR;858while ( (qR-1) % (mR-1) != 0 || (vR-1) % ((qR-1)/(mR-1)) != 0 ) mR *= pR;859860/* elements in smaller fields are smaller too */861if ( mL != mR ) {862return (mL < mR);863}864865/* otherwise compare the elements in the common minimal field */866return ((vL-1)/((qL-1)/(mL-1)) < (vR-1)/((qR-1)/(mR-1)));867}868869870/****************************************************************************871**872*F PrFFV(<fld>,<val>) . . . . . . . . . . . . . print a finite field value873**874** 'PrFFV' prints the value <val> from the finite field <fld>.875**876*/877void PrFFV (878FF fld,879FFV val )880{881UInt q; /* size of finite field */882UInt p; /* char. of finite field */883UInt m; /* size of minimal field */884UInt d; /* degree of minimal field */885886/* get the characteristic, order of the minimal field and the degree */887q = SIZE_FF( fld );888p = CHAR_FF( fld );889890/* print the zero */891if ( val == 0 ) {892Pr( "%>0*Z(%>%d%2<)", (Int)p, 0L );893}894895/* print a nonzero element as power of the primitive root */896else {897898/* find the degree of the minimal field in that the element lies */899d = 1; m = p;900while ( (q-1) % (m-1) != 0 || (val-1) % ((q-1)/(m-1)) != 0 ) {901d++; m *= p;902}903val = (val-1) / ((q-1)/(m-1)) + 1;904905/* print the element */906Pr( "%>Z(%>%d%<", (Int)p, 0L );907if ( d == 1 ) {908Pr( "%<)", 0L, 0L );909}910else {911Pr( "^%>%d%2<)", (Int)d, 0L );912}913if ( val != 2 ) {914Pr( "^%>%d%<", (Int)(val-1), 0L );915}916}917918}919920921/****************************************************************************922**923*F PrFFE(<ffe>) . . . . . . . . . . . . . . . print a finite field element924**925** 'PrFFE' prints the finite field element <ffe>.926*/927void PrFFE (928Obj ffe )929{930PrFFV( FLD_FFE(ffe), VAL_FFE(ffe) );931}932933934/****************************************************************************935**936*F SumFFEFFE(<opL>,<opR>) . . . . . . . . . . sum of finite field elements937**938** 'SumFFEFFE' returns the sum of the two finite field elements <opL> and939** <opR>. The sum is represented over the field over which the operands are940** represented, even if it lies in a much smaller field.941**942** If one of the elements is represented over a subfield of the field over943** which the other element is represented, it is lifted into the larger944** field before the addition.945**946** 'SumFFEFFE' just does the conversions mentioned above and then calls the947** macro 'SUM_FFV' to do the actual addition.948*/949Obj SUM_FFE_LARGE;950951Obj SumFFEFFE (952Obj opL,953Obj opR )954{955FFV vL, vR, vX; /* value of left, right, result */956FF fL, fR, fX; /* field of left, right, result */957UInt qL, qR, qX; /* size of left, right, result */958959/* get the values, handle trivial cases */960vL = VAL_FFE( opL );961vR = VAL_FFE( opR );962963/* bring the two operands into a common field <fX> */964fL = FLD_FFE( opL );965qL = SIZE_FF( fL );966fR = FLD_FFE( opR );967qR = SIZE_FF( fR );968969/*N 1997/01/04 mschoene this is likely to explode if 'FFV' is 'UInt4' */970if ( qL == qR ) {971fX = fL;972}973else if ( qL % qR == 0 && (qL-1) % (qR-1) == 0 ) {974fX = fL;975if ( vR != 0 ) vR = (qL-1) / (qR-1) * (vR-1) + 1;976}977else if ( qR % qL == 0 && (qR-1) % (qL-1) == 0 ) {978fX = fR;979if ( vL != 0 ) vL = (qR-1) / (qL-1) * (vL-1) + 1;980}981else {982fX = CommonFF( fL, DegreeFFE(opL), fR, DegreeFFE(opR) );983if ( fX == 0 ) return CALL_2ARGS( SUM_FFE_LARGE, opL, opR );984qX = SIZE_FF( fX );985/* if ( vL != 0 ) vL = (qX-1) / (qL-1) * (vL-1) + 1; */986if ( vL != 0 ) vL = ((qX-1) * (vL-1)) / (qL-1) + 1;987/* if ( vR != 0 ) vR = (qX-1) / (qR-1) * (vR-1) + 1; */988if ( vR != 0 ) vR = ((qX-1) * (vR-1)) / (qR-1) + 1;989}990991/* compute and return the result */992vX = SUM_FFV( vL, vR, SUCC_FF(fX) );993return NEW_FFE( fX, vX );994}995996Obj SumFFEInt (997Obj opL,998Obj opR )999{1000FFV vL, vR, vX; /* value of left, right, result */1001FF fX; /* field of result */1002Int pX; /* char. of result */1003FF* sX; /* successor table of result field */10041005/* get the field for the result */1006fX = FLD_FFE( opL );1007pX = CHAR_FF( fX );1008sX = SUCC_FF( fX );10091010/* get the right operand */1011vX = ((INT_INTOBJ( opR ) % pX) + pX) % pX;1012if ( vX == 0 ) {1013vR = 0;1014}1015else {1016vR = 1;1017for ( ; 1 < vX; vX-- ) vR = sX[vR];1018}10191020/* get the left operand */1021vL = VAL_FFE( opL );10221023/* compute and return the result */1024vX = SUM_FFV( vL, vR, sX );1025return NEW_FFE( fX, vX );1026}10271028Obj SumIntFFE (1029Obj opL,1030Obj opR )1031{1032FFV vL, vR, vX; /* value of left, right, result */1033FF fX; /* field of result */1034Int pX; /* char. of result */1035FF* sX; /* successor table of result field */10361037/* get the field for the result */1038fX = FLD_FFE( opR );1039pX = CHAR_FF( fX );1040sX = SUCC_FF( fX );10411042/* get the left operand */1043vX = ((INT_INTOBJ( opL ) % pX) + pX) % pX;1044if ( vX == 0 ) {1045vL = 0;1046}1047else {1048vL = 1;1049for ( ; 1 < vX; vX-- ) vL = sX[vL];1050}10511052/* get the right operand */1053vR = VAL_FFE( opR );10541055/* compute and return the result */1056vX = SUM_FFV( vL, vR, sX );1057return NEW_FFE( fX, vX );1058}105910601061/****************************************************************************1062**1063*F ZeroFFE(<op>) . . . . . . . . . . . . . . zero of a finite field element1064*/1065Obj ZeroFFE (1066Obj op )1067{1068FF fX; /* field of result */10691070/* get the field for the result */1071fX = FLD_FFE( op );10721073/* return the result */1074return NEW_FFE( fX, 0 );1075}107610771078/****************************************************************************1079**1080*F AInvFFE(<op>) . . . . . . . . . . additive inverse of finite field element1081*/1082Obj AInvFFE (1083Obj op )1084{1085FFV v, vX; /* value of operand, result */1086FF fX; /* field of result */1087FF* sX; /* successor table of result field */10881089/* get the field for the result */1090fX = FLD_FFE( op );1091sX = SUCC_FF( fX );10921093/* get the operand */1094v = VAL_FFE( op );10951096/* compute and return the result */1097vX = NEG_FFV( v, sX );1098return NEW_FFE( fX, vX );1099}110011011102/****************************************************************************1103**1104*F DiffFFEFFE(<opL>,<opR>) . . . . . . . difference of finite field elements1105**1106** 'DiffFFEFFE' returns the difference of the two finite field elements1107** <opL> and <opR>. The difference is represented over the field over which1108** the operands are represented, even if it lies in a much smaller field.1109**1110** If one of the elements is represented over a subfield of the field over1111** which the other element is represented, it is lifted into the larger1112** field before the subtraction.1113**1114** 'DiffFFEFFE' just does the conversions mentioned above and then calls the1115** macros 'NEG_FFV' and 'SUM_FFV' to do the actual subtraction.1116*/1117Obj DIFF_FFE_LARGE;11181119Obj DiffFFEFFE (1120Obj opL,1121Obj opR )1122{1123FFV vL, vR, vX; /* value of left, right, result */1124FF fL, fR, fX; /* field of left, right, result */1125UInt qL, qR, qX; /* size of left, right, result */11261127/* get the values, handle trivial cases */1128vL = VAL_FFE( opL );1129vR = VAL_FFE( opR );11301131/* bring the two operands into a common field <fX> */1132fL = FLD_FFE( opL );1133qL = SIZE_FF( fL );1134fR = FLD_FFE( opR );1135qR = SIZE_FF( fR );11361137/*N 1997/01/04 mschoene this is likely to explode if 'FFV' is 'UInt4' */1138if ( qL == qR ) {1139fX = fL;1140}1141else if ( qL % qR == 0 && (qL-1) % (qR-1) == 0 ) {1142fX = fL;1143if ( vR != 0 ) vR = (qL-1) / (qR-1) * (vR-1) + 1;1144}1145else if ( qR % qL == 0 && (qR-1) % (qL-1) == 0 ) {1146fX = fR;1147if ( vL != 0 ) vL = (qR-1) / (qL-1) * (vL-1) + 1;1148}1149else {1150fX = CommonFF( fL, DegreeFFE(opL), fR, DegreeFFE(opR) );1151if ( fX == 0 ) return CALL_2ARGS( DIFF_FFE_LARGE, opL, opR );1152qX = SIZE_FF( fX );1153/* if ( vL != 0 ) vL = (qX-1) / (qL-1) * (vL-1) + 1; */1154if ( vL != 0 ) vL = ((qX-1) * (vL-1)) / (qL-1) + 1;1155/* if ( vR != 0 ) vR = (qX-1) / (qR-1) * (vR-1) + 1; */1156if ( vR != 0 ) vR = ((qX-1) * (vR-1)) / (qR-1) + 1;1157}11581159/* compute and return the result */1160vR = NEG_FFV( vR, SUCC_FF(fX) );1161vX = SUM_FFV( vL, vR, SUCC_FF(fX) );1162return NEW_FFE( fX, vX );1163}11641165Obj DiffFFEInt (1166Obj opL,1167Obj opR )1168{1169FFV vL, vR, vX; /* value of left, right, result */1170FF fX; /* field of result */1171Int pX; /* char. of result */1172FF* sX; /* successor table of result field */11731174/* get the field for the result */1175fX = FLD_FFE( opL );1176pX = CHAR_FF( fX );1177sX = SUCC_FF( fX );11781179/* get the right operand */1180vX = ((INT_INTOBJ( opR ) % pX) + pX) % pX;1181if ( vX == 0 ) {1182vR = 0;1183}1184else {1185vR = 1;1186for ( ; 1 < vX; vX-- ) vR = sX[vR];1187}11881189/* get the left operand */1190vL = VAL_FFE( opL );11911192/* compute and return the result */1193vR = NEG_FFV( vR, sX );1194vX = SUM_FFV( vL, vR, sX );1195return NEW_FFE( fX, vX );1196}11971198Obj DiffIntFFE (1199Obj opL,1200Obj opR )1201{1202FFV vL, vR, vX; /* value of left, right, result */1203FF fX; /* field of result */1204Int pX; /* char. of result */1205FF* sX; /* successor table of result field */12061207/* get the field for the result */1208fX = FLD_FFE( opR );1209pX = CHAR_FF( fX );1210sX = SUCC_FF( fX );12111212/* get the left operand */1213vX = ((INT_INTOBJ( opL ) % pX) + pX) % pX;1214if ( vX == 0 ) {1215vL = 0;1216}1217else {1218vL = 1;1219for ( ; 1 < vX; vX-- ) vL = sX[vL];1220}12211222/* get the right operand */1223vR = VAL_FFE( opR );12241225/* compute and return the result */1226vR = NEG_FFV( vR, sX );1227vX = SUM_FFV( vL, vR, sX );1228return NEW_FFE( fX, vX );1229}123012311232/****************************************************************************1233**1234*F ProdFFEFFE(<opL>,<opR>) . . . . . . . . product of finite field elements1235**1236** 'ProdFFEFFE' returns the product of the two finite field elements <opL>1237** and <opR>. The product is represented over the field over which the1238** operands are represented, even if it lies in a much smaller field.1239**1240** If one of the elements is represented over a subfield of the field over1241** which the other element is represented, it is lifted into the larger1242** field before the multiplication.1243**1244** 'ProdFFEFFE' just does the conversions mentioned above and then calls the1245** macro 'PROD_FFV' to do the actual multiplication.1246*/1247Obj PROD_FFE_LARGE;12481249Obj ProdFFEFFE (1250Obj opL,1251Obj opR )1252{1253FFV vL, vR, vX; /* value of left, right, result */1254FF fL, fR, fX; /* field of left, right, result */1255UInt qL, qR, qX; /* size of left, right, result */12561257/* get the values, handle trivial cases */1258vL = VAL_FFE( opL );1259vR = VAL_FFE( opR );12601261/* bring the two operands into a common field <fX> */1262fL = FLD_FFE( opL );1263qL = SIZE_FF( fL );1264fR = FLD_FFE( opR );1265qR = SIZE_FF( fR );12661267/*N 1997/01/04 mschoene this is likely to explode if 'FFV' is 'UInt4' */1268if ( qL == qR ) {1269fX = fL;1270}1271else if ( qL % qR == 0 && (qL-1) % (qR-1) == 0 ) {1272fX = fL;1273if ( vR != 0 ) vR = (qL-1) / (qR-1) * (vR-1) + 1;1274}1275else if ( qR % qL == 0 && (qR-1) % (qL-1) == 0 ) {1276fX = fR;1277if ( vL != 0 ) vL = (qR-1) / (qL-1) * (vL-1) + 1;1278}1279else {1280fX = CommonFF( fL, DegreeFFE(opL), fR, DegreeFFE(opR) );1281if ( fX == 0 ) return CALL_2ARGS( PROD_FFE_LARGE, opL, opR );1282qX = SIZE_FF( fX );1283/* if ( vL != 0 ) vL = (qX-1) / (qL-1) * (vL-1) + 1; */1284if ( vL != 0 ) vL = ((qX-1) * (vL-1)) / (qL-1) + 1;1285/* if ( vR != 0 ) vR = (qX-1) / (qR-1) * (vR-1) + 1; */1286if ( vR != 0 ) vR = ((qX-1) * (vR-1)) / (qR-1) + 1;1287}12881289/* compute and return the result */1290vX = PROD_FFV( vL, vR, SUCC_FF(fX) );1291return NEW_FFE( fX, vX );1292}12931294Obj ProdFFEInt (1295Obj opL,1296Obj opR )1297{1298FFV vL, vR, vX; /* value of left, right, result */1299FF fX; /* field of result */1300Int pX; /* char. of result */1301FF* sX; /* successor table of result field */13021303/* get the field for the result */1304fX = FLD_FFE( opL );1305pX = CHAR_FF( fX );1306sX = SUCC_FF( fX );13071308/* get the right operand */1309vX = ((INT_INTOBJ( opR ) % pX) + pX) % pX;1310if ( vX == 0 ) {1311vR = 0;1312}1313else {1314vR = 1;1315for ( ; 1 < vX; vX-- ) vR = sX[vR];1316}13171318/* get the left operand */1319vL = VAL_FFE( opL );13201321/* compute and return the result */1322vX = PROD_FFV( vL, vR, sX );1323return NEW_FFE( fX, vX );1324}13251326Obj ProdIntFFE (1327Obj opL,1328Obj opR )1329{1330FFV vL, vR, vX; /* value of left, right, result */1331FF fX; /* field of result */1332Int pX; /* char. of result */1333FF* sX; /* successor table of result field */13341335/* get the field for the result */1336fX = FLD_FFE( opR );1337pX = CHAR_FF( fX );1338sX = SUCC_FF( fX );13391340/* get the left operand */1341vX = ((INT_INTOBJ( opL ) % pX) + pX) % pX;1342if ( vX == 0 ) {1343vL = 0;1344}1345else {1346vL = 1;1347for ( ; 1 < vX; vX-- ) vL = sX[vL];1348}13491350/* get the right operand */1351vR = VAL_FFE( opR );13521353/* compute and return the result */1354vX = PROD_FFV( vL, vR, sX );1355return NEW_FFE( fX, vX );1356}135713581359/****************************************************************************1360**1361*F OneFFE(<op>) . . . . . . . . . . . . . . . one of a finite field element1362*/1363Obj OneFFE (1364Obj op )1365{1366FF fX; /* field of result */13671368/* get the field for the result */1369fX = FLD_FFE( op );13701371/* return the result */1372return NEW_FFE( fX, 1 );1373}137413751376/****************************************************************************1377**1378*F InvFFE(<op>) . . . . . . . . . . . . . . inverse of finite field element1379*/1380Obj InvFFE (1381Obj op )1382{1383FFV v, vX; /* value of operand, result */1384FF fX; /* field of result */1385FF* sX; /* successor table of result field */13861387/* get the field for the result */1388fX = FLD_FFE( op );1389sX = SUCC_FF( fX );13901391/* get the operand */1392v = VAL_FFE( op );1393if ( v == 0 ) return Fail;13941395/* compute and return the result */1396vX = QUO_FFV( 1, v, sX );1397return NEW_FFE( fX, vX );1398}139914001401/****************************************************************************1402**1403*F QuoFFEFFE(<opL>,<opR>) . . . . . . . . quotient of finite field elements1404**1405** 'QuoFFEFFE' returns the quotient of the two finite field elements <opL>1406** and <opR>. The quotient is represented over the field over which the1407** operands are represented, even if it lies in a much smaller field.1408**1409** If one of the elements is represented over a subfield of the field over1410** which the other element is represented, it is lifted into the larger1411** field before the division.1412**1413** 'QuoFFEFFE' just does the conversions mentioned above and then calls the1414** macro 'QUO_FFV' to do the actual division.1415*/1416Obj QUO_FFE_LARGE;14171418Obj QuoFFEFFE (1419Obj opL,1420Obj opR )1421{1422FFV vL, vR, vX; /* value of left, right, result */1423FF fL, fR, fX; /* field of left, right, result */1424UInt qL, qR, qX; /* size of left, right, result */14251426/* get the values, handle trivial cases */1427vL = VAL_FFE( opL );1428vR = VAL_FFE( opR );14291430/* bring the two operands into a common field <fX> */1431fL = FLD_FFE( opL );1432qL = SIZE_FF( fL );1433fR = FLD_FFE( opR );1434qR = SIZE_FF( fR );14351436/*N 1997/01/04 mschoene this is likely to explode if 'FFV' is 'UInt4' */1437if ( qL == qR ) {1438fX = fL;1439}1440else if ( qL % qR == 0 && (qL-1) % (qR-1) == 0 ) {1441fX = fL;1442if ( vR != 0 ) vR = (qL-1) / (qR-1) * (vR-1) + 1;1443}1444else if ( qR % qL == 0 && (qR-1) % (qL-1) == 0 ) {1445fX = fR;1446if ( vL != 0 ) vL = (qR-1) / (qL-1) * (vL-1) + 1;1447}1448else {1449fX = CommonFF( fL, DegreeFFE(opL), fR, DegreeFFE(opR) );1450if ( fX == 0 ) return CALL_2ARGS( QUO_FFE_LARGE, opL, opR );1451qX = SIZE_FF( fX );1452/* if ( vL != 0 ) vL = (qX-1) / (qL-1) * (vL-1) + 1; */1453if ( vL != 0 ) vL = ((qX-1) * (vL-1)) / (qL-1) + 1;1454/* if ( vR != 0 ) vR = (qX-1) / (qR-1) * (vR-1) + 1; */1455if ( vR != 0 ) vR = ((qX-1) * (vR-1)) / (qR-1) + 1;1456}14571458/* compute and return the result */1459if ( vR == 0 ) {1460opR = ErrorReturnObj(1461"FFE operations: <divisor> must not be zero",14620L, 0L,1463"you can replace <divisor> via 'return <divisor>;'" );1464return QUO( opL, opR );1465}1466vX = QUO_FFV( vL, vR, SUCC_FF(fX) );1467return NEW_FFE( fX, vX );1468}14691470Obj QuoFFEInt (1471Obj opL,1472Obj opR )1473{1474FFV vL, vR, vX; /* value of left, right, result */1475FF fX; /* field of result */1476Int pX; /* char. of result */1477FF* sX; /* successor table of result field */14781479/* get the field for the result */1480fX = FLD_FFE( opL );1481pX = CHAR_FF( fX );1482sX = SUCC_FF( fX );14831484/* get the right operand */1485vX = ((INT_INTOBJ( opR ) % pX) + pX) % pX;1486if ( vX == 0 ) {1487vR = 0;1488}1489else {1490vR = 1;1491for ( ; 1 < vX; vX-- ) vR = sX[vR];1492}14931494/* get the left operand */1495vL = VAL_FFE( opL );14961497/* compute and return the result */1498if ( vR == 0 ) {1499opR = ErrorReturnObj(1500"FFE operations: <divisor> must not be zero",15010L, 0L,1502"you can replace <divisor> via 'return <divisor>;'" );1503return QUO( opL, opR );1504}1505vX = QUO_FFV( vL, vR, sX );1506return NEW_FFE( fX, vX );1507}15081509Obj QuoIntFFE (1510Obj opL,1511Obj opR )1512{1513FFV vL, vR, vX; /* value of left, right, result */1514FF fX; /* field of result */1515Int pX; /* char. of result */1516FF* sX; /* successor table of result field */15171518/* get the field for the result */1519fX = FLD_FFE( opR );1520pX = CHAR_FF( fX );1521sX = SUCC_FF( fX );15221523/* get the left operand */1524vX = ((INT_INTOBJ( opL ) % pX) + pX) % pX;1525if ( vX == 0 ) {1526vL = 0;1527}1528else {1529vL = 1;1530for ( ; 1 < vX; vX-- ) vL = sX[vL];1531}15321533/* get the right operand */1534vR = VAL_FFE( opR );15351536/* compute and return the result */1537if ( vR == 0 ) {1538opR = ErrorReturnObj(1539"FFE operations: <divisor> must not be zero",15400L, 0L,1541"you can replace <divisor> via 'return <divisor>;'" );1542return QUO( opL, opR );1543}1544vX = QUO_FFV( vL, vR, sX );1545return NEW_FFE( fX, vX );1546}154715481549/****************************************************************************1550**1551*F PowFFEInt(<opL>,<opR>) . . . . . . . . . power of a finite field element1552**1553** 'PowFFEInt' returns the power of the finite field element <opL> and the1554** integer <opR>. The power is represented over the field over which the1555** left operand is represented, even if it lies in a much smaller field.1556**1557** 'PowFFEInt' just does the conversions mentioned above and then calls the1558** macro 'POW_FFV' to do the actual exponentiation.1559*/1560Obj PowFFEInt (1561Obj opL,1562Obj opR )1563{1564FFV vL, vX; /* value of left, result */1565Int vR; /* value of right */1566FF fX; /* field of result */1567FF* sX; /* successor table of result field */15681569/* get the field for the result */1570fX = FLD_FFE( opL );1571sX = SUCC_FF( fX );15721573/* get the right operand */1574vR = INT_INTOBJ( opR );15751576/* get the left operand */1577vL = VAL_FFE( opL );15781579/* if the exponent is negative, invert the left operand */1580if ( vR < 0 ) {1581if ( vL == 0 ) {1582opL = ErrorReturnObj(1583"FFE operations: <divisor> must not be zero",15840L, 0L,1585"you can replace <divisor> via 'return <divisor>;'" );1586return POW( opL, opR );1587}1588vL = QUO_FFV( 1, vL, sX );1589vR = -vR;1590}15911592/* catch the case when vL is zero. */1593if( vL == 0 ) return NEW_FFE( fX, (vR == 0 ? 1 : 0 ) );15941595/* reduce vR modulo the order of the multiplicative group first. */1596vR %= *sX;15971598/* compute and return the result */1599vX = POW_FFV( vL, vR, sX );1600return NEW_FFE( fX, vX );1601}160216031604/****************************************************************************1605**1606*F PowFFEFFE( <opL>, <opR> ) . . . . . . conjugate of a finite field element1607*/1608Obj PowFFEFFE (1609Obj opL,1610Obj opR )1611{1612/* get the field for the result */1613if ( CHAR_FF( FLD_FFE(opL) ) != CHAR_FF( FLD_FFE(opR) ) ) {1614opR = ErrorReturnObj(1615"FFE operations: characteristic of conjugating element must be %d",1616(Int)CHAR_FF(FLD_FFE(opL)), 0L,1617"you can replace conjugating element <elt> via 'return <elt>;'" );1618return POW( opL, opR );1619}16201621/* compute and return the result */1622return opL;1623}162416251626/****************************************************************************1627**1628*F FuncIS_FFE( <self>, <obj> ) . . . . . . . test for finite field elements1629**1630** 'FuncIsFFE' implements the internal function 'IsFFE( <obj> )'.1631**1632** 'IsFFE' returns 'true' if its argument <obj> is a finite field element1633** and 'false' otherwise. 'IsFFE' will cause an error if called with an1634** unbound variable.1635*/1636Obj IsFFEFilt;16371638Obj FuncIS_FFE (1639Obj self,1640Obj obj )1641{1642/* return 'true' if <obj> is a finite field element */1643if ( TNUM_OBJ(obj) == T_FFE ) {1644return True;1645}1646else if ( TNUM_OBJ(obj) < FIRST_EXTERNAL_TNUM ) {1647return False;1648}1649else {1650return DoFilter( self, obj );1651}1652}165316541655/****************************************************************************1656**1657*F FuncLOG_FFE_DEFAULT( <self>, <opZ>, <opR> ) . logarithm of a ff constant1658**1659** 'FuncLOG_FFE_DEFAULT' implements the function 'LogFFE( <z>, <r> )'.1660**1661** 'LogFFE' returns the logarithm of the nonzero finite field element <z>1662** with respect to the root <r> which must lie in the same field like <z>.1663*/1664Obj LOG_FFE_LARGE;1665#include <stdio.h>16661667Obj FuncLOG_FFE_DEFAULT (1668Obj self,1669Obj opZ,1670Obj opR )1671{1672FFV vZ, vR; /* value of left, right */1673FF fZ, fR, fX; /* field of left, right, common */1674UInt qZ, qR, qX; /* size of left, right, common */1675Int a, b, c, d, t; /* temporaries */16761677/* check the arguments */1678if ( ! IS_FFE(opZ) || VAL_FFE(opZ) == 0 ) {1679opZ = ErrorReturnObj(1680"LogFFE: <z> must be a nonzero finite field element",16810L, 0L,1682"you can replace <z> via 'return <z>;'" );1683return FuncLOG_FFE_DEFAULT( self, opZ, opR );1684}1685if ( ! IS_FFE(opR) || VAL_FFE(opR) == 0 ) {1686opR = ErrorReturnObj(1687"LogFFE: <r> must be a nonzero finite field element",16880L, 0L,1689"you can replace <r> via 'return <r>;'" );1690return FuncLOG_FFE_DEFAULT( self, opZ, opR );1691}16921693/* get the values, handle trivial cases */1694vZ = VAL_FFE( opZ );1695vR = VAL_FFE( opR );16961697/* bring the two operands into a common field <fX> */1698fZ = FLD_FFE( opZ );1699qZ = SIZE_FF( fZ );1700fR = FLD_FFE( opR );1701qR = SIZE_FF( fR );17021703/*N 1997/01/04 mschoene this is likely to explode if 'FFV' is 'UInt4' */1704if ( qZ == qR ) {1705fX = fZ;1706qX = qZ;1707}1708else if ( qZ % qR == 0 && (qZ-1) % (qR-1) == 0 ) {1709fX = fZ;1710qX = qZ;1711if ( vR != 0 ) vR = (qZ-1) / (qR-1) * (vR-1) + 1;1712}1713else if ( qR % qZ == 0 && (qR-1) % (qZ-1) == 0 ) {1714fX = fR;1715qX = qR;1716if ( vZ != 0 ) vZ = (qR-1) / (qZ-1) * (vZ-1) + 1;1717}1718else {1719fX = CommonFF( fZ, DegreeFFE(opZ), fR, DegreeFFE(opR) );1720if ( fX == 0 ) return CALL_2ARGS( LOG_FFE_LARGE, opZ, opR );1721qX = SIZE_FF( fX );1722/* if ( vZ != 0 ) vZ = (qX-1) / (qZ-1) * (vZ-1) + 1; */1723if ( vZ != 0 ) vZ = ((qX-1) * (vZ-1)) / (qZ-1) + 1;1724/* if ( vR != 0 ) vR = (qX-1) / (qR-1) * (vR-1) + 1; */1725if ( vR != 0 ) vR = ((qX-1) * (vR-1)) / (qR-1) + 1;1726}17271728/* now solve <l> * (<vR>-1) = (<vZ>-1) % (<qX>-1) */1729/*N 1990/02/04 mschoene this is likely to explode if 'FFV' is 'UInt4' */1730a = 1; b = 0;1731c = (Int) (vR-1); d = (Int) (qX-1);1732while ( d != 0 ) {1733t = b; b = a - (c/d) * b; a = t;1734t = d; d = c - (c/d) * d; c = t;1735}1736if ( ((Int) (vZ-1)) % c != 0 ) {1737return Fail;1738}173917401741while (a < 0)1742a+= (qX -1)/c;1743/* return the logarithm */174417451746return INTOBJ_INT( (((Int) (vZ-1) / c) * a) % ((Int) (qX-1)) );17471748}174917501751/****************************************************************************1752**1753*F FuncINT_FFE_DEFAULT( <self>, <z> ) . . . . convert a ffe to an integer1754**1755** 'FuncINT_FFE_DEFAULT' implements the internal function 'IntFFE( <z> )'.1756**1757** 'IntFFE' returns the integer that corresponds to the finite field1758** element <z>, which must of course be an element of a prime field, i.e.,1759** the smallest integer <i> such that '<i> * <z>^0 = <z>'.1760*/1761Obj IntFF;17621763Obj INT_FF (1764FF ff )1765{1766Obj conv; /* conversion table, result */1767Int q; /* size of finite field */1768Int p; /* char of finite field */1769FFV * succ; /* successor table of finite field */1770FFV z; /* one element of finite field */1771UInt i; /* loop variable */17721773/* if the conversion table is not already known, construct it */1774if ( LEN_PLIST(IntFF) < ff || ELM_PLIST(IntFF,ff) == 0 ) {1775q = SIZE_FF( ff );1776p = CHAR_FF( ff );1777conv = NEW_PLIST( T_PLIST, p-1 );1778succ = SUCC_FF( ff );1779SET_LEN_PLIST( conv, p-1 );1780z = 1;1781for ( i = 1; i < p; i++ ) {1782SET_ELM_PLIST( conv, (z-1)/((q-1)/(p-1))+1, INTOBJ_INT(i) );1783z = succ[ z ];1784}1785if ( LEN_PLIST(IntFF) < ff ) {1786GROW_PLIST( IntFF, ff );1787SET_LEN_PLIST( IntFF, (Int)ff );1788}1789SET_ELM_PLIST( IntFF, ff, conv );1790CHANGED_BAG( IntFF );1791}17921793/* return the conversion table */1794return ELM_PLIST( IntFF, ff );1795}1796179717981799Obj FuncINT_FFE_DEFAULT (1800Obj self,1801Obj z )1802{1803FFV v; /* value of finite field element */1804FF ff; /* finite field */1805Int q; /* size of finite field */1806Int p; /* char of finite field */1807Obj conv; /* conversion table */18081809/* get the value */1810v = VAL_FFE( z );18111812/* special case for 0 */1813if ( v == 0 ) {1814return INTOBJ_INT( 0 );1815}18161817/* get the field, size, characteristic, and conversion table */1818ff = FLD_FFE( z );1819q = SIZE_FF( ff );1820p = CHAR_FF( ff );1821conv = INT_FF( ff );18221823/* check the argument */1824if ( (v-1) % ((q-1)/(p-1)) != 0 ) {1825z = ErrorReturnObj(1826"IntFFE: <z> must lie in prime field",18270L, 0L,1828"you can replace <z> via 'return <z>;'" );1829return FuncINT_FFE_DEFAULT( self, z );1830}18311832/* convert the value into the prime field */1833v = (v-1) / ((q-1)/(p-1)) + 1;18341835/* return the integer value */1836return ELM_PLIST( conv, v );1837}183818391840/****************************************************************************1841**1842*F FuncZ( <self>, <q> ) . . . return the generator of a small finite field1843**1844** 'FuncZ' implements the internal function 'Z( <q> )'.1845**1846** 'Z' returns the generators of the small finite field with <q> elements.1847** <q> must be a positive prime power.1848*/1849static Obj ZOp;18501851185218531854Obj FuncZ (1855Obj self,1856Obj q )1857{1858FF ff; /* the finite field */1859UInt p; /* characteristic */1860UInt d; /* degree */1861UInt r; /* temporary */18621863/* check the argument */1864if ( (TNUM_OBJ(q) == T_INT && (INT_INTOBJ(q) > 65536)) ||1865(TNUM_OBJ(q) == T_INTPOS))1866return CALL_1ARGS(ZOp, q);18671868if ( TNUM_OBJ(q)!=T_INT || INT_INTOBJ(q)<=1 ) {1869q = ErrorReturnObj(1870"Z: <q> must be a positive prime power (not a %s)",1871(Int)TNAM_OBJ(q), 0L,1872"you can replace <q> via 'return <q>;'" );1873return FuncZ( self, q );1874}18751876/* compute the prime and check that <q> is a prime power */1877if ( INT_INTOBJ(q) % 2 == 0 ) {1878p = 2;1879}1880else {1881p = 3;1882while ( INT_INTOBJ(q) % p != 0 ) {1883p += 2;1884}1885}1886d = 1;1887r = p;1888while ( r < INT_INTOBJ(q) ) {1889d = d + 1;1890r = r * p;1891}1892if ( r != INT_INTOBJ(q) ) {1893q = ErrorReturnObj(1894"Z: <q> must be a positive prime power (not a %s)",1895(Int)TNAM_OBJ(q), 0L,1896"you can replace <q> via 'return <q>;'" );1897return FuncZ( self, q );1898}18991900/* get the finite field */1901ff = FiniteField( p, d );19021903/* make the root */1904return NEW_FFE( ff, (p == 2 && d == 1 ? 1 : 2) );1905}19061907Obj FuncZ2 ( Obj self, Obj p, Obj d)1908{1909FF ff;1910Int ip,id,id1;1911UInt q;1912if (ARE_INTOBJS(p,d))1913{1914ip = INT_INTOBJ(p);1915id = INT_INTOBJ(d);1916if (ip > 1 && id > 0 && id <= 16 && ip <= 65536)1917{1918id1 = id;1919q = ip;1920while (--id1 > 0 && q <= 65536)1921q *= ip;1922if (q <= 65536)1923{1924/* get the finite field */1925ff = FiniteField( ip, id );19261927/* make the root */1928return NEW_FFE( ff, (ip == 2 && id == 1 ? 1 : 2) );1929}1930}1931}1932return CALL_2ARGS(ZOp, p, d);1933}193419351936/****************************************************************************1937**19381939*F * * * * * * * * * * * * * initialize package * * * * * * * * * * * * * * *1940*/194119421943/****************************************************************************1944**19451946*V GVarFilts . . . . . . . . . . . . . . . . . . . list of filters to export1947*/1948static StructGVarFilt GVarFilts [] = {19491950{ "IS_FFE", "obj", &IsFFEFilt,1951FuncIS_FFE, "src/finifield.c:IS_FFE" },19521953{ 0 }19541955};195619571958/****************************************************************************1959**1960*V GVarFuncs . . . . . . . . . . . . . . . . . . list of functions to export1961*/1962static StructGVarFunc GVarFuncs [] = {19631964{ "CHAR_FFE_DEFAULT", 1, "z",1965FuncCHAR_FFE_DEFAULT, "src/finifield.c:CHAR_FFE_DEFAULT" },19661967{ "DEGREE_FFE_DEFAULT", 1, "z",1968FunDEGREE_FFE_DEFAULT, "src/finifield.c:DEGREE_FFE_DEFAULT" },19691970{ "LOG_FFE_DEFAULT", 2, "z, root",1971FuncLOG_FFE_DEFAULT, "src/finifield.c:LOG_FFE_DEFAULT" },19721973{ "INT_FFE_DEFAULT", 1, "z",1974FuncINT_FFE_DEFAULT, "src/finifield.c:INT_FFE_DEFAULT" },19751976{ "Z", 1, "q",1977FuncZ, "src/finifield.c:Z" },19781979{ 0 }19801981};198219831984/****************************************************************************1985**19861987*F InitKernel( <module> ) . . . . . . . . initialise kernel data structures1988*/1989static Int InitKernel (1990StructInitInfo * module )1991{1992/* install the marking function */1993InfoBags[ T_FFE ].name = "ffe";1994/* InitMarkFuncBags( T_FFE, MarkNoSubBags ); */19951996/* install the type functions */1997ImportFuncFromLibrary( "TYPE_FFE", &TYPE_FFE );1998ImportFuncFromLibrary( "TYPE_FFE0", &TYPE_FFE0 );1999ImportFuncFromLibrary( "ZOp", &ZOp );2000TypeObjFuncs[ T_FFE ] = TypeFFE;20012002/* create the fields and integer conversion bags */2003InitGlobalBag( &CharFF, "src/finfield.c:CharFF" );2004InitGlobalBag( &DegrFF, "src/finfield.c:DegrFF" );2005InitGlobalBag( &SuccFF, "src/finfield.c:SuccFF" );2006InitGlobalBag( &TypeFF, "src/finfield.c:TypeFF" );2007InitGlobalBag( &TypeFF0, "src/finfield.c:TypeFF0" );2008InitGlobalBag( &IntFF, "src/finifield.c:IntFF" );20092010/* install the functions that handle overflow */2011ImportFuncFromLibrary( "SUM_FFE_LARGE", &SUM_FFE_LARGE );2012ImportFuncFromLibrary( "DIFF_FFE_LARGE", &DIFF_FFE_LARGE );2013ImportFuncFromLibrary( "PROD_FFE_LARGE", &PROD_FFE_LARGE );2014ImportFuncFromLibrary( "QUO_FFE_LARGE", &QUO_FFE_LARGE );2015ImportFuncFromLibrary( "LOG_FFE_LARGE", &LOG_FFE_LARGE );20162017/* init filters and functions */2018InitHdlrFiltsFromTable( GVarFilts );2019InitHdlrFuncsFromTable( GVarFuncs );2020InitHandlerFunc( FuncZ2, "src/finfield.c: Z (2 args)");202120222023/* install the printing method */2024PrintObjFuncs[ T_FFE ] = PrFFE;20252026/* install the comparison methods */2027EqFuncs[ T_FFE ][ T_FFE ] = EqFFE;2028LtFuncs[ T_FFE ][ T_FFE ] = LtFFE;20292030/* install the arithmetic methods */2031ZeroFuncs[ T_FFE ] = ZeroFFE;2032ZeroMutFuncs[ T_FFE ] = ZeroFFE;2033AInvFuncs[ T_FFE ] = AInvFFE;2034AInvMutFuncs[ T_FFE ] = AInvFFE;2035OneFuncs [ T_FFE ] = OneFFE;2036OneMutFuncs [ T_FFE ] = OneFFE;2037InvFuncs [ T_FFE ] = InvFFE;2038InvMutFuncs [ T_FFE ] = InvFFE;2039SumFuncs[ T_FFE ][ T_FFE ] = SumFFEFFE;2040SumFuncs[ T_FFE ][ T_INT ] = SumFFEInt;2041SumFuncs[ T_INT ][ T_FFE ] = SumIntFFE;2042DiffFuncs[ T_FFE ][ T_FFE ] = DiffFFEFFE;2043DiffFuncs[ T_FFE ][ T_INT ] = DiffFFEInt;2044DiffFuncs[ T_INT ][ T_FFE ] = DiffIntFFE;2045ProdFuncs[ T_FFE ][ T_FFE ] = ProdFFEFFE;2046ProdFuncs[ T_FFE ][ T_INT ] = ProdFFEInt;2047ProdFuncs[ T_INT ][ T_FFE ] = ProdIntFFE;2048QuoFuncs[ T_FFE ][ T_FFE ] = QuoFFEFFE;2049QuoFuncs[ T_FFE ][ T_INT ] = QuoFFEInt;2050QuoFuncs[ T_INT ][ T_FFE ] = QuoIntFFE;2051PowFuncs[ T_FFE ][ T_INT ] = PowFFEInt;2052PowFuncs[ T_FFE ][ T_FFE ] = PowFFEFFE;20532054/* return success */2055return 0;2056}205720582059/****************************************************************************2060**2061*F InitLibrary( <module> ) . . . . . . . initialise library data structures2062*/2063static Int InitLibrary (2064StructInitInfo * module )2065{2066/* create the fields and integer conversion bags */2067CharFF = NEW_PLIST( T_PLIST, 0 );2068SET_LEN_PLIST( CharFF, 0 );20692070DegrFF = NEW_PLIST( T_PLIST, 0 );2071SET_LEN_PLIST( DegrFF, 0 );20722073SuccFF = NEW_PLIST( T_PLIST, 0 );2074SET_LEN_PLIST( SuccFF, 0 );20752076TypeFF = NEW_PLIST( T_PLIST, 0 );2077SET_LEN_PLIST( TypeFF, 0 );20782079TypeFF0 = NEW_PLIST( T_PLIST, 0 );2080SET_LEN_PLIST( TypeFF0, 0 );20812082IntFF = NEW_PLIST( T_PLIST, 0 );2083SET_LEN_PLIST( IntFF, 0 );20842085/* init filters and functions */2086InitGVarFiltsFromTable( GVarFilts );2087InitGVarFuncsFromTable( GVarFuncs );2088HDLR_FUNC(VAL_GVAR(GVarName("Z")),2) = FuncZ2;20892090/* return success */2091return 0;2092}209320942095/****************************************************************************2096**2097*F InitInfoFinfield() . . . . . . . . . . . . . . . table of init functions2098*/2099static StructInitInfo module = {2100MODULE_BUILTIN, /* type */2101"finfield", /* name */21020, /* revision entry of c file */21030, /* revision entry of h file */21040, /* version */21050, /* crc */2106InitKernel, /* initKernel */2107InitLibrary, /* initLibrary */21080, /* checkInit */21090, /* preSave */21100, /* postSave */21110 /* postRestore */2112};21132114StructInitInfo * InitInfoFinfield ( void )2115{2116return &module;2117}211821192120/****************************************************************************2121**21222123*E finfield.c . . . . . . . . . . . . . . . . . . . . . . . . . . ends here2124*/212521262127