pollard_phi.cc

Go to the documentation of this file.
00001 #include "polphi_template.H"
00002 #include "my_mpz_powm_ui.cc"
00003 
00010 class CRingPhi
00011 {
00012 private:
00013  mpz_t a;
00014 public:
00015  static const std::string name;
00016  static const int SieveIntervalSize=2*3*5*7*11*13*17;
00017  CRingPhi() { mpz_init(a); }
00018  CRingPhi(const CRingPhi &x) { mpz_init_set(a,x.a); }
00019  ~CRingPhi() { mpz_clear(a); }
00020  bool set_startvalue(const unsigned int seed=1) { mpz_set_ui(a,seed+1); return true; }
00021  void set(const CRingPhi &x) { mpz_set(a,x.a); }
00022  void pow_mod(const unsigned int i, const mpz_t M) { mpz_powm_ui(a,a,i,M); }
00023  void fast_pow_mod(const unsigned int i, const mpz_t M) { my_mpz_powm_ui(a,i,M); }
00024  void test_gcd(mpz_t x, const mpz_t M) { mpz_sub_ui(x,a,1); mpz_gcd(x,x,M); }
00025  friend class CRingPhiPhase2;
00026 };
00027 const std::string CRingPhi::name = "phi";
00028 
00029 class CRingPhiPhase2 : private ForbidAssignment
00030 {
00031 private:
00032  CRingPhi a;
00033  mpz_t b_inv, b, d, d_inv, b_plus_b_inv, d_plus_d_inv, prev_b_plus_b_inv,
00034        temp1, temp2;
00035 
00036 public:
00037  explicit CRingPhiPhase2(const CRingPhi &_a) : a(_a)
00038   {
00039     // "a" contains the starting value (base) for Phase 2
00040  
00041    /* rough description:
00042       utilize the identity:
00043       (a^(i+d) -1) * (a^(i-d) -1) = a^i * ( (a^i +a^(-i)) - (a^d +a^(-d)) )
00044       
00045       1. The multiplier "a^i" can be ignored, as it has no influence on the gcd
00046       2. D will be increased in steps of i.
00047           -> precalculate (a^d +a^(-d)) for 0<d<D,
00048           -> furthermore: per interval determine/update (a^i + a^(-i))
00049       3. a^(i+D) can be computed by using a^(i+D)=a^i * a^D;
00050          a^(-(i+D)) can be computed analogously, because a^(-i)=(a^(-1))^i.
00051          -> two multiplications per interval to determine a^(i+D) + a^(-(i+D)).
00052  
00053      Bemerkung I: (remark I; not very important)
00054        Die hierauf aufbauende Paarbildungsmethode konstruiert nicht
00055        die durch andere Methoden erreichbaren Primzahlpaare, sie ist
00056        aber dafür vergleichsweise einfach zu implementieren und sie
00057        kommt mit weniger Speicherplatz als die improved-standard-continuation
00058        aus. Sobald mehrere Primzahlpaare innerhalb eines Intervalls
00059        auftauchen, ist sie schneller als die improved standard continuation.
00060     
00061      remark II: (ad 3.)
00062        a^i+a^(-i) can be computed efficiently via Lucas sequences
00063        because of x^2-x(a^1+a^(-1))+1=(x-a)*(x-a^(-1)):
00064        a^i+a^(-i)=Vi(a^1+a^(-1))=:V[i];
00065        a^(i+D)+a^(-(i+D)))=V[i+D]=V[i]*V[D]-V[i-D].
00066        The number of required multiplications per interval-step can be reduced from 2 to 1.
00067        
00068        This is another way leading (conceptually) to the same continuation as it is
00069        described in the paper of P.L. Montgomery.
00070        (cf. Peter L. Montgomery, "Speeding the Pollard and Elliptic Curve
00071         Methods of Factorization", MathComp Vol 48 (177), Jan 1987, p.243-264;
00072         especially section 4, 5 and 9).
00073    */
00074  
00075     mpz_init(b); mpz_init(b_inv); mpz_init(d); mpz_init(d_inv); mpz_init(b_plus_b_inv);
00076     mpz_init(d_plus_d_inv); mpz_init(prev_b_plus_b_inv);
00077     mpz_init(temp1); mpz_init(temp2);
00078  
00079     // b,b_inv, d,d_inv don't get updated anymore in the following,
00080     // because the associated sums will be computed via Lucas sequences.
00081  
00082     // Precomputing most common used values:
00083     mpz_set(b,a.a); mpz_invert(b_inv,b,n); mpz_mod(b_inv,b_inv,n);
00084     mpz_powm_ui(d,b,2,n); mpz_powm_ui(d_inv,b_inv,2,n);
00085     mpz_add(d_plus_d_inv,d,d_inv); mpz_mod(d_plus_d_inv,d_plus_d_inv,n);
00086     mpz_add(b_plus_b_inv,b,b_inv); mpz_mod(b_plus_b_inv,b_plus_b_inv,n);
00087     mpz_set(prev_b_plus_b_inv,b_plus_b_inv);
00088    
00089   }
00090  ~CRingPhiPhase2()
00091   {
00092     mpz_clear(b); mpz_clear(b_inv); mpz_clear(d); mpz_clear(d_inv); mpz_clear(b_plus_b_inv);
00093     mpz_clear(d_plus_d_inv); mpz_clear(prev_b_plus_b_inv);
00094     mpz_clear(temp1); mpz_clear(temp2);
00095   }
00096 
00097  void get_polynomdef_point(mpz_t x)
00098   {
00099     mpz_set(x,b_plus_b_inv);
00100   }
00101   
00102  void calc_polynomdef_next_point()
00103   {
00104     mpz_set(temp1,prev_b_plus_b_inv); mpz_set(prev_b_plus_b_inv,b_plus_b_inv);
00105     mpz_mul(b_plus_b_inv,b_plus_b_inv,d_plus_d_inv);
00106     mpz_sub(b_plus_b_inv,b_plus_b_inv,temp1);
00107     mpz_mod(b_plus_b_inv,b_plus_b_inv,n);
00108   }
00109 
00110  void calc_EvalStartingPoint(const int D, const double ii)
00111   {
00112     mpz_powm_ui(d,a.a,D,n); mpz_invert(d_inv,d,n); mpz_mod(d_inv,d_inv,n);
00113     mpz_add(d_plus_d_inv,d,d_inv); mpz_mod(d_plus_d_inv,d_plus_d_inv,n);
00114     mpz_set_d(temp1,ii); mpz_powm(b,a.a,temp1,n);
00115     mpz_invert(b_inv,b,n); mpz_mod(b_inv,b_inv,n);
00116     mpz_add(b_plus_b_inv,b,b_inv); mpz_mod(b_plus_b_inv,b_plus_b_inv,n);
00117     mpz_mul(temp1,b,d_inv); mpz_mod(temp1,temp1,n);
00118     mpz_mul(temp2,b_inv,d); mpz_mod(temp2,temp2,n);
00119     mpz_add(prev_b_plus_b_inv,temp1,temp2); mpz_mod(prev_b_plus_b_inv,prev_b_plus_b_inv,n);
00120   }
00121 
00122  void get_point_and_calc_next_point(mpz_t x)
00123   {
00124     mpz_set(x,prev_b_plus_b_inv); mpz_set(prev_b_plus_b_inv,b_plus_b_inv);
00125     mpz_mul(b_plus_b_inv,b_plus_b_inv,d_plus_d_inv);
00126     mpz_sub(b_plus_b_inv,b_plus_b_inv,x);
00127     mpz_mod(b_plus_b_inv,b_plus_b_inv,n);
00128     mpz_set(x,prev_b_plus_b_inv);    
00129   }
00130  
00131 };
00132 
00133 
00134 // explicit instantiation (not necessary)
00135 template void polphi_template<CRingPhi,CRingPhiPhase2>(const int phase1, const double phase2);
00136 
00137 #define pollard_phi(phase1,phase2) polphi_template<CRingPhi,CRingPhiPhase2>(phase1,phase2)
00138 

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