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

spielwiese
Last change on this file since a0acbc was a0acbc, checked in by Burcin Erocal <burcin@…>, 12 years ago
Fix typo where ntCopy() was called instead of n_Copy().
  • Property mode set to 100644
File size: 38.6 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);
833    if (!omitBrackets) StringAppendS("(");
834    p_String0(NUM(f), ntRing, ntRing);
835    if (!omitBrackets) StringAppendS(")");
836    if (!DENIS1(f))
837    {
838      StringAppendS("/");
839      omitBrackets = p_IsConstant(DEN(f), ntRing);
840      if (!omitBrackets) StringAppendS("(");
841      p_String0(DEN(f), ntRing, ntRing);
842      if (!omitBrackets) StringAppendS(")");
843    }
844  }
845}
846
847const char * ntRead(const char *s, number *a, const coeffs cf)
848{
849  poly p;
850  const char * result = p_Read(s, p, ntRing);
851  if (p == NULL) { *a = NULL; return result; }
852  else
853  {
854    fraction f = (fraction)omAlloc0Bin(fractionObjectBin);
855    NUM(f) = p;
856    DEN(f) = NULL;
857    COM(f) = 0;
858    *a = (number)f;
859    return result;
860  }
861}
862
863/* expects *param to be castable to TransExtInfo */
864static BOOLEAN ntCoeffIsEqual(const coeffs cf, n_coeffType n, void * param)
865{
866  if (ID != n) return FALSE;
867  TransExtInfo *e = (TransExtInfo *)param;
868  /* for rational function fields we expect the underlying
869     polynomial rings to be IDENTICAL, i.e. the SAME OBJECT;
870     this expectation is based on the assumption that we have properly
871     registered cf and perform reference counting rather than creating
872     multiple copies of the same coefficient field/domain/ring */
873  return (ntRing == e->r);
874}
875
876number ntLcm(number a, number b, const coeffs cf)
877{
878  ntTest(a); ntTest(b);
879  fraction fb = (fraction)b;
880  if ((b==NULL)||(DEN(fb)==NULL)) return ntCopy(a,cf);
881#ifdef HAVE_FACTORY
882  fraction fa = (fraction)a;
883  /* singclap_gcd destroys its arguments; we hence need copies: */
884  poly pa = p_Copy(NUM(fa), ntRing);
885  poly pb = p_Copy(DEN(fb), ntRing);
886
887  /* Note that, over Q, singclap_gcd will remove the denominators in all
888     rational coefficients of pa and pb, before starting to compute
889     the gcd. Thus, we do not need to ensure that the coefficients of
890     pa and pb live in Z; they may well be elements of Q\Z. */
891  poly pGcd = singclap_gcd(pa, pb, cf->extRing);
892  if (p_IsConstant(pGcd, ntRing) &&
893      n_IsOne(p_GetCoeff(pGcd, ntRing), ntCoeffs))
894  { /* gcd = 1; return pa*pb*/
895    p_Delete(&pGcd,ntRing);
896    fraction result = (fraction)omAlloc0Bin(fractionObjectBin);
897    NUM(result) = pp_Mult_qq(NUM(fa),DEN(fb),ntRing);
898    return (number)result;
899  }
900  else
901  { /* return pa*pb/gcd */
902    poly newNum = singclap_pdivide(NUM(fa), pGcd, ntRing);
903    p_Delete(&pGcd,ntRing);
904    fraction result = (fraction)omAlloc0Bin(fractionObjectBin);
905    NUM(result) = p_Mult_q(p_Copy(DEN(fb),ntRing),newNum,ntRing);
906    return (number)result;
907  }
908#else
909  Print("// factory needed: transext.cc:ntLcm\n");
910  return NULL;
911#endif /* HAVE_FACTORY */
912  return NULL;
913}
914
915number ntGcd(number a, number b, const coeffs cf)
916{
917  ntTest(a); ntTest(b);
918  if (a==NULL) return ntCopy(b,cf);
919  if (b==NULL) return ntCopy(a,cf);
920#ifdef HAVE_FACTORY
921  fraction fa = (fraction)a;
922  fraction fb = (fraction)b;
923  /* singclap_gcd destroys its arguments; we hence need copies: */
924  poly pa = p_Copy(NUM(fa), ntRing);
925  poly pb = p_Copy(NUM(fb), ntRing);
926
927  /* Note that, over Q, singclap_gcd will remove the denominators in all
928     rational coefficients of pa and pb, before starting to compute
929     the gcd. Thus, we do not need to ensure that the coefficients of
930     pa and pb live in Z; they may well be elements of Q\Z. */
931  poly pGcd = singclap_gcd(pa, pb, cf->extRing);
932  fraction result = (fraction)omAlloc0Bin(fractionObjectBin);
933  NUM(result) = pGcd;
934  return (number)result;
935#else
936  Print("// factory needed: transext.cc:ntGcd\n");
937  return NULL;
938#endif /* HAVE_FACTORY */
939}
940
941int ntSize(number a, const coeffs cf)
942{
943  ntTest(a);
944  if (IS0(a)) return -1;
945  /* this has been taken from the old implementation of field extensions,
946     where we computed the sum of the degrees and the numbers of terms in
947     the numerator and denominator of a; so we leave it at that, for the
948     time being */
949  fraction f = (fraction)a;
950  poly p = NUM(f);
951  int noOfTerms = 0;
952  int numDegree = 0;
953  while (p != NULL)
954  {
955    noOfTerms++;
956    int d = 0;
957    for (int i = 1; i <= rVar(ntRing); i++)
958      d += p_GetExp(p, i, ntRing);
959    if (d > numDegree) numDegree = d;
960    pIter(p);
961  }
962  int denDegree = 0;
963  if (!DENIS1(f))
964  {
965    p = DEN(f);
966    while (p != NULL)
967    {
968      noOfTerms++;
969      int d = 0;
970      for (int i = 1; i <= rVar(ntRing); i++)
971        d += p_GetExp(p, i, ntRing);
972      if (d > denDegree) denDegree = d;
973      pIter(p);
974    }
975  }
976  return numDegree + denDegree + noOfTerms;
977}
978
979number ntInvers(number a, const coeffs cf)
980{
981  ntTest(a);
982  if (IS0(a)) WerrorS(nDivBy0);
983  fraction f = (fraction)a;
984  fraction result = (fraction)omAlloc0Bin(fractionObjectBin);
985  poly g;
986  if (DENIS1(f)) g = p_One(ntRing);
987  else           g = p_Copy(DEN(f), ntRing);
988  NUM(result) = g;
989  DEN(result) = p_Copy(NUM(f), ntRing);
990  COM(result) = COM(f);
991  return (number)result;
992}
993
994/* assumes that src = Q, dst = Q(t_1, ..., t_s) */
995number ntMap00(number a, const coeffs src, const coeffs dst)
996{
997  if (n_IsZero(a, src)) return NULL;
998  assume(src == dst->extRing->cf);
999  poly p = p_One(dst->extRing);
1000  p_SetCoeff(p, ntCopy(a, src), dst->extRing);
1001  fraction f = (fraction)omAlloc0Bin(fractionObjectBin);
1002  NUM(f) = p; DEN(f) = NULL; COM(f) = 0;
1003  return (number)f;
1004}
1005
1006/* assumes that src = Z/p, dst = Q(t_1, ..., t_s) */
1007number ntMapP0(number a, const coeffs src, const coeffs dst)
1008{
1009  if (n_IsZero(a, src)) return NULL;
1010  /* mapping via intermediate int: */
1011  int n = n_Int(a, src);
1012  number q = n_Init(n, dst->extRing->cf);
1013  poly p;
1014  if (n_IsZero(q, dst->extRing->cf))
1015  {
1016    n_Delete(&q, dst->extRing->cf);
1017    return NULL;
1018  }
1019  p = p_One(dst->extRing);
1020  p_SetCoeff(p, q, dst->extRing);
1021  fraction f = (fraction)omAlloc0Bin(fractionObjectBin);
1022  NUM(f) = p; DEN(f) = NULL; COM(f) = 0;
1023  return (number)f;
1024}
1025
1026/* assumes that either src = Q(t_1, ..., t_s), dst = Q(t_1, ..., t_s), or
1027                       src = Z/p(t_1, ..., t_s), dst = Z/p(t_1, ..., t_s) */
1028number ntCopyMap(number a, const coeffs src, const coeffs dst)
1029{
1030  return ntCopy(a, dst);
1031}
1032
1033number ntCopyAlg(number a, const coeffs src, const coeffs dst)
1034{
1035  if (n_IsZero(a, src)) return NULL;
1036  fraction f = (fraction)omAlloc0Bin(fractionObjectBin);
1037  NUM(f) = p_Copy((poly)a,src->extRing);// DEN(f) = NULL; COM(f) = 0;
1038  return (number)f;
1039}
1040
1041/* assumes that src = Q, dst = Z/p(t_1, ..., t_s) */
1042number ntMap0P(number a, const coeffs src, const coeffs dst)
1043{
1044  if (n_IsZero(a, src)) return NULL;
1045  int p = rChar(dst->extRing);
1046  int n = nlModP(a, p, src);
1047  number q = n_Init(n, dst->extRing->cf);
1048  poly g;
1049  if (n_IsZero(q, dst->extRing->cf))
1050  {
1051    n_Delete(&q, dst->extRing->cf);
1052    return NULL;
1053  }
1054  g = p_One(dst->extRing);
1055  p_SetCoeff(g, q, dst->extRing);
1056  fraction f = (fraction)omAlloc0Bin(fractionObjectBin);
1057  NUM(f) = g; // DEN(f) = NULL; COM(f) = 0;
1058  return (number)f;
1059}
1060
1061/* assumes that src = Z/p, dst = Z/p(t_1, ..., t_s) */
1062number ntMapPP(number a, const coeffs src, const coeffs dst)
1063{
1064  if (n_IsZero(a, src)) return NULL;
1065  assume(src == dst->extRing->cf);
1066  poly p = p_One(dst->extRing);
1067  p_SetCoeff(p, n_Copy(a, src), dst->extRing);
1068  fraction f = (fraction)omAlloc0Bin(fractionObjectBin);
1069  NUM(f) = p; DEN(f) = NULL; COM(f) = 0;
1070  return (number)f;
1071}
1072
1073/* assumes that src = Z/u, dst = Z/p(t_1, ..., t_s), where u != p */
1074number ntMapUP(number a, const coeffs src, const coeffs dst)
1075{
1076  if (n_IsZero(a, src)) return NULL;
1077  /* mapping via intermediate int: */
1078  int n = n_Int(a, src);
1079  number q = n_Init(n, dst->extRing->cf);
1080  poly p;
1081  if (n_IsZero(q, dst->extRing->cf))
1082  {
1083    n_Delete(&q, dst->extRing->cf);
1084    return NULL;
1085  }
1086  p = p_One(dst->extRing);
1087  p_SetCoeff(p, q, dst->extRing);
1088  fraction f = (fraction)omAlloc0Bin(fractionObjectBin);
1089  NUM(f) = p; DEN(f) = NULL; COM(f) = 0;
1090  return (number)f;
1091}
1092
1093nMapFunc ntSetMap(const coeffs src, const coeffs dst)
1094{
1095  /* dst is expected to be a rational function field */
1096  assume(getCoeffType(dst) == ID);
1097
1098  int h = 0; /* the height of the extension tower given by dst */
1099  coeffs bDst = nCoeff_bottom(dst, h); /* the bottom field in the tower dst */
1100  coeffs bSrc = nCoeff_bottom(src, h); /* the bottom field in the tower src */
1101
1102  /* for the time being, we only provide maps if h = 1 and if b is Q or
1103     some field Z/pZ: */
1104  if (h==0)
1105  {
1106    if (nCoeff_is_Q(src) && nCoeff_is_Q(bDst))
1107      return ntMap00;                                 /// Q       -->  Q(T)
1108    if (nCoeff_is_Zp(src) && nCoeff_is_Q(bDst))
1109      return ntMapP0;                                 /// Z/p     -->  Q(T)
1110    if (nCoeff_is_Q(src) && nCoeff_is_Zp(bDst))
1111      return ntMap0P;                                 /// Q       --> Z/p(T)
1112    if (nCoeff_is_Zp(src) && nCoeff_is_Zp(bDst))
1113    {
1114      if (src->ch == dst->ch) return ntMapPP;         /// Z/p     --> Z/p(T)
1115      else return ntMapUP;                            /// Z/u     --> Z/p(T)
1116    }
1117  }
1118  if (h != 1) return NULL;
1119  if ((!nCoeff_is_Zp(bDst)) && (!nCoeff_is_Q(bDst))) return NULL;
1120
1121  /* Let T denote the sequence of transcendental extension variables, i.e.,
1122     K[t_1, ..., t_s] =: K[T];
1123     Let moreover, for any such sequence T, T' denote any subsequence of T
1124     of the form t_1, ..., t_w with w <= s. */
1125
1126  if ((!nCoeff_is_Zp(bSrc)) && (!nCoeff_is_Q(bSrc))) return NULL;
1127
1128  if (nCoeff_is_Q(bSrc) && nCoeff_is_Q(bDst))
1129  {
1130    if (rVar(src->extRing) > rVar(dst->extRing)) return NULL;
1131    for (int i = 0; i < rVar(src->extRing); i++)
1132      if (strcmp(rRingVar(i, src->extRing),
1133                 rRingVar(i, dst->extRing)) != 0) return NULL;
1134      if (src->type==n_transExt)
1135        return ndCopyMap; //ntCopyMap;          /// Q(T')   --> Q(T)
1136      else
1137        return ntCopyAlg;
1138  }
1139
1140  if (nCoeff_is_Zp(bSrc) && nCoeff_is_Zp(bDst))
1141  {
1142    if (rVar(src->extRing) > rVar(dst->extRing)) return NULL;
1143    for (int i = 0; i < rVar(src->extRing); i++)
1144      if (strcmp(rRingVar(i, src->extRing),
1145                 rRingVar(i, dst->extRing)) != 0) return NULL;
1146      if (src->type==n_transExt)
1147        return ndCopyMap; //ntCopyMap;         /// Z/p(T') --> Z/p(T)
1148      else
1149        return ntCopyAlg;
1150  }
1151
1152  return NULL;                                 /// default
1153}
1154
1155void ntKillChar(coeffs cf)
1156{
1157  if ((--cf->extRing->ref) == 0)
1158    rDelete(cf->extRing);
1159}
1160
1161BOOLEAN ntInitChar(coeffs cf, void * infoStruct)
1162{
1163
1164  assume( infoStruct != NULL );
1165
1166  TransExtInfo *e = (TransExtInfo *)infoStruct;
1167
1168  assume( e->r                != NULL);      // extRing;
1169  assume( e->r->cf            != NULL);      // extRing->cf;
1170  assume( e->r->minideal == NULL );
1171
1172  assume( cf != NULL );
1173  assume(getCoeffType(cf) == ID);                // coeff type;
1174
1175  cf->extRing           = e->r;
1176  cf->extRing->ref ++; // increase the ref.counter for the ground poly. ring!
1177
1178  /* propagate characteristic up so that it becomes
1179     directly accessible in cf: */
1180  cf->ch = cf->extRing->cf->ch;
1181
1182  cf->cfGreaterZero  = ntGreaterZero;
1183  cf->cfGreater      = ntGreater;
1184  cf->cfEqual        = ntEqual;
1185  cf->cfIsZero       = ntIsZero;
1186  cf->cfIsOne        = ntIsOne;
1187  cf->cfIsMOne       = ntIsMOne;
1188  cf->cfInit         = ntInit;
1189  cf->cfInt          = ntInt;
1190  cf->cfNeg          = ntNeg;
1191  cf->cfAdd          = ntAdd;
1192  cf->cfSub          = ntSub;
1193  cf->cfMult         = ntMult;
1194  cf->cfDiv          = ntDiv;
1195  cf->cfExactDiv     = ntDiv;
1196  cf->cfPower        = ntPower;
1197  cf->cfCopy         = ntCopy;
1198  cf->cfWrite        = ntWrite;
1199  cf->cfRead         = ntRead;
1200  cf->cfDelete       = ntDelete;
1201  cf->cfSetMap       = ntSetMap;
1202  cf->cfGetDenom     = ntGetDenom;
1203  cf->cfGetNumerator = ntGetNumerator;
1204  cf->cfRePart       = ntCopy;
1205  cf->cfImPart       = ntImPart;
1206  cf->cfCoeffWrite   = ntCoeffWrite;
1207#ifdef LDEBUG
1208  cf->cfDBTest       = ntDBTest;
1209#endif
1210  cf->cfGcd          = ntGcd;
1211  cf->cfLcm          = ntLcm;
1212  cf->cfSize         = ntSize;
1213  cf->nCoeffIsEqual  = ntCoeffIsEqual;
1214  cf->cfInvers       = ntInvers;
1215  cf->cfIntDiv       = ntDiv;
1216  cf->cfKillChar     = ntKillChar;
1217
1218#ifndef HAVE_FACTORY
1219  PrintS("// Warning: The 'factory' module is not available.\n");
1220  PrintS("//          Hence gcd's cannot be cancelled in any\n");
1221  PrintS("//          computed fraction!\n");
1222#endif
1223
1224  return FALSE;
1225}
1226
1227
1228number ntParam(const short iParameter, const coeffs cf)
1229{
1230  assume(getCoeffType(cf) == ID);
1231
1232  const ring R = cf->extRing;
1233  assume( R != NULL );
1234  assume( 0 < iParameter && iParameter <= rVar(R) );
1235
1236  poly p = p_One(R); p_SetExp(p, iParameter, 1, R); p_Setm(p, R);
1237
1238//  return (number) p;
1239
1240  fraction f = (fraction)omAlloc0Bin(fractionObjectBin);
1241  NUM(f) = p;
1242  DEN(f) = NULL;
1243  COM(f) = 0;
1244
1245  return (number)f;
1246}
1247
1248
1249/// if m == var(i)/1 => return i,
1250int ntIsParam(number m, const coeffs cf)
1251{
1252  assume(getCoeffType(cf) == ID);
1253
1254  const ring R = cf->extRing;
1255  assume( R != NULL );
1256
1257  fraction f = (fraction)m;
1258
1259  if( DEN(f) != NULL )
1260    return 0;
1261
1262  return p_Var( NUM(f), R );
1263}
Note: See TracBrowser for help on using the repository browser.