source: git/coeffs/rmodulon.cc @ c08834

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