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

fieker-DuValspielwiese
Last change on this file since c28ecf was c28ecf, checked in by Frank Seelisch <seelisch@…>, 13 years ago
alg ext implementation now passing all coeffs and polys tests
  • Property mode set to 100644
File size: 18.2 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 */
339void heuristicReduce(poly p, poly reducer, const coeffs cf)
340{
341  #ifdef LDEBUG
342  p_Test((poly)p, naRing);
343  p_Test((poly)reducer, naRing);
344  #endif
345  if (p_Deg(p, naRing) > 10 * p_Deg(reducer, naRing))
346    definiteReduce(p, reducer, cf);
347}
348
349void naWrite(number &a, const coeffs cf)
350{
351  naTest(a);
352  if (a == NULL)
353    StringAppendS("0");
354  else
355  {
356    poly aAsPoly = (poly)a;
357    /* basically, just write aAsPoly using p_Write,
358       but use brackets around the output, if a is not
359       a constant living in naCoeffs = cf->algring->cf */
360    BOOLEAN useBrackets = TRUE;
361    if (p_Deg(aAsPoly, naRing) == 0) useBrackets = FALSE;
362    if (useBrackets) StringAppendS("(");
363    p_Write(aAsPoly, 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 */
428void definiteReduce(poly p, poly reducer, const coeffs cf)
429{
430  #ifdef LDEBUG
431  p_Test((poly)p, naRing);
432  p_Test((poly)reducer, naRing);
433  #endif
434  p_PolyDiv(p, reducer, FALSE, naRing);
435}
436
437number naGcd(number a, number b, const coeffs cf)
438{
439  naTest(a); naTest(b);
440  if ((a == NULL) && (b == NULL)) WerrorS(nDivBy0);
441  return (number)p_Gcd((poly)a, (poly)b, naRing);
442}
443
444number naInvers(number a, const coeffs cf)
445{
446  naTest(a);
447  if (a == NULL) WerrorS(nDivBy0);
448  poly aFactor = NULL; poly mFactor = NULL;
449  poly theGcd = p_ExtGcd((poly)a, aFactor, naMinpoly, mFactor, naRing);
450  /* the gcd must be 1 since naMinpoly is irreducible and a != NULL: */
451  assume(naIsOne((number)theGcd, cf));     
452  p_Delete(&theGcd, naRing);
453  p_Delete(&mFactor, naRing);
454  /* printf("naInvers\n");
455     p_Write((poly)a, naRing);
456     p_Write(aFactor, naRing); */
457  return (number)(aFactor);
458}
459
460/* assumes that src = Q, dst = Q(a) */
461number naMap00(number a, const coeffs src, const coeffs dst)
462{
463  assume(src == dst->algring->cf);
464  poly result = p_One(dst->algring);
465  p_SetCoeff(result, naCopy(a, src), dst->algring);
466  return (number)result;
467}
468
469/* assumes that src = Z/p, dst = Q(a) */
470number naMapP0(number a, const coeffs src, const coeffs dst)
471{
472  /* mapping via intermediate int: */
473  int n = n_Int(a, src);
474  number q = n_Init(n, dst->algring->cf);
475  poly result = p_One(dst->algring);
476  p_SetCoeff(result, q, dst->algring);
477  return (number)result;
478}
479
480/* assumes that either src = Q(a), dst = Q(a), or
481                       src = Zp(a), dst = Zp(a)     */
482number naCopyMap(number a, const coeffs src, const coeffs dst)
483{
484  return naCopy(a, dst);
485}
486
487/* assumes that src = Q, dst = Z/p(a) */
488number naMap0P(number a, const coeffs src, const coeffs dst)
489{
490  int p = rChar(dst->algring);
491  int n = nlModP(a, p, src);
492  number q = n_Init(n, dst->algring->cf);
493  poly result = p_One(dst->algring);
494  p_SetCoeff(result, q, dst->algring);
495  return (number)result;
496}
497
498/* assumes that src = Z/p, dst = Z/p(a) */
499number naMapPP(number a, const coeffs src, const coeffs dst)
500{
501  assume(src == dst->algring->cf);
502  poly result = p_One(dst->algring);
503  p_SetCoeff(result, naCopy(a, src), dst->algring);
504  return (number)result;
505}
506
507/* assumes that src = Z/u, dst = Z/p(a), where u != p */
508number naMapUP(number a, const coeffs src, const coeffs dst)
509{
510  /* mapping via intermediate int: */
511  int n = n_Int(a, src);
512  number q = n_Init(n, dst->algring->cf);
513  poly result = p_One(dst->algring);
514  p_SetCoeff(result, q, dst->algring);
515  return (number)result;
516}
517
518nMapFunc naSetMap(const coeffs src, const coeffs dst)
519{
520  /* dst is expected to be an (algebraic) extension field */
521  assume(getCoeffType(dst) == n_Ext);
522 
523  if (nCoeff_is_Q(src) && nCoeff_is_Q_a(dst))
524    return naMap00;                                      /// Q     -->  Q(a)
525 
526  if (nCoeff_is_Zp(src) && nCoeff_is_Q_a(dst))
527    return naMapP0;                                      /// Z/p   -->  Q(a)
528 
529  if (nCoeff_is_Q_a(src) && nCoeff_is_Q_a(dst))
530  {
531    if (strcmp(rParameter(src->algring)[0],
532               rParameter(dst->algring)[0]) == 0)
533      return naCopyMap;                                  /// Q(a)   --> Q(a)
534    else
535      return NULL;                                       /// Q(b)   --> Q(a)
536  }
537 
538  if (nCoeff_is_Q(src) && nCoeff_is_Zp_a(dst))
539    return naMap0P;                                      /// Q      --> Z/p(a)
540 
541  if (nCoeff_is_Zp(src) && nCoeff_is_Zp_a(dst))
542  {
543    if (src->ch == dst->ch) return naMapPP;              /// Z/p    --> Z/p(a)
544    else return naMapUP;                                 /// Z/u    --> Z/p(a)
545  }
546 
547  if (nCoeff_is_Zp_a(src) && nCoeff_is_Zp_a(dst))
548  {
549    if (strcmp(rParameter(src->algring)[0],
550               rParameter(dst->algring)[0]) == 0)
551      return naCopyMap;                                  /// Z/p(a) --> Z/p(a)
552    else
553      return NULL;                                       /// Z/p(b) --> Z/p(a)
554  }
555 
556  return NULL;                                           /// default
557}
558
559BOOLEAN naInitChar(coeffs cf, void * infoStruct)
560{
561  ExtInfo *e = (ExtInfo *)infoStruct;
562  /// first check whether cf->algring != NULL and delete old ring???
563  cf->algring           = e->r;
564  cf->algring->minideal = e->i;
565
566  assume(cf->algring                     != NULL);      // algring;
567  assume((cf->algring->minideal          != NULL) &&    // minideal has one
568         (IDELEMS(cf->algring->minideal) != 0)    &&    // non-zero generator
569         (cf->algring->minideal->m[0]    != NULL)    ); // at m[0];
570  assume(cf->algring->cf                 != NULL);      // algring->cf;
571  assume(getCoeffType(cf) == naID);                     // coeff type;
572 
573  #ifdef LDEBUG
574  p_Test((poly)naMinpoly, naRing);
575  #endif
576 
577  cf->cfGreaterZero  = naGreaterZero;
578  cf->cfGreater      = naGreater;
579  cf->cfEqual        = naEqual;
580  cf->cfIsZero       = naIsZero;
581  cf->cfIsOne        = naIsOne;
582  cf->cfIsMOne       = naIsMOne;
583  cf->cfInit         = naInit;
584  cf->cfInt          = naInt;
585  cf->cfNeg          = naNeg;
586  cf->cfPar          = naPar;
587  cf->cfAdd          = naAdd;
588  cf->cfSub          = naSub;
589  cf->cfMult         = naMult;
590  cf->cfDiv          = naDiv;
591  cf->cfExactDiv     = naDiv;
592  cf->cfPower        = naPower;
593  cf->cfCopy         = naCopy;
594  cf->cfWrite        = naWrite;
595  cf->cfRead         = naRead;
596  cf->cfDelete       = naDelete;
597  cf->cfSetMap       = naSetMap;
598  cf->cfGetDenom     = naGetDenom;
599  cf->cfGetNumerator = naGetNumerator;
600  cf->cfRePart       = naCopy;
601  cf->cfImPart       = naImPart;
602  cf->cfCoeffWrite   = naCoeffWrite;
603  cf->cfDBTest       = naDBTest;
604  cf->cfGcd          = naGcd;
605  cf->cfLcm          = naLcm;
606  cf->cfSize         = naSize;
607  cf->nCoeffIsEqual  = naCoeffIsEqual;
608  cf->cfInvers       = naInvers;
609  cf->cfIntDiv       = naDiv;
610 
611  return FALSE;
612}
Note: See TracBrowser for help on using the repository browser.