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

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