├── .gitignore ├── vec_svec_ZZ.h ├── vec_svec_ZZ_p.h ├── vec_svec_long.h ├── mat_long.h ├── svec_ZZ.h ├── svec_long.h ├── svec_ZZ_p.h ├── NEWS ├── pair_ZZ_long.h ├── vector.cpp ├── mat_long.cpp ├── vec_long.h ├── vec_short.h ├── Makefile ├── smat_ZZ_p.h ├── svector.cpp ├── smat_ZZ.h ├── smat_long.h ├── AlgebraicFactorBase.h ├── ZZFactoring.h ├── dlog-test.cpp ├── NumberFieldSieve.h ├── DLog_IC_Base.h ├── smatrix.cpp ├── README ├── Lanczos.h ├── ZZFactoring.cpp ├── ntl5_matrix.h ├── DiscreteLog.cpp ├── FactorBase.h ├── Group.h ├── DiscreteLog.h ├── AlgebraicFactorBase.cpp ├── smatrix.txt ├── DLog_IC_Base.cpp ├── smatrix.h ├── svector.txt ├── COPYING ├── SGauss.cpp ├── NumberFieldSieve.cpp └── FactorBase.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | dlog-test 3 | -------------------------------------------------------------------------------- /vec_svec_ZZ.h: -------------------------------------------------------------------------------- 1 | #ifndef NTLX_vec_svec_ZZ_H 2 | #define NTLX_vec_svec_ZZ_H 3 | 4 | #include 5 | #include "svec_ZZ.h" 6 | 7 | NTL_OPEN_NNS; 8 | 9 | typedef Vec vec_svec_ZZ; 10 | 11 | NTL_CLOSE_NNS; 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /vec_svec_ZZ_p.h: -------------------------------------------------------------------------------- 1 | #ifndef NTLX_vec_svec_ZZ_p_H 2 | #define NTLX_vec_svec_ZZ_p_H 3 | 4 | #include 5 | #include "svec_ZZ_p.h" 6 | 7 | NTL_OPEN_NNS; 8 | 9 | typedef Vec vec_svec_ZZ_p; 10 | 11 | NTL_CLOSE_NNS; 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /vec_svec_long.h: -------------------------------------------------------------------------------- 1 | #ifndef NTLX_vec_svec_long_H 2 | #define NTLX_vec_svec_long_H 3 | 4 | #include 5 | #include "svec_long.h" 6 | 7 | NTL_OPEN_NNS; 8 | 9 | typedef Vec vec_svec_long; 10 | 11 | NTL_CLOSE_NNS; 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /mat_long.h: -------------------------------------------------------------------------------- 1 | #ifndef NTLX_mat_long_H 2 | #define NTLX_mat_long_H 3 | 4 | #include "vec_long.h" 5 | #include 6 | 7 | NTL_OPEN_NNS; 8 | 9 | typedef Mat mat_long; 10 | void clear(mat_long& A); 11 | 12 | NTL_CLOSE_NNS; 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /svec_ZZ.h: -------------------------------------------------------------------------------- 1 | #ifndef NTLX_svec_ZZ__H 2 | #define NTLX_svec_ZZ__H 3 | 4 | #include 5 | #include "svector.h" 6 | 7 | NTL_OPEN_NNS; 8 | 9 | typedef SVec svec_ZZ; 10 | NTL_math_svector_decl(ZZ,vec_ZZ,svec_ZZ); 11 | 12 | NTL_CLOSE_NNS; 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /svec_long.h: -------------------------------------------------------------------------------- 1 | #ifndef NTLX_svec_long__H 2 | #define NTLX_svec_long__H 3 | 4 | #include "vec_long.h" 5 | #include "svector.h" 6 | 7 | NTL_OPEN_NNS; 8 | 9 | typedef SVec svec_long; 10 | NTL_math_svector_decl(long,vec_long,svec_long); 11 | 12 | NTL_CLOSE_NNS; 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /svec_ZZ_p.h: -------------------------------------------------------------------------------- 1 | #ifndef NTLX_svec_ZZ_p__H 2 | #define NTLX_svec_ZZ_p__H 3 | 4 | #include 5 | #include "svector.h" 6 | 7 | NTL_OPEN_NNS; 8 | 9 | typedef SVec svec_ZZ_p; 10 | NTL_math_svector_decl(ZZ_p,vec_ZZ_p,svec_ZZ_p); 11 | 12 | NTL_CLOSE_NNS; 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- 1 | 2 | New in v1.1 3 | + fixed namespace related compile problems 4 | + sparse vector now has parameter for index type (still long for now) 5 | + improved linear sieve methods 6 | + formal structured gaussian elimination method 7 | - IndexCalculus class still does its SGE too (should be fixed someday) 8 | -------------------------------------------------------------------------------- /pair_ZZ_long.h: -------------------------------------------------------------------------------- 1 | #ifndef NTL_pair_ZZ_long__H 2 | #define NTL_pair_ZZ_long__H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | NTL_OPEN_NNS; 9 | 10 | typedef Pair pair_ZZ_long; 11 | typedef Vec vec_pair_ZZ_long; 12 | 13 | NTL_CLOSE_NNS; 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /vector.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "vec_short.h" 3 | 4 | NTL_START_IMPL; 5 | 6 | static inline 7 | void BlockConstruct(short*, long) {} 8 | 9 | static inline 10 | void BlockDestroy(short*, long) {} 11 | 12 | /* need to provide: 13 | inline svec_ZZ& operator*=(svec_ZZ& x, long a) { 14 | mul(x, x, a); return x; 15 | } 16 | */ 17 | 18 | NTL_END_IMPL; 19 | -------------------------------------------------------------------------------- /mat_long.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "mat_long.h" 3 | 4 | /* Implementation of a matrix of long values. 5 | * 6 | * Written by: Chris Studholme 7 | * Copyright: GPL (http://www.fsf.org/copyleft/gpl.html) 8 | */ 9 | 10 | NTL_START_IMPL; 11 | 12 | void clear(mat_long& A) { 13 | for (long i=0; i 5 | #include 6 | 7 | NTL_OPEN_NNS; 8 | 9 | inline bool IsZero(long i) { 10 | return (i==0); 11 | } 12 | 13 | inline void clear(long &i) { 14 | i=0; 15 | } 16 | 17 | inline void clear(vec_long& v) { 18 | memset(v.elts(),0,v.length()*sizeof(long)); 19 | } 20 | 21 | NTL_CLOSE_NNS; 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /vec_short.h: -------------------------------------------------------------------------------- 1 | #ifndef NTLX_vec_short__H 2 | #define NTLX_vec_short__H 3 | 4 | #include 5 | 6 | #include 7 | 8 | NTL_OPEN_NNS; 9 | 10 | typedef Vec vec_short; 11 | 12 | inline void clear(vec_short& x) { 13 | memset(x.elts(),0,x.length()*sizeof(short)); 14 | } 15 | 16 | /* need to provide: 17 | inline svec_ZZ& operator*=(svec_ZZ& x, long a) { 18 | mul(x, x, a); return x; 19 | } 20 | */ 21 | 22 | NTL_CLOSE_NNS; 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | CXX = g++ 3 | LINK = g++ 4 | 5 | NTLPREFIX = /usr/local 6 | NTLLIB = -L$(NTLPREFIX)/lib -lntl -lgmp 7 | NTLINCLUDE = -I$(NTLPREFIX)/include 8 | 9 | PREFFLAGS = -O2 -Wall -I. 10 | CXXFLAGS = $(PREFFLAGS) $(NTLINCLUDE) 11 | LINKFLAGS = $(NTLLIB) 12 | 13 | ALL_PROGS = dlog-test 14 | COMMON_OBJS = ZZFactoring.o \ 15 | mat_long.o svector.o smatrix.o \ 16 | vector.o FactorBase.o AlgebraicFactorBase.o \ 17 | SGauss.o DiscreteLog.o DLog_IC_Base.o \ 18 | NumberFieldSieve.o 19 | COMMON_HEADERS = 20 | 21 | 22 | all: $(ALL_PROGS) 23 | 24 | dlog-test: $(COMMON_OBJS) dlog-test.o 25 | $(LINK) -o $@ $^ $(LINKFLAGS) 26 | 27 | clean: 28 | rm -f *% *~ *.o core a.out $(ALL_PROGS) 29 | 30 | -------------------------------------------------------------------------------- /smat_ZZ_p.h: -------------------------------------------------------------------------------- 1 | #ifndef NTLX_smat_ZZ_p_H 2 | #define NTLX_smat_ZZ_p_H 3 | 4 | #include 5 | 6 | #include "smatrix.h" 7 | #include "vec_svec_ZZ_p.h" 8 | #include "Lanczos.h" 9 | #include "smat_long.h" 10 | 11 | NTL_OPEN_NNS; 12 | 13 | NTL_smatrix_decl(ZZ_p,svec_ZZ_p,vec_svec_ZZ_p,smat_ZZ_p); 14 | NTL_conv_smatrix_decl(ZZ_p,svec_ZZ_p,vec_svec_ZZ_p,mat_ZZ_p,smat_ZZ_p); 15 | NTL_math_smatrix_decl(ZZ_p,vec_ZZ_p,svec_ZZ_p,vec_svec_ZZ_p,smat_ZZ_p); 16 | NTL_eq_smatrix_decl(ZZ_p,svec_ZZ_p,vec_svec_ZZ_p,smat_ZZ_p); 17 | NTL_io_smatrix_decl(ZZ_p,svec_ZZ_p,vec_svec_ZZ_p,smat_ZZ_p); 18 | 19 | // methods for solving sparse linear systems 20 | NTL_Lanczos_decl(vec_ZZ_p,smat_ZZ_p); 21 | 22 | NTL_CLOSE_NNS; 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /svector.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "svec_long.h" 3 | #include "svec_ZZ.h" 4 | #include "svec_ZZ_p.h" 5 | 6 | /* Implementation of sparse vectors. 7 | * 8 | * Written by: Chris Studholme 9 | * Copyright: GPL (http://www.fsf.org/copyleft/gpl.html) 10 | */ 11 | 12 | NTL_START_IMPL; 13 | 14 | static const long _long_zero = 0; 15 | template<> const long& zero_ref() { return _long_zero; } 16 | template<> const ZZ& zero_ref() { return ZZ::zero(); } 17 | template<> const ZZ_p& zero_ref() { return ZZ_p::zero(); } 18 | 19 | inline void add(long&x, long a, long b) { 20 | x=a+b; 21 | } 22 | 23 | inline void sub(long&x, long a, long b) { 24 | x=a-b; 25 | } 26 | 27 | inline void mul(long&x, long a, long b) { 28 | x=a*b; 29 | } 30 | 31 | inline void negate(long& x, long a) { 32 | x=-a; 33 | } 34 | 35 | NTL_math_svector_impl(long,vec_long,svec_long); 36 | NTL_math_svector_impl(ZZ,vec_ZZ,svec_ZZ); 37 | NTL_math_svector_impl(ZZ_p,vec_ZZ_p,svec_ZZ_p); 38 | 39 | NTL_END_IMPL; 40 | -------------------------------------------------------------------------------- /smat_ZZ.h: -------------------------------------------------------------------------------- 1 | #ifndef NTLX_smat_ZZ_H 2 | #define NTLX_smat_ZZ_H 3 | 4 | #include 5 | #include 6 | #include "smatrix.h" 7 | #include "vec_svec_ZZ.h" 8 | #include "Lanczos.h" 9 | 10 | 11 | NTL_OPEN_NNS; 12 | 13 | NTL_smatrix_decl(ZZ,svec_ZZ,vec_svec_ZZ,smat_ZZ); 14 | NTL_conv_smatrix_decl(ZZ,svec_ZZ,vec_svec_ZZ,mat_ZZ,smat_ZZ); 15 | NTL_math_smatrix_decl(ZZ,vec_ZZ,svec_ZZ,vec_svec_ZZ,smat_ZZ); 16 | NTL_eq_smatrix_decl(ZZ,svec_ZZ,vec_svec_ZZ,smat_ZZ); 17 | NTL_io_smatrix_decl(ZZ,svec_ZZ,vec_svec_ZZ,smat_ZZ); 18 | 19 | // methods for solving sparse linear systems 20 | NTL_Lanczos_decl(vec_ZZ_p,smat_ZZ); 21 | 22 | /* Structured Gaussian Elimination. 23 | * Finds a smaller version of system Aorig*x=yorig and returns it 24 | * in Anew and ynew. cols is the list of column indices from Aorig 25 | * that were kept in Anew. 26 | */ 27 | void SGauss(smat_ZZ& Anew, vec_ZZ_p& ynew, vec_long& cols, 28 | const smat_ZZ& Aorig, const vec_ZZ_p& yorig); 29 | 30 | /* Undo gaussian elimination. Assuming Aorig and yorig were reduced with 31 | * SGauss(), cols is the list of columns that were kept, and x is the solution 32 | * to the reduced system that was found, then xorig, the solution to the 33 | * original system, will be computed. 34 | */ 35 | bool SGauss_undo(vec_ZZ_p& xorig, const vec_ZZ_p& x, 36 | const vec_long& cols, 37 | const smat_ZZ& Aorig, const vec_ZZ_p& yorig); 38 | 39 | 40 | NTL_CLOSE_NNS; 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /smat_long.h: -------------------------------------------------------------------------------- 1 | #ifndef NTLX_smat_long_H 2 | #define NTLX_smat_long_H 3 | 4 | #include 5 | #include "smatrix.h" 6 | #include "mat_long.h" 7 | #include "vec_svec_long.h" 8 | #include "Lanczos.h" 9 | 10 | 11 | NTL_OPEN_NNS; 12 | 13 | NTL_smatrix_decl(long,svec_long,vec_svec_long,smat_long); 14 | NTL_conv_smatrix_decl(long,svec_long,vec_svec_long,mat_long,smat_long); 15 | NTL_math_smatrix_decl(long,vec_long,svec_long,vec_svec_long,smat_long); 16 | NTL_eq_smatrix_decl(long,svec_long,vec_svec_long,smat_long); 17 | NTL_io_smatrix_decl(long,svec_long,vec_svec_long,smat_long); 18 | 19 | // methods for solving sparse linear systems 20 | NTL_Lanczos_decl(vec_ZZ_p,smat_long); 21 | 22 | /* Structured Gaussian Elimination. 23 | * Finds a smaller version of system Aorig*x=yorig and returns it 24 | * in Anew and ynew. cols is the list of column indices from Aorig 25 | * that were kept in Anew. 26 | */ 27 | void SGauss(smat_long& Anew, vec_ZZ_p& ynew, vec_long& cols, 28 | const smat_long& Aorig, const vec_ZZ_p& yorig); 29 | 30 | /* Undo gaussian elimination. Assuming Aorig and yorig were reduced with 31 | * SGauss(), cols is the list of columns that were kept, and x is the solution 32 | * to the reduced system that was found, then xorig, the solution to the 33 | * original system, will be computed. 34 | */ 35 | bool SGauss_undo(vec_ZZ_p& xorig, const vec_ZZ_p& x, 36 | const vec_long& cols, 37 | const smat_long& Aorig, const vec_ZZ_p& yorig); 38 | 39 | 40 | NTL_CLOSE_NNS; 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /AlgebraicFactorBase.h: -------------------------------------------------------------------------------- 1 | #ifndef _ALGEBRAICFACTORBASE_H_ 2 | #define _ALGEBRAICFACTORBASE_H_ 3 | 4 | #include 5 | #include "vec_svec_long.h" 6 | #include "FactorBase.h" 7 | 8 | /* Class representing an algebraic factor base. 9 | * 10 | * Written by: Chris Studholme 11 | * Copyright: GPL (http://www.fsf.org/copyleft/gpl.html) 12 | */ 13 | 14 | NTL_OPEN_NNS; 15 | 16 | class AlgebraicFactorBase { 17 | public: 18 | // minimal polynomial 19 | ZZX f; 20 | 21 | // rational factorbase 22 | FactorBase zfb; 23 | 24 | // indices into algebraic factorbase 25 | // index[i] is assoicated with zfb[i] 26 | vec_svec_long index; 27 | 28 | // number of good first degree prime ideals 29 | long nprimes; 30 | 31 | // modulus and exponent for character map calculation 32 | ZZ q,e; 33 | 34 | public: 35 | AlgebraicFactorBase(const ZZX& f, long bound); 36 | 37 | ~AlgebraicFactorBase() {} 38 | 39 | // update index to reflect primes lying above zfb[i]. 40 | void primes_above(long i); 41 | 42 | inline long length() const { 43 | return nprimes; 44 | } 45 | 46 | // factor c+d*alpha and return true if smooth 47 | bool factor(long* fact, long c, long d) const; 48 | 49 | // return norm of c+d*alpha 50 | ZZ norm(long c, long d) const; 51 | 52 | // modulus for character map calculation 53 | void SetModulus(const ZZ& q); 54 | 55 | // compute character map for c+d*alpha 56 | void CharacterMap(ZZ* l, long c, long d) const; 57 | 58 | }; 59 | 60 | NTL_CLOSE_NNS; 61 | 62 | #endif 63 | -------------------------------------------------------------------------------- /ZZFactoring.h: -------------------------------------------------------------------------------- 1 | #ifndef NTL_ZZFactoring__H 2 | #define NTL_ZZFactoring__H 3 | 4 | #include 5 | #include "pair_ZZ_long.h" 6 | 7 | 8 | /* Methods for factoring integers. 9 | * 10 | * Written by: Chris Studholme 11 | * Copyright: GPL (http://www.fsf.org/copyleft/gpl.html) 12 | */ 13 | 14 | NTL_OPEN_NNS; 15 | 16 | 17 | /* Prove that n is prime. If n<0, then the absolute value of n is tested. 18 | * If n is 0 or 1, then 0 is returned. 19 | * 20 | * Not implemented; just calls ProbPrime() for now. 21 | */ 22 | long ProvePrime(const ZZ& n); 23 | 24 | 25 | /* General purpose factoring of integer n using best known methods. If n<0, 26 | * the absolute value of n will be factored. If n==0 or n==1, factors will 27 | * be set to zero length. 28 | * 29 | * When finished, the factors vector will contain the factors and exponents 30 | * sorted in increasing order by factor. 31 | * 32 | * If bnd>0, the method only runs long enough to find prime factors less than 33 | * bnd with probability ???. In this case, the method may inadvertantly find 34 | * larger prime factors. Furthermore, large composite factors may contain 35 | * primes <=bnd. 36 | * 37 | * If deterministic!=0, all factors will have their primality proved with 38 | * ProvePrime(). If bnd>0 then only factors <=bnd will have had their 39 | * primality proved. 40 | */ 41 | void factor(vec_pair_ZZ_long& factors, const ZZ& n, 42 | const ZZ& bnd=ZZ::zero(), 43 | long deterministic=0, long verbose=0); 44 | 45 | 46 | /* Recursively factor n by Pollard Rho method and update factors. 47 | * 48 | * The factors vector is assumed to either be zero length or already contain 49 | * a properly sorted list of factors. 50 | * 51 | * Also, n must satisfy n>1. 52 | * 53 | * See factor() for details regarding bnd and deterministic. 54 | */ 55 | void PollardRho(vec_pair_ZZ_long& factors, const ZZ& n, 56 | const ZZ& bnd=ZZ::zero(), 57 | long deterministic=0, long verbose=0); 58 | 59 | 60 | NTL_CLOSE_NNS; 61 | 62 | #endif 63 | -------------------------------------------------------------------------------- /dlog-test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "NumberFieldSieve.h" 5 | 6 | using namespace NTL; 7 | 8 | // test if g is a generator of the group ZZ_p 9 | // f is the factorization of p-1 10 | bool isGenerator(const ZZ_p& g, const vec_pair_ZZ_long& f) { 11 | ZZ m,e; 12 | ZZ_p t; 13 | sub(m,ZZ_p::modulus(),1); 14 | for (long i=0; i 5 | #include 6 | #include 7 | #include "smat_ZZ.h" 8 | 9 | #include "DLog_IC_Base.h" 10 | #include "FactorBase.h" 11 | 12 | NTL_OPEN_NNS; 13 | 14 | // helper class defined internally 15 | class NFS_Relations; 16 | 17 | 18 | /* Solve discrete log problems using the Number Field Sieve method. This 19 | * method is only applicable in the field ZZ_p. 20 | * 21 | * Written by: Chris Studholme 22 | * Copyright: GPL (http://www.fsf.org/copyleft/gpl.html) 23 | */ 24 | class DLog_NFS : public DLog_IC_Base { 25 | public: 26 | // tuning parameters 27 | static long MAX_SIEVE; /* maximum size of a single sieve */ 28 | 29 | protected: 30 | // degree of the number field 31 | long k; 32 | 33 | // largest prime factor of p-1 34 | ZZ q; 35 | 36 | // width and length of sieve 37 | long sieve_width; 38 | long sieve_length; // set after each run 39 | 40 | // factorbase 41 | FactorBase zfb; 42 | 43 | public: 44 | DLog_NFS() : DLog_IC_Base() { 45 | } 46 | DLog_NFS(const ZZ_p& base, long k=0, long bound=0, long width=0) 47 | : DLog_IC_Base(base) { 48 | setBase(base,k,bound,width); 49 | } 50 | 51 | ~DLog_NFS() { 52 | } 53 | 54 | // set the base to use for logs, along with the degree of the number field, 55 | // the factorbase smoothness bound, and the width of the sieve 56 | void setBase(const ZZ_p& base, long k, long bound=0, long sieve_width=0); 57 | 58 | // set the base to use for logs 59 | // factorbase bound is determined automatically 60 | virtual void setBase(const ZZ_p& base) { 61 | // the other setBase() will figure out the optimal parameters 62 | setBase(base,0); 63 | } 64 | 65 | long getSieveLength() const { 66 | return sieve_length; 67 | } 68 | 69 | // compute optimum parameters for a given p 70 | // any of k, bound, or width that are non-zero are not computed 71 | static void parameters(long& k, long& bound, long& width, const ZZ& p); 72 | 73 | private: 74 | // compute logarithm of a (smallish) prime to base g 75 | // return 0 if unsuccessful 76 | ZZ log_prime(const ZZ& power); 77 | 78 | // solve linear system induced by rels 79 | bool ls_solve(vec_ZZ& X, const NFS_Relations& rels, const vec_ZZ& b, 80 | const ZZ& q); 81 | 82 | // L_p[1/3;c] = exp(c*log(p)^{1/3}*log(log(p))^{2/3}) 83 | inline static double L_p(const ZZ& p, double c) { 84 | double lm = NTL::log(p); 85 | double llm = ::log(lm); 86 | double lllm = ::log(llm); 87 | return exp(c*exp(llm/3)*exp(lllm*2/3)); 88 | } 89 | 90 | 91 | }; 92 | 93 | NTL_CLOSE_NNS; 94 | 95 | #endif 96 | -------------------------------------------------------------------------------- /DLog_IC_Base.h: -------------------------------------------------------------------------------- 1 | #ifndef _DLOG_IC_BASE_H_ 2 | #define _DLOG_IC_BASE_H_ 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | #include "pair_ZZ_long.h" 9 | 10 | #include "DiscreteLog.h" 11 | 12 | 13 | NTL_OPEN_NNS; 14 | 15 | /* Base class for methods of computing discrete logarithms based on the 16 | * Index Calculus method. These include the classic Index Calculus method 17 | * and the Number Field Sieve method. These methods are only applicable 18 | * to the field ZZ_p. 19 | * 20 | * Written by: Chris Studholme 21 | * Copyright: GPL (http://www.fsf.org/copyleft/gpl.html) 22 | */ 23 | class DLog_IC_Base : public DiscreteLog { 24 | public: 25 | static long VERBOSE; /* verbosity level */ 26 | 27 | 28 | protected: 29 | // prime generator (mod p); internally all log are to this base 30 | ZZ_p g; 31 | 32 | // base of discrete logarithms 33 | ZZ_p base; // hides DiscreteLog::base, but that's ok 34 | 35 | // discrete log of base (w.r.t. g) 36 | ZZ log_base; 37 | 38 | // bound on size of primes that log_prime() can handle 39 | ZZ upper_bound; 40 | 41 | // cache of known logarithms 42 | ZZ* cache_prime; // a prime 43 | ZZ* cache_log; // it's logarithm 44 | long acache; // number of allocated entries 45 | long ncache; // number of valid entries 46 | 47 | 48 | public: 49 | DLog_IC_Base() : DiscreteLog() { 50 | log_base=0; 51 | cache_prime=NULL; 52 | cache_log=NULL; 53 | acache=ncache=0; 54 | } 55 | DLog_IC_Base(const ZZ_p& base) : DiscreteLog(base) { 56 | log_base=0; 57 | cache_prime=NULL; 58 | cache_log=NULL; 59 | acache=ncache=0; 60 | setBase(base); 61 | } 62 | 63 | ~DLog_IC_Base() { 64 | if (cache_prime) delete[] cache_prime; 65 | if (cache_log) delete[] cache_log; 66 | } 67 | 68 | // set the base to use for logs 69 | // factorbase bound is determined automatically 70 | //virtual void setBase(const ZZ_p& base); 71 | 72 | // returns -1 if the discrete log does not exist 73 | ZZ log(const GroupElement& power) { 74 | std::cerr<<"DLog_IC_Base::log() " 75 | <<"cannot use index calculus method with an arbitrary group" 76 | < svec_ZZ_p) 37 | inline void mul(svec_ZZ_p& result, const svec_long& a, const ZZ_p& b) { 38 | result.SetLength(a.length()); 39 | clear(result); 40 | long an = a.nvalues(); 41 | const long* ai = a.indices(); 42 | const svec_long::value_type* av = a.values(); 43 | for (long i=0; i svec_ZZ_p) 49 | inline void mul(svec_ZZ_p& result, const svec_ZZ& a, const ZZ_p& b) { 50 | result.SetLength(a.length()); 51 | clear(result); 52 | long an = a.nvalues(); 53 | const long* ai = a.indices(); 54 | const svec_ZZ::value_type* av = a.values(); 55 | for (long i=0; i100 (but still small) 50 | are needed, this can be added without much difficulty. The case where p-1 51 | is a product of several large primes or a power (square, etc.) is much more 52 | difficult handle. 53 | 54 | The base for the logarithms can be any group element, but a small base 55 | (especially a prime generator) will result in a slightly faster precomputation. 56 | The algorithm should also work in the case where the base is not a generator of 57 | the group; however, some logarithms will be impossible to compute. 58 | 59 | 60 | PERFORMANCE: 61 | 62 | The precomputation requires much more time than the computation of an 63 | individual logarithm. Furthermore, the time required to compute each 64 | individual logarithm is highly variable, is faster for small residules, 65 | and gets faster (ever so slowly) as more logarithms are computed. When 66 | the same logarithm is computed multiple times, it will be almost instantaneous 67 | the second and subsequent times due to the internal caching that is done. 68 | 69 | The precomputation has been optimized on an Athalon XP1700 machine with 256MB 70 | of RAM so it should be as fast as it can be on any similar machine. The 71 | computation of an individual logarithm has not been as thoroughly optimized 72 | and uses a substandard algorithm for testing smoothness, so it could be 73 | improved if necessary. 74 | 75 | Here are some rough timing measurements for various problems solved on a 76 | 400MHz PowerPC with 128MB of RAM: 77 | 78 | 64 bit modulus: 1 minute setup, 2 seconds per logarithm 79 | 80 | 80 bit modulus: 5 minute setup, 1 minute per logarithm 81 | 82 | 100 bit modulus: 1 hour setup, 8 minutes per logarithm 83 | 84 | 85 | POTENTIAL PROBLEMS: 86 | 87 | The following warning message may appear: 88 | 89 | IndexCalculus::make_system() 4 INCORRECT LOGARITHMS 90 | 91 | This is normal (at least I think it's normal) and it doesn't seem to impact 92 | the performance of the algorithm as long as the number mentioned is small. 93 | 94 | The line: 95 | 96 | DLog_IC_Base::VERBOSE=1; 97 | 98 | can be added before creating an IndexCalculus object to get a lot more messages 99 | displayed. With VERBOSE=0, messages regarding sieving and linear algebra 100 | progress will still be displayed. If you need the algorithm to operate in 101 | complete silence, let me know. 102 | 103 | 104 | Question, comments, problems, or other concerns can be emailed to: 105 | chris.studholme@utoronto.ca 106 | 107 | -- END OF README -- 108 | -------------------------------------------------------------------------------- /Lanczos.h: -------------------------------------------------------------------------------- 1 | #ifndef _NTL_Lanczos__H_ 2 | #define _NTL_Lanczos__H_ 3 | 4 | 5 | 6 | /* Template for methods implementing the Lanczos algorithms for solving 7 | * sparse linear systems. 8 | * 9 | * Written by: Chris Studholme 10 | * Copyright: GPL (http://www.fsf.org/copyleft/gpl.html) 11 | */ 12 | 13 | 14 | #define NTL_Lanczos_decl(vec_T,smat_T) \ 15 | bool Lanczos(const smat_T& A, vec_T& x, const vec_T& y, \ 16 | long deterministic=0, long verbose=0); \ 17 | 18 | 19 | #define NTL_Lanczos_impl(T,vec_T,svec_T,smat_T) \ 20 | bool Lanczos(const smat_T& A, vec_T& x, const vec_T& y, \ 21 | long deterministic, long verbose) { \ 22 | \ 23 | long nrows = A.NumRows(); \ 24 | long ncols = A.NumCols(); \ 25 | \ 26 | if (deterministic) { \ 27 | Error("Lanczos() deterministic algorithm not implemented yet"); \ 28 | } \ 29 | \ 30 | if (nrows=20)) { \ 120 | std::cout<<"Lanczos: "< 3 | #include "ZZFactoring.h" 4 | 5 | 6 | /* Method for factoring integers. 7 | * 8 | * Written by: Chris Studholme 9 | * Copyright: GPL (http://www.fsf.org/copyleft/gpl.html) 10 | */ 11 | 12 | NTL_START_IMPL; 13 | 14 | 15 | long ProvePrime(const ZZ& _n) { 16 | ZZ n(_n); 17 | if (n<0) 18 | abs(n,n); 19 | if (n<=1) 20 | return 0; 21 | 22 | if (n<=1000000) { 23 | // n is small so use trial division to check primality 24 | long ln = to_long(n); 25 | long end = to_long(SqrRoot(n)); 26 | PrimeSeq s; 27 | for (long p=s.next(); p<=end; p=s.next()) 28 | if ((ln%p)==0) 29 | return 0; 30 | return 1; 31 | } 32 | 33 | // check small primes 34 | PrimeSeq s; 35 | for (long p=s.next(); p<1000; p=s.next()) 36 | if (divide(n,p)) 37 | return 0; 38 | 39 | // obviously, something is missing here! 40 | 41 | return ProbPrime(n); 42 | } 43 | 44 | // factors is kept sorted by p 45 | void addFactor(vec_pair_ZZ_long& factors, const ZZ& p, long exponent=1) { 46 | // fast path: factors.length()==0 47 | if (factors.length()==0) { 48 | factors.SetLength(1); 49 | factors[0].a = p; 50 | factors[0].b = exponent; 51 | return; 52 | } 53 | 54 | // fast path: p>=factors[factors.length()-1].a 55 | if (p>=factors[factors.length()-1].a) { 56 | if (p==factors[factors.length()-1].a) 57 | factors[factors.length()-1].b += exponent; 58 | else { 59 | factors.SetLength(factors.length()+1); 60 | factors[factors.length()-1].a = p; 61 | factors[factors.length()-1].b = exponent; 62 | } 63 | return; 64 | } 65 | 66 | // binary search to find location to insert 67 | long low=0; 68 | long high=factors.length(); 69 | while (high>low) { 70 | long mid = (low+high)/2; 71 | if (factors[mid].alow; --i) 82 | factors[i] = factors[i-1]; 83 | factors[low].a = p; 84 | factors[low].b = exponent; 85 | } 86 | } 87 | 88 | // factor n into a*b using Pollard Rho method 89 | // pre-condition: n>1 90 | inline void PollardRho(ZZ& a, ZZ& b, const ZZ& n, 91 | const ZZ& bnd=ZZ::zero()) { 92 | ZZ_pBak bak; 93 | bak.save(); 94 | ZZ_p::init(n); 95 | 96 | ZZ d; 97 | ZZ_p x1; 98 | random(x1); 99 | ZZ_p x2(x1); 100 | 101 | ZZ end(IsZero(bnd)?5*SqrRoot(SqrRoot(n)):2*SqrRoot(bnd)); 102 | for (; !IsZero(end); --end) { 103 | x1 = x1*x1 + 1; 104 | x2 = x2*x2 + 1; 105 | x2 = x2*x2 + 1; 106 | GCD(d,n,rep(x2-x1)); 107 | if ((d>1)&&(d1 120 | void PollardRho(vec_pair_ZZ_long& factors, const ZZ& n, 121 | const ZZ& _bnd, long deterministic, long verbose) { 122 | bool pn = deterministic ? ProvePrime(n) : ProbPrime(n); 123 | if (pn) { 124 | addFactor(factors,n); 125 | return; 126 | } 127 | 128 | ZZ bnd(n<=_bnd ? ZZ::zero() : _bnd); 129 | 130 | ZZ a,b; 131 | do { 132 | PollardRho(a,b,n,bnd); 133 | if (!IsOne(a)&&!IsOne(b)) 134 | break; 135 | if (!deterministic||!IsZero(bnd)) { 136 | addFactor(factors,n); 137 | return; 138 | } 139 | } while (true); 140 | 141 | PollardRho(factors,a,bnd,deterministic,verbose); 142 | PollardRho(factors,b,bnd,deterministic,verbose); 143 | } 144 | 145 | // do trial division by small primes 146 | // pre-conditions: n>0 147 | ZZ SmallPrimes(vec_pair_ZZ_long& factors, const ZZ& _n) { 148 | ZZ n(_n); 149 | ZZ q; 150 | PrimeSeq s; 151 | long p; 152 | 153 | //long prime_bnd = ComputePrimeBound(NumBits(n)); 154 | long prime_bnd = SqrRoot(n)>1000 ? 1000 : to_long(SqrRoot(n)); 155 | 156 | for (p=s.next(); (p>0)&&(p<=prime_bnd); p=s.next()) { 157 | if (DivRem(q,n,p)==0) { 158 | long e=1; 159 | n=q; 160 | while (DivRem(q,n,p)==0) { 161 | ++e; 162 | n=q; 163 | } 164 | addFactor(factors,to_ZZ(p),e); 165 | if (IsOne(n)) 166 | return n; 167 | } 168 | } 169 | return n; 170 | } 171 | 172 | // general purpose factoring method 173 | void factor(vec_pair_ZZ_long& factors, const ZZ& _n, 174 | const ZZ& _bnd, long deterministic, long verbose) { 175 | // initialize factors 176 | factors.SetLength(0); 177 | 178 | ZZ n(_n); 179 | 180 | if (n<=1) { 181 | abs(n,n); 182 | if (n<=1) 183 | return; 184 | } 185 | 186 | ZZ bnd(_bnd>0 ? _bnd : ZZ::zero()); 187 | 188 | // small primes test 189 | n = SmallPrimes(factors,n); 190 | 191 | // Pollard Rho method 192 | if (n>1) 193 | PollardRho(factors,n,bnd,deterministic,verbose); 194 | } 195 | 196 | 197 | NTL_END_IMPL; 198 | -------------------------------------------------------------------------------- /ntl5_matrix.h: -------------------------------------------------------------------------------- 1 | #ifndef NTL5_matrix__H 2 | #define NTL5_matrix__H 3 | 4 | #include 5 | #include 6 | 7 | 8 | // matrix templates 9 | 10 | 11 | #define NTL_matrix_decl(T,vec_T,vec_vec_T,mat_T) \ 12 | class mat_T { \ 13 | public: \ 14 | \ 15 | vec_vec_T _mat__rep; \ 16 | long _mat__numcols; \ 17 | \ 18 | \ 19 | mat_T() { _mat__numcols = 0; } \ 20 | mat_T(const mat_T& l__a); \ 21 | mat_T& operator=(const mat_T& l__a); \ 22 | ~mat_T() { } \ 23 | \ 24 | mat_T(NTL_NNS INIT_SIZE_TYPE, long l__n, long l__m); \ 25 | \ 26 | void kill(); \ 27 | \ 28 | void SetDims(long l__n, long l__m); \ 29 | \ 30 | long NumRows() const { return _mat__rep.length(); } \ 31 | long NumCols() const { return _mat__numcols; } \ 32 | \ 33 | vec_T& operator[](long l__i) { return _mat__rep[l__i]; } \ 34 | const vec_T& operator[](long l__i) const { return _mat__rep[l__i]; } \ 35 | \ 36 | vec_T& operator()(long l__i) { return _mat__rep[l__i-1]; } \ 37 | const vec_T& operator()(long l__i) const { return _mat__rep[l__i-1]; } \ 38 | \ 39 | T& operator()(long l__i, long l__j) { return _mat__rep[l__i-1][l__j-1]; } \ 40 | const T& operator()(long l__i, long l__j) const \ 41 | { return _mat__rep[l__i-1][l__j-1]; } \ 42 | \ 43 | \ 44 | \ 45 | long position(const vec_T& l__a) const { return _mat__rep.position(l__a); } \ 46 | long position1(const vec_T& l__a) const { return _mat__rep.position1(l__a); } \ 47 | mat_T(mat_T& l__x, NTL_NNS INIT_TRANS_TYPE) : \ 48 | _mat__rep(l__x._mat__rep, NTL_NNS INIT_TRANS), _mat__numcols(l__x._mat__numcols) { } \ 49 | }; \ 50 | \ 51 | inline const vec_vec_T& rep(const mat_T& l__a) \ 52 | { return l__a._mat__rep; } \ 53 | \ 54 | void swap(mat_T& l__X, mat_T& l__Y); \ 55 | \ 56 | void MakeMatrix(mat_T& l__x, const vec_vec_T& l__a); \ 57 | 58 | 59 | 60 | #define NTL_eq_matrix_decl(T,vec_T,vec_vec_T,mat_T) \ 61 | long operator==(const mat_T& l__a, const mat_T& l__b); \ 62 | long operator!=(const mat_T& l__a, const mat_T& l__b); \ 63 | 64 | 65 | 66 | #define NTL_io_matrix_decl(T,vec_T,vec_vec_T,mat_T) \ 67 | NTL_SNS istream& operator>>(NTL_SNS istream&, mat_T&); \ 68 | NTL_SNS ostream& operator<<(NTL_SNS ostream&, const mat_T&); \ 69 | 70 | 71 | #define NTL_matrix_impl(T,vec_T,vec_vec_T,mat_T) \ 72 | mat_T::mat_T(const mat_T& l__a) \ 73 | { \ 74 | _mat__numcols = 0; \ 75 | SetDims(l__a.NumRows(), l__a.NumCols()); \ 76 | _mat__rep = l__a._mat__rep; \ 77 | } \ 78 | \ 79 | mat_T& mat_T::operator=(const mat_T& l__a) \ 80 | { \ 81 | SetDims(l__a.NumRows(), l__a.NumCols()); \ 82 | _mat__rep = l__a._mat__rep; \ 83 | return *this; \ 84 | } \ 85 | \ 86 | \ 87 | mat_T::mat_T(NTL_NNS INIT_SIZE_TYPE, long l__n, long l__m) \ 88 | { \ 89 | _mat__numcols = 0; \ 90 | SetDims(l__n, l__m); \ 91 | } \ 92 | \ 93 | void mat_T::kill() \ 94 | { \ 95 | _mat__numcols = 0; \ 96 | _mat__rep.kill(); \ 97 | } \ 98 | \ 99 | void mat_T::SetDims(long l__n, long l__m) \ 100 | { \ 101 | if (l__n < 0 || l__m < 0) \ 102 | NTL_NNS Error("SetDims: bad args"); \ 103 | \ 104 | if (l__m != _mat__numcols) { \ 105 | _mat__rep.kill(); \ 106 | _mat__numcols = l__m; \ 107 | } \ 108 | \ 109 | long l__oldmax = _mat__rep.MaxLength(); \ 110 | long l__i; \ 111 | _mat__rep.SetLength(l__n); \ 112 | \ 113 | for (l__i = l__oldmax; l__i < l__n; l__i++) \ 114 | _mat__rep[l__i].FixLength(l__m); \ 115 | } \ 116 | \ 117 | \ 118 | void MakeMatrix(mat_T& l__x, const vec_vec_T& l__a) \ 119 | { \ 120 | long l__n = l__a.length(); \ 121 | \ 122 | if (l__n == 0) { \ 123 | l__x.SetDims(0, 0); \ 124 | return; \ 125 | } \ 126 | \ 127 | long l__m = l__a[0].length(); \ 128 | long l__i; \ 129 | \ 130 | for (l__i = 1; l__i < l__n; l__i++) \ 131 | if (l__a[l__i].length() != l__m) \ 132 | NTL_NNS Error("nonrectangular matrix"); \ 133 | \ 134 | l__x.SetDims(l__n, l__m); \ 135 | for (l__i = 0; l__i < l__n; l__i++) \ 136 | l__x[l__i] = l__a[l__i]; \ 137 | } \ 138 | \ 139 | void swap(mat_T& l__X, mat_T& l__Y) \ 140 | { \ 141 | NTL_NNS swap(l__X._mat__numcols, l__Y._mat__numcols); \ 142 | swap(l__X._mat__rep, l__Y._mat__rep); \ 143 | } \ 144 | \ 145 | 146 | 147 | 148 | 149 | 150 | 151 | #define NTL_eq_matrix_impl(T,vec_T,vec_vec_T,mat_T) \ 152 | long operator==(const mat_T& l__a, const mat_T& l__b) \ 153 | { \ 154 | if (l__a.NumCols() != l__b.NumCols()) \ 155 | return 0; \ 156 | \ 157 | if (l__a.NumRows() != l__b.NumRows()) \ 158 | return 0; \ 159 | \ 160 | long l__n = l__a.NumRows(); \ 161 | long l__i; \ 162 | \ 163 | for (l__i = 0; l__i < l__n; l__i++) \ 164 | if (l__a[l__i] != l__b[l__i]) \ 165 | return 0; \ 166 | \ 167 | return 1; \ 168 | } \ 169 | \ 170 | \ 171 | long operator!=(const mat_T& l__a, const mat_T& l__b) \ 172 | { \ 173 | return !(l__a == l__b); \ 174 | } \ 175 | 176 | 177 | 178 | 179 | #define NTL_io_matrix_impl(T,vec_T,vec_vec_T,mat_T) \ 180 | NTL_SNS istream& operator>>(NTL_SNS istream& l__s, mat_T& l__x) \ 181 | { \ 182 | vec_vec_T l__buf; \ 183 | l__s >> l__buf; \ 184 | MakeMatrix(l__x, l__buf); \ 185 | return l__s; \ 186 | } \ 187 | \ 188 | NTL_SNS ostream& operator<<(NTL_SNS ostream& l__s, const mat_T& l__a) \ 189 | { \ 190 | long l__n = l__a.NumRows(); \ 191 | long l__i; \ 192 | l__s << "["; \ 193 | for (l__i = 0; l__i < l__n; l__i++) { \ 194 | l__s << l__a[l__i]; \ 195 | l__s << "\n"; \ 196 | } \ 197 | l__s << "]"; \ 198 | return l__s; \ 199 | } \ 200 | 201 | 202 | 203 | 204 | #endif 205 | -------------------------------------------------------------------------------- /DiscreteLog.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "DiscreteLog.h" 4 | 5 | 6 | /* Classes for discrete logarithm algorithms and square-root methods. 7 | * 8 | * Written by: Chris Studholme 9 | * Copyright: GPL (http://www.fsf.org/copyleft/gpl.html) 10 | */ 11 | 12 | NTL_START_IMPL; 13 | 14 | 15 | /**************** class DiscreteLog ****************/ 16 | 17 | ZZ_p_Group DiscreteLog::ZZ_p_group; 18 | 19 | ZZ DiscreteLog::log(const ZZ_p& power) { 20 | if (IsZero(power)) 21 | return to_ZZ(-1); 22 | ZZ_p_GE *p = new ZZ_p_GE(power); 23 | ZZ result; 24 | result = log(*p); 25 | delete p; 26 | return result; 27 | } 28 | 29 | bool DiscreteLog::verify(const GroupElement& power, const ZZ& log) const { 30 | GroupElement* b = group.newElementCopy(*base); 31 | b->power(log); 32 | bool result = (*b==power); 33 | delete b; 34 | return result; 35 | } 36 | 37 | bool DiscreteLog::verify(const ZZ_p& power, const ZZ& log) const { 38 | ZZ_p_GE *p = new ZZ_p_GE(power); 39 | bool result = verify(*p,log); 40 | delete p; 41 | return result; 42 | } 43 | 44 | 45 | /**************** class DLog_dumb ****************/ 46 | 47 | /* Approximate minimum number of loops per second expressed as a mask 48 | * to be used with & to do modulo arithmatic 49 | */ 50 | #define DLog_dumb_LOOPS_PER_SEC 0xff 51 | 52 | ZZ DLog_dumb::log(const GroupElement& power) { 53 | if (power.isIdentity()) 54 | return to_ZZ(0); 55 | if (power==*base) 56 | return to_ZZ(1); 57 | 58 | GroupElement* p = group.newElementCopy(*base); 59 | GroupElement* power_inv = group.newElementCopy(power); 60 | power_inv->invert(); 61 | 62 | long maxloop = group.size()isIdentity()) { 88 | delete p; 89 | std::cout<0)&&((exp&DLog_dumb_LOOPS_PER_SEC)==0)&&(clock()>end)) { 94 | delete p; 95 | std::cout<0)&&((count&DLog_dumb_LOOPS_PER_SEC)==0)&&(clock()>end)) { 163 | delete x1; 164 | delete x2; 165 | std::cout<maxloop) { 169 | // log doesn't exist 170 | delete x1; 171 | delete x2; 172 | std::cout<=0; --i) { 202 | const pair_ZZ_long& factor = factors[i]; 203 | ZZ d; 204 | NTL::power(d,factor.a,factor.b); 205 | ZZ s; 206 | s = size/d; 207 | GroupElement* bs = group.newElementCopy(*base); 208 | bs->power(s); 209 | GroupElement* pw = group.newElementCopy(power); 210 | pw->power(s); 211 | ZZ e; 212 | e = raw(*bs,*pw,d); 213 | delete pw; 214 | delete bs; 215 | if (e<0) 216 | return e; 217 | 218 | if (IsZero(p)) { 219 | a = e; 220 | p = d; 221 | } 222 | else { 223 | // Chinese Remainder Algorithm 224 | CRT(a,p,e,d); 225 | } 226 | } 227 | if (a<0) a+=p; 228 | return a; 229 | } 230 | 231 | 232 | NTL_END_IMPL; 233 | 234 | -------------------------------------------------------------------------------- /FactorBase.h: -------------------------------------------------------------------------------- 1 | #ifndef _FACTORBASE_H_ 2 | #define _FACTORBASE_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "vec_short.h" 9 | 10 | 11 | /* Class representing a factor base. 12 | * 13 | * Written by: Chris Studholme 14 | * Copyright: GPL (http://www.fsf.org/copyleft/gpl.html) 15 | */ 16 | 17 | NTL_OPEN_NNS; 18 | 19 | typedef Pair pair_long_long; 20 | typedef Vec vec_pair_long_long; 21 | 22 | inline void append(vec_pair_long_long& x, long a, long b) { 23 | append(x,cons(a,b)); 24 | } 25 | 26 | //void sieve1_times(); 27 | 28 | class FactorBase { 29 | private: 30 | long *primes; // array of primes starting with 2 31 | long aprimes; // allocated size of primes 32 | long nprimes; // number of primes 33 | long sprime; // least index such that: 34 | // primes[sprime] > sqrt(primes[nprimes-1]) 35 | 36 | public: 37 | 38 | /* Set to half L2 cache size to optimize sieve. Setting to 0 disables 39 | * cache optimization. 40 | */ 41 | static long CACHE_SIZE; 42 | 43 | /* Create empty factorbase. Call setBound() to create usable factorbase. 44 | */ 45 | FactorBase(); 46 | 47 | /* Create factorbase consisting of primes up to and including bound. 48 | */ 49 | FactorBase(long bound); 50 | 51 | ~FactorBase(); 52 | 53 | /* Create factorbase consisting of primes up to and including bound. 54 | */ 55 | void setBound(long bound); 56 | 57 | /* Sieve over polynomial (deterministic). The sieve is over the domain 58 | * [start,start+smooth.length()). Entries in smooth must be initialized 59 | * to zero for domain values you want checked and a non-zero value (such 60 | * as -1) for domain values you don't want checked. When sieve() completes, 61 | * entries in smooth with contain either: -1 for values that were not 62 | * checked, 1 for smooth domain elements, and the non-smooth part of the 63 | * absolute value of the image of the polynomial in cases where the image 64 | * is not smooth. In the case where f(a)=0, smooth[a-start]=0. 65 | */ 66 | void sieve(vec_ZZ& smooth, const ZZX& polynomial, const ZZ& start) const; 67 | 68 | /* Sieve over polynomial (probabilistic). The sieve is over the domain 69 | * [start,start+smooth.length()). Entries in smooth must be initialized 70 | * to zero for domain values you want checked and a negative value (such 71 | * as -1) for domain values you don't want checked. When sieve() completes, 72 | * entries in smooth with contain either: -1 for values that were not 73 | * checked, 1 for smooth images, and zero for non-smooth images. 74 | * In the case where f(a)=0, smooth[a-start]=0. 75 | * 76 | * New parameters: 77 | * rem_factor - maximum size of remaining factor (default 0) 78 | * bound_low - start sieve at this prime (default: 2) 79 | * bound_high - end sieve at this prime (default: fb bound) 80 | * exclude - pairs (p,r) where p prime and r mod p are domain values 81 | * to avoid 82 | */ 83 | void sieve(vec_short& smooth, const ZZX& f, const ZZ& start=ZZ::zero(), 84 | const ZZ& rem_factor=ZZ::zero(), 85 | long bound_low=0, long bound_high=0, 86 | const vec_pair_long_long& exclude=vec_pair_long_long()) const; 87 | 88 | 89 | /* Sieve over a two variable polynomial (probabilistic). 90 | */ 91 | //void sieve(vec_vec_long& smooth, const ZZX& f, 92 | // const ZZ& c_start=ZZ::zero(), const ZZ& d_start=ZZ::zero()) const; 93 | 94 | /* Reduce polynomial f by removing any smooth factor common to all 95 | * coefficients. Result is g. 96 | */ 97 | void reduce(ZZX& g, const ZZX& f) const; 98 | 99 | /* Factor n using trial division and return true if n is smooth. f is the 100 | * exponents in the factorization of n and is expected to be of size length. 101 | * In the case that n is smooth, rem is set to 1 and the method returns true. 102 | * If n is not smooth, then f contains the exponents of the smooth part of 103 | * n, rem contains the non-smooth factor, and the method returns false. 104 | */ 105 | bool factor(long* f, ZZ& rem, const ZZ& n) const; 106 | bool factor(long* f, long& rem, long n) const; 107 | 108 | /* Factor n using trial division and return true if n is smooth. f is the 109 | * exponents in the factorization of n and is expected to be of size length. 110 | * Returns true if n is smooth, false otherwise. 111 | */ 112 | inline bool factor(long* f, const ZZ& n) const { 113 | ZZ rem; 114 | return factor(f,rem,n); 115 | } 116 | inline bool factor(long* f, long n) const { 117 | long rem; 118 | return factor(f,rem,n); 119 | } 120 | 121 | // test if n is smooth using trial division 122 | bool isSmooth(const ZZ& n) const; 123 | 124 | // return true if p is a prime in this factorbase 125 | bool isPrime(long p) const; 126 | 127 | // returns largest prime in factorbase 128 | inline long bound() const { 129 | return primes[nprimes-1]; 130 | } 131 | 132 | // number of primes in array of primes 133 | inline long length() const { 134 | return nprimes; 135 | } 136 | 137 | // a prime in the factorbase 138 | inline long operator[](long i) const { 139 | return primes[i]; 140 | } 141 | 142 | // a prime in the factorbase 143 | inline long prime(long i) const { 144 | return primes[i]; 145 | } 146 | 147 | // find prime, returns -1 if not found 148 | inline long find(long p) const { 149 | for (long i=0; i 5 | #include 6 | 7 | NTL_OPEN_NNS; 8 | 9 | /* Group and GroupElement abstract interfaces to a general group. 10 | * GroupElement represents an individual element of a general group 11 | * and supports tests for identity and equality, transformation to 12 | * the inverse element, combination with another element via the group 13 | * operation, and repeated application (power) or the group operation. 14 | * 15 | * Also, there should be a one-to-one mapping from group elements to 16 | * the integers. This mapping should be such that it is possible to 17 | * parition the group elements into a number of similarly sized subsets. 18 | * n subsets can be computed by index() (mod n). 19 | * 20 | * Written by: Chris Studholme 21 | * Copyright: GPL (http://www.fsf.org/copyleft/gpl.html) 22 | */ 23 | class GroupElement { 24 | public: 25 | virtual ~GroupElement() {} 26 | 27 | // test if this element is the identity 28 | virtual bool isIdentity() const=0; 29 | 30 | // test two group elements for equality 31 | virtual bool operator==(const GroupElement& other) const=0; 32 | 33 | // test for inequality (default is not ==) 34 | inline bool operator!=(const GroupElement& other) const { 35 | return !(*this==other); 36 | } 37 | 38 | // multiply this group element by another 39 | virtual GroupElement& operator*=(const GroupElement& other)=0; 40 | 41 | // set this to this ^ exponent 42 | virtual void power(const ZZ& exponent)=0; 43 | 44 | // set this to this ^ exponent 45 | virtual void power(long exponent)=0; 46 | 47 | // invert this group element 48 | virtual void invert()=0; 49 | 50 | // completely arbitrary one-to-one mapping from G -> Z 51 | virtual ZZ index() const=0; 52 | 53 | // set this to group element associate with index 54 | virtual void set(const ZZ& index)=0; 55 | }; 56 | 57 | 58 | /* Group and GroupElement abstract interfaces to a general group. 59 | * Group provides methods necessary for dealing with an entire group. 60 | * Methods are available for creating a new identity element, copy of 61 | * some other group element, an element from an index, and a random 62 | * group element. Also, a read-only reference to an identity element 63 | * is provided along with the order of the group. This interface is 64 | * intended to be used with finite groups of known order. 65 | */ 66 | class Group { 67 | public: 68 | virtual ~Group() {} 69 | 70 | // create new group element that is identity 71 | virtual GroupElement* newElementIdentity()=0; 72 | 73 | // create new group element associated with index 74 | virtual GroupElement* newElementFromIndex(const ZZ& index)=0; 75 | 76 | // create new group element that is a copy of some other element 77 | virtual GroupElement* newElementCopy(const GroupElement& other)=0; 78 | 79 | // create new random group element 80 | virtual GroupElement* newElementRandom()=0; 81 | 82 | // number of elements in group 83 | virtual ZZ size()=0; 84 | }; 85 | 86 | 87 | /* ZZ_p_GE objects are congurency classes mod p (for p some prime). The 88 | * identity is 1 and the group operation is multiplication. 89 | */ 90 | class ZZ_p_GE : public GroupElement { 91 | private: 92 | ZZ_p value; 93 | 94 | public: 95 | ZZ_p_GE() { 96 | value=1; 97 | } 98 | ZZ_p_GE(const ZZ_p& v) { 99 | value=v; 100 | } 101 | ZZ_p_GE(const ZZ_p_GE& other) { 102 | value=other.value; 103 | } 104 | virtual ~ZZ_p_GE() { 105 | } 106 | 107 | // test if this element is the identity 108 | virtual bool isIdentity() const { 109 | return IsOne(value); 110 | } 111 | 112 | // test two group elements for equality 113 | virtual bool operator==(const GroupElement& other) const { 114 | return value==(*(ZZ_p_GE*)&other).value; 115 | } 116 | 117 | // multiply this group element by another 118 | virtual GroupElement& operator*=(const GroupElement& other) { 119 | value*=(*(ZZ_p_GE*)&other).value; 120 | return *this; 121 | } 122 | 123 | // set this to this ^ exponent 124 | virtual void power(const ZZ& exponent) { 125 | NTL::power(value,value,exponent); 126 | } 127 | 128 | // set this to this ^ exponent 129 | virtual void power(long exponent) { 130 | NTL::power(value,value,exponent); 131 | } 132 | 133 | // invert this group element 134 | virtual void invert() { 135 | value = inv(value); 136 | } 137 | 138 | // completely arbitrary one-to-one mapping from G -> Z 139 | virtual ZZ index() const { 140 | return rep(value); 141 | } 142 | 143 | // set this to group element associate with index 144 | virtual void set(const ZZ& index) { 145 | value = to_ZZ_p(index); 146 | } 147 | 148 | // make this a random group element 149 | virtual void makeRandom() { 150 | value = random_ZZ_p(); 151 | } 152 | }; 153 | 154 | 155 | /* ZZ_p_Group is the group of congruency classes mod p (p some prime) 156 | * combined with the multiplication operation and identity 1. The 157 | * order of the group is simply p-1. 158 | */ 159 | class ZZ_p_Group : public Group { 160 | public: 161 | ZZ_p_Group() { 162 | } 163 | virtual ~ZZ_p_Group() { 164 | } 165 | 166 | // create new group element that is identity 167 | virtual GroupElement* newElementIdentity() { 168 | return new ZZ_p_GE(); 169 | } 170 | 171 | // create new group element associated with index 172 | virtual GroupElement* newElementFromIndex(const ZZ& index) { 173 | return new ZZ_p_GE(to_ZZ_p(index)); 174 | } 175 | 176 | // create new group element that is a copy of some other element 177 | virtual GroupElement* newElementCopy(const GroupElement& other) { 178 | return new ZZ_p_GE(*(ZZ_p_GE*)&other); 179 | } 180 | 181 | // create new random group element 182 | virtual GroupElement* newElementRandom() { 183 | ZZ_p_GE* g = new ZZ_p_GE(); 184 | g->makeRandom(); 185 | return g; 186 | } 187 | 188 | // number of elements in group 189 | virtual ZZ size() { 190 | return ZZ_p::modulus()-1; 191 | } 192 | 193 | }; 194 | 195 | NTL_CLOSE_NNS; 196 | 197 | #endif 198 | -------------------------------------------------------------------------------- /DiscreteLog.h: -------------------------------------------------------------------------------- 1 | #ifndef _DISCRETELOG_H_ 2 | #define _DISCRETELOG_H_ 3 | 4 | #include 5 | #include 6 | #include "ZZFactoring.h" 7 | 8 | #include "Group.h" 9 | 10 | /* Classes for discrete logarithm algorithms. 11 | * 12 | * Written by: Chris Studholme 13 | * Copyright: GPL (http://www.fsf.org/copyleft/gpl.html) 14 | */ 15 | 16 | NTL_OPEN_NNS; 17 | 18 | /* Abstract interface to algorithms for finding the discrete log in 19 | * arbitrary groups and in the group ZZ_p. 20 | */ 21 | class DiscreteLog { 22 | protected: 23 | static ZZ_p_Group ZZ_p_group; 24 | Group& group; 25 | GroupElement* base; 26 | 27 | public: 28 | // set group to ZZ_p and leave base unset 29 | DiscreteLog() : group(ZZ_p_group) { 30 | base=NULL; 31 | } 32 | // set group to ZZ_p and set base 33 | DiscreteLog(const ZZ_p& base) : group(ZZ_p_group) { 34 | this->base = new ZZ_p_GE(base); 35 | } 36 | // set group to some general group and leave base unset 37 | DiscreteLog(Group& g) : group(g) { 38 | base=NULL; 39 | } 40 | // set group to some general group and set base 41 | DiscreteLog(Group& g, const GroupElement& base) : group(g) { 42 | this->base = group.newElementCopy(base); 43 | } 44 | virtual ~DiscreteLog() { 45 | if (base) 46 | delete base; 47 | } 48 | 49 | // set base to an element of a general group 50 | virtual void setBase(const GroupElement& base) { 51 | if (this->base) delete this->base; 52 | this->base = group.newElementCopy(base); 53 | } 54 | 55 | // set base to an element of ZZ_p 56 | virtual void setBase(const ZZ_p& base) { 57 | if (this->base) delete this->base; 58 | this->base = new ZZ_p_GE(base); 59 | } 60 | 61 | // find log of a power from a general group 62 | // returns -1 if the discrete log does not exist 63 | // may return -2 if some limit was exceeded before the log was found 64 | virtual ZZ log(const GroupElement& power)=0; 65 | 66 | // find log of a power from ZZ_p 67 | // returns -1 if the discrete log does not exist 68 | // may return -2 if some limit was exceeded before the log was found 69 | virtual ZZ log(const ZZ_p& power); 70 | 71 | // check discrete log calculation (returns true if all is ok) 72 | bool verify(const GroupElement& power, const ZZ& log) const; 73 | 74 | // check discrete log calculation (returns true if all is ok) 75 | bool verify(const ZZ_p& power, const ZZ& log) const; 76 | 77 | }; 78 | 79 | /* Dumb way to find discrete logarithms. Just start at exponent 1 and 80 | * loop through the powers of base one by one until the logarithm is 81 | * found. 82 | * 83 | * This method works with any general group. 84 | */ 85 | class DLog_dumb : public DiscreteLog { 86 | private: 87 | long limit; // run-time limit in seconds 88 | 89 | public: 90 | DLog_dumb() : DiscreteLog() { 91 | limit=0; 92 | } 93 | DLog_dumb(const ZZ_p& base) : DiscreteLog(base) { 94 | limit=0; 95 | } 96 | DLog_dumb(Group& g) : DiscreteLog(g) { 97 | limit=0; 98 | } 99 | DLog_dumb(Group& g, const GroupElement& base) : DiscreteLog(g,base) { 100 | limit=0; 101 | } 102 | DLog_dumb(long limit) : DiscreteLog() { 103 | this->limit=limit; 104 | } 105 | DLog_dumb(const ZZ_p& base, long limit) : DiscreteLog(base) { 106 | this->limit=limit; 107 | } 108 | DLog_dumb(Group& g, long limit) : DiscreteLog(g) { 109 | this->limit=limit; 110 | } 111 | DLog_dumb(Group& g, const GroupElement& base, long limit) 112 | : DiscreteLog(g,base) { 113 | this->limit=limit; 114 | } 115 | 116 | void setLimit(long limit) { 117 | this->limit=limit; 118 | } 119 | 120 | // returns -1 if the discrete log does not exist (or limit was reached) 121 | virtual ZZ log(const GroupElement& power); 122 | }; 123 | 124 | /* Use the Pollard Rho algorithm to find the discrete log in a general 125 | * group. The group order is factored (also using the Pollard Rho method), 126 | * then the discrete log is found modulo each factor and these logs are 127 | * combined using the Chinese Remainder Theorem. 128 | * 129 | * The run time (in seconds) of this algorithm can be limited, but its 130 | * measurement is per factor. 131 | */ 132 | class DLog_Pollard : public DiscreteLog { 133 | private: 134 | long limit; // run-time limit in seconds 135 | vec_pair_ZZ_long factors; 136 | 137 | public: 138 | DLog_Pollard() : DiscreteLog() { 139 | limit=0; 140 | factor(factors,group.size()); 141 | } 142 | DLog_Pollard(const ZZ_p& base) : DiscreteLog(base) { 143 | limit=0; 144 | factor(factors,group.size()); 145 | } 146 | DLog_Pollard(Group& g) : DiscreteLog(g) { 147 | limit=0; 148 | factor(factors,group.size()); 149 | } 150 | DLog_Pollard(Group& g, const GroupElement& base) : DiscreteLog(g,base) { 151 | limit=0; 152 | factor(factors,group.size()); 153 | } 154 | DLog_Pollard(long limit) : DiscreteLog() { 155 | this->limit=limit; 156 | factor(factors,group.size()); 157 | } 158 | DLog_Pollard(const ZZ_p& base, long limit) : DiscreteLog(base) { 159 | this->limit=limit; 160 | factor(factors,group.size()); 161 | } 162 | DLog_Pollard(Group& g, long limit) : DiscreteLog(g) { 163 | this->limit=limit; 164 | factor(factors,group.size()); 165 | } 166 | DLog_Pollard(Group& g, const GroupElement& base, long limit) 167 | : DiscreteLog(g,base) { 168 | this->limit=limit; 169 | factor(factors,group.size()); 170 | } 171 | ~DLog_Pollard() { 172 | } 173 | 174 | // Set run-time limit in seconds. Set to zero for no limit. 175 | void setLimit(long limit) { 176 | this->limit=limit; 177 | } 178 | 179 | // returns -1 if the discrete log does not exist 180 | virtual ZZ log(const GroupElement& power); 181 | 182 | private: 183 | // a single step of the algorithm 184 | static void step(GroupElement& x, ZZ& a, ZZ& b, 185 | const GroupElement& base, 186 | const GroupElement& power); 187 | 188 | // raw application of algorithm 189 | ZZ raw(const GroupElement& base, const GroupElement& power, 190 | const ZZ& size) const; 191 | 192 | }; 193 | 194 | NTL_CLOSE_NNS; 195 | 196 | #endif 197 | -------------------------------------------------------------------------------- /AlgebraicFactorBase.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | 6 | #include "AlgebraicFactorBase.h" 7 | 8 | //#define AFB_VERBOSE 9 | 10 | /* Class representing an algebraic factor base. 11 | * 12 | * Written by: Chris Studholme 13 | * Copyright: GPL (http://www.fsf.org/copyleft/gpl.html) 14 | */ 15 | 16 | NTL_START_IMPL; 17 | 18 | AlgebraicFactorBase::AlgebraicFactorBase(const ZZX& _f, long bound) { 19 | f = _f; 20 | zfb.setBound(bound); 21 | index.SetLength(zfb.length()); 22 | nprimes = 0; 23 | for (long i=0; i=0; --j) 38 | SetCoeff(fp,j,to_zz_p(coeff(f,j))); 39 | 40 | // factor fp 41 | vec_pair_zz_pX_long u; 42 | CanZass(u,fp); 43 | 44 | if ((u.length()==1)&&(u[0].b==1)) { 45 | #ifdef AFB_VERBOSE 46 | cout<<"AlgebraicFactorBase::primes_above() " 47 | <0) 99 | cout<<"; "<=0; --j) 190 | SetCoeff(fq,j,to_ZZ_p(coeff(f,j))); 191 | 192 | // factor fq 193 | vec_pair_ZZ_pX_long u; 194 | CanZass(u,fq); 195 | 196 | #ifdef AFB_VERBOSE 197 | cout<<"AFB::SetModulus() fq = "<1) { 204 | cerr<<"AFB::SetModulus() q is (partially) ramified\n"; 205 | clear(e); 206 | return; 207 | } 208 | ZZ p; 209 | power(p,q,deg(u[i].a)); 210 | --p; 211 | ZZ d; 212 | GCD(d,p,e); 213 | p/=d; 214 | e*=p; 215 | } 216 | 217 | #ifdef AFB_VERBOSE 218 | cout<<"AFB::SetModulus() e = "<>(istream&, smat_T&); 152 | ostream& operator<<(ostream&, const smat_T&); 153 | 154 | 155 | 156 | /**************************************************************************\ 157 | 158 | Equality Testing 159 | 160 | The equality testing operators == and != can be declared 161 | NTL_eq_smatrix_decl(T,svec_T,vec_svec_T,smat_T), and 162 | implemented using NTL_eq_smatrix_impl(T,svec_T,vec_svec_T,smat_T). 163 | Equality testing is implemented using the underlying 164 | equality operators for vec_svec_T. 165 | 166 | \**************************************************************************/ 167 | 168 | long operator==(const smat_T& a, const smat_T& b); 169 | long operator!=(const smat_T& a, const smat_T& b); 170 | 171 | 172 | -------------------------------------------------------------------------------- /DLog_IC_Base.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "DLog_IC_Base.h" 5 | 6 | 7 | /* Base class for index calculus like algorithms and the classic index 8 | * calculus technique. 9 | * 10 | * Written by: Chris Studholme 11 | * Copyright: GPL (http://www.fsf.org/copyleft/gpl.html) 12 | */ 13 | 14 | NTL_START_IMPL; 15 | 16 | #define IC_INITIAL_CACHE_SIZE 16 17 | 18 | // sieve beyond relations needed (complete sieving) to ensure 19 | // proper optimization 20 | //#define IC_EXTRA_SIEVING 21 | 22 | 23 | /**************** class DLog_IC_Base ****************/ 24 | 25 | long DLog_IC_Base::VERBOSE=0; /* verbosity level */ 26 | 27 | 28 | // test if g is a generator of the field ZZ_p 29 | // f is the factorization of p-1 30 | bool DLog_IC_Base::isGenerator(const ZZ_p& g, 31 | const vec_pair_ZZ_long& f) { 32 | ZZ m,e; 33 | ZZ_p t; 34 | sub(m,ZZ_p::modulus(),1); 35 | for (long i=0; i=acache) { 75 | // reallocate cache 76 | acache = (acache==0 ? IC_INITIAL_CACHE_SIZE : 2*acache); 77 | ZZ* new_prime = new ZZ[acache]; 78 | ZZ* new_log = new ZZ[acache]; 79 | for (long i=0; ilow) { 92 | long mid = (low+high)/2; 93 | if (cache_prime[mid]low; --i) { 105 | cache_prime[i] = cache_prime[i-1]; 106 | cache_log[i] = cache_log[i-1]; 107 | } 108 | // set new entry 109 | cache_prime[low] = prime; 110 | cache_log[low] = log; 111 | ++ncache; 112 | } 113 | 114 | // lookup log_g(prime) in cache 115 | ZZ DLog_IC_Base::log_cache(const ZZ& prime) { 116 | if (ncache==0) 117 | return ZZ::zero(); 118 | // binary search to find prime 119 | long low=0; 120 | long high=ncache; 121 | while (high>low) { 122 | long mid = (low+high)/2; 123 | if (cache_prime[mid]=0)&&(fi>=0)) { 148 | pf = factors[fi].a; 149 | while ((ci>=0)&&(cache_prime[ci]>pf)) 150 | --ci; 151 | if ((ci<0)||(cache_prime[ci]!=pf)) 152 | break; 153 | --ci; 154 | --fi; 155 | } 156 | // if it's small enough, we can move on 157 | if (pf<=upper_bound) 158 | break; 159 | sm *= g; 160 | --result; 161 | 162 | if ((VERBOSE)&&(result<-1000)) { 163 | std::cout<<"DLog_IC_Base::log_g() searching... ("<<(-result)<<") \r"<=0; --i) { 174 | ZZ l; 175 | l = log_cache(factors[i].a); 176 | if (IsZero(l)) { 177 | if (cacheonly) 178 | return ZZ::zero(); 179 | l = log_prime(factors[i].a); 180 | if (IsZero(l)) 181 | return ZZ::zero(); 182 | add_cache(factors[i].a,l); 183 | } 184 | l*=factors[i].b; 185 | result += l; 186 | } 187 | 188 | // normalize result 189 | rem(result,result,ZZ_p::modulus()-1); 190 | return result; 191 | } 192 | 193 | // log of any power relative to base 194 | ZZ DLog_IC_Base::log(const ZZ_p& pw) { 195 | if (IsZero(pw)) { 196 | std::cerr<<"DLog_IC_Base::log() log of 0 requested"<=0; --i) \ 155 | clear(a[i]); \ 156 | } \ 157 | \ 158 | long IsZero(const smat_T& a) { \ 159 | for (long i=a.NumRows()-1; i>=0; --i) \ 160 | if (!IsZero(a[i])) \ 161 | return 0; \ 162 | return 1; \ 163 | } \ 164 | \ 165 | void transpose(smat_T& dest, const smat_T& src) { \ 166 | dest.SetDims(src.NumCols(),src.NumRows()); \ 167 | clear(dest); \ 168 | for (long i=0; i0) { \ 316 | OutputVector(out,a[0]); \ 317 | for (long i=1; i v; 12 | 13 | creates a zero-length vector. To grow this vector to length n, execute 14 | 15 | v.SetLength(n) 16 | 17 | Note that this call does not allocate any space for the elements. Instead, 18 | elements are allocated as they are set. Since this vector is intended to be 19 | used for sparse vectors, the number of elements allocated in the vector should 20 | be much less than the length. As elements get allocated, the default 21 | constructor for T is called to initialize the elements. 22 | 23 | The current length of a vector is available as v.length(). 24 | 25 | The i-th vector element (counting from 0) is accessed as v[i]. If the 26 | macro NTL_RANGE_CHECK is defined, code is emitted to test if 0 <= i < 27 | v.length(). This check is not performed by default. 28 | 29 | For old-time FORTRAN programmers, the i-th vector element (counting 30 | from 1) is accessed as v(i). 31 | 32 | If v is const and a "zero" element is accessed (an element for which storage 33 | has not been allocated), then a reference to a static const "zero" element is 34 | returned. To provide this reference, one must also declare somewhere 35 | 36 | template<> const T& zero_ref() { return ...; } 37 | 38 | If v is not const and an element that has not been allocated is accessed, 39 | space is allocated for the element and initialized to zero using clear(). 40 | Because of this automatic allocation of elements, care must be taken when 41 | iterating through the elements of the vector. The most efficient method 42 | for iterating through the elements is to make use of the methods nvalues(), 43 | indices(), and values(). Alternatively, cast v to const before attempting 44 | to read all of the elements of the vector. 45 | 46 | Let n = v.length(). Calling v.SetLength(m) with m <= n sets the 47 | current length of v to m but does not call any destructors or free 48 | any space. As discussed above, calling v.SetLength(m) with m > n does not 49 | allocate any new space or change any existing elements. Space is allocated 50 | strictly as needed. 51 | 52 | v.MaxLength() is the largest value of n for which v.SetLength(n) was invoked. 53 | v.SetMaxLength(n) only changes MaxLength if n is greater than the previous 54 | value of MaxLength. MaxLength is not of much use in svector. It is provided 55 | simply for compatibility with (non-sparse) vectors. 56 | 57 | When v's destructor is called, all constructed elements will be destructed, 58 | and all space will be relinquished. 59 | 60 | Space for storing elements is allocated by the underlying (non-sparse) vector 61 | class. See the vector module for details regarding space management. 62 | 63 | Note that when new space is required to store the non-zero elements, the space 64 | is reallocated using realloc, and thus the addresses of vector elements may 65 | change, possibly creating dangling references to vector elements. This 66 | behaviour is also an issue with the (non-sparse) vector classes; however, 67 | since new space may be allocated when elements of the sparse vector are simply 68 | referenced (as opposed to when SetLength() is called), extra care must be 69 | taken when passing references to vector elements around. 70 | 71 | v.allocated() is the number of elements which have been allocated, which 72 | indicates an upper bound on the number of non-zero elements in the vector. 73 | The method v.SetAlloc(n) may be used to force allocation for up to n elements 74 | in advance of setting values. 75 | 76 | If the type T supports standard arithmetic operations such as add(x,a,b), 77 | sub(x,a,b), mul(x,a,b), negate(x,a), and the operators +, -, and * (as most 78 | NTL types do) then many standard math function can be declared using 79 | NTL_math_svector_decl(T,vec_T,svec_T) and implemented with 80 | NTL_math_svector_impl(T,vec_T,svec_T). 81 | 82 | 83 | 84 | \**************************************************************************/ 85 | 86 | template 87 | class SVec { 88 | public: 89 | 90 | /* Default constructor. Initial length is zero and no memory 91 | * is allocated. */ 92 | SVec(); 93 | 94 | /* Copy constructor. Allocates exactly the right amount of memory 95 | * to hold the contents of other and uses T's assignment operator to 96 | * do the copying. If compact then zero values in other are not copied. 97 | * The "fixed" status of other is not copied. */ 98 | SVec(const SVec& other, bool compact = false); 99 | 100 | /* Assignment. Performs an element-wise assignment using T's assignment 101 | * operator. If this is "fixed", other must have the same length as 102 | * this. */ 103 | SVec& operator=(const SVec& other); 104 | 105 | /* Initialize with a specific length and allocation. If alloc is zero then 106 | * no memory is allocated until needed (and then the default allocation is 107 | * made). */ 108 | SVec(INIT_SIZE_TYPE, long length, long alloc = 0); 109 | 110 | /* Destructor. Free all allocated memory. */ 111 | ~SVec(); 112 | 113 | /* Release all allocated space and set to length 0. */ 114 | void kill(); 115 | 116 | /* Ensure enough memory is allocated for n non-zero entries. */ 117 | void SetAlloc(long n); 118 | 119 | /* Set maximum length to n. Does not allocate memory and does not change 120 | * the current length. Here for compatibility with non-sparse vector 121 | * classes. */ 122 | void SetMaxLength(long n); 123 | 124 | /* Sets length to n and prohibits all future length changes. 125 | * FixLength may only be invoked immediately after the default 126 | * construction or kill. 127 | * 128 | * The kill operation is also subsequently prohibited, and swap is 129 | * allowed on fixed length vectors of the same length. 130 | * 131 | * FixLength is provided mainly to implement smat_T, to enforce 132 | * the restriction that all rows have the same length. */ 133 | void FixLength(long n); 134 | 135 | /* Set current length to n. If the length is being set smaller than it was, 136 | * values at the end of the vector may disappear. If n is being set larger, 137 | * existing values are not changed. */ 138 | void SetLength(long n); 139 | 140 | /* Current length. */ 141 | long length() const; 142 | 143 | /* Has this vector been fixed? */ 144 | bool fixed() const; 145 | 146 | /* Maximum length ever achieved. Here for compatibility with non-sparse 147 | * vector classes. */ 148 | long MaxLength() const; 149 | 150 | /* The number of objects for which space has been allocated but not 151 | * necessarily initialized. */ 152 | long allocated() const; 153 | 154 | /* Indexing operation, starting from 0. This version returns a non-const 155 | * reference to a T and will allocate memory for the vector element as 156 | * needed. If you are just reading vector elements and you want to make 157 | * sure you maintain the sparsity of the vector, use the const version 158 | * instead. */ 159 | T& operator[](long i); 160 | 161 | /* Indexing operation, starting from 0. This version can be used with a 162 | * const object and returns a const reference to a T. No memory will be 163 | * allocated. If the i'th vector element is not allocated, a const 164 | * reference to zero will be returned. */ 165 | const T& operator[](long i) const; 166 | 167 | /* Indexing operation, starting from 1. See operator[] for details. */ 168 | T& operator()(long i); 169 | 170 | /* Indexing operation, starting from 1. See operator[] for details. */ 171 | const T& operator()(long i) const; 172 | 173 | /* Direct access to arrays, use with care. */ 174 | long nvalues() const; 175 | const long* indices() const; 176 | T* values(); 177 | const T* values() const; 178 | 179 | /* Indexing with no range checking. See operator[] for details. */ 180 | T& RawGet(long i); 181 | const T& RawGet(long i) const; 182 | 183 | /* Returns position of a in the vector, or -1 if it is not there. 184 | * The search is conducted from position 0 to MaxAlloc()-1 of the vector, 185 | * and an error is raised if the object is found at position MaxLength() 186 | * or higher (in which case a references an uninitialized object). 187 | * Note that if NTL_CLEAN_PTR flag is set, this routine takes 188 | * linear time, and otherwise, it takes constant time. */ 189 | long position(const T& a) const; 190 | 191 | /* Returns position of a in the vector, or -1 if it is not there. 192 | * The search is conducted from position 0 to length()-1 of the vector. 193 | * Note that if NTL_CLEAN_PTR flag is set, this routine takes 194 | * linear time, and otherwise, it takes constant time. */ 195 | long position1(const T& a) const; 196 | 197 | /* Eliminate zero values from vector to speed up read-only access. */ 198 | void compact(); 199 | 200 | /* Set all elements to zero. Does not change length or release any 201 | * memory. */ 202 | void clear(); 203 | 204 | /* Swaps this and other by swapping internal pointers. If either this or 205 | * other is fixed, then both must be have the same length. The "fixed" 206 | * status of the vectors is not swapped. */ 207 | void swap(SVec& other); 208 | }; 209 | 210 | 211 | 212 | /**************************************************************************\ 213 | 214 | Some utility routines 215 | 216 | \**************************************************************************/ 217 | 218 | // test if x is the zero vector 219 | long IsZero(const SVec& x); 220 | 221 | // make x the zero vector (without changing its length) 222 | void clear(SVec& x); 223 | 224 | // swap x and y by swapping pointers 225 | void swap(SVec& x, SVec& y); 226 | 227 | // convert between Vec and SVec 228 | void conv(SVec& dest, const Vec& src); 229 | void conv(Vec& dest, const SVec& src); 230 | 231 | // create copy of a with length exactly n (input is truncated or padded 232 | // with zeros as necessary) 233 | void VectorCopy(SVec& x, const SVec& a, long n); 234 | 235 | // create copy of a with length exactly n (input is truncated or padded 236 | // with zeros as necessary) 237 | SVec VectorCopy(const SVec& a, long n); 238 | 239 | 240 | 241 | /**************************************************************************\ 242 | 243 | Equality Testing 244 | 245 | The tests are performed using the underlying operator == for T. 246 | 247 | \**************************************************************************/ 248 | 249 | long operator==(const SVec& a, const SVec& b); 250 | long operator!=(const SVec& a, const SVec& b); 251 | 252 | 253 | 254 | /**************************************************************************\ 255 | 256 | Input/Output 257 | 258 | Elements are written and read using the underlying I/O operators << and >> 259 | for T. 260 | 261 | The I/O format for a sparse vector v with length n is: 262 | 263 | 264 | 265 | where the i's are indices and the v's are (non-zero) values. The i's are in 266 | order and 0 <= i < n. 267 | 268 | The method OutputVector() will write out the sparse vector as a dense vector 269 | compatible with Vec. 270 | 271 | [v[0] v[1] ... v[n-1]] 272 | 273 | This will waste storage if the vector is really sparse, but can be read back 274 | as a dense vector. 275 | 276 | The input method will read either format. 277 | 278 | \**************************************************************************/ 279 | 280 | istream& operator>>(istream&, SVec&); 281 | ostream& operator<<(ostream&, const SVec&); 282 | ostream& OutputVector(ostream&, const SVec&); 283 | 284 | 285 | 286 | /************************************************************************** \ 287 | 288 | Arithmetic 289 | 290 | The arithmetic functions and operators can be declared with 291 | NTL_math_svector_decl(T,vec_T,svec_T) and implemented with 292 | NTL_math_svector_impl(T,vec_T,svec_T). 293 | 294 | These methods require add(x,a,b), sub(x,a,b), mul(x,a,b), negate(x,a), 295 | and the +, -, * operators for the underlying type T. 296 | 297 | \**************************************************************************/ 298 | 299 | void mul(svec_T& x, const svec_T& a, const T& b); 300 | void mul(svec_T& x, const T& a, const svec_T& b); 301 | 302 | void add(svec_T& x, const svec_T& a, const svec_T& b); 303 | void sub(svec_T& x, const svec_T& a, const svec_T& b); 304 | void negate(svec_T& x, const svec_T& a); 305 | 306 | void InnerProduct(T& x, const svec_T& a, const svec_T& b); 307 | 308 | svec_T operator+(const svec_T& a, const svec_T& b); 309 | svec_T operator-(const svec_T& a, const svec_T& b); 310 | svec_T operator-(const svec_T& a); 311 | 312 | svec_T operator*(const svec_T& a, const T& b); 313 | svec_T operator*(const T& a, const svec_T& b); 314 | 315 | T operator*(const svec_T& a, const svec_T& b); 316 | 317 | svec_T& operator+=(svec_T& x, const svec_T& a); 318 | svec_T& operator-=(svec_T& x, const svec_T& a); 319 | 320 | 321 | /* mixed vector/svector math methods */ 322 | 323 | void mul(vec_T& x, const svec_T& a, const T& b); 324 | void mul(vec_T& x, const T& a, const svec_T& b); 325 | 326 | void add(vec_T& x, const vec_T& a, const svec_T& b); 327 | void add(vec_T& x, const svec_T& a, const vec_T& b); 328 | void sub(vec_T& x, const vec_T& a, const svec_T& b); 329 | void sub(vec_T& x, const svec_T& a, const vec_T& b); 330 | void negate(vec_T& x, const svec_T& a); 331 | 332 | void InnerProduct(T& x, const vec_T& a, const svec_T& b); 333 | void InnerProduct(T& x, const svec_T& a, const vec_T& b); 334 | 335 | vec_T operator+(const vec_T& a, const svec_T& b); 336 | vec_T operator+(const svec_T& a, const vec_T& b); 337 | vec_T operator-(const vec_T& a, const svec_T& b); 338 | vec_T operator-(const svec_T& a, const vec_T& b); 339 | 340 | T operator*(const vec_T& a, const svec_T& b); 341 | T operator*(const svec_T& a, const vec_T& b); 342 | 343 | vec_T& operator+=(vec_T& x, const svec_T& a); 344 | vec_T& operator-=(vec_T& x, const svec_T& a); 345 | 346 | 347 | 348 | 349 | 350 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 5 | 59 Temple Place, Suite 330 6 | Boston, MA 02111-1307 USA 7 | Everyone is permitted to copy and distribute verbatim copies 8 | of this license document, but changing it is not allowed. 9 | 10 | Preamble 11 | 12 | The licenses for most software are designed to take away your 13 | freedom to share and change it. By contrast, the GNU General Public 14 | License is intended to guarantee your freedom to share and change free 15 | software--to make sure the software is free for all its users. This 16 | General Public License applies to most of the Free Software 17 | Foundation's software and to any other program whose authors commit to 18 | using it. (Some other Free Software Foundation software is covered by 19 | the GNU Library General Public License instead.) You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | this service if you wish), that you receive source code or can get it 26 | if you want it, that you can change the software or use pieces of it 27 | in new free programs; and that you know you can do these things. 28 | 29 | To protect your rights, we need to make restrictions that forbid 30 | anyone to deny you these rights or to ask you to surrender the rights. 31 | These restrictions translate to certain responsibilities for you if you 32 | distribute copies of the software, or if you modify it. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must give the recipients all the rights that 36 | you have. You must make sure that they, too, receive or can get the 37 | source code. And you must show them these terms so they know their 38 | rights. 39 | 40 | We protect your rights with two steps: (1) copyright the software, and 41 | (2) offer you this license which gives you legal permission to copy, 42 | distribute and/or modify the software. 43 | 44 | Also, for each author's protection and ours, we want to make certain 45 | that everyone understands that there is no warranty for this free 46 | software. If the software is modified by someone else and passed on, we 47 | want its recipients to know that what they have is not the original, so 48 | that any problems introduced by others will not reflect on the original 49 | authors' reputations. 50 | 51 | Finally, any free program is threatened constantly by software 52 | patents. We wish to avoid the danger that redistributors of a free 53 | program will individually obtain patent licenses, in effect making the 54 | program proprietary. To prevent this, we have made it clear that any 55 | patent must be licensed for everyone's free use or not licensed at all. 56 | 57 | The precise terms and conditions for copying, distribution and 58 | modification follow. 59 | 60 | 61 | GNU GENERAL PUBLIC LICENSE 62 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 63 | 64 | 0. This License applies to any program or other work which contains 65 | a notice placed by the copyright holder saying it may be distributed 66 | under the terms of this General Public License. The "Program", below, 67 | refers to any such program or work, and a "work based on the Program" 68 | means either the Program or any derivative work under copyright law: 69 | that is to say, a work containing the Program or a portion of it, 70 | either verbatim or with modifications and/or translated into another 71 | language. (Hereinafter, translation is included without limitation in 72 | the term "modification".) Each licensee is addressed as "you". 73 | 74 | Activities other than copying, distribution and modification are not 75 | covered by this License; they are outside its scope. The act of 76 | running the Program is not restricted, and the output from the Program 77 | is covered only if its contents constitute a work based on the 78 | Program (independent of having been made by running the Program). 79 | Whether that is true depends on what the Program does. 80 | 81 | 1. You may copy and distribute verbatim copies of the Program's 82 | source code as you receive it, in any medium, provided that you 83 | conspicuously and appropriately publish on each copy an appropriate 84 | copyright notice and disclaimer of warranty; keep intact all the 85 | notices that refer to this License and to the absence of any warranty; 86 | and give any other recipients of the Program a copy of this License 87 | along with the Program. 88 | 89 | You may charge a fee for the physical act of transferring a copy, and 90 | you may at your option offer warranty protection in exchange for a fee. 91 | 92 | 2. You may modify your copy or copies of the Program or any portion 93 | of it, thus forming a work based on the Program, and copy and 94 | distribute such modifications or work under the terms of Section 1 95 | above, provided that you also meet all of these conditions: 96 | 97 | a) You must cause the modified files to carry prominent notices 98 | stating that you changed the files and the date of any change. 99 | 100 | b) You must cause any work that you distribute or publish, that in 101 | whole or in part contains or is derived from the Program or any 102 | part thereof, to be licensed as a whole at no charge to all third 103 | parties under the terms of this License. 104 | 105 | c) If the modified program normally reads commands interactively 106 | when run, you must cause it, when started running for such 107 | interactive use in the most ordinary way, to print or display an 108 | announcement including an appropriate copyright notice and a 109 | notice that there is no warranty (or else, saying that you provide 110 | a warranty) and that users may redistribute the program under 111 | these conditions, and telling the user how to view a copy of this 112 | License. (Exception: if the Program itself is interactive but 113 | does not normally print such an announcement, your work based on 114 | the Program is not required to print an announcement.) 115 | 116 | These requirements apply to the modified work as a whole. If 117 | identifiable sections of that work are not derived from the Program, 118 | and can be reasonably considered independent and separate works in 119 | themselves, then this License, and its terms, do not apply to those 120 | sections when you distribute them as separate works. But when you 121 | distribute the same sections as part of a whole which is a work based 122 | on the Program, the distribution of the whole must be on the terms of 123 | this License, whose permissions for other licensees extend to the 124 | entire whole, and thus to each and every part regardless of who wrote it. 125 | 126 | Thus, it is not the intent of this section to claim rights or contest 127 | your rights to work written entirely by you; rather, the intent is to 128 | exercise the right to control the distribution of derivative or 129 | collective works based on the Program. 130 | 131 | In addition, mere aggregation of another work not based on the Program 132 | with the Program (or with a work based on the Program) on a volume of 133 | a storage or distribution medium does not bring the other work under 134 | the scope of this License. 135 | 136 | 3. You may copy and distribute the Program (or a work based on it, 137 | under Section 2) in object code or executable form under the terms of 138 | Sections 1 and 2 above provided that you also do one of the following: 139 | 140 | a) Accompany it with the complete corresponding machine-readable 141 | source code, which must be distributed under the terms of Sections 142 | 1 and 2 above on a medium customarily used for software interchange; or, 143 | 144 | b) Accompany it with a written offer, valid for at least three 145 | years, to give any third party, for a charge no more than your 146 | cost of physically performing source distribution, a complete 147 | machine-readable copy of the corresponding source code, to be 148 | distributed under the terms of Sections 1 and 2 above on a medium 149 | customarily used for software interchange; or, 150 | 151 | c) Accompany it with the information you received as to the offer 152 | to distribute corresponding source code. (This alternative is 153 | allowed only for noncommercial distribution and only if you 154 | received the program in object code or executable form with such 155 | an offer, in accord with Subsection b above.) 156 | 157 | The source code for a work means the preferred form of the work for 158 | making modifications to it. For an executable work, complete source 159 | code means all the source code for all modules it contains, plus any 160 | associated interface definition files, plus the scripts used to 161 | control compilation and installation of the executable. However, as a 162 | special exception, the source code distributed need not include 163 | anything that is normally distributed (in either source or binary 164 | form) with the major components (compiler, kernel, and so on) of the 165 | operating system on which the executable runs, unless that component 166 | itself accompanies the executable. 167 | 168 | If distribution of executable or object code is made by offering 169 | access to copy from a designated place, then offering equivalent 170 | access to copy the source code from the same place counts as 171 | distribution of the source code, even though third parties are not 172 | compelled to copy the source along with the object code. 173 | 174 | 4. You may not copy, modify, sublicense, or distribute the Program 175 | except as expressly provided under this License. Any attempt 176 | otherwise to copy, modify, sublicense or distribute the Program is 177 | void, and will automatically terminate your rights under this License. 178 | However, parties who have received copies, or rights, from you under 179 | this License will not have their licenses terminated so long as such 180 | parties remain in full compliance. 181 | 182 | 5. You are not required to accept this License, since you have not 183 | signed it. However, nothing else grants you permission to modify or 184 | distribute the Program or its derivative works. These actions are 185 | prohibited by law if you do not accept this License. Therefore, by 186 | modifying or distributing the Program (or any work based on the 187 | Program), you indicate your acceptance of this License to do so, and 188 | all its terms and conditions for copying, distributing or modifying 189 | the Program or works based on it. 190 | 191 | 6. Each time you redistribute the Program (or any work based on the 192 | Program), the recipient automatically receives a license from the 193 | original licensor to copy, distribute or modify the Program subject to 194 | these terms and conditions. You may not impose any further 195 | restrictions on the recipients' exercise of the rights granted herein. 196 | You are not responsible for enforcing compliance by third parties to 197 | this License. 198 | 199 | 7. If, as a consequence of a court judgment or allegation of patent 200 | infringement or for any other reason (not limited to patent issues), 201 | conditions are imposed on you (whether by court order, agreement or 202 | otherwise) that contradict the conditions of this License, they do not 203 | excuse you from the conditions of this License. If you cannot 204 | distribute so as to satisfy simultaneously your obligations under this 205 | License and any other pertinent obligations, then as a consequence you 206 | may not distribute the Program at all. For example, if a patent 207 | license would not permit royalty-free redistribution of the Program by 208 | all those who receive copies directly or indirectly through you, then 209 | the only way you could satisfy both it and this License would be to 210 | refrain entirely from distribution of the Program. 211 | 212 | If any portion of this section is held invalid or unenforceable under 213 | any particular circumstance, the balance of the section is intended to 214 | apply and the section as a whole is intended to apply in other 215 | circumstances. 216 | 217 | It is not the purpose of this section to induce you to infringe any 218 | patents or other property right claims or to contest validity of any 219 | such claims; this section has the sole purpose of protecting the 220 | integrity of the free software distribution system, which is 221 | implemented by public license practices. Many people have made 222 | generous contributions to the wide range of software distributed 223 | through that system in reliance on consistent application of that 224 | system; it is up to the author/donor to decide if he or she is willing 225 | to distribute software through any other system and a licensee cannot 226 | impose that choice. 227 | 228 | This section is intended to make thoroughly clear what is believed to 229 | be a consequence of the rest of this License. 230 | 231 | 8. If the distribution and/or use of the Program is restricted in 232 | certain countries either by patents or by copyrighted interfaces, the 233 | original copyright holder who places the Program under this License 234 | may add an explicit geographical distribution limitation excluding 235 | those countries, so that distribution is permitted only in or among 236 | countries not thus excluded. In such case, this License incorporates 237 | the limitation as if written in the body of this License. 238 | 239 | 9. The Free Software Foundation may publish revised and/or new versions 240 | of the General Public License from time to time. Such new versions will 241 | be similar in spirit to the present version, but may differ in detail to 242 | address new problems or concerns. 243 | 244 | Each version is given a distinguishing version number. If the Program 245 | specifies a version number of this License which applies to it and "any 246 | later version", you have the option of following the terms and conditions 247 | either of that version or of any later version published by the Free 248 | Software Foundation. If the Program does not specify a version number of 249 | this License, you may choose any version ever published by the Free Software 250 | Foundation. 251 | 252 | 10. If you wish to incorporate parts of the Program into other free 253 | programs whose distribution conditions are different, write to the author 254 | to ask for permission. For software which is copyrighted by the Free 255 | Software Foundation, write to the Free Software Foundation; we sometimes 256 | make exceptions for this. Our decision will be guided by the two goals 257 | of preserving the free status of all derivatives of our free software and 258 | of promoting the sharing and reuse of software generally. 259 | 260 | NO WARRANTY 261 | 262 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 263 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 264 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 265 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 266 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 267 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 268 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 269 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 270 | REPAIR OR CORRECTION. 271 | 272 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 273 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 274 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 275 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 276 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 277 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 278 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 279 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 280 | POSSIBILITY OF SUCH DAMAGES. 281 | 282 | END OF TERMS AND CONDITIONS 283 | -------------------------------------------------------------------------------- /SGauss.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include "svec_long.h" 4 | 5 | #include 6 | #include "smat_long.h" 7 | #include "smat_ZZ.h" 8 | 9 | 10 | /* Implementation of structured gaussian elimination. 11 | * 12 | * Written by: Chris Studholme 13 | * Copyright: GPL (http://www.fsf.org/copyleft/gpl.html) 14 | */ 15 | 16 | NTL_START_IMPL; 17 | 18 | static const bool SGAUSS_VERBOSE = false; 19 | 20 | inline const ZZ_p& operator/=(ZZ_p& a, const NTL::ZZ& b) { 21 | a /= to_ZZ_p(b); 22 | return a; 23 | } 24 | inline ZZ_p operator*(const ZZ& a, const ZZ_p& b) { 25 | return to_ZZ_p(a)*b; 26 | } 27 | inline ZZ_p operator/(const ZZ_p& a, const ZZ& b) { 28 | return a/to_ZZ_p(b); 29 | } 30 | 31 | 32 | // inner product (svec_long and svec_ZZ_p) 33 | template 34 | inline void InnerProduct(ZZ_p& result, const svec_T& a, const vec_T& b) { 35 | if (a.length()!=b.length()) { 36 | std::cerr<<"InnerProduct() length mismatch"< 49 | void nonzero(svec_long& x, const svec_T& y) { 50 | x.SetLength(y.length()); 51 | x.SetAlloc(y.nvalues()); 52 | clear(x); 53 | const long* yi = y.indices(); 54 | const typename svec_T::value_type* yv = y.values(); 55 | for (long j=0; j=0) { 103 | if (i>=npos*BITS_PER_LONG) { 104 | long new_size = (i/BITS_PER_LONG)+1; 105 | pos = (unsigned long*)realloc(pos,new_size*sizeof(unsigned long)); 106 | memset(pos+npos,0,(new_size-npos)*sizeof(unsigned long)); 107 | npos = new_size; 108 | } 109 | pos[i/BITS_PER_LONG] |= 1<<(i%BITS_PER_LONG); 110 | } 111 | else { 112 | i = -(i+1); 113 | if (i>=nneg*BITS_PER_LONG) { 114 | long new_size = (i/BITS_PER_LONG)+1; 115 | neg = (unsigned long*)realloc(neg,new_size*sizeof(unsigned long)); 116 | memset(neg+nneg,0,(new_size-nneg)*sizeof(unsigned long)); 117 | nneg = new_size; 118 | } 119 | neg[i/BITS_PER_LONG] |= 1<<(i%BITS_PER_LONG); 120 | } 121 | } 122 | 123 | bool set_long::contains(long i) const { 124 | if (i>=0) { 125 | if (i>(i%BITS_PER_LONG))&1; 127 | } 128 | else { 129 | i = -(i+1); 130 | if (i>(i%BITS_PER_LONG))&1; 132 | } 133 | return false; 134 | } 135 | 136 | 137 | /**************** structured gaussian elimination ****************/ 138 | 139 | template 140 | class smat_gauss { 141 | public: 142 | 143 | // types 144 | //typedef smat_T smat_t; 145 | //typedef svec_T svec_t; 146 | typedef typename svec_T::value_type value_t; 147 | 148 | // matrix and column representing system A * x = y 149 | smat_gauss(const smat_T& A, const vec_Tp& y); 150 | ~smat_gauss(); 151 | 152 | inline long NumRows() const { 153 | return nrows; 154 | } 155 | inline long NumCols() const { 156 | return A.NumCols()-first_col; 157 | } 158 | 159 | inline const svec_T& row(long i) const { 160 | return i>=0 ? A[i] : E[-i-1]; 161 | } 162 | 163 | inline Tp& y(long i) { 164 | return i>=0 ? Ay[i] : Ey[-i-1]; 165 | } 166 | 167 | inline long row_weight(long i) const { 168 | return i>=0 ? Arw[i] : Erw[-i-1]; 169 | } 170 | 171 | inline void set_row_weight(long i, long w=0) { 172 | if (i>=0) Arw[i]=w; else Erw[-i-1]=w; 173 | } 174 | 175 | // bubble sort AEcs to ensure column c is correctly positioned 176 | // note: this method doesn't handle the case where AEcw[c] increased 177 | void resort(long c); 178 | 179 | // eliminate column with weight 1 180 | void eliminate_col1(long c); 181 | 182 | // eliminate column with weight 2 183 | void eliminate_col2(long c); 184 | 185 | // eliminate row with weight 1 and the column that has the non-zero entry 186 | void eliminate_row1(long r); 187 | 188 | // eliminate row 189 | void eliminate_row(long r); 190 | 191 | // eliminate up to max rows, starting with ones touching column first_col 192 | void eliminate_rows(long max=1); 193 | 194 | // reduce matrix to (N+e) x N 195 | void reduce(long extra_rows=0); 196 | 197 | // create new system A' * x' = y' (cols is needed to undo) 198 | void make_system(smat_T& Aprime, vec_Tp& yprime, vec_long& cols) const; 199 | 200 | // compute solution x to A*x=y, given solution x' to A'*x'=y' 201 | // returns true if all values of x were recovered 202 | static bool undo(vec_Tp& x, const vec_Tp& xprime, 203 | const smat_T& A, const vec_Tp& y, const vec_long& cols); 204 | 205 | 206 | // compare long values 207 | static int compar_long(const void* a, const void* b) { 208 | if (*(long*)a < *(long*)b) 209 | return -1; 210 | else if (*(long*)a == *(long*)b) 211 | return 0; 212 | return 1; 213 | } 214 | 215 | 216 | public: 217 | long nrows; // current number of non-trivial rows 218 | long first_col; // first non-trivial column in AEcs 219 | 220 | const smat_T& A; // original matrix 221 | vec_long Arw; // row weights (0 for eliminated row) 222 | 223 | smat_T E; // extra rows 224 | vec_long Erw; // row weights (0 for eliminated row) 225 | 226 | vec_vec_long AEc; // column index of matrix (negative values for extra rows) 227 | // note: row numbers in AEc are kept sorted in reverse order 228 | 229 | vec_long AEcw; // column weights (0 for eliminated column) 230 | vec_long AEcs; // columns indices sorted by weight 231 | vec_long AEcr; // reverse pointers into AEcs to enable sort adjustment 232 | // invariant: c = AEcs[AEcr[c]] 233 | 234 | vec_Tp Ay; // constant term 235 | vec_Tp Ey; // constant term for extra rows 236 | }; 237 | 238 | 239 | template 240 | smat_gauss::smat_gauss(const smat_T& A1, 241 | const vec_Tp& y1) 242 | : nrows(0), A(A1), Ay(y1) { 243 | 244 | Arw.SetLength(A.NumRows()); 245 | AEc.SetLength(A.NumCols()); 246 | AEcw.SetLength(A.NumCols()); 247 | 248 | // scan matrix to generate Arw, AEc and AEcw 249 | bool row1 = false; 250 | for (long i=A.NumRows()-1; i>=0; --i) { 251 | const long* ri = A[i].indices(); 252 | const value_t* rv = A[i].values(); 253 | for (long j=0; j=1) { 260 | ++nrows; 261 | if (Arw[i]==1) 262 | row1=true; 263 | } 264 | } 265 | 266 | // sort columns by weight 267 | long* ar = new long[2*A.NumCols()]; 268 | for (long i=0; i 295 | smat_gauss::~smat_gauss() { 296 | } 297 | 298 | // bubble sort AEcs to ensure column c is correctly positioned 299 | template 300 | void smat_gauss::resort(long c) { 301 | // my column weight is AEcw[c] = AEcw[AEcs[AEcr[c]]] 302 | // prev weight is AEcw[AEcs[AEcr[c]-1]] 303 | while (AEcr[c]>0 && AEcw[AEcs[AEcr[c]-1]]>AEcw[c]) { 304 | swap(AEcs[AEcr[c]],AEcs[AEcr[c]-1]); 305 | ++AEcr[AEcs[AEcr[c]]]; 306 | --AEcr[c]; 307 | } 308 | } 309 | 310 | template 311 | void smat_gauss::eliminate_row1(long i) { 312 | set_row_weight(i,0); 313 | --nrows; 314 | const long* ri = row(i).indices(); 315 | const value_t* rv = row(i).values(); 316 | for (long j=0; j0) { 324 | y(r) -= row(r)[c]*y(i)/rv[j]; 325 | set_row_weight(r,row_weight(r)-1); 326 | if (row_weight(r)<=1) { 327 | if (row_weight(r)==1) 328 | row1 = true; 329 | else 330 | --nrows; 331 | } 332 | } 333 | } 334 | // eliminate column 335 | AEcw[c] = 0; 336 | resort(c); 337 | // eliminate new weight 1 rows 338 | if (row1) { 339 | for (long k=0; k 350 | void smat_gauss::eliminate_col1(long c) { 351 | // find the row that has the non-zero entry and eliminate it 352 | for (long i=0; i0) { 355 | AEcw[c]=0; 356 | resort(c); 357 | set_row_weight(r,0); 358 | --nrows; 359 | const long* ri = row(r).indices(); 360 | const value_t* rv = row(r).values(); 361 | for (long j=0; j0 && !IsZero(rv[j])) { 363 | --AEcw[ri[j]]; 364 | resort(ri[j]); 365 | } 366 | return; 367 | } 368 | } 369 | Error("smat_gauss::eliminate_col1() FATAL ERROR!"); 370 | } 371 | 372 | template 373 | void smat_gauss::eliminate_col2(long c) { 374 | // find the two rows 375 | long i=0; 376 | long r1=0,r2; 377 | while (i0) 380 | break; 381 | } 382 | while (i0) { 385 | AEcw[c]=0; 386 | resort(c); 387 | // subtract rows to create new (extra) row having 0 in this column 388 | long r = E.NumRows(); 389 | E.SetDims(r+1,A.NumCols()); 390 | Ey.SetLength(r+1); 391 | value_t g; 392 | g = GCD(row(r1)[c],row(r2)[c]); 393 | E[r] = (row(r2)[c]/g)*row(r1) - (row(r1)[c]/g)*row(r2); 394 | Ey[r] = (row(r2)[c]/g)*y(r1) - (row(r1)[c]/g)*y(r2); 395 | // fixup EAc, Erw 396 | Erw.SetLength(r+1); 397 | Erw[r] = 0; 398 | svec_long rnz; 399 | nonzero(rnz,E[r]); 400 | const long* ri = rnz.indices(); 401 | const svec_long::value_type* rv = rnz.values(); 402 | for (long k=0; k0) { 404 | append(AEc[ri[k]],-r-1); 405 | ++Erw[r]; 406 | } 407 | } 408 | if (Erw[r]>0) 409 | ++nrows; 410 | // fixup AEcw 411 | svec_long nz; 412 | nonzero(nz,row(r1)); 413 | rnz -= nz; 414 | nonzero(nz,row(r2)); 415 | rnz -= nz; 416 | ri = rnz.indices(); // these may have changed 417 | rv = rnz.values(); 418 | for (long k=0; k0) { 420 | AEcw[ri[k]] += rv[k]; 421 | resort(ri[k]); 422 | } 423 | // remove original rows 424 | set_row_weight(r1,0); 425 | set_row_weight(r2,0); 426 | nrows-=2; 427 | if (Erw[r]==1) 428 | eliminate_row1(r); 429 | return; 430 | } 431 | } 432 | Error("smat_gauss::eliminate_col2() FATAL ERROR!"); 433 | } 434 | 435 | template 436 | void smat_gauss::eliminate_row(long r) { 437 | const long* ri = row(r).indices(); 438 | const value_t* rv = row(r).values(); 439 | for (long j=0; j0) { 442 | --AEcw[c]; 443 | resort(c); 444 | } 445 | } 446 | set_row_weight(r,0); 447 | --nrows; 448 | } 449 | 450 | template 451 | void smat_gauss::eliminate_rows(long max) { 452 | if (max<1) 453 | return; 454 | long start=first_col; 455 | long end=first_col+1; 456 | while (end1); ++i) { 462 | for (long j=0; j0) { 465 | if (s.contains(r)) { 466 | append(dups,r); 467 | if (max==1) 468 | break; 469 | } 470 | else 471 | s.insert(r); 472 | } 473 | } 474 | } 475 | while (dups.length()==0 && end0) { 481 | if (s.contains(r)) { 482 | append(dups,r); 483 | if (max==1) 484 | break; 485 | } 486 | } 487 | } 488 | ++end; 489 | } 490 | // delete all rows in dups 491 | for (long i=0; i0) { 493 | eliminate_row(dups[i]); 494 | if (--max<=0) 495 | break; 496 | } 497 | } 498 | 499 | // reduce matrix to (N+e) x N 500 | template 501 | void smat_gauss::reduce(long extra) { 502 | do { 503 | while (first_col 519 | void smat_gauss::make_system(smat_T& newA, 520 | vec_Tp& newy, 521 | vec_long& cols) const { 522 | vec_long cmap; 523 | cmap.SetLength(AEcw.length()); 524 | cols.SetLength(NumCols()); 525 | for (long i=0,j=0; i0) { 527 | cols[j] = i; 528 | cmap[i] = j++; 529 | } 530 | 531 | newA.SetDims(NumRows(),NumCols()); 532 | clear(newA); 533 | newy.SetLength(NumRows()); 534 | clear(newy); 535 | long r=0; 536 | for (long i=0; i0) { 538 | const long* ri = A[i].indices(); 539 | const value_t* rv = A[i].values(); 540 | for (long j=0; j0) 542 | newA[r][cmap[ri[j]]] = rv[j]; 543 | newy[r] = Ay[i]; 544 | ++r; 545 | } 546 | for (long i=0; i0) { 548 | const long* ri = E[i].indices(); 549 | const value_t* rv = E[i].values(); 550 | for (long j=0; j0) 552 | newA[r][cmap[ri[j]]] = rv[j]; 553 | newy[r] = Ey[i]; 554 | ++r; 555 | } 556 | } 557 | 558 | 559 | template 560 | bool smat_gauss::undo(vec_Tp& x, 561 | const vec_Tp& xprime, 562 | const smat_T& A, 563 | const vec_Tp& y, 564 | const vec_long& cols) { 565 | // copy known results to xorig 566 | x.SetLength(A.NumCols()); 567 | clear(x); 568 | bool* known = new bool[x.length()]; 569 | memset(known,0,x.length()*sizeof(bool)); 570 | long nknown = 0; 571 | for (long i=0; i=0) { 605 | // compute unknown value 606 | Tp v; 607 | InnerProduct(v,A[i],x); 608 | v -= y[i]; 609 | v /= A[i][unknown]; 610 | negate(x[unknown],v); 611 | known[unknown] = true; 612 | ++nknown; 613 | done=false; 614 | } 615 | } 616 | } while (!done); 617 | 618 | delete[] used; 619 | 620 | /* 621 | if (nknown=x.length(); 632 | } 633 | 634 | 635 | 636 | 637 | /* Structured Gaussian Elimination. 638 | * Finds a smaller version of system Aorig*x=yorig and returns it 639 | * in Anew and ynew. cols is the list of column indices from Aorig 640 | * that were kept in Anew. 641 | */ 642 | void SGauss(smat_long& Anew, vec_ZZ_p& ynew, vec_long& cols, 643 | const smat_long& Aorig, const vec_ZZ_p& yorig) { 644 | 645 | if (SGAUSS_VERBOSE) 646 | std::cerr<<"SGauss: pre "< SGE(Aorig,yorig); 649 | if (SGAUSS_VERBOSE) 650 | std::cerr<<"SGauss: init "< SGE(Aorig,yorig); 662 | if (SGAUSS_VERBOSE) 663 | std::cerr<<"SGauss: init "<::undo(xorig,x,Aorig,yorig, 681 | cols); 682 | } 683 | bool SGauss_undo(vec_ZZ_p& xorig, const vec_ZZ_p& x, 684 | const vec_long& cols, 685 | const smat_ZZ& Aorig, const vec_ZZ_p& yorig) { 686 | return 687 | smat_gauss::undo(xorig,x,Aorig,yorig,cols); 688 | } 689 | 690 | NTL_END_IMPL; 691 | -------------------------------------------------------------------------------- /NumberFieldSieve.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "vec_long.h" 5 | #include 6 | #include "ZZFactoring.h" 7 | #include "smat_ZZ_p.h" 8 | 9 | #include "NumberFieldSieve.h" 10 | #include "AlgebraicFactorBase.h" 11 | 12 | 13 | /* Number Field Sieve (NFS) algorithm. 14 | * 15 | * Written by: Chris Studholme 16 | * Copyright: GPL (http://www.fsf.org/copyleft/gpl.html) 17 | */ 18 | 19 | NTL_START_IMPL; 20 | 21 | // create a file named 'nfs.data' showing the distribution of smooth integers 22 | //#define NFS_CREATE_DIST_FILE 23 | 24 | long DLog_NFS::MAX_SIEVE=20000000; /* maximum size of a single sieve */ 25 | 26 | 27 | inline long rem(long a, long b) { 28 | long r = a%b; 29 | while (r<0) 30 | r+=b; 31 | return r; 32 | } 33 | 34 | // compute fg = f(g(X)) 35 | inline void compose(ZZX& fg, const ZZX& f, const ZZX& g) { 36 | fg = coeff(f,deg(f)); 37 | for (long i=deg(f)-1; i>=0; --i) { 38 | fg*=g; 39 | fg+=coeff(f,i); 40 | } 41 | } 42 | 43 | // find and remove a from the sorted vector v 44 | inline void remove(vec_long& v, long a) { 45 | // binary search for a in v 46 | long low=0; 47 | long high=v.length(); 48 | while (high>low) { 49 | long mid = (low+high)/2; 50 | if (v[mid]k+afb.length()+zfb.length()+extra); 93 | } 94 | 95 | void add(const long* zfact, const long* afact, const ZZ* charmap) { 96 | long pos=rels.length(); 97 | rels.SetLength(pos+1); 98 | for (long i=0; i0) 175 | ++col_count; 176 | 177 | if (row_count>=col_count) { 178 | // need to choose a row to delete here 179 | // find the row that matters least as far as must_keep columns go 180 | long best=0; 181 | long best_value=0; 182 | for (long i=0; icol_use[rj[j]].length())&& 191 | (!IsZero(rv[j]))) 192 | value = col_use[rj[j]].length(); 193 | if (value>best_value) { 194 | best_value=value; 195 | best=i; 196 | } 197 | } 198 | // delete row best 199 | long rn = rels[best].nvalues(); 200 | const long* rj = rels[best].indices(); 201 | for (long i=0; i0) 234 | append(cols,j); 235 | 236 | // make the matrix (actually, transpose of matrix) 237 | A.SetDims(cols.length(),1+rows.length()); 238 | clear(A); 239 | // first column is one associated with generator 240 | for (long j=0; jbase=base; 340 | k=_k; 341 | sieve_width = _sieve_width; 342 | sieve_length = 0; 343 | 344 | // modulus 345 | ZZ p; 346 | p = ZZ_p::modulus(); 347 | 348 | // factor order of group 349 | vec_pair_ZZ_long factors; 350 | factor(factors,p-1); 351 | 352 | // largest factor must have exponent 1 353 | if (factors[factors.length()-1].b!=1) { 354 | cerr<<"DLog_NFS::setBase() largest factor of order has multiplicity>1\n"; 355 | return; 356 | } 357 | 358 | // modulus for solving the linear system 359 | q = factors[factors.length()-1].a; 360 | if (VERBOSE) 361 | cout<<"DLog_NFS::setBase() q = "<p^{1/k} 488 | ZZ h; 489 | h=1; 490 | ZZ m; 491 | mul(m,mp,2); 492 | ZZ pk; 493 | conv(pk,exp(NTL::log(p)/k)); 494 | //cout<<"DLog_NFS::log_prime() pk = "<= m^k 503 | ZZ mk; 504 | power(mk,m,k); 505 | ZZ cp(p); 506 | while (cp0; --i) { 516 | ZZ mi; 517 | power(mi,m,i); 518 | ZZ c; 519 | div(c,j,mi); // c=j/mi; 520 | SetCoeff(f,i,c); 521 | j -= c*mi; 522 | } 523 | // constant term 524 | SetCoeff(f,0,j); 525 | //cout<<"DLog_NFS::log_prime() f' = "<100) { 535 | cerr<<"DLog_NFS::log_prime() failed to make constant term smooth!\n"; 536 | return ZZ::zero(); 537 | } 538 | } 539 | if (VERBOSE) 540 | cout<<"DLog_NFS::log_prime() f = "<1)||(u[0].b!=1)) { 548 | cerr<<"DLog_NFS::log_prime() f is not irreducible!\n"; 549 | return ZZ::zero(); 550 | } 551 | 552 | // check that q does not divide the discriminant 553 | ZZ disc; 554 | disc = discriminant(f); 555 | if (IsZero(disc%q)) { 556 | cerr<<"DLog_NFS::log_prime() q divides discriminant!\n"; 557 | return ZZ::zero(); 558 | } 559 | 560 | AlgebraicFactorBase afb(f,zfb.bound()); 561 | long aprimes = afb.length(); 562 | if (VERBOSE) 563 | cout<<"DLog_NFS::log_prime() " 564 | <m) { 578 | cerr<<"DLog_NFS::log_prime() sieve_width too large ("<2) { 655 | long rm; 656 | zfb.factor(zfact,rm,d); 657 | for (long i=1; i0) { 659 | // remove prime 660 | long p = zfb[i]; 661 | if ((d%2)==1) { 662 | // start+i = 0 mod p => i = -start mod p; 663 | for (long i=rem(-start,p); i i = -1/2 - start mod p 669 | for (long i=rem(-InvMod(2,p)-start,p); i x = -1/2 mod p 672 | append(excludes,p,InvMod(p-2,p)); 673 | } 674 | } 675 | } 676 | if (rm>1) { 677 | if ((d%2)==1) { 678 | sieve[-start] = -1; 679 | for (long i=0; i=0) { 740 | // not-smooth (we count it as having been checked) 741 | ++sieve_total; 742 | } 743 | } 744 | 745 | long percent = sieve_smooth*100/(aprimes+zprimes); 746 | if ((percent!=percent_last)||(d-d_last>20)) { 747 | cout<<"Sieving: [d="<10)&&(d_lastsmooth 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "FactorBase.h" 15 | 16 | 17 | /* Class representing a factor base of integers. 18 | * 19 | * Written by: Chris Studholme 20 | * Copyright: GPL (http://www.fsf.org/copyleft/gpl.html) 21 | */ 22 | 23 | NTL_START_IMPL; 24 | 25 | class sieve_run { 26 | public: 27 | long pi,e,start,inc; 28 | }; 29 | typedef Vec vec_run; 30 | 31 | inline void append(vec_run& plan, long pi, long e, long start, long inc) { 32 | plan.SetLength(plan.length()+1); 33 | plan[plan.length()-1].pi = pi; 34 | plan[plan.length()-1].e = e; 35 | plan[plan.length()-1].start = start; 36 | plan[plan.length()-1].inc = inc; 37 | } 38 | 39 | inline bool IsOne(long a) { 40 | return a==1; 41 | } 42 | 43 | // if uniq==true, dups are removed 44 | static int compar_long(const void *a, const void *b) { 45 | if (*(long*)a < *(long*)b) 46 | return -1; 47 | else if (*(long*)a == *(long*)b) 48 | return 0; 49 | return 1; 50 | } 51 | 52 | static void sort(vec_long& x, bool uniq=false) { 53 | long* v = x.elts(); 54 | qsort(v,x.length(),sizeof(long),compar_long); 55 | if (uniq) 56 | for (long i=x.length()-1; i>0; --i) 57 | if (v[i-1]==v[i]) { 58 | memmove(v+i,v+i+1,(x.length()-i-1)*sizeof(long)); 59 | x.SetLength(x.length()-1); 60 | } 61 | } 62 | 63 | inline long DivRem(long& q, long a, long b) { 64 | q = a/b; 65 | long r = a%b; 66 | while (r<0) 67 | r+=b; 68 | return r; 69 | } 70 | 71 | inline long rem(long a, long b) { 72 | long r = a%b; 73 | while (r<0) 74 | r+=b; 75 | return r; 76 | } 77 | 78 | // compute f(a) 79 | inline void evaluate(ZZ& image, const ZZX& f, const ZZ& a) { 80 | image = coeff(f,deg(f)); 81 | for (long i=deg(f)-1; i>=0; --i) { 82 | image*=a; 83 | image+=coeff(f,i); 84 | } 85 | } 86 | 87 | // compute fg = f(g(X)) 88 | inline void compose(ZZX& fg, const ZZX& f, const ZZX& g) { 89 | fg = coeff(f,deg(f)); 90 | for (long i=deg(f)-1; i>=0; --i) { 91 | fg*=g; 92 | fg+=coeff(f,i); 93 | } 94 | } 95 | 96 | 97 | // if f(start) and f(end-1) have different sign, then 98 | // either z in [start,end) with f(z)=0 99 | // or z in (start,end) with f(z-1) and f(z) having different sign 100 | // is found and appended to zeros 101 | static void AppendZeroCrossing(vec_ZZ& zeros, const ZZX& f, 102 | const ZZ& start, const ZZ& end) { 103 | if (start>=end) 104 | return; 105 | 106 | ZZ s(start),e(end); 107 | --e; 108 | ZZ fs,fe; 109 | evaluate(fs,f,start); 110 | evaluate(fe,f,end); 111 | if (fs>fe) { 112 | // swap start and end 113 | swap(s,e); 114 | swap(fs,fe); 115 | } 116 | 117 | if ((fs>0)||(fe<0)) 118 | return; 119 | 120 | // at this point: fs<=0<=fe 121 | // binary search 122 | ZZ m,fm; 123 | while (abs(s-e)>1) { 124 | m = (s+e)/2; 125 | evaluate(fm,f,m); 126 | if (fm<0) { 127 | s=m; 128 | fs=fm; 129 | } 130 | else if (fm>0) { 131 | e=m; 132 | fe=fm; 133 | } 134 | else { 135 | append(zeros,m); 136 | return; 137 | } 138 | } 139 | append(zeros,s>e?s:e); 140 | } 141 | 142 | 143 | // find all zeros f(z)=0, where z in [start,end) 144 | // furthermore, z in (start,end) such that f(z-1) and f(z) have different 145 | // sign are also considered zeros 146 | static void FindZeros(vec_ZZ& zeros, const ZZX& f, 147 | const ZZ& start, const ZZ& end) { 148 | zeros.SetLength(0); 149 | 150 | // base cases 151 | if (deg(f)<=1) { 152 | if (IsZero(f)) 153 | Error("FindZeros() zero polynomial provided"); 154 | else if (deg(f)==1) 155 | AppendZeroCrossing(zeros,f,start,end); 156 | return; 157 | } 158 | 159 | ZZX df; 160 | diff(df,f); 161 | vec_ZZ extrema; 162 | FindZeros(extrema,df,start,end); 163 | 164 | if (extrema.length()==0) { 165 | AppendZeroCrossing(zeros,f,start,end); 166 | return; 167 | } 168 | 169 | AppendZeroCrossing(zeros,f,start,extrema[0]); 170 | for (long i=1; i1 is GCD of all non-zero coefficients 354 | if (c>primes[nprimes-1]) { 355 | ZZ rm; 356 | factor(0,rm,c); 357 | c /= rm; 358 | } 359 | g /= c; 360 | } 361 | 362 | 363 | // the zz_p modulus is expected to be set to p 364 | // actually, start+prev_zero is a zero of f_{p^e}(X) 365 | void sieve_r(vec_ZZ& smooth, const ZZ& start, const ZZX& f, 366 | long e=0, long prev_zero=0) { 367 | long p = zz_p::modulus(); 368 | 369 | long length = smooth.length(); 370 | vec_long zeros; 371 | 372 | if (e==0) { 373 | // reduce coefficients of f modulo p 374 | zz_pX fp; 375 | conv(fp,f); 376 | 377 | // factor fp 378 | vec_pair_zz_pX_long u; 379 | CanZass(u,fp); 380 | 381 | // note all zeros 382 | for (long j=0; j0 388 | else { 389 | ZZ pe; 390 | power(pe,p,e); 391 | 392 | // polynomial: start+prev_zero + Y*p^e 393 | ZZX g; 394 | SetCoeff(g,0,start+prev_zero); 395 | SetCoeff(g,1,pe); 396 | 397 | // compose f and g 398 | ZZX fg; 399 | compose(fg,f,g); 400 | 401 | // all coefficients of fg must be divisible by pe 402 | fg/=pe; 403 | 404 | // reduce coefficients of fg modulo p 405 | zz_pX fp; 406 | conv(fp,fg); 407 | 408 | if (IsZero(fp)) { 409 | // all values [0,p) are zeros 410 | ZZ r; 411 | for (long j=0; j1, does this ever happen? 434 | MakeMonic(fp); 435 | 436 | // factor fp 437 | vec_pair_zz_pX_long u; 438 | CanZass(u,fp); 439 | 440 | // note all zeros 441 | ZZ r; 442 | for (long j=0; j1) { 461 | fv[l]/=p; 462 | done=false; 463 | } 464 | if (!done) 465 | sieve_r(smooth,start,f,e,zeros[j]); // recurse 466 | } 467 | } 468 | 469 | // sieve over a polynomial (deterministic) 470 | void FactorBase::sieve(vec_ZZ& smooth, const ZZX& f, const ZZ& start) const { 471 | zz_pBak bak; 472 | bak.save(); 473 | 474 | long length=smooth.length(); 475 | ZZ* fv = smooth.elts(); 476 | 477 | // efficient evaluation of f using successor functions 478 | long k = deg(f); 479 | ZZX g[k+1]; 480 | ZZ pv[k+1]; // previous value 481 | 482 | g[k] = f; 483 | evaluate(pv[k],g[k],start); 484 | for (long i=k-1; i>=0; --i) { 485 | // compute successor function 486 | ZZX t; 487 | SetCoeff(t,0,1); 488 | SetCoeff(t,1,1); 489 | compose(g[i],g[i+1],t); 490 | g[i]-=g[i+1]; 491 | evaluate(pv[i],g[i],start); 492 | } 493 | 494 | // image of f 495 | for (long i=0; ; ) { 496 | if (IsZero(fv[i])) 497 | abs(fv[i],pv[k]); 498 | else 499 | conv(fv[i],-1); 500 | if (++i>=length) 501 | break; 502 | // update function 503 | for (long j=k; j>0; --j) 504 | pv[j]+=pv[j-1]; 505 | } 506 | 507 | for (long i=0; i 1"); 562 | 563 | long depth=0; 564 | 565 | if (deg(fp)==1) { 566 | // exactly one zero 567 | MakeMonic(fp); 568 | long ofs = rep(-ConstTerm(fp)); 569 | if (pos+pe*ofs=exclude.length() || j!=exclude[xi]) { 610 | long d = 1+sieve_r(plan,start,length,f,pi,j); 611 | if (depth=0) 749 | fv[j] += logp; 750 | } 751 | } 752 | else { 753 | long end = 0; 754 | do { 755 | end += stride; 756 | if (end>length) 757 | end = length; 758 | for (long i=0; i=0) 762 | fv[plan[i].start] += logp; 763 | plan[i].start += plan[i].inc; 764 | } 765 | } 766 | } while (end0) { 771 | long lr; 772 | if (rem_factor=0) 778 | fv[i] += lr; 779 | } 780 | 781 | t_end = GetTime(); 782 | s1_exec += t_end-t_start; 783 | t_start=t_end; 784 | 785 | // now, figure out which ones are smooth by checking if their logarithms 786 | // are sufficiently large 787 | 788 | // find all zeros of f 789 | vec_ZZ zeros; 790 | FindZeros(zeros,f,start,start+length); 791 | 792 | // make list of endpoints consisting of start, end, extrema, and zeros 793 | vec_ZZ endpoints; 794 | append(endpoints,start); 795 | for (long i=0,j=0; ; ) { 796 | if (i=p2) 819 | continue; 820 | --p2; 821 | ZZ fp1,fp2; 822 | evaluate(fp1,f,p1); 823 | evaluate(fp2,f,p2); 824 | abs(fp1,fp1); 825 | abs(fp2,fp2); 826 | long dir=1; 827 | if (fp1>fp2) { 828 | swap(p1,p2); 829 | swap(fp1,fp2); 830 | dir=-1; 831 | } 832 | 833 | // since fp1<=fp2, we can use log(f(x-dir)) as lower bound for log(f(x)) 834 | 835 | // look for smooth elements 836 | long j = to_long(p1-start); 837 | long lastlog = IsZero(fp1) ? 0 : (long)(logmult*log(fp1)); 838 | do { 839 | if (fv[j]>0) { 840 | if (fv[j]low) { 900 | long mid = (low+high)/2; 901 | if (primes[mid] composite 925 | memset(sieve,0,(bound+1)*sizeof(unsigned char)); 926 | 927 | long end = (long)ceil(sqrt((double)bound)); 928 | for (long i=2; i<=end; ++i) 929 | if (sieve[i]==0) 930 | for (long j=i*i; j<=bound; j+=i) 931 | sieve[j]=1; 932 | 933 | aprimes=0; 934 | for (long i=2; i<=bound; ++i) 935 | if (sieve[i]==0) 936 | ++aprimes; 937 | 938 | if (primes) delete[] primes; 939 | primes = new long[aprimes]; 940 | nprimes = 0; 941 | 942 | for (long i=2; i<=bound; ++i) 943 | if (sieve[i]==0) 944 | primes[nprimes++] = i; 945 | 946 | delete[] sieve; 947 | 948 | // figure out sprime 949 | sprime=0; 950 | while (primes[sprime]