CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In

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

Views: 418346
1
/****************************************************************************
2
**
3
*W cyclotom.c GAP source Martin Schönert
4
**
5
**
6
*Y Copyright (C) 1996, Lehrstuhl D für Mathematik, RWTH Aachen, Germany
7
*Y (C) 1998 School Math and Comp. Sci., University of St Andrews, Scotland
8
*Y Copyright (C) 2002 The GAP Group
9
**
10
** This file implements the arithmetic for elements from cyclotomic fields
11
** $Q(e^{{2 \pi i}/n}) = Q(e_n)$, which we call cyclotomics for short.
12
**
13
** The obvious way to represent cyclotomics is to write them as a polynom in
14
** $e_n$, the primitive <n>th root of unity. However, if we do this it
15
** happens that various polynomials actually represent the same cyclotomic,
16
** e.g., $2+e_3^2 = -2e_3-e_3^2$. This is because, if viewed as a vector
17
** space over the rationals, $Q(e_n)$ has dimension $\phi(n)$ and not $n$.
18
**
19
** This is solved by taking a system of $\phi(n)$ linear independent
20
** vectors, i.e., a base, instead of the $n$ linear dependent roots $e_n^i$,
21
** and writing cyclotomics as linear combinations in those vectors. A
22
** possible base would be the set of $e_n^i$ with $i=0..\phi(n)-1$. In this
23
** representation we have $2+e_3^2 = 1-e_3$.
24
**
25
** However we take a different base. We take the set of roots $e_n^i$ such
26
** that $i \notin (n/q)*[-(q/p-1)/2..(q/p-1)/2]$ mod $q$, for every odd
27
** prime divisor $p$ of $n$, where $q$ is the maximal power of $p$ in $n$,
28
** and $i \notin (n/q)*[q/2..q-1]$, if $q$ is the maximal power of 2 in $n$.
29
** It is not too difficult to see, that this gives in fact $\phi(n)$ roots.
30
**
31
** For example for $n = 45$ we take the roots $e_{45}^i$ such that $i$ is
32
** not congruent to $(45/5)*[-(5/5-1)/2..(5/5-1)/2]$ mod $5$, i.e., is not
33
** divisable by 5, and is not congruent to $(45/9)[-(9/3-1)/2 .. (9/3-1)/2]
34
** = [-5,0,5]$ mod $9$, i.e., $i \in [1,2,3,6,7,8,11,12,16,17,19,21,24,26,
35
** 28,29,33,34,37,38,39,42,43,44]$.
36
**
37
** This base has two properties, which make computing with this base easy.
38
** First we can convert an arbitrary polynom in $e_n$ into this base without
39
** doing polynom arithmetic. This is necessary for the base $e_n^i$ with
40
** $i=0..\phi(n)$, where we have to compute modulo the cyclotomic polynom.
41
** The algorithm for this is given in the description of 'ConvertToBase'.
42
**
43
** It follows from this algorithm that the set of roots is in fact a
44
** generating system, and because the set contains exactly $\phi(n)$ roots
45
** it is also linear independent system, so it is in fact a base. Actually
46
** it is even an integral base, but this is not so easy to prove.
47
**
48
** On the other hand we can test if a cyclotomic lies in fact in a proper
49
** cyclotomic subfield of $Q(e_n)$ and if so reduce it into this field. So
50
** each cyclotomic now has a unique representation in its minimal cyclotomic
51
** field, which makes testing for equality easy. Also a reduced cyclotomic
52
** has less terms than the unreduced cyclotomic, which makes arithmetic
53
** operations, whose effort depends on the number of terms, cheaper.
54
**
55
** For odd $n$ this base is also closed under complex conjugation, i.e.,
56
** complex conjugation just permutes the roots of the base in this case.
57
** This is not possible if $n$ is even for any base. This shows again that
58
** 2 is the oddest of all primes.
59
**
60
** Better descriptions of the base and related topics can be found in:
61
** Matthias Zumbroich,
62
** Grundlagen der Kreisteilungskoerper und deren Implementation in CAS,
63
** Diplomarbeit Mathematik, Lehrstuhl D für Mathematik, RWTH Aachen, 1989
64
**
65
** We represent a cyclotomic with <d> terms, i.e., <d> nonzero coefficients
66
** in the linear combination, by a bag of type 'T_CYC' with <d>+1 subbags
67
** and <d>+1 unsigned short integers. All the bag identifiers are stored at
68
** the beginning of the bag and all unsigned short integers are stored at
69
** the end of the bag.
70
**
71
** +-------+-------+-------+-------+- - - -+----+----+----+----+- - -
72
** | order | coeff | coeff | coeff | | un | exp| exp| exp|
73
** | | 1 | 2 | 3 | |used| 1 | 2 | 3 |
74
** +-------+-------+-------+-------+- - - -+----+----+----+----+- - -
75
**
76
** The first subbag is the order of the primitive root of the cyclotomic
77
** field in which the cyclotomic lies. It is an immediate positive integer,
78
** therefore 'INT_INTOBJ( ADDR_OBJ(<cyc>)[ 0 ] )' gives you the order. The
79
** first unsigned short integer is unused (but reserved for future use :-).
80
**
81
** The other subbags and shorts are paired and each pair describes one term.
82
** The subbag is the coefficient and the unsigned short gives the exponent.
83
** The coefficient will usually be an immediate integer, but could as well
84
** be a large integer or even a rational.
85
**
86
** The terms are sorted with respect to the exponent. Note that none of the
87
** arithmetic functions need this, but it makes the equality test simpler.
88
**
89
** Chnaged the exponent size from 2 to 4 bytes to avoid overflows SL, 2008
90
*/
91
#include "system.h" /* Ints, UInts */
92
93
94
#include "gasman.h" /* garbage collector */
95
#include "objects.h" /* objects */
96
#include "scanner.h" /* scanner */
97
98
#include "gap.h" /* error handling, initialisation */
99
100
#include "gvars.h" /* global variables */
101
102
#include "calls.h" /* generic call mechanism */
103
#include "opers.h" /* generic operations */
104
105
#include "ariths.h" /* basic arithmetic */
106
107
#include "bool.h" /* booleans */
108
109
#include "integer.h" /* integers */
110
111
#include "cyclotom.h" /* cyclotomics */
112
113
#include "records.h" /* generic records */
114
#include "precord.h" /* plain records */
115
116
#include "lists.h" /* generic lists */
117
#include "plist.h" /* plain lists */
118
#include "string.h" /* strings */
119
120
#include "saveload.h" /* saving and loading */
121
122
#include "code.h"
123
#include "tls.h"
124
125
/****************************************************************************
126
**
127
*/
128
#define SIZE_CYC(cyc) (SIZE_OBJ(cyc) / (sizeof(Obj)+sizeof(UInt4)))
129
#define COEFS_CYC(cyc) (ADDR_OBJ(cyc))
130
#define EXPOS_CYC(cyc,len) ((UInt4*)(ADDR_OBJ(cyc)+(len)))
131
#define NOF_CYC(cyc) (COEFS_CYC(cyc)[0])
132
#define XXX_CYC(cyc,len) (EXPOS_CYC(cyc,len)[0])
133
134
135
/****************************************************************************
136
**
137
138
*V ResultCyc . . . . . . . . . . . . temporary buffer for the result, local
139
**
140
** 'ResultCyc' is used by all the arithmetic functions as a buffer for the
141
** result. Unlike bags of type 'T_CYC' it stores the cyclotomics unpacked,
142
** i.e., 'ADDR_OBJ( ResultCyc )[<i+1>]' is the coefficient of $e_n^i$.
143
**
144
** It is created in 'InitCyc' with room for up to 1000 coefficients and is
145
** resized when need arises.
146
*/
147
Obj ResultCyc;
148
149
void GrowResultCyc(UInt size) {
150
Obj *res;
151
UInt i;
152
if ( LEN_PLIST(TLS(ResultCyc)) < size ) {
153
GROW_PLIST( TLS(ResultCyc), size );
154
SET_LEN_PLIST( TLS(ResultCyc), size );
155
res = &(ELM_PLIST( TLS(ResultCyc), 1 ));
156
for ( i = 0; i < size; i++ ) { res[i] = INTOBJ_INT(0); }
157
}
158
}
159
160
/****************************************************************************
161
**
162
*V LastECyc . . . . . . . . . . . . last constructed primitive root, local
163
*V LastNCyc . . . . . . . . order of last constructed primitive root, local
164
**
165
** 'LastECyc' remembers the primitive root that was last constructed by
166
** 'FunE'.
167
**
168
** 'LastNCyc' is the order of this primitive root.
169
**
170
** These values are used in 'FunE' to avoid constructing the same primitive
171
** root over and over again. This might be expensive, because $e_n$ need
172
** itself not belong to the base.
173
**
174
** Also these values are used in 'PowCyc' which thereby can recognize if it
175
** is called to compute $e_n^i$ and can then do this easier by just putting
176
** 1 at the <i>th place in 'ResultCyc' and then calling 'Cyclotomic'.
177
*/
178
Obj LastECyc;
179
UInt LastNCyc;
180
181
182
/****************************************************************************
183
**
184
*F TypeCyc( <cyc> ) . . . . . . . . . . . . . . . . . type of a cyclotomic
185
**
186
** 'TypeCyc' returns the type of a cyclotomic.
187
**
188
** 'TypeCyc' is the function in 'TypeObjFuncs' for cyclotomics.
189
*/
190
Obj TYPE_CYC;
191
192
Obj TypeCyc (
193
Obj cyc )
194
{
195
return TYPE_CYC;
196
}
197
198
199
/****************************************************************************
200
**
201
*F PrintCyc( <cyc> ) . . . . . . . . . . . . . . . . . . print a cyclotomic
202
**
203
** 'PrintCyc' prints the cyclotomic <cyc> in the standard form.
204
**
205
** In principle this is very easy, but it is complicated because we do not
206
** want to print stuff like '+1*', '-1*', 'E(<n>)^0', 'E(<n>)^1, etc.
207
*/
208
void PrintCyc (
209
Obj cyc )
210
{
211
UInt n; /* order of the field */
212
UInt len; /* number of terms */
213
Obj * cfs; /* pointer to the coefficients */
214
UInt4 * exs; /* pointer to the exponents */
215
UInt i; /* loop variable */
216
217
n = INT_INTOBJ( NOF_CYC(cyc) );
218
len = SIZE_CYC(cyc);
219
Pr("%>",0L,0L);
220
for ( i = 1; i < len; i++ ) {
221
/* get pointers, they can change during Pr */
222
cfs = COEFS_CYC(cyc);
223
exs = EXPOS_CYC(cyc,len);
224
if ( cfs[i]==INTOBJ_INT(1) && exs[i]==0 )
225
Pr("1",0L,0L);
226
else if ( cfs[i]==INTOBJ_INT(1) && exs[i]==1 && i==1 )
227
Pr("%>E(%d%<)",n,0L);
228
else if ( cfs[i]==INTOBJ_INT(1) && exs[i]==1 )
229
Pr("%>+E(%d%<)",n,0L);
230
else if ( cfs[i]==INTOBJ_INT(1) && i==1 )
231
Pr("%>E(%d)%>^%2<%d",n,(Int)exs[i]);
232
else if ( cfs[i]==INTOBJ_INT(1) )
233
Pr("%>+E(%d)%>^%2<%d",n,(Int)exs[i]);
234
else if ( LT(INTOBJ_INT(0),cfs[i]) && exs[i]==0 )
235
PrintObj(cfs[i]);
236
else if ( LT(INTOBJ_INT(0),cfs[i]) && exs[i]==1 && i==1 ) {
237
Pr("%>",0L,0L); PrintObj(cfs[i]); Pr("%>*%<E(%d%<)",n,0L); }
238
else if ( LT(INTOBJ_INT(0),cfs[i]) && exs[i]==1 ) {
239
Pr("%>+",0L,0L); PrintObj(cfs[i]); Pr("%>*%<E(%d%<)",n,0L); }
240
else if ( LT(INTOBJ_INT(0),cfs[i]) && i==1 ) {
241
Pr("%>",0L,0L); PrintObj(cfs[i]);
242
Pr("%>*%<E(%d)%>^%2<%d",n,(Int)exs[i]); }
243
else if ( LT(INTOBJ_INT(0),cfs[i]) ) {
244
Pr("%>+",0L,0L); PrintObj(cfs[i]);
245
Pr("%>*%<E(%d)%>^%2<%d",n,(Int)exs[i]); }
246
else if ( cfs[i]==INTOBJ_INT(-1) && exs[i]==0 )
247
Pr("%>-%<1",0L,0L);
248
else if ( cfs[i]==INTOBJ_INT(-1) && exs[i]==1 )
249
Pr("%>-E(%d%<)",n,0L);
250
else if ( cfs[i]==INTOBJ_INT(-1) )
251
Pr("%>-E(%d)%>^%2<%d",n,(Int)exs[i]);
252
else if ( exs[i]==0 )
253
PrintObj(cfs[i]);
254
else if ( exs[i]==1 ) {
255
Pr("%>",0L,0L); PrintObj(cfs[i]); Pr("%>*%<E(%d%<)",n,0L); }
256
else {
257
Pr("%>",0L,0L); PrintObj(cfs[i]);
258
Pr("%>*%<E(%d)%>^%2<%d",n,(Int)exs[i]); }
259
}
260
Pr("%<",0L,0L);
261
}
262
263
264
/****************************************************************************
265
**
266
*F EqCyc( <opL>, <opR> ) . . . . . . . . . test if two cyclotomics are equal
267
**
268
** 'EqCyc' returns 'true' if the two cyclotomics <opL> and <opR> are equal
269
** and 'false' otherwise.
270
**
271
** 'EqCyc' is pretty simple because every cyclotomic has a unique
272
** representation, so we just have to compare the terms.
273
*/
274
Int EqCyc (
275
Obj opL,
276
Obj opR )
277
{
278
UInt len; /* number of terms */
279
Obj * cfl; /* ptr to coeffs of left operand */
280
UInt4 * exl; /* ptr to expnts of left operand */
281
Obj * cfr; /* ptr to coeffs of right operand */
282
UInt4 * exr; /* ptr to expnts of right operand */
283
UInt i; /* loop variable */
284
285
/* compare the order of both fields */
286
if ( NOF_CYC(opL) != NOF_CYC(opR) )
287
return 0L;
288
289
/* compare the number of terms */
290
if ( SIZE_CYC(opL) != SIZE_CYC(opR) )
291
return 0L;
292
293
/* compare the cyclotomics termwise */
294
len = SIZE_CYC(opL);
295
cfl = COEFS_CYC(opL);
296
cfr = COEFS_CYC(opR);
297
exl = EXPOS_CYC(opL,len);
298
exr = EXPOS_CYC(opR,len);
299
for ( i = 1; i < len; i++ ) {
300
if ( exl[i] != exr[i] )
301
return 0L;
302
else if ( ! EQ(cfl[i],cfr[i]) )
303
return 0L;
304
}
305
306
/* all terms are equal */
307
return 1L;
308
}
309
310
311
/****************************************************************************
312
**
313
*F LtCyc( <opL>, <opR> ) . . . . test if one cyclotomic is less than another
314
**
315
** 'LtCyc' returns 'true' if the cyclotomic <opL> is less than the
316
** cyclotomic <opR> and 'false' otherwise.
317
**
318
** Cyclotomics are first sorted according to the order of the primitive root
319
** they are written in. That means that the rationals are smallest, then
320
** come cyclotomics from $Q(e_3)$ followed by cyclotomics from $Q(e_4)$ etc.
321
** Cyclotomics from the same field are sorted lexicographicaly with respect
322
** to their representation in the base of this field. That means that the
323
** cyclotomic with smaller coefficient for the first base root is smaller,
324
** for cyclotomics with the same first coefficient the second decides which
325
** is smaller, etc.
326
**
327
** 'LtCyc' is pretty simple because every cyclotomic has a unique
328
** representation, so we just have to compare the terms.
329
*/
330
Int LtCyc (
331
Obj opL,
332
Obj opR )
333
{
334
UInt lel; /* nr of terms of left operand */
335
Obj * cfl; /* ptr to coeffs of left operand */
336
UInt4 * exl; /* ptr to expnts of left operand */
337
UInt ler; /* nr of terms of right operand */
338
Obj * cfr; /* ptr to coeffs of right operand */
339
UInt4 * exr; /* ptr to expnts of right operand */
340
UInt i; /* loop variable */
341
342
/* compare the order of both fields */
343
if ( NOF_CYC(opL) != NOF_CYC(opR) ) {
344
if ( INT_INTOBJ( NOF_CYC(opL) ) < INT_INTOBJ( NOF_CYC(opR) ) )
345
return 1L;
346
else
347
return 0L;
348
}
349
350
/* compare the cyclotomics termwise */
351
lel = SIZE_CYC(opL);
352
ler = SIZE_CYC(opR);
353
cfl = COEFS_CYC(opL);
354
cfr = COEFS_CYC(opR);
355
exl = EXPOS_CYC(opL,lel);
356
exr = EXPOS_CYC(opR,ler);
357
for ( i = 1; i < lel && i < ler; i++ ) {
358
if ( exl[i] != exr[i] )
359
if ( exl[i] < exr[i] )
360
return LT( cfl[i], INTOBJ_INT(0) );
361
else
362
return LT( INTOBJ_INT(0), cfr[i] );
363
else if ( ! EQ(cfl[i],cfr[i]) )
364
return LT( cfl[i], cfr[i] );
365
}
366
367
/* if one cyclotomic has more terms than the other compare it agains 0 */
368
if ( lel < ler )
369
return LT( INTOBJ_INT(0), cfr[i] );
370
else if ( ler < lel )
371
return LT( cfl[i], INTOBJ_INT(0) );
372
else
373
return 0L;
374
}
375
376
Int LtCycYes (
377
Obj opL,
378
Obj opR )
379
{
380
return 1L;
381
}
382
383
Int LtCycNot (
384
Obj opL,
385
Obj opR )
386
{
387
return 0L;
388
}
389
390
391
/****************************************************************************
392
**
393
*F ConvertToBase(<n>) . . . . . . convert a cyclotomic into the base, local
394
**
395
** 'ConvertToBase' converts the cyclotomic 'TLS(ResultCyc)' from the cyclotomic
396
** field of <n>th roots of unity, into the base form. This means that it
397
** replaces every root $e_n^i$ that does not belong to the base by a sum of
398
** other roots that do.
399
**
400
** Suppose that $c*e_n^i$ appears in 'TLS(ResultCyc)' but $e_n^i$ does not lie in
401
** the base. This happens because, for some prime $p$ dividing $n$, with
402
** maximal power $q$, $i \in (n/q)*[-(q/p-1)/2..(q/p-1)/2]$ mod $q$.
403
**
404
** We take the identity $1+e_p+e_p^2+..+e_p^{p-1}=0$, write it using $n$th
405
** roots of unity, $0=1+e_n^{n/p}+e_n^{2n/p}+..+e_n^{(p-1)n/p}$ and multiply
406
** it by $e_n^i$, $0=e_n^i+e_n^{n/p+i}+e_n^{2n/p+i}+..+e_n^{(p-1)n/p+i}$.
407
** Now we subtract $c$ times the left hand side from 'TLS(ResultCyc)'.
408
**
409
** If $p^2$ does not divide $n$ then the roots that are not in the base
410
** because of $p$ are those whose exponent is divisable by $p$. But $n/p$
411
** is not divisable by $p$, so neither of the exponent $k*n/p+i, k=1..p-1$
412
** is divisable by $p$, so those new roots are acceptable w.r.t. $p$.
413
**
414
** A similar argument shows that the new roots are also acceptable w.r.t.
415
** $p$ even if $p^2$ divides $n$...
416
**
417
** Note that the new roots might still not lie in the case because of some
418
** other prime $p2$. However, because $i = k*n/p+i$ mod $p2$, this can only
419
** happen if $e_n^i$ did also not lie in the base because of $p2$. So if we
420
** remove all roots that lie in the base because of $p$, the later steps,
421
** which remove the roots that are not in the base because of larger primes,
422
** will not add new roots that do not lie in the base because of $p$ again.
423
**
424
** For an example, suppose 'TLS(ResultCyc)' is $e_{45}+e_{45}^5 =: e+e^5$. $e^5$
425
** does not lie in the base because $5 \in 5*[-1,0,1]$ mod $9$ and also
426
** because it is divisable by 5. After subtracting $e^5*(1+e_3+e_3^2) =
427
** e^5+e^{20}+e^{35}$ from 'TLS(ResultCyc)' we get $e-e^{20}-e^{35}$. Those two
428
** roots are still not in the base because of 5. But after subtracting
429
** $-e^{20}*(1+e_5+e_5^2+e_5^3+e_5^4)=-e^{20}-e^{29}-e^{38}-e^2-e^{11}$ and
430
** $-e^{35}*(1+e_5+e_5^2+e_5^3+e_5^4)=-e^{35}-e^{44}-e^8-e^{17}-e^{26}$ we
431
** get $e+e^{20}+e^{29}+e^{38}+e^2+e^{11}+e^{35}+e^{44}+e^8+e^{17}+e^{26}$,
432
** which contains only roots that lie in the base.
433
**
434
** 'ConvertToBase' and 'Cyclotomic' are the functions that know about the
435
** structure of the base. 'EqCyc' and 'LtCyc' only need the property that
436
** the representation of all cyclotomic integers is unique. All other
437
** functions dont even require that cyclotomics are written as a linear
438
** combination of linear independent roots, they would work also if
439
** cyclotomic integers were written as polynomials in $e_n$.
440
**
441
** The inner loops in this function have been duplicated to avoid using the
442
** modulo ('%') operator to reduce the exponents into the range $0..n-1$.
443
** Those divisions are quite expensive on some processors, e.g., MIPS and
444
** SPARC, and they may singlehanded account for 20 percent of the runtime.
445
*/
446
void ConvertToBase (
447
UInt n )
448
{
449
Obj * res; /* pointer to the result */
450
UInt nn; /* copy of n to factorize */
451
UInt p, q; /* prime and prime power */
452
UInt i, k, l; /* loop variables */
453
UInt t; /* temporary holds n+i+(n/p-n/q)/2 */
454
Obj sum; /* sum of two coefficients */
455
456
/* get a pointer to the cyclotomic and a copy of n to factor */
457
res = &(ELM_PLIST( TLS(ResultCyc), 1 ));
458
nn = n;
459
460
/* first handle 2 */
461
if ( nn % 2 == 0 ) {
462
q = 2; while ( nn % (2*q) == 0 ) q = 2*q;
463
nn = nn / q;
464
465
/* get rid of all terms e^{a*q+b*(n/q)} a=0..(n/q)-1 b=q/2..q-1 */
466
for ( i = 0; i < n; i += q ) {
467
t = i + (n/q)*(q-1) + n/q; /* end (n <= t < 2n) */
468
k = i + (n/q)*(q/2); /* start (0 <= k <= t) */
469
for ( ; k < n; k += n/q ) {
470
if ( res[k] != INTOBJ_INT(0) ) {
471
l = (k + n/2) % n;
472
if ( ! ARE_INTOBJS( res[l], res[k] )
473
|| ! DIFF_INTOBJS( sum, res[l], res[k] ) ) {
474
CHANGED_BAG( TLS(ResultCyc) );
475
sum = DIFF( res[l], res[k] );
476
res = &(ELM_PLIST( TLS(ResultCyc), 1 ));
477
}
478
res[l] = sum;
479
res[k] = INTOBJ_INT(0);
480
}
481
}
482
t = t - n; /* end (0 <= t < n) */
483
k = k - n; /* cont. (0 <= k ) */
484
for ( ; k < t; k += n/q ) {
485
if ( res[k] != INTOBJ_INT(0) ) {
486
l = (k + n/2) % n;
487
if ( ! ARE_INTOBJS( res[l], res[k] )
488
|| ! DIFF_INTOBJS( sum, res[l], res[k] ) ) {
489
CHANGED_BAG( TLS(ResultCyc) );
490
sum = DIFF( res[l], res[k] );
491
res = &(ELM_PLIST( TLS(ResultCyc), 1 ));
492
}
493
res[l] = sum;
494
res[k] = INTOBJ_INT(0);
495
}
496
}
497
}
498
}
499
500
/* now handle the odd primes */
501
for ( p = 3; p <= nn; p += 2 ) {
502
if ( nn % p != 0 ) continue;
503
q = p; while ( nn % (p*q) == 0 ) q = p*q;
504
nn = nn / q;
505
506
/* get rid of e^{a*q+b*(n/q)} a=0..(n/q)-1 b=-(q/p-1)/2..(q/p-1)/2 */
507
for ( i = 0; i < n; i += q ) {
508
if ( n <= i+(n/p-n/q)/2 ) {
509
t = i + (n/p-n/q)/2; /* end (n <= t < 2n) */
510
k = i - (n/p-n/q)/2; /* start (t-n <= k <= t) */
511
}
512
else {
513
t = i + (n/p-n/q)/2+n; /* end (n <= t < 2n) */
514
k = i - (n/p-n/q)/2+n; /* start (t-n <= k <= t) */
515
}
516
for ( ; k < n; k += n/q ) {
517
if ( res[k] != INTOBJ_INT(0) ) {
518
for ( l = k+n/p; l < k+n; l += n/p ) {
519
if ( ! ARE_INTOBJS( res[l%n], res[k] )
520
|| ! DIFF_INTOBJS( sum, res[l%n], res[k] ) ) {
521
CHANGED_BAG( TLS(ResultCyc) );
522
sum = DIFF( res[l%n], res[k] );
523
res = &(ELM_PLIST( TLS(ResultCyc), 1 ));
524
}
525
res[l%n] = sum;
526
}
527
res[k] = INTOBJ_INT(0);
528
}
529
}
530
t = t - n; /* end (0 <= t < n) */
531
k = k - n; /* start (0 <= k ) */
532
for ( ; k <= t; k += n/q ) {
533
if ( res[k] != INTOBJ_INT(0) ) {
534
for ( l = k+n/p; l < k+n; l += n/p ) {
535
if ( ! ARE_INTOBJS( res[l%n], res[k] )
536
|| ! DIFF_INTOBJS( sum, res[l%n], res[k] ) ) {
537
CHANGED_BAG( TLS(ResultCyc) );
538
sum = DIFF( res[l%n], res[k] );
539
res = &(ELM_PLIST( TLS(ResultCyc), 1 ));
540
}
541
res[l%n] = sum;
542
}
543
res[k] = INTOBJ_INT(0);
544
}
545
}
546
}
547
}
548
549
/* notify Gasman */
550
CHANGED_BAG( TLS(ResultCyc) );
551
}
552
553
554
/****************************************************************************
555
**
556
*F Cyclotomic(<n>,<m>) . . . . . . . . . . create a packed cyclotomic, local
557
**
558
** 'Cyclotomic' reduces the cyclotomic 'TLS(ResultCyc)' into the smallest
559
** possible cyclotomic subfield and returns it in packed form.
560
**
561
** 'TLS(ResultCyc)' must also be already converted into the base by
562
** 'ConvertToBase'. <n> must be the order of the primitive root in which
563
** written.
564
**
565
** <m> must be a divisor of $n$ and gives a hint about possible subfields.
566
** If a prime $p$ divides <m> then no reduction into a subfield whose order
567
** is $n / p$ is possible. In the arithmetic functions you can take
568
** $lcm(n_l,n_r) / gcd(n_l,n_r) = n / gcd(n_l,n_r)$. If you can not provide
569
** such a hint just pass 1.
570
**
571
** A special case of the reduction is the case that the cyclotomic is a
572
** rational. If this is the case 'Cyclotomic' reduces it into the rationals
573
** and returns it as a rational.
574
**
575
** After 'Cyclotomic' has done its work it clears the 'TLS(ResultCyc)' bag, so
576
** that it only contains 'INTOBJ_INT(0)'. Thus the arithmetic functions can
577
** use this buffer without clearing it first.
578
**
579
** 'ConvertToBase' and 'Cyclotomic' are the functions that know about the
580
** structure of the base. 'EqCyc' and 'LtCyc' only need the property that
581
** the representation of all cyclotomic integers is unique. All other
582
** functions dont even require that cyclotomics are written as a linear
583
** combination of linear independent roots, they would work also if
584
** cyclotomic integers were written as polynomials in $e_n$.
585
*/
586
Obj Cyclotomic (
587
UInt n,
588
UInt m )
589
{
590
Obj cyc; /* cyclotomic, result */
591
UInt len; /* number of terms */
592
Obj * cfs; /* pointer to the coefficients */
593
UInt4 * exs; /* pointer to the exponents */
594
Obj * res; /* pointer to the result */
595
UInt gcd, s, t; /* gcd of the exponents, temporary */
596
UInt eql; /* are all coefficients equal? */
597
Obj cof; /* if so this is the coefficient */
598
UInt i, k; /* loop variables */
599
UInt nn; /* copy of n to factorize */
600
UInt p; /* prime factor */
601
static UInt lastN; /* rember last n, dont recompute: */
602
static UInt phi; /* Euler phi(n) */
603
static UInt isSqfree; /* is n squarefree? */
604
static UInt nrp; /* number of its prime factors */
605
606
/* get a pointer to the cyclotomic and a copy of n to factor */
607
res = &(ELM_PLIST( TLS(ResultCyc), 1 ));
608
609
/* count the terms and compute the gcd of the exponents with n */
610
len = 0;
611
gcd = n;
612
eql = 1;
613
cof = 0;
614
for ( i = 0; i < n; i++ ) {
615
if ( res[i] != INTOBJ_INT(0) ) {
616
len++;
617
if ( gcd != 1 ) {
618
s = i; while ( s != 0 ) { t = s; s = gcd % s; gcd = t; }
619
}
620
if ( eql && cof == 0 )
621
cof = res[i];
622
else if ( eql && ! EQ(cof,res[i]) )
623
eql = 0;
624
}
625
}
626
627
/* if all exps are divisable 1 < k replace $e_n^i$ by $e_{n/k}^{i/k}$ */
628
/* this is the only way a prime whose square divides $n$ could reduce */
629
if ( 1 < gcd ) {
630
for ( i = 1; i < n/gcd; i++ ) {
631
res[i] = res[i*gcd];
632
res[i*gcd] = INTOBJ_INT(0);
633
}
634
n = n / gcd;
635
}
636
637
/* compute $phi(n)$, test if n is squarefree, compute number of primes */
638
if ( n != lastN ) {
639
lastN = n;
640
phi = n; k = n;
641
isSqfree = 1;
642
nrp = 0;
643
for ( p = 2; p <= k; p++ ) {
644
if ( k % p == 0 ) {
645
phi = phi * (p-1) / p;
646
if ( k % (p*p) == 0 ) isSqfree = 0;
647
nrp++;
648
while ( k % p == 0 ) k = k / p;
649
}
650
}
651
}
652
653
/* if possible reduce into the rationals, clear buffer bag */
654
if ( len == phi && eql && isSqfree ) {
655
for ( i = 0; i < n; i++ )
656
res[i] = INTOBJ_INT(0);
657
/* return as rational $(-1)^{number primes}*{common coefficient}$ */
658
if ( nrp % 2 == 0 )
659
res[0] = cof;
660
else {
661
CHANGED_BAG( TLS(ResultCyc) );
662
res[0] = DIFF( INTOBJ_INT(0), cof );
663
}
664
n = 1;
665
}
666
CHANGED_BAG( TLS(ResultCyc) );
667
668
/* for all primes $p$ try to reduce from $Q(e_n)$ into $Q(e_{n/p})$ */
669
gcd = phi; s = len; while ( s != 0 ) { t = s; s = gcd % s; gcd = t; }
670
nn = n;
671
for ( p = 3; p <= nn && p-1 <= gcd; p += 2 ) {
672
if ( nn % p != 0 ) continue;
673
nn = nn / p; while ( nn % p == 0 ) nn = nn / p;
674
675
/* if $p$ is not quadratic and the number of terms is divisiable */
676
/* $p-1$ and $p$ divides $m$ not then a reduction is possible */
677
if ( n % (p*p) != 0 && len % (p-1) == 0 && m % p != 0 ) {
678
679
/* test that coeffs for expnts congruent mod $n/p$ are equal */
680
eql = 1;
681
for ( i = 0; i < n && eql; i += p ) {
682
cof = res[(i+n/p)%n];
683
for ( k = i+2*n/p; k < i+n && eql; k += n/p )
684
if ( ! EQ(res[k%n],cof) )
685
eql = 0;
686
}
687
688
/* if all coeffs for expnts in all classes are equal reduce */
689
if ( eql ) {
690
691
/* replace every sum of $p-1$ terms with expnts congruent */
692
/* to $i*p$ mod $n/p$ by the term with exponent $i*p$ */
693
/* is just the inverse transformation of 'ConvertToBase' */
694
for ( i = 0; i < n; i += p ) {
695
cof = res[(i+n/p)%n];
696
res[i] = INTOBJ_INT( - INT_INTOBJ(cof) );
697
if ( ! IS_INTOBJ(cof)
698
|| (cof == INTOBJ_INT(-(1L<<NR_SMALL_INT_BITS))) ) {
699
CHANGED_BAG( TLS(ResultCyc) );
700
cof = DIFF( INTOBJ_INT(0), cof );
701
res = &(ELM_PLIST( TLS(ResultCyc), 1 ));
702
res[i] = cof;
703
}
704
for ( k = i+n/p; k < i+n && eql; k += n/p )
705
res[k%n] = INTOBJ_INT(0);
706
}
707
len = len / (p-1);
708
CHANGED_BAG( TLS(ResultCyc) );
709
710
/* now replace $e_n^{i*p}$ by $e_{n/p}^{i}$ */
711
for ( i = 1; i < n/p; i++ ) {
712
res[i] = res[i*p];
713
res[i*p] = INTOBJ_INT(0);
714
}
715
n = n / p;
716
717
}
718
719
}
720
721
}
722
723
/* if the cyclotomic is a rational return it as a rational */
724
if ( n == 1 ) {
725
cyc = res[0];
726
res[0] = INTOBJ_INT(0);
727
}
728
729
/* otherwise copy terms into a new 'T_CYC' bag and clear 'TLS(ResultCyc)' */
730
else {
731
cyc = NewBag( T_CYC, (len+1)*(sizeof(Obj)+sizeof(UInt4)) );
732
cfs = COEFS_CYC(cyc);
733
exs = EXPOS_CYC(cyc,len+1);
734
cfs[0] = INTOBJ_INT(n);
735
exs[0] = 0;
736
k = 1;
737
res = &(ELM_PLIST( TLS(ResultCyc), 1 ));
738
for ( i = 0; i < n; i++ ) {
739
if ( res[i] != INTOBJ_INT(0) ) {
740
cfs[k] = res[i];
741
exs[k] = i;
742
k++;
743
res[i] = INTOBJ_INT(0);
744
}
745
}
746
/* 'CHANGED_BAG' not needed for last bag */
747
}
748
749
/* return the result */
750
return cyc;
751
}
752
753
/****************************************************************************
754
**
755
*F find smallest field size containing CF(nl) and CF(nr)
756
** Also adjusts the results bag to ensure that it is big enough
757
** returns the field size n, and sets *ml and *mr to n/nl and n/nr
758
** respectively.
759
*/
760
761
UInt4 CyclotomicsLimit = 1000000;
762
763
static UInt FindCommonField(UInt nl, UInt nr, UInt *ml, UInt *mr)
764
{
765
UInt n,a,b,c;
766
UInt8 n8;
767
768
/* get the smallest field that contains both cyclotomics */
769
/* First Euclid's Algorithm for gcd */
770
if (nl > nr) {
771
a = nl;
772
b = nr;
773
} else {
774
a = nr;
775
b = nl;
776
}
777
while (b > 0) {
778
c = a % b;
779
a = b;
780
b = c;
781
}
782
*ml = nr/a;
783
/* Compute the result (lcm) in 64 bit */
784
n8 = (UInt8)nl * ((UInt8)*ml);
785
/* Check if it is too large for a small int */
786
if (n8 > ((UInt8)(1) << NR_SMALL_INT_BITS))
787
ErrorMayQuit("This computation would require a cyclotomic field too large to be handled",0L, 0L);
788
789
/* Switch to UInt now we know we can*/
790
n = (UInt)n8;
791
792
/* Handle the soft limit */
793
while (n > CyclotomicsLimit) {
794
ErrorReturnVoid("This computation requires a cyclotomic field of degree %d, larger than the current limit of %d", n, (Int)CyclotomicsLimit, "You may return after raising the limit with SetCyclotomicsLimit");
795
}
796
797
/* Finish up */
798
*mr = n/nr;
799
800
/* make sure that the result bag is large enough */
801
GrowResultCyc(n);
802
return n;
803
}
804
805
Obj FuncSetCyclotomicsLimit(Obj self, Obj NewLimit) {
806
UInt ok;
807
Int limit;
808
UInt ulimit;
809
do {
810
ok = 1;
811
if (!IS_INTOBJ(NewLimit)) {
812
ok = 0;
813
NewLimit = ErrorReturnObj("Cyclotomic Field size limit must be a small integer, not a %s ",(Int)TNAM_OBJ(NewLimit), 0L, "You can return a new value");
814
} else {
815
limit = INT_INTOBJ(NewLimit);
816
if (limit <= 0) {
817
ok = 0;
818
NewLimit = ErrorReturnObj("Cyclotomic Field size limit must be positive",0L, 0L, "You can return a new value");
819
} else {
820
ulimit = limit;
821
if (ulimit < CyclotomicsLimit) {
822
ok = 0;
823
NewLimit = ErrorReturnObj("Cyclotomic Field size limit must not be less than old limit of %d",CyclotomicsLimit, 0L, "You can return a new value");
824
}
825
#ifdef SYS_IS_64_BIT
826
else if (ulimit > (1L << 32)) {
827
ok = 0;
828
NewLimit = ErrorReturnObj("Cyclotomic field size limit must be less than 2^32", 0L, 0L, "You can return a new value");
829
}
830
#endif
831
832
}
833
}
834
} while (!ok);
835
CyclotomicsLimit = ulimit;
836
return (Obj) 0L;
837
}
838
839
Obj FuncGetCyclotomicsLimit( Obj self) {
840
return INTOBJ_INT(CyclotomicsLimit);
841
}
842
843
/****************************************************************************
844
**
845
*F SumCyc( <opL>, <opR> ) . . . . . . . . . . . . . sum of two cyclotomics
846
**
847
** 'SumCyc' returns the sum of the two cyclotomics <opL> and <opR>.
848
** Either operand may also be an integer or a rational.
849
**
850
** This function is lengthy because we try to use immediate integer
851
** arithmetic if possible to avoid the function call overhead.
852
*/
853
Obj SumCyc (
854
Obj opL,
855
Obj opR )
856
{
857
UInt nl, nr; /* order of left and right field */
858
UInt n; /* order of smallest superfield */
859
UInt ml, mr; /* cofactors into the superfield */
860
UInt len; /* number of terms */
861
Obj * cfs; /* pointer to the coefficients */
862
UInt4 * exs; /* pointer to the exponents */
863
Obj * res; /* pointer to the result */
864
Obj sum; /* sum of two coefficients */
865
UInt i; /* loop variable */
866
867
/* take the cyclotomic with less terms as the right operand */
868
if ( TNUM_OBJ(opL) != T_CYC
869
|| (TNUM_OBJ(opR) == T_CYC && SIZE_CYC(opL) < SIZE_CYC(opR)) ) {
870
sum = opL; opL = opR; opR = sum;
871
}
872
873
nl = (TNUM_OBJ(opL) != T_CYC ? 1 : INT_INTOBJ( NOF_CYC(opL) ));
874
nr = (TNUM_OBJ(opR) != T_CYC ? 1 : INT_INTOBJ( NOF_CYC(opR) ));
875
876
n = FindCommonField(nl, nr, &ml, &mr);
877
878
/* Copy the left operand into the result */
879
if ( TNUM_OBJ(opL) != T_CYC ) {
880
res = &(ELM_PLIST( TLS(ResultCyc), 1 ));
881
res[0] = opL;
882
CHANGED_BAG( TLS(ResultCyc) );
883
}
884
else {
885
len = SIZE_CYC(opL);
886
cfs = COEFS_CYC(opL);
887
exs = EXPOS_CYC(opL,len);
888
res = &(ELM_PLIST( TLS(ResultCyc), 1 ));
889
if ( ml == 1 ) {
890
for ( i = 1; i < len; i++ )
891
res[exs[i]] = cfs[i];
892
}
893
else {
894
for ( i = 1; i < len; i++ )
895
res[exs[i]*ml] = cfs[i];
896
}
897
CHANGED_BAG( TLS(ResultCyc) );
898
}
899
900
/* add the right operand to the result */
901
if ( TNUM_OBJ(opR) != T_CYC ) {
902
res = &(ELM_PLIST( TLS(ResultCyc), 1 ));
903
sum = SUM( res[0], opR );
904
res = &(ELM_PLIST( TLS(ResultCyc), 1 ));
905
res[0] = sum;
906
CHANGED_BAG( TLS(ResultCyc) );
907
}
908
else {
909
len = SIZE_CYC(opR);
910
cfs = COEFS_CYC(opR);
911
exs = EXPOS_CYC(opR,len);
912
res = &(ELM_PLIST( TLS(ResultCyc), 1 ));
913
for ( i = 1; i < len; i++ ) {
914
if ( ! ARE_INTOBJS( res[exs[i]*mr], cfs[i] )
915
|| ! SUM_INTOBJS( sum, res[exs[i]*mr], cfs[i] ) ) {
916
CHANGED_BAG( TLS(ResultCyc) );
917
sum = SUM( res[exs[i]*mr], cfs[i] );
918
cfs = COEFS_CYC(opR);
919
exs = EXPOS_CYC(opR,len);
920
res = &(ELM_PLIST( TLS(ResultCyc), 1 ));
921
}
922
res[exs[i]*mr] = sum;
923
}
924
CHANGED_BAG( TLS(ResultCyc) );
925
}
926
927
/* return the base reduced packed cyclotomic */
928
if ( nl % ml != 0 || nr % mr != 0 ) ConvertToBase( n );
929
return Cyclotomic( n, ml * mr );
930
}
931
932
933
/****************************************************************************
934
**
935
*F ZeroCyc( <op> ) . . . . . . . . . . . . . . . . . . zero of a cyclotomic
936
**
937
** 'ZeroCyc' returns the additive neutral element of the cyclotomic <op>.
938
*/
939
Obj ZeroCyc (
940
Obj op )
941
{
942
return INTOBJ_INT( 0L );
943
}
944
945
946
/****************************************************************************
947
**
948
*F AInvCyc( <op> ) . . . . . . . . . . . . additive inverse of a cyclotomic
949
**
950
** 'AInvCyc' returns the additive inverse element of the cyclotomic <op>.
951
*/
952
Obj AInvCyc (
953
Obj op )
954
{
955
Obj res; /* inverse, result */
956
UInt len; /* number of terms */
957
Obj * cfs; /* ptr to coeffs of left operand */
958
UInt4 * exs; /* ptr to expnts of left operand */
959
Obj * cfp; /* ptr to coeffs of product */
960
UInt4 * exp; /* ptr to expnts of product */
961
UInt i; /* loop variable */
962
Obj prd; /* product of two coefficients */
963
964
/* simply invert the coefficients */
965
res = NewBag( T_CYC, SIZE_CYC(op) * (sizeof(Obj)+sizeof(UInt4)) );
966
NOF_CYC(res) = NOF_CYC(op);
967
len = SIZE_CYC(op);
968
cfs = COEFS_CYC(op);
969
cfp = COEFS_CYC(res);
970
exs = EXPOS_CYC(op,len);
971
exp = EXPOS_CYC(res,len);
972
for ( i = 1; i < len; i++ ) {
973
prd = INTOBJ_INT( - INT_INTOBJ(cfs[i]) );
974
if ( ! IS_INTOBJ( cfs[i] ) ||
975
cfs[i] == INTOBJ_INT(-(1L<<NR_SMALL_INT_BITS)) ) {
976
CHANGED_BAG( res );
977
prd = AINV( cfs[i] );
978
cfs = COEFS_CYC(op);
979
cfp = COEFS_CYC(res);
980
exs = EXPOS_CYC(op,len);
981
exp = EXPOS_CYC(res,len);
982
}
983
cfp[i] = prd;
984
exp[i] = exs[i];
985
}
986
CHANGED_BAG( res );
987
988
/* return the result */
989
return res;
990
}
991
992
993
/****************************************************************************
994
**
995
*F DiffCyc( <opL>, <opR> ) . . . . . . . . . . difference of two cyclotomics
996
**
997
** 'DiffCyc' returns the difference of the two cyclotomic <opL> and <opR>.
998
** Either operand may also be an integer or a rational.
999
**
1000
** This function is lengthy because we try to use immediate integer
1001
** arithmetic if possible to avoid the function call overhead.
1002
*/
1003
Obj DiffCyc (
1004
Obj opL,
1005
Obj opR )
1006
{
1007
UInt nl, nr; /* order of left and right field */
1008
UInt n; /* order of smallest superfield */
1009
UInt ml, mr; /* cofactors into the superfield */
1010
UInt len; /* number of terms */
1011
Obj * cfs; /* pointer to the coefficients */
1012
UInt4 * exs; /* pointer to the exponents */
1013
Obj * res; /* pointer to the result */
1014
Obj sum; /* difference of two coefficients */
1015
UInt i; /* loop variable */
1016
1017
/* get the smallest field that contains both cyclotomics */
1018
nl = (TNUM_OBJ(opL) != T_CYC ? 1 : INT_INTOBJ( NOF_CYC(opL) ));
1019
nr = (TNUM_OBJ(opR) != T_CYC ? 1 : INT_INTOBJ( NOF_CYC(opR) ));
1020
n = FindCommonField(nl, nr, &ml, &mr);
1021
1022
/* copy the left operand into the result */
1023
if ( TNUM_OBJ(opL) != T_CYC ) {
1024
res = &(ELM_PLIST( TLS(ResultCyc), 1 ));
1025
res[0] = opL;
1026
CHANGED_BAG( TLS(ResultCyc) );
1027
}
1028
else {
1029
len = SIZE_CYC(opL);
1030
cfs = COEFS_CYC(opL);
1031
exs = EXPOS_CYC(opL,len);
1032
res = &(ELM_PLIST( TLS(ResultCyc), 1 ));
1033
if ( ml == 1 ) {
1034
for ( i = 1; i < len; i++ )
1035
res[exs[i]] = cfs[i];
1036
}
1037
else {
1038
for ( i = 1; i < len; i++ )
1039
res[exs[i]*ml] = cfs[i];
1040
}
1041
CHANGED_BAG( TLS(ResultCyc) );
1042
}
1043
1044
/* subtract the right operand from the result */
1045
if ( TNUM_OBJ(opR) != T_CYC ) {
1046
res = &(ELM_PLIST( TLS(ResultCyc), 1 ));
1047
sum = DIFF( res[0], opR );
1048
res = &(ELM_PLIST( TLS(ResultCyc), 1 ));
1049
res[0] = sum;
1050
CHANGED_BAG( TLS(ResultCyc) );
1051
}
1052
else {
1053
len = SIZE_CYC(opR);
1054
cfs = COEFS_CYC(opR);
1055
exs = EXPOS_CYC(opR,len);
1056
res = &(ELM_PLIST( TLS(ResultCyc), 1 ));
1057
for ( i = 1; i < len; i++ ) {
1058
if ( ! ARE_INTOBJS( res[exs[i]*mr], cfs[i] )
1059
|| ! DIFF_INTOBJS( sum, res[exs[i]*mr], cfs[i] ) ) {
1060
CHANGED_BAG( TLS(ResultCyc) );
1061
sum = DIFF( res[exs[i]*mr], cfs[i] );
1062
cfs = COEFS_CYC(opR);
1063
exs = EXPOS_CYC(opR,len);
1064
res = &(ELM_PLIST( TLS(ResultCyc), 1 ));
1065
}
1066
res[exs[i]*mr] = sum;
1067
}
1068
CHANGED_BAG( TLS(ResultCyc) );
1069
}
1070
1071
/* return the base reduced packed cyclotomic */
1072
if ( nl % ml != 0 || nr % mr != 0 ) ConvertToBase( n );
1073
return Cyclotomic( n, ml * mr );
1074
}
1075
1076
1077
/****************************************************************************
1078
**
1079
*F ProdCycInt( <opL>, <opR> ) . . . product of a cyclotomic and an integer
1080
**
1081
** 'ProdCycInt' returns the product of a cyclotomic and a integer or
1082
** rational. Which operand is the cyclotomic and wich the integer does not
1083
** matter.
1084
**
1085
** This is a special case, because if the integer is not 0, the product will
1086
** automatically be base reduced. So we dont need to call 'ConvertToBase'
1087
** or 'Reduce' and directly write into a result bag.
1088
**
1089
** This function is lengthy because we try to use immediate integer
1090
** arithmetic if possible to avoid the function call overhead.
1091
*/
1092
Obj ProdCycInt (
1093
Obj opL,
1094
Obj opR )
1095
{
1096
Obj hdP; /* product, result */
1097
UInt len; /* number of terms */
1098
Obj * cfs; /* ptr to coeffs of left operand */
1099
UInt4 * exs; /* ptr to expnts of left operand */
1100
Obj * cfp; /* ptr to coeffs of product */
1101
UInt4 * exp; /* ptr to expnts of product */
1102
UInt i; /* loop variable */
1103
Obj prd; /* product of two coefficients */
1104
1105
/* for $rat * rat$ delegate */
1106
if ( TNUM_OBJ(opL) != T_CYC && TNUM_OBJ(opR) != T_CYC ) {
1107
return PROD( opL, opR );
1108
}
1109
1110
/* make the right operand the non cyclotomic */
1111
if ( TNUM_OBJ(opL) != T_CYC ) { hdP = opL; opL = opR; opR = hdP; }
1112
1113
/* for $cyc * 0$ return 0 and for $cyc * 1$ return $cyc$ */
1114
if ( opR == INTOBJ_INT(0) ) {
1115
hdP = INTOBJ_INT(0);
1116
}
1117
else if ( opR == INTOBJ_INT(1) ) {
1118
hdP = opL;
1119
}
1120
1121
/* for $cyc * -1$ need no multiplication or division */
1122
else if ( opR == INTOBJ_INT(-1) ) {
1123
return AInvCyc( opL );
1124
}
1125
1126
/* for $cyc * small$ use immediate multiplication if possible */
1127
else if ( TNUM_OBJ(opR) == T_INT ) {
1128
hdP = NewBag( T_CYC, SIZE_CYC(opL) * (sizeof(Obj)+sizeof(UInt4)) );
1129
NOF_CYC(hdP) = NOF_CYC(opL);
1130
len = SIZE_CYC(opL);
1131
cfs = COEFS_CYC(opL);
1132
cfp = COEFS_CYC(hdP);
1133
exs = EXPOS_CYC(opL,len);
1134
exp = EXPOS_CYC(hdP,len);
1135
for ( i = 1; i < len; i++ ) {
1136
if ( ! IS_INTOBJ( cfs[i] )
1137
|| ! PROD_INTOBJS( prd, cfs[i], opR ) ) {
1138
CHANGED_BAG( hdP );
1139
prd = PROD( cfs[i], opR );
1140
cfs = COEFS_CYC(opL);
1141
cfp = COEFS_CYC(hdP);
1142
exs = EXPOS_CYC(opL,len);
1143
exp = EXPOS_CYC(hdP,len);
1144
}
1145
cfp[i] = prd;
1146
exp[i] = exs[i];
1147
}
1148
CHANGED_BAG( hdP );
1149
}
1150
1151
/* otherwise multiply every coefficent */
1152
else {
1153
hdP = NewBag( T_CYC, SIZE_CYC(opL) * (sizeof(Obj)+sizeof(UInt4)) );
1154
NOF_CYC(hdP) = NOF_CYC(opL);
1155
len = SIZE_CYC(opL);
1156
cfs = COEFS_CYC(opL);
1157
cfp = COEFS_CYC(hdP);
1158
exs = EXPOS_CYC(opL,len);
1159
exp = EXPOS_CYC(hdP,len);
1160
for ( i = 1; i < len; i++ ) {
1161
CHANGED_BAG( hdP );
1162
prd = PROD( cfs[i], opR );
1163
cfs = COEFS_CYC(opL);
1164
cfp = COEFS_CYC(hdP);
1165
exs = EXPOS_CYC(opL,len);
1166
exp = EXPOS_CYC(hdP,len);
1167
cfp[i] = prd;
1168
exp[i] = exs[i];
1169
}
1170
CHANGED_BAG( hdP );
1171
}
1172
1173
/* return the result */
1174
return hdP;
1175
}
1176
1177
1178
/****************************************************************************
1179
**
1180
*F ProdCyc( <opL>, <opR> ) . . . . . . . . . . . product of two cyclotomics
1181
**
1182
** 'ProdCyc' returns the product of the two cyclotomics <opL> and <opR>.
1183
** Either operand may also be an integer or a rational.
1184
**
1185
** This function is lengthy because we try to use immediate integer
1186
** arithmetic if possible to avoid the function call overhead.
1187
*/
1188
Obj ProdCyc (
1189
Obj opL,
1190
Obj opR )
1191
{
1192
UInt nl, nr; /* order of left and right field */
1193
UInt n; /* order of smallest superfield */
1194
UInt ml, mr; /* cofactors into the superfield */
1195
Obj c; /* one coefficient of the left op */
1196
UInt e; /* one exponent of the left op */
1197
UInt len; /* number of terms */
1198
Obj * cfs; /* pointer to the coefficients */
1199
UInt4 * exs; /* pointer to the exponents */
1200
Obj * res; /* pointer to the result */
1201
Obj sum; /* sum of two coefficients */
1202
Obj prd; /* product of two coefficients */
1203
UInt i, k; /* loop variable */
1204
1205
/* for $rat * cyc$ and $cyc * rat$ delegate */
1206
if ( TNUM_OBJ(opL) != T_CYC || TNUM_OBJ(opR) != T_CYC ) {
1207
return ProdCycInt( opL, opR );
1208
}
1209
1210
/* take the cyclotomic with less terms as the right operand */
1211
if ( SIZE_CYC(opL) < SIZE_CYC(opR) ) {
1212
prd = opL; opL = opR; opR = prd;
1213
}
1214
1215
/* get the smallest field that contains both cyclotomics */
1216
nl = (TNUM_OBJ(opL) != T_CYC ? 1 : INT_INTOBJ( NOF_CYC(opL) ));
1217
nr = (TNUM_OBJ(opR) != T_CYC ? 1 : INT_INTOBJ( NOF_CYC(opR) ));
1218
n = FindCommonField(nl, nr, &ml, &mr);
1219
1220
/* loop over the terms of the right operand */
1221
for ( k = 1; k < SIZE_CYC(opR); k++ ) {
1222
c = COEFS_CYC(opR)[k];
1223
e = (mr * EXPOS_CYC( opR, SIZE_CYC(opR) )[k]) % n;
1224
1225
/* if the coefficient is 1 just add */
1226
if ( c == INTOBJ_INT(1) ) {
1227
len = SIZE_CYC(opL);
1228
cfs = COEFS_CYC(opL);
1229
exs = EXPOS_CYC(opL,len);
1230
res = &(ELM_PLIST( TLS(ResultCyc), 1 ));
1231
for ( i = 1; i < len; i++ ) {
1232
if ( ! ARE_INTOBJS( res[(e+exs[i]*ml)%n], cfs[i] )
1233
|| ! SUM_INTOBJS( sum, res[(e+exs[i]*ml)%n], cfs[i] ) ) {
1234
CHANGED_BAG( TLS(ResultCyc) );
1235
sum = SUM( res[(e+exs[i]*ml)%n], cfs[i] );
1236
cfs = COEFS_CYC(opL);
1237
exs = EXPOS_CYC(opL,len);
1238
res = &(ELM_PLIST( TLS(ResultCyc), 1 ));
1239
}
1240
res[(e+exs[i]*ml)%n] = sum;
1241
}
1242
CHANGED_BAG( TLS(ResultCyc) );
1243
}
1244
1245
/* if the coefficient is -1 just subtract */
1246
else if ( c == INTOBJ_INT(-1) ) {
1247
len = SIZE_CYC(opL);
1248
cfs = COEFS_CYC(opL);
1249
exs = EXPOS_CYC(opL,len);
1250
res = &(ELM_PLIST( TLS(ResultCyc), 1 ));
1251
for ( i = 1; i < len; i++ ) {
1252
if ( ! ARE_INTOBJS( res[(e+exs[i]*ml)%n], cfs[i] )
1253
|| ! DIFF_INTOBJS( sum, res[(e+exs[i]*ml)%n], cfs[i] ) ) {
1254
CHANGED_BAG( TLS(ResultCyc) );
1255
sum = DIFF( res[(e+exs[i]*ml)%n], cfs[i] );
1256
cfs = COEFS_CYC(opL);
1257
exs = EXPOS_CYC(opL,len);
1258
res = &(ELM_PLIST( TLS(ResultCyc), 1 ));
1259
}
1260
res[(e+exs[i]*ml)%n] = sum;
1261
}
1262
CHANGED_BAG( TLS(ResultCyc) );
1263
}
1264
1265
/* if the coefficient is a small integer use immediate operations */
1266
else if ( TNUM_OBJ(c) == T_INT ) {
1267
len = SIZE_CYC(opL);
1268
cfs = COEFS_CYC(opL);
1269
exs = EXPOS_CYC(opL,len);
1270
res = &(ELM_PLIST( TLS(ResultCyc), 1 ));
1271
for ( i = 1; i < len; i++ ) {
1272
if ( ! ARE_INTOBJS( cfs[i], res[(e+exs[i]*ml)%n] )
1273
|| ! PROD_INTOBJS( prd, cfs[i], c )
1274
|| ! SUM_INTOBJS( sum, res[(e+exs[i]*ml)%n], prd ) ) {
1275
CHANGED_BAG( TLS(ResultCyc) );
1276
prd = PROD( cfs[i], c );
1277
exs = EXPOS_CYC(opL,len);
1278
res = &(ELM_PLIST( TLS(ResultCyc), 1 ));
1279
sum = SUM( res[(e+exs[i]*ml)%n], prd );
1280
cfs = COEFS_CYC(opL);
1281
exs = EXPOS_CYC(opL,len);
1282
res = &(ELM_PLIST( TLS(ResultCyc), 1 ));
1283
}
1284
res[(e+exs[i]*ml)%n] = sum;
1285
}
1286
CHANGED_BAG( TLS(ResultCyc) );
1287
}
1288
1289
/* otherwise do it the normal way */
1290
else {
1291
len = SIZE_CYC(opL);
1292
for ( i = 1; i < len; i++ ) {
1293
CHANGED_BAG( TLS(ResultCyc) );
1294
cfs = COEFS_CYC(opL);
1295
prd = PROD( cfs[i], c );
1296
exs = EXPOS_CYC(opL,len);
1297
res = &(ELM_PLIST( TLS(ResultCyc), 1 ));
1298
sum = SUM( res[(e+exs[i]*ml)%n], prd );
1299
exs = EXPOS_CYC(opL,len);
1300
res = &(ELM_PLIST( TLS(ResultCyc), 1 ));
1301
res[(e+exs[i]*ml)%n] = sum;
1302
}
1303
CHANGED_BAG( TLS(ResultCyc) );
1304
}
1305
1306
}
1307
1308
/* return the base reduced packed cyclotomic */
1309
ConvertToBase( n );
1310
return Cyclotomic( n, ml * mr );
1311
}
1312
1313
1314
/****************************************************************************
1315
**
1316
*F OneCyc( <op> ) . . . . . . . . . . . . . . . . . . . one of a cyclotomic
1317
**
1318
** 'OneCyc' returns the multiplicative neutral element of the cyclotomic
1319
** <op>.
1320
*/
1321
Obj OneCyc (
1322
Obj op )
1323
{
1324
return INTOBJ_INT( 1L );
1325
}
1326
1327
1328
/****************************************************************************
1329
**
1330
*F InvCyc( <op> ) . . . . . . . . . . . . . . . . . inverse of a cyclotomic
1331
**
1332
** 'InvCyc' returns the multiplicative inverse element of the cyclotomic
1333
** <op>.
1334
**
1335
** 'InvCyc' computes the inverse of <op> by computing the product $prd$ of
1336
** nontrivial Galois conjugates of <op>. Then $op * (prd / (op * prd)) = 1$
1337
** so $prd / (op * prd)$ is the inverse of $op$. Because the denominator
1338
** $op * prd$ is the norm of $op$ over the rationals it is rational so we
1339
** can compute the quotient $prd / (op * prd)$ with 'ProdCycInt'.
1340
*T better multiply only the *different* conjugates?
1341
*/
1342
Obj InvCyc (
1343
Obj op )
1344
{
1345
Obj prd; /* product of conjugates */
1346
UInt n; /* order of the field */
1347
UInt sqr; /* if n < sqr*sqr n is squarefree */
1348
UInt len; /* number of terms */
1349
Obj * cfs; /* pointer to the coefficients */
1350
UInt4 * exs; /* pointer to the exponents */
1351
Obj * res; /* pointer to the result */
1352
UInt i, k; /* loop variable */
1353
UInt gcd, s, t; /* gcd of i and n, temporaries */
1354
1355
/* get the order of the field, test if it is squarefree */
1356
n = INT_INTOBJ( NOF_CYC(op) );
1357
for ( sqr = 2; sqr*sqr <= n && n % (sqr*sqr) != 0; sqr++ )
1358
;
1359
1360
/* compute the product of all nontrivial galois conjugates of <opL> */
1361
len = SIZE_CYC(op);
1362
prd = INTOBJ_INT(1);
1363
for ( i = 2; i < n; i++ ) {
1364
1365
/* if i gives a galois automorphism apply it */
1366
gcd = n; s = i; while ( s != 0 ) { t = s; s = gcd % s; gcd = t; }
1367
if ( gcd == 1 ) {
1368
1369
/* permute the terms */
1370
cfs = COEFS_CYC(op);
1371
exs = EXPOS_CYC(op,len);
1372
res = &(ELM_PLIST( TLS(ResultCyc), 1 ));
1373
for ( k = 1; k < len; k++ )
1374
res[(i*exs[k])%n] = cfs[k];
1375
CHANGED_BAG( TLS(ResultCyc) );
1376
1377
/* if n is squarefree conversion and reduction are unnecessary */
1378
if ( n < sqr*sqr ) {
1379
prd = ProdCyc( prd, Cyclotomic( n, n ) );
1380
}
1381
else {
1382
ConvertToBase( n );
1383
prd = ProdCyc( prd, Cyclotomic( n, 1 ) );
1384
}
1385
1386
}
1387
1388
}
1389
1390
/* the inverse is the product divided by the norm */
1391
return ProdCycInt( prd, INV( ProdCyc( op, prd ) ) );
1392
}
1393
1394
1395
/****************************************************************************
1396
**
1397
*F PowCyc( <opL>, <opR> ) . . . . . . . . . . . . . . power of a cyclotomic
1398
**
1399
** 'PowCyc' returns the <opR>th, which must be an integer, power of the
1400
** cyclotomic <opL>. The left operand may also be an integer or a rational.
1401
*/
1402
Obj PowCyc (
1403
Obj opL,
1404
Obj opR )
1405
{
1406
Obj pow; /* power (result) */
1407
Int exp; /* exponent (right operand) */
1408
UInt n; /* order of the field */
1409
Obj * res; /* pointer into the result */
1410
UInt i; /* exponent of left operand */
1411
1412
/* get the exponent */
1413
exp = INT_INTOBJ(opR);
1414
1415
/* for $cyc^0$ return 1, for $cyc^1$ return cyc, for $rat^exp$ delegate*/
1416
if ( exp == 0 ) {
1417
pow = INTOBJ_INT(1);
1418
}
1419
else if ( exp == 1 ) {
1420
pow = opL;
1421
}
1422
else if ( TNUM_OBJ(opL) != T_CYC ) {
1423
pow = PowInt( opL, opR );
1424
}
1425
1426
/* for $e_n^exp$ just put a 1 at the <exp>th position and convert */
1427
else if ( opL == TLS(LastECyc) ) {
1428
exp = (exp % TLS(LastNCyc) + TLS(LastNCyc)) % TLS(LastNCyc);
1429
SET_ELM_PLIST( TLS(ResultCyc), exp, INTOBJ_INT(1) );
1430
CHANGED_BAG( TLS(ResultCyc) );
1431
ConvertToBase( TLS(LastNCyc) );
1432
pow = Cyclotomic( TLS(LastNCyc), 1 );
1433
}
1434
1435
/* for $(c*e_n^i)^exp$ if $e_n^i$ belongs to the base put 1 at $i*exp$ */
1436
else if ( SIZE_CYC(opL) == 2 ) {
1437
n = INT_INTOBJ( NOF_CYC(opL) );
1438
pow = POW( COEFS_CYC(opL)[1], opR );
1439
i = EXPOS_CYC(opL,2)[1];
1440
res = &(ELM_PLIST( TLS(ResultCyc), 1 ));
1441
res[((exp*i)%n+n)%n] = pow;
1442
CHANGED_BAG( TLS(ResultCyc) );
1443
ConvertToBase( n );
1444
pow = Cyclotomic( n, 1 );
1445
}
1446
1447
/* otherwise compute the power with repeated squaring */
1448
else {
1449
1450
/* if neccessary invert the cyclotomic */
1451
if ( exp < 0 ) {
1452
opL = InvCyc( opL );
1453
exp = -exp;
1454
}
1455
1456
/* compute the power using repeated squaring */
1457
pow = INTOBJ_INT(1);
1458
while ( exp != 0 ) {
1459
if ( exp % 2 == 1 ) pow = ProdCyc( pow, opL );
1460
if ( exp > 1 ) opL = ProdCyc( opL, opL );
1461
exp = exp / 2;
1462
}
1463
1464
}
1465
1466
/* return the result */
1467
return pow;
1468
}
1469
1470
1471
/****************************************************************************
1472
**
1473
*F FuncE( <self>, <n> ) . . . . . . . . . . . . create a new primitive root
1474
**
1475
** 'FuncE' implements the internal function 'E'.
1476
**
1477
** 'E( <n> )'
1478
**
1479
** 'E' returns a primitive root of order <n>, which must be a positive
1480
** integer, represented as cyclotomic.
1481
*/
1482
Obj EOper;
1483
1484
Obj FuncE (
1485
Obj self,
1486
Obj n )
1487
{
1488
Obj * res; /* pointer into result bag */
1489
1490
/* do full operation */
1491
if ( FIRST_EXTERNAL_TNUM <= TNUM_OBJ(n) ) {
1492
return DoOperation1Args( self, n );
1493
}
1494
1495
/* get and check the argument */
1496
while ( TNUM_OBJ(n) != T_INT || INT_INTOBJ(n) <= 0 ) {
1497
n = ErrorReturnObj(
1498
"E: <n> must be a positive integer (not a %s)",
1499
(Int)TNAM_OBJ(n), 0L,
1500
"you can replace <n> via 'return <n>;'" );
1501
}
1502
1503
/* for $e_1$ return 1 and for $e_2$ return -1 */
1504
if ( n == INTOBJ_INT(1) )
1505
return INTOBJ_INT(1);
1506
else if ( n == INTOBJ_INT(2) )
1507
return INTOBJ_INT(-1);
1508
1509
/* if the root is not known already construct it */
1510
if ( TLS(LastNCyc) != INT_INTOBJ(n) ) {
1511
TLS(LastNCyc) = INT_INTOBJ(n);
1512
GrowResultCyc(TLS(LastNCyc));
1513
res = &(ELM_PLIST( TLS(ResultCyc), 1 ));
1514
res[1] = INTOBJ_INT(1);
1515
CHANGED_BAG( TLS(ResultCyc) );
1516
ConvertToBase( TLS(LastNCyc) );
1517
TLS(LastECyc) = Cyclotomic( TLS(LastNCyc), 1 );
1518
}
1519
1520
/* return the root */
1521
return TLS(LastECyc);
1522
}
1523
1524
1525
/****************************************************************************
1526
**
1527
*F FuncIS_CYC( <self>, <val> ) . . . . . . test if an object is a cyclomtic
1528
**
1529
** 'FuncIS_CYC' implements the internal function 'IsCyc'.
1530
**
1531
** 'IsCyc( <val> )'
1532
**
1533
** 'IsCyc' returns 'true' if the value <val> is a cyclotomic and 'false'
1534
** otherwise.
1535
*/
1536
Obj IsCycFilt;
1537
1538
Obj FuncIS_CYC (
1539
Obj self,
1540
Obj val )
1541
{
1542
/* return 'true' if <obj> is a cyclotomic and 'false' otherwise */
1543
if ( TNUM_OBJ(val) == T_CYC
1544
|| TNUM_OBJ(val) == T_INT || TNUM_OBJ(val) == T_RAT
1545
|| TNUM_OBJ(val) == T_INTPOS || TNUM_OBJ(val) == T_INTNEG )
1546
return True;
1547
else if ( TNUM_OBJ(val) < FIRST_EXTERNAL_TNUM ) {
1548
return False;
1549
}
1550
else {
1551
return DoFilter( self, val );
1552
}
1553
}
1554
1555
1556
/****************************************************************************
1557
**
1558
*F FuncIS_CYC_INT( <self>, <val> ) test if an object is a cyclomtic integer
1559
**
1560
** 'FuncIS_CYC_INT' implements the internal function 'IsCycInt'.
1561
**
1562
** 'IsCycInt( <val> )'
1563
**
1564
** 'IsCycInt' returns 'true' if the value <val> is a cyclotomic integer and
1565
** 'false' otherwise.
1566
**
1567
** 'IsCycInt' relies on the fact that the base is an integral base.
1568
*/
1569
Obj IsCycIntOper;
1570
1571
Obj FuncIS_CYC_INT (
1572
Obj self,
1573
Obj val )
1574
{
1575
UInt len; /* number of terms */
1576
Obj * cfs; /* pointer to the coefficients */
1577
UInt i; /* loop variable */
1578
1579
/* return 'true' if <obj> is a cyclotomic integer and 'false' otherwise*/
1580
if ( TNUM_OBJ(val) == T_INT
1581
|| TNUM_OBJ(val) == T_INTPOS || TNUM_OBJ(val) == T_INTNEG ) {
1582
return True;
1583
}
1584
else if ( TNUM_OBJ(val) == T_RAT ) {
1585
return False;
1586
}
1587
else if ( TNUM_OBJ(val) == T_CYC ) {
1588
len = SIZE_CYC(val);
1589
cfs = COEFS_CYC(val);
1590
for ( i = 1; i < len; i++ ) {
1591
if ( TNUM_OBJ(cfs[i]) == T_RAT )
1592
return False;
1593
}
1594
return True;
1595
}
1596
else if ( TNUM_OBJ(val) < FIRST_EXTERNAL_TNUM ) {
1597
return False;
1598
}
1599
else {
1600
return DoOperation1Args( self, val );
1601
}
1602
}
1603
1604
1605
/****************************************************************************
1606
**
1607
*F FuncCONDUCTOR( <self>, <cyc> ) . . . . . . . . . . . . N of a cyclotomic
1608
**
1609
** 'FuncCONDUCTOR' implements the internal function 'Conductor'.
1610
**
1611
** 'Conductor( <cyc> )'
1612
**
1613
** 'Conductor' returns the N of the cyclotomic <cyc>, i.e., the order of the
1614
** roots of which <cyc> is written as a linear combination.
1615
*/
1616
Obj ConductorAttr;
1617
1618
Obj FuncCONDUCTOR (
1619
Obj self,
1620
Obj cyc )
1621
{
1622
UInt n; /* N of the cyclotomic, result */
1623
UInt m; /* N of element of the list */
1624
UInt gcd, s, t; /* gcd of n and m, temporaries */
1625
Obj list; /* list of cyclotomics */
1626
UInt i; /* loop variable */
1627
1628
/* do full operation */
1629
if ( FIRST_EXTERNAL_TNUM <= TNUM_OBJ(cyc) ) {
1630
return DoAttribute( ConductorAttr, cyc );
1631
}
1632
1633
/* check the argument */
1634
while ( TNUM_OBJ(cyc) != T_INT && TNUM_OBJ(cyc) != T_RAT
1635
&& TNUM_OBJ(cyc) != T_INTPOS && TNUM_OBJ(cyc) != T_INTNEG
1636
&& TNUM_OBJ(cyc) != T_CYC
1637
&& ! IS_SMALL_LIST(cyc) ) {
1638
cyc = ErrorReturnObj(
1639
"Conductor: <cyc> must be a cyclotomic or a small list (not a %s)",
1640
(Int)TNAM_OBJ(cyc), 0L,
1641
"you can replace <cyc> via 'return <cyc>;'" );
1642
}
1643
1644
/* handle cyclotomics */
1645
if ( TNUM_OBJ(cyc) == T_INT || TNUM_OBJ(cyc) == T_RAT
1646
|| TNUM_OBJ(cyc) == T_INTPOS || TNUM_OBJ(cyc) == T_INTNEG ) {
1647
n = 1;
1648
}
1649
else if ( TNUM_OBJ(cyc) == T_CYC ) {
1650
n = INT_INTOBJ( NOF_CYC(cyc) );
1651
}
1652
1653
/* handle a list by computing the lcm of the entries */
1654
else {
1655
list = cyc;
1656
n = 1;
1657
for ( i = 1; i <= LEN_LIST( list ); i++ ) {
1658
cyc = ELMV_LIST( list, i );
1659
while ( TNUM_OBJ(cyc) != T_INT && TNUM_OBJ(cyc) != T_RAT
1660
&& TNUM_OBJ(cyc) != T_INTPOS && TNUM_OBJ(cyc) != T_INTNEG
1661
&& TNUM_OBJ(cyc) != T_CYC ) {
1662
cyc = ErrorReturnObj(
1663
"Conductor: <list>[%d] must be a cyclotomic (not a %s)",
1664
(Int)i, (Int)TNAM_OBJ(cyc),
1665
"you can replace the list element with <cyc> via 'return <cyc>;'" );
1666
}
1667
if ( TNUM_OBJ(cyc) == T_INT || TNUM_OBJ(cyc) == T_RAT
1668
|| TNUM_OBJ(cyc) == T_INTPOS || TNUM_OBJ(cyc) == T_INTNEG ) {
1669
m = 1;
1670
}
1671
else /* if ( TNUM_OBJ(cyc) == T_CYC ) */ {
1672
m = INT_INTOBJ( NOF_CYC(cyc) );
1673
}
1674
gcd = n; s = m; while ( s != 0 ) { t = s; s = gcd % s; gcd = t; }
1675
n = n / gcd * m;
1676
}
1677
}
1678
1679
/* return the N of the cyclotomic */
1680
return INTOBJ_INT( n );
1681
}
1682
1683
1684
/****************************************************************************
1685
**
1686
*F FuncCOEFFS_CYC( <self>, <cyc> ) . . . . . . coefficients of a cyclotomic
1687
**
1688
** 'FuncCOEFFS_CYC' implements the internal function 'COEFFSCYC'.
1689
**
1690
** 'COEFFSCYC( <cyc> )'
1691
**
1692
** 'COEFFSCYC' returns a list of the coefficients of the cyclotomic <cyc>.
1693
** The list has length <n> if <n> is the order of the primitive root $e_n$
1694
** of which <cyc> is written as a linear combination. The <i>th element of
1695
** the list is the coefficient of $e_l^{i-1}$.
1696
*/
1697
Obj CoeffsCycOper;
1698
1699
Obj FuncCOEFFS_CYC (
1700
Obj self,
1701
Obj cyc )
1702
{
1703
Obj list; /* list of coefficients, result */
1704
UInt n; /* order of field */
1705
UInt len; /* number of terms */
1706
Obj * cfs; /* pointer to the coefficients */
1707
UInt4 * exs; /* pointer to the exponents */
1708
UInt i; /* loop variable */
1709
1710
/* do full operation */
1711
if ( FIRST_EXTERNAL_TNUM <= TNUM_OBJ(cyc) ) {
1712
return DoOperation1Args( self, cyc );
1713
}
1714
1715
/* check the argument */
1716
while ( TNUM_OBJ(cyc) != T_INT && TNUM_OBJ(cyc) != T_RAT
1717
&& TNUM_OBJ(cyc) != T_INTPOS && TNUM_OBJ(cyc) != T_INTNEG
1718
&& TNUM_OBJ(cyc) != T_CYC ) {
1719
cyc = ErrorReturnObj(
1720
"COEFFSCYC: <cyc> must be a cyclotomic (not a %s)",
1721
(Int)TNAM_OBJ(cyc), 0L,
1722
"you can replace <cyc> via 'return <cyc>;'" );
1723
}
1724
1725
/* if <cyc> is rational just put it in a list of length 1 */
1726
if ( TNUM_OBJ(cyc) == T_INT || TNUM_OBJ(cyc) == T_RAT
1727
|| TNUM_OBJ(cyc) == T_INTPOS || TNUM_OBJ(cyc) == T_INTNEG ) {
1728
list = NEW_PLIST( T_PLIST, 1 );
1729
SET_LEN_PLIST( list, 1 );
1730
SET_ELM_PLIST( list, 1, cyc );
1731
/* 'CHANGED_BAG' not needed for last bag */
1732
}
1733
1734
/* otherwise make a list and fill it with zeroes and copy the coeffs */
1735
else {
1736
n = INT_INTOBJ( NOF_CYC(cyc) );
1737
list = NEW_PLIST( T_PLIST, n );
1738
SET_LEN_PLIST( list, n );
1739
len = SIZE_CYC(cyc);
1740
cfs = COEFS_CYC(cyc);
1741
exs = EXPOS_CYC(cyc,len);
1742
for ( i = 1; i <= n; i++ )
1743
SET_ELM_PLIST( list, i, INTOBJ_INT(0) );
1744
for ( i = 1; i < len; i++ )
1745
SET_ELM_PLIST( list, exs[i]+1, cfs[i] );
1746
/* 'CHANGED_BAG' not needed for last bag */
1747
}
1748
1749
/* return the result */
1750
return list;
1751
}
1752
1753
1754
/****************************************************************************
1755
**
1756
*F FuncGALOIS_CYC( <self>, <cyc>, <ord> ) image of a cyc. under galois aut
1757
**
1758
** 'FuncGALOIS_CYC' implements the internal function 'GaloisCyc'.
1759
**
1760
** 'GaloisCyc( <cyc>, <ord> )'
1761
**
1762
** 'GaloisCyc' computes the image of the cyclotomic <cyc> under the galois
1763
** automorphism given by <ord>, which must be an integer.
1764
**
1765
** The galois automorphism is the mapping that takes $e_n$ to $e_n^ord$.
1766
** <ord> may be any integer, of course if it is not relative prime to $ord$
1767
** the mapping will not be an automorphism, though still an endomorphism.
1768
*/
1769
Obj GaloisCycOper;
1770
1771
Obj FuncGALOIS_CYC (
1772
Obj self,
1773
Obj cyc,
1774
Obj ord )
1775
{
1776
Obj gal; /* galois conjugate, result */
1777
Obj sum; /* sum of two coefficients */
1778
Int n; /* order of the field */
1779
UInt sqr; /* if n < sqr*sqr n is squarefree */
1780
Int o; /* galois automorphism */
1781
UInt gcd, s, t; /* gcd of n and ord, temporaries */
1782
UInt len; /* number of terms */
1783
Obj * cfs; /* pointer to the coefficients */
1784
UInt4 * exs; /* pointer to the exponents */
1785
Obj * res; /* pointer to the result */
1786
UInt i; /* loop variable */
1787
UInt tnumord, tnumcyc;
1788
1789
/* do full operation for any but standard arguments */
1790
1791
tnumord = TNUM_OBJ(ord);
1792
tnumcyc = TNUM_OBJ(cyc);
1793
if ( FIRST_EXTERNAL_TNUM <= tnumcyc
1794
|| FIRST_EXTERNAL_TNUM <= tnumord
1795
|| (tnumord != T_INT && tnumord != T_INTNEG && tnumord != T_INTPOS)
1796
|| ( tnumcyc != T_INT && tnumcyc != T_RAT
1797
&& tnumcyc != T_INTPOS && tnumcyc != T_INTNEG
1798
&& tnumcyc != T_CYC )
1799
)
1800
{
1801
return DoOperation2Args( self, cyc, ord );
1802
}
1803
1804
/* get and check <ord> */
1805
if ( TNAM_OBJ(ord) == T_INT ) {
1806
o = INT_INTOBJ(ord);
1807
}
1808
else {
1809
ord = MOD( ord, FuncCONDUCTOR( 0, cyc ) );
1810
o = INT_INTOBJ(ord);
1811
}
1812
1813
/* every galois automorphism fixes the rationals */
1814
if ( tnumcyc == T_INT || tnumcyc == T_RAT
1815
|| tnumcyc == T_INTPOS || tnumcyc == T_INTNEG ) {
1816
return cyc;
1817
}
1818
1819
/* get the order of the field, test if it squarefree */
1820
n = INT_INTOBJ( NOF_CYC(cyc) );
1821
for ( sqr = 2; sqr*sqr <= n && n % (sqr*sqr) != 0; sqr++ )
1822
;
1823
1824
/* force <ord> into the range 0..n-1, compute the gcd of <ord> and <n> */
1825
o = (o % n + n) % n;
1826
gcd = n; s = o; while ( s != 0 ) { t = s; s = gcd % s; gcd = t; }
1827
1828
/* if <ord> = 1 just return <cyc> */
1829
if ( o == 1 ) {
1830
gal = cyc;
1831
}
1832
1833
/* if <ord> == 0 compute the sum of the entries */
1834
else if ( o == 0 ) {
1835
len = SIZE_CYC(cyc);
1836
cfs = COEFS_CYC(cyc);
1837
gal = INTOBJ_INT(0);
1838
for ( i = 1; i < len; i++ ) {
1839
if ( ! ARE_INTOBJS( gal, cfs[i] )
1840
|| ! SUM_INTOBJS( sum, gal, cfs[i] ) ) {
1841
sum = SUM( gal, cfs[i] );
1842
cfs = COEFS_CYC( cyc );
1843
}
1844
gal = sum;
1845
}
1846
}
1847
1848
/* if <ord> == n/2 compute alternating sum since $(e_n^i)^ord = -1^i$ */
1849
else if ( n % 2 == 0 && o == n/2 ) {
1850
gal = INTOBJ_INT(0);
1851
len = SIZE_CYC(cyc);
1852
cfs = COEFS_CYC(cyc);
1853
exs = EXPOS_CYC(cyc,len);
1854
for ( i = 1; i < len; i++ ) {
1855
if ( exs[i] % 2 == 1 ) {
1856
if ( ! ARE_INTOBJS( gal, cfs[i] )
1857
|| ! DIFF_INTOBJS( sum, gal, cfs[i] ) ) {
1858
sum = DIFF( gal, cfs[i] );
1859
cfs = COEFS_CYC(cyc);
1860
exs = EXPOS_CYC(cyc,len);
1861
}
1862
gal = sum;
1863
}
1864
else {
1865
if ( ! ARE_INTOBJS( gal, cfs[i] )
1866
|| ! SUM_INTOBJS( sum, gal, cfs[i] ) ) {
1867
sum = SUM( gal, cfs[i] );
1868
cfs = COEFS_CYC(cyc);
1869
exs = EXPOS_CYC(cyc,len);
1870
}
1871
gal = sum;
1872
}
1873
}
1874
}
1875
1876
/* if <ord> is prime to <n> (automorphism) permute the coefficients */
1877
else if ( gcd == 1 ) {
1878
1879
/* permute the coefficients */
1880
len = SIZE_CYC(cyc);
1881
cfs = COEFS_CYC(cyc);
1882
exs = EXPOS_CYC(cyc,len);
1883
res = &(ELM_PLIST( TLS(ResultCyc), 1 ));
1884
for ( i = 1; i < len; i++ ) {
1885
res[(UInt8)exs[i]*(UInt8)o%(UInt8)n] = cfs[i];
1886
}
1887
CHANGED_BAG( TLS(ResultCyc) );
1888
1889
/* if n is squarefree conversion and reduction are unnecessary */
1890
if ( n < sqr*sqr || (o == n-1 && n % 2 != 0) ) {
1891
gal = Cyclotomic( n, n );
1892
}
1893
else {
1894
ConvertToBase( n );
1895
gal = Cyclotomic( n, 1 );
1896
}
1897
1898
}
1899
1900
/* if <ord> is not prime to <n> (endomorphism) compute it the hard way */
1901
else {
1902
1903
/* multiple roots may be mapped to the same root, add the coeffs */
1904
len = SIZE_CYC(cyc);
1905
cfs = COEFS_CYC(cyc);
1906
exs = EXPOS_CYC(cyc,len);
1907
res = &(ELM_PLIST( TLS(ResultCyc), 1 ));
1908
for ( i = 1; i < len; i++ ) {
1909
if ( ! ARE_INTOBJS( res[(UInt8)exs[i]*(UInt8)o%(UInt8)n], cfs[i] )
1910
|| ! SUM_INTOBJS( sum, res[(UInt8)exs[i]*(UInt8)o%(UInt8)n], cfs[i] ) ) {
1911
CHANGED_BAG( TLS(ResultCyc) );
1912
sum = SUM( res[(UInt8)exs[i]*(UInt8)o%(UInt8)n], cfs[i] );
1913
cfs = COEFS_CYC(cyc);
1914
exs = EXPOS_CYC(cyc,len);
1915
res = &(ELM_PLIST( TLS(ResultCyc), 1 ));
1916
}
1917
res[exs[i]*o%n] = sum;
1918
}
1919
CHANGED_BAG( TLS(ResultCyc) );
1920
1921
/* if n is squarefree conversion and reduction are unnecessary */
1922
if ( n < sqr*sqr ) {
1923
gal = Cyclotomic( n, 1 ); /*N?*/
1924
}
1925
else {
1926
ConvertToBase( n );
1927
gal = Cyclotomic( n, 1 );
1928
}
1929
1930
}
1931
1932
/* return the result */
1933
return gal;
1934
}
1935
1936
1937
/****************************************************************************
1938
**
1939
*F FuncCycList( <self>, <list> ) . . . . . . . . . . . . create a cyclotomic
1940
**
1941
** 'FuncCycList' implements the internal function 'CycList'.
1942
**
1943
** 'CycList( <list> )'
1944
**
1945
** 'CycList' returns the cyclotomic described by the list <list>
1946
** of rationals.
1947
*/
1948
Obj CycListOper;
1949
1950
Obj FuncCycList (
1951
Obj self,
1952
Obj list )
1953
{
1954
UInt i; /* loop variable */
1955
Obj * res; /* pointer into result bag */
1956
Obj val; /* one list entry */
1957
UInt n; /* length of the given list */
1958
1959
/* do full operation */
1960
if ( FIRST_EXTERNAL_TNUM <= TNUM_OBJ( list ) ) {
1961
return DoOperation1Args( self, list );
1962
}
1963
1964
/* get and check the argument */
1965
if ( ! IS_PLIST( list ) || ! IS_DENSE_LIST( list ) ) {
1966
ErrorQuit( "CycList: <list> must be a dense plain list (not a %s)",
1967
(Int)TNAM_OBJ( list ), 0L );
1968
}
1969
1970
/* enlarge the buffer if necessary */
1971
n = LEN_PLIST( list );
1972
GrowResultCyc(n);
1973
1974
/* transfer the coefficients into the buffer */
1975
res = &(ELM_PLIST( TLS(ResultCyc), 1 ));
1976
for ( i = 0; i < n; i++ ) {
1977
val = ELM_PLIST( list, i+1 );
1978
if ( ! ( TNUM_OBJ(val) == T_INT ||
1979
TNUM_OBJ(val) == T_RAT ||
1980
TNUM_OBJ(val) == T_INTPOS ||
1981
TNUM_OBJ(val) == T_INTNEG ) ) {
1982
ErrorQuit( "CycList: each entry must be a rational (not a %s)",
1983
(Int)TNAM_OBJ( val ), 0L );
1984
}
1985
res[i] = val;
1986
}
1987
1988
/* return the base reduced packed cyclotomic */
1989
CHANGED_BAG( TLS(ResultCyc) );
1990
ConvertToBase( n );
1991
return Cyclotomic( n, 1 );
1992
}
1993
1994
1995
/****************************************************************************
1996
**
1997
*F MarkCycSubBags( <bag> ) . . . . . . . . marking function for cyclotomics
1998
**
1999
** 'MarkCycSubBags' is the marking function for bags of type 'T_CYC'.
2000
*/
2001
void MarkCycSubBags (
2002
Obj cyc )
2003
{
2004
Obj * cfs; /* pointer to coeffs */
2005
UInt i; /* loop variable */
2006
2007
/* mark everything */
2008
cfs = COEFS_CYC( cyc );
2009
for ( i = SIZE_CYC(cyc); 0 < i; i-- ) {
2010
MARK_BAG( cfs[i-1] );
2011
}
2012
2013
}
2014
2015
2016
/****************************************************************************
2017
**
2018
2019
*F SaveCyc() . . . . . . . . . . . . . . . . . . . . . . save a cyclotyomic
2020
**
2021
** We do not save the XXX_CYC field, since it is not used.
2022
*/
2023
void SaveCyc ( Obj cyc )
2024
{
2025
UInt len, i;
2026
Obj *coefs;
2027
UInt4 *expos;
2028
len = SIZE_CYC(cyc);
2029
coefs = COEFS_CYC(cyc);
2030
for (i = 0; i < len; i++)
2031
SaveSubObj(*coefs++);
2032
expos = EXPOS_CYC(cyc,len);
2033
expos++; /*Skip past the XXX */
2034
for (i = 1; i < len; i++)
2035
SaveUInt4(*expos++);
2036
return;
2037
}
2038
2039
/****************************************************************************
2040
**
2041
*F LoadCyc() . . . . . . . . . . . . . . . . . . . . . . load a cyclotyomic
2042
**
2043
** We do not load the XXX_CYC field, since it is not used.
2044
*/
2045
void LoadCyc ( Obj cyc )
2046
{
2047
UInt len, i;
2048
Obj *coefs;
2049
UInt4 *expos;
2050
len = SIZE_CYC(cyc);
2051
coefs = COEFS_CYC(cyc);
2052
for (i = 0; i < len; i++)
2053
*coefs++ = LoadSubObj();
2054
expos = EXPOS_CYC(cyc,len);
2055
expos++; /*Skip past the XXX */
2056
for (i = 1; i < len; i++)
2057
*expos++ = LoadUInt4();
2058
return;
2059
}
2060
2061
2062
/****************************************************************************
2063
**
2064
**
2065
2066
*F * * * * * * * * * * * * * initialize package * * * * * * * * * * * * * * *
2067
*/
2068
2069
2070
/****************************************************************************
2071
**
2072
2073
*V GVarFilts . . . . . . . . . . . . . . . . . . . list of filters to export
2074
*/
2075
static StructGVarFilt GVarFilts [] = {
2076
2077
{ "IS_CYC", "obj", &IsCycFilt,
2078
FuncIS_CYC, "src/cyclotom.c:IS_CYC" },
2079
2080
{ 0 }
2081
2082
};
2083
2084
2085
/****************************************************************************
2086
**
2087
*V GVarAttrs . . . . . . . . . . . . . . . . . list of attributes to export
2088
*/
2089
static StructGVarAttr GVarAttrs [] = {
2090
2091
{ "CONDUCTOR", "cyc", &ConductorAttr,
2092
FuncCONDUCTOR, "src/cyclotom.c:CONDUCTOR" },
2093
2094
{ 0 }
2095
2096
};
2097
2098
2099
/****************************************************************************
2100
**
2101
*V GVarOpers . . . . . . . . . . . . . . . . . list of operations to export
2102
*/
2103
static StructGVarOper GVarOpers [] = {
2104
2105
{ "E", 1, "n", &EOper,
2106
FuncE, "src/cyclotom.c:E" },
2107
2108
{ "IS_CYC_INT", 1, "obj", &IsCycIntOper,
2109
FuncIS_CYC_INT, "src/cyclotom.c:IS_CYC_INT" },
2110
2111
{ "COEFFS_CYC", 1, "cyc", &CoeffsCycOper,
2112
FuncCOEFFS_CYC, "src/cyclotom.c:COEFFS_CYC" },
2113
2114
{ "GALOIS_CYC", 2, "cyc, n", &GaloisCycOper,
2115
FuncGALOIS_CYC, "src/cyclotom.c:GALOIS_CYC" },
2116
2117
{ "CycList", 1, "list", &CycListOper,
2118
FuncCycList, "src/cyclotom.c:CycList" },
2119
2120
2121
{ 0 }
2122
2123
};
2124
2125
2126
/****************************************************************************
2127
**
2128
*V GVarFuncs . . . . . . . . . . . . . . . . . list of functions to export
2129
*/
2130
static StructGVarFunc GVarFuncs [] = {
2131
{ "SetCyclotomicsLimit", 1, "newlimit",
2132
FuncSetCyclotomicsLimit, "src/cyclotomics.c:SetCyclotomicsLimit" },
2133
2134
{ "GetCyclotomicsLimit", 0, "",
2135
FuncGetCyclotomicsLimit, "src/cyclotomics.c:GetCyclotomicsLimit" },
2136
2137
{0}
2138
};
2139
2140
/****************************************************************************
2141
**
2142
2143
*F InitKernel( <module> ) . . . . . . . . initialise kernel data structures
2144
*/
2145
static Int InitKernel (
2146
StructInitInfo * module )
2147
{
2148
TLS(LastECyc) = (Obj)0;
2149
TLS(LastNCyc) = 0;
2150
2151
/* install the marking function */
2152
InfoBags[ T_CYC ].name = "cyclotomic";
2153
InitMarkFuncBags( T_CYC, MarkCycSubBags );
2154
2155
/* create the result buffer */
2156
InitGlobalBag( &ResultCyc , "src/cyclotom.c:ResultCyc" );
2157
2158
/* tell Gasman about the place were we remember the primitive root */
2159
InitGlobalBag( &LastECyc, "src/cyclotom.c:LastECyc" );
2160
2161
/* install the type function */
2162
ImportGVarFromLibrary( "TYPE_CYC", &TYPE_CYC );
2163
TypeObjFuncs[ T_CYC ] = TypeCyc;
2164
2165
/* init filters and functions */
2166
InitHdlrFiltsFromTable( GVarFilts );
2167
InitHdlrAttrsFromTable( GVarAttrs );
2168
InitHdlrOpersFromTable( GVarOpers );
2169
InitHdlrFuncsFromTable( GVarFuncs );
2170
2171
/* and the saving function */
2172
SaveObjFuncs[ T_CYC ] = SaveCyc;
2173
LoadObjFuncs[ T_CYC ] = LoadCyc;
2174
2175
/* install the evaluation and print function */
2176
PrintObjFuncs[ T_CYC ] = PrintCyc;
2177
2178
/* install the comparison methods */
2179
EqFuncs[ T_CYC ][ T_CYC ] = EqCyc;
2180
LtFuncs[ T_CYC ][ T_CYC ] = LtCyc;
2181
LtFuncs[ T_INT ][ T_CYC ] = LtCycYes;
2182
LtFuncs[ T_INTPOS ][ T_CYC ] = LtCycYes;
2183
LtFuncs[ T_INTNEG ][ T_CYC ] = LtCycYes;
2184
LtFuncs[ T_RAT ][ T_CYC ] = LtCycYes;
2185
LtFuncs[ T_CYC ][ T_INT ] = LtCycNot;
2186
LtFuncs[ T_CYC ][ T_INTPOS ] = LtCycNot;
2187
LtFuncs[ T_CYC ][ T_INTNEG ] = LtCycNot;
2188
LtFuncs[ T_CYC ][ T_RAT ] = LtCycNot;
2189
2190
/* install the unary arithmetic methods */
2191
ZeroFuncs[ T_CYC ] = ZeroCyc;
2192
ZeroMutFuncs[ T_CYC ] = ZeroCyc;
2193
AInvFuncs[ T_CYC ] = AInvCyc;
2194
AInvMutFuncs[ T_CYC ] = AInvCyc;
2195
OneFuncs [ T_CYC ] = OneCyc;
2196
OneMutFuncs [ T_CYC ] = OneCyc;
2197
InvFuncs [ T_CYC ] = InvCyc;
2198
InvMutFuncs [ T_CYC ] = InvCyc;
2199
2200
/* install the arithmetic methods */
2201
SumFuncs[ T_CYC ][ T_CYC ] = SumCyc;
2202
SumFuncs[ T_INT ][ T_CYC ] = SumCyc;
2203
SumFuncs[ T_INTPOS ][ T_CYC ] = SumCyc;
2204
SumFuncs[ T_INTNEG ][ T_CYC ] = SumCyc;
2205
SumFuncs[ T_RAT ][ T_CYC ] = SumCyc;
2206
SumFuncs[ T_CYC ][ T_INT ] = SumCyc;
2207
SumFuncs[ T_CYC ][ T_INTPOS ] = SumCyc;
2208
SumFuncs[ T_CYC ][ T_INTNEG ] = SumCyc;
2209
SumFuncs[ T_CYC ][ T_RAT ] = SumCyc;
2210
DiffFuncs[ T_CYC ][ T_CYC ] = DiffCyc;
2211
DiffFuncs[ T_INT ][ T_CYC ] = DiffCyc;
2212
DiffFuncs[ T_INTPOS ][ T_CYC ] = DiffCyc;
2213
DiffFuncs[ T_INTNEG ][ T_CYC ] = DiffCyc;
2214
DiffFuncs[ T_RAT ][ T_CYC ] = DiffCyc;
2215
DiffFuncs[ T_CYC ][ T_INT ] = DiffCyc;
2216
DiffFuncs[ T_CYC ][ T_INTPOS ] = DiffCyc;
2217
DiffFuncs[ T_CYC ][ T_INTNEG ] = DiffCyc;
2218
DiffFuncs[ T_CYC ][ T_RAT ] = DiffCyc;
2219
ProdFuncs[ T_CYC ][ T_CYC ] = ProdCyc;
2220
ProdFuncs[ T_INT ][ T_CYC ] = ProdCycInt;
2221
ProdFuncs[ T_INTPOS ][ T_CYC ] = ProdCycInt;
2222
ProdFuncs[ T_INTNEG ][ T_CYC ] = ProdCycInt;
2223
ProdFuncs[ T_RAT ][ T_CYC ] = ProdCycInt;
2224
ProdFuncs[ T_CYC ][ T_INT ] = ProdCycInt;
2225
ProdFuncs[ T_CYC ][ T_INTPOS ] = ProdCycInt;
2226
ProdFuncs[ T_CYC ][ T_INTNEG ] = ProdCycInt;
2227
ProdFuncs[ T_CYC ][ T_RAT ] = ProdCycInt;
2228
2229
/* return success */
2230
return 0;
2231
}
2232
2233
2234
/****************************************************************************
2235
**
2236
*F InitLibrary( <module> ) . . . . . . . initialise library data structures
2237
*/
2238
static Int InitLibrary (
2239
StructInitInfo * module )
2240
{
2241
Obj * res; /* pointer into the result */
2242
UInt i; /* loop variable */
2243
2244
/* create the result buffer */
2245
TLS(ResultCyc) = NEW_PLIST( T_PLIST, 1024 );
2246
SET_LEN_PLIST( TLS(ResultCyc), 1024 );
2247
res = &(ELM_PLIST( TLS(ResultCyc), 1 ));
2248
for ( i = 0; i < 1024; i++ ) { res[i] = INTOBJ_INT(0); }
2249
2250
/* init filters and functions */
2251
InitGVarFiltsFromTable( GVarFilts );
2252
InitGVarAttrsFromTable( GVarAttrs );
2253
InitGVarOpersFromTable( GVarOpers );
2254
InitGVarFuncsFromTable( GVarFuncs );
2255
2256
/* return success */
2257
return 0;
2258
}
2259
2260
2261
/****************************************************************************
2262
**
2263
*F InitInfoCyc() . . . . . . . . . . . . . . . . . . table of init functions
2264
*/
2265
static StructInitInfo module = {
2266
MODULE_BUILTIN, /* type */
2267
"cyclotom", /* name */
2268
0, /* revision entry of c file */
2269
0, /* revision entry of h file */
2270
0, /* version */
2271
0, /* crc */
2272
InitKernel, /* initKernel */
2273
InitLibrary, /* initLibrary */
2274
0, /* checkInit */
2275
0, /* preSave */
2276
0, /* postSave */
2277
0 /* postRestore */
2278
};
2279
2280
StructInitInfo * InitInfoCyc ( void )
2281
{
2282
return &module;
2283
}
2284
2285
2286
/****************************************************************************
2287
**
2288
2289
*E cyclotom.c . . . . . . . . . . . . . . . . . . . . . . . . . . ends here
2290
*/
2291
2292