source: git/libpolys/polys/ext_fields/transext.cc @ 2206753

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