source: git/libpolys/coeffs/rmodulon.cc @ 279976

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