Skip to content

Commit bc0e415

Browse files
Refactor for human readability and performance
1 parent 94fa2af commit bc0e415

File tree

1 file changed

+43
-42
lines changed

1 file changed

+43
-42
lines changed

FindAFactor/_find_a_factor.cpp

Lines changed: 43 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -705,27 +705,27 @@ struct Factorizer {
705705
BigInteger batchTotal;
706706
BigInteger smoothWheelRadius;
707707
BigInteger diffWheelRadius;
708-
size_t firstGaussianElimPrimeId;
708+
size_t afterGearPrimeId;
709709
size_t wheelEntryCount;
710710
size_t rowLimit;
711711
bool isIncomplete;
712-
std::vector<size_t> primes;
712+
std::vector<size_t> smoothPrimes;
713713
std::set<BigInteger> smoothNumberSet;
714714
std::vector<BigInteger> smoothNumberKeys;
715715
std::vector<boost::dynamic_bitset<size_t>> smoothNumberValues;
716716
ForwardFn forwardFn;
717717
ForwardFn backwardFn;
718718

719-
Factorizer(const BigInteger &tf, const BigInteger &tfsqrt, const BigInteger &range, size_t nodeCount, size_t nodeId, size_t fgepi, size_t w, size_t rl, size_t bn,
720-
const std::vector<size_t> &p, ForwardFn ffn, ForwardFn bfn)
719+
Factorizer(const BigInteger &tf, const BigInteger &tfsqrt, const BigInteger &range, size_t nodeCount, size_t nodeId, size_t agpi, size_t w, size_t rl, size_t bn,
720+
const std::vector<size_t> &sp, ForwardFn ffn, ForwardFn bfn)
721721
: toFactorSqr(tf * tf), toFactor(tf), toFactorSqrt(tfsqrt), batchRange(range), batchNumber(bn), batchOffset(nodeId * range), batchTotal(nodeCount * range),
722-
firstGaussianElimPrimeId(fgepi), smoothWheelRadius(1U), diffWheelRadius(1U), wheelEntryCount(w), rowLimit(rl), isIncomplete(true), primes(p), forwardFn(ffn), backwardFn(bfn)
722+
afterGearPrimeId(agpi), smoothWheelRadius(1U), diffWheelRadius(1U), wheelEntryCount(w), rowLimit(rl), isIncomplete(true), smoothPrimes(sp), forwardFn(ffn), backwardFn(bfn)
723723
{
724-
for (size_t i = 0U; i < firstGaussianElimPrimeId; ++i) {
725-
smoothWheelRadius *= primes[i];
724+
for (size_t i = 0U; i < afterGearPrimeId; ++i) {
725+
smoothWheelRadius *= smoothPrimes[i];
726726
}
727-
for (size_t i = firstGaussianElimPrimeId; i < primes.size(); ++i) {
728-
const size_t& p = primes[i];
727+
for (size_t i = afterGearPrimeId; i < smoothPrimes.size(); ++i) {
728+
const size_t& p = smoothPrimes[i];
729729
smoothWheelRadius *= p;
730730
diffWheelRadius *= p;
731731
}
@@ -830,14 +830,14 @@ struct Factorizer {
830830
const boost::dynamic_bitset<size_t>& freeRow = ger.solutionColumns[solutionColumnId].first;
831831

832832
// Find the indices where the free row has true values.
833-
for (size_t i = 0; i < freeRow.size(); i++) {
833+
for (size_t i = 0U; i < freeRow.size(); ++i) {
834834
if (freeRow[i]) {
835835
indices.push_back(i);
836836
}
837837
}
838838

839839
// Find dependent rows from the original matrix
840-
for (size_t r = 0; r < primes.size(); r++) {
840+
for (size_t r = 0U; r < smoothPrimes.size(); ++r) {
841841
for (size_t i : indices) {
842842
if (smoothNumberValues[i][r] && ger.marks[r]) {
843843
solutionVec.push_back(r);
@@ -885,9 +885,9 @@ struct Factorizer {
885885
auto mColIt = smoothNumberValues.begin();
886886
auto nColIt = smoothNumberKeys.begin();
887887
const size_t rows = smoothNumberValues.size();
888-
GaussianEliminationResult result(primes.size());
888+
GaussianEliminationResult result(smoothPrimes.size());
889889

890-
for (size_t col = 0U; col < primes.size(); ++col) {
890+
for (size_t col = 0U; col < smoothPrimes.size(); ++col) {
891891
auto mRowIt = mColIt;
892892
auto nRowIt = nColIt;
893893
const size_t colPlus1 = col + 1U;
@@ -955,7 +955,7 @@ struct Factorizer {
955955
}
956956

957957
// Step 2: Identify free rows
958-
for (size_t i = 0U; i < primes.size(); i++) {
958+
for (size_t i = 0U; i < smoothPrimes.size(); ++i) {
959959
if (result.marks[i]) {
960960
continue;
961961
}
@@ -1001,7 +1001,7 @@ struct Factorizer {
10011001
// Produce a smooth number with its factorization vector.
10021002
BigInteger makeSmooth(BigInteger num) {
10031003
BigInteger n = num;
1004-
boost::dynamic_bitset<size_t> vec(primes.size(), 0);
1004+
boost::dynamic_bitset<size_t> vec(smoothPrimes.size(), 0U);
10051005
while (true) {
10061006
// Proceed in steps of the GCD with the smooth prime wheel radius.
10071007
BigInteger factor = gcd(n, diffWheelRadius);
@@ -1011,8 +1011,8 @@ struct Factorizer {
10111011
n /= factor;
10121012
// Remove smooth primes from factor.
10131013
// (The GCD is necessarily smooth.)
1014-
for (size_t pi = firstGaussianElimPrimeId; pi < primes.size(); ++pi) {
1015-
const size_t& p = primes[pi];
1014+
for (size_t pi = afterGearPrimeId; pi < smoothPrimes.size(); ++pi) {
1015+
const size_t& p = smoothPrimes[pi];
10161016
if (factor % p) {
10171017
continue;
10181018
}
@@ -1044,11 +1044,11 @@ struct Factorizer {
10441044

10451045
// We actually want not just a smooth number,
10461046
// but a smooth perfect square.
1047-
// for (size_t pi = 0U; pi < primes.size(); ++pi) {
1047+
// for (size_t pi = 0U; pi < smoothPrimes.size(); ++pi) {
10481048
// if (vec.test(pi)) {
10491049
// // If the prime factor component parity is odd,
10501050
// // multiply by the prime once to make it even.
1051-
// num *= primes[pi];
1051+
// num *= smoothPrimes[pi];
10521052
// }
10531053
// // The parity is necessarily even in this factor, by now.
10541054
// }
@@ -1065,7 +1065,7 @@ struct Factorizer {
10651065

10661066
// Compute the prime factorization modulo 2
10671067
boost::dynamic_bitset<size_t> factorizationParityVector(BigInteger num) {
1068-
boost::dynamic_bitset<size_t> vec(primes.size(), 0);
1068+
boost::dynamic_bitset<size_t> vec(smoothPrimes.size(), 0U);
10691069
while (true) {
10701070
// Proceed in steps of the GCD with the smooth prime wheel radius.
10711071
BigInteger factor = gcd(num, smoothWheelRadius);
@@ -1075,8 +1075,8 @@ struct Factorizer {
10751075
num /= factor;
10761076
// Remove smooth primes from factor.
10771077
// (The GCD is necessarily smooth.)
1078-
for (size_t pi = 0U; pi < primes.size(); ++pi) {
1079-
const size_t& p = primes[pi];
1078+
for (size_t pi = 0U; pi < smoothPrimes.size(); ++pi) {
1079+
const size_t& p = smoothPrimes[pi];
10801080
if (factor % p) {
10811081
continue;
10821082
}
@@ -1110,7 +1110,7 @@ std::string find_a_factor(std::string toFactorStr, size_t method, size_t nodeCou
11101110
std::cout << "Mode number " << method << " not implemented. Defaulting to FACTOR_FINDER." << std::endl;
11111111
method = 1U;
11121112
}
1113-
const bool isFactorFinder = (method > 0);
1113+
const bool isFactorFinder = (method > 0U);
11141114
if (!wheelFactorizationLevel) {
11151115
wheelFactorizationLevel = 1U;
11161116
} else if (wheelFactorizationLevel > 13U) {
@@ -1128,13 +1128,13 @@ std::string find_a_factor(std::string toFactorStr, size_t method, size_t nodeCou
11281128
const BigInteger toFactor(toFactorStr);
11291129

11301130
// The largest possible discrete factor of "toFactor" is its square root (as with any integer).
1131-
const BigInteger fullMaxBase = sqrt(toFactor);
1132-
if (fullMaxBase * fullMaxBase == toFactor) {
1133-
return boost::lexical_cast<std::string>(fullMaxBase);
1131+
const BigInteger sqrtN = sqrt(toFactor);
1132+
if (sqrtN * sqrtN == toFactor) {
1133+
return boost::lexical_cast<std::string>(sqrtN);
11341134
}
11351135

11361136
// This level default (scaling) was suggested by Elara (OpenAI GPT).
1137-
const double N = fullMaxBase.convert_to<double>();
1137+
const double N = sqrtN.convert_to<double>();
11381138
const double logN = log(N);
11391139
const BigInteger primeCeilingBigInt = (BigInteger)(smoothnessBoundMultiplier * exp(0.5 * std::sqrt(logN * log(logN))) + 0.5);
11401140
const size_t primeCeiling = (size_t)primeCeilingBigInt;
@@ -1177,18 +1177,20 @@ std::string find_a_factor(std::string toFactorStr, size_t method, size_t nodeCou
11771177
std::vector<size_t> gearFactorizationPrimes(primes.begin(), itg);
11781178
std::vector<size_t> wheelFactorizationPrimes(primes.begin(), itw);
11791179
// Primes are only present in range above wheel factorization level
1180-
const size_t firstGaussianElimPrimeId = std::distance(primes.begin(), itg);
1180+
const size_t afterGearPrimeId = isFactorFinder ? std::distance(primes.begin(), itg) : 0U;
11811181
std::vector<size_t> smoothPrimes;
1182-
for (size_t primeId = 0U; primeId < primes.size(); ++primeId) {
1183-
const size_t p = primes[primeId];
1184-
const size_t residue = (size_t)(toFactor % p);
1185-
const size_t sr = _sqrt(residue);
1186-
if ((sr * sr) == residue) {
1187-
smoothPrimes.push_back(p);
1182+
if (isFactorFinder) {
1183+
for (size_t primeId = 0U; primeId < primes.size(); ++primeId) {
1184+
const size_t p = primes[primeId];
1185+
const size_t residue = (size_t)(toFactor % p);
1186+
const size_t sr = _sqrt(residue);
1187+
if ((sr * sr) == residue) {
1188+
smoothPrimes.push_back(p);
1189+
}
1190+
}
1191+
if (smoothPrimes.empty()) {
1192+
throw std::runtime_error("No smooth primes found under bound. (Increase the smoothness bound multiplier, unless this is not in range of check_small_factors=True.)");
11881193
}
1189-
}
1190-
if (smoothPrimes.empty()) {
1191-
throw std::runtime_error("No smooth primes found under bound. (Increase the smoothness bound multiplier, unless this is not in range of check_small_factors=True.)");
11921194
}
11931195
// From 1, this is a period for wheel factorization
11941196
size_t biggestWheel = 1ULL;
@@ -1214,18 +1216,17 @@ std::string find_a_factor(std::string toFactorStr, size_t method, size_t nodeCou
12141216

12151217
// Range per parallel node
12161218
const auto backwardFn = backward(SMALLEST_WHEEL);
1217-
const BigInteger nodeRange = (((backwardFn(fullMaxBase) + nodeCount - 1U) / nodeCount) + wheelEntryCount - 1U) / wheelEntryCount;
1219+
const BigInteger nodeRange = (((backwardFn(sqrtN) + nodeCount - 1U) / nodeCount) + wheelEntryCount - 1U) / wheelEntryCount;
12181220
const size_t batchStart = ((size_t)backwardFn(primeCeiling)) / wheelEntryCount;
1221+
const size_t rowLimit = (size_t)(gaussianEliminationRowMultiplier * (smoothPrimes.size() + 1U) + 0.5);
12191222
// This manages the work of all threads.
1220-
Factorizer worker(toFactor, fullMaxBase, nodeRange, nodeCount, nodeId, firstGaussianElimPrimeId,
1221-
wheelEntryCount, (size_t)(gaussianEliminationRowMultiplier * (smoothPrimes.size() + 1U) + 0.5),
1222-
batchStart, smoothPrimes, forward(SMALLEST_WHEEL), backwardFn);
1223+
Factorizer worker(toFactor, sqrtN, nodeRange, nodeCount, nodeId, afterGearPrimeId, wheelEntryCount, rowLimit, batchStart, smoothPrimes, forward(SMALLEST_WHEEL), backwardFn);
12231224
// Square of count of smooth primes, for FACTOR_FINDER batch multiplier base unit, was suggested by Lyra (OpenAI GPT)
12241225

12251226
if (isFactorFinder) {
12261227
std::vector<std::future<void>> futures;
12271228
futures.reserve(CpuCount);
1228-
const BigInteger sievingNodeRange = (BigInteger)(fullMaxBase.convert_to<double>() * sievingBoundMultiplier / nodeCount + 0.5);
1229+
const BigInteger sievingNodeRange = (BigInteger)(sqrtN.convert_to<double>() * sievingBoundMultiplier / nodeCount + 0.5);
12291230
const BigInteger sievingThreadRange = sievingNodeRange / CpuCount;
12301231
const BigInteger nodeOffset = nodeId * sievingNodeRange;
12311232
for (unsigned cpu = 0U; cpu < CpuCount; ++cpu) {

0 commit comments

Comments
 (0)