source: git/kernel/rmodulon.cc @ e1634d

spielwiese
Last change on this file since e1634d was e1634d, checked in by Hans Schönemann <hannes@…>, 15 years ago
*hannes: syntax git-svn-id: file:///usr/local/Singular/svn/trunk@11941 2c84dea3-7e68-4137-9b89-c4e89433aadc
  • Property mode set to 100644
File size: 14.1 KB
Line 
1/****************************************
2*  Computer Algebra System SINGULAR     *
3****************************************/
4/* $Id: rmodulon.cc,v 1.36 2009-07-03 14:38:34 Singular 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     Remark: according to mpz_mod: a,b are always non-negative
341  */
342  int_number g = (int_number) omAllocBin(gmp_nrn_bin);
343  int_number r = (int_number) omAllocBin(gmp_nrn_bin);
344  mpz_init(g);
345  mpz_init_set_si(r,(long)0);
346  mpz_gcd(g, (int_number) nrnModul, (int_number)b); // g is now as above
347  if (mpz_cmp_si(g, (long)1) != 0) mpz_mod(r, (int_number)a, g); // the case g <> 1
348  mpz_clear(g);
349  omFreeBin(g, gmp_nrn_bin);
350  return (number)r;
351}
352
353number nrnIntDiv (number a,number b)
354{
355  int_number erg = (int_number) omAllocBin(gmp_nrn_bin);
356  mpz_init(erg);
357  if (a == NULL) a = (number) nrnModul;
358  mpz_tdiv_q(erg, (int_number) a, (int_number) b);
359  return (number) erg;
360}
361
362/*
363 * Helper function for computing the module
364 */
365
366int_number nrnMapCoef = NULL;
367
368number nrnMapModN(number from)
369{
370  return nrnMult(from, (number) nrnMapCoef);
371}
372
373number nrnMap2toM(number from)
374{
375  int_number erg = (int_number) omAllocBin(gmp_nrn_bin);
376  mpz_init(erg);
377  mpz_mul_ui(erg, nrnMapCoef, (NATNUMBER) from);
378  mpz_mod(erg, erg, nrnModul);
379  return (number) erg;
380}
381
382number nrnMapZp(number from)
383{
384  int_number erg = (int_number) omAllocBin(gmp_nrn_bin);
385  mpz_init(erg);
386  mpz_mul_si(erg, nrnMapCoef, (NATNUMBER) from);
387  mpz_mod(erg, erg, nrnModul);
388  return (number) erg;
389}
390
391number nrnMapGMP(number from)
392{
393  int_number erg = (int_number) omAllocBin(gmp_nrn_bin);
394  mpz_init(erg);
395  mpz_mod(erg, (int_number) from, nrnModul);
396  return (number) erg;
397}
398
399number nrnMapQ(number from)
400{
401  int_number erg = (int_number) omAllocBin(gmp_nrn_bin);
402  mpz_init(erg);
403  nlGMP(from, (number) erg);
404  mpz_mod(erg, erg, nrnModul);
405  return (number) erg;
406}
407
408nMapFunc nrnSetMap(ring src, ring dst)
409{
410  /* dst = currRing */
411  if (rField_is_Ring_Z(src))
412  {
413    return nrnMapGMP;
414  }
415  if (rField_is_Q(src))
416  {
417    return nrnMapQ;
418  }
419  // Some type of Z/n ring / field
420  if (rField_is_Ring_ModN(src) || rField_is_Ring_PtoM(src) || rField_is_Ring_2toM(src) || rField_is_Zp(src))
421  {
422    if (   (src->ringtype > 0)
423        && (mpz_cmp(src->ringflaga, dst->ringflaga) == 0)
424        && (src->ringflagb == dst->ringflagb)) return nrnMapGMP;
425    else
426    {
427      int_number nrnMapModul = (int_number) omAllocBin(gmp_nrn_bin);
428      // Computing the n of Z/n
429      if (rField_is_Zp(src))
430      {
431        mpz_init_set_si(nrnMapModul, src->ch);
432      }
433      else
434      {
435        mpz_init(nrnMapModul);
436        mpz_set(nrnMapModul, src->ringflaga);
437        mpz_pow_ui(nrnMapModul, nrnMapModul, src->ringflagb);
438      }
439      // nrnMapCoef = 1 in dst       if dst is a subring of src
440      // nrnMapCoef = 0 in dst / src if src is a subring of dst
441      if (nrnMapCoef == NULL)
442      {
443        nrnMapCoef = (int_number) omAllocBin(gmp_nrn_bin);
444        mpz_init(nrnMapCoef);
445      }
446      if (mpz_divisible_p(nrnMapModul, nrnModul))
447      {
448        mpz_set_si(nrnMapCoef, 1);
449      }
450      else
451      if (nrnDivBy(NULL, (number) nrnMapModul))
452      {
453        mpz_divexact(nrnMapCoef, nrnModul, nrnMapModul);
454        int_number tmp = nrnModul;
455        nrnModul = nrnMapModul;
456        if (!nrnIsUnit((number) nrnMapCoef))
457        {
458          nrnModul = tmp;
459          nrnDelete((number*) &nrnMapModul, currRing);
460          return NULL;
461        }
462        int_number inv = (int_number) nrnInvers((number) nrnMapCoef);
463        nrnModul = tmp;
464        mpz_mul(nrnMapCoef, nrnMapCoef, inv);
465        mpz_mod(nrnMapCoef, nrnMapCoef, nrnModul);
466        nrnDelete((number*) &inv, currRing);
467      }
468      else
469      {
470        nrnDelete((number*) &nrnMapModul, currRing);
471        return NULL;
472      }
473      nrnDelete((number*) &nrnMapModul, currRing);
474      if (rField_is_Ring_2toM(src))
475        return nrnMap2toM;
476      else if (rField_is_Zp(src))
477        return nrnMapZp;
478      else
479        return nrnMapModN;
480    }
481  }
482  return NULL;      // default
483}
484
485/*
486 * set the exponent (allocate and init tables) (TODO)
487 */
488
489void nrnSetExp(int m, ring r)
490{
491  if ((nrnModul != NULL) && (mpz_cmp(nrnModul, r->ringflaga) == 0) && (nrnExponent == r->ringflagb)) return;
492
493  nrnExponent = r->ringflagb;
494  if (nrnModul == NULL)
495  {
496    nrnModul = (int_number) omAllocBin(gmp_nrn_bin);
497    mpz_init(nrnModul);
498    nrnMinusOne = (int_number) omAllocBin(gmp_nrn_bin);
499    mpz_init(nrnMinusOne);
500  }
501  mpz_set(nrnModul, r->ringflaga);
502  mpz_pow_ui(nrnModul, nrnModul, nrnExponent);
503  mpz_sub_ui(nrnMinusOne, nrnModul, 1);
504}
505
506void nrnInitExp(int m, ring r)
507{
508  nrnSetExp(m, r);
509
510  if (mpz_cmp_ui(nrnModul,2) <= 0)
511  {
512    WarnS("nrnInitExp failed");
513  }
514}
515
516#ifdef LDEBUG
517BOOLEAN nrnDBTest (number a, const char *f, const int l)
518{
519  if ( (mpz_cmp_si((int_number) a, 0) < 0) || (mpz_cmp((int_number) a, nrnModul) > 0) )
520  {
521    return FALSE;
522  }
523  return TRUE;
524}
525#endif
526
527void nrnWrite (number &a)
528{
529  char *s,*z;
530  if (a==NULL)
531  {
532    StringAppendS("o");
533  }
534  else
535  {
536    int l=mpz_sizeinbase((int_number) a, 10);
537    if (a->s<2) l=si_max(l,mpz_sizeinbase((int_number) a,10));
538    l+=2;
539    s=(char*)omAlloc(l);
540    z=mpz_get_str(s,10,(int_number) a);
541    StringAppendS(z);
542    omFreeSize((ADDRESS)s,l);
543  }
544}
545
546/*2
547* extracts a long integer from s, returns the rest    (COPY FROM longrat0.cc)
548*/
549static const char * nlCPEatLongC(char *s, MP_INT *i)
550{
551  const char * start=s;
552  if (!(*s >= '0' && *s <= '9'))
553  {
554    mpz_init_set_si(i, 1);
555    return s;
556  }
557  mpz_init(i);
558  while (*s >= '0' && *s <= '9') s++;
559  if (*s=='\0')
560  {
561    mpz_set_str(i,start,10);
562  }
563  else
564  {
565    char c=*s;
566    *s='\0';
567    mpz_set_str(i,start,10);
568    *s=c;
569  }
570  return s;
571}
572
573const char * nrnRead (const char *s, number *a)
574{
575  int_number z = (int_number) omAllocBin(gmp_nrn_bin);
576  {
577    s = nlCPEatLongC((char *)s, z);
578  }
579  mpz_mod(z, z, nrnModul);
580  *a = (number) z;
581  return s;
582}
583#endif
Note: See TracBrowser for help on using the repository browser.