source: git/libpolys/polys/ext_fields/transext.cc @ 4132ee

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