source: git/libpolys/polys/ext_fields/transext.cc @ 331fd0

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