source: git/kernel/rmodulon.cc @ 6ea941

spielwiese
Last change on this file since 6ea941 was 6ea941, checked in by Frank Seelisch <seelisch@…>, 14 years ago
corrected a modulo b in Z/n and Z/2^m git-svn-id: file:///usr/local/Singular/svn/trunk@11940 2c84dea3-7e68-4137-9b89-c4e89433aadc
  • Property mode set to 100644
File size: 14.2 KB
Line 
1/****************************************
2*  Computer Algebra System SINGULAR     *
3****************************************/
4/* $Id: rmodulon.cc,v 1.35 2009-07-03 13:14:10 seelisch Exp $ */
5/*
6* ABSTRACT: numbers modulo n
7*/
8
9#include <string.h>
10#include "mod2.h"
11#include <mylimits.h>
12#include "structs.h"
13#include "febase.h"
14#include "omalloc.h"
15#include "numbers.h"
16#include "longrat.h"
17#include "mpr_complex.h"
18#include "ring.h"
19#include "rmodulon.h"
20#include "si_gmp.h"
21
22#ifdef HAVE_RINGS
23  #define gmp_nrn_bin gmp_nrz_bin
24  extern omBin gmp_nrz_bin;
25
26int_number nrnModul = NULL;
27int_number nrnMinusOne = NULL;
28unsigned long nrnExponent = 0;
29
30/*
31 * create a number from int
32 */
33number nrnInit (int i)
34{
35  int_number erg = (int_number) omAllocBin(gmp_nrn_bin);
36  mpz_init_set_si(erg, i);
37  mpz_mod(erg, erg, nrnModul);
38  return (number) erg;
39}
40
41void nrnDelete(number *a, const ring r)
42{
43  if (*a == NULL) return;
44  mpz_clear((int_number) *a);
45  omFreeBin((ADDRESS) *a, gmp_nrn_bin);
46  *a = NULL;
47}
48
49number nrnCopy(number a)
50{
51  int_number erg = (int_number) omAllocBin(gmp_nrn_bin);
52  mpz_init_set(erg, (int_number) a);
53  return (number) erg;
54}
55
56number cfrnCopy(number a, const ring r)
57{
58  return nrnCopy(a);
59}
60
61int nrnSize(number a)
62{
63  if (a == NULL) return 0;
64  return sizeof(MP_INT);
65}
66
67/*
68 * convert a number to int (-p/2 .. p/2)
69 */
70int nrnInt(number &n)
71{
72  return (int) mpz_get_si( (int_number) &n);
73}
74
75/*
76 * Multiply two numbers
77 */
78number nrnMult (number a, number b)
79{
80  int_number erg = (int_number) omAllocBin(gmp_nrn_bin);
81  mpz_init(erg);
82  mpz_mul(erg, (int_number) a, (int_number) b);
83  mpz_mod(erg, erg, nrnModul);
84  return (number) erg;
85}
86
87void nrnPower (number a, int i, number * result)
88{
89  int_number erg = (int_number) omAllocBin(gmp_nrn_bin);
90  mpz_init(erg);
91  mpz_powm_ui(erg, (int_number) a, i, nrnModul);
92  *result = (number) erg;
93}
94
95number nrnAdd (number a, number b)
96{
97  int_number erg = (int_number) omAllocBin(gmp_nrn_bin);
98  mpz_init(erg);
99  mpz_add(erg, (int_number) a, (int_number) b);
100  mpz_mod(erg, erg, nrnModul);
101  return (number) erg;
102}
103
104number nrnSub (number a, number b)
105{
106  int_number erg = (int_number) omAllocBin(gmp_nrn_bin);
107  mpz_init(erg);
108  mpz_sub(erg, (int_number) a, (int_number) b);
109  mpz_mod(erg, erg, nrnModul);
110  return (number) erg;
111}
112
113number nrnNeg (number c)
114{
115// nNeg inplace !!!
116  mpz_sub((int_number) c, nrnModul, (int_number) c);
117  return c;
118}
119
120number  nrnInvers (number c)
121{
122  int_number erg = (int_number) omAllocBin(gmp_nrn_bin);
123  mpz_init(erg);
124  mpz_invert(erg, (int_number) c, nrnModul);
125  return (number) erg;
126}
127
128/*
129 * Give the smallest non unit k, such that a * x = k = b * y has a solution
130 * TODO: lcm(gcd,gcd) besser als gcd(lcm) ?
131 */
132number nrnLcm (number a,number b,ring r)
133{
134  number erg = nrnGcd(NULL, a, NULL);
135  number tmp = nrnGcd(NULL, b, NULL);
136  mpz_lcm((int_number) erg, (int_number) erg, (int_number) tmp);
137  nrnDelete(&tmp, NULL);
138  return (number) erg;
139}
140
141/*
142 * Give the largest non unit k, such that a = x * k, b = y * k has
143 * a solution.
144 */
145number nrnGcd (number a,number b,ring r)
146{
147  if ((a == NULL) && (b == NULL)) return nrnInit(0);
148  int_number erg = (int_number) omAllocBin(gmp_nrn_bin);
149  mpz_init_set(erg, nrnModul);
150  if (a != NULL) mpz_gcd(erg, erg, (int_number) a);
151  if (b != NULL) mpz_gcd(erg, erg, (int_number) b);
152  return (number) erg;
153}
154
155/* Not needed any more, but may have room for improvement
156number nrnGcd3 (number a,number b, number c,ring r)
157{
158  int_number erg = (int_number) omAllocBin(gmp_nrn_bin);
159  mpz_init(erg);
160  if (a == NULL) a = (number) nrnModul;
161  if (b == NULL) b = (number) nrnModul;
162  if (c == NULL) c = (number) nrnModul;
163  mpz_gcd(erg, (int_number) a, (int_number) b);
164  mpz_gcd(erg, erg, (int_number) c);
165  mpz_gcd(erg, erg, nrnModul);
166  return (number) erg;
167}
168*/
169
170/*
171 * Give the largest non unit k, such that a = x * k, b = y * k has
172 * a solution and r, s, s.t. k = s*a + t*b
173 */
174number  nrnExtGcd (number a, number b, number *s, number *t)
175{
176  int_number erg = (int_number) omAllocBin(gmp_nrn_bin);
177  int_number bs = (int_number) omAllocBin(gmp_nrn_bin);
178  int_number bt = (int_number) omAllocBin(gmp_nrn_bin);
179  mpz_init(erg);
180  mpz_init(bs);
181  mpz_init(bt);
182  mpz_gcdext(erg, bs, bt, (int_number) a, (int_number) b);
183  mpz_mod(bs, bs, nrnModul);
184  mpz_mod(bt, bt, nrnModul);
185  *s = (number) bs;
186  *t = (number) bt;
187  return (number) erg;
188}
189
190BOOLEAN nrnIsZero (number  a)
191{
192  return 0 == mpz_cmpabs_ui((int_number) a, 0);
193}
194
195BOOLEAN nrnIsOne (number a)
196{
197  return 0 == mpz_cmp_si((int_number) a, 1);
198}
199
200BOOLEAN nrnIsMOne (number a)
201{
202  return 0 == mpz_cmp((int_number) a, nrnMinusOne);
203}
204
205BOOLEAN nrnEqual (number a,number b)
206{
207  return 0 == mpz_cmp((int_number) a, (int_number) b);
208}
209
210BOOLEAN nrnGreater (number a,number b)
211{
212  return 0 < mpz_cmp((int_number) a, (int_number) b);
213}
214
215BOOLEAN nrnGreaterZero (number k)
216{
217  return 0 < mpz_cmp_si((int_number) k, 0);
218}
219
220BOOLEAN nrnIsUnit (number a)
221{
222  number tmp = nrnGcd(a, (number) nrnModul, NULL);
223  bool res = nrnIsOne(tmp);
224  nrnDelete(&tmp, NULL);
225  return res;
226}
227
228number  nrnGetUnit (number k)
229{
230  if (mpz_divisible_p(nrnModul, (int_number) k)) return nrnInit(1);
231
232  int_number unit = (int_number) nrnGcd(k, 0, currRing);
233  mpz_tdiv_q(unit, (int_number) k, unit);
234  int_number gcd = (int_number) nrnGcd((number) unit, 0, currRing);
235  if (!nrnIsOne((number) gcd))
236  {
237    int_number ctmp;
238    // tmp := unit^2
239    int_number tmp = (int_number) nrnMult((number) unit,(number) unit);
240    // gcd_new := gcd(tmp, 0)
241    int_number gcd_new = (int_number) nrnGcd((number) tmp, 0, currRing);
242    while (!nrnEqual((number) gcd_new,(number) gcd))
243    {
244      // gcd := gcd_new
245      ctmp = gcd;
246      gcd = gcd_new;
247      gcd_new = ctmp;
248      // tmp := tmp * unit
249      mpz_mul(tmp, tmp, unit);
250      mpz_mod(tmp, tmp, nrnModul);
251      // gcd_new := gcd(tmp, 0)
252      mpz_gcd(gcd_new, tmp, nrnModul);
253    }
254    // unit := unit + nrnModul / gcd_new
255    mpz_tdiv_q(tmp, nrnModul, gcd_new);
256    mpz_add(unit, unit, tmp);
257    mpz_mod(unit, unit, nrnModul);
258    nrnDelete((number*) &gcd_new, NULL);
259    nrnDelete((number*) &tmp, NULL);
260  }
261  nrnDelete((number*) &gcd, NULL);
262  return (number) unit;
263}
264
265BOOLEAN nrnDivBy (number a,number b)
266{
267  if (a == NULL)
268    return mpz_divisible_p(nrnModul, (int_number) b);
269  else
270    return mpz_divisible_p((int_number) a, (int_number) b);
271  /*
272  number bs = nrnGcd(a, b, NULL);
273  mpz_tdiv_q((int_number) bs, (int_number) b, (int_number) bs);
274  bool res = nrnIsUnit(bs);
275  nrnDelete(&bs, NULL);
276  return res;
277  */
278}
279
280int nrnDivComp(number a, number b)
281{
282  if (nrnEqual(a, b)) return 0;
283  if (mpz_divisible_p((int_number) a, (int_number) b)) return -1;
284  if (mpz_divisible_p((int_number) b, (int_number) a)) return 1;
285  return 2;
286}
287
288number nrnDiv (number a,number b)
289{
290  if (a == NULL) a = (number) nrnModul;
291  int_number erg = (int_number) omAllocBin(gmp_nrn_bin);
292  mpz_init(erg);
293  if (mpz_divisible_p((int_number) a, (int_number) b))
294  {
295    mpz_divexact(erg, (int_number) a, (int_number) b);
296    return (number) erg;
297  }
298  else
299  {
300    int_number gcd = (int_number) nrnGcd(a, b, NULL);
301    mpz_divexact(erg, (int_number) b, gcd);
302    if (!nrnIsUnit((number) erg))
303    {
304      WarnS("Division not possible, even by cancelling zero divisors.");
305      WarnS("Result is integer division without remainder.");
306      mpz_tdiv_q(erg, (int_number) a, (int_number) b);
307      nrnDelete((number*) &gcd, NULL);
308      return (number) erg;
309    }
310    // a / gcd(a,b) * [b / gcd (a,b)]^(-1)
311    int_number tmp = (int_number) nrnInvers((number) erg);
312    mpz_divexact(erg, (int_number) a, gcd);
313    mpz_mul(erg, erg, tmp);
314    nrnDelete((number*) &gcd, NULL);
315    nrnDelete((number*) &tmp, NULL);
316    mpz_mod(erg, erg, nrnModul);
317    return (number) erg;
318  }
319}
320
321number nrnMod (number a, number b)
322{
323  /*
324    We need to return the number r which is uniquely determined by the
325    following two properties:
326      (1) 0 <= r < |b| (with respect to '<' and '<=' performed in Z x Z)
327      (2) There exists some k in the integers Z such that a = k * b + r.
328    Consider g := gcd(n, |b|). Note that then |b|/g is a unit in Z/n.
329    Now, there are three cases:
330      (a) g = 1
331          Then |b| is a unit in Z/n, i.e. |b| (and also b) divides a.
332          Thus r = 0.
333      (b) g <> 1 and g divides a
334          Then a = (a/g) * (|b|/g)^(-1) * b (up to sign), i.e. again r = 0.
335      (c) g <> 1 and g does not divide a
336          Then denote the division with remainder of a by g as this:
337          a = s * g + t. Then t = a - s * g = a - s * (|b|/g)^(-1) * |b|
338          fulfills (1) and (2), i.e. r := t is the correct result. Hence
339          in this third case, r is the remainder of division of a by g in Z.
340  */
341  int_number g = (int_number) omAllocBin(gmp_nrn_bin);
342  int_number b_abs = (int_number) omAllocBin(gmp_nrn_bin);
343  int_number r = (int_number) omAllocBin(gmp_nrn_bin);
344  mpz_init(g);
345  mpz_init_set(b_abs,(int_number)b);
346  mpz_init_set_si(r,(long)0);
347  if (mpz_isNeg(b_abs)) mpz_neg(b_abs, b_abs); // b_abs now represents |b|
348  mpz_gcd(g, (int_number) nrnModul, b_abs); // g is now as above
349  if (mpz_cmp_si(g, (long)1) != 0) mpz_mod(r, (int_number)a, g); // the case g <> 1
350  mpz_clear(g);
351  mpz_clear(b_abs);
352  omFreeBin(g, gmp_nrn_bin);
353  omFreeBin(b_abs, gmp_nrn_bin);
354  return (number)r;
355}
356
357number nrnIntDiv (number a,number b)
358{
359  int_number erg = (int_number) omAllocBin(gmp_nrn_bin);
360  mpz_init(erg);
361  if (a == NULL) a = (number) nrnModul;
362  mpz_tdiv_q(erg, (int_number) a, (int_number) b);
363  return (number) erg;
364}
365
366/*
367 * Helper function for computing the module
368 */
369
370int_number nrnMapCoef = NULL;
371
372number nrnMapModN(number from)
373{
374  return nrnMult(from, (number) nrnMapCoef);
375}
376
377number nrnMap2toM(number from)
378{
379  int_number erg = (int_number) omAllocBin(gmp_nrn_bin);
380  mpz_init(erg);
381  mpz_mul_ui(erg, nrnMapCoef, (NATNUMBER) from);
382  mpz_mod(erg, erg, nrnModul);
383  return (number) erg;
384}
385
386number nrnMapZp(number from)
387{
388  int_number erg = (int_number) omAllocBin(gmp_nrn_bin);
389  mpz_init(erg);
390  mpz_mul_si(erg, nrnMapCoef, (NATNUMBER) from);
391  mpz_mod(erg, erg, nrnModul);
392  return (number) erg;
393}
394
395number nrnMapGMP(number from)
396{
397  int_number erg = (int_number) omAllocBin(gmp_nrn_bin);
398  mpz_init(erg);
399  mpz_mod(erg, (int_number) from, nrnModul);
400  return (number) erg;
401}
402
403number nrnMapQ(number from)
404{
405  int_number erg = (int_number) omAllocBin(gmp_nrn_bin);
406  mpz_init(erg);
407  nlGMP(from, (number) erg);
408  mpz_mod(erg, erg, nrnModul);
409  return (number) erg;
410}
411
412nMapFunc nrnSetMap(ring src, ring dst)
413{
414  /* dst = currRing */
415  if (rField_is_Ring_Z(src))
416  {
417    return nrnMapGMP;
418  }
419  if (rField_is_Q(src))
420  {
421    return nrnMapQ;
422  }
423  // Some type of Z/n ring / field
424  if (rField_is_Ring_ModN(src) || rField_is_Ring_PtoM(src) || rField_is_Ring_2toM(src) || rField_is_Zp(src))
425  {
426    if (   (src->ringtype > 0)
427        && (mpz_cmp(src->ringflaga, dst->ringflaga) == 0)
428        && (src->ringflagb == dst->ringflagb)) return nrnMapGMP;
429    else
430    {
431      int_number nrnMapModul = (int_number) omAllocBin(gmp_nrn_bin);
432      // Computing the n of Z/n
433      if (rField_is_Zp(src))
434      {
435        mpz_init_set_si(nrnMapModul, src->ch);
436      }
437      else
438      {
439        mpz_init(nrnMapModul);
440        mpz_set(nrnMapModul, src->ringflaga);
441        mpz_pow_ui(nrnMapModul, nrnMapModul, src->ringflagb);
442      }
443      // nrnMapCoef = 1 in dst       if dst is a subring of src
444      // nrnMapCoef = 0 in dst / src if src is a subring of dst
445      if (nrnMapCoef == NULL)
446      {
447        nrnMapCoef = (int_number) omAllocBin(gmp_nrn_bin);
448        mpz_init(nrnMapCoef);
449      }
450      if (mpz_divisible_p(nrnMapModul, nrnModul))
451      {
452        mpz_set_si(nrnMapCoef, 1);
453      }
454      else
455      if (nrnDivBy(NULL, (number) nrnMapModul))
456      {
457        mpz_divexact(nrnMapCoef, nrnModul, nrnMapModul);
458        int_number tmp = nrnModul;
459        nrnModul = nrnMapModul;
460        if (!nrnIsUnit((number) nrnMapCoef))
461        {
462          nrnModul = tmp;
463          nrnDelete((number*) &nrnMapModul, currRing);
464          return NULL;
465        }
466        int_number inv = (int_number) nrnInvers((number) nrnMapCoef);
467        nrnModul = tmp;
468        mpz_mul(nrnMapCoef, nrnMapCoef, inv);
469        mpz_mod(nrnMapCoef, nrnMapCoef, nrnModul);
470        nrnDelete((number*) &inv, currRing);
471      }
472      else
473      {
474        nrnDelete((number*) &nrnMapModul, currRing);
475        return NULL;
476      }
477      nrnDelete((number*) &nrnMapModul, currRing);
478      if (rField_is_Ring_2toM(src))
479        return nrnMap2toM;
480      else if (rField_is_Zp(src))
481        return nrnMapZp;
482      else
483        return nrnMapModN;
484    }
485  }
486  return NULL;      // default
487}
488
489/*
490 * set the exponent (allocate and init tables) (TODO)
491 */
492
493void nrnSetExp(int m, ring r)
494{
495  if ((nrnModul != NULL) && (mpz_cmp(nrnModul, r->ringflaga) == 0) && (nrnExponent == r->ringflagb)) return;
496
497  nrnExponent = r->ringflagb;
498  if (nrnModul == NULL)
499  {
500    nrnModul = (int_number) omAllocBin(gmp_nrn_bin);
501    mpz_init(nrnModul);
502    nrnMinusOne = (int_number) omAllocBin(gmp_nrn_bin);
503    mpz_init(nrnMinusOne);
504  }
505  mpz_set(nrnModul, r->ringflaga);
506  mpz_pow_ui(nrnModul, nrnModul, nrnExponent);
507  mpz_sub_ui(nrnMinusOne, nrnModul, 1);
508}
509
510void nrnInitExp(int m, ring r)
511{
512  nrnSetExp(m, r);
513
514  if (mpz_cmp_ui(nrnModul,2) <= 0)
515  {
516    WarnS("nrnInitExp failed");
517  }
518}
519
520#ifdef LDEBUG
521BOOLEAN nrnDBTest (number a, const char *f, const int l)
522{
523  if ( (mpz_cmp_si((int_number) a, 0) < 0) || (mpz_cmp((int_number) a, nrnModul) > 0) )
524  {
525    return FALSE;
526  }
527  return TRUE;
528}
529#endif
530
531void nrnWrite (number &a)
532{
533  char *s,*z;
534  if (a==NULL)
535  {
536    StringAppendS("o");
537  }
538  else
539  {
540    int l=mpz_sizeinbase((int_number) a, 10);
541    if (a->s<2) l=si_max(l,mpz_sizeinbase((int_number) a,10));
542    l+=2;
543    s=(char*)omAlloc(l);
544    z=mpz_get_str(s,10,(int_number) a);
545    StringAppendS(z);
546    omFreeSize((ADDRESS)s,l);
547  }
548}
549
550/*2
551* extracts a long integer from s, returns the rest    (COPY FROM longrat0.cc)
552*/
553static const char * nlCPEatLongC(char *s, MP_INT *i)
554{
555  const char * start=s;
556  if (!(*s >= '0' && *s <= '9'))
557  {
558    mpz_init_set_si(i, 1);
559    return s;
560  }
561  mpz_init(i);
562  while (*s >= '0' && *s <= '9') s++;
563  if (*s=='\0')
564  {
565    mpz_set_str(i,start,10);
566  }
567  else
568  {
569    char c=*s;
570    *s='\0';
571    mpz_set_str(i,start,10);
572    *s=c;
573  }
574  return s;
575}
576
577const char * nrnRead (const char *s, number *a)
578{
579  int_number z = (int_number) omAllocBin(gmp_nrn_bin);
580  {
581    s = nlCPEatLongC((char *)s, z);
582  }
583  mpz_mod(z, z, nrnModul);
584  *a = (number) z;
585  return s;
586}
587#endif
Note: See TracBrowser for help on using the repository browser.