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

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