Skip to content

Commit 70baa4c

Browse files
Refactor for readability
1 parent 05b58f5 commit 70baa4c

File tree

1 file changed

+35
-8
lines changed

1 file changed

+35
-8
lines changed

FindAFactor/_find_a_factor.cpp

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -670,7 +670,7 @@ bool isMultiple(const BigInteger &p, const std::vector<size_t> &knownPrimes) {
670670
return false;
671671
}
672672

673-
boost::dynamic_bitset<size_t> wheel_inc(std::vector<size_t> primes) {
673+
boost::dynamic_bitset<size_t> nestGearGeneration(std::vector<size_t> primes) {
674674
BigInteger radius = 1U;
675675
for (const size_t &i : primes) {
676676
radius *= i;
@@ -688,12 +688,12 @@ boost::dynamic_bitset<size_t> wheel_inc(std::vector<size_t> primes) {
688688
return o;
689689
}
690690

691-
std::vector<boost::dynamic_bitset<size_t>> wheel_gen(const std::vector<size_t> &primes) {
691+
std::vector<boost::dynamic_bitset<size_t>> generateGears(const std::vector<size_t> &primes) {
692692
std::vector<boost::dynamic_bitset<size_t>> output;
693693
std::vector<size_t> wheelPrimes;
694694
for (const size_t &p : primes) {
695695
wheelPrimes.push_back(p);
696-
output.push_back(wheel_inc(wheelPrimes));
696+
output.push_back(nestGearGeneration(wheelPrimes));
697697
}
698698

699699
return output;
@@ -818,15 +818,18 @@ struct Factorizer {
818818
if (candidate < toFactorSqrt) {
819819
continue;
820820
}
821-
// The residue (mod N) also ultimately needs to be smooth.
822-
const boost::dynamic_bitset<size_t> rfv = factorizationVector(candidate % toFactor);
821+
// The residue (mod N) also needs to be smooth (but not a perfect square).
822+
const boost::dynamic_bitset<size_t> rfv = factorizationParityVector(candidate % toFactor);
823823
if (!(rfv.size())) {
824+
// The number is useless to us.
824825
continue;
825826
}
827+
// We have a successful candidate.
826828

827829
// For lock_guard scope
828830
if (true) {
829831
std::lock_guard<std::mutex> lock(batchMutex);
832+
// Insert the number if it isn't found (in a binary search) of the accepted set.
830833
if (smoothNumberSet.find(candidate) == smoothNumberSet.end()) {
831834
smoothNumberSet.insert(candidate);
832835
smoothNumberKeys.push_back(candidate);
@@ -854,6 +857,7 @@ struct Factorizer {
854857
auto mRowIt = mColIt;
855858
auto nRowIt = nColIt;
856859

860+
// Check all rows below the outer loop row.
857861
int64_t pivot = -1;
858862
for (size_t row = col; row < rows; ++row) {
859863
if ((*mRowIt)[col]) {
@@ -871,6 +875,7 @@ struct Factorizer {
871875
}
872876

873877
if (pivot != -1) {
878+
// We pivot.
874879
const boost::dynamic_bitset<size_t> &cm = *mColIt;
875880
const BigInteger &cn = *nColIt;
876881
mRowIt = smoothNumberValues.begin();
@@ -879,6 +884,8 @@ struct Factorizer {
879884
dispatch.dispatch([cpu, &cpuCount, &col, &rows, &cm, &cn, nRowIt, mRowIt]() -> bool {
880885
auto mrIt = mRowIt;
881886
auto nrIt = nRowIt;
887+
// Notice that each thread updates rows with space increments of cpuCount,
888+
// based on the same unchanged outer-loop row, and this covers the inner-loop set.
882889
for (size_t row = cpu; ; row += cpuCount) {
883890
boost::dynamic_bitset<size_t> &rm = *mrIt;
884891
BigInteger &rn = *nrIt;
@@ -889,20 +896,25 @@ struct Factorizer {
889896
rn *= cn;
890897
}
891898
if ((row + cpuCount) >= rows) {
899+
// This is the completion condition.
892900
return false;
893901
}
902+
// Every row advance is staggered according to cpuCount.
894903
std::advance(nrIt, cpuCount);
895904
std::advance(mrIt, cpuCount);
896905
}
897906

898907
return false;
899908
});
909+
// Next inner-loop row (all at once by dispatch).
900910
++mRowIt;
901911
++nRowIt;
902912
}
913+
// All dispatched work must complete.
903914
dispatch.finish();
904915
}
905916

917+
// Next outer-loop row.
906918
++mColIt;
907919
++nColIt;
908920
}
@@ -928,6 +940,9 @@ struct Factorizer {
928940

929941
for (size_t j = i; j < this->smoothNumberKeys.size(); ++j) {
930942
if ((*ivit) == (*jvit)) {
943+
// The rows have the same value. Hence, multiplied together,
944+
// they form a perfect square residue we can check for congruence.
945+
931946
// Compute x and y
932947
const BigInteger x = ((*ikit) * (*jkit)) % this->toFactor;
933948
const BigInteger y = modExp(x, this->toFactor >> 1U, this->toFactor);
@@ -953,19 +968,23 @@ struct Factorizer {
953968
}
954969
}
955970

971+
// Next inner-loop row (synchronously).
956972
++jkit;
957973
++jvit;
958974
}
959975

960976
return false;
961977
});
962978

979+
// Next outer-loop row (all dispatched at once).
963980
++ikit;
964981
++ivit;
965982
}
966983

984+
// All work has been dispatched, but now we must complete it.
967985
dispatch.finish();
968986

987+
// Depending on row count, a successful result should be nearly guaranteed.
969988
return result;
970989
}
971990

@@ -990,6 +1009,7 @@ struct Factorizer {
9901009
factor /= p;
9911010
vec.flip(pi);
9921011
if (factor == 1U) {
1012+
// The step is fully factored.
9931013
break;
9941014
}
9951015
}
@@ -1019,15 +1039,17 @@ struct Factorizer {
10191039
}
10201040

10211041
// Compute the prime factorization modulo 2
1022-
boost::dynamic_bitset<size_t> factorizationVector(BigInteger num) {
1042+
boost::dynamic_bitset<size_t> factorizationParityVector(BigInteger num) {
10231043
boost::dynamic_bitset<size_t> vec(primes.size(), 0);
10241044
while (true) {
1045+
// Proceed in steps of the GCD with the smooth prime wheel radius.
10251046
BigInteger factor = gcd(num, wheelRadius);
10261047
if (factor == 1U) {
10271048
break;
10281049
}
10291050
num /= factor;
1030-
// Remove smooth primes from factor
1051+
// Remove smooth primes from factor.
1052+
// (The GCD is necessarily smooth.)
10311053
for (size_t pi = 0U; pi < primes.size(); ++pi) {
10321054
const size_t& p = primes[pi];
10331055
if (factor % p) {
@@ -1036,17 +1058,22 @@ struct Factorizer {
10361058
factor /= p;
10371059
vec.flip(pi);
10381060
if (factor == 1U) {
1061+
// The step is fully factored.
10391062
break;
10401063
}
10411064
}
10421065
if (num == 1U) {
1066+
// The number is fully factored and smooth.
10431067
return vec;
10441068
}
10451069
}
10461070
if (num != 1U) {
1071+
// The number was not fully factored, because it is not smooth.
1072+
// We reject it as a sieving candidate.
10471073
return boost::dynamic_bitset<size_t>();
10481074
}
10491075

1076+
// This number is smooth, and we return its factorization parity.
10501077
return vec;
10511078
}
10521079
};
@@ -1149,7 +1176,7 @@ std::string find_a_factor(std::string toFactorStr, size_t method, size_t nodeCou
11491176
}
11501177
wheelFactorizationPrimes.clear();
11511178
// These are "gears," for wheel factorization (on top of a "wheel" already in place up to the selected level).
1152-
std::vector<boost::dynamic_bitset<size_t>> inc_seqs = wheel_gen(gearFactorizationPrimes);
1179+
std::vector<boost::dynamic_bitset<size_t>> inc_seqs = generateGears(gearFactorizationPrimes);
11531180
// We're done with the lowest primes.
11541181
const size_t MIN_RTD_LEVEL = gearFactorizationPrimes.size() - wgDiff;
11551182
const Wheel SMALLEST_WHEEL = wheelByPrimeCardinal(MIN_RTD_LEVEL);

0 commit comments

Comments
 (0)