source: git/libpolys/coeffs/rmodulon.cc @ c3304a

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