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

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