Expand GPU coverage for even perfect candidate tests

This commit is contained in:
Marek Lemańczyk committed 2025-09-20 10:50:10 +02:00
1 parent b676d89293
commit 94b314df23
4 files changed
+189

No files matched your search

+138
View File
@@ -1,6 +1,7 @@
using FluentAssertions;
using Xunit;
using System;
using System.Collections.Generic;
using System.Numerics;
using System.Reflection;
using System.Text;
@@ -398,6 +399,143 @@ public class ProgramTests
}
}
[Theory]
[MemberData(nameof(KnownMersennePrimeExponents))]
public void IsEvenPerfectCandidate_accepts_known_small_mersenne_primes(ulong exponent)
{
var useDivisorField = typeof(Program).GetField("_useDivisor", BindingFlags.NonPublic | BindingFlags.Static)!;
var mersenneField = typeof(Program).GetField("MersenneTesters", BindingFlags.NonPublic | BindingFlags.Static)!;
var primeField = typeof(Program).GetField("PrimeTesters", BindingFlags.NonPublic | BindingFlags.Static)!;
var residueField = typeof(Program).GetField("PResidue", BindingFlags.NonPublic | BindingFlags.Static)!;
var gcdFilterField = typeof(Program).GetField("_useGcdFilter", BindingFlags.NonPublic | BindingFlags.Static)!;
var forceCpuProp = typeof(GpuContextPool).GetProperty("ForceCpu");
useDivisorField.SetValue(null, false);
gcdFilterField.SetValue(null, false);
mersenneField.SetValue(null, new ThreadLocal<MersenneNumberTester>(() => new MersenneNumberTester(
useIncremental: true,
useGpuScan: false,
useGpuOrder: false,
useResidue: true,
maxK: 1_024UL,
residueDivisorSets: 1UL), trackAllValues: true));
primeField.SetValue(null, new ThreadLocal<PrimeTester>(() => new PrimeTester(), trackAllValues: true));
residueField.SetValue(null, new ThreadLocal<ModResidueTracker>(() => new ModResidueTracker(ResidueModel.Identity, exponent, true), trackAllValues: true));
forceCpuProp!.SetValue(null, true);
try
{
Program.IsEvenPerfectCandidate(exponent, 0UL, out bool searched, out bool detailedCheck).Should().BeTrue();
searched.Should().BeTrue();
}
finally
{
useDivisorField.SetValue(null, false);
mersenneField.SetValue(null, null);
primeField.SetValue(null, null);
residueField.SetValue(null, null);
gcdFilterField.SetValue(null, false);
forceCpuProp!.SetValue(null, false);
}
}
[Theory]
[MemberData(nameof(KnownMersennePrimeGpuConfigurations))]
public void IsEvenPerfectCandidate_accepts_known_small_mersenne_primes_on_gpu(
ulong exponent,
MersenneGpuCandidateConfig configuration)
{
var useDivisorField = typeof(Program).GetField("_useDivisor", BindingFlags.NonPublic | BindingFlags.Static)!;
var mersenneField = typeof(Program).GetField("MersenneTesters", BindingFlags.NonPublic | BindingFlags.Static)!;
var primeField = typeof(Program).GetField("PrimeTesters", BindingFlags.NonPublic | BindingFlags.Static)!;
var residueField = typeof(Program).GetField("PResidue", BindingFlags.NonPublic | BindingFlags.Static)!;
var gcdFilterField = typeof(Program).GetField("_useGcdFilter", BindingFlags.NonPublic | BindingFlags.Static)!;
var forceCpuProp = typeof(GpuContextPool).GetProperty("ForceCpu");
useDivisorField.SetValue(null, false);
gcdFilterField.SetValue(null, false);
mersenneField.SetValue(null, new ThreadLocal<MersenneNumberTester>(() => new MersenneNumberTester(
useIncremental: false,
kernelType: configuration.KernelType,
useGpuScan: true,
useGpuOrder: configuration.UseGpuOrder,
useResidue: true,
maxK: (UInt128)configuration.ResidueMaxK,
residueDivisorSets: (UInt128)configuration.ResidueSetCount), trackAllValues: true));
primeField.SetValue(null, new ThreadLocal<PrimeTester>(() => new PrimeTester(), trackAllValues: true));
residueField.SetValue(null, new ThreadLocal<ModResidueTracker>(() => new ModResidueTracker(ResidueModel.Identity, exponent, true), trackAllValues: true));
forceCpuProp!.SetValue(null, false);
try
{
Program.IsEvenPerfectCandidate(exponent, 0UL, out bool searched, out bool detailedCheck).Should().BeTrue();
searched.Should().BeTrue();
}
finally
{
useDivisorField.SetValue(null, false);
mersenneField.SetValue(null, null);
primeField.SetValue(null, null);
residueField.SetValue(null, null);
gcdFilterField.SetValue(null, false);
forceCpuProp!.SetValue(null, false);
GpuContextPool.DisposeAll();
}
}
public static IEnumerable<object[]> KnownMersennePrimeExponents()
{
foreach (ulong exponent in KnownMersennePrimeExponentValues)
{
yield return new object[] { exponent };
}
}
public static IEnumerable<object[]> KnownMersennePrimeGpuConfigurations()
{
MersenneGpuCandidateConfig[] configs =
{
new(GpuKernelType.Incremental, true, 1_024UL, 1UL),
new(GpuKernelType.Incremental, false, 2_048UL, 1UL),
new(GpuKernelType.Pow2Mod, true, 4_096UL, 2UL),
new(GpuKernelType.Pow2Mod, false, 512UL, 2UL),
};
int index = 0;
foreach (ulong exponent in KnownMersennePrimeExponentValues)
{
var config = configs[index % configs.Length];
yield return new object[] { exponent, config };
index++;
}
}
private static readonly ulong[] KnownMersennePrimeExponentValues =
[
31UL,
61UL,
89UL,
107UL,
127UL,
521UL,
607UL,
1279UL,
2203UL,
2281UL,
3217UL,
4253UL,
4423UL,
9689UL,
9941UL,
11213UL,
];
public readonly record struct MersenneGpuCandidateConfig(
GpuKernelType KernelType,
bool UseGpuOrder,
ulong ResidueMaxK,
ulong ResidueSetCount);
[Fact]
public void Composite_candidates_flagged_for_residue_output_skip()
{
@@ -21,6 +21,18 @@ public class MersenneNumberResidueCpuTesterTests
RunCase(tester, 127UL, 1_000UL, expectedPrime: true);
}
[Fact]
[Trait("Category", "Fast")]
public void Scan_recognizes_all_known_small_mersenne_primes()
{
var tester = new MersenneNumberResidueCpuTester();
foreach (ulong exponent in MersennePrimeTestData.Exponents)
{
RunCase(tester, exponent, 1UL, expectedPrime: true);
}
}
private static void RunCase(MersenneNumberResidueCpuTester tester, ulong exponent, ulong maxK, bool expectedPrime)
{
bool isPrime = true;
@@ -25,6 +25,20 @@ public class MersenneNumberResidueGpuTesterTests
RunCase(tester, 127UL, 1_001UL, expectedPrime: true);
}
[Theory]
[InlineData(false)]
[InlineData(true)]
[Trait("Category", "Fast")]
public void Scan_recognizes_all_known_small_mersenne_primes(bool useGpuOrder)
{
var tester = new MersenneNumberResidueGpuTester(useGpuOrder);
foreach (ulong exponent in MersennePrimeTestData.Exponents)
{
RunCase(tester, exponent, 1UL, expectedPrime: true);
}
}
[Theory]
[InlineData(false)]
[InlineData(true)]
@@ -0,0 +1,25 @@
namespace PerfectNumbers.Core.Tests;
internal static class MersennePrimeTestData
{
public static readonly ulong[] Exponents =
{
31UL,
61UL,
89UL,
107UL,
127UL,
521UL,
607UL,
1279UL,
2203UL,
2281UL,
3217UL,
4253UL,
4423UL,
9689UL,
9941UL,
11213UL
};
}