StaticFactorbase.cc

Go to the documentation of this file.
00001 
00006 #include "StaticFactorbase.H"
00007 #include "Sieving.H"
00008 #include <cmath>
00009 
00010 StaticFactorbaseSettings::FBsizetype StaticFactorbaseSettings::Size_StaticFactorbase = 5000; // default size for factorbase
00011 /*  
00012     Constraint for AMD-3DNow! specific code: Size_StaticFactorbase%2 == 0  (because of SIMD)
00013     Useful values are between 1000 and 50000 (depending on available memory and the number to factorize).
00014     Normally this value will be overwritten by a value given in the config file (see "tune_parameters").
00015 */
00016 
00017 int StaticFactorbaseSettings::PrimeNumbers[StaticFactorbaseSettings::MaxSize] __attribute__ ((aligned (64)));
00018 int StaticFactorbaseSettings::PrimeNumberReciprocals[StaticFactorbaseSettings::MaxSize] __attribute__ ((aligned (64)));
00019 float StaticFactorbaseSettings::PrimeNumberFloatReciprocals[StaticFactorbaseSettings::MaxSize] __attribute__ ((aligned (64)));
00020 int StaticFactorbaseSettings::biggest_Prime_in_Factorbase = 0; // will be initialized at runtine
00021 
00022 
00023 int StaticFactorbase::NumberOf_more_PrimePowers = 0; // actual number (will be evaluated in runtime)
00024 int StaticFactorbase::FB_maxQuadrate = 0; // actual number of squares to sieve with (will be evaluated in runtime)
00025 int StaticFactorbase::PrimePowers[StaticFactorbase::max_additional_Powers];
00026 int StaticFactorbase::PrimePowerReciprocals[StaticFactorbase::max_additional_Powers];
00027 int StaticFactorbase::SQRT_kN_of_PrimeNumbers[MaxSize];
00028 int StaticFactorbase::SQRT_kN_of_PrimePowers[StaticFactorbase::max_additional_Powers];
00029 int StaticFactorbase::SQRT_kN_of_PrimeSquares[StaticFactorbase::MaxSize];
00030 
00031 
00032 
00046 int LogicalSieveSize = 1000000; // sieving interval will be [-LogicalSieveSize,LogicalSieveSize] for each MPQS polynomial
00047 
00048 
00049 int MPQS_Multiplier; // multiplier for n (kN=MPQS_Multiplier*n), will be determined later!
00050 
00051 using std::cin;
00052 using std::cout;
00053 using std::cerr;
00054 using std::endl;
00055 using std::flush;
00056 using std::sqrt;
00057 using namespace numtheory;
00058 
00059 int check_SQRT_kN_mod_PrimeNumber(const int Primzahl)
00060 {
00061   // can be called for debugging
00062   // (and to check, whether "SQRT_kN_mod_PrimeNumber" works correctly)
00063   int w1 = SQRT_kN_mod_PrimeNumber(Primzahl);
00064   if (w1>Primzahl/2) w1=Primzahl-w1;
00065 
00066   mpz_t x;
00067   mpz_init_set_ui(x,w1); mpz_mul(x,x,x); mpz_sub(x,x,kN);
00068   if (mpz_mod_ui(x,x,Primzahl)!=0)
00069     {
00070       MARK;
00071       cerr << "wrong result! " << w1 << " mod " << Primzahl << endl;
00072       exit(1);
00073     }
00074   mpz_clear(x);
00075   return w1;
00076 }
00077 
00078 // ------ pre-multiplier for MPQS -----------
00079 #include "mpqsMultiplier.cc"
00080 // ------------------------------------------
00081 
00082 
00083 
00084 void StaticFactorbase::compute_StaticFactorbase()
00085 {
00086 #if defined(ASM_MMX) || defined(ASM_3DNOW) || defined(ASM_ATHLON) || defined(ASM_SSE) || defined(ASM_SSE2) || defined(ASM_X86_64)
00087   // ATHLON specific sanity checks
00088   if ( LogicalSieveSize>(1<<23) || (StaticFactorbase::Size()&3) )
00089    {
00090      MARK;
00091      cerr << "Sorry! Processor specific constraints not met." << endl;
00092      cerr << "For using AMD-3DNow! or SSE optimized version we need:" << endl;
00093      cerr << "Constraint 1 (SIMD): (Size_StaticFactorbase&3)==0" << endl;
00094      cerr << "Constraint 2 (float precision): LogicalSieveSize<=(1<<23) [=8388608]" << endl;
00095      cerr << "Please edit ConfigFile according to these constraints" << endl;
00096      cerr << "OR use a version without these optimizations." << endl;
00097      exit(1);
00098    }
00099 #endif
00100 
00101 #ifdef VERBOSE_NOTICE
00102   cout << "Calculating static factorbase." << endl;
00103 #endif
00104   PrimeNumbers[0]=-1; // for handling sign of the relation
00105   SieveControl::set_logVal_for_Primenumber(0,0,0); // sign has no logarithmic value
00106 
00107   int Primzahl=2;
00108   // in this implementation of MPQS the prime number 2 is a member of any
00109   // static factorbase (without exception!)
00110   PrimeNumbers[1]=2;
00111   SieveControl::set_logVal_for_Primenumber(1,static_cast<TSieveElement>(ceil(log_SieveEntryMultiplier*log(Primzahl))),static_cast<TSieveElement>(ceil(log_SieveEntryMultiplier*log(Primzahl))));
00112 
00113   Primzahl=1; // initial value (for the loop, expected step: +2)
00114   mpz_t x,y,wuqu;
00115   mpz_init(x); mpz_init(y); mpz_init(wuqu); // for computing square root of prime powers
00116   for (int Primzahl_nr=2; Primzahl_nr<StaticFactorbase::Size(); Primzahl_nr++)
00117     {
00118       do // compute next prime number in static factorbase
00119         {
00120           do Primzahl+=2; while(!is_prime(Primzahl)); // next prime number
00121           mpz_set_ui(x,Primzahl);
00122         }
00123       while (mpz_legendre(kN,x)<0); // until prime number is member of factorbase
00124       
00125       PrimeNumbers[Primzahl_nr]=Primzahl;
00126       PrimeNumberReciprocals[Primzahl_nr]=reciprocal(Primzahl);
00127       PrimeNumberFloatReciprocals[Primzahl_nr]=static_cast<float>(1.0)/static_cast<float>(Primzahl);
00128       
00129       // needed for efficient sieving (spares repeated recomputing)
00130       SieveControl::set_logVal_for_Primenumber(Primzahl_nr,
00131               static_cast<TSieveElement>(ceil(log_SieveEntryMultiplier*log(Primzahl))),
00132               static_cast<TSieveElement>(ceil(log_SieveEntryMultiplier*log(Primzahl)*SieveControl::DirtyFactor(Primzahl_nr))));
00133       
00134       // needed to compute the Delta values for sieving
00135       SQRT_kN_of_PrimeNumbers[Primzahl_nr]=SQRT_kN_mod_PrimeNumber(Primzahl);
00136       
00137       // check, whether computations of square roots were correct:
00138       if ( squaremod(SQRT_kN_of_PrimeNumbers[Primzahl_nr],Primzahl) != mpz_remainder_ui(kN,Primzahl) )
00139        {
00140          cerr << "square root not correct!" << endl;
00141          cerr << SQRT_kN_of_PrimeNumbers[Primzahl_nr] << "^2 <> "
00142               << mpz_remainder_ui(kN,Primzahl) << " (mod " << Primzahl << ")" << endl;
00143          exit(1);
00144        }
00145 
00146 
00147       if ( Primzahl < sqrt(std::numeric_limits<int>::max()) && MPQS_Multiplier%Primzahl!=0 )
00148        {
00149           // *** compute square roots of kN mod Primzahl^2 ***
00150           const unsigned int P = Primzahl*Primzahl;
00151           const unsigned int Wu = SQRT_kN_of_PrimeNumbers[Primzahl_nr];
00152           unsigned int iy = invmod(2*Wu,P);
00153           unsigned int ix = mpz_remainder_ui(kN,P);
00154           
00155           unsigned int wuq=Wu*Wu;
00156           if (ix>=wuq) ix-=wuq; else ix=ix-wuq+P; // ix-=wuq; avoid overflow; we compute values modulo P
00157           ix=mulmod(ix,iy,P)+Wu;
00158           wuq = (ix<P) ? ix : ix-P; // this is a faster version for: wuq=ix%P
00159 
00160 #if 1 || defined(DEBUG)
00161           if (mulmod(wuq,wuq,P)!=mpz_remainder_ui(kN,P))
00162            {
00163              cerr << "PQ-root incorrect!" << endl;
00164              cerr << "Primzahl=" << PrimeNumbers[Primzahl_nr] << endl;
00165              cerr << "kN= " << kN << endl;
00166              cerr << mulmod(Wu,Wu,P) << " != " << mpz_remainder_ui(kN,P) << endl;
00167              exit(1); 
00168            }
00169 #endif
00170           SQRT_kN_of_PrimeSquares[Primzahl_nr]=wuq;
00171        } else SQRT_kN_of_PrimeSquares[Primzahl_nr]=-1;
00172 
00173 
00174       const int Threshold = LogicalSieveSize < std::numeric_limits<int>::max()/8 ? 8*LogicalSieveSize/Primzahl : LogicalSieveSize/Primzahl;
00175       if (Primzahl<=Threshold && Primzahl>2 && mpz_remainder_ui(kN,Primzahl)!=0)
00176         // constraint for Primzahl to assure correct sieving with prime-powers: 
00177         //  - not too big, bigger than 2, and no divisor of kN
00178         {
00179           FB_maxQuadrate=Primzahl_nr; // at the end of the loop this will be the limit, up to which we can sieve squares the normal way...
00180 
00181           // compute square roots of kN modulo Primzahl^pot
00182           // initial values:
00183           int P_Potenz = Primzahl*Primzahl;
00184           int Wu       = SQRT_kN_of_PrimeNumbers[Primzahl_nr];
00185 
00186           double Weight = Primzahl_nr<SieveControl::FBLowestStartIndex ? 2.0 : 1.0;
00187            // We do not sieve with the first couple of primes of the
00188            // factorbase (because these primes are very small and sieving
00189            // with them takes too long); as a minor correction of this
00190            // "dirty behaviour" the value of the smallest power of each dirty prime
00191            // can be adapted for sieving: log(P_Potenz)=Potenz*log(Primzahl).
00192            // All other powers are handled the usual way: since it is a recurrence of a known factor,
00193            // only log(Primzahl) has to be subtracted.
00194 
00195           for (int pot=2; ;pot++)
00196             {
00197               //cout << "computing square root of " << Primzahl << "^" << pot << endl;
00198 
00199               mpz_set_ui(y,2*Wu); mpz_set_ui(x,P_Potenz);
00200               if (mpz_invert(y,y,x)==0)
00201                 { 
00202                   cerr << "PPot-root for " << Primzahl  << ": inverse doesn't exist!" << endl;
00203                   break;
00204                 }
00205 
00206               if (NumberOf_more_PrimePowers>=StaticFactorbase::max_additional_Powers)
00207                { 
00208                  static char weitermachen = 'n';
00209                  if (weitermachen!='y')
00210                   {
00211                    cerr << "Overflow for " << Primzahl << "^" << pot << endl;
00212                    cerr << "Reserved memory for storing prime powers is too small..." << endl;
00213                    cerr << "sieving will be less efficient..." << endl;
00214                    cerr << "(You may increase \"StaticFactorbase::max_additional_Powers\" and recompile the program.)" << endl;
00215                    cerr << "continue anyway? (y/n) " << flush;
00216                    cin >> weitermachen;
00217                    if (weitermachen=='n') exit(1);
00218                   }
00219                  break; // avoid overflow by breaking the loop
00220                }
00221 
00222               mpz_mod_ui(x,kN,P_Potenz); mpz_set_ui(wuqu,Wu); mpz_mul_ui(wuqu,wuqu,Wu); mpz_sub(x,x,wuqu);
00223               mpz_mul(x,x,y); mpz_add_ui(x,x,Wu); mpz_mod_ui(x,x,P_Potenz);
00224               Wu = mpz_get_ui(x); if (Wu>P_Potenz-Wu) Wu=P_Potenz-Wu; // normalize to the "lower" of the two square roots
00225               // "Wu" is now the square root of kN (mod P_Potenz)
00226 
00227               // check, whether computation was correct:
00228               mpz_set_ui(x,Wu); mpz_mul(x,x,x); mpz_sub(x,kN,x); 
00229               if (mpz_mod_ui(x,x,P_Potenz)!=0)
00230                 {
00231                   cerr << "PPot-root incorrect!" << endl;
00232                   cerr << "Primzahl=" << PrimeNumbers[Primzahl_nr] << " Nr. " << Primzahl_nr << endl;
00233                   cerr << "kN= " << kN << endl;
00234                   cerr << "SQRT(kN) mod p=" << SQRT_kN_of_PrimeNumbers[Primzahl_nr] << endl;
00235                   cerr << "SQRT(kN) mod p^i=" << SQRT_kN_of_PrimePowers[NumberOf_more_PrimePowers] << endl;
00236                   cerr << "but we got a wrong value: " << x << endl;
00237                   exit(1);
00238                 }
00239 
00240               // heuristics: Increase the weight of the last power a little bit,
00241               // since we have a slight chance, that this hit is a hit of higher powers, too.
00242               if (P_Potenz>Threshold) Weight+=4.0/Primzahl;
00243 
00244 #if 1
00245               // heuristics: (determined by trial&error):
00246               // For factorizing "small" numbers: Sieving is significantly
00247               // faster, if sieving is skipped for smaller values;
00248               // the sieve gets more wide-meshed, but this doesn't matter, since relations come plentiful...
00249               // For factorizing "bigger" numbers: If we sieve more carefully, we detect more DLP in the same time,
00250               // this effect is by far more important!
00251               if ( P_Potenz<250 && mpz_sizeinbase(kN,10)<70 ) Weight+=1.0;
00252               else
00253 #endif
00254                {
00255                  PrimePowers[NumberOf_more_PrimePowers]=P_Potenz;
00256                  PrimePowerReciprocals[NumberOf_more_PrimePowers]=numtheory::reciprocal(P_Potenz);
00257                  SQRT_kN_of_PrimePowers[NumberOf_more_PrimePowers]=Wu;
00258 
00259                  SieveControl::set_logVal_for_Primepower(NumberOf_more_PrimePowers,
00260                    static_cast<TSieveElement>(ceil(log_SieveEntryMultiplier*Weight*log(Primzahl))));
00261                  Weight=1.0;
00262                  ++NumberOf_more_PrimePowers; // we got one more...
00263                }
00264               
00265               if (P_Potenz>Threshold) break; // next one would be too big...
00266               P_Potenz*=Primzahl;
00267             }
00268         }
00269     }
00270   mpz_clear(x); mpz_clear(y); mpz_clear(wuqu);
00271 
00272   biggest_Prime_in_Factorbase=Primzahl;
00273 #ifdef VERBOSE_INFO
00274   cout << "prime numbers in static factorbase have been computed." << endl;
00275   if (Primzahl>=PhysicalSieveSize)
00276     cout << "Remark: Some members of the static factorbase are bigger than the sieve size!" << endl;
00277 
00278   cout << "The first 20 members of the static factorbase are" << endl;
00279   for (int i=0; i<20; i++) cout << StaticFactorbase::PrimeNumbers[i] << " "; cout << endl;
00280   cout << "Biggest prime in static factorbase: " << StaticFactorbase::BiggestPrime() << endl;
00281   cout << "#squares (of primes) in FB: " << StaticFactorbase::FB_maxQuadrate << endl;
00282   cout << "#powers (of primes) in FB: " << StaticFactorbase::NumberOf_more_PrimePowers << endl;
00283 #endif
00284 }

Generated on Wed Nov 7 23:29:26 2007 for Qsieve by  doxygen 1.5.4