easy_factor.cc

Go to the documentation of this file.
00001 
00006 #include "easy_factor.H"
00007 #include <cmath>
00008 #include "modulo.H"
00009 #include "elliptic_curve.H"
00010 #include <sstream>
00011 
00012 extern std::string MAL(const mpz_t factor, const std::ostringstream &comment);
00013 extern std::string MAL(const mpz_t factor, const unsigned int exponent, const std::ostringstream &comment);
00014 extern std::string MAL(const mpz_t factor, const unsigned int exponent=1);
00015 extern std::string MAL(const unsigned long int factor, const unsigned int exponent=1);
00016 extern void tune_parameters(const unsigned int Dezimalstellen);
00017 
00018 #include <fstream>
00019 extern std::ofstream Factorization_to_file;
00020 
00021 #ifdef REACT_ON_SIGUSR
00022  #include "usr_signals.H"
00023  extern Cusr_signal_proxy USRSignalHandler;
00024 #endif
00025 
00026 class ExitManager
00027 {
00028  public:
00029   static void StopFactorization();
00030 };
00031 
00032 // propagate DEFINE condition for IS_STANDALONE from compiletime
00033 // to runtime...
00034 extern bool compiled_IS_STANDALONE();
00035 
00036 
00037 
00038 void pollard(const int runden) /* Pollard-rho-Methode */
00039 {
00040 #ifdef VERBOSE_INFO
00041   cout << "Trying Pollard-rho up to " << runden << endl;
00042 #endif
00043   mpz_t a,a2,x;
00044   mpz_init(a); mpz_init(a2); mpz_init(x);
00045   mpz_set_ui(a,1); mpz_set(a2,a);
00046   
00047   for (int i=1; i<=runden; i++)
00048    {
00049 #ifdef REACT_ON_SIGUSR
00050      if (USRSignalHandler.got_SIGUSR1()) break;
00051      if (USRSignalHandler.got_SIGUSR2()) break;
00052 #endif
00053      mpz_mul(a,a,a); mpz_add_ui(a,a,1); mpz_mod(a,a,n);
00054      mpz_mul(a2,a2,a2); mpz_add_ui(a2,a2,1); mpz_mod(a2,a2,n);
00055      mpz_mul(a2,a2,a2); mpz_add_ui(a2,a2,1); mpz_mod(a2,a2,n);
00056      mpz_sub(x,a2,a);
00057      mpz_gcd(x,x,n);
00058      while (mpz_cmp_ui(x,1)!=0)
00059       {
00060         if (mpz_cmp(x,n)==0)
00061           {
00062 #ifdef VERBOSE_INFO
00063             cout << "trivial factor in round " << i << endl;
00064 #endif
00065             continue;
00066           }
00067         unsigned int exp=mpz_remove(n,n,x); // divide out all occurrences of x in n
00068         if (mpz_probab_prime_p(x,probab_prime_checks))
00069          {
00070            cout << x << " is factor. [round " << i <<"]" << endl;
00071            Factorization_to_file << MAL(x,exp) << flush;
00072          }
00073         else
00074          {
00075            cout << x << " is a composite factor. [round " << i <<"]" << endl;
00076            std::ostringstream comment;
00077            comment << " [rho/composite]";
00078            Factorization_to_file << MAL(x,exp,comment) <<  flush;
00079          }
00080         if (mpz_probab_prime_p(n,probab_prime_checks)) goto done; // remaining number is most probably prime
00081         mpz_gcd(x,x,n); // possible case: x=p*q and n=p*q*q*r -> second q would not be found!
00082       }
00083    };
00084 done:
00085   mpz_clear(a); mpz_clear(a2); mpz_clear(x);
00086 }
00087 
00088 bool try_memorized_factors(mpz_t n, const std::string& memfilename)
00089 {
00090   // trial division by some factors given in a file...
00091   bool reduced = false;
00092 
00093   std::ifstream in(memfilename.c_str());
00094   if (in)
00095     {
00096 #ifdef VERBOSE_INFO
00097       cout << "Trial division by factors in " << memfilename << endl; 
00098 #endif
00099       mpz_t x;
00100       mpz_init(x);
00101       while (!in.eof())
00102         {
00103           while (isspace(in.peek())) in.get(); // ignore all whitespaces
00104           if (in.peek()=='#')
00105            {
00106              in.ignore(1000,'\n'); // ignore comment lines
00107              continue;
00108            }
00109 
00110           // it seems that gcc-3.2.3 has some problems detecting eof,
00111           // I hope this helps...
00112           in.get();
00113           if (in.eof()) break;
00114           in.unget();
00115 
00116           in >> x;
00117           //cout << "try " << x << endl;
00118           if (mpz_cmp(n,x)==0) return reduced; // remaining factor should reside in n!
00119           while (mpz_divisible_p(n,x))
00120            {
00121              if (mpz_probab_prime_p(x,probab_prime_checks))
00122                {
00123                  cout << x << " is factor. [memorized]" << endl;
00124                  std::ostringstream comment;
00125                  comment << " [memorized]";
00126                  Factorization_to_file << MAL(x,comment) << flush;
00127                }
00128              else
00129                {
00130                  cout << x << " is a composite factor. [memorized]" << endl;
00131                  std::ostringstream comment;
00132                  comment << " [composite/memorized]";
00133                  Factorization_to_file << MAL(x,comment) <<  flush;
00134                }
00135              mpz_divexact(n,n,x); reduced=true;
00136            }
00137           while (isspace(in.peek())) in.get(); // ignore all whitespaces
00138         }
00139       mpz_clear(x);
00140     }
00141   else
00142     {
00143 #ifdef VERBOSE_WARN
00144       cerr << memfilename << " inaccessible!" << endl;
00145 #endif
00146     }
00147  return reduced;
00148 }
00149 
00150 #include "pollard_phi.cc"
00151 #include "fibonacci_ppm1.cc"
00152 
00153 bool Potenztest(const mpz_t n)
00154 {
00155   // check whether n can be written as a square, a cube or
00156   // any other x-th power of a natural number.
00157   mpz_t y;
00158   mpz_init(y);
00159   for (unsigned int k=mpz_sizeinbase(n,256); k>1; k--)
00160     {
00161       //cout << "k=" << k << "?" << endl;
00162       if (mpz_root(y,n,k))
00163         {
00164           cout << y << "^" << k <<  " is ";
00165           Factorization_to_file << MAL(y,k);
00166           if (!mpz_probab_prime_p(y,probab_prime_checks))
00167             {
00168               cout << "composite ";
00169               Factorization_to_file << " [composite power]";
00170             }
00171           Factorization_to_file << flush;
00172           cout << "factor." << endl;
00173           mpz_clear(y);
00174           return true; 
00175         }
00176     }
00177   mpz_clear(y);
00178   return false;
00179 }
00180 
00181 
00182 #include "fermat.cc"
00183 
00184 void easy_factor()
00185 {
00186   /* einfache Faktorisierung versuchen:
00187      vielleicht kann die Zahl dadurch komplett faktorisiert werden
00188      oder zumindest um einige Faktoren reduziert werden... */
00189 
00190   if (!SkipFermat) fermat_like_method();
00191   /* try a Fermat-like method to check for cases, where the
00192      number can be written as (a-d)*(a+d) using a small d... */
00193   
00194   const unsigned long int UpperLimit_Easy = 1000000;
00195 #ifdef VERBOSE_INFO
00196   cout << "Trialdivision up to " << UpperLimit_Easy << endl;
00197 #endif
00198   {
00199     const unsigned int some_primes [] = { 2,3,5,7,11,13,0 };
00200     unsigned long int p = 0;
00201 
00202     // trial division using small prime numbers
00203     for (unsigned int index=0; some_primes[index]; ++index)
00204      {
00205        p=some_primes[index];
00206        //cout << "Trial Division with " << p << endl;
00207        int exp=0;
00208        while (mpz_divisible_ui_p(n,p)) { mpz_divexact_ui(n,n,p); exp++; }
00209        if (exp>0)
00210         {
00211           cout << p << "^" << exp << " is factor." << endl;
00212           Factorization_to_file << MAL(p,exp);
00213         }
00214      }
00215     
00216     /* Trial division up to UpperLimit_Easy */
00217     unsigned int delta;
00218     if (p%6==1) delta=4;
00219      else 
00220       if (p%6==5) delta=2;
00221       else
00222        {
00223          MARK;
00224          cerr << "Something is wrong with some_primes!" << endl;
00225          exit(1);
00226        }
00227       
00228     while (p<UpperLimit_Easy)
00229      {
00230        p+=delta; delta=6-delta;
00231        if ( p%5==0 || p%7==0 || p%11==0 || p%13==0 ) continue;
00232        //cout << "Trial Division with " << p << endl;
00233        int exp=0;
00234        while (mpz_divisible_ui_p(n,p)) { mpz_divexact_ui(n,n,p); exp++; }
00235        if (exp>0)
00236          {
00237            cout << p << "^" << exp << " is factor." << endl;
00238            Factorization_to_file << MAL(p,exp);
00239            if (mpz_cmp_ui(n,1)==0) break; // work is done!
00240          }
00241      } 
00242     
00243     Factorization_to_file.flush();
00244   }
00245 
00246   if (Potenztest(n)) mpz_set_ui(n,1);
00247   if (mpz_cmp_ui(n,1)==0) goto done; 
00248   if (mpz_probab_prime_p(n,probab_prime_checks)) goto done;
00249 
00250   { 
00251     std::string cached_factorfile;
00252  #if defined(PKGDATADIR)
00253     cached_factorfile = PKGDATADIR; // use this prefix (if defined)
00254     cached_factorfile+="/";
00255  #endif
00256    cached_factorfile+= "fibonacci.factors";
00257 
00258    if (try_memorized_factors(n,cached_factorfile)) // "cached" factors
00259     {
00260       if (mpz_probab_prime_p(n,probab_prime_checks)) goto done;
00261     }
00262   }
00263 
00264   {
00265     unsigned int dezimalstellen = mpz_sizeinbase(n,10);
00266     tune_parameters(dezimalstellen);
00267     pollard(rho_Phase); // try the pollard-rho factorization method
00268 
00269     if (Potenztest(n)) mpz_set_ui(n,1);
00270     if (mpz_cmp_ui(n,1)==0) goto done;
00271     if (mpz_probab_prime_p(n,probab_prime_checks)) goto done;
00272 
00273     if (dezimalstellen != mpz_sizeinbase(n,10))
00274      {
00275        dezimalstellen=mpz_sizeinbase(n,10);
00276        tune_parameters(dezimalstellen);
00277      }
00278 
00279   if (UsePhimat)
00280    {
00281      // this is an experimental method!
00282      // Don't use it by default since it takes very long
00283      // (except for certain numbers)
00284      phimat2(); if (mpz_cmp_ui(n,1)==0) goto done;
00285    }
00286 
00287 #if 1
00288    if (dezimalstellen>200)
00289     {
00290       // number seems to be very large
00291       // if it partly contains fibonacci factors, we should try to split it
00292       // here to save time.  (Since I'm trying to factor some fibonacci &
00293       // lucas numbers, this test is implemented.)
00294       fibonacci_ppm1(100000,0); /* Fibonacci (p+-1)-Methode */
00295       if (dezimalstellen != mpz_sizeinbase(n,10))
00296        {
00297          if (Potenztest(n)) mpz_set_ui(n,1);
00298          if (mpz_cmp_ui(n,1)==0) goto done;
00299          if (mpz_probab_prime_p(n,probab_prime_checks)) goto done;
00300          dezimalstellen=mpz_sizeinbase(n,10);
00301          tune_parameters(dezimalstellen);
00302        }
00303     }
00304 #endif
00305 
00306 
00307 #if 1
00308     // in the standalone version the mpqs will be quite fast in finding
00309     // small factors, so we do not need to run ecm on small composite numbers.
00310     // However, in a networked client-server system, factoring small composite
00311     // numbers causes too much overhead and is therefore annoying...
00312 
00313     // to make it separately compileable, we must not evaluate the DEFINE "IS_STANDALONE";
00314     // we have it to evaluate on runtime, not at compiletime!
00315     if ( !compiled_IS_STANDALONE() || (compiled_IS_STANDALONE() && mpz_sizeinbase(n,10)>70))
00316      if (!SkipEasyECM)
00317       {
00318         // easy-ecm: try a few elliptic curves just to eliminate some small numbers
00319         // in the range up to let's say 10-20 digits.
00320         // This is especially advantageous for composite Fibonacci-
00321         // and Lucasnumbers, because fibfactor has the chance to find the
00322         // remaining cofactors!
00323         for (int i=0; i<10; ++i)
00324          {
00325            elliptic_curves elliptic_curve; // instantiate an elliptic curve
00326            elliptic_curve.go(7+i,60000,15000000); // and try a factorization using this curve
00327 
00328            if (dezimalstellen != mpz_sizeinbase(n,10))
00329             {
00330               if (Potenztest(n)) mpz_set_ui(n,1);
00331               if (mpz_cmp_ui(n,1)==0) goto done;
00332               if (mpz_probab_prime_p(n,probab_prime_checks)) goto done;
00333               dezimalstellen=mpz_sizeinbase(n,10);
00334               tune_parameters(dezimalstellen);
00335             }
00336          }
00337       }
00338 #endif
00339 
00340 
00341 #if 1
00342     if (SkipPhi || (phi_Phase1<=0 && phi_Phase2<=0))
00343      {
00344 #ifdef VERBOSE_NOTICE
00345        cout << "Phi-Phase is deactivated!" << endl;
00346 #endif
00347      }
00348     else
00349      {
00350        pollard_phi(phi_Phase1,phi_Phase2); /* Faktorisierung nach Pollard-Phi-Methode versuchen */
00351        if (dezimalstellen != mpz_sizeinbase(n,10))
00352         {
00353           if (Potenztest(n)) mpz_set_ui(n,1);
00354           if (mpz_cmp_ui(n,1)==0) goto done;
00355           if (mpz_probab_prime_p(n,probab_prime_checks)) goto done;
00356           dezimalstellen=mpz_sizeinbase(n,10);
00357           tune_parameters(dezimalstellen);
00358         }
00359      }
00360 #endif
00361 
00362     if (SkipFibonacci || (phi_Phase1<=0 && phi_Phase2<=0))
00363      {
00364 #ifdef VERBOSE_NOTICE
00365        cout << "Fibonacci-Phase is deactivated!" << endl;
00366 #endif
00367      }
00368     else
00369      {
00370        fibonacci_ppm1(phi_Phase1,phi_Phase2); /* Fibonacci (p+-1)-Methode */
00371        if (dezimalstellen != mpz_sizeinbase(n,10))
00372         {
00373           if (Potenztest(n)) mpz_set_ui(n,1);
00374           if (mpz_cmp_ui(n,1)==0) goto done;
00375           if (mpz_probab_prime_p(n,probab_prime_checks)) goto done;
00376           dezimalstellen=mpz_sizeinbase(n,10);
00377           tune_parameters(dezimalstellen);
00378         }
00379      }
00380   }
00381 
00382 done:
00383 #ifdef VERBOSE_NOTICE  
00384   cout << "remaining number:" << endl << n << endl;
00385 #endif
00386   
00387   if ( (mpz_cmp_ui(n,1)==0) || Potenztest(n) )
00388     {
00389       Factorization_to_file << endl;
00390       ExitManager::StopFactorization(); // factorization complete!
00391     }  
00392 
00393   if (mpz_probab_prime_p(n,probab_prime_checks))
00394     {
00395       Factorization_to_file << MAL(n) << endl;
00396       cout << "remaining number is most probably a prime!" << endl;
00397       mpz_set_ui(n,1);
00398       ExitManager::StopFactorization();
00399     }
00400 //Factorization_to_file << " * " << n << " [REST]" << endl; exit(0);
00401 }

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