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
+279 -244

No files matched your search

@@ -623,7 +623,7 @@ public class Pow2ModBenchmarks
modulus, modulus,
previousPrimeOrder, previousPrimeOrder,
divisorData, divisorData,
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault); PrimeOrderCalculator.PrimeOrderCalculatorConfig.HeuristicDefault);
if (order != 0UL) if (order != 0UL)
{ {
@@ -645,7 +645,7 @@ public class Pow2ModBenchmarks
UInt128 order = PrimeOrderCalculator.CalculateCpu( UInt128 order = PrimeOrderCalculator.CalculateCpu(
modulus, modulus,
previousWidePrimeOrder, previousWidePrimeOrder,
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault); PrimeOrderCalculator.PrimeOrderCalculatorConfig.HeuristicDefault);
if (order != UInt128.Zero) if (order != UInt128.Zero)
{ {
@@ -693,7 +693,7 @@ public class Pow2ModBenchmarks
modulus, modulus,
_previousPrimeOrder, _previousPrimeOrder,
divisorData, divisorData,
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault); PrimeOrderCalculator.PrimeOrderCalculatorConfig.HeuristicDefault);
if (order != 0UL) if (order != 0UL)
{ {
@@ -723,7 +723,7 @@ public class Pow2ModBenchmarks
modulus, modulus,
_previousPrimeOrder, _previousPrimeOrder,
divisorData, divisorData,
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault); PrimeOrderCalculator.PrimeOrderCalculatorConfig.HeuristicDefault);
if (order != 0UL) if (order != 0UL)
{ {
@@ -750,7 +750,7 @@ public class Pow2ModBenchmarks
UInt128 order = PrimeOrderCalculator.CalculateCpu( UInt128 order = PrimeOrderCalculator.CalculateCpu(
modulus, modulus,
_previousWidePrimeOrder, _previousWidePrimeOrder,
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault); PrimeOrderCalculator.PrimeOrderCalculatorConfig.HeuristicDefault);
if (order != UInt128.Zero) if (order != UInt128.Zero)
{ {
@@ -778,7 +778,7 @@ public class Pow2ModBenchmarks
gpu, gpu,
modulus, modulus,
_previousWidePrimeOrder, _previousWidePrimeOrder,
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault); PrimeOrderCalculator.PrimeOrderCalculatorConfig.HeuristicDefault);
if (order != UInt128.Zero) if (order != UInt128.Zero)
{ {
+2
View File
@@ -448,6 +448,8 @@ internal static class Program
// Configure batch size for GPU primality sieve // Configure batch size for GPU primality sieve
PrimeTester.GpuBatchSize = gpuPrimeBatch; PrimeTester.GpuBatchSize = gpuPrimeBatch;
_ = AcceleratorPool.Shared;
Stopwatch? stopwatch = null; Stopwatch? stopwatch = null;
if (testMode) if (testMode)
{ {
@@ -398,7 +398,7 @@ public class PrimeOrderGpuHeuristicsTests
PrimeOrderGpuHeuristics.OverflowRegistry[prime] = 0; PrimeOrderGpuHeuristics.OverflowRegistry[prime] = 0;
MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(prime); MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(prime);
ulong result = PrimeOrderCalculator.CalculateGpu(gpu, prime, null, divisorData, PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault); ulong result = PrimeOrderCalculator.CalculateGpu(gpu, prime, null, divisorData, PrimeOrderCalculator.PrimeOrderCalculatorConfig.HeuristicDefault);
result.Should().Be(3UL); result.Should().Be(3UL);
} }
@@ -50,7 +50,7 @@ public class PrimeOrderCalculatorTests
prime, prime,
previousOrder: null, previousOrder: null,
MontgomeryDivisorDataPool.Shared.FromModulus(prime), MontgomeryDivisorDataPool.Shared.FromModulus(prime),
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault); PrimeOrderCalculator.PrimeOrderCalculatorConfig.HeuristicDefault);
PrimeOrderCalculatorAccelerator.Return(gpu); PrimeOrderCalculatorAccelerator.Return(gpu);
@@ -70,14 +70,14 @@ public class PrimeOrderCalculatorTests
prime, prime,
previousOrder, previousOrder,
MontgomeryDivisorDataPool.Shared.FromModulus(prime), MontgomeryDivisorDataPool.Shared.FromModulus(prime),
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault); PrimeOrderCalculator.PrimeOrderCalculatorConfig.HeuristicDefault);
ulong strict = PrimeOrderCalculator.CalculateGpu( ulong strict = PrimeOrderCalculator.CalculateGpu(
gpu, gpu,
prime, prime,
previousOrder: null, previousOrder: null,
MontgomeryDivisorDataPool.Shared.FromModulus(prime), MontgomeryDivisorDataPool.Shared.FromModulus(prime),
PrimeOrderCalculator.PrimeOrderSearchConfig.StrictDefault); PrimeOrderCalculator.PrimeOrderCalculatorConfig.StrictDefault);
PrimeOrderCalculatorAccelerator.Return(gpu); PrimeOrderCalculatorAccelerator.Return(gpu);
@@ -96,7 +96,7 @@ public class PrimeOrderCalculatorTests
prime, prime,
previousOrder: null, previousOrder: null,
MontgomeryDivisorDataPool.Shared.FromModulus(prime), MontgomeryDivisorDataPool.Shared.FromModulus(prime),
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault); PrimeOrderCalculator.PrimeOrderCalculatorConfig.HeuristicDefault);
PrimeOrderCalculatorAccelerator.Return(gpu); PrimeOrderCalculatorAccelerator.Return(gpu);
result.Should().Be(expectedOrder); result.Should().Be(expectedOrder);
@@ -106,11 +106,11 @@ public class PrimeOrderCalculatorTests
[Trait("Category", "Fast")] [Trait("Category", "Fast")]
public void Calculate_heuristic_mode_returns_unresolved_when_phi_cannot_be_factored() public void Calculate_heuristic_mode_returns_unresolved_when_phi_cannot_be_factored()
{ {
var config = new PrimeOrderCalculator.PrimeOrderSearchConfig( var config = new PrimeOrderCalculator.PrimeOrderCalculatorConfig(
smallFactorLimit: 1, smallFactorLimit: 1,
pollardRhoMilliseconds: 0, pollardRhoMilliseconds: 0,
maxPowChecks: 8, maxPowChecks: 8,
mode: PrimeOrderCalculator.PrimeOrderMode.Heuristic); strictMode: false);
var gpu = PrimeOrderCalculatorAccelerator.Rent(1); var gpu = PrimeOrderCalculatorAccelerator.Rent(1);
ulong result = PrimeOrderCalculator.CalculateGpu( ulong result = PrimeOrderCalculator.CalculateGpu(
@@ -128,11 +128,11 @@ public class PrimeOrderCalculatorTests
[Trait("Category", "Fast")] [Trait("Category", "Fast")]
public void Calculate_heuristic_mode_attempts_candidates_before_falling_back_to_strict_mode() public void Calculate_heuristic_mode_attempts_candidates_before_falling_back_to_strict_mode()
{ {
var heuristicConfig = new PrimeOrderCalculator.PrimeOrderSearchConfig( var heuristicConfig = new PrimeOrderCalculator.PrimeOrderCalculatorConfig(
smallFactorLimit: 2, smallFactorLimit: 2,
pollardRhoMilliseconds: 0, pollardRhoMilliseconds: 0,
maxPowChecks: 1, maxPowChecks: 1,
mode: PrimeOrderCalculator.PrimeOrderMode.Heuristic); strictMode: false);
var gpu = PrimeOrderCalculatorAccelerator.Rent(1); var gpu = PrimeOrderCalculatorAccelerator.Rent(1);
try try
@@ -147,11 +147,11 @@ public class PrimeOrderCalculatorTests
heuristic.Should().Be(ComputeOrderByDoubling(239UL)); heuristic.Should().Be(ComputeOrderByDoubling(239UL));
var strictConfig = new PrimeOrderCalculator.PrimeOrderSearchConfig( var strictConfig = new PrimeOrderCalculator.PrimeOrderCalculatorConfig(
smallFactorLimit: 2, smallFactorLimit: 2,
pollardRhoMilliseconds: 0, pollardRhoMilliseconds: 0,
maxPowChecks: 1, maxPowChecks: 1,
mode: PrimeOrderCalculator.PrimeOrderMode.Strict); strictMode: true);
ulong strict = PrimeOrderCalculator.CalculateGpu( ulong strict = PrimeOrderCalculator.CalculateGpu(
gpu, gpu,
@@ -179,7 +179,7 @@ public class PrimeOrderCalculatorTests
gpu, gpu,
prime, prime,
previousOrder: null, previousOrder: null,
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault); PrimeOrderCalculator.PrimeOrderCalculatorConfig.HeuristicDefault);
PrimeOrderCalculatorAccelerator.Return(gpu); PrimeOrderCalculatorAccelerator.Return(gpu);
result.Should().Be((UInt128)1229782938247309446UL); result.Should().Be((UInt128)1229782938247309446UL);
+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; 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 ulong PreviousOrder = previousOrder;
public readonly byte HasPreviousOrder = hasPreviousOrder; public readonly byte HasPreviousOrder = hasPreviousOrder;
public readonly uint SmallFactorLimit = smallFactorLimit; public readonly uint SmallFactorLimit = smallFactorLimit;
public readonly int MaxPowChecks = maxPowChecks; 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, PrimeOrderCalculatorAccelerator gpu,
ulong prime, ulong prime,
ulong? previousOrder, ulong? previousOrder,
PrimeOrderCalculator.PrimeOrderSearchConfig config, PrimeOrderCalculator.PrimeOrderCalculatorConfig config,
in MontgomeryDivisorData divisorData, in MontgomeryDivisorData divisorData,
out ulong order) out ulong order)
{ {
@@ -258,7 +258,7 @@ internal static partial class PrimeOrderGpuHeuristics
byte hasPrevious = previousOrder.HasValue ? (byte)1 : (byte)0; byte hasPrevious = previousOrder.HasValue ? (byte)1 : (byte)0;
ulong previousValue = previousOrder ?? 0UL; 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; ref var buffers = ref gpu.CalculateOrderKernelBuffers;
var kernelLauncher = gpu.CalculateOrderKernelLauncher; var kernelLauncher = gpu.CalculateOrderKernelLauncher;
+9 -9
View File
@@ -404,7 +404,7 @@ public class MersenneDivisorCycles
UInt128 wideOrder = PrimeOrderCalculator.CalculateCpu( UInt128 wideOrder = PrimeOrderCalculator.CalculateCpu(
divisor, divisor,
previousOrder: null, previousOrder: null,
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault); PrimeOrderCalculator.PrimeOrderCalculatorConfig.HeuristicDefault);
if (wideOrder != UInt128.Zero) if (wideOrder != UInt128.Zero)
{ {
return wideOrder; return wideOrder;
@@ -452,7 +452,7 @@ public class MersenneDivisorCycles
gpu, gpu,
divisor, divisor,
previousOrder: null, previousOrder: null,
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault); PrimeOrderCalculator.PrimeOrderCalculatorConfig.HeuristicDefault);
if (wideOrder != UInt128.Zero) if (wideOrder != UInt128.Zero)
{ {
return wideOrder; return wideOrder;
@@ -500,7 +500,7 @@ public class MersenneDivisorCycles
gpu, gpu,
divisor, divisor,
previousOrder: null, previousOrder: null,
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault); PrimeOrderCalculator.PrimeOrderCalculatorConfig.HeuristicDefault);
if (wideOrder != UInt128.Zero) if (wideOrder != UInt128.Zero)
{ {
return wideOrder; return wideOrder;
@@ -554,7 +554,7 @@ public class MersenneDivisorCycles
divisor, divisor,
previousOrder: null, previousOrder: null,
divisorData, divisorData,
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault); PrimeOrderCalculator.PrimeOrderCalculatorConfig.HeuristicDefault);
if (computedOrder != 0UL) if (computedOrder != 0UL)
{ {
cycleLength = computedOrder; cycleLength = computedOrder;
@@ -639,7 +639,7 @@ public class MersenneDivisorCycles
divisor, divisor,
previousOrder: null, previousOrder: null,
divisorData, divisorData,
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault); PrimeOrderCalculator.PrimeOrderCalculatorConfig.HeuristicDefault);
if (computedOrder != 0UL) if (computedOrder != 0UL)
{ {
cycleLength = computedOrder; cycleLength = computedOrder;
@@ -724,7 +724,7 @@ public class MersenneDivisorCycles
divisor, divisor,
previousOrder: null, previousOrder: null,
divisorData, divisorData,
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault); PrimeOrderCalculator.PrimeOrderCalculatorConfig.HeuristicDefault);
if (computedOrder != 0UL) if (computedOrder != 0UL)
{ {
cycleLength = computedOrder; cycleLength = computedOrder;
@@ -1401,7 +1401,7 @@ public class MersenneDivisorCycles
divisor, divisor,
previousOrder: null, previousOrder: null,
divisorData, divisorData,
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault); PrimeOrderCalculator.PrimeOrderCalculatorConfig.HeuristicDefault);
if (computedOrder != 0UL) if (computedOrder != 0UL)
{ {
cycleLength = computedOrder; cycleLength = computedOrder;
@@ -1434,7 +1434,7 @@ public class MersenneDivisorCycles
divisor, divisor,
previousOrder: null, previousOrder: null,
divisorData, divisorData,
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault); PrimeOrderCalculator.PrimeOrderCalculatorConfig.HeuristicDefault);
if (computedOrder != 0UL) if (computedOrder != 0UL)
{ {
cycleLength = computedOrder; cycleLength = computedOrder;
@@ -1467,7 +1467,7 @@ public class MersenneDivisorCycles
divisor, divisor,
previousOrder: null, previousOrder: null,
divisorData, divisorData,
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault); PrimeOrderCalculator.PrimeOrderCalculatorConfig.HeuristicDefault);
if (computedOrder != 0UL) if (computedOrder != 0UL)
{ {
cycleLength = computedOrder; cycleLength = computedOrder;
+15 -20
View File
@@ -78,14 +78,12 @@ namespace PerfectNumbers.Core
} }
int newSize = sourceCount + 1; int newSize = sourceCount + 1;
int[] extendedExponents;
ulong[] extendedFactors = sourceFactors.Length >= newSize ulong[] extendedFactors = sourceFactors.Length >= newSize
? sourceFactors ? sourceFactors
: ResizeFactors(sourceFactors, sourceCount, newSize); : ResizeFactors(sourceFactors, sourceCount, newSize);
int[] sourceExponents = Exponents!; int[] sourceExponents = Exponents!;
extendedExponents = sourceExponents.Length >= newSize int[] extendedExponents = sourceExponents.Length >= newSize
? sourceExponents ? sourceExponents
: ResizeExponents(sourceCount, newSize, sourceExponents); : ResizeExponents(sourceCount, newSize, sourceExponents);
@@ -101,31 +99,29 @@ namespace PerfectNumbers.Core
CofactorIsPrime = false; 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); Array.Copy(sourceExponents, 0, extendedExponents, 0, sourceCount);
ThreadStaticPools.IntPool.Return(sourceExponents, clearArray: false); Pools.ExclusiveIntArray.Return(sourceExponents);
return extendedExponents; 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); Array.Copy(sourceFactors, 0, extendedFactors, 0, sourceCount);
ThreadStaticPools.UlongPool.Return(sourceFactors, clearArray: false); Pools.ExclusiveUlongArray.Return(sourceFactors);
return extendedFactors; return extendedFactors;
} }
private void InitializeWithPrime(ulong prime) private void InitializeWithPrime(ulong prime)
{ {
ulong[] source = ThreadStaticPools.UlongPool.Rent(1); ulong[] factors = Pools.ExclusiveUlongArray.Rent(1);
int[] exponents = ThreadStaticPools.IntPool.Rent(1); int[] exponents = Pools.ExclusiveIntArray.Rent(1);
// source = new ulong[1]; factors[0] = prime;
// exponents = new int[1];
source[0] = prime;
exponents[0] = 1; exponents[0] = 1;
Factors = source; Factors = factors;
Exponents = exponents; Exponents = exponents;
Cofactor = 1UL; Cofactor = 1UL;
FullyFactored = true; FullyFactored = true;
@@ -137,18 +133,17 @@ namespace PerfectNumbers.Core
{ {
if (this != Empty) if (this != Empty)
{ {
ulong[]? factors = Factors; ulong[]? factors = Factors;
if (factors is not null) if (factors is not null)
{ {
int[] exponents = Exponents!; int[] exponents = Exponents!;
Factors = null; Factors = null;
Exponents = null; Exponents = null;
// if (factors.Length > 1) Pools.ExclusiveUlongArray.Return(factors);
// { Pools.ExclusiveIntArray.Return(exponents);
ThreadStaticPools.UlongPool.Return(factors, clearArray: false);
ThreadStaticPools.IntPool.Return(exponents, clearArray: false);
// }
} }
_next = s_poolHead; _next = s_poolHead;
+108 -168
View File
@@ -12,9 +12,37 @@ namespace PerfectNumbers.Core;
internal static partial class PrimeOrderCalculator 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 KnownComposite = knownComposite;
public bool HasKnownPrimality = knownComposite; public bool HasKnownPrimality = knownComposite;
public bool IsPrime = false; public bool IsPrime = false;
@@ -32,7 +60,7 @@ internal static partial class PrimeOrderCalculator
ulong prime, ulong prime,
ulong? previousOrder, ulong? previousOrder,
in MontgomeryDivisorData divisorData, 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. // 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) if (prime <= 3UL)
@@ -61,7 +89,7 @@ internal static partial class PrimeOrderCalculator
public static UInt128 CalculateCpu( public static UInt128 CalculateCpu(
in UInt128 prime, in UInt128 prime,
in UInt128? previousOrder, in UInt128? previousOrder,
in PrimeOrderSearchConfig config) in PrimeOrderCalculatorConfig config)
{ {
MontgomeryDivisorData divisorData; MontgomeryDivisorData divisorData;
UInt128 result; UInt128 result;
@@ -97,7 +125,7 @@ internal static partial class PrimeOrderCalculator
return result; 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) if (prime <= UInt128.One)
{ {
@@ -127,7 +155,7 @@ internal static partial class PrimeOrderCalculator
private static ulong RunHeuristicPipelineCpu( private static ulong RunHeuristicPipelineCpu(
ulong prime, ulong prime,
ulong? previousOrder, ulong? previousOrder,
in PrimeOrderSearchConfig config, in PrimeOrderCalculatorConfig config,
in MontgomeryDivisorData divisorData, in MontgomeryDivisorData divisorData,
ulong phi, ulong phi,
PartialFactorResult phiFactors) PartialFactorResult phiFactors)
@@ -145,7 +173,7 @@ internal static partial class PrimeOrderCalculator
return candidateOrder; return candidateOrder;
} }
if (config.Mode == PrimeOrderMode.Strict) if (config.StrictMode)
{ {
orderFactors?.Dispose(); orderFactors?.Dispose();
return CalculateByFactorizationCpu(prime, divisorData); return CalculateByFactorizationCpu(prime, divisorData);
@@ -163,7 +191,7 @@ internal static partial class PrimeOrderCalculator
PrimeOrderCalculatorAccelerator gpu, PrimeOrderCalculatorAccelerator gpu,
ulong prime, ulong prime,
ulong? previousOrder, ulong? previousOrder,
in PrimeOrderSearchConfig config, in PrimeOrderCalculatorConfig config,
in MontgomeryDivisorData divisorData, in MontgomeryDivisorData divisorData,
ulong phi, ulong phi,
PartialFactorResult phiFactors) PartialFactorResult phiFactors)
@@ -181,7 +209,7 @@ internal static partial class PrimeOrderCalculator
return candidateOrder; return candidateOrder;
} }
if (config.Mode == PrimeOrderMode.Strict) if (config.StrictMode)
{ {
orderFactors?.Dispose(); orderFactors?.Dispose();
return CalculateByFactorizationCpu(prime, divisorData); return CalculateByFactorizationCpu(prime, divisorData);
@@ -199,7 +227,7 @@ internal static partial class PrimeOrderCalculator
in UInt128 prime, in UInt128 prime,
in UInt128? previousOrder, in UInt128? previousOrder,
in MontgomeryDivisorData? divisorData, in MontgomeryDivisorData? divisorData,
in PrimeOrderSearchConfig config, in PrimeOrderCalculatorConfig config,
in UInt128 phi, in UInt128 phi,
in PartialFactorResult128 phiFactors) in PartialFactorResult128 phiFactors)
{ {
@@ -216,7 +244,7 @@ internal static partial class PrimeOrderCalculator
return candidateOrder; return candidateOrder;
} }
if (config.Mode == PrimeOrderMode.Strict) if (config.StrictMode)
{ {
return FinishStrictlyWideCpu(prime, divisorData); return FinishStrictlyWideCpu(prime, divisorData);
} }
@@ -354,7 +382,7 @@ internal static partial class PrimeOrderCalculator
return order; 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) if (order == UInt128.Zero)
{ {
@@ -416,7 +444,7 @@ internal static partial class PrimeOrderCalculator
in UInt128 order, in UInt128 order,
in UInt128? previousOrder, in UInt128? previousOrder,
in MontgomeryDivisorData? divisorData, in MontgomeryDivisorData? divisorData,
in PrimeOrderSearchConfig config, in PrimeOrderCalculatorConfig config,
out UInt128 result) out UInt128 result)
{ {
result = UInt128.Zero; 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) 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<ulong> factorSpan = factors.Factors;
ReadOnlySpan<int> exponentsSpan = factors.Exponents; ReadOnlySpan<int> exponentsSpan = factors.Exponents;
int length = factors.Count; int length = factors.Count;
ulong[] tempFactorsArray = ulongPool.Rent(length + 1); ulong[] tempFactorsArray = Pools.ExclusiveUlongArray.Rent(length + 1);
int[] tempExponentsArray = intPool.Rent(length + 1); int[] tempExponentsArray = Pools.ExclusiveIntArray.Rent(length + 1);
Span<ulong> ulongBuffer = tempFactorsArray; Span<ulong> ulongBuffer = tempFactorsArray;
factorSpan.CopyTo(ulongBuffer); factorSpan.CopyTo(ulongBuffer);
@@ -664,7 +689,7 @@ internal static partial class PrimeOrderCalculator
continue; continue;
} }
heapCandidateArray ??= ThreadStaticPools.UlongPool.Rent(ExponentHardLimit); heapCandidateArray ??= Pools.ExclusiveUlongArray.Rent(ExponentHardLimit);
heapEvaluationArray ??= ThreadStaticPools.BoolPool.Rent(ExponentHardLimit); heapEvaluationArray ??= ThreadStaticPools.BoolPool.Rent(ExponentHardLimit);
ProcessExponentLoweringPrime(heapCandidateArray.AsSpan(0, exponent), heapEvaluationArray.AsSpan(0, exponent), ref order, primeFactor, exponent, ref stepper); 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) if (heapCandidateArray is not null)
{ {
ThreadStaticPools.UlongPool.Return(heapCandidateArray); Pools.ExclusiveUlongArray.Return(heapCandidateArray);
ThreadStaticPools.BoolPool.Return(heapEvaluationArray!); ThreadStaticPools.BoolPool.Return(heapEvaluationArray!);
} }
ulongPool.Return(tempFactorsArray, clearArray: false); Pools.ExclusiveUlongArray.Return(tempFactorsArray);
return order; return order;
} }
@@ -735,7 +760,7 @@ internal static partial class PrimeOrderCalculator
ulong prime, ulong prime,
ulong order, ulong order,
in MontgomeryDivisorData divisorData, in MontgomeryDivisorData divisorData,
in PrimeOrderSearchConfig config, in PrimeOrderCalculatorConfig config,
out PartialFactorResult? reusableFactorization) out PartialFactorResult? reusableFactorization)
{ {
reusableFactorization = null; reusableFactorization = null;
@@ -783,7 +808,7 @@ internal static partial class PrimeOrderCalculator
ulong prime, ulong prime,
ulong order, ulong order,
in MontgomeryDivisorData divisorData, in MontgomeryDivisorData divisorData,
in PrimeOrderSearchConfig config, in PrimeOrderCalculatorConfig config,
out PartialFactorResult? reusableFactorization) out PartialFactorResult? reusableFactorization)
{ {
reusableFactorization = null; reusableFactorization = null;
@@ -873,7 +898,7 @@ internal static partial class PrimeOrderCalculator
continue; continue;
} }
heapCandidateArray ??= ThreadStaticPools.UlongPool.Rent(ExponentHardLimit); heapCandidateArray ??= Pools.ExclusiveUlongArray.Rent(ExponentHardLimit);
if (ValidateOrderForFactor(heapCandidateArray.AsSpan(0, exponent), primeFactor, exponent, order, ref stepper)) if (ValidateOrderForFactor(heapCandidateArray.AsSpan(0, exponent), primeFactor, exponent, order, ref stepper))
{ {
violates = true; violates = true;
@@ -885,7 +910,7 @@ internal static partial class PrimeOrderCalculator
if (heapCandidateArray is not null) if (heapCandidateArray is not null)
{ {
ThreadStaticPools.UlongPool.Return(heapCandidateArray); Pools.ExclusiveUlongArray.Return(heapCandidateArray);
} }
return !violates; return !violates;
@@ -944,7 +969,7 @@ internal static partial class PrimeOrderCalculator
ulong order, ulong order,
ulong? previousOrder, ulong? previousOrder,
in MontgomeryDivisorData divisorData, in MontgomeryDivisorData divisorData,
in PrimeOrderSearchConfig config, in PrimeOrderCalculatorConfig config,
PartialFactorResult phiFactors, PartialFactorResult phiFactors,
PartialFactorResult? cachedOrderFactors, PartialFactorResult? cachedOrderFactors,
out ulong result) out ulong result)
@@ -1079,7 +1104,7 @@ internal static partial class PrimeOrderCalculator
ulong order, ulong order,
ulong? previousOrder, ulong? previousOrder,
in MontgomeryDivisorData divisorData, in MontgomeryDivisorData divisorData,
in PrimeOrderSearchConfig config, in PrimeOrderCalculatorConfig config,
PartialFactorResult phiFactors, PartialFactorResult phiFactors,
PartialFactorResult? cachedOrderFactors, PartialFactorResult? cachedOrderFactors,
out ulong result) out ulong result)
@@ -1211,7 +1236,7 @@ internal static partial class PrimeOrderCalculator
ulong order, ulong order,
ulong? previousOrder, ulong? previousOrder,
in MontgomeryDivisorData divisorData, in MontgomeryDivisorData divisorData,
in PrimeOrderSearchConfig config, in PrimeOrderCalculatorConfig config,
PartialFactorResult phiFactors, PartialFactorResult phiFactors,
PartialFactorResult? cachedOrderFactors, PartialFactorResult? cachedOrderFactors,
out ulong result) out ulong result)
@@ -1437,7 +1462,7 @@ internal static partial class PrimeOrderCalculator
int group = GetGroup(value, threshold1, threshold2, threshold3); int group = GetGroup(value, threshold1, threshold2, threshold3);
if (group == 0) if (group == 0)
{ {
return new CandidateKey(int.MaxValue, long.MaxValue, long.MaxValue); return CandidateKey.Max;
} }
bool isGe = !hasPrevious || value >= previous; bool isGe = !hasPrevious || value >= previous;
@@ -1453,14 +1478,15 @@ internal static partial class PrimeOrderCalculator
else else
{ {
ulong reference = hasPrevious ? previous : 0UL; ulong reference = hasPrevious ? previous : 0UL;
ulong distance = hasPrevious ? (value > reference ? value - reference : reference - value) : value; reference = hasPrevious ? (value > reference ? value - reference : reference - value) : value;
secondary = (long)distance; secondary = (long)reference;
tertiary = (long)value; tertiary = (long)value;
} }
return new CandidateKey(primary, secondary, tertiary); return new CandidateKey(primary, secondary, tertiary);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int ComputePrimary(int group, bool isGe, int previousGroup) private static int ComputePrimary(int group, bool isGe, int previousGroup)
{ {
int groupOffset = group switch int groupOffset = group switch
@@ -1484,6 +1510,7 @@ internal static partial class PrimeOrderCalculator
return groupOffset + (isGe ? 0 : 1); return groupOffset + (isGe ? 0 : 1);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int GetGroup(ulong value, ulong threshold1, ulong threshold2, ulong threshold3) private static int GetGroup(ulong value, ulong threshold1, ulong threshold2, ulong threshold3)
{ {
if (value <= threshold1) if (value <= threshold1)
@@ -1504,8 +1531,6 @@ internal static partial class PrimeOrderCalculator
return 0; 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) private static void BuildCandidates(ulong order, ulong[] factors, int[] exponents, int count, List<ulong> candidates, int limit)
{ {
if (count == 0) 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); PartialFactorResult factorization = PartialFactorCpu(candidate, config);
@@ -1638,7 +1663,7 @@ internal static partial class PrimeOrderCalculator
continue; 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)) if (CheckCandidateViolation(heapCandidateArray.AsSpan(0, exponent), primeFactor, exponent, candidate, prime, ref powUsed, powBudget, ref stepper))
{ {
violates = true; violates = true;
@@ -1650,14 +1675,14 @@ internal static partial class PrimeOrderCalculator
if (heapCandidateArray is not null) if (heapCandidateArray is not null)
{ {
ThreadStaticPools.UlongPool.Return(heapCandidateArray); Pools.ExclusiveUlongArray.Return(heapCandidateArray);
} }
factorization.Dispose(); factorization.Dispose();
return !violates; 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); PartialFactorResult factorization = PartialFactorHybrid(gpu, candidate, config);
@@ -1839,14 +1864,12 @@ internal static partial class PrimeOrderCalculator
return exponent.Pow2MontgomeryModWindowedConvertToStandardCpu(divisorData) == 1UL; 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 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) if (value <= 1UL)
{ {
@@ -1856,8 +1879,6 @@ internal static partial class PrimeOrderCalculator
// stackalloc is faster than pooling // stackalloc is faster than pooling
Span<ulong> primeSlots = stackalloc ulong[PrimeOrderConstants.GpuSmallPrimeFactorSlots]; Span<ulong> primeSlots = stackalloc ulong[PrimeOrderConstants.GpuSmallPrimeFactorSlots];
Span<int> exponentSlots = stackalloc int[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 // We don't need to worry about leftovers, because we always use indexes within the calculated counts
// primeSlots.Clear(); // primeSlots.Clear();
@@ -1866,15 +1887,13 @@ internal static partial class PrimeOrderCalculator
uint limit = config.SmallFactorLimit == 0 ? uint.MaxValue : config.SmallFactorLimit; uint limit = config.SmallFactorLimit == 0 ? uint.MaxValue : config.SmallFactorLimit;
ulong remaining = value; ulong remaining = value;
List<PendingEntry> pending = ThreadStaticPools.RentPrimeOrderPendingEntryList(2); List<PendingEntry> pending = ThreadStaticPools.RentPrimeOrderPendingEntryList(PrimeOrderConstants.GpuSmallPrimeFactorSlots);
PopulateSmallPrimeFactorsCpu( PopulateSmallPrimeFactorsCpu(
value, value,
limit, limit,
ref primeSlots, primeSlots,
ref exponentSlots, exponentSlots,
ref primeSlotArray,
ref exponentSlotArray,
out int factorCount, out int factorCount,
out remaining); out remaining);
@@ -1884,16 +1903,16 @@ internal static partial class PrimeOrderCalculator
if (config.PollardRhoMilliseconds > 0) if (config.PollardRhoMilliseconds > 0)
{ {
long deadlineTimestamp = CreateDeadlineTimestamp(config.PollardRhoMilliseconds); long deadlineTimestamp = CreateDeadlineTimestamp(config.PollardRhoMilliseconds);
Stack<ulong> compositeStack = ThreadStaticPools.RentUlongStack(4); Stack<ulong> compositeStack = ThreadStaticPools.RentUlongStack(PrimeOrderConstants.GpuSmallPrimeFactorSlots);
compositeStack.Push(remaining); 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) if (limitReached)
{ {
while (compositeStack.Count > 0) 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 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); cofactor = checked(cofactor * composite);
cofactorContainsComposite = true; cofactorContainsComposite = true;
PendingEntry.Return(entry);
continue; continue;
} }
@@ -1926,16 +1946,12 @@ internal static partial class PrimeOrderCalculator
{ {
bool isPrime = PrimeTesterByLastDigit.IsPrimeCpu(composite); bool isPrime = PrimeTesterByLastDigit.IsPrimeCpu(composite);
// Atomic.Add(ref _partialFactorPendingHits, 1UL);
// Console.WriteLine($"Partial factor pending hits {Volatile.Read(ref _partialFactorPendingHits)}");
entry.WithPrimality(isPrime); entry.WithPrimality(isPrime);
pending[index] = entry;
} }
if (entry.IsPrime) 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 // composite is never smaller on the execution path
// else if (composite > 1UL) // else if (composite > 1UL)
@@ -1944,6 +1960,8 @@ internal static partial class PrimeOrderCalculator
cofactor = checked(cofactor * composite); cofactor = checked(cofactor * composite);
cofactorContainsComposite = true; cofactorContainsComposite = true;
} }
PendingEntry.Return(entry);
} }
bool cofactorIsPrime; bool cofactorIsPrime;
@@ -1958,9 +1976,6 @@ internal static partial class PrimeOrderCalculator
else else
{ {
cofactorIsPrime = PrimeTesterByLastDigit.IsPrimeCpu(cofactor); cofactorIsPrime = PrimeTesterByLastDigit.IsPrimeCpu(cofactor);
// Atomic.Add(ref _partialFactorCofactorHits, 1UL);
// Console.WriteLine($"Partial factor cofactor hits {Volatile.Read(ref _partialFactorCofactorHits)}");
} }
PartialFactorResult result; PartialFactorResult result;
@@ -1989,11 +2004,8 @@ internal static partial class PrimeOrderCalculator
// goto ReturnResult; // goto ReturnResult;
// } // }
ArrayPool<ulong> ulongPool = ThreadStaticPools.UlongPool; ulong[] factorsArray = Pools.ExclusiveUlongArray.Rent(factorCount);
ArrayPool<int> intPool = ThreadStaticPools.IntPool; int[] exponentsArray = Pools.ExclusiveIntArray.Rent(factorCount);
ulong[] factorsArray = ulongPool.Rent(factorCount);
int[] exponentsArray = intPool.Rent(factorCount);
for (int i = 0; i < factorCount; i++) 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); result = PartialFactorResult.Rent(factorsArray, exponentsArray, cofactor, limitReached, factorCount, cofactorIsPrime);
ReturnResult: ReturnResult:
if (primeSlotArray.Length > 0)
{
ThreadStaticPools.UlongPool.Return(primeSlotArray, clearArray: false);
ThreadStaticPools.IntPool.Return(exponentSlotArray, clearArray: false);
}
pending.Clear(); pending.Clear();
ThreadStaticPools.ReturnPrimeOrderPendingEntryList(pending); ThreadStaticPools.ReturnPrimeOrderPendingEntryList(pending);
return result; 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) if (value <= 1UL)
{ {
@@ -2051,10 +2057,8 @@ internal static partial class PrimeOrderCalculator
PopulateSmallPrimeFactorsCpu( PopulateSmallPrimeFactorsCpu(
value, value,
limit, limit,
ref primeSlots, primeSlots,
ref exponentSlots, exponentSlots,
ref primeSlotArray,
ref exponentSlotArray,
out int factorCount, out int factorCount,
out remaining); out remaining);
@@ -2067,7 +2071,7 @@ internal static partial class PrimeOrderCalculator
Stack<ulong> compositeStack = ThreadStaticPools.RentUlongStack(4); Stack<ulong> compositeStack = ThreadStaticPools.RentUlongStack(4);
compositeStack.Push(remaining); 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) if (limitReached)
{ {
@@ -2106,16 +2110,13 @@ internal static partial class PrimeOrderCalculator
{ {
bool isPrime = RunOnCpu() ? PrimeTesterByLastDigit.IsPrimeCpu(composite) : HeuristicCombinedPrimeTester.IsPrimeGpu(gpu, composite); 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); entry.WithPrimality(isPrime);
pending[index] = entry; pending[index] = entry;
} }
if (entry.IsPrime) 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 // composite is never smaller on the execution path
// else if (composite > 1UL) // else if (composite > 1UL)
@@ -2204,7 +2205,7 @@ internal static partial class PrimeOrderCalculator
return result; 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) if (value <= 1UL)
{ {
@@ -2232,10 +2233,8 @@ internal static partial class PrimeOrderCalculator
PopulateSmallPrimeFactorsCpu( PopulateSmallPrimeFactorsCpu(
value, value,
limit, limit,
ref primeSlots, primeSlots,
ref exponentSlots, exponentSlots,
ref primeSlotArray,
ref exponentSlotArray,
out factorCount, out factorCount,
out remaining); out remaining);
} }
@@ -2249,7 +2248,7 @@ internal static partial class PrimeOrderCalculator
Stack<ulong> compositeStack = ThreadStaticPools.RentUlongStack(4); Stack<ulong> compositeStack = ThreadStaticPools.RentUlongStack(4);
compositeStack.Push(remaining); 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) if (limitReached)
{ {
@@ -2288,16 +2287,13 @@ internal static partial class PrimeOrderCalculator
{ {
bool isPrime = PrimeTesterByLastDigit.IsPrimeCpu(composite); bool isPrime = PrimeTesterByLastDigit.IsPrimeCpu(composite);
// Atomic.Add(ref _partialFactorPendingHits, 1UL);
// Console.WriteLine($"Partial factor pending hits {Volatile.Read(ref _partialFactorPendingHits)}");
entry.WithPrimality(isPrime); entry.WithPrimality(isPrime);
pending[index] = entry; pending[index] = entry;
} }
if (entry.IsPrime) 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 // composite is never smaller on the execution path
// else if (composite > 1UL) // else if (composite > 1UL)
@@ -2320,9 +2316,6 @@ internal static partial class PrimeOrderCalculator
else else
{ {
cofactorIsPrime = PrimeTesterByLastDigit.IsPrimeCpu(cofactor); cofactorIsPrime = PrimeTesterByLastDigit.IsPrimeCpu(cofactor);
// Atomic.Add(ref _partialFactorCofactorHits, 1UL);
// Console.WriteLine($"Partial factor cofactor hits {Volatile.Read(ref _partialFactorCofactorHits)}");
} }
PartialFactorResult result; PartialFactorResult result;
@@ -2390,7 +2383,7 @@ internal static partial class PrimeOrderCalculator
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [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) while (compositeStack.Count > 0)
{ {
@@ -2399,7 +2392,7 @@ internal static partial class PrimeOrderCalculator
if (isPrime) if (isPrime)
{ {
AddFactorToCollector(ref primeSlots, ref exponentSlots, ref primeSlotArray, ref exponentSlotArray, ref factorCount, composite, 1); AddFactorToCollector(primeSlots, exponentSlots, ref factorCount, composite, 1);
continue; continue;
} }
@@ -2425,7 +2418,7 @@ internal static partial class PrimeOrderCalculator
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [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) while (compositeStack.Count > 0)
{ {
@@ -2434,20 +2427,20 @@ internal static partial class PrimeOrderCalculator
if (isPrime) if (isPrime)
{ {
AddFactorToCollector(ref primeSlots, ref exponentSlots, ref primeSlotArray, ref exponentSlotArray, ref factorCount, composite, 1); AddFactorToCollector(primeSlots, exponentSlots, ref factorCount, composite, 1);
continue; continue;
} }
pollardRhoDeadlineReached = Stopwatch.GetTimestamp() > deadlineTimestamp; pollardRhoDeadlineReached = Stopwatch.GetTimestamp() > deadlineTimestamp;
if (pollardRhoDeadlineReached) if (pollardRhoDeadlineReached)
{ {
pending.Add(new PendingEntry(composite, knownComposite: true)); pending.Add(PendingEntry.Rent(composite, knownComposite: true));
continue; continue;
} }
if (!TryPollardRhoCpu(composite, deadlineTimestamp, out ulong factor)) if (!TryPollardRhoCpu(composite, deadlineTimestamp, out ulong factor))
{ {
pending.Add(new PendingEntry(composite, knownComposite: true)); pending.Add(PendingEntry.Rent(composite, knownComposite: true));
continue; continue;
} }
@@ -2469,7 +2462,7 @@ internal static partial class PrimeOrderCalculator
if (isPrime) if (isPrime)
{ {
AddFactorToCollector(ref primeSlots, ref exponentSlots, ref primeSlotArray, ref exponentSlotArray, ref factorCount, composite, 1); AddFactorToCollector(primeSlots, exponentSlots, ref factorCount, composite, 1);
continue; continue;
} }
@@ -2535,10 +2528,8 @@ internal static partial class PrimeOrderCalculator
private static void PopulateSmallPrimeFactorsCpu( private static void PopulateSmallPrimeFactorsCpu(
ulong value, ulong value,
uint limit, uint limit,
ref Span<ulong> primeTargets, Span<ulong> primeTargets,
ref Span<int> exponentTargets, Span<int> exponentTargets,
ref ulong[] primeArray,
ref int[] exponentArray,
out int factorCount, out int factorCount,
out ulong remaining) out ulong remaining)
{ {
@@ -2591,11 +2582,7 @@ internal static partial class PrimeOrderCalculator
} }
EnsureCollectorCapacity( EnsureCollectorCapacity(
ref primeTargets, primeTargets,
ref exponentTargets,
ref primeArray,
ref exponentArray,
factorCount,
factorCount + 1); factorCount + 1);
primeTargets[factorCount] = primeValue; primeTargets[factorCount] = primeValue;
@@ -2797,10 +2784,8 @@ internal static partial class PrimeOrderCalculator
} }
private static void AddFactorToCollector( private static void AddFactorToCollector(
ref Span<ulong> primes, Span<ulong> primes,
ref Span<int> exponents, Span<int> exponents,
ref ulong[] primeArray,
ref int[] exponentArray,
ref int count, ref int count,
ulong prime, ulong prime,
int exponent) int exponent)
@@ -2820,11 +2805,7 @@ internal static partial class PrimeOrderCalculator
} }
EnsureCollectorCapacity( EnsureCollectorCapacity(
ref primes, primes,
ref exponents,
ref primeArray,
ref exponentArray,
count,
count + 1); count + 1);
primes[count] = prime; primes[count] = prime;
@@ -2832,43 +2813,12 @@ internal static partial class PrimeOrderCalculator
count++; count++;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void EnsureCollectorCapacity( private static void EnsureCollectorCapacity(
ref Span<ulong> primes, Span<ulong> primes,
ref Span<int> exponents,
ref ulong[] primeArray,
ref int[] exponentArray,
int count,
int requiredCapacity) int requiredCapacity)
{ {
if (requiredCapacity <= primes.Length) ArgumentOutOfRangeException.ThrowIfGreaterThan(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;
} }
private static ulong CalculateByFactorizationCpu(ulong prime, in MontgomeryDivisorData divisorData) private static ulong CalculateByFactorizationCpu(ulong prime, in MontgomeryDivisorData divisorData)
@@ -2918,9 +2868,6 @@ internal static partial class PrimeOrderCalculator
return order; return order;
} }
// private static ulong _factorCompletelyHits;
// private static ulong _factorCompletelyPollardRhoHits;
private static void FactorCompletelyCpu(ulong value, Dictionary<ulong, int> counts, bool knownComposite) private static void FactorCompletelyCpu(ulong value, Dictionary<ulong, int> counts, bool knownComposite)
{ {
if (value <= 1UL) if (value <= 1UL)
@@ -2928,9 +2875,6 @@ internal static partial class PrimeOrderCalculator
return; return;
} }
// Atomic.Add(ref _factorCompletelyHits, 1UL);
// Console.WriteLine($"Factor completely hits {Volatile.Read(ref _factorCompletelyHits)}");
bool isPrime = PrimeTesterByLastDigit.IsPrimeCpu(value); bool isPrime = PrimeTesterByLastDigit.IsPrimeCpu(value);
if (!knownComposite && isPrime) if (!knownComposite && isPrime)
{ {
@@ -2941,9 +2885,6 @@ internal static partial class PrimeOrderCalculator
ulong factor = PollardRhoStrict(value); ulong factor = PollardRhoStrict(value);
ulong quotient = value / factor; ulong quotient = value / factor;
// Atomic.Add(ref _factorCompletelyPollardRhoHits, 1UL);
// Console.WriteLine($"Factor completely after PollardRho hits {Volatile.Read(ref _factorCompletelyPollardRhoHits)}");
isPrime = PrimeTesterByLastDigit.IsPrimeCpu(factor); isPrime = PrimeTesterByLastDigit.IsPrimeCpu(factor);
if (isPrime) if (isPrime)
{ {
@@ -2973,9 +2914,6 @@ internal static partial class PrimeOrderCalculator
} }
else else
{ {
// Atomic.Add(ref _partialFactorCofactorHits, 1UL);
// Console.WriteLine($"Partial factor cofactor hits {Volatile.Read(ref _partialFactorCofactorHits)}");
isPrime = PrimeTesterByLastDigit.IsPrimeCpu(quotient); isPrime = PrimeTesterByLastDigit.IsPrimeCpu(quotient);
} }
@@ -3029,7 +2967,7 @@ internal static partial class PrimeOrderCalculator
return exponent.Pow2MontgomeryModWindowed(modulus); 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); PartialFactorResult128 factorization = PartialFactorWide(candidate, config);
if (factorization.Factors is null) if (factorization.Factors is null)
@@ -3084,6 +3022,8 @@ internal static partial class PrimeOrderCalculator
private readonly struct CandidateKey(int primary, long secondary, long tertiary) 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 int Primary = primary;
public readonly long Secondary = secondary; public readonly long Secondary = secondary;
public readonly long Tertiary = tertiary; public readonly long Tertiary = tertiary;
@@ -15,7 +15,7 @@ internal static partial class PrimeOrderCalculator
ulong prime, ulong prime,
ulong? previousOrder, ulong? previousOrder,
in MontgomeryDivisorData divisorData, 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. // 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) if (prime <= 3UL)
@@ -50,7 +50,7 @@ internal static partial class PrimeOrderCalculator
PrimeOrderCalculatorAccelerator gpu, PrimeOrderCalculatorAccelerator gpu,
in UInt128 prime, in UInt128 prime,
in UInt128? previousOrder, in UInt128? previousOrder,
in PrimeOrderSearchConfig config) in PrimeOrderCalculatorConfig config)
{ {
MontgomeryDivisorData divisorData; MontgomeryDivisorData divisorData;
UInt128 result; UInt128 result;
@@ -86,7 +86,7 @@ internal static partial class PrimeOrderCalculator
return result; 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) if (prime <= UInt128.One)
{ {
@@ -118,7 +118,7 @@ internal static partial class PrimeOrderCalculator
in UInt128 prime, in UInt128 prime,
in UInt128? previousOrder, in UInt128? previousOrder,
in MontgomeryDivisorData? divisorData, in MontgomeryDivisorData? divisorData,
in PrimeOrderSearchConfig config, in PrimeOrderCalculatorConfig config,
in UInt128 phi, in UInt128 phi,
in PartialFactorResult128 phiFactors) in PartialFactorResult128 phiFactors)
{ {
@@ -135,7 +135,7 @@ internal static partial class PrimeOrderCalculator
return candidateOrder; return candidateOrder;
} }
if (config.Mode == PrimeOrderMode.Strict) if (config.StrictMode)
{ {
return FinishStrictlyWideGpu(gpu, prime, divisorData); return FinishStrictlyWideGpu(gpu, prime, divisorData);
} }
@@ -268,7 +268,7 @@ internal static partial class PrimeOrderCalculator
return order; 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) if (order == UInt128.Zero)
{ {
@@ -331,7 +331,7 @@ internal static partial class PrimeOrderCalculator
in UInt128 order, in UInt128 order,
in UInt128? previousOrder, in UInt128? previousOrder,
in MontgomeryDivisorData? divisorData, in MontgomeryDivisorData? divisorData,
in PrimeOrderSearchConfig config, in PrimeOrderCalculatorConfig config,
out UInt128 result) out UInt128 result)
{ {
result = UInt128.Zero; result = UInt128.Zero;
@@ -575,7 +575,7 @@ internal static partial class PrimeOrderCalculator
return exponent.Pow2MontgomeryModWindowed(modulus); 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); PartialFactorResult128 factorization = PartialFactorWide(candidate, config);
if (factorization.Factors is null) if (factorization.Factors is null)
@@ -9,7 +9,7 @@ internal static partial class PrimeOrderCalculator
ulong prime, ulong prime,
ulong? previousOrder, ulong? previousOrder,
in MontgomeryDivisorData divisorData, 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. // 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) if (prime <= 3UL)
@@ -40,7 +40,7 @@ internal static partial class PrimeOrderCalculator
PrimeOrderCalculatorAccelerator gpu, PrimeOrderCalculatorAccelerator gpu,
in UInt128 prime, in UInt128 prime,
in UInt128? previousOrder, in UInt128? previousOrder,
in PrimeOrderSearchConfig config) in PrimeOrderCalculatorConfig config)
{ {
MontgomeryDivisorData divisorData; MontgomeryDivisorData divisorData;
UInt128 result; 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) if (value <= UInt128.One)
{ {
+7 -13
View File
@@ -4,39 +4,33 @@ namespace PerfectNumbers.Core;
internal static partial class PrimeOrderCalculator internal static partial class PrimeOrderCalculator
{ {
internal enum PrimeOrderMode internal readonly struct PrimeOrderCalculatorConfig(uint smallFactorLimit, int pollardRhoMilliseconds, int maxPowChecks, bool strictMode)
{ {
Heuristic, private static PrimeOrderCalculatorConfig _heuristicDefault = CreateHeuristicDefault(UnboundedTaskScheduler.ConfiguredThreadCount);
Strict,
}
internal readonly struct PrimeOrderSearchConfig(uint smallFactorLimit, int pollardRhoMilliseconds, int maxPowChecks, PrimeOrderMode mode) public static PrimeOrderCalculatorConfig HeuristicDefault
{
private static PrimeOrderSearchConfig _heuristicDefault = CreateHeuristicDefault(UnboundedTaskScheduler.ConfiguredThreadCount);
public static PrimeOrderSearchConfig HeuristicDefault
{ {
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _heuristicDefault; 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) public static void ConfigureHeuristicDefault(int threadCount)
{ {
_heuristicDefault = CreateHeuristicDefault(threadCount); _heuristicDefault = CreateHeuristicDefault(threadCount);
} }
public static PrimeOrderSearchConfig CreateHeuristicDefault(int threadCount) public static PrimeOrderCalculatorConfig CreateHeuristicDefault(int threadCount)
{ {
int normalizedThreadCount = threadCount < 1 ? 1 : 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 uint SmallFactorLimit = smallFactorLimit;
public readonly int PollardRhoMilliseconds = pollardRhoMilliseconds; public readonly int PollardRhoMilliseconds = pollardRhoMilliseconds;
public readonly int MaxPowChecks = maxPowChecks; public readonly int MaxPowChecks = maxPowChecks;
public readonly PrimeOrderMode Mode = mode; public readonly bool StrictMode = strictMode;
} }
// TODO: Remove branching on the CPU / GPU paths // TODO: Remove branching on the CPU / GPU paths
@@ -19,7 +19,7 @@ public sealed class UnboundedTaskScheduler : TaskScheduler
public static void ConfigureThreadCount(int threadCount) public static void ConfigureThreadCount(int threadCount)
{ {
_configuredThreadCount = threadCount; _configuredThreadCount = threadCount;
PrimeOrderCalculator.PrimeOrderSearchConfig.ConfigureHeuristicDefault(threadCount); PrimeOrderCalculator.PrimeOrderCalculatorConfig.ConfigureHeuristicDefault(threadCount);
// On EvenPerfectBitScanner's execution path the scheduler instance is created after configuration, // 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. // so updating an existing pool would never run. Leave the update path disabled for now.