source: git/libpolys/polys/ext_fields/transext.cc @ 57f6787

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