source: git/kernel/rmodulon.cc @ 2f2bb21

spielwiese
Last change on this file since 2f2bb21 was c1526f, checked in by Hans Schönemann <hannes@…>, 15 years ago
*hannes: no direct include of gmp.h git-svn-id: file:///usr/local/Singular/svn/trunk@11220 2c84dea3-7e68-4137-9b89-c4e89433aadc
  • Property mode set to 100644
File size: 13.4 KB
Line 
1/****************************************
2*  Computer Algebra System SINGULAR     *
3****************************************/
4/* $Id: rmodulon.cc,v 1.31 2008-12-08 15:00:43 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_RINGMODN
23
24omBin gmp_nrn_bin = omGetSpecBin(sizeof(MP_INT));
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); // evtl. spaeter mit 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); // evtl. spaeter mit 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); // evtl. spaeter mit 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); // evtl. spaeter mit 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); // evtl. spaeter mit 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); // evtl. spaeter mit 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 !!! TODO
116//  int_number erg = (int_number) omAllocBin(gmp_nrn_bin); // evtl. spaeter mit bin
117//  mpz_init(erg);
118  mpz_sub((int_number) c, nrnModul, (int_number) c);
119  return c;
120}
121
122number  nrnInvers (number c)
123{
124  int_number erg = (int_number) omAllocBin(gmp_nrn_bin); // evtl. spaeter mit bin
125  mpz_init(erg);
126  mpz_invert(erg, (int_number) c, nrnModul);
127  return (number) erg;
128}
129
130/*
131 * Give the smallest non unit k, such that a * x = k = b * y has a solution
132 * TODO: lcm(gcd,gcd) besser als gcd(lcm) ?
133 */
134number nrnLcm (number a,number b,ring r)
135{
136  number erg = nrnGcd(NULL, a, NULL);
137  number tmp = nrnGcd(NULL, b, NULL);
138  mpz_lcm((int_number) erg, (int_number) erg, (int_number) tmp);
139  nrnDelete(&tmp, NULL);
140  return (number) erg;
141}
142
143/*
144 * Give the largest non unit k, such that a = x * k, b = y * k has
145 * a solution.
146 */
147number nrnGcd (number a,number b,ring r)
148{
149  if ((a == NULL) && (b == NULL)) return nrnInit(0);
150  int_number erg = (int_number) omAllocBin(gmp_nrn_bin); // evtl. spaeter mit bin
151  mpz_init_set(erg, nrnModul);
152  if (a != NULL) mpz_gcd(erg, erg, (int_number) a);
153  if (b != NULL) mpz_gcd(erg, erg, (int_number) b);
154  return (number) erg;
155}
156
157/* Not needed any more, but may have room for improvement
158number nrnGcd3 (number a,number b, number c,ring r)
159{
160  int_number erg = (int_number) omAllocBin(gmp_nrn_bin); // evtl. spaeter mit bin
161  mpz_init(erg);
162  if (a == NULL) a = (number) nrnModul;
163  if (b == NULL) b = (number) nrnModul;
164  if (c == NULL) c = (number) nrnModul;
165  mpz_gcd(erg, (int_number) a, (int_number) b);
166  mpz_gcd(erg, erg, (int_number) c);
167  mpz_gcd(erg, erg, nrnModul);
168  return (number) erg;
169}
170*/
171
172/*
173 * Give the largest non unit k, such that a = x * k, b = y * k has
174 * a solution and r, s, s.t. k = s*a + t*b
175 */
176number  nrnExtGcd (number a, number b, number *s, number *t)
177{
178  int_number erg = (int_number) omAllocBin(gmp_nrn_bin); // evtl. spaeter mit bin
179  int_number bs = (int_number) omAllocBin(gmp_nrn_bin); // evtl. spaeter mit bin
180  int_number bt = (int_number) omAllocBin(gmp_nrn_bin); // evtl. spaeter mit bin
181  mpz_init(erg);
182  mpz_init(bs);
183  mpz_init(bt);
184  mpz_gcdext(erg, bs, bt, (int_number) a, (int_number) b);
185  mpz_mod(bs, bs, nrnModul);
186  mpz_mod(bt, bt, nrnModul);
187  *s = (number) bs;
188  *t = (number) bt;
189  return (number) erg;
190}
191
192BOOLEAN nrnIsZero (number  a)
193{
194  return 0 == mpz_cmpabs_ui((int_number) a, 0);
195}
196
197BOOLEAN nrnIsOne (number a)
198{
199  return 0 == mpz_cmp_si((int_number) a, 1);
200}
201
202BOOLEAN nrnIsMOne (number a)
203{
204  return 0 == mpz_cmp((int_number) a, nrnMinusOne);
205}
206
207BOOLEAN nrnEqual (number a,number b)
208{
209  return 0 == mpz_cmp((int_number) a, (int_number) b);
210}
211
212BOOLEAN nrnGreater (number a,number b)
213{
214  return 0 < mpz_cmp((int_number) a, (int_number) b);
215}
216
217BOOLEAN nrnGreaterZero (number k)
218{
219  return 0 <= mpz_cmp_si((int_number) k, 0);
220}
221
222BOOLEAN nrnIsUnit (number a)
223{
224  number tmp = nrnGcd(a, (number) nrnModul, NULL);
225  bool res = nrnIsOne(tmp);
226  nrnDelete(&tmp, NULL);
227  return res;
228}
229
230number  nrnGetUnit (number k)
231{
232  if (mpz_divisible_p(nrnModul, (int_number) k)) return nrnInit(1);
233
234  int_number unit = (int_number) nrnGcd(k, 0, currRing);
235  mpz_tdiv_q(unit, (int_number) k, unit);
236  int_number gcd = (int_number) nrnGcd((number) unit, 0, currRing);
237  if (!nrnIsOne((number) gcd))
238  {
239    int_number ctmp;
240    // tmp := unit^2
241    int_number tmp = (int_number) nrnMult((number) unit,(number) unit);
242    // gcd_new := gcd(tmp, 0)
243    int_number gcd_new = (int_number) nrnGcd((number) tmp, 0, currRing);
244    while (!nrnEqual((number) gcd_new,(number) gcd))
245    {
246      // gcd := gcd_new
247      ctmp = gcd;
248      gcd = gcd_new;
249      gcd_new = ctmp;
250      // tmp := tmp * unit
251      mpz_mul(tmp, tmp, unit);
252      mpz_mod(tmp, tmp, nrnModul);
253      // gcd_new := gcd(tmp, 0)
254      mpz_gcd(gcd_new, tmp, nrnModul);
255    }
256    // unit := unit + nrnModul / gcd_new
257    mpz_tdiv_q(tmp, nrnModul, gcd_new);
258    mpz_add(unit, unit, tmp);
259    mpz_mod(unit, unit, nrnModul);
260    nrnDelete((number*) &gcd_new, NULL);
261    nrnDelete((number*) &tmp, NULL);
262  }
263  nrnDelete((number*) &gcd, NULL);
264  return (number) unit;
265}
266
267BOOLEAN nrnDivBy (number a,number b)
268{
269  if (a == NULL)
270    return mpz_divisible_p(nrnModul, (int_number) b);
271  else
272    return mpz_divisible_p((int_number) a, (int_number) b);
273  /*
274  number bs = nrnGcd(a, b, NULL);
275  mpz_tdiv_q((int_number) bs, (int_number) b, (int_number) bs);
276  bool res = nrnIsUnit(bs);
277  nrnDelete(&bs, NULL);
278  return res;
279  */
280}
281
282int nrnDivComp(number a, number b)
283{
284  if (nrnEqual(a, b)) return 0;
285  if (mpz_divisible_p((int_number) a, (int_number) b)) return -1;
286  if (mpz_divisible_p((int_number) b, (int_number) a)) return 1;
287  return 2;
288}
289
290number nrnDiv (number a,number b)
291{
292  if (a == NULL) a = (number) nrnModul;
293  int_number erg = (int_number) omAllocBin(gmp_nrn_bin); // evtl. spaeter mit bin
294  mpz_init(erg);
295  if (mpz_divisible_p((int_number) a, (int_number) b))
296  {
297    mpz_divexact(erg, (int_number) a, (int_number) b);
298    return (number) erg;
299  }
300  else
301  {
302    int_number gcd = (int_number) nrnGcd(a, b, NULL);
303    mpz_divexact(erg, (int_number) b, gcd);
304    if (!nrnIsUnit((number) erg))
305    {
306      WarnS("Division not possible, even by cancelling zero divisors.");
307      WarnS("Result is integer division without remainder.");
308      mpz_tdiv_q(erg, (int_number) a, (int_number) b);
309      nrnDelete((number*) &gcd, NULL);
310      return (number) erg;
311    }
312    // a / gcd(a,b) * [b / gcd (a,b)]^(-1)
313    int_number tmp = (int_number) nrnInvers((number) erg);
314    mpz_divexact(erg, (int_number) a, gcd);
315    mpz_mul(erg, erg, tmp);
316    nrnDelete((number*) &gcd, NULL);
317    nrnDelete((number*) &tmp, NULL);
318    mpz_mod(erg, erg, nrnModul);
319    return (number) erg;
320  }
321}
322
323number nrnIntDiv (number a,number b)
324{
325  int_number erg = (int_number) omAllocBin(gmp_nrn_bin); // evtl. spaeter mit bin
326  mpz_init(erg);
327  if (a == NULL) a = (number) nrnModul;
328  mpz_tdiv_q(erg, (int_number) a, (int_number) b);
329  return (number) erg;
330}
331
332/*
333 * Helper function for computing the module
334 */
335
336int_number nrnMapCoef = NULL;
337
338number nrnMapModN(number from)
339{
340  return nrnMult(from, (number) nrnMapCoef);
341}
342
343number nrnMap2toM(number from)
344{
345  int_number erg = (int_number) omAllocBin(gmp_nrn_bin); // evtl. spaeter mit bin
346  mpz_init(erg);
347  mpz_mul_ui(erg, nrnMapCoef, (NATNUMBER) from);
348  mpz_mod(erg, erg, nrnModul);
349  return (number) erg;
350}
351
352number nrnMapZp(number from)
353{
354  int_number erg = (int_number) omAllocBin(gmp_nrn_bin); // evtl. spaeter mit bin
355  mpz_init(erg);
356  mpz_mul_si(erg, nrnMapCoef, (NATNUMBER) from);
357  mpz_mod(erg, erg, nrnModul);
358  return (number) erg;
359}
360
361number nrnMapGMP(number from)
362{
363  int_number erg = (int_number) omAllocBin(gmp_nrn_bin); // evtl. spaeter mit bin
364  mpz_init(erg);
365  mpz_mod(erg, (int_number) from, nrnModul);
366  return (number) erg;
367}
368
369number nrnMapQ(number from)
370{
371  int_number erg = (int_number) omAllocBin(gmp_nrn_bin); // evtl. spaeter mit bin
372  mpz_init(erg);
373  nlGMP(from, (number) erg);
374  mpz_mod(erg, erg, nrnModul);
375  return (number) erg;
376}
377
378nMapFunc nrnSetMap(ring src, ring dst)
379{
380  /* dst = currRing */
381  if (rField_is_Ring_Z(src))
382  {
383    return nrnMapGMP;
384  }
385  if (rField_is_Q(src))
386  {
387    return nrnMapQ;
388  }
389  // Some type of Z/n ring / field
390  if (rField_is_Ring_ModN(src) || rField_is_Ring_PtoM(src) || rField_is_Ring_2toM(src) || rField_is_Zp(src))
391  {
392    if (   (src->ringtype > 0)
393        && (mpz_cmp(src->ringflaga, dst->ringflaga) == 0)
394        && (src->ringflagb == dst->ringflagb)) return nrnMapGMP;
395    else
396    {
397      int_number nrnMapModul = (int_number) omAllocBin(gmp_nrn_bin); // evtl. spaeter mit bin
398      // Computing the n of Z/n
399      if (rField_is_Zp(src))
400      {
401        mpz_init_set_si(nrnMapModul, src->ch);
402      }
403      else
404      {
405        mpz_init(nrnMapModul);
406        mpz_set(nrnMapModul, src->ringflaga);
407        mpz_pow_ui(nrnMapModul, nrnMapModul, src->ringflagb);
408      }
409      // nrnMapCoef = 1 in dst       if dst is a subring of src
410      // nrnMapCoef = 0 in dst / src if src is a subring of dst
411      if (nrnMapCoef == NULL)
412      {
413        nrnMapCoef = (int_number) omAllocBin(gmp_nrn_bin); // evtl. spaeter mit bin
414        mpz_init(nrnMapCoef);
415      }
416      if (mpz_divisible_p(nrnMapModul, nrnModul))
417      {
418        mpz_set_si(nrnMapCoef, 1);
419      }
420      else
421      if (nrnDivBy(NULL, (number) nrnMapModul))
422      {
423        mpz_divexact(nrnMapCoef, nrnModul, nrnMapModul);
424        int_number tmp = nrnModul;
425        nrnModul = nrnMapModul;
426        if (!nrnIsUnit((number) nrnMapCoef))
427        {
428          nrnModul = tmp;
429          nrnDelete((number*) &nrnMapModul, currRing);
430          return NULL;
431        }
432        int_number inv = (int_number) nrnInvers((number) nrnMapCoef);
433        nrnModul = tmp;
434        mpz_mul(nrnMapCoef, nrnMapCoef, inv);
435        mpz_mod(nrnMapCoef, nrnMapCoef, nrnModul);
436        nrnDelete((number*) &inv, currRing);
437      }
438      else
439      {
440        nrnDelete((number*) &nrnMapModul, currRing);
441        return NULL;
442      }
443      nrnDelete((number*) &nrnMapModul, currRing);
444      if (rField_is_Ring_2toM(src))
445        return nrnMap2toM;
446      else if (rField_is_Zp(src))
447        return nrnMapZp;
448      else
449        return nrnMapModN;
450    }
451  }
452  return NULL;      // default
453}
454
455/*
456 * set the exponent (allocate and init tables) (TODO)
457 */
458
459void nrnSetExp(int m, ring r)
460{
461  if ((nrnModul != NULL) && (mpz_cmp(nrnModul, r->ringflaga) == 0) && (nrnExponent == r->ringflagb)) return;
462
463  nrnExponent = r->ringflagb;
464  if (nrnModul == NULL)
465  {
466    nrnModul = (int_number) omAllocBin(gmp_nrn_bin); // evtl. spaeter mit bin
467    mpz_init(nrnModul);
468    nrnMinusOne = (int_number) omAllocBin(gmp_nrn_bin); // evtl. spaeter mit bin
469    mpz_init(nrnMinusOne);
470  }
471  mpz_set(nrnModul, r->ringflaga);
472  mpz_pow_ui(nrnModul, nrnModul, nrnExponent);
473  mpz_sub_ui(nrnMinusOne, nrnModul, 1);
474}
475
476void nrnInitExp(int m, ring r)
477{
478  nrnSetExp(m, r);
479
480  if (mpz_cmp_ui(nrnModul,2) <= 0)
481  {
482    WarnS("nrnInitExp failed");
483  }
484}
485
486#ifdef LDEBUG
487BOOLEAN nrnDBTest (number a, const char *f, const int l)
488{
489  if ( (mpz_cmp_si((int_number) a, 0) < 0) || (mpz_cmp((int_number) a, nrnModul) > 0) )
490  {
491    return FALSE;
492  }
493  return TRUE;
494}
495#endif
496
497void nrnWrite (number &a)
498{
499  char *s,*z;
500  if (a==NULL)
501  {
502    StringAppendS("o");
503  }
504  else
505  {
506    int l=mpz_sizeinbase((int_number) a, 10);
507    if (a->s<2) l=si_max(l,mpz_sizeinbase((int_number) a,10));
508    l+=2;
509    s=(char*)omAlloc(l);
510    z=mpz_get_str(s,10,(int_number) a);
511    StringAppendS(z);
512    omFreeSize((ADDRESS)s,l);
513  }
514}
515
516/*2
517* extracts a long integer from s, returns the rest    (COPY FROM longrat0.cc)
518*/
519static const char * nlCPEatLongC(char *s, MP_INT *i)
520{
521  const char * start=s;
522  if (!(*s >= '0' && *s <= '9'))
523  {
524    mpz_init_set_si(i, 1);
525    return s;
526  }
527  mpz_init(i);
528  while (*s >= '0' && *s <= '9') s++;
529  if (*s=='\0')
530  {
531    mpz_set_str(i,start,10);
532  }
533  else
534  {
535    char c=*s;
536    *s='\0';
537    mpz_set_str(i,start,10);
538    *s=c;
539  }
540  return s;
541}
542
543const char * nrnRead (const char *s, number *a)
544{
545  int_number z = (int_number) omAllocBin(gmp_nrn_bin); // evtl. spaeter mit bin
546  {
547    s = nlCPEatLongC((char *)s, z);
548  }
549  mpz_mod(z, z, nrnModul);
550  *a = (number) z;
551  return s;
552}
553#endif
Note: See TracBrowser for help on using the repository browser.