source: git/libpolys/coeffs/rmodulon.cc @ 417a91a

spielwiese
Last change on this file since 417a91a was 417a91a, checked in by Hans Schoenemann <hannes@…>, 5 years ago
improvements for Z/n (esp. if n prime)
  • Property mode set to 100644
File size: 27.0 KB
Line 
1/****************************************
2*  Computer Algebra System SINGULAR     *
3****************************************/
4/*
5* ABSTRACT: numbers modulo n
6*/
7#include "misc/auxiliary.h"
8#include "omalloc/omalloc.h"
9
10#include "misc/mylimits.h"
11#include "misc/prime.h" // IsPrime
12#include "reporter/reporter.h"
13
14#include "coeffs/si_gmp.h"
15#include "coeffs/coeffs.h"
16#include "coeffs/numbers.h"
17
18#include "coeffs/mpr_complex.h"
19
20#include "coeffs/longrat.h"
21#include "coeffs/rmodulon.h"
22
23#include <string.h>
24
25#ifdef HAVE_RINGS
26
27void nrnWrite (number a, const coeffs);
28#ifdef LDEBUG
29BOOLEAN nrnDBTest      (number a, const char *f, const int l, const coeffs r);
30#endif
31
32extern omBin gmp_nrz_bin;
33
34static void nrnCoeffWrite  (const coeffs r, BOOLEAN /*details*/)
35{
36  size_t l = (size_t)mpz_sizeinbase(r->modBase, 10) + 2;
37  char* s = (char*) omAlloc(l);
38  s= mpz_get_str (s, 10, r->modBase);
39
40  #ifdef TEST_ZN_AS_ZP
41  if (l<10)
42  {
43    if (nCoeff_is_Ring_ModN(r)) Print("ZZ/%s", s);
44    else if (nCoeff_is_Ring_PtoM(r)) Print("ZZ/(%s^%lu)", s, r->modExponent);
45  }
46  else
47  #endif
48  {
49    if (nCoeff_is_Ring_ModN(r)) Print("ZZ/bigint(%s)", s);
50    else if (nCoeff_is_Ring_PtoM(r)) Print("ZZ/(bigint(%s)^%lu)", s, r->modExponent);
51  }
52
53  omFreeSize((ADDRESS)s, l);
54}
55
56static char* nrnCoeffName_buff=NULL;
57static char* nrnCoeffName(const coeffs r)
58{
59  if(nrnCoeffName_buff!=NULL) omFree(nrnCoeffName_buff);
60  size_t l = (size_t)mpz_sizeinbase(r->modBase, 10) + 2;
61  nrnCoeffName_buff=(char*)omAlloc(l+6);
62  char* s = (char*) omAlloc(l);
63  s= mpz_get_str (s, 10, r->modBase);
64  if (nCoeff_is_Ring_ModN(r))
65    snprintf(nrnCoeffName_buff,l+6,"ZZ/%s",s);
66  else if (nCoeff_is_Ring_PtoM(r))
67    snprintf(nrnCoeffName_buff,l+6,"ZZ/%s^%lu",s,r->modExponent);
68  omFreeSize((ADDRESS)s, l);
69  return nrnCoeffName_buff;
70}
71
72
73static BOOLEAN nrnCoeffIsEqual(const coeffs r, n_coeffType n, void * parameter)
74{
75  /* test, if r is an instance of nInitCoeffs(n,parameter) */
76  ZnmInfo *info=(ZnmInfo*)parameter;
77  return (n==r->type) && (r->modExponent==info->exp)
78  && (mpz_cmp(r->modBase,info->base)==0);
79}
80
81static char* nrnCoeffString(const coeffs r)
82{
83  size_t l = (size_t)mpz_sizeinbase(r->modBase, 10) +2;
84  char* b = (char*) omAlloc(l);
85  b= mpz_get_str (b, 10, r->modBase);
86  char* s = (char*) omAlloc(15+l);
87  if (nCoeff_is_Ring_ModN(r)) sprintf(s,"ZZ/%s",b);
88  else /*if (nCoeff_is_Ring_PtoM(r))*/ sprintf(s,"ZZ/(bigint(%s)^%lu)",b,r->modExponent);
89  omFreeSize(b,l);
90  return s;
91}
92
93static void nrnKillChar(coeffs r)
94{
95  mpz_clear(r->modNumber);
96  mpz_clear(r->modBase);
97  omFreeBin((void *) r->modBase, gmp_nrz_bin);
98  omFreeBin((void *) r->modNumber, gmp_nrz_bin);
99}
100
101static coeffs nrnQuot1(number c, const coeffs r)
102{
103    coeffs rr;
104    long ch = r->cfInt(c, r);
105    mpz_t a,b;
106    mpz_init_set(a, r->modNumber);
107    mpz_init_set_ui(b, ch);
108    mpz_t gcd;
109    mpz_init(gcd);
110    mpz_gcd(gcd, a,b);
111    if(mpz_cmp_ui(gcd, 1) == 0)
112    {
113      WerrorS("constant in q-ideal is coprime to modulus in ground ring");
114      WerrorS("Unable to create qring!");
115      return NULL;
116    }
117    if(r->modExponent == 1)
118    {
119      ZnmInfo info;
120      info.base = gcd;
121      info.exp = (unsigned long) 1;
122      rr = nInitChar(n_Zn, (void*)&info);
123    }
124    else
125    {
126      ZnmInfo info;
127      info.base = r->modBase;
128      int kNew = 1;
129      mpz_t baseTokNew;
130      mpz_init(baseTokNew);
131      mpz_set(baseTokNew, r->modBase);
132      while(mpz_cmp(gcd, baseTokNew) > 0)
133      {
134        kNew++;
135        mpz_mul(baseTokNew, baseTokNew, r->modBase);
136      }
137      //printf("\nkNew = %i\n",kNew);
138      info.exp = kNew;
139      mpz_clear(baseTokNew);
140      rr = nInitChar(n_Znm, (void*)&info);
141    }
142    mpz_clear(gcd);
143    return(rr);
144}
145
146static number nrnCopy(number a, const coeffs)
147{
148  mpz_ptr erg = (mpz_ptr) omAllocBin(gmp_nrz_bin);
149  mpz_init_set(erg, (mpz_ptr) a);
150  return (number) erg;
151}
152
153/*
154 * create a number from int
155 */
156static number nrnInit(long i, const coeffs r)
157{
158  mpz_ptr erg = (mpz_ptr) omAllocBin(gmp_nrz_bin);
159  mpz_init_set_si(erg, i);
160  mpz_mod(erg, erg, r->modNumber);
161  return (number) erg;
162}
163
164static void nrnDelete(number *a, const coeffs)
165{
166  if (*a == NULL) return;
167  mpz_clear((mpz_ptr) *a);
168  omFreeBin((void *) *a, gmp_nrz_bin);
169  *a = NULL;
170}
171
172static int nrnSize(number a, const coeffs)
173{
174  if (a == NULL) return 0;
175  mpz_ptr p=(mpz_ptr)a;
176  int s=p->_mp_alloc;
177  return s;
178}
179
180/*
181 * convert a number to int
182 */
183static long nrnInt(number &n, const coeffs)
184{
185  return mpz_get_si((mpz_ptr) n);
186}
187
188/*
189 * Multiply two numbers
190 */
191static number nrnMult(number a, number b, const coeffs r)
192{
193  mpz_ptr erg = (mpz_ptr)omAllocBin(gmp_nrz_bin);
194  mpz_init(erg);
195  mpz_mul(erg, (mpz_ptr)a, (mpz_ptr) b);
196  mpz_mod(erg, erg, r->modNumber);
197  return (number) erg;
198}
199
200static void nrnPower(number a, int i, number * result, const coeffs r)
201{
202  mpz_ptr erg = (mpz_ptr)omAllocBin(gmp_nrz_bin);
203  mpz_init(erg);
204  mpz_powm_ui(erg, (mpz_ptr)a, i, r->modNumber);
205  *result = (number) erg;
206}
207
208static number nrnAdd(number a, number b, const coeffs r)
209{
210  mpz_ptr erg = (mpz_ptr)omAllocBin(gmp_nrz_bin);
211  mpz_init(erg);
212  mpz_add(erg, (mpz_ptr)a, (mpz_ptr) b);
213  mpz_mod(erg, erg, r->modNumber);
214  return (number) erg;
215}
216
217static number nrnSub(number a, number b, const coeffs r)
218{
219  mpz_ptr erg = (mpz_ptr)omAllocBin(gmp_nrz_bin);
220  mpz_init(erg);
221  mpz_sub(erg, (mpz_ptr)a, (mpz_ptr) b);
222  mpz_mod(erg, erg, r->modNumber);
223  return (number) erg;
224}
225
226static BOOLEAN nrnIsZero(number a, const coeffs)
227{
228#ifdef LDEBUG
229  if (a == NULL) return FALSE;
230#endif
231  return 0 == mpz_cmpabs_ui((mpz_ptr)a, 0);
232}
233
234static number nrnNeg(number c, const coeffs r)
235{
236  if( !nrnIsZero(c, r) )
237    // Attention: This method operates in-place.
238    mpz_sub((mpz_ptr)c, r->modNumber, (mpz_ptr)c);
239  return c;
240}
241
242static number nrnInvers(number c, const coeffs r)
243{
244  mpz_ptr erg = (mpz_ptr)omAllocBin(gmp_nrz_bin);
245  mpz_init(erg);
246  mpz_invert(erg, (mpz_ptr)c, r->modNumber);
247  return (number) erg;
248}
249
250/*
251 * Give the largest k, such that a = x * k, b = y * k has
252 * a solution.
253 */
254static number nrnGcd(number a, number b, const coeffs r)
255{
256  if ((a == NULL) && (b == NULL)) return nrnInit(0,r);
257  mpz_ptr erg = (mpz_ptr)omAllocBin(gmp_nrz_bin);
258  mpz_init_set(erg, r->modNumber);
259  if (a != NULL) mpz_gcd(erg, erg, (mpz_ptr)a);
260  if (b != NULL) mpz_gcd(erg, erg, (mpz_ptr)b);
261  if(mpz_cmp(erg,r->modNumber)==0)
262  {
263    mpz_clear(erg);
264    omFreeBin((ADDRESS)erg,gmp_nrz_bin);
265    return nrnInit(0,r);
266  }
267  return (number)erg;
268}
269
270/*
271 * Give the smallest k, such that a * x = k = b * y has a solution
272 * TODO: lcm(gcd,gcd) better than gcd(lcm) ?
273 */
274static number nrnLcm(number a, number b, const coeffs r)
275{
276  number erg = nrnGcd(NULL, a, r);
277  number tmp = nrnGcd(NULL, b, r);
278  mpz_lcm((mpz_ptr)erg, (mpz_ptr)erg, (mpz_ptr)tmp);
279  nrnDelete(&tmp, r);
280  return (number)erg;
281}
282
283/* Not needed any more, but may have room for improvement
284   number nrnGcd3(number a,number b, number c,ring r)
285{
286  mpz_ptr erg = (mpz_ptr) omAllocBin(gmp_nrz_bin);
287  mpz_init(erg);
288  if (a == NULL) a = (number)r->modNumber;
289  if (b == NULL) b = (number)r->modNumber;
290  if (c == NULL) c = (number)r->modNumber;
291  mpz_gcd(erg, (mpz_ptr)a, (mpz_ptr)b);
292  mpz_gcd(erg, erg, (mpz_ptr)c);
293  mpz_gcd(erg, erg, r->modNumber);
294  return (number)erg;
295}
296*/
297
298/*
299 * Give the largest k, such that a = x * k, b = y * k has
300 * a solution and r, s, s.t. k = s*a + t*b
301 * CF: careful: ExtGcd is wrong as implemented (or at least may not
302 * give you what you want:
303 * ExtGcd(5, 10 modulo 12):
304 * the gcdext will return 5 = 1*5 + 0*10
305 * however, mod 12, the gcd should be 1
306 */
307static number nrnExtGcd(number a, number b, number *s, number *t, const coeffs r)
308{
309  mpz_ptr erg = (mpz_ptr)omAllocBin(gmp_nrz_bin);
310  mpz_ptr bs  = (mpz_ptr)omAllocBin(gmp_nrz_bin);
311  mpz_ptr bt  = (mpz_ptr)omAllocBin(gmp_nrz_bin);
312  mpz_init(erg);
313  mpz_init(bs);
314  mpz_init(bt);
315  mpz_gcdext(erg, bs, bt, (mpz_ptr)a, (mpz_ptr)b);
316  mpz_mod(bs, bs, r->modNumber);
317  mpz_mod(bt, bt, r->modNumber);
318  *s = (number)bs;
319  *t = (number)bt;
320  return (number)erg;
321}
322
323static BOOLEAN nrnIsOne(number a, const coeffs)
324{
325#ifdef LDEBUG
326  if (a == NULL) return FALSE;
327#endif
328  return 0 == mpz_cmp_si((mpz_ptr)a, 1);
329}
330
331static BOOLEAN nrnEqual(number a, number b, const coeffs)
332{
333  return 0 == mpz_cmp((mpz_ptr)a, (mpz_ptr)b);
334}
335
336static number nrnGetUnit(number k, const coeffs r)
337{
338  if (mpz_divisible_p(r->modNumber, (mpz_ptr)k)) return nrnInit(1,r);
339
340  mpz_ptr unit = (mpz_ptr)nrnGcd(k, 0, r);
341  mpz_tdiv_q(unit, (mpz_ptr)k, unit);
342  mpz_ptr gcd = (mpz_ptr)nrnGcd((number)unit, 0, r);
343  if (!nrnIsOne((number)gcd,r))
344  {
345    mpz_ptr ctmp;
346    // tmp := unit^2
347    mpz_ptr tmp = (mpz_ptr) nrnMult((number) unit,(number) unit,r);
348    // gcd_new := gcd(tmp, 0)
349    mpz_ptr gcd_new = (mpz_ptr) nrnGcd((number) tmp, 0, r);
350    while (!nrnEqual((number) gcd_new,(number) gcd,r))
351    {
352      // gcd := gcd_new
353      ctmp = gcd;
354      gcd = gcd_new;
355      gcd_new = ctmp;
356      // tmp := tmp * unit
357      mpz_mul(tmp, tmp, unit);
358      mpz_mod(tmp, tmp, r->modNumber);
359      // gcd_new := gcd(tmp, 0)
360      mpz_gcd(gcd_new, tmp, r->modNumber);
361    }
362    // unit := unit + modNumber / gcd_new
363    mpz_tdiv_q(tmp, r->modNumber, gcd_new);
364    mpz_add(unit, unit, tmp);
365    mpz_mod(unit, unit, r->modNumber);
366    nrnDelete((number*) &gcd_new, NULL);
367    nrnDelete((number*) &tmp, NULL);
368  }
369  nrnDelete((number*) &gcd, NULL);
370  return (number)unit;
371}
372
373/* XExtGcd  returns a unimodular matrix ((s,t)(u,v)) sth.
374 * (a,b)^t ((st)(uv)) = (g,0)^t
375 * Beware, the ExtGcd will not necessaairly do this.
376 * Problem: if g = as+bt then (in Z/nZ) it follows NOT that
377 *             1 = (a/g)s + (b/g) t
378 * due to the zero divisors.
379 */
380
381//#define CF_DEB;
382static number nrnXExtGcd(number a, number b, number *s, number *t, number *u, number *v, const coeffs r)
383{
384  number xx;
385#ifdef CF_DEB
386  StringSetS("XExtGcd of ");
387  nrnWrite(a, r);
388  StringAppendS("\t");
389  nrnWrite(b, r);
390  StringAppendS(" modulo ");
391  nrnWrite(xx = (number)r->modNumber, r);
392  Print("%s\n", StringEndS());
393#endif
394
395  mpz_ptr one = (mpz_ptr)omAllocBin(gmp_nrz_bin);
396  mpz_ptr erg = (mpz_ptr)omAllocBin(gmp_nrz_bin);
397  mpz_ptr bs  = (mpz_ptr)omAllocBin(gmp_nrz_bin);
398  mpz_ptr bt  = (mpz_ptr)omAllocBin(gmp_nrz_bin);
399  mpz_ptr bu  = (mpz_ptr)omAllocBin(gmp_nrz_bin);
400  mpz_ptr bv  = (mpz_ptr)omAllocBin(gmp_nrz_bin);
401  mpz_init(erg);
402  mpz_init(one);
403  mpz_init_set(bs, (mpz_ptr) a);
404  mpz_init_set(bt, (mpz_ptr) b);
405  mpz_init(bu);
406  mpz_init(bv);
407  mpz_gcd(erg, bs, bt);
408
409#ifdef CF_DEB
410  StringSetS("1st gcd:");
411  nrnWrite(xx= (number)erg, r);
412#endif
413
414  mpz_gcd(erg, erg, r->modNumber);
415
416  mpz_div(bs, bs, erg);
417  mpz_div(bt, bt, erg);
418
419#ifdef CF_DEB
420  Print("%s\n", StringEndS());
421  StringSetS("xgcd: ");
422#endif
423
424  mpz_gcdext(one, bu, bv, bs, bt);
425  number ui = nrnGetUnit(xx = (number) one, r);
426#ifdef CF_DEB
427  n_Write(xx, r);
428  StringAppendS("\t");
429  n_Write(ui, r);
430  Print("%s\n", StringEndS());
431#endif
432  nrnDelete(&xx, r);
433  if (!nrnIsOne(ui, r))
434  {
435#ifdef CF_DEB
436    PrintS("Scaling\n");
437#endif
438    number uii = nrnInvers(ui, r);
439    nrnDelete(&ui, r);
440    ui = uii;
441    mpz_ptr uu = (mpz_ptr)omAllocBin(gmp_nrz_bin);
442    mpz_init_set(uu, (mpz_ptr)ui);
443    mpz_mul(bu, bu, uu);
444    mpz_mul(bv, bv, uu);
445    mpz_clear(uu);
446    omFreeBin(uu, gmp_nrz_bin);
447  }
448  nrnDelete(&ui, r);
449#ifdef CF_DEB
450  StringSetS("xgcd");
451  nrnWrite(xx= (number)bs, r);
452  StringAppendS("*");
453  nrnWrite(xx= (number)bu, r);
454  StringAppendS(" + ");
455  nrnWrite(xx= (number)bt, r);
456  StringAppendS("*");
457  nrnWrite(xx= (number)bv, r);
458  Print("%s\n", StringEndS());
459#endif
460
461  mpz_mod(bs, bs, r->modNumber);
462  mpz_mod(bt, bt, r->modNumber);
463  mpz_mod(bu, bu, r->modNumber);
464  mpz_mod(bv, bv, r->modNumber);
465  *s = (number)bu;
466  *t = (number)bv;
467  *u = (number)bt;
468  *u = nrnNeg(*u, r);
469  *v = (number)bs;
470  return (number)erg;
471}
472
473static BOOLEAN nrnIsMOne(number a, const coeffs r)
474{
475#ifdef LDEBUG
476  if (a == NULL) return FALSE;
477#endif
478  if((r->ch==2) && (nrnIsOne(a,r))) return FALSE;
479  mpz_t t; mpz_init_set(t, (mpz_ptr)a);
480  mpz_add_ui(t, t, 1);
481  bool erg = (0 == mpz_cmp(t, r->modNumber));
482  mpz_clear(t);
483  return erg;
484}
485
486static BOOLEAN nrnGreater(number a, number b, const coeffs)
487{
488  return 0 < mpz_cmp((mpz_ptr)a, (mpz_ptr)b);
489}
490
491static BOOLEAN nrnGreaterZero(number k, const coeffs cf)
492{
493  if (cf->is_field)
494  {
495    if (mpz_cmp_ui(cf->modBase,2)==0)
496    {
497      return TRUE;
498    }
499    mpz_t ch2; mpz_init_set(ch2, cf->modBase);
500    mpz_sub_ui(ch2,ch2,1);
501    mpz_divexact_ui(ch2,ch2,2);
502    if (mpz_cmp(ch2,(mpz_ptr)k)<0)
503      return FALSE;
504    mpz_clear(ch2);
505  }
506  return 0 < mpz_sgn1((mpz_ptr)k);
507}
508
509static BOOLEAN nrnIsUnit(number a, const coeffs r)
510{
511  number tmp = nrnGcd(a, (number)r->modNumber, r);
512  bool res = nrnIsOne(tmp, r);
513  nrnDelete(&tmp, NULL);
514  return res;
515}
516
517static number nrnAnn(number k, const coeffs r)
518{
519  mpz_ptr tmp = (mpz_ptr) omAllocBin(gmp_nrz_bin);
520  mpz_init(tmp);
521  mpz_gcd(tmp, (mpz_ptr) k, r->modNumber);
522  if (mpz_cmp_si(tmp, 1)==0) {
523    mpz_set_ui(tmp, 0);
524    return (number) tmp;
525  }
526  mpz_divexact(tmp, r->modNumber, tmp);
527  return (number) tmp;
528}
529
530static BOOLEAN nrnDivBy(number a, number b, const coeffs r)
531{
532  if (a == NULL)
533    return mpz_divisible_p(r->modNumber, (mpz_ptr)b);
534  else
535  { /* b divides a iff b/gcd(a, b) is a unit in the given ring: */
536    number n = nrnGcd(a, b, r);
537    mpz_tdiv_q((mpz_ptr)n, (mpz_ptr)b, (mpz_ptr)n);
538    bool result = nrnIsUnit(n, r);
539    nrnDelete(&n, NULL);
540    return result;
541  }
542}
543
544static int nrnDivComp(number a, number b, const coeffs r)
545{
546  if (nrnEqual(a, b,r)) return 2;
547  if (mpz_divisible_p((mpz_ptr) a, (mpz_ptr) b)) return -1;
548  if (mpz_divisible_p((mpz_ptr) b, (mpz_ptr) a)) return 1;
549  return 0;
550}
551
552static number nrnDiv(number a, number b, const coeffs r)
553{
554  if (r->is_field)
555  {
556    number inv=nrnInvers(b,r);
557    number erg=nrnMult(a,inv,r);
558    nrnDelete(&inv,r);
559    return erg;
560  }
561  if (a == NULL) a = (number)r->modNumber;
562  mpz_ptr erg = (mpz_ptr)omAllocBin(gmp_nrz_bin);
563  mpz_init(erg);
564  if (mpz_divisible_p((mpz_ptr)a, (mpz_ptr)b))
565  {
566    mpz_divexact(erg, (mpz_ptr)a, (mpz_ptr)b);
567    return (number)erg;
568  }
569  else
570  {
571    mpz_ptr gcd = (mpz_ptr)nrnGcd(a, b, r);
572    mpz_divexact(erg, (mpz_ptr)b, gcd);
573    if (!nrnIsUnit((number)erg, r))
574    {
575      WerrorS("Division not possible, even by cancelling zero divisors.");
576      WerrorS("Result is integer division without remainder.");
577      mpz_tdiv_q(erg, (mpz_ptr) a, (mpz_ptr) b);
578      nrnDelete((number*) &gcd, NULL);
579      return (number)erg;
580    }
581    // a / gcd(a,b) * [b / gcd (a,b)]^(-1)
582    mpz_ptr tmp = (mpz_ptr)nrnInvers((number) erg,r);
583    mpz_divexact(erg, (mpz_ptr)a, gcd);
584    mpz_mul(erg, erg, tmp);
585    nrnDelete((number*) &gcd, NULL);
586    nrnDelete((number*) &tmp, NULL);
587    mpz_mod(erg, erg, r->modNumber);
588    return (number)erg;
589  }
590}
591
592static number nrnMod(number a, number b, const coeffs r)
593{
594  /*
595    We need to return the number rr which is uniquely determined by the
596    following two properties:
597      (1) 0 <= rr < |b| (with respect to '<' and '<=' performed in Z x Z)
598      (2) There exists some k in the integers Z such that a = k * b + rr.
599    Consider g := gcd(n, |b|). Note that then |b|/g is a unit in Z/n.
600    Now, there are three cases:
601      (a) g = 1
602          Then |b| is a unit in Z/n, i.e. |b| (and also b) divides a.
603          Thus rr = 0.
604      (b) g <> 1 and g divides a
605          Then a = (a/g) * (|b|/g)^(-1) * b (up to sign), i.e. again rr = 0.
606      (c) g <> 1 and g does not divide a
607          Then denote the division with remainder of a by g as this:
608          a = s * g + t. Then t = a - s * g = a - s * (|b|/g)^(-1) * |b|
609          fulfills (1) and (2), i.e. rr := t is the correct result. Hence
610          in this third case, rr is the remainder of division of a by g in Z.
611     Remark: according to mpz_mod: a,b are always non-negative
612  */
613  mpz_ptr g = (mpz_ptr)omAllocBin(gmp_nrz_bin);
614  mpz_ptr rr = (mpz_ptr)omAllocBin(gmp_nrz_bin);
615  mpz_init(g);
616  mpz_init_set_ui(rr, 0);
617  mpz_gcd(g, (mpz_ptr)r->modNumber, (mpz_ptr)b); // g is now as above
618  if (mpz_cmp_si(g, 1L) != 0) mpz_mod(rr, (mpz_ptr)a, g); // the case g <> 1
619  mpz_clear(g);
620  omFreeBin(g, gmp_nrz_bin);
621  return (number)rr;
622}
623
624static number nrnIntDiv(number a, number b, const coeffs r)
625{
626  mpz_ptr erg = (mpz_ptr)omAllocBin(gmp_nrz_bin);
627  mpz_init(erg);
628  if (a == NULL) a = (number)r->modNumber;
629  mpz_tdiv_q(erg, (mpz_ptr)a, (mpz_ptr)b);
630  return (number)erg;
631}
632
633/* CF: note that Z/nZ has (at least) two distinct euclidean structures
634 * 1st phi(a) := (a mod n) which is just the structure directly
635 *     inherited from Z
636 * 2nd phi(a) := gcd(a, n)
637 * The 1st version is probably faster as everything just comes from Z,
638 * but the 2nd version behaves nicely wrt. to quotient operations
639 * and HNF and such. In agreement with nrnMod we imlement the 2nd here
640 *
641 * For quotrem note that if b exactly divides a, then
642 *   min(v_p(a), v_p(n))  >= min(v_p(b), v_p(n))
643 * so if we divide  a and b by g:= gcd(a,b,n), then   b becomes a
644 * unit mod n/g.
645 * Thus we 1st compute the remainder (similar to nrnMod) and then
646 * the exact quotient.
647 */
648static number nrnQuotRem(number a, number b, number  * rem, const coeffs r)
649{
650  mpz_t g, aa, bb;
651  mpz_ptr qq = (mpz_ptr)omAllocBin(gmp_nrz_bin);
652  mpz_ptr rr = (mpz_ptr)omAllocBin(gmp_nrz_bin);
653  mpz_init(qq);
654  mpz_init(rr);
655  mpz_init(g);
656  mpz_init_set(aa, (mpz_ptr)a);
657  mpz_init_set(bb, (mpz_ptr)b);
658
659  mpz_gcd(g, bb, r->modNumber);
660  mpz_mod(rr, aa, g);
661  mpz_sub(aa, aa, rr);
662  mpz_gcd(g, aa, g);
663  mpz_div(aa, aa, g);
664  mpz_div(bb, bb, g);
665  mpz_div(g, r->modNumber, g);
666  mpz_invert(g, bb, g);
667  mpz_mul(qq, aa, g);
668  if (rem)
669    *rem = (number)rr;
670  else {
671    mpz_clear(rr);
672    omFreeBin(rr, gmp_nrz_bin);
673  }
674  mpz_clear(g);
675  mpz_clear(aa);
676  mpz_clear(bb);
677  return (number) qq;
678}
679
680/*
681 * Helper function for computing the module
682 */
683
684static mpz_ptr nrnMapCoef = NULL;
685
686static number nrnMapModN(number from, const coeffs /*src*/, const coeffs dst)
687{
688  return nrnMult(from, (number) nrnMapCoef, dst);
689}
690
691static number nrnMap2toM(number from, const coeffs /*src*/, const coeffs dst)
692{
693  mpz_ptr erg = (mpz_ptr)omAllocBin(gmp_nrz_bin);
694  mpz_init(erg);
695  mpz_mul_ui(erg, nrnMapCoef, (unsigned long)from);
696  mpz_mod(erg, erg, dst->modNumber);
697  return (number)erg;
698}
699
700static number nrnMapZp(number from, const coeffs /*src*/, const coeffs dst)
701{
702  mpz_ptr erg = (mpz_ptr)omAllocBin(gmp_nrz_bin);
703  mpz_init(erg);
704  // TODO: use npInt(...)
705  mpz_mul_si(erg, nrnMapCoef, (unsigned long)from);
706  mpz_mod(erg, erg, dst->modNumber);
707  return (number)erg;
708}
709
710number nrnMapGMP(number from, const coeffs /*src*/, const coeffs dst)
711{
712  mpz_ptr erg = (mpz_ptr)omAllocBin(gmp_nrz_bin);
713  mpz_init(erg);
714  mpz_mod(erg, (mpz_ptr)from, dst->modNumber);
715  return (number)erg;
716}
717
718static number nrnMapQ(number from, const coeffs src, const coeffs dst)
719{
720  mpz_ptr erg = (mpz_ptr)omAllocBin(gmp_nrz_bin);
721  mpz_init(erg);
722  nlGMP(from, erg, src); // FIXME? TODO? // extern void   nlGMP(number &i, number n, const coeffs r); // to be replaced with n_MPZ(erg, from, src); // ?
723  mpz_mod(erg, erg, dst->modNumber);
724  return (number)erg;
725}
726
727#if SI_INTEGER_VARIANT==3
728static number nrnMapZ(number from, const coeffs /*src*/, const coeffs dst)
729{
730  mpz_ptr erg = (mpz_ptr)omAllocBin(gmp_nrz_bin);
731  if (n_Z_IS_SMALL(from))
732    mpz_init_set_si(erg, SR_TO_INT(from));
733  else
734    mpz_init_set(erg, (mpz_ptr) from);
735  mpz_mod(erg, erg, dst->modNumber);
736  return (number)erg;
737}
738#elif SI_INTEGER_VARIANT==2
739
740static number nrnMapZ(number from, const coeffs src, const coeffs dst)
741{
742  if (SR_HDL(from) & SR_INT)
743  {
744    long f_i=SR_TO_INT(from);
745    return nrnInit(f_i,dst);
746  }
747  return nrnMapGMP(from,src,dst);
748}
749#elif SI_INTEGER_VARIANT==1
750static number nrnMapZ(number from, const coeffs src, const coeffs dst)
751{
752  return nrnMapQ(from,src,dst);
753}
754#endif
755void nrnWrite (number a, const coeffs cf)
756{
757  char *s,*z;
758  if (a==NULL)
759  {
760    StringAppendS("o");
761  }
762  else
763  {
764    int l=mpz_sizeinbase((mpz_ptr) a, 10) + 2;
765    s=(char*)omAlloc(l);
766    if (cf->is_field)
767    {
768      mpz_t ch2; mpz_init_set(ch2, cf->modBase);
769      mpz_sub_ui(ch2,ch2,1);
770      mpz_divexact_ui(ch2,ch2,2);
771      if ((mpz_cmp_ui(cf->modBase,2)!=0) && (mpz_cmp(ch2,(mpz_ptr)a)<0))
772      {
773        mpz_sub(ch2,(mpz_ptr)a,cf->modBase);
774        z=mpz_get_str(s,10,ch2);
775        StringAppendS(z);
776      }
777      else
778      {
779        z=mpz_get_str(s,10,(mpz_ptr) a);
780        StringAppendS(z);
781      }
782      mpz_clear(ch2);
783    }
784    else
785    {
786      z=mpz_get_str(s,10,(mpz_ptr) a);
787      StringAppendS(z);
788    }
789    omFreeSize((ADDRESS)s,l);
790  }
791}
792
793nMapFunc nrnSetMap(const coeffs src, const coeffs dst)
794{
795  /* dst = nrn */
796  if ((src->rep==n_rep_gmp) && nCoeff_is_Ring_Z(src))
797  {
798    return nrnMapZ;
799  }
800  if ((src->rep==n_rep_gap_gmp) /*&& nCoeff_is_Ring_Z(src)*/)
801  {
802    return nrnMapZ;
803  }
804  if (src->rep==n_rep_gap_rat) /*&& nCoeff_is_Q(src)) or Z*/
805  {
806    return nrnMapQ;
807  }
808  // Some type of Z/n ring / field
809  if (nCoeff_is_Ring_ModN(src) || nCoeff_is_Ring_PtoM(src) ||
810      nCoeff_is_Ring_2toM(src) || nCoeff_is_Zp(src))
811  {
812    if (   (!nCoeff_is_Zp(src))
813        && (mpz_cmp(src->modBase, dst->modBase) == 0)
814        && (src->modExponent == dst->modExponent)) return ndCopyMap;
815    else
816    {
817      mpz_ptr nrnMapModul = (mpz_ptr) omAllocBin(gmp_nrz_bin);
818      // Computing the n of Z/n
819      if (nCoeff_is_Zp(src))
820      {
821        mpz_init_set_si(nrnMapModul, src->ch);
822      }
823      else
824      {
825        mpz_init(nrnMapModul);
826        mpz_set(nrnMapModul, src->modNumber);
827      }
828      // nrnMapCoef = 1 in dst       if dst is a subring of src
829      // nrnMapCoef = 0 in dst / src if src is a subring of dst
830      if (nrnMapCoef == NULL)
831      {
832        nrnMapCoef = (mpz_ptr) omAllocBin(gmp_nrz_bin);
833        mpz_init(nrnMapCoef);
834      }
835      if (mpz_divisible_p(nrnMapModul, dst->modNumber))
836      {
837        mpz_set_ui(nrnMapCoef, 1);
838      }
839      else
840      if (nrnDivBy(NULL, (number) nrnMapModul,dst))
841      {
842        mpz_divexact(nrnMapCoef, dst->modNumber, nrnMapModul);
843        mpz_ptr tmp = dst->modNumber;
844        dst->modNumber = nrnMapModul;
845        if (!nrnIsUnit((number) nrnMapCoef,dst))
846        {
847          dst->modNumber = tmp;
848          nrnDelete((number*) &nrnMapModul, dst);
849          return NULL;
850        }
851        mpz_ptr inv = (mpz_ptr) nrnInvers((number) nrnMapCoef,dst);
852        dst->modNumber = tmp;
853        mpz_mul(nrnMapCoef, nrnMapCoef, inv);
854        mpz_mod(nrnMapCoef, nrnMapCoef, dst->modNumber);
855        nrnDelete((number*) &inv, dst);
856      }
857      else
858      {
859        nrnDelete((number*) &nrnMapModul, dst);
860        return NULL;
861      }
862      nrnDelete((number*) &nrnMapModul, dst);
863      if (nCoeff_is_Ring_2toM(src))
864        return nrnMap2toM;
865      else if (nCoeff_is_Zp(src))
866        return nrnMapZp;
867      else
868        return nrnMapModN;
869    }
870  }
871  return NULL;      // default
872}
873
874/*
875 * set the exponent (allocate and init tables) (TODO)
876 */
877
878static void nrnSetExp(unsigned long m, coeffs r)
879{
880  /* clean up former stuff */
881  if (r->modNumber != NULL) mpz_clear(r->modNumber);
882
883  r->modExponent= m;
884  r->modNumber = (mpz_ptr)omAllocBin(gmp_nrz_bin);
885  mpz_init_set (r->modNumber, r->modBase);
886  mpz_pow_ui (r->modNumber, r->modNumber, m);
887}
888
889/* We expect this ring to be Z/n^m for some m > 0 and for some n > 2 which is not a prime. */
890static void nrnInitExp(unsigned long m, coeffs r)
891{
892  nrnSetExp(m, r);
893  assume (r->modNumber != NULL);
894//CF: in general, the modulus is computed somewhere. I don't want to
895//  check it's size before I construct the best ring.
896//  if (mpz_cmp_ui(r->modNumber,2) <= 0)
897//    WarnS("nrnInitExp failed (m in Z/m too small)");
898}
899
900#ifdef LDEBUG
901BOOLEAN nrnDBTest (number a, const char *f, const int l, const coeffs r)
902{
903  if (a==NULL) return TRUE;
904  if ( (mpz_sgn1((mpz_ptr) a) < 0) || (mpz_cmp((mpz_ptr) a, r->modNumber) > 0) )
905  {
906    Warn("mod-n: out of range at %s:%d\n",f,l);
907    return FALSE;
908  }
909  return TRUE;
910}
911#endif
912
913/*2
914* extracts a long integer from s, returns the rest    (COPY FROM longrat0.cc)
915*/
916static const char * nlCPEatLongC(char *s, mpz_ptr i)
917{
918  const char * start=s;
919  if (!(*s >= '0' && *s <= '9'))
920  {
921    mpz_init_set_ui(i, 1);
922    return s;
923  }
924  mpz_init(i);
925  while (*s >= '0' && *s <= '9') s++;
926  if (*s=='\0')
927  {
928    mpz_set_str(i,start,10);
929  }
930  else
931  {
932    char c=*s;
933    *s='\0';
934    mpz_set_str(i,start,10);
935    *s=c;
936  }
937  return s;
938}
939
940static const char * nrnRead (const char *s, number *a, const coeffs r)
941{
942  mpz_ptr z = (mpz_ptr) omAllocBin(gmp_nrz_bin);
943  {
944    s = nlCPEatLongC((char *)s, z);
945  }
946  mpz_mod(z, z, r->modNumber);
947  if ((*s)=='/')
948  {
949    mpz_ptr n = (mpz_ptr) omAllocBin(gmp_nrz_bin);
950    s++;
951    s=nlCPEatLongC((char*)s,n);
952    if (!nrnIsOne((number)n,r))
953    {
954      *a=nrnDiv((number)z,(number)n,r);
955      mpz_clear(z);
956      omFreeBin((void *)z, gmp_nrz_bin);
957      mpz_clear(n);
958      omFreeBin((void *)n, gmp_nrz_bin);
959    }
960  }
961  else
962    *a = (number) z;
963  return s;
964}
965
966static number nrnConvFactoryNSingN( const CanonicalForm n, const coeffs r)
967{
968  return nrnInit(n.intval(),r);
969}
970
971static CanonicalForm nrnConvSingNFactoryN( number n, BOOLEAN setChar, const coeffs r )
972{
973  if (setChar) setCharacteristic( r->ch );
974   return CanonicalForm(nrnInt( n,r ));
975}
976
977/* for initializing function pointers */
978BOOLEAN nrnInitChar (coeffs r, void* p)
979{
980  assume( (getCoeffType(r) == n_Zn) || (getCoeffType (r) == n_Znm) );
981  ZnmInfo * info= (ZnmInfo *) p;
982  r->modBase= (mpz_ptr)nrnCopy((number)info->base, r); //this circumvents the problem
983  //in bigintmat.cc where we cannot create a "legal" nrn that can be freed.
984  //If we take a copy, we can do whatever we want.
985
986  nrnInitExp (info->exp, r);
987
988  /* next computation may yield wrong characteristic as r->modNumber
989     is a GMP number */
990  r->ch = mpz_get_ui(r->modNumber);
991
992  r->is_field=FALSE;
993  r->is_domain=FALSE;
994  r->rep=n_rep_gmp;
995
996
997  r->cfCoeffString = nrnCoeffString;
998
999  r->cfInit        = nrnInit;
1000  r->cfDelete      = nrnDelete;
1001  r->cfCopy        = nrnCopy;
1002  r->cfSize        = nrnSize;
1003  r->cfInt         = nrnInt;
1004  r->cfAdd         = nrnAdd;
1005  r->cfSub         = nrnSub;
1006  r->cfMult        = nrnMult;
1007  r->cfDiv         = nrnDiv;
1008  r->cfAnn         = nrnAnn;
1009  r->cfIntMod      = nrnMod;
1010  r->cfExactDiv    = nrnDiv;
1011  r->cfInpNeg      = nrnNeg;
1012  r->cfInvers      = nrnInvers;
1013  r->cfDivBy       = nrnDivBy;
1014  r->cfDivComp     = nrnDivComp;
1015  r->cfGreater     = nrnGreater;
1016  r->cfEqual       = nrnEqual;
1017  r->cfIsZero      = nrnIsZero;
1018  r->cfIsOne       = nrnIsOne;
1019  r->cfIsMOne      = nrnIsMOne;
1020  r->cfGreaterZero = nrnGreaterZero;
1021  r->cfWriteLong   = nrnWrite;
1022  r->cfRead        = nrnRead;
1023  r->cfPower       = nrnPower;
1024  r->cfSetMap      = nrnSetMap;
1025  //r->cfNormalize   = ndNormalize;
1026  r->cfLcm         = nrnLcm;
1027  r->cfGcd         = nrnGcd;
1028  r->cfIsUnit      = nrnIsUnit;
1029  r->cfGetUnit     = nrnGetUnit;
1030  r->cfExtGcd      = nrnExtGcd;
1031  r->cfXExtGcd     = nrnXExtGcd;
1032  r->cfQuotRem     = nrnQuotRem;
1033  r->cfCoeffName   = nrnCoeffName;
1034  r->cfCoeffWrite  = nrnCoeffWrite;
1035  r->nCoeffIsEqual = nrnCoeffIsEqual;
1036  r->cfKillChar    = nrnKillChar;
1037  r->cfQuot1       = nrnQuot1;
1038#ifdef LDEBUG
1039  r->cfDBTest      = nrnDBTest;
1040#endif
1041  if ((r->modExponent==1)&&(mpz_size1(r->modBase)==1))
1042  {
1043    long p=mpz_get_si(r->modBase);
1044    if ((p<=536870909)&&(p==IsPrime(p))) /*factory limit: <2^29*/
1045    {
1046      r->convFactoryNSingN=nrnConvFactoryNSingN;
1047      r->convSingNFactoryN=nrnConvSingNFactoryN;
1048    }
1049  }
1050  return FALSE;
1051}
1052
1053#endif
1054/* #ifdef HAVE_RINGS */
Note: See TracBrowser for help on using the repository browser.