source: git/libpolys/polys/ext_fields/transext.cc @ 271d25

spielwiese
Last change on this file since 271d25 was 558f3cc, checked in by Oleksandr Motsak <motsak@…>, 11 years ago
Fix: make positive leading coeff at normalizing!
  • Property mode set to 100644
File size: 55.5 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 = 0;
611  number bNumCoeff = NULL; int bNumDeg = 0;
612  if (!IS0(a))
613  {
614    fraction fa = (fraction)a;
615    aNumDeg = p_Totaldegree(NUM(fa), ntRing);
616    aNumCoeff = p_GetCoeff(NUM(fa), ntRing);
617  }
618  if (!IS0(b))
619  {
620    fraction fb = (fraction)b;
621    bNumDeg = p_Totaldegree(NUM(fb), ntRing);
622    bNumCoeff = p_GetCoeff(NUM(fb), ntRing);
623  }
624  if (aNumDeg > bNumDeg) return TRUE;
625  if (aNumDeg < bNumDeg) return FALSE;
626  return n_Greater(aNumCoeff, bNumCoeff, ntCoeffs);
627}
628
629/* this method will only consider the numerator of a, without cancelling
630   the gcd before;
631   returns TRUE iff the leading coefficient of the numerator of a is > 0
632                    or the leading term of the numerator of a is not a
633                    constant */
634BOOLEAN ntGreaterZero(number a, const coeffs cf)
635{
636  ntTest(a);
637  if (IS0(a)) return FALSE;
638  fraction f = (fraction)a;
639  poly g = NUM(f);
640  return (n_GreaterZero(p_GetCoeff(g, ntRing), ntCoeffs) ||
641          (!p_LmIsConstant(g, ntRing)));
642}
643
644void ntCoeffWrite(const coeffs cf, BOOLEAN details)
645{
646  assume( cf != NULL );
647
648  const ring A = cf->extRing;
649
650  assume( A != NULL );
651  assume( A->cf != NULL );
652
653  n_CoeffWrite(A->cf, details);
654
655//  rWrite(A);
656
657  const int P = rVar(A);
658  assume( P > 0 );
659
660  Print("//   %d parameter    : ", P);
661
662  for (int nop=0; nop < P; nop ++)
663    Print("%s ", rRingVar(nop, A));
664
665  assume( A->qideal == NULL );
666
667  PrintS("\n//   minpoly        : 0\n");
668
669/*
670  PrintS("//   Coefficients live in the rational function field\n");
671  Print("//   K(");
672  for (int i = 0; i < rVar(ntRing); i++)
673  {
674    if (i > 0) PrintS(" ");
675    Print("%s", rRingVar(i, ntRing));
676  }
677  PrintS(") with\n");
678  PrintS("//   K: "); n_CoeffWrite(cf->extRing->cf);
679*/
680}
681
682number ntAdd(number a, number b, const coeffs cf)
683{
684  ntTest(a);
685  ntTest(b);
686  if (IS0(a)) return ntCopy(b, cf);
687  if (IS0(b)) return ntCopy(a, cf);
688
689  fraction fa = (fraction)a;
690  fraction fb = (fraction)b;
691
692  poly g = p_Copy(NUM(fa), ntRing);
693  if (!DENIS1(fb)) g = p_Mult_q(g, p_Copy(DEN(fb), ntRing), ntRing);
694  poly h = p_Copy(NUM(fb), ntRing);
695  if (!DENIS1(fa)) h = p_Mult_q(h, p_Copy(DEN(fa), ntRing), ntRing);
696  g = p_Add_q(g, h, ntRing);
697
698  if (g == NULL) return NULL;
699
700  poly f;
701  if      (DENIS1(fa) && DENIS1(fb))  f = NULL;
702  else if (!DENIS1(fa) && DENIS1(fb)) f = p_Copy(DEN(fa), ntRing);
703  else if (DENIS1(fa) && !DENIS1(fb)) f = p_Copy(DEN(fb), ntRing);
704  else /* both denom's are != 1 */    f = p_Mult_q(p_Copy(DEN(fa), ntRing),
705                                                   p_Copy(DEN(fb), ntRing),
706                                                   ntRing);
707
708  fraction result = (fraction)omAlloc0Bin(fractionObjectBin);
709  NUM(result) = g;
710  DEN(result) = f;
711  COM(result) = COM(fa) + COM(fb) + ADD_COMPLEXITY;
712  heuristicGcdCancellation((number)result, cf);
713
714//  ntTest((number)result);
715
716  return (number)result;
717}
718
719number ntSub(number a, number b, const coeffs cf)
720{
721  ntTest(a);
722  ntTest(b);
723  if (IS0(a)) return ntNeg(ntCopy(b, cf), cf);
724  if (IS0(b)) return ntCopy(a, cf);
725
726  fraction fa = (fraction)a;
727  fraction fb = (fraction)b;
728
729  poly g = p_Copy(NUM(fa), ntRing);
730  if (!DENIS1(fb)) g = p_Mult_q(g, p_Copy(DEN(fb), ntRing), ntRing);
731  poly h = p_Copy(NUM(fb), ntRing);
732  if (!DENIS1(fa)) h = p_Mult_q(h, p_Copy(DEN(fa), ntRing), ntRing);
733  g = p_Add_q(g, p_Neg(h, ntRing), ntRing);
734
735  if (g == NULL) return NULL;
736
737  poly f;
738  if      (DENIS1(fa) && DENIS1(fb))  f = NULL;
739  else if (!DENIS1(fa) && DENIS1(fb)) f = p_Copy(DEN(fa), ntRing);
740  else if (DENIS1(fa) && !DENIS1(fb)) f = p_Copy(DEN(fb), ntRing);
741  else /* both den's are != 1 */      f = p_Mult_q(p_Copy(DEN(fa), ntRing),
742                                                   p_Copy(DEN(fb), ntRing),
743                                                   ntRing);
744
745  fraction result = (fraction)omAlloc0Bin(fractionObjectBin);
746  NUM(result) = g;
747  DEN(result) = f;
748  COM(result) = COM(fa) + COM(fb) + ADD_COMPLEXITY;
749  heuristicGcdCancellation((number)result, cf);
750//  ntTest((number)result);
751  return (number)result;
752}
753
754number ntMult(number a, number b, const coeffs cf)
755{
756  ntTest(a); // !!!?
757  ntTest(b); // !!!?
758
759  if (IS0(a) || IS0(b)) return NULL;
760
761  fraction fa = (fraction)a;
762  fraction fb = (fraction)b;
763
764  const poly g = pp_Mult_qq(NUM(fa), NUM(fb), ntRing);
765
766  if (g == NULL) return NULL; // may happen due to zero divisors???
767
768  fraction result = (fraction)omAlloc0Bin(fractionObjectBin);
769
770  NUM(result) = g;
771
772  const poly da = DEN(fa);
773  const poly db = DEN(fb);
774
775
776  if (db == NULL)
777  {
778    // b = ? // NULL
779
780    if(da == NULL)
781    { // both fa && fb are ?? // NULL!
782      assume (da == NULL && db == NULL);
783      DEN(result) = NULL;
784      COM(result) = 0;
785    }
786    else
787    {
788      assume (da != NULL && db == NULL);
789      DEN(result) = p_Copy(da, ntRing);
790      COM(result) = COM(fa) + MULT_COMPLEXITY;
791      heuristicGcdCancellation((number)result, cf);
792    }
793  } else
794  { // b = ?? / ??
795    if (da == NULL)
796    { // a == ? // NULL
797      assume( db != NULL && da == NULL);
798      DEN(result) = p_Copy(db, ntRing);
799      COM(result) = COM(fb) + MULT_COMPLEXITY;
800      heuristicGcdCancellation((number)result, cf);
801    }
802    else /* both den's are != 1 */
803    {
804      assume (da != NULL && db != NULL);
805      DEN(result) = pp_Mult_qq(da, db, ntRing);
806      COM(result) = COM(fa) + COM(fb) + MULT_COMPLEXITY;
807      heuristicGcdCancellation((number)result, cf);
808    }
809  }
810
811//  ntTest((number)result);
812
813  return (number)result;
814}
815
816number ntDiv(number a, number b, const coeffs cf)
817{
818  ntTest(a);
819  ntTest(b);
820  if (IS0(a)) return NULL;
821  if (IS0(b)) WerrorS(nDivBy0);
822
823  fraction fa = (fraction)a;
824  fraction fb = (fraction)b;
825
826  poly g = p_Copy(NUM(fa), ntRing);
827  if (!DENIS1(fb)) g = p_Mult_q(g, p_Copy(DEN(fb), ntRing), ntRing);
828
829  if (g == NULL) return NULL;   /* may happen due to zero divisors */
830
831  poly f = p_Copy(NUM(fb), ntRing);
832  if (!DENIS1(fa)) f = p_Mult_q(f, p_Copy(DEN(fa), ntRing), ntRing);
833
834  fraction result = (fraction)omAlloc0Bin(fractionObjectBin);
835  NUM(result) = g;
836  if (!p_IsConstant(f,ntRing) || !n_IsOne(pGetCoeff(f),ntRing->cf))
837    DEN(result) = f;
838  COM(result) = COM(fa) + COM(fb) + MULT_COMPLEXITY;
839  heuristicGcdCancellation((number)result, cf);
840//  ntTest((number)result);
841  return (number)result;
842}
843
844/* 0^0 = 0;
845   for |exp| <= 7 compute power by a simple multiplication loop;
846   for |exp| >= 8 compute power along binary presentation of |exp|, e.g.
847      p^13 = p^1 * p^4 * p^8, where we utilise that
848      p^(2^(k+1)) = p^(2^k) * p^(2^k);
849   intermediate cancellation is controlled by the in-place method
850   heuristicGcdCancellation; see there.
851*/
852void ntPower(number a, int exp, number *b, const coeffs cf)
853{
854  ntTest(a);
855
856  /* special cases first */
857  if (IS0(a))
858  {
859    if (exp >= 0) *b = NULL;
860    else          WerrorS(nDivBy0);
861  }
862  else if (exp ==  0) { *b = ntInit(1, cf); return;}
863  else if (exp ==  1) { *b = ntCopy(a, cf); return;}
864  else if (exp == -1) { *b = ntInvers(a, cf); return;}
865
866  int expAbs = exp; if (expAbs < 0) expAbs = -expAbs;
867
868  /* now compute a^expAbs */
869  number pow; number t;
870  if (expAbs <= 7)
871  {
872    pow = ntCopy(a, cf);
873    for (int i = 2; i <= expAbs; i++)
874    {
875      t = ntMult(pow, a, cf);
876      ntDelete(&pow, cf);
877      pow = t;
878      heuristicGcdCancellation(pow, cf);
879    }
880  }
881  else
882  {
883    pow = ntInit(1, cf);
884    number factor = ntCopy(a, cf);
885    while (expAbs != 0)
886    {
887      if (expAbs & 1)
888      {
889        t = ntMult(pow, factor, cf);
890        ntDelete(&pow, cf);
891        pow = t;
892        heuristicGcdCancellation(pow, cf);
893      }
894      expAbs = expAbs / 2;
895      if (expAbs != 0)
896      {
897        t = ntMult(factor, factor, cf);
898        ntDelete(&factor, cf);
899        factor = t;
900        heuristicGcdCancellation(factor, cf);
901      }
902    }
903    ntDelete(&factor, cf);
904  }
905
906  /* invert if original exponent was negative */
907  if (exp < 0)
908  {
909    t = ntInvers(pow, cf);
910    ntDelete(&pow, cf);
911    pow = t;
912  }
913  *b = pow;
914  ntTest(*b);
915}
916
917/* assumes that cf represents the rationals, i.e. Q, and will only
918   be called in that case;
919   assumes furthermore that f != NULL and that the denominator of f != 1;
920   generally speaking, this method removes denominators in the rational
921   coefficients of the numerator and denominator of 'a';
922   more concretely, the following normalizations will be performed,
923   where t^alpha denotes a monomial in the transcendental variables t_k
924   (1) if 'a' is of the form
925          (sum_alpha a_alpha/b_alpha * t^alpha)
926          -------------------------------------
927            (sum_beta c_beta/d_beta * t^beta)
928       with integers a_alpha, b_alpha, c_beta, d_beta, then both the
929       numerator and the denominator will be multiplied by the LCM of
930       the b_alpha's and the d_beta's (if this LCM is != 1),
931   (2) if 'a' is - e.g. after having performed step (1) - of the form
932          (sum_alpha a_alpha * t^alpha)
933          -----------------------------
934            (sum_beta c_beta * t^beta)
935       with integers a_alpha, c_beta, and with a non-constant denominator,
936       then both the numerator and the denominator will be divided by the
937       GCD of the a_alpha's and the c_beta's (if this GCD is != 1),
938   (3) if 'a' is - e.g. after having performed steps (1) and (2) - of the
939       form
940          (sum_alpha a_alpha * t^alpha)
941          -----------------------------
942                        c
943       with integers a_alpha, and c != 1, then 'a' will be replaced by
944       (sum_alpha a_alpha/c * t^alpha);
945   this procedure does not alter COM(f) (this has to be done by the
946   calling procedure);
947   modifies f */
948void handleNestedFractionsOverQ(fraction f, const coeffs cf)
949{
950  assume(nCoeff_is_Q(ntCoeffs));
951  assume(!IS0(f));
952  assume(!DENIS1(f));
953
954  if (!p_IsConstant(DEN(f), ntRing))
955  { /* step (1); see documentation of this procedure above */
956    p_Normalize(NUM(f), ntRing);
957    p_Normalize(DEN(f), ntRing);
958    number lcmOfDenominators = n_Init(1, ntCoeffs);
959    number c; number tmp;
960    poly p = NUM(f);
961    /* careful when using n_Lcm!!! It computes the lcm of the numerator
962       of the 1st argument and the denominator of the 2nd!!! */
963    while (p != NULL)
964    {
965      c = p_GetCoeff(p, ntRing);
966      tmp = n_Lcm(lcmOfDenominators, c, ntCoeffs);
967      n_Delete(&lcmOfDenominators, ntCoeffs);
968      lcmOfDenominators = tmp;
969      pIter(p);
970    }
971    p = DEN(f);
972    while (p != NULL)
973    {
974      c = p_GetCoeff(p, ntRing);
975      tmp = n_Lcm(lcmOfDenominators, c, ntCoeffs);
976      n_Delete(&lcmOfDenominators, ntCoeffs);
977      lcmOfDenominators = tmp;
978      pIter(p);
979    }
980    if (!n_IsOne(lcmOfDenominators, ntCoeffs))
981    { /* multiply NUM(f) and DEN(f) with lcmOfDenominators */
982      NUM(f) = p_Mult_nn(NUM(f), lcmOfDenominators, ntRing);
983      p_Normalize(NUM(f), ntRing);
984      DEN(f) = p_Mult_nn(DEN(f), lcmOfDenominators, ntRing);
985      p_Normalize(DEN(f), ntRing);
986    }
987    n_Delete(&lcmOfDenominators, ntCoeffs);
988    if (!p_IsConstant(DEN(f), ntRing))
989    { /* step (2); see documentation of this procedure above */
990      p = NUM(f);
991      number gcdOfCoefficients = n_Copy(p_GetCoeff(p, ntRing), ntCoeffs);
992      pIter(p);
993      while ((p != NULL) && (!n_IsOne(gcdOfCoefficients, ntCoeffs)))
994      {
995        c = p_GetCoeff(p, ntRing);
996        tmp = n_Gcd(c, gcdOfCoefficients, ntCoeffs);
997        n_Delete(&gcdOfCoefficients, ntCoeffs);
998        gcdOfCoefficients = tmp;
999        pIter(p);
1000      }
1001      p = DEN(f);
1002      while ((p != NULL) && (!n_IsOne(gcdOfCoefficients, ntCoeffs)))
1003      {
1004        c = p_GetCoeff(p, ntRing);
1005        tmp = n_Gcd(c, gcdOfCoefficients, ntCoeffs);
1006        n_Delete(&gcdOfCoefficients, ntCoeffs);
1007        gcdOfCoefficients = tmp;
1008        pIter(p);
1009      }
1010      if (!n_IsOne(gcdOfCoefficients, ntCoeffs))
1011      { /* divide NUM(f) and DEN(f) by gcdOfCoefficients */
1012        number inverseOfGcdOfCoefficients = n_Invers(gcdOfCoefficients,
1013                                                     ntCoeffs);
1014        NUM(f) = p_Mult_nn(NUM(f), inverseOfGcdOfCoefficients, ntRing);
1015        p_Normalize(NUM(f), ntRing);
1016        DEN(f) = p_Mult_nn(DEN(f), inverseOfGcdOfCoefficients, ntRing);
1017        p_Normalize(DEN(f), ntRing);
1018        n_Delete(&inverseOfGcdOfCoefficients, ntCoeffs);
1019      }
1020      n_Delete(&gcdOfCoefficients, ntCoeffs);
1021    }
1022  }
1023  if (p_IsConstant(DEN(f), ntRing) &&
1024      (!n_IsOne(p_GetCoeff(DEN(f), ntRing), ntCoeffs)))
1025  { /* step (3); see documentation of this procedure above */
1026    number inverseOfDen = n_Invers(p_GetCoeff(DEN(f), ntRing), ntCoeffs);
1027    NUM(f) = p_Mult_nn(NUM(f), inverseOfDen, ntRing);
1028    n_Delete(&inverseOfDen, ntCoeffs);
1029    p_Delete(&DEN(f), ntRing);
1030    DEN(f) = NULL;
1031  }
1032
1033  /* Now, due to the above computations, DEN(f) may have become the
1034     1-polynomial which needs to be represented by NULL: */
1035  if ((DEN(f) != NULL) &&
1036      p_IsConstant(DEN(f), ntRing) &&
1037      n_IsOne(p_GetCoeff(DEN(f), ntRing), ntCoeffs))
1038  {
1039    p_Delete(&DEN(f), ntRing); DEN(f) = NULL;
1040  }
1041
1042  if( DEN(f) != NULL )
1043    if( !n_GreaterZero(pGetCoeff(DEN(f)), ntCoeffs) )
1044    {
1045      NUM(f) = p_Neg(NUM(f), ntRing);
1046      DEN(f) = p_Neg(DEN(f), ntRing);
1047    }
1048
1049  ntTest((number)f); // TODO!
1050}
1051
1052/* modifies a */
1053void heuristicGcdCancellation(number a, const coeffs cf)
1054{
1055//  ntTest(a); // !!!!????
1056  if (IS0(a)) return;
1057
1058  fraction f = (fraction)a;
1059  if (DENIS1(f) || NUMIS1(f)) { COM(f) = 0; ntTest(a); return; }
1060
1061  assume( DEN(f) != NULL );
1062
1063  /* check whether NUM(f) = DEN(f), and - if so - replace 'a' by 1 */
1064  if (p_EqualPolys(NUM(f), DEN(f), ntRing))
1065  { /* numerator and denominator are both != 1 */
1066    p_Delete(&NUM(f), ntRing); NUM(f) = p_ISet(1, ntRing);
1067    p_Delete(&DEN(f), ntRing); DEN(f) = NULL;
1068    COM(f) = 0;
1069  } else
1070  {
1071    if (COM(f) > BOUND_COMPLEXITY)
1072      definiteGcdCancellation(a, cf, TRUE);
1073
1074  // TODO: check if it is enough to put the following into definiteGcdCancellation?!
1075  if( DEN(f) != NULL )
1076    if( !n_GreaterZero(pGetCoeff(DEN(f)), ntCoeffs) )
1077    {
1078      NUM(f) = p_Neg(NUM(f), ntRing);
1079      DEN(f) = p_Neg(DEN(f), ntRing);
1080    }
1081  }
1082
1083
1084  ntTest(a); // !!!!????
1085}
1086
1087/// modifies a
1088void definiteGcdCancellation(number a, const coeffs cf,
1089                             BOOLEAN simpleTestsHaveAlreadyBeenPerformed)
1090{
1091  ntTest(a); // !!!!
1092
1093  fraction f = (fraction)a;
1094
1095  if (!simpleTestsHaveAlreadyBeenPerformed)
1096  {
1097    if (IS0(a)) return;
1098    if (DENIS1(f) || NUMIS1(f)) { COM(f) = 0; return; }
1099
1100    /* check whether NUM(f) = DEN(f), and - if so - replace 'a' by 1 */
1101    if (p_EqualPolys(NUM(f), DEN(f), ntRing))
1102    { /* numerator and denominator are both != 1 */
1103      p_Delete(&NUM(f), ntRing); NUM(f) = p_ISet(1, ntRing);
1104      p_Delete(&DEN(f), ntRing); DEN(f) = NULL;
1105      COM(f) = 0;
1106      ntTest(a); // !!!!
1107      return;
1108    }
1109  }
1110
1111#ifdef HAVE_FACTORY
1112  /* Note that, over Q, singclap_gcd will remove the denominators in all
1113     rational coefficients of pNum and pDen, before starting to compute
1114     the gcd. Thus, we do not need to ensure that the coefficients of
1115     pNum and pDen live in Z; they may well be elements of Q\Z. */
1116  /* singclap_gcd destroys its arguments; we hence need copies: */
1117  poly pGcd = singclap_gcd(p_Copy(NUM(f), ntRing), p_Copy(DEN(f), ntRing), cf->extRing);
1118  if (p_IsConstant(pGcd, ntRing) &&
1119      n_IsOne(p_GetCoeff(pGcd, ntRing), ntCoeffs))
1120  { /* gcd = 1; nothing to cancel;
1121       Suppose the given rational function field is over Q. Although the
1122       gcd is 1, we may have produced fractional coefficients in NUM(f),
1123       DEN(f), or both, due to previous arithmetics. The next call will
1124       remove those nested fractions, in case there are any. */
1125    if (nCoeff_is_Zp(ntCoeffs) && p_IsConstant (DEN (f), ntRing))
1126    {
1127      NUM (f) = p_Div_nn (NUM (f), p_GetCoeff (DEN(f),ntRing), ntRing);
1128      //poly newNum= singclap_pdivide (NUM(f), DEN (f), ntRing);
1129      //p_Delete(&NUM (f), ntRing);
1130      //NUM (f)= newNum;
1131      p_Delete(&DEN (f), ntRing);
1132      DEN (f) = NULL;
1133      COM (f) = 0;
1134    } else if (nCoeff_is_Q(ntCoeffs)) handleNestedFractionsOverQ(f, cf);
1135  }
1136  else
1137  { /* We divide both NUM(f) and DEN(f) by the gcd which is known
1138       to be != 1. */
1139    poly newNum = singclap_pdivide(NUM(f), pGcd, ntRing);
1140    p_Delete(&NUM(f), ntRing);
1141    NUM(f) = newNum;
1142    poly newDen = singclap_pdivide(DEN(f), pGcd, ntRing);
1143    p_Delete(&DEN(f), ntRing);
1144    DEN(f) = newDen;
1145    if (p_IsConstant(DEN(f), ntRing) &&
1146        n_IsOne(p_GetCoeff(DEN(f), ntRing), ntCoeffs))
1147    {
1148      /* DEN(f) = 1 needs to be represented by NULL! */
1149      p_Delete(&DEN(f), ntRing);
1150      newDen = NULL;
1151    }
1152    else
1153    { /* Note that over Q, by cancelling the gcd, we may have produced
1154         fractional coefficients in NUM(f), DEN(f), or both. The next
1155         call will remove those nested fractions, in case there are
1156         any. */
1157      if (nCoeff_is_Q(ntCoeffs)) handleNestedFractionsOverQ(f, cf);
1158    }
1159  }
1160  COM(f) = 0;
1161  p_Delete(&pGcd, ntRing);
1162
1163  if( DEN(f) != NULL )
1164    if( !n_GreaterZero(pGetCoeff(DEN(f)), ntCoeffs) )
1165    {
1166      NUM(f) = p_Neg(NUM(f), ntRing);
1167      DEN(f) = p_Neg(DEN(f), ntRing);
1168    }
1169#endif /* HAVE_FACTORY */
1170
1171  ntTest(a); // !!!!
1172}
1173
1174// NOTE: modifies a
1175void ntWriteLong(number &a, const coeffs cf)
1176{
1177  ntTest(a);
1178  definiteGcdCancellation(a, cf, FALSE);
1179  if (IS0(a))
1180    StringAppendS("0");
1181  else
1182  {
1183    fraction f = (fraction)a;
1184    // stole logic from napWrite from kernel/longtrans.cc of legacy singular
1185    BOOLEAN omitBrackets = p_IsConstant(NUM(f), ntRing);
1186    if (!omitBrackets) StringAppendS("(");
1187    p_String0Long(NUM(f), ntRing, ntRing);
1188    if (!omitBrackets) StringAppendS(")");
1189    if (!DENIS1(f))
1190    {
1191      StringAppendS("/");
1192      omitBrackets = p_IsConstant(DEN(f), ntRing);
1193      if (!omitBrackets) StringAppendS("(");
1194      p_String0Long(DEN(f), ntRing, ntRing);
1195      if (!omitBrackets) StringAppendS(")");
1196    }
1197  }
1198  ntTest(a); // !!!!
1199}
1200
1201// NOTE: modifies a
1202void ntWriteShort(number &a, const coeffs cf)
1203{
1204  ntTest(a);
1205  definiteGcdCancellation(a, cf, FALSE);
1206  if (IS0(a))
1207    StringAppendS("0");
1208  else
1209  {
1210    fraction f = (fraction)a;
1211    // stole logic from napWrite from kernel/longtrans.cc of legacy singular
1212    BOOLEAN omitBrackets = p_IsConstant(NUM(f), ntRing);
1213    if (!omitBrackets) StringAppendS("(");
1214    p_String0Short(NUM(f), ntRing, ntRing);
1215    if (!omitBrackets) StringAppendS(")");
1216    if (!DENIS1(f))
1217    {
1218      StringAppendS("/");
1219      omitBrackets = p_IsConstant(DEN(f), ntRing);
1220      if (!omitBrackets) StringAppendS("(");
1221      p_String0Short(DEN(f), ntRing, ntRing);
1222      if (!omitBrackets) StringAppendS(")");
1223    }
1224  }
1225  ntTest(a);
1226}
1227
1228const char * ntRead(const char *s, number *a, const coeffs cf)
1229{
1230  poly p;
1231  const char * result = p_Read(s, p, ntRing);
1232  if (p == NULL) *a = NULL;
1233  else *a = ntInit(p, cf);
1234  return result;
1235}
1236
1237void ntNormalize (number &a, const coeffs cf)
1238{
1239  if ((a!=NULL))
1240  {
1241    definiteGcdCancellation(a, cf, FALSE);
1242    if ((DEN(a)!=NULL)
1243    &&(!n_GreaterZero(pGetCoeff(DEN(a)),ntRing->cf)))
1244    {
1245      NUM(a)=p_Neg(NUM(a),ntRing);
1246      DEN(a)=p_Neg(DEN(a),ntRing);
1247    }
1248  }
1249  ntTest(a); // !!!!
1250}
1251
1252/* expects *param to be castable to TransExtInfo */
1253static BOOLEAN ntCoeffIsEqual(const coeffs cf, n_coeffType n, void * param)
1254{
1255  if (ID != n) return FALSE;
1256  TransExtInfo *e = (TransExtInfo *)param;
1257  /* for rational function fields we expect the underlying
1258     polynomial rings to be IDENTICAL, i.e. the SAME OBJECT;
1259     this expectation is based on the assumption that we have properly
1260     registered cf and perform reference counting rather than creating
1261     multiple copies of the same coefficient field/domain/ring */
1262  if (ntRing == e->r)
1263    return TRUE;
1264
1265  // NOTE: Q(a)[x] && Q(a)[y] should better share the _same_ Q(a)...
1266  if( rEqual(ntRing, e->r, TRUE) )
1267  {
1268    rDelete(e->r);
1269    return TRUE;
1270  }
1271
1272  return FALSE;
1273}
1274
1275number ntLcm(number a, number b, const coeffs cf)
1276{
1277  ntTest(a);
1278  ntTest(b);
1279  fraction fb = (fraction)b;
1280  if ((b==NULL)||(DEN(fb)==NULL)) return ntCopy(a,cf);
1281#ifdef HAVE_FACTORY
1282  fraction fa = (fraction)a;
1283  /* singclap_gcd destroys its arguments; we hence need copies: */
1284  poly pa = p_Copy(NUM(fa), ntRing);
1285  poly pb = p_Copy(DEN(fb), ntRing);
1286
1287  /* Note that, over Q, singclap_gcd will remove the denominators in all
1288     rational coefficients of pa and pb, before starting to compute
1289     the gcd. Thus, we do not need to ensure that the coefficients of
1290     pa and pb live in Z; they may well be elements of Q\Z. */
1291  poly pGcd = singclap_gcd(pa, pb, cf->extRing);
1292  if (p_IsConstant(pGcd, ntRing) &&
1293      n_IsOne(p_GetCoeff(pGcd, ntRing), ntCoeffs))
1294  { /* gcd = 1; return pa*pb*/
1295    p_Delete(&pGcd,ntRing);
1296    fraction result = (fraction)omAlloc0Bin(fractionObjectBin);
1297    NUM(result) = pp_Mult_qq(NUM(fa),DEN(fb),ntRing);
1298
1299    ntTest((number)result); // !!!!
1300
1301    return (number)result;
1302  }
1303
1304
1305  /* return pa*pb/gcd */
1306    poly newNum = singclap_pdivide(NUM(fa), pGcd, ntRing);
1307    p_Delete(&pGcd,ntRing);
1308    fraction result = (fraction)omAlloc0Bin(fractionObjectBin);
1309    NUM(result) = p_Mult_q(p_Copy(DEN(fb),ntRing),newNum,ntRing);
1310    ntTest((number)result); // !!!!
1311    return (number)result;
1312
1313#else
1314  Print("// factory needed: transext.cc:ntLcm\n");
1315  return NULL;
1316#endif /* HAVE_FACTORY */
1317  return NULL;
1318}
1319
1320number ntGcd(number a, number b, const coeffs cf)
1321{
1322  ntTest(a);
1323  ntTest(b);
1324  if (a==NULL) return ntCopy(b,cf);
1325  if (b==NULL) return ntCopy(a,cf);
1326#ifdef HAVE_FACTORY
1327  fraction fa = (fraction)a;
1328  fraction fb = (fraction)b;
1329  /* singclap_gcd destroys its arguments; we hence need copies: */
1330  poly pa = p_Copy(NUM(fa), ntRing);
1331  poly pb = p_Copy(NUM(fb), ntRing);
1332
1333  /* Note that, over Q, singclap_gcd will remove the denominators in all
1334     rational coefficients of pa and pb, before starting to compute
1335     the gcd. Thus, we do not need to ensure that the coefficients of
1336     pa and pb live in Z; they may well be elements of Q\Z. */
1337  poly pGcd = singclap_gcd(pa, pb, cf->extRing);
1338  fraction result = (fraction)omAlloc0Bin(fractionObjectBin);
1339  NUM(result) = pGcd;
1340  ntTest((number)result); // !!!!
1341  return (number)result;
1342#else
1343  Print("// factory needed: transext.cc:ntGcd\n");
1344  return NULL;
1345#endif /* HAVE_FACTORY */
1346}
1347
1348int ntSize(number a, const coeffs cf)
1349{
1350  ntTest(a);
1351  if (IS0(a)) return -1;
1352  /* this has been taken from the old implementation of field extensions,
1353     where we computed the sum of the degrees and the numbers of terms in
1354     the numerator and denominator of a; so we leave it at that, for the
1355     time being */
1356  fraction f = (fraction)a;
1357  poly p = NUM(f);
1358  int noOfTerms = 0;
1359  int numDegree = 0;
1360  while (p != NULL)
1361  {
1362    noOfTerms++;
1363    int d = 0;
1364    for (int i = 1; i <= rVar(ntRing); i++)
1365      d += p_GetExp(p, i, ntRing);
1366    if (d > numDegree) numDegree = d;
1367    pIter(p);
1368  }
1369  int denDegree = 0;
1370  if (!DENIS1(f))
1371  {
1372    p = DEN(f);
1373    while (p != NULL)
1374    {
1375      noOfTerms++;
1376      int d = 0;
1377      for (int i = 1; i <= rVar(ntRing); i++)
1378        d += p_GetExp(p, i, ntRing);
1379      if (d > denDegree) denDegree = d;
1380      pIter(p);
1381    }
1382  }
1383  ntTest(a); // !!!!
1384  return numDegree + denDegree + noOfTerms;
1385}
1386
1387number ntInvers(number a, const coeffs cf)
1388{
1389  ntTest(a);
1390  if (IS0(a))
1391  {
1392    WerrorS(nDivBy0);
1393    return NULL;
1394  }
1395  fraction f = (fraction)a;
1396  assume( f != NULL );
1397
1398  fraction result = (fraction)omAlloc0Bin(fractionObjectBin);
1399
1400  assume( NUM(f) != NULL );
1401  const poly den = DEN(f);
1402
1403  if (den == NULL)
1404    NUM(result) = p_One(ntRing);
1405  else
1406    NUM(result) = p_Copy(den, ntRing);
1407
1408  if( !NUMIS1(f) )
1409  {
1410    poly num_f=NUM(f);
1411    BOOLEAN neg= !n_GreaterZero(pGetCoeff(num_f),ntRing->cf);
1412    if (neg)
1413    {
1414      num_f=p_Neg(p_Copy(num_f, ntRing), ntRing);
1415      NUM(result)=p_Neg(NUM(result), ntRing);
1416    }
1417    else
1418    {
1419      num_f=p_Copy(num_f, ntRing);
1420    }
1421    DEN(result) = num_f;
1422    COM(result) = COM(f);
1423    if (neg)
1424    {
1425      if (p_IsOne(num_f, ntRing))
1426      {
1427        DEN(result)=NULL;
1428        COM(result) = 0;
1429        p_Delete(&num_f,ntRing);
1430      }
1431    }
1432  }
1433  else
1434  {
1435    DEN(result) = NULL;
1436    COM(result) = 0;
1437  }
1438  ntTest((number)result); // !!!!
1439  return (number)result;
1440}
1441
1442/* assumes that src = Q, dst = Q(t_1, ..., t_s) */
1443number ntMap00(number a, const coeffs src, const coeffs dst)
1444{
1445  if (n_IsZero(a, src)) return NULL;
1446  assume(n_Test(a, src));
1447  assume(src == dst->extRing->cf);
1448  return ntInit(p_NSet(n_Copy(a, src), dst->extRing), dst);
1449}
1450
1451/* assumes that src = Z/p, dst = Q(t_1, ..., t_s) */
1452number ntMapP0(number a, const coeffs src, const coeffs dst)
1453{
1454  if (n_IsZero(a, src)) return NULL;
1455  assume(n_Test(a, src));
1456  /* mapping via intermediate int: */
1457  int n = n_Int(a, src);
1458  number q = n_Init(n, dst->extRing->cf);
1459  if (n_IsZero(q, dst->extRing->cf))
1460  {
1461    n_Delete(&q, dst->extRing->cf);
1462    return NULL;
1463  }
1464  return ntInit(p_NSet(q, dst->extRing), dst);
1465}
1466
1467/* assumes that either src = Q(t_1, ..., t_s), dst = Q(t_1, ..., t_s), or
1468                       src = Z/p(t_1, ..., t_s), dst = Z/p(t_1, ..., t_s) */
1469number ntCopyMap(number a, const coeffs cf, const coeffs dst)
1470{
1471//  if (n_IsZero(a, cf)) return NULL;
1472
1473  ntTest(a);
1474
1475  if (IS0(a)) return NULL;
1476
1477  const ring rSrc = cf->extRing;
1478  const ring rDst = dst->extRing;
1479
1480  if( rSrc == rDst )
1481    return ntCopy(a, dst); // USUALLY WRONG!
1482
1483  fraction f = (fraction)a;
1484  poly g = prCopyR(NUM(f), rSrc, rDst);
1485
1486  poly h = NULL;
1487
1488  if (!DENIS1(f))
1489     h = prCopyR(DEN(f), rSrc, rDst);
1490
1491  fraction result = (fraction)omAlloc0Bin(fractionObjectBin);
1492
1493  NUM(result) = g;
1494  DEN(result) = h;
1495  COM(result) = COM(f);
1496  assume(n_Test((number)result, dst));
1497  return (number)result;
1498}
1499
1500number ntCopyAlg(number a, const coeffs cf, const coeffs dst)
1501{
1502  assume( n_Test(a, cf) );
1503  if (n_IsZero(a, cf)) return NULL;
1504
1505  fraction f = (fraction)omAlloc0Bin(fractionObjectBin);
1506  // DEN(f) = NULL; COM(f) = 0;
1507  NUM(f) = prCopyR((poly)a, cf->extRing, dst->extRing);
1508  assume(n_Test((number)f, dst));
1509  return (number)f;
1510}
1511
1512/* assumes that src = Q, dst = Z/p(t_1, ..., t_s) */
1513number ntMap0P(number a, const coeffs src, const coeffs dst)
1514{
1515  assume( n_Test(a, src) );
1516  if (n_IsZero(a, src)) return NULL;
1517  int p = rChar(dst->extRing);
1518  number q = nlModP(a, src, dst->extRing->cf);
1519
1520  if (n_IsZero(q, dst->extRing->cf))
1521  {
1522    n_Delete(&q, dst->extRing->cf);
1523    return NULL;
1524  }
1525
1526  poly g = p_NSet(q, dst->extRing);
1527
1528  fraction f = (fraction)omAlloc0Bin(fractionObjectBin);
1529  NUM(f) = g; // DEN(f) = NULL; COM(f) = 0;
1530  assume(n_Test((number)f, dst));
1531  return (number)f;
1532}
1533
1534/* assumes that src = Z/p, dst = Z/p(t_1, ..., t_s) */
1535number ntMapPP(number a, const coeffs src, const coeffs dst)
1536{
1537  assume( n_Test(a, src) );
1538  if (n_IsZero(a, src)) return NULL;
1539  assume(src == dst->extRing->cf);
1540  poly p = p_One(dst->extRing);
1541  p_SetCoeff(p, n_Copy(a, src), dst->extRing);
1542  fraction f = (fraction)omAlloc0Bin(fractionObjectBin);
1543  NUM(f) = p; DEN(f) = NULL; COM(f) = 0;
1544  assume(n_Test((number)f, dst));
1545  return (number)f;
1546}
1547
1548/* assumes that src = Z/u, dst = Z/p(t_1, ..., t_s), where u != p */
1549number ntMapUP(number a, const coeffs src, const coeffs dst)
1550{
1551  assume( n_Test(a, src) );
1552  if (n_IsZero(a, src)) return NULL;
1553  /* mapping via intermediate int: */
1554  int n = n_Int(a, src);
1555  number q = n_Init(n, dst->extRing->cf);
1556  poly p;
1557  if (n_IsZero(q, dst->extRing->cf))
1558  {
1559    n_Delete(&q, dst->extRing->cf);
1560    return NULL;
1561  }
1562  p = p_One(dst->extRing);
1563  p_SetCoeff(p, q, dst->extRing);
1564  fraction f = (fraction)omAlloc0Bin(fractionObjectBin);
1565  NUM(f) = p; DEN(f) = NULL; COM(f) = 0;
1566  assume(n_Test((number)f, dst));
1567  return (number)f;
1568}
1569
1570nMapFunc ntSetMap(const coeffs src, const coeffs dst)
1571{
1572  /* dst is expected to be a rational function field */
1573  assume(getCoeffType(dst) == ID);
1574
1575  if( src == dst ) return ndCopyMap;
1576
1577  int h = 0; /* the height of the extension tower given by dst */
1578  coeffs bDst = nCoeff_bottom(dst, h); /* the bottom field in the tower dst */
1579  coeffs bSrc = nCoeff_bottom(src, h); /* the bottom field in the tower src */
1580
1581  /* for the time being, we only provide maps if h = 1 and if b is Q or
1582     some field Z/pZ: */
1583  if (h==0)
1584  {
1585    if (nCoeff_is_Q(src) && nCoeff_is_Q(bDst))
1586      return ntMap00;                                 /// Q       -->  Q(T)
1587    if (nCoeff_is_Zp(src) && nCoeff_is_Q(bDst))
1588      return ntMapP0;                                 /// Z/p     -->  Q(T)
1589    if (nCoeff_is_Q(src) && nCoeff_is_Zp(bDst))
1590      return ntMap0P;                                 /// Q       --> Z/p(T)
1591    if (nCoeff_is_Zp(src) && nCoeff_is_Zp(bDst))
1592    {
1593      if (src->ch == dst->ch) return ntMapPP;         /// Z/p     --> Z/p(T)
1594      else return ntMapUP;                            /// Z/u     --> Z/p(T)
1595    }
1596  }
1597  if (h != 1) return NULL;
1598  if ((!nCoeff_is_Zp(bDst)) && (!nCoeff_is_Q(bDst))) return NULL;
1599
1600  /* Let T denote the sequence of transcendental extension variables, i.e.,
1601     K[t_1, ..., t_s] =: K[T];
1602     Let moreover, for any such sequence T, T' denote any subsequence of T
1603     of the form t_1, ..., t_w with w <= s. */
1604
1605  if ((!nCoeff_is_Zp(bSrc)) && (!nCoeff_is_Q(bSrc))) return NULL;
1606
1607  if (nCoeff_is_Q(bSrc) && nCoeff_is_Q(bDst))
1608  {
1609    if (rVar(src->extRing) > rVar(dst->extRing))
1610       return NULL;
1611
1612    for (int i = 0; i < rVar(src->extRing); i++)
1613      if (strcmp(rRingVar(i, src->extRing), rRingVar(i, dst->extRing)) != 0)
1614         return NULL;
1615
1616    if (src->type==n_transExt)
1617       return ntCopyMap;          /// Q(T')   --> Q(T)
1618    else
1619       return ntCopyAlg;
1620  }
1621
1622  if (nCoeff_is_Zp(bSrc) && nCoeff_is_Zp(bDst))
1623  {
1624    if (rVar(src->extRing) > rVar(dst->extRing))
1625       return NULL;
1626
1627    for (int i = 0; i < rVar(src->extRing); i++)
1628      if (strcmp(rRingVar(i, src->extRing), rRingVar(i, dst->extRing)) != 0)
1629         return NULL;
1630
1631    if (src->type==n_transExt)
1632       return ntCopyMap;         /// Z/p(T') --> Z/p(T)
1633    else
1634       return ntCopyAlg;
1635  }
1636
1637  return NULL;                                 /// default
1638}
1639#if 0
1640nMapFunc ntSetMap_T(const coeffs src, const coeffs dst)
1641{
1642  nMapFunc n=ntSetMap(src,dst);
1643  if (n==ntCopyAlg) printf("n=ntCopyAlg\n");
1644  else if (n==ntCopyMap) printf("n=ntCopyMap\n");
1645  else if (n==ntMapUP) printf("n=ntMapUP\n");
1646  else if (n==ntMap0P) printf("n=ntMap0P\n");
1647  else if (n==ntMapP0) printf("n=ntMapP0\n");
1648  else if (n==ntMap00) printf("n=ntMap00\n");
1649  else if (n==NULL) printf("n=NULL\n");
1650  else printf("n=?\n");
1651  return n;
1652}
1653#endif
1654
1655void ntKillChar(coeffs cf)
1656{
1657  if ((--cf->extRing->ref) == 0)
1658    rDelete(cf->extRing);
1659}
1660#ifdef HAVE_FACTORY
1661number ntConvFactoryNSingN( const CanonicalForm n, const coeffs cf)
1662{
1663  if (n.isZero()) return NULL;
1664  poly p=convFactoryPSingP(n,ntRing);
1665  fraction result = (fraction)omAlloc0Bin(fractionObjectBin);
1666  NUM(result) = p;
1667  //DEN(result) = NULL; // done by omAlloc0Bin
1668  //COM(result) = 0; // done by omAlloc0Bin
1669  ntTest((number)result);
1670  return (number)result;
1671}
1672CanonicalForm ntConvSingNFactoryN( number n, BOOLEAN setChar, const coeffs cf )
1673{
1674  ntTest(n);
1675  if (IS0(n)) return CanonicalForm(0);
1676
1677  fraction f = (fraction)n;
1678  return convSingPFactoryP(NUM(f),ntRing);
1679}
1680#endif
1681
1682static int ntParDeg(number a, const coeffs cf)
1683{
1684  ntTest(a);
1685  if (IS0(a)) return -1;
1686  fraction fa = (fraction)a;
1687  return cf->extRing->pFDeg(NUM(fa),cf->extRing);
1688}
1689
1690/// return the specified parameter as a number in the given trans.ext.
1691static number ntParameter(const int iParameter, const coeffs cf)
1692{
1693  assume(getCoeffType(cf) == ID);
1694
1695  const ring R = cf->extRing;
1696  assume( R != NULL );
1697  assume( 0 < iParameter && iParameter <= rVar(R) );
1698
1699  poly p = p_One(R); p_SetExp(p, iParameter, 1, R); p_Setm(p, R);
1700
1701//  return (number) p;
1702
1703  fraction f = (fraction)omAlloc0Bin(fractionObjectBin);
1704  NUM(f) = p;
1705  DEN(f) = NULL;
1706  COM(f) = 0;
1707
1708  ntTest((number)f);
1709
1710  return (number)f;
1711}
1712
1713/// if m == var(i)/1 => return i,
1714int ntIsParam(number m, const coeffs cf)
1715{
1716  ntTest(m);
1717  assume(getCoeffType(cf) == ID);
1718
1719  const ring R = cf->extRing;
1720  assume( R != NULL );
1721
1722  fraction f = (fraction)m;
1723
1724  if( DEN(f) != NULL )
1725    return 0;
1726
1727  return p_Var( NUM(f), R );
1728}
1729
1730struct NTNumConverter
1731{
1732  static inline poly convert(const number& n)
1733  {
1734    // suitable for trans. ext. numbers that are fractions of polys
1735    return NUM((fraction)n); // return the numerator
1736  }
1737};
1738
1739
1740static void ntClearContent(ICoeffsEnumerator& numberCollectionEnumerator, number& c, const coeffs cf)
1741{
1742  assume(cf != NULL);
1743  assume(getCoeffType(cf) == ID);
1744  // all coeffs are given by fractions of polynomails over integers!!!
1745  // without denominators!!!
1746
1747  const ring   R = cf->extRing;
1748  assume(R != NULL);
1749  const coeffs Q = R->cf;
1750  assume(Q != NULL);
1751  assume(nCoeff_is_Q(Q));
1752
1753
1754  numberCollectionEnumerator.Reset();
1755
1756  if( !numberCollectionEnumerator.MoveNext() ) // empty zero polynomial?
1757  {
1758    c = ntInit(1, cf);
1759    return;
1760  }
1761
1762  // all coeffs are given by integers after returning from this routine
1763
1764  // part 1, collect product of all denominators /gcds
1765  poly cand = NULL;
1766
1767  do
1768  {
1769    number &n = numberCollectionEnumerator.Current();
1770
1771    ntNormalize(n, cf);
1772
1773    fraction f = (fraction)n;
1774
1775    assume( f != NULL );
1776
1777    const poly den = DEN(f);
1778
1779    assume( den == NULL ); // ?? / 1 ?
1780
1781    const poly num = NUM(f);
1782
1783    if( cand == NULL )
1784      cand = p_Copy(num, R);
1785    else
1786      cand = singclap_gcd(cand, p_Copy(num, R), R); // gcd(cand, num)
1787
1788    if( p_IsConstant(cand, R) )
1789      break;
1790  }
1791  while( numberCollectionEnumerator.MoveNext() ) ;
1792
1793
1794  // part2: all coeffs = all coeffs * cand
1795  if( cand != NULL )
1796  {
1797  if( !p_IsConstant(cand, R) )
1798  {
1799    c = ntInit(cand, cf);
1800    numberCollectionEnumerator.Reset();
1801    while (numberCollectionEnumerator.MoveNext() )
1802    {
1803      number &n = numberCollectionEnumerator.Current();
1804      const number t = ntDiv(n, c, cf); // TODO: rewrite!?
1805      ntDelete(&n, cf);
1806      n = t;
1807    }
1808  } // else NUM (result) = p_One(R);
1809  else { p_Delete(&cand, R); cand = NULL; }
1810  }
1811
1812  // Quick and dirty fix for constant content clearing: consider numerators???
1813  CRecursivePolyCoeffsEnumerator<NTNumConverter> itr(numberCollectionEnumerator); // recursively treat the NUM(numbers) as polys!
1814  number cc;
1815
1816  n_ClearContent(itr, cc, Q);
1817  number g = ntInit(p_NSet(cc, R), cf);
1818
1819  if( cand != NULL )
1820  {
1821    number gg = ntMult(g, c, cf);
1822    ntDelete(&g, cf);
1823    ntDelete(&c, cf); c = gg;
1824  } else
1825    c = g;
1826  ntTest(c);
1827}
1828
1829static void ntClearDenominators(ICoeffsEnumerator& numberCollectionEnumerator, number& c, const coeffs cf)
1830{
1831  assume(cf != NULL);
1832  assume(getCoeffType(cf) == ID); // both over Q(a) and Zp(a)!
1833  // all coeffs are given by fractions of polynomails over integers!!!
1834
1835  numberCollectionEnumerator.Reset();
1836
1837  if( !numberCollectionEnumerator.MoveNext() ) // empty zero polynomial?
1838  {
1839    c = ntInit(1, cf);
1840    return;
1841  }
1842
1843  // all coeffs are given by integers after returning from this routine
1844
1845  // part 1, collect product of all denominators /gcds
1846  poly cand = NULL;
1847
1848  const ring R = cf->extRing;
1849  assume(R != NULL);
1850
1851  const coeffs Q = R->cf;
1852  assume(Q != NULL);
1853//  assume(nCoeff_is_Q(Q));
1854
1855  do
1856  {
1857    number &n = numberCollectionEnumerator.Current();
1858
1859    ntNormalize(n, cf);
1860
1861    fraction f = (fraction)ntGetDenom (n, cf);
1862
1863    assume( f != NULL );
1864
1865    const poly den = NUM(f);
1866
1867    if( den == NULL ) // ?? / 1 ?
1868      continue;
1869
1870    if( cand == NULL )
1871      cand = p_Copy(den, R);
1872    else
1873    {
1874      // cand === LCM( cand, den )!!!!
1875      // NOTE: maybe it's better to make the product and clearcontent afterwards!?
1876      // TODO: move the following to factory?
1877      poly gcd = singclap_gcd(p_Copy(cand, R), p_Copy(den, R), R); // gcd(cand, den) is monic no mater leading coeffs! :((((
1878      if (nCoeff_is_Q (Q))
1879      {
1880        number LcGcd= n_Gcd (p_GetCoeff (cand, R), p_GetCoeff(den, R), Q);
1881        gcd = p_Mult_nn(gcd, LcGcd, R);
1882        n_Delete(&LcGcd,Q);
1883      }
1884//      assume( n_IsOne(pGetCoeff(gcd), Q) ); // TODO: this may be wrong...
1885      cand = p_Mult_q(cand, p_Copy(den, R), R); // cand *= den
1886      const poly t = singclap_pdivide( cand, gcd, R ); // cand' * den / gcd(cand', den)
1887      p_Delete(&cand, R);
1888      p_Delete(&gcd, R);
1889      cand = t;
1890    }
1891  }
1892  while( numberCollectionEnumerator.MoveNext() );
1893
1894  if( cand == NULL )
1895  {
1896    c = ntInit(1, cf);
1897    return;
1898  }
1899
1900  c = ntInit(cand, cf);
1901
1902  numberCollectionEnumerator.Reset();
1903
1904  number d = NULL;
1905
1906  while (numberCollectionEnumerator.MoveNext() )
1907  {
1908    number &n = numberCollectionEnumerator.Current();
1909    number t = ntMult(n, c, cf); // TODO: rewrite!?
1910    ntDelete(&n, cf);
1911
1912    ntNormalize(t, cf); // TODO: needed?
1913    n = t;
1914
1915    fraction f = (fraction)t;
1916    assume( f != NULL );
1917
1918    const poly den = DEN(f);
1919
1920    if( den != NULL ) // ?? / ?? ?
1921    {
1922      assume( p_IsConstant(den, R) );
1923      assume( pNext(den) == NULL );
1924
1925      if( d == NULL )
1926        d = n_Copy(pGetCoeff(den), Q);
1927      else
1928      {
1929        number g = n_Lcm(d, pGetCoeff(den), Q);
1930        n_Delete(&d, Q); d = g;
1931      }
1932    }
1933  }
1934
1935  if( d != NULL )
1936  {
1937    numberCollectionEnumerator.Reset();
1938    while (numberCollectionEnumerator.MoveNext() )
1939    {
1940      number &n = numberCollectionEnumerator.Current();
1941      fraction f = (fraction)n;
1942
1943      assume( f != NULL );
1944
1945      const poly den = DEN(f);
1946
1947      if( den == NULL ) // ?? / 1 ?
1948        NUM(f) = p_Mult_nn(NUM(f), d, R);
1949      else
1950      {
1951        assume( p_IsConstant(den, R) );
1952        assume( pNext(den) == NULL );
1953
1954        number ddd = n_Div(d, pGetCoeff(den), Q); // but be an integer now!!!
1955        NUM(f) = p_Mult_nn(NUM(f), ddd, R);
1956        n_Delete(&ddd, Q);
1957
1958        p_Delete(&DEN(f), R);
1959        DEN(f) = NULL; // TODO: check if this is needed!?
1960      }
1961
1962      assume( DEN(f) == NULL );
1963    }
1964
1965    NUM(c) = p_Mult_nn(NUM(c), d, R);
1966    n_Delete(&d, Q);
1967  }
1968
1969
1970  ntTest(c);
1971}
1972
1973BOOLEAN ntInitChar(coeffs cf, void * infoStruct)
1974{
1975
1976  assume( infoStruct != NULL );
1977
1978  TransExtInfo *e = (TransExtInfo *)infoStruct;
1979
1980  assume( e->r                != NULL);      // extRing;
1981  assume( e->r->cf            != NULL);      // extRing->cf;
1982  assume( e->r->qideal == NULL );
1983
1984  assume( cf != NULL );
1985  assume(getCoeffType(cf) == ID);                // coeff type;
1986
1987  ring R = e->r;
1988  assume(R != NULL);
1989
1990  R->ref ++; // increase the ref.counter for the ground poly. ring!
1991
1992  cf->extRing           = R;
1993  /* propagate characteristic up so that it becomes
1994     directly accessible in cf: */
1995  cf->ch = R->cf->ch;
1996  cf->factoryVarOffset = R->cf->factoryVarOffset + rVar(R);
1997
1998  cf->cfGreaterZero  = ntGreaterZero;
1999  cf->cfGreater      = ntGreater;
2000  cf->cfEqual        = ntEqual;
2001  cf->cfIsZero       = ntIsZero;
2002  cf->cfIsOne        = ntIsOne;
2003  cf->cfIsMOne       = ntIsMOne;
2004  cf->cfInit         = ntInit;
2005  cf->cfInit_bigint  = ntInit_bigint;
2006  cf->cfInt          = ntInt;
2007  cf->cfNeg          = ntNeg;
2008  cf->cfAdd          = ntAdd;
2009  cf->cfSub          = ntSub;
2010  cf->cfMult         = ntMult;
2011  cf->cfDiv          = ntDiv;
2012  cf->cfExactDiv     = ntDiv;
2013  cf->cfPower        = ntPower;
2014  cf->cfCopy         = ntCopy;
2015  cf->cfWriteLong    = ntWriteLong;
2016  cf->cfRead         = ntRead;
2017  cf->cfNormalize    = ntNormalize;
2018  cf->cfDelete       = ntDelete;
2019  cf->cfSetMap       = ntSetMap;
2020  cf->cfGetDenom     = ntGetDenom;
2021  cf->cfGetNumerator = ntGetNumerator;
2022  cf->cfRePart       = ntCopy;
2023  cf->cfImPart       = ntImPart;
2024  cf->cfCoeffWrite   = ntCoeffWrite;
2025#ifdef LDEBUG
2026  cf->cfDBTest       = ntDBTest;
2027#endif
2028  cf->cfGcd          = ntGcd;
2029  cf->cfLcm          = ntLcm;
2030  cf->cfSize         = ntSize;
2031  cf->nCoeffIsEqual  = ntCoeffIsEqual;
2032  cf->cfInvers       = ntInvers;
2033  cf->cfIntDiv       = ntDiv;
2034  cf->cfKillChar     = ntKillChar;
2035
2036  if( rCanShortOut(ntRing) )
2037    cf->cfWriteShort = ntWriteShort;
2038  else
2039    cf->cfWriteShort = ntWriteLong;
2040
2041#ifndef HAVE_FACTORY
2042  PrintS("// Warning: The 'factory' module is not available.\n");
2043  PrintS("//          Hence gcd's cannot be cancelled in any\n");
2044  PrintS("//          computed fraction!\n");
2045#else
2046  cf->convFactoryNSingN =ntConvFactoryNSingN;
2047  cf->convSingNFactoryN =ntConvSingNFactoryN;
2048#endif
2049  cf->cfParDeg = ntParDeg;
2050
2051  cf->iNumberOfParameters = rVar(R);
2052  cf->pParameterNames = R->names;
2053  cf->cfParameter = ntParameter;
2054
2055  if( nCoeff_is_Q(R->cf) )
2056    cf->cfClearContent = ntClearContent;
2057
2058  cf->cfClearDenominators = ntClearDenominators;
2059
2060  return FALSE;
2061}
Note: See TracBrowser for help on using the repository browser.