source: git/coeffs/rmodulon.cc @ f1c465f

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