source: git/libpolys/coeffs/rmodulon.cc @ 0486a3

spielwiese
Last change on this file since 0486a3 was 0486a3, checked in by Martin Lee <martinlee84@…>, 11 years ago
fix: init of Z/n^m - now takes a ZnmInfo with modBase=n and modExponent=m
  • Property mode set to 100644
File size: 17.1 KB
Line 
1/****************************************
2*  Computer Algebra System SINGULAR     *
3****************************************/
4/*
5* ABSTRACT: numbers modulo n
6*/
7
8#include "config.h"
9#include <misc/auxiliary.h>
10
11#ifdef HAVE_RINGS
12
13#include <misc/mylimits.h>
14#include <coeffs/coeffs.h>
15#include <reporter/reporter.h>
16#include <omalloc/omalloc.h>
17#include <coeffs/numbers.h>
18#include <coeffs/longrat.h>
19#include <coeffs/mpr_complex.h>
20#include <coeffs/rmodulon.h>
21#include "si_gmp.h"
22
23#include <string.h>
24
25/// Our Type!
26static const n_coeffType ID = n_Zn;
27static const n_coeffType ID2 = n_Znm;
28
29extern omBin gmp_nrz_bin;
30
31void    nrnCoeffWrite  (const coeffs r, BOOLEAN /*details*/)
32{
33  long l = (long)mpz_sizeinbase(r->modBase, 10) + 2;
34  char* s = (char*) omAlloc(l);
35  s= mpz_get_str (s, 10, r->modBase);
36  if (nCoeff_is_Ring_ModN(r)) Print("//   coeff. ring is : Z/%s\n", s);
37  else if (nCoeff_is_Ring_PtoM(r)) Print("//   coeff. ring is : Z/%s^%lu\n", s, r->modExponent);
38  omFreeSize((ADDRESS)s, l);
39}
40
41static BOOLEAN nrnCoeffsEqual(const coeffs r, n_coeffType n, void * parameter)
42{
43  /* test, if r is an instance of nInitCoeffs(n,parameter) */
44  return (n==n_Zn) && (mpz_cmp_ui(r->modNumber,(long)parameter)==0);
45}
46
47
48/* for initializing function pointers */
49BOOLEAN nrnInitChar (coeffs r, void* p)
50{
51  assume( (getCoeffType(r) == ID) || (getCoeffType (r) == ID2) );
52  ZnmInfo * info= (ZnmInfo *) p;
53  r->modBase = (int_number) omAlloc(sizeof(mpz_t));
54  mpz_init_set (r->modBase, info->base);
55
56  nrnInitExp (info->exp, r);
57
58  if (info->exp > 1)
59    r->ringtype= 3;
60  else
61    r->ringtype= 2;
62  /* next computation may yield wrong characteristic as r->modNumber
63     is a GMP number */
64  r->ch = mpz_get_ui(r->modNumber);
65
66  r->cfInit        = nrnInit;
67  r->cfDelete      = nrnDelete;
68  r->cfCopy        = nrnCopy;
69  r->cfSize        = nrnSize;
70  r->cfInt         = nrnInt;
71  r->cfAdd         = nrnAdd;
72  r->cfSub         = nrnSub;
73  r->cfMult        = nrnMult;
74  r->cfDiv         = nrnDiv;
75  r->cfIntDiv      = nrnIntDiv;
76  r->cfIntMod      = nrnMod;
77  r->cfExactDiv    = nrnDiv;
78  r->cfNeg         = nrnNeg;
79  r->cfInvers      = nrnInvers;
80  r->cfDivBy       = nrnDivBy;
81  r->cfDivComp     = nrnDivComp;
82  r->cfGreater     = nrnGreater;
83  r->cfEqual       = nrnEqual;
84  r->cfIsZero      = nrnIsZero;
85  r->cfIsOne       = nrnIsOne;
86  r->cfIsMOne      = nrnIsMOne;
87  r->cfGreaterZero = nrnGreaterZero;
88  r->cfWriteLong       = nrnWrite;
89  r->cfRead        = nrnRead;
90  r->cfPower       = nrnPower;
91  r->cfSetMap      = nrnSetMap;
92  r->cfNormalize   = ndNormalize;
93  r->cfLcm         = nrnLcm;
94  r->cfGcd         = nrnGcd;
95  r->cfIsUnit      = nrnIsUnit;
96  r->cfGetUnit     = nrnGetUnit;
97  r->cfExtGcd      = nrnExtGcd;
98  r->cfName        = ndName;
99  r->cfCoeffWrite  = nrnCoeffWrite;
100  r->nCoeffIsEqual = nrnCoeffsEqual;
101#ifdef LDEBUG
102  r->cfDBTest      = nrnDBTest;
103#endif
104  return FALSE;
105}
106
107/*
108 * create a number from int
109 */
110number nrnInit(long i, const coeffs r)
111{
112  int_number erg = (int_number) omAllocBin(gmp_nrz_bin);
113  mpz_init_set_si(erg, i);
114  mpz_mod(erg, erg, r->modNumber);
115  return (number) erg;
116}
117
118void nrnDelete(number *a, const coeffs)
119{
120  if (*a == NULL) return;
121  mpz_clear((int_number) *a);
122  omFreeBin((void *) *a, gmp_nrz_bin);
123  *a = NULL;
124}
125
126number nrnCopy(number a, const coeffs)
127{
128  int_number erg = (int_number) omAllocBin(gmp_nrz_bin);
129  mpz_init_set(erg, (int_number) a);
130  return (number) erg;
131}
132
133int nrnSize(number a, const coeffs)
134{
135  if (a == NULL) return 0;
136  return sizeof(mpz_t);
137}
138
139/*
140 * convert a number to int
141 */
142int nrnInt(number &n, const coeffs)
143{
144  return (int)mpz_get_si((int_number) n);
145}
146
147/*
148 * Multiply two numbers
149 */
150number nrnMult(number a, number b, const coeffs r)
151{
152  int_number erg = (int_number)omAllocBin(gmp_nrz_bin);
153  mpz_init(erg);
154  mpz_mul(erg, (int_number)a, (int_number) b);
155  mpz_mod(erg, erg, r->modNumber);
156  return (number) erg;
157}
158
159void nrnPower(number a, int i, number * result, const coeffs r)
160{
161  int_number erg = (int_number)omAllocBin(gmp_nrz_bin);
162  mpz_init(erg);
163  mpz_powm_ui(erg, (int_number)a, i, r->modNumber);
164  *result = (number) erg;
165}
166
167number nrnAdd(number a, number b, const coeffs r)
168{
169  int_number erg = (int_number)omAllocBin(gmp_nrz_bin);
170  mpz_init(erg);
171  mpz_add(erg, (int_number)a, (int_number) b);
172  mpz_mod(erg, erg, r->modNumber);
173  return (number) erg;
174}
175
176number nrnSub(number a, number b, const coeffs r)
177{
178  int_number erg = (int_number)omAllocBin(gmp_nrz_bin);
179  mpz_init(erg);
180  mpz_sub(erg, (int_number)a, (int_number) b);
181  mpz_mod(erg, erg, r->modNumber);
182  return (number) erg;
183}
184
185number nrnNeg(number c, const coeffs r)
186{
187  if( !nrnIsZero(c, r) )
188    // Attention: This method operates in-place.
189    mpz_sub((int_number)c, r->modNumber, (int_number)c);
190  return c;
191}
192
193number nrnInvers(number c, const coeffs r)
194{
195  int_number erg = (int_number)omAllocBin(gmp_nrz_bin);
196  mpz_init(erg);
197  mpz_invert(erg, (int_number)c, r->modNumber);
198  return (number) erg;
199}
200
201/*
202 * Give the smallest k, such that a * x = k = b * y has a solution
203 * TODO: lcm(gcd,gcd) better than gcd(lcm) ?
204 */
205number nrnLcm(number a, number b, const coeffs r)
206{
207  number erg = nrnGcd(NULL, a, r);
208  number tmp = nrnGcd(NULL, b, r);
209  mpz_lcm((int_number)erg, (int_number)erg, (int_number)tmp);
210  nrnDelete(&tmp, NULL);
211  return (number)erg;
212}
213
214/*
215 * Give the largest k, such that a = x * k, b = y * k has
216 * a solution.
217 */
218number nrnGcd(number a, number b, const coeffs r)
219{
220  if ((a == NULL) && (b == NULL)) return nrnInit(0,r);
221  int_number erg = (int_number)omAllocBin(gmp_nrz_bin);
222  mpz_init_set(erg, r->modNumber);
223  if (a != NULL) mpz_gcd(erg, erg, (int_number)a);
224  if (b != NULL) mpz_gcd(erg, erg, (int_number)b);
225  return (number)erg;
226}
227
228/* Not needed any more, but may have room for improvement
229   number nrnGcd3(number a,number b, number c,ring r)
230{
231  int_number erg = (int_number) omAllocBin(gmp_nrz_bin);
232  mpz_init(erg);
233  if (a == NULL) a = (number)r->modNumber;
234  if (b == NULL) b = (number)r->modNumber;
235  if (c == NULL) c = (number)r->modNumber;
236  mpz_gcd(erg, (int_number)a, (int_number)b);
237  mpz_gcd(erg, erg, (int_number)c);
238  mpz_gcd(erg, erg, r->modNumber);
239  return (number)erg;
240}
241*/
242
243/*
244 * Give the largest k, such that a = x * k, b = y * k has
245 * a solution and r, s, s.t. k = s*a + t*b
246 */
247number nrnExtGcd(number a, number b, number *s, number *t, const coeffs r)
248{
249  int_number erg = (int_number)omAllocBin(gmp_nrz_bin);
250  int_number bs  = (int_number)omAllocBin(gmp_nrz_bin);
251  int_number bt  = (int_number)omAllocBin(gmp_nrz_bin);
252  mpz_init(erg);
253  mpz_init(bs);
254  mpz_init(bt);
255  mpz_gcdext(erg, bs, bt, (int_number)a, (int_number)b);
256  mpz_mod(bs, bs, r->modNumber);
257  mpz_mod(bt, bt, r->modNumber);
258  *s = (number)bs;
259  *t = (number)bt;
260  return (number)erg;
261}
262
263BOOLEAN nrnIsZero(number a, const coeffs)
264{
265#ifdef LDEBUG
266  if (a == NULL) return FALSE;
267#endif
268  return 0 == mpz_cmpabs_ui((int_number)a, 0);
269}
270
271BOOLEAN nrnIsOne(number a, const coeffs)
272{
273#ifdef LDEBUG
274  if (a == NULL) return FALSE;
275#endif
276  return 0 == mpz_cmp_si((int_number)a, 1);
277}
278
279BOOLEAN nrnIsMOne(number a, const coeffs r)
280{
281#ifdef LDEBUG
282  if (a == NULL) return FALSE;
283#endif
284  mpz_t t; mpz_init_set(t, (int_number)a);
285  mpz_add_ui(t, t, 1);
286  bool erg = (0 == mpz_cmp(t, r->modNumber));
287  mpz_clear(t);
288  return erg;
289}
290
291BOOLEAN nrnEqual(number a, number b, const coeffs)
292{
293  return 0 == mpz_cmp((int_number)a, (int_number)b);
294}
295
296BOOLEAN nrnGreater(number a, number b, const coeffs)
297{
298  return 0 < mpz_cmp((int_number)a, (int_number)b);
299}
300
301BOOLEAN nrnGreaterZero(number k, const coeffs)
302{
303  return 0 < mpz_cmp_si((int_number)k, 0);
304}
305
306BOOLEAN nrnIsUnit(number a, const coeffs r)
307{
308  number tmp = nrnGcd(a, (number)r->modNumber, r);
309  bool res = nrnIsOne(tmp, r);
310  nrnDelete(&tmp, NULL);
311  return res;
312}
313
314number nrnGetUnit(number k, const coeffs r)
315{
316  if (mpz_divisible_p(r->modNumber, (int_number)k)) return nrnInit(1,r);
317
318  int_number unit = (int_number)nrnGcd(k, 0, r);
319  mpz_tdiv_q(unit, (int_number)k, unit);
320  int_number gcd = (int_number)nrnGcd((number)unit, 0, r);
321  if (!nrnIsOne((number)gcd,r))
322  {
323    int_number ctmp;
324    // tmp := unit^2
325    int_number tmp = (int_number) nrnMult((number) unit,(number) unit,r);
326    // gcd_new := gcd(tmp, 0)
327    int_number gcd_new = (int_number) nrnGcd((number) tmp, 0, r);
328    while (!nrnEqual((number) gcd_new,(number) gcd,r))
329    {
330      // gcd := gcd_new
331      ctmp = gcd;
332      gcd = gcd_new;
333      gcd_new = ctmp;
334      // tmp := tmp * unit
335      mpz_mul(tmp, tmp, unit);
336      mpz_mod(tmp, tmp, r->modNumber);
337      // gcd_new := gcd(tmp, 0)
338      mpz_gcd(gcd_new, tmp, r->modNumber);
339    }
340    // unit := unit + modNumber / gcd_new
341    mpz_tdiv_q(tmp, r->modNumber, gcd_new);
342    mpz_add(unit, unit, tmp);
343    mpz_mod(unit, unit, r->modNumber);
344    nrnDelete((number*) &gcd_new, NULL);
345    nrnDelete((number*) &tmp, NULL);
346  }
347  nrnDelete((number*) &gcd, NULL);
348  return (number)unit;
349}
350
351BOOLEAN nrnDivBy(number a, number b, const coeffs r)
352{
353  if (a == NULL)
354    return mpz_divisible_p(r->modNumber, (int_number)b);
355  else
356  { /* b divides a iff b/gcd(a, b) is a unit in the given ring: */
357    number n = nrnGcd(a, b, r);
358    mpz_tdiv_q((int_number)n, (int_number)b, (int_number)n);
359    bool result = nrnIsUnit(n, r);
360    nrnDelete(&n, NULL);
361    return result;
362  }
363}
364
365int nrnDivComp(number a, number b, const coeffs r)
366{
367  if (nrnEqual(a, b,r)) return 2;
368  if (mpz_divisible_p((int_number) a, (int_number) b)) return -1;
369  if (mpz_divisible_p((int_number) b, (int_number) a)) return 1;
370  return 0;
371}
372
373number nrnDiv(number a, number b, const coeffs r)
374{
375  if (a == NULL) a = (number)r->modNumber;
376  int_number erg = (int_number)omAllocBin(gmp_nrz_bin);
377  mpz_init(erg);
378  if (mpz_divisible_p((int_number)a, (int_number)b))
379  {
380    mpz_divexact(erg, (int_number)a, (int_number)b);
381    return (number)erg;
382  }
383  else
384  {
385    int_number gcd = (int_number)nrnGcd(a, b, r);
386    mpz_divexact(erg, (int_number)b, gcd);
387    if (!nrnIsUnit((number)erg, r))
388    {
389      WerrorS("Division not possible, even by cancelling zero divisors.");
390      WerrorS("Result is integer division without remainder.");
391      mpz_tdiv_q(erg, (int_number) a, (int_number) b);
392      nrnDelete((number*) &gcd, NULL);
393      return (number)erg;
394    }
395    // a / gcd(a,b) * [b / gcd (a,b)]^(-1)
396    int_number tmp = (int_number)nrnInvers((number) erg,r);
397    mpz_divexact(erg, (int_number)a, gcd);
398    mpz_mul(erg, erg, tmp);
399    nrnDelete((number*) &gcd, NULL);
400    nrnDelete((number*) &tmp, NULL);
401    mpz_mod(erg, erg, r->modNumber);
402    return (number)erg;
403  }
404}
405
406number nrnMod(number a, number b, const coeffs r)
407{
408  /*
409    We need to return the number rr which is uniquely determined by the
410    following two properties:
411      (1) 0 <= rr < |b| (with respect to '<' and '<=' performed in Z x Z)
412      (2) There exists some k in the integers Z such that a = k * b + rr.
413    Consider g := gcd(n, |b|). Note that then |b|/g is a unit in Z/n.
414    Now, there are three cases:
415      (a) g = 1
416          Then |b| is a unit in Z/n, i.e. |b| (and also b) divides a.
417          Thus rr = 0.
418      (b) g <> 1 and g divides a
419          Then a = (a/g) * (|b|/g)^(-1) * b (up to sign), i.e. again rr = 0.
420      (c) g <> 1 and g does not divide a
421          Then denote the division with remainder of a by g as this:
422          a = s * g + t. Then t = a - s * g = a - s * (|b|/g)^(-1) * |b|
423          fulfills (1) and (2), i.e. rr := t is the correct result. Hence
424          in this third case, rr is the remainder of division of a by g in Z.
425     Remark: according to mpz_mod: a,b are always non-negative
426  */
427  int_number g = (int_number)omAllocBin(gmp_nrz_bin);
428  int_number rr = (int_number)omAllocBin(gmp_nrz_bin);
429  mpz_init(g);
430  mpz_init_set_si(rr, 0);
431  mpz_gcd(g, (int_number)r->modNumber, (int_number)b); // g is now as above
432  if (mpz_cmp_si(g, (long)1) != 0) mpz_mod(rr, (int_number)a, g); // the case g <> 1
433  mpz_clear(g);
434  omFreeBin(g, gmp_nrz_bin);
435  return (number)rr;
436}
437
438number nrnIntDiv(number a, number b, const coeffs r)
439{
440  int_number erg = (int_number)omAllocBin(gmp_nrz_bin);
441  mpz_init(erg);
442  if (a == NULL) a = (number)r->modNumber;
443  mpz_tdiv_q(erg, (int_number)a, (int_number)b);
444  return (number)erg;
445}
446
447/*
448 * Helper function for computing the module
449 */
450
451int_number nrnMapCoef = NULL;
452
453number nrnMapModN(number from, const coeffs /*src*/, const coeffs dst)
454{
455  return nrnMult(from, (number) nrnMapCoef, dst);
456}
457
458number nrnMap2toM(number from, const coeffs /*src*/, const coeffs dst)
459{
460  int_number erg = (int_number)omAllocBin(gmp_nrz_bin);
461  mpz_init(erg);
462  mpz_mul_ui(erg, nrnMapCoef, (NATNUMBER)from);
463  mpz_mod(erg, erg, dst->modNumber);
464  return (number)erg;
465}
466
467number nrnMapZp(number from, const coeffs /*src*/, const coeffs dst)
468{
469  int_number erg = (int_number)omAllocBin(gmp_nrz_bin);
470  mpz_init(erg);
471  // TODO: use npInt(...)
472  mpz_mul_si(erg, nrnMapCoef, (NATNUMBER)from);
473  mpz_mod(erg, erg, dst->modNumber);
474  return (number)erg;
475}
476
477number nrnMapGMP(number from, const coeffs /*src*/, const coeffs dst)
478{
479  int_number erg = (int_number)omAllocBin(gmp_nrz_bin);
480  mpz_init(erg);
481  mpz_mod(erg, (int_number)from, dst->modNumber);
482  return (number)erg;
483}
484
485number nrnMapQ(number from, const coeffs src, const coeffs /*dst*/)
486{
487  int_number erg = (int_number)omAllocBin(gmp_nrz_bin);
488  mpz_init(erg);
489  nlGMP(from, (number)erg, src);
490  mpz_mod(erg, erg, src->modNumber);
491  return (number)erg;
492}
493
494nMapFunc nrnSetMap(const coeffs src, const coeffs dst)
495{
496  /* dst = currRing->cf */
497  if (nCoeff_is_Ring_Z(src))
498  {
499    return nrnMapGMP;
500  }
501  if (nCoeff_is_Q(src))
502  {
503    return nrnMapQ;
504  }
505  // Some type of Z/n ring / field
506  if (nCoeff_is_Ring_ModN(src) || nCoeff_is_Ring_PtoM(src) ||
507      nCoeff_is_Ring_2toM(src) || nCoeff_is_Zp(src))
508  {
509    if (   (src->ringtype > 0)
510        && (mpz_cmp(src->modBase, dst->modBase) == 0)
511        && (src->modExponent == dst->modExponent)) return nrnMapGMP;
512    else
513    {
514      int_number nrnMapModul = (int_number) omAllocBin(gmp_nrz_bin);
515      // Computing the n of Z/n
516      if (nCoeff_is_Zp(src))
517      {
518        mpz_init_set_si(nrnMapModul, src->ch);
519      }
520      else
521      {
522        mpz_init(nrnMapModul);
523        mpz_set(nrnMapModul, src->modNumber);
524      }
525      // nrnMapCoef = 1 in dst       if dst is a subring of src
526      // nrnMapCoef = 0 in dst / src if src is a subring of dst
527      if (nrnMapCoef == NULL)
528      {
529        nrnMapCoef = (int_number) omAllocBin(gmp_nrz_bin);
530        mpz_init(nrnMapCoef);
531      }
532      if (mpz_divisible_p(nrnMapModul, dst->modNumber))
533      {
534        mpz_set_si(nrnMapCoef, 1);
535      }
536      else
537      if (nrnDivBy(NULL, (number) nrnMapModul,dst))
538      {
539        mpz_divexact(nrnMapCoef, dst->modNumber, nrnMapModul);
540        int_number tmp = dst->modNumber;
541        dst->modNumber = nrnMapModul;
542        if (!nrnIsUnit((number) nrnMapCoef,dst))
543        {
544          dst->modNumber = tmp;
545          nrnDelete((number*) &nrnMapModul, dst);
546          return NULL;
547        }
548        int_number inv = (int_number) nrnInvers((number) nrnMapCoef,dst);
549        dst->modNumber = tmp;
550        mpz_mul(nrnMapCoef, nrnMapCoef, inv);
551        mpz_mod(nrnMapCoef, nrnMapCoef, dst->modNumber);
552        nrnDelete((number*) &inv, dst);
553      }
554      else
555      {
556        nrnDelete((number*) &nrnMapModul, dst);
557        return NULL;
558      }
559      nrnDelete((number*) &nrnMapModul, dst);
560      if (nCoeff_is_Ring_2toM(src))
561        return nrnMap2toM;
562      else if (nCoeff_is_Zp(src))
563        return nrnMapZp;
564      else
565        return nrnMapModN;
566    }
567  }
568  return NULL;      // default
569}
570
571/*
572 * set the exponent (allocate and init tables) (TODO)
573 */
574
575void nrnSetExp(unsigned long m, coeffs r)
576{
577  /* clean up former stuff */
578  //if (r->modBase   != NULL) mpz_clear(r->modBase);
579  if (r->modNumber != NULL) mpz_clear(r->modNumber);
580
581  r->modExponent= m;
582  /* this is Z/m = Z/(m^1), hence set modBase = m, modExponent = 1: */
583  //r->modBase = (int_number)omAllocBin(gmp_nrz_bin);
584  //mpz_init(r->modBase);
585  //mpz_set_ui(r->modBase, (unsigned long)m);
586  r->modNumber = (int_number)omAllocBin(gmp_nrz_bin);
587  mpz_init_set (r->modNumber, r->modBase);
588  mpz_pow_ui (r->modNumber, r->modNumber, m);
589}
590
591/* We expect this ring to be Z/n^m for some m > 0 and for some n > 2 which is not a prime. */
592void nrnInitExp(unsigned long m, coeffs r)
593{
594  nrnSetExp(m, r);
595  assume (r->modNumber != NULL);
596  if (mpz_cmp_ui(r->modNumber,2) <= 0)
597    WarnS("nrnInitExp failed (m in Z/m too small)");
598}
599
600#ifdef LDEBUG
601BOOLEAN nrnDBTest (number a, const char *, const int, const coeffs r)
602{
603  if (a==NULL) return TRUE;
604  if ( (mpz_cmp_si((int_number) a, 0) < 0) || (mpz_cmp((int_number) a, r->modNumber) > 0) )
605  {
606    return FALSE;
607  }
608  return TRUE;
609}
610#endif
611
612/*2
613* extracts a long integer from s, returns the rest    (COPY FROM longrat0.cc)
614*/
615static const char * nlCPEatLongC(char *s, mpz_ptr i)
616{
617  const char * start=s;
618  if (!(*s >= '0' && *s <= '9'))
619  {
620    mpz_init_set_si(i, 1);
621    return s;
622  }
623  mpz_init(i);
624  while (*s >= '0' && *s <= '9') s++;
625  if (*s=='\0')
626  {
627    mpz_set_str(i,start,10);
628  }
629  else
630  {
631    char c=*s;
632    *s='\0';
633    mpz_set_str(i,start,10);
634    *s=c;
635  }
636  return s;
637}
638
639const char * nrnRead (const char *s, number *a, const coeffs r)
640{
641  int_number z = (int_number) omAllocBin(gmp_nrz_bin);
642  {
643    s = nlCPEatLongC((char *)s, z);
644  }
645  mpz_mod(z, z, r->modNumber);
646  *a = (number) z;
647  return s;
648}
649#endif
650/* #ifdef HAVE_RINGS */
Note: See TracBrowser for help on using the repository browser.