source: git/libpolys/coeffs/rmodulon.cc @ 0b7bf7

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