source: git/libpolys/coeffs/modulop.cc

spielwiese
Last change on this file was 738395, checked in by Hans Schoenemann <hannes@…>, 8 days ago
HAVE_RINGS is default (p2)
  • 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
26static BOOLEAN npGreaterZero (number k, const coeffs r);
27static BOOLEAN npIsMOne       (number a,const coeffs r);
28static number  npDiv         (number a, number b,const coeffs r);
29static number  npNeg         (number c,const coeffs r);
30static number  npInvers      (number c,const coeffs r);
31static BOOLEAN npGreater     (number a, number b,const coeffs r);
32static BOOLEAN npEqual       (number a, number b,const coeffs r);
33static void    npWrite       (number a, const coeffs r);
34static const char *  npRead  (const char *s, number *a,const coeffs r);
35static void nvInpMult(number &a, number b, const coeffs r);
36
37#ifdef LDEBUG
38static BOOLEAN npDBTest      (number a, const char *f, const int l, const coeffs r);
39#endif
40
41static nMapFunc npSetMap(const coeffs src, const coeffs dst);
42
43#include "coeffs/modulop_inl.h" // npMult, npInit
44
45#ifdef NV_OPS
46static number  nvDiv         (number a, number b, const coeffs r);
47number  nvInvers      (number c, const coeffs r);
48//void    nvPower       (number a, int i, number * result, const coeffs r);
49#endif
50
51static BOOLEAN npGreaterZero (number k, const coeffs r)
52{
53  n_Test(k, r);
54
55  int h = (int)((long) k);
56  return ((int)h !=0) && (h <= (r->ch>>1));
57}
58
59//unsigned long npMultMod(unsigned long a, unsigned long b, int npPrimeM)
60//{
61//  unsigned long c = a*b;
62//  c = c % npPrimeM;
63//  assume(c == (unsigned long) npMultM((number) a, (number) b, npPrimeM));
64//  return c;
65//}
66
67
68void npInpMult (number &a,number b, const coeffs r)
69{
70  n_Test(a, r);
71  n_Test(b, r);
72
73  if (((long)a == 0) || ((long)b == 0))
74    a=(number)0;
75  else
76    a = npMultM(a,b, r);
77  n_Test(a, r);
78}
79
80/*2
81 * convert a number to an int in (-p/2 .. p/2]
82 */
83long npInt(number &n, const coeffs r)
84{
85  n_Test(n, r);
86
87  if ((long)n > (((long)r->ch) >>1)) return ((long)n -((long)r->ch));
88  else                               return ((long)n);
89}
90
91static BOOLEAN npIsMOne (number a, const coeffs r)
92{
93  n_Test(a, r);
94
95  return ((r->npPminus1M == (long)a) &&(1L!=(long)a))/*for char 2*/;
96}
97
98static number npDiv (number a,number b, const coeffs r)
99{
100  n_Test(a, r);
101  n_Test(b, r);
102
103  if ((long)b==0L)
104  {
105    WerrorS(nDivBy0);
106    return (number)0L;
107  }
108  if ((long)a==0) return (number)0L;
109
110  number d;
111#ifndef HAVE_GENERIC_MULT
112  int s = r->npLogTable[(long)a] - r->npLogTable[(long)b];
113  #ifdef HAVE_GENERIC_ADD
114    if (s < 0)
115      s += r->npPminus1M;
116  #else
117    #if SIZEOF_LONG == 8
118    s += ((long)s >> 63) & r->npPminus1M;
119    #else
120    s += ((long)s >> 31) & r->npPminus1M;
121    #endif
122  #endif
123  d = (number)(long)r->npExpTable[s];
124#else
125  number inv=npInversM(b,r);
126  d = npMultM(a,inv,r);
127#endif
128
129  n_Test(d, r);
130  return d;
131
132}
133static number  npInvers (number c, const coeffs r)
134{
135  n_Test(c, r);
136
137  if ((long)c==0L)
138  {
139    WerrorS("1/0");
140    return (number)0L;
141  }
142  number d = npInversM(c,r);
143
144  n_Test(d, r);
145  return d;
146}
147
148static number npNeg (number c, const coeffs r)
149{
150  n_Test(c, r);
151
152  if ((long)c==0L) return c;
153
154#if 0
155  number d = npNegM(c,r);
156  n_Test(d, r);
157  return d;
158#else
159  c = npNegM(c,r);
160  n_Test(c, r);
161  return c;
162#endif
163}
164
165static BOOLEAN npGreater (number a,number b, const coeffs r)
166{
167  n_Test(a, r);
168  n_Test(b, r);
169
170  //return (long)a != (long)b;
171  return ((long)a) > ((long)b);
172}
173
174static BOOLEAN npEqual (number a,number b, const coeffs r)
175{
176  n_Test(a, r);
177  n_Test(b, r);
178
179//  return (long)a == (long)b;
180
181  return npEqualM(a,b,r);
182}
183
184static void npWrite (number a, const coeffs r)
185{
186  n_Test(a, r);
187
188  if ((long)a>(((long)r->ch) >>1)) StringAppend("-%d",(int)(((long)r->ch)-((long)a)));
189  else                             StringAppend("%d",(int)((long)a));
190}
191
192#if 0
193static void npPower (number a, int i, number * result, const coeffs r)
194{
195  n_Test(a, r);
196
197  if (i==0)
198  {
199    //npInit(1,result);
200    *(long *)result = 1;
201  }
202  else if (i==1)
203  {
204    *result = a;
205  }
206  else
207  {
208    npPower(a,i-1,result,r);
209    *result = npMultM(a,*result,r);
210  }
211}
212#endif
213
214static inline const char* npEati(const char *s, int *i, const coeffs r)
215{
216  return nEati((char *)s,i,(int)r->ch);
217}
218
219static const char * npRead (const char *s, number *a, const coeffs r)
220{
221  int z;
222  int n=1;
223
224  s = npEati(s, &z, r);
225  if ((*s) == '/')
226  {
227    s++;
228    s = npEati(s, &n, r);
229  }
230  if (n == 1)
231    *a = (number)(long)z;
232  else
233  {
234    if ((z==0)&&(n==0))
235    {
236      WerrorS(nDivBy0);
237      *a=(number)0L;
238    }
239    else
240    {
241#ifdef NV_OPS
242      if (r->ch>NV_MAX_PRIME)
243        *a = nvDiv((number)(long)z,(number)(long)n,r);
244      else
245#endif
246        *a = npDiv((number)(long)z,(number)(long)n,r);
247    }
248  }
249  n_Test(*a, r);
250  return s;
251}
252
253/*2
254* set the charcteristic (allocate and init tables)
255*/
256
257void npKillChar(coeffs r)
258{
259  #ifdef HAVE_INVTABLE
260  if (r->npInvTable!=NULL)
261  {
262    omFreeSize( (void *)r->npInvTable, r->ch*sizeof(unsigned short) );
263    r->npInvTable=NULL;
264  }
265  #endif
266  #ifndef HAVE_GENERIC_MULT
267  if (r->npExpTable!=NULL)
268  {
269    omFreeSize( (void *)r->npExpTable, r->ch*sizeof(unsigned short) );
270    omFreeSize( (void *)r->npLogTable, r->ch*sizeof(unsigned short) );
271    r->npExpTable=NULL; r->npLogTable=NULL;
272  }
273  #endif
274}
275
276static BOOLEAN npCoeffsEqual(const coeffs r, n_coeffType n, void * parameter)
277{
278  /* test, if r is an instance of nInitCoeffs(n,parameter) */
279  return (n==n_Zp) && (r->ch==(int)(long)parameter);
280}
281CanonicalForm npConvSingNFactoryN( number n, BOOLEAN setChar, const coeffs r )
282{
283  if (setChar) setCharacteristic( r->ch );
284  return CanonicalForm(npInt( n,r ));
285}
286
287number npConvFactoryNSingN( const CanonicalForm n, const coeffs r)
288{
289  if (n.isImm())
290  {
291    return npInit(n.intval(),r);
292  }
293  else
294  {
295    assume(0);
296    return NULL;
297  }
298}
299
300static char* npCoeffName(const coeffs cf)
301{
302  STATIC_VAR char npCoeffName_buf[15];
303  snprintf(npCoeffName_buf,14,"ZZ/%d",cf->ch);
304  return npCoeffName_buf;
305}
306
307static void npWriteFd(number n, const ssiInfo* d, const coeffs)
308{
309  fprintf(d->f_write,"%d ",(int)(long)n);
310}
311
312static number npReadFd(const ssiInfo *d, const coeffs)
313{
314  // read int
315  int dd;
316  dd=s_readint(d->f_read);
317  return (number)(long)dd;
318}
319
320static number npRandom(siRandProc p, number, number, const coeffs cf)
321{
322  return npInit(p(),cf);
323}
324
325
326#ifndef HAVE_GENERIC_MULT
327static number npPar(int, coeffs r)
328{
329  return (number)(long)r->npExpTable[1];
330}
331#endif
332
333static number npInitMPZ(mpz_t m, const coeffs r)
334{
335  return (number)mpz_fdiv_ui(m, r->ch);
336}
337
338BOOLEAN npInitChar(coeffs r, void* p)
339{
340  assume( getCoeffType(r) == n_Zp );
341  const int c = (int) (long) p;
342
343  assume( c > 0 );
344
345  int i, w;
346
347  r->is_field=TRUE;
348  r->is_domain=TRUE;
349  r->rep=n_rep_int;
350
351  r->ch = c;
352  r->npPminus1M = c /*r->ch*/ - 1;
353
354  //r->cfInitChar=npInitChar;
355  r->cfKillChar=npKillChar;
356  r->nCoeffIsEqual=npCoeffsEqual;
357  r->cfCoeffName=npCoeffName;
358
359  r->cfMult  = npMult;
360  r->cfInpMult  = npInpMult;
361  r->cfSub   = npSubM;
362  r->cfAdd   = npAddM;
363  r->cfInpAdd   = npInpAddM;
364  r->cfDiv   = npDiv;
365  r->cfInit = npInit;
366  //r->cfSize  = ndSize;
367  r->cfInt  = npInt;
368  r->cfInitMPZ = npInitMPZ;
369  //r->cfDivComp = NULL; // only for ring stuff
370  //r->cfIsUnit = NULL; // only for ring stuff
371  //r->cfGetUnit = NULL; // only for ring stuff
372  //r->cfExtGcd = NULL; // only for ring stuff
373  // r->cfDivBy = NULL; // only for ring stuff
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
474static BOOLEAN 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/*2
570* convert from a GMP integer
571*/
572static number npMapGMP(number from, const coeffs /*src*/, const coeffs dst)
573{
574  return (number)mpz_fdiv_ui((mpz_ptr) from, dst->ch);
575}
576
577static number npMapZ(number from, const coeffs src, const coeffs dst)
578{
579  if (SR_HDL(from) & SR_INT)
580  {
581    long f_i=SR_TO_INT(from);
582    return npInit(f_i,dst);
583  }
584  return npMapGMP(from,src,dst);
585}
586
587/*2
588* convert from an machine long
589*/
590static number npMapMachineInt(number from, const coeffs /*src*/,const coeffs dst)
591{
592  long i = (long) (((unsigned long) from) % dst->ch);
593  return (number) i;
594}
595
596static number npMapCanonicalForm (number a, const coeffs /*src*/, const coeffs dst)
597{
598  setCharacteristic (dst ->ch);
599  CanonicalForm f= CanonicalForm ((InternalCF*)(a));
600  return (number) (f.intval());
601}
602
603static nMapFunc npSetMap(const coeffs src, const coeffs)
604{
605  if ((src->rep==n_rep_int) && nCoeff_is_Ring_2toM(src))
606  {
607    return npMapMachineInt;
608  }
609  if (src->rep==n_rep_gmp) //nCoeff_is_Z(src) || nCoeff_is_Ring_PtoM(src) || nCoeff_is_Zn(src))
610  {
611    return npMapGMP;
612  }
613  if (src->rep==n_rep_gap_gmp) //nCoeff_is_Z(src)
614  {
615    return npMapZ;
616  }
617  if (src->rep==n_rep_gap_rat)  /* Q, Z */
618  {
619    return nlModP; // npMap0; // FIXME? TODO? // extern number nlModP(number q, const coeffs Q, const coeffs Zp); // Map q \in QQ \to Zp // FIXME!
620  }
621  if ((src->rep==n_rep_int) &&  nCoeff_is_Zp(src) )
622  {
623    return npMapP;
624  }
625  if ((src->rep==n_rep_gmp_float) && nCoeff_is_long_R(src))
626  {
627    return npMapLongR;
628  }
629  if (nCoeff_is_CF (src))
630  {
631    return npMapCanonicalForm;
632  }
633  return NULL;      /* default */
634}
635
636// -----------------------------------------------------------
637//  operation for very large primes (32749< p < 2^31-1)
638// ----------------------------------------------------------
639#ifdef NV_OPS
640static void nvInpMult(number &a, number b, const coeffs r)
641{
642  number n=nvMult(a,b,r);
643  a=n;
644}
645
646static inline number nvInversM (number c, const coeffs r)
647{
648  long inv=npInvMod((long)c,r);
649  return (number)inv;
650}
651
652static number nvDiv (number a,number b, const coeffs r)
653{
654  if ((long)a==0L)
655    return (number)0L;
656  else if ((long)b==0L)
657  {
658    WerrorS(nDivBy0);
659    return (number)0L;
660  }
661  else
662  {
663    number inv=nvInversM(b,r);
664    return nvMult(a,inv,r);
665  }
666}
667number  nvInvers (number c, const coeffs r)
668{
669  if ((long)c==0L)
670  {
671    WerrorS(nDivBy0);
672    return (number)0L;
673  }
674  return nvInversM(c,r);
675}
676#if 0
677void nvPower (number a, int i, number * result, const coeffs r)
678{
679  if (i==0)
680  {
681    //npInit(1,result);
682    *(long *)result = 1;
683  }
684  else if (i==1)
685  {
686    *result = a;
687  }
688  else
689  {
690    nvPower(a,i-1,result,r);
691    *result = nvMult(a,*result,r);
692  }
693}
694#endif
695#endif
696
Note: See TracBrowser for help on using the repository browser.