source: git/libpolys/polys/ext_fields/transext.cc @ 616d685

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