source: git/libpolys/coeffs/rmodulon.cc @ 61e855

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