MersenneDivisorCycles converted to device template.

This commit is contained in:
mlemanczyk committed 2025-12-19 04:03:27 +01:00
1 parent 31ecf24522
commit 74837a407e
23 files changed
+272 -647

No files matched your search

@@ -235,7 +235,8 @@ public sealed class DeviceDependentGenerator : IIncrementalGenerator
private static TypeDeclarationSyntax TransformTemplateType(TypeDeclarationSyntax templateType, string generatedTypeName)
{
TypeDeclarationSyntax withoutAttribute = RemoveDeviceDependentAttribute(templateType);
return withoutAttribute.WithIdentifier(SyntaxFactory.Identifier(generatedTypeName));
TypeDeclarationSyntax renamed = (TypeDeclarationSyntax)new SelfIdentifierRewriter(templateType.Identifier.ValueText, generatedTypeName).Visit(withoutAttribute)!;
return renamed.WithIdentifier(SyntaxFactory.Identifier(generatedTypeName));
}
private static TypeDeclarationSyntax RemoveDeviceDependentAttribute(TypeDeclarationSyntax typeDeclaration)
@@ -271,6 +272,28 @@ public sealed class DeviceDependentGenerator : IIncrementalGenerator
return typeDeclaration.WithAttributeLists(SyntaxFactory.List(newLists));
}
private sealed class SelfIdentifierRewriter : CSharpSyntaxRewriter
{
private readonly string templateName;
private readonly string generatedName;
public SelfIdentifierRewriter(string templateName, string generatedName)
{
this.templateName = templateName;
this.generatedName = generatedName;
}
public override SyntaxToken VisitToken(SyntaxToken token)
{
if (token.IsKind(SyntaxKind.IdentifierToken) && string.Equals(token.ValueText, templateName, StringComparison.Ordinal))
{
return SyntaxFactory.Identifier(token.LeadingTrivia, generatedName, token.TrailingTrivia);
}
return base.VisitToken(token);
}
}
private static bool IsDeviceDependentTemplateAttribute(NameSyntax attributeName)
{
string text = attributeName.ToString();
@@ -380,6 +403,11 @@ public sealed class DeviceDependentGenerator : IIncrementalGenerator
return generatedFileName;
}
if (relativeDirectory.StartsWith("..", StringComparison.Ordinal))
{
return generatedFileName;
}
relativeDirectory = relativeDirectory.Replace('\\', '/');
return relativeDirectory.TrimEnd('/') + "/" + generatedFileName;
}
@@ -161,7 +161,7 @@ public class Pow2ModBenchmarks
for (int i = 0; i < SampleCount; i++)
{
ulong cycle = MersenneDivisorCycles.CalculateCycleLengthGpu(divisors[i].Modulus);
ulong cycle = MersenneDivisorCyclesGpu.CalculateCycleLength(divisors[i].Modulus);
checksum ^= exponents[i].Pow2MontgomeryModWithCycleConvertToStandardCpu(cycle, divisors[i]);
}
@@ -183,7 +183,7 @@ public class Pow2ModBenchmarks
var gpu = PrimeOrderCalculatorAccelerator.Rent(1);
for (int i = 0; i < SampleCount; i++)
{
ulong cycle = MersenneDivisorCycles.CalculateCycleLengthGpu(divisors[i].Modulus);
ulong cycle = MersenneDivisorCyclesGpu.CalculateCycleLength(divisors[i].Modulus);
checksum ^= exponents[i].Pow2MontgomeryModWithCycleGpu(gpu, cycle, divisors[i]);
}
@@ -500,7 +500,7 @@ public class Pow2ModBenchmarks
Console.WriteLine($"Calculating small cycle {smallModulus}");
smallDivisors[i] = CreateMontgomeryDivisorData(smallModulus);
smallExponents[i] = NextSmallExponent(random);
smallCycles[i] = MersenneDivisorCycles.CalculateCycleLengthCpu(smallModulus, MontgomeryDivisorData.FromModulus(smallModulus));
smallCycles[i] = MersenneDivisorCyclesCpu.CalculateCycleLength(smallModulus, MontgomeryDivisorData.FromModulus(smallModulus));
(ulong largeModulus, ulong largeCycle) = NextLargeModulusAndCycle(random);
Console.WriteLine($"Calculating large cycle {largeModulus}");
@@ -616,7 +616,7 @@ public class Pow2ModBenchmarks
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(modulus);
if (modulus <= 1UL || (modulus & 1UL) == 0UL)
{
return MersenneDivisorCycles.CalculateCycleLengthCpu(modulus, divisorData);
return MersenneDivisorCyclesCpu.CalculateCycleLength(modulus, divisorData);
}
ulong order = PrimeOrderCalculator.CalculateCpu(
@@ -632,14 +632,14 @@ public class Pow2ModBenchmarks
}
previousPrimeOrder = null;
return MersenneDivisorCycles.CalculateCycleLengthCpu(modulus, divisorData);
return MersenneDivisorCyclesCpu.CalculateCycleLength(modulus, divisorData);
}
private static UInt128 CalculateCycleLengthWithHeuristicsCpu(UInt128 modulus, ref UInt128? previousWidePrimeOrder)
{
if (modulus <= UInt128.One || (modulus & UInt128.One) == UInt128.Zero)
{
return MersenneDivisorCycles.GetCycleCpu(modulus);
return MersenneDivisorCyclesCpu.GetCycle(modulus);
}
UInt128 order = PrimeOrderCalculator.CalculateCpu(
@@ -654,7 +654,7 @@ public class Pow2ModBenchmarks
}
previousWidePrimeOrder = null;
return MersenneDivisorCycles.GetCycleCpu(modulus);
return MersenneDivisorCyclesCpu.GetCycle(modulus);
}
}
@@ -683,7 +683,7 @@ public class Pow2ModBenchmarks
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(modulus);
if (modulus <= 1UL || (modulus & 1UL) == 0UL)
{
return fallbackOrder != 0UL ? fallbackOrder : MersenneDivisorCycles.CalculateCycleLengthCpu(modulus, divisorData);
return fallbackOrder != 0UL ? fallbackOrder : MersenneDivisorCyclesCpu.CalculateCycleLength(modulus, divisorData);
}
#if DEBUG
@@ -704,7 +704,7 @@ public class Pow2ModBenchmarks
_previousPrimeOrder = null;
Console.WriteLine($"Heuristic failed for {modulus}, falling back to full cycle calculation");
return fallbackOrder != 0UL ? fallbackOrder : MersenneDivisorCycles.CalculateCycleLengthCpu(modulus, divisorData);
return fallbackOrder != 0UL ? fallbackOrder : MersenneDivisorCyclesCpu.CalculateCycleLength(modulus, divisorData);
}
private ulong CalculateCycleLengthWithHeuristicsGpu(PrimeOrderCalculatorAccelerator gpu, ulong modulus, ulong fallbackOrder = 0UL)
@@ -712,7 +712,7 @@ public class Pow2ModBenchmarks
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(modulus);
if (modulus <= 1UL || (modulus & 1UL) == 0UL)
{
return fallbackOrder != 0UL ? fallbackOrder : MersenneDivisorCycles.CalculateCycleLengthGpu(gpu, modulus, divisorData);
return fallbackOrder != 0UL ? fallbackOrder : MersenneDivisorCyclesGpu.CalculateCycleLength(gpu, modulus, divisorData);
}
#if DEBUG
@@ -734,14 +734,14 @@ public class Pow2ModBenchmarks
_previousPrimeOrder = null;
Console.WriteLine($"Heuristic failed for {modulus}, falling back to full cycle calculation");
return fallbackOrder != 0UL ? fallbackOrder : MersenneDivisorCycles.CalculateCycleLengthGpu(gpu, modulus, divisorData);
return fallbackOrder != 0UL ? fallbackOrder : MersenneDivisorCyclesGpu.CalculateCycleLength(gpu, modulus, divisorData);
}
private UInt128 CalculateCycleLengthWithHeuristicsCpu(UInt128 modulus)
{
if (modulus <= UInt128.One || (modulus & UInt128.One) == UInt128.Zero)
{
return MersenneDivisorCycles.GetCycleCpu(modulus);
return MersenneDivisorCyclesCpu.GetCycle(modulus);
}
#if DEBUG
@@ -761,14 +761,14 @@ public class Pow2ModBenchmarks
_previousWidePrimeOrder = null;
Console.WriteLine($"Wide heuristic failed for {modulus}, falling back to full cycle calculation");
return MersenneDivisorCycles.GetCycleCpu(modulus);
return MersenneDivisorCyclesCpu.GetCycle(modulus);
}
private UInt128 CalculateCycleLengthWithHeuristicsGpu(PrimeOrderCalculatorAccelerator gpu, UInt128 modulus)
{
if (modulus <= UInt128.One || (modulus & UInt128.One) == UInt128.Zero)
{
return MersenneDivisorCycles.GetCycleGpu(gpu, modulus);
return MersenneDivisorCyclesGpu.GetCycle(gpu, modulus);
}
#if DEBUG
@@ -789,7 +789,7 @@ public class Pow2ModBenchmarks
_previousWidePrimeOrder = null;
Console.WriteLine($"Wide heuristic failed for {modulus}, falling back to full cycle calculation");
return MersenneDivisorCycles.GetCycleGpu(gpu, modulus);
return MersenneDivisorCyclesGpu.GetCycle(gpu, modulus);
}
private static ulong ComputeMontgomeryResidue(ulong value, ulong modulus) => (ulong)((UInt128)value * (UInt128.One << 64) % modulus);
@@ -1209,3 +1209,4 @@ public class Pow2ModBenchmarks
return (ulong)(product % modulus);
}
}
@@ -39,7 +39,7 @@ public class Pow2MontgomeryModBenchmarks
ulong smallModulus = NextSmallOddModulus();
_smallDivisors[i] = CreateMontgomeryDivisorData(smallModulus);
_smallExponents[i] = NextSmallExponent();
_smallCycles[i] = MersenneDivisorCycles.CalculateCycleLengthGpu(gpu, smallModulus, MontgomeryDivisorData.FromModulus(smallModulus));
_smallCycles[i] = MersenneDivisorCyclesGpu.CalculateCycleLength(gpu, smallModulus, MontgomeryDivisorData.FromModulus(smallModulus));
Console.WriteLine($"Calculating large cycle {i + 1} with heuristics");
(ulong largeModulus, ulong largeCycle) = NextLargeModulusAndCycle();
@@ -524,3 +524,4 @@ public class Pow2MontgomeryModBenchmarks
}
}
@@ -67,7 +67,7 @@ internal static class Pow2MontgomeryModWindowedBenchmarkInputsProvider
Pow2MontgomeryModWindowedBenchmarkSeed seed = seeds[i];
ulong modulus = 2UL * seed.Multiplier * seed.Exponent + 1UL;
MontgomeryDivisorData divisor = MontgomeryDivisorData.FromModulus(modulus);
ulong cycleLength = MersenneDivisorCycles.CalculateCycleLengthGpu(gpu, modulus, divisor);
ulong cycleLength = MersenneDivisorCyclesGpu.CalculateCycleLength(gpu, modulus, divisor);
ulong reducedExponent = seed.Exponent % cycleLength;
cases[i] = new Pow2MontgomeryModWindowedBenchmarkCase(
seed.Exponent,
@@ -94,3 +94,4 @@ internal static class Pow2MontgomeryModWindowedBenchmarkInputsProvider
public ulong Multiplier { get; }
}
}
@@ -14,7 +14,7 @@ public class MersenneDivisorCyclesGenerateGpuTests
var gpu = PrimeOrderCalculatorAccelerator.Rent(1);
try
{
MersenneDivisorCycles.GenerateGpu(path, maxDivisor: 50UL, batchSize: 16, skipCount: 0, nextPosition: 0);
MersenneDivisorCyclesGpu.GenerateGpu(path, maxDivisor: 50UL, batchSize: 16, skipCount: 0, nextPosition: 0);
var pairs = new List<(ulong divisor, ulong cycle)>();
using var stream = new FileStream(path, FileMode.Open, FileAccess.Read);
using var reader = new BinaryReader(stream);
@@ -41,7 +41,7 @@ public class MersenneDivisorCyclesGenerateGpuTests
{
expected.Should().Contain(pair.divisor);
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(pair.divisor);
pair.cycle.Should().Be(MersenneDivisorCycles.CalculateCycleLengthCpu(pair.divisor, divisorData));
pair.cycle.Should().Be(MersenneDivisorCyclesCpu.CalculateCycleLength(pair.divisor, divisorData));
}
}
finally
@@ -61,7 +61,7 @@ public class MersenneDivisorCyclesGenerateGpuTests
string path = Path.GetTempFileName();
try
{
MersenneDivisorCycles.Generate(path, maxDivisor: 50UL, threads: 4);
MersenneDivisorCyclesCpu.Generate(path, maxDivisor: 50UL, threads: 4);
var pairs = new List<(ulong divisor, ulong cycle)>();
using var stream = new FileStream(path, FileMode.Open, FileAccess.Read);
@@ -91,12 +91,12 @@ public class MersenneDivisorCyclesGenerateGpuTests
{
uniqueDivisors.Add(pair.divisor).Should().BeTrue();
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(pair.divisor);
pair.cycle.Should().Be(MersenneDivisorCycles.CalculateCycleLengthCpu(pair.divisor, divisorData));
pair.cycle.Should().Be(MersenneDivisorCyclesCpu.CalculateCycleLength(pair.divisor, divisorData));
}
uniqueDivisors.Should().BeEquivalentTo(expected);
var (_, completeCount) = MersenneDivisorCycles.FindLast(path);
var (_, completeCount) = MersenneDivisorCyclesCpu.FindLast(path);
completeCount.Should().Be(expected.Count);
}
finally
@@ -23,8 +23,8 @@ public class MersenneDivisorCyclesTests
try
{
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(divisor);
MersenneDivisorCycles.CalculateCycleLengthCpu(divisor, divisorData).Should().Be(expected);
MersenneDivisorCycles.CalculateCycleLengthGpu(divisor).Should().Be(expected);
MersenneDivisorCyclesCpu.CalculateCycleLength(divisor, divisorData).Should().Be(expected);
MersenneDivisorCyclesGpu.CalculateCycleLength(gpu, divisor, divisorData).Should().Be(expected);
}
finally
{
@@ -41,13 +41,13 @@ public class MersenneNumberDivisorCpuTesterTests
ulong[] primes = [5UL, 7UL, 11UL, 13UL];
ulong cycle23 = MersenneDivisorCycles.CalculateCycleLengthCpu(23UL, MontgomeryDivisorData.FromModulus(23UL));
ulong cycle23 = MersenneDivisorCyclesCpu.CalculateCycleLength(23UL, MontgomeryDivisorData.FromModulus(23UL));
session.CheckDivisor(23UL, MontgomeryDivisorData.FromModulus(23UL), cycle23, primes).Should().BeTrue();
ulong[] primesWithoutHit = [5UL, 7UL, 13UL];
session.CheckDivisor(23UL, MontgomeryDivisorData.FromModulus(23UL), cycle23, primesWithoutHit).Should().BeFalse();
ulong cycle31 = MersenneDivisorCycles.CalculateCycleLengthCpu(31UL, MontgomeryDivisorData.FromModulus(31UL));
ulong cycle31 = MersenneDivisorCyclesCpu.CalculateCycleLength(31UL, MontgomeryDivisorData.FromModulus(31UL));
session.CheckDivisor(31UL, MontgomeryDivisorData.FromModulus(31UL), cycle31, primes).Should().BeTrue();
ulong[] primesBeforeHit = [7UL, 11UL, 13UL];
@@ -63,7 +63,7 @@ public class MersenneNumberDivisorCpuTesterTests
ulong[] exponents = [6UL, 7UL, 9UL, 10UL, 12UL];
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(7UL);
ulong cycle = MersenneDivisorCycles.CalculateCycleLengthCpu(7UL, divisorData);
ulong cycle = MersenneDivisorCyclesCpu.CalculateCycleLength(7UL, divisorData);
session.CheckDivisor(7UL, divisorData, cycle, exponents).Should().BeTrue();
ulong[] nonDivisibleExponents = [5UL, 11UL];
@@ -79,7 +79,7 @@ public class MersenneNumberDivisorCpuTesterTests
ulong[] exponents = [10UL, 11UL, 20UL, 21UL, 30UL];
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(11UL);
ulong cycle = MersenneDivisorCycles.CalculateCycleLengthCpu(11UL, divisorData);
ulong cycle = MersenneDivisorCyclesCpu.CalculateCycleLength(11UL, divisorData);
session.CheckDivisor(11UL, divisorData, cycle, exponents).Should().BeTrue();
ulong[] nonDivisibleExponents = [5UL, 17UL];
@@ -104,3 +104,4 @@ public class MersenneNumberDivisorCpuTesterTests
}
}
@@ -235,13 +235,13 @@ public class MersenneNumberDivisorGpuTesterTests
ulong[] primes = [31UL, 37UL, 41UL, 43UL];
ulong cycle223 = MersenneDivisorCycles.CalculateCycleLengthGpu(gpu, 223UL, MontgomeryDivisorData.FromModulus(223UL));
ulong cycle223 = MersenneDivisorCyclesGpu.CalculateCycleLength(gpu, 223UL, MontgomeryDivisorData.FromModulus(223UL));
session.CheckDivisor(223UL, MontgomeryDivisorData.FromModulus(223UL), cycle223, primes).Should().BeTrue();
ulong[] primesBeforeHit = [31UL];
session.CheckDivisor(223UL, MontgomeryDivisorData.FromModulus(223UL), cycle223, primesBeforeHit).Should().BeFalse();
ulong cycle13367 = MersenneDivisorCycles.CalculateCycleLengthGpu(gpu, 13367UL, MontgomeryDivisorData.FromModulus(13367UL));
ulong cycle13367 = MersenneDivisorCyclesGpu.CalculateCycleLength(gpu, 13367UL, MontgomeryDivisorData.FromModulus(13367UL));
session.CheckDivisor(13367UL, MontgomeryDivisorData.FromModulus(13367UL), cycle13367, primes).Should().BeTrue();
ulong[] primesWithoutMatchingExponent = [31UL, 37UL, 43UL];
@@ -271,7 +271,7 @@ public class MersenneNumberDivisorGpuTesterTests
ulong[] primes = [31UL, 37UL, 41UL, 43UL, 47UL];
ulong cycle223 = MersenneDivisorCycles.CalculateCycleLengthGpu(gpu, 223UL, MontgomeryDivisorData.FromModulus(223UL));
ulong cycle223 = MersenneDivisorCyclesGpu.CalculateCycleLength(gpu, 223UL, MontgomeryDivisorData.FromModulus(223UL));
session.CheckDivisor(223UL, MontgomeryDivisorData.FromModulus(223UL), cycle223, primes).Should().BeTrue();
ulong[] primesBeforeHit = [31UL];
@@ -302,7 +302,7 @@ public class MersenneNumberDivisorGpuTesterTests
ulong[] exponents = [6UL, 7UL, 9UL, 10UL, 12UL];
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(7UL);
ulong cycle = MersenneDivisorCycles.CalculateCycleLengthGpu(gpu, 7UL, divisorData);
ulong cycle = MersenneDivisorCyclesGpu.CalculateCycleLength(gpu, 7UL, divisorData);
session.CheckDivisor(7UL, divisorData, cycle, exponents).Should().BeTrue();
@@ -329,7 +329,7 @@ public class MersenneNumberDivisorGpuTesterTests
ulong[] exponents = [10UL, 11UL, 20UL, 21UL, 30UL];
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(11UL);
ulong cycle = MersenneDivisorCycles.CalculateCycleLengthGpu(gpu, 11UL, divisorData);
ulong cycle = MersenneDivisorCyclesGpu.CalculateCycleLength(gpu, 11UL, divisorData);
session.CheckDivisor(11UL, divisorData, cycle, exponents).Should().BeTrue();
@@ -346,9 +346,9 @@ public class MersenneNumberDivisorGpuTesterTests
[Trait("Category", "Fast")]
public void ByDivisor_gpu_tester_skips_divisors_excluded_by_small_cycle_generation()
{
var cycles = MersenneDivisorCycles.Shared;
var tableField = typeof(MersenneDivisorCycles).GetField("_table", BindingFlags.NonPublic | BindingFlags.Instance)!;
var smallCyclesField = typeof(MersenneDivisorCycles).GetField("_smallCycles", BindingFlags.NonPublic | BindingFlags.Instance)!;
var cycles = MersenneDivisorCyclesGpu.Shared;
var tableField = typeof(MersenneDivisorCyclesGpu).GetField("_table", BindingFlags.NonPublic | BindingFlags.Instance)!;
var smallCyclesField = typeof(MersenneDivisorCyclesGpu).GetField("_smallCycles", BindingFlags.NonPublic | BindingFlags.Instance)!;
var originalTable = (List<(ulong Divisor, ulong Cycle)>)tableField.GetValue(cycles)!;
var originalSmall = (ulong[]?)smallCyclesField.GetValue(cycles);
@@ -360,7 +360,7 @@ public class MersenneNumberDivisorGpuTesterTests
ulong[] patchedSmall = new ulong[PerfectNumberConstants.MaxQForDivisorCycles + 1];
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(191UL);
patchedSmall[191] = MersenneDivisorCycles.CalculateCycleLengthGpu(gpu, 191UL, divisorData);
patchedSmall[191] = MersenneDivisorCyclesGpu.CalculateCycleLength(gpu, 191UL, divisorData);
tableField.SetValue(cycles, patchedTable);
smallCyclesField.SetValue(cycles, patchedSmall);
@@ -393,7 +393,7 @@ public class MersenneNumberDivisorGpuTesterTests
var session = new MersenneCpuDivisorScanSessionWithCpuOrder();
ulong[] primes = [31UL, 37UL, 41UL, 43UL, 47UL];
ulong cycle223 = MersenneDivisorCycles.CalculateCycleLengthCpu(223UL, MontgomeryDivisorData.FromModulus(223UL));
ulong cycle223 = MersenneDivisorCyclesCpu.CalculateCycleLength(223UL, MontgomeryDivisorData.FromModulus(223UL));
session.CheckDivisor(223UL, MontgomeryDivisorData.FromModulus(223UL), cycle223, primes).Should().BeTrue();
ulong[] primesBeforeHit = [31UL];
@@ -45,9 +45,9 @@ public class MersenneNumberOrderGpuTesterTests
writer.Write((ulong)uint.MaxValue);
}
var cycles = MersenneDivisorCycles.Shared;
var tableField = typeof(MersenneDivisorCycles).GetField("_table", BindingFlags.NonPublic | BindingFlags.Instance)!;
var smallCyclesField = typeof(MersenneDivisorCycles).GetField("_smallCycles", BindingFlags.NonPublic | BindingFlags.Instance)!;
var cycles = MersenneDivisorCyclesGpu.Shared;
var tableField = typeof(MersenneDivisorCyclesGpu).GetField("_table", BindingFlags.NonPublic | BindingFlags.Instance)!;
var smallCyclesField = typeof(MersenneDivisorCyclesGpu).GetField("_smallCycles", BindingFlags.NonPublic | BindingFlags.Instance)!;
var originalTable = ((List<(ulong Divisor, ulong Cycle)>)tableField.GetValue(cycles)!).Select(x => x).ToList();
var originalSmall = (ulong[]?)smallCyclesField.GetValue(cycles);
@@ -88,4 +88,3 @@ public class MersenneNumberOrderGpuTesterTests
isPrime.Should().Be(expectedPrime);
}
}
@@ -193,7 +193,7 @@ public class PrimeOrderCalculatorTests
var gpu = PrimeOrderCalculatorAccelerator.Rent(1);
try
{
var mersenneDivisorCycles = MersenneDivisorCycles.GetCycleGpu(gpu, prime).Should().Be((UInt128)1229782938247309446UL);
var mersenneDivisorCycles = MersenneDivisorCyclesGpu.GetCycle(gpu, prime).Should().Be((UInt128)1229782938247309446UL);
}
finally
{
@@ -225,3 +225,4 @@ public class PrimeOrderCalculatorTests
return order;
}
}
@@ -4,7 +4,7 @@ namespace PerfectNumbers.Core.Cpu;
public class MersenneNumberIncrementalCpuTester(GpuKernelType kernelType)
{
private static readonly MersenneDivisorCycles _cycles = MersenneDivisorCycles.Shared;
private static readonly MersenneDivisorCyclesCpu _cycles = MersenneDivisorCyclesCpu.Shared;
private readonly GpuKernelType _kernelType = kernelType;
public void Scan(PrimeOrderCalculatorAccelerator gpu, ulong exponent, UInt128 twoP, LastDigit lastDigit, UInt128 maxK, ref bool isPrime)
@@ -31,7 +31,7 @@ public class MersenneNumberIncrementalCpuTester(GpuKernelType kernelType)
{
// TODO: Replace this direct GetCycle call with DivisorCycleCache.Lookup so we reuse the single snapshot block
// and compute missing cycles on the configured device without queuing additional block generation.
qCycle = MersenneDivisorCycles.GetCycleCpu(q);
qCycle = MersenneDivisorCyclesCpu.GetCycle(q);
shouldCheck = auto.Mod10R != 5UL;
if (shouldCheck)
{
@@ -34,7 +34,7 @@ public class MersenneNumberLucasLehmerCpuTester
for (UInt128 i = UInt128.Zero; i < limit; i++)
{
// Lucas–Lehmer squares the evolving residue, so we stay on the Montgomery powmod path rather than the pow2-specific helper.
s = s.PowModWithCycle(two, MersenneDivisorCycles.GetCycleCpu(m)) - two;
s = s.PowModWithCycle(two, MersenneDivisorCyclesCpu.GetCycle(m)) - two;
if (s < UInt128.Zero)
{
s += m;
@@ -44,3 +44,4 @@ public class MersenneNumberLucasLehmerCpuTester
return s == UInt128.Zero;
}
}
@@ -15,7 +15,7 @@ public class MersenneNumberOrderCpuTester(GpuKernelType kernelType)
while (k <= maxK && Volatile.Read(ref isPrime))
{
qCycle = MersenneDivisorCycles.GetCycleCpu(q);
qCycle = MersenneDivisorCyclesCpu.GetCycle(q);
// TODO: When this lookup misses the snapshot, invoke the configured device to compute the
// single required cycle on demand without persisting it so the CPU order path retains the
// cycle-stepping speedups while honoring the no-extra-cache constraint for large divisors.
@@ -76,4 +76,4 @@ public class MersenneNumberOrderCpuTester(GpuKernelType kernelType)
return;
}
}
}
+8 -8
View File
@@ -39,12 +39,12 @@ public sealed class DivisorCycleCache
Accelerator accelerator = AcceleratorPool.Shared.Accelerators[acceleratorIndex];
_accelerator = accelerator;
_gpuKernel = LoadKernel(accelerator);
_snapshot = MersenneDivisorCycles.Shared.ExportSmallCyclesSnapshot();
_snapshot = MersenneDivisorCyclesCpu.Shared.ExportSmallCyclesSnapshot();
}
public void RefreshSnapshot()
{
_snapshot = MersenneDivisorCycles.Shared.ExportSmallCyclesSnapshot();
_snapshot = MersenneDivisorCyclesCpu.Shared.ExportSmallCyclesSnapshot();
}
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
@@ -60,7 +60,7 @@ public sealed class DivisorCycleCache
return cached;
}
return MersenneDivisorCycles.CalculateCycleLengthCpu(divisor, divisorData);
return MersenneDivisorCyclesCpu.CalculateCycleLength(divisor, divisorData);
}
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
@@ -89,7 +89,7 @@ public sealed class DivisorCycleCache
return cycleLength;
}
cycleLength = MersenneDivisorCycles.CalculateCycleLengthHybrid(gpu, divisor, divisorData, skipPrimeOrderHeuristic: true);
cycleLength = MersenneDivisorCyclesHybrid.CalculateCycleLength(gpu, divisor, divisorData, skipPrimeOrderHeuristic: true);
return cycleLength;
}
@@ -122,7 +122,7 @@ public sealed class DivisorCycleCache
return cycleLength;
}
cycleLength = MersenneDivisorCycles.CalculateCycleLengthGpu(gpu, divisor, divisorData, skipPrimeOrderHeuristic: true);
cycleLength = MersenneDivisorCyclesGpu.CalculateCycleLength(gpu, divisor, divisorData, skipPrimeOrderHeuristic: true);
return cycleLength;
}
@@ -179,7 +179,7 @@ public sealed class DivisorCycleCache
return cached;
}
return MersenneDivisorCycles.CalculateCycleLengthHybrid(gpu, divisor, divisorData);
return MersenneDivisorCyclesHybrid.CalculateCycleLength(gpu, divisor, divisorData);
}
public void GetCycleLengthsHybrid(PrimeOrderCalculatorAccelerator gpu, ReadOnlySpan<ulong> divisors, Span<ulong> cycles)
@@ -270,7 +270,7 @@ public sealed class DivisorCycleCache
int targetIndex = indices[i];
ulong divisor = divisors[targetIndex];
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(divisor);
cycles[targetIndex] = MersenneDivisorCycles.CalculateCycleLengthCpu(divisor, divisorData);
cycles[targetIndex] = MersenneDivisorCyclesCpu.CalculateCycleLength(divisor, divisorData);
}
}
@@ -282,7 +282,7 @@ public sealed class DivisorCycleCache
int targetIndex = indices[i];
ulong divisor = divisors[targetIndex];
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(divisor);
cycles[targetIndex] = MersenneDivisorCycles.CalculateCycleLengthHybrid(gpu, divisor, divisorData);
cycles[targetIndex] = MersenneDivisorCyclesHybrid.CalculateCycleLength(gpu, divisor, divisorData);
}
}
+1 -1
View File
@@ -150,7 +150,7 @@ public class GpuKernelPool
return;
}
var host = MersenneDivisorCycles.Shared.ExportSmallCyclesSnapshot();
var host = MersenneDivisorCyclesGpu.Shared.ExportSmallCyclesSnapshot();
MemoryBuffer1D<ulong, Stride1D.Dense>? device;
// lock (accelerator)
@@ -452,9 +452,9 @@ public sealed partial class MersenneNumberDivisorByDivisorGpuTester : IMersenneN
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static ulong ResolveDivisorCycle(PrimeOrderCalculatorAccelerator gpu, ulong divisor, ulong prime, in MontgomeryDivisorData divisorData)
{
if (!MersenneDivisorCycles.TryCalculateCycleLengthForExponentGpu(gpu, divisor, prime, divisorData, out ulong computedCycle, out bool primeOrderFailed) || computedCycle == 0UL)
if (!MersenneDivisorCyclesGpu.TryCalculateCycleLengthForExponent(gpu, divisor, prime, divisorData, out ulong computedCycle, out bool primeOrderFailed) || computedCycle == 0UL)
{
return MersenneDivisorCycles.CalculateCycleLengthGpu(gpu, divisor, divisorData, skipPrimeOrderHeuristic: primeOrderFailed);
return MersenneDivisorCyclesGpu.CalculateCycleLength(gpu, divisor, divisorData, skipPrimeOrderHeuristic: primeOrderFailed);
}
return computedCycle;
@@ -601,9 +601,9 @@ public sealed partial class MersenneNumberDivisorByDivisorGpuTester : IMersenneN
var gpu = _primeOrderCalculatorAccelerator;
if (cycle == 0UL)
{
if (!MersenneDivisorCycles.TryCalculateCycleLengthForExponentCpu(divisor, firstPrime, divisorData, out ulong computedCycle, out bool primeOrderFailed) || computedCycle == 0UL)
if (!MersenneDivisorCyclesCpu.TryCalculateCycleLengthForExponent(divisor, firstPrime, divisorData, out ulong computedCycle, out bool primeOrderFailed) || computedCycle == 0UL)
{
cycle = MersenneDivisorCycles.CalculateCycleLengthGpu(gpu, divisor, divisorData, skipPrimeOrderHeuristic: primeOrderFailed);
cycle = MersenneDivisorCyclesGpu.CalculateCycleLength(gpu, divisor, divisorData, skipPrimeOrderHeuristic: primeOrderFailed);
}
else
{
@@ -740,3 +740,4 @@ public sealed partial class MersenneNumberDivisorByDivisorGpuTester : IMersenneN
return new DivisorScanSession(gpu, this);
}
}
@@ -35,7 +35,7 @@ public sealed class MersenneNumberDivisorGpuTester
public static void BuildDivisorCandidates()
{
ulong[] snapshot = MersenneDivisorCycles.Shared.ExportSmallCyclesSnapshot();
ulong[] snapshot = MersenneDivisorCyclesGpu.Shared.ExportSmallCyclesSnapshot();
(ulong divisor, uint cycle)[] list = new (ulong divisor, uint cycle)[snapshot.Length / 2];
ulong cycle;
int count = 0, i, snapshotLength = snapshot.Length;
@@ -142,7 +142,7 @@ public sealed class MersenneNumberDivisorGpuTester
continue;
}
UInt128 cycle128 = MersenneDivisorCycles.GetCycleGpu(gpu, d);
UInt128 cycle128 = MersenneDivisorCyclesGpu.GetCycle(gpu, d);
if ((UInt128)p % cycle128 != UInt128.Zero)
{
continue;
@@ -109,7 +109,7 @@ public sealed class HeuristicCombinedPrimeTester
internal static readonly ulong[] CombinedDivisorsEnding7Squares;
internal static readonly ulong[] CombinedDivisorsEnding9Squares;
private static readonly ulong[] HeuristicSmallCycleSnapshot = MersenneDivisorCycles.Shared.ExportSmallCyclesSnapshot();
private static readonly ulong[] HeuristicSmallCycleSnapshot = MersenneDivisorCyclesCpu.Shared.ExportSmallCyclesSnapshot();
internal enum CombinedDivisorPattern : byte
{
@@ -507,7 +507,7 @@ public sealed class HeuristicCombinedPrimeTester
ulong divisor = preparation.Candidate.Value;
MontgomeryDivisorData divisorData = preparation.DivisorData;
bool trySuccess = MersenneDivisorCycles.TryCalculateCycleLengthForExponentCpu(
bool trySuccess = MersenneDivisorCyclesCpu.TryCalculateCycleLengthForExponent(
divisor,
exponent,
divisorData,
@@ -523,7 +523,7 @@ public sealed class HeuristicCombinedPrimeTester
}
primeOrderFailed = primeOrderFailedLocal || !trySuccess || computedCycle == 0UL;
ulong resolvedCycle = MersenneDivisorCycles.CalculateCycleLengthCpu(divisor, divisorData, skipPrimeOrderHeuristic: primeOrderFailed);
ulong resolvedCycle = MersenneDivisorCyclesCpu.CalculateCycleLength(divisor, divisorData, skipPrimeOrderHeuristic: primeOrderFailed);
cycleFromHint = false;
cycleComputed = resolvedCycle != 0UL;
return resolvedCycle;
@@ -549,7 +549,7 @@ public sealed class HeuristicCombinedPrimeTester
ulong divisor = preparation.Candidate.Value;
MontgomeryDivisorData divisorData = preparation.DivisorData;
bool trySuccess = MersenneDivisorCycles.TryCalculateCycleLengthForExponentCpu(
bool trySuccess = MersenneDivisorCyclesCpu.TryCalculateCycleLengthForExponent(
divisor,
exponent,
divisorData,
@@ -565,7 +565,7 @@ public sealed class HeuristicCombinedPrimeTester
}
primeOrderFailed = primeOrderFailedLocal || !trySuccess || computedCycle == 0UL;
ulong resolvedCycle = MersenneDivisorCycles.CalculateCycleLengthGpu(gpu, divisor, divisorData, skipPrimeOrderHeuristic: primeOrderFailed);
ulong resolvedCycle = MersenneDivisorCyclesGpu.CalculateCycleLength(gpu, divisor, divisorData, skipPrimeOrderHeuristic: primeOrderFailed);
cycleFromHint = false;
cycleComputed = resolvedCycle != 0UL;
return resolvedCycle;
+5 -5
View File
@@ -28,7 +28,7 @@ public sealed class HeuristicPrimeTester
private static readonly bool UseHeuristicGroupBTrialDivision = false; // Temporary fallback gate for Group B.
private static readonly ulong[] HeuristicSmallCycleSnapshot = MersenneDivisorCycles.Shared.ExportSmallCyclesSnapshot();
private static readonly ulong[] HeuristicSmallCycleSnapshot = MersenneDivisorCyclesCpu.Shared.ExportSmallCyclesSnapshot();
[ThreadStatic]
private static BidirectionalCycleRemainderStepper _mod10Stepper;
@@ -437,7 +437,7 @@ public sealed class HeuristicPrimeTester
ulong divisor = preparation.Candidate.Value;
MontgomeryDivisorData divisorData = preparation.DivisorData;
bool trySuccess = MersenneDivisorCycles.TryCalculateCycleLengthForExponentCpu(
bool trySuccess = MersenneDivisorCyclesCpu.TryCalculateCycleLengthForExponent(
divisor,
exponent,
divisorData,
@@ -453,7 +453,7 @@ public sealed class HeuristicPrimeTester
}
primeOrderFailed = primeOrderFailedLocal || !trySuccess || computedCycle == 0UL;
ulong resolvedCycle = MersenneDivisorCycles.CalculateCycleLengthCpu(divisor, divisorData, skipPrimeOrderHeuristic: primeOrderFailed);
ulong resolvedCycle = MersenneDivisorCyclesCpu.CalculateCycleLength(divisor, divisorData, skipPrimeOrderHeuristic: primeOrderFailed);
cycleFromHint = false;
cycleComputed = resolvedCycle != 0UL;
return resolvedCycle;
@@ -479,7 +479,7 @@ public sealed class HeuristicPrimeTester
ulong divisor = preparation.Candidate.Value;
MontgomeryDivisorData divisorData = preparation.DivisorData;
bool trySuccess = MersenneDivisorCycles.TryCalculateCycleLengthForExponentCpu(
bool trySuccess = MersenneDivisorCyclesCpu.TryCalculateCycleLengthForExponent(
divisor,
exponent,
divisorData,
@@ -495,7 +495,7 @@ public sealed class HeuristicPrimeTester
}
primeOrderFailed = primeOrderFailedLocal || !trySuccess || computedCycle == 0UL;
ulong resolvedCycle = MersenneDivisorCycles.CalculateCycleLengthGpu(gpu, divisor, divisorData, skipPrimeOrderHeuristic: primeOrderFailed);
ulong resolvedCycle = MersenneDivisorCyclesGpu.CalculateCycleLength(gpu, divisor, divisorData, skipPrimeOrderHeuristic: primeOrderFailed);
cycleFromHint = false;
cycleComputed = resolvedCycle != 0UL;
return resolvedCycle;
@@ -11,15 +11,17 @@ using PerfectNumbers.Core.Gpu.Accelerators;
namespace PerfectNumbers.Core;
public class MersenneDivisorCycles
[DeviceDependentTemplate(typeof(ComputationDevice))]
public struct MersenneDivisorCyclesTemplate
{
private List<(ulong divisor, ulong cycleLength)> _table = [];
private List<(ulong divisor, ulong cycleLength)> _table;
// Lightweight read-mostly cache for small divisors (<= 4,000,000). 0 => unknown
private ulong[]? _smallCycles;
public static MersenneDivisorCycles Shared { get; } = new MersenneDivisorCycles();
public static readonly MersenneDivisorCyclesTemplate Shared = new();
public MersenneDivisorCycles()
public MersenneDivisorCyclesTemplate()
{
_table = [];
}
public void LoadFrom(string path)
@@ -50,7 +52,11 @@ public class MersenneDivisorCycles
return _smallCycles!;
}
#if DEVICE_GPU || DEVICE_HYBRID
public static bool CycleEqualsExponent(PrimeOrderCalculatorAccelerator gpu, ulong divisor, in MontgomeryDivisorData divisorData, ulong exponent)
#else
public static bool CycleEqualsExponent(ulong divisor, in MontgomeryDivisorData divisorData, ulong exponent)
#endif
{
if (CycleEqualsExponentForMersenneCandidate(divisor, divisorData, exponent))
{
@@ -75,88 +81,20 @@ public class MersenneDivisorCycles
}
}
if (TryCalculateCycleLengthHeuristicCpu(divisor, divisorData, out ulong heuristicCycle) && heuristicCycle != 0UL)
#if DEVICE_GPU || DEVICE_HYBRID
if (TryCalculateCycleLengthHeuristic(gpu, divisor, divisorData, out ulong heuristicCycle, skipPrimeOrderHeuristic: false) && heuristicCycle != 0UL)
#else
if (TryCalculateCycleLengthHeuristic(divisor, divisorData, out ulong heuristicCycle, skipPrimeOrderHeuristic: false) && heuristicCycle != 0UL)
#endif
{
return heuristicCycle == exponent;
}
if (TryCalculateCycleLengthForExponentCpu(divisor, exponent, divisorData, out ulong cycleLength, out bool _) && cycleLength != 0UL)
{
return cycleLength == exponent;
}
return exponent.Pow2MontgomeryModWindowedConvertToStandardCpu(divisorData) == 1UL;
}
public static bool CycleEqualsExponentGpu(PrimeOrderCalculatorAccelerator gpu, ulong divisor, in MontgomeryDivisorData divisorData, ulong exponent)
{
if (CycleEqualsExponentForMersenneCandidate(divisor, divisorData, exponent))
{
return true;
}
if (exponent <= 1UL || divisor <= 1UL || (divisor & 1UL) == 0UL)
{
return false;
}
if (divisor <= PerfectNumberConstants.MaxQForDivisorCycles)
{
var small = Shared._smallCycles;
if (small is not null)
{
ulong cached = small[(int)divisor];
if (cached != 0UL)
{
return cached == exponent;
}
}
}
if (TryCalculateCycleLengthHeuristicGpu(gpu, divisor, divisorData, out ulong heuristicCycle) && heuristicCycle != 0UL)
{
return heuristicCycle == exponent;
}
if (TryCalculateCycleLengthForExponentCpu(divisor, exponent, divisorData, out ulong cycleLength, out bool _) && cycleLength != 0UL)
{
return cycleLength == exponent;
}
return exponent.Pow2MontgomeryModWindowedConvertToStandardCpu(divisorData) == 1UL;
}
public static bool CycleEqualsExponentHybrid(PrimeOrderCalculatorAccelerator gpu, ulong divisor, in MontgomeryDivisorData divisorData, ulong exponent)
{
if (CycleEqualsExponentForMersenneCandidate(divisor, divisorData, exponent))
{
return true;
}
if (exponent <= 1UL || divisor <= 1UL || (divisor & 1UL) == 0UL)
{
return false;
}
if (divisor <= PerfectNumberConstants.MaxQForDivisorCycles)
{
var small = Shared._smallCycles;
if (small is not null)
{
ulong cached = small[(int)divisor];
if (cached != 0UL)
{
return cached == exponent;
}
}
}
if (TryCalculateCycleLengthHeuristicHybrid(gpu, divisor, divisorData, out ulong heuristicCycle) && heuristicCycle != 0UL)
{
return heuristicCycle == exponent;
}
if (TryCalculateCycleLengthForExponentCpu(divisor, exponent, divisorData, out ulong cycleLength, out bool _) && cycleLength != 0UL)
#if DEVICE_GPU || DEVICE_HYBRID
if (TryCalculateCycleLengthForExponent(gpu, divisor, exponent, divisorData, out ulong cycleLength, out bool _) && cycleLength != 0UL)
#else
if (TryCalculateCycleLengthForExponent(divisor, exponent, divisorData, out ulong cycleLength, out bool _) && cycleLength != 0UL)
#endif
{
return cycleLength == exponent;
}
@@ -175,7 +113,7 @@ public class MersenneDivisorCycles
if (divisor <= PerfectNumberConstants.MaxQForDivisorCycles)
{
MersenneDivisorCycles shared = Shared;
MersenneDivisorCyclesTemplate shared = Shared;
ulong[]? small = shared._smallCycles;
if (small is not null)
{
@@ -239,7 +177,12 @@ public class MersenneDivisorCycles
}
}
public ulong GetCycle(ulong divisor, in MontgomeryDivisorData divisorData)
public readonly ulong GetCycle(
#if DEVICE_GPU || DEVICE_HYBRID
PrimeOrderCalculatorAccelerator gpu,
#endif
ulong divisor,
in MontgomeryDivisorData divisorData)
{
// Fast-path: in-memory array for small divisors
if (divisor <= PerfectNumberConstants.MaxQForDivisorCycles)
@@ -284,106 +227,18 @@ public class MersenneDivisorCycles
// TODO: Route this miss to an ephemeral single-cycle computation on the device selected by the current
// configuration (and skip persisting the result) when the divisor falls outside the in-memory snapshot
// so we respect the large-p memory limits and avoid extra cache locks.
return CalculateCycleLengthCpu(divisor, divisorData);
#if DEVICE_GPU || DEVICE_HYBRID
return CalculateCycleLength(gpu, divisor, divisorData);
#else
return CalculateCycleLength(divisor, divisorData);
#endif
}
public ulong GetCycleGpu(PrimeOrderCalculatorAccelerator gpu, ulong divisor, in MontgomeryDivisorData divisorData)
{
// Fast-path: in-memory array for small divisors
if (divisor <= PerfectNumberConstants.MaxQForDivisorCycles)
{
var arr = _smallCycles;
if (arr is not null)
{
ulong cached = arr[(int)divisor];
if (cached != 0UL)
{
return cached;
}
}
}
// Binary search for divisor in sorted _table
int mid, right, left = 0;
ulong d;
List<(ulong divisor, ulong cycleLength)> cycles = _table;
right = cycles.Count - 1;
while (left <= right)
{
mid = left + ((right - left) >> 1);
d = cycles[mid].divisor;
if (d == divisor)
{
return cycles[mid].cycleLength;
}
if (d < divisor)
{
left = mid + 1;
}
else
{
right = mid - 1;
}
}
// TODO: Route this miss to an ephemeral single-cycle computation on the device selected by the current
// configuration (and skip persisting the result) when the divisor falls outside the in-memory snapshot
// so we respect the large-p memory limits and avoid extra cache locks.
return CalculateCycleLengthGpu(gpu, divisor, divisorData);
}
public ulong GetCycleHybrid(PrimeOrderCalculatorAccelerator gpu, ulong divisor, in MontgomeryDivisorData divisorData)
{
// Fast-path: in-memory array for small divisors
if (divisor <= PerfectNumberConstants.MaxQForDivisorCycles)
{
var arr = _smallCycles;
if (arr is not null)
{
ulong cached = arr[(int)divisor];
if (cached != 0UL)
{
return cached;
}
}
}
// Binary search for divisor in sorted _table
int mid, right, left = 0;
ulong d;
List<(ulong divisor, ulong cycleLength)> cycles = _table;
right = cycles.Count - 1;
while (left <= right)
{
mid = left + ((right - left) >> 1);
d = cycles[mid].divisor;
if (d == divisor)
{
return cycles[mid].cycleLength;
}
if (d < divisor)
{
left = mid + 1;
}
else
{
right = mid - 1;
}
}
// TODO: Route this miss to an ephemeral single-cycle computation on the device selected by the current
// configuration (and skip persisting the result) when the divisor falls outside the in-memory snapshot
// so we respect the large-p memory limits and avoid extra cache locks.
return CalculateCycleLengthHybrid(gpu, divisor, divisorData);
}
public static UInt128 GetCycleCpu(UInt128 divisor)
#if DEVICE_GPU || DEVICE_HYBRID
public static UInt128 GetCycle(PrimeOrderCalculatorAccelerator gpu, UInt128 divisor)
#else
public static UInt128 GetCycle(UInt128 divisor)
#endif
{
// For divisor = 2^k, cycle is 1
if ((divisor & (divisor - UInt128.One)) == UInt128.Zero)
@@ -395,106 +250,32 @@ public class MersenneDivisorCycles
{
ulong divisor64 = (ulong)divisor;
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(divisor64);
ulong cycle = CalculateCycleLengthCpu(divisor64, divisorData);
return (UInt128)cycle;
}
UInt128 wideOrder = PrimeOrderCalculator.CalculateCpu(
divisor,
previousOrder: null,
PrimeOrderCalculator.PrimeOrderCalculatorConfig.HeuristicDefault);
if (wideOrder != UInt128.Zero)
{
return wideOrder;
}
// Otherwise, find order of 2 mod divisor
// TODO: Port this UInt128 path to the unrolled-hex cycle calculator so wide
// divisors stop relying on the slow shift-and-subtract loop measured in the
// GPU benchmarks.
UInt128 order = UInt128.One;
UInt128 pow = UInt128Numbers.Two;
while (pow != UInt128.One)
{
pow <<= 1;
if (pow >= divisor)
{
pow -= divisor;
}
order++;
}
return order;
}
public static UInt128 GetCycleHybrid(PrimeOrderCalculatorAccelerator gpu, UInt128 divisor)
{
// For divisor = 2^k, cycle is 1
if ((divisor & (divisor - UInt128.One)) == UInt128.Zero)
{
return UInt128.One;
}
if (divisor <= ulong.MaxValue)
{
ulong divisor64 = (ulong)divisor;
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(divisor64);
ulong cycle = CalculateCycleLengthHybrid(gpu, divisor64, divisorData);
return (UInt128)cycle;
}
UInt128 wideOrder = PrimeOrderCalculator.CalculateHybrid(
gpu,
divisor,
previousOrder: null,
PrimeOrderCalculator.PrimeOrderCalculatorConfig.HeuristicDefault);
if (wideOrder != UInt128.Zero)
{
return wideOrder;
}
// Otherwise, find order of 2 mod divisor
// TODO: Port this UInt128 path to the unrolled-hex cycle calculator so wide
// divisors stop relying on the slow shift-and-subtract loop measured in the
// GPU benchmarks.
UInt128 order = UInt128.One;
UInt128 pow = UInt128Numbers.Two;
while (pow != UInt128.One)
{
pow <<= 1;
if (pow >= divisor)
{
pow -= divisor;
}
order++;
}
return order;
}
public static UInt128 GetCycleGpu(PrimeOrderCalculatorAccelerator gpu, UInt128 divisor)
{
// For divisor = 2^k, cycle is 1
if ((divisor & (divisor - UInt128.One)) == UInt128.Zero)
{
return UInt128.One;
}
if (divisor <= ulong.MaxValue)
{
ulong divisor64 = (ulong)divisor;
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(divisor64);
ulong cycle = CalculateCycleLengthGpu(gpu, divisor64, divisorData);
#if DEVICE_GPU || DEVICE_HYBRID
ulong cycle = CalculateCycleLength(gpu, divisor64, divisorData);
#else
ulong cycle = CalculateCycleLength(divisor64, divisorData);
#endif
return (UInt128)cycle;
}
#if DEVICE_GPU
UInt128 wideOrder = PrimeOrderCalculator.CalculateGpu(
gpu,
divisor,
previousOrder: null,
PrimeOrderCalculator.PrimeOrderCalculatorConfig.HeuristicDefault);
#elif DEVICE_HYBRID
UInt128 wideOrder = PrimeOrderCalculator.CalculateHybrid(
gpu,
divisor,
previousOrder: null,
PrimeOrderCalculator.PrimeOrderCalculatorConfig.HeuristicDefault);
#else
UInt128 wideOrder = PrimeOrderCalculator.CalculateCpu(
divisor,
previousOrder: null,
PrimeOrderCalculator.PrimeOrderCalculatorConfig.HeuristicDefault);
#endif
if (wideOrder != UInt128.Zero)
{
return wideOrder;
@@ -520,176 +301,10 @@ public class MersenneDivisorCycles
return order;
}
public static bool TryCalculateCycleLengthForExponentCpu(
ulong divisor,
ulong exponent,
in MontgomeryDivisorData divisorData,
out ulong cycleLength,
out bool primeOrderFailed)
{
cycleLength = 0UL;
primeOrderFailed = false;
// EvenPerfectBitScanner never feeds powers of two into this helper, so leave the branch commented out to avoid redundant work.
// if ((divisor & (divisor - 1UL)) == 0UL)
// {
// cycleLength = 1UL;
// return true;
// }
// The scanner only calls this path with prime exponents greater than one and odd divisors above three, keeping the small-parameter guard unreachable.
// if (divisor <= 3UL || exponent <= 1UL)
// {
// cycleLength = CalculateCycleLength(divisor, divisorData);
// return true;
// }
ulong computedOrder = PrimeOrderCalculator.CalculateCpu(
divisor,
previousOrder: null,
divisorData,
PrimeOrderCalculator.PrimeOrderCalculatorConfig.HeuristicDefault);
if (computedOrder != 0UL)
{
cycleLength = computedOrder;
return true;
}
primeOrderFailed = true;
ulong phi = divisor - 1UL;
// A zero totient would imply divisor == 0, which never occurs on the tested path. Keep the guard documented without
// branching in the hot loop.
// if (phi == 0UL)
// {
// return false;
// }
int twoCount = BitOperations.TrailingZeroCount(phi);
ulong reducedPhi = phi >> twoCount;
if (reducedPhi == 0UL || (reducedPhi % exponent) != 0UL)
{
return false;
}
ulong k = reducedPhi / exponent;
// k == 0 would indicate reducedPhi < exponent, which the EvenPerfectBitScanner call flow prevents. Document the
// assumption instead of branching.
// if (k == 0UL)
// {
// return false;
// }
Dictionary<ulong, int> factorCounts = ThreadStaticPools.RentFactorCountDictionary();
bool success = false;
if (twoCount > 0)
{
factorCounts[2UL] = twoCount;
}
bool exponentAccumulated = AccumulateFactors(exponent, factorCounts);
bool factorsAccumulated = exponentAccumulated && AccumulateFactors(k, factorCounts);
if (factorsAccumulated)
{
cycleLength = ReduceOrder(divisorData, phi, factorCounts);
success = true;
primeOrderFailed = false;
}
factorCounts.Clear();
ThreadStaticPools.ReturnFactorCountDictionary(factorCounts);
return success;
}
public static bool TryCalculateCycleLengthForExponentHybrid(
PrimeOrderCalculatorAccelerator gpu,
ulong divisor,
ulong exponent,
in MontgomeryDivisorData divisorData,
out ulong cycleLength,
out bool primeOrderFailed)
{
cycleLength = 0UL;
primeOrderFailed = false;
// EvenPerfectBitScanner never feeds powers of two into this helper, so leave the branch commented out to avoid redundant work.
// if ((divisor & (divisor - 1UL)) == 0UL)
// {
// cycleLength = 1UL;
// return true;
// }
// The scanner only calls this path with prime exponents greater than one and odd divisors above three, keeping the small-parameter guard unreachable.
// if (divisor <= 3UL || exponent <= 1UL)
// {
// cycleLength = CalculateCycleLength(divisor, divisorData);
// return true;
// }
ulong computedOrder = PrimeOrderCalculator.CalculateHybrid(
gpu,
divisor,
previousOrder: null,
divisorData,
PrimeOrderCalculator.PrimeOrderCalculatorConfig.HeuristicDefault);
if (computedOrder != 0UL)
{
cycleLength = computedOrder;
return true;
}
primeOrderFailed = true;
ulong phi = divisor - 1UL;
// A zero totient would imply divisor == 0, which never occurs on the tested path. Keep the guard documented without
// branching in the hot loop.
// if (phi == 0UL)
// {
// return false;
// }
int twoCount = BitOperations.TrailingZeroCount(phi);
ulong reducedPhi = phi >> twoCount;
if (reducedPhi == 0UL || (reducedPhi % exponent) != 0UL)
{
return false;
}
ulong k = reducedPhi / exponent;
// k == 0 would indicate reducedPhi < exponent, which the EvenPerfectBitScanner call flow prevents. Document the
// assumption instead of branching.
// if (k == 0UL)
// {
// return false;
// }
Dictionary<ulong, int> factorCounts = ThreadStaticPools.RentFactorCountDictionary();
bool success = false;
if (twoCount > 0)
{
factorCounts[2UL] = twoCount;
}
bool exponentAccumulated = AccumulateFactors(exponent, factorCounts);
bool factorsAccumulated = exponentAccumulated && AccumulateFactors(k, factorCounts);
if (factorsAccumulated)
{
cycleLength = ReduceOrder(divisorData, phi, factorCounts);
success = true;
primeOrderFailed = false;
}
factorCounts.Clear();
ThreadStaticPools.ReturnFactorCountDictionary(factorCounts);
return success;
}
public static bool TryCalculateCycleLengthForExponentGpu(
public static bool TryCalculateCycleLengthForExponent(
#if DEVICE_GPU || DEVICE_HYBRID
PrimeOrderCalculatorAccelerator gpu,
#endif
ulong divisor,
ulong exponent,
in MontgomeryDivisorData divisorData,
@@ -713,12 +328,27 @@ public class MersenneDivisorCycles
// return true;
// }
#if DEVICE_GPU
ulong computedOrder = PrimeOrderCalculator.CalculateGpu(
gpu,
divisor,
previousOrder: null,
divisorData,
PrimeOrderCalculator.PrimeOrderCalculatorConfig.HeuristicDefault);
#elif DEVICE_HYBRID
ulong computedOrder = PrimeOrderCalculator.CalculateHybrid(
gpu,
divisor,
previousOrder: null,
divisorData,
PrimeOrderCalculator.PrimeOrderCalculatorConfig.HeuristicDefault);
#else
ulong computedOrder = PrimeOrderCalculator.CalculateCpu(
divisor,
previousOrder: null,
divisorData,
PrimeOrderCalculator.PrimeOrderCalculatorConfig.HeuristicDefault);
#endif
if (computedOrder != 0UL)
{
cycleLength = computedOrder;
@@ -773,6 +403,8 @@ public class MersenneDivisorCycles
return success;
}
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static bool AccumulateFactors(
ulong value,
Dictionary<ulong, int> counts)
@@ -805,6 +437,7 @@ public class MersenneDivisorCycles
// private static ulong _tryFactorIntoCountsInternalHits;
// private static ulong _tryCalculateCycleLengthHeuristicHits;
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static bool TryFactorIntoCountsInternal(ulong value, Dictionary<ulong, int> counts)
{
// The EvenPerfectBitScanner only requests factors for values >= 2 here. Leave the guard documented without executing it.
@@ -873,18 +506,21 @@ public class MersenneDivisorCycles
return true;
}
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
private static void AddFactor(Dictionary<ulong, int> counts, ulong factor)
{
ref int entry = ref CollectionsMarshal.GetValueRefOrAddDefault(counts, factor, out bool exists);
entry = exists ? entry + 1 : 1;
}
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
private static void AddFactor(Dictionary<ulong, int> counts, ulong factor, int multiplicity)
{
ref int entry = ref CollectionsMarshal.GetValueRefOrAddDefault(counts, factor, out bool exists);
entry = exists ? entry + multiplicity : multiplicity;
}
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static ulong ReduceOrder(in MontgomeryDivisorData divisorData, ulong initialOrder, Dictionary<ulong, int> factorCounts)
{
if (factorCounts.Count == 0)
@@ -1007,6 +643,7 @@ public class MersenneDivisorCycles
}
}
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static ulong PollardRho64(ulong n)
{
// The EvenPerfectBitScanner path removes all factors of two before invoking Pollard-Rho, so this branch never executes
@@ -1045,13 +682,14 @@ public class MersenneDivisorCycles
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
private static ulong AdvancePolynomial(ulong x, ulong c, ulong modulus)
{
UInt128 value = (UInt128)x * x + c;
return (ulong)(value % modulus);
}
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static ulong BinaryGcd(ulong a, ulong b)
{
if (a == 0UL)
@@ -1083,6 +721,7 @@ public class MersenneDivisorCycles
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
private static ulong NextRandomUInt64()
{
Span<byte> buffer = stackalloc byte[8];
@@ -1090,30 +729,6 @@ public class MersenneDivisorCycles
return BinaryPrimitives.ReadUInt64LittleEndian(buffer);
}
private sealed class FactorPairValueComparer : IComparer<KeyValuePair<ulong, int>>
{
public static readonly FactorPairValueComparer Instance = new FactorPairValueComparer();
private FactorPairValueComparer()
{
}
public int Compare(KeyValuePair<ulong, int> x, KeyValuePair<ulong, int> y)
{
if (x.Key < y.Key)
{
return -1;
}
if (x.Key > y.Key)
{
return 1;
}
return 0;
}
}
public static (long nextPosition, long completeCount) FindLast(string path)
{
using Stream outputStream = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read, BufferSize10M, useAsync: false);
@@ -1122,6 +737,7 @@ public class MersenneDivisorCycles
{
count++;
}
return (outputStream.Position, count);
}
@@ -1182,7 +798,11 @@ public class MersenneDivisorCycles
// unrolled-hex calculator so the CPU generator matches
// the GPU benchmark leader for large divisors.
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(divisor);
ulong cycle = CalculateCycleLengthGpu(gpu, divisor, divisorData);
#if DEVICE_GPU || DEVICE_HYBRID
ulong cycle = CalculateCycleLength(gpu, divisor, divisorData);
#else
ulong cycle = CalculateCycleLength(divisor, divisorData);
#endif
localCycles[localCycleIndex++] = (divisor, cycle);
}
@@ -1347,98 +967,36 @@ public class MersenneDivisorCycles
return loaded;
}
public static ulong CalculateCycleLengthGpu(ulong divisor) => DivisorCycleKernels.CalculateCycleLengthGpu(divisor);
#if DEVICE_GPU
public static ulong CalculateCycleLength(ulong divisor) => DivisorCycleKernels.CalculateCycleLengthGpu(divisor);
#endif
public static ulong CalculateCycleLengthCpu(ulong divisor, in MontgomeryDivisorData divisorData, bool skipPrimeOrderHeuristic = false)
#if DEVICE_GPU || DEVICE_HYBRID
public static ulong CalculateCycleLength(PrimeOrderCalculatorAccelerator gpu, ulong divisor, in MontgomeryDivisorData divisorData, bool skipPrimeOrderHeuristic = false)
#else
public static ulong CalculateCycleLength(ulong divisor, in MontgomeryDivisorData divisorData, bool skipPrimeOrderHeuristic = false)
#endif
{
if (TryCalculateCycleLengthHeuristicCpu(divisor, divisorData, out ulong cycleLength, skipPrimeOrderHeuristic))
if (TryCalculateCycleLengthHeuristic(
#if DEVICE_GPU || DEVICE_HYBRID
gpu,
#endif
divisor,
divisorData,
out ulong cycleLength,
skipPrimeOrderHeuristic))
{
return cycleLength;
}
return CalculateCycleLengthFallback(divisor);
}
public static ulong CalculateCycleLengthGpu(PrimeOrderCalculatorAccelerator gpu, ulong divisor, in MontgomeryDivisorData divisorData, bool skipPrimeOrderHeuristic = false)
{
if (TryCalculateCycleLengthHeuristicGpu(gpu, divisor, divisorData, out ulong cycleLength, skipPrimeOrderHeuristic))
return cycleLength;
return CalculateCycleLengthFallback(divisor);
}
public static ulong CalculateCycleLengthHybrid(PrimeOrderCalculatorAccelerator gpu, ulong divisor, in MontgomeryDivisorData divisorData, bool skipPrimeOrderHeuristic = false)
{
if (TryCalculateCycleLengthHeuristicHybrid(gpu, divisor, divisorData, out ulong cycleLength, skipPrimeOrderHeuristic))
return cycleLength;
return CalculateCycleLengthFallback(divisor);
}
internal static bool TryCalculateCycleLengthHeuristicCpu(ulong divisor, in MontgomeryDivisorData divisorData, out ulong cycleLength, bool skipPrimeOrderHeuristic = false)
{
if ((divisor & (divisor - 1UL)) == 0UL)
{
cycleLength = 1UL;
return true;
}
if (divisor <= 3UL)
{
cycleLength = CalculateCycleLengthFallback(divisor);
return true;
}
if (!skipPrimeOrderHeuristic && HeuristicPrimeTester.IsPrimeCpu(divisor))
{
ulong computedOrder = PrimeOrderCalculator.CalculateCpu(
divisor,
previousOrder: null,
divisorData,
PrimeOrderCalculator.PrimeOrderCalculatorConfig.HeuristicDefault);
if (computedOrder != 0UL)
{
cycleLength = computedOrder;
return true;
}
}
cycleLength = 0UL;
return false;
}
internal static bool TryCalculateCycleLengthHeuristicHybrid(PrimeOrderCalculatorAccelerator gpu, ulong divisor, in MontgomeryDivisorData divisorData, out ulong cycleLength, bool skipPrimeOrderHeuristic = false)
{
if ((divisor & (divisor - 1UL)) == 0UL)
{
cycleLength = 1UL;
return true;
}
if (divisor <= 3UL)
{
cycleLength = CalculateCycleLengthFallback(divisor);
return true;
}
if (!skipPrimeOrderHeuristic && HeuristicPrimeTester.IsPrimeCpu(divisor))
{
ulong computedOrder = PrimeOrderCalculator.CalculateHybrid(
gpu,
divisor,
previousOrder: null,
divisorData,
PrimeOrderCalculator.PrimeOrderCalculatorConfig.HeuristicDefault);
if (computedOrder != 0UL)
{
cycleLength = computedOrder;
return true;
}
}
cycleLength = 0UL;
return false;
}
internal static bool TryCalculateCycleLengthHeuristicGpu(PrimeOrderCalculatorAccelerator gpu, ulong divisor, in MontgomeryDivisorData divisorData, out ulong cycleLength, bool skipPrimeOrderHeuristic = false)
#if DEVICE_GPU || DEVICE_HYBRID
internal static bool TryCalculateCycleLengthHeuristic(PrimeOrderCalculatorAccelerator gpu, ulong divisor, in MontgomeryDivisorData divisorData, out ulong cycleLength, bool skipPrimeOrderHeuristic = false)
#else
internal static bool TryCalculateCycleLengthHeuristic(ulong divisor, in MontgomeryDivisorData divisorData, out ulong cycleLength, bool skipPrimeOrderHeuristic = false)
#endif
{
if ((divisor & (divisor - 1UL)) == 0UL)
{
@@ -1452,6 +1010,7 @@ public class MersenneDivisorCycles
return true;
}
#if DEVICE_GPU
if (!skipPrimeOrderHeuristic && HeuristicPrimeTester.IsPrimeGpu(gpu, divisor))
{
ulong computedOrder = PrimeOrderCalculator.CalculateGpu(
@@ -1466,16 +1025,45 @@ public class MersenneDivisorCycles
return true;
}
}
#elif DEVICE_HYBRID
if (!skipPrimeOrderHeuristic && HeuristicPrimeTester.IsPrimeCpu(divisor))
{
ulong computedOrder = PrimeOrderCalculator.CalculateHybrid(
gpu,
divisor,
previousOrder: null,
divisorData,
PrimeOrderCalculator.PrimeOrderCalculatorConfig.HeuristicDefault);
if (computedOrder != 0UL)
{
cycleLength = computedOrder;
return true;
}
}
#else
if (!skipPrimeOrderHeuristic && HeuristicPrimeTester.IsPrimeCpu(divisor))
{
ulong computedOrder = PrimeOrderCalculator.CalculateCpu(
divisor,
previousOrder: null,
divisorData,
PrimeOrderCalculator.PrimeOrderCalculatorConfig.HeuristicDefault);
if (computedOrder != 0UL)
{
cycleLength = computedOrder;
return true;
}
}
#endif
cycleLength = 0UL;
return false;
}
private static ulong CalculateCycleLengthFallback(ulong divisor)
{
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
private static ulong CalculateCycleLengthFallback(ulong divisor) =>
// Otherwise, find order of 2 mod divisor using the shared unrolled-hex stepping sequence.
return divisor.CalculateMersenneDivisorCycleLengthUnrolledHexCpu();
}
divisor.CalculateMersenneDivisorCycleLengthUnrolledHexCpu();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void EnsureSmallBuffer()
@@ -270,7 +270,7 @@ public static class MersenneNumberDivisorByDivisorTester
ulong exponent,
in MontgomeryDivisorData divisorData,
out ulong cycleLength,
out bool primeOrderFailed) => MersenneDivisorCycles.TryCalculateCycleLengthForExponentCpu(
out bool primeOrderFailed) => MersenneDivisorCyclesCpu.TryCalculateCycleLengthForExponent(
divisor,
exponent,
divisorData,
@@ -284,7 +284,7 @@ public static class MersenneNumberDivisorByDivisorTester
ulong exponent,
in MontgomeryDivisorData divisorData,
out ulong cycleLength,
out bool primeOrderFailed) => MersenneDivisorCycles.TryCalculateCycleLengthForExponentHybrid(
out bool primeOrderFailed) => MersenneDivisorCyclesHybrid.TryCalculateCycleLengthForExponent(
gpu,
divisor,
exponent,
@@ -299,7 +299,7 @@ public static class MersenneNumberDivisorByDivisorTester
ulong exponent,
in MontgomeryDivisorData divisorData,
out ulong cycleLength,
out bool primeOrderFailed) => MersenneDivisorCycles.TryCalculateCycleLengthForExponentGpu(
out bool primeOrderFailed) => MersenneDivisorCyclesGpu.TryCalculateCycleLengthForExponent(
gpu,
divisor,
exponent,
@@ -311,7 +311,7 @@ public static class MersenneNumberDivisorByDivisorTester
public static ulong CalculateCycleLengthCpu(
ulong divisor,
in MontgomeryDivisorData divisorData,
bool skipPrimeOrderHeuristic) => MersenneDivisorCycles.CalculateCycleLengthCpu(
bool skipPrimeOrderHeuristic) => MersenneDivisorCyclesCpu.CalculateCycleLength(
divisor,
divisorData,
skipPrimeOrderHeuristic);
@@ -321,7 +321,7 @@ public static class MersenneNumberDivisorByDivisorTester
ulong divisor,
PrimeOrderCalculatorAccelerator gpu,
in MontgomeryDivisorData divisorData,
bool skipPrimeOrderHeuristic) => MersenneDivisorCycles.CalculateCycleLengthHybrid(
bool skipPrimeOrderHeuristic) => MersenneDivisorCyclesHybrid.CalculateCycleLength(
gpu,
divisor,
divisorData,
@@ -332,7 +332,7 @@ public static class MersenneNumberDivisorByDivisorTester
ulong divisor,
PrimeOrderCalculatorAccelerator gpu,
in MontgomeryDivisorData divisorData,
bool skipPrimeOrderHeuristic) => MersenneDivisorCycles.CalculateCycleLengthGpu(
bool skipPrimeOrderHeuristic) => MersenneDivisorCyclesGpu.CalculateCycleLength(
gpu,
divisor,
divisorData,
@@ -1232,3 +1232,4 @@ public static class MersenneNumberDivisorByDivisorTester
startGate.Dispose();
}
}
+4 -3
View File
@@ -583,7 +583,7 @@ public static class UInt128Extensions
ulong[] smallPrimesPow2 = PrimesGenerator.SmallPrimesPow2;
int i = 0, primesLength = smallPrimes.Length;
UInt128 cycle = MersenneDivisorCycles.GetCycleCpu(q);
UInt128 cycle = MersenneDivisorCyclesCpu.GetCycle(q);
// TODO: If the cache lacks this cycle, immediately schedule the configured device
// (GPU by default) to compute it on the fly and skip inserting it into the cache so
@@ -634,7 +634,7 @@ public static class UInt128Extensions
ulong[] smallPrimesPow2 = PrimesGenerator.SmallPrimesPow2;
int i = 0, primesLength = smallPrimes.Length;
UInt128 cycle = MersenneDivisorCycles.GetCycleGpu(gpu, q);
UInt128 cycle = MersenneDivisorCyclesGpu.GetCycle(gpu, q);
// TODO: If the cache lacks this cycle, immediately schedule the configured device
// (GPU by default) to compute it on the fly and skip inserting it into the cache so
// wide-order factoring can still leverage cycle stepping without breaching the
@@ -684,7 +684,7 @@ public static class UInt128Extensions
ulong[] smallPrimesPow2 = PrimesGenerator.SmallPrimesPow2;
int i = 0, primesLength = smallPrimes.Length;
UInt128 cycle = MersenneDivisorCycles.GetCycleHybrid(gpu, q);
UInt128 cycle = MersenneDivisorCyclesHybrid.GetCycle(gpu, q);
// TODO: If the cache lacks this cycle, immediately schedule the configured device
// (GPU by default) to compute it on the fly and skip inserting it into the cache so
// wide-order factoring can still leverage cycle stepping without breaching the
@@ -1013,3 +1013,4 @@ public static class UInt128Extensions
return result;
}
}
+7 -6
View File
@@ -111,7 +111,7 @@ public static partial class ULongExtensions
int i = 0, primesLength = smallPrimes.Length;
UInt128 q128 = q,
cycle = MersenneDivisorCycles.GetCycleCpu(q128);
cycle = MersenneDivisorCyclesCpu.GetCycle(q128);
// TODO: When the shared cycle snapshot cannot serve this divisor, trigger an on-demand
// GPU computation (respecting the configured device) without promoting the result into
// the cache so the order calculator still benefits from cycle stepping while keeping the
@@ -158,7 +158,7 @@ public static partial class ULongExtensions
int i = 0, primesLength = smallPrimes.Length;
UInt128 q128 = q,
cycle = MersenneDivisorCycles.GetCycleGpu(gpu, q128);
cycle = MersenneDivisorCyclesGpu.GetCycle(gpu, q128);
// TODO: When the shared cycle snapshot cannot serve this divisor, trigger an on-demand
// GPU computation (respecting the configured device) without promoting the result into
// the cache so the order calculator still benefits from cycle stepping while keeping the
@@ -205,7 +205,7 @@ public static partial class ULongExtensions
int i = 0, primesLength = smallPrimes.Length;
UInt128 q128 = q,
cycle = MersenneDivisorCycles.GetCycleHybrid(gpu, q128);
cycle = MersenneDivisorCyclesHybrid.GetCycle(gpu, q128);
// TODO: When the shared cycle snapshot cannot serve this divisor, trigger an on-demand
// GPU computation (respecting the configured device) without promoting the result into
// the cache so the order calculator still benefits from cycle stepping while keeping the
@@ -986,7 +986,7 @@ public static partial class ULongExtensions
for (; modulusCandidate <= modulus; modulusCandidate++)
{
cycle = MersenneDivisorCycles.GetCycleCpu(modulusCandidate);
cycle = MersenneDivisorCyclesCpu.GetCycle(modulusCandidate);
remainderForCandidate = cycle > zero
? PowModWithCycle(exponent, modulusCandidate, cycle)
: PowMod(exponent, modulusCandidate);
@@ -1030,7 +1030,7 @@ public static partial class ULongExtensions
for (; modulusCandidate <= modulus; modulusCandidate++)
{
cycle = MersenneDivisorCycles.GetCycleGpu(gpu, modulusCandidate);
cycle = MersenneDivisorCyclesGpu.GetCycle(gpu, modulusCandidate);
remainderForCandidate = cycle > zero
? PowModWithCycle(exponent, modulusCandidate, cycle)
: PowMod(exponent, modulusCandidate);
@@ -1074,7 +1074,7 @@ public static partial class ULongExtensions
for (; modulusCandidate <= modulus; modulusCandidate++)
{
cycle = MersenneDivisorCycles.GetCycleHybrid(gpu, modulusCandidate);
cycle = MersenneDivisorCyclesHybrid.GetCycle(gpu, modulusCandidate);
remainderForCandidate = cycle > zero
? PowModWithCycle(exponent, modulusCandidate, cycle)
: PowMod(exponent, modulusCandidate);
@@ -1310,3 +1310,4 @@ public static partial class ULongExtensions
}
}