source: git/libpolys/polys/ext_fields/transext.cc @ 20f29bb

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