source: git/libpolys/polys/ext_fields/transext.cc @ 805db88

spielwiese
Last change on this file since 805db88 was 805db88, checked in by Oleksandr Motsak <motsak@…>, 10 years ago
Avoid "if ((P)) " since clang treats such statements specially
  • Property mode set to 100644
File size: 64.0 KB
Line 
1/****************************************
2*  Computer Algebra System SINGULAR     *
3****************************************/
4/*
5* ABSTRACT: numbers in a rational function field K(t_1, .., t_s) with
6*           transcendental variables t_1, ..., t_s, where s >= 1.
7*           Denoting the implemented coeffs object by cf, then these numbers
8*           are represented as quotients of polynomials living in the
9*           polynomial ring K[t_1, .., t_s] represented by cf->extring.
10*
11*           An element of K(t_1, .., t_s) may have numerous representations,
12*           due to the possibility of common polynomial factors in the
13*           numerator and denominator. This problem is handled by a
14*           cancellation heuristic: Each number "knows" its complexity
15*           which is 0 if and only if common factors have definitely been
16*           cancelled, and some positive integer otherwise.
17*           Each arithmetic operation of two numbers with complexities c1
18*           and c2 will result in a number of complexity c1 + c2 + some
19*           penalty (specific for each arithmetic operation; see constants
20*           in the *.h file). Whenever the resulting complexity exceeds a
21*           certain threshold (see constant in the *.h file), then the
22*           cancellation heuristic will call 'factory' to compute the gcd
23*           and cancel it out in the given number. (This definite cancel-
24*           lation will also be performed at the beginning of ntWrite,
25*           ensuring that any output is free of common factors.
26*           For the special case of K = Q (i.e., when computing over the
27*           rationals), this definite cancellation procedure will also take
28*           care of nested fractions: If there are fractional coefficients
29*           in the numerator or denominator of a number, then this number
30*           is being replaced by a quotient of two polynomials over Z, or
31*           - if the denominator is a constant - by a polynomial over Q.
32*
33*           TODO: the description above needs a major update!!!
34*/
35
36
37
38
39
40#define TRANSEXT_PRIVATES
41
42#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))
1390    {
1391      NUM (f) = p_Div_nn (NUM (f), p_GetCoeff (DEN(f),ntRing), ntRing);
1392      if (p_IsConstant (DEN (f), ntRing))
1393      {
1394        p_Delete(&DEN (f), ntRing);
1395        DEN (f) = NULL;
1396      }
1397      else
1398      {
1399        p_Norm (DEN (f),ntRing);
1400      }
1401    } else if (nCoeff_is_Q(ntCoeffs)) handleNestedFractionsOverQ(f, cf);
1402  }
1403  else
1404  { /* We divide both NUM(f) and DEN(f) by the gcd which is known
1405       to be != 1. */
1406    if (p_IsConstant(DEN(f), ntRing) &&
1407        n_IsOne(p_GetCoeff(DEN(f), ntRing), ntCoeffs))
1408    {
1409      /* DEN(f) = 1 needs to be represented by NULL! */
1410      p_Delete(&DEN(f), ntRing);
1411      DEN(f) = NULL;
1412    }
1413    else
1414    {
1415      if (nCoeff_is_Zp(ntCoeffs))
1416      {
1417        NUM (f) = p_Div_nn (NUM (f), p_GetCoeff (DEN(f),ntRing), ntRing);
1418        if (p_IsConstant (DEN (f), ntRing))
1419        {
1420          p_Delete(&DEN (f), ntRing);
1421          DEN (f) = NULL;
1422        }
1423        else
1424        {
1425          p_Norm (DEN (f),ntRing);
1426        }
1427      }
1428    }
1429  }
1430  COM(f) = 0;
1431  p_Delete(&pGcd, ntRing);
1432
1433  if( DEN(f) != NULL )
1434    if( !n_GreaterZero(pGetCoeff(DEN(f)), ntCoeffs) )
1435    {
1436      NUM(f) = p_Neg(NUM(f), ntRing);
1437      DEN(f) = p_Neg(DEN(f), ntRing);
1438      if (p_IsConstant(DEN(f), ntRing) &&
1439        n_IsOne(p_GetCoeff(DEN(f), ntRing), ntCoeffs))
1440      {
1441        /* DEN(f) = 1 needs to be represented by NULL! */
1442        p_Delete(&DEN(f), ntRing);
1443        DEN (f) = NULL;
1444      }
1445    }
1446#endif /* HAVE_FACTORY */
1447
1448  ntTest(a); // !!!!
1449}
1450
1451// NOTE: modifies a
1452void ntWriteLong(number &a, const coeffs cf)
1453{
1454  ntTest(a);
1455  definiteGcdCancellation(a, cf, FALSE);
1456  if (IS0(a))
1457    StringAppendS("0");
1458  else
1459  {
1460    fraction f = (fraction)a;
1461    // stole logic from napWrite from kernel/longtrans.cc of legacy singular
1462    BOOLEAN omitBrackets = p_IsConstant(NUM(f), ntRing);
1463    if (!omitBrackets) StringAppendS("(");
1464    p_String0Long(NUM(f), ntRing, ntRing);
1465    if (!omitBrackets) StringAppendS(")");
1466    if (!DENIS1(f))
1467    {
1468      StringAppendS("/");
1469      omitBrackets = p_IsConstant(DEN(f), ntRing);
1470      if (!omitBrackets) StringAppendS("(");
1471      p_String0Long(DEN(f), ntRing, ntRing);
1472      if (!omitBrackets) StringAppendS(")");
1473    }
1474  }
1475  ntTest(a); // !!!!
1476}
1477
1478// NOTE: modifies a
1479void ntWriteShort(number &a, const coeffs cf)
1480{
1481  ntTest(a);
1482  definiteGcdCancellation(a, cf, FALSE);
1483  if (IS0(a))
1484    StringAppendS("0");
1485  else
1486  {
1487    fraction f = (fraction)a;
1488    // stole logic from napWrite from kernel/longtrans.cc of legacy singular
1489    BOOLEAN omitBrackets = p_IsConstant(NUM(f), ntRing);
1490    if (!omitBrackets) StringAppendS("(");
1491    p_String0Short(NUM(f), ntRing, ntRing);
1492    if (!omitBrackets) StringAppendS(")");
1493    if (!DENIS1(f))
1494    {
1495      StringAppendS("/");
1496      omitBrackets = p_IsConstant(DEN(f), ntRing);
1497      if (!omitBrackets) StringAppendS("(");
1498      p_String0Short(DEN(f), ntRing, ntRing);
1499      if (!omitBrackets) StringAppendS(")");
1500    }
1501  }
1502  ntTest(a);
1503}
1504
1505const char * ntRead(const char *s, number *a, const coeffs cf)
1506{
1507  poly p;
1508  const char * result = p_Read(s, p, ntRing);
1509  if (p == NULL) *a = NULL;
1510  else *a = ntInit(p, cf);
1511  return result;
1512}
1513
1514void ntNormalize (number &a, const coeffs cf)
1515{
1516  if ( /*(*/ a!=NULL /*)*/ )
1517  {
1518    definiteGcdCancellation(a, cf, FALSE);
1519    if ((DEN(a)!=NULL)
1520    &&(!n_GreaterZero(pGetCoeff(DEN(a)),ntCoeffs)))
1521    {
1522      NUM(a)=p_Neg(NUM(a),ntRing);
1523      DEN(a)=p_Neg(DEN(a),ntRing);
1524    }
1525  }
1526  ntTest(a); // !!!!
1527}
1528
1529/* expects *param to be castable to TransExtInfo */
1530static BOOLEAN ntCoeffIsEqual(const coeffs cf, n_coeffType n, void * param)
1531{
1532  if (ID != n) return FALSE;
1533  TransExtInfo *e = (TransExtInfo *)param;
1534  /* for rational function fields we expect the underlying
1535     polynomial rings to be IDENTICAL, i.e. the SAME OBJECT;
1536     this expectation is based on the assumption that we have properly
1537     registered cf and perform reference counting rather than creating
1538     multiple copies of the same coefficient field/domain/ring */
1539  if (ntRing == e->r)
1540    return TRUE;
1541
1542  // NOTE: Q(a)[x] && Q(a)[y] should better share the _same_ Q(a)...
1543  if( rEqual(ntRing, e->r, TRUE) )
1544  {
1545    rDelete(e->r);
1546    return TRUE;
1547  }
1548
1549  return FALSE;
1550}
1551
1552number ntLcm(number a, number b, const coeffs cf)
1553{
1554  ntTest(a);
1555  ntTest(b);
1556  fraction fb = (fraction)b;
1557  if ((b==NULL)||(DEN(fb)==NULL)) return ntCopy(a,cf);
1558#ifdef HAVE_FACTORY
1559  fraction fa = (fraction)a;
1560  /* singclap_gcd destroys its arguments; we hence need copies: */
1561  poly pa = p_Copy(NUM(fa), ntRing);
1562  poly pb = p_Copy(DEN(fb), ntRing);
1563
1564  poly pGcd;
1565  if (nCoeff_is_Q(ntCoeffs))
1566  {
1567    if (p_IsConstant(pa,ntRing) && p_IsConstant(pb,ntRing))
1568    {
1569      pGcd = pa;
1570      p_SetCoeff (pGcd, n_Gcd (pGetCoeff(pGcd), pGetCoeff(pb), ntCoeffs), ntRing);
1571    }
1572    else
1573    {
1574      number contentpa, contentpb, tmp;
1575
1576      contentpb= p_GetCoeff(pb, ntRing);
1577      pIter(pb);
1578      while (pb != NULL)
1579      {
1580        tmp = n_Gcd(contentpb, p_GetCoeff(pb, ntRing) , ntCoeffs);
1581        n_Delete(&contentpb, ntCoeffs);
1582        contentpb = tmp;
1583        pIter(pb);
1584      }
1585
1586      contentpa= p_GetCoeff(pa, ntRing);
1587      pIter(pa);
1588      while (pa != NULL)
1589      {
1590        tmp = n_Gcd(contentpa, p_GetCoeff(pa, ntRing), ntCoeffs);
1591        n_Delete(&contentpa, ntCoeffs);
1592        contentpa = tmp;
1593        pIter(pa);
1594      }
1595
1596      tmp= n_Gcd (contentpb, contentpa, ntCoeffs);
1597      n_Delete(&contentpa, ntCoeffs);
1598      n_Delete(&contentpb, ntCoeffs);
1599      contentpa= tmp;
1600      p_Delete(&pb, ntRing);
1601      p_Delete(&pa, ntRing);
1602
1603      /* singclap_gcd destroys its arguments; we hence need copies: */
1604      pGcd = singclap_gcd(p_Copy(NUM(fa),ntRing), p_Copy(DEN(fb),ntRing), ntRing);
1605      pGcd= p_Mult_nn (pGcd, contentpa, ntRing);
1606      n_Delete(&contentpa, ntCoeffs);
1607    }
1608  }
1609  else
1610    pGcd = singclap_gcd(pa, pb, cf->extRing);
1611
1612  /* Note that, over Q, singclap_gcd will remove the denominators in all
1613     rational coefficients of pa and pb, before starting to compute
1614     the gcd. Thus, we do not need to ensure that the coefficients of
1615     pa and pb live in Z; they may well be elements of Q\Z. */
1616
1617  if (p_IsConstant(pGcd, ntRing) &&
1618      n_IsOne(p_GetCoeff(pGcd, ntRing), ntCoeffs))
1619  { /* gcd = 1; return pa*pb*/
1620    p_Delete(&pGcd,ntRing);
1621    fraction result = (fraction)omAlloc0Bin(fractionObjectBin);
1622    NUM(result) = pp_Mult_qq(NUM(fa),DEN(fb),ntRing);
1623
1624    ntTest((number)result); // !!!!
1625
1626    return (number)result;
1627  }
1628
1629
1630  /* return pa*pb/gcd */
1631    poly newNum = singclap_pdivide(NUM(fa), pGcd, ntRing);
1632    p_Delete(&pGcd,ntRing);
1633    fraction result = (fraction)omAlloc0Bin(fractionObjectBin);
1634    NUM(result) = p_Mult_q(p_Copy(DEN(fb),ntRing),newNum,ntRing);
1635    ntTest((number)result); // !!!!
1636    return (number)result;
1637
1638#else
1639  Print("// factory needed: transext.cc:ntLcm\n");
1640  return NULL;
1641#endif /* HAVE_FACTORY */
1642  return NULL;
1643}
1644
1645number ntGcd(number a, number b, const coeffs cf)
1646{
1647  ntTest(a);
1648  ntTest(b);
1649  if (a==NULL) return ntCopy(b,cf);
1650  if (b==NULL) return ntCopy(a,cf);
1651#ifdef HAVE_FACTORY
1652  fraction fa = (fraction)a;
1653  fraction fb = (fraction)b;
1654
1655  poly pa = p_Copy(NUM(fa), ntRing);
1656  poly pb = p_Copy(NUM(fb), ntRing);
1657
1658  poly pGcd;
1659  if (nCoeff_is_Q(ntCoeffs))
1660  {
1661    if (p_IsConstant(pa,ntRing) && p_IsConstant(pb,ntRing))
1662    {
1663      pGcd = pa;
1664      p_SetCoeff (pGcd, n_Gcd (pGetCoeff(pGcd), pGetCoeff(pb), ntCoeffs), ntRing);
1665    }
1666    else
1667    {
1668      number contentpa, contentpb, tmp;
1669
1670      contentpb= p_GetCoeff(pb, ntRing);
1671      pIter(pb);
1672      while (pb != NULL)
1673      {
1674        tmp = n_Gcd(contentpb, p_GetCoeff(pb, ntRing) , ntCoeffs);
1675        n_Delete(&contentpb, ntCoeffs);
1676        contentpb = tmp;
1677        pIter(pb);
1678      }
1679
1680      contentpa= p_GetCoeff(pa, ntRing);
1681      pIter(pa);
1682      while (pa != NULL)
1683      {
1684        tmp = n_Gcd(contentpa, p_GetCoeff(pa, ntRing), ntCoeffs);
1685        n_Delete(&contentpa, ntCoeffs);
1686        contentpa = tmp;
1687        pIter(pa);
1688      }
1689
1690      tmp= n_Gcd (contentpb, contentpa, ntCoeffs);
1691      n_Delete(&contentpa, ntCoeffs);
1692      n_Delete(&contentpb, ntCoeffs);
1693      contentpa= tmp;
1694      p_Delete(&pb, ntRing);
1695      p_Delete(&pa, ntRing);
1696
1697      /* singclap_gcd destroys its arguments; we hence need copies: */
1698      pGcd = singclap_gcd(p_Copy(NUM(fa),ntRing), p_Copy(NUM(fb),ntRing), ntRing);
1699      pGcd= p_Mult_nn (pGcd, contentpa, ntRing);
1700      n_Delete(&contentpa, ntCoeffs);
1701    }
1702  }
1703  else
1704    pGcd = singclap_gcd(pa, pb, cf->extRing);
1705  /* Note that, over Q, singclap_gcd will remove the denominators in all
1706     rational coefficients of pa and pb, before starting to compute
1707     the gcd. Thus, we do not need to ensure that the coefficients of
1708     pa and pb live in Z; they may well be elements of Q\Z. */
1709
1710  fraction result = (fraction)omAlloc0Bin(fractionObjectBin);
1711  NUM(result) = pGcd;
1712  ntTest((number)result); // !!!!
1713  return (number)result;
1714#else
1715  Print("// factory needed: transext.cc:ntGcd\n");
1716  return NULL;
1717#endif /* HAVE_FACTORY */
1718}
1719
1720int ntSize(number a, const coeffs cf)
1721{
1722  ntTest(a);
1723  if (IS0(a)) return -1;
1724  /* this has been taken from the old implementation of field extensions,
1725     where we computed the sum of the degrees and the numbers of terms in
1726     the numerator and denominator of a; so we leave it at that, for the
1727     time being */
1728  fraction f = (fraction)a;
1729  poly p = NUM(f);
1730  int noOfTerms = 0;
1731  int numDegree = 0;
1732  while (p != NULL)
1733  {
1734    noOfTerms++;
1735    int d = 0;
1736    for (int i = 1; i <= rVar(ntRing); i++)
1737      d += p_GetExp(p, i, ntRing);
1738    if (d > numDegree) numDegree = d;
1739    pIter(p);
1740  }
1741  int denDegree = 0;
1742  if (!DENIS1(f))
1743  {
1744    p = DEN(f);
1745    while (p != NULL)
1746    {
1747      noOfTerms++;
1748      int d = 0;
1749      for (int i = 1; i <= rVar(ntRing); i++)
1750        d += p_GetExp(p, i, ntRing);
1751      if (d > denDegree) denDegree = d;
1752      pIter(p);
1753    }
1754  }
1755  ntTest(a); // !!!!
1756  return numDegree + denDegree + noOfTerms;
1757}
1758
1759number ntInvers(number a, const coeffs cf)
1760{
1761  //check_N(a,cf);
1762  ntTest(a);
1763  if (IS0(a))
1764  {
1765    WerrorS(nDivBy0);
1766    return NULL;
1767  }
1768  fraction f = (fraction)a;
1769  assume( f != NULL );
1770
1771  fraction result = (fraction)omAlloc0Bin(fractionObjectBin);
1772
1773  assume( NUM(f) != NULL );
1774  const poly den = DEN(f);
1775
1776  if (den == NULL)
1777    NUM(result) = p_One(ntRing);
1778  else
1779    NUM(result) = p_Copy(den, ntRing);
1780
1781  if( !NUMIS1(f) )
1782  {
1783    poly num_f=NUM(f);
1784    BOOLEAN neg= !n_GreaterZero(pGetCoeff(num_f),ntCoeffs);
1785    if (neg)
1786    {
1787      num_f=p_Neg(p_Copy(num_f, ntRing), ntRing);
1788      NUM(result)=p_Neg(NUM(result), ntRing);
1789    }
1790    else
1791    {
1792      num_f=p_Copy(num_f, ntRing);
1793    }
1794    DEN(result) = num_f;
1795    COM(result) = COM(f);
1796    if (neg)
1797    {
1798      if (p_IsOne(num_f, ntRing))
1799      {
1800        DEN(result)=NULL;
1801        //COM(result) = 0;
1802        p_Delete(&num_f,ntRing);
1803      }
1804    }
1805  }
1806  //else// Alloc0
1807  //{
1808  //  DEN(result) = NULL;
1809  //  COM(result) = 0;
1810  //}
1811  ntTest((number)result); // !!!!
1812  //check_N((number)result,cf);
1813  return (number)result;
1814}
1815
1816/* assumes that src = Q, dst = Q(t_1, ..., t_s) */
1817number ntMap00(number a, const coeffs src, const coeffs dst)
1818{
1819  if (n_IsZero(a, src)) return NULL;
1820  assume(n_Test(a, src));
1821  assume(src == dst->extRing->cf);
1822  if ((SR_HDL(a) & SR_INT) || (a->s==3))
1823  {
1824    number res=ntInit(p_NSet(n_Copy(a, src), dst->extRing), dst);
1825    n_Test(res,dst);
1826    return res;
1827  }
1828  number nn=nlGetDenom(a,src);
1829  number zz=nlGetNumerator(a,src);
1830  number res=ntInit(p_NSet(zz,dst->extRing), dst);
1831  fraction ff=(fraction)res;
1832  if (n_IsOne(nn,src)) DEN(ff)=NULL;
1833  else                 DEN(ff)=p_NSet(nn,dst->extRing);
1834  n_Test((number)ff,dst);
1835  //check_N((number)ff,dst);
1836  return (number)ff;
1837}
1838
1839/* assumes that src = Z/p, dst = Q(t_1, ..., t_s) */
1840number ntMapP0(number a, const coeffs src, const coeffs dst)
1841{
1842  if (n_IsZero(a, src)) return NULL;
1843  assume(n_Test(a, src));
1844  /* mapping via intermediate int: */
1845  int n = n_Int(a, src);
1846  number q = n_Init(n, dst->extRing->cf);
1847  if (n_IsZero(q, dst->extRing->cf))
1848  {
1849    n_Delete(&q, dst->extRing->cf);
1850    return NULL;
1851  }
1852  return ntInit(p_NSet(q, dst->extRing), dst);
1853}
1854
1855/* assumes that either src = Q(t_1, ..., t_s), dst = Q(t_1, ..., t_s), or
1856                       src = Z/p(t_1, ..., t_s), dst = Z/p(t_1, ..., t_s) */
1857number ntCopyMap(number a, const coeffs cf, const coeffs dst)
1858{
1859//  if (n_IsZero(a, cf)) return NULL;
1860
1861  ntTest(a);
1862
1863  if (IS0(a)) return NULL;
1864
1865  const ring rSrc = cf->extRing;
1866  const ring rDst = dst->extRing;
1867
1868  if( rSrc == rDst )
1869    return ntCopy(a, dst); // USUALLY WRONG!
1870
1871  fraction f = (fraction)a;
1872  poly g = prCopyR(NUM(f), rSrc, rDst);
1873
1874  poly h = NULL;
1875
1876  if (!DENIS1(f))
1877     h = prCopyR(DEN(f), rSrc, rDst);
1878
1879  fraction result = (fraction)omAllocBin(fractionObjectBin);
1880
1881  NUM(result) = g;
1882  DEN(result) = h;
1883  COM(result) = COM(f);
1884  //check_N((number)result,dst);
1885  assume(n_Test((number)result, dst));
1886  return (number)result;
1887}
1888
1889number ntCopyAlg(number a, const coeffs cf, const coeffs dst)
1890{
1891  assume( n_Test(a, cf) );
1892  if (n_IsZero(a, cf)) return NULL;
1893  return ntInit(prCopyR((poly)a, cf->extRing, dst->extRing),dst);
1894}
1895
1896/* assumes that src = Q, dst = Z/p(t_1, ..., t_s) */
1897number ntMap0P(number a, const coeffs src, const coeffs dst)
1898{
1899  assume( n_Test(a, src) );
1900  if (n_IsZero(a, src)) return NULL;
1901  // int p = rChar(dst->extRing);
1902  number q = nlModP(a, src, dst->extRing->cf);
1903
1904  if (n_IsZero(q, dst->extRing->cf))
1905  {
1906    n_Delete(&q, dst->extRing->cf);
1907    return NULL;
1908  }
1909
1910  poly g = p_NSet(q, dst->extRing);
1911
1912  fraction f = (fraction)omAlloc0Bin(fractionObjectBin);
1913  NUM(f) = g; // DEN(f) = NULL; COM(f) = 0;
1914  assume(n_Test((number)f, dst));
1915  //check_N((number)f,dst);
1916  return (number)f;
1917}
1918
1919/* assumes that src = Z/p, dst = Z/p(t_1, ..., t_s) */
1920number ntMapPP(number a, const coeffs src, const coeffs dst)
1921{
1922  assume( n_Test(a, src) );
1923  if (n_IsZero(a, src)) return NULL;
1924  assume(src == dst->extRing->cf);
1925  poly p = p_One(dst->extRing);
1926  p_SetCoeff(p, n_Copy(a, src), dst->extRing);
1927  fraction f = (fraction)omAlloc0Bin(fractionObjectBin);
1928  NUM(f) = p; // DEN(f) = NULL; COM(f) = 0;
1929  assume(n_Test((number)f, dst));
1930  //check_N((number)f,dst);
1931  return (number)f;
1932}
1933
1934/* assumes that src = Z/u, dst = Z/p(t_1, ..., t_s), where u != p */
1935number ntMapUP(number a, const coeffs src, const coeffs dst)
1936{
1937  assume( n_Test(a, src) );
1938  if (n_IsZero(a, src)) return NULL;
1939  /* mapping via intermediate int: */
1940  int n = n_Int(a, src);
1941  number q = n_Init(n, dst->extRing->cf);
1942  poly p;
1943  if (n_IsZero(q, dst->extRing->cf))
1944  {
1945    n_Delete(&q, dst->extRing->cf);
1946    return NULL;
1947  }
1948  p = p_One(dst->extRing);
1949  p_SetCoeff(p, q, dst->extRing);
1950  fraction f = (fraction)omAlloc0Bin(fractionObjectBin);
1951  NUM(f) = p; // DEN(f) = NULL; COM(f) = 0;
1952  assume(n_Test((number)f, dst));
1953  //check_N((number)f,dst);
1954  return (number)f;
1955}
1956
1957nMapFunc ntSetMap(const coeffs src, const coeffs dst)
1958{
1959  /* dst is expected to be a rational function field */
1960  assume(getCoeffType(dst) == ID);
1961
1962  if( src == dst ) return ndCopyMap;
1963
1964  int h = 0; /* the height of the extension tower given by dst */
1965  coeffs bDst = nCoeff_bottom(dst, h); /* the bottom field in the tower dst */
1966  coeffs bSrc = nCoeff_bottom(src, h); /* the bottom field in the tower src */
1967
1968  /* for the time being, we only provide maps if h = 1 and if b is Q or
1969     some field Z/pZ: */
1970  if (h==0)
1971  {
1972    if (nCoeff_is_Q(src) && nCoeff_is_Q(bDst))
1973      return ntMap00;                                 /// Q       -->  Q(T)
1974    if (nCoeff_is_Zp(src) && nCoeff_is_Q(bDst))
1975      return ntMapP0;                                 /// Z/p     -->  Q(T)
1976    if (nCoeff_is_Q(src) && nCoeff_is_Zp(bDst))
1977      return ntMap0P;                                 /// Q       --> Z/p(T)
1978    if (nCoeff_is_Zp(src) && nCoeff_is_Zp(bDst))
1979    {
1980      if (src->ch == dst->ch) return ntMapPP;         /// Z/p     --> Z/p(T)
1981      else return ntMapUP;                            /// Z/u     --> Z/p(T)
1982    }
1983  }
1984  if (h != 1) return NULL;
1985  if ((!nCoeff_is_Zp(bDst)) && (!nCoeff_is_Q(bDst))) return NULL;
1986
1987  /* Let T denote the sequence of transcendental extension variables, i.e.,
1988     K[t_1, ..., t_s] =: K[T];
1989     Let moreover, for any such sequence T, T' denote any subsequence of T
1990     of the form t_1, ..., t_w with w <= s. */
1991
1992  if ((!nCoeff_is_Zp(bSrc)) && (!nCoeff_is_Q(bSrc))) return NULL;
1993
1994  if (nCoeff_is_Q(bSrc) && nCoeff_is_Q(bDst))
1995  {
1996    if (rVar(src->extRing) > rVar(dst->extRing))
1997       return NULL;
1998
1999    for (int i = 0; i < rVar(src->extRing); i++)
2000      if (strcmp(rRingVar(i, src->extRing), rRingVar(i, dst->extRing)) != 0)
2001         return NULL;
2002
2003    if (src->type==n_transExt)
2004       return ntCopyMap;          /// Q(T')   --> Q(T)
2005    else
2006       return ntCopyAlg;
2007  }
2008
2009  if (nCoeff_is_Zp(bSrc) && nCoeff_is_Zp(bDst))
2010  {
2011    if (rVar(src->extRing) > rVar(dst->extRing))
2012       return NULL;
2013
2014    for (int i = 0; i < rVar(src->extRing); i++)
2015      if (strcmp(rRingVar(i, src->extRing), rRingVar(i, dst->extRing)) != 0)
2016         return NULL;
2017
2018    if (src->type==n_transExt)
2019       return ntCopyMap;         /// Z/p(T') --> Z/p(T)
2020    else
2021       return ntCopyAlg;
2022  }
2023
2024  return NULL;                                 /// default
2025}
2026#if 0
2027nMapFunc ntSetMap_T(const coeffs src, const coeffs dst)
2028{
2029  nMapFunc n=ntSetMap(src,dst);
2030  if (n==ntCopyAlg) printf("n=ntCopyAlg\n");
2031  else if (n==ntCopyMap) printf("n=ntCopyMap\n");
2032  else if (n==ntMapUP) printf("n=ntMapUP\n");
2033  else if (n==ntMap0P) printf("n=ntMap0P\n");
2034  else if (n==ntMapP0) printf("n=ntMapP0\n");
2035  else if (n==ntMap00) printf("n=ntMap00\n");
2036  else if (n==NULL) printf("n=NULL\n");
2037  else printf("n=?\n");
2038  return n;
2039}
2040#endif
2041
2042void ntKillChar(coeffs cf)
2043{
2044  if ((--cf->extRing->ref) == 0)
2045    rDelete(cf->extRing);
2046}
2047#ifdef HAVE_FACTORY
2048number ntConvFactoryNSingN( const CanonicalForm n, const coeffs cf)
2049{
2050  if (n.isZero()) return NULL;
2051  poly p=convFactoryPSingP(n,ntRing);
2052  p_Normalize(p,ntRing);
2053  fraction result = (fraction)omAlloc0Bin(fractionObjectBin);
2054  NUM(result) = p;
2055  //DEN(result) = NULL; // done by omAlloc0Bin
2056  //COM(result) = 0; // done by omAlloc0Bin
2057  ntTest((number)result);
2058  return (number)result;
2059}
2060CanonicalForm ntConvSingNFactoryN( number n, BOOLEAN /*setChar*/, const coeffs cf )
2061{
2062  ntTest(n);
2063  if (IS0(n)) return CanonicalForm(0);
2064
2065  fraction f = (fraction)n;
2066  return convSingPFactoryP(NUM(f),ntRing);
2067}
2068#endif
2069
2070static int ntParDeg(number a, const coeffs cf)
2071{
2072  ntTest(a);
2073  if (IS0(a)) return -1;
2074  fraction fa = (fraction)a;
2075  return cf->extRing->pFDeg(NUM(fa),cf->extRing);
2076}
2077
2078/// return the specified parameter as a number in the given trans.ext.
2079static number ntParameter(const int iParameter, const coeffs cf)
2080{
2081  assume(getCoeffType(cf) == ID);
2082
2083  const ring R = cf->extRing;
2084  assume( R != NULL );
2085  assume( 0 < iParameter && iParameter <= rVar(R) );
2086
2087  poly p = p_One(R); p_SetExp(p, iParameter, 1, R); p_Setm(p, R);
2088  p_Test(p,R);
2089
2090  fraction f = (fraction)omAlloc0Bin(fractionObjectBin);
2091  NUM(f) = p;
2092  //DEN(f) = NULL;
2093  //COM(f) = 0;
2094
2095  ntTest((number)f);
2096
2097  return (number)f;
2098}
2099
2100/// if m == var(i)/1 => return i,
2101int ntIsParam(number m, const coeffs cf)
2102{
2103  ntTest(m);
2104  assume(getCoeffType(cf) == ID);
2105
2106  const ring R = cf->extRing;
2107  assume( R != NULL );
2108
2109  fraction f = (fraction)m;
2110
2111  if( DEN(f) != NULL )
2112    return 0;
2113
2114  return p_Var( NUM(f), R );
2115}
2116
2117struct NTNumConverter
2118{
2119  static inline poly convert(const number& n)
2120  {
2121    // suitable for trans. ext. numbers that are fractions of polys
2122    return NUM((fraction)n); // return the numerator
2123  }
2124};
2125
2126
2127static void ntClearContent(ICoeffsEnumerator& numberCollectionEnumerator, number& c, const coeffs cf)
2128{
2129  assume(cf != NULL);
2130  assume(getCoeffType(cf) == ID);
2131  // all coeffs are given by fractions of polynomails over integers!!!
2132  // without denominators!!!
2133
2134  const ring   R = cf->extRing;
2135  assume(R != NULL);
2136  const coeffs Q = R->cf;
2137  assume(Q != NULL);
2138  assume(nCoeff_is_Q(Q));
2139
2140
2141  numberCollectionEnumerator.Reset();
2142
2143  if( !numberCollectionEnumerator.MoveNext() ) // empty zero polynomial?
2144  {
2145    c = ntInit(1, cf);
2146    return;
2147  }
2148
2149  // all coeffs are given by integers after returning from this routine
2150
2151  // part 1, collect product of all denominators /gcds
2152  poly cand = NULL;
2153
2154  do
2155  {
2156    number &n = numberCollectionEnumerator.Current();
2157
2158    ntNormalize(n, cf);
2159
2160    fraction f = (fraction)n;
2161
2162    assume( f != NULL );
2163
2164    const poly den = DEN(f);
2165
2166    assume( den == NULL ); // ?? / 1 ?
2167
2168    const poly num = NUM(f);
2169
2170    if( cand == NULL )
2171      cand = p_Copy(num, R);
2172    else
2173      cand = singclap_gcd(cand, p_Copy(num, R), R); // gcd(cand, num)
2174
2175    if( p_IsConstant(cand, R) )
2176      break;
2177  }
2178  while( numberCollectionEnumerator.MoveNext() ) ;
2179
2180
2181  // part2: all coeffs = all coeffs * cand
2182  if( cand != NULL )
2183  {
2184  if( !p_IsConstant(cand, R) )
2185  {
2186    c = ntInit(cand, cf);
2187    numberCollectionEnumerator.Reset();
2188    while (numberCollectionEnumerator.MoveNext() )
2189    {
2190      number &n = numberCollectionEnumerator.Current();
2191      const number t = ntDiv(n, c, cf); // TODO: rewrite!?
2192      ntDelete(&n, cf);
2193      n = t;
2194    }
2195  } // else NUM (result) = p_One(R);
2196  else { p_Delete(&cand, R); cand = NULL; }
2197  }
2198
2199  // Quick and dirty fix for constant content clearing: consider numerators???
2200  CRecursivePolyCoeffsEnumerator<NTNumConverter> itr(numberCollectionEnumerator); // recursively treat the NUM(numbers) as polys!
2201  number cc;
2202
2203  n_ClearContent(itr, cc, Q);
2204  number g = ntInit(p_NSet(cc, R), cf);
2205
2206  if( cand != NULL )
2207  {
2208    number gg = ntMult(g, c, cf);
2209    ntDelete(&g, cf);
2210    ntDelete(&c, cf); c = gg;
2211  } else
2212    c = g;
2213  ntTest(c);
2214}
2215
2216static void ntClearDenominators(ICoeffsEnumerator& numberCollectionEnumerator, number& c, const coeffs cf)
2217{
2218  assume(cf != NULL);
2219  assume(getCoeffType(cf) == ID); // both over Q(a) and Zp(a)!
2220  // all coeffs are given by fractions of polynomails over integers!!!
2221
2222  numberCollectionEnumerator.Reset();
2223
2224  if( !numberCollectionEnumerator.MoveNext() ) // empty zero polynomial?
2225  {
2226    c = ntInit(1, cf);
2227    return;
2228  }
2229
2230  // all coeffs are given by integers after returning from this routine
2231
2232  // part 1, collect product of all denominators /gcds
2233  poly cand = NULL;
2234
2235  const ring R = cf->extRing;
2236  assume(R != NULL);
2237
2238  const coeffs Q = R->cf;
2239  assume(Q != NULL);
2240//  assume(nCoeff_is_Q(Q));
2241
2242  do
2243  {
2244    number &n = numberCollectionEnumerator.Current();
2245
2246    ntNormalize(n, cf);
2247
2248    fraction f = (fraction)ntGetDenom (n, cf);
2249
2250    assume( f != NULL );
2251
2252    const poly den = NUM(f);
2253
2254    if( den == NULL ) // ?? / 1 ?
2255      continue;
2256
2257    if( cand == NULL )
2258      cand = p_Copy(den, R);
2259    else
2260    {
2261      // cand === LCM( cand, den )!!!!
2262      // NOTE: maybe it's better to make the product and clearcontent afterwards!?
2263      // TODO: move the following to factory?
2264      poly gcd = singclap_gcd(p_Copy(cand, R), p_Copy(den, R), R); // gcd(cand, den) is monic no mater leading coeffs! :((((
2265      if (nCoeff_is_Q (Q))
2266      {
2267        number LcGcd= n_Gcd (p_GetCoeff (cand, R), p_GetCoeff(den, R), Q);
2268        gcd = p_Mult_nn(gcd, LcGcd, R);
2269        n_Delete(&LcGcd,Q);
2270      }
2271//      assume( n_IsOne(pGetCoeff(gcd), Q) ); // TODO: this may be wrong...
2272      cand = p_Mult_q(cand, p_Copy(den, R), R); // cand *= den
2273      const poly t = singclap_pdivide( cand, gcd, R ); // cand' * den / gcd(cand', den)
2274      p_Delete(&cand, R);
2275      p_Delete(&gcd, R);
2276      cand = t;
2277    }
2278  }
2279  while( numberCollectionEnumerator.MoveNext() );
2280
2281  if( cand == NULL )
2282  {
2283    c = ntInit(1, cf);
2284    return;
2285  }
2286
2287  c = ntInit(cand, cf);
2288
2289  numberCollectionEnumerator.Reset();
2290
2291  number d = NULL;
2292
2293  while (numberCollectionEnumerator.MoveNext() )
2294  {
2295    number &n = numberCollectionEnumerator.Current();
2296    number t = ntMult(n, c, cf); // TODO: rewrite!?
2297    ntDelete(&n, cf);
2298
2299    ntNormalize(t, cf); // TODO: needed?
2300    n = t;
2301
2302    fraction f = (fraction)t;
2303    assume( f != NULL );
2304
2305    const poly den = DEN(f);
2306
2307    if( den != NULL ) // ?? / ?? ?
2308    {
2309      assume( p_IsConstant(den, R) );
2310      assume( pNext(den) == NULL );
2311
2312      if( d == NULL )
2313        d = n_Copy(pGetCoeff(den), Q);
2314      else
2315      {
2316        number g = n_Lcm(d, pGetCoeff(den), Q);
2317        n_Delete(&d, Q); d = g;
2318      }
2319    }
2320  }
2321
2322  if( d != NULL )
2323  {
2324    numberCollectionEnumerator.Reset();
2325    while (numberCollectionEnumerator.MoveNext() )
2326    {
2327      number &n = numberCollectionEnumerator.Current();
2328      fraction f = (fraction)n;
2329
2330      assume( f != NULL );
2331
2332      const poly den = DEN(f);
2333
2334      if( den == NULL ) // ?? / 1 ?
2335        NUM(f) = p_Mult_nn(NUM(f), d, R);
2336      else
2337      {
2338        assume( p_IsConstant(den, R) );
2339        assume( pNext(den) == NULL );
2340
2341        number ddd = n_Div(d, pGetCoeff(den), Q); // but be an integer now!!!
2342        NUM(f) = p_Mult_nn(NUM(f), ddd, R);
2343        n_Delete(&ddd, Q);
2344
2345        p_Delete(&DEN(f), R);
2346        DEN(f) = NULL; // TODO: check if this is needed!?
2347      }
2348
2349      assume( DEN(f) == NULL );
2350    }
2351
2352    NUM(c) = p_Mult_nn(NUM(c), d, R);
2353    n_Delete(&d, Q);
2354  }
2355
2356
2357  ntTest(c);
2358}
2359
2360BOOLEAN ntInitChar(coeffs cf, void * infoStruct)
2361{
2362
2363  assume( infoStruct != NULL );
2364
2365  TransExtInfo *e = (TransExtInfo *)infoStruct;
2366
2367  assume( e->r                != NULL);      // extRing;
2368  assume( e->r->cf            != NULL);      // extRing->cf;
2369  assume( e->r->qideal == NULL );
2370
2371  assume( cf != NULL );
2372  assume(getCoeffType(cf) == ID);                // coeff type;
2373
2374  ring R = e->r;
2375  assume(R != NULL);
2376
2377  R->ref ++; // increase the ref.counter for the ground poly. ring!
2378
2379  cf->extRing           = R;
2380  /* propagate characteristic up so that it becomes
2381     directly accessible in cf: */
2382  cf->ch = R->cf->ch;
2383  cf->factoryVarOffset = R->cf->factoryVarOffset + rVar(R);
2384
2385  cf->cfGreaterZero  = ntGreaterZero;
2386  cf->cfGreater      = ntGreater;
2387  cf->cfEqual        = ntEqual;
2388  cf->cfIsZero       = ntIsZero;
2389  cf->cfIsOne        = ntIsOne;
2390  cf->cfIsMOne       = ntIsMOne;
2391  cf->cfInit         = ntInit;
2392  cf->cfInit_bigint  = ntInit_bigint;
2393  cf->cfInt          = ntInt;
2394  cf->cfNeg          = ntNeg;
2395  cf->cfAdd          = ntAdd;
2396  cf->cfSub          = ntSub;
2397  cf->cfMult         = ntMult;
2398  cf->cfDiv          = ntDiv;
2399  cf->cfExactDiv     = ntDiv;
2400  cf->cfPower        = ntPower;
2401  cf->cfCopy         = ntCopy;
2402  cf->cfWriteLong    = ntWriteLong;
2403  cf->cfRead         = ntRead;
2404  cf->cfNormalize    = ntNormalize;
2405  cf->cfDelete       = ntDelete;
2406  cf->cfSetMap       = ntSetMap;
2407  cf->cfGetDenom     = ntGetDenom;
2408  cf->cfGetNumerator = ntGetNumerator;
2409  cf->cfRePart       = ntCopy;
2410  cf->cfImPart       = ntImPart;
2411  cf->cfCoeffWrite   = ntCoeffWrite;
2412#ifdef LDEBUG
2413  cf->cfDBTest       = ntDBTest;
2414#endif
2415  cf->cfGcd          = ntGcd;
2416  cf->cfLcm          = ntLcm;
2417  cf->cfSize         = ntSize;
2418  cf->nCoeffIsEqual  = ntCoeffIsEqual;
2419  cf->cfInvers       = ntInvers;
2420  cf->cfIntDiv       = ntDiv;
2421  cf->cfKillChar     = ntKillChar;
2422
2423  if( rCanShortOut(ntRing) )
2424    cf->cfWriteShort = ntWriteShort;
2425  else
2426    cf->cfWriteShort = ntWriteLong;
2427
2428#ifndef HAVE_FACTORY
2429  PrintS("// Warning: The 'factory' module is not available.\n");
2430  PrintS("//          Hence gcd's cannot be cancelled in any\n");
2431  PrintS("//          computed fraction!\n");
2432#else
2433  cf->convFactoryNSingN =ntConvFactoryNSingN;
2434  cf->convSingNFactoryN =ntConvSingNFactoryN;
2435#endif
2436  cf->cfParDeg = ntParDeg;
2437
2438  cf->iNumberOfParameters = rVar(R);
2439  cf->pParameterNames = R->names;
2440  cf->cfParameter = ntParameter;
2441  cf->has_simple_Inverse= FALSE;
2442  /* cf->has_simple_Alloc= FALSE; */
2443
2444
2445  if( nCoeff_is_Q(R->cf) )
2446    cf->cfClearContent = ntClearContent;
2447
2448  cf->cfClearDenominators = ntClearDenominators;
2449
2450  return FALSE;
2451}
2452
2453template class CRecursivePolyCoeffsEnumerator<NTNumConverter>;
2454template class IEnumerator<snumber*>;
Note: See TracBrowser for help on using the repository browser.