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

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