@@ -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