source: git/libpolys/polys/ext_fields/transext.cc @ 03f7b5

fieker-DuValspielwiese
Last change on this file since 03f7b5 was 03f7b5, checked in by Oleksandr Motsak <motsak@…>, 13 years ago
ADD: detailed printing vs typing for coeff. domains (mostly - minpoly related)
  • Property mode set to 100644
File size: 39.2 KB
Line 
1/****************************************
2*  Computer Algebra System SINGULAR     *
3****************************************/
4/* $Id$ */
5/*
6* ABSTRACT: numbers in a rational function field K(t_1, .., t_s) with
7*           transcendental variables t_1, ..., t_s, where s >= 1.
8*           Denoting the implemented coeffs object by cf, then these numbers
9*           are represented as quotients of polynomials living in the
10*           polynomial ring K[t_1, .., t_s] represented by cf->extring.
11*
12*           An element of K(t_1, .., t_s) may have numerous representations,
13*           due to the possibility of common polynomial factors in the
14*           numerator and denominator. This problem is handled by a
15*           cancellation heuristic: Each number "knows" its complexity
16*           which is 0 if and only if common factors have definitely been
17*           cancelled, and some positive integer otherwise.
18*           Each arithmetic operation of two numbers with complexities c1
19*           and c2 will result in a number of complexity c1 + c2 + some
20*           penalty (specific for each arithmetic operation; see constants
21*           in the *.h file). Whenever the resulting complexity exceeds a
22*           certain threshold (see constant in the *.h file), then the
23*           cancellation heuristic will call 'factory' to compute the gcd
24*           and cancel it out in the given number. (This definite cancel-
25*           lation will also be performed at the beginning of ntWrite,
26*           ensuring that any output is free of common factors.
27*           For the special case of K = Q (i.e., when computing over the
28*           rationals), this definite cancellation procedure will also take
29*           care of nested fractions: If there are fractional coefficients
30*           in the numerator or denominator of a number, then this number
31*           is being replaced by a quotient of two polynomials over Z, or
32*           - if the denominator is a constant - by a polynomial over Q.
33*/
34#define TRANSEXT_PRIVATES
35
36#include "config.h"
37#include <misc/auxiliary.h>
38
39#include <omalloc/omalloc.h>
40
41#include <reporter/reporter.h>
42
43#include <coeffs/coeffs.h>
44#include <coeffs/numbers.h>
45#include <coeffs/longrat.h>
46
47#include <polys/monomials/ring.h>
48#include <polys/monomials/p_polys.h>
49#include <polys/simpleideals.h>
50
51#ifdef HAVE_FACTORY
52#include <polys/clapsing.h>
53#endif
54
55#include "ext_fields/transext.h"
56#include "prCopy.h"
57
58/* constants for controlling the complexity of numbers */
59#define ADD_COMPLEXITY 1   /**< complexity increase due to + and - */
60#define MULT_COMPLEXITY 2   /**< complexity increase due to * and / */
61#define BOUND_COMPLEXITY 10   /**< maximum complexity of a number */
62
63#define NUMIS1(f) (p_IsConstant(NUM(f), cf->extRing) && \
64                   n_IsOne(p_GetCoeff(NUM(f), cf->extRing), \
65                           cf->extRing->cf))
66                   /**< TRUE iff num. represents 1 */
67#define COM(f) f->complexity
68
69
70#ifdef LDEBUG
71#define ntTest(a) ntDBTest(a,__FILE__,__LINE__,cf)
72BOOLEAN  ntDBTest(number a, const char *f, const int l, const coeffs r);
73#else
74#define ntTest(a) (TRUE)
75#endif
76
77/// Our own type!
78static const n_coeffType ID = n_transExt;
79
80/* polynomial ring in which the numerators and denominators of our
81   numbers live */
82#define ntRing cf->extRing
83
84/* coeffs object in which the coefficients of our numbers live;
85 * methods attached to ntCoeffs may be used to compute with the
86 * coefficients of our numbers, e.g., use ntCoeffs->nAdd to add
87 * coefficients of our numbers */
88#define ntCoeffs cf->extRing->cf
89
90
91
92extern omBin fractionObjectBin = omGetSpecBin(sizeof(fractionObject));
93
94/// forward declarations
95BOOLEAN  ntGreaterZero(number a, const coeffs cf);
96BOOLEAN  ntGreater(number a, number b, const coeffs cf);
97BOOLEAN  ntEqual(number a, number b, const coeffs cf);
98BOOLEAN  ntIsOne(number a, const coeffs cf);
99BOOLEAN  ntIsMOne(number a, const coeffs cf);
100BOOLEAN  ntIsZero(number a, const coeffs cf);
101number   ntInit(int i, const coeffs cf);
102int      ntInt(number &a, const coeffs cf);
103number   ntNeg(number a, const coeffs cf);
104number   ntInvers(number a, const coeffs cf);
105number   ntAdd(number a, number b, const coeffs cf);
106number   ntSub(number a, number b, const coeffs cf);
107number   ntMult(number a, number b, const coeffs cf);
108number   ntDiv(number a, number b, const coeffs cf);
109void     ntPower(number a, int exp, number *b, const coeffs cf);
110number   ntCopy(number a, const coeffs cf);
111void     ntWrite(number &a, const coeffs cf);
112number   ntRePart(number a, const coeffs cf);
113number   ntImPart(number a, const coeffs cf);
114number   ntGetDenom(number &a, const coeffs cf);
115number   ntGetNumerator(number &a, const coeffs cf);
116number   ntGcd(number a, number b, const coeffs cf);
117number   ntLcm(number a, number b, const coeffs cf);
118int      ntSize(number a, const coeffs cf);
119void     ntDelete(number * a, const coeffs cf);
120void     ntCoeffWrite(const coeffs cf, BOOLEAN details);
121number   ntIntDiv(number a, number b, const coeffs cf);
122const char * ntRead(const char *s, number *a, const coeffs cf);
123static BOOLEAN ntCoeffIsEqual(const coeffs cf, n_coeffType n, void * param);
124
125void heuristicGcdCancellation(number a, const coeffs cf);
126void definiteGcdCancellation(number a, const coeffs cf,
127                             BOOLEAN simpleTestsHaveAlreadyBeenPerformed);
128void handleNestedFractionsOverQ(fraction f, const coeffs cf);
129
130#ifdef LDEBUG
131BOOLEAN ntDBTest(number a, const char *f, const int l, const coeffs cf)
132{
133  assume(getCoeffType(cf) == ID);
134  fraction t = (fraction)a;
135  if (IS0(t)) return TRUE;
136  assume(NUM(t) != NULL);   /**< t != 0 ==> numerator(t) != 0 */
137  p_Test(NUM(t), ntRing);
138  if (!DENIS1(t)) p_Test(DEN(t), ntRing);
139  return TRUE;
140}
141#endif
142
143/* returns the bottom field in this field extension tower; if the tower
144   is flat, i.e., if there is no extension, then r itself is returned;
145   as a side-effect, the counter 'height' is filled with the height of
146   the extension tower (in case the tower is flat, 'height' is zero) */
147static coeffs nCoeff_bottom(const coeffs r, int &height)
148{
149  assume(r != NULL);
150  coeffs cf = r;
151  height = 0;
152  while (nCoeff_is_Extension(cf))
153  {
154    assume(cf->extRing != NULL); assume(cf->extRing->cf != NULL);
155    cf = cf->extRing->cf;
156    height++;
157  }
158  return cf;
159}
160
161BOOLEAN ntIsZero(number a, const coeffs cf)
162{
163  ntTest(a);
164  return (IS0(a));
165}
166
167void ntDelete(number * a, const coeffs cf)
168{
169  fraction f = (fraction)(*a);
170  if (IS0(f)) return;
171  p_Delete(&NUM(f), ntRing);
172  if (!DENIS1(f)) p_Delete(&DEN(f), ntRing);
173  omFreeBin((ADDRESS)f, fractionObjectBin);
174  *a = NULL;
175}
176
177BOOLEAN ntEqual(number a, number b, const coeffs cf)
178{
179  ntTest(a); ntTest(b);
180
181  /// simple tests
182  if (a == b) return TRUE;
183  if ((IS0(a)) && (!IS0(b))) return FALSE;
184  if ((IS0(b)) && (!IS0(a))) return FALSE;
185
186  /// cheap test if gcd's have been cancelled in both numbers
187  fraction fa = (fraction)a;
188  fraction fb = (fraction)b;
189  if ((COM(fa) == 1) && (COM(fb) == 1))
190  {
191    poly f = p_Add_q(p_Copy(NUM(fa), ntRing),
192                     p_Neg(p_Copy(NUM(fb), ntRing), ntRing),
193                     ntRing);
194    if (f != NULL) { p_Delete(&f, ntRing); return FALSE; }
195    if (DENIS1(fa) && DENIS1(fb))  return TRUE;
196    if (DENIS1(fa) && !DENIS1(fb)) return FALSE;
197    if (!DENIS1(fa) && DENIS1(fb)) return FALSE;
198    f = p_Add_q(p_Copy(DEN(fa), ntRing),
199                p_Neg(p_Copy(DEN(fb), ntRing), ntRing),
200                ntRing);
201    if (f != NULL) { p_Delete(&f, ntRing); return FALSE; }
202    return TRUE;
203  }
204
205  /* default: the more expensive multiplication test
206              a/b = c/d  <==>  a*d = b*c */
207  poly f = p_Copy(NUM(fa), ntRing);
208  if (!DENIS1(fb)) f = p_Mult_q(f, p_Copy(DEN(fb), ntRing), ntRing);
209  poly g = p_Copy(NUM(fb), ntRing);
210  if (!DENIS1(fa)) g = p_Mult_q(g, p_Copy(DEN(fa), ntRing), ntRing);
211  poly h = p_Add_q(f, p_Neg(g, ntRing), ntRing);
212  if (h == NULL) return TRUE;
213  else
214  {
215    p_Delete(&h, ntRing);
216    return FALSE;
217  }
218}
219
220number ntCopy(number a, const coeffs cf)
221{
222  ntTest(a);
223  if (IS0(a)) return NULL;
224  fraction f = (fraction)a;
225  poly g = p_Copy(NUM(f), ntRing);
226  poly h = NULL; if (!DENIS1(f)) h = p_Copy(DEN(f), ntRing);
227  fraction result = (fraction)omAlloc0Bin(fractionObjectBin);
228  NUM(result) = g;
229  DEN(result) = h;
230  COM(result) = COM(f);
231  return (number)result;
232}
233
234number ntGetNumerator(number &a, const coeffs cf)
235{
236  ntTest(a);
237  definiteGcdCancellation(a, cf, FALSE);
238  if (IS0(a)) return NULL;
239  fraction f = (fraction)a;
240  poly g = p_Copy(NUM(f), ntRing);
241  fraction result = (fraction)omAlloc0Bin(fractionObjectBin);
242  NUM(result) = g;
243  DEN(result) = NULL;
244  COM(result) = 0;
245  return (number)result;
246}
247
248number ntGetDenom(number &a, const coeffs cf)
249{
250  ntTest(a);
251  definiteGcdCancellation(a, cf, FALSE);
252  fraction f = (fraction)a;
253  poly g;
254  if (IS0(f) || DENIS1(f)) g = p_One(ntRing);
255  else g = p_Copy(DEN(f), ntRing);
256  fraction result = (fraction)omAlloc0Bin(fractionObjectBin);
257  NUM(result) = g;
258  DEN(result) = NULL;
259  COM(result) = 0;
260  return (number)result;
261}
262
263BOOLEAN ntIsOne(number a, const coeffs cf)
264{
265  ntTest(a);
266  definiteGcdCancellation(a, cf, FALSE);
267  fraction f = (fraction)a;
268  return (f!=NULL) && DENIS1(f) && NUMIS1(f);
269}
270
271BOOLEAN ntIsMOne(number a, const coeffs cf)
272{
273  ntTest(a);
274  definiteGcdCancellation(a, cf, FALSE);
275  fraction f = (fraction)a;
276  if ((f==NULL) || (!DENIS1(f))) return FALSE;
277  poly g = NUM(f);
278  if (!p_IsConstant(g, ntRing)) return FALSE;
279  return n_IsMOne(p_GetCoeff(g, ntRing), ntCoeffs);
280}
281
282/// this is in-place, modifies a
283number ntNeg(number a, const coeffs cf)
284{
285  ntTest(a);
286  if (!IS0(a))
287  {
288    fraction f = (fraction)a;
289    NUM(f) = p_Neg(NUM(f), ntRing);
290  }
291  return a;
292}
293
294number ntImPart(number a, const coeffs cf)
295{
296  ntTest(a);
297  return NULL;
298}
299
300number ntInit(int i, const coeffs cf)
301{
302  if (i == 0) return NULL;
303  else
304  {
305    fraction result = (fraction)omAlloc0Bin(fractionObjectBin);
306    NUM(result) = p_ISet(i, ntRing);
307    DEN(result) = NULL;
308    COM(result) = 0;
309    return (number)result;
310  }
311}
312
313number ntInit(poly p, const coeffs cf)
314{
315  if (p == 0) return NULL;
316  else
317  {
318    fraction result = (fraction)omAlloc0Bin(fractionObjectBin);
319    NUM(result) = p;
320    DEN(result) = NULL;
321    COM(result) = 0;
322    return (number)result;
323  }
324}
325
326int ntInt(number &a, const coeffs cf)
327{
328  ntTest(a);
329  if (IS0(a)) return 0;
330  definiteGcdCancellation(a, cf, FALSE);
331  fraction f = (fraction)a;
332  if (!DENIS1(f)) return 0;
333  if (!p_IsConstant(NUM(f), ntRing)) return 0;
334  return n_Int(p_GetCoeff(NUM(f), ntRing), ntCoeffs);
335}
336
337/* This method will only consider the numerators of a and b, without
338   cancelling gcd's before.
339   Moreover it may return TRUE only if one or both numerators
340   are zero or if their degrees are equal. Then TRUE is returned iff
341   coeff(numerator(a)) > coeff(numerator(b));
342   In all other cases, FALSE will be returned. */
343BOOLEAN ntGreater(number a, number b, const coeffs cf)
344{
345  ntTest(a); ntTest(b);
346  number aNumCoeff = NULL; int aNumDeg = 0;
347  number bNumCoeff = NULL; int bNumDeg = 0;
348  if (!IS0(a))
349  {
350    fraction fa = (fraction)a;
351    aNumDeg = p_Totaldegree(NUM(fa), ntRing);
352    aNumCoeff = p_GetCoeff(NUM(fa), ntRing);
353  }
354  if (!IS0(b))
355  {
356    fraction fb = (fraction)b;
357    bNumDeg = p_Totaldegree(NUM(fb), ntRing);
358    bNumCoeff = p_GetCoeff(NUM(fb), ntRing);
359  }
360  if (aNumDeg != bNumDeg) return FALSE;
361  else return n_Greater(aNumCoeff, bNumCoeff, ntCoeffs);
362}
363
364/* this method will only consider the numerator of a, without cancelling
365   the gcd before;
366   returns TRUE iff the leading coefficient of the numerator of a is > 0
367                    or the leading term of the numerator of a is not a
368                    constant */
369BOOLEAN ntGreaterZero(number a, const coeffs cf)
370{
371  ntTest(a);
372  if (IS0(a)) return FALSE;
373  fraction f = (fraction)a;
374  poly g = NUM(f);
375  return (n_GreaterZero(p_GetCoeff(g, ntRing), ntCoeffs) ||
376          (!p_LmIsConstant(g, ntRing)));
377}
378
379void ntCoeffWrite(const coeffs cf, BOOLEAN details)
380{
381  assume( cf != NULL );
382
383  const ring A = cf->extRing;
384
385  assume( A != NULL );
386  assume( A->cf != NULL );
387
388  n_CoeffWrite(A->cf, details);
389
390//  rWrite(A);
391
392  const int P = rVar(A);
393  assume( P > 0 );
394
395  Print("//   %d parameter    : ", P);
396
397  for (int nop=0; nop < P; nop ++)
398    Print("%s ", rRingVar(nop, A));
399
400  assume( A->minideal == NULL );
401
402  PrintS("\n//   minpoly        : 0\n");
403
404/*
405  PrintS("//   Coefficients live in the rational function field\n");
406  Print("//   K(");
407  for (int i = 0; i < rVar(ntRing); i++)
408  {
409    if (i > 0) PrintS(" ");
410    Print("%s", rRingVar(i, ntRing));
411  }
412  PrintS(") with\n");
413  PrintS("//   K: "); n_CoeffWrite(cf->extRing->cf);
414*/
415}
416
417number ntAdd(number a, number b, const coeffs cf)
418{
419  ntTest(a); ntTest(b);
420  if (IS0(a)) return ntCopy(b, cf);
421  if (IS0(b)) return ntCopy(a, cf);
422
423  fraction fa = (fraction)a;
424  fraction fb = (fraction)b;
425
426  poly g = p_Copy(NUM(fa), ntRing);
427  if (!DENIS1(fb)) g = p_Mult_q(g, p_Copy(DEN(fb), ntRing), ntRing);
428  poly h = p_Copy(NUM(fb), ntRing);
429  if (!DENIS1(fa)) h = p_Mult_q(h, p_Copy(DEN(fa), ntRing), ntRing);
430  g = p_Add_q(g, h, ntRing);
431
432  if (g == NULL) return NULL;
433
434  poly f;
435  if      (DENIS1(fa) && DENIS1(fb))  f = NULL;
436  else if (!DENIS1(fa) && DENIS1(fb)) f = p_Copy(DEN(fa), ntRing);
437  else if (DENIS1(fa) && !DENIS1(fb)) f = p_Copy(DEN(fb), ntRing);
438  else /* both denom's are != 1 */    f = p_Mult_q(p_Copy(DEN(fa), ntRing),
439                                                   p_Copy(DEN(fb), ntRing),
440                                                   ntRing);
441
442  fraction result = (fraction)omAlloc0Bin(fractionObjectBin);
443  NUM(result) = g;
444  DEN(result) = f;
445  COM(result) = COM(fa) + COM(fb) + ADD_COMPLEXITY;
446  heuristicGcdCancellation((number)result, cf);
447  return (number)result;
448}
449
450number ntSub(number a, number b, const coeffs cf)
451{
452  ntTest(a); ntTest(b);
453  if (IS0(a)) return ntNeg(ntCopy(b, cf), cf);
454  if (IS0(b)) return ntCopy(a, cf);
455
456  fraction fa = (fraction)a;
457  fraction fb = (fraction)b;
458
459  poly g = p_Copy(NUM(fa), ntRing);
460  if (!DENIS1(fb)) g = p_Mult_q(g, p_Copy(DEN(fb), ntRing), ntRing);
461  poly h = p_Copy(NUM(fb), ntRing);
462  if (!DENIS1(fa)) h = p_Mult_q(h, p_Copy(DEN(fa), ntRing), ntRing);
463  g = p_Add_q(g, p_Neg(h, ntRing), ntRing);
464
465  if (g == NULL) return NULL;
466
467  poly f;
468  if      (DENIS1(fa) && DENIS1(fb))  f = NULL;
469  else if (!DENIS1(fa) && DENIS1(fb)) f = p_Copy(DEN(fa), ntRing);
470  else if (DENIS1(fa) && !DENIS1(fb)) f = p_Copy(DEN(fb), ntRing);
471  else /* both den's are != 1 */      f = p_Mult_q(p_Copy(DEN(fa), ntRing),
472                                                   p_Copy(DEN(fb), ntRing),
473                                                   ntRing);
474
475  fraction result = (fraction)omAlloc0Bin(fractionObjectBin);
476  NUM(result) = g;
477  DEN(result) = f;
478  COM(result) = COM(fa) + COM(fb) + ADD_COMPLEXITY;
479  heuristicGcdCancellation((number)result, cf);
480  return (number)result;
481}
482
483number ntMult(number a, number b, const coeffs cf)
484{
485  ntTest(a); ntTest(b);
486  if (IS0(a) || IS0(b)) return NULL;
487
488  fraction fa = (fraction)a;
489  fraction fb = (fraction)b;
490
491  poly g = p_Copy(NUM(fa), ntRing);
492  poly h = p_Copy(NUM(fb), ntRing);
493  g = p_Mult_q(g, h, ntRing);
494
495  if (g == NULL) return NULL;   /* may happen due to zero divisors */
496
497  poly f;
498  if      (DENIS1(fa) && DENIS1(fb))  f = NULL;
499  else if (!DENIS1(fa) && DENIS1(fb)) f = p_Copy(DEN(fa), ntRing);
500  else if (DENIS1(fa) && !DENIS1(fb)) f = p_Copy(DEN(fb), ntRing);
501  else /* both den's are != 1 */      f = p_Mult_q(p_Copy(DEN(fa), ntRing),
502                                                   p_Copy(DEN(fb), ntRing),
503                                                   ntRing);
504
505  fraction result = (fraction)omAlloc0Bin(fractionObjectBin);
506  NUM(result) = g;
507  DEN(result) = f;
508  COM(result) = COM(fa) + COM(fb) + MULT_COMPLEXITY;
509  heuristicGcdCancellation((number)result, cf);
510  return (number)result;
511}
512
513number ntDiv(number a, number b, const coeffs cf)
514{
515  ntTest(a); ntTest(b);
516  if (IS0(a)) return NULL;
517  if (IS0(b)) WerrorS(nDivBy0);
518
519  fraction fa = (fraction)a;
520  fraction fb = (fraction)b;
521
522  poly g = p_Copy(NUM(fa), ntRing);
523  if (!DENIS1(fb)) g = p_Mult_q(g, p_Copy(DEN(fb), ntRing), ntRing);
524
525  if (g == NULL) return NULL;   /* may happen due to zero divisors */
526
527  poly f = p_Copy(NUM(fb), ntRing);
528  if (!DENIS1(fa)) f = p_Mult_q(f, p_Copy(DEN(fa), ntRing), ntRing);
529
530  fraction result = (fraction)omAlloc0Bin(fractionObjectBin);
531  NUM(result) = g;
532  DEN(result) = f;
533  COM(result) = COM(fa) + COM(fb) + MULT_COMPLEXITY;
534  heuristicGcdCancellation((number)result, cf);
535  return (number)result;
536}
537
538/* 0^0 = 0;
539   for |exp| <= 7 compute power by a simple multiplication loop;
540   for |exp| >= 8 compute power along binary presentation of |exp|, e.g.
541      p^13 = p^1 * p^4 * p^8, where we utilise that
542      p^(2^(k+1)) = p^(2^k) * p^(2^k);
543   intermediate cancellation is controlled by the in-place method
544   heuristicGcdCancellation; see there.
545*/
546void ntPower(number a, int exp, number *b, const coeffs cf)
547{
548  ntTest(a);
549
550  /* special cases first */
551  if (IS0(a))
552  {
553    if (exp >= 0) *b = NULL;
554    else          WerrorS(nDivBy0);
555  }
556  else if (exp ==  0) { *b = ntInit(1, cf); return;}
557  else if (exp ==  1) { *b = ntCopy(a, cf); return;}
558  else if (exp == -1) { *b = ntInvers(a, cf); return;}
559
560  int expAbs = exp; if (expAbs < 0) expAbs = -expAbs;
561
562  /* now compute a^expAbs */
563  number pow; number t;
564  if (expAbs <= 7)
565  {
566    pow = ntCopy(a, cf);
567    for (int i = 2; i <= expAbs; i++)
568    {
569      t = ntMult(pow, a, cf);
570      ntDelete(&pow, cf);
571      pow = t;
572      heuristicGcdCancellation(pow, cf);
573    }
574  }
575  else
576  {
577    pow = ntInit(1, cf);
578    number factor = ntCopy(a, cf);
579    while (expAbs != 0)
580    {
581      if (expAbs & 1)
582      {
583        t = ntMult(pow, factor, cf);
584        ntDelete(&pow, cf);
585        pow = t;
586        heuristicGcdCancellation(pow, cf);
587      }
588      expAbs = expAbs / 2;
589      if (expAbs != 0)
590      {
591        t = ntMult(factor, factor, cf);
592        ntDelete(&factor, cf);
593        factor = t;
594        heuristicGcdCancellation(factor, cf);
595      }
596    }
597    ntDelete(&factor, cf);
598  }
599
600  /* invert if original exponent was negative */
601  if (exp < 0)
602  {
603    t = ntInvers(pow, cf);
604    ntDelete(&pow, cf);
605    pow = t;
606  }
607  *b = pow;
608}
609
610/* assumes that cf represents the rationals, i.e. Q, and will only
611   be called in that case;
612   assumes furthermore that f != NULL and that the denominator of f != 1;
613   generally speaking, this method removes denominators in the rational
614   coefficients of the numerator and denominator of 'a';
615   more concretely, the following normalizations will be performed,
616   where t^alpha denotes a monomial in the transcendental variables t_k
617   (1) if 'a' is of the form
618          (sum_alpha a_alpha/b_alpha * t^alpha)
619          -------------------------------------
620            (sum_beta c_beta/d_beta * t^beta)
621       with integers a_alpha, b_alpha, c_beta, d_beta, then both the
622       numerator and the denominator will be multiplied by the LCM of
623       the b_alpha's and the d_beta's (if this LCM is != 1),
624   (2) if 'a' is - e.g. after having performed step (1) - of the form
625          (sum_alpha a_alpha * t^alpha)
626          -----------------------------
627            (sum_beta c_beta * t^beta)
628       with integers a_alpha, c_beta, and with a non-constant denominator,
629       then both the numerator and the denominator will be divided by the
630       GCD of the a_alpha's and the c_beta's (if this GCD is != 1),
631   (3) if 'a' is - e.g. after having performed steps (1) and (2) - of the
632       form
633          (sum_alpha a_alpha * t^alpha)
634          -----------------------------
635                        c
636       with integers a_alpha, and c != 1, then 'a' will be replaced by
637       (sum_alpha a_alpha/c * t^alpha);
638   this procedure does not alter COM(f) (this has to be done by the
639   calling procedure);
640   modifies f */
641void handleNestedFractionsOverQ(fraction f, const coeffs cf)
642{
643  assume(nCoeff_is_Q(ntCoeffs));
644  assume(!IS0(f));
645  assume(!DENIS1(f));
646
647  if (!p_IsConstant(DEN(f), ntRing))
648  { /* step (1); see documentation of this procedure above */
649    p_Normalize(NUM(f), ntRing);
650    p_Normalize(DEN(f), ntRing);
651    number lcmOfDenominators = n_Init(1, ntCoeffs);
652    number c; number tmp;
653    poly p = NUM(f);
654    /* careful when using n_Lcm!!! It computes the lcm of the numerator
655       of the 1st argument and the denominator of the 2nd!!! */
656    while (p != NULL)
657    {
658      c = p_GetCoeff(p, ntRing);
659      tmp = n_Lcm(lcmOfDenominators, c, ntCoeffs);
660      n_Delete(&lcmOfDenominators, ntCoeffs);
661      lcmOfDenominators = tmp;
662      pIter(p);
663    }
664    p = DEN(f);
665    while (p != NULL)
666    {
667      c = p_GetCoeff(p, ntRing);
668      tmp = n_Lcm(lcmOfDenominators, c, ntCoeffs);
669      n_Delete(&lcmOfDenominators, ntCoeffs);
670      lcmOfDenominators = tmp;
671      pIter(p);
672    }
673    if (!n_IsOne(lcmOfDenominators, ntCoeffs))
674    { /* multiply NUM(f) and DEN(f) with lcmOfDenominators */
675      NUM(f) = p_Mult_nn(NUM(f), lcmOfDenominators, ntRing);
676      p_Normalize(NUM(f), ntRing);
677      DEN(f) = p_Mult_nn(DEN(f), lcmOfDenominators, ntRing);
678      p_Normalize(DEN(f), ntRing);
679    }
680    n_Delete(&lcmOfDenominators, ntCoeffs);
681    if (!p_IsConstant(DEN(f), ntRing))
682    { /* step (2); see documentation of this procedure above */
683      p = NUM(f);
684      number gcdOfCoefficients = n_Copy(p_GetCoeff(p, ntRing), ntCoeffs);
685      pIter(p);
686      while ((p != NULL) && (!n_IsOne(gcdOfCoefficients, ntCoeffs)))
687      {
688        c = p_GetCoeff(p, ntRing);
689        tmp = n_Gcd(c, gcdOfCoefficients, ntCoeffs);
690        n_Delete(&gcdOfCoefficients, ntCoeffs);
691        gcdOfCoefficients = tmp;
692        pIter(p);
693      }
694      p = DEN(f);
695      while ((p != NULL) && (!n_IsOne(gcdOfCoefficients, ntCoeffs)))
696      {
697        c = p_GetCoeff(p, ntRing);
698        tmp = n_Gcd(c, gcdOfCoefficients, ntCoeffs);
699        n_Delete(&gcdOfCoefficients, ntCoeffs);
700        gcdOfCoefficients = tmp;
701        pIter(p);
702      }
703      if (!n_IsOne(gcdOfCoefficients, ntCoeffs))
704      { /* divide NUM(f) and DEN(f) by gcdOfCoefficients */
705        number inverseOfGcdOfCoefficients = n_Invers(gcdOfCoefficients,
706                                                     ntCoeffs);
707        NUM(f) = p_Mult_nn(NUM(f), inverseOfGcdOfCoefficients, ntRing);
708        p_Normalize(NUM(f), ntRing);
709        DEN(f) = p_Mult_nn(DEN(f), inverseOfGcdOfCoefficients, ntRing);
710        p_Normalize(DEN(f), ntRing);
711        n_Delete(&inverseOfGcdOfCoefficients, ntCoeffs);
712      }
713      n_Delete(&gcdOfCoefficients, ntCoeffs);
714    }
715  }
716  if (p_IsConstant(DEN(f), ntRing) &&
717      (!n_IsOne(p_GetCoeff(DEN(f), ntRing), ntCoeffs)))
718  { /* step (3); see documentation of this procedure above */
719    number inverseOfDen = n_Invers(p_GetCoeff(DEN(f), ntRing), ntCoeffs);
720    NUM(f) = p_Mult_nn(NUM(f), inverseOfDen, ntRing);
721    n_Delete(&inverseOfDen, ntCoeffs);
722    p_Delete(&DEN(f), ntRing);
723    DEN(f) = NULL;
724  }
725
726  /* Now, due to the above computations, DEN(f) may have become the
727     1-polynomial which needs to be represented by NULL: */
728  if ((DEN(f) != NULL) &&
729      p_IsConstant(DEN(f), ntRing) &&
730      n_IsOne(p_GetCoeff(DEN(f), ntRing), ntCoeffs))
731  {
732    p_Delete(&DEN(f), ntRing); DEN(f) = NULL;
733  }
734}
735
736/* modifies a */
737void heuristicGcdCancellation(number a, const coeffs cf)
738{
739  ntTest(a);
740  if (IS0(a)) return;
741
742  fraction f = (fraction)a;
743  if (DENIS1(f) || NUMIS1(f)) { COM(f) = 0; return; }
744
745  /* check whether NUM(f) = DEN(f), and - if so - replace 'a' by 1 */
746  if (p_EqualPolys(NUM(f), DEN(f), ntRing))
747  { /* numerator and denominator are both != 1 */
748    p_Delete(&NUM(f), ntRing); NUM(f) = p_ISet(1, ntRing);
749    p_Delete(&DEN(f), ntRing); DEN(f) = NULL;
750    COM(f) = 0;
751    return;
752  }
753
754  if (COM(f) <= BOUND_COMPLEXITY) return;
755  else definiteGcdCancellation(a, cf, TRUE);
756}
757
758/* modifies a */
759void definiteGcdCancellation(number a, const coeffs cf,
760                             BOOLEAN simpleTestsHaveAlreadyBeenPerformed)
761{
762  ntTest(a);
763
764  fraction f = (fraction)a;
765
766  if (!simpleTestsHaveAlreadyBeenPerformed)
767  {
768    if (IS0(a)) return;
769    if (DENIS1(f) || NUMIS1(f)) { COM(f) = 0; return; }
770
771    /* check whether NUM(f) = DEN(f), and - if so - replace 'a' by 1 */
772    if (p_EqualPolys(NUM(f), DEN(f), ntRing))
773    { /* numerator and denominator are both != 1 */
774      p_Delete(&NUM(f), ntRing); NUM(f) = p_ISet(1, ntRing);
775      p_Delete(&DEN(f), ntRing); DEN(f) = NULL;
776      COM(f) = 0;
777      return;
778    }
779  }
780
781#ifdef HAVE_FACTORY
782  /* singclap_gcd destroys its arguments; we hence need copies: */
783  poly pNum = p_Copy(NUM(f), ntRing);
784  poly pDen = p_Copy(DEN(f), ntRing);
785
786  /* Note that, over Q, singclap_gcd will remove the denominators in all
787     rational coefficients of pNum and pDen, before starting to compute
788     the gcd. Thus, we do not need to ensure that the coefficients of
789     pNum and pDen live in Z; they may well be elements of Q\Z. */
790  poly pGcd = singclap_gcd(pNum, pDen, cf->extRing);
791  if (p_IsConstant(pGcd, ntRing) &&
792      n_IsOne(p_GetCoeff(pGcd, ntRing), ntCoeffs))
793  { /* gcd = 1; nothing to cancel;
794       Suppose the given rational function field is over Q. Although the
795       gcd is 1, we may have produced fractional coefficients in NUM(f),
796       DEN(f), or both, due to previous arithmetics. The next call will
797       remove those nested fractions, in case there are any. */
798    if (nCoeff_is_Q(ntCoeffs)) handleNestedFractionsOverQ(f, cf);
799  }
800  else
801  { /* We divide both NUM(f) and DEN(f) by the gcd which is known
802       to be != 1. */
803    poly newNum = singclap_pdivide(NUM(f), pGcd, ntRing);
804    p_Delete(&NUM(f), ntRing);
805    NUM(f) = newNum;
806    poly newDen = singclap_pdivide(DEN(f), pGcd, ntRing);
807    p_Delete(&DEN(f), ntRing);
808    DEN(f) = newDen;
809    if (p_IsConstant(DEN(f), ntRing) &&
810        n_IsOne(p_GetCoeff(DEN(f), ntRing), ntCoeffs))
811    {
812      /* DEN(f) = 1 needs to be represented by NULL! */
813      p_Delete(&DEN(f), ntRing);
814      newDen = NULL;
815    }
816    else
817    { /* Note that over Q, by cancelling the gcd, we may have produced
818         fractional coefficients in NUM(f), DEN(f), or both. The next
819         call will remove those nested fractions, in case there are
820         any. */
821      if (nCoeff_is_Q(ntCoeffs)) handleNestedFractionsOverQ(f, cf);
822    }
823  }
824  COM(f) = 0;
825  p_Delete(&pGcd, ntRing);
826#endif /* HAVE_FACTORY */
827}
828
829/* modifies a */
830void ntWrite(number &a, const coeffs cf)
831{
832  ntTest(a);
833  definiteGcdCancellation(a, cf, FALSE);
834  if (IS0(a))
835    StringAppendS("0");
836  else
837  {
838    fraction f = (fraction)a;
839    // stole logic from napWrite from kernel/longtrans.cc of legacy singular
840    BOOLEAN omitBrackets = p_IsConstant(NUM(f), ntRing);
841    if (!omitBrackets) StringAppendS("(");
842    p_String0(NUM(f), ntRing, ntRing);
843    if (!omitBrackets) StringAppendS(")");
844    if (!DENIS1(f))
845    {
846      StringAppendS("/");
847      omitBrackets = p_IsConstant(DEN(f), ntRing);
848      if (!omitBrackets) StringAppendS("(");
849      p_String0(DEN(f), ntRing, ntRing);
850      if (!omitBrackets) StringAppendS(")");
851    }
852  }
853}
854
855const char * ntRead(const char *s, number *a, const coeffs cf)
856{
857  poly p;
858  const char * result = p_Read(s, p, ntRing);
859  if (p == NULL) { *a = NULL; return result; }
860  else
861  {
862    fraction f = (fraction)omAlloc0Bin(fractionObjectBin);
863    NUM(f) = p;
864    DEN(f) = NULL;
865    COM(f) = 0;
866    *a = (number)f;
867    return result;
868  }
869}
870
871/* expects *param to be castable to TransExtInfo */
872static BOOLEAN ntCoeffIsEqual(const coeffs cf, n_coeffType n, void * param)
873{
874  if (ID != n) return FALSE;
875  TransExtInfo *e = (TransExtInfo *)param;
876  /* for rational function fields we expect the underlying
877     polynomial rings to be IDENTICAL, i.e. the SAME OBJECT;
878     this expectation is based on the assumption that we have properly
879     registered cf and perform reference counting rather than creating
880     multiple copies of the same coefficient field/domain/ring */
881  return (ntRing == e->r);
882}
883
884number ntLcm(number a, number b, const coeffs cf)
885{
886  ntTest(a); ntTest(b);
887  fraction fb = (fraction)b;
888  if ((b==NULL)||(DEN(fb)==NULL)) return ntCopy(a,cf);
889#ifdef HAVE_FACTORY
890  fraction fa = (fraction)a;
891  /* singclap_gcd destroys its arguments; we hence need copies: */
892  poly pa = p_Copy(NUM(fa), ntRing);
893  poly pb = p_Copy(DEN(fb), ntRing);
894
895  /* Note that, over Q, singclap_gcd will remove the denominators in all
896     rational coefficients of pa and pb, before starting to compute
897     the gcd. Thus, we do not need to ensure that the coefficients of
898     pa and pb live in Z; they may well be elements of Q\Z. */
899  poly pGcd = singclap_gcd(pa, pb, cf->extRing);
900  if (p_IsConstant(pGcd, ntRing) &&
901      n_IsOne(p_GetCoeff(pGcd, ntRing), ntCoeffs))
902  { /* gcd = 1; return pa*pb*/
903    p_Delete(&pGcd,ntRing);
904    fraction result = (fraction)omAlloc0Bin(fractionObjectBin);
905    NUM(result) = pp_Mult_qq(NUM(fa),DEN(fb),ntRing);
906    return (number)result;
907  }
908  else
909  { /* return pa*pb/gcd */
910    poly newNum = singclap_pdivide(NUM(fa), pGcd, ntRing);
911    p_Delete(&pGcd,ntRing);
912    fraction result = (fraction)omAlloc0Bin(fractionObjectBin);
913    NUM(result) = p_Mult_q(p_Copy(DEN(fb),ntRing),newNum,ntRing);
914    return (number)result;
915  }
916#else
917  Print("// factory needed: transext.cc:ntLcm\n");
918  return NULL;
919#endif /* HAVE_FACTORY */
920  return NULL;
921}
922
923number ntGcd(number a, number b, const coeffs cf)
924{
925  ntTest(a); ntTest(b);
926  if (a==NULL) return ntCopy(b,cf);
927  if (b==NULL) return ntCopy(a,cf);
928#ifdef HAVE_FACTORY
929  fraction fa = (fraction)a;
930  fraction fb = (fraction)b;
931  /* singclap_gcd destroys its arguments; we hence need copies: */
932  poly pa = p_Copy(NUM(fa), ntRing);
933  poly pb = p_Copy(NUM(fb), ntRing);
934
935  /* Note that, over Q, singclap_gcd will remove the denominators in all
936     rational coefficients of pa and pb, before starting to compute
937     the gcd. Thus, we do not need to ensure that the coefficients of
938     pa and pb live in Z; they may well be elements of Q\Z. */
939  poly pGcd = singclap_gcd(pa, pb, cf->extRing);
940  fraction result = (fraction)omAlloc0Bin(fractionObjectBin);
941  NUM(result) = pGcd;
942  return (number)result;
943#else
944  Print("// factory needed: transext.cc:ntGcd\n");
945  return NULL;
946#endif /* HAVE_FACTORY */
947}
948
949int ntSize(number a, const coeffs cf)
950{
951  ntTest(a);
952  if (IS0(a)) return -1;
953  /* this has been taken from the old implementation of field extensions,
954     where we computed the sum of the degrees and the numbers of terms in
955     the numerator and denominator of a; so we leave it at that, for the
956     time being */
957  fraction f = (fraction)a;
958  poly p = NUM(f);
959  int noOfTerms = 0;
960  int numDegree = 0;
961  while (p != NULL)
962  {
963    noOfTerms++;
964    int d = 0;
965    for (int i = 1; i <= rVar(ntRing); i++)
966      d += p_GetExp(p, i, ntRing);
967    if (d > numDegree) numDegree = d;
968    pIter(p);
969  }
970  int denDegree = 0;
971  if (!DENIS1(f))
972  {
973    p = DEN(f);
974    while (p != NULL)
975    {
976      noOfTerms++;
977      int d = 0;
978      for (int i = 1; i <= rVar(ntRing); i++)
979        d += p_GetExp(p, i, ntRing);
980      if (d > denDegree) denDegree = d;
981      pIter(p);
982    }
983  }
984  return numDegree + denDegree + noOfTerms;
985}
986
987number ntInvers(number a, const coeffs cf)
988{
989  ntTest(a);
990  if (IS0(a)) WerrorS(nDivBy0);
991  fraction f = (fraction)a;
992  fraction result = (fraction)omAlloc0Bin(fractionObjectBin);
993  poly g;
994  if (DENIS1(f)) g = p_One(ntRing);
995  else           g = p_Copy(DEN(f), ntRing);
996  NUM(result) = g;
997  DEN(result) = p_Copy(NUM(f), ntRing);
998  COM(result) = COM(f);
999  return (number)result;
1000}
1001
1002/* assumes that src = Q, dst = Q(t_1, ..., t_s) */
1003number ntMap00(number a, const coeffs src, const coeffs dst)
1004{
1005  if (n_IsZero(a, src)) return NULL;
1006  assume(src == dst->extRing->cf);
1007  poly p = p_One(dst->extRing);
1008  p_SetCoeff(p, n_Copy(a, src), dst->extRing);
1009  fraction f = (fraction)omAlloc0Bin(fractionObjectBin);
1010  NUM(f) = p; DEN(f) = NULL; COM(f) = 0;
1011  return (number)f;
1012}
1013
1014/* assumes that src = Z/p, dst = Q(t_1, ..., t_s) */
1015number ntMapP0(number a, const coeffs src, const coeffs dst)
1016{
1017  if (n_IsZero(a, src)) return NULL;
1018  /* mapping via intermediate int: */
1019  int n = n_Int(a, src);
1020  number q = n_Init(n, dst->extRing->cf);
1021  poly p;
1022  if (n_IsZero(q, dst->extRing->cf))
1023  {
1024    n_Delete(&q, dst->extRing->cf);
1025    return NULL;
1026  }
1027  p = p_One(dst->extRing);
1028  p_SetCoeff(p, q, dst->extRing);
1029  fraction f = (fraction)omAlloc0Bin(fractionObjectBin);
1030  NUM(f) = p; DEN(f) = NULL; COM(f) = 0;
1031  return (number)f;
1032}
1033
1034/* assumes that either src = Q(t_1, ..., t_s), dst = Q(t_1, ..., t_s), or
1035                       src = Z/p(t_1, ..., t_s), dst = Z/p(t_1, ..., t_s) */
1036number ntCopyMap(number a, const coeffs cf, const coeffs dst)
1037{
1038//  if (n_IsZero(a, cf)) return NULL;
1039   
1040  ntTest(a);
1041
1042  if (IS0(a)) return NULL;
1043   
1044  const ring rSrc = cf->extRing;
1045  const ring rDst = dst->extRing;
1046 
1047  if( rSrc == rDst )
1048    return ntCopy(a, dst); // USUALLY WRONG!
1049 
1050  fraction f = (fraction)a;
1051  poly g = prCopyR(NUM(f), rSrc, rDst);
1052   
1053  poly h = NULL;
1054 
1055  if (!DENIS1(f))
1056     h = prCopyR(DEN(f), rSrc, rDst);
1057   
1058  fraction result = (fraction)omAlloc0Bin(fractionObjectBin);
1059   
1060  NUM(result) = g;
1061  DEN(result) = h;
1062  COM(result) = COM(f);
1063  return (number)result; 
1064}
1065
1066number ntCopyAlg(number a, const coeffs cf, const coeffs dst)
1067{
1068  if (n_IsZero(a, cf)) return NULL;
1069   
1070  fraction f = (fraction)omAlloc0Bin(fractionObjectBin); 
1071  // DEN(f) = NULL; COM(f) = 0;
1072  NUM(f) = prCopyR((poly)a, cf->extRing, dst->extRing);
1073  return (number)f;
1074}
1075
1076/* assumes that src = Q, dst = Z/p(t_1, ..., t_s) */
1077number ntMap0P(number a, const coeffs src, const coeffs dst)
1078{
1079  if (n_IsZero(a, src)) return NULL;
1080  int p = rChar(dst->extRing);
1081  int n = nlModP(a, p, src);
1082  number q = n_Init(n, dst->extRing->cf);
1083  poly g;
1084  if (n_IsZero(q, dst->extRing->cf))
1085  {
1086    n_Delete(&q, dst->extRing->cf);
1087    return NULL;
1088  }
1089  g = p_One(dst->extRing);
1090  p_SetCoeff(g, q, dst->extRing);
1091  fraction f = (fraction)omAlloc0Bin(fractionObjectBin);
1092  NUM(f) = g; // DEN(f) = NULL; COM(f) = 0;
1093  return (number)f;
1094}
1095
1096/* assumes that src = Z/p, dst = Z/p(t_1, ..., t_s) */
1097number ntMapPP(number a, const coeffs src, const coeffs dst)
1098{
1099  if (n_IsZero(a, src)) return NULL;
1100  assume(src == dst->extRing->cf);
1101  poly p = p_One(dst->extRing);
1102  p_SetCoeff(p, n_Copy(a, src), dst->extRing);
1103  fraction f = (fraction)omAlloc0Bin(fractionObjectBin);
1104  NUM(f) = p; DEN(f) = NULL; COM(f) = 0;
1105  return (number)f;
1106}
1107
1108/* assumes that src = Z/u, dst = Z/p(t_1, ..., t_s), where u != p */
1109number ntMapUP(number a, const coeffs src, const coeffs dst)
1110{
1111  if (n_IsZero(a, src)) return NULL;
1112  /* mapping via intermediate int: */
1113  int n = n_Int(a, src);
1114  number q = n_Init(n, dst->extRing->cf);
1115  poly p;
1116  if (n_IsZero(q, dst->extRing->cf))
1117  {
1118    n_Delete(&q, dst->extRing->cf);
1119    return NULL;
1120  }
1121  p = p_One(dst->extRing);
1122  p_SetCoeff(p, q, dst->extRing);
1123  fraction f = (fraction)omAlloc0Bin(fractionObjectBin);
1124  NUM(f) = p; DEN(f) = NULL; COM(f) = 0;
1125  return (number)f;
1126}
1127
1128nMapFunc ntSetMap(const coeffs src, const coeffs dst)
1129{
1130  /* dst is expected to be a rational function field */
1131  assume(getCoeffType(dst) == ID);
1132
1133  int h = 0; /* the height of the extension tower given by dst */
1134  coeffs bDst = nCoeff_bottom(dst, h); /* the bottom field in the tower dst */
1135  coeffs bSrc = nCoeff_bottom(src, h); /* the bottom field in the tower src */
1136
1137  /* for the time being, we only provide maps if h = 1 and if b is Q or
1138     some field Z/pZ: */
1139  if (h==0)
1140  {
1141    if (nCoeff_is_Q(src) && nCoeff_is_Q(bDst))
1142      return ntMap00;                                 /// Q       -->  Q(T)
1143    if (nCoeff_is_Zp(src) && nCoeff_is_Q(bDst))
1144      return ntMapP0;                                 /// Z/p     -->  Q(T)
1145    if (nCoeff_is_Q(src) && nCoeff_is_Zp(bDst))
1146      return ntMap0P;                                 /// Q       --> Z/p(T)
1147    if (nCoeff_is_Zp(src) && nCoeff_is_Zp(bDst))
1148    {
1149      if (src->ch == dst->ch) return ntMapPP;         /// Z/p     --> Z/p(T)
1150      else return ntMapUP;                            /// Z/u     --> Z/p(T)
1151    }
1152  }
1153  if (h != 1) return NULL;
1154  if ((!nCoeff_is_Zp(bDst)) && (!nCoeff_is_Q(bDst))) return NULL;
1155
1156  /* Let T denote the sequence of transcendental extension variables, i.e.,
1157     K[t_1, ..., t_s] =: K[T];
1158     Let moreover, for any such sequence T, T' denote any subsequence of T
1159     of the form t_1, ..., t_w with w <= s. */
1160
1161  if ((!nCoeff_is_Zp(bSrc)) && (!nCoeff_is_Q(bSrc))) return NULL;
1162
1163  if (nCoeff_is_Q(bSrc) && nCoeff_is_Q(bDst))
1164  {
1165    if (rVar(src->extRing) > rVar(dst->extRing)) 
1166       return NULL;
1167     
1168    for (int i = 0; i < rVar(src->extRing); i++)
1169      if (strcmp(rRingVar(i, src->extRing), rRingVar(i, dst->extRing)) != 0) 
1170         return NULL;
1171     
1172    if (src->type==n_transExt)
1173       return ntCopyMap;          /// Q(T')   --> Q(T)
1174    else
1175       return ntCopyAlg;
1176  }
1177
1178  if (nCoeff_is_Zp(bSrc) && nCoeff_is_Zp(bDst))
1179  {
1180    if (rVar(src->extRing) > rVar(dst->extRing)) 
1181       return NULL;
1182     
1183    for (int i = 0; i < rVar(src->extRing); i++)
1184      if (strcmp(rRingVar(i, src->extRing), rRingVar(i, dst->extRing)) != 0) 
1185         return NULL;
1186     
1187    if (src->type==n_transExt)
1188       return ntCopyMap;         /// Z/p(T') --> Z/p(T)
1189    else
1190       return ntCopyAlg;
1191  }
1192
1193  return NULL;                                 /// default
1194}
1195
1196void ntKillChar(coeffs cf)
1197{
1198  if ((--cf->extRing->ref) == 0)
1199    rDelete(cf->extRing);
1200}
1201
1202BOOLEAN ntInitChar(coeffs cf, void * infoStruct)
1203{
1204
1205  assume( infoStruct != NULL );
1206
1207  TransExtInfo *e = (TransExtInfo *)infoStruct;
1208
1209  assume( e->r                != NULL);      // extRing;
1210  assume( e->r->cf            != NULL);      // extRing->cf;
1211  assume( e->r->minideal == NULL );
1212
1213  assume( cf != NULL );
1214  assume(getCoeffType(cf) == ID);                // coeff type;
1215
1216  cf->extRing           = e->r;
1217  cf->extRing->ref ++; // increase the ref.counter for the ground poly. ring!
1218
1219  /* propagate characteristic up so that it becomes
1220     directly accessible in cf: */
1221  cf->ch = cf->extRing->cf->ch;
1222
1223  cf->cfGreaterZero  = ntGreaterZero;
1224  cf->cfGreater      = ntGreater;
1225  cf->cfEqual        = ntEqual;
1226  cf->cfIsZero       = ntIsZero;
1227  cf->cfIsOne        = ntIsOne;
1228  cf->cfIsMOne       = ntIsMOne;
1229  cf->cfInit         = ntInit;
1230  cf->cfInt          = ntInt;
1231  cf->cfNeg          = ntNeg;
1232  cf->cfAdd          = ntAdd;
1233  cf->cfSub          = ntSub;
1234  cf->cfMult         = ntMult;
1235  cf->cfDiv          = ntDiv;
1236  cf->cfExactDiv     = ntDiv;
1237  cf->cfPower        = ntPower;
1238  cf->cfCopy         = ntCopy;
1239  cf->cfWrite        = ntWrite;
1240  cf->cfRead         = ntRead;
1241  cf->cfDelete       = ntDelete;
1242  cf->cfSetMap       = ntSetMap;
1243  cf->cfGetDenom     = ntGetDenom;
1244  cf->cfGetNumerator = ntGetNumerator;
1245  cf->cfRePart       = ntCopy;
1246  cf->cfImPart       = ntImPart;
1247  cf->cfCoeffWrite   = ntCoeffWrite;
1248#ifdef LDEBUG
1249  cf->cfDBTest       = ntDBTest;
1250#endif
1251  cf->cfGcd          = ntGcd;
1252  cf->cfLcm          = ntLcm;
1253  cf->cfSize         = ntSize;
1254  cf->nCoeffIsEqual  = ntCoeffIsEqual;
1255  cf->cfInvers       = ntInvers;
1256  cf->cfIntDiv       = ntDiv;
1257  cf->cfKillChar     = ntKillChar;
1258
1259#ifndef HAVE_FACTORY
1260  PrintS("// Warning: The 'factory' module is not available.\n");
1261  PrintS("//          Hence gcd's cannot be cancelled in any\n");
1262  PrintS("//          computed fraction!\n");
1263#endif
1264
1265  return FALSE;
1266}
1267
1268
1269number ntParam(const short iParameter, const coeffs cf)
1270{
1271  assume(getCoeffType(cf) == ID);
1272
1273  const ring R = cf->extRing;
1274  assume( R != NULL );
1275  assume( 0 < iParameter && iParameter <= rVar(R) );
1276
1277  poly p = p_One(R); p_SetExp(p, iParameter, 1, R); p_Setm(p, R);
1278
1279//  return (number) p;
1280
1281  fraction f = (fraction)omAlloc0Bin(fractionObjectBin);
1282  NUM(f) = p;
1283  DEN(f) = NULL;
1284  COM(f) = 0;
1285
1286  return (number)f;
1287}
1288
1289
1290/// if m == var(i)/1 => return i,
1291int ntIsParam(number m, const coeffs cf)
1292{
1293  assume(getCoeffType(cf) == ID);
1294
1295  const ring R = cf->extRing;
1296  assume( R != NULL );
1297
1298  fraction f = (fraction)m;
1299
1300  if( DEN(f) != NULL )
1301    return 0;
1302
1303  return p_Var( NUM(f), R );
1304}
Note: See TracBrowser for help on using the repository browser.