source: git/libpolys/polys/ext_fields/transext.cc @ 1e8006

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