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

spielwiese
Last change on this file since e961571 was e961571, checked in by Hans Schoenemann <hannes@…>, 10 years ago
fix: naGcd/naLcm
• Property mode set to `100644`
File size: 37.5 KB
Line
1/****************************************
2*  Computer Algebra System SINGULAR     *
3****************************************/
4/**
5  * ABSTRACT: numbers in an algebraic extension field K[a] / < f(a) >
6  *           Assuming that we have a coeffs object cf, then these numbers
7  *           are polynomials in the polynomial ring K[a] represented by
8  *           cf->extRing.
9  *           IMPORTANT ASSUMPTIONS:
10  *           1.) So far we assume that cf->extRing is a valid polynomial
11  *               ring in exactly one variable, i.e., K[a], where K is allowed
12  *               to be any field (representable in SINGULAR and which may
13  *               itself be some extension field, thus allowing for extension
14  *               towers).
15  *           2.) Moreover, this implementation assumes that
16  *               cf->extRing->qideal is not NULL but an ideal with at
17  *               least one non-zero generator which may be accessed by
18  *               cf->extRing->qideal->m[0] and which represents the minimal
19  *               polynomial f(a) of the extension variable 'a' in K[a].
20  *           3.) As soon as an std method for polynomial rings becomes
21  *               availabe, all reduction steps modulo f(a) should be replaced
22  *               by a call to std. Moreover, in this situation one can finally
23  *               move from K[a] / < f(a) > to
24  *                  K[a_1, ..., a_s] / I, with I some zero-dimensional ideal
25  *                                        in K[a_1, ..., a_s] given by a lex
26  *                                        GrÃ¶bner basis.
27  *               The code in algext.h and algext.cc is then capable of
28  *               computing in K[a_1, ..., a_s] / I.
29  **/
30
31#include "config.h"
32#include <misc/auxiliary.h>
33
34#include <omalloc/omalloc.h>
35
36#include <reporter/reporter.h>
37
38#include <coeffs/coeffs.h>
39#include <coeffs/numbers.h>
40#include <coeffs/longrat.h>
41
42#include <polys/monomials/ring.h>
43#include <polys/monomials/p_polys.h>
44#include <polys/simpleideals.h>
45
46#include <polys/PolyEnumerator.h>
47
48#ifdef HAVE_FACTORY
49#include <factory/factory.h>
50#include <polys/clapconv.h>
51#include <polys/clapsing.h>
52#endif
53
54
55#include <polys/ext_fields/algext.h>
56#define TRANSEXT_PRIVATES 1
57#include <polys/ext_fields/transext.h>
58
59#ifdef LDEBUG
61BOOLEAN  naDBTest(number a, const char *f, const int l, const coeffs r);
62#else
63#define naTest(a) do {} while (0)
64#endif
65
66/// Our own type!
67static const n_coeffType ID = n_algExt;
68
69/* polynomial ring in which our numbers live */
70#define naRing cf->extRing
71
72/* coeffs object in which the coefficients of our numbers live;
73 * methods attached to naCoeffs may be used to compute with the
74 * coefficients of our numbers, e.g., use naCoeffs->nAdd to add
75 * coefficients of our numbers */
76#define naCoeffs cf->extRing->cf
77
78/* minimal polynomial */
79#define naMinpoly naRing->qideal->m[0]
80
81/// forward declarations
82BOOLEAN  naGreaterZero(number a, const coeffs cf);
83BOOLEAN  naGreater(number a, number b, const coeffs cf);
84BOOLEAN  naEqual(number a, number b, const coeffs cf);
85BOOLEAN  naIsOne(number a, const coeffs cf);
86BOOLEAN  naIsMOne(number a, const coeffs cf);
87BOOLEAN  naIsZero(number a, const coeffs cf);
88number   naInit(long i, const coeffs cf);
89int      naInt(number &a, const coeffs cf);
90number   naNeg(number a, const coeffs cf);
91number   naInvers(number a, const coeffs cf);
92number   naAdd(number a, number b, const coeffs cf);
93number   naSub(number a, number b, const coeffs cf);
94number   naMult(number a, number b, const coeffs cf);
95number   naDiv(number a, number b, const coeffs cf);
96void     naPower(number a, int exp, number *b, const coeffs cf);
97number   naCopy(number a, const coeffs cf);
98void     naWriteLong(number &a, const coeffs cf);
99void     naWriteShort(number &a, const coeffs cf);
100number   naRePart(number a, const coeffs cf);
101number   naImPart(number a, const coeffs cf);
102number   naGetDenom(number &a, const coeffs cf);
103number   naGetNumerator(number &a, const coeffs cf);
104number   naGcd(number a, number b, const coeffs cf);
105//number   naLcm(number a, number b, const coeffs cf);
106int      naSize(number a, const coeffs cf);
107void     naDelete(number *a, const coeffs cf);
108void     naCoeffWrite(const coeffs cf, BOOLEAN details);
109//number   naIntDiv(number a, number b, const coeffs cf);
110const char * naRead(const char *s, number *a, const coeffs cf);
111
112static BOOLEAN naCoeffIsEqual(const coeffs cf, n_coeffType n, void * param);
113
114
115/// returns NULL if p == NULL, otherwise makes p monic by dividing
116///   by its leading coefficient (only done if this is not already 1);
117///   this assumes that we are over a ground field so that division
118///   is well-defined;
119///   modifies p
120// void      p_Monic(poly p, const ring r);
121
122///   assumes that p and q are univariate polynomials in r,
123///   mentioning the same variable;
124///   assumes a global monomial ordering in r;
125///   assumes that not both p and q are NULL;
126///   returns the gcd of p and q;
127///   leaves p and q unmodified
128// poly      p_Gcd(const poly p, const poly q, const ring r);
129
130/* returns NULL if p == NULL, otherwise makes p monic by dividing
131   by its leading coefficient (only done if this is not already 1);
132   this assumes that we are over a ground field so that division
133   is well-defined;
134   modifies p */
135static inline void p_Monic(poly p, const ring r)
136{
137  if (p == NULL) return;
138  number n = n_Init(1, r->cf);
139  if (p->next==NULL) { p_SetCoeff(p,n,r); return; }
140  poly pp = p;
141  number lc = p_GetCoeff(p, r);
142  if (n_IsOne(lc, r->cf)) return;
143  number lcInverse = n_Invers(lc, r->cf);
144  p_SetCoeff(p, n, r);   // destroys old leading coefficient!
145  pIter(p);
146  while (p != NULL)
147  {
148    number n = n_Mult(p_GetCoeff(p, r), lcInverse, r->cf);
149    n_Normalize(n,r->cf);
150    p_SetCoeff(p, n, r);   // destroys old leading coefficient!
151    pIter(p);
152  }
153  n_Delete(&lcInverse, r->cf);
154  p = pp;
155}
156
157/// see p_Gcd;
158///   additional assumption: deg(p) >= deg(q);
159///   must destroy p and q (unless one of them is returned)
160static inline poly p_GcdHelper(poly &p, poly &q, const ring r)
161{
162  while (q != NULL)
163  {
164    p_PolyDiv(p, q, FALSE, r);
165    // swap p and q:
166    poly& t = q;
167    q = p;
168    p = t;
169
170  }
171  return p;
172}
173
174/* assumes that p and q are univariate polynomials in r,
175   mentioning the same variable;
176   assumes a global monomial ordering in r;
177   assumes that not both p and q are NULL;
178   returns the gcd of p and q;
179   leaves p and q unmodified */
180static inline poly      p_Gcd(const poly p, const poly q, const ring r)
181{
182  assume((p != NULL) || (q != NULL));
183
184  poly a = p; poly b = q;
185  if (p_Deg(a, r) < p_Deg(b, r)) { a = q; b = p; }
186  a = p_Copy(a, r); b = p_Copy(b, r);
187
188  /* We have to make p monic before we return it, so that if the
189     gcd is a unit in the ground field, we will actually return 1. */
190  a = p_GcdHelper(a, b, r);
191  p_Monic(a, r);
192  return a;
193}
194
195/* see p_ExtGcd;
196   additional assumption: deg(p) >= deg(q);
197   must destroy p and q (unless one of them is returned) */
198static inline poly p_ExtGcdHelper(poly &p, poly &pFactor, poly &q, poly &qFactor,
199                                  ring r)
200{
201  if (q == NULL)
202  {
203    qFactor = NULL;
204    pFactor = p_ISet(1, r);
205    p_SetCoeff(pFactor, n_Invers(p_GetCoeff(p, r), r->cf), r);
206    p_Monic(p, r);
207    return p;
208  }
209  else
210  {
211    poly pDivQ = p_PolyDiv(p, q, TRUE, r);
212    poly ppFactor = NULL; poly qqFactor = NULL;
213    poly theGcd = p_ExtGcdHelper(q, qqFactor, p, ppFactor, r);
214    pFactor = ppFactor;
215    qFactor = p_Add_q(qqFactor,
216                      p_Neg(p_Mult_q(pDivQ, p_Copy(ppFactor, r), r), r),
217                      r);
218    return theGcd;
219  }
220}
221
222/* assumes that p and q are univariate polynomials in r,
223   mentioning the same variable;
224   assumes a global monomial ordering in r;
225   assumes that not both p and q are NULL;
226   returns the gcd of p and q;
227   moreover, afterwards pFactor and qFactor contain appropriate
228   factors such that gcd(p, q) = p * pFactor + q * qFactor;
229   leaves p and q unmodified */
230poly p_ExtGcd(poly p, poly &pFactor, poly q, poly &qFactor, ring r)
231{
232  assume((p != NULL) || (q != NULL));
233  poly a = p; poly b = q; BOOLEAN aCorrespondsToP = TRUE;
234  if (p_Deg(a, r) < p_Deg(b, r))
235    { a = q; b = p; aCorrespondsToP = FALSE; }
236  a = p_Copy(a, r); b = p_Copy(b, r);
237  poly aFactor = NULL; poly bFactor = NULL;
238  poly theGcd = p_ExtGcdHelper(a, aFactor, b, bFactor, r);
239  if (aCorrespondsToP) { pFactor = aFactor; qFactor = bFactor; }
240  else                 { pFactor = bFactor; qFactor = aFactor; }
241  return theGcd;
242}
243
244
245
246#ifdef LDEBUG
247BOOLEAN naDBTest(number a, const char *f, const int l, const coeffs cf)
248{
249  assume(getCoeffType(cf) == ID);
250  if (a == NULL) return TRUE;
251  p_Test((poly)a, naRing);
252  if((((poly)a)!=naMinpoly)
253  && p_Totaldegree((poly)a, naRing) >= p_Totaldegree(naMinpoly, naRing))
254  {
255    Print("deg >= deg(minpoly) in %s:%d\n",f,l);
256    return FALSE;
257  }
258  return TRUE;
259}
260#endif
261
262void heuristicReduce(poly &p, poly reducer, const coeffs cf);
263void definiteReduce(poly &p, poly reducer, const coeffs cf);
264
265/* returns the bottom field in this field extension tower; if the tower
266   is flat, i.e., if there is no extension, then r itself is returned;
267   as a side-effect, the counter 'height' is filled with the height of
268   the extension tower (in case the tower is flat, 'height' is zero) */
269static coeffs nCoeff_bottom(const coeffs r, int &height)
270{
271  assume(r != NULL);
272  coeffs cf = r;
273  height = 0;
274  while (nCoeff_is_Extension(cf))
275  {
276    assume(cf->extRing != NULL); assume(cf->extRing->cf != NULL);
277    cf = cf->extRing->cf;
278    height++;
279  }
280  return cf;
281}
282
283BOOLEAN naIsZero(number a, const coeffs cf)
284{
285  naTest(a);
286  return (a == NULL);
287}
288
289void naDelete(number * a, const coeffs cf)
290{
291  if (*a == NULL) return;
292  if (((poly)*a)==naMinpoly) { *a=NULL;return;}
293  poly aAsPoly = (poly)(*a);
294  p_Delete(&aAsPoly, naRing);
295  *a = NULL;
296}
297
298BOOLEAN naEqual(number a, number b, const coeffs cf)
299{
300  naTest(a); naTest(b);
301  /// simple tests
302  if (a == NULL) return (b == NULL);
303  if (b == NULL) return (a == NULL);
304  return p_EqualPolys((poly)a,(poly)b,naRing);
305}
306
307number naCopy(number a, const coeffs cf)
308{
309  naTest(a);
310  if (a == NULL) return NULL;
311  if (((poly)a)==naMinpoly) return a;
312  return (number)p_Copy((poly)a, naRing);
313}
314
315number naGetNumerator(number &a, const coeffs cf)
316{
317  return naCopy(a, cf);
318}
319
320number naGetDenom(number &a, const coeffs cf)
321{
322  naTest(a);
323  return naInit(1, cf);
324}
325
326BOOLEAN naIsOne(number a, const coeffs cf)
327{
328  naTest(a);
329  poly aAsPoly = (poly)a;
330  if ((a==NULL) || (!p_IsConstant(aAsPoly, naRing))) return FALSE;
331  return n_IsOne(p_GetCoeff(aAsPoly, naRing), naCoeffs);
332}
333
334BOOLEAN naIsMOne(number a, const coeffs cf)
335{
336  naTest(a);
337  poly aAsPoly = (poly)a;
338  if ((a==NULL) || (!p_IsConstant(aAsPoly, naRing))) return FALSE;
339  return n_IsMOne(p_GetCoeff(aAsPoly, naRing), naCoeffs);
340}
341
342/// this is in-place, modifies a
343number naNeg(number a, const coeffs cf)
344{
345  naTest(a);
346  if (a != NULL) a = (number)p_Neg((poly)a, naRing);
347  return a;
348}
349
350number naImPart(number a, const coeffs cf)
351{
352  naTest(a);
353  return NULL;
354}
355
356number naInit_bigint(number longratBigIntNumber, const coeffs src, const coeffs cf)
357{
358  assume( cf != NULL );
359
360  const ring A = cf->extRing;
361
362  assume( A != NULL );
363
364  const coeffs C = A->cf;
365
366  assume( C != NULL );
367
368  number n = n_Init_bigint(longratBigIntNumber, src, C);
369
370  if ( n_IsZero(n, C) )
371  {
372    n_Delete(&n, C);
373    return NULL;
374  }
375
376  return (number)p_NSet(n, A);
377}
378
379
380
381number naInit(long i, const coeffs cf)
382{
383  if (i == 0) return NULL;
384  else        return (number)p_ISet(i, naRing);
385}
386
387int naInt(number &a, const coeffs cf)
388{
389  naTest(a);
390  poly aAsPoly = (poly)a;
391  if(aAsPoly == NULL)
392    return 0;
393  if (!p_IsConstant(aAsPoly, naRing))
394    return 0;
395  assume( aAsPoly != NULL );
396  return n_Int(p_GetCoeff(aAsPoly, naRing), naCoeffs);
397}
398
399/* TRUE iff (a != 0 and (b == 0 or deg(a) > deg(b) or (deg(a)==deg(b) && lc(a)>lc(b))) */
400BOOLEAN naGreater(number a, number b, const coeffs cf)
401{
402  naTest(a); naTest(b);
403  if (naIsZero(a, cf))
404  {
405    if (naIsZero(b, cf)) return FALSE;
406    return !n_GreaterZero(pGetCoeff((poly)b),cf);
407  }
408  if (naIsZero(b, cf))
409  {
410    return n_GreaterZero(pGetCoeff((poly)a),cf);
411  }
412  int aDeg = p_Totaldegree((poly)a, naRing);
413  int bDeg = p_Totaldegree((poly)b, naRing);
414  if (aDeg>bDeg) return TRUE;
415  if (aDeg<bDeg) return FALSE;
416  return n_Greater(pGetCoeff((poly)a),pGetCoeff((poly)b),naCoeffs);
417}
418
419/* TRUE iff a != 0 and (LC(a) > 0 or deg(a) > 0) */
420BOOLEAN naGreaterZero(number a, const coeffs cf)
421{
422  naTest(a);
423  if (a == NULL)                                            return FALSE;
424  if (n_GreaterZero(p_GetCoeff((poly)a, naRing), naCoeffs)) return TRUE;
425  if (p_Totaldegree((poly)a, naRing) > 0)                   return TRUE;
426  return FALSE;
427}
428
429void naCoeffWrite(const coeffs cf, BOOLEAN details)
430{
431  assume( cf != NULL );
432
433  const ring A = cf->extRing;
434
435  assume( A != NULL );
436  assume( A->cf != NULL );
437
438  n_CoeffWrite(A->cf, details);
439
440//  rWrite(A);
441
442  const int P = rVar(A);
443  assume( P > 0 );
444
445  Print("//   %d parameter    : ", P);
446
447  for (int nop=0; nop < P; nop ++)
448    Print("%s ", rRingVar(nop, A));
449
450  PrintLn();
451
452  const ideal I = A->qideal;
453
454  assume( I != NULL );
455  assume( IDELEMS(I) == 1 );
456
457
458  if ( details )
459  {
460    PrintS("//   minpoly        : (");
461    p_Write0( I->m[0], A);
462    PrintS(")");
463  }
464  else
465    PrintS("//   minpoly        : ...");
466
467  PrintLn();
468
469/*
470  char *x = rRingVar(0, A);
471
472  Print("//   Coefficients live in the extension field K[%s]/<f(%s)>\n", x, x);
473  Print("//   with the minimal polynomial f(%s) = %s\n", x,
474        p_String(A->qideal->m[0], A));
475  PrintS("//   and K: ");
476*/
477}
478
479number naAdd(number a, number b, const coeffs cf)
480{
481  naTest(a); naTest(b);
482  if (a == NULL) return naCopy(b, cf);
483  if (b == NULL) return naCopy(a, cf);
484  poly aPlusB = p_Add_q(p_Copy((poly)a, naRing),
485                        p_Copy((poly)b, naRing), naRing);
486  definiteReduce(aPlusB, naMinpoly, cf);
487  return (number)aPlusB;
488}
489
490number naSub(number a, number b, const coeffs cf)
491{
492  naTest(a); naTest(b);
493  if (b == NULL) return naCopy(a, cf);
494  poly minusB = p_Neg(p_Copy((poly)b, naRing), naRing);
495  if (a == NULL) return (number)minusB;
496  poly aMinusB = p_Add_q(p_Copy((poly)a, naRing), minusB, naRing);
497  definiteReduce(aMinusB, naMinpoly, cf);
498  return (number)aMinusB;
499}
500
501number naMult(number a, number b, const coeffs cf)
502{
503  naTest(a); naTest(b);
504  if ((a == NULL)||(b == NULL)) return NULL;
505  poly aTimesB = p_Mult_q(p_Copy((poly)a, naRing),
506                          p_Copy((poly)b, naRing), naRing);
507  p_Normalize(aTimesB,naRing);
508  definiteReduce(aTimesB, naMinpoly, cf);
509  return (number)aTimesB;
510}
511
512number naDiv(number a, number b, const coeffs cf)
513{
514  naTest(a); naTest(b);
515  if (b == NULL) WerrorS(nDivBy0);
516  if (a == NULL) return NULL;
517  poly bInverse = (poly)naInvers(b, cf);
518  if(bInverse != NULL) // b is non-zero divisor!
519  {
520    poly aDivB = p_Mult_q(p_Copy((poly)a, naRing), bInverse, naRing);
521    definiteReduce(aDivB, naMinpoly, cf);
523  }
524  return NULL;
525}
526
527/* 0^0 = 0;
528   for |exp| <= 7 compute power by a simple multiplication loop;
529   for |exp| >= 8 compute power along binary presentation of |exp|, e.g.
530      p^13 = p^1 * p^4 * p^8, where we utilise that
531      p^(2^(k+1)) = p^(2^k) * p^(2^k);
532   intermediate reduction modulo the minimal polynomial is controlled by
533   the in-place method heuristicReduce(poly, poly, coeffs); see there.
534*/
535void naPower(number a, int exp, number *b, const coeffs cf)
536{
537  naTest(a);
538
539  /* special cases first */
540  if (a == NULL)
541  {
542    if (exp >= 0) *b = NULL;
543    else          WerrorS(nDivBy0);
544    return;
545  }
546  else if (exp ==  0) { *b = naInit(1, cf); return; }
547  else if (exp ==  1) { *b = naCopy(a, cf); return; }
548  else if (exp == -1) { *b = naInvers(a, cf); return; }
549
550  int expAbs = exp; if (expAbs < 0) expAbs = -expAbs;
551
552  /* now compute a^expAbs */
553  poly pow; poly aAsPoly = (poly)a;
554  if (expAbs <= 7)
555  {
556    pow = p_Copy(aAsPoly, naRing);
557    for (int i = 2; i <= expAbs; i++)
558    {
559      pow = p_Mult_q(pow, p_Copy(aAsPoly, naRing), naRing);
560      heuristicReduce(pow, naMinpoly, cf);
561    }
562    definiteReduce(pow, naMinpoly, cf);
563  }
564  else
565  {
566    pow = p_ISet(1, naRing);
567    poly factor = p_Copy(aAsPoly, naRing);
568    while (expAbs != 0)
569    {
570      if (expAbs & 1)
571      {
572        pow = p_Mult_q(pow, p_Copy(factor, naRing), naRing);
573        heuristicReduce(pow, naMinpoly, cf);
574      }
575      expAbs = expAbs / 2;
576      if (expAbs != 0)
577      {
578        factor = p_Mult_q(factor, p_Copy(factor, naRing), naRing);
579        heuristicReduce(factor, naMinpoly, cf);
580      }
581    }
582    p_Delete(&factor, naRing);
583    definiteReduce(pow, naMinpoly, cf);
584  }
585
586  /* invert if original exponent was negative */
587  number n = (number)pow;
588  if (exp < 0)
589  {
590    number m = naInvers(n, cf);
592    n = m;
593  }
594  *b = n;
595}
596
597/* may reduce p modulo the reducer by calling definiteReduce;
598   the decision is made based on the following heuristic
599   (which should also only be changed here in this method):
600      if (deg(p) > 10*deg(reducer) then perform reduction;
601   modifies p */
602void heuristicReduce(poly &p, poly reducer, const coeffs cf)
603{
604  #ifdef LDEBUG
605  p_Test((poly)p, naRing);
606  p_Test((poly)reducer, naRing);
607  #endif
608  if (p_Totaldegree(p, naRing) > 10 * p_Totaldegree(reducer, naRing))
609    definiteReduce(p, reducer, cf);
610}
611
612void naWriteLong(number &a, const coeffs cf)
613{
614  naTest(a);
615  if (a == NULL)
616    StringAppendS("0");
617  else
618  {
619    poly aAsPoly = (poly)a;
620    /* basically, just write aAsPoly using p_Write,
621       but use brackets around the output, if a is not
622       a constant living in naCoeffs = cf->extRing->cf */
623    BOOLEAN useBrackets = !(p_IsConstant(aAsPoly, naRing));
624    if (useBrackets) StringAppendS("(");
625    p_String0Long(aAsPoly, naRing, naRing);
626    if (useBrackets) StringAppendS(")");
627  }
628}
629
630void naWriteShort(number &a, const coeffs cf)
631{
632  naTest(a);
633  if (a == NULL)
634    StringAppendS("0");
635  else
636  {
637    poly aAsPoly = (poly)a;
638    /* basically, just write aAsPoly using p_Write,
639       but use brackets around the output, if a is not
640       a constant living in naCoeffs = cf->extRing->cf */
641    BOOLEAN useBrackets = !(p_IsConstant(aAsPoly, naRing));
642    if (useBrackets) StringAppendS("(");
643    p_String0Short(aAsPoly, naRing, naRing);
644    if (useBrackets) StringAppendS(")");
645  }
646}
647
648const char * naRead(const char *s, number *a, const coeffs cf)
649{
650  poly aAsPoly;
651  const char * result = p_Read(s, aAsPoly, naRing);
652  definiteReduce(aAsPoly, naMinpoly, cf);
653  *a = (number)aAsPoly;
654  return result;
655}
656
657#if 0
658/* implemented by the rule lcm(a, b) = a * b / gcd(a, b) */
659number naLcm(number a, number b, const coeffs cf)
660{
661  naTest(a); naTest(b);
662  if (a == NULL) return NULL;
663  if (b == NULL) return NULL;
664  number theProduct = (number)p_Mult_q(p_Copy((poly)a, naRing),
665                                       p_Copy((poly)b, naRing), naRing);
666  /* note that theProduct needs not be reduced w.r.t. naMinpoly;
667     but the final division will take care of the necessary reduction */
668  number theGcd = naGcd(a, b, cf);
669  return naDiv(theProduct, theGcd, cf);
670}
671#endif
672number napLcm(number b, const coeffs cf)
673{
674  number h=n_Init(1,naRing->cf);
675  poly bb=(poly)b;
676  number d;
677  while(bb!=NULL)
678  {
679    d=n_Lcm(h,pGetCoeff(bb), naRing->cf);
680    n_Delete(&h,naRing->cf);
681    h=d;
682    pIter(bb);
683  }
684}
685number naLcmContent(number a, number b, const coeffs cf)
686{
687  if (nCoeff_is_Zp(naRing->cf)) return naCopy(a,cf);
688  else return ndGcd(a,b,cf);
689  #if 0
690  {
691    a=(number)p_Copy((poly)a,naRing);
692    number t=napLcm(b,cf);
693    if(!naIsOne(t,cf))
694    {
695      number bt, rr;
696      poly xx=(poly)a;
697      while (xx!=NULL)
698      {
699        bt = n_Gcd(t, pGetCoeff(xx), naRing->cf);
700        rr = n_Mult(t, pGetCoeff(xx), naRing->cf);
701        n_Delete(&pGetCoeff(xx),naRing->cf);
702        pGetCoeff(xx) = n_Div(rr, bt, naRing->cf);
703        n_Normalize(pGetCoeff(xx),naRing->cf);
704        n_Delete(&bt,naRing->cf);
705        n_Delete(&rr,naRing->cf);
706        pIter(xx);
707      }
708    }
709    n_Delete(&t,naRing->cf);
710    return (number) a;
711  }
712  #endif
713}
714
715/* expects *param to be castable to AlgExtInfo */
716static BOOLEAN naCoeffIsEqual(const coeffs cf, n_coeffType n, void * param)
717{
718  if (ID != n) return FALSE;
719  AlgExtInfo *e = (AlgExtInfo *)param;
720  /* for extension coefficient fields we expect the underlying
721     polynomial rings to be IDENTICAL, i.e. the SAME OBJECT;
722     this expectation is based on the assumption that we have properly
723     registered cf and perform reference counting rather than creating
724     multiple copies of the same coefficient field/domain/ring */
725  if (naRing == e->r)
726    return TRUE;
727  /* (Note that then also the minimal ideals will necessarily be
728     the same, as they are attached to the ring.) */
729
730  // NOTE: Q(a)[x] && Q(a)[y] should better share the _same_ Q(a)...
731  if( rEqual(naRing, e->r, TRUE) ) // also checks the equality of qideals
732  {
733    const ideal mi = naRing->qideal;
734    assume( IDELEMS(mi) == 1 );
735    const ideal ii = e->r->qideal;
736    assume( IDELEMS(ii) == 1 );
737
738    // TODO: the following should be extended for 2 *equal* rings...
739    assume( p_EqualPolys(mi->m[0], ii->m[0], naRing, e->r) );
740
741    rDelete(e->r);
742
743    return TRUE;
744  }
745
746  return FALSE;
747
748}
749
750int naSize(number a, const coeffs cf)
751{
752  if (a == NULL) return -1;
753  /* this has been taken from the old implementation of field extensions,
754     where we computed the sum of the degree and the number of terms in
755     (poly)a; so we leave it at that, for the time being;
756     maybe, the number of terms alone is a better measure? */
757  poly aAsPoly = (poly)a;
758  int theDegree = 0; int noOfTerms = 0;
759  while (aAsPoly != NULL)
760  {
761    noOfTerms++;
762    int d = p_GetExp(aAsPoly, 1, naRing);
763    if (d > theDegree) theDegree = d;
764    pIter(aAsPoly);
765  }
766  return theDegree + noOfTerms;
767}
768
769/* performs polynomial division and overrides p by the remainder
770   of division of p by the reducer;
771   modifies p */
772void definiteReduce(poly &p, poly reducer, const coeffs cf)
773{
774  #ifdef LDEBUG
775  p_Test((poly)p, naRing);
776  p_Test((poly)reducer, naRing);
777  #endif
778  if ((p!=NULL) && (p_GetExp(p,1,naRing)>=p_GetExp(reducer,1,naRing)))
779  {
780    p_PolyDiv(p, reducer, FALSE, naRing);
781  }
782}
783
784void  naNormalize(number &a, const coeffs cf)
785{
786  poly aa=(poly)a;
787  if (aa!=naMinpoly)
788    definiteReduce(aa,naMinpoly,cf);
789  a=(number)aa;
790}
791
792#ifdef HAVE_FACTORY
793number naConvFactoryNSingN( const CanonicalForm n, const coeffs cf)
794{
795  if (n.isZero()) return NULL;
796  poly p=convFactoryPSingP(n,naRing);
797  return (number)p;
798}
799CanonicalForm naConvSingNFactoryN( number n, BOOLEAN /*setChar*/, const coeffs cf )
800{
801  naTest(n);
802  if (n==NULL) return CanonicalForm(0);
803
804  return convSingPFactoryP((poly)n,naRing);
805}
806#endif
807
808
809/* IMPORTANT NOTE: Since an algebraic field extension is again a field,
810                   the gcd of two elements is not very interesting. (It
811                   is actually any unit in the field, i.e., any non-
812                   zero element.) Note that the below method does not operate
813                   in this strong sense but rather computes the gcd of
814                   two given elements in the underlying polynomial ring. */
815number naGcd(number a, number b, const coeffs cf)
816{
817  if (a==NULL)  return naCopy(b,cf);
818  if (b==NULL)  return naCopy(a,cf);
819
820  poly ax=(poly)a;
821  poly bx=(poly)b;
822  if (pNext(ax)!=NULL)
823    return (number)p_Copy(ax, naRing);
824  else
825  {
826    if(nCoeff_is_Zp(naRing->cf))
827      return naInit(1,cf);
828    else
829    {
830      number x = n_Copy(pGetCoeff((poly)a),naRing->cf);
831      if (n_IsOne(x,naRing->cf))
832        return (number)p_NSet(x,naRing);
833      while (pNext(ax)!=NULL)
834      {
835        pIter(ax);
836        number y = n_Gcd(x, pGetCoeff(ax), naRing->cf);
837        n_Delete(&x,naRing->cf);
838        x = y;
839        if (n_IsOne(x,naRing->cf))
840          return (number)p_NSet(x,naRing);
841      }
842      do
843      {
844        number y = n_Gcd(x, pGetCoeff(bx), naRing->cf);
845        n_Delete(&x,naRing->cf);
846        x = y;
847        if (n_IsOne(x,naRing->cf))
848          return (number)p_NSet(x,naRing);
849        pIter(bx);
850      }
851      while (bx!=NULL);
852      return (number)p_NSet(x,naRing);
853    }
854  }
855#if 0
856  naTest(a); naTest(b);
857  const ring R = naRing;
858  return (number) singclap_gcd(p_Copy((poly)a, R), p_Copy((poly)b, R), R);
859#endif
860//  return (number)p_Gcd((poly)a, (poly)b, naRing);
861}
862
863number naInvers(number a, const coeffs cf)
864{
865  naTest(a);
866  if (a == NULL) WerrorS(nDivBy0);
867
868  poly aFactor = NULL; poly mFactor = NULL; poly theGcd = NULL;
869// singclap_extgcd!
870  const BOOLEAN ret = singclap_extgcd ((poly)a, naMinpoly, theGcd, aFactor, mFactor, naRing);
871
872  assume( !ret );
873
874//  if( ret ) theGcd = p_ExtGcd((poly)a, aFactor, naMinpoly, mFactor, naRing);
875
876  naTest((number)theGcd); naTest((number)aFactor); naTest((number)mFactor);
877  p_Delete(&mFactor, naRing);
878
879  //  /* the gcd must be 1 since naMinpoly is irreducible and a != NULL: */
880  //  assume(naIsOne((number)theGcd, cf));
881
882  if( !naIsOne((number)theGcd, cf) )
883  {
884    WerrorS("zero divisor found - your minpoly is not irreducible");
885    p_Delete(&aFactor, naRing); aFactor = NULL;
886  }
887  p_Delete(&theGcd, naRing);
888
889  return (number)(aFactor);
890}
891
892/* assumes that src = Q, dst = Q(a) */
893number naMap00(number a, const coeffs src, const coeffs dst)
894{
895  if (n_IsZero(a, src)) return NULL;
896  assume(src == dst->extRing->cf);
897  poly result = p_One(dst->extRing);
898  p_SetCoeff(result, n_Copy(a, src), dst->extRing);
899  return (number)result;
900}
901
902/* assumes that src = Z/p, dst = Q(a) */
903number naMapP0(number a, const coeffs src, const coeffs dst)
904{
905  if (n_IsZero(a, src)) return NULL;
906  /* mapping via intermediate int: */
907  int n = n_Int(a, src);
908  number q = n_Init(n, dst->extRing->cf);
909  poly result = p_One(dst->extRing);
910  p_SetCoeff(result, q, dst->extRing);
911  return (number)result;
912}
913
914#if 0
915/* assumes that either src = Q(a), dst = Q(a), or
916                       src = Z/p(a), dst = Z/p(a)     */
917number naCopyMap(number a, const coeffs src, const coeffs dst)
918{
919  return naCopy(a, dst);
920}
921#endif
922
923number naCopyExt(number a, const coeffs src, const coeffs)
924{
925  fraction fa=(fraction)a;
926  return (number)p_Copy(NUM(fa),src->extRing);
927}
928
929/* assumes that src = Q, dst = Z/p(a) */
930number naMap0P(number a, const coeffs src, const coeffs dst)
931{
932  if (n_IsZero(a, src)) return NULL;
933  int p = rChar(dst->extRing);
934
935  number q = nlModP(a, src, dst->extRing->cf);
936
937  poly result = p_NSet(q, dst->extRing);
938
939  return (number)result;
940}
941
942/* assumes that src = Z/p, dst = Z/p(a) */
943number naMapPP(number a, const coeffs src, const coeffs dst)
944{
945  if (n_IsZero(a, src)) return NULL;
946  assume(src == dst->extRing->cf);
947  poly result = p_One(dst->extRing);
948  p_SetCoeff(result, n_Copy(a, src), dst->extRing);
949  return (number)result;
950}
951
952/* assumes that src = Z/u, dst = Z/p(a), where u != p */
953number naMapUP(number a, const coeffs src, const coeffs dst)
954{
955  if (n_IsZero(a, src)) return NULL;
956  /* mapping via intermediate int: */
957  int n = n_Int(a, src);
958  number q = n_Init(n, dst->extRing->cf);
959  poly result = p_One(dst->extRing);
960  p_SetCoeff(result, q, dst->extRing);
961  return (number)result;
962}
963
964nMapFunc naSetMap(const coeffs src, const coeffs dst)
965{
966  /* dst is expected to be an algebraic field extension */
967  assume(getCoeffType(dst) == ID);
968
969  if( src == dst ) return ndCopyMap;
970
971  int h = 0; /* the height of the extension tower given by dst */
972  coeffs bDst = nCoeff_bottom(dst, h); /* the bottom field in the tower dst */
973  coeffs bSrc = nCoeff_bottom(src, h); /* the bottom field in the tower src */
974
975  /* for the time being, we only provide maps if h = 1 and if b is Q or
976     some field Z/pZ: */
977  if (h==0)
978  {
979    if (nCoeff_is_Q(src) && nCoeff_is_Q(bDst))
980      return naMap00;                            /// Q     -->  Q(a)
981    if (nCoeff_is_Zp(src) && nCoeff_is_Q(bDst))
982      return naMapP0;                            /// Z/p   -->  Q(a)
983    if (nCoeff_is_Q(src) && nCoeff_is_Zp(bDst))
984      return naMap0P;                            /// Q      --> Z/p(a)
985    if (nCoeff_is_Zp(src) && nCoeff_is_Zp(bDst))
986    {
987      if (src->ch == dst->ch) return naMapPP;    /// Z/p    --> Z/p(a)
988      else return naMapUP;                       /// Z/u    --> Z/p(a)
989    }
990  }
991  if (h != 1) return NULL;
992  if ((!nCoeff_is_Zp(bDst)) && (!nCoeff_is_Q(bDst))) return NULL;
993  if ((!nCoeff_is_Zp(bSrc)) && (!nCoeff_is_Q(bSrc))) return NULL;
994
995  if (nCoeff_is_Q(bSrc) && nCoeff_is_Q(bDst))
996  {
997    if (strcmp(rRingVar(0, src->extRing),
998               rRingVar(0, dst->extRing)) == 0)
999    {
1000      if (src->type==n_algExt)
1001         return ndCopyMap; // naCopyMap;         /// Q(a)   --> Q(a)
1002      else
1003         return naCopyExt;
1004    }
1005    else
1006      return NULL;                               /// Q(b)   --> Q(a)
1007  }
1008
1009  if (nCoeff_is_Zp(bSrc) && nCoeff_is_Zp(bDst))
1010  {
1011    if (strcmp(rRingVar(0,src->extRing),rRingVar(0,dst->extRing))==0)
1012    {
1013      if (src->type==n_algExt)
1014        return ndCopyMap; // naCopyMap;          /// Z/p(a) --> Z/p(a)
1015      else
1016         return naCopyExt;
1017    }
1018    else
1019      return NULL;                               /// Z/p(b) --> Z/p(a)
1020  }
1021
1022  return NULL;                                           /// default
1023}
1024
1025static int naParDeg(number a, const coeffs cf)
1026{
1027  if (a == NULL) return -1;
1028  poly aa=(poly)a;
1029  return cf->extRing->pFDeg(aa,cf->extRing);
1030}
1031
1032/// return the specified parameter as a number in the given alg. field
1033static number naParameter(const int iParameter, const coeffs cf)
1034{
1035  assume(getCoeffType(cf) == ID);
1036
1037  const ring R = cf->extRing;
1038  assume( R != NULL );
1039  assume( 0 < iParameter && iParameter <= rVar(R) );
1040
1041  poly p = p_One(R); p_SetExp(p, iParameter, 1, R); p_Setm(p, R);
1042
1043  return (number) p;
1044}
1045
1046
1047/// if m == var(i)/1 => return i,
1048int naIsParam(number m, const coeffs cf)
1049{
1050  assume(getCoeffType(cf) == ID);
1051
1052  const ring R = cf->extRing;
1053  assume( R != NULL );
1054
1055  return p_Var( (poly)m, R );
1056}
1057
1058
1059static void naClearContent(ICoeffsEnumerator& numberCollectionEnumerator, number& c, const coeffs cf)
1060{
1061  assume(cf != NULL);
1062  assume(getCoeffType(cf) == ID);
1063  assume(nCoeff_is_Q_algext(cf)); // only over (Q[a]/m(a)), while the default impl. is used over Zp[a]/m(a) !
1064
1065  const ring   R = cf->extRing;
1066  assume(R != NULL);
1067  const coeffs Q = R->cf;
1068  assume(Q != NULL);
1069  assume(nCoeff_is_Q(Q));
1070
1071  numberCollectionEnumerator.Reset();
1072
1073  if( !numberCollectionEnumerator.MoveNext() ) // empty zero polynomial?
1074  {
1075    c = n_Init(1, cf);
1076    return;
1077  }
1078
1079  naTest(numberCollectionEnumerator.Current());
1080
1081  // part 1, find a small candidate for gcd
1082  int s1; int s=2147483647; // max. int
1083
1084  const BOOLEAN lc_is_pos=naGreaterZero(numberCollectionEnumerator.Current(),cf);
1085
1086  int normalcount = 0;
1087
1088  poly cand1, cand;
1089
1090  do
1091  {
1092    number& n = numberCollectionEnumerator.Current();
1093    naNormalize(n, cf); ++normalcount;
1094
1095    naTest(n);
1096
1097    cand1 = (poly)n;
1098
1099    s1 = p_Deg(cand1, R); // naSize?
1100    if (s>s1)
1101    {
1102      cand = cand1;
1103      s = s1;
1104    }
1105  } while (numberCollectionEnumerator.MoveNext() );
1106
1107//  assume( nlGreaterZero(cand,cf) ); // cand may be a negative integer!
1108
1109  cand = p_Copy(cand, R);
1110  // part 2: compute gcd(cand,all coeffs)
1111
1112  numberCollectionEnumerator.Reset();
1113
1114  int length = 0;
1115  while (numberCollectionEnumerator.MoveNext() )
1116  {
1117    number& n = numberCollectionEnumerator.Current();
1118    ++length;
1119
1120    if( (--normalcount) <= 0)
1121      naNormalize(n, cf);
1122
1123    naTest(n);
1124
1125//    p_InpGcd(cand, (poly)n, R);
1126
1127    cand = singclap_gcd(cand, p_Copy((poly)n, R), R);
1128
1129//    cand1 = p_Gcd(cand,(poly)n, R); p_Delete(&cand, R); cand = cand1;
1130
1131    assume( naGreaterZero((number)cand, cf) ); // ???
1132/*
1133    if(p_IsConstant(cand,R))
1134    {
1135      c = cand;
1136
1137      if(!lc_is_pos)
1138      {
1139        // make the leading coeff positive
1140        c = nlNeg(c, cf);
1141        numberCollectionEnumerator.Reset();
1142
1143        while (numberCollectionEnumerator.MoveNext() )
1144        {
1145          number& nn = numberCollectionEnumerator.Current();
1146          nn = nlNeg(nn, cf);
1147        }
1148      }
1149      return;
1150    }
1151*/
1152
1153  }
1154
1155  // part3: all coeffs = all coeffs / cand
1156  if (!lc_is_pos)
1157    cand = p_Neg(cand, R);
1158
1159  c = (number)cand; naTest(c);
1160
1161  poly cInverse = (poly)naInvers(c, cf);
1162  assume(cInverse != NULL); // c is non-zero divisor!?
1163
1164
1165  numberCollectionEnumerator.Reset();
1166
1167
1168  while (numberCollectionEnumerator.MoveNext() )
1169  {
1170    number& n = numberCollectionEnumerator.Current();
1171
1172    assume( length > 0 );
1173
1174    if( --length > 0 )
1175    {
1176      assume( cInverse != NULL );
1177      n = (number) p_Mult_q(p_Copy(cInverse, R), (poly)n, R);
1178    }
1179    else
1180    {
1181      n = (number) p_Mult_q(cInverse, (poly)n, R);
1182      cInverse = NULL;
1183      assume(length == 0);
1184    }
1185
1186    definiteReduce((poly &)n, naMinpoly, cf);
1187  }
1188
1189  assume(length == 0);
1190  assume(cInverse == NULL); //   p_Delete(&cInverse, R);
1191
1192  // Quick and dirty fix for constant content clearing... !?
1193  CRecursivePolyCoeffsEnumerator<NAConverter> itr(numberCollectionEnumerator); // recursively treat the numbers as polys!
1194
1195  number cc;
1196
1197  n_ClearContent(itr, cc, Q); // TODO: get rid of (-LC) normalization!?
1198
1199  // over alg. ext. of Q // takes over the input number
1200  c = (number) p_Mult_nn( (poly)c, cc, R);
1201//      p_Mult_q(p_NSet(cc, R), , R);
1202
1203  n_Delete(&cc, Q);
1204
1205  // TODO: the above is not enough! need GCD's of polynomial coeffs...!
1206/*
1207  // old and wrong part of p_Content
1208    if (rField_is_Q_a(r) && !CLEARENUMERATORS) // should not be used anymore if CLEARENUMERATORS is 1
1209    {
1210      // we only need special handling for alg. ext.
1211      if (getCoeffType(r->cf)==n_algExt)
1212      {
1213        number hzz = n_Init(1, r->cf->extRing->cf);
1214        p=ph;
1215        while (p!=NULL)
1216        { // each monom: coeff in Q_a
1217          poly c_n_n=(poly)pGetCoeff(p);
1218          poly c_n=c_n_n;
1219          while (c_n!=NULL)
1220          { // each monom: coeff in Q
1221            d=n_Lcm(hzz,pGetCoeff(c_n),r->cf->extRing->cf);
1222            n_Delete(&hzz,r->cf->extRing->cf);
1223            hzz=d;
1224            pIter(c_n);
1225          }
1226          pIter(p);
1227        }
1228        // hzz contains the 1/lcm of all denominators in c_n_n
1229        h=n_Invers(hzz,r->cf->extRing->cf);
1230        n_Delete(&hzz,r->cf->extRing->cf);
1231        n_Normalize(h,r->cf->extRing->cf);
1232        if(!n_IsOne(h,r->cf->extRing->cf))
1233        {
1234          p=ph;
1235          while (p!=NULL)
1236          { // each monom: coeff in Q_a
1237            poly c_n=(poly)pGetCoeff(p);
1238            while (c_n!=NULL)
1239            { // each monom: coeff in Q
1240              d=n_Mult(h,pGetCoeff(c_n),r->cf->extRing->cf);
1241              n_Normalize(d,r->cf->extRing->cf);
1242              n_Delete(&pGetCoeff(c_n),r->cf->extRing->cf);
1243              pGetCoeff(c_n)=d;
1244              pIter(c_n);
1245            }
1246            pIter(p);
1247          }
1248        }
1249        n_Delete(&h,r->cf->extRing->cf);
1250      }
1251    }
1252*/
1253
1254
1255//  c = n_Init(1, cf); assume(FALSE); // TODO: NOT YET IMPLEMENTED!!!
1256}
1257
1258
1259static void naClearDenominators(ICoeffsEnumerator& numberCollectionEnumerator, number& c, const coeffs cf)
1260{
1261  assume(cf != NULL);
1262  assume(getCoeffType(cf) == ID);
1263  assume(nCoeff_is_Q_algext(cf)); // only over (Q[a]/m(a)), while the default impl. is used over Zp[a]/m(a) !
1264
1265  assume(cf->extRing != NULL);
1266  const coeffs Q = cf->extRing->cf;
1267  assume(Q != NULL);
1268  assume(nCoeff_is_Q(Q));
1269  number n;
1270  CRecursivePolyCoeffsEnumerator<NAConverter> itr(numberCollectionEnumerator); // recursively treat the numbers as polys!
1271  n_ClearDenominators(itr, n, Q); // this should probably be fine...
1272  c = (number)p_NSet(n, cf->extRing); // over alg. ext. of Q // takes over the input number
1273}
1274
1275void naKillChar(coeffs cf)
1276{
1277   if ((--cf->extRing->ref) == 0)
1278     rDelete(cf->extRing);
1279}
1280
1281
1282
1283BOOLEAN naInitChar(coeffs cf, void * infoStruct)
1284{
1285  assume( infoStruct != NULL );
1286
1287  AlgExtInfo *e = (AlgExtInfo *)infoStruct;
1288  /// first check whether cf->extRing != NULL and delete old ring???
1289
1290  assume(e->r                     != NULL);      // extRing;
1291  assume(e->r->cf                 != NULL);      // extRing->cf;
1292
1293  assume((e->r->qideal            != NULL) &&    // minideal has one
1294         (IDELEMS(e->r->qideal)   == 1)    &&    // non-zero generator
1295         (e->r->qideal->m[0]      != NULL)    ); // at m[0];
1296
1297  assume( cf != NULL );
1298  assume(getCoeffType(cf) == ID);                     // coeff type;
1299
1300  e->r->ref ++; // increase the ref.counter for the ground poly. ring!
1301  const ring R = e->r; // no copy!
1302  assume( R->qideal == e->r->qideal );
1303  cf->extRing  = R;
1304
1305  /* propagate characteristic up so that it becomes
1306     directly accessible in cf: */
1307  cf->ch = R->cf->ch;
1308
1309  #ifdef LDEBUG
1310  p_Test((poly)naMinpoly, naRing);
1311  #endif
1312
1313  cf->cfGreaterZero  = naGreaterZero;
1314  cf->cfGreater      = naGreater;
1315  cf->cfEqual        = naEqual;
1316  cf->cfIsZero       = naIsZero;
1317  cf->cfIsOne        = naIsOne;
1318  cf->cfIsMOne       = naIsMOne;
1319  cf->cfInit         = naInit;
1320  cf->cfInit_bigint  = naInit_bigint;
1321  cf->cfInt          = naInt;
1322  cf->cfNeg          = naNeg;
1324  cf->cfSub          = naSub;
1325  cf->cfMult         = naMult;
1326  cf->cfDiv          = naDiv;
1327  cf->cfExactDiv     = naDiv;
1328  cf->cfPower        = naPower;
1329  cf->cfCopy         = naCopy;
1330
1331  cf->cfWriteLong        = naWriteLong;
1332
1333  if( rCanShortOut(naRing) )
1334    cf->cfWriteShort = naWriteShort;
1335  else
1336    cf->cfWriteShort = naWriteLong;
1337
1339  cf->cfDelete       = naDelete;
1340  cf->cfSetMap       = naSetMap;
1341  cf->cfGetDenom     = naGetDenom;
1342  cf->cfGetNumerator = naGetNumerator;
1343  cf->cfRePart       = naCopy;
1344  cf->cfImPart       = naImPart;
1345  cf->cfCoeffWrite   = naCoeffWrite;
1346  cf->cfNormalize    = naNormalize;
1347  cf->cfKillChar     = naKillChar;
1348#ifdef LDEBUG
1349  cf->cfDBTest       = naDBTest;
1350#endif
1351  cf->cfGcd          = naGcd;
1352  cf->cfLcm          = naLcmContent;
1353  cf->cfSize         = naSize;
1354  cf->nCoeffIsEqual  = naCoeffIsEqual;
1355  cf->cfInvers       = naInvers;
1356  cf->cfIntDiv       = naDiv; // ???
1357#ifdef HAVE_FACTORY
1358  cf->convFactoryNSingN=naConvFactoryNSingN;
1359  cf->convSingNFactoryN=naConvSingNFactoryN;
1360#endif
1361  cf->cfParDeg = naParDeg;
1362
1363  cf->iNumberOfParameters = rVar(R);
1364  cf->pParameterNames = R->names;
1365  cf->cfParameter = naParameter;
1366
1367  if( nCoeff_is_Q(R->cf) )
1368  {
1369    cf->cfClearContent = naClearContent;
1370    cf->cfClearDenominators = naClearDenominators;
1371  }
1372
1373  return FALSE;
1374}
Note: See TracBrowser for help on using the repository browser.