source: git/libpolys/coeffs/rmodulon.cc @ 2f3764

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