Hybrid device mode implemented as the current --mersenne=bydivisor CPU execution path. CPU path is now limited to CPU calculations, only.
This commit is contained in:
1 parent
353a121d03
commit
941733905b
49 files changed
+4965
-1726
No files matched your search
@@ -398,7 +398,7 @@ public class PrimeOrderGpuHeuristicsTests
|
||||
PrimeOrderGpuHeuristics.OverflowRegistry[prime] = 0;
|
||||
|
||||
MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(prime);
|
||||
ulong result = PrimeOrderCalculator.Calculate(gpu, prime, null, divisorData, PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault, PrimeOrderCalculator.PrimeOrderHeuristicDevice.Gpu);
|
||||
ulong result = PrimeOrderCalculator.CalculateGpu(gpu, prime, null, divisorData, PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault);
|
||||
|
||||
result.Should().Be(3UL);
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ public class ULongExtensionsGpuTests
|
||||
public void Pow2ModWindowedGpu_matches_montgomery_cpu_for_known_values(ulong exponent, ulong modulus)
|
||||
{
|
||||
MontgomeryDivisorData divisor = MontgomeryDivisorDataPool.Shared.FromModulus(modulus);
|
||||
ulong expected = exponent.Pow2MontgomeryModWindowedCpu(divisor, keepMontgomery: false);
|
||||
ulong expected = exponent.Pow2MontgomeryModWindowedConvertToStandardCpu(divisor);
|
||||
|
||||
exponent.Pow2ModWindowedGpu(modulus).Should().Be(expected);
|
||||
}
|
||||
@@ -55,7 +55,7 @@ public class ULongExtensionsGpuTests
|
||||
MontgomeryDivisorData divisor = MontgomeryDivisorDataPool.Shared.FromModulus(modulus);
|
||||
foreach (ulong exponent in exponents)
|
||||
{
|
||||
ulong expected = exponent.Pow2MontgomeryModWindowedCpu(divisor, keepMontgomery: false);
|
||||
ulong expected = exponent.Pow2MontgomeryModWindowedConvertToStandardCpu(divisor);
|
||||
exponent.Pow2ModWindowedGpu(modulus).Should().Be(expected);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ public class MersenneDivisorCyclesGenerateGpuTests
|
||||
{
|
||||
expected.Should().Contain(pair.divisor);
|
||||
MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(pair.divisor);
|
||||
pair.cycle.Should().Be(MersenneDivisorCycles.CalculateCycleLength(gpu, pair.divisor, divisorData));
|
||||
pair.cycle.Should().Be(MersenneDivisorCycles.CalculateCycleLengthCpu(pair.divisor, divisorData));
|
||||
}
|
||||
}
|
||||
finally
|
||||
@@ -59,7 +59,6 @@ public class MersenneDivisorCyclesGenerateGpuTests
|
||||
public void Generate_produces_unique_cycles_for_expected_divisors()
|
||||
{
|
||||
string path = Path.GetTempFileName();
|
||||
var gpu = PrimeOrderCalculatorAccelerator.Rent(1);
|
||||
try
|
||||
{
|
||||
MersenneDivisorCycles.Generate(path, maxDivisor: 50UL, threads: 4);
|
||||
@@ -92,7 +91,7 @@ public class MersenneDivisorCyclesGenerateGpuTests
|
||||
{
|
||||
uniqueDivisors.Add(pair.divisor).Should().BeTrue();
|
||||
MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(pair.divisor);
|
||||
pair.cycle.Should().Be(MersenneDivisorCycles.CalculateCycleLength(gpu, pair.divisor, divisorData));
|
||||
pair.cycle.Should().Be(MersenneDivisorCycles.CalculateCycleLengthCpu(pair.divisor, divisorData));
|
||||
}
|
||||
|
||||
uniqueDivisors.Should().BeEquivalentTo(expected);
|
||||
@@ -102,7 +101,6 @@ public class MersenneDivisorCyclesGenerateGpuTests
|
||||
}
|
||||
finally
|
||||
{
|
||||
PrimeOrderCalculatorAccelerator.Return(gpu);
|
||||
if (File.Exists(path))
|
||||
{
|
||||
File.Delete(path);
|
||||
|
||||
@@ -23,7 +23,7 @@ public class MersenneDivisorCyclesTests
|
||||
try
|
||||
{
|
||||
MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(divisor);
|
||||
MersenneDivisorCycles.CalculateCycleLength(gpu, divisor, divisorData).Should().Be(expected);
|
||||
MersenneDivisorCycles.CalculateCycleLengthCpu(divisor, divisorData).Should().Be(expected);
|
||||
MersenneDivisorCycles.CalculateCycleLengthGpu(divisor).Should().Be(expected);
|
||||
}
|
||||
finally
|
||||
|
||||
@@ -46,17 +46,17 @@ public class MersenneNumberDivisorCpuTesterTests
|
||||
var session = tester.CreateDivisorSession(gpu);
|
||||
try
|
||||
{
|
||||
ulong[] primes = { 5UL, 7UL, 11UL, 13UL };
|
||||
ulong[] primes = [5UL, 7UL, 11UL, 13UL];
|
||||
byte[] hits = new byte[primes.Length];
|
||||
|
||||
ulong cycle23 = MersenneDivisorCycles.CalculateCycleLength(gpu, 23UL, MontgomeryDivisorDataPool.Shared.FromModulus(23UL));
|
||||
ulong cycle23 = MersenneDivisorCycles.CalculateCycleLengthCpu(23UL, MontgomeryDivisorDataPool.Shared.FromModulus(23UL));
|
||||
session.CheckDivisor(23UL, MontgomeryDivisorDataPool.Shared.FromModulus(23UL), cycle23, primes, hits);
|
||||
hits.Should().ContainInOrder(new byte[] { 0, 0, 1, 0 });
|
||||
hits.Should().ContainInOrder([0, 0, 1, 0]);
|
||||
|
||||
Array.Fill(hits, (byte)0);
|
||||
ulong cycle31 = MersenneDivisorCycles.CalculateCycleLength(gpu, 31UL, MontgomeryDivisorDataPool.Shared.FromModulus(31UL));
|
||||
ulong cycle31 = MersenneDivisorCycles.CalculateCycleLengthCpu(31UL, MontgomeryDivisorDataPool.Shared.FromModulus(31UL));
|
||||
session.CheckDivisor(31UL, MontgomeryDivisorDataPool.Shared.FromModulus(31UL), cycle31, primes, hits);
|
||||
hits.Should().ContainInOrder(new byte[] { 1, 0, 0, 0 });
|
||||
hits.Should().ContainInOrder([1, 0, 0, 0]);
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -76,14 +76,14 @@ public class MersenneNumberDivisorCpuTesterTests
|
||||
var session = tester.CreateDivisorSession(gpu);
|
||||
try
|
||||
{
|
||||
ulong[] exponents = { 6UL, 7UL, 9UL, 10UL, 12UL };
|
||||
ulong[] exponents = [6UL, 7UL, 9UL, 10UL, 12UL];
|
||||
byte[] hits = new byte[exponents.Length];
|
||||
|
||||
MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(7UL);
|
||||
ulong cycle = MersenneDivisorCycles.CalculateCycleLength(gpu, 7UL, divisorData);
|
||||
ulong cycle = MersenneDivisorCycles.CalculateCycleLengthCpu(7UL, divisorData);
|
||||
session.CheckDivisor(7UL, divisorData, cycle, exponents, hits);
|
||||
|
||||
hits.Should().Equal(new byte[] { 1, 0, 1, 0, 1 });
|
||||
hits.Should().Equal([1, 0, 1, 0, 1]);
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -103,14 +103,14 @@ public class MersenneNumberDivisorCpuTesterTests
|
||||
var session = tester.CreateDivisorSession(gpu);
|
||||
try
|
||||
{
|
||||
ulong[] exponents = { 10UL, 11UL, 20UL, 21UL, 30UL };
|
||||
ulong[] exponents = [10UL, 11UL, 20UL, 21UL, 30UL];
|
||||
byte[] hits = new byte[exponents.Length];
|
||||
|
||||
MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(11UL);
|
||||
ulong cycle = MersenneDivisorCycles.CalculateCycleLength(gpu, 11UL, divisorData);
|
||||
ulong cycle = MersenneDivisorCycles.CalculateCycleLengthCpu(11UL, divisorData);
|
||||
session.CheckDivisor(11UL, divisorData, cycle, exponents, hits);
|
||||
|
||||
hits.Should().Equal(new byte[] { 1, 0, 1, 0, 1 });
|
||||
hits.Should().Equal([1, 0, 1, 0, 1]);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
||||
@@ -128,7 +128,7 @@ public class MersenneNumberDivisorGpuTesterTests
|
||||
|
||||
tester.DivisorLimit.Should().Be(0UL);
|
||||
|
||||
ulong[] primes = { 31UL, 37UL };
|
||||
ulong[] primes = [31UL, 37UL];
|
||||
ulong[] allowed = new ulong[primes.Length];
|
||||
|
||||
tester.PrepareCandidates(primes, allowed);
|
||||
@@ -228,12 +228,12 @@ public class MersenneNumberDivisorGpuTesterTests
|
||||
var session = tester.CreateDivisorSession(gpu);
|
||||
try
|
||||
{
|
||||
ulong[] primes = { 31UL, 37UL, 41UL };
|
||||
ulong[] primes = [31UL, 37UL, 41UL];
|
||||
byte[] hits = new byte[primes.Length];
|
||||
|
||||
session.CheckDivisor(223UL, MontgomeryDivisorDataPool.Shared.FromModulus(223UL), 0UL, primes, hits);
|
||||
|
||||
hits.Should().ContainInOrder(new byte[] { 0, 1, 0 });
|
||||
hits.Should().ContainInOrder([0, 1, 0]);
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -253,17 +253,17 @@ public class MersenneNumberDivisorGpuTesterTests
|
||||
var session = tester.CreateDivisorSession(gpu);
|
||||
try
|
||||
{
|
||||
ulong[] primes = { 31UL, 37UL, 41UL, 43UL };
|
||||
ulong[] primes = [31UL, 37UL, 41UL, 43UL];
|
||||
byte[] hits = new byte[primes.Length];
|
||||
|
||||
ulong cycle223 = MersenneDivisorCycles.CalculateCycleLength(gpu, 223UL, MontgomeryDivisorDataPool.Shared.FromModulus(223UL));
|
||||
ulong cycle223 = MersenneDivisorCycles.CalculateCycleLengthGpu(gpu, 223UL, MontgomeryDivisorDataPool.Shared.FromModulus(223UL));
|
||||
session.CheckDivisor(223UL, MontgomeryDivisorDataPool.Shared.FromModulus(223UL), cycle223, primes, hits);
|
||||
hits.Should().ContainInOrder(new byte[] { 0, 1, 0, 0 });
|
||||
hits.Should().ContainInOrder([0, 1, 0, 0]);
|
||||
|
||||
Array.Fill(hits, (byte)0);
|
||||
ulong cycle13367 = MersenneDivisorCycles.CalculateCycleLength(gpu, 13367UL, MontgomeryDivisorDataPool.Shared.FromModulus(13367UL));
|
||||
ulong cycle13367 = MersenneDivisorCycles.CalculateCycleLengthGpu(gpu, 13367UL, MontgomeryDivisorDataPool.Shared.FromModulus(13367UL));
|
||||
session.CheckDivisor(13367UL, MontgomeryDivisorDataPool.Shared.FromModulus(13367UL), cycle13367, primes, hits);
|
||||
hits.Should().ContainInOrder(new byte[] { 0, 0, 1, 0 });
|
||||
hits.Should().ContainInOrder([0, 0, 1, 0]);
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -287,13 +287,13 @@ public class MersenneNumberDivisorGpuTesterTests
|
||||
var session = tester.CreateDivisorSession(gpu);
|
||||
try
|
||||
{
|
||||
ulong[] primes = { 31UL, 37UL, 41UL, 43UL, 47UL };
|
||||
ulong[] primes = [31UL, 37UL, 41UL, 43UL, 47UL];
|
||||
byte[] hits = new byte[primes.Length];
|
||||
|
||||
ulong cycle223 = MersenneDivisorCycles.CalculateCycleLength(gpu, 223UL, MontgomeryDivisorDataPool.Shared.FromModulus(223UL));
|
||||
ulong cycle223 = MersenneDivisorCycles.CalculateCycleLengthGpu(gpu, 223UL, MontgomeryDivisorDataPool.Shared.FromModulus(223UL));
|
||||
session.CheckDivisor(223UL, MontgomeryDivisorDataPool.Shared.FromModulus(223UL), cycle223, primes, hits);
|
||||
|
||||
hits.Should().ContainInOrder(new byte[] { 0, 1, 0, 0, 0 });
|
||||
hits.Should().ContainInOrder([0, 1, 0, 0, 0]);
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -316,15 +316,15 @@ public class MersenneNumberDivisorGpuTesterTests
|
||||
var session = tester.CreateDivisorSession(gpu);
|
||||
try
|
||||
{
|
||||
ulong[] exponents = { 6UL, 7UL, 9UL, 10UL, 12UL };
|
||||
ulong[] exponents = [6UL, 7UL, 9UL, 10UL, 12UL];
|
||||
byte[] hits = new byte[exponents.Length];
|
||||
|
||||
MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(7UL);
|
||||
ulong cycle = MersenneDivisorCycles.CalculateCycleLength(gpu, 7UL, divisorData);
|
||||
ulong cycle = MersenneDivisorCycles.CalculateCycleLengthGpu(gpu, 7UL, divisorData);
|
||||
|
||||
session.CheckDivisor(7UL, divisorData, cycle, exponents, hits);
|
||||
|
||||
hits.Should().Equal(new byte[] { 1, 0, 1, 0, 1 });
|
||||
hits.Should().Equal([1, 0, 1, 0, 1]);
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -347,15 +347,15 @@ public class MersenneNumberDivisorGpuTesterTests
|
||||
var session = tester.CreateDivisorSession(gpu);
|
||||
try
|
||||
{
|
||||
ulong[] exponents = { 10UL, 11UL, 20UL, 21UL, 30UL };
|
||||
ulong[] exponents = [10UL, 11UL, 20UL, 21UL, 30UL];
|
||||
byte[] hits = new byte[exponents.Length];
|
||||
|
||||
MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(11UL);
|
||||
ulong cycle = MersenneDivisorCycles.CalculateCycleLength(gpu, 11UL, divisorData);
|
||||
ulong cycle = MersenneDivisorCycles.CalculateCycleLengthGpu(gpu, 11UL, divisorData);
|
||||
|
||||
session.CheckDivisor(11UL, divisorData, cycle, exponents, hits);
|
||||
|
||||
hits.Should().Equal(new byte[] { 1, 0, 1, 0, 1 });
|
||||
hits.Should().Equal([1, 0, 1, 0, 1]);
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -382,7 +382,7 @@ public class MersenneNumberDivisorGpuTesterTests
|
||||
ulong[] patchedSmall = new ulong[PerfectNumberConstants.MaxQForDivisorCycles + 1];
|
||||
|
||||
MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(191UL);
|
||||
patchedSmall[191] = MersenneDivisorCycles.CalculateCycleLength(gpu, 191UL, divisorData);
|
||||
patchedSmall[191] = MersenneDivisorCycles.CalculateCycleLengthGpu(gpu, 191UL, divisorData);
|
||||
|
||||
tableField.SetValue(cycles, patchedTable);
|
||||
smallCyclesField.SetValue(cycles, patchedSmall);
|
||||
@@ -423,13 +423,13 @@ public class MersenneNumberDivisorGpuTesterTests
|
||||
var session = tester.CreateDivisorSession(gpu);
|
||||
try
|
||||
{
|
||||
ulong[] primes = { 31UL, 37UL, 41UL, 43UL, 47UL };
|
||||
ulong[] primes = [31UL, 37UL, 41UL, 43UL, 47UL];
|
||||
byte[] hits = new byte[primes.Length];
|
||||
|
||||
ulong cycle223 = MersenneDivisorCycles.CalculateCycleLength(gpu, 223UL, MontgomeryDivisorDataPool.Shared.FromModulus(223UL));
|
||||
ulong cycle223 = MersenneDivisorCycles.CalculateCycleLengthGpu(gpu, 223UL, MontgomeryDivisorDataPool.Shared.FromModulus(223UL));
|
||||
session.CheckDivisor(223UL, MontgomeryDivisorDataPool.Shared.FromModulus(223UL), cycle223, primes, hits);
|
||||
|
||||
hits.Should().ContainInOrder(new byte[] { 0, 1, 0, 0, 0 });
|
||||
hits.Should().ContainInOrder([0, 1, 0, 0, 0]);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
||||
@@ -25,15 +25,8 @@ public class MersenneNumberResidueCpuTesterTests
|
||||
private static void RunCase(MersenneNumberResidueCpuTester tester, ulong exponent, ulong maxK, bool expectedPrime)
|
||||
{
|
||||
bool isPrime = true;
|
||||
var gpu = PrimeOrderCalculatorAccelerator.Rent(1);
|
||||
try
|
||||
{
|
||||
tester.Scan(gpu, exponent, (UInt128)exponent << 1, GetLastDigit(exponent), (UInt128)maxK, ref isPrime);
|
||||
isPrime.Should().Be(expectedPrime);
|
||||
}
|
||||
finally
|
||||
{
|
||||
PrimeOrderCalculatorAccelerator.Return(gpu);
|
||||
}
|
||||
tester.Scan(exponent, (UInt128)exponent << 1, GetLastDigit(exponent), (UInt128)maxK, ref isPrime);
|
||||
|
||||
isPrime.Should().Be(expectedPrime);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using FluentAssertions;
|
||||
using PerfectNumbers.Core.Gpu;
|
||||
using PerfectNumbers.Core.Gpu.Accelerators;
|
||||
using Xunit;
|
||||
using UInt128 = System.UInt128;
|
||||
|
||||
@@ -7,27 +8,36 @@ namespace PerfectNumbers.Core.Tests;
|
||||
|
||||
public class MersenneNumberResidueGpuTesterTests
|
||||
{
|
||||
private static LastDigit GetLastDigit(ulong exponent) => (exponent & 3UL) == 3UL ? LastDigit.Seven : LastDigit.One;
|
||||
private static LastDigit GetLastDigit(ulong exponent) => (exponent & 3UL) == 3UL ? LastDigit.Seven : LastDigit.One;
|
||||
|
||||
[Theory]
|
||||
[InlineData(false)]
|
||||
[InlineData(true)]
|
||||
[Trait("Category", "Fast")]
|
||||
public void Scan_handles_various_prime_exponents(bool useGpuOrder)
|
||||
{
|
||||
var tester = new MersenneNumberResidueGpuTester(useGpuOrder);
|
||||
[Theory]
|
||||
[InlineData(false)]
|
||||
[InlineData(true)]
|
||||
[Trait("Category", "Fast")]
|
||||
public void Scan_handles_various_prime_exponents(bool useGpuOrder)
|
||||
{
|
||||
var tester = new MersenneNumberResidueGpuTester(useGpuOrder);
|
||||
|
||||
RunCase(tester, 23UL, 2UL, expectedPrime: false);
|
||||
RunCase(tester, 29UL, 37UL, expectedPrime: false);
|
||||
RunCase(tester, 31UL, 1_000UL, expectedPrime: true);
|
||||
RunCase(tester, 89UL, 1_001UL, expectedPrime: true);
|
||||
RunCase(tester, 127UL, 1_001UL, expectedPrime: true);
|
||||
}
|
||||
RunCase(tester, 23UL, 2UL, expectedPrime: false);
|
||||
RunCase(tester, 29UL, 37UL, expectedPrime: false);
|
||||
RunCase(tester, 31UL, 1_000UL, expectedPrime: true);
|
||||
RunCase(tester, 89UL, 1_001UL, expectedPrime: true);
|
||||
RunCase(tester, 127UL, 1_001UL, expectedPrime: true);
|
||||
}
|
||||
|
||||
private static void RunCase(MersenneNumberResidueGpuTester tester, ulong exponent, ulong maxK, bool expectedPrime)
|
||||
{
|
||||
bool isPrime = true;
|
||||
tester.Scan(exponent, (UInt128)exponent << 1, GetLastDigit(exponent), (UInt128)maxK, ref isPrime);
|
||||
isPrime.Should().Be(expectedPrime);
|
||||
}
|
||||
private static void RunCase(MersenneNumberResidueGpuTester tester, ulong exponent, ulong maxK, bool expectedPrime)
|
||||
{
|
||||
bool isPrime = true;
|
||||
var gpu = PrimeOrderCalculatorAccelerator.Rent(1);
|
||||
try
|
||||
{
|
||||
tester.Scan(gpu, exponent, (UInt128)exponent << 1, GetLastDigit(exponent), (UInt128)maxK, ref isPrime);
|
||||
|
||||
isPrime.Should().Be(expectedPrime);
|
||||
}
|
||||
finally
|
||||
{
|
||||
PrimeOrderCalculatorAccelerator.Return(gpu);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,10 +27,27 @@ public class MersenneNumberTesterTests
|
||||
|
||||
[Theory]
|
||||
[InlineData(125UL)]
|
||||
public void WarmUpOrders_populates_cache_without_affecting_results(ulong p)
|
||||
public void WarmUpOrdersCpu_populates_cache_without_affecting_results(ulong p)
|
||||
{
|
||||
var tester = new MersenneNumberTester(useOrderCache: true, useGpuOrder: true);
|
||||
tester.WarmUpOrders(p, 1_000UL);
|
||||
tester.WarmUpOrdersCpu(p, 1_000UL);
|
||||
var gpu = PrimeOrderCalculatorAccelerator.Rent(1);
|
||||
try
|
||||
{
|
||||
tester.IsMersennePrime(gpu, p).Should().BeFalse();
|
||||
}
|
||||
finally
|
||||
{
|
||||
PrimeOrderCalculatorAccelerator.Return(gpu);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(125UL)]
|
||||
public void WarmUpOrdersGpu_populates_cache_without_affecting_results(ulong p)
|
||||
{
|
||||
var tester = new MersenneNumberTester(useOrderCache: true, useGpuOrder: true);
|
||||
tester.WarmUpOrdersGpu(p, 1_000UL);
|
||||
var gpu = PrimeOrderCalculatorAccelerator.Rent(1);
|
||||
try
|
||||
{
|
||||
@@ -45,12 +62,20 @@ public class MersenneNumberTesterTests
|
||||
[Theory]
|
||||
[InlineData(125UL, true)]
|
||||
[InlineData(127UL, false)]
|
||||
public void SharesFactorWithExponentMinusOne_detects_common_factors(ulong p, bool expected)
|
||||
public void SharesFactorWithExponentMinusOneCpu_detects_common_factors(ulong p, bool expected)
|
||||
{
|
||||
p.SharesFactorWithExponentMinusOneCpu().Should().Be(expected);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(125UL, true)]
|
||||
[InlineData(127UL, false)]
|
||||
public void SharesFactorWithExponentMinusOneGpu_detects_common_factors(ulong p, bool expected)
|
||||
{
|
||||
var gpu = PrimeOrderCalculatorAccelerator.Rent(1);
|
||||
try
|
||||
{
|
||||
p.SharesFactorWithExponentMinusOne(gpu).Should().Be(expected);
|
||||
p.SharesFactorWithExponentMinusOneGpu(gpu).Should().Be(expected);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
||||
@@ -8,16 +8,26 @@ namespace PerfectNumbers.Core.Tests;
|
||||
public class ModResidueTrackerTests
|
||||
{
|
||||
[Fact]
|
||||
public void IsDivisible_advances_residue_for_identity()
|
||||
public void IsDivisibleCpu_advances_residue_for_identity()
|
||||
{
|
||||
var tracker = new ModResidueTracker(ResidueModel.Identity);
|
||||
|
||||
tracker.IsDivisibleCpu(5, 2).Should().BeFalse();
|
||||
tracker.IsDivisibleCpu(6, 2).Should().BeTrue();
|
||||
tracker.IsDivisibleCpu(7, 2).Should().BeFalse();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsDivisibleGpu_advances_residue_for_identity()
|
||||
{
|
||||
var tracker = new ModResidueTracker(ResidueModel.Identity);
|
||||
|
||||
var gpu = PrimeOrderCalculatorAccelerator.Rent(1);
|
||||
try
|
||||
{
|
||||
tracker.IsDivisible(gpu, 5, 2).Should().BeFalse();
|
||||
tracker.IsDivisible(gpu, 6, 2).Should().BeTrue();
|
||||
tracker.IsDivisible(gpu, 7, 2).Should().BeFalse();
|
||||
tracker.IsDivisibleGpu(gpu, 5, 2).Should().BeFalse();
|
||||
tracker.IsDivisibleGpu(gpu, 6, 2).Should().BeTrue();
|
||||
tracker.IsDivisibleGpu(gpu, 7, 2).Should().BeFalse();
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -31,14 +41,26 @@ public class ModResidueTrackerTests
|
||||
[InlineData(5UL, 7UL, false)]
|
||||
[InlineData(11UL, 23UL, true)]
|
||||
[InlineData(11UL, 31UL, false)]
|
||||
public void IsDivisible_handles_mersenne_model(ulong p, ulong divisor, bool expected)
|
||||
public void IsDivisibleCpu_handles_mersenne_model(ulong p, ulong divisor, bool expected)
|
||||
{
|
||||
var tracker = new ModResidueTracker(ResidueModel.Mersenne);
|
||||
tracker.IsDivisibleCpu(p, divisor).Should().Be(expected);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(3UL, 7UL, true)]
|
||||
[InlineData(5UL, 31UL, true)]
|
||||
[InlineData(5UL, 7UL, false)]
|
||||
[InlineData(11UL, 23UL, true)]
|
||||
[InlineData(11UL, 31UL, false)]
|
||||
public void IsDivisibleGpu_handles_mersenne_model(ulong p, ulong divisor, bool expected)
|
||||
{
|
||||
var tracker = new ModResidueTracker(ResidueModel.Mersenne);
|
||||
var gpu = PrimeOrderCalculatorAccelerator.Rent(1);
|
||||
|
||||
try
|
||||
{
|
||||
tracker.IsDivisible(gpu, p, divisor).Should().Be(expected);
|
||||
tracker.IsDivisibleGpu(gpu, p, divisor).Should().Be(expected);
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -47,7 +69,31 @@ public class ModResidueTrackerTests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MergeOrAppend_tracks_existing_and_new_divisors()
|
||||
public void MergeOrAppendCpu_tracks_existing_and_new_divisors()
|
||||
{
|
||||
var tracker = new ModResidueTracker(ResidueModel.Identity);
|
||||
|
||||
tracker.BeginMerge(10);
|
||||
tracker.MergeOrAppendCpu(10, 3, out bool d3).Should().BeTrue();
|
||||
d3.Should().BeFalse();
|
||||
tracker.MergeOrAppendCpu(10, 5, out bool d5).Should().BeTrue();
|
||||
d5.Should().BeTrue();
|
||||
|
||||
tracker.BeginMerge(10);
|
||||
tracker.MergeOrAppendCpu(10, 4, out bool d4).Should().BeTrue();
|
||||
d4.Should().BeFalse();
|
||||
|
||||
tracker.BeginMerge(11);
|
||||
tracker.MergeOrAppendCpu(11, 3, out d3).Should().BeTrue();
|
||||
d3.Should().BeFalse();
|
||||
tracker.MergeOrAppendCpu(11, 4, out d4).Should().BeTrue();
|
||||
d4.Should().BeFalse();
|
||||
tracker.MergeOrAppendCpu(11, 5, out d5).Should().BeTrue();
|
||||
d5.Should().BeFalse();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MergeOrAppendGpu_tracks_existing_and_new_divisors()
|
||||
{
|
||||
var tracker = new ModResidueTracker(ResidueModel.Identity);
|
||||
var gpu = PrimeOrderCalculatorAccelerator.Rent(1);
|
||||
@@ -55,21 +101,21 @@ public class ModResidueTrackerTests
|
||||
try
|
||||
{
|
||||
tracker.BeginMerge(10);
|
||||
tracker.MergeOrAppend(gpu, 10, 3, out bool d3).Should().BeTrue();
|
||||
tracker.MergeOrAppendGpu(gpu, 10, 3, out bool d3).Should().BeTrue();
|
||||
d3.Should().BeFalse();
|
||||
tracker.MergeOrAppend(gpu, 10, 5, out bool d5).Should().BeTrue();
|
||||
tracker.MergeOrAppendGpu(gpu, 10, 5, out bool d5).Should().BeTrue();
|
||||
d5.Should().BeTrue();
|
||||
|
||||
tracker.BeginMerge(10);
|
||||
tracker.MergeOrAppend(gpu, 10, 4, out bool d4).Should().BeTrue();
|
||||
tracker.MergeOrAppendGpu(gpu, 10, 4, out bool d4).Should().BeTrue();
|
||||
d4.Should().BeFalse();
|
||||
|
||||
tracker.BeginMerge(11);
|
||||
tracker.MergeOrAppend(gpu, 11, 3, out d3).Should().BeTrue();
|
||||
tracker.MergeOrAppendGpu(gpu, 11, 3, out d3).Should().BeTrue();
|
||||
d3.Should().BeFalse();
|
||||
tracker.MergeOrAppend(gpu, 11, 4, out d4).Should().BeTrue();
|
||||
tracker.MergeOrAppendGpu(gpu, 11, 4, out d4).Should().BeTrue();
|
||||
d4.Should().BeFalse();
|
||||
tracker.MergeOrAppend(gpu, 11, 5, out d5).Should().BeTrue();
|
||||
tracker.MergeOrAppendGpu(gpu, 11, 5, out d5).Should().BeTrue();
|
||||
d5.Should().BeFalse();
|
||||
}
|
||||
finally
|
||||
@@ -79,15 +125,26 @@ public class ModResidueTrackerTests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsDivisible_requires_non_decreasing_numbers()
|
||||
public void IsDivisibleCpu_requires_non_decreasing_numbers()
|
||||
{
|
||||
var tracker = new ModResidueTracker(ResidueModel.Identity);
|
||||
|
||||
tracker.IsDivisibleCpu(5, 2);
|
||||
|
||||
Action act = () => tracker.IsDivisibleCpu(4, 2);
|
||||
act.Should().Throw<InvalidOperationException>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsDivisibleGpu_requires_non_decreasing_numbers()
|
||||
{
|
||||
var tracker = new ModResidueTracker(ResidueModel.Identity);
|
||||
var gpu = PrimeOrderCalculatorAccelerator.Rent(1);
|
||||
try
|
||||
{
|
||||
tracker.IsDivisible(gpu, 5, 2);
|
||||
tracker.IsDivisibleGpu(gpu, 5, 2);
|
||||
|
||||
Action act = () => tracker.IsDivisible(gpu, 4, 2);
|
||||
Action act = () => tracker.IsDivisibleGpu(gpu, 4, 2);
|
||||
act.Should().Throw<InvalidOperationException>();
|
||||
}
|
||||
finally
|
||||
|
||||
@@ -45,13 +45,12 @@ public class PrimeOrderCalculatorTests
|
||||
ulong expected = ComputeOrderByDoubling(prime);
|
||||
var gpu = PrimeOrderCalculatorAccelerator.Rent(1);
|
||||
|
||||
ulong result = PrimeOrderCalculator.Calculate(
|
||||
ulong result = PrimeOrderCalculator.CalculateGpu(
|
||||
gpu,
|
||||
prime,
|
||||
previousOrder: null,
|
||||
MontgomeryDivisorDataPool.Shared.FromModulus(prime),
|
||||
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault,
|
||||
PrimeOrderCalculator.PrimeOrderHeuristicDevice.Gpu);
|
||||
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault);
|
||||
|
||||
PrimeOrderCalculatorAccelerator.Return(gpu);
|
||||
|
||||
@@ -66,21 +65,19 @@ public class PrimeOrderCalculatorTests
|
||||
ulong previousOrder = ComputeOrderByDoubling(previousPrime);
|
||||
|
||||
var gpu = PrimeOrderCalculatorAccelerator.Rent(1);
|
||||
ulong heuristic = PrimeOrderCalculator.Calculate(
|
||||
ulong heuristic = PrimeOrderCalculator.CalculateGpu(
|
||||
gpu,
|
||||
prime,
|
||||
previousOrder,
|
||||
MontgomeryDivisorDataPool.Shared.FromModulus(prime),
|
||||
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault,
|
||||
PrimeOrderCalculator.PrimeOrderHeuristicDevice.Gpu);
|
||||
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault);
|
||||
|
||||
ulong strict = PrimeOrderCalculator.Calculate(
|
||||
ulong strict = PrimeOrderCalculator.CalculateGpu(
|
||||
gpu,
|
||||
prime,
|
||||
previousOrder: null,
|
||||
MontgomeryDivisorDataPool.Shared.FromModulus(prime),
|
||||
PrimeOrderCalculator.PrimeOrderSearchConfig.StrictDefault,
|
||||
PrimeOrderCalculator.PrimeOrderHeuristicDevice.Gpu);
|
||||
PrimeOrderCalculator.PrimeOrderSearchConfig.StrictDefault);
|
||||
|
||||
PrimeOrderCalculatorAccelerator.Return(gpu);
|
||||
|
||||
@@ -94,13 +91,12 @@ public class PrimeOrderCalculatorTests
|
||||
public void Calculate_handles_trivial_primes(ulong prime, ulong expectedOrder)
|
||||
{
|
||||
var gpu = PrimeOrderCalculatorAccelerator.Rent(1);
|
||||
ulong result = PrimeOrderCalculator.Calculate(
|
||||
ulong result = PrimeOrderCalculator.CalculateGpu(
|
||||
gpu,
|
||||
prime,
|
||||
previousOrder: null,
|
||||
MontgomeryDivisorDataPool.Shared.FromModulus(prime),
|
||||
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault,
|
||||
PrimeOrderCalculator.PrimeOrderHeuristicDevice.Gpu);
|
||||
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault);
|
||||
|
||||
PrimeOrderCalculatorAccelerator.Return(gpu);
|
||||
result.Should().Be(expectedOrder);
|
||||
@@ -117,13 +113,12 @@ public class PrimeOrderCalculatorTests
|
||||
mode: PrimeOrderCalculator.PrimeOrderMode.Heuristic);
|
||||
|
||||
var gpu = PrimeOrderCalculatorAccelerator.Rent(1);
|
||||
ulong result = PrimeOrderCalculator.Calculate(
|
||||
ulong result = PrimeOrderCalculator.CalculateGpu(
|
||||
gpu,
|
||||
prime: 13UL,
|
||||
previousOrder: null,
|
||||
MontgomeryDivisorDataPool.Shared.FromModulus(13UL),
|
||||
config,
|
||||
PrimeOrderCalculator.PrimeOrderHeuristicDevice.Gpu);
|
||||
config);
|
||||
|
||||
PrimeOrderCalculatorAccelerator.Return(gpu);
|
||||
result.Should().Be(ComputeOrderByDoubling(13UL));
|
||||
@@ -143,13 +138,12 @@ public class PrimeOrderCalculatorTests
|
||||
try
|
||||
{
|
||||
MontgomeryDivisorData divisorData = MontgomeryDivisorDataPool.Shared.FromModulus(239UL);
|
||||
ulong heuristic = PrimeOrderCalculator.Calculate(
|
||||
ulong heuristic = PrimeOrderCalculator.CalculateGpu(
|
||||
gpu,
|
||||
prime: 239UL,
|
||||
previousOrder: null,
|
||||
divisorData,
|
||||
heuristicConfig,
|
||||
PrimeOrderCalculator.PrimeOrderHeuristicDevice.Gpu);
|
||||
heuristicConfig);
|
||||
|
||||
heuristic.Should().Be(ComputeOrderByDoubling(239UL));
|
||||
|
||||
@@ -159,13 +153,12 @@ public class PrimeOrderCalculatorTests
|
||||
maxPowChecks: 1,
|
||||
mode: PrimeOrderCalculator.PrimeOrderMode.Strict);
|
||||
|
||||
ulong strict = PrimeOrderCalculator.Calculate(
|
||||
ulong strict = PrimeOrderCalculator.CalculateGpu(
|
||||
gpu,
|
||||
prime: 239UL,
|
||||
previousOrder: null,
|
||||
divisorData,
|
||||
strictConfig,
|
||||
PrimeOrderCalculator.PrimeOrderHeuristicDevice.Gpu);
|
||||
strictConfig);
|
||||
|
||||
strict.Should().Be(heuristic);
|
||||
}
|
||||
@@ -182,12 +175,11 @@ public class PrimeOrderCalculatorTests
|
||||
UInt128 prime = UInt128.Parse("18446744073709641691");
|
||||
|
||||
var gpu = PrimeOrderCalculatorAccelerator.Rent(1);
|
||||
UInt128 result = PrimeOrderCalculator.Calculate(
|
||||
UInt128 result = PrimeOrderCalculator.CalculateGpu(
|
||||
gpu,
|
||||
prime,
|
||||
previousOrder: null,
|
||||
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault,
|
||||
PrimeOrderCalculator.PrimeOrderHeuristicDevice.Gpu);
|
||||
PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault);
|
||||
|
||||
PrimeOrderCalculatorAccelerator.Return(gpu);
|
||||
result.Should().Be((UInt128)1229782938247309446UL);
|
||||
@@ -201,7 +193,7 @@ public class PrimeOrderCalculatorTests
|
||||
var gpu = PrimeOrderCalculatorAccelerator.Rent(1);
|
||||
try
|
||||
{
|
||||
var mersenneDivisorCycles = MersenneDivisorCycles.GetCycle(gpu, prime).Should().Be((UInt128)1229782938247309446UL);
|
||||
var mersenneDivisorCycles = MersenneDivisorCycles.GetCycleGpu(gpu, prime).Should().Be((UInt128)1229782938247309446UL);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
||||
@@ -51,14 +51,26 @@ public class UInt128ExtensionsTests
|
||||
[InlineData(3UL)]
|
||||
[InlineData(5UL)]
|
||||
[InlineData(7UL)]
|
||||
public void CalculateOrder_matches_naive(ulong q)
|
||||
public void CalculateOrderCpu_matches_naive(ulong q)
|
||||
{
|
||||
UInt128 q128 = q;
|
||||
ulong expected = NaiveOrder(q);
|
||||
q128.CalculateOrderCpu().Should().Be(expected);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[Trait("Category", "Fast")]
|
||||
[InlineData(3UL)]
|
||||
[InlineData(5UL)]
|
||||
[InlineData(7UL)]
|
||||
public void CalculateOrderGpu_matches_naive(ulong q)
|
||||
{
|
||||
UInt128 q128 = q;
|
||||
ulong expected = NaiveOrder(q);
|
||||
var gpu = PrimeOrderCalculatorAccelerator.Rent(1);
|
||||
try
|
||||
{
|
||||
q128.CalculateOrder(gpu).Should().Be(expected);
|
||||
q128.CalculateOrderGpu(gpu).Should().Be(expected);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
||||
@@ -68,14 +68,27 @@ public class ULongExtensionsTests
|
||||
[InlineData(5UL)]
|
||||
[InlineData(7UL)]
|
||||
[InlineData(11UL)]
|
||||
public void CalculateOrder_matches_naive_algorithm(ulong q)
|
||||
public void CalculateOrderCpu_matches_naive_algorithm(ulong q)
|
||||
{
|
||||
ulong expected = NaiveOrder(q);
|
||||
|
||||
q.CalculateOrderCpu().Should().Be(expected);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[Trait("Category", "Fast")]
|
||||
[InlineData(3UL)]
|
||||
[InlineData(5UL)]
|
||||
[InlineData(7UL)]
|
||||
[InlineData(11UL)]
|
||||
public void CalculateOrderGpu_matches_naive_algorithm(ulong q)
|
||||
{
|
||||
ulong expected = NaiveOrder(q);
|
||||
|
||||
var gpu = PrimeOrderCalculatorAccelerator.Rent(1);
|
||||
try
|
||||
{
|
||||
q.CalculateOrder(gpu).Should().Be(expected);
|
||||
q.CalculateOrderGpu(gpu).Should().Be(expected);
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -119,12 +132,22 @@ public class ULongExtensionsTests
|
||||
[InlineData(15UL, true)]
|
||||
[InlineData(7UL, false)]
|
||||
[InlineData(9UL, false)]
|
||||
public void SharesFactorWithExponentMinusOne_detects_relationship(ulong exponent, bool expected)
|
||||
public void SharesFactorWithExponentMinusOneCpu_detects_relationship(ulong exponent, bool expected)
|
||||
{
|
||||
exponent.SharesFactorWithExponentMinusOneCpu().Should().Be(expected);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[Trait("Category", "Fast")]
|
||||
[InlineData(15UL, true)]
|
||||
[InlineData(7UL, false)]
|
||||
[InlineData(9UL, false)]
|
||||
public void SharesFactorWithExponentMinusOneGpu_detects_relationship(ulong exponent, bool expected)
|
||||
{
|
||||
var gpu = PrimeOrderCalculatorAccelerator.Rent(1);
|
||||
try
|
||||
{
|
||||
exponent.SharesFactorWithExponentMinusOne(gpu).Should().Be(expected);
|
||||
exponent.SharesFactorWithExponentMinusOneGpu(gpu).Should().Be(expected);
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -213,15 +236,24 @@ public class ULongExtensionsTests
|
||||
[Theory]
|
||||
[Trait("Category", "Fast")]
|
||||
[InlineData(11UL, 13UL)]
|
||||
public void PowModCrt_matches_BigInteger(ulong exponent, ulong modulus)
|
||||
public void PowModCrtCpu_matches_BigInteger(ulong exponent, ulong modulus)
|
||||
{
|
||||
UInt128 expected = (UInt128)BigInteger.ModPow(2, exponent, modulus);
|
||||
|
||||
exponent.PowModCrtCpu((UInt128)modulus).Should().Be(expected);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[Trait("Category", "Fast")]
|
||||
[InlineData(11UL, 13UL)]
|
||||
public void PowModCrtGpu_matches_BigInteger(ulong exponent, ulong modulus)
|
||||
{
|
||||
MersenneDivisorCycles cycles = MersenneDivisorCycles.Shared;
|
||||
UInt128 expected = (UInt128)BigInteger.ModPow(2, exponent, modulus);
|
||||
|
||||
var gpu = PrimeOrderCalculatorAccelerator.Rent(1);
|
||||
try
|
||||
{
|
||||
exponent.PowModCrt(gpu, (UInt128)modulus, cycles).Should().Be(expected);
|
||||
exponent.PowModCrtGpu(gpu, (UInt128)modulus).Should().Be(expected);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user