source: git/libpolys/coeffs/rmodulon.cc @ 488056

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