source: git/libpolys/polys/ext_fields/transext.cc @ 7a09e1d

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