├── Makefile.am ├── AUTHORS ├── NEWS ├── .gitignore ├── src ├── Makefile.am ├── ModuloArith.h ├── F2matrix.h ├── TonelliShanks.h ├── ModuloArith.cpp ├── lprels.h ├── lanczos.h ├── TonelliShanks.cpp ├── F2matrix.cpp ├── lprels.cpp ├── lanczos.cpp └── QS.cpp ├── README ├── configure.ac ├── QStodo.txt ├── INSTALL └── COPYING /Makefile.am: -------------------------------------------------------------------------------- 1 | ACLOCAL_AMFLAGS = -I m4 2 | SUBDIRS = src 3 | 4 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | William Hart: Original implementation 2 | Michael Abshoff: Sage patches 3 | Jeroen Demeyer: Sage patches 4 | Volker Braun: Autotoolize, new repo 5 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- 1 | The original repo 2 | https://svn.sourceforge.net/svnroot/fastlibnt/trunk/QS does no longer 3 | exist. This the currently the upstream repository. Please file bugs on 4 | github. 5 | 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | autom4te.cache/ 3 | *.in 4 | /aclocal.m4 5 | /compile 6 | /config.guess 7 | /config.sub 8 | /configure 9 | /depcomp 10 | /install-sh 11 | /missing 12 | /ChangeLog 13 | /flintqs-*.tar.gz -------------------------------------------------------------------------------- /src/Makefile.am: -------------------------------------------------------------------------------- 1 | bin_PROGRAMS = QuadraticSieve 2 | QuadraticSieve_SOURCES = \ 3 | F2matrix.cpp F2matrix.h lanczos.cpp lanczos.h ModuloArith.cpp ModuloArith.h \ 4 | TonelliShanks.cpp TonelliShanks.h \ 5 | lprels.cpp lprels.h \ 6 | QS.cpp 7 | 8 | # QuadraticSieve_CFLAGS = $(AM_CFLAGS) -ansi -std=c99 9 | 10 | 11 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Standalone CLI implementation of William Hart's Quadratic Sieve. 2 | 3 | William Hart was the maintainer of FLINT (https://www.flintlib.org/) 4 | for many years; a modern and actively-maintained version of this 5 | quadratic sieve is available in FLINT itself, as qsieve_factor(). 6 | There remain unfixed build issues and at least one security 7 | vulnerability (CVE-2023-29465) in FlintQS. As a result, FlintQS is 8 | considered obsolete. 9 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_PREREQ([2.66]) 2 | AC_INIT([FlintQS], [1.0], [sage-devel@googlegroups.com]) 3 | 4 | AC_CANONICAL_TARGET 5 | AM_INIT_AUTOMAKE 6 | 7 | AC_CONFIG_MACRO_DIR([m4]) 8 | AC_CONFIG_HEADERS([src/config.h]) 9 | 10 | AC_CONFIG_FILES([ 11 | Makefile 12 | src/Makefile 13 | ]) 14 | 15 | 16 | AC_CHECK_HEADERS([gmp.h]) 17 | AC_CHECK_LIB([gmp], [__gmpz_init], , 18 | AC_MSG_ERROR([GNU Multiple Precision Arithmetic Library not found. 19 | Set CFLAGS/LDFLAGS if it is installed in a non-standard directory]) 20 | ) 21 | 22 | AC_PROG_CXX 23 | AC_OUTPUT 24 | -------------------------------------------------------------------------------- /src/ModuloArith.h: -------------------------------------------------------------------------------- 1 | /*============================================================================ 2 | Copyright 2006 William Hart 3 | 4 | This file is part of FLINT. 5 | 6 | FLINT is free software; you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation; either version 2 of the License, or 9 | (at your option) any later version. 10 | 11 | FLINT is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with FLINT; if not, write to the Free Software 18 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 19 | 20 | ============================================================================*/ 21 | 22 | // ===================================================================== 23 | // INTERFACE: 24 | // 25 | // void ChineseInit(void) 26 | // - Initialise variables for chinese 27 | // 28 | // void modmul(mpz_t ab, mpz_t a, mpz_t b, mpz_t p) 29 | // - sets ab to a*b modulo p 30 | // 31 | // void chinese(mpz_t res, mpz_t n, mpz_t x1, mpz_t x2, mpz_t n1, mpz_t n2) 32 | // - sets n to n1*n2 33 | // - sets res mod n to a value congruent to x1 mod n1 and x2 mod n2 34 | // 35 | // ====================================================================== 36 | 37 | extern void ChineseInit(void); 38 | extern void modmul(mpz_t, mpz_t, mpz_t, mpz_t); 39 | extern void chinese(mpz_t, mpz_t, mpz_t, mpz_t, mpz_t, mpz_t); 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /src/F2matrix.h: -------------------------------------------------------------------------------- 1 | /*============================================================================ 2 | Copyright 2006 William Hart 3 | 4 | This file is part of FLINT. 5 | 6 | FLINT is free software; you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation; either version 2 of the License, or 9 | (at your option) any later version. 10 | 11 | FLINT is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with FLINT; if not, write to the Free Software 18 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 19 | 20 | ============================================================================*/ 21 | #ifndef F2MATRIX_H 22 | #define F2MATRIX_H 23 | 24 | #include 25 | #include "lanczos.h" 26 | 27 | typedef u_int32_t * row; //row of an F2 matrix 28 | typedef row * matrix; //matrix as a list of pointers to rows 29 | 30 | extern void insertEntry(matrix, u_int32_t, u_int32_t); 31 | extern void xorEntry(matrix, u_int32_t, u_int32_t); 32 | extern u_int32_t getEntry(matrix, u_int32_t, u_int32_t); 33 | extern matrix constructMat(u_int32_t, u_int32_t); 34 | extern void xorRows(row, row, u_int32_t); 35 | extern void clearRow(matrix, u_int32_t, u_int32_t); 36 | extern void swapRows(row, row); 37 | extern u_int32_t gaussReduce(matrix, u_int32_t, u_int32_t, int32_t); 38 | extern void displayRow(matrix, u_int32_t, u_int32_t); 39 | 40 | #endif 41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /src/TonelliShanks.h: -------------------------------------------------------------------------------- 1 | /*============================================================================ 2 | Copyright 2006 William Hart 3 | 4 | This file is part of FLINT. 5 | 6 | FLINT is free software; you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation; either version 2 of the License, or 9 | (at your option) any later version. 10 | 11 | FLINT is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with FLINT; if not, write to the Free Software 18 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 19 | 20 | ============================================================================*/ 21 | 22 | #include 23 | #include 24 | 25 | // ===================================================================== 26 | // INTERFACE: 27 | // 28 | // void TonelliInit(void) 29 | // - Initialises variables 30 | // 31 | // int sqrtmod(mpz_t asqrt, mpz_t a, mpz_t p) 32 | // - Tonelli-Shanks: sets asqrt to a square root of a modulo p 33 | // - Return: 0 if a is not a square mod p, 1 otherwise. 34 | // 35 | // void sqrtmodpk(mpz_t res, mpz_t z, mpz_t a, mpz_t p, int k) 36 | // - Given a square root z, of a mod p (from Tonelli-Shanks say) 37 | // - sets res to a square root of a mod p^k 38 | // 39 | // ======================================================================== 40 | 41 | extern void TonelliInit(void); 42 | extern int32_t sqrtmod(mpz_t, mpz_t, mpz_t); 43 | extern inline void sqrtmodpow(mpz_t, mpz_t, mpz_t, mpz_t); 44 | extern void sqrtmodpk(mpz_t, mpz_t, mpz_t, mpz_t, int32_t); 45 | 46 | 47 | -------------------------------------------------------------------------------- /QStodo.txt: -------------------------------------------------------------------------------- 1 | QStodo 2 | ======= 3 | 4 | 1. ***Check for duplicate ordinary relations 5 | 2. ***Make large prime cutoff table 6 | 3. ***Change sievediv to 1 for all but 60 digit factorizations or separate into tuning files 7 | 4. Make sieve look for additional relations if factorization fails 8 | 5. ***Set all LESS values to 0 9 | 6. ***Update old version of sieve to include new corrected polynomial choosing 10 | 7. ***Make better polynomial choosing code 11 | 8. ***Write ordinary relations to file 12 | 9. ***Fix all printf %d's etc 13 | 10. Make structures in memory smaller by using shorter data types 14 | 11. Pass pointers to structs to functions 15 | 12. Use structs instead of separated data types 16 | 13. Remove second copy of large prime check for negated value 17 | 14. ***Remove printf's from lanczos code 18 | 15. Ensure polynomial chooser can't pick wrong A factors 19 | 16. ***Count actual number of relations, not including duplicates 20 | 17. ***Check more often near end of sieving if we are done 21 | 18. ***Replace all errors with aborts 22 | 19. Replace all file operations with safe ones 23 | 20. Clean up after a run, i.e. free memory allocated 24 | 21. Introduce hash tables for computers with large caches 25 | 22. In candidate evaluation, multiply by inverses modulo a large prime instead of dividing out by each prime. (maybe not for version 0.99) 26 | 23. Adjust 4X sieve eval code for factorisations under 40 digits 27 | 24. Make reentrant and into a single callable function 28 | 25. Make parallelisable 29 | 26. Package output into factor tree 30 | 27. Integrate into Pari 31 | 28. Rename .cpp to .c and make compile with gcc 32 | 29. Integrate into FLINT makefile 33 | 30. Remove sievediv 34 | 31. ***Use unique filenames 35 | 32. Write README file 36 | 37 | a. 38 | b. Optimise for other architectures 39 | c. Comment code 40 | d. 41 | e. 42 | f. 43 | 44 | I. ***Add single prime variant 45 | II. Add double prime variant 46 | III. Optimize cache usage for larger factor bases 47 | IV. Implement SQUFOf, elliptic curve, pollard-brent, etc and make single factoring algorithm 48 | 49 | *** Already done. 50 | 51 | -------------------------------------------------------------------------------- /src/ModuloArith.cpp: -------------------------------------------------------------------------------- 1 | /*============================================================================ 2 | Copyright 2006 William Hart 3 | 4 | This file is part of FLINT. 5 | 6 | FLINT is free software; you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation; either version 2 of the License, or 9 | (at your option) any later version. 10 | 11 | FLINT is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with FLINT; if not, write to the Free Software 18 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 19 | 20 | ============================================================================*/ 21 | 22 | // ------------------------------------------------------- 23 | // 24 | // ModuloArith.cpp 25 | // 26 | // Provides Functions for doing Modulo Arithmetic 27 | // 28 | // ------------------------------------------------------- 29 | 30 | #include 31 | #include "ModuloArith.h" 32 | 33 | mpz_t restemp; //chinese variables 34 | mpz_t ntemp; 35 | mpz_t chtemp; 36 | 37 | void modmul(mpz_t ab, mpz_t a, mpz_t b, mpz_t p) 38 | { 39 | mpz_mul(ab,a,b); 40 | mpz_fdiv_r(ab,ab,p); 41 | } 42 | 43 | void ChineseInit(void) 44 | { 45 | mpz_init(restemp); 46 | mpz_init(ntemp); 47 | mpz_init(chtemp); 48 | 49 | return; 50 | } 51 | 52 | void chinese(mpz_t res, mpz_t n, mpz_t x1, mpz_t x2, mpz_t n1, mpz_t n2) 53 | { 54 | mpz_mul(ntemp,n1,n2); 55 | mpz_invert(restemp,n2,n1); 56 | modmul(restemp,restemp,n2,ntemp); 57 | modmul(restemp,restemp,x1,ntemp); 58 | 59 | mpz_invert(chtemp,n1,n2); 60 | modmul(chtemp,chtemp,n1,ntemp); 61 | modmul(chtemp,chtemp,x2,ntemp); 62 | 63 | mpz_add(res,restemp,chtemp); 64 | mpz_fdiv_r(res,res,ntemp); 65 | mpz_set(n,ntemp); 66 | 67 | return; 68 | } 69 | 70 | -------------------------------------------------------------------------------- /src/lprels.h: -------------------------------------------------------------------------------- 1 | /*============================================================================ 2 | Copyright 2006 William Hart 3 | 4 | This file is part of FLINT. 5 | 6 | FLINT is free software; you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation; either version 2 of the License, or 9 | (at your option) any later version. 10 | 11 | FLINT is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with FLINT; if not, write to the Free Software 18 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 19 | 20 | ===============================================================================*/ 21 | 22 | #ifndef LPRELS_H 23 | #define LPRELS_H 24 | 25 | #include "lanczos.h" 26 | 27 | #define MPQS_STRING_LENGTH (4 * 1024UL) 28 | 29 | typedef struct { 30 | long q; 31 | char Y[MPQS_STRING_LENGTH]; 32 | char E[MPQS_STRING_LENGTH]; 33 | } mpqs_lp_entry; 34 | 35 | char * get_filename(char *dir, char *s); 36 | int mpqs_relations_cmp(const void *a, const void *b); 37 | void flint_fputs(char *s, FILE *file); 38 | long sort_lp_file(char *filename); 39 | long append_file(FILE *fp, FILE *fp1); 40 | long mpqs_mergesort_lp_file_internal(FILE *LPREL, FILE *LPNEW, FILE *COMB, FILE *TMP); 41 | long mergesort_lp_file(char *REL_str, char *NEW_str, char *TMP_str, FILE *COMB); 42 | void add_factor(char **last, unsigned long ei, unsigned long pi); 43 | void add_0(char **last); 44 | void set_exponents(unsigned long *ei, char *r); 45 | void set_lp_entry(mpqs_lp_entry *e, char *buf); 46 | long combine_large_primes(unsigned long numPrimes, FILE *COMB, FILE *FNEW, mpz_t N, mpz_t factor); 47 | void read_matrix(unsigned long ** relations, FILE *FREL, la_col_t* colarray, unsigned long * relsFound, unsigned long relSought, mpz_t * XArr, mpz_t n, unsigned long * factorBase); 48 | FILE * flint_fopen(char * name, char * mode); 49 | char * unique_filename(char *s); 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /src/lanczos.h: -------------------------------------------------------------------------------- 1 | /*============================================================================ 2 | Copyright 2006 William Hart 3 | 4 | This file is part of FLINT. 5 | 6 | FLINT is free software; you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation; either version 2 of the License, or 9 | (at your option) any later version. 10 | 11 | FLINT is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with FLINT; if not, write to the Free Software 18 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 19 | 20 | ============================================================================*/ 21 | #ifndef LANCZOS_H 22 | #define LANCZOS_H 23 | 24 | #ifdef __sun 25 | #define u_int32_t unsigned int 26 | #define u_int64_t unsigned long long 27 | #endif 28 | 29 | #include // needed on MacOS X 10.5 for uint type 30 | 31 | #include 32 | 33 | typedef struct { 34 | unsigned long *data; /* The list of occupied rows in this column */ 35 | unsigned long weight; /* Number of nonzero entries in this column */ 36 | unsigned long orig; /* Original relation number */ 37 | } la_col_t; 38 | 39 | u_int64_t getNullEntry(u_int64_t *, long, long); 40 | void reduce_matrix(unsigned long *, unsigned long *, la_col_t *); 41 | u_int64_t * block_lanczos(unsigned long, unsigned long, unsigned long, la_col_t*); 42 | 43 | /*========================================================================== 44 | insertColEntry: 45 | 46 | Function: insert an entry into a column of the matrix, 47 | reallocating the space for the column if necessary 48 | 49 | ===========================================================================*/ 50 | static inline void insertColEntry(la_col_t* colarray, unsigned long colNum, unsigned long entry) 51 | { 52 | unsigned long* temp; 53 | 54 | if ((((colarray[colNum].weight)>>4)<<4)==colarray[colNum].weight) //need more space 55 | { 56 | temp = colarray[colNum].data; 57 | colarray[colNum].data = (unsigned long*)malloc((colarray[colNum].weight+16)*sizeof(unsigned long)); 58 | for (long i = 0; i 31 | #include "TonelliShanks.h" 32 | #include "ModuloArith.h" //need multiplication mod p 33 | 34 | mpz_t two; //variables for sqrtmod 35 | mpz_t p1; 36 | mpz_t b; 37 | mpz_t g; 38 | mpz_t xsq; 39 | mpz_t mk; 40 | mpz_t bpow; 41 | mpz_t gpow; 42 | 43 | mpz_t inv; //variables for sqrtmodpow 44 | mpz_t tempsqpow; 45 | 46 | mpz_t pk; //variable for sqrtmodpk 47 | 48 | void TonelliInit(void) 49 | { 50 | mpz_init(two); 51 | mpz_init(p1); 52 | mpz_init(b); 53 | mpz_init(g); 54 | mpz_init(xsq); 55 | mpz_init(mk); 56 | mpz_init(bpow); 57 | mpz_init(gpow); 58 | 59 | mpz_init(inv); 60 | mpz_init(tempsqpow); 61 | 62 | mpz_init(pk); 63 | 64 | return; 65 | } 66 | 67 | int32_t sqrtmod(mpz_t asqrt, mpz_t a, mpz_t p) 68 | { 69 | int32_t r,k,m; 70 | 71 | if (mpz_kronecker(a,p)!=1) 72 | { 73 | mpz_set_ui(asqrt,0); 74 | return 0; //return 0 if a is not a square mod p 75 | } 76 | 77 | mpz_set_ui(two,2); 78 | 79 | mpz_sub_ui(p1,p,1); 80 | r = mpz_remove(p1,p1,two); 81 | mpz_powm(b,a,p1,p); 82 | for (k=2; ;k++) 83 | { 84 | if (mpz_ui_kronecker(k,p) == -1) break; 85 | } 86 | mpz_set_ui(mk,k); 87 | mpz_powm(g,mk,p1,p); 88 | mpz_add_ui(p1,p1,1); 89 | mpz_divexact_ui(p1,p1,2); 90 | mpz_powm(xsq,a,p1,p); 91 | if (!mpz_cmp_ui(b,1)) 92 | { 93 | mpz_set(asqrt,xsq); 94 | 95 | return 1; 96 | } 97 | 98 | while (mpz_cmp_ui(b,1)) 99 | { 100 | mpz_set(bpow,b); 101 | for (m=1; (m<=r-1) && (mpz_cmp_ui(bpow,1));m++) 102 | { 103 | mpz_powm_ui(bpow,bpow,2,p); 104 | } 105 | mpz_set(gpow,g); 106 | for (int32_t i = 1;i<= r-m-1;i++) 107 | { 108 | mpz_powm_ui(gpow,gpow,2,p); 109 | }; 110 | modmul(xsq,xsq,gpow,p); 111 | mpz_powm_ui(gpow,gpow,2,p); 112 | modmul(b,b,gpow,p); 113 | mpz_set(gpow,g); 114 | r = m; 115 | } 116 | 117 | mpz_set(asqrt,xsq); 118 | 119 | return 1; 120 | } 121 | 122 | inline void sqrtmodpow(mpz_t res, mpz_t z, mpz_t a, mpz_t pk) 123 | { 124 | mpz_mul_ui(inv,z,2); 125 | mpz_invert(inv,inv,pk); 126 | mpz_set(tempsqpow,a); 127 | mpz_submul(tempsqpow,z,z); 128 | mpz_fdiv_r(tempsqpow,tempsqpow,pk); 129 | modmul(tempsqpow,tempsqpow,inv,pk); 130 | mpz_add(tempsqpow,tempsqpow,z); 131 | mpz_set(res,tempsqpow); 132 | 133 | return; 134 | } 135 | 136 | void sqrtmodpk(mpz_t res, mpz_t z, mpz_t a, mpz_t p, int32_t k) 137 | { 138 | mpz_set(res,z); 139 | mpz_set(pk,p); 140 | for (int32_t i = 2;i<=k;i++) 141 | { 142 | mpz_mul(pk,pk,p); 143 | sqrtmodpow(res,res,a,pk); 144 | } 145 | 146 | return; 147 | } 148 | -------------------------------------------------------------------------------- /src/F2matrix.cpp: -------------------------------------------------------------------------------- 1 | /*============================================================================ 2 | Copyright 2006 William Hart 3 | 4 | This file is part of SIMPQS. 5 | 6 | SIMPQS is free software; you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation; either version 2 of the License, or 9 | (at your option) any later version. 10 | 11 | SIMPQS is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SIMPQS; if not, write to the Free Software 18 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 19 | 20 | ============================================================================*/ 21 | 22 | #include 23 | #include 24 | #include 25 | #include "F2matrix.h" 26 | 27 | static u_int32_t bitPattern[] = 28 | { 29 | 0x80000000, 0x40000000, 0x20000000, 0x10000000, 30 | 0x08000000, 0x04000000, 0x02000000, 0x01000000, 31 | 0x00800000, 0x00400000, 0x00200000, 0x00100000, 32 | 0x00080000, 0x00040000, 0x00020000, 0x00010000, 33 | 0x00008000, 0x00004000, 0x00002000, 0x00001000, 34 | 0x00000800, 0x00000400, 0x00000200, 0x00000100, 35 | 0x00000080, 0x00000040, 0x00000020, 0x00000010, 36 | 0x00000008, 0x00000004, 0x00000002, 0x00000001 37 | }; 38 | 39 | void insertEntry(matrix m, u_int32_t i, u_int32_t j) 40 | { 41 | m[i][j / 32] |= bitPattern[j % 32]; 42 | 43 | return; 44 | } 45 | 46 | void xorEntry(matrix m, u_int32_t i, u_int32_t j) 47 | { 48 | m[i][j / 32] ^= bitPattern[j % 32]; 49 | 50 | return; 51 | } 52 | 53 | u_int32_t getEntry(matrix m, u_int32_t i, u_int32_t j) 54 | { 55 | return m[i][j / 32] & bitPattern[j % 32]; 56 | } 57 | 58 | void swapRows(matrix m, u_int32_t x, u_int32_t y) 59 | { 60 | row temp; 61 | 62 | temp = m[x]; 63 | m[x] = m[y]; 64 | m[y] = temp; 65 | 66 | return; 67 | } 68 | 69 | 70 | void clearRow(matrix m, u_int32_t numcols, u_int32_t row) 71 | { 72 | int32_t dwords = numcols/32; 73 | 74 | if (numcols%32) dwords++; 75 | memset(m[row],0,dwords*4); 76 | 77 | return; 78 | } 79 | 80 | void displayRow(matrix m, u_int32_t row, u_int32_t numPrimes) 81 | { 82 | int32_t length = numPrimes/32; 83 | if (numPrimes%32) length++; 84 | length*=64; 85 | 86 | printf("["); 87 | for (int32_t j = 0; j < length/2; j++) 88 | { 89 | if (getEntry(m,row,j)) printf("1"); 90 | else printf("0"); 91 | } 92 | printf(" "); 93 | for (int32_t j = length/2; j < length; j++) 94 | { 95 | if (getEntry(m,row,j)) printf("1"); 96 | else printf("0"); 97 | } 98 | printf("]\n"); 99 | return; 100 | } 101 | 102 | void xorRows(matrix m, u_int32_t source, u_int32_t dest, u_int32_t length) 103 | { 104 | u_int32_t i, q, r; 105 | row x = m[dest]; 106 | row y = m[source]; 107 | 108 | r = length % 8; q = length - r; 109 | for (i=0; i < q; i += 8) 110 | { 111 | x[i] ^= y[i]; x[1+i] ^= y[1+i]; x[2+i] ^= y[2+i]; x[3+i] ^= y[3+i]; 112 | x[4+i] ^= y[4+i]; x[5+i] ^= y[5+i]; x[6+i] ^= y[6+i]; x[7+i] ^= y[7+i]; 113 | } 114 | switch (r) 115 | { 116 | case 7: x[i] ^= y[i]; i++; 117 | case 6: x[i] ^= y[i]; i++; 118 | case 5: x[i] ^= y[i]; i++; 119 | case 4: x[i] ^= y[i]; i++; 120 | case 3: x[i] ^= y[i]; i++; 121 | case 2: x[i] ^= y[i]; i++; 122 | case 1: x[i] ^= y[i]; i++; 123 | } 124 | 125 | return; 126 | } 127 | 128 | matrix constructMat(u_int32_t cols, u_int32_t rows) 129 | { 130 | static matrix m; 131 | 132 | u_int32_t dwords = cols/32; 133 | if (cols%32) dwords++; 134 | m = (row *) calloc(sizeof(row),rows); 135 | if (m==NULL) 136 | { 137 | printf("Unable to allocate memory for matrix!\n"); 138 | exit(1); 139 | } 140 | 141 | for (u_int32_t i = 0; i < rows; i++) 142 | { 143 | m[i] = (row) calloc(2*dwords,sizeof(u_int32_t)); //two matrices, side by side 144 | } 145 | if (m[rows-1]==NULL) 146 | { 147 | printf("Unable to allocate memory for matrix!\n"); 148 | exit(1); 149 | } 150 | 151 | for (int32_t i = 0; i < rows; i++) //make second matrix identity, i.e. 1's along diagonal 152 | { 153 | insertEntry(m,i,i+32*dwords); 154 | } 155 | 156 | return m; 157 | } 158 | 159 | //=========================================================================== 160 | // gaussReduce: 161 | // 162 | // Function: Apply Gaussian elimination to a matrix. 163 | // 164 | //=========================================================================== 165 | u_int32_t gaussReduce(matrix m, u_int32_t numPrimes, u_int32_t relSought,int32_t extras) 166 | { 167 | static u_int32_t rowUpto = 0; 168 | static u_int32_t irow; 169 | static u_int32_t length = (numPrimes+extras)/32; 170 | 171 | if (numPrimes%32) length++; 172 | length*=2; 173 | 174 | for (int32_t icol = numPrimes-1; icol >= 0; icol--) 175 | { 176 | irow = rowUpto; 177 | while ((irow < relSought)&&(getEntry(m,irow,icol)==0UL)) irow++; 178 | if (irow < relSought) 179 | { 180 | 181 | swapRows(m,rowUpto,irow); 182 | 183 | for (u_int32_t checkRow = rowUpto+1; checkRow' header file. The option `-nodtk' can be used as 236 | a workaround. If GNU CC is not installed, it is therefore recommended 237 | to try 238 | 239 | ./configure CC="cc" 240 | 241 | and if that doesn't work, try 242 | 243 | ./configure CC="cc -nodtk" 244 | 245 | On Solaris, don't put `/usr/ucb' early in your `PATH'. This 246 | directory contains several dysfunctional programs; working variants of 247 | these programs are available in `/usr/bin'. So, if you need `/usr/ucb' 248 | in your `PATH', put it _after_ `/usr/bin'. 249 | 250 | On Haiku, software installed for all users goes in `/boot/common', 251 | not `/usr/local'. It is recommended to use the following options: 252 | 253 | ./configure --prefix=/boot/common 254 | 255 | Specifying the System Type 256 | ========================== 257 | 258 | There may be some features `configure' cannot figure out 259 | automatically, but needs to determine by the type of machine the package 260 | will run on. Usually, assuming the package is built to be run on the 261 | _same_ architectures, `configure' can figure that out, but if it prints 262 | a message saying it cannot guess the machine type, give it the 263 | `--build=TYPE' option. TYPE can either be a short name for the system 264 | type, such as `sun4', or a canonical name which has the form: 265 | 266 | CPU-COMPANY-SYSTEM 267 | 268 | where SYSTEM can have one of these forms: 269 | 270 | OS 271 | KERNEL-OS 272 | 273 | See the file `config.sub' for the possible values of each field. If 274 | `config.sub' isn't included in this package, then this package doesn't 275 | need to know the machine type. 276 | 277 | If you are _building_ compiler tools for cross-compiling, you should 278 | use the option `--target=TYPE' to select the type of system they will 279 | produce code for. 280 | 281 | If you want to _use_ a cross compiler, that generates code for a 282 | platform different from the build platform, you should specify the 283 | "host" platform (i.e., that on which the generated programs will 284 | eventually be run) with `--host=TYPE'. 285 | 286 | Sharing Defaults 287 | ================ 288 | 289 | If you want to set default values for `configure' scripts to share, 290 | you can create a site shell script called `config.site' that gives 291 | default values for variables like `CC', `cache_file', and `prefix'. 292 | `configure' looks for `PREFIX/share/config.site' if it exists, then 293 | `PREFIX/etc/config.site' if it exists. Or, you can set the 294 | `CONFIG_SITE' environment variable to the location of the site script. 295 | A warning: not all `configure' scripts look for a site script. 296 | 297 | Defining Variables 298 | ================== 299 | 300 | Variables not defined in a site shell script can be set in the 301 | environment passed to `configure'. However, some packages may run 302 | configure again during the build, and the customized values of these 303 | variables may be lost. In order to avoid this problem, you should set 304 | them in the `configure' command line, using `VAR=value'. For example: 305 | 306 | ./configure CC=/usr/local2/bin/gcc 307 | 308 | causes the specified `gcc' to be used as the C compiler (unless it is 309 | overridden in the site shell script). 310 | 311 | Unfortunately, this technique does not work for `CONFIG_SHELL' due to 312 | an Autoconf limitation. Until the limitation is lifted, you can use 313 | this workaround: 314 | 315 | CONFIG_SHELL=/bin/bash ./configure CONFIG_SHELL=/bin/bash 316 | 317 | `configure' Invocation 318 | ====================== 319 | 320 | `configure' recognizes the following options to control how it 321 | operates. 322 | 323 | `--help' 324 | `-h' 325 | Print a summary of all of the options to `configure', and exit. 326 | 327 | `--help=short' 328 | `--help=recursive' 329 | Print a summary of the options unique to this package's 330 | `configure', and exit. The `short' variant lists options used 331 | only in the top level, while the `recursive' variant lists options 332 | also present in any nested packages. 333 | 334 | `--version' 335 | `-V' 336 | Print the version of Autoconf used to generate the `configure' 337 | script, and exit. 338 | 339 | `--cache-file=FILE' 340 | Enable the cache: use and save the results of the tests in FILE, 341 | traditionally `config.cache'. FILE defaults to `/dev/null' to 342 | disable caching. 343 | 344 | `--config-cache' 345 | `-C' 346 | Alias for `--cache-file=config.cache'. 347 | 348 | `--quiet' 349 | `--silent' 350 | `-q' 351 | Do not print messages saying which checks are being made. To 352 | suppress all normal output, redirect it to `/dev/null' (any error 353 | messages will still be shown). 354 | 355 | `--srcdir=DIR' 356 | Look for the package's source code in directory DIR. Usually 357 | `configure' can determine that directory automatically. 358 | 359 | `--prefix=DIR' 360 | Use DIR as the installation prefix. *note Installation Names:: 361 | for more details, including other options available for fine-tuning 362 | the installation locations. 363 | 364 | `--no-create' 365 | `-n' 366 | Run the configure checks, but stop before creating any output 367 | files. 368 | 369 | `configure' also accepts some other, not widely useful, options. Run 370 | `configure --help' for more details. 371 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /src/lprels.cpp: -------------------------------------------------------------------------------- 1 | /*============================================================================ 2 | Copyright 2006 William Hart 3 | 4 | This file is part of FLINT. 5 | 6 | FLINT is free software; you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation; either version 2 of the License, or 9 | (at your option) any later version. 10 | 11 | FLINT is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with FLINT; if not, write to the Free Software 18 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 19 | 20 | ===============================================================================*/ 21 | 22 | /* 23 | This code has been adapted for FLINT from mpqs.c in the Pari/GP package. 24 | See http://pari.math.u-bordeaux.fr/ 25 | */ 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include "lprels.h" 33 | 34 | #define min_bufspace 120UL /* use new buffer when < min_bufspace left */ 35 | #define buflist_size 4096UL /* size of list-of-buffers blocks */ 36 | #define sort_table_size 100000UL 37 | 38 | /********************************************************************* 39 | 40 | File based large prime routines 41 | 42 | *********************************************************************/ 43 | 44 | /* 45 | Concatenates a filename and directory name to give a full path 46 | */ 47 | 48 | char * get_filename(char *dir, char *s) 49 | { 50 | char *buf = (char *) malloc(strlen(dir) + strlen(s) + 2); 51 | #if defined(__EMX__) || defined(WINCE) 52 | sprintf(buf, "%s\\%s", dir,s); 53 | #else 54 | sprintf(buf, "%s/%s", dir,s); 55 | #endif 56 | return buf; 57 | } 58 | 59 | char * unique_filename(char *s) 60 | { 61 | char *buf, suf[64]; 62 | size_t lsuf; 63 | 64 | sprintf(suf,".%ld.%ld", (long)getuid(), (long)getpid()); 65 | 66 | lsuf = strlen(suf); 67 | /* room for s + suffix '\0' */ 68 | buf = (char*) malloc(8 + lsuf + 1); 69 | 70 | sprintf(buf, "%.8s%s", s, suf); 71 | return buf; 72 | } 73 | 74 | 75 | FILE * flint_fopen(char * name, char * mode) 76 | { 77 | #if defined(WINCE) || defined(macintosh) 78 | char * tmp_dir = NULL; 79 | #else 80 | char * tmp_dir = getenv("TMPDIR"); 81 | #endif 82 | if (tmp_dir == NULL) tmp_dir = "./"; 83 | FILE * temp_file = fopen(get_filename(tmp_dir,unique_filename(name)),mode); 84 | if (!temp_file) 85 | { 86 | printf("Unable to open temporary file\n"); 87 | abort(); 88 | } 89 | return temp_file; 90 | } 91 | 92 | /* 93 | Compares two large prime relations according to their first 94 | element (the large prime). Used by qsort. 95 | */ 96 | 97 | int relations_cmp(const void *a, const void *b) 98 | { 99 | char **sa = (char**) a; 100 | char **sb = (char**) b; 101 | long qa = strtol(*sa, NULL, 10); 102 | long qb = strtol(*sb, NULL, 10); 103 | 104 | if (qa < qb) return -1; 105 | else if (qa > qb) return 1; 106 | else return strcmp(*sa, *sb); 107 | } 108 | 109 | 110 | /* 111 | Writes the given string to the given file and aborts upon error 112 | */ 113 | 114 | void flint_fputs(char *s, FILE *file) 115 | { 116 | if (fputs(s, file) < 0) 117 | { 118 | printf("Error whilst writing to large prime file!"); 119 | abort(); 120 | } 121 | } 122 | 123 | /* 124 | Given a file "filename" containing full or large prime relations, 125 | rearrange the file so that relations are sorted by their first elements. 126 | Works in memory, discards duplicate lines, and overwrites the original 127 | file. Returns the number of relations after sorting and discarding. 128 | */ 129 | 130 | long sort_lp_file(char *filename) 131 | { 132 | FILE *TMP; 133 | char *old_s, *buf, *cur_line; 134 | char **s_table, **sort_table, **buflist, **buflist_head; 135 | long i, j, count; 136 | size_t length, bufspace; 137 | 138 | buflist_head = (char**) malloc(buflist_size * sizeof(char*)); 139 | buflist = buflist_head; 140 | 141 | *buflist++ = NULL; /* flag this as last and only buflist block */ 142 | 143 | TMP = flint_fopen(filename, "r"); 144 | 145 | /* allocate first buffer and read first line, if any, into it */ 146 | buf = (char*) malloc(MPQS_STRING_LENGTH * sizeof(char)); 147 | cur_line = buf; 148 | bufspace = MPQS_STRING_LENGTH; 149 | 150 | if (fgets(cur_line, bufspace, TMP) == NULL) 151 | { /* file empty */ 152 | free(buf); free(buflist_head); 153 | fclose(TMP); 154 | return 0; 155 | } 156 | /* enter first buffer into buflist */ 157 | *buflist++ = buf; /* can't overflow the buflist block */ 158 | length = strlen(cur_line) + 1; /* count the \0 byte as well */ 159 | bufspace -= length; 160 | 161 | s_table = (char**) malloc(sort_table_size*sizeof(char*)); 162 | sort_table = s_table+sort_table_size; 163 | 164 | /* at start of loop, one line from the file is sitting in cur_line inside buf, 165 | the next will go into cur_line + length, and there's room for bufspace 166 | further characters in buf. The loop reads another line if one exists, and 167 | if this overruns the current buffer, it allocates a fresh one --GN */ 168 | 169 | for (i = 0, sort_table--; /* until end of file */; i++, sort_table--) 170 | { 171 | 172 | *sort_table = cur_line; 173 | cur_line += length; 174 | 175 | /* if little room is left, allocate a fresh buffer before attempting to 176 | * read a line, and remember to free it if no further line is forthcoming. 177 | * This avoids some copying of partial lines --GN */ 178 | if (bufspace < min_bufspace) 179 | { 180 | buf = (char*) malloc(MPQS_STRING_LENGTH * sizeof(char)); 181 | cur_line = buf; 182 | bufspace = MPQS_STRING_LENGTH; 183 | if (fgets(cur_line, bufspace, TMP) == NULL) { free(buf); break; } 184 | 185 | if (buflist - buflist_head >= buflist_size) abort(); 186 | 187 | /* remember buffer for later deallocation */ 188 | *buflist++ = buf; 189 | length = strlen(cur_line) + 1; 190 | bufspace -= length; continue; 191 | } 192 | 193 | /* normal case: try fitting another line into the current buffer */ 194 | if (fgets(cur_line, bufspace, TMP) == NULL) break; /* none exists */ 195 | length = strlen(cur_line) + 1; 196 | bufspace -= length; 197 | 198 | /* check whether we got the entire line or only part of it */ 199 | if (bufspace == 0 && cur_line[length-2] != '\n') 200 | { 201 | size_t lg1; 202 | buf = (char*) malloc(MPQS_STRING_LENGTH * sizeof(char)); 203 | if (buflist - buflist_head >= buflist_size) abort(); 204 | /* remember buffer for later deallocation */ 205 | *buflist++ = buf; 206 | 207 | /* copy what we've got to the new buffer */ 208 | (void)strcpy(buf, cur_line); /* cannot overflow */ 209 | cur_line = buf + length - 1; /* point at the \0 byte */ 210 | bufspace = MPQS_STRING_LENGTH - length + 1; 211 | 212 | /* read remainder of line */ 213 | if (fgets(cur_line, bufspace, TMP) == NULL) 214 | { 215 | printf("MPQS: relations file truncated?!\n"); 216 | abort(); 217 | } 218 | lg1 = strlen(cur_line); 219 | length += lg1; /* we already counted the \0 once */ 220 | bufspace -= (lg1 + 1); /* but here we must take it into account */ 221 | cur_line = buf; /* back up to the beginning of the line */ 222 | } 223 | } /* for */ 224 | 225 | fclose(TMP); 226 | 227 | /* sort the whole lot in place by swapping pointers */ 228 | qsort(sort_table, i, sizeof(char*), relations_cmp); 229 | 230 | /* copy results back to the original file, skipping exact duplicates */ 231 | TMP = flint_fopen(filename, "w"); 232 | old_s = sort_table[0]; 233 | flint_fputs(sort_table[0], TMP); 234 | count = 1; 235 | for(j = 1; j < i; j++) 236 | { 237 | if (strcmp(old_s, sort_table[j])) 238 | { 239 | flint_fputs(sort_table[j], TMP); 240 | count++; 241 | } 242 | old_s = sort_table[j]; 243 | } 244 | fflush(TMP); 245 | fclose(TMP); 246 | /* deallocate buffers */ 247 | while (*--buflist) 248 | { 249 | if (buflist != buflist_head) 250 | free(*buflist); /* free a buffer */ 251 | } 252 | free(buflist_head); 253 | free(s_table); 254 | return count; 255 | } 256 | 257 | /* 258 | Appends contents of file fp1 to fp (auxiliary routine for merge sort) and 259 | returns number of lines copied. Closes fp afterwards. 260 | */ 261 | 262 | long append_file(FILE *fp, FILE *fp1) 263 | { 264 | char line[MPQS_STRING_LENGTH]; 265 | long c = 0; 266 | while (fgets(line, MPQS_STRING_LENGTH, fp1)) { flint_fputs(line, fp); c++; } 267 | if (fflush(fp)) 268 | { 269 | printf("Error while flushing file.\n"); 270 | abort(); 271 | } 272 | fclose(fp); return c; 273 | } 274 | 275 | /* 276 | Merge-sort on the files LPREL and LPNEW; assumes that LPREL and LPNEW are 277 | already sorted. Creates/truncates the TMP file, writes result to it and 278 | closes it (via append_file()). Instead of LPREL, LPNEW we may also call 279 | this with FREL, FNEW. In the latter case COMB should be NULL (and we 280 | return the count of all full relations), in the former case it should be 281 | non-NULL (and we return the count of frels we expect to be able to combine 282 | out of the present lprels). If COMB is non-NULL, the combinable lprels 283 | are written out to this separate file. 284 | 285 | We retain only one occurrence of each large prime in TMP (i.e. in the 286 | future LPREL file). --GN 287 | */ 288 | 289 | #define swap_lines() { char *line_tmp;\ 290 | line_tmp = line_new_old; \ 291 | line_new_old = line_new; \ 292 | line_new = line_tmp; } 293 | 294 | long mergesort_lp_file_internal(FILE *LPREL, FILE *LPNEW, FILE *COMB, FILE *TMP) 295 | { 296 | char line1[MPQS_STRING_LENGTH], line2[MPQS_STRING_LENGTH]; 297 | char line[MPQS_STRING_LENGTH]; 298 | char *line_new = line1, *line_new_old = line2; 299 | long q_new, q_new_old = -1, q, i = 0, c = 0; 300 | long comb_in_progress; 301 | 302 | if ( !fgets(line_new, MPQS_STRING_LENGTH, LPNEW) ) 303 | { 304 | /* LPNEW is empty: copy LPREL to TMP. Could be done by a rename if we 305 | didn't want to count the lines (again)... however, this case will not 306 | normally happen */ 307 | i = append_file(TMP, LPREL); 308 | return COMB ? 0 : i; 309 | } 310 | /* we now have a line_new from LPNEW */ 311 | 312 | if (!fgets(line, MPQS_STRING_LENGTH, LPREL)) 313 | { 314 | /* LPREL is empty: copy LPNEW to TMP... almost. */ 315 | flint_fputs(line_new, TMP); 316 | 317 | if (!COMB) 318 | { 319 | /* full relations mode */ 320 | i = append_file(TMP, LPNEW); 321 | return i + 1; 322 | } 323 | 324 | /* LP mode: check for combinable relations */ 325 | q_new_old = atol(line_new); 326 | /* we need to retain a copy of the old line just for a moment, because we 327 | may yet have to write it to COMB. Do this by swapping the two buffers */ 328 | swap_lines(); 329 | comb_in_progress = 0; 330 | i = 0; 331 | 332 | while (fgets(line_new, MPQS_STRING_LENGTH, LPNEW)) 333 | { 334 | q_new = atol(line_new); 335 | if (q_new_old == q_new) 336 | { 337 | /* found combinables, check whether we're already busy on this 338 | particular large prime */ 339 | if (!comb_in_progress) 340 | { 341 | /* if not, write first line to COMB, creating and opening the 342 | file first if it isn't open yet */ 343 | flint_fputs(line_new_old, COMB); 344 | comb_in_progress = 1; 345 | } 346 | /* in any case, write the current line, and count it */ 347 | flint_fputs(line_new, COMB); 348 | i++; 349 | } 350 | else 351 | { 352 | /* not combinable */ 353 | q_new_old = q_new; 354 | comb_in_progress = 0; 355 | /* and dump it to the TMP file */ 356 | flint_fputs(line_new, TMP); 357 | /* and stash it away for a moment */ 358 | swap_lines(); 359 | comb_in_progress = 0; 360 | } 361 | } /* while */ 362 | fclose(TMP); return i; 363 | } 364 | 365 | /* normal case: both LPNEW and LPREL are not empty */ 366 | q_new = atol(line_new); 367 | q = atol(line); 368 | 369 | for(;;) 370 | { 371 | /* main merging loop */ 372 | i = comb_in_progress = 0; 373 | 374 | /* first the harder case: let LPNEW catch up with LPREL, and possibly 375 | overtake it, checking for combinables coming from LPNEW alone */ 376 | while (q > q_new) 377 | { 378 | if (!COMB || !comb_in_progress) flint_fputs(line_new, TMP); 379 | if (!COMB) c++; /* in FREL mode, count lines written */ 380 | else if (!comb_in_progress) 381 | { 382 | q_new_old = q_new; 383 | swap_lines(); 384 | } 385 | if (!fgets(line_new, MPQS_STRING_LENGTH, LPNEW)) 386 | { 387 | flint_fputs(line, TMP); 388 | if (!COMB) c++; else c += i; 389 | i = append_file(TMP, LPREL); 390 | return COMB ? c : c + i; 391 | } 392 | q_new = atol(line_new); 393 | if (!COMB) continue; 394 | 395 | /* LP mode only: */ 396 | if (q_new_old != q_new) /* not combinable */ 397 | comb_in_progress = 0; /* next loop will deal with it, or loop may end */ 398 | else 399 | { 400 | /* found combinables, check whether we're already busy on this 401 | large prime */ 402 | if (!comb_in_progress) 403 | { 404 | flint_fputs(line_new_old, COMB); 405 | comb_in_progress = 1; 406 | } 407 | /* in any case, write the current line, and count it */ 408 | flint_fputs(line_new, COMB); 409 | i++; 410 | } 411 | } /* while q > q_new */ 412 | 413 | /* q <= q_new */ 414 | 415 | if (COMB) c += i; /* accumulate count of combinables */ 416 | i = 0; /* and clear it */ 417 | comb_in_progress = 0;/* redundant */ 418 | 419 | /* now let LPREL catch up with LPNEW, and possibly overtake it */ 420 | while (q < q_new) 421 | { 422 | flint_fputs(line, TMP); 423 | if (!COMB) c++; 424 | if (!fgets(line, MPQS_STRING_LENGTH, LPREL)) 425 | { 426 | flint_fputs(line_new, TMP); 427 | i = append_file(TMP, LPNEW); 428 | return COMB ? c : c + i + 1; 429 | } 430 | else 431 | q = atol(line); 432 | } 433 | 434 | /* q >= q_new */ 435 | 436 | /* Finally, it may happen that q == q_new, indicating combinables whose 437 | large prime is already in LPREL, and appears now one or more times in 438 | LPNEW. Thus in this sub-loop we advance LPNEW. The `line' from LPREL is 439 | left alone, and will be written to TMP the next time around the main for 440 | loop; we only write it to COMB here -- unless all we find is an exact 441 | duplicate of the line we already have, that is. (There can be at most 442 | one such, and if so it is simply discarded.) */ 443 | while (q == q_new) 444 | { 445 | if (!strcmp(line_new, line)) 446 | { 447 | /* duplicate -- move right ahead to the next LPNEW line */ 448 | ;/* do nothing here */ 449 | } 450 | else if (!COMB) 451 | { /* full relations mode: write line_new out first, keep line */ 452 | flint_fputs(line_new, TMP); 453 | c++; 454 | } 455 | else 456 | { 457 | /* LP mode, and combinable relation */ 458 | if (!comb_in_progress) 459 | { 460 | flint_fputs(line, COMB); 461 | comb_in_progress = 1; 462 | } 463 | flint_fputs(line_new, COMB); 464 | i++; 465 | } 466 | /* NB comb_in_progress is cleared by q_new becoming bigger than q, thus 467 | the current while loop terminating, the next time through the main for 468 | loop */ 469 | 470 | /* common ending: get another line_new, if any */ 471 | if (!fgets(line_new, MPQS_STRING_LENGTH, LPNEW)) 472 | { 473 | flint_fputs(line, TMP); 474 | if (!COMB) c++; else c += i; 475 | i = append_file(TMP, LPREL); 476 | return COMB ? c : c + i; 477 | } 478 | else 479 | q_new = atol(line_new); 480 | } /* while */ 481 | 482 | if (COMB) c += i; /* accumulate count of combinables */ 483 | } 484 | } 485 | 486 | /* 487 | Perform mergesort of large prime files 488 | */ 489 | 490 | long mergesort_lp_file(char *REL_str, char *NEW_str, char *TMP_str, FILE *COMB) 491 | { 492 | FILE *NEW = flint_fopen(NEW_str, "r"); 493 | 494 | #if defined(WINCE) || defined(macintosh) 495 | char * tmp_dir = NULL; 496 | #else 497 | char * tmp_dir = getenv("TMPDIR"); 498 | #endif 499 | if (tmp_dir == NULL) tmp_dir = "./"; 500 | char * TMP_name = get_filename(tmp_dir,unique_filename(TMP_str)); 501 | char * REL_name = get_filename(tmp_dir,unique_filename(REL_str)); 502 | FILE * TMP = fopen(TMP_name,"w"); 503 | FILE * REL = fopen(REL_name,"r"); 504 | if ((!TMP) || (!REL)) 505 | { 506 | printf("Unable to open temporary file\n"); 507 | abort(); 508 | } 509 | 510 | long tp = mergesort_lp_file_internal(REL, NEW, COMB, TMP); 511 | fclose(REL); 512 | fclose(NEW); 513 | 514 | if (rename(TMP_name,REL_name)) 515 | { 516 | printf("Cannot rename file %s to %s", TMP_str, REL_str); 517 | abort(); 518 | } 519 | return tp; 520 | } 521 | 522 | void read_matrix(unsigned long ** relations, FILE *FREL, la_col_t* colarray, unsigned long * relsFound, unsigned long relSought, mpz_t * XArr, mpz_t n, unsigned long * factorBase) 523 | { 524 | long e, p; 525 | char buf[MPQS_STRING_LENGTH], *s; 526 | //char buf2[MPQS_STRING_LENGTH]; 527 | unsigned long numfactors; 528 | mpz_t test1, test2; 529 | mpz_init(test1); 530 | mpz_init(test2); 531 | 532 | 533 | if (ftell(FREL) < 0) 534 | { 535 | printf("Error on full relations file\n"); 536 | abort(); 537 | } 538 | while ((fgets(buf, MPQS_STRING_LENGTH, FREL)) && ((*relsFound) < relSought)) 539 | { 540 | numfactors = 0; 541 | gmp_sscanf(buf,"%Zd",XArr[*relsFound]); 542 | s = strchr(buf, ':') + 2; 543 | s = strtok(s, " \n"); 544 | while (s != NULL) 545 | { 546 | e = atol(s); if (!e) break; 547 | s = strtok(NULL, " \n"); 548 | p = atol(s); 549 | if (e & 1) xorColEntry(colarray,*relsFound,p); 550 | for (long i = 0; i < e; i++) relations[*relsFound][++numfactors] = p; 551 | s = strtok(NULL, " \n"); 552 | } 553 | relations[*relsFound][0] = numfactors; 554 | 555 | mpz_set_ui(test1,1); 556 | for (unsigned long i = 1; i<=relations[*relsFound][0]; i++) 557 | { 558 | mpz_mul_ui(test1,test1,factorBase[relations[*relsFound][i]]); 559 | if (i%30 == 0) mpz_mod(test1,test1,n); 560 | } 561 | mpz_mod(test1,test1,n); 562 | mpz_mul(test2,XArr[*relsFound],XArr[*relsFound]); 563 | mpz_mod(test2,test2,n); 564 | if (mpz_cmp(test1,test2)!=0) 565 | { 566 | mpz_add(test1,test1,test2); 567 | if (mpz_cmp(test1,n)!=0) 568 | { 569 | clearCol(colarray,*relsFound); 570 | } 571 | else (*relsFound)++; 572 | } else (*relsFound)++; 573 | } 574 | 575 | mpz_clear(test1); 576 | mpz_clear(test2); 577 | 578 | return; 579 | } 580 | 581 | /********************************************************************* 582 | 583 | Routines for writing relations as strings 584 | 585 | *********************************************************************/ 586 | 587 | /* 588 | Writes a factor pi^ei into a string as " ei pi" 589 | */ 590 | 591 | void add_factor(char **last, unsigned long ei, unsigned long pi) 592 | { 593 | sprintf(*last, " %ld %ld", ei, pi); 594 | *last += strlen(*last); 595 | } 596 | 597 | /* 598 | Concatenate " 0" to string 599 | */ 600 | 601 | void add_0(char **last) 602 | { 603 | char *s = *last; 604 | *s++ = ' '; 605 | *s++ = '0'; 606 | *s++ = 0; *last = s; 607 | } 608 | 609 | /********************************************************************* 610 | 611 | Large prime relation combining 612 | 613 | *********************************************************************/ 614 | 615 | /* 616 | Add to an array of unsigned longs the exponents from a relation string 617 | */ 618 | 619 | void set_exponents(unsigned long *ei, char *r) 620 | { 621 | char *s, b[MPQS_STRING_LENGTH]; 622 | long e; 623 | 624 | strcpy(b, r); 625 | s = strtok(b, " \n"); 626 | while (s != NULL) 627 | { 628 | e = atol(s); if (!e) break; 629 | s = strtok(NULL, " \n"); 630 | ei[atol(s)] += e; 631 | s = strtok(NULL, " \n"); 632 | } 633 | } 634 | 635 | /* Writes an lp_entry from a string */ 636 | 637 | void set_lp_entry(mpqs_lp_entry *e, char *buf) 638 | { 639 | char *s1, *s2; 640 | s1 = buf; s2 = strchr(s1, ' '); *s2 = '\0'; 641 | e->q = atol(s1); 642 | s1 = s2 + 3; s2 = strchr(s1, ' '); *s2 = '\0'; 643 | strcpy(e->Y, s1); 644 | s1 = s2 + 3; s2 = strchr(s1, '\n'); *s2 = '\0'; 645 | strcpy(e->E, s1); 646 | } 647 | 648 | /* 649 | Combines the large prime relations in COMB to full relations in FNEW. 650 | FNEW is assumed to be open for writing / appending. 651 | */ 652 | 653 | long combine_large_primes(unsigned long numPrimes, 654 | FILE *COMB, FILE *FNEW, mpz_t N, mpz_t factor) 655 | { 656 | char new_relation[MPQS_STRING_LENGTH], buf[MPQS_STRING_LENGTH]; 657 | mpqs_lp_entry e[2]; /* we'll use the two alternatingly */ 658 | unsigned long *ei; 659 | long ei_size = numPrimes; 660 | long old_q; 661 | mpz_t inv_q, Y1, Y2, new_Y, new_Y1; 662 | mpz_init(inv_q);mpz_init(Y1);mpz_init(Y2);mpz_init(new_Y);mpz_init(new_Y1); 663 | long i, l, c = 0; 664 | 665 | if (!fgets(buf, MPQS_STRING_LENGTH, COMB)) return 0; /* should not happen */ 666 | 667 | ei = (unsigned long *) malloc(sizeof(unsigned long)*ei_size); 668 | 669 | /* put first lp relation in row 0 of e */ 670 | set_lp_entry(&e[0], buf); 671 | 672 | i = 1; /* second relation will go into row 1 */ 673 | old_q = e[0].q; 674 | mpz_set_ui(inv_q, old_q); 675 | while (!mpz_invert(inv_q, inv_q, N)) /* can happen */ 676 | { 677 | /* We have found a factor. It could be N when N is quite small; 678 | or we might just have found a divisor by sheer luck. */ 679 | mpz_gcd_ui(inv_q, N, old_q); 680 | if (!mpz_cmp(inv_q, N)) /* pity */ 681 | { 682 | if (!fgets(buf, MPQS_STRING_LENGTH, COMB)) { return 0; } 683 | set_lp_entry(&e[0], buf); 684 | old_q = e[0].q; 685 | mpz_set_ui(inv_q, old_q); 686 | continue; 687 | } 688 | mpz_set(factor, inv_q); 689 | free(ei); 690 | return c; 691 | } 692 | gmp_sscanf(e[0].Y, "%Zd", Y1); 693 | 694 | while (fgets(buf, MPQS_STRING_LENGTH, COMB)) 695 | { 696 | set_lp_entry(&e[i], buf); 697 | if (e[i].q != old_q) 698 | { 699 | /* switch to combining a new bunch, swapping the rows */ 700 | old_q = e[i].q; 701 | mpz_set_ui(inv_q, old_q); 702 | while (!mpz_invert(inv_q, inv_q, N)) /* can happen */ 703 | { 704 | mpz_gcd_ui(inv_q, N, old_q); 705 | if (!mpz_cmp(inv_q, N)) /* pity */ 706 | { 707 | old_q = -1; /* sentinel */ 708 | continue; /* discard this combination */ 709 | } 710 | mpz_set(factor, inv_q); 711 | free(ei); 712 | return c; 713 | } 714 | gmp_sscanf(e[i].Y, "%Zd", Y1); 715 | i = 1 - i; /* subsequent relations go to other row */ 716 | continue; 717 | } 718 | /* count and combine the two we've got, and continue in the same row */ 719 | memset((void *)ei, 0, ei_size * sizeof(long)); 720 | set_exponents(ei, e[0].E); 721 | set_exponents(ei, e[1].E); 722 | gmp_sscanf(e[i].Y, "%Zd", Y2); 723 | 724 | if (mpz_cmpabs(Y1,Y2)!=0) 725 | { 726 | c++; 727 | mpz_mul(new_Y, Y1, Y2); 728 | mpz_mul(new_Y, new_Y, inv_q); 729 | mpz_mod(new_Y, new_Y, N); 730 | 731 | mpz_sub(new_Y1, N, new_Y); 732 | if (mpz_cmpabs(new_Y1, new_Y) < 0) mpz_set(new_Y, new_Y1); 733 | 734 | gmp_sprintf(buf, "%Zd\0", new_Y); 735 | strcpy(new_relation, buf); 736 | strcat(new_relation, " :"); 737 | for (l = 0; l < ei_size; l++) 738 | if (ei[l]) 739 | { 740 | sprintf(buf, " %ld %ld", ei[l], l); 741 | strcat(new_relation, buf); 742 | } 743 | strcat(new_relation, " 0"); 744 | strcat(new_relation, "\n"); 745 | 746 | flint_fputs(new_relation, FNEW); 747 | } 748 | } /* while */ 749 | 750 | free(ei); 751 | mpz_clear(inv_q);mpz_clear(Y1);mpz_clear(Y2);mpz_clear(new_Y);mpz_clear(new_Y1); 752 | 753 | return c; 754 | } 755 | 756 | 757 | -------------------------------------------------------------------------------- /src/lanczos.cpp: -------------------------------------------------------------------------------- 1 | /*============================================================================ 2 | Copyright 2006 Jason Papadopoulos 3 | 4 | This file is part of FLINT. 5 | 6 | FLINT is free software; you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation; either version 2 of the License, or 9 | (at your option) any later version. 10 | 11 | FLINT is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with FLINT; if not, write to the Free Software 18 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 19 | 20 | =============================================================================== 21 | 22 | Optionally, please be nice and tell me if you find this source to be 23 | useful. Again optionally, if you add to the functionality present here 24 | please consider making those additions public too, so that others may 25 | benefit from your work. 26 | --jasonp@boo.net 9/8/06 27 | 28 | The following modifications were made by William Hart: 29 | -addition of a random generator and max function 30 | -added the utility function getNullEntry 31 | -reformatted original code so it would operate as a standalone 32 | filter and block Lanczos module 33 | --------------------------------------------------------------------*/ 34 | 35 | 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include "lanczos.h" 41 | 42 | #define NUM_EXTRA_RELATIONS 64 43 | 44 | #define BIT(x) (((u_int64_t)(1)) << (x)) 45 | 46 | static const u_int64_t bitmask[64] = { 47 | BIT( 0), BIT( 1), BIT( 2), BIT( 3), BIT( 4), BIT( 5), BIT( 6), BIT( 7), 48 | BIT( 8), BIT( 9), BIT(10), BIT(11), BIT(12), BIT(13), BIT(14), BIT(15), 49 | BIT(16), BIT(17), BIT(18), BIT(19), BIT(20), BIT(21), BIT(22), BIT(23), 50 | BIT(24), BIT(25), BIT(26), BIT(27), BIT(28), BIT(29), BIT(30), BIT(31), 51 | BIT(32), BIT(33), BIT(34), BIT(35), BIT(36), BIT(37), BIT(38), BIT(39), 52 | BIT(40), BIT(41), BIT(42), BIT(43), BIT(44), BIT(45), BIT(46), BIT(47), 53 | BIT(48), BIT(49), BIT(50), BIT(51), BIT(52), BIT(53), BIT(54), BIT(55), 54 | BIT(56), BIT(57), BIT(58), BIT(59), BIT(60), BIT(61), BIT(62), BIT(63), 55 | }; 56 | 57 | /*--------------------------------------------------------------------*/ 58 | u_int64_t getNullEntry(u_int64_t * nullrows, long i, long l) { 59 | 60 | /* Returns true if the entry with indices i,l is 1 in the 61 | supplied 64xN matrix. This is used to read the nullspace 62 | vectors which are output by the Lanczos routine */ 63 | 64 | return nullrows[i]&bitmask[l]; 65 | } 66 | 67 | u_long random32(void) { 68 | 69 | /* Poor man's random number generator. It satisfies no 70 | particularly good randomness properties, but is good 71 | enough for this application */ 72 | 73 | static unsigned long randval = 4035456057U; 74 | randval = ((u_int64_t)randval*1025416097U+286824428U)%(u_int64_t)4294967291U; 75 | 76 | return (unsigned long)randval; 77 | } 78 | 79 | unsigned long max(unsigned long a, unsigned long b) { 80 | 81 | /* Returns the maximum of two unsigned long's */ 82 | 83 | return (aweight; k++) { 135 | if (counts[col->data[k]] < 2) 136 | break; 137 | } 138 | 139 | if (k < col->weight) { 140 | for (k = 0; k < col->weight; k++) { 141 | counts[col->data[k]]--; 142 | } 143 | free(col->data); 144 | } 145 | else { 146 | cols[j++] = cols[i]; 147 | } 148 | } 149 | reduced_cols = j; 150 | } while (c != reduced_cols); 151 | 152 | /* count the number of rows that contain a 153 | nonzero entry */ 154 | 155 | for (i = reduced_rows = 0; i < *nrows; i++) { 156 | if (counts[i]) 157 | reduced_rows++; 158 | } 159 | 160 | /* Because deleting a column reduces the weight 161 | of many rows, the number of nonzero rows may 162 | be much less than the number of columns. Delete 163 | more columns until the matrix has the correct 164 | aspect ratio. Columns at the end of cols[] are 165 | the heaviest, so delete those (and update the 166 | row counts again) */ 167 | 168 | if (reduced_cols > reduced_rows + NUM_EXTRA_RELATIONS) { 169 | for (i = reduced_rows + NUM_EXTRA_RELATIONS; 170 | i < reduced_cols; i++) { 171 | 172 | la_col_t *col = cols + i; 173 | for (j = 0; j < col->weight; j++) { 174 | counts[col->data[j]]--; 175 | } 176 | free(col->data); 177 | } 178 | reduced_cols = reduced_rows + NUM_EXTRA_RELATIONS; 179 | } 180 | 181 | /* if any columns were deleted in the previous step, 182 | then the matrix is less dense and more columns 183 | can be deleted; iterate until no further deletions 184 | are possible */ 185 | 186 | passes++; 187 | 188 | } while (r != reduced_rows); 189 | 190 | printf("reduce to %ld x %ld in %ld passes\n", 191 | reduced_rows, reduced_cols, passes); 192 | 193 | free(counts); 194 | 195 | /* record the final matrix size. Note that we can't touch 196 | nrows because all the column data (and the sieving relations 197 | that produced it) would have to be updated */ 198 | 199 | *ncols = reduced_cols; 200 | } 201 | 202 | /*-------------------------------------------------------------------*/ 203 | static void mul_64x64_64x64(u_int64_t *a, u_int64_t *b, u_int64_t *c ) { 204 | 205 | /* c[][] = x[][] * y[][], where all operands are 64 x 64 206 | (i.e. contain 64 words of 64 bits each). The result 207 | may overwrite a or b. */ 208 | 209 | u_int64_t ai, bj, accum; 210 | u_int64_t tmp[64]; 211 | unsigned long i, j; 212 | 213 | for (i = 0; i < 64; i++) { 214 | j = 0; 215 | accum = 0; 216 | ai = a[i]; 217 | 218 | while (ai) { 219 | bj = b[j]; 220 | if( ai & 1 ) 221 | accum ^= bj; 222 | ai >>= 1; 223 | j++; 224 | } 225 | 226 | tmp[i] = accum; 227 | } 228 | memcpy(c, tmp, sizeof(tmp)); 229 | } 230 | 231 | /*-----------------------------------------------------------------------*/ 232 | static void precompute_Nx64_64x64(u_int64_t *x, u_int64_t *c) { 233 | 234 | /* Let x[][] be a 64 x 64 matrix in GF(2), represented 235 | as 64 words of 64 bits each. Let c[][] be an 8 x 256 236 | matrix of 64-bit words. This code fills c[][] with 237 | a bunch of "partial matrix multiplies". For 0<=i<256, 238 | the j_th row of c[][] contains the matrix product 239 | 240 | ( i << (8*j) ) * x[][] 241 | 242 | where the quantity in parentheses is considered a 243 | 1 x 64 vector of elements in GF(2). The resulting 244 | table can dramatically speed up matrix multiplies 245 | by x[][]. */ 246 | 247 | u_int64_t accum, xk; 248 | unsigned long i, j, k, index; 249 | 250 | for (j = 0; j < 8; j++) { 251 | for (i = 0; i < 256; i++) { 252 | k = 0; 253 | index = i; 254 | accum = 0; 255 | while (index) { 256 | xk = x[k]; 257 | if (index & 1) 258 | accum ^= xk; 259 | index >>= 1; 260 | k++; 261 | } 262 | c[i] = accum; 263 | } 264 | 265 | x += 8; 266 | c += 256; 267 | } 268 | } 269 | 270 | /*-------------------------------------------------------------------*/ 271 | static void mul_Nx64_64x64_acc(u_int64_t *v, u_int64_t *x, u_int64_t *c, 272 | u_int64_t *y, unsigned long n) { 273 | 274 | /* let v[][] be a n x 64 matrix with elements in GF(2), 275 | represented as an array of n 64-bit words. Let c[][] 276 | be an 8 x 256 scratch matrix of 64-bit words. 277 | This code multiplies v[][] by the 64x64 matrix 278 | x[][], then XORs the n x 64 result into y[][] */ 279 | 280 | unsigned long i; 281 | u_int64_t word; 282 | 283 | precompute_Nx64_64x64(x, c); 284 | 285 | for (i = 0; i < n; i++) { 286 | word = v[i]; 287 | y[i] ^= c[ 0*256 + ((word>> 0) & 0xff) ] 288 | ^ c[ 1*256 + ((word>> 8) & 0xff) ] 289 | ^ c[ 2*256 + ((word>>16) & 0xff) ] 290 | ^ c[ 3*256 + ((word>>24) & 0xff) ] 291 | ^ c[ 4*256 + ((word>>32) & 0xff) ] 292 | ^ c[ 5*256 + ((word>>40) & 0xff) ] 293 | ^ c[ 6*256 + ((word>>48) & 0xff) ] 294 | ^ c[ 7*256 + ((word>>56) ) ]; 295 | } 296 | } 297 | 298 | /*-------------------------------------------------------------------*/ 299 | static void mul_64xN_Nx64(u_int64_t *x, u_int64_t *y, 300 | u_int64_t *c, u_int64_t *xy, unsigned long n) { 301 | 302 | /* Let x and y be n x 64 matrices. This routine computes 303 | the 64 x 64 matrix xy[][] given by transpose(x) * y. 304 | c[][] is a 256 x 8 scratch matrix of 64-bit words. */ 305 | 306 | unsigned long i; 307 | 308 | memset(c, 0, 256 * 8 * sizeof(u_int64_t)); 309 | memset(xy, 0, 64 * sizeof(u_int64_t)); 310 | 311 | for (i = 0; i < n; i++) { 312 | u_int64_t xi = x[i]; 313 | u_int64_t yi = y[i]; 314 | c[ 0*256 + ( xi & 0xff) ] ^= yi; 315 | c[ 1*256 + ((xi >> 8) & 0xff) ] ^= yi; 316 | c[ 2*256 + ((xi >> 16) & 0xff) ] ^= yi; 317 | c[ 3*256 + ((xi >> 24) & 0xff) ] ^= yi; 318 | c[ 4*256 + ((xi >> 32) & 0xff) ] ^= yi; 319 | c[ 5*256 + ((xi >> 40) & 0xff) ] ^= yi; 320 | c[ 6*256 + ((xi >> 48) & 0xff) ] ^= yi; 321 | c[ 7*256 + ((xi >> 56) ) ] ^= yi; 322 | } 323 | 324 | 325 | for(i = 0; i < 8; i++) { 326 | 327 | unsigned long j; 328 | u_int64_t a0, a1, a2, a3, a4, a5, a6, a7; 329 | 330 | a0 = a1 = a2 = a3 = 0; 331 | a4 = a5 = a6 = a7 = 0; 332 | 333 | for (j = 0; j < 256; j++) { 334 | if ((j >> i) & 1) { 335 | a0 ^= c[0*256 + j]; 336 | a1 ^= c[1*256 + j]; 337 | a2 ^= c[2*256 + j]; 338 | a3 ^= c[3*256 + j]; 339 | a4 ^= c[4*256 + j]; 340 | a5 ^= c[5*256 + j]; 341 | a6 ^= c[6*256 + j]; 342 | a7 ^= c[7*256 + j]; 343 | } 344 | } 345 | 346 | xy[ 0] = a0; xy[ 8] = a1; xy[16] = a2; xy[24] = a3; 347 | xy[32] = a4; xy[40] = a5; xy[48] = a6; xy[56] = a7; 348 | xy++; 349 | } 350 | } 351 | 352 | /*-------------------------------------------------------------------*/ 353 | static unsigned long find_nonsingular_sub(u_int64_t *t, unsigned long *s, 354 | unsigned long *last_s, unsigned long last_dim, 355 | u_int64_t *w) { 356 | 357 | /* given a 64x64 matrix t[][] (i.e. sixty-four 358 | 64-bit words) and a list of 'last_dim' column 359 | indices enumerated in last_s[]: 360 | 361 | - find a submatrix of t that is invertible 362 | - invert it and copy to w[][] 363 | - enumerate in s[] the columns represented in w[][] */ 364 | 365 | unsigned long i, j; 366 | unsigned long dim; 367 | unsigned long cols[64]; 368 | u_int64_t M[64][2]; 369 | u_int64_t mask, *row_i, *row_j; 370 | u_int64_t m0, m1; 371 | 372 | /* M = [t | I] for I the 64x64 identity matrix */ 373 | 374 | for (i = 0; i < 64; i++) { 375 | M[i][0] = t[i]; 376 | M[i][1] = bitmask[i]; 377 | } 378 | 379 | /* put the column indices from last_s[] into the 380 | back of cols[], and copy to the beginning of cols[] 381 | any column indices not in last_s[] */ 382 | 383 | mask = 0; 384 | for (i = 0; i < last_dim; i++) { 385 | cols[63 - i] = last_s[i]; 386 | mask |= bitmask[last_s[i]]; 387 | } 388 | for (i = j = 0; i < 64; i++) { 389 | if (!(mask & bitmask[i])) 390 | cols[j++] = i; 391 | } 392 | 393 | /* compute the inverse of t[][] */ 394 | 395 | for (i = dim = 0; i < 64; i++) { 396 | 397 | /* find the next pivot row and put in row i */ 398 | 399 | mask = bitmask[cols[i]]; 400 | row_i = M[cols[i]]; 401 | 402 | for (j = i; j < 64; j++) { 403 | row_j = M[cols[j]]; 404 | if (row_j[0] & mask) { 405 | m0 = row_j[0]; 406 | m1 = row_j[1]; 407 | row_j[0] = row_i[0]; 408 | row_j[1] = row_i[1]; 409 | row_i[0] = m0; 410 | row_i[1] = m1; 411 | break; 412 | } 413 | } 414 | 415 | /* if a pivot row was found, eliminate the pivot 416 | column from all other rows */ 417 | 418 | if (j < 64) { 419 | for (j = 0; j < 64; j++) { 420 | row_j = M[cols[j]]; 421 | if ((row_i != row_j) && (row_j[0] & mask)) { 422 | row_j[0] ^= row_i[0]; 423 | row_j[1] ^= row_i[1]; 424 | } 425 | } 426 | 427 | /* add the pivot column to the list of 428 | accepted columns */ 429 | 430 | s[dim++] = cols[i]; 431 | continue; 432 | } 433 | 434 | /* otherwise, use the right-hand half of M[] 435 | to compensate for the absence of a pivot column */ 436 | 437 | for (j = i; j < 64; j++) { 438 | row_j = M[cols[j]]; 439 | if (row_j[1] & mask) { 440 | m0 = row_j[0]; 441 | m1 = row_j[1]; 442 | row_j[0] = row_i[0]; 443 | row_j[1] = row_i[1]; 444 | row_i[0] = m0; 445 | row_i[1] = m1; 446 | break; 447 | } 448 | } 449 | 450 | if (j == 64) { 451 | #ifdef ERRORS 452 | printf("lanczos error: submatrix " 453 | "is not invertible\n"); 454 | #endif 455 | return 0; 456 | } 457 | 458 | /* eliminate the pivot column from the other rows 459 | of the inverse */ 460 | 461 | for (j = 0; j < 64; j++) { 462 | row_j = M[cols[j]]; 463 | if ((row_i != row_j) && (row_j[1] & mask)) { 464 | row_j[0] ^= row_i[0]; 465 | row_j[1] ^= row_i[1]; 466 | } 467 | } 468 | 469 | /* wipe out the pivot row */ 470 | 471 | row_i[0] = row_i[1] = 0; 472 | } 473 | 474 | /* the right-hand half of M[] is the desired inverse */ 475 | 476 | for (i = 0; i < 64; i++) 477 | w[i] = M[i][1]; 478 | 479 | /* The block Lanczos recurrence depends on all columns 480 | of t[][] appearing in s[] and/or last_s[]. 481 | Verify that condition here */ 482 | 483 | mask = 0; 484 | for (i = 0; i < dim; i++) 485 | mask |= bitmask[s[i]]; 486 | for (i = 0; i < last_dim; i++) 487 | mask |= bitmask[last_s[i]]; 488 | 489 | if (mask != (u_int64_t)(-1)) { 490 | #ifdef ERRORS 491 | printf("lanczos error: not all columns used\n"); 492 | #endif 493 | return 0; 494 | } 495 | 496 | return dim; 497 | } 498 | 499 | /*-------------------------------------------------------------------*/ 500 | void mul_MxN_Nx64(unsigned long vsize, unsigned long dense_rows, 501 | unsigned long ncols, la_col_t *A, 502 | u_int64_t *x, u_int64_t *b) { 503 | 504 | /* Multiply the vector x[] by the matrix A (stored 505 | columnwise) and put the result in b[]. vsize 506 | refers to the number of u_int64_t's allocated for 507 | x[] and b[]; vsize is probably different from ncols */ 508 | 509 | unsigned long i, j; 510 | 511 | memset(b, 0, vsize * sizeof(u_int64_t)); 512 | 513 | for (i = 0; i < ncols; i++) { 514 | la_col_t *col = A + i; 515 | unsigned long *row_entries = col->data; 516 | u_int64_t tmp = x[i]; 517 | 518 | for (j = 0; j < col->weight; j++) { 519 | b[row_entries[j]] ^= tmp; 520 | } 521 | } 522 | 523 | if (dense_rows) { 524 | for (i = 0; i < ncols; i++) { 525 | la_col_t *col = A + i; 526 | unsigned long *row_entries = col->data + col->weight; 527 | u_int64_t tmp = x[i]; 528 | 529 | for (j = 0; j < dense_rows; j++) { 530 | if (row_entries[j / 32] & 531 | ((unsigned long)1 << (j % 32))) { 532 | b[j] ^= tmp; 533 | } 534 | } 535 | } 536 | } 537 | } 538 | 539 | /*-------------------------------------------------------------------*/ 540 | void mul_trans_MxN_Nx64(unsigned long dense_rows, unsigned long ncols, 541 | la_col_t *A, u_int64_t *x, u_int64_t *b) { 542 | 543 | /* Multiply the vector x[] by the transpose of the 544 | matrix A and put the result in b[]. Since A is stored 545 | by columns, this is just a matrix-vector product */ 546 | 547 | unsigned long i, j; 548 | 549 | for (i = 0; i < ncols; i++) { 550 | la_col_t *col = A + i; 551 | unsigned long *row_entries = col->data; 552 | u_int64_t accum = 0; 553 | 554 | for (j = 0; j < col->weight; j++) { 555 | accum ^= x[row_entries[j]]; 556 | } 557 | b[i] = accum; 558 | } 559 | 560 | if (dense_rows) { 561 | for (i = 0; i < ncols; i++) { 562 | la_col_t *col = A + i; 563 | unsigned long *row_entries = col->data + col->weight; 564 | u_int64_t accum = b[i]; 565 | 566 | for (j = 0; j < dense_rows; j++) { 567 | if (row_entries[j / 32] & 568 | ((unsigned long)1 << (j % 32))) { 569 | accum ^= x[j]; 570 | } 571 | } 572 | b[i] = accum; 573 | } 574 | } 575 | } 576 | 577 | /*-----------------------------------------------------------------------*/ 578 | static void transpose_vector(unsigned long ncols, u_int64_t *v, u_int64_t **trans) { 579 | 580 | /* Hideously inefficent routine to transpose a 581 | vector v[] of 64-bit words into a 2-D array 582 | trans[][] of 64-bit words */ 583 | 584 | unsigned long i, j; 585 | unsigned long col; 586 | u_int64_t mask, word; 587 | 588 | for (i = 0; i < ncols; i++) { 589 | col = i / 64; 590 | mask = bitmask[i % 64]; 591 | word = v[i]; 592 | j = 0; 593 | while (word) { 594 | if (word & 1) 595 | trans[j][col] |= mask; 596 | word = word >> 1; 597 | j++; 598 | } 599 | } 600 | } 601 | 602 | /*-----------------------------------------------------------------------*/ 603 | void combine_cols(unsigned long ncols, 604 | u_int64_t *x, u_int64_t *v, 605 | u_int64_t *ax, u_int64_t *av) { 606 | 607 | /* Once the block Lanczos iteration has finished, 608 | x[] and v[] will contain mostly nullspace vectors 609 | between them, as well as possibly some columns 610 | that are linear combinations of nullspace vectors. 611 | Given vectors ax[] and av[] that are the result of 612 | multiplying x[] and v[] by the matrix, this routine 613 | will use Gauss elimination on the columns of [ax | av] 614 | to find all of the linearly dependent columns. The 615 | column operations needed to accomplish this are mir- 616 | rored in [x | v] and the columns that are independent 617 | are skipped. Finally, the dependent columns are copied 618 | back into x[] and represent the nullspace vector output 619 | of the block Lanczos code. 620 | 621 | v[] and av[] can be NULL, in which case the elimination 622 | process assumes 64 dependencies instead of 128 */ 623 | 624 | unsigned long i, j, k, bitpos, col, col_words, num_deps; 625 | u_int64_t mask; 626 | u_int64_t *matrix[128], *amatrix[128], *tmp; 627 | 628 | num_deps = 128; 629 | if (v == NULL || av == NULL) 630 | num_deps = 64; 631 | 632 | col_words = (ncols + 63) / 64; 633 | 634 | for (i = 0; i < num_deps; i++) { 635 | matrix[i] = (u_int64_t *)calloc((size_t)col_words, 636 | sizeof(u_int64_t)); 637 | amatrix[i] = (u_int64_t *)calloc((size_t)col_words, 638 | sizeof(u_int64_t)); 639 | } 640 | 641 | /* operations on columns can more conveniently become 642 | operations on rows if all the vectors are first 643 | transposed */ 644 | 645 | transpose_vector(ncols, x, matrix); 646 | transpose_vector(ncols, ax, amatrix); 647 | if (num_deps == 128) { 648 | transpose_vector(ncols, v, matrix + 64); 649 | transpose_vector(ncols, av, amatrix + 64); 650 | } 651 | 652 | /* Keep eliminating rows until the unprocessed part 653 | of amatrix[][] is all zero. The rows where this 654 | happens correspond to linearly dependent vectors 655 | in the nullspace */ 656 | 657 | for (i = bitpos = 0; i < num_deps && bitpos < ncols; bitpos++) { 658 | 659 | /* find the next pivot row */ 660 | 661 | mask = bitmask[bitpos % 64]; 662 | col = bitpos / 64; 663 | for (j = i; j < num_deps; j++) { 664 | if (amatrix[j][col] & mask) { 665 | tmp = matrix[i]; 666 | matrix[i] = matrix[j]; 667 | matrix[j] = tmp; 668 | tmp = amatrix[i]; 669 | amatrix[i] = amatrix[j]; 670 | amatrix[j] = tmp; 671 | break; 672 | } 673 | } 674 | if (j == num_deps) 675 | continue; 676 | 677 | /* a pivot was found; eliminate it from the 678 | remaining rows */ 679 | 680 | for (j++; j < num_deps; j++) { 681 | if (amatrix[j][col] & mask) { 682 | 683 | /* Note that the entire row, *not* 684 | just the nonzero part of it, must 685 | be eliminated; this is because the 686 | corresponding (dense) row of matrix[][] 687 | must have the same operation applied */ 688 | 689 | for (k = 0; k < col_words; k++) { 690 | amatrix[j][k] ^= amatrix[i][k]; 691 | matrix[j][k] ^= matrix[i][k]; 692 | } 693 | } 694 | } 695 | i++; 696 | } 697 | 698 | /* transpose rows i to 64 back into x[] */ 699 | 700 | for (j = 0; j < ncols; j++) { 701 | u_int64_t word = 0; 702 | 703 | col = j / 64; 704 | mask = bitmask[j % 64]; 705 | 706 | for (k = i; k < 64; k++) { 707 | if (matrix[k][col] & mask) 708 | word |= bitmask[k]; 709 | } 710 | x[j] = word; 711 | } 712 | 713 | for (i = 0; i < num_deps; i++) { 714 | free(matrix[i]); 715 | free(amatrix[i]); 716 | } 717 | } 718 | 719 | /*-----------------------------------------------------------------------*/ 720 | u_int64_t * block_lanczos(unsigned long nrows, 721 | unsigned long dense_rows, unsigned long ncols, la_col_t *B) { 722 | 723 | /* Solve Bx = 0 for some nonzero x; the computed 724 | solution, containing up to 64 of these nullspace 725 | vectors, is returned */ 726 | 727 | u_int64_t *vnext, *v[3], *x, *v0; 728 | u_int64_t *winv[3]; 729 | u_int64_t *vt_a_v[2], *vt_a2_v[2]; 730 | u_int64_t *scratch; 731 | u_int64_t *d, *e, *f, *f2; 732 | u_int64_t *tmp; 733 | unsigned long s[2][64]; 734 | unsigned long i, iter; 735 | unsigned long n = ncols; 736 | unsigned long dim0, dim1; 737 | u_int64_t mask0, mask1; 738 | unsigned long vsize; 739 | 740 | /* allocate all of the size-n variables. Note that because 741 | B has been preprocessed to ignore singleton rows, the 742 | number of rows may really be less than nrows and may 743 | be greater than ncols. vsize is the maximum of these 744 | two numbers */ 745 | 746 | vsize = max(nrows, ncols); 747 | v[0] = (u_int64_t *)malloc(vsize * sizeof(u_int64_t)); 748 | v[1] = (u_int64_t *)malloc(vsize * sizeof(u_int64_t)); 749 | v[2] = (u_int64_t *)malloc(vsize * sizeof(u_int64_t)); 750 | vnext = (u_int64_t *)malloc(vsize * sizeof(u_int64_t)); 751 | x = (u_int64_t *)malloc(vsize * sizeof(u_int64_t)); 752 | v0 = (u_int64_t *)malloc(vsize * sizeof(u_int64_t)); 753 | scratch = (u_int64_t *)malloc(max(vsize, 256 * 8) * sizeof(u_int64_t)); 754 | 755 | /* allocate all the 64x64 variables */ 756 | 757 | winv[0] = (u_int64_t *)malloc(64 * sizeof(u_int64_t)); 758 | winv[1] = (u_int64_t *)malloc(64 * sizeof(u_int64_t)); 759 | winv[2] = (u_int64_t *)malloc(64 * sizeof(u_int64_t)); 760 | vt_a_v[0] = (u_int64_t *)malloc(64 * sizeof(u_int64_t)); 761 | vt_a_v[1] = (u_int64_t *)malloc(64 * sizeof(u_int64_t)); 762 | vt_a2_v[0] = (u_int64_t *)malloc(64 * sizeof(u_int64_t)); 763 | vt_a2_v[1] = (u_int64_t *)malloc(64 * sizeof(u_int64_t)); 764 | d = (u_int64_t *)malloc(64 * sizeof(u_int64_t)); 765 | e = (u_int64_t *)malloc(64 * sizeof(u_int64_t)); 766 | f = (u_int64_t *)malloc(64 * sizeof(u_int64_t)); 767 | f2 = (u_int64_t *)malloc(64 * sizeof(u_int64_t)); 768 | 769 | /* The iterations computes v[0], vt_a_v[0], 770 | vt_a2_v[0], s[0] and winv[0]. Subscripts larger 771 | than zero represent past versions of these 772 | quantities, which start off empty (except for 773 | the past version of s[], which contains all 774 | the column indices */ 775 | 776 | memset(v[1], 0, vsize * sizeof(u_int64_t)); 777 | memset(v[2], 0, vsize * sizeof(u_int64_t)); 778 | for (i = 0; i < 64; i++) { 779 | s[1][i] = i; 780 | vt_a_v[1][i] = 0; 781 | vt_a2_v[1][i] = 0; 782 | winv[1][i] = 0; 783 | winv[2][i] = 0; 784 | } 785 | dim0 = 0; 786 | dim1 = 64; 787 | mask1 = (u_int64_t)(-1); 788 | iter = 0; 789 | 790 | /* The computed solution 'x' starts off random, 791 | and v[0] starts off as B*x. This initial copy 792 | of v[0] must be saved off separately */ 793 | 794 | for (i = 0; i < n; i++) 795 | v[0][i] = (u_int64_t)(random32()) << 32 | 796 | (u_int64_t)(random32()); 797 | 798 | memcpy(x, v[0], vsize * sizeof(u_int64_t)); 799 | mul_MxN_Nx64(vsize, dense_rows, ncols, B, v[0], scratch); 800 | mul_trans_MxN_Nx64(dense_rows, ncols, B, scratch, v[0]); 801 | memcpy(v0, v[0], vsize * sizeof(u_int64_t)); 802 | 803 | /* perform the iteration */ 804 | 805 | while (1) { 806 | iter++; 807 | 808 | /* multiply the current v[0] by a symmetrized 809 | version of B, or B'B (apostrophe means 810 | transpose). Use "A" to refer to B'B */ 811 | 812 | mul_MxN_Nx64(vsize, dense_rows, ncols, B, v[0], scratch); 813 | mul_trans_MxN_Nx64(dense_rows, ncols, B, scratch, vnext); 814 | 815 | /* compute v0'*A*v0 and (A*v0)'(A*v0) */ 816 | 817 | mul_64xN_Nx64(v[0], vnext, scratch, vt_a_v[0], n); 818 | mul_64xN_Nx64(vnext, vnext, scratch, vt_a2_v[0], n); 819 | 820 | /* if the former is orthogonal to itself, then 821 | the iteration has finished */ 822 | 823 | for (i = 0; i < 64; i++) { 824 | if (vt_a_v[0][i] != 0) 825 | break; 826 | } 827 | if (i == 64) { 828 | break; 829 | } 830 | 831 | /* Find the size-'dim0' nonsingular submatrix 832 | of v0'*A*v0, invert it, and list the column 833 | indices present in the submatrix */ 834 | 835 | dim0 = find_nonsingular_sub(vt_a_v[0], s[0], 836 | s[1], dim1, winv[0]); 837 | if (dim0 == 0) 838 | break; 839 | 840 | /* mask0 contains one set bit for every column 841 | that participates in the inverted submatrix 842 | computed above */ 843 | 844 | mask0 = 0; 845 | for (i = 0; i < dim0; i++) 846 | mask0 |= bitmask[s[0][i]]; 847 | 848 | /* compute d */ 849 | 850 | for (i = 0; i < 64; i++) 851 | d[i] = (vt_a2_v[0][i] & mask0) ^ vt_a_v[0][i]; 852 | 853 | mul_64x64_64x64(winv[0], d, d); 854 | 855 | for (i = 0; i < 64; i++) 856 | d[i] = d[i] ^ bitmask[i]; 857 | 858 | /* compute e */ 859 | 860 | mul_64x64_64x64(winv[1], vt_a_v[0], e); 861 | 862 | for (i = 0; i < 64; i++) 863 | e[i] = e[i] & mask0; 864 | 865 | /* compute f */ 866 | 867 | mul_64x64_64x64(vt_a_v[1], winv[1], f); 868 | 869 | for (i = 0; i < 64; i++) 870 | f[i] = f[i] ^ bitmask[i]; 871 | 872 | mul_64x64_64x64(winv[2], f, f); 873 | 874 | for (i = 0; i < 64; i++) 875 | f2[i] = ((vt_a2_v[1][i] & mask1) ^ 876 | vt_a_v[1][i]) & mask0; 877 | 878 | mul_64x64_64x64(f, f2, f); 879 | 880 | /* compute the next v */ 881 | 882 | for (i = 0; i < n; i++) 883 | vnext[i] = vnext[i] & mask0; 884 | 885 | mul_Nx64_64x64_acc(v[0], d, scratch, vnext, n); 886 | mul_Nx64_64x64_acc(v[1], e, scratch, vnext, n); 887 | mul_Nx64_64x64_acc(v[2], f, scratch, vnext, n); 888 | 889 | /* update the computed solution 'x' */ 890 | 891 | mul_64xN_Nx64(v[0], v0, scratch, d, n); 892 | mul_64x64_64x64(winv[0], d, d); 893 | mul_Nx64_64x64_acc(v[0], d, scratch, x, n); 894 | 895 | /* rotate all the variables */ 896 | 897 | tmp = v[2]; 898 | v[2] = v[1]; 899 | v[1] = v[0]; 900 | v[0] = vnext; 901 | vnext = tmp; 902 | 903 | tmp = winv[2]; 904 | winv[2] = winv[1]; 905 | winv[1] = winv[0]; 906 | winv[0] = tmp; 907 | 908 | tmp = vt_a_v[1]; vt_a_v[1] = vt_a_v[0]; vt_a_v[0] = tmp; 909 | 910 | tmp = vt_a2_v[1]; vt_a2_v[1] = vt_a2_v[0]; vt_a2_v[0] = tmp; 911 | 912 | memcpy(s[1], s[0], 64 * sizeof(unsigned long)); 913 | mask1 = mask0; 914 | dim1 = dim0; 915 | } 916 | 917 | printf("lanczos halted after %ld iterations\n", iter); 918 | 919 | /* free unneeded storage */ 920 | 921 | free(vnext); 922 | free(scratch); 923 | free(v0); 924 | free(vt_a_v[0]); 925 | free(vt_a_v[1]); 926 | free(vt_a2_v[0]); 927 | free(vt_a2_v[1]); 928 | free(winv[0]); 929 | free(winv[1]); 930 | free(winv[2]); 931 | free(d); 932 | free(e); 933 | free(f); 934 | free(f2); 935 | 936 | /* if a recoverable failure occurred, start everything 937 | over again */ 938 | 939 | if (dim0 == 0) { 940 | #ifdef ERRORS 941 | printf("linear algebra failed; retrying...\n"); 942 | #endif 943 | free(x); 944 | free(v[0]); 945 | free(v[1]); 946 | free(v[2]); 947 | return NULL; 948 | } 949 | 950 | /* convert the output of the iteration to an actual 951 | collection of nullspace vectors */ 952 | 953 | mul_MxN_Nx64(vsize, dense_rows, ncols, B, x, v[1]); 954 | mul_MxN_Nx64(vsize, dense_rows, ncols, B, v[0], v[2]); 955 | 956 | combine_cols(ncols, x, v[0], v[1], v[2]); 957 | 958 | /* verify that these really are linear dependencies of B */ 959 | 960 | mul_MxN_Nx64(vsize, dense_rows, ncols, B, x, v[0]); 961 | 962 | for (i = 0; i < ncols; i++) { 963 | if (v[0][i] != 0) 964 | break; 965 | } 966 | if (i < ncols) { 967 | printf("lanczos error: dependencies don't work %ld\n",i); 968 | abort(); 969 | } 970 | 971 | free(v[0]); 972 | free(v[1]); 973 | free(v[2]); 974 | return x; 975 | } 976 | -------------------------------------------------------------------------------- /src/QS.cpp: -------------------------------------------------------------------------------- 1 | /*============================================================================ 2 | Copyright 2006 William Hart 3 | 4 | This file is part of FLINT. 5 | 6 | FLINT is free software; you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation; either version 2 of the License, or 9 | (at your option) any later version. 10 | 11 | FLINT is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with FLINT; if not, write to the Free Software 18 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 19 | 20 | Description: 21 | 22 | This is a relatively fast implementation of the self-initialising quadratic sieve. 23 | If you manage to improve the code, the author would like to hear about it. 24 | 25 | Contact: hart_wb {at-thingy} yahoo.com 26 | ================================================================================*/ 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | #include "TonelliShanks.h" 38 | #include "ModuloArith.h" 39 | #include "F2matrix.h" 40 | #include "lanczos.h" 41 | #include "lprels.h" 42 | 43 | //=========================================================================== 44 | //Uncomment these for various pieces of debugging information 45 | 46 | #define COUNT // Shows the number of relations generated and curves used during sieving 47 | //#define RELPRINT // Shows the actual factorizations of the relations 48 | //#define ERRORS // Error if relation should be divisible by a prime but isn't 49 | //#define POLS // Shows the polynomials being used by the sieve 50 | //#define ADETAILS // Prints some details about the factors of the A coefficients of the polys 51 | //#define LARGESTP // Prints the size of the largest factorbase prime 52 | //#define CURPARTS // Prints the number of curves used and number of partial relations 53 | //#define TIMING //displays some relative timings, if feature is available 54 | //#define REPORT //report sieve size, multiplier and number of primes used 55 | 56 | //=========================================================================== 57 | //Architecture dependent fudge factors 58 | 59 | #if ULONG_MAX == 4294967295U 60 | #define SIEVEMASK 0xC0C0C0C0U 61 | #define MIDPRIME 1500 62 | #define SIEVEDIV 1 63 | #elif ULONG_MAX == 18446744073709551615U 64 | #define SIEVEMASK 0xC0C0C0C0C0C0C0C0U 65 | #define MIDPRIME 1500 66 | #define SIEVEDIV 1 67 | #endif 68 | 69 | #define CACHEBLOCKSIZE 64000 //Should be a little less than the L1/L2 cache size 70 | //and a multiple of 64000 71 | #define MEDIUMPRIME 900 72 | #define SECONDPRIME 6000 //This should be lower for slower machines 73 | #define FUDGE 0.15 //Every program needs a mysterious fudge factor 74 | 75 | #define MINDIG 40 //Will not factor numbers with less than this number of decimal digits 76 | 77 | #define PREFETCH(addr,n) __builtin_prefetch((unsigned long*)addr+n,0,1) 78 | 79 | //=========================================================================== 80 | //Knuth-Schroeppel multipliers and a macro to count them 81 | 82 | static const unsigned long multipliers[] = {1, 2, 3, 5, 7, 11, 13, 17, 19, 83 | 23, 29, 31, 37, 41, 43}; 84 | 85 | #define NUMMULTS (sizeof(multipliers)/sizeof(unsigned long)) 86 | 87 | //=========================================================================== 88 | // Large prime cutoffs 89 | 90 | unsigned long largeprimes[] = 91 | { 92 | 250000, 300000, 370000, 440000, 510000, 580000, 650000, 720000, 790000, 8600000, //40-49 93 | 930000, 1000000, 1700000, 2400000, 3100000, 3800000, 4500000, 5200000, 5900000, 6600000, //50-59 94 | 7300000, 8000000, 8900000, 10000000, 11300000, 12800000, 14500000, 16300000, 18100000, 20000000, //60-69 95 | 22000000, 24000000, 27000000, 32000000, 39000000, //70-74 96 | 53000000, 65000000, 75000000, 87000000, 100000000, //75-79 97 | 114000000, 130000000, 150000000, 172000000, 195000000, //80-84 98 | 220000000, 250000000, 300000000, 350000000, 400000000, //85-89 99 | 450000000, 500000000 //90-91 100 | }; 101 | 102 | //============================================================================ 103 | // Number of primes to use in factor base, given the number of decimal digits specified 104 | unsigned long primesNo[] = 105 | { 106 | 1500, 1500, 1600, 1700, 1750, 1800, 1900, 2000, 2050, 2100, //40-49 107 | 2150, 2200, 2250, 2300, 2400, 2500, 2600, 2700, 2800, 2900, //50-59 108 | 3000, 3150, 5500, 6000, 6500, 7000, 7500, 8000, 8500, 9000, //60-69 109 | 9500, 10000, 11500, 13000, 15000, //70-74 110 | 17000, 24000, 27000, 30000, 37000, //75-79 111 | 45000, 47000, 53000, 57000, 58000, //80-84 112 | 59000, 60000, 64000, 68000, 72000, //85-89 113 | 76000, 80000 //90-91 114 | }; 115 | 116 | //============================================================================ 117 | // First prime actually sieved for 118 | unsigned long firstPrimes[] = 119 | { 120 | 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, //40-49 121 | 9, 8, 9, 9, 9, 9, 10, 10, 10, 10, //50-59 122 | 10, 10, 11, 11, 12, 12, 13, 14, 15, 17, //60-69 //10 123 | 19, 21, 22, 22, 23, //70-74 124 | 24, 25, 25, 26, 26, //75-79 125 | 27, 27, 27, 27, 28, //80-84 126 | 28, 28, 28, 29, 29, //85-89 127 | 29, 29 //90-91 128 | }; 129 | 130 | //============================================================================ 131 | // Logs of primes are rounded and errors accumulate; this specifies how great an error to allow 132 | unsigned long errorAmounts[] = 133 | { 134 | 16, 17, 17, 18, 18, 19, 19, 19, 20, 20, //40-49 135 | 21, 21, 21, 22, 22, 22, 23, 23, 23, 24, //50-59 136 | 24, 24, 25, 25, 25, 25, 26, 26, 26, 26, //60-69 //24 137 | 27, 27, 28, 28, 29, //70-74 138 | 29, 30, 30, 30, 31, //75-79 139 | 31, 31, 31, 32, 32, //80-84 140 | 32, 32, 32, 33, 33, //85-89 141 | 33, 33 //90-91 142 | }; 143 | 144 | //============================================================================ 145 | // This is the threshold the sieve value must exceed in order to be considered for smoothness 146 | unsigned long thresholds[] = 147 | { 148 | 66, 67, 67, 68, 68, 68, 69, 69, 69, 69, //40-49 149 | 70, 70, 70, 71, 71, 71, 72, 72, 73, 73, //50-59 150 | 74, 74, 75, 75, 76, 76, 77, 77, 78, 79, //60-69 //74 151 | 80, 81, 82, 83, 84, //70-74 152 | 85, 86, 87, 88, 89, //75-79 153 | 91, 92, 93, 93, 94, //80-84 154 | 95, 96, 97, 98, 100, //85-89 155 | 101, 102 //90-91 156 | }; 157 | 158 | //============================================================================ 159 | // Size of sieve to use divided by 2, given the number of decimal digits specified 160 | //N.B: probably optimal if chosen to be a multiple of 32000, though other sizes are supported 161 | unsigned long sieveSize[] = 162 | { 163 | 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, //40-49 164 | 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, //50-59 165 | 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, //60-69 166 | 32000, 32000, 64000, 64000, 64000, //70-74 167 | 96000, 96000, 96000, 128000, 128000, //75-79 168 | 160000, 160000, 160000, 160000, 160000, //80-84 169 | 192000, 192000, 192000, 192000, 192000, //85-89 170 | 192000, 192000 //90-91 171 | }; 172 | 173 | // Athlon tuning parameters 174 | /*unsigned long sieveSize[] = 175 | { 176 | 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, //40-49 177 | 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, //50-59 178 | 64000, 64000, 64000, 64000, 64000, 64000, 64000, 64000, 64000, 64000, //60-69 179 | 64000, 64000, 64000, 64000, 64000, //70-74 180 | 128000, 128000, 128000, 128000, 128000, //75-79 181 | 160000, 160000, 160000, 160000, 160000, //80-84 182 | 192000, 192000, 192000, 192000, 192000, //85-89 183 | 192000, 192000 //90-91 184 | };*/ 185 | 186 | //============================================================================ 187 | long decdigits; //number of decimal digits of n 188 | unsigned long secondprime; //min(numprimes, SECONDPRIME) = cutoff for using flags when sieving 189 | unsigned long firstprime; //first prime actually sieved with 190 | unsigned char errorbits; //first prime actually sieved with 191 | unsigned char threshold; //sieve threshold cutoff for smooth relations 192 | unsigned long midprime; 193 | unsigned long largeprime; 194 | 195 | unsigned long * factorBase; //array of factor base primes 196 | unsigned long numPrimes; //number of primes in factor base 197 | unsigned long relSought; //number of relations sought, i.e. a "few" more than numPrimes 198 | unsigned char * primeSizes; //array of sizes in bits, of the factor base primes 199 | unsigned char * sieve; //actual array where sieving takes place 200 | unsigned char * * offsets; //offsets for each prime to use in sieve 201 | unsigned char * * offsets2; //offsets for each prime to use in sieve (we switch between these) 202 | unsigned long relsFound =0; //number of relations found so far 203 | unsigned long potrels = 0; //potential relations (including duplicates) 204 | unsigned char * flags; //flags used for speeding up sieving for large primes 205 | unsigned long partials = 0; //number of partial relations 206 | unsigned long Mdiv2; //size of sieving interval divide 2 207 | unsigned long mat2off; //offset of second square block in matrix 208 | 209 | mpz_t * sqrts; //square roots of n modulo each prime in the factor base 210 | 211 | mpz_t n; //number to be factored 212 | mpz_t res; //smooth values which are trial factored 213 | 214 | mpz_t temp, temp2, temp3; //temporary variables 215 | mpz_t q,r; //quotient and remainder 216 | 217 | //Variables used for keeping time 218 | 219 | unsigned long clockstart; 220 | unsigned long clocktotal = 0; 221 | 222 | //Variables used by the modular inversion macro function 223 | long u1, u3; 224 | long v1, v3; 225 | long t1, t3, quot; 226 | 227 | //Variable used for random function 228 | unsigned long randval = 2994439072U; 229 | 230 | //========================================================================================== 231 | //Timing: provides some relative timings on X86 machines running gcc 232 | 233 | #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) 234 | 235 | #ifdef TIMING 236 | #define TIMES 237 | #endif 238 | 239 | double counterfirst[4]; 240 | double countertotal[4] = {0,0,0,0}; 241 | 242 | static unsigned counthi = 0; 243 | static unsigned countlo = 0; 244 | 245 | void counterasm(unsigned *hi, unsigned *lo) 246 | { 247 | asm("rdtsc; movl %%edx,%0; movl %%eax,%1" 248 | : "=r" (*hi), "=r" (*lo) 249 | : 250 | : "%edx", "%eax"); 251 | } 252 | 253 | double getcounter() 254 | { 255 | double total; 256 | 257 | counterasm(&counthi, &countlo); 258 | 259 | total = (double) counthi * (1 << 30) * 4 + countlo; 260 | return total; 261 | } 262 | 263 | #endif 264 | 265 | /*======================================================================== 266 | Modular Inversion: 267 | 268 | Function: GMP has a modular inverse function, but believe it or not, 269 | this clumsy implementation is apparently quite a bit faster. 270 | It inverts the value a, modulo the prime p, using the extended 271 | gcd algorithm. 272 | 273 | ========================================================================*/ 274 | 275 | inline unsigned long modinverse(unsigned long a, unsigned long p) 276 | { 277 | u1=1; u3=a; 278 | v1=0; v3=p; 279 | t1=0; t3=0; 280 | while (v3) 281 | { 282 | quot=u3-v3; 283 | if (u3 < (v3<<2)) 284 | { 285 | if (quot < v3) 286 | { 287 | if (quot < 0) 288 | { 289 | t1 = u1; u1 = v1; v1 = t1; 290 | t3 = u3; u3 = v3; v3 = t3; 291 | } else 292 | { 293 | t1 = u1 - v1; u1 = v1; v1 = t1; 294 | t3 = u3 - v3; u3 = v3; v3 = t3; 295 | } 296 | } else if (quot < (v3<<1)) 297 | { 298 | t1 = u1 - (v1<<1); u1 = v1; v1 = t1; 299 | t3 = u3 - (v3<<1); u3 = v3; v3 = t3; 300 | } else 301 | { 302 | t1 = u1 - v1*3; u1 = v1; v1 = t1; 303 | t3 = u3 - v3*3; u3 = v3; v3 = t3; 304 | } 305 | } else 306 | { 307 | quot=u3/v3; 308 | t1 = u1 - v1*quot; u1 = v1; v1 = t1; 309 | t3 = u3 - v3*quot; u3 = v3; v3 = t3; 310 | } 311 | } 312 | 313 | if (u1<0) u1+=p; 314 | 315 | return u1; 316 | } 317 | 318 | /*========================================================================= 319 | Knuth_Schroeppel Multiplier: 320 | 321 | Function: Find the best multiplier to use (allows 2 as a multiplier). 322 | The general idea is to find a multiplier k such that kn will 323 | be faster to factor. This is achieved by making kn a square 324 | modulo lots of small primes. These primes will then be factor 325 | base primes, and the more small factor base primes, the faster 326 | relations will accumulate, since they hit the sieving interval 327 | more often. 328 | 329 | ==========================================================================*/ 330 | unsigned long knuthSchroeppel(mpz_t n) 331 | { 332 | float bestFactor = -10.0f; 333 | unsigned long multiplier = 1; 334 | unsigned long nmod8; 335 | float factors[NUMMULTS]; 336 | float logpdivp; 337 | mpz_t prime, r, mult; 338 | long kron, multindex; 339 | 340 | mpz_init(prime); 341 | mpz_init(r); 342 | mpz_init(mult); 343 | 344 | nmod8 = mpz_fdiv_r_ui(r,n,8); 345 | 346 | for (multindex = 0; multindex < NUMMULTS; multindex++) 347 | { 348 | long mod = nmod8*multipliers[multindex]%8; 349 | factors[multindex] = 0.34657359; // ln2/2 350 | if (mod == 1) factors[multindex] *= 4.0; 351 | if (mod == 5) factors[multindex] *= 2.0; 352 | factors[multindex] -= (log((float) multipliers[multindex]) / 2.0); 353 | } 354 | 355 | mpz_set_ui(prime,3); 356 | while (mpz_cmp_ui(prime,10000)<0) 357 | { 358 | logpdivp = log((float)mpz_get_ui(prime)) / mpz_get_ui(prime); 359 | kron = mpz_kronecker(n,prime); 360 | for (multindex = 0; multindex < NUMMULTS; multindex++) 361 | { 362 | mpz_set_ui(mult,multipliers[multindex]); 363 | switch (kron*mpz_kronecker(mult,prime)) 364 | { 365 | case 0: 366 | { 367 | factors[multindex] += logpdivp; 368 | } break; 369 | case 1: 370 | { 371 | factors[multindex] += 2.0*logpdivp; 372 | } break; 373 | default: break; 374 | } 375 | } 376 | 377 | mpz_nextprime(prime,prime); 378 | } 379 | 380 | for (multindex=0; multindex bestFactor) 383 | { 384 | bestFactor = factors[multindex]; 385 | multiplier = multipliers[multindex]; 386 | } 387 | } 388 | 389 | mpz_clear(prime); 390 | mpz_clear(r); 391 | mpz_clear(mult); 392 | 393 | return multiplier; 394 | } 395 | 396 | 397 | 398 | /*======================================================================== 399 | Initialize Quadratic Sieve: 400 | 401 | Function: Initialises the global gmp variables. 402 | 403 | ========================================================================*/ 404 | void initSieve(void) 405 | { 406 | mpz_init(n); 407 | mpz_init(temp); 408 | mpz_init(temp2); 409 | mpz_init(temp3); 410 | mpz_init(res); 411 | mpz_init(q); 412 | mpz_init(r); 413 | 414 | return; 415 | } 416 | 417 | /*======================================================================== 418 | Compute Factor Base: 419 | 420 | Function: Computes primes p up to B for which n is a square mod p, 421 | allocates memory and stores them in an array pointed to by factorBase 422 | Returns: number of primes actually in the factor base 423 | 424 | ========================================================================*/ 425 | void computeFactorBase(mpz_t n, unsigned long B,unsigned long multiplier) 426 | { 427 | mpz_t currentPrime; 428 | unsigned long primesinbase = 0; 429 | 430 | factorBase = (unsigned long *) calloc(sizeof(unsigned long),B); 431 | 432 | factorBase[primesinbase] = multiplier; 433 | primesinbase++; 434 | if (multiplier!=2) 435 | { 436 | factorBase[primesinbase] = 2; 437 | primesinbase++; 438 | } 439 | mpz_init_set_ui(currentPrime,3); 440 | while (primesinbase < B) 441 | { 442 | if (mpz_kronecker(n,currentPrime)==1) 443 | { 444 | factorBase[primesinbase] = mpz_get_ui(currentPrime); 445 | primesinbase++; 446 | } 447 | mpz_nextprime(currentPrime,currentPrime); 448 | } 449 | #ifdef LARGESTP 450 | gmp_printf("Largest prime less than %Zd\n",currentPrime); 451 | #endif 452 | 453 | mpz_clear(currentPrime); 454 | return; 455 | } 456 | 457 | /*=========================================================================== 458 | Compute Prime Sizes: 459 | 460 | Function: Computes the size in bits of each prime in the factor base 461 | allocates memory for an array, primeSizes, to store the sizes 462 | stores the size for each of the numPrimes primes in the array 463 | 464 | ===========================================================================*/ 465 | void computeSizes(unsigned long numPrimes) 466 | { 467 | primeSizes = (unsigned char *) calloc(sizeof(unsigned char),numPrimes); 468 | for (unsigned long i = 0; i 0) printf(" %ld",(long)factorBase[k]); 586 | if (exponent > 1) printf("^%ld",exponent); 587 | #endif 588 | exponents[k] = exponent; 589 | } else exponents[k] = 0; 590 | } else 591 | { 592 | mpz_set_ui(temp,factorBase[k]); 593 | exponent = mpz_remove(res,res,temp); 594 | if (exponent) extra+=primeSizes[k]; 595 | #ifdef RELPRINT 596 | if (exponent > 0) gmp_printf(" %Zd",factorBase[k]); 597 | if (exponent > 1) printf("^%ld",exponent); 598 | #endif 599 | exponents[k] = exponent; 600 | } 601 | } 602 | factnum = 0; 603 | sieve[i]+=extra; 604 | if (sieve[i] >= bits) 605 | { 606 | vv=((unsigned char)1<<(i&7)); 607 | for (k = firstprime; (k 0) printf(" %ld",(long)factorBase[k]); 624 | if (exponent > 1) printf("^%ld",exponent); 625 | #endif 626 | factors[factnum+1] = k; 627 | factors[factnum] = exponent; 628 | factnum+=2; 629 | } 630 | } else 631 | { 632 | mpz_set_ui(temp,factorBase[k]); 633 | exponent = mpz_remove(res,res,temp); 634 | if (exponent) extra+=primeSizes[k]; 635 | 636 | #ifdef RELPRINT 637 | if (exponent > 0) printf(" %ld",(long)factorBase[k]); 638 | if (exponent > 1) printf("^%ld",exponent); 639 | #endif 640 | if (exponent) 641 | { 642 | factors[factnum+1] = k; 643 | factors[factnum] = exponent; 644 | factnum+=2; 645 | } 646 | } 647 | } 648 | 649 | for (k = secondprime; (k 0) printf(" %ld",(long)factorBase[k]); 664 | if (exponent > 1) printf("^%ld",exponent); 665 | #endif 666 | factors[factnum+1] = k; 667 | factors[factnum] = exponent; 668 | factnum+=2; 669 | } 670 | } 671 | } 672 | 673 | last_ptr = rel_str; 674 | if (mpz_cmp_ui(res,1000)>0) 675 | { 676 | if (mpz_cmp_ui(res,largeprime)<0) 677 | { 678 | for (unsigned long i = 0; i < firstprime; i++) 679 | { 680 | if (exponents[i]) add_factor(&last_ptr, (unsigned long) exponents[i], (unsigned long) i); 681 | } 682 | for (unsigned long i = 0; i < factnum; i+=2) 683 | { 684 | add_factor(&last_ptr, (unsigned long) factors[i], (unsigned long) factors[i+1]); 685 | } 686 | for (long i =0; i0) 704 | { 705 | if (mpz_cmp_ui(res,largeprime)<0) 706 | { 707 | for (unsigned long i = 0; i < firstprime; i++) 708 | { 709 | if (exponents[i]) add_factor(&last_ptr, (unsigned long) exponents[i], (unsigned long) i); 710 | } 711 | for (unsigned long i = 0; i < factnum; i+=2) 712 | { 713 | add_factor(&last_ptr, (unsigned long) factors[i], (unsigned long) factors[i+1]); 714 | } 715 | for (long i =0; i=currentprime) soln1[prime]-=currentprime; 800 | soln2[prime]+=correction; 801 | while (soln2[prime]>=currentprime) soln2[prime]-=currentprime; 802 | } 803 | } 804 | 805 | for (unsigned long prime=firstprime; prime=currentprime) soln1[prime]-=currentprime; 816 | soln2[prime]+=correction; 817 | while (soln2[prime]>=currentprime) soln2[prime]-=currentprime; 818 | 819 | position = sieve+soln1[prime]; 820 | position2 = sieve+soln2[prime]; 821 | } else 822 | { 823 | position = offsets[prime]; 824 | position2 = offsets2[prime]; 825 | } 826 | diff=position2-position; 827 | 828 | ptimes4 = currentprime*4; 829 | register unsigned char * bound=end-ptimes4; 830 | while (bound - position > 0) 831 | { 832 | (* position)+=currentprimesize,(* (position+diff))+=currentprimesize, position+=currentprime; 833 | (* position)+=currentprimesize,(* (position+diff))+=currentprimesize, position+=currentprime; 834 | (* position)+=currentprimesize,(* (position+diff))+=currentprimesize, position+=currentprime; 835 | (* position)+=currentprimesize,(* (position+diff))+=currentprimesize, position+=currentprime; 836 | } 837 | while ((end - position > 0)&&(end - position - diff > 0)) 838 | { 839 | (* position)+=currentprimesize,(* (position+diff))+=currentprimesize, position+=currentprime; 840 | 841 | } 842 | position2 = position+diff; 843 | if (end - position2 > 0) 844 | { 845 | (* position2)+=currentprimesize, position2+=currentprime; 846 | } 847 | if (end - position > 0) 848 | { 849 | (* position)+=currentprimesize, position+=currentprime; 850 | } 851 | 852 | if (!last) 853 | { 854 | offsets[prime] = position; 855 | offsets2[prime] = position2; 856 | } 857 | } 858 | 859 | for (unsigned long prime=MEDIUMPRIME; prime=currentprime) soln1[prime]-=currentprime; 869 | soln2[prime]+=correction; 870 | while (soln2[prime]>=currentprime) soln2[prime]-=currentprime; 871 | 872 | position = sieve+soln1[prime]; 873 | position2 = sieve+soln2[prime]; 874 | } else 875 | { 876 | position = offsets[prime]; 877 | position2 = offsets2[prime]; 878 | } 879 | diff=position2-position; 880 | 881 | ptimes4 = 2*currentprime; 882 | register unsigned char * bound=end-ptimes4; 883 | while (bound - position > 0) 884 | { 885 | (* position)+=currentprimesize,(* (position+diff))+=currentprimesize, position+=currentprime; 886 | (* position)+=currentprimesize,(* (position+diff))+=currentprimesize, position+=currentprime; 887 | } 888 | position2 = position+diff; 889 | while ((end - position > 0)&&(end - position2 > 0)) 890 | { 891 | (* position)+=currentprimesize, position+=currentprime, (* position2)+=currentprimesize, position2+=currentprime; 892 | 893 | } 894 | 895 | if (end - position2 > 0) 896 | { 897 | (* position2)+=currentprimesize, position2+=currentprime; 898 | } 899 | if (end - position > 0) 900 | { 901 | (* position)+=currentprimesize, position+=currentprime; 902 | } 903 | if (!last) 904 | { 905 | offsets[prime] = position; 906 | offsets2[prime] = position2; 907 | } 908 | } 909 | 910 | return; 911 | } 912 | 913 | /*=========================================================================== 914 | Sieve 2: 915 | 916 | Function: Second sieve for larger primes 917 | 918 | =========================================================================== */ 919 | void sieve2(unsigned long M, unsigned long numPrimes, unsigned char * sieve, long last, long first, long polyadd, unsigned long * soln1, unsigned long * soln2, unsigned long * polycorr, unsigned char * * offsets, unsigned char * * offsets2) 920 | { 921 | register unsigned char currentprimesize; 922 | register unsigned long currentprime; 923 | register unsigned char * position2; 924 | register unsigned char * position; 925 | unsigned char * end; 926 | long correction; 927 | 928 | memset(sieve,0,M*sizeof(unsigned char)); 929 | memset(flags,0,numPrimes*sizeof(unsigned char)); 930 | end = sieve+M; 931 | *end = 255; //sentinel to speed up sieve evaluators inner loop 932 | 933 | for (unsigned long prime=midprime; prime=currentprime) soln1[prime]-=currentprime; 941 | soln2[prime]+=correction; 942 | while (soln2[prime]>=currentprime) soln2[prime]-=currentprime; 943 | 944 | position = sieve+soln1[prime]; 945 | position2 = sieve+soln2[prime]; 946 | 947 | while ((end - position > 0)&&(end - position2 > 0)) 948 | { 949 | (* position)+=currentprimesize, position+=currentprime, (* position2)+=currentprimesize, position2+=currentprime; 950 | } 951 | 952 | if (end - position2 > 0) 953 | { 954 | (* position2)+=currentprimesize; 955 | } 956 | if (end - position > 0) 957 | { 958 | (* position)+=currentprimesize; 959 | } 960 | } 961 | 962 | for (unsigned long prime=secondprime; prime=currentprime) soln1[prime]-=currentprime; 970 | soln2[prime]+=correction; 971 | while (soln2[prime]>=currentprime) soln2[prime]-=currentprime; 972 | 973 | position = sieve+soln1[prime]; 974 | position2 = sieve+soln2[prime]; 975 | 976 | while (end - position > 0) 977 | { 978 | flags[prime]|=((unsigned char)1<<((position-sieve)&7)), (* position)+=currentprimesize, position+=currentprime; 979 | } 980 | 981 | while (end - position2 > 0) 982 | { 983 | flags[prime]|=((unsigned char)1<<((position2-sieve)&7)), (* position2)+=currentprimesize, position2+=currentprime; 984 | } 985 | } 986 | 987 | return; 988 | } 989 | 990 | /*============================================================================ 991 | 992 | random: 993 | 994 | Function: Generates a pseudo-random integer between 0 and n-1 inclusive 995 | 996 | ============================================================================*/ 997 | unsigned long random(unsigned long upto) 998 | { 999 | randval = ((u_int64_t)randval*1025416097U+286824428U)%(u_int64_t)4294967291U; 1000 | return randval%upto; 1001 | } 1002 | 1003 | 1004 | /*============================================================================ 1005 | mainRoutine: 1006 | 1007 | Function: Generates the polynomials, initialises and calls the sieve, 1008 | implementing cache blocking (breaking the sieve interval into 1009 | small blocks for the small primes. 1010 | 1011 | ============================================================================*/ 1012 | void mainRoutine(unsigned long Mdiv2, mpz_t n, unsigned long multiplier) 1013 | { 1014 | mpz_t A; mpz_init(A); 1015 | mpz_t B; mpz_init(B); 1016 | mpz_t C; mpz_init(C); 1017 | mpz_t D; mpz_init(D); 1018 | mpz_t temp; mpz_init(temp); 1019 | mpz_t temp2; mpz_init(temp2); 1020 | mpz_t q; mpz_init(q); 1021 | mpz_t r; mpz_init(r); 1022 | mpz_t Bdivp2; mpz_init(Bdivp2); 1023 | mpz_t factor; mpz_init(factor); 1024 | 1025 | unsigned long u1; 1026 | 1027 | long s, fact, span, min; 1028 | unsigned long p; 1029 | unsigned long reps; 1030 | 1031 | unsigned long curves = 0; 1032 | 1033 | unsigned long ** relations; 1034 | long * primecount; 1035 | 1036 | long * exponents = (long *) calloc(firstprime,sizeof(long)); 1037 | if (exponents==NULL) 1038 | { 1039 | printf("Unable to allocate memory!\n"); 1040 | abort(); 1041 | } 1042 | unsigned long factors[200]; 1043 | char rel_str[MPQS_STRING_LENGTH]; 1044 | 1045 | unsigned long totcomb = 0; 1046 | 1047 | unsigned long next_cutoff = (relSought - 1)/40 +1; 1048 | unsigned long next_inc = next_cutoff; 1049 | 1050 | FILE * LPNEW; 1051 | FILE * LPRELS; 1052 | FILE * COMB; 1053 | FILE * FNEW; 1054 | FILE * RELS; 1055 | FILE * FRELS; 1056 | FILE * FLPRELS; 1057 | LPNEW = flint_fopen("lpnew","w"); 1058 | LPRELS = flint_fopen("lprels","w"); 1059 | RELS = flint_fopen("rels","w"); 1060 | FNEW = flint_fopen("fnew","w"); 1061 | fclose(FNEW); 1062 | FLPRELS = flint_fopen("flprels","w"); 1063 | fclose(FLPRELS); 1064 | FRELS = flint_fopen("frels","w"); 1065 | fclose(LPRELS); 1066 | fclose(FRELS); 1067 | 1068 | 1069 | #ifdef TIMES 1070 | counterfirst[2] = getcounter(); 1071 | #endif 1072 | s = mpz_sizeinbase(n,2)/28+1; 1073 | 1074 | unsigned long * aind = (unsigned long*) calloc(sizeof(unsigned long),s); 1075 | unsigned long * amodp = (unsigned long*) calloc(sizeof(unsigned long),s); 1076 | unsigned long * Ainv = (unsigned long*) calloc(sizeof(unsigned long),numPrimes); 1077 | unsigned long * soln1 = (unsigned long*) calloc(sizeof(unsigned long),numPrimes); 1078 | unsigned long * soln2 = (unsigned long*) calloc(sizeof(unsigned long),numPrimes); 1079 | unsigned long ** Ainv2B = (unsigned long**) calloc(sizeof(unsigned long*),s); 1080 | if (Ainv2B==NULL) 1081 | { 1082 | printf("Unable to allocate memory!\n"); 1083 | abort(); 1084 | } 1085 | for (long i=0; i=0; fact++); 1133 | span = numPrimes/s/s/2; 1134 | min=fact-span/2; 1135 | while ((fact*fact)/min - min < span) {min--;} 1136 | 1137 | #ifdef ADETAILS 1138 | printf("s = %ld, fact = %ld, min = %ld, span = %ld\n",s,fact,min,span); 1139 | #endif 1140 | 1141 | //Compute first polynomial and adjustments 1142 | 1143 | while (relsFound + totcomb < relSought) 1144 | { 1145 | long i,j; 1146 | long ran; 1147 | 1148 | mpz_set_ui(A,1); 1149 | 1150 | for (i = 0; i < s-1; ) 1151 | { 1152 | j=-1L; 1153 | ran = span/2+random(span/2); 1154 | while (j!=i) 1155 | { 1156 | ran++; 1157 | for (j=0;((j=0; fact++); 1179 | fact-=min; 1180 | do 1181 | { 1182 | for (j=0;((j0) 1199 | { 1200 | mpz_sub_ui(temp,temp,p); 1201 | mpz_neg(temp,temp); 1202 | } 1203 | mpz_mul(temp,temp,A); 1204 | mpz_div_ui(Bterms[i],temp,p); 1205 | } 1206 | 1207 | mpz_set(B,Bterms[0]); 1208 | for (long i=1; i>j)&1)!=0) break; 1244 | } 1245 | if ((polyadd = (((polyindex>>j)&2)!=0))) 1246 | { 1247 | mpz_add(B,B,Bterms[j]); 1248 | mpz_add(B,B,Bterms[j]); 1249 | } else 1250 | { 1251 | mpz_sub(B,B,Bterms[j]); 1252 | mpz_sub(B,B,Bterms[j]); 1253 | } 1254 | polycorr = Ainv2B[j]; 1255 | 1256 | long index; 1257 | for (long j=0; j0) 1300 | { 1301 | for (reps = 1;reps < mpz_get_ui(q)-1; reps++) 1302 | { 1303 | sieveInterval(CACHEBLOCKSIZE,numPrimes,sieve+CACHEBLOCKSIZE*reps,0,0,polyadd,soln1,soln2,polycorr,offsets,offsets2); 1304 | } 1305 | if (mpz_cmp_ui(r,0)==0) 1306 | { 1307 | sieveInterval(CACHEBLOCKSIZE,numPrimes,sieve+CACHEBLOCKSIZE*reps,1,0,polyadd,soln1,soln2,polycorr,offsets,offsets2); 1308 | } else 1309 | { 1310 | sieveInterval(CACHEBLOCKSIZE,numPrimes,sieve+CACHEBLOCKSIZE*reps,0,0,polyadd,soln1,soln2,polycorr,offsets,offsets2); 1311 | reps++; 1312 | sieveInterval(mpz_get_ui(r),numPrimes,sieve+CACHEBLOCKSIZE*reps,1,0,polyadd,soln1,soln2,polycorr,offsets,offsets2); 1313 | } 1314 | } 1315 | 1316 | #ifdef TIMES 1317 | countertotal[0]+=(getcounter()-counterfirst[0]); 1318 | counterfirst[1] = getcounter(); 1319 | #endif 1320 | evaluateSieve(relations,0,mpz_get_ui(temp),sieve,A,B,C,soln1, soln2, polyadd, polycorr,XArr,aind,min,s,multiplier,exponents,colarray,factors,rel_str,LPNEW,RELS); 1321 | 1322 | if (2*potrels >= next_cutoff) 1323 | { 1324 | fclose(LPNEW); 1325 | sort_lp_file("lpnew"); 1326 | COMB = flint_fopen("comb","w"); 1327 | mergesort_lp_file("lprels", "lpnew", "tmp", COMB); 1328 | fclose(COMB); 1329 | LPNEW = flint_fopen("lpnew","w"); 1330 | 1331 | fclose(RELS); 1332 | sort_lp_file("rels"); 1333 | relsFound = mergesort_lp_file("frels","rels","tmp2",NULL); 1334 | RELS = flint_fopen("rels","w"); 1335 | 1336 | COMB = flint_fopen("comb", "r"); 1337 | FNEW = flint_fopen("fnew","w"); 1338 | combine_large_primes(numPrimes, COMB, FNEW, n, factor); 1339 | fclose(FNEW); 1340 | fclose(COMB); 1341 | sort_lp_file("fnew"); 1342 | totcomb = mergesort_lp_file("flprels","fnew","tmp3",NULL); 1343 | #ifdef COUNT 1344 | printf("%ld full relations, %ld combined relations\n",relsFound,totcomb); 1345 | #endif 1346 | if ((next_cutoff < relSought) && (next_cutoff + next_inc/2 >= relSought)) 1347 | next_inc = next_inc/2; 1348 | next_cutoff += next_inc; 1349 | } 1350 | #ifdef TIMES 1351 | countertotal[1]+=(getcounter()-counterfirst[1]); 1352 | #endif 1353 | } 1354 | 1355 | #ifdef COUNT 1356 | if (curves%20==0) printf("%ld curves.\n",(long)curves); 1357 | #endif 1358 | } 1359 | 1360 | #ifdef CURPARTS 1361 | printf("%ld curves, %ld partials.\n",(long)curves,(long)partials); 1362 | #endif 1363 | 1364 | #ifdef REPORT 1365 | printf("Done with sieving!\n"); 1366 | #endif 1367 | 1368 | unsigned long ncols = relSought; 1369 | unsigned long nrows = numPrimes; 1370 | 1371 | #ifdef ERRORS 1372 | for (unsigned long j = relsFound; j numPrimes) printf("Error prime too large: %ld\n",colarray[j].data[i]); 1406 | 1407 | mpz_t test1; 1408 | mpz_init(test1); 1409 | mpz_t test2; 1410 | mpz_init(test2); 1411 | mpz_t test3; 1412 | mpz_init(test3); 1413 | unsigned long * exps = (unsigned long *) malloc(numPrimes*sizeof(unsigned long)); 1414 | for (unsigned long j = 0; j=40 decimal digits]: "); 1573 | gmp_scanf("%Zd",n);getchar(); 1574 | 1575 | decdigits = mpz_sizeinbase(n,10); 1576 | if (decdigits < 40) 1577 | { 1578 | printf("Error in input or number has too few digits.\n"); 1579 | abort(); 1580 | } 1581 | 1582 | multiplier = knuthSchroeppel(n); 1583 | mpz_mul_ui(n,n,multiplier); 1584 | 1585 | if (decdigits<=91) 1586 | { 1587 | numPrimes=primesNo[decdigits-MINDIG]; 1588 | 1589 | Mdiv2 = sieveSize[decdigits-MINDIG]/SIEVEDIV; 1590 | if (Mdiv2*2 < CACHEBLOCKSIZE) Mdiv2 = CACHEBLOCKSIZE/2; 1591 | largeprime = largeprimes[decdigits-MINDIG]; 1592 | 1593 | #ifdef REPORT 1594 | printf("Using multiplier: %ld\n",(long)multiplier); 1595 | printf("%ld primes in factor base.\n",(long)numPrimes); 1596 | printf("Sieving interval M = %ld\n",(long)Mdiv2*2); 1597 | printf("Large prime cutoff = factorBase[%ld]\n",largeprime); 1598 | #endif 1599 | 1600 | if (numPrimes < SECONDPRIME) secondprime = numPrimes; 1601 | else secondprime = SECONDPRIME; 1602 | if (numPrimes < MIDPRIME) midprime = numPrimes; 1603 | else midprime = MIDPRIME; 1604 | 1605 | firstprime = firstPrimes[decdigits-MINDIG]; 1606 | errorbits = errorAmounts[decdigits-MINDIG]; 1607 | threshold = thresholds[decdigits-MINDIG]; 1608 | 1609 | } else //all bets are off 1610 | { 1611 | numPrimes = 64000; 1612 | Mdiv2 = 192000/SIEVEDIV; 1613 | largeprime = numPrimes*10*decdigits; 1614 | 1615 | #ifdef REPORT 1616 | printf("Using multiplier: %ld\n",(long)multiplier); 1617 | printf("%ld primes in factor base.\n",(long)numPrimes); 1618 | printf("Sieving interval M = %ld\n",(long)Mdiv2*2); 1619 | printf("Large prime cutoff = factorBase[%ld]\n",largeprime); 1620 | #endif 1621 | 1622 | secondprime = SECONDPRIME; 1623 | midprime = MIDPRIME; 1624 | firstprime = 30; 1625 | errorbits = decdigits/4 + 2; 1626 | threshold = 43+(7*decdigits)/10; 1627 | 1628 | } 1629 | relSought = numPrimes+64; 1630 | computeFactorBase(n, numPrimes, multiplier); 1631 | 1632 | computeSizes(numPrimes); 1633 | 1634 | TonelliInit(); 1635 | tonelliShanks(numPrimes,n); 1636 | 1637 | mainRoutine(Mdiv2, n,multiplier); 1638 | 1639 | getchar(); 1640 | #if defined(WINCE) || defined(macintosh) 1641 | char * tmp_dir = NULL; 1642 | #else 1643 | char * tmp_dir = getenv("TMPDIR"); 1644 | #endif 1645 | if (tmp_dir == NULL) tmp_dir = "./"; 1646 | char * delfile; 1647 | 1648 | delfile = get_filename(tmp_dir,unique_filename("comb")); 1649 | remove(delfile); 1650 | delfile = get_filename(tmp_dir,unique_filename("frels")); 1651 | remove(delfile); 1652 | delfile = get_filename(tmp_dir,unique_filename("flprels")); 1653 | remove(delfile); 1654 | delfile = get_filename(tmp_dir,unique_filename("lpnew")); 1655 | remove(delfile); 1656 | delfile = get_filename(tmp_dir,unique_filename("rels")); 1657 | remove(delfile); 1658 | delfile = get_filename(tmp_dir,unique_filename("fnew")); 1659 | remove(delfile); 1660 | delfile = get_filename(tmp_dir,unique_filename("lprels")); 1661 | remove(delfile); 1662 | 1663 | return 0; 1664 | } 1665 | 1666 | --------------------------------------------------------------------------------