# source:git/libpolys/polys/ext_fields/algext.cc@2c7f28

spielwiese
Last change on this file since 2c7f28 was 2c7f28, checked in by Frank Seelisch <seelisch@…>, 12 years ago
impl. of rat. funct. fields (no tests yet, no cancellation of gcd's yet)
• Property mode set to `100644`
File size: 20.7 KB
Line
1/****************************************
2*  Computer Algebra System SINGULAR     *
3****************************************/
4/* \$Id\$ */
5/*
6* ABSTRACT: numbers in an algebraic extension field K[a] / < f(a) >
7*           Assuming that we have a coeffs object cf, then these numbers
8*           are polynomials in the polynomial ring K[a] represented by
9*           cf->extRing.
10*           IMPORTANT ASSUMPTIONS:
11*           1.) So far we assume that cf->extRing is a valid polynomial
12*               ring in exactly one variable, i.e., K[a], where K is allowed
13*               to be any field (representable in SINGULAR and which may
14*               itself be some extension field, thus allowing for extension
15*               towers).
16*           2.) Moreover, this implementation assumes that
17*               cf->extRing->minideal is not NULL but an ideal with at
18*               least one non-zero generator which may be accessed by
19*               cf->extRing->minideal->m and which represents the minimal
20*               polynomial f(a) of the extension variable 'a' in K[a].
21*           3.) As soon as an std method for polynomial rings becomes
22*               availabe, all reduction steps modulo f(a) should be replaced
23*               by a call to std. Moreover, in this situation one can finally
24*               move from K[a] / < f(a) > to
25*                  K[a_1, ..., a_s] / I, with I some zero-dimensional ideal
26*                                        in K[a_1, ..., a_s] given by a lex
27*                                        GrÃ¶bner basis.
28*               The code in algext.h and algext.cc is then capable of
29*               computing in K[a_1, ..., a_s] / I.
30*/
31
32#include "config.h"
33#include <misc/auxiliary.h>
34
35#include <omalloc/omalloc.h>
36
37#include <reporter/reporter.h>
38
39#include <coeffs/coeffs.h>
40#include <coeffs/numbers.h>
41#include <coeffs/longrat.h>
42
43#include <polys/monomials/ring.h>
44#include <polys/monomials/p_polys.h>
45#include <polys/simpleideals.h>
46
47#include <polys/ext_fields/algext.h>
48
49/// our type has been defined as a macro in algext.h
50/// and is accessible by 'naID'
51
52/// forward declarations
53BOOLEAN  naGreaterZero(number a, const coeffs cf);
54BOOLEAN  naGreater(number a, number b, const coeffs cf);
55BOOLEAN  naEqual(number a, number b, const coeffs cf);
56BOOLEAN  naIsOne(number a, const coeffs cf);
57BOOLEAN  naIsMOne(number a, const coeffs cf);
58BOOLEAN  naIsZero(number a, const coeffs cf);
59number   naInit(int i, const coeffs cf);
60int      naInt(number &a, const coeffs cf);
61number   naNeg(number a, const coeffs cf);
62number   naInvers(number a, const coeffs cf);
63number   naPar(int i, const coeffs cf);
64number   naAdd(number a, number b, const coeffs cf);
65number   naSub(number a, number b, const coeffs cf);
66number   naMult(number a, number b, const coeffs cf);
67number   naDiv(number a, number b, const coeffs cf);
68void     naPower(number a, int exp, number *b, const coeffs cf);
69number   naCopy(number a, const coeffs cf);
70void     naWrite(number &a, const coeffs cf);
71number   naRePart(number a, const coeffs cf);
72number   naImPart(number a, const coeffs cf);
73number   naGetDenom(number &a, const coeffs cf);
74number   naGetNumerator(number &a, const coeffs cf);
75number   naGcd(number a, number b, const coeffs cf);
76number   naLcm(number a, number b, const coeffs cf);
77int      naSize(number a, const coeffs cf);
78void     naDelete(number *a, const coeffs cf);
79void     naCoeffWrite(const coeffs cf);
80number   naIntDiv(number a, number b, const coeffs cf);
81const char * naRead(const char *s, number *a, const coeffs cf);
82static BOOLEAN naCoeffIsEqual(const coeffs cf, n_coeffType n, void * param);
83
84#ifdef LDEBUG
85BOOLEAN naDBTest(number a, const char *f, const int l, const coeffs cf)
86{
87  assume(getCoeffType(cf) == naID);
88  if (a == NULL) return TRUE;
89  p_Test((poly)a, naRing);
90  assume(p_Totaldegree((poly)a, naRing) <= p_Totaldegree(naMinpoly, naRing));
91  return TRUE;
92}
93#endif
94
95void heuristicReduce(poly &p, poly reducer, const coeffs cf);
96void definiteReduce(poly &p, poly reducer, const coeffs cf);
97
98/* returns the bottom field in this field extension tower; if the tower
99   is flat, i.e., if there is no extension, then r itself is returned;
100   as a side-effect, the counter 'height' is filled with the height of
101   the extension tower (in case the tower is flat, 'height' is zero) */
102static coeffs nCoeff_bottom(const coeffs r, int &height)
103{
104  assume(r != NULL);
105  coeffs cf = r;
106  height = 0;
107  while (nCoeff_is_Extension(cf))
108  {
109    assume(cf->extRing != NULL); assume(cf->extRing->cf != NULL);
110    cf = cf->extRing->cf;
111    height++;
112  }
113  return cf;
114}
115
116BOOLEAN naIsZero(number a, const coeffs cf)
117{
118  naTest(a);
119  return (a == NULL);
120}
121
122void naDelete(number * a, const coeffs cf)
123{
124  if (*a == NULL) return;
125  poly aAsPoly = (poly)(*a);
126  p_Delete(&aAsPoly, naRing);
127  *a = NULL;
128}
129
130BOOLEAN naEqual(number a, number b, const coeffs cf)
131{
132  naTest(a); naTest(b);
133
134  /// simple tests
135  if (a == b) return TRUE;
136  if ((a == NULL) && (b != NULL)) return FALSE;
137  if ((b == NULL) && (a != NULL)) return FALSE;
138
139  /// deg test
141  if (a != NULL) aDeg = p_Totaldegree((poly)a, naRing);
142  int bDeg = 0;
143  if (b != NULL) bDeg = p_Totaldegree((poly)b, naRing);
144  if (aDeg != bDeg) return FALSE;
145
146  /// subtraction test
147  number c = naSub(a, b, cf);
148  BOOLEAN result = naIsZero(c, cf);
150  return result;
151}
152
153number naCopy(number a, const coeffs cf)
154{
155  naTest(a);
156  if (a == NULL) return NULL;
157  return (number)p_Copy((poly)a, naRing);
158}
159
160number naGetNumerator(number &a, const coeffs cf)
161{
162  return naCopy(a, cf);
163}
164
165number naGetDenom(number &a, const coeffs cf)
166{
167  naTest(a);
168  return naInit(1, cf);
169}
170
171BOOLEAN naIsOne(number a, const coeffs cf)
172{
173  naTest(a);
174  poly aAsPoly = (poly)a;
175  if (!p_IsConstant(aAsPoly, naRing)) return FALSE;
176  return n_IsOne(p_GetCoeff(aAsPoly, naRing), naCoeffs);
177}
178
179BOOLEAN naIsMOne(number a, const coeffs cf)
180{
181  naTest(a);
182  poly aAsPoly = (poly)a;
183  if (!p_IsConstant(aAsPoly, naRing)) return FALSE;
184  return n_IsMOne(p_GetCoeff(aAsPoly, naRing), naCoeffs);
185}
186
187/// this is in-place, modifies a
188number naNeg(number a, const coeffs cf)
189{
190  naTest(a);
191  if (a != NULL) a = (number)p_Neg((poly)a, naRing);
192  return a;
193}
194
195number naImPart(number a, const coeffs cf)
196{
197  naTest(a);
198  return NULL;
199}
200
201number naInit(int i, const coeffs cf)
202{
203  if (i == 0) return NULL;
204  else        return (number)p_ISet(i, naRing);
205}
206
207int naInt(number &a, const coeffs cf)
208{
209  naTest(a);
210  poly aAsPoly = (poly)a;
211  if (!p_IsConstant(aAsPoly, naRing)) return 0;
212  return n_Int(p_GetCoeff(aAsPoly, naRing), naCoeffs);
213}
214
215/* TRUE iff (a != 0 and (b == 0 or deg(a) > deg(b))) */
216BOOLEAN naGreater(number a, number b, const coeffs cf)
217{
218  naTest(a); naTest(b);
219  if (naIsZero(a, cf)) return FALSE;
220  if (naIsZero(b, cf)) return TRUE;
222  if (a != NULL) aDeg = p_Totaldegree((poly)a, naRing);
223  int bDeg = 0;
224  if (b != NULL) bDeg = p_Totaldegree((poly)b, naRing);
226}
227
228/* TRUE iff a != 0 and (LC(a) > 0 or deg(a) > 0) */
229BOOLEAN naGreaterZero(number a, const coeffs cf)
230{
231  naTest(a);
232  if (a == NULL)                                            return FALSE;
233  if (n_GreaterZero(p_GetCoeff((poly)a, naRing), naCoeffs)) return TRUE;
234  if (p_Totaldegree((poly)a, naRing) > 0)                   return TRUE;
235  return FALSE;
236}
237
238void naCoeffWrite(const coeffs cf)
239{
240  char *x = rRingVar(0, naRing);
241  Print("//   Coefficients live in the extension field K[%s]/<f(%s)>\n", x, x);
242  Print("//   with the minimal polynomial f(%s) = %s\n", x,
243        p_String(naMinpoly, naRing));
244  PrintS("//   and K: "); n_CoeffWrite(cf->extRing->cf);
245}
246
247number naPar(int i, const coeffs cf)
248{
249  assume(i == 1);   // there is only one parameter in this extension field
250  poly p = p_ISet(1, naRing);   // p = 1
251  p_SetExp(p, 1, 1, naRing);    // p = the sole extension variable
252  p_Setm(p, naRing);
253  return (number)p;
254}
255
256number naAdd(number a, number b, const coeffs cf)
257{
258  naTest(a); naTest(b);
259  if (a == NULL) return naCopy(b, cf);
260  if (b == NULL) return naCopy(a, cf);
261  poly aPlusB = p_Add_q(p_Copy((poly)a, naRing),
262                        p_Copy((poly)b, naRing), naRing);
263  definiteReduce(aPlusB, naMinpoly, cf);
264  return (number)aPlusB;
265}
266
267number naSub(number a, number b, const coeffs cf)
268{
269  naTest(a); naTest(b);
270  if (b == NULL) return naCopy(a, cf);
271  poly minusB = p_Neg(p_Copy((poly)b, naRing), naRing);
272  if (a == NULL) return (number)minusB;
273  poly aMinusB = p_Add_q(p_Copy((poly)a, naRing), minusB, naRing);
274  definiteReduce(aMinusB, naMinpoly, cf);
275  return (number)aMinusB;
276}
277
278number naMult(number a, number b, const coeffs cf)
279{
280  naTest(a); naTest(b);
281  if (a == NULL) return NULL;
282  if (b == NULL) return NULL;
283  poly aTimesB = p_Mult_q(p_Copy((poly)a, naRing),
284                          p_Copy((poly)b, naRing), naRing);
285  definiteReduce(aTimesB, naMinpoly, cf);
286  return (number)aTimesB;
287}
288
289number naDiv(number a, number b, const coeffs cf)
290{
291  naTest(a); naTest(b);
292  if (b == NULL) WerrorS(nDivBy0);
293  if (a == NULL) return NULL;
294  poly bInverse = (poly)naInvers(b, cf);
295  poly aDivB = p_Mult_q(p_Copy((poly)a, naRing), bInverse, naRing);
298}
299
300/* 0^0 = 0;
301   for |exp| <= 7 compute power by a simple multiplication loop;
302   for |exp| >= 8 compute power along binary presentation of |exp|, e.g.
303      p^13 = p^1 * p^4 * p^8, where we utilise that
304      p^(2^(k+1)) = p^(2^k) * p^(2^k);
305   intermediate reduction modulo the minimal polynomial is controlled by
306   the in-place method heuristicReduce(poly, poly, coeffs); see there.
307*/
308void naPower(number a, int exp, number *b, const coeffs cf)
309{
310  naTest(a);
311
312  /* special cases first */
313  if (a == NULL)
314  {
315    if (exp >= 0) *b = NULL;
316    else          WerrorS(nDivBy0);
317  }
318  else if (exp ==  0) *b = naInit(1, cf);
319  else if (exp ==  1) *b = naCopy(a, cf);
320  else if (exp == -1) *b = naInvers(a, cf);
321
322  int expAbs = exp; if (expAbs < 0) expAbs = -expAbs;
323
324  /* now compute a^expAbs */
325  poly pow; poly aAsPoly = (poly)a;
326  if (expAbs <= 7)
327  {
328    pow = p_Copy(aAsPoly, naRing);
329    for (int i = 2; i <= expAbs; i++)
330    {
331      pow = p_Mult_q(pow, p_Copy(aAsPoly, naRing), naRing);
332      heuristicReduce(pow, naMinpoly, cf);
333    }
334    definiteReduce(pow, naMinpoly, cf);
335  }
336  else
337  {
338    pow = p_ISet(1, naRing);
339    poly factor = p_Copy(aAsPoly, naRing);
340    while (expAbs != 0)
341    {
342      if (expAbs & 1)
343      {
344        pow = p_Mult_q(pow, p_Copy(factor, naRing), naRing);
345        heuristicReduce(pow, naMinpoly, cf);
346      }
347      expAbs = expAbs / 2;
348      if (expAbs != 0)
349      {
350        factor = p_Mult_q(factor, factor, naRing);
351        heuristicReduce(factor, naMinpoly, cf);
352      }
353    }
354    p_Delete(&factor, naRing);
355    definiteReduce(pow, naMinpoly, cf);
356  }
357
358  /* invert if original exponent was negative */
359  number n = (number)pow;
360  if (exp < 0)
361  {
362    number m = naInvers(n, cf);
364    n = m;
365  }
366  *b = n;
367}
368
369/* may reduce p modulo the reducer by calling definiteReduce;
370   the decision is made based on the following heuristic
371   (which should also only be changed here in this method):
372      if (deg(p) > 10*deg(reducer) then perform reduction;
373   modifies p */
374void heuristicReduce(poly &p, poly reducer, const coeffs cf)
375{
376  #ifdef LDEBUG
377  p_Test((poly)p, naRing);
378  p_Test((poly)reducer, naRing);
379  #endif
380  if (p_Totaldegree(p, naRing) > 10 * p_Totaldegree(reducer, naRing))
381    definiteReduce(p, reducer, cf);
382}
383
384void naWrite(number &a, const coeffs cf)
385{
386  naTest(a);
387  if (a == NULL)
388    StringAppendS("0");
389  else
390  {
391    poly aAsPoly = (poly)a;
392    /* basically, just write aAsPoly using p_Write,
393       but use brackets around the output, if a is not
394       a constant living in naCoeffs = cf->extRing->cf */
395    BOOLEAN useBrackets = !(p_IsConstant(aAsPoly, naRing));
396    if (useBrackets) StringAppendS("(");
397    p_String0(aAsPoly, naRing, naRing);
398    if (useBrackets) StringAppendS(")");
399  }
400}
401
402const char * naRead(const char *s, number *a, const coeffs cf)
403{
404  poly aAsPoly;
405  const char * result = p_Read(s, aAsPoly, naRing);
406  *a = (number)aAsPoly;
407  return result;
408}
409
410/* implemented by the rule lcm(a, b) = a * b / gcd(a, b) */
411number naLcm(number a, number b, const coeffs cf)
412{
413  naTest(a); naTest(b);
414  if (a == NULL) return NULL;
415  if (b == NULL) return NULL;
416  number theProduct = (number)p_Mult_q(p_Copy((poly)a, naRing),
417                                       p_Copy((poly)b, naRing), naRing);
418  /* note that theProduct needs not be reduced w.r.t. naMinpoly;
419     but the final division will take care of the necessary reduction */
420  number theGcd = naGcd(a, b, cf);
422}
423
424/* expects *param to be castable to AlgExtInfo */
425static BOOLEAN naCoeffIsEqual(const coeffs cf, n_coeffType n, void * param)
426{
427  if (naID != n) return FALSE;
428  AlgExtInfo *e = (AlgExtInfo *)param;
429  /* for extension coefficient fields we expect the underlying
430     polynomial rings to be IDENTICAL, i.e. the SAME OBJECT;
431     this expectation is based on the assumption that we have properly
432     registered cf and perform reference counting rather than creating
433     multiple copies of the same coefficient field/domain/ring */
434  return (naRing == e->r);
435  /* (Note that then also the minimal ideals will necessarily be
436     the same, as they are attached to the ring.) */
437}
438
439int naSize(number a, const coeffs cf)
440{
441  if (a == NULL) return -1;
442  /* this has been taken from the old implementation of field extensions,
443     where we computed the sum of the degree and the number of terms in
444     (poly)a; so we leave it at that, for the time being;
445     maybe, the number of terms alone is a better measure? */
446  poly aAsPoly = (poly)a;
447  int theDegree = 0; int noOfTerms = 0;
448  while (aAsPoly != NULL)
449  {
450    noOfTerms++;
451    int d = p_GetExp(aAsPoly, 1, naRing);
452    if (d > theDegree) theDegree = d;
453    pIter(aAsPoly);
454  }
455  return theDegree + noOfTerms;
456}
457
458/* performs polynomial division and overrides p by the remainder
459   of division of p by the reducer;
460   modifies p */
461void definiteReduce(poly &p, poly reducer, const coeffs cf)
462{
463  #ifdef LDEBUG
464  p_Test((poly)p, naRing);
465  p_Test((poly)reducer, naRing);
466  #endif
467  p_PolyDiv(p, reducer, FALSE, naRing);
468}
469
470/* IMPORTANT NOTE: Since an algebraic field extension is again a field,
471                   the gcd of two elements is not very interesting. (It
472                   is actually any unit in the field, i.e., any non-
473                   zero element.) Note that the below method does not operate
474                   in this strong sense but rather computes the gcd of
475                   two given elements in the underlying polynomial ring. */
476number naGcd(number a, number b, const coeffs cf)
477{
478  naTest(a); naTest(b);
479  if ((a == NULL) && (b == NULL)) WerrorS(nDivBy0);
480  return (number)p_Gcd((poly)a, (poly)b, naRing);
481}
482
483number naInvers(number a, const coeffs cf)
484{
485  naTest(a);
486  if (a == NULL) WerrorS(nDivBy0);
487  poly aFactor = NULL; poly mFactor = NULL;
488  poly theGcd = p_ExtGcd((poly)a, aFactor, naMinpoly, mFactor, naRing);
489  naTest((number)theGcd); naTest((number)aFactor); naTest((number)mFactor);
490  /* the gcd must be 1 since naMinpoly is irreducible and a != NULL: */
491  assume(naIsOne((number)theGcd, cf));
492  p_Delete(&theGcd, naRing);
493  p_Delete(&mFactor, naRing);
494  return (number)(aFactor);
495}
496
497/* assumes that src = Q, dst = Q(a) */
498number naMap00(number a, const coeffs src, const coeffs dst)
499{
500  if (n_IsZero(a, src)) return NULL;
501  assume(src == dst->extRing->cf);
502  poly result = p_One(dst->extRing);
503  p_SetCoeff(result, naCopy(a, src), dst->extRing);
504  return (number)result;
505}
506
507/* assumes that src = Z/p, dst = Q(a) */
508number naMapP0(number a, const coeffs src, const coeffs dst)
509{
510  if (n_IsZero(a, src)) return NULL;
511  /* mapping via intermediate int: */
512  int n = n_Int(a, src);
513  number q = n_Init(n, dst->extRing->cf);
514  poly result = p_One(dst->extRing);
515  p_SetCoeff(result, q, dst->extRing);
516  return (number)result;
517}
518
519/* assumes that either src = Q(a), dst = Q(a), or
520                       src = Z/p(a), dst = Z/p(a)     */
521number naCopyMap(number a, const coeffs src, const coeffs dst)
522{
523  return naCopy(a, dst);
524}
525
526/* assumes that src = Q, dst = Z/p(a) */
527number naMap0P(number a, const coeffs src, const coeffs dst)
528{
529  if (n_IsZero(a, src)) return NULL;
530  int p = rChar(dst->extRing);
531  int n = nlModP(a, p, src);
532  number q = n_Init(n, dst->extRing->cf);
533  poly result = p_One(dst->extRing);
534  p_SetCoeff(result, q, dst->extRing);
535  return (number)result;
536}
537
538/* assumes that src = Z/p, dst = Z/p(a) */
539number naMapPP(number a, const coeffs src, const coeffs dst)
540{
541  if (n_IsZero(a, src)) return NULL;
542  assume(src == dst->extRing->cf);
543  poly result = p_One(dst->extRing);
544  p_SetCoeff(result, naCopy(a, src), dst->extRing);
545  return (number)result;
546}
547
548/* assumes that src = Z/u, dst = Z/p(a), where u != p */
549number naMapUP(number a, const coeffs src, const coeffs dst)
550{
551  if (n_IsZero(a, src)) return NULL;
552  /* mapping via intermediate int: */
553  int n = n_Int(a, src);
554  number q = n_Init(n, dst->extRing->cf);
555  poly result = p_One(dst->extRing);
556  p_SetCoeff(result, q, dst->extRing);
557  return (number)result;
558}
559
560nMapFunc naSetMap(const coeffs src, const coeffs dst)
561{
562  /* dst is expected to be an algebraic field extension */
563  assume(getCoeffType(dst) == naID);
564
565  int h = 0; /* the height of the extension tower given by dst */
566  coeffs bDst = nCoeff_bottom(dst, h); /* the bottom field in the tower dst */
567
568  /* for the time being, we only provide maps if h = 1 and if b is Q or
569     some field Z/pZ: */
570  if (h != 1) return NULL;
571  if ((!nCoeff_is_Zp(bDst)) && (!nCoeff_is_Q(bDst))) return NULL;
572
573  if (nCoeff_is_Q(src) && nCoeff_is_Q(bDst))
574    return naMap00;                                      /// Q     -->  Q(a)
575
576  if (nCoeff_is_Zp(src) && nCoeff_is_Q(bDst))
577    return naMapP0;                                      /// Z/p   -->  Q(a)
578
579  if (nCoeff_is_Q(src) && nCoeff_is_Zp(bDst))
580    return naMap0P;                                      /// Q      --> Z/p(a)
581
582  if (nCoeff_is_Zp(src) && nCoeff_is_Zp(bDst))
583  {
584    if (src->ch == dst->ch) return naMapPP;              /// Z/p    --> Z/p(a)
585    else return naMapUP;                                 /// Z/u    --> Z/p(a)
586  }
587
588  coeffs bSrc = nCoeff_bottom(src, h); /* the bottom field in the tower src */
589  if (h != 1) return NULL;
590  if ((!nCoeff_is_Zp(bSrc)) && (!nCoeff_is_Q(bSrc))) return NULL;
591
592  if (nCoeff_is_Q(bSrc) && nCoeff_is_Q(bDst))
593  {
594    if (strcmp(rRingVar(0, src->extRing),
595               rRingVar(0, dst->extRing)) == 0)
596      return naCopyMap;                                  /// Q(a)   --> Q(a)
597    else
598      return NULL;                                       /// Q(b)   --> Q(a)
599  }
600
601  if (nCoeff_is_Zp(bSrc) && nCoeff_is_Zp(bDst))
602  {
603    if (strcmp(rParameter(src->extRing),
604               rParameter(dst->extRing)) == 0)
605      return naCopyMap;                                  /// Z/p(a) --> Z/p(a)
606    else
607      return NULL;                                       /// Z/p(b) --> Z/p(a)
608  }
609
610  return NULL;                                           /// default
611}
612
613BOOLEAN naInitChar(coeffs cf, void * infoStruct)
614{
615  AlgExtInfo *e = (AlgExtInfo *)infoStruct;
616  /// first check whether cf->extRing != NULL and delete old ring???
617  cf->extRing           = e->r;
618  cf->extRing->minideal = e->i;
619
620  assume(cf->extRing                     != NULL);      // extRing;
621  assume((cf->extRing->minideal          != NULL) &&    // minideal has one
622         (IDELEMS(cf->extRing->minideal) != 0)    &&    // non-zero generator
623         (cf->extRing->minideal->m    != NULL)    ); // at m;
624  assume(cf->extRing->cf                 != NULL);      // extRing->cf;
625  assume(getCoeffType(cf) == naID);                     // coeff type;
626
627  /* propagate characteristic up so that it becomes
628     directly accessible in cf: */
629  cf->ch = cf->extRing->cf->ch;
630
631  #ifdef LDEBUG
632  p_Test((poly)naMinpoly, naRing);
633  #endif
634
635  cf->cfGreaterZero  = naGreaterZero;
636  cf->cfGreater      = naGreater;
637  cf->cfEqual        = naEqual;
638  cf->cfIsZero       = naIsZero;
639  cf->cfIsOne        = naIsOne;
640  cf->cfIsMOne       = naIsMOne;
641  cf->cfInit         = naInit;
642  cf->cfInt          = naInt;
643  cf->cfNeg          = naNeg;
644  cf->cfPar          = naPar;
646  cf->cfSub          = naSub;
647  cf->cfMult         = naMult;
650  cf->cfPower        = naPower;
651  cf->cfCopy         = naCopy;
652  cf->cfWrite        = naWrite;
655  cf->cfSetMap       = naSetMap;
656  cf->cfGetDenom     = naGetDenom;
657  cf->cfGetNumerator = naGetNumerator;
658  cf->cfRePart       = naCopy;
659  cf->cfImPart       = naImPart;
660  cf->cfCoeffWrite   = naCoeffWrite;