source: git/libpolys/polys/ext_fields/algext.cc @ cdf22a9

fieker-DuValspielwiese
Last change on this file since cdf22a9 was cdf22a9, checked in by Frank Seelisch <seelisch@…>, 13 years ago
using negative chars: needs to be discussed
  • Property mode set to 100644
File size: 19.1 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  if (a == NULL) return TRUE;
77  p_Test((poly)a, naRing);
78  assume(p_Deg((poly)a, naRing) <= p_Deg(naMinpoly, naRing));
79  return TRUE;
80}
81#endif
82
83void heuristicReduce(poly &p, poly reducer, const coeffs cf);
84void definiteReduce(poly &p, poly reducer, const coeffs cf);
85
86BOOLEAN naIsZero(number a, const coeffs cf)
87{
88  naTest(a);
89  return (a == NULL);
90}
91
92void naDelete(number * a, const coeffs cf)
93{
94  if (*a == NULL) return;
95  poly aAsPoly = (poly)(*a);
96  p_Delete(&aAsPoly, 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;
339   modifies p */
340void heuristicReduce(poly &p, poly reducer, const coeffs cf)
341{
342  #ifdef LDEBUG
343  p_Test((poly)p, naRing);
344  p_Test((poly)reducer, naRing);
345  #endif
346  if (p_Deg(p, naRing) > 10 * p_Deg(reducer, naRing))
347    definiteReduce(p, reducer, cf);
348}
349
350void naWrite(number &a, const coeffs cf)
351{
352  naTest(a);
353  if (a == NULL)
354    StringAppendS("0");
355  else
356  {
357    poly aAsPoly = (poly)a;
358    /* basically, just write aAsPoly using p_Write,
359       but use brackets around the output, if a is not
360       a constant living in naCoeffs = cf->algring->cf */
361    BOOLEAN useBrackets = !(p_IsConstant(aAsPoly, naRing));
362    if (useBrackets) StringAppendS("(");
363    p_String0(aAsPoly, naRing, naRing);
364    if (useBrackets) StringAppendS(")");
365  }
366}
367
368const char * naRead(const char *s, number *a, const coeffs cf)
369{
370  poly aAsPoly;
371  const char * result = p_Read(s, aAsPoly, naRing);
372  *a = (number)aAsPoly;
373  return result;
374}
375
376/* implemented by the rule lcm(a, b) = a * b / gcd(a, b) */
377number naLcm(number a, number b, const coeffs cf)
378{
379  naTest(a); naTest(b);
380  if (a == NULL) return NULL;
381  if (b == NULL) return NULL;
382  number theProduct = (number)p_Mult_q(p_Copy((poly)a, naRing),
383                                       p_Copy((poly)b, naRing), naRing);
384  /* note that theProduct needs not be reduced w.r.t. naMinpoly;
385     but the final division will take care of the necessary reduction */
386  number theGcd = naGcd(a, b, cf);
387  return naDiv(theProduct, theGcd, cf);
388}
389
390/* expects *param to be castable to ExtInfo */
391static BOOLEAN naCoeffIsEqual(const coeffs cf, n_coeffType n, void * param)
392{
393  if (naID != n) return FALSE;
394  ExtInfo *e = (ExtInfo *)param;
395  /* for extension coefficient fields we expect the underlying
396     polynomials rings to be IDENTICAL, i.e. the SAME OBJECT;
397     this expectation is based on the assumption that we have properly
398     registered cf and perform reference counting rather than creating
399     multiple copies of the same coefficient field/domain/ring */
400  return (naRing == e->r);
401  /* (Note that then also the minimal ideals will necessarily be
402     the same, as they are attached to the ring.) */
403}
404
405int naSize(number a, const coeffs cf)
406{
407  if (a == NULL) return -1;
408  /* this has been taken from the old implementation of field extensions,
409     where we computed the sum of the degree and the number of terms in
410     (poly)a; so we leave it at that, for the time being;
411     maybe, the number of terms alone is a better measure? */
412  poly aAsPoly = (poly)a;
413  int theDegree = 0; int noOfTerms = 0;
414  while (aAsPoly != NULL)
415  {
416    noOfTerms++;
417    int d = 0;
418    for (int i = 1; i <= rVar(naRing); i++)
419      d += p_GetExp(aAsPoly, i, naRing);
420    if (d > theDegree) theDegree = d;
421    pIter(aAsPoly);
422  }
423  return theDegree + noOfTerms;
424}
425
426/* performs polynomial division and overrides p by the remainder
427   of division of p by the reducer;
428   modifies p */
429void definiteReduce(poly &p, poly reducer, const coeffs cf)
430{
431  #ifdef LDEBUG
432  p_Test((poly)p, naRing);
433  p_Test((poly)reducer, naRing);
434  #endif
435  p_PolyDiv(p, reducer, FALSE, naRing);
436}
437
438/* IMPORTANT NOTE: Since an algebraic field extension is again a field,
439                   the gcd of two elements is not very interesting. (It
440                   is actually any unit in the field, i.e., any non-
441                   zero element.) Note that the below method does not operate
442                   in this strong sense but rather computes the gcd of
443                   two given elements in the underlying polynomial ring. */
444number naGcd(number a, number b, const coeffs cf)
445{
446  naTest(a); naTest(b);
447  if ((a == NULL) && (b == NULL)) WerrorS(nDivBy0);
448  return (number)p_Gcd((poly)a, (poly)b, naRing);
449}
450
451number naInvers(number a, const coeffs cf)
452{
453  naTest(a);
454  if (a == NULL) WerrorS(nDivBy0);
455  poly aFactor = NULL; poly mFactor = NULL;
456  poly theGcd = p_ExtGcd((poly)a, aFactor, naMinpoly, mFactor, naRing);
457  naTest((number)theGcd); naTest((number)aFactor); naTest((number)mFactor);
458  /* the gcd must be 1 since naMinpoly is irreducible and a != NULL: */
459  assume(naIsOne((number)theGcd, cf));     
460  p_Delete(&theGcd, naRing);
461  p_Delete(&mFactor, naRing);
462  return (number)(aFactor);
463}
464
465/* assumes that src = Q, dst = Q(a) */
466number naMap00(number a, const coeffs src, const coeffs dst)
467{
468  assume(src == dst->algring->cf);
469  poly result = p_One(dst->algring);
470  p_SetCoeff(result, naCopy(a, src), dst->algring);
471  return (number)result;
472}
473
474/* assumes that src = Z/p, dst = Q(a) */
475number naMapP0(number a, const coeffs src, const coeffs dst)
476{
477  /* mapping via intermediate int: */
478  int n = n_Int(a, src);
479  number q = n_Init(n, dst->algring->cf);
480  poly result = p_One(dst->algring);
481  p_SetCoeff(result, q, dst->algring);
482  return (number)result;
483}
484
485/* assumes that either src = Q(a), dst = Q(a), or
486                       src = Zp(a), dst = Zp(a)     */
487number naCopyMap(number a, const coeffs src, const coeffs dst)
488{
489  return naCopy(a, dst);
490}
491
492/* assumes that src = Q, dst = Z/p(a) */
493number naMap0P(number a, const coeffs src, const coeffs dst)
494{
495  int p = rChar(dst->algring);
496  int n = nlModP(a, p, src);
497  number q = n_Init(n, dst->algring->cf);
498  poly result = p_One(dst->algring);
499  p_SetCoeff(result, q, dst->algring);
500  return (number)result;
501}
502
503/* assumes that src = Z/p, dst = Z/p(a) */
504number naMapPP(number a, const coeffs src, const coeffs dst)
505{
506  assume(src == dst->algring->cf);
507  poly result = p_One(dst->algring);
508  p_SetCoeff(result, naCopy(a, src), dst->algring);
509  return (number)result;
510}
511
512/* assumes that src = Z/u, dst = Z/p(a), where u != p */
513number naMapUP(number a, const coeffs src, const coeffs dst)
514{
515  /* mapping via intermediate int: */
516  int n = n_Int(a, src);
517  number q = n_Init(n, dst->algring->cf);
518  poly result = p_One(dst->algring);
519  p_SetCoeff(result, q, dst->algring);
520  return (number)result;
521}
522
523nMapFunc naSetMap(const coeffs src, const coeffs dst)
524{
525  /* dst is expected to be an algebraic extension field */
526  assume(getCoeffType(dst) == n_algExt);
527 
528  /* ATTENTION: This code assumes that dst is an algebraic extension of Q
529                or Zp. So, dst must NOT BE an algebraic extension of some
530                extension etc. This code will NOT WORK for extension
531                towers of height >= 2. */
532 
533  if (nCoeff_is_Q(src) && nCoeff_is_Q_a(dst))
534    return naMap00;                                      /// Q     -->  Q(a)
535 
536  if (nCoeff_is_Zp(src) && nCoeff_is_Q_a(dst))
537    return naMapP0;                                      /// Z/p   -->  Q(a)
538 
539  if (nCoeff_is_Q_a(src) && nCoeff_is_Q_a(dst))
540  {
541    if (strcmp(rParameter(src->algring)[0],
542               rParameter(dst->algring)[0]) == 0)
543      return naCopyMap;                                  /// Q(a)   --> Q(a)
544    else
545      return NULL;                                       /// Q(b)   --> Q(a)
546  }
547 
548  if (nCoeff_is_Q(src) && nCoeff_is_Zp_a(dst))
549    return naMap0P;                                      /// Q      --> Z/p(a)
550 
551  if (nCoeff_is_Zp(src) && nCoeff_is_Zp_a(dst))
552  {
553    if (src->ch == dst->ch) return naMapPP;              /// Z/p    --> Z/p(a)
554    else return naMapUP;                                 /// Z/u    --> Z/p(a)
555  }
556 
557  if (nCoeff_is_Zp_a(src) && nCoeff_is_Zp_a(dst))
558  {
559    if (strcmp(rParameter(src->algring)[0],
560               rParameter(dst->algring)[0]) == 0)
561      return naCopyMap;                                  /// Z/p(a) --> Z/p(a)
562    else
563      return NULL;                                       /// Z/p(b) --> Z/p(a)
564  }
565 
566  return NULL;                                           /// default
567}
568
569BOOLEAN naInitChar(coeffs cf, void * infoStruct)
570{
571  ExtInfo *e = (ExtInfo *)infoStruct;
572  /// first check whether cf->algring != NULL and delete old ring???
573  cf->algring           = e->r;
574  cf->algring->minideal = e->i;
575
576  assume(cf->algring                     != NULL);      // algring;
577  assume((cf->algring->minideal          != NULL) &&    // minideal has one
578         (IDELEMS(cf->algring->minideal) != 0)    &&    // non-zero generator
579         (cf->algring->minideal->m[0]    != NULL)    ); // at m[0];
580  assume(cf->algring->cf                 != NULL);      // algring->cf;
581  assume(getCoeffType(cf) == naID);                     // coeff type;
582 
583  cf->ch = -cf->algring->cf->ch;   /* propagate characteristic up so that it
584                                      becomes directly accessible in cf;
585                                      negative sign to signal that it's an
586                                      extension field */
587 
588  #ifdef LDEBUG
589  p_Test((poly)naMinpoly, naRing);
590  #endif
591 
592  cf->cfGreaterZero  = naGreaterZero;
593  cf->cfGreater      = naGreater;
594  cf->cfEqual        = naEqual;
595  cf->cfIsZero       = naIsZero;
596  cf->cfIsOne        = naIsOne;
597  cf->cfIsMOne       = naIsMOne;
598  cf->cfInit         = naInit;
599  cf->cfInt          = naInt;
600  cf->cfNeg          = naNeg;
601  cf->cfPar          = naPar;
602  cf->cfAdd          = naAdd;
603  cf->cfSub          = naSub;
604  cf->cfMult         = naMult;
605  cf->cfDiv          = naDiv;
606  cf->cfExactDiv     = naDiv;
607  cf->cfPower        = naPower;
608  cf->cfCopy         = naCopy;
609  cf->cfWrite        = naWrite;
610  cf->cfRead         = naRead;
611  cf->cfDelete       = naDelete;
612  cf->cfSetMap       = naSetMap;
613  cf->cfGetDenom     = naGetDenom;
614  cf->cfGetNumerator = naGetNumerator;
615  cf->cfRePart       = naCopy;
616  cf->cfImPart       = naImPart;
617  cf->cfCoeffWrite   = naCoeffWrite;
618  cf->cfDBTest       = naDBTest;
619  cf->cfGcd          = naGcd;
620  cf->cfLcm          = naLcm;
621  cf->cfSize         = naSize;
622  cf->nCoeffIsEqual  = naCoeffIsEqual;
623  cf->cfInvers       = naInvers;
624  cf->cfIntDiv       = naDiv;
625 
626  return FALSE;
627}
Note: See TracBrowser for help on using the repository browser.