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

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