# source:git/libpolys/polys/ext_fields/transext.cc@8d1432e

jengelh-datetimespielwiese
Last change on this file since 8d1432e was 8d1432e, checked in by Hans Schoenemann <hannes@…>, 6 years ago
use of CoeffWrite/CoeffName/CoeffString p1
• Property mode set to 100644
File size: 69.0 KB
Line
1/****************************************
2*  Computer Algebra System SINGULAR     *
3****************************************/
4/*
5* ABSTRACT: numbers in a rational function field K(t_1, .., t_s) with
6*           transcendental variables t_1, ..., t_s, where s >= 1.
7*           Denoting the implemented coeffs object by cf, then these numbers
8*           are represented as quotients of polynomials living in the
9*           polynomial ring K[t_1, .., t_s] represented by cf->extring.
10*
11*           An element of K(t_1, .., t_s) may have numerous representations,
12*           due to the possibility of common polynomial factors in the
13*           numerator and denominator. This problem is handled by a
14*           cancellation heuristic: Each number "knows" its complexity
15*           which is 0 if and only if common factors have definitely been
16*           cancelled, and some positive integer otherwise.
17*           Each arithmetic operation of two numbers with complexities c1
18*           and c2 will result in a number of complexity c1 + c2 + some
19*           penalty (specific for each arithmetic operation; see constants
20*           in the *.h file). Whenever the resulting complexity exceeds a
21*           certain threshold (see constant in the *.h file), then the
22*           cancellation heuristic will call 'factory' to compute the gcd
23*           and cancel it out in the given number.
24*           For the special case of K = Q (i.e., when computing over the
25*           rationals), this definite cancellation procedure will also take
26*           care of nested fractions: If there are fractional coefficients
27*           in the numerator or denominator of a number, then this number
28*           is being replaced by a quotient of two polynomials over Z, or
29*           - if the denominator is a constant - by a polynomial over Q.
30*
31*           TODO: the description above needs a major update!!!
32*/
33#define TRANSEXT_PRIVATES
34
35#include <misc/auxiliary.h>
36
37#include <omalloc/omalloc.h>
38#include <factory/factory.h>
39
40#include <reporter/reporter.h>
41
42#include <coeffs/coeffs.h>
43#include <coeffs/numbers.h>
44
45#include <coeffs/longrat.h>
46
47#include <polys/monomials/ring.h>
48#include <polys/monomials/p_polys.h>
49#include <polys/simpleideals.h>
50
51#include <polys/clapsing.h>
52#include <polys/clapconv.h>
53
54#include <polys/prCopy.h>
55#include "transext.h"
56#include "algext.h"
57
58#include <polys/PolyEnumerator.h>
59
60
61/* constants for controlling the complexity of numbers */
62#define ADD_COMPLEXITY 1   /**< complexity increase due to + and - */
63#define MULT_COMPLEXITY 2   /**< complexity increase due to * and / */
64#define DIFF_COMPLEXITY 2   /**< complexity increase due to * and / */
65#define BOUND_COMPLEXITY 10   /**< maximum complexity of a number */
66
67/// TRUE iff num. represents 1
68#define NUMIS1(f) (p_IsOne(NUM(f), cf->extRing))
69
70#define COM(f) f->complexity
71
72
73#ifdef LDEBUG
74BOOLEAN  ntDBTest(number a, const char *f, const int l, const coeffs r);
75#endif
76
77#define ntTest(a) n_Test(a, cf)
78
79/* polynomial ring in which the numerators and denominators of our
80   numbers live */
81#define ntRing cf->extRing
82
83/* coeffs object in which the coefficients of our numbers live;
84 * methods attached to ntCoeffs may be used to compute with the
86 * coefficients of our numbers */
87#define ntCoeffs cf->extRing->cf
88
89
90omBin fractionObjectBin = omGetSpecBin(sizeof(fractionObject));
91
92/// forward declarations
93BOOLEAN  ntGreaterZero(number a, const coeffs cf);
94BOOLEAN  ntGreater(number a, number b, const coeffs cf);
95BOOLEAN  ntEqual(number a, number b, const coeffs cf);
96BOOLEAN  ntIsOne(number a, const coeffs cf);
97BOOLEAN  ntIsMOne(number a, const coeffs cf);
98BOOLEAN  ntIsZero(number a, const coeffs cf);
99number   ntInit(long i, const coeffs cf);
100long     ntInt(number &a, const coeffs cf);
101number   ntNeg(number a, const coeffs cf);
102number   ntInvers(number a, const coeffs cf);
103number   ntAdd(number a, number b, const coeffs cf);
104number   ntSub(number a, number b, const coeffs cf);
105number   ntMult(number a, number b, const coeffs cf);
106number   ntDiv(number a, number b, const coeffs cf);
107void     ntPower(number a, int exp, number *b, const coeffs cf);
108number   ntCopy(number a, const coeffs cf);
109void     ntWriteLong(number a, const coeffs cf);
110void     ntWriteShort(number a, const coeffs cf);
111number   ntRePart(number a, const coeffs cf);
112number   ntImPart(number a, const coeffs cf);
113number   ntGetDenom(number &a, const coeffs cf);
114number   ntGetNumerator(number &a, const coeffs cf);
115number   ntGcd(number a, number b, const coeffs cf);
116number   ntNormalizeHelper(number a, number b, const coeffs cf);
117int      ntSize(number a, const coeffs cf);
118void     ntDelete(number * a, const coeffs cf);
119void     ntCoeffWrite(const coeffs cf, BOOLEAN details);
120const char * ntRead(const char *s, number *a, const coeffs cf);
121static BOOLEAN ntCoeffIsEqual(const coeffs cf, n_coeffType n, void * param);
122
123void heuristicGcdCancellation(number a, const coeffs cf);
124void definiteGcdCancellation(number a, const coeffs cf,
126void handleNestedFractionsOverQ(fraction f, const coeffs cf);
127
128/* test routine, usualy disabled *
129 * if want to activate it, activate also the calls to check_N *
130 *
131void check_normalized(number t,const coeffs cf, const char *f, int l)
132{
133  if (IS0(t)) return;
134  if(rField_is_Q(ntRing))
135  {
136    poly pp=NUM(t);
137    while(pp!=NULL)
138    {
139      if (((SR_HDL(pGetCoeff(pp)) & SR_INT)==0)&&(SR_HDL(pGetCoeff(pp))!=NULL))
140      {
141        if (pGetCoeff(pp)->s==0)
142        {
143          Print("NUM not normalized in %s:%d\n",f,l);
144          p_Normalize(pp,ntRing);
145        }
146        else if (pGetCoeff(pp)->s==1)
147          Print("NUM is rational in %s:%d\n",f,l);
148      }
149      pIter(pp);
150    }
151    pp=DEN(t);
152    while(pp!=NULL)
153    {
154      if (((SR_HDL(pGetCoeff(pp)) & SR_INT)==0)&&(SR_HDL(pGetCoeff(pp))!=NULL))
155      {
156        if (pGetCoeff(pp)->s==0)
157        {
158          Print("NUM not normalized in %s:%d\n",f,l);
159          p_Normalize(pp,ntRing);
160        }
161        else if (pGetCoeff(pp)->s==1)
162          Print("DEN is rational in %s:%d\n",f,l);
163      }
164      pIter(pp);
165    }
166  }
167}
168#define check_N(A,B) check_normalized(A,B,__FILE__,__LINE__)
169*/
170
171#ifdef LDEBUG
172BOOLEAN ntDBTest(number a, const char *f, const int l, const coeffs cf)
173{
174  assume(getCoeffType(cf) == n_transExt);
175
176  if (IS0(a)) return TRUE;
177
178  const fraction t = (fraction)a;
179
180  //check_N(a,cf);
181  const poly num = NUM(t);
182  assume(num != NULL);   ///< t != 0 ==> numerator(t) != 0
183
184  p_Test(num, ntRing);
185
186  if (getCoeffType(ntCoeffs)==n_Q)
187    for( poly p = num; p != NULL; pIter(p) )
188      if (! nlIsInteger( p_GetCoeff(p, ntRing), ntCoeffs) )
189      {
190        Print("ERROR in %s:%d: non-integer Q coeff in num. poly\n",f,l);
191        Print("TERM: ");  p_wrp(p, ntRing); PrintLn();
192        return FALSE;
193      }
194
195  const poly den = DEN(t);
196
197  if (den != NULL) // !DENIS1(f)
198  {
199    p_Test(den, ntRing);
200
201    if (getCoeffType(ntCoeffs)==n_Q)
202      for( poly p = den; p != NULL; pIter(p) )
203        if (! nlIsInteger( p_GetCoeff(p, ntRing), ntCoeffs) )
204        {
205          Print("ERROR in %s:%d: non-integer Q coeff in den. poly\n",f,l);
206          Print("TERM: "); p_wrp(p, ntRing);  PrintLn();
207          return FALSE;
208        }
209
210    if (getCoeffType(ntCoeffs)==n_Zp)
211    {
212      if( p_IsConstant(den, ntRing) )
213      {
214        Print("ERROR in %s:%d: constant den. poly / Zp\n",f,l);
215        PrintS("NUM: ");  p_Write(num, ntRing);
216        PrintS("DEN: ");  p_Write(den, ntRing);
217        return FALSE;
218      }
219
220      if( !n_IsOne(pGetCoeff(den), ntCoeffs) )
221      {
222        Print("ERROR in %s:%d: non-monic den. poly / Zp\n",f,l);
223        PrintS("NUM: ");  p_Write(num, ntRing);
224        PrintS("DEN: ");  p_Write(den, ntRing);
225        return FALSE;
226      }
227    }
228
229    if (COM(t)==0)
230    {
231      poly gcd = singclap_gcd_r( num, den, ntRing );
232      if(gcd!=NULL)
233      {
234        if((gcd!=NULL) && !p_IsOne(gcd, ntRing) )
235        {
236          Print("ERROR in %s:%d: 1 != GCD between num. & den. poly\n",f,l);
237          PrintS("GCD: ");  p_Write(gcd, ntRing);
238          PrintS("NUM: ");  p_Write(num, ntRing);
239          PrintS("DEN: ");  p_Write(den, ntRing);
240          return FALSE;
241        }
242        p_Delete( &gcd, ntRing );
243      }
244    }
245    return TRUE;
246
247    if(p_IsConstant(den, ntRing) && (n_IsOne(pGetCoeff(den), ntCoeffs)))
248    {
249      Print("?/1 in %s:%d\n",f,l);
250      return FALSE;
251    }
252    if( !n_GreaterZero(pGetCoeff(den), ntCoeffs) )
253    {
254      Print("negative sign of DEN. of a fraction in %s:%d\n",f,l);
255      return FALSE;
256    }
257    // test that den is over integers!?
258  }
259  else
260  {
261    return TRUE;
262
263    // num != NULL // den == NULL
264//    if( COM(t) != 0 )
265//    {
266//      Print("?//NULL with non-zero complexity: %d in %s:%d\n", COM(t), f, l);
267//      return FALSE;
268//    }
269    // test that nume is over integers!?
270  }
271  if (getCoeffType(ntCoeffs)==n_Q)
272  {
273    poly p=num; // !=NULL
274    do
275    {
276      number n=pGetCoeff(p);
277      n_Test(n,ntCoeffs);
278      if ((!(SR_HDL(n) & SR_INT))&&(n->s==0))
279      /* not normalized, just do for the following test*/
280      {
281        n_Normalize(pGetCoeff(p),ntCoeffs);
282        n=pGetCoeff(p);
283      }
284      if (!(SR_HDL(n) & SR_INT))
285      {
286        if (n->s<2)
287          Print("rational coeff in num: %s:%d\n",f,l);
288      }
289      pIter(p);
290    } while(p!=NULL);
291    p=den;
292    while(p!=NULL)
293    {
294      number n=pGetCoeff(p);
295      if (!(SR_HDL(n) & SR_INT))
296      {
297        if (n->s!=3)
298          Print("rational coeff in den.:%s:%d\n",f,l);
299      }
300      pIter(p);
301    }
302  }
303  return TRUE;
304}
305#endif
306
307/* returns the bottom field in this field extension tower; if the tower
308   is flat, i.e., if there is no extension, then r itself is returned;
309   as a side-effect, the counter 'height' is filled with the height of
310   the extension tower (in case the tower is flat, 'height' is zero) */
311static coeffs nCoeff_bottom(const coeffs r, int &height)
312{
313  assume(r != NULL);
314  coeffs cf = r;
315  height = 0;
316  while (nCoeff_is_Extension(cf))
317  {
318    assume(cf->extRing != NULL); assume(cf->extRing->cf != NULL);
319    cf = cf->extRing->cf;
320    height++;
321  }
322  return cf;
323}
324
325BOOLEAN ntIsZero(number a, const coeffs cf)
326{
327  //check_N(a,cf);
328  ntTest(a); // !!!
329  return (IS0(a));
330}
331
332void ntDelete(number * a, const coeffs cf)
333{
334  //check_N(*a,cf);
335  ntTest(*a); // !!!
336
337  fraction f = (fraction)(*a);
338  if (IS0(f)) return;
339  p_Delete(&NUM(f), ntRing);
340  if (!DENIS1(f)) p_Delete(&DEN(f), ntRing);
342  *a = NULL;
343}
344
345BOOLEAN ntEqual(number a, number b, const coeffs cf)
346{
347  //check_N(a,cf);
348  //check_N(b,cf);
349  ntTest(a);
350  ntTest(b);
351
352  /// simple tests
353  if (a == b) return TRUE;
354  if ((IS0(a)) && (!IS0(b))) return FALSE;
355  if ((IS0(b)) && (!IS0(a))) return FALSE;
356
357  /// cheap test if gcd's have been cancelled in both numbers
358  fraction fa = (fraction)a;
359  fraction fb = (fraction)b;
360  if ((COM(fa) == 1) && (COM(fb) == 1))
361  {
362    poly f = p_Add_q(p_Copy(NUM(fa), ntRing),
363                     p_Neg(p_Copy(NUM(fb), ntRing), ntRing),
364                     ntRing);
365    if (f != NULL) { p_Delete(&f, ntRing); return FALSE; }
366    if (DENIS1(fa) && DENIS1(fb))  return TRUE;
367    if (DENIS1(fa) && !DENIS1(fb)) return FALSE;
368    if (!DENIS1(fa) && DENIS1(fb)) return FALSE;
370                p_Neg(p_Copy(DEN(fb), ntRing), ntRing),
371                ntRing);
372    if (f != NULL) { p_Delete(&f, ntRing); return FALSE; }
373    return TRUE;
374  }
375
376  /* default: the more expensive multiplication test
377              a/b = c/d  <==>  a*d = b*c */
378  poly f = p_Copy(NUM(fa), ntRing);
379  if (!DENIS1(fb)) f = p_Mult_q(f, p_Copy(DEN(fb), ntRing), ntRing);
380  poly g = p_Copy(NUM(fb), ntRing);
381  if (!DENIS1(fa)) g = p_Mult_q(g, p_Copy(DEN(fa), ntRing), ntRing);
382  poly h = p_Add_q(f, p_Neg(g, ntRing), ntRing);
383  if (h == NULL) return TRUE;
384  else
385  {
386    p_Delete(&h, ntRing);
387    return FALSE;
388  }
389}
390
391number ntCopy(number a, const coeffs cf)
392{
393  //check_N(a,cf);
394  ntTest(a); // !!!
395  if (IS0(a)) return NULL;
396  fraction f = (fraction)a;
397  poly g = NUM(f);
398  poly h = NULL;
399  h =DEN(f);
400  fraction result = (fraction)omAlloc0Bin(fractionObjectBin);
401  NUM(result) = p_Copy(g,cf->extRing);
402  DEN(result) = p_Copy(h,cf->extRing);
403  COM(result) = COM(f);
404  ntTest((number)result);
405  return (number)result;
406}
407
408/// TODO: normalization of a!?
409number ntGetNumerator(number &a, const coeffs cf)
410{
411  //check_N(a,cf);
412  ntTest(a);
413  if (IS0(a)) return NULL;
414
415  definiteGcdCancellation(a, cf, FALSE);
416
417  fraction f = (fraction)a;
418  fraction result = (fraction)omAlloc0Bin(fractionObjectBin);
419
420  const BOOLEAN denis1= DENIS1 (f);
421
422  if (getCoeffType (ntCoeffs) == n_Q && !denis1)
423    handleNestedFractionsOverQ (f, cf);
424
425  if (getCoeffType (ntCoeffs) == n_Q && denis1)
426  {
427    assume( DEN (f) == NULL );
428
429    number g;
430    // TODO/NOTE: the following should not be necessary (due to
431    // Hannes!) as NUM (f) should be over Z!!!
432    CPolyCoeffsEnumerator itr(NUM(f));
433
434
435    n_ClearDenominators(itr, g, ntCoeffs);
436
437    if( !n_GreaterZero(g, ntCoeffs) )
438    {
439      NUM (f) = p_Neg(NUM (f), ntRing);
440      g = n_InpNeg(g, ntCoeffs);
441    }
442
443    // g should be a positive integer now!
444    assume( n_GreaterZero(g, ntCoeffs) );
445
446    if( !n_IsOne(g, ntCoeffs) )
447    {
448      DEN (f) = p_NSet(g, ntRing);
449      COM (f) ++;
450      assume( DEN (f) != NULL );
451    }
452    else
453      n_Delete(&g, ntCoeffs);
454
455    ntTest(a);
456  }
457
458  // Call ntNormalize instead of above?!?
459
460  NUM (result) = p_Copy (NUM (f), ntRing); // ???
461  //DEN (result) = NULL; // done by ..Alloc0..
462  //COM (result) = 0; // done by ..Alloc0..
463
464  ntTest((number)result);
465  //check_N((number)result,cf);
466  return (number)result;
467}
468
469/// TODO: normalization of a!?
470number ntGetDenom(number &a, const coeffs cf)
471{
472  //check_N(a,cf);
473  ntTest(a);
474
475  fraction result = (fraction)omAlloc0Bin(fractionObjectBin);
476  //DEN (result)= NULL; // done by ..Alloc0..
477  //COM (result)= 0; // done by ..Alloc0..
478
479  if (IS0(a))
480  {
481    NUM (result) = p_One(ntRing);
482    return (number)result;
483  }
484
485  definiteGcdCancellation(a, cf, FALSE);
486
487  fraction f = (fraction)a;
488
489  assume( !IS0(f) );
490
491  const BOOLEAN denis1 = DENIS1 (f);
492
493  if( denis1 && (getCoeffType (ntCoeffs) != n_Q) ) // */1 or 0
494  {
495    NUM (result)= p_One(ntRing);
496    ntTest((number)result);
497    return (number)result;
498  }
499
500  if (!denis1) // */* / Q
501  {
502    assume( DEN (f) != NULL );
503
504    if (getCoeffType (ntCoeffs) == n_Q)
505      handleNestedFractionsOverQ (f, cf);
506
507    ntTest(a);
508
509    if( DEN (f) != NULL ) // is it ?? // 1 now???
510    {
511      assume( !p_IsOne(DEN (f), ntRing) );
512
513      NUM (result) = p_Copy (DEN (f), ntRing);
514      ntTest((number)result);
515      return (number)result;
516    }
517//    NUM (result) = p_One(ntRing); // NOTE: just in order to be sure...
518  }
519
520  // */1 / Q
521  assume( getCoeffType (ntCoeffs) == n_Q );
522  assume( DEN (f) == NULL );
523
524  number g;
525//    poly num= p_Copy (NUM (f), ntRing); // ???
526
527
528  // TODO/NOTE: the following should not be necessary (due to
529  // Hannes!) as NUM (f) should be over Z!!!
530  CPolyCoeffsEnumerator itr(NUM(f));
531
532  n_ClearDenominators(itr, g, ntCoeffs); // may return -1 :(((
533
534  if( !n_GreaterZero(g, ntCoeffs) )
535  {
536//     NUM (f) = p_Neg(NUM (f), ntRing); // Ugly :(((
537//     g = n_InpNeg(g, ntCoeffs);
538    NUM (f) = p_Neg(NUM (f), ntRing); // Ugly :(((
539    g = n_InpNeg(g, ntCoeffs);
540  }
541
542  // g should be a positive integer now!
543  assume( n_GreaterZero(g, ntCoeffs) );
544
545  if( !n_IsOne(g, ntCoeffs) )
546  {
547    assume( n_GreaterZero(g, ntCoeffs) );
548    assume( !n_IsOne(g, ntCoeffs) );
549
550    DEN (f) = p_NSet(g, ntRing); // update COM(f)???
551    assume( DEN (f) != NULL );
552    COM (f) ++;
553
554    NUM (result)= p_Copy (DEN (f), ntRing);
555  }
556  else
557  { // common denom == 1?
558    NUM (result)= p_NSet(g, ntRing); // p_Copy (DEN (f), ntRing);
559//  n_Delete(&g, ntCoeffs);
560  }
561
562//    if (!p_IsConstant (num, ntRing) && pNext(num) != NULL)
563//    else
564//      g= p_GetAllDenom (num, ntRing);
565//    result= (fraction) ntSetMap (ntCoeffs, cf) (g, ntCoeffs, cf);
566
567  ntTest((number)result);
568  //check_N((number)result,cf);
569  return (number)result;
570}
571
572BOOLEAN ntIsOne(number a, const coeffs cf)
573{
574  //check_N(a,cf);
575  ntTest(a); // !!!
576  definiteGcdCancellation(a, cf, FALSE);
577  fraction f = (fraction)a;
578  return (f!=NULL) && DENIS1(f) && NUMIS1(f);
579}
580
581BOOLEAN ntIsMOne(number a, const coeffs cf)
582{
583  //check_N(a,cf);
584  ntTest(a);
585  definiteGcdCancellation(a, cf, FALSE);
586  fraction f = (fraction)a;
587  if ((f==NULL) || (!DENIS1(f))) return FALSE;
588  poly g = NUM(f);
589  if (!p_IsConstant(g, ntRing)) return FALSE;
590  return n_IsMOne(p_GetCoeff(g, ntRing), ntCoeffs);
591}
592
593/// this is in-place, modifies a
594number ntNeg(number a, const coeffs cf)
595{
596  //check_N(a,cf);
597  ntTest(a);
598  if (!IS0(a))
599  {
600    fraction f = (fraction)a;
601    NUM(f) = p_Neg(NUM(f), ntRing);
602  }
603  ntTest(a);
604  return a;
605}
606
607number ntImPart(number a, const coeffs cf)
608{
609  ntTest(a);
610  return NULL;
611}
612
613number ntInit(long i, const coeffs cf)
614{
615  if (i != 0)
616  {
617    poly p=p_ISet(i, ntRing);
618    if (p!=NULL)
619    {
620      fraction result = (fraction)omAlloc0Bin(fractionObjectBin);
621      NUM(result) = p;
622      //DEN(result) = NULL; // done by omAlloc0Bin
623      //COM(result) = 0; // done by omAlloc0Bin
624      ntTest((number)result);
625      //check_N((number)result,cf);
626      return (number)result;
627    }
628  }
629  return NULL;
630}
631
632
633/// takes over p!
634number ntInit(poly p, const coeffs cf)
635{
636  if (p == NULL) return NULL;
637
638  p_Test( p, ntRing);
639  fraction f = (fraction)omAlloc0Bin(fractionObjectBin);
640
641  if (nCoeff_is_Q(ntCoeffs))
642  {
643    number g;
644    // the following is necessary because
645    // NUM (f) should be over Z,
646    // while p may be over Q
647    CPolyCoeffsEnumerator itr(p);
648
649    n_ClearDenominators(itr, g, ntCoeffs);
650
651    if( !n_GreaterZero(g, ntCoeffs) )
652    {
653      p = p_Neg(p, ntRing);
654      g = n_InpNeg(g, ntCoeffs);
655    }
656
657    // g should be a positive integer now!
658    assume( n_GreaterZero(g, ntCoeffs) );
659
660    if( !n_IsOne(g, ntCoeffs) )
661    {
662      DEN (f) = p_NSet(g, ntRing);
663      p_Normalize(DEN(f), ntRing);
664      assume( DEN (f) != NULL );
665    }
666    else
667    {
668      //DEN(f) = NULL; // done by omAlloc0
669      n_Delete(&g, ntCoeffs);
670    }
671  }
672
673  p_Normalize(p, ntRing);
674  NUM(f) = p;
675  //COM(f) = 0; // done by omAlloc0
676
677  //check_N((number)f,cf);
678  ntTest((number)f);
679  return (number)f;
680}
681
682long ntInt(number &a, const coeffs cf)
683{
684  //check_N(a,cf);
685  ntTest(a);
686  if (IS0(a)) return 0;
687  definiteGcdCancellation(a, cf, FALSE);
688  fraction f = (fraction)a;
689  if (!DENIS1(f)) return 0;
690
691  const poly aAsPoly = NUM(f);
692
693  if(aAsPoly == NULL)
694    return 0;
695
696  if (!p_IsConstant(aAsPoly, ntRing))
697    return 0;
698
699  assume( aAsPoly != NULL );
700
701  return n_Int(p_GetCoeff(aAsPoly, ntRing), ntCoeffs);
702}
703
704/* This method will only consider the numerators of a and b, without
705   cancelling gcd's before.
706   Moreover it may return TRUE only if one or both numerators
707   are zero or if their degrees are equal. Then TRUE is returned iff
708   coeff(numerator(a)) > coeff(numerator(b));
709   In all other cases, FALSE will be returned. */
710BOOLEAN ntGreater(number a, number b, const coeffs cf)
711{
712  //check_N(a,cf);
713  //check_N(b,cf);
714  ntTest(a);
715  ntTest(b);
716  number aNumCoeff = NULL; int aNumDeg = 0;
718  number bNumCoeff = NULL; int bNumDeg = 0;
719  number bDenCoeff = NULL; int bDenDeg = 0;
720  if (!IS0(a))
721  {
722    fraction fa = (fraction)a;
723    aNumDeg = p_Totaldegree(NUM(fa), ntRing);
724    aNumCoeff = p_GetCoeff(NUM(fa), ntRing);
725    if (DEN(fa)!=NULL)
726    {
729    }
730  }
731  else return !(ntGreaterZero (b,cf));
732  if (!IS0(b))
733  {
734    fraction fb = (fraction)b;
735    bNumDeg = p_Totaldegree(NUM(fb), ntRing);
736    bNumCoeff = p_GetCoeff(NUM(fb), ntRing);
737    if (DEN(fb)!=NULL)
738    {
739      bDenDeg = p_Totaldegree(DEN(fb), ntRing);
740      bDenCoeff=p_GetCoeff(DEN(fb),ntRing);
741    }
742  }
743  else return ntGreaterZero(a,cf);
744  if (aNumDeg-aDenDeg > bNumDeg-bDenDeg) return TRUE;
745  if (aNumDeg-aDenDeg < bNumDeg-bDenDeg) return FALSE;
746  number aa;
747  number bb;
748  if (bDenCoeff==NULL) aa=n_Copy(aNumCoeff,ntCoeffs);
749  else                 aa=n_Mult(aNumCoeff,bDenCoeff,ntCoeffs);
752  BOOLEAN rr= n_Greater(aa, bb, ntCoeffs);
753  n_Delete(&aa,ntCoeffs);
754  n_Delete(&bb,ntCoeffs);
755  return rr;
756}
757
758/* this method will only consider the numerator of a, without cancelling
759   the gcd before;
760   returns TRUE iff the leading coefficient of the numerator of a is > 0
761                    or the leading term of the numerator of a is not a
762                    constant */
763BOOLEAN ntGreaterZero(number a, const coeffs cf)
764{
765  //check_N(a,cf);
766  ntTest(a);
767  if (IS0(a)) return FALSE;
768  fraction f = (fraction)a;
769  poly g = NUM(f);
770  return (!p_LmIsConstant(g,ntRing)|| n_GreaterZero(pGetCoeff(g), ntCoeffs));
771}
772
773void ntCoeffWrite(const coeffs cf, BOOLEAN details)
774{
775  assume( cf != NULL );
776
777  const ring A = cf->extRing;
778
779  assume( A != NULL );
780  assume( A->cf != NULL );
781
782  n_CoeffWrite(A->cf, details);
783
784//  rWrite(A);
785
786  const int P = rVar(A);
787  assume( P > 0 );
788
789  PrintS("(");
790
791  for (int nop=0; nop < P; nop ++)
792  {
793    Print("%s", rRingVar(nop, A));
794    if (nop!=P-1) PrintS(", ");
795  }
796
797  PrintS(")");
798
799  assume( A->qideal == NULL );
800
801/*
802  PrintS("//   Coefficients live in the rational function field\n");
803  Print("//   K(");
804  for (int i = 0; i < rVar(ntRing); i++)
805  {
806    if (i > 0) PrintS(" ");
807    Print("%s", rRingVar(i, ntRing));
808  }
809  PrintS(") with\n");
810  PrintS("//   K: "); n_CoeffWrite(cf->extRing->cf);
811*/
812}
813
814number ntDiff(number a, number d, const coeffs cf)
815{
816  //check_N(a,cf);
817  //check_N(d,cf);
818  ntTest(a);
819  ntTest(d);
820
821  if (IS0(d))
822  {
823    WerrorS("ringvar expected");
824    return NULL;
825  }
826  fraction t = (fraction) d;
827  if (!DENIS1(t))
828  {
829    WerrorS("expected differentiation by a variable");
830    return NULL;
831  }
832  int k=p_Var(NUM(t),ntRing);
833  if (k==0)
834  {
835    WerrorS("expected differentiation by a variable");
836    return NULL;
837  }
838
839  if (IS0(a)) return ntCopy(a, cf);
840
841  fraction fa = (fraction)a;
842  fraction result = (fraction)omAlloc0Bin(fractionObjectBin);
843  if (DENIS1(fa))
844  {
845     NUM(result) = p_Diff(NUM(fa),k,ntRing);
846     //DEN(result) = NULL; // done by ..Alloc0..
847     if (NUM(result)==NULL)
848     {
850       return(NULL);
851     }
852     COM(result) = COM(fa);
853     //check_N((number)result,cf);
854     ntTest((number)result);
855     return (number)result;
856  }
857
858  poly fg = p_Mult_q(p_Copy(DEN(fa),ntRing),p_Diff(NUM(fa),k,ntRing),ntRing);
859  poly gf = p_Mult_q(p_Copy(NUM(fa),ntRing),p_Diff(DEN(fa),k,ntRing),ntRing);
860  NUM(result) = p_Sub(fg,gf,ntRing);
861  if (NUM(result)==NULL) return(NULL);
862  DEN(result) = pp_Mult_qq(DEN(fa), DEN(fa), ntRing);
863  COM(result) = COM(fa) + COM(fa) + DIFF_COMPLEXITY;
864  heuristicGcdCancellation((number)result, cf);
865
866  //check_N((number)result,cf);
867  ntTest((number)result);
868  return (number)result;
869}
870
871
872number ntAdd(number a, number b, const coeffs cf)
873{
874  //check_N(a,cf);
875  //check_N(b,cf);
876  ntTest(a);
877  ntTest(b);
878  if (IS0(a)) return ntCopy(b, cf);
879  if (IS0(b)) return ntCopy(a, cf);
880
881  fraction fa = (fraction)a;
882  fraction fb = (fraction)b;
883
884  poly g = p_Copy(NUM(fa), ntRing);
885  if (!DENIS1(fb)) g = p_Mult_q(g, p_Copy(DEN(fb), ntRing), ntRing);
886  poly h = p_Copy(NUM(fb), ntRing);
887  if (!DENIS1(fa)) h = p_Mult_q(h, p_Copy(DEN(fa), ntRing), ntRing);
888  g = p_Add_q(g, h, ntRing);
889
890  if (g == NULL) return NULL;
891
892  poly f;
893  if      (DENIS1(fa) && DENIS1(fb))  f = NULL;
894  else if (!DENIS1(fa) && DENIS1(fb)) f = p_Copy(DEN(fa), ntRing);
895  else if (DENIS1(fa) && !DENIS1(fb)) f = p_Copy(DEN(fb), ntRing);
896  else /* both denom's are != 1 */    f = p_Mult_q(p_Copy(DEN(fa), ntRing),
897                                                   p_Copy(DEN(fb), ntRing),
898                                                   ntRing);
899
900  fraction result = (fraction)omAllocBin(fractionObjectBin);
901  NUM(result) = g;
902  DEN(result) = f;
903  COM(result) = COM(fa) + COM(fb) + ADD_COMPLEXITY;
904  heuristicGcdCancellation((number)result, cf);
905
906//  ntTest((number)result);
907
908  //check_N((number)result,cf);
909  ntTest((number)result);
910  return (number)result;
911}
912
913number ntSub(number a, number b, const coeffs cf)
914{
915  //check_N(a,cf);
916  //check_N(b,cf);
917  ntTest(a);
918  ntTest(b);
919  if (IS0(a)) return ntNeg(ntCopy(b, cf), cf);
920  if (IS0(b)) return ntCopy(a, cf);
921
922  fraction fa = (fraction)a;
923  fraction fb = (fraction)b;
924
925  poly g = p_Copy(NUM(fa), ntRing);
926  if (!DENIS1(fb)) g = p_Mult_q(g, p_Copy(DEN(fb), ntRing), ntRing);
927  poly h = p_Copy(NUM(fb), ntRing);
928  if (!DENIS1(fa)) h = p_Mult_q(h, p_Copy(DEN(fa), ntRing), ntRing);
929  g = p_Add_q(g, p_Neg(h, ntRing), ntRing);
930
931  if (g == NULL) return NULL;
932
933  poly f;
934  if      (DENIS1(fa) && DENIS1(fb))  f = NULL;
935  else if (!DENIS1(fa) && DENIS1(fb)) f = p_Copy(DEN(fa), ntRing);
936  else if (DENIS1(fa) && !DENIS1(fb)) f = p_Copy(DEN(fb), ntRing);
937  else /* both den's are != 1 */      f = p_Mult_q(p_Copy(DEN(fa), ntRing),
938                                                   p_Copy(DEN(fb), ntRing),
939                                                   ntRing);
940
941  fraction result = (fraction)omAllocBin(fractionObjectBin);
942  NUM(result) = g;
943  DEN(result) = f;
944  COM(result) = COM(fa) + COM(fb) + ADD_COMPLEXITY;
945  heuristicGcdCancellation((number)result, cf);
946//  ntTest((number)result);
947  //check_N((number)result,cf);
948  ntTest((number)result);
949  return (number)result;
950}
951
952number ntMult(number a, number b, const coeffs cf)
953{
954  //check_N(a,cf);
955  //check_N(b,cf);
956  ntTest(a); // !!!?
957  ntTest(b); // !!!?
958
959  if (IS0(a) || IS0(b)) return NULL;
960
961  fraction fa = (fraction)a;
962  fraction fb = (fraction)b;
963
964  const poly g = pp_Mult_qq(NUM(fa), NUM(fb), ntRing);
965
966  if (g == NULL) return NULL; // may happen due to zero divisors???
967
968  fraction result = (fraction)omAllocBin(fractionObjectBin);
969
970  NUM(result) = g;
971
972  const poly da = DEN(fa);
973  const poly db = DEN(fb);
974
975
976  //check_N((number)result,cf);
977  if (db == NULL)
978  {
979    // b = ? // NULL
980
981    if(da == NULL)
982    { // both fa && fb are ?? // NULL!
983      assume (da == NULL && db == NULL);
984      DEN(result) = NULL;
985      COM(result) = 0;
986    }
987    else
988    {
989      assume (da != NULL && db == NULL);
990      DEN(result) = p_Copy(da, ntRing);
991      COM(result) = COM(fa) + MULT_COMPLEXITY;
992      heuristicGcdCancellation((number)result, cf);
993      //check_N((number)result,cf);
994    }
995  }
996  else
997  { // b = ?? / ??
998    if (da == NULL)
999    { // a == ? // NULL
1000      assume( db != NULL && da == NULL);
1001      DEN(result) = p_Copy(db, ntRing);
1002      COM(result) = COM(fb) + MULT_COMPLEXITY;
1003      heuristicGcdCancellation((number)result, cf);
1004      //check_N((number)result,cf);
1005    }
1006    else /* both den's are != 1 */
1007    {
1008      assume (da != NULL && db != NULL);
1009      DEN(result) = pp_Mult_qq(da, db, ntRing);
1010      COM(result) = COM(fa) + COM(fb) + MULT_COMPLEXITY;
1011      heuristicGcdCancellation((number)result, cf);
1012      //check_N((number)result,cf);
1013    }
1014  }
1015
1016//  ntTest((number)result);
1017
1018  //check_N((number)result,cf);
1019  ntTest((number)result);
1020  return (number)result;
1021}
1022
1023static void ntNormalizeDen(fraction result, const ring R)
1024{
1025  if ((nCoeff_has_simple_inverse(R->cf))
1026  && (result!=NULL)
1027  && (DEN(result)!=NULL))
1028  {
1029    poly n=DEN(result);
1030    if (!n_IsOne(pGetCoeff(n),R->cf))
1031    {
1032      number inv=n_Invers(pGetCoeff(n),R->cf);
1033      DEN(result)=p_Mult_nn(n,inv,R);
1034      NUM(result)=p_Mult_nn(NUM(result),inv,R);
1035      n_Delete(&inv,R->cf);
1036      if (p_IsOne(DEN(result), R))
1037      {
1038        n=DEN(result);
1039        DEN(result)=NULL;
1040        COM(result) = 0;
1041        p_Delete(&n,R);
1042      }
1043    }
1044  }
1045}
1046
1047number ntDiv(number a, number b, const coeffs cf)
1048{
1049  //check_N(a,cf);
1050  //check_N(b,cf);
1051  ntTest(a);
1052  ntTest(b);
1053  if (IS0(a)) return NULL;
1054  if (IS0(b)) WerrorS(nDivBy0);
1055
1056  fraction fa = (fraction)a;
1057  fraction fb = (fraction)b;
1058
1059  poly g = p_Copy(NUM(fa), ntRing);
1060  if (!DENIS1(fb)) g = p_Mult_q(g, p_Copy(DEN(fb), ntRing), ntRing);
1061
1062  if (g == NULL) return NULL;   /* may happen due to zero divisors */
1063
1064  poly f = p_Copy(NUM(fb), ntRing);
1065  if (!DENIS1(fa)) f = p_Mult_q(f, p_Copy(DEN(fa), ntRing), ntRing);
1066
1067  fraction result = (fraction)omAlloc0Bin(fractionObjectBin);
1068  NUM(result) = g;
1069  if (!n_GreaterZero(pGetCoeff(f),ntCoeffs))
1070  {
1071    g=p_Neg(g,ntRing);
1072    f=p_Neg(f,ntRing);
1073    NUM(result) = g;
1074  }
1075  if (!p_IsConstant(f,ntRing) || !n_IsOne(pGetCoeff(f),ntCoeffs))
1076  {
1077    DEN(result) = f;
1078  }
1079  COM(result) = COM(fa) + COM(fb) + MULT_COMPLEXITY;
1080//  definiteGcdCancellation((number)result, cf,FALSE);
1081  heuristicGcdCancellation((number)result, cf);
1082//  ntTest((number)result);
1083  //check_N((number)result,cf);
1084  ntNormalizeDen(result,ntRing);
1085  ntTest((number)result);
1086  return (number)result;
1087}
1088
1089/* 0^0 = 0;
1090   for |exp| <= 7 compute power by a simple multiplication loop;
1091   for |exp| >= 8 compute power along binary presentation of |exp|, e.g.
1092      p^13 = p^1 * p^4 * p^8, where we utilise that
1093      p^(2^(k+1)) = p^(2^k) * p^(2^k);
1094   intermediate cancellation is controlled by the in-place method
1095   heuristicGcdCancellation; see there.
1096*/
1097void ntPower(number a, int exp, number *b, const coeffs cf)
1098{
1099  ntTest(a);
1100
1101  /* special cases first */
1102  if (IS0(a))
1103  {
1104    if (exp >= 0) *b = NULL;
1105    else          WerrorS(nDivBy0);
1106  }
1107  else if (exp ==  0) { *b = ntInit(1, cf); return;}
1108  else if (exp ==  1) { *b = ntCopy(a, cf); return;}
1109  else if (exp == -1) { *b = ntInvers(a, cf); return;}
1110
1111  int expAbs = exp; if (expAbs < 0) expAbs = -expAbs;
1112
1113  /* now compute a^expAbs */
1114  number pow; number t;
1115  if (expAbs <= 7)
1116  {
1117    pow = ntCopy(a, cf);
1118    for (int i = 2; i <= expAbs; i++)
1119    {
1120      t = ntMult(pow, a, cf);
1121      ntDelete(&pow, cf);
1122      pow = t;
1123      heuristicGcdCancellation(pow, cf);
1124    }
1125  }
1126  else
1127  {
1128    pow = ntInit(1, cf);
1129    number factor = ntCopy(a, cf);
1130    while (expAbs != 0)
1131    {
1132      if (expAbs & 1)
1133      {
1134        t = ntMult(pow, factor, cf);
1135        ntDelete(&pow, cf);
1136        pow = t;
1137        heuristicGcdCancellation(pow, cf);
1138      }
1139      expAbs = expAbs / 2;
1140      if (expAbs != 0)
1141      {
1142        t = ntMult(factor, factor, cf);
1143        ntDelete(&factor, cf);
1144        factor = t;
1145        heuristicGcdCancellation(factor, cf);
1146      }
1147    }
1148    ntDelete(&factor, cf);
1149  }
1150
1151  /* invert if original exponent was negative */
1152  if (exp < 0)
1153  {
1154    t = ntInvers(pow, cf);
1155    ntDelete(&pow, cf);
1156    pow = t;
1157  }
1158  *b = pow;
1159  ntTest(*b);
1160  //check_N(*b,cf);
1161}
1162
1163/* assumes that cf represents the rationals, i.e. Q, and will only
1164   be called in that case;
1165   assumes furthermore that f != NULL and that the denominator of f != 1;
1166   generally speaking, this method removes denominators in the rational
1167   coefficients of the numerator and denominator of 'a';
1168   more concretely, the following normalizations will be performed,
1169   where t^alpha denotes a monomial in the transcendental variables t_k
1170   (1) if 'a' is of the form
1171          (sum_alpha a_alpha/b_alpha * t^alpha)
1172          -------------------------------------
1173            (sum_beta c_beta/d_beta * t^beta)
1174       with integers a_alpha, b_alpha, c_beta, d_beta, then both the
1175       numerator and the denominator will be multiplied by the LCM of
1176       the b_alpha's and the d_beta's (if this LCM is != 1),
1177   (2) if 'a' is - e.g. after having performed step (1) - of the form
1178          (sum_alpha a_alpha * t^alpha)
1179          -----------------------------
1180            (sum_beta c_beta * t^beta)
1181       with integers a_alpha, c_beta, and with a non-constant denominator,
1182       then both the numerator and the denominator will be divided by the
1183       GCD of the a_alpha's and the c_beta's (if this GCD is != 1),
1184   this procedure does not alter COM(f) (this has to be done by the
1185   calling procedure);
1186   modifies f */
1187void handleNestedFractionsOverQ(fraction f, const coeffs cf)
1188{
1189  assume(nCoeff_is_Q(ntCoeffs));
1190  assume(!IS0(f));
1191  assume(!DENIS1(f));
1192
1193  { /* step (1); see documentation of this procedure above */
1194    number lcmOfDenominators = n_Init(1, ntCoeffs);
1195    number c; number tmp;
1196    poly p = NUM(f);
1197    /* careful when using n_NormalizeHelper!!! It computes the lcm of the numerator
1198       of the 1st argument and the denominator of the 2nd!!! */
1199    while (p != NULL)
1200    {
1201      c = p_GetCoeff(p, ntRing);
1202      tmp = n_NormalizeHelper(lcmOfDenominators, c, ntCoeffs);
1203      n_Delete(&lcmOfDenominators, ntCoeffs);
1204      lcmOfDenominators = tmp;
1205      pIter(p);
1206    }
1207    p = DEN(f);
1208    while (p != NULL)
1209    {
1210      c = p_GetCoeff(p, ntRing);
1211      tmp = n_NormalizeHelper(lcmOfDenominators, c, ntCoeffs);
1212      n_Delete(&lcmOfDenominators, ntCoeffs);
1213      lcmOfDenominators = tmp;
1214      pIter(p);
1215    }
1216    if (!n_IsOne(lcmOfDenominators, ntCoeffs))
1217    { /* multiply NUM(f) and DEN(f) with lcmOfDenominators */
1218      NUM(f) = p_Mult_nn(NUM(f), lcmOfDenominators, ntRing);
1219      p_Normalize(NUM(f), ntRing);
1220      DEN(f) = p_Mult_nn(DEN(f), lcmOfDenominators, ntRing);
1221      p_Normalize(DEN(f), ntRing);
1222    }
1223    n_Delete(&lcmOfDenominators, ntCoeffs);
1224    if (DEN(f)!=NULL)
1225    { /* step (2); see documentation of this procedure above */
1226      p = NUM(f);
1227      number gcdOfCoefficients = n_Copy(p_GetCoeff(p, ntRing), ntCoeffs);
1228      pIter(p);
1229      while ((p != NULL) && (!n_IsOne(gcdOfCoefficients, ntCoeffs)))
1230      {
1231        c = p_GetCoeff(p, ntRing);
1232        tmp = n_Gcd(c, gcdOfCoefficients, ntCoeffs);
1233        n_Delete(&gcdOfCoefficients, ntCoeffs);
1234        gcdOfCoefficients = tmp;
1235        pIter(p);
1236      }
1237      p = DEN(f);
1238      while ((p != NULL) && (!n_IsOne(gcdOfCoefficients, ntCoeffs)))
1239      {
1240        c = p_GetCoeff(p, ntRing);
1241        tmp = n_Gcd(c, gcdOfCoefficients, ntCoeffs);
1242        n_Delete(&gcdOfCoefficients, ntCoeffs);
1243        gcdOfCoefficients = tmp;
1244        pIter(p);
1245      }
1246      if (!n_IsOne(gcdOfCoefficients, ntCoeffs))
1247      { /* divide NUM(f) and DEN(f) by gcdOfCoefficients */
1248        number inverseOfGcdOfCoefficients = n_Invers(gcdOfCoefficients,
1249                                                     ntCoeffs);
1250        NUM(f) = p_Mult_nn(NUM(f), inverseOfGcdOfCoefficients, ntRing);
1251        p_Normalize(NUM(f), ntRing);
1252        DEN(f) = p_Mult_nn(DEN(f), inverseOfGcdOfCoefficients, ntRing);
1253        p_Normalize(DEN(f), ntRing);
1254        n_Delete(&inverseOfGcdOfCoefficients, ntCoeffs);
1255      }
1256      n_Delete(&gcdOfCoefficients, ntCoeffs);
1257    }
1258  }
1259
1260  /* Now, due to the above computations, DEN(f) may have become the
1261     1-polynomial which needs to be represented by NULL: */
1262  if ((DEN(f) != NULL) &&
1263      p_IsConstant(DEN(f), ntRing) &&
1264      n_IsOne(p_GetCoeff(DEN(f), ntRing), ntCoeffs))
1265  {
1266    p_Delete(&DEN(f), ntRing); DEN(f) = NULL;
1267  }
1268
1269  if( DEN(f) != NULL )
1270    if( !n_GreaterZero(pGetCoeff(DEN(f)), ntCoeffs) )
1271    {
1272      NUM(f) = p_Neg(NUM(f), ntRing);
1273      DEN(f) = p_Neg(DEN(f), ntRing);
1274    }
1275
1276  ntTest((number)f); // TODO!
1277}
1278
1279/* modifies a */
1280/* this is an intermediate simplification routine - not a comple "normalize" */
1281void heuristicGcdCancellation(number a, const coeffs cf)
1282{
1283  if (IS0(a)) return;
1284
1285  fraction f = (fraction)a;
1286  p_Normalize(NUM(f),ntRing);
1287  if (DENIS1(f) || NUMIS1(f)) { COM(f) = 0; return; }
1288
1289  assume( DEN(f) != NULL );
1290  p_Normalize(DEN(f),ntRing);
1291
1292  /* check whether NUM(f) = DEN(f), and - if so - replace 'a' by 1 */
1293  if (p_EqualPolys(NUM(f), DEN(f), ntRing))
1294  { /* numerator and denominator are both != 1 */
1295    p_Delete(&NUM(f), ntRing); NUM(f) = p_ISet(1, ntRing);
1296    p_Delete(&DEN(f), ntRing); DEN(f) = NULL;
1297    COM(f) = 0;
1298  }
1299  else
1300  {
1301    if (COM(f) > BOUND_COMPLEXITY)
1302      definiteGcdCancellation(a, cf, TRUE);
1303
1304    // TODO: check if it is enough to put the following into definiteGcdCancellation?!
1305    if( DEN(f) != NULL )
1306    {
1307      if( !n_GreaterZero(pGetCoeff(DEN(f)), ntCoeffs) )
1308      {
1309        NUM(f) = p_Neg(NUM(f), ntRing);
1310        DEN(f) = p_Neg(DEN(f), ntRing);
1311      }
1312      if (ntCoeffs->has_simple_Inverse)
1313      {
1314        if (!n_IsOne(pGetCoeff(DEN(f)),ntCoeffs))
1315        {
1316          number inv=n_Invers(pGetCoeff(DEN(f)),ntCoeffs);
1317          DEN(f)=p_Mult_nn(DEN(f),inv,ntRing);
1318          NUM(f)=p_Mult_nn(NUM(f),inv,ntRing);
1319        }
1320        if(p_LmIsConstant(DEN(f),ntRing))
1321        {
1322          p_Delete(&DEN(f),ntRing);
1323          COM(f)=0;
1324        }
1325      }
1326      if ((DEN(f)!=NULL)
1327      && (pNext(DEN(f))==NULL))
1328      {
1329        poly den_f=DEN(f);
1330        poly h=NUM(f);
1331        loop
1332        {
1333          if (h==NULL)
1334          {
1335            h=NUM(f);
1336            do
1337            {
1338              p_ExpVectorDiff(h,h,den_f,ntRing);
1339              pIter(h);
1340            } while(h!=NULL);
1341            p_ExpVectorDiff(den_f,den_f,den_f,ntRing);
1342            break;
1343          }
1344          int i=0;
1345          do
1346          {
1347            i++;
1348            if (p_GetExp(den_f,i,ntRing) > p_GetExp(h,i,ntRing)) return;
1349          } while(i<ntRing->N);
1350          pIter(h);
1351        }
1352      }
1353    }
1354  }
1355  if ((DEN(f)!=NULL)
1356  && (pNext(DEN(f))==NULL)
1357  && (p_LmIsConstantComp(DEN(f),ntRing))
1358  && (n_IsOne(pGetCoeff(DEN(f)),ntCoeffs)))
1359  {
1360     p_Delete(&DEN(f),ntRing);
1361     COM(f)=0;
1362  }
1363}
1364
1365/// modifies a
1366void definiteGcdCancellation(number a, const coeffs cf,
1368{
1369//  ntTest(a); // !!!!
1370
1371  fraction f = (fraction)a;
1372
1373  if (IS0(a)) return;
1374  if (DENIS1(f) || NUMIS1(f)) { COM(f) = 0; ntTest(a); return; }
1376  {
1377
1378    /* check whether NUM(f) = DEN(f), and - if so - replace 'a' by 1 */
1379    if (p_EqualPolys(NUM(f), DEN(f), ntRing))
1380    { /* numerator and denominator are both != 1 */
1381      p_Delete(&NUM(f), ntRing); NUM(f) = p_ISet(1, ntRing);
1382      p_Delete(&DEN(f), ntRing); DEN(f) = NULL;
1383      COM(f) = 0;
1384      ntTest(a);
1385      return;
1386    }
1387  }
1388  /*if (rField_is_Q(ntRing))
1389  {
1390    number c=n_Copy(pGetCoeff(NUM(f)),ntCoeffs);
1391    poly p=pNext(NUM(f));
1392    while((p!=NULL)&&(!n_IsOne(c,ntCoeffs)))
1393    {
1394      number cc=n_Gcd(c,pGetCoeff(p),ntCoeffs);
1395      n_Delete(&c,ntCoeffs);
1396      c=cc;
1397      pIter(p);
1398    };
1399    p=DEN(f);
1400    while((p!=NULL)&&(!n_IsOne(c,ntCoeffs)))
1401    {
1402      number cc=n_Gcd(c,pGetCoeff(p),ntCoeffs);
1403      n_Delete(&c,ntCoeffs);
1404      c=cc;
1405      pIter(p);
1406    };
1407    if(!n_IsOne(c,ntCoeffs))
1408    {
1409      p=NUM(f);
1410      do
1411      {
1412        number cc=n_Div(pGetCoeff(p),c,ntCoeffs);
1413        n_Normalize(cc,ntCoeffs);
1414        p_SetCoeff(p,cc,ntRing);
1415        pIter(p);
1416      } while(p!=NULL);
1417      p=DEN(f);
1418      do
1419      {
1420        number cc=n_Div(pGetCoeff(p),c,ntCoeffs);
1421        n_Normalize(cc,ntCoeffs);
1422        p_SetCoeff(p,cc,ntRing);
1423        pIter(p);
1424      } while(p!=NULL);
1425      n_Delete(&c,ntCoeffs);
1426      if(pNext(DEN(f))==NULL)
1427      {
1428        if (p_IsOne(DEN(f),ntRing))
1429        {
1430          p_LmDelete(&DEN(f),ntRing);
1431          COM(f)=0;
1432          return;
1433        }
1434        else
1435        {
1436          return;
1437        }
1438      }
1439    }
1440  }*/
1441
1442  /* here we assume: NUM(f), DEN(f) !=NULL, in Z_a reqp. Z/p_a */
1443  poly pGcd = singclap_gcd_and_divide(NUM(f), DEN(f), ntRing);
1444  //PrintS("gcd= ");p_wrp(pGcd,ntRing);PrintLn();
1445  if (p_IsConstant(pGcd, ntRing)
1446  && n_IsOne(p_GetCoeff(pGcd, ntRing), ntCoeffs)
1447  )
1448  { /* gcd = 1; nothing to cancel;
1449       Suppose the given rational function field is over Q. Although the
1450       gcd is 1, we may have produced fractional coefficients in NUM(f),
1451       DEN(f), or both, due to previous arithmetics. The next call will
1452       remove those nested fractions, in case there are any. */
1453    if (nCoeff_is_Zp(ntCoeffs))
1454    {
1455      NUM (f) = p_Div_nn (NUM (f), p_GetCoeff (DEN(f),ntRing), ntRing);
1456      if (p_IsConstant (DEN (f), ntRing))
1457      {
1458        p_Delete(&DEN (f), ntRing);
1459        DEN (f) = NULL;
1460      }
1461      else
1462      {
1463        p_Norm (DEN (f),ntRing);
1464      }
1465    } else if (nCoeff_is_Q(ntCoeffs)) handleNestedFractionsOverQ(f, cf);
1466  }
1467  else
1468  { /* We divide both NUM(f) and DEN(f) by the gcd which is known
1469       to be != 1. */
1470    if (p_IsConstant(DEN(f), ntRing) &&
1471      n_IsOne(p_GetCoeff(DEN(f), ntRing), ntCoeffs))
1472    {
1473      /* DEN(f) = 1 needs to be represented by NULL! */
1474      p_Delete(&DEN(f), ntRing);
1475      DEN(f) = NULL;
1476    }
1477    else
1478    {
1479      if (nCoeff_is_Zp(ntCoeffs))
1480      {
1481        NUM (f) = p_Div_nn (NUM (f), p_GetCoeff (DEN(f),ntRing), ntRing);
1482        if (p_IsConstant (DEN (f), ntRing))
1483        {
1484          p_Delete(&DEN (f), ntRing);
1485          DEN (f) = NULL;
1486        }
1487        else
1488        {
1489          p_Norm (DEN (f),ntRing);
1490        }
1491      }
1492    }
1493  }
1494  p_Delete(&pGcd, ntRing);
1495  COM(f) = 0;
1496
1497  if( DEN(f) != NULL )
1498  {
1499    if( !n_GreaterZero(pGetCoeff(DEN(f)), ntCoeffs) )
1500    {
1501      NUM(f) = p_Neg(NUM(f), ntRing);
1502      DEN(f) = p_Neg(DEN(f), ntRing);
1503      if (p_IsConstant(DEN(f), ntRing) &&
1504        n_IsOne(p_GetCoeff(DEN(f), ntRing), ntCoeffs))
1505      {
1506        /* DEN(f) = 1 needs to be represented by NULL! */
1507        p_Delete(&DEN(f), ntRing);
1508        DEN (f) = NULL;
1509      }
1510    }
1511  }
1512  ntTest(a); // !!!!
1513}
1514
1515void ntWriteLong(number a, const coeffs cf)
1516{
1517  ntTest(a);
1518  if (IS0(a))
1519    StringAppendS("0");
1520  else
1521  {
1522    fraction f = (fraction)a;
1523    // stole logic from napWrite from kernel/longtrans.cc of legacy singular
1524    BOOLEAN omitBrackets = p_IsConstant(NUM(f), ntRing);
1525    if (!omitBrackets) StringAppendS("(");
1526    p_String0Long(NUM(f), ntRing, ntRing);
1527    if (!omitBrackets) StringAppendS(")");
1528    if (!DENIS1(f))
1529    {
1530      StringAppendS("/");
1531      omitBrackets = p_IsConstant(DEN(f), ntRing);
1532      if (!omitBrackets) StringAppendS("(");
1533      p_String0Long(DEN(f), ntRing, ntRing);
1534      if (!omitBrackets) StringAppendS(")");
1535    }
1536  }
1537  ntTest(a); // !!!!
1538}
1539
1540void ntWriteShort(number a, const coeffs cf)
1541{
1542  ntTest(a);
1543  if (IS0(a))
1544    StringAppendS("0");
1545  else
1546  {
1547    fraction f = (fraction)a;
1548    // stole logic from napWrite from kernel/longtrans.cc of legacy singular
1549    BOOLEAN omitBrackets = p_IsConstant(NUM(f), ntRing);
1550    if (!omitBrackets) StringAppendS("(");
1551    p_String0Short(NUM(f), ntRing, ntRing);
1552    if (!omitBrackets) StringAppendS(")");
1553    if (!DENIS1(f))
1554    {
1555      StringAppendS("/");
1556      omitBrackets = p_IsConstant(DEN(f), ntRing);
1557      if (!omitBrackets) StringAppendS("(");
1558      p_String0Short(DEN(f), ntRing, ntRing);
1559      if (!omitBrackets) StringAppendS(")");
1560    }
1561  }
1562  ntTest(a);
1563}
1564
1565const char * ntRead(const char *s, number *a, const coeffs cf)
1566{
1567  poly p;
1568  const char * result = p_Read(s, p, ntRing);
1569  if (p == NULL) *a = NULL;
1570  else *a = ntInit(p, cf);
1571  ntTest(*a);
1572  return result;
1573}
1574
1575void ntNormalize (number &a, const coeffs cf)
1576{
1577  if ( /*(*/ a!=NULL /*)*/ )
1578  {
1579    //PrintS("num=");p_wrp(NUM(a),ntRing);
1580    //PrintS(" den=");p_wrp(DEN(a),ntRing);PrintLn();
1581    definiteGcdCancellation(a, cf, FALSE);
1582    if ((DEN((fraction)a)!=NULL)
1583    &&(!n_GreaterZero(pGetCoeff(DEN((fraction)a)),ntCoeffs)))
1584    {
1585      NUM((fraction)a)=p_Neg(NUM((fraction)a),ntRing);
1586      DEN((fraction)a)=p_Neg(DEN((fraction)a),ntRing);
1587    }
1588  }
1589  ntNormalizeDen((fraction)a,ntRing);
1590  ntTest(a); // !!!!
1591}
1592
1593/* expects *param to be castable to TransExtInfo */
1594static BOOLEAN ntCoeffIsEqual(const coeffs cf, n_coeffType n, void * param)
1595{
1596  if (n_transExt != n) return FALSE;
1597  TransExtInfo *e = (TransExtInfo *)param;
1598  /* for rational function fields we expect the underlying
1599     polynomial rings to be IDENTICAL, i.e. the SAME OBJECT;
1600     this expectation is based on the assumption that we have properly
1601     registered cf and perform reference counting rather than creating
1602     multiple copies of the same coefficient field/domain/ring */
1603  if (ntRing == e->r)
1604    return TRUE;
1605
1606  // NOTE: Q(a)[x] && Q(a)[y] should better share the _same_ Q(a)...
1607  if( rEqual(ntRing, e->r, TRUE) )
1608  {
1609    rDelete(e->r);
1610    return TRUE;
1611  }
1612
1613  return FALSE;
1614}
1615
1616number ntNormalizeHelper(number a, number b, const coeffs cf)
1617{
1618  ntTest(a);
1619  ntTest(b);
1620  fraction fb = (fraction)b;
1621  if ((b==NULL)||(DEN(fb)==NULL)) return ntCopy(a,cf);
1622  fraction fa = (fraction)a;
1623  /* singclap_gcd destroys its arguments; we hence need copies: */
1624  poly pa = p_Copy(NUM(fa), ntRing);
1625  poly pb = p_Copy(DEN(fb), ntRing);
1626
1627  poly pGcd;
1628  if (nCoeff_is_Q(ntCoeffs))
1629  {
1630    if (p_IsConstant(pa,ntRing) && p_IsConstant(pb,ntRing))
1631    {
1632      pGcd = pa;
1633      p_SetCoeff (pGcd, n_Gcd (pGetCoeff(pGcd), pGetCoeff(pb), ntCoeffs), ntRing);
1634    }
1635    else
1636    {
1637      number contentpa, contentpb, tmp;
1638
1639      contentpb= p_GetCoeff(pb, ntRing);
1640      pIter(pb);
1641      while (pb != NULL)
1642      {
1643        tmp = n_SubringGcd(contentpb, p_GetCoeff(pb, ntRing) , ntCoeffs);
1644        n_Delete(&contentpb, ntCoeffs);
1645        contentpb = tmp;
1646        pIter(pb);
1647      }
1648
1649      contentpa= p_GetCoeff(pa, ntRing);
1650      pIter(pa);
1651      while (pa != NULL)
1652      {
1653        tmp = n_SubringGcd(contentpa, p_GetCoeff(pa, ntRing), ntCoeffs);
1654        n_Delete(&contentpa, ntCoeffs);
1655        contentpa = tmp;
1656        pIter(pa);
1657      }
1658
1659      tmp= n_SubringGcd (contentpb, contentpa, ntCoeffs);
1660      n_Delete(&contentpa, ntCoeffs);
1661      n_Delete(&contentpb, ntCoeffs);
1662      contentpa= tmp;
1663      p_Delete(&pb, ntRing);
1664      p_Delete(&pa, ntRing);
1665
1666      /* singclap_gcd destroys its arguments; we hence need copies: */
1667      pGcd = singclap_gcd(p_Copy(NUM(fa),ntRing), p_Copy(DEN(fb),ntRing), ntRing);
1668      pGcd= p_Mult_nn (pGcd, contentpa, ntRing);
1669      n_Delete(&contentpa, ntCoeffs);
1670    }
1671  }
1672  else
1673    pGcd = singclap_gcd(pa, pb, cf->extRing);
1674
1675  /* Note that, over Q, singclap_gcd will remove the denominators in all
1676     rational coefficients of pa and pb, before starting to compute
1677     the gcd. Thus, we do not need to ensure that the coefficients of
1678     pa and pb live in Z; they may well be elements of Q\Z. */
1679
1680  if (p_IsConstant(pGcd, ntRing) &&
1681      n_IsOne(p_GetCoeff(pGcd, ntRing), ntCoeffs))
1682  { /* gcd = 1; return pa*pb*/
1683    p_Delete(&pGcd,ntRing);
1684    fraction result = (fraction)omAlloc0Bin(fractionObjectBin);
1685    NUM(result) = pp_Mult_qq(NUM(fa),DEN(fb),ntRing);
1686
1687    ntTest((number)result); // !!!!
1688
1689    return (number)result;
1690  }
1691
1692
1693  /* return pa*pb/gcd */
1694    poly newNum = singclap_pdivide(NUM(fa), pGcd, ntRing);
1695    p_Delete(&pGcd,ntRing);
1696    fraction result = (fraction)omAlloc0Bin(fractionObjectBin);
1697    NUM(result) = p_Mult_q(p_Copy(DEN(fb),ntRing),newNum,ntRing);
1698    ntTest((number)result); // !!!!
1699    return (number)result;
1700
1701    return NULL;
1702}
1703
1704number ntGcd(number a, number b, const coeffs cf)
1705{
1706  ntTest(a);
1707  ntTest(b);
1708  if (a==NULL) return ntCopy(b,cf);
1709  if (b==NULL) return ntCopy(a,cf);
1710  fraction fa = (fraction)a;
1711  fraction fb = (fraction)b;
1712
1713  poly pa = p_Copy(NUM(fa), ntRing);
1714  poly pb = p_Copy(NUM(fb), ntRing);
1715
1716  poly pGcd;
1717  if (nCoeff_is_Q(ntCoeffs))
1718  {
1719    if (p_IsConstant(pa,ntRing) && p_IsConstant(pb,ntRing))
1720    {
1721      pGcd = pa;
1722      p_SetCoeff (pGcd, n_SubringGcd (pGetCoeff(pGcd), pGetCoeff(pb), ntCoeffs), ntRing);
1723    }
1724    else
1725    {
1726      number contentpa, contentpb, tmp;
1727
1728      contentpb= p_GetCoeff(pb, ntRing);
1729      pIter(pb);
1730      while (pb != NULL)
1731      {
1732        tmp = n_SubringGcd(contentpb, p_GetCoeff(pb, ntRing) , ntCoeffs);
1733        n_Delete(&contentpb, ntCoeffs);
1734        contentpb = tmp;
1735        pIter(pb);
1736      }
1737
1738      contentpa= p_GetCoeff(pa, ntRing);
1739      pIter(pa);
1740      while (pa != NULL)
1741      {
1742        tmp = n_SubringGcd(contentpa, p_GetCoeff(pa, ntRing), ntCoeffs);
1743        n_Delete(&contentpa, ntCoeffs);
1744        contentpa = tmp;
1745        pIter(pa);
1746      }
1747
1748      tmp= n_SubringGcd (contentpb, contentpa, ntCoeffs);
1749      n_Delete(&contentpa, ntCoeffs);
1750      n_Delete(&contentpb, ntCoeffs);
1751      contentpa= tmp;
1752      p_Delete(&pb, ntRing);
1753      p_Delete(&pa, ntRing);
1754
1755      /* singclap_gcd destroys its arguments; we hence need copies: */
1756      pGcd = singclap_gcd(p_Copy(NUM(fa),ntRing), p_Copy(NUM(fb),ntRing), ntRing);
1757      pGcd= p_Mult_nn (pGcd, contentpa, ntRing);
1758      n_Delete(&contentpa, ntCoeffs);
1759    }
1760  }
1761  else
1762    pGcd = singclap_gcd(pa, pb, cf->extRing);
1763  /* Note that, over Q, singclap_gcd will remove the denominators in all
1764     rational coefficients of pa and pb, before starting to compute
1765     the gcd. Thus, we do not need to ensure that the coefficients of
1766     pa and pb live in Z; they may well be elements of Q\Z. */
1767
1768  fraction result = (fraction)omAlloc0Bin(fractionObjectBin);
1769  NUM(result) = pGcd;
1770  ntTest((number)result); // !!!!
1771  return (number)result;
1772}
1773//number ntGcd_dummy(number a, number b, const coeffs cf)
1774//{
1775//  extern char my_yylinebuf[80];
1776//  Print("ntGcd in >>%s<<\n",my_yylinebuf);
1777//  return ntGcd(a,b,cf);
1778//}
1779
1780int ntSize(number a, const coeffs cf)
1781{
1782  ntTest(a);
1783  if (IS0(a)) return -1;
1784  /* this has been taken from the old implementation of field extensions,
1785     where we computed the sum of the degrees and the numbers of terms in
1786     the numerator and denominator of a; so we leave it at that, for the
1787     time being */
1788  fraction f = (fraction)a;
1789  poly p = NUM(f);
1790  int noOfTerms = 0;
1791  int numDegree = 0;
1792  if (p!=NULL)
1793  {
1794    numDegree = p_Totaldegree(p,ntRing);
1795    noOfTerms = pLength(p);
1796  }
1797  int denDegree = 0;
1798  if (!DENIS1(f))
1799  {
1800    denDegree =  p_Totaldegree(DEN(f),ntRing);
1801    noOfTerms += pLength(DEN(f));
1802  }
1803  ntTest(a); // !!!!
1804  return numDegree + denDegree + noOfTerms;
1805}
1806
1807number ntInvers(number a, const coeffs cf)
1808{
1809  //check_N(a,cf);
1810  ntTest(a);
1811  if (IS0(a))
1812  {
1813    WerrorS(nDivBy0);
1814    return NULL;
1815  }
1816  fraction f = (fraction)a;
1817  assume( f != NULL );
1818
1819  fraction result = (fraction)omAlloc0Bin(fractionObjectBin);
1820
1821  assume( NUM(f) != NULL );
1822  const poly den = DEN(f);
1823
1824  if (den == NULL)
1825    NUM(result) = p_One(ntRing);
1826  else
1827    NUM(result) = p_Copy(den, ntRing);
1828
1829  if( !NUMIS1(f) )
1830  {
1831    poly num_f=NUM(f);
1832    BOOLEAN neg= !n_GreaterZero(pGetCoeff(num_f),ntCoeffs);
1833    if (neg)
1834    {
1835      num_f=p_Neg(p_Copy(num_f, ntRing), ntRing);
1836      NUM(result)=p_Neg(NUM(result), ntRing);
1837    }
1838    else
1839    {
1840      num_f=p_Copy(num_f, ntRing);
1841    }
1842    DEN(result) = num_f;
1843    COM(result) = COM(f);
1844    if (neg)
1845    {
1846      if (p_IsOne(num_f, ntRing))
1847      {
1848        DEN(result)=NULL;
1849        //COM(result) = 0;
1850        p_Delete(&num_f,ntRing);
1851      }
1852    }
1853  }
1854  //else// Alloc0
1855  //{
1856  //  DEN(result) = NULL;
1857  //  COM(result) = 0;
1858  //}
1859  ntNormalizeDen(result,ntRing);
1860  ntTest((number)result); // !!!!
1861  //check_N((number)result,cf);
1862  return (number)result;
1863}
1864
1865/* assumes that src = Q or Z, dst = Q(t_1, ..., t_s) */
1866number ntMap00(number a, const coeffs src, const coeffs dst)
1867{
1868  n_Test(a, src);
1869
1870  if (n_IsZero(a, src)) return NULL;
1871  assume(src->rep == dst->extRing->cf->rep);
1872  if ((SR_HDL(a) & SR_INT) || (a->s==3))
1873  {
1874    number res=ntInit(p_NSet(n_Copy(a, src), dst->extRing), dst);
1875    n_Test(res, dst);
1876    return res;
1877  }
1878  number nn=n_GetDenom(a,src);
1879  number zz=n_GetNumerator(a,src);
1880  number res=ntInit(p_NSet(zz,dst->extRing), dst);
1881  fraction ff=(fraction)res;
1882  if (n_IsOne(nn,src)) DEN(ff)=NULL;
1883  else                 DEN(ff)=p_NSet(nn,dst->extRing);
1884
1885  n_Test((number)ff,dst);
1886  //check_N((number)ff,dst);
1887  return (number)ff;
1888}
1889
1890number ntMapZ0(number a, const coeffs src, const coeffs dst)
1891{
1892  n_Test(a, src);
1893  if (n_IsZero(a, src)) return NULL;
1894  nMapFunc nMap=n_SetMap(src,dst->extRing->cf);
1895  poly p=p_NSet(nMap(a, src,dst->extRing->cf), dst->extRing);
1896  if (n_IsZero(pGetCoeff(p),dst->extRing->cf))
1897    p_Delete(&p,dst->extRing);
1898  number res=ntInit(p, dst);
1899  n_Test(res,dst);
1900  return res;
1901}
1902
1903/* assumes that src = Z/p, dst = Q(t_1, ..., t_s) */
1904number ntMapP0(number a, const coeffs src, const coeffs dst)
1905{
1906  n_Test(a, src);
1907  if (n_IsZero(a, src)) return NULL;
1908  /* mapping via intermediate int: */
1909  int n = n_Int(a, src);
1910  number q = n_Init(n, dst->extRing->cf);
1911  if (n_IsZero(q, dst->extRing->cf))
1912  {
1913    n_Delete(&q, dst->extRing->cf);
1914    return NULL;
1915  }
1916  return ntInit(p_NSet(q, dst->extRing), dst);
1917}
1918
1919 /* assumes that either src = K(t_1, ..., t_s), dst = K(t_1, ..., t_s) */
1920number ntCopyMap(number a, const coeffs cf, const coeffs dst)
1921{
1922  ntTest(a);
1923  if (IS0(a)) return NULL;
1924
1925  const ring rSrc = cf->extRing;
1926  const ring rDst = dst->extRing;
1927
1928  if( rSrc == rDst )
1929    return ntCopy(a, dst); // USUALLY WRONG!
1930
1931  fraction f = (fraction)a;
1932  poly g = prCopyR(NUM(f), rSrc, rDst);
1933
1934  poly h = NULL;
1935
1936  if (!DENIS1(f))
1937     h = prCopyR(DEN(f), rSrc, rDst);
1938
1939  fraction result = (fraction)omAllocBin(fractionObjectBin);
1940
1941  NUM(result) = g;
1942  DEN(result) = h;
1943  COM(result) = COM(f);
1944  //check_N((number)result,dst);
1945  n_Test((number)result, dst);
1946  return (number)result;
1947}
1948
1949number ntGenMap(number a, const coeffs cf, const coeffs dst)
1950{
1951  ntTest(a);
1952  if (IS0(a)) return NULL;
1953
1954  const ring rSrc = cf->extRing;
1955  const ring rDst = dst->extRing;
1956
1957  const nMapFunc nMap=n_SetMap(rSrc->cf,rDst->cf);
1958  fraction f = (fraction)a;
1959  poly g = prMapR(NUM(f), nMap, rSrc, rDst);
1960  /* g may contain summands with coeff 0 */
1961  poly hh=g;
1962  poly prev=NULL;
1963  while(hh!=NULL)
1964  {
1965    if (n_IsZero(pGetCoeff(hh),rDst->cf))
1966    {
1967      if (prev==NULL)
1968      {
1969        g=p_LmFreeAndNext(g,rDst);
1970        hh=g;
1971      }
1972      else
1973      {
1974        prev->next=p_LmFreeAndNext(prev->next,rDst);
1975        hh=prev->next;
1976      }
1977    }
1978    else
1979    {
1980      prev=hh;
1981      pIter(hh);
1982    }
1983  }
1984  if (g==NULL) return NULL;
1985
1986  poly h = NULL;
1987
1988  if (!DENIS1(f))
1989  {
1990     h = prMapR(DEN(f), nMap, rSrc, rDst);
1991     /* h may contain summands with coeff 0 */
1992    hh=h;
1993    prev=NULL;
1994    while(hh!=NULL)
1995    {
1996      if (n_IsZero(pGetCoeff(hh),rDst->cf))
1997      {
1998        if (prev==NULL)
1999        {
2000          h=p_LmFreeAndNext(h,rDst);
2001          hh=h;
2002        }
2003        else
2004        {
2005          prev->next=p_LmFreeAndNext(prev->next,rDst);
2006          hh=prev->next;
2007        }
2008      }
2009      else
2010      {
2011        prev=hh;
2012        pIter(hh);
2013      }
2014    }
2015    if (h==NULL) WerrorS("mapping to */0");
2016  }
2017
2018  fraction result = (fraction)omAllocBin(fractionObjectBin);
2019
2020  NUM(result) = g;
2021  DEN(result) = h;
2022  COM(result) = COM(f);
2023  //check_N((number)result,dst);
2024  n_Test((number)result, dst);
2025  return (number)result;
2026}
2027
2028number ntCopyAlg(number a, const coeffs cf, const coeffs dst)
2029{
2030  n_Test(a, cf) ;
2031  if (n_IsZero(a, cf)) return NULL;
2032  return ntInit(prCopyR((poly)a, cf->extRing, dst->extRing),dst);
2033}
2034
2035number ntGenAlg(number a, const coeffs cf, const coeffs dst)
2036{
2037  n_Test(a, cf) ;
2038  if (n_IsZero(a, cf)) return NULL;
2039
2040  const nMapFunc nMap=n_SetMap(cf->extRing->cf,dst->extRing->cf);
2041  return ntInit(prMapR((poly)a, nMap, cf->extRing, dst->extRing),dst);
2042}
2043
2044/* assumes that src = Q, dst = Z/p(t_1, ..., t_s) */
2045number ntMap0P(number a, const coeffs src, const coeffs dst)
2046{
2047  n_Test(a, src) ;
2048  if (n_IsZero(a, src)) return NULL;
2049  // int p = rChar(dst->extRing);
2050
2051  number q = nlModP(a, src, dst->extRing->cf); // FIXME? TODO? // extern number nlModP(number q, const coeffs Q, const coeffs Zp); // Map q \in QQ \to Zp
2052
2053  if (n_IsZero(q, dst->extRing->cf))
2054  {
2055    n_Delete(&q, dst->extRing->cf);
2056    return NULL;
2057  }
2058
2059  poly g = p_NSet(q, dst->extRing);
2060
2061  fraction f = (fraction)omAlloc0Bin(fractionObjectBin);
2062  NUM(f) = g; // DEN(f) = NULL; COM(f) = 0;
2063  n_Test((number)f, dst);
2064  //check_N((number)f,dst);
2065  return (number)f;
2066}
2067
2068/* assumes that src = Z/p, dst = Z/p(t_1, ..., t_s) */
2069number ntMapPP(number a, const coeffs src, const coeffs dst)
2070{
2071  n_Test(a, src) ;
2072  if (n_IsZero(a, src)) return NULL;
2073  assume(src == dst->extRing->cf);
2074  poly p = p_One(dst->extRing);
2075  p_SetCoeff(p, n_Copy(a, src), dst->extRing);
2076  fraction f = (fraction)omAlloc0Bin(fractionObjectBin);
2077  NUM(f) = p; // DEN(f) = NULL; COM(f) = 0;
2078  n_Test((number)f, dst);
2079  //check_N((number)f,dst);
2080  return (number)f;
2081}
2082
2083/* assumes that src = Z/u, dst = Z/p(t_1, ..., t_s), where u != p */
2084number ntMapUP(number a, const coeffs src, const coeffs dst)
2085{
2086  n_Test(a, src) ;
2087  if (n_IsZero(a, src)) return NULL;
2088  /* mapping via intermediate int: */
2089  int n = n_Int(a, src);
2090  number q = n_Init(n, dst->extRing->cf);
2091  poly p;
2092  if (n_IsZero(q, dst->extRing->cf))
2093  {
2094    n_Delete(&q, dst->extRing->cf);
2095    return NULL;
2096  }
2097  p = p_One(dst->extRing);
2098  p_SetCoeff(p, q, dst->extRing);
2099  fraction f = (fraction)omAlloc0Bin(fractionObjectBin);
2100  NUM(f) = p; // DEN(f) = NULL; COM(f) = 0;
2101  n_Test((number)f, dst);
2102  //check_N((number)f,dst);
2103  return (number)f;
2104}
2105
2106nMapFunc ntSetMap(const coeffs src, const coeffs dst)
2107{
2108  /* dst is expected to be a rational function field */
2109  assume(getCoeffType(dst) == n_transExt);
2110
2111  if( src == dst ) return ndCopyMap;
2112
2113  int h = 0; /* the height of the extension tower given by dst */
2114  coeffs bDst = nCoeff_bottom(dst, h); /* the bottom field in the tower dst */
2115  coeffs bSrc = nCoeff_bottom(src, h); /* the bottom field in the tower src */
2116
2117  /* for the time being, we only provide maps if h = 1 and if b is Q or
2118     some field Z/pZ: */
2119  if (h==0)
2120  {
2121    if ((src->rep==n_rep_gap_rat) && nCoeff_is_Q(bDst))
2122      return ntMap00;                                 /// Q or Z   -->  Q(T)
2123    if (src->rep==n_rep_gap_gmp)
2124      return ntMapZ0;                                 /// Z   -->  K(T)
2125    if (nCoeff_is_Zp(src) && nCoeff_is_Q(bDst))
2126      return ntMapP0;                                 /// Z/p     -->  Q(T)
2127    if (nCoeff_is_Q_or_BI(src) && nCoeff_is_Zp(bDst))
2128      return ntMap0P;                                 /// Q       --> Z/p(T)
2129    if (nCoeff_is_Zp(src) && nCoeff_is_Zp(bDst))
2130    {
2131      if (src->ch == dst->ch) return ntMapPP;         /// Z/p     --> Z/p(T)
2132      else return ntMapUP;                            /// Z/u     --> Z/p(T)
2133    }
2134  }
2135  if (h != 1) return NULL;
2136  //if ((!nCoeff_is_Zp(bDst)) && (!nCoeff_is_Q(bDst))) return NULL;
2137
2138  /* Let T denote the sequence of transcendental extension variables, i.e.,
2139     K[t_1, ..., t_s] =: K[T];
2140     Let moreover, for any such sequence T, T' denote any subsequence of T
2141     of the form t_1, ..., t_w with w <= s. */
2142
2143  if (rVar(src->extRing) > rVar(dst->extRing))
2144     return NULL;
2145
2146  for (int i = 0; i < rVar(src->extRing); i++)
2147    if (strcmp(rRingVar(i, src->extRing), rRingVar(i, dst->extRing)) != 0)
2148       return NULL;
2149
2150  if (src->type==n_transExt)
2151  {
2152     if (src->extRing->cf==dst->extRing->cf)
2153       return ntCopyMap;          /// K(T')   --> K(T)
2154     else
2155       return ntGenMap;          /// K(T')   --> K'(T)
2156  }
2157  else
2158  {
2159     if (src->extRing->cf==dst->extRing->cf)
2160       return ntCopyAlg;          /// K(T')   --> K(T)
2161     else
2162       return ntGenAlg;          /// K(T')   --> K'(T)
2163  }
2164
2165  return NULL;                                 /// default
2166}
2167#if 0
2168nMapFunc ntSetMap_T(const coeffs src, const coeffs dst)
2169{
2170  nMapFunc n=ntSetMap(src,dst);
2171  if (n==ntCopyAlg) printf("n=ntCopyAlg\n");
2172  else if (n==ntCopyMap) printf("n=ntCopyMap\n");
2173  else if (n==ntMapUP) printf("n=ntMapUP\n");
2174  else if (n==ntMap0P) printf("n=ntMap0P\n");
2175  else if (n==ntMapP0) printf("n=ntMapP0\n");
2176  else if (n==ntMap00) printf("n=ntMap00\n");
2177  else if (n==NULL) printf("n=NULL\n");
2178  else printf("n=?\n");
2179  return n;
2180}
2181#endif
2182
2183void ntKillChar(coeffs cf)
2184{
2185  if ((--cf->extRing->ref) == 0)
2186    rDelete(cf->extRing);
2187}
2188number ntConvFactoryNSingN( const CanonicalForm n, const coeffs cf)
2189{
2190  if (n.isZero()) return NULL;
2191  poly p=convFactoryPSingP(n,ntRing);
2192  p_Normalize(p,ntRing);
2193  fraction result = (fraction)omAlloc0Bin(fractionObjectBin);
2194  NUM(result) = p;
2195  //DEN(result) = NULL; // done by omAlloc0Bin
2196  //COM(result) = 0; // done by omAlloc0Bin
2197  ntTest((number)result);
2198  return (number)result;
2199}
2200CanonicalForm ntConvSingNFactoryN( number n, BOOLEAN /*setChar*/, const coeffs cf )
2201{
2202  ntTest(n);
2203  if (IS0(n)) return CanonicalForm(0);
2204
2205  fraction f = (fraction)n;
2206  return convSingPFactoryP(NUM(f),ntRing);
2207}
2208
2209static int ntParDeg(number a, const coeffs cf)
2210{
2211  ntTest(a);
2212  if (IS0(a)) return -1;
2213  fraction fa = (fraction)a;
2214  return cf->extRing->pFDeg(NUM(fa),cf->extRing);
2215}
2216
2217/// return the specified parameter as a number in the given trans.ext.
2218static number ntParameter(const int iParameter, const coeffs cf)
2219{
2220  assume(getCoeffType(cf) == n_transExt);
2221
2222  const ring R = cf->extRing;
2223  assume( R != NULL );
2224  assume( 0 < iParameter && iParameter <= rVar(R) );
2225
2226  poly p = p_One(R); p_SetExp(p, iParameter, 1, R); p_Setm(p, R);
2227  p_Test(p,R);
2228
2229  fraction f = (fraction)omAlloc0Bin(fractionObjectBin);
2230  NUM(f) = p;
2231  //DEN(f) = NULL;
2232  //COM(f) = 0;
2233
2234  ntTest((number)f);
2235
2236  return (number)f;
2237}
2238
2239/// if m == var(i)/1 => return i,
2240int ntIsParam(number m, const coeffs cf)
2241{
2242  ntTest(m);
2243  assume(getCoeffType(cf) == n_transExt);
2244
2245  const ring R = cf->extRing;
2246  assume( R != NULL );
2247
2248  fraction f = (fraction)m;
2249
2250  if( DEN(f) != NULL )
2251    return 0;
2252
2253  return p_Var( NUM(f), R );
2254}
2255
2256struct NTNumConverter
2257{
2258  static inline poly convert(const number& n)
2259  {
2260    // suitable for trans. ext. numbers that are fractions of polys
2261    return NUM((fraction)n); // return the numerator
2262  }
2263};
2264
2265
2266static void ntClearContent(ICoeffsEnumerator& numberCollectionEnumerator, number& c, const coeffs cf)
2267{
2268  assume(cf != NULL);
2269  assume(getCoeffType(cf) == n_transExt);
2270  // all coeffs are given by fractions of polynomails over integers!!!
2271  // without denominators!!!
2272
2273  const ring   R = cf->extRing;
2274  assume(R != NULL);
2275  const coeffs Q = R->cf;
2276  assume(Q != NULL);
2277  assume(nCoeff_is_Q(Q));
2278
2279
2280  numberCollectionEnumerator.Reset();
2281
2282  if( !numberCollectionEnumerator.MoveNext() ) // empty zero polynomial?
2283  {
2284    c = ntInit(1, cf);
2285    return;
2286  }
2287
2288  // all coeffs are given by integers after returning from this routine
2289
2290  // part 1, collect product of all denominators /gcds
2291  poly cand = NULL;
2292
2293  do
2294  {
2295    number &n = numberCollectionEnumerator.Current();
2296
2297    ntNormalize(n, cf);
2298
2299    fraction f = (fraction)n;
2300
2301    assume( f != NULL );
2302
2303    const poly den = DEN(f);
2304
2305    assume( den == NULL ); // ?? / 1 ?
2306
2307    const poly num = NUM(f);
2308
2309    if( cand == NULL )
2310      cand = p_Copy(num, R);
2311    else
2312      cand = singclap_gcd(cand, p_Copy(num, R), R); // gcd(cand, num)
2313
2314    if( p_IsConstant(cand, R) )
2315      break;
2316  }
2317  while( numberCollectionEnumerator.MoveNext() ) ;
2318
2319
2320  // part2: all coeffs = all coeffs * cand
2321  if( cand != NULL )
2322  {
2323  if( !p_IsConstant(cand, R) )
2324  {
2325    c = ntInit(cand, cf);
2326    numberCollectionEnumerator.Reset();
2327    while (numberCollectionEnumerator.MoveNext() )
2328    {
2329      number &n = numberCollectionEnumerator.Current();
2330      const number t = ntDiv(n, c, cf); // TODO: rewrite!?
2331      ntDelete(&n, cf);
2332      n = t;
2333    }
2334  } // else NUM (result) = p_One(R);
2335  else { p_Delete(&cand, R); cand = NULL; }
2336  }
2337
2338  // Quick and dirty fix for constant content clearing: consider numerators???
2339  CRecursivePolyCoeffsEnumerator<NTNumConverter> itr(numberCollectionEnumerator); // recursively treat the NUM(numbers) as polys!
2340  number cc;
2341
2342  n_ClearContent(itr, cc, Q);
2343  number g = ntInit(p_NSet(cc, R), cf);
2344
2345  if( cand != NULL )
2346  {
2347    number gg = ntMult(g, c, cf);
2348    ntDelete(&g, cf);
2349    ntDelete(&c, cf); c = gg;
2350  } else
2351    c = g;
2352  ntTest(c);
2353}
2354
2355static void ntClearDenominators(ICoeffsEnumerator& numberCollectionEnumerator, number& c, const coeffs cf)
2356{
2357  assume(cf != NULL);
2358  assume(getCoeffType(cf) == n_transExt); // both over Q(a) and Zp(a)!
2359  // all coeffs are given by fractions of polynomails over integers!!!
2360
2361  numberCollectionEnumerator.Reset();
2362
2363  if( !numberCollectionEnumerator.MoveNext() ) // empty zero polynomial?
2364  {
2365    c = ntInit(1, cf);
2366    return;
2367  }
2368
2369  // all coeffs are given by integers after returning from this routine
2370
2371  // part 1, collect product of all denominators /gcds
2372  poly cand = NULL;
2373
2374  const ring R = cf->extRing;
2375  assume(R != NULL);
2376
2377  const coeffs Q = R->cf;
2378  assume(Q != NULL);
2379//  assume(nCoeff_is_Q(Q));
2380
2381  do
2382  {
2383    number &n = numberCollectionEnumerator.Current();
2384
2385    ntNormalize(n, cf);
2386
2387    fraction f = (fraction)ntGetDenom (n, cf);
2388
2389    assume( f != NULL );
2390
2391    const poly den = NUM(f);
2392
2393    if( den == NULL ) // ?? / 1 ?
2394      continue;
2395
2396    if( cand == NULL )
2397      cand = p_Copy(den, R);
2398    else
2399    {
2400      // cand === LCM( cand, den )!!!!
2401      // NOTE: maybe it's better to make the product and clearcontent afterwards!?
2402      // TODO: move the following to factory?
2403      poly gcd = singclap_gcd(p_Copy(cand, R), p_Copy(den, R), R); // gcd(cand, den) is monic no mater leading coeffs! :((((
2404      if (nCoeff_is_Q (Q))
2405      {
2406        number LcGcd= n_SubringGcd (p_GetCoeff (cand, R), p_GetCoeff(den, R), Q);
2407        gcd = p_Mult_nn(gcd, LcGcd, R);
2408        n_Delete(&LcGcd,Q);
2409      }
2410//      assume( n_IsOne(pGetCoeff(gcd), Q) ); // TODO: this may be wrong...
2411      cand = p_Mult_q(cand, p_Copy(den, R), R); // cand *= den
2412      const poly t = singclap_pdivide( cand, gcd, R ); // cand' * den / gcd(cand', den)
2413      p_Delete(&cand, R);
2414      p_Delete(&gcd, R);
2415      cand = t;
2416    }
2417  }
2418  while( numberCollectionEnumerator.MoveNext() );
2419
2420  if( cand == NULL )
2421  {
2422    c = ntInit(1, cf);
2423    return;
2424  }
2425
2426  c = ntInit(cand, cf);
2427
2428  numberCollectionEnumerator.Reset();
2429
2430  number d = NULL;
2431
2432  while (numberCollectionEnumerator.MoveNext() )
2433  {
2434    number &n = numberCollectionEnumerator.Current();
2435    number t = ntMult(n, c, cf); // TODO: rewrite!?
2436    ntDelete(&n, cf);
2437
2438    ntNormalize(t, cf); // TODO: needed?
2439    n = t;
2440
2441    fraction f = (fraction)t;
2442    assume( f != NULL );
2443
2444    const poly den = DEN(f);
2445
2446    if( den != NULL ) // ?? / ?? ?
2447    {
2448      assume( p_IsConstant(den, R) );
2449      assume( pNext(den) == NULL );
2450
2451      if( d == NULL )
2452        d = n_Copy(pGetCoeff(den), Q);
2453      else
2454      {
2455        number g = n_NormalizeHelper(d, pGetCoeff(den), Q);
2456        n_Delete(&d, Q); d = g;
2457      }
2458    }
2459  }
2460
2461  if( d != NULL )
2462  {
2463    numberCollectionEnumerator.Reset();
2464    while (numberCollectionEnumerator.MoveNext() )
2465    {
2466      number &n = numberCollectionEnumerator.Current();
2467      fraction f = (fraction)n;
2468
2469      assume( f != NULL );
2470
2471      const poly den = DEN(f);
2472
2473      if( den == NULL ) // ?? / 1 ?
2474        NUM(f) = p_Mult_nn(NUM(f), d, R);
2475      else
2476      {
2477        assume( p_IsConstant(den, R) );
2478        assume( pNext(den) == NULL );
2479
2480        number ddd = n_Div(d, pGetCoeff(den), Q); // but be an integer now!!!
2481        NUM(f) = p_Mult_nn(NUM(f), ddd, R);
2482        n_Delete(&ddd, Q);
2483
2484        p_Delete(&DEN(f), R);
2485        DEN(f) = NULL; // TODO: check if this is needed!?
2486      }
2487
2488      assume( DEN(f) == NULL );
2489    }
2490
2491    NUM((fraction)c) = p_Mult_nn(NUM((fraction)c), d, R);
2492    n_Delete(&d, Q);
2493  }
2494
2495
2496  ntTest(c);
2497}
2498
2499number  ntChineseRemainder(number *x, number *q,int rl, BOOLEAN /*sym*/,CFArray &inv_cache,const coeffs cf)
2500{
2501  fraction result = (fraction)omAlloc0Bin(fractionObjectBin);
2502
2503  poly *P=(poly*)omAlloc(rl*sizeof(poly*));
2504  number *X=(number *)omAlloc(rl*sizeof(number));
2505
2506  int i;
2507
2508  for(i=0;i<rl;i++) P[i]=p_Copy(NUM((fraction)(x[i])),cf->extRing);
2509  NUM(result)=p_ChineseRemainder(P,X,q,rl,inv_cache,cf->extRing);
2510
2511  for(i=0;i<rl;i++)
2512  {
2513    P[i]=p_Copy(DEN((fraction)(x[i])),cf->extRing);
2514    if (P[i]==NULL) P[i]=p_One(cf->extRing);
2515  }
2516  DEN(result)=p_ChineseRemainder(P,X,q,rl,inv_cache,cf->extRing);
2517
2518  omFreeSize(X,rl*sizeof(number));
2519  omFreeSize(P,rl*sizeof(poly*));
2520  if (p_IsConstant(DEN(result), ntRing)
2521  && n_IsOne(pGetCoeff(DEN(result)), ntCoeffs))
2522  {
2523    p_Delete(&DEN(result),ntRing);
2524  }
2525  ntTest((number)result);
2526  return ((number)result);
2527}
2528
2529number  ntFarey(number p, number n, const coeffs cf)
2530{
2531  // n is really a bigint
2532  fraction result = (fraction)omAlloc0Bin(fractionObjectBin);
2533  NUM(result)=p_Farey(p_Copy(NUM((fraction)p),cf->extRing),n,cf->extRing);
2534  DEN(result)=p_Farey(p_Copy(DEN((fraction)p),cf->extRing),n,cf->extRing);
2535  ntTest((number)result);
2536  return ((number)result);
2537}
2538
2539BOOLEAN ntInitChar(coeffs cf, void * infoStruct)
2540{
2541
2542  assume( infoStruct != NULL );
2543
2544  TransExtInfo *e = (TransExtInfo *)infoStruct;
2545
2546  assume( e->r                != NULL);      // extRing;
2547  assume( e->r->cf            != NULL);      // extRing->cf;
2548  assume( e->r->qideal == NULL );
2549
2550  assume( cf != NULL );
2551  assume(getCoeffType(cf) == n_transExt);                // coeff type;
2552
2553  ring R = e->r;
2554  assume(R != NULL);
2555
2556  R->ref ++; // increase the ref.counter for the ground poly. ring!
2557
2558  cf->extRing           = R;
2559  /* propagate characteristic up so that it becomes
2560     directly accessible in cf: */
2561  cf->ch = R->cf->ch;
2562
2563  cf->is_field=TRUE;
2564  cf->is_domain=TRUE;
2565  cf->rep=n_rep_rat_fct;
2566
2567  cf->factoryVarOffset = R->cf->factoryVarOffset + rVar(R);
2568
2569  cf->cfCoeffString = naCoeffString; // FIXME? TODO? // extern char* naCoeffString(const coeffs r);
2570  cf->cfCoeffName =  naCoeffName; // FIXME? TODO? // extern char* naCoeffString(const coeffs r);
2571
2572  cf->cfGreaterZero  = ntGreaterZero;
2573  cf->cfGreater      = ntGreater;
2574  cf->cfEqual        = ntEqual;
2575  cf->cfIsZero       = ntIsZero;
2576  cf->cfIsOne        = ntIsOne;
2577  cf->cfIsMOne       = ntIsMOne;
2578  cf->cfInit         = ntInit;
2579  cf->cfFarey        = ntFarey;
2580  cf->cfChineseRemainder = ntChineseRemainder;
2581  cf->cfInt          = ntInt;
2582  cf->cfInpNeg          = ntNeg;
2584  cf->cfSub          = ntSub;
2585  cf->cfMult         = ntMult;
2586  cf->cfDiv          = ntDiv;
2587  cf->cfExactDiv     = ntDiv;
2588  cf->cfPower        = ntPower;
2589  cf->cfCopy         = ntCopy;
2590  cf->cfWriteLong    = ntWriteLong;
2592  cf->cfNormalize    = ntNormalize;
2593  cf->cfDelete       = ntDelete;
2594  cf->cfSetMap       = ntSetMap;
2595  cf->cfGetDenom     = ntGetDenom;
2596  cf->cfGetNumerator = ntGetNumerator;
2597  cf->cfRePart       = ntCopy;
2598  cf->cfImPart       = ntImPart;
2599  cf->cfCoeffWrite   = ntCoeffWrite;
2600#ifdef LDEBUG
2601  cf->cfDBTest       = ntDBTest;
2602#endif
2603  //cf->cfGcd          = ntGcd_dummy;
2604  cf->cfSubringGcd   = ntGcd;
2605  cf->cfNormalizeHelper = ntNormalizeHelper;
2606  cf->cfSize         = ntSize;
2607  cf->nCoeffIsEqual  = ntCoeffIsEqual;
2608  cf->cfInvers       = ntInvers;
2609  cf->cfKillChar     = ntKillChar;
2610
2611  if( rCanShortOut(ntRing) )
2612    cf->cfWriteShort = ntWriteShort;
2613  else
2614    cf->cfWriteShort = ntWriteLong;
2615
2616  cf->convFactoryNSingN =ntConvFactoryNSingN;
2617  cf->convSingNFactoryN =ntConvSingNFactoryN;
2618  cf->cfParDeg = ntParDeg;
2619
2620  cf->iNumberOfParameters = rVar(R);
2621  cf->pParameterNames = (const char**)R->names;
2622  cf->cfParameter = ntParameter;
2623  cf->has_simple_Inverse= FALSE;
2624  /* cf->has_simple_Alloc= FALSE; */
2625
2626
2627  if( nCoeff_is_Q(R->cf) )
2628    cf->cfClearContent = ntClearContent;
2629
2630  cf->cfClearDenominators = ntClearDenominators;
2631
2632  return FALSE;
2633}
2634
2635template class CRecursivePolyCoeffsEnumerator<NTNumConverter>;
2636template class IEnumerator<snumber*>;
Note: See TracBrowser for help on using the repository browser.