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

spielwiese
Last change on this file since e82417 was e82417, checked in by Oleksandr Motsak <motsak@…>, 13 years ago
ADD: new function "int n_IsParam(number m, const ring r)" a-la onld p_Var
  • Property mode set to 100644
File size: 36.1 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)
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 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 (!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  PrintS("//   Coefficients live in the rational function field\n");
373  Print("//   K(");
374  for (int i = 0; i < rVar(ntRing); i++)
375  {
376    if (i > 0) PrintS(", ");
377    Print("%s", rRingVar(i, ntRing));
378  }
379  PrintS(") with\n");
380  PrintS("//   K: "); n_CoeffWrite(cf->extRing->cf);
381}
382
383number ntAdd(number a, number b, const coeffs cf)
384{
385  ntTest(a); ntTest(b);
386  if (IS0(a)) return ntCopy(b, cf);
387  if (IS0(b)) return ntCopy(a, cf);
388 
389  fraction fa = (fraction)a;
390  fraction fb = (fraction)b;
391 
392  poly g = p_Copy(NUM(fa), ntRing);
393  if (!DENIS1(fb)) g = p_Mult_q(g, p_Copy(DEN(fb), ntRing), ntRing);
394  poly h = p_Copy(NUM(fb), ntRing);
395  if (!DENIS1(fa)) h = p_Mult_q(h, p_Copy(DEN(fa), ntRing), ntRing);
396  g = p_Add_q(g, h, ntRing);
397 
398  if (g == NULL) return NULL;
399 
400  poly f;
401  if      (DENIS1(fa) && DENIS1(fb))  f = NULL;
402  else if (!DENIS1(fa) && DENIS1(fb)) f = p_Copy(DEN(fa), ntRing);
403  else if (DENIS1(fa) && !DENIS1(fb)) f = p_Copy(DEN(fb), ntRing);
404  else /* both denom's are != 1 */    f = p_Mult_q(p_Copy(DEN(fa), ntRing),
405                                                   p_Copy(DEN(fb), ntRing),
406                                                   ntRing);
407 
408  fraction result = (fraction)omAlloc0Bin(fractionObjectBin);
409  NUM(result) = g;
410  DEN(result) = f;
411  COM(result) = COM(fa) + COM(fb) + ADD_COMPLEXITY;
412  heuristicGcdCancellation((number)result, cf);
413  return (number)result;
414}
415
416number ntSub(number a, number b, const coeffs cf)
417{
418  ntTest(a); ntTest(b);
419  if (IS0(a)) return ntNeg(ntCopy(b, cf), cf);
420  if (IS0(b)) return ntCopy(a, cf);
421 
422  fraction fa = (fraction)a;
423  fraction fb = (fraction)b;
424 
425  poly g = p_Copy(NUM(fa), ntRing);
426  if (!DENIS1(fb)) g = p_Mult_q(g, p_Copy(DEN(fb), ntRing), ntRing);
427  poly h = p_Copy(NUM(fb), ntRing);
428  if (!DENIS1(fa)) h = p_Mult_q(h, p_Copy(DEN(fa), ntRing), ntRing);
429  g = p_Add_q(g, p_Neg(h, ntRing), ntRing);
430 
431  if (g == NULL) return NULL;
432 
433  poly f;
434  if      (DENIS1(fa) && DENIS1(fb))  f = NULL;
435  else if (!DENIS1(fa) && DENIS1(fb)) f = p_Copy(DEN(fa), ntRing);
436  else if (DENIS1(fa) && !DENIS1(fb)) f = p_Copy(DEN(fb), ntRing);
437  else /* both den's are != 1 */      f = p_Mult_q(p_Copy(DEN(fa), ntRing),
438                                                   p_Copy(DEN(fb), ntRing),
439                                                   ntRing);
440 
441  fraction result = (fraction)omAlloc0Bin(fractionObjectBin);
442  NUM(result) = g;
443  DEN(result) = f;
444  COM(result) = COM(fa) + COM(fb) + ADD_COMPLEXITY;
445  heuristicGcdCancellation((number)result, cf);
446  return (number)result;
447}
448
449number ntMult(number a, number b, const coeffs cf)
450{
451  ntTest(a); ntTest(b);
452  if (IS0(a) || IS0(b)) return NULL;
453 
454  fraction fa = (fraction)a;
455  fraction fb = (fraction)b;
456 
457  poly g = p_Copy(NUM(fa), ntRing);
458  poly h = p_Copy(NUM(fb), ntRing);
459  g = p_Mult_q(g, h, ntRing);
460 
461  if (g == NULL) return NULL;   /* may happen due to zero divisors */
462 
463  poly f;
464  if      (DENIS1(fa) && DENIS1(fb))  f = NULL;
465  else if (!DENIS1(fa) && DENIS1(fb)) f = p_Copy(DEN(fa), ntRing);
466  else if (DENIS1(fa) && !DENIS1(fb)) f = p_Copy(DEN(fb), ntRing);
467  else /* both den's are != 1 */      f = p_Mult_q(p_Copy(DEN(fa), ntRing),
468                                                   p_Copy(DEN(fb), ntRing),
469                                                   ntRing);
470 
471  fraction result = (fraction)omAlloc0Bin(fractionObjectBin);
472  NUM(result) = g;
473  DEN(result) = f;
474  COM(result) = COM(fa) + COM(fb) + MULT_COMPLEXITY;
475  heuristicGcdCancellation((number)result, cf);
476  return (number)result;
477}
478
479number ntDiv(number a, number b, const coeffs cf)
480{
481  ntTest(a); ntTest(b);
482  if (IS0(a)) return NULL;
483  if (IS0(b)) WerrorS(nDivBy0);
484 
485  fraction fa = (fraction)a;
486  fraction fb = (fraction)b;
487 
488  poly g = p_Copy(NUM(fa), ntRing);
489  if (!DENIS1(fb)) g = p_Mult_q(g, p_Copy(DEN(fb), ntRing), ntRing);
490 
491  if (g == NULL) return NULL;   /* may happen due to zero divisors */
492 
493  poly f = p_Copy(NUM(fb), ntRing);
494  if (!DENIS1(fa)) f = p_Mult_q(f, p_Copy(DEN(fa), ntRing), ntRing);
495 
496  fraction result = (fraction)omAlloc0Bin(fractionObjectBin);
497  NUM(result) = g;
498  DEN(result) = f;
499  COM(result) = COM(fa) + COM(fb) + MULT_COMPLEXITY;
500  heuristicGcdCancellation((number)result, cf);
501  return (number)result;
502}
503
504/* 0^0 = 0;
505   for |exp| <= 7 compute power by a simple multiplication loop;
506   for |exp| >= 8 compute power along binary presentation of |exp|, e.g.
507      p^13 = p^1 * p^4 * p^8, where we utilise that
508      p^(2^(k+1)) = p^(2^k) * p^(2^k);
509   intermediate cancellation is controlled by the in-place method
510   heuristicGcdCancellation; see there.
511*/
512void ntPower(number a, int exp, number *b, const coeffs cf)
513{
514  ntTest(a);
515 
516  /* special cases first */
517  if (IS0(a))
518  {
519    if (exp >= 0) *b = NULL;
520    else          WerrorS(nDivBy0);
521  }
522  else if (exp ==  0) *b = ntInit(1, cf);
523  else if (exp ==  1) *b = ntCopy(a, cf);
524  else if (exp == -1) *b = ntInvers(a, cf);
525 
526  int expAbs = exp; if (expAbs < 0) expAbs = -expAbs;
527 
528  /* now compute a^expAbs */
529  number pow; number t;
530  if (expAbs <= 7)
531  {
532    pow = ntCopy(a, cf);
533    for (int i = 2; i <= expAbs; i++)
534    {
535      t = ntMult(pow, a, cf);
536      ntDelete(&pow, cf);
537      pow = t;
538      heuristicGcdCancellation(pow, cf);
539    }
540  }
541  else
542  {
543    pow = ntInit(1, cf);
544    number factor = ntCopy(a, cf);
545    while (expAbs != 0)
546    {
547      if (expAbs & 1)
548      {
549        t = ntMult(pow, factor, cf);
550        ntDelete(&pow, cf);
551        pow = t;
552        heuristicGcdCancellation(pow, cf);
553      }
554      expAbs = expAbs / 2;
555      if (expAbs != 0)
556      {
557        t = ntMult(factor, factor, cf);
558        ntDelete(&factor, cf);
559        factor = t;
560        heuristicGcdCancellation(factor, cf);
561      }
562    }
563    ntDelete(&factor, cf);
564  }
565 
566  /* invert if original exponent was negative */
567  if (exp < 0)
568  {
569    t = ntInvers(pow, cf);
570    ntDelete(&pow, cf);
571    pow = t;
572  }
573  *b = pow;
574}
575
576/* assumes that cf represents the rationals, i.e. Q, and will only
577   be called in that case;
578   assumes furthermore that f != NULL and that the denominator of f != 1;
579   generally speaking, this method removes denominators in the rational
580   coefficients of the numerator and denominator of 'a';
581   more concretely, the following normalizations will be performed,
582   where t^alpha denotes a monomial in the transcendental variables t_k
583   (1) if 'a' is of the form
584          (sum_alpha a_alpha/b_alpha * t^alpha)
585          -------------------------------------
586            (sum_beta c_beta/d_beta * t^beta)
587       with integers a_alpha, b_alpha, c_beta, d_beta, then both the
588       numerator and the denominator will be multiplied by the LCM of
589       the b_alpha's and the d_beta's (if this LCM is != 1),
590   (2) if 'a' is - e.g. after having performed step (1) - of the form
591          (sum_alpha a_alpha * t^alpha)
592          -----------------------------
593            (sum_beta c_beta * t^beta)
594       with integers a_alpha, c_beta, and with a non-constant denominator,
595       then both the numerator and the denominator will be divided by the
596       GCD of the a_alpha's and the c_beta's (if this GCD is != 1),
597   (3) if 'a' is - e.g. after having performed steps (1) and (2) - of the
598       form
599          (sum_alpha a_alpha * t^alpha)
600          -----------------------------
601                        c
602       with integers a_alpha, and c != 1, then 'a' will be replaced by
603       (sum_alpha a_alpha/c * t^alpha);
604   this procedure does not alter COM(f) (this has to be done by the
605   calling procedure);
606   modifies f */
607void handleNestedFractionsOverQ(fraction f, const coeffs cf)
608{
609  assume(nCoeff_is_Q(ntCoeffs));
610  assume(!IS0(f));
611  assume(!DENIS1(f));
612 
613  if (!p_IsConstant(DEN(f), ntRing))
614  { /* step (1); see documentation of this procedure above */
615    p_Normalize(NUM(f), ntRing);
616    p_Normalize(DEN(f), ntRing);
617    number lcmOfDenominators = n_Init(1, ntCoeffs);
618    number c; number tmp;
619    poly p = NUM(f);
620    /* careful when using n_Lcm!!! It computes the lcm of the numerator
621       of the 1st argument and the denominator of the 2nd!!! */
622    while (p != NULL)
623    {
624      c = p_GetCoeff(p, ntRing);
625      tmp = n_Lcm(lcmOfDenominators, c, ntCoeffs);
626      n_Delete(&lcmOfDenominators, ntCoeffs);
627      lcmOfDenominators = tmp;
628      pIter(p);
629    }
630    p = DEN(f);
631    while (p != NULL)
632    {
633      c = p_GetCoeff(p, ntRing);
634      tmp = n_Lcm(lcmOfDenominators, c, ntCoeffs);
635      n_Delete(&lcmOfDenominators, ntCoeffs);
636      lcmOfDenominators = tmp;
637      pIter(p);
638    }
639    if (!n_IsOne(lcmOfDenominators, ntCoeffs))
640    { /* multiply NUM(f) and DEN(f) with lcmOfDenominators */
641      NUM(f) = p_Mult_nn(NUM(f), lcmOfDenominators, ntRing);
642      p_Normalize(NUM(f), ntRing);
643      DEN(f) = p_Mult_nn(DEN(f), lcmOfDenominators, ntRing);
644      p_Normalize(DEN(f), ntRing);
645    }
646    n_Delete(&lcmOfDenominators, ntCoeffs);
647    if (!p_IsConstant(DEN(f), ntRing))
648    { /* step (2); see documentation of this procedure above */
649      p = NUM(f);
650      number gcdOfCoefficients = n_Copy(p_GetCoeff(p, ntRing), ntCoeffs);
651      pIter(p);
652      while ((p != NULL) && (!n_IsOne(gcdOfCoefficients, ntCoeffs)))
653      {
654        c = p_GetCoeff(p, ntRing);
655        tmp = n_Gcd(c, gcdOfCoefficients, ntCoeffs);
656        n_Delete(&gcdOfCoefficients, ntCoeffs);
657        gcdOfCoefficients = tmp;
658        pIter(p);
659      }
660      p = DEN(f);
661      while ((p != NULL) && (!n_IsOne(gcdOfCoefficients, ntCoeffs)))
662      {
663        c = p_GetCoeff(p, ntRing);
664        tmp = n_Gcd(c, gcdOfCoefficients, ntCoeffs);
665        n_Delete(&gcdOfCoefficients, ntCoeffs);
666        gcdOfCoefficients = tmp;
667        pIter(p);
668      }
669      if (!n_IsOne(gcdOfCoefficients, ntCoeffs))
670      { /* divide NUM(f) and DEN(f) by gcdOfCoefficients */
671        number inverseOfGcdOfCoefficients = n_Invers(gcdOfCoefficients,
672                                                     ntCoeffs);
673        NUM(f) = p_Mult_nn(NUM(f), inverseOfGcdOfCoefficients, ntRing);
674        p_Normalize(NUM(f), ntRing);
675        DEN(f) = p_Mult_nn(DEN(f), inverseOfGcdOfCoefficients, ntRing);
676        p_Normalize(DEN(f), ntRing);
677        n_Delete(&inverseOfGcdOfCoefficients, ntCoeffs);
678      }
679      n_Delete(&gcdOfCoefficients, ntCoeffs);
680    }
681  }
682  if (p_IsConstant(DEN(f), ntRing) &&
683      (!n_IsOne(p_GetCoeff(DEN(f), ntRing), ntCoeffs)))
684  { /* step (3); see documentation of this procedure above */
685    number inverseOfDen = n_Invers(p_GetCoeff(DEN(f), ntRing), ntCoeffs);
686    NUM(f) = p_Mult_nn(NUM(f), inverseOfDen, ntRing);
687    n_Delete(&inverseOfDen, ntCoeffs);
688    p_Delete(&DEN(f), ntRing);
689    DEN(f) = NULL;
690  }
691 
692  /* Now, due to the above computations, DEN(f) may have become the
693     1-polynomial which needs to be represented by NULL: */
694  if ((DEN(f) != NULL) &&
695      p_IsConstant(DEN(f), ntRing) &&
696      n_IsOne(p_GetCoeff(DEN(f), ntRing), ntCoeffs))
697  {
698    p_Delete(&DEN(f), ntRing); DEN(f) = NULL;
699  }
700}
701
702/* modifies a */
703void heuristicGcdCancellation(number a, const coeffs cf)
704{
705  ntTest(a);
706  if (IS0(a)) return;
707 
708  fraction f = (fraction)a;
709  if (DENIS1(f) || NUMIS1(f)) { COM(f) = 0; return; }
710 
711  /* check whether NUM(f) = DEN(f), and - if so - replace 'a' by 1 */
712  if (p_EqualPolys(NUM(f), DEN(f), ntRing))
713  { /* numerator and denominator are both != 1 */
714    p_Delete(&NUM(f), ntRing); NUM(f) = p_ISet(1, ntRing);
715    p_Delete(&DEN(f), ntRing); DEN(f) = NULL;
716    COM(f) = 0;
717    return;
718  }
719 
720  if (COM(f) <= BOUND_COMPLEXITY) return;
721  else definiteGcdCancellation(a, cf, TRUE);
722}
723
724/* modifies a */
725void definiteGcdCancellation(number a, const coeffs cf,
726                             BOOLEAN simpleTestsHaveAlreadyBeenPerformed)
727{
728  ntTest(a);
729 
730  fraction f = (fraction)a;
731 
732  if (!simpleTestsHaveAlreadyBeenPerformed)
733  {
734    if (IS0(a)) return;
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 
747#ifdef HAVE_FACTORY 
748  /* singclap_gcd destroys its arguments; we hence need copies: */
749  poly pNum = p_Copy(NUM(f), ntRing);
750  poly pDen = p_Copy(DEN(f), ntRing);
751 
752  /* Note that, over Q, singclap_gcd will remove the denominators in all
753     rational coefficients of pNum and pDen, before starting to compute
754     the gcd. Thus, we do not need to ensure that the coefficients of
755     pNum and pDen live in Z; they may well be elements of Q\Z. */
756  poly pGcd = singclap_gcd(pNum, pDen, cf->extRing);
757  if (p_IsConstant(pGcd, ntRing) &&
758      n_IsOne(p_GetCoeff(pGcd, ntRing), ntCoeffs))
759  { /* gcd = 1; nothing to cancel;
760       Suppose the given rational function field is over Q. Although the
761       gcd is 1, we may have produced fractional coefficients in NUM(f),
762       DEN(f), or both, due to previous arithmetics. The next call will
763       remove those nested fractions, in case there are any. */
764    if (nCoeff_is_Q(ntCoeffs)) handleNestedFractionsOverQ(f, cf);
765  }
766  else
767  { /* We divide both NUM(f) and DEN(f) by the gcd which is known
768       to be != 1. */
769    poly newNum = singclap_pdivide(NUM(f), pGcd, ntRing);
770    p_Delete(&NUM(f), ntRing);
771    NUM(f) = newNum;
772    poly newDen = singclap_pdivide(DEN(f), pGcd, ntRing);
773    p_Delete(&DEN(f), ntRing);
774    DEN(f) = newDen;
775    if (p_IsConstant(DEN(f), ntRing) &&
776        n_IsOne(p_GetCoeff(DEN(f), ntRing), ntCoeffs))
777    {
778      /* DEN(f) = 1 needs to be represented by NULL! */
779      p_Delete(&DEN(f), ntRing);
780      newDen = NULL;
781    }
782    else
783    { /* Note that over Q, by cancelling the gcd, we may have produced
784         fractional coefficients in NUM(f), DEN(f), or both. The next
785         call will remove those nested fractions, in case there are
786         any. */
787      if (nCoeff_is_Q(ntCoeffs)) handleNestedFractionsOverQ(f, cf);
788    }
789  }
790  COM(f) = 0;
791  p_Delete(&pGcd, ntRing);
792#endif /* HAVE_FACTORY */
793}
794
795/* modifies a */
796void ntWrite(number &a, const coeffs cf)
797{
798  ntTest(a);
799  definiteGcdCancellation(a, cf, FALSE);
800  if (IS0(a))
801    StringAppendS("0");
802  else
803  {
804    fraction f = (fraction)a;
805    BOOLEAN useBrackets = (!p_IsConstant(NUM(f), ntRing)) ||
806                          (!n_GreaterZero(p_GetCoeff(NUM(f), ntRing),
807                                          ntCoeffs));
808    if (useBrackets) StringAppendS("(");
809    p_String0(NUM(f), ntRing, ntRing);
810    if (useBrackets) StringAppendS(")");
811    if (!DENIS1(f))
812    {
813      StringAppendS("/");
814      useBrackets = (!p_IsConstant(DEN(f), ntRing)) ||
815                    (!n_GreaterZero(p_GetCoeff(DEN(f), ntRing), ntCoeffs));
816      if (useBrackets) StringAppendS("(");
817      p_String0(DEN(f), ntRing, ntRing);
818      if (useBrackets) StringAppendS(")");
819    }
820  }
821}
822
823const char * ntRead(const char *s, number *a, const coeffs cf)
824{
825  poly p;
826  const char * result = p_Read(s, p, ntRing);
827  if (p == NULL) { *a = NULL; return result; }
828  else
829  {
830    fraction f = (fraction)omAlloc0Bin(fractionObjectBin);
831    NUM(f) = p;
832    DEN(f) = NULL;
833    COM(f) = 0;
834    *a = (number)f;
835    return result;
836  }
837}
838
839/* expects *param to be castable to TransExtInfo */
840static BOOLEAN ntCoeffIsEqual(const coeffs cf, n_coeffType n, void * param)
841{
842  if (ID != n) return FALSE;
843  TransExtInfo *e = (TransExtInfo *)param;
844  /* for rational function fields we expect the underlying
845     polynomial rings to be IDENTICAL, i.e. the SAME OBJECT;
846     this expectation is based on the assumption that we have properly
847     registered cf and perform reference counting rather than creating
848     multiple copies of the same coefficient field/domain/ring */
849  return (ntRing == e->r);
850}
851
852number ntLcm(number a, number b, const coeffs cf)
853{
854  ntTest(a); ntTest(b);
855  /* TO BE IMPLEMENTED!
856     for the time, we simply return NULL, representing the number zero */
857  Print("// TO BE IMPLEMENTED: transext.cc:ntLcm\n");
858  return NULL;
859}
860
861number ntGcd(number a, number b, const coeffs cf)
862{
863  ntTest(a); ntTest(b);
864  /* TO BE IMPLEMENTED!
865     for the time, we simply return NULL, representing the number zero */
866  Print("// TO BE IMPLEMENTED: transext.cc:ntGcd\n");
867  return NULL;
868}
869
870int ntSize(number a, const coeffs cf)
871{
872  ntTest(a);
873  if (IS0(a)) return -1;
874  /* this has been taken from the old implementation of field extensions,
875     where we computed the sum of the degrees and the numbers of terms in
876     the numerator and denominator of a; so we leave it at that, for the
877     time being */
878  fraction f = (fraction)a;
879  poly p = NUM(f);
880  int noOfTerms = 0;
881  int numDegree = 0;
882  while (p != NULL)
883  {
884    noOfTerms++;
885    int d = 0;
886    for (int i = 1; i <= rVar(ntRing); i++)
887      d += p_GetExp(p, i, ntRing);
888    if (d > numDegree) numDegree = d;
889    pIter(p);
890  }
891  int denDegree = 0;
892  if (!DENIS1(f))
893  {
894    p = DEN(f);
895    while (p != NULL)
896    {
897      noOfTerms++;
898      int d = 0;
899      for (int i = 1; i <= rVar(ntRing); i++)
900        d += p_GetExp(p, i, ntRing);
901      if (d > denDegree) denDegree = d;
902      pIter(p);
903    }
904  }
905  return numDegree + denDegree + noOfTerms;
906}
907
908number ntInvers(number a, const coeffs cf)
909{
910  ntTest(a);
911  if (IS0(a)) WerrorS(nDivBy0);
912  fraction f = (fraction)a;
913  fraction result = (fraction)omAlloc0Bin(fractionObjectBin);
914  poly g;
915  if (DENIS1(f)) g = p_One(ntRing);
916  else           g = p_Copy(DEN(f), ntRing);
917  NUM(result) = g;
918  DEN(result) = p_Copy(NUM(f), ntRing);
919  COM(result) = COM(f);
920  return (number)result;
921}
922
923/* assumes that src = Q, dst = Q(t_1, ..., t_s) */
924number ntMap00(number a, const coeffs src, const coeffs dst)
925{
926  if (n_IsZero(a, src)) return NULL;
927  assume(src == dst->extRing->cf);
928  poly p = p_One(dst->extRing);
929  p_SetCoeff(p, ntCopy(a, src), dst->extRing);
930  fraction f = (fraction)omAlloc0Bin(fractionObjectBin);
931  NUM(f) = p; DEN(f) = NULL; COM(f) = 0;
932  return (number)f;
933}
934
935/* assumes that src = Z/p, dst = Q(t_1, ..., t_s) */
936number ntMapP0(number a, const coeffs src, const coeffs dst)
937{
938  if (n_IsZero(a, src)) return NULL;
939  /* mapping via intermediate int: */
940  int n = n_Int(a, src);
941  number q = n_Init(n, dst->extRing->cf);
942  poly p;
943  if (n_IsZero(q, dst->extRing->cf))
944  {
945    n_Delete(&q, dst->extRing->cf);
946    return NULL;
947  }
948  p = p_One(dst->extRing);
949  p_SetCoeff(p, q, dst->extRing);
950  fraction f = (fraction)omAlloc0Bin(fractionObjectBin);
951  NUM(f) = p; DEN(f) = NULL; COM(f) = 0;
952  return (number)f;
953}
954
955/* assumes that either src = Q(t_1, ..., t_s), dst = Q(t_1, ..., t_s), or
956                       src = Z/p(t_1, ..., t_s), dst = Z/p(t_1, ..., t_s) */
957number ntCopyMap(number a, const coeffs src, const coeffs dst)
958{
959  return ntCopy(a, dst);
960}
961
962/* assumes that src = Q, dst = Z/p(t_1, ..., t_s) */
963number ntMap0P(number a, const coeffs src, const coeffs dst)
964{
965  if (n_IsZero(a, src)) return NULL;
966  int p = rChar(dst->extRing);
967  int n = nlModP(a, p, src);
968  number q = n_Init(n, dst->extRing->cf);
969  poly g;
970  if (n_IsZero(q, dst->extRing->cf))
971  {
972    n_Delete(&q, dst->extRing->cf);
973    return NULL;
974  }
975  g = p_One(dst->extRing);
976  p_SetCoeff(g, q, dst->extRing);
977  fraction f = (fraction)omAlloc0Bin(fractionObjectBin);
978  NUM(f) = g; DEN(f) = NULL; COM(f) = 0;
979  return (number)f;
980}
981
982/* assumes that src = Z/p, dst = Z/p(t_1, ..., t_s) */
983number ntMapPP(number a, const coeffs src, const coeffs dst)
984{
985  if (n_IsZero(a, src)) return NULL;
986  assume(src == dst->extRing->cf);
987  poly p = p_One(dst->extRing);
988  p_SetCoeff(p, ntCopy(a, src), dst->extRing);
989  fraction f = (fraction)omAlloc0Bin(fractionObjectBin);
990  NUM(f) = p; DEN(f) = NULL; COM(f) = 0;
991  return (number)f;
992}
993
994/* assumes that src = Z/u, dst = Z/p(t_1, ..., t_s), where u != p */
995number ntMapUP(number a, const coeffs src, const coeffs dst)
996{
997  if (n_IsZero(a, src)) return NULL;
998  /* mapping via intermediate int: */
999  int n = n_Int(a, src);
1000  number q = n_Init(n, dst->extRing->cf);
1001  poly p;
1002  if (n_IsZero(q, dst->extRing->cf))
1003  {
1004    n_Delete(&q, dst->extRing->cf);
1005    return NULL;
1006  }
1007  p = p_One(dst->extRing);
1008  p_SetCoeff(p, q, dst->extRing);
1009  fraction f = (fraction)omAlloc0Bin(fractionObjectBin);
1010  NUM(f) = p; DEN(f) = NULL; COM(f) = 0;
1011  return (number)f;
1012}
1013
1014nMapFunc ntSetMap(const coeffs src, const coeffs dst)
1015{
1016  /* dst is expected to be a rational function field */
1017  assume(getCoeffType(dst) == ID);
1018 
1019  int h = 0; /* the height of the extension tower given by dst */
1020  coeffs bDst = nCoeff_bottom(dst, h); /* the bottom field in the tower dst */
1021 
1022  /* for the time being, we only provide maps if h = 1 and if b is Q or
1023     some field Z/pZ: */
1024  if (h != 1) return NULL;
1025  if ((!nCoeff_is_Zp(bDst)) && (!nCoeff_is_Q(bDst))) return NULL;
1026 
1027  /* Let T denote the sequence of transcendental extension variables, i.e.,
1028     K[t_1, ..., t_s] =: K[T];
1029     Let moreover, for any such sequence T, T' denote any subsequence of T
1030     of the form t_1, ..., t_w with w <= s. */
1031 
1032  if (nCoeff_is_Q(src) && nCoeff_is_Q(bDst))
1033    return ntMap00;                                      /// Q       -->  Q(T)
1034 
1035  if (nCoeff_is_Zp(src) && nCoeff_is_Q(bDst))
1036    return ntMapP0;                                      /// Z/p     -->  Q(T)
1037 
1038  if (nCoeff_is_Q(src) && nCoeff_is_Zp(bDst))
1039    return ntMap0P;                                      /// Q       --> Z/p(T)
1040 
1041  if (nCoeff_is_Zp(src) && nCoeff_is_Zp(bDst))
1042  {
1043    if (src->ch == dst->ch) return ntMapPP;              /// Z/p     --> Z/p(T)
1044    else return ntMapUP;                                 /// Z/u     --> Z/p(T)
1045  }
1046 
1047  coeffs bSrc = nCoeff_bottom(src, h); /* the bottom field in the tower src */
1048  if (h != 1) return NULL;
1049  if ((!nCoeff_is_Zp(bSrc)) && (!nCoeff_is_Q(bSrc))) return NULL;
1050 
1051  if (nCoeff_is_Q(bSrc) && nCoeff_is_Q(bDst))
1052  {
1053    if (rVar(src->extRing) > rVar(dst->extRing)) return NULL;
1054    for (int i = 0; i < rVar(src->extRing); i++)
1055      if (strcmp(rRingVar(i, src->extRing),
1056                 rRingVar(i, dst->extRing)) != 0) return NULL;
1057      return ntCopyMap;                                  /// Q(T')   --> Q(T)
1058  }
1059 
1060  if (nCoeff_is_Zp(bSrc) && nCoeff_is_Zp(bDst))
1061  {
1062    if (rVar(src->extRing) > rVar(dst->extRing)) return NULL;
1063    for (int i = 0; i < rVar(src->extRing); i++)
1064      if (strcmp(rRingVar(i, src->extRing),
1065                 rRingVar(i, dst->extRing)) != 0) return NULL;
1066      return ntCopyMap;                                  /// Z/p(T') --> Z/p(T)
1067  }
1068 
1069  return NULL;                                           /// default
1070}
1071
1072BOOLEAN ntInitChar(coeffs cf, void * infoStruct)
1073{ 
1074  TransExtInfo *e = (TransExtInfo *)infoStruct;
1075  /// first check whether cf->extRing != NULL and delete old ring???
1076  cf->extRing           = e->r;
1077  cf->extRing->minideal = NULL;
1078
1079  assume(cf->extRing                != NULL);      // extRing;
1080  assume(cf->extRing->cf            != NULL);      // extRing->cf;
1081  assume(getCoeffType(cf) == ID);                // coeff type;
1082 
1083  /* propagate characteristic up so that it becomes
1084     directly accessible in cf: */
1085  cf->ch = cf->extRing->cf->ch;
1086 
1087  cf->cfGreaterZero  = ntGreaterZero;
1088  cf->cfGreater      = ntGreater;
1089  cf->cfEqual        = ntEqual;
1090  cf->cfIsZero       = ntIsZero;
1091  cf->cfIsOne        = ntIsOne;
1092  cf->cfIsMOne       = ntIsMOne;
1093  cf->cfInit         = ntInit;
1094  cf->cfInt          = ntInt;
1095  cf->cfNeg          = ntNeg;
1096  cf->cfAdd          = ntAdd;
1097  cf->cfSub          = ntSub;
1098  cf->cfMult         = ntMult;
1099  cf->cfDiv          = ntDiv;
1100  cf->cfExactDiv     = ntDiv;
1101  cf->cfPower        = ntPower;
1102  cf->cfCopy         = ntCopy;
1103  cf->cfWrite        = ntWrite;
1104  cf->cfRead         = ntRead;
1105  cf->cfDelete       = ntDelete;
1106  cf->cfSetMap       = ntSetMap;
1107  cf->cfGetDenom     = ntGetDenom;
1108  cf->cfGetNumerator = ntGetNumerator;
1109  cf->cfRePart       = ntCopy;
1110  cf->cfImPart       = ntImPart;
1111  cf->cfCoeffWrite   = ntCoeffWrite;
1112  cf->cfDBTest       = ntDBTest;
1113  cf->cfGcd          = ntGcd;
1114  cf->cfLcm          = ntLcm;
1115  cf->cfSize         = ntSize;
1116  cf->nCoeffIsEqual  = ntCoeffIsEqual;
1117  cf->cfInvers       = ntInvers;
1118  cf->cfIntDiv       = ntDiv;
1119 
1120#ifndef HAVE_FACTORY
1121  PrintS("// Warning: The 'factory' module is not available.\n");
1122  PrintS("//          Hence gcd's cannot be cancelled in any\n");
1123  PrintS("//          computed fraction!\n");
1124#endif
1125 
1126  return FALSE;
1127}
1128
1129
1130number ntParam(const short iParameter, const coeffs cf)
1131{
1132  assume(getCoeffType(cf) == ID);
1133
1134  const ring R = cf->extRing;
1135  assume( R != NULL ); 
1136  assume( 0 < iParameter && iParameter <= rVar(R) );
1137
1138  poly p = p_One(R); p_SetExp(p, iParameter, 1, R); p_Setm(p, R);
1139
1140//  return (number) p;
1141
1142  fraction f = (fraction)omAlloc0Bin(fractionObjectBin);
1143  NUM(f) = p;
1144  DEN(f) = NULL;
1145  COM(f) = 0;
1146
1147  return (number)f;
1148}
1149
1150
1151/// if m == var(i)/1 => return i,
1152int ntIsParam(number m, const coeffs cf)
1153{
1154  assume(getCoeffType(cf) == ID);
1155
1156  const ring R = cf->extRing;
1157  assume( R != NULL );
1158
1159  fraction f = (fraction)m;
1160
1161  if( DEN(f) != NULL )
1162    return 0;
1163
1164  return p_Var( NUM(f), R ); 
1165}
Note: See TracBrowser for help on using the repository browser.