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

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