source: git/libpolys/polys/ext_fields/transext.cc @ 314f0a2

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