source: git/libpolys/polys/ext_fields/transext.cc @ 8d5f05

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