source: git/libpolys/coeffs/rmodulon.cc @ 6ce030f

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