source: git/libpolys/polys/ext_fields/transext.cc @ 2de7b0

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