source: git/libpolys/coeffs/rmodulon.cc @ 7a8011

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