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

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