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