source: git/libpolys/polys/ext_fields/transext.cc @ 9ccaaf

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