source: git/libpolys/polys/ext_fields/transext.cc @ 6d92ca

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