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

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