source: git/libpolys/coeffs/modulop.cc @ 35c6e2c

spielwiese
Last change on this file since 35c6e2c was 35c6e2c, checked in by Hans Schoenemann <hannes@…>, 3 years ago
fix: map Z, Zn ->Zp, mpz_z ->Zp
  • Property mode set to 100644
File size: 14.2 KB
Line 
1/****************************************
2*  Computer Algebra System SINGULAR     *
3****************************************/
4/*
5* ABSTRACT: numbers modulo p (<=32749)
6*/
7
8#include "misc/auxiliary.h"
9
10#include "factory/factory.h"
11
12#include "misc/mylimits.h"
13#include "misc/sirandom.h"
14
15#include "reporter/reporter.h"
16
17#include "coeffs/coeffs.h"
18#include "coeffs/numbers.h"
19#include "coeffs/mpr_complex.h"
20
21#include "coeffs/longrat.h"
22#include "coeffs/modulop.h"
23
24#include <string.h>
25
26BOOLEAN npGreaterZero (number k, const coeffs r);
27long    npInt         (number &n, const coeffs r);
28void    npPower       (number a, int i, number * result,const coeffs r);
29BOOLEAN npIsMOne       (number a,const coeffs r);
30number  npDiv         (number a, number b,const coeffs r);
31number  npNeg         (number c,const coeffs r);
32number  npInvers      (number c,const coeffs r);
33BOOLEAN npGreater     (number a, number b,const coeffs r);
34BOOLEAN npEqual       (number a, number b,const coeffs r);
35void    npWrite       (number a, const coeffs r);
36const char *  npRead  (const char *s, number *a,const coeffs r);
37void nvInpMult(number &a, number b, const coeffs r);
38
39#ifdef LDEBUG
40BOOLEAN npDBTest      (number a, const char *f, const int l, const coeffs r);
41#endif
42
43nMapFunc npSetMap(const coeffs src, const coeffs dst);
44
45#include "coeffs/modulop_inl.h" // npMult, npInit
46
47#ifdef NV_OPS
48number  nvDiv         (number a, number b, const coeffs r);
49number  nvInvers      (number c, const coeffs r);
50//void    nvPower       (number a, int i, number * result, const coeffs r);
51#endif
52
53BOOLEAN npGreaterZero (number k, const coeffs r)
54{
55  n_Test(k, r);
56
57  int h = (int)((long) k);
58  return ((int)h !=0) && (h <= (r->ch>>1));
59}
60
61//unsigned long npMultMod(unsigned long a, unsigned long b, int npPrimeM)
62//{
63//  unsigned long c = a*b;
64//  c = c % npPrimeM;
65//  assume(c == (unsigned long) npMultM((number) a, (number) b, npPrimeM));
66//  return c;
67//}
68
69
70void npInpMult (number &a,number b, const coeffs r)
71{
72  n_Test(a, r);
73  n_Test(b, r);
74
75  if (((long)a == 0) || ((long)b == 0))
76    a=(number)0;
77  else
78    a = npMultM(a,b, r);
79  n_Test(a, r);
80}
81
82/*2
83 * convert a number to an int in (-p/2 .. p/2]
84 */
85long npInt(number &n, const coeffs r)
86{
87  n_Test(n, r);
88
89  if ((long)n > (((long)r->ch) >>1)) return ((long)n -((long)r->ch));
90  else                               return ((long)n);
91}
92
93BOOLEAN npIsMOne (number a, const coeffs r)
94{
95  n_Test(a, r);
96
97  return ((r->npPminus1M == (long)a) &&(1L!=(long)a))/*for char 2*/;
98}
99
100number npDiv (number a,number b, const coeffs r)
101{
102  n_Test(a, r);
103  n_Test(b, r);
104
105  if ((long)b==0L)
106  {
107    WerrorS(nDivBy0);
108    return (number)0L;
109  }
110  if ((long)a==0) return (number)0L;
111
112  number d;
113#ifndef HAVE_GENERIC_MULT
114  int s = r->npLogTable[(long)a] - r->npLogTable[(long)b];
115  #ifdef HAVE_GENERIC_ADD
116    if (s < 0)
117      s += r->npPminus1M;
118  #else
119    #if SIZEOF_LONG == 8
120    s += ((long)s >> 63) & r->npPminus1M;
121    #else
122    s += ((long)s >> 31) & r->npPminus1M;
123    #endif
124  #endif
125  d = (number)(long)r->npExpTable[s];
126#else
127  number inv=npInversM(b,r);
128  d = npMultM(a,inv,r);
129#endif
130
131  n_Test(d, r);
132  return d;
133
134}
135number  npInvers (number c, const coeffs r)
136{
137  n_Test(c, r);
138
139  if ((long)c==0L)
140  {
141    WerrorS("1/0");
142    return (number)0L;
143  }
144  number d = npInversM(c,r);
145
146  n_Test(d, r);
147  return d;
148}
149
150number npNeg (number c, const coeffs r)
151{
152  n_Test(c, r);
153
154  if ((long)c==0L) return c;
155
156#if 0
157  number d = npNegM(c,r);
158  n_Test(d, r);
159  return d;
160#else
161  c = npNegM(c,r);
162  n_Test(c, r);
163  return c;
164#endif
165}
166
167BOOLEAN npGreater (number a,number b, const coeffs r)
168{
169  n_Test(a, r);
170  n_Test(b, r);
171
172  //return (long)a != (long)b;
173  return ((long)a) > ((long)b);
174}
175
176BOOLEAN npEqual (number a,number b, const coeffs r)
177{
178  n_Test(a, r);
179  n_Test(b, r);
180
181//  return (long)a == (long)b;
182
183  return npEqualM(a,b,r);
184}
185
186void npWrite (number a, const coeffs r)
187{
188  n_Test(a, r);
189
190  if ((long)a>(((long)r->ch) >>1)) StringAppend("-%d",(int)(((long)r->ch)-((long)a)));
191  else                             StringAppend("%d",(int)((long)a));
192}
193
194#if 0
195void npPower (number a, int i, number * result, const coeffs r)
196{
197  n_Test(a, r);
198
199  if (i==0)
200  {
201    //npInit(1,result);
202    *(long *)result = 1;
203  }
204  else if (i==1)
205  {
206    *result = a;
207  }
208  else
209  {
210    npPower(a,i-1,result,r);
211    *result = npMultM(a,*result,r);
212  }
213}
214#endif
215
216static inline const char* npEati(const char *s, int *i, const coeffs r)
217{
218  return nEati((char *)s,i,(int)r->ch);
219}
220
221const char * npRead (const char *s, number *a, const coeffs r)
222{
223  int z;
224  int n=1;
225
226  s = npEati(s, &z, r);
227  if ((*s) == '/')
228  {
229    s++;
230    s = npEati(s, &n, r);
231  }
232  if (n == 1)
233    *a = (number)(long)z;
234  else
235  {
236    if ((z==0)&&(n==0)) WerrorS(nDivBy0);
237    else
238    {
239#ifdef NV_OPS
240      if (r->ch>NV_MAX_PRIME)
241        *a = nvDiv((number)(long)z,(number)(long)n,r);
242      else
243#endif
244        *a = npDiv((number)(long)z,(number)(long)n,r);
245    }
246  }
247  n_Test(*a, r);
248  return s;
249}
250
251/*2
252* set the charcteristic (allocate and init tables)
253*/
254
255void npKillChar(coeffs r)
256{
257  #ifdef HAVE_INVTABLE
258  if (r->npInvTable!=NULL)
259  {
260    omFreeSize( (void *)r->npInvTable, r->ch*sizeof(unsigned short) );
261    r->npInvTable=NULL;
262  }
263  #endif
264  #ifndef HAVE_GENERIC_MULT
265  if (r->npExpTable!=NULL)
266  {
267    omFreeSize( (void *)r->npExpTable, r->ch*sizeof(unsigned short) );
268    omFreeSize( (void *)r->npLogTable, r->ch*sizeof(unsigned short) );
269    r->npExpTable=NULL; r->npLogTable=NULL;
270  }
271  #endif
272}
273
274static BOOLEAN npCoeffsEqual(const coeffs r, n_coeffType n, void * parameter)
275{
276  /* test, if r is an instance of nInitCoeffs(n,parameter) */
277  return (n==n_Zp) && (r->ch==(int)(long)parameter);
278}
279CanonicalForm npConvSingNFactoryN( number n, BOOLEAN setChar, const coeffs r )
280{
281  if (setChar) setCharacteristic( r->ch );
282  return CanonicalForm(npInt( n,r ));
283}
284
285number npConvFactoryNSingN( const CanonicalForm n, const coeffs r)
286{
287  if (n.isImm())
288  {
289    return npInit(n.intval(),r);
290  }
291  else
292  {
293    assume(0);
294    return NULL;
295  }
296}
297
298static char* npCoeffName(const coeffs cf)
299{
300  STATIC_VAR char npCoeffName_buf[15];
301  snprintf(npCoeffName_buf,14,"ZZ/%d",cf->ch);
302  return npCoeffName_buf;
303}
304
305static void npWriteFd(number n, const ssiInfo* d, const coeffs)
306{
307  fprintf(d->f_write,"%d ",(int)(long)n);
308}
309
310static number npReadFd(const ssiInfo *d, const coeffs)
311{
312  // read int
313  int dd;
314  dd=s_readint(d->f_read);
315  return (number)(long)dd;
316}
317
318static number npRandom(siRandProc p, number, number, const coeffs cf)
319{
320  return npInit(p(),cf);
321}
322
323
324#ifndef HAVE_GENERIC_MULT
325static number npPar(int i, coeffs r)
326{
327  return (number)(long)r->npExpTable[1];
328}
329#endif
330
331static number npInitMPZ(mpz_t m, const coeffs r)
332{
333  return (number)mpz_fdiv_ui(m, r->ch);
334}
335
336BOOLEAN npInitChar(coeffs r, void* p)
337{
338  assume( getCoeffType(r) == n_Zp );
339  const int c = (int) (long) p;
340
341  assume( c > 0 );
342
343  int i, w;
344
345  r->is_field=TRUE;
346  r->is_domain=TRUE;
347  r->rep=n_rep_int;
348
349  r->ch = c;
350  r->npPminus1M = c /*r->ch*/ - 1;
351
352  //r->cfInitChar=npInitChar;
353  r->cfKillChar=npKillChar;
354  r->nCoeffIsEqual=npCoeffsEqual;
355  r->cfCoeffName=npCoeffName;
356
357  r->cfMult  = npMult;
358  r->cfInpMult  = npInpMult;
359  r->cfSub   = npSubM;
360  r->cfAdd   = npAddM;
361  r->cfInpAdd   = npInpAddM;
362  r->cfDiv   = npDiv;
363  r->cfInit = npInit;
364  //r->cfSize  = ndSize;
365  r->cfInt  = npInt;
366  r->cfInitMPZ = npInitMPZ;
367  #ifdef HAVE_RINGS
368  //r->cfDivComp = NULL; // only for ring stuff
369  //r->cfIsUnit = NULL; // only for ring stuff
370  //r->cfGetUnit = NULL; // only for ring stuff
371  //r->cfExtGcd = NULL; // only for ring stuff
372  // r->cfDivBy = NULL; // only for ring stuff
373  #endif
374  r->cfInpNeg   = npNeg;
375  r->cfInvers= npInvers;
376  //r->cfCopy  = ndCopy;
377  //r->cfRePart = ndCopy;
378  //r->cfImPart = ndReturn0;
379  r->cfWriteLong = npWrite;
380  r->cfRead = npRead;
381  //r->cfNormalize=ndNormalize;
382  r->cfGreater = npGreater;
383  r->cfEqual = npEqual;
384  r->cfIsZero = npIsZero;
385  r->cfIsOne = npIsOne;
386  r->cfIsMOne = npIsMOne;
387  r->cfGreaterZero = npGreaterZero;
388  //r->cfPower = npPower;
389  //r->cfGetDenom = ndGetDenom;
390  //r->cfGetNumerator = ndGetNumerator;
391  //r->cfGcd  = ndGcd;
392  //r->cfLcm  = ndGcd;
393  //r->cfDelete= ndDelete;
394  r->cfSetMap = npSetMap;
395  //r->cfName = ndName;
396  //r->cfInpMult=ndInpMult;
397  r->convSingNFactoryN=npConvSingNFactoryN;
398  r->convFactoryNSingN=npConvFactoryNSingN;
399  r->cfRandom=npRandom;
400#ifdef LDEBUG
401  // debug stuff
402  r->cfDBTest=npDBTest;
403#endif
404
405  // io via ssi
406  r->cfWriteFd=npWriteFd;
407  r->cfReadFd=npReadFd;
408
409  // the variables:
410  r->type = n_Zp;
411  r->has_simple_Alloc=TRUE;
412  r->has_simple_Inverse=TRUE;
413
414  // the tables
415#ifdef NV_OPS
416  if (r->ch <=NV_MAX_PRIME)
417#endif
418  {
419#ifdef HAVE_INVTABLE
420    r->npInvTable=(unsigned short*)omAlloc0( r->ch*sizeof(unsigned short) );
421#endif
422#ifndef HAVE_GENERIC_MULT
423    r->cfParameter=npPar; /* Singular.jl */
424    r->npExpTable=(unsigned short *)omAlloc0( r->ch*sizeof(unsigned short) );
425    r->npLogTable=(unsigned short *)omAlloc0( r->ch*sizeof(unsigned short) );
426    r->npExpTable[0] = 1;
427    r->npLogTable[0] = 0;
428    if (r->ch > 2)
429    {
430      w = 1;
431      loop
432      {
433        r->npLogTable[1] = 0;
434        w++;
435        i = 0;
436        loop
437        {
438          i++;
439          r->npExpTable[i] =(int)(((long)w * (long)r->npExpTable[i-1]) % r->ch);
440          r->npLogTable[r->npExpTable[i]] = i;
441          if /*(i == r->ch - 1 ) ||*/ (/*(*/ r->npExpTable[i] == 1 /*)*/)
442            break;
443        }
444        if (i == r->ch - 1)
445          break;
446      }
447    }
448    else
449    {
450      r->npExpTable[1] = 1;
451      r->npLogTable[1] = 0;
452    }
453#endif
454  }
455#ifdef NV_OPS
456  else /*if (c>NV_MAX_PRIME)*/
457  {
458    r->cfMult  = nvMult;
459    r->cfDiv   = nvDiv;
460    r->cfExactDiv = nvDiv;
461    r->cfInvers  = nvInvers;
462    r->cfInpMult = nvInpMult;
463    //r->cfPower= nvPower;
464    //if (c>FACTORY_MAX_PRIME) // factory will catch this error
465    //{
466    //  r->convSingNFactoryN=ndConvSingNFactoryN;
467    //}
468  }
469#endif
470  return FALSE;
471}
472
473#ifdef LDEBUG
474BOOLEAN npDBTest (number a, const char *f, const int l, const coeffs r)
475{
476  if (((long)a<0L) || ((long)a>(long)r->ch))
477  {
478    Print("wrong mod p number %ld at %s,%d\n",(long)a,f,l);
479    return FALSE;
480  }
481  return TRUE;
482}
483#endif
484
485static number npMapP(number from, const coeffs src, const coeffs dst_r)
486{
487  long i = (long)from;
488  if (i>src->ch/2)
489  {
490    i-=src->ch;
491    while (i < 0) i+=dst_r->ch;
492  }
493  i%=dst_r->ch;
494  return (number)i;
495}
496
497static number npMapLongR(number from, const coeffs /*src*/, const coeffs dst_r)
498{
499  gmp_float *ff=(gmp_float*)from;
500  mpf_t *f=ff->_mpfp();
501  number res;
502  mpz_ptr dest,ndest;
503  int size,i;
504  int e,al,bl;
505  long iz;
506  mp_ptr qp,dd,nn;
507
508  size = (*f)[0]._mp_size;
509  if (size == 0)
510    return npInit(0,dst_r);
511  if(size<0)
512    size = -size;
513
514  qp = (*f)[0]._mp_d;
515  while(qp[0]==0)
516  {
517    qp++;
518    size--;
519  }
520
521  if(dst_r->ch>2)
522    e=(*f)[0]._mp_exp-size;
523  else
524    e=0;
525  res = ALLOC_RNUMBER();
526#if defined(LDEBUG)
527  res->debug=123456;
528#endif
529  dest = res->z;
530
531  long in=0;
532  if (e<0)
533  {
534    al = dest->_mp_size = size;
535    if (al<2) al = 2;
536    dd = (mp_ptr)omAlloc(sizeof(mp_limb_t)*al);
537    for (i=0;i<size;i++) dd[i] = qp[i];
538    bl = 1-e;
539    nn = (mp_ptr)omAlloc(sizeof(mp_limb_t)*bl);
540    nn[bl-1] = 1;
541    for (i=bl-2;i>=0;i--) nn[i] = 0;
542    ndest = res->n;
543    ndest->_mp_d = nn;
544    ndest->_mp_alloc = ndest->_mp_size = bl;
545    res->s = 0;
546    in=mpz_fdiv_ui(ndest,dst_r->ch);
547    mpz_clear(ndest);
548  }
549  else
550  {
551    al = dest->_mp_size = size+e;
552    if (al<2) al = 2;
553    dd = (mp_ptr)omAlloc(sizeof(mp_limb_t)*al);
554    for (i=0;i<size;i++) dd[i+e] = qp[i];
555    for (i=0;i<e;i++) dd[i] = 0;
556    res->s = 3;
557  }
558
559  dest->_mp_d = dd;
560  dest->_mp_alloc = al;
561  iz=mpz_fdiv_ui(dest,dst_r->ch);
562  mpz_clear(dest);
563  if(res->s==0)
564    iz=(long)npDiv((number)iz,(number)in,dst_r);
565  FREE_RNUMBER(res); // Q!?
566  return (number)iz;
567}
568
569#ifdef HAVE_RINGS
570/*2
571* convert from a GMP integer
572*/
573static number npMapGMP(number from, const coeffs /*src*/, const coeffs dst)
574{
575  return (number)mpz_fdiv_ui((mpz_ptr) from, dst->ch);
576}
577
578static number npMapZ(number from, const coeffs src, const coeffs dst)
579{
580  if (SR_HDL(from) & SR_INT)
581  {
582    long f_i=SR_TO_INT(from);
583    return npInit(f_i,dst);
584  }
585  return npMapGMP(from,src,dst);
586}
587
588/*2
589* convert from an machine long
590*/
591static number npMapMachineInt(number from, const coeffs /*src*/,const coeffs dst)
592{
593  long i = (long) (((unsigned long) from) % dst->ch);
594  return (number) i;
595}
596#endif
597
598static number npMapCanonicalForm (number a, const coeffs /*src*/, const coeffs dst)
599{
600  setCharacteristic (dst ->ch);
601  CanonicalForm f= CanonicalForm ((InternalCF*)(a));
602  return (number) (f.intval());
603}
604
605nMapFunc npSetMap(const coeffs src, const coeffs dst)
606{
607#ifdef HAVE_RINGS
608  if ((src->rep==n_rep_int) && nCoeff_is_Ring_2toM(src))
609  {
610    return npMapMachineInt;
611  }
612  if (src->rep==n_rep_gmp) //nCoeff_is_Z(src) || nCoeff_is_Ring_PtoM(src) || nCoeff_is_Zn(src))
613  {
614    return npMapGMP;
615  }
616  if (src->rep==n_rep_gap_gmp) //nCoeff_is_Z(src)
617  {
618    return npMapZ;
619  }
620#endif
621  if (src->rep==n_rep_gap_rat)  /* Q, Z */
622  {
623    return nlModP; // npMap0; // FIXME? TODO? // extern number nlModP(number q, const coeffs Q, const coeffs Zp); // Map q \in QQ \to Zp // FIXME!
624  }
625  if ((src->rep==n_rep_int) &&  nCoeff_is_Zp(src) )
626  {
627    return npMapP;
628  }
629  if ((src->rep==n_rep_gmp_float) && nCoeff_is_long_R(src))
630  {
631    return npMapLongR;
632  }
633  if (nCoeff_is_CF (src))
634  {
635    return npMapCanonicalForm;
636  }
637  return NULL;      /* default */
638}
639
640// -----------------------------------------------------------
641//  operation for very large primes (32749< p < 2^31-1)
642// ----------------------------------------------------------
643#ifdef NV_OPS
644void nvInpMult(number &a, number b, const coeffs r)
645{
646  number n=nvMult(a,b,r);
647  a=n;
648}
649
650static inline number nvInversM (number c, const coeffs r)
651{
652  long inv=npInvMod((long)c,r);
653  return (number)inv;
654}
655
656number nvDiv (number a,number b, const coeffs r)
657{
658  if ((long)a==0L)
659    return (number)0L;
660  else if ((long)b==0L)
661  {
662    WerrorS(nDivBy0);
663    return (number)0L;
664  }
665  else
666  {
667    number inv=nvInversM(b,r);
668    return nvMult(a,inv,r);
669  }
670}
671number  nvInvers (number c, const coeffs r)
672{
673  if ((long)c==0L)
674  {
675    WerrorS(nDivBy0);
676    return (number)0L;
677  }
678  return nvInversM(c,r);
679}
680#if 0
681void nvPower (number a, int i, number * result, const coeffs r)
682{
683  if (i==0)
684  {
685    //npInit(1,result);
686    *(long *)result = 1;
687  }
688  else if (i==1)
689  {
690    *result = a;
691  }
692  else
693  {
694    nvPower(a,i-1,result,r);
695    *result = nvMult(a,*result,r);
696  }
697}
698#endif
699#endif
700
Note: See TracBrowser for help on using the repository browser.