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

fieker-DuValspielwiese
Last change on this file since e76d8cb was 66ce6d, checked in by Martin Lee <martinlee84@…>, 11 years ago
chg: got rid of ringtype
  • Property mode set to 100644
File size: 16.7 KB
RevLine 
[275ecc]1/****************************************
2*  Computer Algebra System SINGULAR     *
3****************************************/
4/*
5* ABSTRACT: numbers modulo n
6*/
7
[691dba]8#include "config.h"
[18cb65]9#include <misc/auxiliary.h>
[275ecc]10
[c90b43]11#ifdef HAVE_RINGS
[f1c465f]12
[18cb65]13#include <misc/mylimits.h>
[2d805a]14#include <coeffs/coeffs.h>
[31213a4]15#include <reporter/reporter.h>
16#include <omalloc/omalloc.h>
[2d805a]17#include <coeffs/numbers.h>
18#include <coeffs/longrat.h>
19#include <coeffs/mpr_complex.h>
20#include <coeffs/rmodulon.h>
[e3b233]21#include "si_gmp.h"
[8d0331d]22
[f1c465f]23#include <string.h>
24
[73a9ffb]25/// Our Type!
26static const n_coeffType ID = n_Zn;
[0486a3]27static const n_coeffType ID2 = n_Znm;
[73a9ffb]28
[8d0331d]29extern omBin gmp_nrz_bin;
[275ecc]30
[03f7b5]31void    nrnCoeffWrite  (const coeffs r, BOOLEAN /*details*/)
[7a8011]32{
33  long l = (long)mpz_sizeinbase(r->modBase, 10) + 2;
34  char* s = (char*) omAlloc(l);
[0486a3]35  s= mpz_get_str (s, 10, r->modBase);
36  if (nCoeff_is_Ring_ModN(r)) Print("//   coeff. ring is : Z/%s\n", s);
37  else if (nCoeff_is_Ring_PtoM(r)) Print("//   coeff. ring is : Z/%s^%lu\n", s, r->modExponent);
[7a8011]38  omFreeSize((ADDRESS)s, l);
39}
40
[b19ab84]41static BOOLEAN nrnCoeffsEqual(const coeffs r, n_coeffType n, void * parameter)
42{
43  /* test, if r is an instance of nInitCoeffs(n,parameter) */
[a2da9e]44  return (n==n_Zn) && (mpz_cmp_ui(r->modNumber,(long)parameter)==0);
[b19ab84]45}
46
47
[14b11bb]48/* for initializing function pointers */
[1cce47]49BOOLEAN nrnInitChar (coeffs r, void* p)
[14b11bb]50{
[0486a3]51  assume( (getCoeffType(r) == ID) || (getCoeffType (r) == ID2) );
52  ZnmInfo * info= (ZnmInfo *) p;
[dc07cbe]53  r->modBase= info->base;
[9bb5457]54
[0486a3]55  nrnInitExp (info->exp, r);
56
[73a9ffb]57  /* next computation may yield wrong characteristic as r->modNumber
58     is a GMP number */
59  r->ch = mpz_get_ui(r->modNumber);
[e90dfd6]60
61  r->cfInit        = nrnInit;
62  r->cfDelete      = nrnDelete;
63  r->cfCopy        = nrnCopy;
64  r->cfSize        = nrnSize;
65  r->cfInt         = nrnInt;
66  r->cfAdd         = nrnAdd;
67  r->cfSub         = nrnSub;
68  r->cfMult        = nrnMult;
69  r->cfDiv         = nrnDiv;
70  r->cfIntDiv      = nrnIntDiv;
71  r->cfIntMod      = nrnMod;
72  r->cfExactDiv    = nrnDiv;
73  r->cfNeg         = nrnNeg;
74  r->cfInvers      = nrnInvers;
75  r->cfDivBy       = nrnDivBy;
76  r->cfDivComp     = nrnDivComp;
77  r->cfGreater     = nrnGreater;
78  r->cfEqual       = nrnEqual;
79  r->cfIsZero      = nrnIsZero;
80  r->cfIsOne       = nrnIsOne;
81  r->cfIsMOne      = nrnIsMOne;
82  r->cfGreaterZero = nrnGreaterZero;
[ce1f78]83  r->cfWriteLong       = nrnWrite;
[e90dfd6]84  r->cfRead        = nrnRead;
85  r->cfPower       = nrnPower;
86  r->cfSetMap      = nrnSetMap;
87  r->cfNormalize   = ndNormalize;
88  r->cfLcm         = nrnLcm;
89  r->cfGcd         = nrnGcd;
90  r->cfIsUnit      = nrnIsUnit;
91  r->cfGetUnit     = nrnGetUnit;
92  r->cfExtGcd      = nrnExtGcd;
93  r->cfName        = ndName;
[7a8011]94  r->cfCoeffWrite  = nrnCoeffWrite;
[b19ab84]95  r->nCoeffIsEqual = nrnCoeffsEqual;
[8c6bd4d]96  r->cfInit_bigint = nrnMapQ;
97
[14b11bb]98#ifdef LDEBUG
[e90dfd6]99  r->cfDBTest      = nrnDBTest;
[14b11bb]100#endif
[5d594a9]101  return FALSE;
[14b11bb]102}
103
[8e1c4e]104/*
105 * create a number from int
106 */
[2f3764]107number nrnInit(long i, const coeffs r)
[8e1c4e]108{
[3c3880b]109  int_number erg = (int_number) omAllocBin(gmp_nrz_bin);
[8e1c4e]110  mpz_init_set_si(erg, i);
[e90dfd6]111  mpz_mod(erg, erg, r->modNumber);
[8e1c4e]112  return (number) erg;
113}
114
[9bb5457]115void nrnDelete(number *a, const coeffs)
[8e1c4e]116{
[befecbc]117  if (*a == NULL) return;
[8e1c4e]118  mpz_clear((int_number) *a);
[7d90aa]119  omFreeBin((void *) *a, gmp_nrz_bin);
[bac8611]120  *a = NULL;
121}
122
[9bb5457]123number nrnCopy(number a, const coeffs)
[bac8611]124{
[3c3880b]125  int_number erg = (int_number) omAllocBin(gmp_nrz_bin);
[bac8611]126  mpz_init_set(erg, (int_number) a);
127  return (number) erg;
128}
129
[9bb5457]130int nrnSize(number a, const coeffs)
[bac8611]131{
132  if (a == NULL) return 0;
[a604c3]133  return sizeof(mpz_t);
[8e1c4e]134}
135
136/*
[25d15e]137 * convert a number to int
[8e1c4e]138 */
[9bb5457]139int nrnInt(number &n, const coeffs)
[8e1c4e]140{
[e90dfd6]141  return (int)mpz_get_si((int_number) n);
[8e1c4e]142}
143
[275ecc]144/*
145 * Multiply two numbers
146 */
[e90dfd6]147number nrnMult(number a, number b, const coeffs r)
[275ecc]148{
[e90dfd6]149  int_number erg = (int_number)omAllocBin(gmp_nrz_bin);
[8e56ad]150  mpz_init(erg);
[e90dfd6]151  mpz_mul(erg, (int_number)a, (int_number) b);
152  mpz_mod(erg, erg, r->modNumber);
[8e56ad]153  return (number) erg;
[275ecc]154}
155
[e90dfd6]156void nrnPower(number a, int i, number * result, const coeffs r)
[8e1c4e]157{
[e90dfd6]158  int_number erg = (int_number)omAllocBin(gmp_nrz_bin);
[8e1c4e]159  mpz_init(erg);
[e90dfd6]160  mpz_powm_ui(erg, (int_number)a, i, r->modNumber);
[8e1c4e]161  *result = (number) erg;
162}
163
[e90dfd6]164number nrnAdd(number a, number b, const coeffs r)
[8e1c4e]165{
[e90dfd6]166  int_number erg = (int_number)omAllocBin(gmp_nrz_bin);
[8e1c4e]167  mpz_init(erg);
[e90dfd6]168  mpz_add(erg, (int_number)a, (int_number) b);
169  mpz_mod(erg, erg, r->modNumber);
[8e1c4e]170  return (number) erg;
171}
172
[e90dfd6]173number nrnSub(number a, number b, const coeffs r)
[8e1c4e]174{
[e90dfd6]175  int_number erg = (int_number)omAllocBin(gmp_nrz_bin);
[8e1c4e]176  mpz_init(erg);
[e90dfd6]177  mpz_sub(erg, (int_number)a, (int_number) b);
178  mpz_mod(erg, erg, r->modNumber);
[8e1c4e]179  return (number) erg;
180}
181
[e90dfd6]182number nrnNeg(number c, const coeffs r)
[8e1c4e]183{
[0b7bf7]184  if( !nrnIsZero(c, r) )
185    // Attention: This method operates in-place.
[9bb5457]186    mpz_sub((int_number)c, r->modNumber, (int_number)c);
[a539ad]187  return c;
[8e1c4e]188}
189
[e90dfd6]190number nrnInvers(number c, const coeffs r)
[8e1c4e]191{
[e90dfd6]192  int_number erg = (int_number)omAllocBin(gmp_nrz_bin);
[8e1c4e]193  mpz_init(erg);
[e90dfd6]194  mpz_invert(erg, (int_number)c, r->modNumber);
[8e1c4e]195  return (number) erg;
196}
197
[275ecc]198/*
[e90dfd6]199 * Give the smallest k, such that a * x = k = b * y has a solution
200 * TODO: lcm(gcd,gcd) better than gcd(lcm) ?
[275ecc]201 */
[e90dfd6]202number nrnLcm(number a, number b, const coeffs r)
[275ecc]203{
[196b4b]204  number erg = nrnGcd(NULL, a, r);
205  number tmp = nrnGcd(NULL, b, r);
[e90dfd6]206  mpz_lcm((int_number)erg, (int_number)erg, (int_number)tmp);
[8e1c4e]207  nrnDelete(&tmp, NULL);
[e90dfd6]208  return (number)erg;
[275ecc]209}
210
211/*
[e90dfd6]212 * Give the largest k, such that a = x * k, b = y * k has
[275ecc]213 * a solution.
214 */
[e90dfd6]215number nrnGcd(number a, number b, const coeffs r)
[275ecc]216{
[8391d8]217  if ((a == NULL) && (b == NULL)) return nrnInit(0,r);
[e90dfd6]218  int_number erg = (int_number)omAllocBin(gmp_nrz_bin);
219  mpz_init_set(erg, r->modNumber);
220  if (a != NULL) mpz_gcd(erg, erg, (int_number)a);
221  if (b != NULL) mpz_gcd(erg, erg, (int_number)b);
222  return (number)erg;
[8e56ad]223}
224
[8e1c4e]225/* Not needed any more, but may have room for improvement
[e90dfd6]226   number nrnGcd3(number a,number b, number c,ring r)
[af378f7]227{
[3c3880b]228  int_number erg = (int_number) omAllocBin(gmp_nrz_bin);
[af378f7]229  mpz_init(erg);
[e90dfd6]230  if (a == NULL) a = (number)r->modNumber;
231  if (b == NULL) b = (number)r->modNumber;
232  if (c == NULL) c = (number)r->modNumber;
233  mpz_gcd(erg, (int_number)a, (int_number)b);
234  mpz_gcd(erg, erg, (int_number)c);
235  mpz_gcd(erg, erg, r->modNumber);
236  return (number)erg;
[af378f7]237}
[8e1c4e]238*/
[af378f7]239
[8e56ad]240/*
[e90dfd6]241 * Give the largest k, such that a = x * k, b = y * k has
[8e56ad]242 * a solution and r, s, s.t. k = s*a + t*b
243 */
[e90dfd6]244number nrnExtGcd(number a, number b, number *s, number *t, const coeffs r)
[8e56ad]245{
[e90dfd6]246  int_number erg = (int_number)omAllocBin(gmp_nrz_bin);
247  int_number bs  = (int_number)omAllocBin(gmp_nrz_bin);
248  int_number bt  = (int_number)omAllocBin(gmp_nrz_bin);
[8e56ad]249  mpz_init(erg);
250  mpz_init(bs);
251  mpz_init(bt);
[e90dfd6]252  mpz_gcdext(erg, bs, bt, (int_number)a, (int_number)b);
253  mpz_mod(bs, bs, r->modNumber);
254  mpz_mod(bt, bt, r->modNumber);
255  *s = (number)bs;
256  *t = (number)bt;
257  return (number)erg;
[275ecc]258}
259
[9bb5457]260BOOLEAN nrnIsZero(number a, const coeffs)
[275ecc]261{
[01d4d3]262#ifdef LDEBUG
[191795]263  if (a == NULL) return FALSE;
[01d4d3]264#endif
[e90dfd6]265  return 0 == mpz_cmpabs_ui((int_number)a, 0);
[275ecc]266}
267
[9bb5457]268BOOLEAN nrnIsOne(number a, const coeffs)
[275ecc]269{
[191795]270#ifdef LDEBUG
271  if (a == NULL) return FALSE;
272#endif
[e90dfd6]273  return 0 == mpz_cmp_si((int_number)a, 1);
[8e56ad]274}
275
[e90dfd6]276BOOLEAN nrnIsMOne(number a, const coeffs r)
[8e56ad]277{
[191795]278#ifdef LDEBUG
279  if (a == NULL) return FALSE;
280#endif
[e90dfd6]281  mpz_t t; mpz_init_set(t, (int_number)a);
282  mpz_add_ui(t, t, 1);
283  bool erg = (0 == mpz_cmp(t, r->modNumber));
284  mpz_clear(t);
285  return erg;
[275ecc]286}
287
[9bb5457]288BOOLEAN nrnEqual(number a, number b, const coeffs)
[275ecc]289{
[e90dfd6]290  return 0 == mpz_cmp((int_number)a, (int_number)b);
[275ecc]291}
292
[9bb5457]293BOOLEAN nrnGreater(number a, number b, const coeffs)
[275ecc]294{
[e90dfd6]295  return 0 < mpz_cmp((int_number)a, (int_number)b);
[275ecc]296}
297
[9bb5457]298BOOLEAN nrnGreaterZero(number k, const coeffs)
[275ecc]299{
[e90dfd6]300  return 0 < mpz_cmp_si((int_number)k, 0);
[8e1c4e]301}
302
[e90dfd6]303BOOLEAN nrnIsUnit(number a, const coeffs r)
[8e1c4e]304{
[e90dfd6]305  number tmp = nrnGcd(a, (number)r->modNumber, r);
306  bool res = nrnIsOne(tmp, r);
[8e1c4e]307  nrnDelete(&tmp, NULL);
308  return res;
[275ecc]309}
310
[e90dfd6]311number nrnGetUnit(number k, const coeffs r)
[1e579c6]312{
[e90dfd6]313  if (mpz_divisible_p(r->modNumber, (int_number)k)) return nrnInit(1,r);
[97c4ad]314
[e90dfd6]315  int_number unit = (int_number)nrnGcd(k, 0, r);
316  mpz_tdiv_q(unit, (int_number)k, unit);
317  int_number gcd = (int_number)nrnGcd((number)unit, 0, r);
318  if (!nrnIsOne((number)gcd,r))
[af378f7]319  {
[31e857]320    int_number ctmp;
321    // tmp := unit^2
[4d1ae5]322    int_number tmp = (int_number) nrnMult((number) unit,(number) unit,r);
[31e857]323    // gcd_new := gcd(tmp, 0)
[14b11bb]324    int_number gcd_new = (int_number) nrnGcd((number) tmp, 0, r);
[4d1ae5]325    while (!nrnEqual((number) gcd_new,(number) gcd,r))
[af378f7]326    {
[31e857]327      // gcd := gcd_new
328      ctmp = gcd;
[af378f7]329      gcd = gcd_new;
[31e857]330      gcd_new = ctmp;
331      // tmp := tmp * unit
332      mpz_mul(tmp, tmp, unit);
[e90dfd6]333      mpz_mod(tmp, tmp, r->modNumber);
[31e857]334      // gcd_new := gcd(tmp, 0)
[e90dfd6]335      mpz_gcd(gcd_new, tmp, r->modNumber);
[af378f7]336    }
[e90dfd6]337    // unit := unit + modNumber / gcd_new
338    mpz_tdiv_q(tmp, r->modNumber, gcd_new);
[31e857]339    mpz_add(unit, unit, tmp);
[e90dfd6]340    mpz_mod(unit, unit, r->modNumber);
[31e857]341    nrnDelete((number*) &gcd_new, NULL);
342    nrnDelete((number*) &tmp, NULL);
[af378f7]343  }
[31e857]344  nrnDelete((number*) &gcd, NULL);
[e90dfd6]345  return (number)unit;
[1e579c6]346}
347
[e90dfd6]348BOOLEAN nrnDivBy(number a, number b, const coeffs r)
[275ecc]349{
[97c4ad]350  if (a == NULL)
[e90dfd6]351    return mpz_divisible_p(r->modNumber, (int_number)b);
[97c4ad]352  else
[a8b44d]353  { /* b divides a iff b/gcd(a, b) is a unit in the given ring: */
[14b11bb]354    number n = nrnGcd(a, b, r);
[a8b44d]355    mpz_tdiv_q((int_number)n, (int_number)b, (int_number)n);
[14b11bb]356    bool result = nrnIsUnit(n, r);
[a8b44d]357    nrnDelete(&n, NULL);
358    return result;
359  }
[275ecc]360}
361
[14b11bb]362int nrnDivComp(number a, number b, const coeffs r)
[275ecc]363{
[4d1ae5]364  if (nrnEqual(a, b,r)) return 2;
[31e857]365  if (mpz_divisible_p((int_number) a, (int_number) b)) return -1;
366  if (mpz_divisible_p((int_number) b, (int_number) a)) return 1;
[e90dfd6]367  return 0;
[275ecc]368}
369
[e90dfd6]370number nrnDiv(number a, number b, const coeffs r)
[275ecc]371{
[e90dfd6]372  if (a == NULL) a = (number)r->modNumber;
373  int_number erg = (int_number)omAllocBin(gmp_nrz_bin);
[8e56ad]374  mpz_init(erg);
[e90dfd6]375  if (mpz_divisible_p((int_number)a, (int_number)b))
[275ecc]376  {
[e90dfd6]377    mpz_divexact(erg, (int_number)a, (int_number)b);
378    return (number)erg;
[275ecc]379  }
380  else
381  {
[e90dfd6]382    int_number gcd = (int_number)nrnGcd(a, b, r);
383    mpz_divexact(erg, (int_number)b, gcd);
384    if (!nrnIsUnit((number)erg, r))
[8e56ad]385    {
[bca575c]386      WerrorS("Division not possible, even by cancelling zero divisors.");
387      WerrorS("Result is integer division without remainder.");
[67dbdb]388      mpz_tdiv_q(erg, (int_number) a, (int_number) b);
[31e857]389      nrnDelete((number*) &gcd, NULL);
[e90dfd6]390      return (number)erg;
[8e56ad]391    }
[31e857]392    // a / gcd(a,b) * [b / gcd (a,b)]^(-1)
[e90dfd6]393    int_number tmp = (int_number)nrnInvers((number) erg,r);
394    mpz_divexact(erg, (int_number)a, gcd);
[12ea9d]395    mpz_mul(erg, erg, tmp);
[31e857]396    nrnDelete((number*) &gcd, NULL);
397    nrnDelete((number*) &tmp, NULL);
[e90dfd6]398    mpz_mod(erg, erg, r->modNumber);
399    return (number)erg;
[275ecc]400  }
401}
402
[e90dfd6]403number nrnMod(number a, number b, const coeffs r)
[6ea941]404{
405  /*
[e90dfd6]406    We need to return the number rr which is uniquely determined by the
[6ea941]407    following two properties:
[e90dfd6]408      (1) 0 <= rr < |b| (with respect to '<' and '<=' performed in Z x Z)
409      (2) There exists some k in the integers Z such that a = k * b + rr.
[6ea941]410    Consider g := gcd(n, |b|). Note that then |b|/g is a unit in Z/n.
411    Now, there are three cases:
412      (a) g = 1
413          Then |b| is a unit in Z/n, i.e. |b| (and also b) divides a.
[e90dfd6]414          Thus rr = 0.
[6ea941]415      (b) g <> 1 and g divides a
[e90dfd6]416          Then a = (a/g) * (|b|/g)^(-1) * b (up to sign), i.e. again rr = 0.
[6ea941]417      (c) g <> 1 and g does not divide a
418          Then denote the division with remainder of a by g as this:
419          a = s * g + t. Then t = a - s * g = a - s * (|b|/g)^(-1) * |b|
[e90dfd6]420          fulfills (1) and (2), i.e. rr := t is the correct result. Hence
421          in this third case, rr is the remainder of division of a by g in Z.
[e1634d]422     Remark: according to mpz_mod: a,b are always non-negative
[6ea941]423  */
[e90dfd6]424  int_number g = (int_number)omAllocBin(gmp_nrz_bin);
425  int_number rr = (int_number)omAllocBin(gmp_nrz_bin);
[6ea941]426  mpz_init(g);
[e90dfd6]427  mpz_init_set_si(rr, 0);
428  mpz_gcd(g, (int_number)r->modNumber, (int_number)b); // g is now as above
429  if (mpz_cmp_si(g, (long)1) != 0) mpz_mod(rr, (int_number)a, g); // the case g <> 1
[6ea941]430  mpz_clear(g);
[3c3880b]431  omFreeBin(g, gmp_nrz_bin);
[e90dfd6]432  return (number)rr;
[6ea941]433}
434
[e90dfd6]435number nrnIntDiv(number a, number b, const coeffs r)
[275ecc]436{
[e90dfd6]437  int_number erg = (int_number)omAllocBin(gmp_nrz_bin);
[8e56ad]438  mpz_init(erg);
[e90dfd6]439  if (a == NULL) a = (number)r->modNumber;
440  mpz_tdiv_q(erg, (int_number)a, (int_number)b);
441  return (number)erg;
[275ecc]442}
443
[d351d8]444/*
[d9301a]445 * Helper function for computing the module
446 */
447
448int_number nrnMapCoef = NULL;
449
[9bb5457]450number nrnMapModN(number from, const coeffs /*src*/, const coeffs dst)
[d351d8]451{
[4d1ae5]452  return nrnMult(from, (number) nrnMapCoef, dst);
[d351d8]453}
[d9301a]454
[9bb5457]455number nrnMap2toM(number from, const coeffs /*src*/, const coeffs dst)
[d9301a]456{
[e90dfd6]457  int_number erg = (int_number)omAllocBin(gmp_nrz_bin);
[d9301a]458  mpz_init(erg);
[e90dfd6]459  mpz_mul_ui(erg, nrnMapCoef, (NATNUMBER)from);
460  mpz_mod(erg, erg, dst->modNumber);
461  return (number)erg;
[d9301a]462}
463
[9bb5457]464number nrnMapZp(number from, const coeffs /*src*/, const coeffs dst)
[894f5b1]465{
[e90dfd6]466  int_number erg = (int_number)omAllocBin(gmp_nrz_bin);
[894f5b1]467  mpz_init(erg);
[4d1ae5]468  // TODO: use npInt(...)
[e90dfd6]469  mpz_mul_si(erg, nrnMapCoef, (NATNUMBER)from);
470  mpz_mod(erg, erg, dst->modNumber);
471  return (number)erg;
[894f5b1]472}
473
[9bb5457]474number nrnMapGMP(number from, const coeffs /*src*/, const coeffs dst)
[d9301a]475{
[e90dfd6]476  int_number erg = (int_number)omAllocBin(gmp_nrz_bin);
[d9301a]477  mpz_init(erg);
[e90dfd6]478  mpz_mod(erg, (int_number)from, dst->modNumber);
479  return (number)erg;
[d9301a]480}
481
[8c6bd4d]482number nrnMapQ(number from, const coeffs src, const coeffs dst)
[894f5b1]483{
[e90dfd6]484  int_number erg = (int_number)omAllocBin(gmp_nrz_bin);
[894f5b1]485  mpz_init(erg);
[e90dfd6]486  nlGMP(from, (number)erg, src);
[8c6bd4d]487  mpz_mod(erg, erg, dst->modNumber);
[e90dfd6]488  return (number)erg;
[894f5b1]489}
490
[4d1ae5]491nMapFunc nrnSetMap(const coeffs src, const coeffs dst)
[275ecc]492{
[14b11bb]493  /* dst = currRing->cf */
[1cce47]494  if (nCoeff_is_Ring_Z(src))
[d351d8]495  {
[894f5b1]496    return nrnMapGMP;
497  }
[1cce47]498  if (nCoeff_is_Q(src))
[894f5b1]499  {
500    return nrnMapQ;
[d9301a]501  }
[894f5b1]502  // Some type of Z/n ring / field
[f0797c]503  if (nCoeff_is_Ring_ModN(src) || nCoeff_is_Ring_PtoM(src) ||
504      nCoeff_is_Ring_2toM(src) || nCoeff_is_Zp(src))
[d9301a]505  {
[66ce6d]506    if (   (!nCoeff_is_Zp(src))
[e90dfd6]507        && (mpz_cmp(src->modBase, dst->modBase) == 0)
508        && (src->modExponent == dst->modExponent)) return nrnMapGMP;
[d351d8]509    else
510    {
[3c3880b]511      int_number nrnMapModul = (int_number) omAllocBin(gmp_nrz_bin);
[894f5b1]512      // Computing the n of Z/n
[1cce47]513      if (nCoeff_is_Zp(src))
[894f5b1]514      {
515        mpz_init_set_si(nrnMapModul, src->ch);
516      }
517      else
518      {
519        mpz_init(nrnMapModul);
[e90dfd6]520        mpz_set(nrnMapModul, src->modNumber);
[894f5b1]521      }
522      // nrnMapCoef = 1 in dst       if dst is a subring of src
523      // nrnMapCoef = 0 in dst / src if src is a subring of dst
[d9301a]524      if (nrnMapCoef == NULL)
[d351d8]525      {
[3c3880b]526        nrnMapCoef = (int_number) omAllocBin(gmp_nrz_bin);
[d9301a]527        mpz_init(nrnMapCoef);
528      }
[e90dfd6]529      if (mpz_divisible_p(nrnMapModul, dst->modNumber))
[894f5b1]530      {
531        mpz_set_si(nrnMapCoef, 1);
532      }
533      else
[4d1ae5]534      if (nrnDivBy(NULL, (number) nrnMapModul,dst))
[d9301a]535      {
[e90dfd6]536        mpz_divexact(nrnMapCoef, dst->modNumber, nrnMapModul);
537        int_number tmp = dst->modNumber;
538        dst->modNumber = nrnMapModul;
[4d1ae5]539        if (!nrnIsUnit((number) nrnMapCoef,dst))
[0959dc]540        {
[e90dfd6]541          dst->modNumber = tmp;
[4d1ae5]542          nrnDelete((number*) &nrnMapModul, dst);
[0959dc]543          return NULL;
544        }
[4d1ae5]545        int_number inv = (int_number) nrnInvers((number) nrnMapCoef,dst);
[e90dfd6]546        dst->modNumber = tmp;
[d9301a]547        mpz_mul(nrnMapCoef, nrnMapCoef, inv);
[e90dfd6]548        mpz_mod(nrnMapCoef, nrnMapCoef, dst->modNumber);
[4d1ae5]549        nrnDelete((number*) &inv, dst);
[d9301a]550      }
551      else
552      {
[4d1ae5]553        nrnDelete((number*) &nrnMapModul, dst);
[d9301a]554        return NULL;
[d351d8]555      }
[4d1ae5]556      nrnDelete((number*) &nrnMapModul, dst);
[1cce47]557      if (nCoeff_is_Ring_2toM(src))
[d9301a]558        return nrnMap2toM;
[1cce47]559      else if (nCoeff_is_Zp(src))
[894f5b1]560        return nrnMapZp;
[d351d8]561      else
[d9301a]562        return nrnMapModN;
[d351d8]563    }
564  }
565  return NULL;      // default
[275ecc]566}
567
568/*
569 * set the exponent (allocate and init tables) (TODO)
570 */
571
[0486a3]572void nrnSetExp(unsigned long m, coeffs r)
[275ecc]573{
[e90dfd6]574  /* clean up former stuff */
575  if (r->modNumber != NULL) mpz_clear(r->modNumber);
[20704f]576
[0486a3]577  r->modExponent= m;
[e90dfd6]578  r->modNumber = (int_number)omAllocBin(gmp_nrz_bin);
[0486a3]579  mpz_init_set (r->modNumber, r->modBase);
580  mpz_pow_ui (r->modNumber, r->modNumber, m);
[275ecc]581}
582
[0486a3]583/* We expect this ring to be Z/n^m for some m > 0 and for some n > 2 which is not a prime. */
584void nrnInitExp(unsigned long m, coeffs r)
[275ecc]585{
[12ea9d]586  nrnSetExp(m, r);
[0486a3]587  assume (r->modNumber != NULL);
588  if (mpz_cmp_ui(r->modNumber,2) <= 0)
589    WarnS("nrnInitExp failed (m in Z/m too small)");
[275ecc]590}
591
592#ifdef LDEBUG
[9bb5457]593BOOLEAN nrnDBTest (number a, const char *, const int, const coeffs r)
[275ecc]594{
[01d4d3]595  if (a==NULL) return TRUE;
[e90dfd6]596  if ( (mpz_cmp_si((int_number) a, 0) < 0) || (mpz_cmp((int_number) a, r->modNumber) > 0) )
[275ecc]597  {
598    return FALSE;
599  }
600  return TRUE;
601}
602#endif
603
[8e56ad]604/*2
605* extracts a long integer from s, returns the rest    (COPY FROM longrat0.cc)
606*/
[a604c3]607static const char * nlCPEatLongC(char *s, mpz_ptr i)
[275ecc]608{
[85e68dd]609  const char * start=s;
[af378f7]610  if (!(*s >= '0' && *s <= '9'))
611  {
612    mpz_init_set_si(i, 1);
613    return s;
614  }
615  mpz_init(i);
[8e56ad]616  while (*s >= '0' && *s <= '9') s++;
617  if (*s=='\0')
[275ecc]618  {
[8e56ad]619    mpz_set_str(i,start,10);
620  }
621  else
622  {
623    char c=*s;
624    *s='\0';
625    mpz_set_str(i,start,10);
626    *s=c;
[275ecc]627  }
628  return s;
629}
630
[14b11bb]631const char * nrnRead (const char *s, number *a, const coeffs r)
[275ecc]632{
[3c3880b]633  int_number z = (int_number) omAllocBin(gmp_nrz_bin);
[275ecc]634  {
[85e68dd]635    s = nlCPEatLongC((char *)s, z);
[275ecc]636  }
[e90dfd6]637  mpz_mod(z, z, r->modNumber);
[8e56ad]638  *a = (number) z;
[275ecc]639  return s;
640}
641#endif
[8d0331d]642/* #ifdef HAVE_RINGS */
Note: See TracBrowser for help on using the repository browser.