Skip to content

Commit 6d8ed5e

Browse files
Fix matrix row number keys
1 parent 8c922e8 commit 6d8ed5e

File tree

2 files changed

+39
-30
lines changed

2 files changed

+39
-30
lines changed

FindAFactor/_find_a_factor.cpp

Lines changed: 38 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -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);

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626

2727
setup(
2828
name='FindAFactor',
29-
version='3.2.1',
29+
version='3.2.2',
3030
author='Dan Strano',
3131
author_email='dan@unitary.fund',
3232
description='Find any nontrivial factor of a number',

0 commit comments

Comments
 (0)