source: git/libpolys/coeffs/modulop.cc @ eb55f8a

spielwiese
Last change on this file since eb55f8a was eb55f8a, checked in by Oleksandr Motsak <motsak@…>, 10 years ago
There should be no *Test in assume call (and no assume in *Test definition)
  • Property mode set to 100644
File size: 16.1 KB
Line 
1/****************************************
2*  Computer Algebra System SINGULAR     *
3****************************************/
4/*
5* ABSTRACT: numbers modulo p (<=32003)
6*/
7
8
9
10
11#include <misc/auxiliary.h>
12
13#include <factory/factory.h>
14
15#include <string.h>
16#include <omalloc/omalloc.h>
17#include <coeffs/coeffs.h>
18#include <reporter/reporter.h>
19#include <coeffs/numbers.h>
20#include <coeffs/longrat.h>
21#include <coeffs/mpr_complex.h>
22#include <misc/mylimits.h>
23#include <misc/sirandom.h>
24#include <coeffs/modulop.h>
25
26// int npGen=0;
27
28/// Our Type!
29static const n_coeffType ID = n_Zp;
30
31#ifdef NV_OPS
32#pragma GCC diagnostic ignored "-Wlong-long"
33static inline number nvMultM(number a, number b, const coeffs r)
34{
35  assume( getCoeffType(r) == ID );
36
37#if SIZEOF_LONG == 4
38#define ULONG64 (unsigned long long)(unsigned long)
39#else
40#define ULONG64 (unsigned long)
41#endif
42  return (number)
43      (unsigned long)((ULONG64 a)*(ULONG64 b) % (ULONG64 r->ch));
44}
45number  nvMult        (number a, number b, const coeffs r);
46number  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
51
52
53
54BOOLEAN npGreaterZero (number k, const coeffs r)
55{
56  n_Test(k, r);
57
58  int h = (int)((long) k);
59  return ((int)h !=0) && (h <= (r->ch>>1));
60}
61
62//unsigned long npMultMod(unsigned long a, unsigned long b, int npPrimeM)
63//{
64//  unsigned long c = a*b;
65//  c = c % npPrimeM;
66//  assume(c == (unsigned long) npMultM((number) a, (number) b, npPrimeM));
67//  return c;
68//}
69
70number npMult (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    return (number)0;
77  number c = npMultM(a,b, r);
78  n_Test(c, r);
79  return c;
80}
81
82/*2
83* create a number from int
84*/
85number npInit (long i, const coeffs r)
86{
87  long ii=i % (long)r->ch;
88  if (ii <  0L)                         ii += (long)r->ch;
89
90  number c = (number)ii;
91  n_Test(c, r);
92  return c;
93
94}
95
96
97/*2
98 * convert a number to an int in (-p/2 .. p/2]
99 */
100int npInt(number &n, const coeffs r)
101{
102  n_Test(n, r);
103
104  if ((long)n > (((long)r->ch) >>1)) return (int)((long)n -((long)r->ch));
105  else                               return (int)((long)n);
106}
107
108number npAdd (number a, number b, const coeffs r)
109{
110  n_Test(a, r);
111  n_Test(b, r);
112
113  number c = npAddM(a,b, r);
114
115  n_Test(c, r);
116
117  return c;
118}
119
120number npSub (number a, number b, const coeffs r)
121{
122  n_Test(a, r);
123  n_Test(b, r);
124
125  number c = npSubM(a,b,r);
126
127  n_Test(c, r);
128
129  return c;
130}
131
132BOOLEAN npIsZero (number  a, const coeffs r)
133{
134  n_Test(a, r);
135
136  return 0 == (long)a;
137}
138
139BOOLEAN npIsOne (number a, const coeffs r)
140{
141  n_Test(a, r);
142
143  return 1 == (long)a;
144}
145
146BOOLEAN npIsMOne (number a, const coeffs r)
147{
148  n_Test(a, r);
149
150  return ((r->npPminus1M == (long)a)&&((long)1!=(long)a));
151}
152
153#ifdef HAVE_DIV_MOD
154
155#ifdef USE_NTL_XGCD
156
157//ifdef HAVE_NTL // in ntl.a
158//extern void XGCD(long& d, long& s, long& t, long a, long b);
159#include <NTL/ZZ.h>
160#ifdef NTL_CLIENT
161NTL_CLIENT
162#endif
163
164#endif
165
166long InvMod(long a, const coeffs R)
167{
168   long d, s, t;
169
170#ifdef USE_NTL_XGCD
171   XGCD(d, s, t, a, R->ch);
172   assume (d == 1);
173#else
174   long  u, v, u0, v0, u1, v1, u2, v2, q, r;
175
176   assume(a>0);
177   u1=1; u2=0;
178   u = a; v = R->ch;
179
180   while (v != 0)
181   {
182      q = u / v;
183      r = u % v;
184      u = v;
185      v = r;
186      u0 = u2;
187      u2 = u1 - q*u2;
188      u1 = u0;
189   }
190
191   assume(u==1);
192   s = u1;
193#endif
194   if (s < 0)
195      return s + R->ch;
196   else
197      return s;
198}
199#endif
200
201inline number npInversM (number c, const coeffs r)
202{
203  n_Test(c, r);
204#ifndef HAVE_DIV_MOD
205  number d = (number)(long)r->npExpTable[r->npPminus1M - r->npLogTable[(long)c]];
206#else
207  long inv=(long)r->npInvTable[(long)c];
208  if (inv==0)
209  {
210    inv=InvMod((long)c,r);
211    r->npInvTable[(long)c]=inv;
212  }
213  number d = (number)inv;
214#endif
215  n_Test(d, r);
216  return d;
217
218}
219
220number npDiv (number a,number b, const coeffs r)
221{
222  n_Test(a, r);
223  n_Test(b, r);
224
225//#ifdef NV_OPS
226//  if (r->ch>NV_MAX_PRIME)
227//    return nvDiv(a,b);
228//#endif
229  if ((long)a==0)
230    return (number)0;
231  number d;
232
233#ifndef HAVE_DIV_MOD
234  if ((long)b==0)
235  {
236    WerrorS(nDivBy0);
237    return (number)0;
238  }
239
240  int s = r->npLogTable[(long)a] - r->npLogTable[(long)b];
241  if (s < 0)
242    s += r->npPminus1M;
243  d = (number)(long)r->npExpTable[s];
244#else
245  number inv=npInversM(b,r);
246  d = npMultM(a,inv,r);
247#endif
248
249  n_Test(d, r);
250  return d;
251
252}
253number  npInvers (number c, const coeffs r)
254{
255  n_Test(c, r);
256
257  if ((long)c==0)
258  {
259    WerrorS("1/0");
260    return (number)0;
261  }
262  number d = npInversM(c,r);
263
264  n_Test(d, r);
265  return d;
266
267}
268
269number npNeg (number c, const coeffs r)
270{
271  n_Test(c, r);
272
273  if ((long)c==0) return c;
274
275#if 0
276  number d = npNegM(c,r);
277  n_Test(d, r);
278  return d;
279#else
280  c = npNegM(c,r);
281  n_Test(c, r);
282  return c;
283#endif
284}
285
286BOOLEAN npGreater (number a,number b, const coeffs r)
287{
288  n_Test(a, r);
289  n_Test(b, r);
290
291  //return (long)a != (long)b;
292  return (long)a > (long)b;
293}
294
295BOOLEAN npEqual (number a,number b, const coeffs r)
296{
297  n_Test(a, r);
298  n_Test(b, r);
299
300//  return (long)a == (long)b;
301
302  return npEqualM(a,b,r);
303}
304
305void npWrite (number &a, const coeffs r)
306{
307  n_Test(a, r);
308
309  if ((long)a>(((long)r->ch) >>1)) StringAppend("-%d",(int)(((long)r->ch)-((long)a)));
310  else                             StringAppend("%d",(int)((long)a));
311}
312
313#if 0
314void npPower (number a, int i, number * result, const coeffs r)
315{
316  n_Test(a, r);
317
318  if (i==0)
319  {
320    //npInit(1,result);
321    *(long *)result = 1;
322  }
323  else if (i==1)
324  {
325    *result = a;
326  }
327  else
328  {
329    npPower(a,i-1,result,r);
330    *result = npMultM(a,*result,r);
331  }
332}
333#endif
334
335static const char* npEati(const char *s, int *i, const coeffs r)
336{
337
338  if (((*s) >= '0') && ((*s) <= '9'))
339  {
340    unsigned long ii=0L;
341    do
342    {
343      ii *= 10;
344      ii += *s++ - '0';
345      if (ii >= (MAX_INT_VAL / 10)) ii = ii % r->ch;
346    }
347    while (((*s) >= '0') && ((*s) <= '9'));
348    if (ii >= (unsigned long)r->ch) ii = ii % r->ch;
349    *i=(int)ii;
350  }
351  else (*i) = 1;
352  return s;
353}
354
355const char * npRead (const char *s, number *a, const coeffs r)
356{
357  int z;
358  int n=1;
359
360  s = npEati(s, &z, r);
361  if ((*s) == '/')
362  {
363    s++;
364    s = npEati(s, &n, r);
365  }
366  if (n == 1)
367    *a = (number)(long)z;
368  else
369  {
370    if ((z==0)&&(n==0)) WerrorS(nDivBy0);
371    else
372    {
373#ifdef NV_OPS
374      if (r->ch>NV_MAX_PRIME)
375        *a = nvDiv((number)(long)z,(number)(long)n,r);
376      else
377#endif
378        *a = npDiv((number)(long)z,(number)(long)n,r);
379    }
380  }
381  n_Test(*a, r);
382  return s;
383}
384
385/*2
386* set the charcteristic (allocate and init tables)
387*/
388
389void npKillChar(coeffs r)
390{
391  #ifdef HAVE_DIV_MOD
392  if (r->npInvTable!=NULL)
393  omFreeSize( (void *)r->npInvTable, r->ch*sizeof(unsigned short) );
394  r->npInvTable=NULL;
395  #else
396  if (r->npExpTable!=NULL)
397  {
398    omFreeSize( (void *)r->npExpTable, r->ch*sizeof(unsigned short) );
399    omFreeSize( (void *)r->npLogTable, r->ch*sizeof(unsigned short) );
400    r->npExpTable=NULL; r->npLogTable=NULL;
401  }
402  #endif
403}
404
405static BOOLEAN npCoeffsEqual(const coeffs r, n_coeffType n, void * parameter)
406{
407  /* test, if r is an instance of nInitCoeffs(n,parameter) */
408  return (n==n_Zp) && (r->ch==(int)(long)parameter);
409}
410CanonicalForm npConvSingNFactoryN( number n, BOOLEAN setChar, const coeffs r )
411{
412  if (setChar) setCharacteristic( r->ch );
413  CanonicalForm term(npInt( n,r ));
414  return term;
415}
416
417number npConvFactoryNSingN( const CanonicalForm n, const coeffs r)
418{
419  if (n.isImm())
420  {
421    return npInit(n.intval(),r);
422  }
423  else
424  {
425    assume(0);
426    return NULL;
427  }
428}
429
430static char* npCoeffString(const coeffs r)
431{
432  char *s=(char*)omAlloc(11);
433  snprintf(s,11,"%d",r->ch);
434  return s;
435}
436
437static void npWriteFd(number n, FILE* f, const coeffs r)
438{
439  fprintf(f,"%d ",(int)(long)n);
440}
441
442static number npReadFd(s_buff f, const coeffs r)
443{
444  // read int
445  int dd;
446  dd=s_readint(f);
447  return (number)(long)dd;
448}
449
450BOOLEAN npInitChar(coeffs r, void* p)
451{
452  assume( getCoeffType(r) == ID );
453  const int c = (int) (long) p;
454
455  assume( c > 0 );
456
457  int i, w;
458
459  r->is_field=TRUE;
460  r->is_domain=TRUE;
461  r->rep=n_rep_int;
462
463  r->ch = c;
464  r->npPminus1M = c /*r->ch*/ - 1;
465
466  //r->cfInitChar=npInitChar;
467  r->cfKillChar=npKillChar;
468  r->nCoeffIsEqual=npCoeffsEqual;
469  r->cfCoeffString=npCoeffString;
470
471  r->cfMult  = npMult;
472  r->cfSub   = npSub;
473  r->cfAdd   = npAdd;
474  r->cfDiv   = npDiv;
475  r->cfInit = npInit;
476  //r->cfSize  = ndSize;
477  r->cfInt  = npInt;
478  #ifdef HAVE_RINGS
479  //r->cfDivComp = NULL; // only for ring stuff
480  //r->cfIsUnit = NULL; // only for ring stuff
481  //r->cfGetUnit = NULL; // only for ring stuff
482  //r->cfExtGcd = NULL; // only for ring stuff
483  // r->cfDivBy = NULL; // only for ring stuff
484  #endif
485  r->cfInpNeg   = npNeg;
486  r->cfInvers= npInvers;
487  //r->cfCopy  = ndCopy;
488  //r->cfRePart = ndCopy;
489  //r->cfImPart = ndReturn0;
490  r->cfWriteLong = npWrite;
491  r->cfRead = npRead;
492  //r->cfNormalize=ndNormalize;
493  r->cfGreater = npGreater;
494  r->cfEqual = npEqual;
495  r->cfIsZero = npIsZero;
496  r->cfIsOne = npIsOne;
497  r->cfIsMOne = npIsMOne;
498  r->cfGreaterZero = npGreaterZero;
499  //r->cfPower = npPower;
500  r->cfGetDenom = ndGetDenom;
501  r->cfGetNumerator = ndGetNumerator;
502  //r->cfGcd  = ndGcd;
503  //r->cfLcm  = ndGcd;
504  //r->cfDelete= ndDelete;
505  r->cfSetMap = npSetMap;
506  //r->cfName = ndName;
507  r->cfInpMult=ndInpMult;
508#ifdef NV_OPS
509  if (c>NV_MAX_PRIME)
510  {
511    r->cfMult  = nvMult;
512    r->cfDiv   = nvDiv;
513    r->cfExactDiv= nvDiv;
514    r->cfInvers= nvInvers;
515    //r->cfPower= nvPower;
516  }
517#endif
518  r->cfCoeffWrite=npCoeffWrite;
519#ifdef LDEBUG
520  // debug stuff
521  r->cfDBTest=npDBTest;
522#endif
523
524  r->convSingNFactoryN=npConvSingNFactoryN;
525  r->convFactoryNSingN=npConvFactoryNSingN;
526
527  // io via ssi
528  r->cfWriteFd=npWriteFd;
529  r->cfReadFd=npReadFd;
530
531  // the variables:
532  r->nNULL = (number)0;
533  r->type = n_Zp;
534  r->ch = c;
535  r->has_simple_Alloc=TRUE;
536  r->has_simple_Inverse=TRUE;
537
538  // the tables
539#ifdef NV_OPS
540  if (r->ch <=NV_MAX_PRIME)
541#endif
542  {
543#if !defined(HAVE_DIV_MOD) || !defined(HAVE_MULT_MOD)
544    r->npExpTable=(unsigned short *)omAlloc( r->ch*sizeof(unsigned short) );
545    r->npLogTable=(unsigned short *)omAlloc( r->ch*sizeof(unsigned short) );
546    r->npExpTable[0] = 1;
547    r->npLogTable[0] = 0;
548    if (r->ch > 2)
549    {
550      w = 1;
551      loop
552      {
553        r->npLogTable[1] = 0;
554        w++;
555        i = 0;
556        loop
557        {
558          i++;
559          r->npExpTable[i] =(int)(((long)w * (long)r->npExpTable[i-1]) % r->ch);
560          r->npLogTable[r->npExpTable[i]] = i;
561          if /*(i == r->ch - 1 ) ||*/ (/*(*/ r->npExpTable[i] == 1 /*)*/)
562            break;
563        }
564        if (i == r->ch - 1)
565          break;
566      }
567    }
568    else
569    {
570      r->npExpTable[1] = 1;
571      r->npLogTable[1] = 0;
572    }
573#endif
574#ifdef HAVE_DIV_MOD
575    r->npInvTable=(unsigned short*)omAlloc0( r->ch*sizeof(unsigned short) );
576#endif
577  }
578  return FALSE;
579}
580
581#ifdef LDEBUG
582BOOLEAN npDBTest (number a, const char *f, const int l, const coeffs r)
583{
584  if (((long)a<0) || ((long)a>r->ch))
585  {
586    Print("wrong mod p number %ld at %s,%d\n",(long)a,f,l);
587    return FALSE;
588  }
589  return TRUE;
590}
591#endif
592
593number npMapP(number from, const coeffs src, const coeffs dst_r)
594{
595  long i = (long)from;
596  if (i>src->ch/2)
597  {
598    i-=src->ch;
599    while (i < 0) i+=dst_r->ch;
600  }
601  i%=dst_r->ch;
602  return (number)i;
603}
604
605static number npMapLongR(number from, const coeffs /*src*/, const coeffs dst_r)
606{
607  gmp_float *ff=(gmp_float*)from;
608  mpf_t *f=ff->_mpfp();
609  number res;
610  mpz_ptr dest,ndest;
611  int size,i;
612  int e,al,bl;
613  long iz;
614  mp_ptr qp,dd,nn;
615
616  size = (*f)[0]._mp_size;
617  if (size == 0)
618    return npInit(0,dst_r);
619  if(size<0)
620    size = -size;
621
622  qp = (*f)[0]._mp_d;
623  while(qp[0]==0)
624  {
625    qp++;
626    size--;
627  }
628
629  if(dst_r->ch>2)
630    e=(*f)[0]._mp_exp-size;
631  else
632    e=0;
633  res = ALLOC_RNUMBER();
634#if defined(LDEBUG)
635  res->debug=123456;
636#endif
637  dest = res->z;
638
639  long in=0;
640  if (e<0)
641  {
642    al = dest->_mp_size = size;
643    if (al<2) al = 2;
644    dd = (mp_ptr)omAlloc(sizeof(mp_limb_t)*al);
645    for (i=0;i<size;i++) dd[i] = qp[i];
646    bl = 1-e;
647    nn = (mp_ptr)omAlloc(sizeof(mp_limb_t)*bl);
648    nn[bl-1] = 1;
649    for (i=bl-2;i>=0;i--) nn[i] = 0;
650    ndest = res->n;
651    ndest->_mp_d = nn;
652    ndest->_mp_alloc = ndest->_mp_size = bl;
653    res->s = 0;
654    in=mpz_fdiv_ui(ndest,dst_r->ch);
655    mpz_clear(ndest);
656  }
657  else
658  {
659    al = dest->_mp_size = size+e;
660    if (al<2) al = 2;
661    dd = (mp_ptr)omAlloc(sizeof(mp_limb_t)*al);
662    for (i=0;i<size;i++) dd[i+e] = qp[i];
663    for (i=0;i<e;i++) dd[i] = 0;
664    res->s = 3;
665  }
666
667  dest->_mp_d = dd;
668  dest->_mp_alloc = al;
669  iz=mpz_fdiv_ui(dest,dst_r->ch);
670  mpz_clear(dest);
671  if(res->s==0)
672    iz=(long)npDiv((number)iz,(number)in,dst_r);
673  FREE_RNUMBER(res); // Q!?
674  return (number)iz;
675}
676
677#ifdef HAVE_RINGS
678/*2
679* convert from a GMP integer
680*/
681number npMapGMP(number from, const coeffs /*src*/, const coeffs dst)
682{
683  int_number erg = (int_number) omAlloc(sizeof(mpz_t)); // evtl. spaeter mit bin
684  mpz_init(erg);
685
686  mpz_mod_ui(erg, (int_number) from, dst->ch);
687  number r = (number) mpz_get_si(erg);
688
689  mpz_clear(erg);
690  omFree((void *) erg);
691  return (number) r;
692}
693
694number npMapZ(number from, const coeffs src, const coeffs dst)
695{
696  if (SR_HDL(from) & SR_INT)
697  {
698    long f_i=SR_TO_INT(from);
699    return npInit(f_i,dst);
700  }
701  return npMapGMP(from,src,dst);
702}
703
704/*2
705* convert from an machine long
706*/
707number npMapMachineInt(number from, const coeffs /*src*/,const coeffs dst)
708{
709  long i = (long) (((unsigned long) from) % dst->ch);
710  return (number) i;
711}
712#endif
713
714number npMapCanonicalForm (number a, const coeffs /*src*/, const coeffs dst)
715{
716  setCharacteristic (dst ->ch);
717  CanonicalForm f= CanonicalForm ((InternalCF*)(a));
718  return (number) (f.intval());
719}
720
721nMapFunc npSetMap(const coeffs src, const coeffs dst)
722{
723#ifdef HAVE_RINGS
724  if ((src->rep==n_rep_int) && nCoeff_is_Ring_2toM(src))
725  {
726    return npMapMachineInt;
727  }
728  if (src->rep==n_rep_gmp) //nCoeff_is_Ring_Z(src) || nCoeff_is_Ring_PtoM(src) || nCoeff_is_Ring_ModN(src))
729  {
730    return npMapGMP;
731  }
732  if (src->rep==n_rep_gap_gmp) //nCoeff_is_Ring_Z(src)
733  {
734    return npMapZ;
735  }
736#endif
737  if (src->rep==n_rep_gap_rat)  /* Q, Z */
738  {
739    return nlModP; // npMap0;
740  }
741  if ((src->rep==n_rep_int) &&  nCoeff_is_Zp(src) )
742  {
743    if (n_GetChar(src) == n_GetChar(dst))
744    {
745      return ndCopyMap;
746    }
747    else
748    {
749      return npMapP;
750    }
751  }
752  if ((src->rep==n_rep_gmp_float) && nCoeff_is_long_R(src))
753  {
754    return npMapLongR;
755  }
756  if (nCoeff_is_CF (src))
757  {
758    return npMapCanonicalForm;
759  }
760  return NULL;      /* default */
761}
762
763// -----------------------------------------------------------
764//  operation for very large primes (32003< p < 2^31-1)
765// ----------------------------------------------------------
766#ifdef NV_OPS
767
768number nvMult (number a,number b, const coeffs r)
769{
770  //if (((long)a == 0) || ((long)b == 0))
771  //  return (number)0;
772  //else
773    return nvMultM(a,b,r);
774}
775
776void   nvInpMult(number &a, number b, const coeffs r)
777{
778  number n=nvMultM(a,b,r);
779  a=n;
780}
781
782
783inline long nvInvMod(long a, const coeffs R)
784{
785#ifdef HAVE_DIV_MOD
786  return InvMod(a, R);
787#else
788/// TODO: use "long InvMod(long a, const coeffs R)"?!
789
790   long  s;
791
792   long  u, u0, u1, u2, q, r; // v0, v1, v2,
793
794   u1=1; // v1=0;
795   u2=0; // v2=1;
796   u = a;
797
798   long v = R->ch;
799
800   while (v != 0)
801   {
802      q = u / v;
803      r = u % v;
804      u = v;
805      v = r;
806      u0 = u2;
807//      v0 = v2;
808      u2 = u1 - q*u2;
809//      v2 = v1 - q*v2;
810      u1 = u0;
811//      v1 = v0;
812   }
813
814   s = u1;
815   //t = v1;
816   if (s < 0)
817      return s + R->ch;
818   else
819     return s;
820#endif
821}
822
823inline number nvInversM (number c, const coeffs r)
824{
825  long inv=nvInvMod((long)c,r);
826  return (number)inv;
827}
828
829number nvDiv (number a,number b, const coeffs r)
830{
831  if ((long)a==0)
832    return (number)0;
833  else if ((long)b==0)
834  {
835    WerrorS(nDivBy0);
836    return (number)0;
837  }
838  else
839  {
840    number inv=nvInversM(b,r);
841    return nvMultM(a,inv,r);
842  }
843}
844number  nvInvers (number c, const coeffs r)
845{
846  if ((long)c==0)
847  {
848    WerrorS(nDivBy0);
849    return (number)0;
850  }
851  return nvInversM(c,r);
852}
853#if 0
854void nvPower (number a, int i, number * result, const coeffs r)
855{
856  if (i==0)
857  {
858    //npInit(1,result);
859    *(long *)result = 1;
860  }
861  else if (i==1)
862  {
863    *result = a;
864  }
865  else
866  {
867    nvPower(a,i-1,result,r);
868    *result = nvMultM(a,*result,r);
869  }
870}
871#endif
872#endif
873
874void    npCoeffWrite  (const coeffs r, BOOLEAN /*details*/)
875{
876  Print("//   characteristic : %d\n",r->ch);
877}
878
Note: See TracBrowser for help on using the repository browser.