source: git/coeffs/rmodulon.cc @ 2d805a

spielwiese
Last change on this file since 2d805a was 2d805a, checked in by Oleksandr Motsak <motsak@…>, 13 years ago
Fixed to "#include <component/header.h>" (even for config.h!)
  • Property mode set to 100644
File size: 15.9 KB
Line 
1/****************************************
2*  Computer Algebra System SINGULAR     *
3****************************************/
4/* $Id$ */
5/*
6* ABSTRACT: numbers modulo n
7*/
8
9#include <coeffs/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 <coeffs/si_gmp.h>
23
24#include <string.h>
25
26extern omBin gmp_nrz_bin;
27
28/* for initializing function pointers */
29BOOLEAN nrnInitChar (coeffs r, void* p)
30{
31 
32  nrnInitExp((int)(long)(p), r);
33
34  r->cfInit        = nrnInit;
35  r->cfDelete      = nrnDelete;
36  r->cfCopy        = nrnCopy;
37  r->cfSize        = nrnSize;
38  r->cfInt         = nrnInt;
39  r->cfAdd         = nrnAdd;
40  r->cfSub         = nrnSub;
41  r->cfMult        = nrnMult;
42  r->cfDiv         = nrnDiv;
43  r->cfIntDiv      = nrnIntDiv;
44  r->cfIntMod      = nrnMod;
45  r->cfExactDiv    = nrnDiv;
46  r->cfNeg         = nrnNeg;
47  r->cfInvers      = nrnInvers;
48  r->cfDivBy       = nrnDivBy;
49  r->cfDivComp     = nrnDivComp;
50  r->cfGreater     = nrnGreater;
51  r->cfEqual       = nrnEqual;
52  r->cfIsZero      = nrnIsZero;
53  r->cfIsOne       = nrnIsOne;
54  r->cfIsMOne      = nrnIsMOne;
55  r->cfGreaterZero = nrnGreaterZero;
56  r->cfWrite       = nrnWrite;
57  r->cfRead        = nrnRead;
58  r->cfPower       = nrnPower;
59  r->cfSetMap      = nrnSetMap;
60  r->cfNormalize   = ndNormalize;
61  r->cfLcm         = nrnLcm;
62  r->cfGcd         = nrnGcd;
63  r->cfIsUnit      = nrnIsUnit;
64  r->cfGetUnit     = nrnGetUnit;
65  r->cfExtGcd      = nrnExtGcd;
66  r->cfName        = ndName;
67#ifdef LDEBUG
68  r->cfDBTest      = nrnDBTest;
69#endif
70  return FALSE;
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->modNumber);
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->modNumber);
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->modNumber);
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->modNumber);
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->modNumber);
148  return (number) erg;
149}
150
151number nrnNeg(number c, const coeffs r)
152{
153  // Attention: This method operates in-place.
154  mpz_sub((int_number)c, r->modNumber, (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->modNumber);
163  return (number) erg;
164}
165
166/*
167 * Give the smallest k, such that a * x = k = b * y has a solution
168 * TODO: lcm(gcd,gcd) better than 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 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->modNumber);
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
194   number 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->modNumber;
199  if (b == NULL) b = (number)r->modNumber;
200  if (c == NULL) c = (number)r->modNumber;
201  mpz_gcd(erg, (int_number)a, (int_number)b);
202  mpz_gcd(erg, erg, (int_number)c);
203  mpz_gcd(erg, erg, r->modNumber);
204  return (number)erg;
205}
206*/
207
208/*
209 * Give the largest 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->modNumber);
222  mpz_mod(bt, bt, r->modNumber);
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  mpz_t t; mpz_init_set(t, (int_number)a);
250  mpz_add_ui(t, t, 1);
251  bool erg = (0 == mpz_cmp(t, r->modNumber));
252  mpz_clear(t);
253  return erg;
254}
255
256BOOLEAN nrnEqual(number a, number b, const coeffs r)
257{
258  return 0 == mpz_cmp((int_number)a, (int_number)b);
259}
260
261BOOLEAN nrnGreater(number a, number b, const coeffs r)
262{
263  return 0 < mpz_cmp((int_number)a, (int_number)b);
264}
265
266BOOLEAN nrnGreaterZero(number k, const coeffs r)
267{
268  return 0 < mpz_cmp_si((int_number)k, 0);
269}
270
271BOOLEAN nrnIsUnit(number a, const coeffs r)
272{
273  number tmp = nrnGcd(a, (number)r->modNumber, r);
274  bool res = nrnIsOne(tmp, r);
275  nrnDelete(&tmp, NULL);
276  return res;
277}
278
279number nrnGetUnit(number k, const coeffs r)
280{
281  if (mpz_divisible_p(r->modNumber, (int_number)k)) return nrnInit(1,r);
282
283  int_number unit = (int_number)nrnGcd(k, 0, r);
284  mpz_tdiv_q(unit, (int_number)k, unit);
285  int_number gcd = (int_number)nrnGcd((number)unit, 0, r);
286  if (!nrnIsOne((number)gcd,r))
287  {
288    int_number ctmp;
289    // tmp := unit^2
290    int_number tmp = (int_number) nrnMult((number) unit,(number) unit,r);
291    // gcd_new := gcd(tmp, 0)
292    int_number gcd_new = (int_number) nrnGcd((number) tmp, 0, r);
293    while (!nrnEqual((number) gcd_new,(number) gcd,r))
294    {
295      // gcd := gcd_new
296      ctmp = gcd;
297      gcd = gcd_new;
298      gcd_new = ctmp;
299      // tmp := tmp * unit
300      mpz_mul(tmp, tmp, unit);
301      mpz_mod(tmp, tmp, r->modNumber);
302      // gcd_new := gcd(tmp, 0)
303      mpz_gcd(gcd_new, tmp, r->modNumber);
304    }
305    // unit := unit + modNumber / gcd_new
306    mpz_tdiv_q(tmp, r->modNumber, gcd_new);
307    mpz_add(unit, unit, tmp);
308    mpz_mod(unit, unit, r->modNumber);
309    nrnDelete((number*) &gcd_new, NULL);
310    nrnDelete((number*) &tmp, NULL);
311  }
312  nrnDelete((number*) &gcd, NULL);
313  return (number)unit;
314}
315
316BOOLEAN nrnDivBy(number a, number b, const coeffs r)
317{
318  if (a == NULL)
319    return mpz_divisible_p(r->modNumber, (int_number)b);
320  else
321  { /* b divides a iff b/gcd(a, b) is a unit in the given ring: */
322    number n = nrnGcd(a, b, r);
323    mpz_tdiv_q((int_number)n, (int_number)b, (int_number)n);
324    bool result = nrnIsUnit(n, r);
325    nrnDelete(&n, NULL);
326    return result;
327  }
328}
329
330int nrnDivComp(number a, number b, const coeffs r)
331{
332  if (nrnEqual(a, b,r)) return 2;
333  if (mpz_divisible_p((int_number) a, (int_number) b)) return -1;
334  if (mpz_divisible_p((int_number) b, (int_number) a)) return 1;
335  return 0;
336}
337
338number nrnDiv(number a, number b, const coeffs r)
339{
340  if (a == NULL) a = (number)r->modNumber;
341  int_number erg = (int_number)omAllocBin(gmp_nrz_bin);
342  mpz_init(erg);
343  if (mpz_divisible_p((int_number)a, (int_number)b))
344  {
345    mpz_divexact(erg, (int_number)a, (int_number)b);
346    return (number)erg;
347  }
348  else
349  {
350    int_number gcd = (int_number)nrnGcd(a, b, r);
351    mpz_divexact(erg, (int_number)b, gcd);
352    if (!nrnIsUnit((number)erg, r))
353    {
354      WerrorS("Division not possible, even by cancelling zero divisors.");
355      WerrorS("Result is integer division without remainder.");
356      mpz_tdiv_q(erg, (int_number) a, (int_number) b);
357      nrnDelete((number*) &gcd, NULL);
358      return (number)erg;
359    }
360    // a / gcd(a,b) * [b / gcd (a,b)]^(-1)
361    int_number tmp = (int_number)nrnInvers((number) erg,r);
362    mpz_divexact(erg, (int_number)a, gcd);
363    mpz_mul(erg, erg, tmp);
364    nrnDelete((number*) &gcd, NULL);
365    nrnDelete((number*) &tmp, NULL);
366    mpz_mod(erg, erg, r->modNumber);
367    return (number)erg;
368  }
369}
370
371number nrnMod(number a, number b, const coeffs r)
372{
373  /*
374    We need to return the number rr which is uniquely determined by the
375    following two properties:
376      (1) 0 <= rr < |b| (with respect to '<' and '<=' performed in Z x Z)
377      (2) There exists some k in the integers Z such that a = k * b + rr.
378    Consider g := gcd(n, |b|). Note that then |b|/g is a unit in Z/n.
379    Now, there are three cases:
380      (a) g = 1
381          Then |b| is a unit in Z/n, i.e. |b| (and also b) divides a.
382          Thus rr = 0.
383      (b) g <> 1 and g divides a
384          Then a = (a/g) * (|b|/g)^(-1) * b (up to sign), i.e. again rr = 0.
385      (c) g <> 1 and g does not divide a
386          Then denote the division with remainder of a by g as this:
387          a = s * g + t. Then t = a - s * g = a - s * (|b|/g)^(-1) * |b|
388          fulfills (1) and (2), i.e. rr := t is the correct result. Hence
389          in this third case, rr is the remainder of division of a by g in Z.
390     Remark: according to mpz_mod: a,b are always non-negative
391  */
392  int_number g = (int_number)omAllocBin(gmp_nrz_bin);
393  int_number rr = (int_number)omAllocBin(gmp_nrz_bin);
394  mpz_init(g);
395  mpz_init_set_si(rr, 0);
396  mpz_gcd(g, (int_number)r->modNumber, (int_number)b); // g is now as above
397  if (mpz_cmp_si(g, (long)1) != 0) mpz_mod(rr, (int_number)a, g); // the case g <> 1
398  mpz_clear(g);
399  omFreeBin(g, gmp_nrz_bin);
400  return (number)rr;
401}
402
403number nrnIntDiv(number a, number b, const coeffs r)
404{
405  int_number erg = (int_number)omAllocBin(gmp_nrz_bin);
406  mpz_init(erg);
407  if (a == NULL) a = (number)r->modNumber;
408  mpz_tdiv_q(erg, (int_number)a, (int_number)b);
409  return (number)erg;
410}
411
412/*
413 * Helper function for computing the module
414 */
415
416int_number nrnMapCoef = NULL;
417
418number nrnMapModN(number from, const coeffs src, const coeffs dst)
419{
420  return nrnMult(from, (number) nrnMapCoef, dst);
421}
422
423number nrnMap2toM(number from, const coeffs src, const coeffs dst)
424{
425  int_number erg = (int_number)omAllocBin(gmp_nrz_bin);
426  mpz_init(erg);
427  mpz_mul_ui(erg, nrnMapCoef, (NATNUMBER)from);
428  mpz_mod(erg, erg, dst->modNumber);
429  return (number)erg;
430}
431
432number nrnMapZp(number from, const coeffs src, const coeffs dst)
433{
434  int_number erg = (int_number)omAllocBin(gmp_nrz_bin);
435  mpz_init(erg);
436  // TODO: use npInt(...)
437  mpz_mul_si(erg, nrnMapCoef, (NATNUMBER)from);
438  mpz_mod(erg, erg, dst->modNumber);
439  return (number)erg;
440}
441
442number nrnMapGMP(number from, const coeffs src, const coeffs dst)
443{
444  int_number erg = (int_number)omAllocBin(gmp_nrz_bin);
445  mpz_init(erg);
446  mpz_mod(erg, (int_number)from, dst->modNumber);
447  return (number)erg;
448}
449
450number nrnMapQ(number from, const coeffs src, const coeffs dst)
451{
452  int_number erg = (int_number)omAllocBin(gmp_nrz_bin);
453  mpz_init(erg);
454  nlGMP(from, (number)erg, src);
455  mpz_mod(erg, erg, src->modNumber);
456  return (number)erg;
457}
458
459nMapFunc nrnSetMap(const coeffs src, const coeffs dst)
460{
461  /* dst = currRing->cf */
462  if (nCoeff_is_Ring_Z(src))
463  {
464    return nrnMapGMP;
465  }
466  if (nCoeff_is_Q(src))
467  {
468    return nrnMapQ;
469  }
470  // Some type of Z/n ring / field
471  if (nCoeff_is_Ring_ModN(src) || nCoeff_is_Ring_PtoM(src) || nCoeff_is_Ring_2toM(src) || nCoeff_is_Zp(src))
472  {
473    if (   (src->ringtype > 0)
474        && (mpz_cmp(src->modBase, dst->modBase) == 0)
475        && (src->modExponent == dst->modExponent)) return nrnMapGMP;
476    else
477    {
478      int_number nrnMapModul = (int_number) omAllocBin(gmp_nrz_bin);
479      // Computing the n of Z/n
480      if (nCoeff_is_Zp(src))
481      {
482        mpz_init_set_si(nrnMapModul, src->ch);
483      }
484      else
485      {
486        mpz_init(nrnMapModul);
487        mpz_set(nrnMapModul, src->modNumber);
488      }
489      // nrnMapCoef = 1 in dst       if dst is a subring of src
490      // nrnMapCoef = 0 in dst / src if src is a subring of dst
491      if (nrnMapCoef == NULL)
492      {
493        nrnMapCoef = (int_number) omAllocBin(gmp_nrz_bin);
494        mpz_init(nrnMapCoef);
495      }
496      if (mpz_divisible_p(nrnMapModul, dst->modNumber))
497      {
498        mpz_set_si(nrnMapCoef, 1);
499      }
500      else
501      if (nrnDivBy(NULL, (number) nrnMapModul,dst))
502      {
503        mpz_divexact(nrnMapCoef, dst->modNumber, nrnMapModul);
504        int_number tmp = dst->modNumber;
505        dst->modNumber = nrnMapModul;
506        if (!nrnIsUnit((number) nrnMapCoef,dst))
507        {
508          dst->modNumber = tmp;
509          nrnDelete((number*) &nrnMapModul, dst);
510          return NULL;
511        }
512        int_number inv = (int_number) nrnInvers((number) nrnMapCoef,dst);
513        dst->modNumber = tmp;
514        mpz_mul(nrnMapCoef, nrnMapCoef, inv);
515        mpz_mod(nrnMapCoef, nrnMapCoef, dst->modNumber);
516        nrnDelete((number*) &inv, dst);
517      }
518      else
519      {
520        nrnDelete((number*) &nrnMapModul, dst);
521        return NULL;
522      }
523      nrnDelete((number*) &nrnMapModul, dst);
524      if (nCoeff_is_Ring_2toM(src))
525        return nrnMap2toM;
526      else if (nCoeff_is_Zp(src))
527        return nrnMapZp;
528      else
529        return nrnMapModN;
530    }
531  }
532  return NULL;      // default
533}
534
535/*
536 * set the exponent (allocate and init tables) (TODO)
537 */
538
539void nrnSetExp(int m, coeffs r)
540{
541  /* clean up former stuff */
542  if (r->modBase   != NULL) mpz_clear(r->modBase);
543  if (r->modNumber != NULL) mpz_clear(r->modNumber);
544
545  /* this is Z/m = Z/(m^1), hence set modBase = m, modExponent = 1: */
546  r->modBase = (int_number)omAllocBin(gmp_nrz_bin);
547  mpz_init(r->modBase);
548  mpz_set_ui(r->modBase, (unsigned long)m);
549  r->modExponent = 1;
550  r->modNumber = (int_number)omAllocBin(gmp_nrz_bin);
551  mpz_init(r->modNumber);
552  mpz_set(r->modNumber, r->modBase);
553  /* mpz_pow_ui(r->modNumber, r->modNumber, r->modExponent); */
554}
555
556/* We expect this ring to be Z/m for some m > 2 which is not a prime. */
557void nrnInitExp(int m, coeffs r)
558{
559  if (m <= 2) WarnS("nrnInitExp failed (m in Z/m too small)");
560  nrnSetExp(m, r);
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->modNumber) > 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->modNumber);
609  *a = (number) z;
610  return s;
611}
612#endif
613/* #ifdef HAVE_RINGS */
Note: See TracBrowser for help on using the repository browser.