PrimeOrderCalculator.PartialFactorCpu simplified to work only with spans and throw exception if the number of factors is exceeded. PrimeOrderMode removed in favor of bool flag.

This commit is contained in:
mlemanczyk committed 2025-12-10 12:47:25 +01:00
1 parent 72890bf343
commit 7a242b3bfa
15 files changed
+337 -302

No files matched your search

+104
View File
@@ -0,0 +1,104 @@
using System.Runtime.CompilerServices;
namespace PerfectNumbers.Core
{
public static class Pools
{
private const int PoolCapacity = 10240; //PerfectNumberConstants.DefaultSmallPrimeFactorSlotCount << 8;
[ThreadStatic]
private static IntArrayPool? _intArrayPool;
internal static IntArrayPool ExclusiveIntArray
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
return _intArrayPool ??= new(PoolCapacity);
}
}
[ThreadStatic]
private static UlongArrayPool? _ulongArrayPool;
internal static UlongArrayPool ExclusiveUlongArray
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
return _ulongArrayPool ??= new(PoolCapacity);
}
}
}
public struct IntArrayPool(int poolCapacity)
{
private readonly int[][] _arrays = new int[poolCapacity][];
private int _count = 0;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int[] Rent(int length)
{
int available = _count;
if (available == 0)
{
return new int[length];
}
int[][] arrays = _arrays;
available--;
_count = available;
int[] candidate = arrays[available];
return candidate.Length >= length ? candidate : new int[length];
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Return(int[] array)
{
int[][] arrays = _arrays;
int available = _count;
if (available < arrays.Length)
{
arrays[available] = array;
_count = available + 1;
}
}
}
public struct UlongArrayPool(int poolCapacity)
{
private readonly ulong[][] _arrays = new ulong[poolCapacity][];
private int _count = 0;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ulong[] Rent(int length)
{
int available = _count;
if (available == 0)
{
return new ulong[length];
}
ulong[][] arrays = _arrays;
available--;
_count = available;
ulong[] candidate = arrays[available];
return candidate.Length >= length ? candidate : new ulong[length];
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Return(ulong[] array)
{
ulong[][] arrays = _arrays;
int available = _count;
if (available < arrays.Length)
{
arrays[available] = array;
_count = available + 1;
}
}
}
}
@@ -1,10 +1,10 @@
namespace PerfectNumbers.Core.Gpu;
public readonly struct CalculateOrderKernelConfig(ulong previousOrder, byte hasPreviousOrder, uint smallFactorLimit, int maxPowChecks, int mode)
public readonly struct CalculateOrderKernelConfig(ulong previousOrder, byte hasPreviousOrder, uint smallFactorLimit, int maxPowChecks, bool strictMode)
{
public readonly ulong PreviousOrder = previousOrder;
public readonly byte HasPreviousOrder = hasPreviousOrder;
public readonly uint SmallFactorLimit = smallFactorLimit;
public readonly int MaxPowChecks = maxPowChecks;
public readonly int Mode = mode;
public readonly int Mode = strictMode ? 1 : 0;
}
@@ -242,7 +242,7 @@ internal static partial class PrimeOrderGpuHeuristics
PrimeOrderCalculatorAccelerator gpu,
ulong prime,
ulong? previousOrder,
PrimeOrderCalculator.PrimeOrderSearchConfig config,
PrimeOrderCalculator.PrimeOrderCalculatorConfig config,
in MontgomeryDivisorData divisorData,
out ulong order)
{
@@ -258,7 +258,7 @@ internal static partial class PrimeOrderGpuHeuristics
byte hasPrevious = previousOrder.HasValue ? (byte)1 : (byte)0;
ulong previousValue = previousOrder ?? 0UL;
var kernelConfig = new CalculateOrderKernelConfig(previousValue, hasPrevious, limit, config.MaxPowChecks, (int)config.Mode);
var kernelConfig = new CalculateOrderKernelConfig(previousValue, hasPrevious, limit, config.MaxPowChecks, config.StrictMode);
ref var buffers = ref gpu.CalculateOrderKernelBuffers;
var kernelLauncher = gpu.CalculateOrderKernelLauncher;
+9 -9
View File
@@ -404,7 +404,7 @@ public class MersenneDivisorCycles
UInt128 wideOrder = PrimeOrderCalculator.CalculateCpu(
divisor,
previousOrder: null,
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault);
PrimeOrderCalculator.PrimeOrderCalculatorConfig.HeuristicDefault);
if (wideOrder != UInt128.Zero)
{
return wideOrder;
@@ -452,7 +452,7 @@ public class MersenneDivisorCycles
gpu,
divisor,
previousOrder: null,
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault);
PrimeOrderCalculator.PrimeOrderCalculatorConfig.HeuristicDefault);
if (wideOrder != UInt128.Zero)
{
return wideOrder;
@@ -500,7 +500,7 @@ public class MersenneDivisorCycles
gpu,
divisor,
previousOrder: null,
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault);
PrimeOrderCalculator.PrimeOrderCalculatorConfig.HeuristicDefault);
if (wideOrder != UInt128.Zero)
{
return wideOrder;
@@ -554,7 +554,7 @@ public class MersenneDivisorCycles
divisor,
previousOrder: null,
divisorData,
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault);
PrimeOrderCalculator.PrimeOrderCalculatorConfig.HeuristicDefault);
if (computedOrder != 0UL)
{
cycleLength = computedOrder;
@@ -639,7 +639,7 @@ public class MersenneDivisorCycles
divisor,
previousOrder: null,
divisorData,
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault);
PrimeOrderCalculator.PrimeOrderCalculatorConfig.HeuristicDefault);
if (computedOrder != 0UL)
{
cycleLength = computedOrder;
@@ -724,7 +724,7 @@ public class MersenneDivisorCycles
divisor,
previousOrder: null,
divisorData,
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault);
PrimeOrderCalculator.PrimeOrderCalculatorConfig.HeuristicDefault);
if (computedOrder != 0UL)
{
cycleLength = computedOrder;
@@ -1401,7 +1401,7 @@ public class MersenneDivisorCycles
divisor,
previousOrder: null,
divisorData,
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault);
PrimeOrderCalculator.PrimeOrderCalculatorConfig.HeuristicDefault);
if (computedOrder != 0UL)
{
cycleLength = computedOrder;
@@ -1434,7 +1434,7 @@ public class MersenneDivisorCycles
divisor,
previousOrder: null,
divisorData,
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault);
PrimeOrderCalculator.PrimeOrderCalculatorConfig.HeuristicDefault);
if (computedOrder != 0UL)
{
cycleLength = computedOrder;
@@ -1467,7 +1467,7 @@ public class MersenneDivisorCycles
divisor,
previousOrder: null,
divisorData,
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault);
PrimeOrderCalculator.PrimeOrderCalculatorConfig.HeuristicDefault);
if (computedOrder != 0UL)
{
cycleLength = computedOrder;
+72 -77
View File
@@ -1,75 +1,75 @@
namespace PerfectNumbers.Core
{
public sealed class PartialFactorResult
{
[ThreadStatic]
private static PartialFactorResult? s_poolHead;
public sealed class PartialFactorResult
{
[ThreadStatic]
private static PartialFactorResult? s_poolHead;
public ulong[]? Factors;
public int[]? Exponents;
private PartialFactorResult? _next;
public ulong Cofactor;
public bool FullyFactored;
private PartialFactorResult? _next;
public ulong Cofactor;
public bool FullyFactored;
public int Count;
public bool CofactorIsPrime;
private PartialFactorResult()
{
}
private PartialFactorResult()
{
}
public static PartialFactorResult Rent(in ulong[]? factors, in int[]? exponents, ulong cofactor, bool fullyFactored, int count, bool cofactorIsPrime)
{
PartialFactorResult? instance = s_poolHead;
if (instance is null)
{
instance = new PartialFactorResult();
}
else
{
s_poolHead = instance._next;
}
public static PartialFactorResult Rent(in ulong[]? factors, in int[]? exponents, ulong cofactor, bool fullyFactored, int count, bool cofactorIsPrime)
{
PartialFactorResult? instance = s_poolHead;
if (instance is null)
{
instance = new PartialFactorResult();
}
else
{
s_poolHead = instance._next;
}
instance._next = null;
instance._next = null;
instance.Factors = factors;
instance.Exponents = exponents;
instance.Cofactor = cofactor;
instance.FullyFactored = fullyFactored;
instance.FullyFactored = fullyFactored;
instance.Count = count;
instance.CofactorIsPrime = cofactorIsPrime;
return instance;
}
return instance;
}
public static PartialFactorResult Rent(ulong cofactor, bool fullyFactored, int count, bool cofactorIsPrime)
{
PartialFactorResult? instance = s_poolHead;
if (instance is null)
{
instance = new PartialFactorResult();
}
else
{
s_poolHead = instance._next;
}
public static PartialFactorResult Rent(ulong cofactor, bool fullyFactored, int count, bool cofactorIsPrime)
{
PartialFactorResult? instance = s_poolHead;
if (instance is null)
{
instance = new PartialFactorResult();
}
else
{
s_poolHead = instance._next;
}
instance._next = null;
instance._next = null;
instance.Factors = null;
instance.Exponents = null;
instance.Cofactor = cofactor;
instance.FullyFactored = fullyFactored;
instance.FullyFactored = fullyFactored;
instance.Count = count;
instance.CofactorIsPrime = cofactorIsPrime;
return instance;
}
return instance;
}
public static readonly PartialFactorResult Empty = new()
public static readonly PartialFactorResult Empty = new()
{
Cofactor = 1UL,
FullyFactored = true
};
public void WithAdditionalPrime(ulong prime)
{
ulong[]? sourceFactors = Factors;
public void WithAdditionalPrime(ulong prime)
{
ulong[]? sourceFactors = Factors;
int sourceCount = Count;
if (sourceFactors is null || sourceCount == 0)
{
@@ -78,14 +78,12 @@ namespace PerfectNumbers.Core
}
int newSize = sourceCount + 1;
int[] extendedExponents;
ulong[] extendedFactors = sourceFactors.Length >= newSize
? sourceFactors
: ResizeFactors(sourceFactors, sourceCount, newSize);
int[] sourceExponents = Exponents!;
extendedExponents = sourceExponents.Length >= newSize
int[] extendedExponents = sourceExponents.Length >= newSize
? sourceExponents
: ResizeExponents(sourceCount, newSize, sourceExponents);
@@ -99,33 +97,31 @@ namespace PerfectNumbers.Core
FullyFactored = true;
Count = newSize;
CofactorIsPrime = false;
}
}
private static int[] ResizeExponents(int sourceCount, int newSize, int[] sourceExponents)
private static int[] ResizeExponents(int sourceCount, int newSize, in int[] sourceExponents)
{
int[] extendedExponents = ThreadStaticPools.IntPool.Rent(newSize);
int[] extendedExponents = Pools.ExclusiveIntArray.Rent(newSize);
Array.Copy(sourceExponents, 0, extendedExponents, 0, sourceCount);
ThreadStaticPools.IntPool.Return(sourceExponents, clearArray: false);
Pools.ExclusiveIntArray.Return(sourceExponents);
return extendedExponents;
}
private static ulong[] ResizeFactors(ulong[] sourceFactors, int sourceCount, int newSize)
private static ulong[] ResizeFactors(in ulong[] sourceFactors, int sourceCount, int newSize)
{
ulong[] extendedFactors = ThreadStaticPools.UlongPool.Rent(newSize);
ulong[] extendedFactors = Pools.ExclusiveUlongArray.Rent(newSize);
Array.Copy(sourceFactors, 0, extendedFactors, 0, sourceCount);
ThreadStaticPools.UlongPool.Return(sourceFactors, clearArray: false);
Pools.ExclusiveUlongArray.Return(sourceFactors);
return extendedFactors;
}
private void InitializeWithPrime(ulong prime)
{
ulong[] source = ThreadStaticPools.UlongPool.Rent(1);
int[] exponents = ThreadStaticPools.IntPool.Rent(1);
// source = new ulong[1];
// exponents = new int[1];
source[0] = prime;
ulong[] factors = Pools.ExclusiveUlongArray.Rent(1);
int[] exponents = Pools.ExclusiveIntArray.Rent(1);
factors[0] = prime;
exponents[0] = 1;
Factors = source;
Factors = factors;
Exponents = exponents;
Cofactor = 1UL;
FullyFactored = true;
@@ -134,26 +130,25 @@ namespace PerfectNumbers.Core
}
public void Dispose()
{
if (this != Empty)
{
ulong[]? factors = Factors;
if (factors is not null)
{
{
if (this != Empty)
{
ulong[]? factors = Factors;
if (factors is not null)
{
int[] exponents = Exponents!;
Factors = null;
Exponents = null;
// if (factors.Length > 1)
// {
ThreadStaticPools.UlongPool.Return(factors, clearArray: false);
ThreadStaticPools.IntPool.Return(exponents, clearArray: false);
// }
}
Pools.ExclusiveUlongArray.Return(factors);
Pools.ExclusiveIntArray.Return(exponents);
}
_next = s_poolHead;
s_poolHead = this;
}
}
}
_next = s_poolHead;
s_poolHead = this;
}
}
}
}
+109 -169
View File
@@ -12,13 +12,41 @@ namespace PerfectNumbers.Core;
internal static partial class PrimeOrderCalculator
{
internal struct PendingEntry(ulong value, bool knownComposite)
internal sealed class PendingEntry(ulong value, bool knownComposite)
{
public readonly ulong Value = value;
[ThreadStatic]
private static PendingEntry? _poolHead;
private PendingEntry? _next;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static PendingEntry Rent(ulong value, bool knownComposite)
{
var poolHead = _poolHead;
if (poolHead == null)
{
return new(value, knownComposite);
}
_poolHead = poolHead._next;
poolHead.Value = value;
poolHead.KnownComposite = knownComposite;
poolHead.HasKnownPrimality = knownComposite;
poolHead.IsPrime = false;
return poolHead;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Return(PendingEntry entry)
{
entry._next = _poolHead;
_poolHead = entry;
}
public ulong Value = value;
public bool KnownComposite = knownComposite;
public bool HasKnownPrimality = knownComposite;
public bool IsPrime = false;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WithPrimality(bool isPrime)
{
@@ -32,7 +60,7 @@ internal static partial class PrimeOrderCalculator
ulong prime,
ulong? previousOrder,
in MontgomeryDivisorData divisorData,
in PrimeOrderSearchConfig config)
in PrimeOrderCalculatorConfig config)
{
// TODO: Is this condition ever met on EvenPerfectBitScanner's execution path? If not, we can add a clarification comment and comment out the entire block. We want to support p candidates at least greater or equal to 31.
if (prime <= 3UL)
@@ -61,7 +89,7 @@ internal static partial class PrimeOrderCalculator
public static UInt128 CalculateCpu(
in UInt128 prime,
in UInt128? previousOrder,
in PrimeOrderSearchConfig config)
in PrimeOrderCalculatorConfig config)
{
MontgomeryDivisorData divisorData;
UInt128 result;
@@ -97,7 +125,7 @@ internal static partial class PrimeOrderCalculator
return result;
}
private static UInt128 CalculateWideInternalCpu(in UInt128 prime, in UInt128? previousOrder, in MontgomeryDivisorData? divisorData, in PrimeOrderSearchConfig config)
private static UInt128 CalculateWideInternalCpu(in UInt128 prime, in UInt128? previousOrder, in MontgomeryDivisorData? divisorData, in PrimeOrderCalculatorConfig config)
{
if (prime <= UInt128.One)
{
@@ -127,7 +155,7 @@ internal static partial class PrimeOrderCalculator
private static ulong RunHeuristicPipelineCpu(
ulong prime,
ulong? previousOrder,
in PrimeOrderSearchConfig config,
in PrimeOrderCalculatorConfig config,
in MontgomeryDivisorData divisorData,
ulong phi,
PartialFactorResult phiFactors)
@@ -145,7 +173,7 @@ internal static partial class PrimeOrderCalculator
return candidateOrder;
}
if (config.Mode == PrimeOrderMode.Strict)
if (config.StrictMode)
{
orderFactors?.Dispose();
return CalculateByFactorizationCpu(prime, divisorData);
@@ -163,7 +191,7 @@ internal static partial class PrimeOrderCalculator
PrimeOrderCalculatorAccelerator gpu,
ulong prime,
ulong? previousOrder,
in PrimeOrderSearchConfig config,
in PrimeOrderCalculatorConfig config,
in MontgomeryDivisorData divisorData,
ulong phi,
PartialFactorResult phiFactors)
@@ -181,7 +209,7 @@ internal static partial class PrimeOrderCalculator
return candidateOrder;
}
if (config.Mode == PrimeOrderMode.Strict)
if (config.StrictMode)
{
orderFactors?.Dispose();
return CalculateByFactorizationCpu(prime, divisorData);
@@ -199,7 +227,7 @@ internal static partial class PrimeOrderCalculator
in UInt128 prime,
in UInt128? previousOrder,
in MontgomeryDivisorData? divisorData,
in PrimeOrderSearchConfig config,
in PrimeOrderCalculatorConfig config,
in UInt128 phi,
in PartialFactorResult128 phiFactors)
{
@@ -216,7 +244,7 @@ internal static partial class PrimeOrderCalculator
return candidateOrder;
}
if (config.Mode == PrimeOrderMode.Strict)
if (config.StrictMode)
{
return FinishStrictlyWideCpu(prime, divisorData);
}
@@ -354,7 +382,7 @@ internal static partial class PrimeOrderCalculator
return order;
}
private static bool TryConfirmOrderWideCpu(in UInt128 prime, in UInt128 order, in MontgomeryDivisorData? divisorData, in PrimeOrderSearchConfig config)
private static bool TryConfirmOrderWideCpu(in UInt128 prime, in UInt128 order, in MontgomeryDivisorData? divisorData, in PrimeOrderCalculatorConfig config)
{
if (order == UInt128.Zero)
{
@@ -416,7 +444,7 @@ internal static partial class PrimeOrderCalculator
in UInt128 order,
in UInt128? previousOrder,
in MontgomeryDivisorData? divisorData,
in PrimeOrderSearchConfig config,
in PrimeOrderCalculatorConfig config,
out UInt128 result)
{
result = UInt128.Zero;
@@ -608,15 +636,12 @@ internal static partial class PrimeOrderCalculator
private static ulong ExponentLoweringCpu(ulong order, ulong prime, PartialFactorResult factors, in MontgomeryDivisorData divisorData)
{
ArrayPool<ulong> ulongPool = ThreadStaticPools.UlongPool;
ArrayPool<int> intPool = ThreadStaticPools.IntPool;
ReadOnlySpan<ulong> factorSpan = factors.Factors;
ReadOnlySpan<int> exponentsSpan = factors.Exponents;
int length = factors.Count;
ulong[] tempFactorsArray = ulongPool.Rent(length + 1);
int[] tempExponentsArray = intPool.Rent(length + 1);
ulong[] tempFactorsArray = Pools.ExclusiveUlongArray.Rent(length + 1);
int[] tempExponentsArray = Pools.ExclusiveIntArray.Rent(length + 1);
Span<ulong> ulongBuffer = tempFactorsArray;
factorSpan.CopyTo(ulongBuffer);
@@ -664,7 +689,7 @@ internal static partial class PrimeOrderCalculator
continue;
}
heapCandidateArray ??= ThreadStaticPools.UlongPool.Rent(ExponentHardLimit);
heapCandidateArray ??= Pools.ExclusiveUlongArray.Rent(ExponentHardLimit);
heapEvaluationArray ??= ThreadStaticPools.BoolPool.Rent(ExponentHardLimit);
ProcessExponentLoweringPrime(heapCandidateArray.AsSpan(0, exponent), heapEvaluationArray.AsSpan(0, exponent), ref order, primeFactor, exponent, ref stepper);
}
@@ -673,11 +698,11 @@ internal static partial class PrimeOrderCalculator
if (heapCandidateArray is not null)
{
ThreadStaticPools.UlongPool.Return(heapCandidateArray);
Pools.ExclusiveUlongArray.Return(heapCandidateArray);
ThreadStaticPools.BoolPool.Return(heapEvaluationArray!);
}
ulongPool.Return(tempFactorsArray, clearArray: false);
Pools.ExclusiveUlongArray.Return(tempFactorsArray);
return order;
}
@@ -735,7 +760,7 @@ internal static partial class PrimeOrderCalculator
ulong prime,
ulong order,
in MontgomeryDivisorData divisorData,
in PrimeOrderSearchConfig config,
in PrimeOrderCalculatorConfig config,
out PartialFactorResult? reusableFactorization)
{
reusableFactorization = null;
@@ -783,7 +808,7 @@ internal static partial class PrimeOrderCalculator
ulong prime,
ulong order,
in MontgomeryDivisorData divisorData,
in PrimeOrderSearchConfig config,
in PrimeOrderCalculatorConfig config,
out PartialFactorResult? reusableFactorization)
{
reusableFactorization = null;
@@ -873,7 +898,7 @@ internal static partial class PrimeOrderCalculator
continue;
}
heapCandidateArray ??= ThreadStaticPools.UlongPool.Rent(ExponentHardLimit);
heapCandidateArray ??= Pools.ExclusiveUlongArray.Rent(ExponentHardLimit);
if (ValidateOrderForFactor(heapCandidateArray.AsSpan(0, exponent), primeFactor, exponent, order, ref stepper))
{
violates = true;
@@ -885,7 +910,7 @@ internal static partial class PrimeOrderCalculator
if (heapCandidateArray is not null)
{
ThreadStaticPools.UlongPool.Return(heapCandidateArray);
Pools.ExclusiveUlongArray.Return(heapCandidateArray);
}
return !violates;
@@ -944,7 +969,7 @@ internal static partial class PrimeOrderCalculator
ulong order,
ulong? previousOrder,
in MontgomeryDivisorData divisorData,
in PrimeOrderSearchConfig config,
in PrimeOrderCalculatorConfig config,
PartialFactorResult phiFactors,
PartialFactorResult? cachedOrderFactors,
out ulong result)
@@ -1079,7 +1104,7 @@ internal static partial class PrimeOrderCalculator
ulong order,
ulong? previousOrder,
in MontgomeryDivisorData divisorData,
in PrimeOrderSearchConfig config,
in PrimeOrderCalculatorConfig config,
PartialFactorResult phiFactors,
PartialFactorResult? cachedOrderFactors,
out ulong result)
@@ -1211,7 +1236,7 @@ internal static partial class PrimeOrderCalculator
ulong order,
ulong? previousOrder,
in MontgomeryDivisorData divisorData,
in PrimeOrderSearchConfig config,
in PrimeOrderCalculatorConfig config,
PartialFactorResult phiFactors,
PartialFactorResult? cachedOrderFactors,
out ulong result)
@@ -1437,7 +1462,7 @@ internal static partial class PrimeOrderCalculator
int group = GetGroup(value, threshold1, threshold2, threshold3);
if (group == 0)
{
return new CandidateKey(int.MaxValue, long.MaxValue, long.MaxValue);
return CandidateKey.Max;
}
bool isGe = !hasPrevious || value >= previous;
@@ -1453,14 +1478,15 @@ internal static partial class PrimeOrderCalculator
else
{
ulong reference = hasPrevious ? previous : 0UL;
ulong distance = hasPrevious ? (value > reference ? value - reference : reference - value) : value;
secondary = (long)distance;
reference = hasPrevious ? (value > reference ? value - reference : reference - value) : value;
secondary = (long)reference;
tertiary = (long)value;
}
return new CandidateKey(primary, secondary, tertiary);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int ComputePrimary(int group, bool isGe, int previousGroup)
{
int groupOffset = group switch
@@ -1484,6 +1510,7 @@ internal static partial class PrimeOrderCalculator
return groupOffset + (isGe ? 0 : 1);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int GetGroup(ulong value, ulong threshold1, ulong threshold2, ulong threshold3)
{
if (value <= threshold1)
@@ -1504,8 +1531,6 @@ internal static partial class PrimeOrderCalculator
return 0;
}
private static readonly Comparer<ulong> _comparer = Comparer<ulong>.Default;
private static void BuildCandidates(ulong order, ulong[] factors, int[] exponents, int count, List<ulong> candidates, int limit)
{
if (count == 0)
@@ -1578,7 +1603,7 @@ internal static partial class PrimeOrderCalculator
}
}
private static bool TryConfirmCandidateCpu(ulong prime, ulong candidate, in MontgomeryDivisorData divisorData, in PrimeOrderSearchConfig config, ref int powUsed, int powBudget)
private static bool TryConfirmCandidateCpu(ulong prime, ulong candidate, in MontgomeryDivisorData divisorData, in PrimeOrderCalculatorConfig config, ref int powUsed, int powBudget)
{
PartialFactorResult factorization = PartialFactorCpu(candidate, config);
@@ -1638,7 +1663,7 @@ internal static partial class PrimeOrderCalculator
continue;
}
heapCandidateArray ??= ThreadStaticPools.UlongPool.Rent(ExponentHardLimit);
heapCandidateArray ??= Pools.ExclusiveUlongArray.Rent(ExponentHardLimit);
if (CheckCandidateViolation(heapCandidateArray.AsSpan(0, exponent), primeFactor, exponent, candidate, prime, ref powUsed, powBudget, ref stepper))
{
violates = true;
@@ -1650,14 +1675,14 @@ internal static partial class PrimeOrderCalculator
if (heapCandidateArray is not null)
{
ThreadStaticPools.UlongPool.Return(heapCandidateArray);
Pools.ExclusiveUlongArray.Return(heapCandidateArray);
}
factorization.Dispose();
return !violates;
}
private static bool TryConfirmCandidateHybrid(PrimeOrderCalculatorAccelerator gpu, ulong prime, ulong candidate, in MontgomeryDivisorData divisorData, in PrimeOrderSearchConfig config, ref int powUsed, int powBudget)
private static bool TryConfirmCandidateHybrid(PrimeOrderCalculatorAccelerator gpu, ulong prime, ulong candidate, in MontgomeryDivisorData divisorData, in PrimeOrderCalculatorConfig config, ref int powUsed, int powBudget)
{
PartialFactorResult factorization = PartialFactorHybrid(gpu, candidate, config);
@@ -1839,14 +1864,12 @@ internal static partial class PrimeOrderCalculator
return exponent.Pow2MontgomeryModWindowedConvertToStandardCpu(divisorData) == 1UL;
}
// private static ulong _partialFactorHits;
// private static ulong _partialFactorPendingHits;
// private static ulong _partialFactorCofactorHits;
private static bool _goToGpu = true;
private static int _cpuCount;
private static PartialFactorResult PartialFactorCpu(ulong value, in PrimeOrderSearchConfig config)
private static readonly ulong[] _emptyUlongArray = [];
private static readonly int[] _emptyIntArray = [];
private static PartialFactorResult PartialFactorCpu(ulong value, in PrimeOrderCalculatorConfig config)
{
if (value <= 1UL)
{
@@ -1856,8 +1879,6 @@ internal static partial class PrimeOrderCalculator
// stackalloc is faster than pooling
Span<ulong> primeSlots = stackalloc ulong[PrimeOrderConstants.GpuSmallPrimeFactorSlots];
Span<int> exponentSlots = stackalloc int[PrimeOrderConstants.GpuSmallPrimeFactorSlots];
ulong[] primeSlotArray = [];
int[] exponentSlotArray = [];
// We don't need to worry about leftovers, because we always use indexes within the calculated counts
// primeSlots.Clear();
@@ -1866,15 +1887,13 @@ internal static partial class PrimeOrderCalculator
uint limit = config.SmallFactorLimit == 0 ? uint.MaxValue : config.SmallFactorLimit;
ulong remaining = value;
List<PendingEntry> pending = ThreadStaticPools.RentPrimeOrderPendingEntryList(2);
List<PendingEntry> pending = ThreadStaticPools.RentPrimeOrderPendingEntryList(PrimeOrderConstants.GpuSmallPrimeFactorSlots);
PopulateSmallPrimeFactorsCpu(
value,
limit,
ref primeSlots,
ref exponentSlots,
ref primeSlotArray,
ref exponentSlotArray,
primeSlots,
exponentSlots,
out int factorCount,
out remaining);
@@ -1884,16 +1903,16 @@ internal static partial class PrimeOrderCalculator
if (config.PollardRhoMilliseconds > 0)
{
long deadlineTimestamp = CreateDeadlineTimestamp(config.PollardRhoMilliseconds);
Stack<ulong> compositeStack = ThreadStaticPools.RentUlongStack(4);
Stack<ulong> compositeStack = ThreadStaticPools.RentUlongStack(PrimeOrderConstants.GpuSmallPrimeFactorSlots);
compositeStack.Push(remaining);
CollectFactorsCpu(ref primeSlots, ref exponentSlots, ref primeSlotArray, ref exponentSlotArray, ref factorCount, pending, compositeStack, deadlineTimestamp, out limitReached);
CollectFactorsCpu(primeSlots, exponentSlots, ref factorCount, pending, compositeStack, deadlineTimestamp, out limitReached);
if (limitReached)
{
while (compositeStack.Count > 0)
{
pending.Add(new PendingEntry(compositeStack.Pop(), knownComposite: false));
pending.Add(PendingEntry.Rent(compositeStack.Pop(), knownComposite: false));
}
}
@@ -1902,7 +1921,7 @@ internal static partial class PrimeOrderCalculator
}
else
{
pending.Add(new PendingEntry(remaining, knownComposite: false));
pending.Add(PendingEntry.Rent(remaining, knownComposite: false));
}
}
@@ -1919,6 +1938,7 @@ internal static partial class PrimeOrderCalculator
{
cofactor = checked(cofactor * composite);
cofactorContainsComposite = true;
PendingEntry.Return(entry);
continue;
}
@@ -1926,16 +1946,12 @@ internal static partial class PrimeOrderCalculator
{
bool isPrime = PrimeTesterByLastDigit.IsPrimeCpu(composite);
// Atomic.Add(ref _partialFactorPendingHits, 1UL);
// Console.WriteLine($"Partial factor pending hits {Volatile.Read(ref _partialFactorPendingHits)}");
entry.WithPrimality(isPrime);
pending[index] = entry;
}
if (entry.IsPrime)
{
AddFactorToCollector(ref primeSlots, ref exponentSlots, ref primeSlotArray, ref exponentSlotArray, ref factorCount, composite, 1);
AddFactorToCollector(primeSlots, exponentSlots, ref factorCount, composite, 1);
}
// composite is never smaller on the execution path
// else if (composite > 1UL)
@@ -1944,6 +1960,8 @@ internal static partial class PrimeOrderCalculator
cofactor = checked(cofactor * composite);
cofactorContainsComposite = true;
}
PendingEntry.Return(entry);
}
bool cofactorIsPrime;
@@ -1958,9 +1976,6 @@ internal static partial class PrimeOrderCalculator
else
{
cofactorIsPrime = PrimeTesterByLastDigit.IsPrimeCpu(cofactor);
// Atomic.Add(ref _partialFactorCofactorHits, 1UL);
// Console.WriteLine($"Partial factor cofactor hits {Volatile.Read(ref _partialFactorCofactorHits)}");
}
PartialFactorResult result;
@@ -1989,11 +2004,8 @@ internal static partial class PrimeOrderCalculator
// goto ReturnResult;
// }
ArrayPool<ulong> ulongPool = ThreadStaticPools.UlongPool;
ArrayPool<int> intPool = ThreadStaticPools.IntPool;
ulong[] factorsArray = ulongPool.Rent(factorCount);
int[] exponentsArray = intPool.Rent(factorCount);
ulong[] factorsArray = Pools.ExclusiveUlongArray.Rent(factorCount);
int[] exponentsArray = Pools.ExclusiveIntArray.Rent(factorCount);
for (int i = 0; i < factorCount; i++)
{
@@ -2016,18 +2028,12 @@ internal static partial class PrimeOrderCalculator
result = PartialFactorResult.Rent(factorsArray, exponentsArray, cofactor, limitReached, factorCount, cofactorIsPrime);
ReturnResult:
if (primeSlotArray.Length > 0)
{
ThreadStaticPools.UlongPool.Return(primeSlotArray, clearArray: false);
ThreadStaticPools.IntPool.Return(exponentSlotArray, clearArray: false);
}
pending.Clear();
ThreadStaticPools.ReturnPrimeOrderPendingEntryList(pending);
return result;
}
private static PartialFactorResult PartialFactorHybrid(PrimeOrderCalculatorAccelerator gpu, ulong value, in PrimeOrderSearchConfig config)
private static PartialFactorResult PartialFactorHybrid(PrimeOrderCalculatorAccelerator gpu, ulong value, in PrimeOrderCalculatorConfig config)
{
if (value <= 1UL)
{
@@ -2051,10 +2057,8 @@ internal static partial class PrimeOrderCalculator
PopulateSmallPrimeFactorsCpu(
value,
limit,
ref primeSlots,
ref exponentSlots,
ref primeSlotArray,
ref exponentSlotArray,
primeSlots,
exponentSlots,
out int factorCount,
out remaining);
@@ -2067,7 +2071,7 @@ internal static partial class PrimeOrderCalculator
Stack<ulong> compositeStack = ThreadStaticPools.RentUlongStack(4);
compositeStack.Push(remaining);
CollectFactorsHybrid(gpu, ref primeSlots, ref exponentSlots, primeSlotArray: ref primeSlotArray, ref exponentSlotArray, ref factorCount, pending, compositeStack, deadlineTimestamp, out limitReached);
CollectFactorsHybrid(gpu, primeSlots, exponentSlots, primeSlotArray: ref primeSlotArray, ref exponentSlotArray, ref factorCount, pending, compositeStack, deadlineTimestamp, out limitReached);
if (limitReached)
{
@@ -2106,16 +2110,13 @@ internal static partial class PrimeOrderCalculator
{
bool isPrime = RunOnCpu() ? PrimeTesterByLastDigit.IsPrimeCpu(composite) : HeuristicCombinedPrimeTester.IsPrimeGpu(gpu, composite);
// Atomic.Add(ref _partialFactorPendingHits, 1UL);
// Console.WriteLine($"Partial factor pending hits {Volatile.Read(ref _partialFactorPendingHits)}");
entry.WithPrimality(isPrime);
pending[index] = entry;
}
if (entry.IsPrime)
{
AddFactorToCollector(ref primeSlots, ref exponentSlots, ref primeSlotArray, ref exponentSlotArray, ref factorCount, composite, 1);
AddFactorToCollector(primeSlots, exponentSlots, ref factorCount, composite, 1);
}
// composite is never smaller on the execution path
// else if (composite > 1UL)
@@ -2204,7 +2205,7 @@ internal static partial class PrimeOrderCalculator
return result;
}
private static PartialFactorResult PartialFactorGpu(PrimeOrderCalculatorAccelerator gpu, ulong value, in PrimeOrderSearchConfig config)
private static PartialFactorResult PartialFactorGpu(PrimeOrderCalculatorAccelerator gpu, ulong value, in PrimeOrderCalculatorConfig config)
{
if (value <= 1UL)
{
@@ -2232,10 +2233,8 @@ internal static partial class PrimeOrderCalculator
PopulateSmallPrimeFactorsCpu(
value,
limit,
ref primeSlots,
ref exponentSlots,
ref primeSlotArray,
ref exponentSlotArray,
primeSlots,
exponentSlots,
out factorCount,
out remaining);
}
@@ -2249,7 +2248,7 @@ internal static partial class PrimeOrderCalculator
Stack<ulong> compositeStack = ThreadStaticPools.RentUlongStack(4);
compositeStack.Push(remaining);
CollectFactorsCpu(ref primeSlots, ref exponentSlots, ref primeSlotArray, ref exponentSlotArray, ref factorCount, pending, compositeStack, deadlineTimestamp, out limitReached);
CollectFactorsCpu(primeSlots, exponentSlots, ref factorCount, pending, compositeStack, deadlineTimestamp, out limitReached);
if (limitReached)
{
@@ -2288,16 +2287,13 @@ internal static partial class PrimeOrderCalculator
{
bool isPrime = PrimeTesterByLastDigit.IsPrimeCpu(composite);
// Atomic.Add(ref _partialFactorPendingHits, 1UL);
// Console.WriteLine($"Partial factor pending hits {Volatile.Read(ref _partialFactorPendingHits)}");
entry.WithPrimality(isPrime);
pending[index] = entry;
}
if (entry.IsPrime)
{
AddFactorToCollector(ref primeSlots, ref exponentSlots, ref primeSlotArray, ref exponentSlotArray, ref factorCount, composite, 1);
AddFactorToCollector(primeSlots, exponentSlots, ref factorCount, composite, 1);
}
// composite is never smaller on the execution path
// else if (composite > 1UL)
@@ -2320,9 +2316,6 @@ internal static partial class PrimeOrderCalculator
else
{
cofactorIsPrime = PrimeTesterByLastDigit.IsPrimeCpu(cofactor);
// Atomic.Add(ref _partialFactorCofactorHits, 1UL);
// Console.WriteLine($"Partial factor cofactor hits {Volatile.Read(ref _partialFactorCofactorHits)}");
}
PartialFactorResult result;
@@ -2390,7 +2383,7 @@ internal static partial class PrimeOrderCalculator
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void CollectFactorsHybrid(PrimeOrderCalculatorAccelerator gpu, ref Span<ulong> primeSlots, ref Span<int> exponentSlots, ref ulong[] primeSlotArray, ref int[] exponentSlotArray, ref int factorCount, List<PendingEntry> pending, Stack<ulong> compositeStack, long deadlineTimestamp, out bool pollardRhoDeadlineReached)
private static void CollectFactorsHybrid(PrimeOrderCalculatorAccelerator gpu, Span<ulong> primeSlots, Span<int> exponentSlots, ref ulong[] primeSlotArray, ref int[] exponentSlotArray, ref int factorCount, List<PendingEntry> pending, Stack<ulong> compositeStack, long deadlineTimestamp, out bool pollardRhoDeadlineReached)
{
while (compositeStack.Count > 0)
{
@@ -2399,7 +2392,7 @@ internal static partial class PrimeOrderCalculator
if (isPrime)
{
AddFactorToCollector(ref primeSlots, ref exponentSlots, ref primeSlotArray, ref exponentSlotArray, ref factorCount, composite, 1);
AddFactorToCollector(primeSlots, exponentSlots, ref factorCount, composite, 1);
continue;
}
@@ -2425,7 +2418,7 @@ internal static partial class PrimeOrderCalculator
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void CollectFactorsCpu(ref Span<ulong> primeSlots, ref Span<int> exponentSlots, ref ulong[] primeSlotArray, ref int[] exponentSlotArray, ref int factorCount, List<PendingEntry> pending, Stack<ulong> compositeStack, long deadlineTimestamp, out bool pollardRhoDeadlineReached)
private static void CollectFactorsCpu(Span<ulong> primeSlots, Span<int> exponentSlots, ref int factorCount, List<PendingEntry> pending, Stack<ulong> compositeStack, long deadlineTimestamp, out bool pollardRhoDeadlineReached)
{
while (compositeStack.Count > 0)
{
@@ -2434,20 +2427,20 @@ internal static partial class PrimeOrderCalculator
if (isPrime)
{
AddFactorToCollector(ref primeSlots, ref exponentSlots, ref primeSlotArray, ref exponentSlotArray, ref factorCount, composite, 1);
AddFactorToCollector(primeSlots, exponentSlots, ref factorCount, composite, 1);
continue;
}
pollardRhoDeadlineReached = Stopwatch.GetTimestamp() > deadlineTimestamp;
if (pollardRhoDeadlineReached)
{
pending.Add(new PendingEntry(composite, knownComposite: true));
pending.Add(PendingEntry.Rent(composite, knownComposite: true));
continue;
}
if (!TryPollardRhoCpu(composite, deadlineTimestamp, out ulong factor))
{
pending.Add(new PendingEntry(composite, knownComposite: true));
pending.Add(PendingEntry.Rent(composite, knownComposite: true));
continue;
}
@@ -2469,7 +2462,7 @@ internal static partial class PrimeOrderCalculator
if (isPrime)
{
AddFactorToCollector(ref primeSlots, ref exponentSlots, ref primeSlotArray, ref exponentSlotArray, ref factorCount, composite, 1);
AddFactorToCollector(primeSlots, exponentSlots, ref factorCount, composite, 1);
continue;
}
@@ -2535,10 +2528,8 @@ internal static partial class PrimeOrderCalculator
private static void PopulateSmallPrimeFactorsCpu(
ulong value,
uint limit,
ref Span<ulong> primeTargets,
ref Span<int> exponentTargets,
ref ulong[] primeArray,
ref int[] exponentArray,
Span<ulong> primeTargets,
Span<int> exponentTargets,
out int factorCount,
out ulong remaining)
{
@@ -2591,11 +2582,7 @@ internal static partial class PrimeOrderCalculator
}
EnsureCollectorCapacity(
ref primeTargets,
ref exponentTargets,
ref primeArray,
ref exponentArray,
factorCount,
primeTargets,
factorCount + 1);
primeTargets[factorCount] = primeValue;
@@ -2797,10 +2784,8 @@ internal static partial class PrimeOrderCalculator
}
private static void AddFactorToCollector(
ref Span<ulong> primes,
ref Span<int> exponents,
ref ulong[] primeArray,
ref int[] exponentArray,
Span<ulong> primes,
Span<int> exponents,
ref int count,
ulong prime,
int exponent)
@@ -2820,11 +2805,7 @@ internal static partial class PrimeOrderCalculator
}
EnsureCollectorCapacity(
ref primes,
ref exponents,
ref primeArray,
ref exponentArray,
count,
primes,
count + 1);
primes[count] = prime;
@@ -2832,43 +2813,12 @@ internal static partial class PrimeOrderCalculator
count++;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void EnsureCollectorCapacity(
ref Span<ulong> primes,
ref Span<int> exponents,
ref ulong[] primeArray,
ref int[] exponentArray,
int count,
Span<ulong> primes,
int requiredCapacity)
{
if (requiredCapacity <= primes.Length)
{
return;
}
int newCapacity = primes.Length << 1;
if (newCapacity < requiredCapacity)
{
newCapacity = requiredCapacity;
}
ulong[] newPrimeArray = ThreadStaticPools.UlongPool.Rent(newCapacity);
int[] newExponentArray = ThreadStaticPools.IntPool.Rent(newCapacity);
Span<ulong> newPrimeSpan = newPrimeArray.AsSpan();
Span<int> newExponentSpan = newExponentArray.AsSpan();
primes[..count].CopyTo(newPrimeSpan);
exponents[..count].CopyTo(newExponentSpan);
if (primeArray.Length > 0)
{
ThreadStaticPools.UlongPool.Return(primeArray, clearArray: false);
ThreadStaticPools.IntPool.Return(exponentArray!, clearArray: false);
}
primeArray = newPrimeArray;
exponentArray = newExponentArray;
primes = newPrimeSpan;
exponents = newExponentSpan;
ArgumentOutOfRangeException.ThrowIfGreaterThan(requiredCapacity, primes.Length);
}
private static ulong CalculateByFactorizationCpu(ulong prime, in MontgomeryDivisorData divisorData)
@@ -2918,9 +2868,6 @@ internal static partial class PrimeOrderCalculator
return order;
}
// private static ulong _factorCompletelyHits;
// private static ulong _factorCompletelyPollardRhoHits;
private static void FactorCompletelyCpu(ulong value, Dictionary<ulong, int> counts, bool knownComposite)
{
if (value <= 1UL)
@@ -2928,9 +2875,6 @@ internal static partial class PrimeOrderCalculator
return;
}
// Atomic.Add(ref _factorCompletelyHits, 1UL);
// Console.WriteLine($"Factor completely hits {Volatile.Read(ref _factorCompletelyHits)}");
bool isPrime = PrimeTesterByLastDigit.IsPrimeCpu(value);
if (!knownComposite && isPrime)
{
@@ -2941,9 +2885,6 @@ internal static partial class PrimeOrderCalculator
ulong factor = PollardRhoStrict(value);
ulong quotient = value / factor;
// Atomic.Add(ref _factorCompletelyPollardRhoHits, 1UL);
// Console.WriteLine($"Factor completely after PollardRho hits {Volatile.Read(ref _factorCompletelyPollardRhoHits)}");
isPrime = PrimeTesterByLastDigit.IsPrimeCpu(factor);
if (isPrime)
{
@@ -2973,9 +2914,6 @@ internal static partial class PrimeOrderCalculator
}
else
{
// Atomic.Add(ref _partialFactorCofactorHits, 1UL);
// Console.WriteLine($"Partial factor cofactor hits {Volatile.Read(ref _partialFactorCofactorHits)}");
isPrime = PrimeTesterByLastDigit.IsPrimeCpu(quotient);
}
@@ -3029,7 +2967,7 @@ internal static partial class PrimeOrderCalculator
return exponent.Pow2MontgomeryModWindowed(modulus);
}
private static bool TryConfirmCandidateWideCpu(in UInt128 prime, in UInt128 candidate, in PrimeOrderSearchConfig config, ref int powUsed, int powBudget, in MontgomeryDivisorData? divisorData)
private static bool TryConfirmCandidateWideCpu(in UInt128 prime, in UInt128 candidate, in PrimeOrderCalculatorConfig config, ref int powUsed, int powBudget, in MontgomeryDivisorData? divisorData)
{
PartialFactorResult128 factorization = PartialFactorWide(candidate, config);
if (factorization.Factors is null)
@@ -3084,6 +3022,8 @@ internal static partial class PrimeOrderCalculator
private readonly struct CandidateKey(int primary, long secondary, long tertiary)
{
public static readonly CandidateKey Max = new(int.MaxValue, long.MaxValue, long.MaxValue);
public readonly int Primary = primary;
public readonly long Secondary = secondary;
public readonly long Tertiary = tertiary;
@@ -15,7 +15,7 @@ internal static partial class PrimeOrderCalculator
ulong prime,
ulong? previousOrder,
in MontgomeryDivisorData divisorData,
in PrimeOrderSearchConfig config)
in PrimeOrderCalculatorConfig config)
{
// TODO: Is this condition ever met on EvenPerfectBitScanner's execution path? If not, we can add a clarification comment and comment out the entire block. We want to support p candidates at least greater or equal to 31.
if (prime <= 3UL)
@@ -50,7 +50,7 @@ internal static partial class PrimeOrderCalculator
PrimeOrderCalculatorAccelerator gpu,
in UInt128 prime,
in UInt128? previousOrder,
in PrimeOrderSearchConfig config)
in PrimeOrderCalculatorConfig config)
{
MontgomeryDivisorData divisorData;
UInt128 result;
@@ -86,7 +86,7 @@ internal static partial class PrimeOrderCalculator
return result;
}
private static UInt128 CalculateWideInternalGpu(PrimeOrderCalculatorAccelerator gpu, in UInt128 prime, in UInt128? previousOrder, in MontgomeryDivisorData? divisorData, in PrimeOrderSearchConfig config)
private static UInt128 CalculateWideInternalGpu(PrimeOrderCalculatorAccelerator gpu, in UInt128 prime, in UInt128? previousOrder, in MontgomeryDivisorData? divisorData, in PrimeOrderCalculatorConfig config)
{
if (prime <= UInt128.One)
{
@@ -118,7 +118,7 @@ internal static partial class PrimeOrderCalculator
in UInt128 prime,
in UInt128? previousOrder,
in MontgomeryDivisorData? divisorData,
in PrimeOrderSearchConfig config,
in PrimeOrderCalculatorConfig config,
in UInt128 phi,
in PartialFactorResult128 phiFactors)
{
@@ -135,7 +135,7 @@ internal static partial class PrimeOrderCalculator
return candidateOrder;
}
if (config.Mode == PrimeOrderMode.Strict)
if (config.StrictMode)
{
return FinishStrictlyWideGpu(gpu, prime, divisorData);
}
@@ -268,7 +268,7 @@ internal static partial class PrimeOrderCalculator
return order;
}
private static bool TryConfirmOrderWideGpu(PrimeOrderCalculatorAccelerator gpu, in UInt128 prime, in UInt128 order, in MontgomeryDivisorData? divisorData, in PrimeOrderSearchConfig config)
private static bool TryConfirmOrderWideGpu(PrimeOrderCalculatorAccelerator gpu, in UInt128 prime, in UInt128 order, in MontgomeryDivisorData? divisorData, in PrimeOrderCalculatorConfig config)
{
if (order == UInt128.Zero)
{
@@ -331,7 +331,7 @@ internal static partial class PrimeOrderCalculator
in UInt128 order,
in UInt128? previousOrder,
in MontgomeryDivisorData? divisorData,
in PrimeOrderSearchConfig config,
in PrimeOrderCalculatorConfig config,
out UInt128 result)
{
result = UInt128.Zero;
@@ -575,7 +575,7 @@ internal static partial class PrimeOrderCalculator
return exponent.Pow2MontgomeryModWindowed(modulus);
}
private static bool TryConfirmCandidateWideGpu(PrimeOrderCalculatorAccelerator gpu, in UInt128 prime, in UInt128 candidate, in PrimeOrderSearchConfig config, ref int powUsed, int powBudget, in MontgomeryDivisorData? divisorData)
private static bool TryConfirmCandidateWideGpu(PrimeOrderCalculatorAccelerator gpu, in UInt128 prime, in UInt128 candidate, in PrimeOrderCalculatorConfig config, ref int powUsed, int powBudget, in MontgomeryDivisorData? divisorData)
{
PartialFactorResult128 factorization = PartialFactorWide(candidate, config);
if (factorization.Factors is null)
@@ -9,7 +9,7 @@ internal static partial class PrimeOrderCalculator
ulong prime,
ulong? previousOrder,
in MontgomeryDivisorData divisorData,
in PrimeOrderSearchConfig config)
in PrimeOrderCalculatorConfig config)
{
// TODO: Is this condition ever met on EvenPerfectBitScanner's execution path? If not, we can add a clarification comment and comment out the entire block. We want to support p candidates at least greater or equal to 31.
if (prime <= 3UL)
@@ -40,7 +40,7 @@ internal static partial class PrimeOrderCalculator
PrimeOrderCalculatorAccelerator gpu,
in UInt128 prime,
in UInt128? previousOrder,
in PrimeOrderSearchConfig config)
in PrimeOrderCalculatorConfig config)
{
MontgomeryDivisorData divisorData;
UInt128 result;
@@ -180,7 +180,7 @@ internal static partial class PrimeOrderCalculator
}
}
private static PartialFactorResult128 PartialFactorWide(in UInt128 value, in PrimeOrderSearchConfig config)
private static PartialFactorResult128 PartialFactorWide(in UInt128 value, in PrimeOrderCalculatorConfig config)
{
if (value <= UInt128.One)
{
+7 -13
View File
@@ -4,39 +4,33 @@ namespace PerfectNumbers.Core;
internal static partial class PrimeOrderCalculator
{
internal enum PrimeOrderMode
internal readonly struct PrimeOrderCalculatorConfig(uint smallFactorLimit, int pollardRhoMilliseconds, int maxPowChecks, bool strictMode)
{
Heuristic,
Strict,
}
private static PrimeOrderCalculatorConfig _heuristicDefault = CreateHeuristicDefault(UnboundedTaskScheduler.ConfiguredThreadCount);
internal readonly struct PrimeOrderSearchConfig(uint smallFactorLimit, int pollardRhoMilliseconds, int maxPowChecks, PrimeOrderMode mode)
{
private static PrimeOrderSearchConfig _heuristicDefault = CreateHeuristicDefault(UnboundedTaskScheduler.ConfiguredThreadCount);
public static PrimeOrderSearchConfig HeuristicDefault
public static PrimeOrderCalculatorConfig HeuristicDefault
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _heuristicDefault;
}
public static readonly PrimeOrderSearchConfig StrictDefault = new(smallFactorLimit: 1_000_000, pollardRhoMilliseconds: 0, maxPowChecks: 0, PrimeOrderMode.Strict);
public static readonly PrimeOrderCalculatorConfig StrictDefault = new(smallFactorLimit: 1_000_000, pollardRhoMilliseconds: 0, maxPowChecks: 0, true);
public static void ConfigureHeuristicDefault(int threadCount)
{
_heuristicDefault = CreateHeuristicDefault(threadCount);
}
public static PrimeOrderSearchConfig CreateHeuristicDefault(int threadCount)
public static PrimeOrderCalculatorConfig CreateHeuristicDefault(int threadCount)
{
int normalizedThreadCount = threadCount < 1 ? 1 : threadCount;
return new(smallFactorLimit: 100_000, pollardRhoMilliseconds: normalizedThreadCount * 24, maxPowChecks: 24, PrimeOrderMode.Heuristic);
return new(smallFactorLimit: 100_000, pollardRhoMilliseconds: normalizedThreadCount * 24, maxPowChecks: 24, false);
}
public readonly uint SmallFactorLimit = smallFactorLimit;
public readonly int PollardRhoMilliseconds = pollardRhoMilliseconds;
public readonly int MaxPowChecks = maxPowChecks;
public readonly PrimeOrderMode Mode = mode;
public readonly bool StrictMode = strictMode;
}
// TODO: Remove branching on the CPU / GPU paths
@@ -19,7 +19,7 @@ public sealed class UnboundedTaskScheduler : TaskScheduler
public static void ConfigureThreadCount(int threadCount)
{
_configuredThreadCount = threadCount;
PrimeOrderCalculator.PrimeOrderSearchConfig.ConfigureHeuristicDefault(threadCount);
PrimeOrderCalculator.PrimeOrderCalculatorConfig.ConfigureHeuristicDefault(threadCount);
// On EvenPerfectBitScanner's execution path the scheduler instance is created after configuration,
// so updating an existing pool would never run. Leave the update path disabled for now.