@@ -722,20 +722,21 @@ inline BigInteger modExp(BigInteger base, BigInteger exp, const BigInteger &mod)
722722}
723723
724724// Perform Gaussian elimination on a binary matrix
725- void gaussianElimination (std::map <BigInteger, boost::dynamic_bitset<size_t >> *matrix) {
725+ void gaussianElimination (std::vector <BigInteger> *keys, std::vector< boost::dynamic_bitset<size_t >> *matrix) {
726726 const unsigned cpuCount = CpuCount;
727727 const auto mBegin = matrix->begin ();
728728 const size_t rows = matrix->size ();
729- const size_t cols = mBegin ->second . size ();
729+ const size_t cols = mBegin ->size ();
730730 std::vector<int > pivots (cols, -1 );
731731 for (size_t col = 0U ; col < cols; ++col) {
732732 auto colIt = mBegin ;
733733 std::advance (colIt, col);
734734
735735 auto rowIt = colIt;
736736 for (size_t row = col; row < rows; ++row) {
737- if (rowIt->second [col]) {
738- std::swap (colIt->second , rowIt->second );
737+ if ((*rowIt)[col]) {
738+ std::swap ((*keys)[col], (*keys)[row]);
739+ std::swap (*colIt, *rowIt);
739740 pivots[col] = row;
740741 break ;
741742 }
@@ -746,7 +747,7 @@ void gaussianElimination(std::map<BigInteger, boost::dynamic_bitset<size_t>> *ma
746747 continue ;
747748 }
748749
749- const boost::dynamic_bitset<size_t > &c = colIt-> second ;
750+ const boost::dynamic_bitset<size_t > &c = * colIt;
750751 for (unsigned cpu = 0U ; cpu < CpuCount; ++cpu) {
751752 if (cpu >= rows) {
752753 break ;
@@ -755,7 +756,7 @@ void gaussianElimination(std::map<BigInteger, boost::dynamic_bitset<size_t>> *ma
755756 auto rowIt = mBegin ;
756757 std::advance (rowIt, cpu);
757758 for (size_t row = cpu; ; row += cpuCount) {
758- boost::dynamic_bitset<size_t > &r = rowIt-> second ;
759+ boost::dynamic_bitset<size_t > &r = * rowIt;
759760 if ((row != col) && r[col]) {
760761 r ^= c;
761762 }
@@ -851,7 +852,7 @@ struct Factorizer {
851852 }
852853
853854 BigInteger smoothCongruences (std::vector<boost::dynamic_bitset<size_t >> *inc_seqs, std::vector<BigInteger> *semiSmoothParts,
854- std::map <BigInteger, boost::dynamic_bitset<size_t >> *smoothNumberMap ) {
855+ std::vector <BigInteger>* keys, std::vector< boost::dynamic_bitset<size_t >> *matrix ) {
855856 // Up to wheel factorization, try all batches up to the square root of toFactor.
856857 // Since the largest prime factors of these numbers is relatively small,
857858 // use the "exhaust" of brute force to produce smooth numbers for Quadratic Sieve.
@@ -874,7 +875,7 @@ struct Factorizer {
874875
875876 // Batch this work, to reduce contention.
876877 if (semiSmoothParts->size () >= smoothPartsLimit) {
877- makeSmoothNumbers (semiSmoothParts, smoothNumberMap );
878+ makeSmoothNumbers (semiSmoothParts, keys, matrix );
878879
879880 return 1U ;
880881 }
@@ -883,7 +884,7 @@ struct Factorizer {
883884 return 1U ;
884885 }
885886
886- void makeSmoothNumbers (std::vector<BigInteger> *semiSmoothParts, std::map <BigInteger, boost::dynamic_bitset<size_t >> *smoothNumberMap ) {
887+ void makeSmoothNumbers (std::vector<BigInteger> *semiSmoothParts, std::vector <BigInteger>* keys, std::vector< boost::dynamic_bitset<size_t >> *matrix ) {
887888 // Factorize all "smooth parts."
888889 std::vector<BigInteger> smoothParts;
889890 std::map<BigInteger, boost::dynamic_bitset<size_t >> smoothPartsMap;
@@ -915,9 +916,10 @@ struct Factorizer {
915916 }
916917 if (true ) {
917918 std::lock_guard<std::mutex> lock (smoothNumberMapMutex);
918- auto it = smoothNumberMap->find (smoothNumber);
919- if (it == smoothNumberMap->end ()) {
920- (*smoothNumberMap)[smoothNumber] = fv;
919+ auto it = std::find (keys->begin (), keys->end (), smoothNumber);
920+ if (it == keys->end ()) {
921+ keys->push_back (smoothNumber);
922+ matrix->push_back (fv);
921923 }
922924 }
923925 // Reset "smoothNumber" and its factorization vector.
@@ -931,36 +933,41 @@ struct Factorizer {
931933 // /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
932934
933935 // Find factor via Gaussian elimination
934- BigInteger findFactorViaGaussianElimination (const BigInteger &target, std::map <BigInteger, boost::dynamic_bitset<size_t >> *smoothNumberMap ) {
936+ BigInteger findFactorViaGaussianElimination (const BigInteger &target, std::vector <BigInteger> *keys, std::vector< boost::dynamic_bitset<size_t >> *matrix ) {
935937 // Perform Gaussian elimination
936- gaussianElimination (smoothNumberMap );
938+ gaussianElimination (keys, matrix );
937939
938940 // Check for linear dependencies and find a congruence of squares
939941 std::mutex rowMutex;
940942 BigInteger result = 1U ;
941- std::set<BigInteger > toStrike;
942- auto iIt = smoothNumberMap ->begin ();
943- const size_t rowCount = smoothNumberMap ->size ();
943+ std::set<size_t > toStrike;
944+ auto iIt = matrix ->begin ();
945+ const size_t rowCount = matrix ->size ();
944946 const size_t rowCountMin1 = rowCount - 1U ;
945947 for (size_t i = 0U ; (i < rowCountMin1) && (result == 1U ); ++i) {
946- dispatch.dispatch ([&target, i, iIt, &rowCount, &result, &toStrike, &rowMutex]() -> bool {
947- boost::dynamic_bitset<size_t > &iRow = iIt-> second ;
948+ dispatch.dispatch ([&target, i, iIt, &rowCount, &result, &keys, & toStrike, &rowMutex]() -> bool {
949+ boost::dynamic_bitset<size_t > &iRow = * iIt;
948950 auto jIt = iIt;
949951 for (size_t j = i + 1U ; j < rowCount; ++j) {
950952 ++jIt;
951953
952- boost::dynamic_bitset<size_t > &jRow = jIt-> second ;
954+ boost::dynamic_bitset<size_t > &jRow = * jIt;
953955 if (iRow != jRow) {
954956 continue ;
955957 }
956958
957959 if (true ) {
958- std::lock_guard<std::mutex> lock (rowMutex);
959- toStrike.insert (jIt->first );
960+ if ((*keys)[i] < (*keys)[j]) {
961+ std::lock_guard<std::mutex> lock (rowMutex);
962+ toStrike.insert (j);
963+ } else {
964+ std::lock_guard<std::mutex> lock (rowMutex);
965+ toStrike.insert (i);
966+ }
960967 }
961968
962969 // Compute x and y
963- const BigInteger x = (iIt-> first * jIt-> first ) % target;
970+ const BigInteger x = ((*keys)[i] * (*keys)[j] ) % target;
964971 const BigInteger y = modExp (x, target >> 1U , target);
965972
966973 // Check congruence of squares
@@ -997,8 +1004,9 @@ struct Factorizer {
9971004 }
9981005
9991006 // These numbers have been tried already:
1000- for (const BigInteger& i : toStrike) {
1001- smoothNumberMap->erase (i);
1007+ for (const size_t & i : toStrike) {
1008+ keys->erase (keys->begin () + i);
1009+ matrix->erase (matrix->begin () + i);
10021010 }
10031011
10041012 return 1U ; // No factor found
@@ -1106,7 +1114,8 @@ std::string find_a_factor(const std::string &toFactorStr, const bool &isConOfSqr
11061114 // Range per parallel node
11071115 const BigInteger nodeRange = (((backward (SMALLEST_WHEEL)(fullMaxBase) + nodeCount - 1U ) / nodeCount) + wheelEntryCount - 1U ) / wheelEntryCount;
11081116 // This is used by all threads:
1109- std::map<BigInteger, boost::dynamic_bitset<size_t >> smoothNumberMap;
1117+ std::vector<BigInteger> keys;
1118+ std::vector<boost::dynamic_bitset<size_t >> matrix;
11101119 std::vector<std::vector<BigInteger>> semiSmoothParts (CpuCount);
11111120 // This manages the work of all threads.
11121121 Factorizer worker (toFactor * toFactor, toFactor, fullMaxBase,
@@ -1144,7 +1153,7 @@ std::string find_a_factor(const std::string &toFactorStr, const bool &isConOfSqr
11441153 return boost::lexical_cast<std::string>(result);
11451154 }
11461155
1147- const auto smoothNumberFn = [&inc_seqs, &wheelEntryCount, &semiSmoothParts, &smoothNumberMap , &worker] (unsigned cpu) {
1156+ const auto smoothNumberFn = [&inc_seqs, &wheelEntryCount, &semiSmoothParts, &keys, &matrix , &worker] (unsigned cpu) {
11481157 // inc_seq needs to be independent per thread.
11491158 std::vector<boost::dynamic_bitset<size_t >> inc_seqs_clone;
11501159 inc_seqs_clone.reserve (inc_seqs.size ());
@@ -1156,7 +1165,7 @@ std::string find_a_factor(const std::string &toFactorStr, const bool &isConOfSqr
11561165 semiSmoothParts.reserve (wheelEntryCount << 1U );
11571166
11581167 // While brute-forcing, use the "exhaust" to feed "smooth" number generation and check conguence of squares.
1159- return worker.smoothCongruences (&inc_seqs_clone, &(semiSmoothParts[cpu]), &smoothNumberMap );
1168+ return worker.smoothCongruences (&inc_seqs_clone, &(semiSmoothParts[cpu]), &keys, &matrix );
11601169 };
11611170
11621171 std::vector<std::future<BigInteger>> futures;
@@ -1181,7 +1190,7 @@ std::string find_a_factor(const std::string &toFactorStr, const bool &isConOfSqr
11811190 futures.clear ();
11821191
11831192 // This next section is for (Quadratic Sieve) Gaussian elimination.
1184- result = worker.findFactorViaGaussianElimination (toFactor, &smoothNumberMap );
1193+ result = worker.findFactorViaGaussianElimination (toFactor, &keys, &matrix );
11851194 } while ((result == 1U ) || (result == toFactor));
11861195
11871196 return boost::lexical_cast<std::string>(result);
0 commit comments