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

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