source: git/libpolys/polys/ext_fields/transext.cc @ ba52f58

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