source: git/kernel/rmodulon.cc @ 675ce47

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