source: git/coeffs/rmodulon.cc @ 7d90aa

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