mpqsMultiplier.cc

Go to the documentation of this file.
00001 
00011 #include "utils.H"
00012 #include "mpz_wrapper.H"
00013 #include "modulo.H"
00014 #include <cmath>
00015 
00016 // switch for method to compute a multiplier
00017 #define BEWERTUNG_MIT_POTENZEN
00018 //#define BEWERTUNG_MIT_DIRTY_SIEVING
00019 
00020 
00031 void determine_best_MPQS_Multiplier(const mpz_t n, mpz_t kN, int &new_MPQS_Multiplier)
00032 {
00033   // Now we're going to determine a convenient multiplier.
00034   // result: new_MPQS_Multiplier and kN = new_MPQS_Multiplier*n
00035 
00036   /* Remark: In this implementation for the multiple polynomial quadratic sieve
00037      the constraint kN=1 (mod 4) must be met, too.
00038      It is also advisable to fulfil kN=1 (mod 8) to assure that 2 is member of the factorbase.
00039      (cf. Silverman paper) */
00040 
00041   using numtheory::is_prime;
00042   using namespace my_mpz_wrapper;
00043 
00044   // determine the multiplier:
00045   const int P=2; // biggest prime, up to which members of the factorbase are consecutive primes.
00046                  // we need at least P=2.
00047   int bound_k = 1000000; /* maximal die ersten bis zum Vorfaktor bound_k den Test
00048                                durchführen. (Während des Tests wird diese Schranke dann
00049                                höchstens noch verkleinert.) */
00050   const int FB_SIM_Size = 100; /* Faktorbasisgröße, mit der Simulation durchgeführt werden soll. */
00051   
00052   // 1. Es sollen alle Primzahlen von 2 bis P in der statischen Faktorbasis enthalten sein.
00053   //    Dafür wird in Kauf genommen, dass der Vorfaktor etwas größer wird...
00054   // 2. Maximal bis "bound_k" wird für Vorfaktoren simuliert, wie gut diese Vorfaktoren abschneiden.
00055   //    Hierfür werden Teilbarkeitswahrscheinlichkeiten verwendet und die Größenordnung
00056   //    der zu siebenden Zahl anhand des Vorfaktors berücksichtigt.
00057   // 3. Wird ein neuer besserer Vorfaktor entdeckt, dann wird "bound_k" neu kalkuliert.
00058   // 4. Der hierbei am besten abschneidende Vorfaktor wird schließlich verwendet.
00059 
00060 #ifdef VERBOSE_INFO  
00061   cout << "Determining a multiplier for MPQS" << endl;
00062 #endif
00063 
00064   if (mpz_sizeinbase(n,10)<50)
00065    bound_k=100; // für kleine Zahlen begrenzen, da sonst die Vorfaktorermittlung länger als Faktorisierung dauert...
00066   
00067   // zunächst die theoretisch (erreichbare) optimale Faktorbasis als Berechnungsgrundlage
00068   // für Optimalwert ermitteln:
00069   double optimal_w, good_w;
00070   int p; // für Primzahltest
00071   
00072   p=2; optimal_w= -2*log(2);
00073   while (p<P)
00074     { 
00075       while (!is_prime(p)) p++;
00076 #ifdef BEWERTUNG_MIT_POTENZEN
00077       optimal_w -= 2*log(p)/(p-1);
00078 #else
00079       optimal_w -= 2*log(p)/p;
00080 #endif
00081       p++;
00082     }
00083   // bis hierher alle Primzahlen in Folge in simulierter FB
00084   // für theoretisch optimale FB müssen sämtliche Primzahlen in Folge in FB liegen
00085   for (int z=0; z<FB_SIM_Size; p++)
00086     { 
00087       while (!is_prime(p)) p++;
00088       z++;
00089 #ifdef BEWERTUNG_MIT_POTENZEN
00090       optimal_w -= 2*log(p)/(p-1);
00091 #else
00092       optimal_w -= 2*log(p)/p;
00093 #endif
00094     }
00095 
00096   // Nun noch eine realistischere Bewertungsgrundlage:
00097   good_w=0.85*optimal_w;
00098 
00099 #ifdef VERBOSE_INFO  
00100   cout << "theoretically optimal valuation: " << std::setprecision(10) << optimal_w << endl;
00101   cout << "theoretically good valuation   : " << good_w << endl; 
00102   cout << "Starting simulation of MPQS multipliers..." << endl;
00103 #endif
00104   
00105   // ab hier die "wirkliche" Vorfaktorermittlung
00106 
00107   // Besonderheit: Dirty-Sieving wird korrekt simuliert, d.h.
00108   // für die ersten "SieveControl::FBLowestStartIndex" Primzahlen wird
00109   // die Trefferwahrscheinlichkeit um 1/p vermindert.  
00110 
00111 
00112   // Feld für sortierte Aufnahme der "sort_bis"+1 besten Vorfaktoren
00113   struct tFeldeintrag
00114    {
00115      double w; int k;
00116      inline tFeldeintrag() : w(0.0), k(0) { }
00117      inline ~tFeldeintrag() { }
00118    };
00119   const short int sort_bis = 5;    
00120   tFeldeintrag Feld[sort_bis]; /* Feld wird automatisch mit Nullen initialisiert
00121                                   -> für Bewertung werden daher grundsätzlich
00122                                   negative Werte vorausgesetzt */
00123 
00124   double best_w = 1e20;
00125   double akt_w;
00126   int best_k = 1;
00127   int k=1; // testweiser Vorfaktor
00128   int z=0; // Index der Primzahl in der Faktorbasis
00129   mpz_t x; mpz_init(x);
00130   
00131   while (k<=bound_k)
00132     {
00133       mpz_mul_ui(kN,n,k); // initialize kN
00134       
00135       // is 2 member of the factorbase?
00136       if (mpz_remainder_ui(kN,8)!=1) goto next;
00137 
00138       akt_w=-2*log(2); // Initialisierung der Bewertung für neuen Vorfaktor
00139       
00140       p=2; z=1;
00141       while (p<P)
00142         {
00143           do p++; while(!is_prime(p));
00144           mpz_set_ui(x,p); if (mpz_legendre(kN,x)==-1) goto next; // goto next -> reject this multiplier
00145           z++;
00146 
00147           // Aktualisierung der Bewertung:
00148 #ifdef BEWERTUNG_MIT_POTENZEN
00149 #ifdef BEWERTUNG_MIT_DIRTY_SIEVING
00150           if (z<SieveControl::FBLowestStartIndex)
00151             akt_w -= (k%p!=0)?  2*log(p)/(p-1) - 1.75*log(p)/p: 0.1*log(p)/p;
00152           else
00153             akt_w -= (k%p!=0)?  2*log(p)/(p-1) : 1*log(p)/p;
00154 #else // ohne BEWERTUNG_MIT_DIRTY_SIEVING
00155           akt_w -= (k%p!=0)?  2*log(p)/(p-1) : 1*log(p)/p;        
00156 #endif
00157 #else
00158 #ifdef BEWERTUNG_MIT_DIRTY_SIEVING
00159           if (z<SieveControl::FBLowestStartIndex)
00160             akt_w -= 0.5*((k%p!=0)?  2*log(p)/p : log(p)/p);
00161           else
00162             akt_w -= (k%p!=0)?  2*log(p)/p : 1*log(p)/p;
00163 #else // ohne BEWERTUNG_MIT_DIRTY_SIEVING
00164           akt_w -= (k%p!=0)?  2*log(p)/p : 1*log(p)/p;
00165 #endif
00166 #endif
00167           
00168         }
00169       
00170       // Vorfaktor prinzipiell geeignet, nun noch weiter bewerten:
00171       {
00172         for ( ; z<FB_SIM_Size; z++)
00173           {
00174             do
00175               {
00176                 do p++; while(!is_prime(p)); /* nächste Primzahl */
00177                 mpz_set_ui(x,p);
00178               }
00179             while (mpz_legendre(kN,x)==-1); // Primzahl gültig für Primzahlbasis?
00180 
00181 
00182             // Aktualisierung der Bewertung:
00183 #ifdef BEWERTUNG_MIT_POTENZEN
00184 #ifdef BEWERTUNG_MIT_DIRTY_SIEVING
00185           if (z<SieveControl::FBLowestStartIndex)
00186             akt_w -= (k%p!=0)?  2*log(p)/(p-1) - 1.75*log(p)/p : 0.1*log(p)/p;
00187           else
00188             akt_w -= (k%p!=0)?  2*log(p)/(p-1) : 1*log(p)/p;
00189 #else // ohne BEWERTUNG_MIT_DIRTY_SIEVING
00190           akt_w -= (k%p!=0)?  2*log(p)/(p-1) : 1*log(p)/p;        
00191 #endif
00192 #else
00193 #ifdef BEWERTUNG_MIT_DIRTY_SIEVING
00194           if (z<SieveControl::FBLowestStartIndex)
00195             akt_w -= 0.5*((k%p!=0)?  2*log(p)/p : log(p)/p);
00196           else
00197             akt_w -= (k%p!=0)?  2*log(p)/p : 1*log(p)/p;
00198 #else // ohne BEWERTUNG_MIT_DIRTY_SIEVING
00199           akt_w -= (k%p!=0)?  2*log(p)/p : 1*log(p)/p;
00200 #endif
00201 #endif
00202             
00203           }
00204 
00205         akt_w += 0.5*log(k); // add threshold
00206 
00207         // nun noch den Vorfaktor mit Bewertung ausgeben
00208         //cout << k << " mit Bewertung " << akt_w << endl;
00209 
00210         { 
00211           // for statistical reasons, collect the best five multipliers:
00212           signed short int i=sort_bis-1;
00213           if (akt_w<Feld[i].w)
00214             {
00215               while (i>0 && akt_w<Feld[i-1].w) { Feld[i]=Feld[i-1]; --i; }
00216               Feld[i].w=akt_w; Feld[i].k=k;
00217             }
00218         }
00219         
00220         if (akt_w<best_w)
00221           {
00222 #ifdef VERBOSE
00223             cout << "best multiplier so far: " <<  k 
00224                  << " valuation: " << akt_w << endl;
00225 #endif
00226             best_w=akt_w; best_k=k;
00227             int computed_bound_k;
00228             if (akt_w>good_w)
00229                  computed_bound_k = static_cast<int>(ceil(exp(2*(akt_w-good_w))));
00230             else computed_bound_k = 0;
00231             if (computed_bound_k<bound_k) bound_k=computed_bound_k;
00232 #ifdef VERBOSE
00233             cout << "New (practical) bound: " << bound_k
00234                  << " (theoretical bound: " << computed_bound_k << ")" <<  endl;
00235 #endif
00236           }
00237       }
00238       
00239       
00240     next: // next multiplier
00241 #if 0
00242       do k++; while(!is_prime(k)); // in case that only prime numbers are allowed as multipliers
00243 #else
00244       // alternative: allow more multipliers (constraint: squarefree, positive integers)
00245       k++;
00246       { // is k squarefree?
00247         int square=4, i=5;
00248         while (square<=k)
00249           {
00250             if (k%square==0) goto next; // contains a square
00251             square+=i; i+=2;
00252           }
00253         // okay, k is squarefree...
00254       }
00255 #endif
00256     }
00257 
00258 #ifdef VERBOSE_INFO
00259   cout << endl;
00260   cout << "The " << sort_bis << " best MPQS multipliers are" << endl;
00261   for (short int i=0; i<sort_bis; i++)
00262     cout << i+1 << ". " << Feld[i].k << " with valuation " << Feld[i].w << endl;
00263   cout << endl;
00264 #endif
00265  
00266 #if 0
00267   // If this block is activated, one can type in a multiplier manually.
00268   cout << "Please input a multiplier: ";
00269   cin >> best_k;
00270 #endif
00271 
00272   new_MPQS_Multiplier=best_k; // this is the new MPQS_Multiplier
00273 #ifdef VERBOSE_NOTICE
00274   cout << "MPQS multiplier set to " << best_k << endl;
00275 #endif
00276   mpz_mul_ui(kN,n,best_k); // compute best kN
00277   mpz_clear(x);
00278 }

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