source: git/libpolys/polys/ext_fields/transext.cc @ 6637ee

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