Merge pull request #141 from mlemanczyk/codex/optimize-evenperfectbitscanner-cpu-path
Remove IDisposable from prime order scopes
This commit is contained in:
7 files changed
+201
-222
No files matched your search
@@ -279,17 +279,17 @@ public class Pow2MontgomeryModCycleComputationBenchmarks
|
||||
#if DEBUG
|
||||
Console.WriteLine("Trying heuristic. Prime order calculation");
|
||||
#endif
|
||||
PrimeOrderCalculator.PrimeOrderResult orderResult = PrimeOrderCalculator.Calculate(
|
||||
modulus,
|
||||
_previousPrimeOrder,
|
||||
divisorData,
|
||||
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault,
|
||||
PrimeOrderCalculator.PrimeOrderHeuristicDevice.Gpu);
|
||||
ulong order = PrimeOrderCalculator.Calculate(
|
||||
modulus,
|
||||
_previousPrimeOrder,
|
||||
divisorData,
|
||||
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault,
|
||||
PrimeOrderCalculator.PrimeOrderHeuristicDevice.Gpu);
|
||||
|
||||
if (orderResult.Order != 0UL)
|
||||
if (order != 0UL)
|
||||
{
|
||||
_previousPrimeOrder = orderResult.Order;
|
||||
return orderResult.Order;
|
||||
_previousPrimeOrder = order;
|
||||
return order;
|
||||
}
|
||||
|
||||
_previousPrimeOrder = null;
|
||||
@@ -308,15 +308,15 @@ public class Pow2MontgomeryModCycleComputationBenchmarks
|
||||
#if DEBUG
|
||||
Console.WriteLine("Trying heuristic. Wide prime order calculation");
|
||||
#endif
|
||||
PrimeOrderCalculator.PrimeOrderResultWide orderResult = PrimeOrderCalculator.Calculate(
|
||||
UInt128 order = PrimeOrderCalculator.Calculate(
|
||||
modulus,
|
||||
_previousWidePrimeOrder,
|
||||
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault);
|
||||
|
||||
if (orderResult.Order != UInt128.Zero)
|
||||
if (order != UInt128.Zero)
|
||||
{
|
||||
_previousWidePrimeOrder = orderResult.Order;
|
||||
return orderResult.Order;
|
||||
_previousWidePrimeOrder = order;
|
||||
return order;
|
||||
}
|
||||
|
||||
_previousWidePrimeOrder = null;
|
||||
|
||||
@@ -359,10 +359,9 @@ public class PrimeOrderGpuHeuristicsTests
|
||||
PrimeOrderGpuHeuristics.OverflowRegistry[prime] = 0;
|
||||
|
||||
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(prime);
|
||||
PrimeOrderCalculator.PrimeOrderResult result = PrimeOrderCalculator.Calculate(prime, null, divisorData, PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault, PrimeOrderCalculator.PrimeOrderHeuristicDevice.Gpu);
|
||||
ulong result = PrimeOrderCalculator.Calculate(prime, null, divisorData, PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault, PrimeOrderCalculator.PrimeOrderHeuristicDevice.Gpu);
|
||||
|
||||
result.Status.Should().Be(PrimeOrderCalculator.PrimeOrderStatus.Found);
|
||||
result.Order.Should().Be(3UL);
|
||||
result.Should().Be(3UL);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
||||
@@ -45,15 +45,14 @@ public class PrimeOrderCalculatorTests
|
||||
{
|
||||
ulong expected = ComputeOrderByDoubling(prime);
|
||||
|
||||
PrimeOrderCalculator.PrimeOrderResult result = PrimeOrderCalculator.Calculate(
|
||||
prime,
|
||||
previousOrder: null,
|
||||
MontgomeryDivisorData.FromModulus(prime),
|
||||
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault,
|
||||
PrimeOrderCalculator.PrimeOrderHeuristicDevice.Gpu);
|
||||
ulong result = PrimeOrderCalculator.Calculate(
|
||||
prime,
|
||||
previousOrder: null,
|
||||
MontgomeryDivisorData.FromModulus(prime),
|
||||
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault,
|
||||
PrimeOrderCalculator.PrimeOrderHeuristicDevice.Gpu);
|
||||
|
||||
result.Status.Should().Be(PrimeOrderCalculator.PrimeOrderStatus.Found);
|
||||
result.Order.Should().Be(expected);
|
||||
result.Should().Be(expected);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
@@ -63,23 +62,21 @@ public class PrimeOrderCalculatorTests
|
||||
{
|
||||
ulong previousOrder = ComputeOrderByDoubling(previousPrime);
|
||||
|
||||
PrimeOrderCalculator.PrimeOrderResult heuristic = PrimeOrderCalculator.Calculate(
|
||||
prime,
|
||||
previousOrder,
|
||||
MontgomeryDivisorData.FromModulus(prime),
|
||||
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault,
|
||||
PrimeOrderCalculator.PrimeOrderHeuristicDevice.Gpu);
|
||||
ulong heuristic = PrimeOrderCalculator.Calculate(
|
||||
prime,
|
||||
previousOrder,
|
||||
MontgomeryDivisorData.FromModulus(prime),
|
||||
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault,
|
||||
PrimeOrderCalculator.PrimeOrderHeuristicDevice.Gpu);
|
||||
|
||||
PrimeOrderCalculator.PrimeOrderResult strict = PrimeOrderCalculator.Calculate(
|
||||
prime,
|
||||
previousOrder: null,
|
||||
MontgomeryDivisorData.FromModulus(prime),
|
||||
PrimeOrderCalculator.PrimeOrderSearchConfig.StrictDefault,
|
||||
PrimeOrderCalculator.PrimeOrderHeuristicDevice.Gpu);
|
||||
ulong strict = PrimeOrderCalculator.Calculate(
|
||||
prime,
|
||||
previousOrder: null,
|
||||
MontgomeryDivisorData.FromModulus(prime),
|
||||
PrimeOrderCalculator.PrimeOrderSearchConfig.StrictDefault,
|
||||
PrimeOrderCalculator.PrimeOrderHeuristicDevice.Gpu);
|
||||
|
||||
heuristic.Status.Should().Be(PrimeOrderCalculator.PrimeOrderStatus.Found);
|
||||
strict.Status.Should().Be(PrimeOrderCalculator.PrimeOrderStatus.Found);
|
||||
heuristic.Order.Should().Be(strict.Order);
|
||||
heuristic.Should().Be(strict);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
@@ -88,15 +85,14 @@ public class PrimeOrderCalculatorTests
|
||||
[InlineData(3UL, 2UL)]
|
||||
public void Calculate_handles_trivial_primes(ulong prime, ulong expectedOrder)
|
||||
{
|
||||
PrimeOrderCalculator.PrimeOrderResult result = PrimeOrderCalculator.Calculate(
|
||||
prime,
|
||||
previousOrder: null,
|
||||
MontgomeryDivisorData.FromModulus(prime),
|
||||
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault,
|
||||
PrimeOrderCalculator.PrimeOrderHeuristicDevice.Gpu);
|
||||
ulong result = PrimeOrderCalculator.Calculate(
|
||||
prime,
|
||||
previousOrder: null,
|
||||
MontgomeryDivisorData.FromModulus(prime),
|
||||
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault,
|
||||
PrimeOrderCalculator.PrimeOrderHeuristicDevice.Gpu);
|
||||
|
||||
result.Status.Should().Be(PrimeOrderCalculator.PrimeOrderStatus.Found);
|
||||
result.Order.Should().Be(expectedOrder);
|
||||
result.Should().Be(expectedOrder);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -109,15 +105,14 @@ public class PrimeOrderCalculatorTests
|
||||
maxPowChecks: 8,
|
||||
mode: PrimeOrderCalculator.PrimeOrderMode.Heuristic);
|
||||
|
||||
PrimeOrderCalculator.PrimeOrderResult result = PrimeOrderCalculator.Calculate(
|
||||
prime: 13UL,
|
||||
previousOrder: null,
|
||||
MontgomeryDivisorData.FromModulus(13UL),
|
||||
config,
|
||||
PrimeOrderCalculator.PrimeOrderHeuristicDevice.Gpu);
|
||||
ulong result = PrimeOrderCalculator.Calculate(
|
||||
prime: 13UL,
|
||||
previousOrder: null,
|
||||
MontgomeryDivisorData.FromModulus(13UL),
|
||||
config,
|
||||
PrimeOrderCalculator.PrimeOrderHeuristicDevice.Gpu);
|
||||
|
||||
result.Status.Should().Be(PrimeOrderCalculator.PrimeOrderStatus.HeuristicUnresolved);
|
||||
result.Order.Should().Be(ComputeOrderByDoubling(13UL));
|
||||
result.Should().Be(ComputeOrderByDoubling(13UL));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -131,15 +126,14 @@ public class PrimeOrderCalculatorTests
|
||||
mode: PrimeOrderCalculator.PrimeOrderMode.Heuristic);
|
||||
|
||||
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(239UL);
|
||||
PrimeOrderCalculator.PrimeOrderResult heuristic = PrimeOrderCalculator.Calculate(
|
||||
prime: 239UL,
|
||||
previousOrder: null,
|
||||
divisorData,
|
||||
heuristicConfig,
|
||||
PrimeOrderCalculator.PrimeOrderHeuristicDevice.Gpu);
|
||||
ulong heuristic = PrimeOrderCalculator.Calculate(
|
||||
prime: 239UL,
|
||||
previousOrder: null,
|
||||
divisorData,
|
||||
heuristicConfig,
|
||||
PrimeOrderCalculator.PrimeOrderHeuristicDevice.Gpu);
|
||||
|
||||
heuristic.Status.Should().Be(PrimeOrderCalculator.PrimeOrderStatus.HeuristicUnresolved);
|
||||
heuristic.Order.Should().Be(ComputeOrderByDoubling(239UL));
|
||||
heuristic.Should().Be(ComputeOrderByDoubling(239UL));
|
||||
|
||||
var strictConfig = new PrimeOrderCalculator.PrimeOrderSearchConfig(
|
||||
smallFactorLimit: 2,
|
||||
@@ -147,15 +141,14 @@ public class PrimeOrderCalculatorTests
|
||||
maxPowChecks: 1,
|
||||
mode: PrimeOrderCalculator.PrimeOrderMode.Strict);
|
||||
|
||||
PrimeOrderCalculator.PrimeOrderResult strict = PrimeOrderCalculator.Calculate(
|
||||
prime: 239UL,
|
||||
previousOrder: null,
|
||||
divisorData,
|
||||
strictConfig,
|
||||
PrimeOrderCalculator.PrimeOrderHeuristicDevice.Gpu);
|
||||
ulong strict = PrimeOrderCalculator.Calculate(
|
||||
prime: 239UL,
|
||||
previousOrder: null,
|
||||
divisorData,
|
||||
strictConfig,
|
||||
PrimeOrderCalculator.PrimeOrderHeuristicDevice.Gpu);
|
||||
|
||||
strict.Status.Should().Be(PrimeOrderCalculator.PrimeOrderStatus.Found);
|
||||
strict.Order.Should().Be(heuristic.Order);
|
||||
strict.Should().Be(heuristic);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -164,13 +157,12 @@ public class PrimeOrderCalculatorTests
|
||||
{
|
||||
UInt128 prime = UInt128.Parse("18446744073709641691");
|
||||
|
||||
PrimeOrderCalculator.PrimeOrderResultWide result = PrimeOrderCalculator.Calculate(
|
||||
UInt128 result = PrimeOrderCalculator.Calculate(
|
||||
prime,
|
||||
previousOrder: null,
|
||||
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault);
|
||||
|
||||
result.Status.Should().Be(PrimeOrderCalculator.PrimeOrderStatus.Found);
|
||||
result.Order.Should().Be((UInt128)1229782938247309446UL);
|
||||
result.Should().Be((UInt128)1229782938247309446UL);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
||||
@@ -415,9 +415,9 @@ internal static partial class PrimeOrderGpuHeuristics
|
||||
ulong? previousOrder,
|
||||
PrimeOrderCalculator.PrimeOrderSearchConfig config,
|
||||
in MontgomeryDivisorData divisorData,
|
||||
out PrimeOrderCalculator.PrimeOrderResult result)
|
||||
out ulong order)
|
||||
{
|
||||
result = default;
|
||||
order = 0UL;
|
||||
|
||||
var lease = GpuKernelPool.GetKernel(useGpuOrder: true);
|
||||
var execution = lease.EnterExecutionScope();
|
||||
@@ -497,18 +497,17 @@ internal static partial class PrimeOrderGpuHeuristics
|
||||
throw new InvalidOperationException("GPU Pollard Rho stack overflow; increase HeuristicStackCapacity.");
|
||||
}
|
||||
|
||||
ulong order = 0UL;
|
||||
resultBuffer.View.CopyToCPU(ref order, 1);
|
||||
|
||||
PrimeOrderCalculator.PrimeOrderStatus finalStatus = kernelStatus == PrimeOrderKernelStatus.Found
|
||||
? PrimeOrderCalculator.PrimeOrderStatus.Found
|
||||
: PrimeOrderCalculator.PrimeOrderStatus.HeuristicUnresolved;
|
||||
if (kernelStatus == PrimeOrderKernelStatus.FactoringFailure)
|
||||
{
|
||||
order = 0UL;
|
||||
}
|
||||
|
||||
result = new PrimeOrderCalculator.PrimeOrderResult(finalStatus, order);
|
||||
DisposeResources();
|
||||
lease.Dispose();
|
||||
|
||||
return true;
|
||||
return order != 0UL;
|
||||
|
||||
void DisposeResources()
|
||||
{
|
||||
|
||||
@@ -234,14 +234,14 @@ public class MersenneDivisorCycles
|
||||
return (UInt128)cycle;
|
||||
}
|
||||
|
||||
PrimeOrderCalculator.PrimeOrderResultWide wideResult = PrimeOrderCalculator.Calculate(
|
||||
UInt128 wideOrder = PrimeOrderCalculator.Calculate(
|
||||
divisor,
|
||||
previousOrder: null,
|
||||
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault,
|
||||
PrimeOrderCalculator.PrimeOrderHeuristicDevice.Cpu);
|
||||
if (wideResult.Order != UInt128.Zero)
|
||||
if (wideOrder != UInt128.Zero)
|
||||
{
|
||||
return wideResult.Order;
|
||||
return wideOrder;
|
||||
}
|
||||
|
||||
// Otherwise, find order of 2 mod divisor
|
||||
@@ -285,15 +285,15 @@ public class MersenneDivisorCycles
|
||||
return true;
|
||||
}
|
||||
|
||||
PrimeOrderCalculator.PrimeOrderResult orderResult = PrimeOrderCalculator.Calculate(
|
||||
ulong order = PrimeOrderCalculator.Calculate(
|
||||
divisor,
|
||||
previousOrder: null,
|
||||
divisorData,
|
||||
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault,
|
||||
PrimeOrderCalculator.PrimeOrderHeuristicDevice.Cpu);
|
||||
if (orderResult.Order != 0UL)
|
||||
if (order != 0UL)
|
||||
{
|
||||
cycleLength = orderResult.Order;
|
||||
cycleLength = order;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -940,15 +940,15 @@ public class MersenneDivisorCycles
|
||||
|
||||
if (PrimeTester.IsPrimeInternal(divisor, CancellationToken.None))
|
||||
{
|
||||
PrimeOrderCalculator.PrimeOrderResult orderResult = PrimeOrderCalculator.Calculate(
|
||||
ulong order = PrimeOrderCalculator.Calculate(
|
||||
divisor,
|
||||
previousOrder: null,
|
||||
divisorData,
|
||||
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault,
|
||||
PrimeOrderCalculator.PrimeOrderHeuristicDevice.Cpu);
|
||||
if (orderResult.Order != 0UL)
|
||||
if (order != 0UL)
|
||||
{
|
||||
cycleLength = orderResult.Order;
|
||||
cycleLength = order;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,23 +9,10 @@ namespace PerfectNumbers.Core;
|
||||
|
||||
internal static partial class PrimeOrderCalculator
|
||||
{
|
||||
internal readonly struct PrimeOrderResultWide
|
||||
{
|
||||
public PrimeOrderResultWide(PrimeOrderStatus status, UInt128 order)
|
||||
{
|
||||
Status = status;
|
||||
Order = order;
|
||||
}
|
||||
|
||||
public PrimeOrderStatus Status { get; }
|
||||
|
||||
public UInt128 Order { get; }
|
||||
}
|
||||
|
||||
public static PrimeOrderResultWide Calculate(UInt128 prime, UInt128? previousOrder, PrimeOrderSearchConfig config)
|
||||
public static UInt128 Calculate(UInt128 prime, UInt128? previousOrder, PrimeOrderSearchConfig config)
|
||||
=> Calculate(prime, previousOrder, config, PrimeOrderHeuristicDevice.Gpu);
|
||||
|
||||
public static PrimeOrderResultWide Calculate(
|
||||
public static UInt128 Calculate(
|
||||
UInt128 prime,
|
||||
UInt128? previousOrder,
|
||||
PrimeOrderSearchConfig config,
|
||||
@@ -33,6 +20,7 @@ internal static partial class PrimeOrderCalculator
|
||||
{
|
||||
var scope = UsePow2Mode(device);
|
||||
MontgomeryDivisorData divisorData;
|
||||
UInt128 result;
|
||||
if (prime <= ulong.MaxValue)
|
||||
{
|
||||
ulong? previous = null;
|
||||
@@ -51,50 +39,49 @@ internal static partial class PrimeOrderCalculator
|
||||
|
||||
ulong prime64 = (ulong)prime;
|
||||
divisorData = MontgomeryDivisorData.FromModulus(prime64);
|
||||
PrimeOrderResult result = Calculate(prime64, previous, divisorData, config, device);
|
||||
scope.Dispose();
|
||||
return new PrimeOrderResultWide(result.Status, result.Order);
|
||||
ulong order64 = Calculate(prime64, previous, divisorData, config, device);
|
||||
result = order64 == 0UL ? UInt128.Zero : (UInt128)order64;
|
||||
}
|
||||
else
|
||||
{
|
||||
divisorData = default;
|
||||
result = CalculateWideInternal(prime, previousOrder, divisorData, config);
|
||||
}
|
||||
|
||||
PrimeOrderResultWide resultWide = CalculateWideInternal(prime, previousOrder, divisorData, config);
|
||||
scope.Dispose();
|
||||
return resultWide;
|
||||
scope.Dispose();
|
||||
return result;
|
||||
}
|
||||
|
||||
private static PrimeOrderResultWide CalculateWideInternal(UInt128 prime, UInt128? previousOrder, in MontgomeryDivisorData divisorData, PrimeOrderSearchConfig config)
|
||||
private static UInt128 CalculateWideInternal(UInt128 prime, UInt128? previousOrder, in MontgomeryDivisorData divisorData, PrimeOrderSearchConfig config)
|
||||
{
|
||||
if (prime <= UInt128.One)
|
||||
{
|
||||
return new PrimeOrderResultWide(PrimeOrderStatus.Found, UInt128.One);
|
||||
return UInt128.One;
|
||||
}
|
||||
|
||||
if (prime == (UInt128)3UL)
|
||||
{
|
||||
return new PrimeOrderResultWide(PrimeOrderStatus.Found, (UInt128)2UL);
|
||||
return (UInt128)2UL;
|
||||
}
|
||||
|
||||
UInt128 phi = prime - UInt128.One;
|
||||
var debugScope = UseDebugLogging(!IsGpuHeuristicDevice);
|
||||
PartialFactorResult128 phiFactors = PartialFactorWide(phi, config);
|
||||
PrimeOrderResultWide result;
|
||||
PartialFactorResult128 phiFactors = PartialFactorWide(phi, config);
|
||||
UInt128 result;
|
||||
if (phiFactors.Factors is null)
|
||||
{
|
||||
// HeuristicFailureLog.Record(prime, null, HeuristicFailureReason.PhiPartialFactorizationFailed);
|
||||
result = FinishStrictlyWide(prime, divisorData, config.Mode);
|
||||
debugScope.Dispose();
|
||||
return result;
|
||||
result = FinishStrictlyWide(prime, divisorData);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = RunHeuristicPipelineWide(prime, previousOrder, divisorData, config, phi, phiFactors);
|
||||
}
|
||||
|
||||
result = RunHeuristicPipelineWide(prime, previousOrder, divisorData, config, phi, phiFactors);
|
||||
debugScope.Dispose();
|
||||
return result;
|
||||
debugScope.Dispose();
|
||||
return result;
|
||||
}
|
||||
|
||||
private static PrimeOrderResultWide RunHeuristicPipelineWide(
|
||||
private static UInt128 RunHeuristicPipelineWide(
|
||||
UInt128 prime,
|
||||
UInt128? previousOrder,
|
||||
in MontgomeryDivisorData divisorData,
|
||||
@@ -104,7 +91,7 @@ internal static partial class PrimeOrderCalculator
|
||||
{
|
||||
if (phiFactors.FullyFactored && TrySpecialMaxWide(phi, prime, divisorData, phiFactors))
|
||||
{
|
||||
return new PrimeOrderResultWide(PrimeOrderStatus.Found, phi);
|
||||
return phi;
|
||||
}
|
||||
|
||||
UInt128 candidateOrder = InitializeStartingOrderWide(prime, phi, divisorData);
|
||||
@@ -112,30 +99,25 @@ internal static partial class PrimeOrderCalculator
|
||||
|
||||
if (TryConfirmOrderWide(prime, candidateOrder, divisorData, config))
|
||||
{
|
||||
return new PrimeOrderResultWide(PrimeOrderStatus.Found, candidateOrder);
|
||||
return candidateOrder;
|
||||
}
|
||||
|
||||
if (config.Mode == PrimeOrderMode.Strict)
|
||||
{
|
||||
// HeuristicFailureLog.Record(prime, candidateOrder, HeuristicFailureReason.StrictModeRequested);
|
||||
return FinishStrictlyWide(prime, divisorData, PrimeOrderMode.Strict);
|
||||
return FinishStrictlyWide(prime, divisorData);
|
||||
}
|
||||
|
||||
if (TryHeuristicFinishWide(prime, candidateOrder, previousOrder, divisorData, config, out UInt128 order))
|
||||
{
|
||||
return new PrimeOrderResultWide(PrimeOrderStatus.Found, order);
|
||||
return order;
|
||||
}
|
||||
|
||||
// HeuristicFailureLog.Record(prime, candidateOrder, HeuristicFailureReason.HeuristicPipelineAssumedFullOrder);
|
||||
// The heuristic pipeline could not narrow the order any further; assume the current order is final.
|
||||
return new PrimeOrderResultWide(PrimeOrderStatus.Found, candidateOrder);
|
||||
return candidateOrder;
|
||||
}
|
||||
|
||||
private static PrimeOrderResultWide FinishStrictlyWide(UInt128 prime, in MontgomeryDivisorData divisorData, PrimeOrderMode mode)
|
||||
private static UInt128 FinishStrictlyWide(UInt128 prime, in MontgomeryDivisorData divisorData)
|
||||
{
|
||||
UInt128 strictOrder = CalculateByFactorizationWide(prime, divisorData);
|
||||
PrimeOrderStatus status = mode == PrimeOrderMode.Strict ? PrimeOrderStatus.Found : PrimeOrderStatus.HeuristicUnresolved;
|
||||
return new PrimeOrderResultWide(status, strictOrder);
|
||||
return CalculateByFactorizationWide(prime, divisorData);
|
||||
}
|
||||
|
||||
private static bool TrySpecialMaxWide(UInt128 phi, UInt128 prime, in MontgomeryDivisorData divisorData, PartialFactorResult128 factors)
|
||||
|
||||
@@ -18,24 +18,7 @@ namespace PerfectNumbers.Core;
|
||||
|
||||
internal static partial class PrimeOrderCalculator
|
||||
{
|
||||
internal enum PrimeOrderStatus
|
||||
{
|
||||
Found,
|
||||
HeuristicUnresolved,
|
||||
}
|
||||
|
||||
internal readonly struct PrimeOrderResult
|
||||
{
|
||||
public PrimeOrderResult(PrimeOrderStatus status, ulong order)
|
||||
{
|
||||
Status = status;
|
||||
Order = order;
|
||||
}
|
||||
|
||||
public PrimeOrderStatus Status { get; }
|
||||
|
||||
public ulong Order { get; }
|
||||
}
|
||||
|
||||
internal enum PrimeOrderMode
|
||||
{
|
||||
@@ -167,7 +150,14 @@ internal static partial class PrimeOrderCalculator
|
||||
}
|
||||
}
|
||||
|
||||
public static PrimeOrderResult Calculate(
|
||||
public static ulong Calculate(
|
||||
ulong prime,
|
||||
ulong? previousOrder,
|
||||
in MontgomeryDivisorData divisorData,
|
||||
in PrimeOrderSearchConfig config)
|
||||
=> Calculate(prime, previousOrder, divisorData, config, PrimeOrderHeuristicDevice.Cpu);
|
||||
|
||||
public static ulong Calculate(
|
||||
ulong prime,
|
||||
ulong? previousOrder,
|
||||
in MontgomeryDivisorData divisorData,
|
||||
@@ -175,41 +165,36 @@ internal static partial class PrimeOrderCalculator
|
||||
PrimeOrderHeuristicDevice device)
|
||||
{
|
||||
var scope = UsePow2Mode(device);
|
||||
PrimeOrderResult result = CalculateInternal(prime, previousOrder, divisorData, config);
|
||||
scope.Dispose();
|
||||
return result;
|
||||
ulong order = CalculateInternal(prime, previousOrder, divisorData, config);
|
||||
scope.Dispose();
|
||||
return order;
|
||||
}
|
||||
|
||||
private static PrimeOrderResult CalculateInternal(ulong prime, ulong? previousOrder, in MontgomeryDivisorData divisorData, in PrimeOrderSearchConfig config)
|
||||
private static ulong CalculateInternal(ulong prime, ulong? previousOrder, in MontgomeryDivisorData divisorData, in PrimeOrderSearchConfig config)
|
||||
{
|
||||
if (prime <= 3UL)
|
||||
{
|
||||
return new PrimeOrderResult(PrimeOrderStatus.Found, prime == 3UL ? 2UL : 1UL);
|
||||
return prime == 3UL ? 2UL : 1UL;
|
||||
}
|
||||
|
||||
ulong phi = prime - 1UL;
|
||||
|
||||
if (IsGpuHeuristicDevice && PrimeOrderGpuHeuristics.TryCalculateOrder(prime, previousOrder, config, divisorData, out PrimeOrderResult gpuResult))
|
||||
if (IsGpuHeuristicDevice && PrimeOrderGpuHeuristics.TryCalculateOrder(prime, previousOrder, config, divisorData, out ulong gpuOrder))
|
||||
{
|
||||
return gpuResult;
|
||||
return gpuOrder;
|
||||
}
|
||||
|
||||
// using var debugScope = UseDebugLogging(!IsGpuHeuristicDevice);
|
||||
// DebugLog("Partial factoring φ(p)");
|
||||
|
||||
using PartialFactorResult phiFactors = PartialFactor(phi, config);
|
||||
|
||||
if (phiFactors.Factors is null)
|
||||
{
|
||||
// DebugLog("No factors found");
|
||||
// HeuristicFailureLog.Record(prime, null, HeuristicFailureReason.PhiPartialFactorizationFailed);
|
||||
return FinishStrictly(prime, divisorData, config.Mode);
|
||||
return FinishStrictly(prime, divisorData);
|
||||
}
|
||||
|
||||
return RunHeuristicPipeline(prime, previousOrder, config, divisorData, phi, phiFactors);
|
||||
}
|
||||
|
||||
private static PrimeOrderResult RunHeuristicPipeline(
|
||||
private static ulong RunHeuristicPipeline(
|
||||
ulong prime,
|
||||
ulong? previousOrder,
|
||||
in PrimeOrderSearchConfig config,
|
||||
@@ -217,44 +202,35 @@ internal static partial class PrimeOrderCalculator
|
||||
ulong phi,
|
||||
PartialFactorResult phiFactors)
|
||||
{
|
||||
// DebugLog("Trying special max check");
|
||||
if (phiFactors.FullyFactored && TrySpecialMax(phi, prime, phiFactors, divisorData))
|
||||
{
|
||||
return new PrimeOrderResult(PrimeOrderStatus.Found, phi);
|
||||
return phi;
|
||||
}
|
||||
|
||||
// DebugLog("Initializing starting order");
|
||||
ulong candidateOrder = InitializeStartingOrder(prime, phi, divisorData);
|
||||
candidateOrder = ExponentLowering(candidateOrder, prime, phiFactors, divisorData);
|
||||
|
||||
// DebugLog("Trying to confirm order");
|
||||
if (TryConfirmOrder(prime, candidateOrder, divisorData, config))
|
||||
{
|
||||
return new PrimeOrderResult(PrimeOrderStatus.Found, candidateOrder);
|
||||
return candidateOrder;
|
||||
}
|
||||
|
||||
if (config.Mode == PrimeOrderMode.Strict)
|
||||
{
|
||||
// HeuristicFailureLog.Record(prime, candidateOrder, HeuristicFailureReason.StrictModeRequested);
|
||||
return FinishStrictly(prime, divisorData, PrimeOrderMode.Strict);
|
||||
return FinishStrictly(prime, divisorData);
|
||||
}
|
||||
|
||||
if (TryHeuristicFinish(prime, candidateOrder, previousOrder, divisorData, config, phiFactors, out ulong order))
|
||||
{
|
||||
return new PrimeOrderResult(PrimeOrderStatus.Found, order);
|
||||
return order;
|
||||
}
|
||||
|
||||
// DebugLog("Heuristic unresolved, assuming current order");
|
||||
// HeuristicFailureLog.Record(prime, candidateOrder, HeuristicFailureReason.HeuristicPipelineAssumedFullOrder);
|
||||
// The heuristic pipeline could not rule out additional divisors; assume the current order is final.
|
||||
return new PrimeOrderResult(PrimeOrderStatus.Found, candidateOrder);
|
||||
return candidateOrder;
|
||||
}
|
||||
|
||||
private static PrimeOrderResult FinishStrictly(ulong prime, in MontgomeryDivisorData divisorData, PrimeOrderMode mode)
|
||||
private static ulong FinishStrictly(ulong prime, in MontgomeryDivisorData divisorData)
|
||||
{
|
||||
ulong strictOrder = CalculateByFactorization(prime, divisorData);
|
||||
PrimeOrderStatus status = mode == PrimeOrderMode.Strict ? PrimeOrderStatus.Found : PrimeOrderStatus.HeuristicUnresolved;
|
||||
return new PrimeOrderResult(status, strictOrder);
|
||||
return CalculateByFactorization(prime, divisorData);
|
||||
}
|
||||
|
||||
private static bool TrySpecialMax(ulong phi, ulong prime, PartialFactorResult factors, in MontgomeryDivisorData divisorData)
|
||||
@@ -993,7 +969,7 @@ internal static partial class PrimeOrderCalculator
|
||||
{
|
||||
if (value <= 1UL)
|
||||
{
|
||||
return PartialFactorResult.Empty;
|
||||
return PartialFactorResult.RentEmpty();
|
||||
}
|
||||
|
||||
const int FactorSlotCount = GpuSmallPrimeFactorSlots;
|
||||
@@ -1098,12 +1074,12 @@ internal static partial class PrimeOrderCalculator
|
||||
{
|
||||
if ((counts is null || counts.Count == 0) && cofactor == value)
|
||||
{
|
||||
return new PartialFactorResult(null, value, false, 0);
|
||||
return PartialFactorResult.Rent(null, value, false, 0);
|
||||
}
|
||||
|
||||
if (counts is null || counts.Count == 0)
|
||||
{
|
||||
return new PartialFactorResult(null, cofactor, cofactor == 1UL, 0);
|
||||
return PartialFactorResult.Rent(null, cofactor, cofactor == 1UL, 0);
|
||||
}
|
||||
|
||||
FactorEntry[] factors = ArrayPool<FactorEntry>.Shared.Rent(counts.Count);
|
||||
@@ -1118,7 +1094,7 @@ internal static partial class PrimeOrderCalculator
|
||||
span.Sort(static (a, b) => a.Value.CompareTo(b.Value));
|
||||
|
||||
bool fullyFactored = cofactor == 1UL;
|
||||
return new PartialFactorResult(factors, cofactor, fullyFactored, index, pooled: true);
|
||||
return PartialFactorResult.Rent(factors, cofactor, fullyFactored, index);
|
||||
}
|
||||
|
||||
int actualCount = 0;
|
||||
@@ -1134,10 +1110,10 @@ internal static partial class PrimeOrderCalculator
|
||||
{
|
||||
if (cofactor == value)
|
||||
{
|
||||
return new PartialFactorResult(null, value, false, 0);
|
||||
return PartialFactorResult.Rent(null, value, false, 0);
|
||||
}
|
||||
|
||||
return new PartialFactorResult(null, cofactor, cofactor == 1UL, 0);
|
||||
return PartialFactorResult.Rent(null, cofactor, cofactor == 1UL, 0);
|
||||
}
|
||||
|
||||
FactorEntry[] array = ArrayPool<FactorEntry>.Shared.Rent(actualCount);
|
||||
@@ -1158,7 +1134,7 @@ internal static partial class PrimeOrderCalculator
|
||||
Span<FactorEntry> arraySpan = array.AsSpan(0, arrayIndex);
|
||||
arraySpan.Sort(static (a, b) => a.Value.CompareTo(b.Value));
|
||||
bool fullyFactoredArray = cofactor == 1UL;
|
||||
return new PartialFactorResult(array, cofactor, fullyFactoredArray, arrayIndex, pooled: true);
|
||||
return PartialFactorResult.Rent(array, cofactor, fullyFactoredArray, arrayIndex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -1588,58 +1564,89 @@ internal static partial class PrimeOrderCalculator
|
||||
public readonly int Exponent = exponent;
|
||||
}
|
||||
|
||||
private struct PartialFactorResult : IDisposable
|
||||
private sealed class PartialFactorResult : IDisposable
|
||||
{
|
||||
private FactorEntry[]? _factors;
|
||||
private readonly bool _pooled;
|
||||
[ThreadStatic]
|
||||
private static PartialFactorResult? s_poolHead;
|
||||
|
||||
public PartialFactorResult(FactorEntry[]? factors, ulong cofactor, bool fullyFactored, int count, bool pooled = false)
|
||||
private PartialFactorResult? _next;
|
||||
private bool _returned;
|
||||
|
||||
public FactorEntry[]? Factors;
|
||||
public ulong Cofactor;
|
||||
public bool FullyFactored;
|
||||
public int Count;
|
||||
|
||||
private PartialFactorResult()
|
||||
{
|
||||
_factors = factors;
|
||||
Cofactor = cofactor;
|
||||
FullyFactored = fullyFactored;
|
||||
Count = count;
|
||||
_pooled = pooled && factors is not null;
|
||||
}
|
||||
|
||||
public FactorEntry[]? Factors => _factors;
|
||||
|
||||
public ulong Cofactor { get; }
|
||||
|
||||
public bool FullyFactored { get; }
|
||||
|
||||
public int Count { get; }
|
||||
|
||||
public static PartialFactorResult Empty => new(null, 1UL, true, 0);
|
||||
|
||||
public void Dispose()
|
||||
public static PartialFactorResult Rent(FactorEntry[]? factors, ulong cofactor, bool fullyFactored, int count)
|
||||
{
|
||||
FactorEntry[]? factors = _factors;
|
||||
if (factors is null || !_pooled)
|
||||
PartialFactorResult? instance = s_poolHead;
|
||||
if (instance is null)
|
||||
{
|
||||
return;
|
||||
instance = new PartialFactorResult();
|
||||
}
|
||||
else
|
||||
{
|
||||
s_poolHead = instance._next;
|
||||
}
|
||||
|
||||
_factors = null;
|
||||
ArrayPool<FactorEntry>.Shared.Return(factors, clearArray: false);
|
||||
instance._next = null;
|
||||
instance._returned = false;
|
||||
instance.Factors = factors;
|
||||
instance.Cofactor = cofactor;
|
||||
instance.FullyFactored = fullyFactored;
|
||||
instance.Count = count;
|
||||
return instance;
|
||||
}
|
||||
|
||||
public static PartialFactorResult RentEmpty()
|
||||
{
|
||||
return Rent(null, 1UL, true, 0);
|
||||
}
|
||||
|
||||
public PartialFactorResult WithAdditionalPrime(ulong prime)
|
||||
{
|
||||
if (_factors is null || Count == 0)
|
||||
FactorEntry[]? source = Factors;
|
||||
if (source is null || Count == 0)
|
||||
{
|
||||
FactorEntry[] local = ArrayPool<FactorEntry>.Shared.Rent(1);
|
||||
local[0] = new FactorEntry(prime, 1);
|
||||
return new PartialFactorResult(local, 1UL, true, 1, pooled: true);
|
||||
return Rent(local, 1UL, true, 1);
|
||||
}
|
||||
|
||||
FactorEntry[] extended = ArrayPool<FactorEntry>.Shared.Rent(Count + 1);
|
||||
Array.Copy(_factors, 0, extended, 0, Count);
|
||||
Array.Copy(source, 0, extended, 0, Count);
|
||||
extended[Count] = new FactorEntry(prime, 1);
|
||||
Span<FactorEntry> span = extended.AsSpan(0, Count + 1);
|
||||
span.Sort(static (a, b) => a.Value.CompareTo(b.Value));
|
||||
return new PartialFactorResult(extended, 1UL, true, Count + 1, pooled: true);
|
||||
return Rent(extended, 1UL, true, Count + 1);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_returned)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_returned = true;
|
||||
|
||||
FactorEntry[]? factors = Factors;
|
||||
if (factors is not null)
|
||||
{
|
||||
Factors = null;
|
||||
ArrayPool<FactorEntry>.Shared.Return(factors, clearArray: false);
|
||||
}
|
||||
|
||||
Cofactor = 0UL;
|
||||
FullyFactored = false;
|
||||
Count = 0;
|
||||
|
||||
_next = s_poolHead;
|
||||
s_poolHead = this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user