source: git/libpolys/polys/ext_fields/algext.cc @ 0fb5991

fieker-DuValspielwiese
Last change on this file since 0fb5991 was 0fb5991, checked in by Frank Seelisch <seelisch@…>, 13 years ago
fixes so that libpoly builds without compiler errors in algext.cc (make check may be broken)
  • Property mode set to 100644
File size: 17.9 KB
Line 
1/****************************************
2*  Computer Algebra System SINGULAR     *
3****************************************/
4/* $Id$ */
5/*
6* ABSTRACT: numbers in an algebraic extension field K(a)
7*           Assuming that we have a coeffs object cf, then these numbers
8*           are polynomials in the polynomial ring K[a] represented by
9*           cf->algring.
10*           IMPORTANT ASSUMPTIONS:
11*           1.) So far we assume that cf->algring is a valid polynomial
12*               ring in exactly one variable, i.e., K[a], where K is allowed
13*               to be any field (representable in SINGULAR and which may
14*               itself be some extension field, thus allowing for extension
15*               towers).
16*           2.) Moreover, this implementation assumes that
17*               cf->algring->minideal is not NULL but an ideal with at
18*               least one non-zero generator which may be accessed by
19*               cf->algring->minideal->m[0] and which represents the minimal
20*               polynomial of the extension variable 'a' in K[a].
21*/
22
23#include "config.h"
24#include <misc/auxiliary.h>
25
26#include <omalloc/omalloc.h>
27
28#include <reporter/reporter.h>
29
30#include <coeffs/coeffs.h>
31#include <coeffs/numbers.h>
32#include <coeffs/longrat.h>
33
34#include <polys/monomials/ring.h>
35#include <polys/monomials/p_polys.h>
36#include <polys/simpleideals.h>
37
38#include <polys/ext_fields/algext.h>
39
40/// forward declarations
41BOOLEAN  naGreaterZero(number a, const coeffs cf); 
42BOOLEAN  naGreater(number a, number b, const coeffs cf);
43BOOLEAN  naEqual(number a, number b, const coeffs cf);
44BOOLEAN  naIsOne(number a, const coeffs cf);
45BOOLEAN  naIsMOne(number a, const coeffs cf);
46BOOLEAN  naIsZero(number a, const coeffs cf);
47number   naInit(int i, const coeffs cf);
48int      naInt(number &a, const coeffs cf);
49number   naNeg(number a, const coeffs cf);
50number   naInvers(number a, const coeffs cf);
51number   naPar(int i, const coeffs cf);
52number   naAdd(number a, number b, const coeffs cf);
53number   naSub(number a, number b, const coeffs cf);
54number   naMult(number a, number b, const coeffs cf);
55number   naDiv(number a, number b, const coeffs cf);
56void     naPower(number a, int exp, number *b, const coeffs cf);
57number   naCopy(number a, const coeffs cf);
58void     naWrite(number &a, const coeffs cf);
59number   naRePart(number a, const coeffs cf);
60number   naImPart(number a, const coeffs cf);
61number   naGetDenom(number &a, const coeffs cf);
62number   naGetNumerator(number &a, const coeffs cf);
63number   naGcd(number a, number b, const coeffs cf);
64number   naLcm(number a, number b, const coeffs cf);
65int      naSize(number a, const coeffs cf);
66void     naDelete(number *a, const coeffs cf);
67void     naCoeffWrite(const coeffs cf);
68number   naIntDiv(number a, number b, const coeffs cf);
69const char * naRead(const char *s, number *a, const coeffs cf);
70static BOOLEAN naCoeffIsEqual(const coeffs cf, n_coeffType n, void * param);
71
72#ifdef LDEBUG
73BOOLEAN naDBTest(number a, const char *f, const int l, const coeffs cf)
74{
75  assume(getCoeffType(cf) == naID);
76  #ifdef LDEBUG
77  omCheckAddr(&a);
78  #endif
79  assume(p_Deg((poly)a, naRing) <= p_Deg(naMinpoly, naRing));
80  return TRUE;
81}
82#endif
83
84void heuristicReduce(poly p, poly reducer, const coeffs cf);
85void definiteReduce(poly p, poly reducer, const coeffs cf);
86
87BOOLEAN naIsZero(number a, const coeffs cf)
88{
89  naTest(a);
90  return (a == NULL);
91}
92
93void naDelete(number *a, const coeffs cf)
94{
95  if (a == NULL) return;
96  p_Delete((poly *)a, naRing);
97  *a = NULL;
98}
99
100BOOLEAN naEqual (number a, number b, const coeffs cf)
101{
102  naTest(a); naTest(b);
103 
104  /// simple tests
105  if (a == b) return TRUE;
106  if ((a == NULL) && (b != NULL)) return FALSE;
107  if ((b == NULL) && (a != NULL)) return FALSE;
108
109  /// deg test
110  int aDeg = 0;
111  if (a != NULL) aDeg = p_Deg((poly)a, naRing);
112  int bDeg = 0;
113  if (b != NULL) bDeg = p_Deg((poly)b, naRing);
114  if (aDeg != bDeg) return FALSE;
115 
116  /// subtraction test
117  number c = naSub(a, b, cf);
118  BOOLEAN result = naIsZero(c, cf);
119  naDelete(&c, naCoeffs);
120  return result;
121}
122
123number naCopy(number a, const coeffs cf)
124{
125  naTest(a);
126  if (a == NULL) return NULL;
127  return (number)p_Copy((poly)a, naRing);
128}
129
130number naGetNumerator(number &a, const coeffs cf)
131{
132  return naCopy(a, cf);
133}
134
135number naGetDenom(number &a, const coeffs cf)
136{
137  naTest(a);
138  return naInit(1, cf);
139}
140
141BOOLEAN naIsOne(number a, const coeffs cf)
142{
143  naTest(a);
144  if (p_GetExp((poly)a, 1, naRing) != 0) return FALSE;
145  return n_IsOne(p_GetCoeff((poly)a, naRing), naCoeffs);
146}
147
148BOOLEAN naIsMOne(number a, const coeffs cf)
149{
150  naTest(a);
151  if (p_GetExp((poly)a, 1, naRing) != 0) return FALSE;
152  return n_IsMOne(p_GetCoeff((poly)a, naRing), naCoeffs);
153}
154
155/// this is in-place, modifies a
156number naNeg(number a, const coeffs cf)
157{
158  naTest(a);
159  if (a != NULL) a = (number)p_Neg((poly)a, naRing);
160  return a;
161}
162
163number naImPart(number a, const coeffs cf)
164{
165  naTest(a);
166  return NULL;
167}
168
169number naInit(int i, const coeffs cf)
170{
171  if (i == 0) return NULL;
172  else        return (number)p_ISet(i, naRing);
173}
174
175int naInt(number &a, const coeffs cf)
176{
177  naTest(a);
178  if (p_GetExp((poly)a, 1, naRing) != 0) return 0;
179  return n_Int(p_GetCoeff((poly)a, naRing), naCoeffs);
180}
181
182/* TRUE iff (a != 0 and (b == 0 or deg(a) > deg(b))) */
183BOOLEAN naGreater(number a, number b, const coeffs cf)
184{
185  if (naIsZero(a, cf)) return FALSE;
186  if (naIsZero(b, cf)) return TRUE;
187  int aDeg = 0;
188  if (a != NULL) aDeg = p_Deg((poly)a, naRing);
189  int bDeg = 0;
190  if (b != NULL) bDeg = p_Deg((poly)b, naRing);
191  return (aDeg > bDeg);
192}
193
194/* TRUE iff a != 0 and (LC(a) > 0 or deg(a) > 0) */
195BOOLEAN naGreaterZero(number a, const coeffs cf)
196{
197  naTest(a);
198  if (a == NULL)                                            return FALSE;
199  if (n_GreaterZero(p_GetCoeff((poly)a, naRing), naCoeffs)) return TRUE;
200  if (p_Deg((poly)a, naRing) > 0)                           return TRUE;
201  return FALSE;
202}
203
204void naCoeffWrite(const coeffs cf)
205{
206  char *x = rRingVar(0, naRing);
207  Print("//   Coefficients live in the extension field K[%s]/<f(%s)>\n", x, x);
208  Print("//   with the minimal polynomial f(%s) = %s\n", x,
209        p_String(naMinpoly, naRing));
210  PrintS("//   and K: "); n_CoeffWrite(cf->algring->cf);
211}
212
213number naPar(int i, const coeffs cf)
214{
215  assume(i == 1);   // there is only one parameter in this extension field
216  poly p = p_ISet(1, naRing);   // p = 1
217  p_SetExp(p, 1, 1, naRing);    // p = the sole extension variable
218  p_Setm(p, naRing);
219  return (number)p;
220}
221
222number naAdd(number a, number b, const coeffs cf)
223{
224  naTest(a); naTest(b);
225  if (a == NULL) return naCopy(b, cf);
226  if (b == NULL) return naCopy(a, cf);
227  poly aPlusB = p_Add_q(p_Copy((poly)a, naRing),
228                        p_Copy((poly)b, naRing), naRing);
229  definiteReduce(aPlusB, naMinpoly, cf);
230  return (number)aPlusB;
231}
232
233number naSub(number a, number b, const coeffs cf)
234{
235  naTest(a); naTest(b);
236  if (b == NULL) return naCopy(a, cf);
237  poly minusB = p_Neg(p_Copy((poly)b, naRing), naRing);
238  if (a == NULL) return (number)minusB;
239  poly aMinusB = p_Add_q(p_Copy((poly)a, naRing), minusB, naRing);
240  definiteReduce(aMinusB, naMinpoly, cf);
241  return (number)aMinusB;
242}
243
244number naMult(number a, number b, const coeffs cf)
245{
246  naTest(a); naTest(b);
247  if (a == NULL) return NULL;
248  if (b == NULL) return NULL;
249  poly aTimesB = p_Mult_q(p_Copy((poly)a, naRing),
250                          p_Copy((poly)b, naRing), naRing);
251  definiteReduce(aTimesB, naMinpoly, cf);
252  return (number)aTimesB;
253}
254
255number naDiv(number a, number b, const coeffs cf)
256{
257  naTest(a); naTest(b);
258  if (b == NULL) WerrorS(nDivBy0);
259  if (a == NULL) return NULL;
260  poly bInverse = (poly)naInvers(b, cf);
261  poly aDivB = p_Mult_q(p_Copy((poly)a, naRing), bInverse, naRing);
262  definiteReduce(aDivB, naMinpoly, cf);
263  return (number)aDivB;
264}
265
266/* 0^0 = 0;
267   for |exp| <= 7 compute power by a simple multiplication loop;
268   for |exp| >= 8 compute power along binary presentation of |exp|, e.g.
269      p^13 = p^1 * p^4 * p^8, where we utilise that
270      p^(2^(k+1)) = p^(2^k) * p^(2^k)
271   intermediate reduction modulo the minimal polynomial is controlled by
272   the in-place method heuristicReduce(poly, poly, coeffs); see there.
273*/
274void naPower(number a, int exp, number *b, const coeffs cf)
275{
276  naTest(a);
277 
278  /* special cases first */
279  if (a == NULL)
280  {
281    if (exp >= 0) *b = NULL;
282    else          WerrorS(nDivBy0);
283  }
284  else if (exp ==  0) *b = naInit(1, cf);
285  else if (exp ==  1) *b = naCopy(a, cf);
286  else if (exp == -1) *b = naInvers(a, cf);
287 
288  int expAbs = exp; if (expAbs < 0) expAbs = -expAbs;
289 
290  /* now compute 'a' to the 'expAbs'-th power */
291  poly pow; poly aAsPoly = (poly)a;
292  if (expAbs <= 7)
293  {
294    pow = p_Copy(aAsPoly, naRing);
295    for (int i = 2; i <= expAbs; i++)
296    {
297      pow = p_Mult_q(pow, p_Copy(aAsPoly, naRing), naRing);
298      heuristicReduce(pow, naMinpoly, cf);
299    }
300    definiteReduce(pow, naMinpoly, cf);
301  }
302  else
303  {
304    pow = p_ISet(1, naRing);
305    poly factor = p_Copy(aAsPoly, naRing);
306    while (expAbs != 0)
307    {
308      if (expAbs & 1)
309      {
310        pow = p_Mult_q(pow, p_Copy(factor, naRing), naRing);
311        heuristicReduce(pow, naMinpoly, cf);
312      }
313      expAbs = expAbs / 2;
314      if (expAbs != 0)
315      {
316        factor = p_Mult_q(factor, factor, naRing);
317        heuristicReduce(factor, naMinpoly, cf);
318      }
319    }
320    p_Delete(&factor, naRing);
321    definiteReduce(pow, naMinpoly, cf);
322  }
323 
324  /* invert if original exponent was negative */
325  number n = (number)pow;
326  if (exp < 0)
327  {
328    number m = naInvers(n, cf);
329    naDelete(&n, cf);
330    n = m;
331  }
332  *b = n;
333}
334
335/* may reduce p module the reducer by calling definiteReduce;
336   the decision is made based on the following heuristic
337   (which should also only be changed here in this method):
338      if (deg(p) > 10*deg(reducer) then perform reduction */
339void heuristicReduce(poly p, poly reducer, const coeffs cf)
340{
341  #ifdef LDEBUG
342  omCheckAddr(p); omCheckAddr(reducer);
343  #endif
344  if (p_Deg(p, naRing) > 10 * p_Deg(reducer, naRing))
345    definiteReduce(p, reducer, cf);
346}
347
348void naWrite(number &a, const coeffs cf)
349{
350  naTest(a);
351  if (a == NULL)
352    StringAppendS("0");
353  else
354  {
355    poly aAsPoly = (poly)a;
356    /* basically, just write aAsPoly using p_Write,
357       but use brackets around the output, if a is not
358       a constant living in naCoeffs = cf->algring->cf */
359    BOOLEAN useBrackets = TRUE;
360    if (p_Deg(aAsPoly, naRing) == 0) useBrackets = FALSE;
361    if (useBrackets) StringAppendS("(");
362    p_Write(aAsPoly, naRing);
363    if (useBrackets) StringAppendS(")");
364  }
365}
366
367const char * naRead(const char *s, number *a, const coeffs cf)
368{
369  poly aAsPoly;
370  const char * result = p_Read(s, aAsPoly, naRing);
371  *a = (number)aAsPoly;
372  return result;
373}
374
375/* implemented by the rule lcm(a, b) = a * b / gcd(a, b) */
376number naLcm(number a, number b, const coeffs cf)
377{
378  naTest(a); naTest(b);
379  if (a == NULL) return NULL;
380  if (b == NULL) return NULL;
381  number theProduct = (number)p_Mult_q(p_Copy((poly)a, naRing),
382                                       p_Copy((poly)b, naRing), naRing);
383  /* note that theProduct needs not be reduced w.r.t. naMinpoly;
384     but the final division will take care of the necessary reduction */
385  number theGcd = naGcd(a, b, cf);
386  return naDiv(theProduct, theGcd, cf);
387}
388
389/* expects *param to be castable to ExtInfo */
390static BOOLEAN naCoeffIsEqual(const coeffs cf, n_coeffType n, void * param)
391{
392  if (naID != n) return FALSE;
393  ExtInfo *e = (ExtInfo *)param;
394  /* for extension coefficient fields we expect the underlying
395     polynomials rings to be IDENTICAL, i.e. the SAME OBJECT;
396     this expectation is based on the assumption that we have properly
397     registered cf and perform reference counting rather than creating
398     multiple copies of the same coefficient field/domain/ring */
399  return (naRing == e->r);
400  /* (Note that then also the minimal ideals will necessarily be
401     the same, as they are attached to the ring.) */
402}
403
404int naSize(number a, const coeffs cf)
405{
406  if (a == NULL) return -1;
407  /* this has been taken from the old implementation of field extensions,
408     where we computed the sum of the degree and the number of terms in
409     (poly)a; so we leave it at that, for the time being;
410     maybe, the number of terms alone is a better measure? */
411  poly aAsPoly = (poly)a;
412  int theDegree = 0; int noOfTerms = 0;
413  while (aAsPoly != NULL)
414  {
415    noOfTerms++;
416    int d = 0;
417    for (int i = 1; i <= rVar(naRing); i++)
418      d += p_GetExp(aAsPoly, i, naRing);
419    if (d > theDegree) theDegree = d;
420    pIter(aAsPoly);
421  }
422  return theDegree + noOfTerms;
423}
424
425/* performs polynomial division and overrides p by the remainder
426   of division of p by the reducer */
427void definiteReduce(poly p, poly reducer, const coeffs cf)
428{
429  #ifdef LDEBUG
430  omCheckAddr(p); omCheckAddr(reducer);
431  #endif
432  p_PolyDiv(&p, reducer, FALSE, naRing);
433}
434
435number naGcd(number a, number b, const coeffs cf)
436{
437  naTest(a); naTest(b);
438  if ((a == NULL) && (b == NULL)) WerrorS(nDivBy0);
439  return (number)p_Gcd((poly)a, (poly)b, naRing);
440}
441
442number naInvers(number a, const coeffs cf)
443{
444  naTest(a);
445  if (a == NULL) WerrorS(nDivBy0);
446  poly *aFactor; poly *mFactor;
447  poly theGcd = p_ExtGcd((poly)a, aFactor, naMinpoly, mFactor, naRing);
448  /* the gcd must be one since naMinpoly is irreducible and a != NULL: */
449  assume(naIsOne((number)theGcd, cf));     
450  p_Delete(&theGcd, naRing);
451  p_Delete(mFactor, naRing);
452  return (number)(*aFactor);
453}
454
455/* assumes that src = Q, dst = Q(a) */
456number naMap00(number a, const coeffs src, const coeffs dst)
457{
458  assume(src == dst->algring->cf);
459  poly result = p_One(dst->algring);
460  p_SetCoeff(result, naCopy(a, src), dst->algring);
461  return (number)result;
462}
463
464/* assumes that src = Z/p, dst = Q(a) */
465number naMapP0(number a, const coeffs src, const coeffs dst)
466{
467  /* mapping via intermediate int: */
468  int n = n_Int(a, src);
469  number q = n_Init(n, dst->algring->cf);
470  poly result = p_One(dst->algring);
471  p_SetCoeff(result, q, dst->algring);
472  return (number)result;
473}
474
475/* assumes that either src = Q(a), dst = Q(a), or
476                       src = Zp(a), dst = Zp(a)     */
477number naCopyMap(number a, const coeffs src, const coeffs dst)
478{
479  return naCopy(a, dst);
480}
481
482/* assumes that src = Q, dst = Z/p(a) */
483number naMap0P(number a, const coeffs src, const coeffs dst)
484{
485  int p = rChar(dst->algring);
486  int n = nlModP(a, p, src);
487  number q = n_Init(n, dst->algring->cf);
488  poly result = p_One(dst->algring);
489  p_SetCoeff(result, q, dst->algring);
490  return (number)result;
491}
492
493/* assumes that src = Z/p, dst = Z/p(a) */
494number naMapPP(number a, const coeffs src, const coeffs dst)
495{
496  assume(src == dst->algring->cf);
497  poly result = p_One(dst->algring);
498  p_SetCoeff(result, naCopy(a, src), dst->algring);
499  return (number)result;
500}
501
502/* assumes that src = Z/u, dst = Z/p(a), where u != p */
503number naMapUP(number a, const coeffs src, const coeffs dst)
504{
505  /* mapping via intermediate int: */
506  int n = n_Int(a, src);
507  number q = n_Init(n, dst->algring->cf);
508  poly result = p_One(dst->algring);
509  p_SetCoeff(result, q, dst->algring);
510  return (number)result;
511}
512
513nMapFunc naSetMap(const ring src, const ring dst)
514{
515  /* dst->cf is expected to be an (algebraic) extension field */
516  assume(dst->cf->type == n_Ext);
517 
518  if (rField_is_Q(src) && rField_is_Q_a(dst))
519    return naMap00;                                      /// Q     -->  Q(a)
520 
521  if (rField_is_Zp(src) && rField_is_Q_a(dst))
522    return naMapP0;                                      /// Z/p   -->  Q(a)
523 
524  if (rField_is_Q_a(src) && rField_is_Q_a(dst))
525  {
526    if (strcmp(rParameter(src)[0], rParameter(dst)[0]) == 0)
527      return naCopyMap;                                  /// Q(a)   --> Q(a)
528    else
529      return NULL;                                       /// Q(b)   --> Q(a)
530  }
531 
532  if (rField_is_Q(src) && rField_is_Zp_a(dst))
533    return naMap0P;                                      /// Q      --> Z/p(a)
534 
535  if (rField_is_Zp(src) && rField_is_Zp_a(dst))
536  {
537    if (rChar(src) == rChar(dst)) return naMapPP;        /// Z/p    --> Z/p(a)
538    else return naMapUP;                                 /// Z/u    --> Z/p(a)
539  }
540 
541  if (rField_is_Zp_a(src) && rField_is_Zp_a(dst))
542  {
543    if (strcmp(rParameter(src)[0], rParameter(dst)[0]) == 0)
544      return naCopyMap;                                  /// Z/p(a) --> Z/p(a)
545    else
546      return NULL;                                       /// Z/p(b) --> Z/p(a)
547  }
548 
549  return NULL;                                           /// default
550}
551
552BOOLEAN naInitChar(coeffs cf, void * infoStruct)
553{
554  ExtInfo *e = (ExtInfo *)infoStruct;
555  /// first check whether cf->algring != NULL and delete old ring???
556  cf->algring           = e->r;
557  cf->algring->minideal = e->i;
558
559  assume(cf->algring                     != NULL);      // algring;
560  assume((cf->algring->minideal          != NULL) &&    // minideal has one
561         (IDELEMS(cf->algring->minideal) != 0)    &&    // non-zero generator
562         (cf->algring->minideal->m[0]    != NULL)    ); // at m[0];
563  assume(cf->algring->cf                 != NULL);      // algring->cf;
564  assume(getCoeffType(cf) == naID);                     // coeff type;
565 
566  #ifdef LDEBUG
567  omCheckAddr(naMinpoly);
568  #endif
569 
570  cf->cfGreaterZero  = naGreaterZero;
571  cf->cfGreater      = naGreater;
572  cf->cfEqual        = naEqual;
573  cf->cfIsZero       = naIsZero;
574  cf->cfIsOne        = naIsOne;
575  cf->cfIsMOne       = naIsMOne;
576  cf->cfInit         = naInit;
577  cf->cfInt          = naInt;
578  cf->cfNeg          = naNeg;
579  cf->cfPar          = naPar;
580  cf->cfAdd          = naAdd;
581  cf->cfSub          = naSub;
582  cf->cfMult         = naMult;
583  cf->cfDiv          = naDiv;
584  cf->cfExactDiv     = naDiv;
585  cf->cfPower        = naPower;
586  cf->cfCopy         = naCopy;
587  cf->cfWrite        = naWrite;
588  cf->cfRead         = naRead;
589  cf->cfDelete       = naDelete;
590  cf->cfSetMap       = naSetMap;
591  cf->cfGetDenom     = naGetDenom;
592  cf->cfGetNumerator = naGetNumerator;
593  cf->cfRePart       = naCopy;
594  cf->cfImPart       = naImPart;
595  cf->cfCoeffWrite   = naCoeffWrite;
596  cf->cfDBTest       = naDBTest;
597  cf->cfGcd          = naGcd;
598  cf->cfLcm          = naLcm;
599  cf->cfSize         = naSize;
600  cf->nCoeffIsEqual  = naCoeffIsEqual;
601  cf->cfInvers       = naInvers;
602  cf->cfIntDiv       = naDiv;
603 
604  return FALSE;
605}
Note: See TracBrowser for help on using the repository browser.