Make by-divisor divisor cycle filtering optional
This commit is contained in:
1 parent
0195960b5a
commit
378d6a2fd8
2 files changed
+165
-85
No files matched your search
@@ -103,6 +103,7 @@ internal static class Program
|
|||||||
bool useResidue = false; // M_p test via residue divisors (replaces LL/incremental)
|
bool useResidue = false; // M_p test via residue divisors (replaces LL/incremental)
|
||||||
bool useDivisor = false; // M_p divisibility by specific divisor
|
bool useDivisor = false; // M_p divisibility by specific divisor
|
||||||
bool useByDivisor = false; // Iterative divisor scan across primes
|
bool useByDivisor = false; // Iterative divisor scan across primes
|
||||||
|
bool useDivisorCycles = false;
|
||||||
UInt128 divisor = UInt128.Zero;
|
UInt128 divisor = UInt128.Zero;
|
||||||
// Device routing
|
// Device routing
|
||||||
bool useGpuCycles = true;
|
bool useGpuCycles = true;
|
||||||
@@ -184,6 +185,13 @@ internal static class Program
|
|||||||
{
|
{
|
||||||
divisor = UInt128.Parse(arg.AsSpan(arg.IndexOf('=') + 1));
|
divisor = UInt128.Parse(arg.AsSpan(arg.IndexOf('=') + 1));
|
||||||
}
|
}
|
||||||
|
else if (arg.StartsWith("--use-divisor-cycles=", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
if (bool.TryParse(arg.AsSpan(arg.IndexOf('=') + 1), out bool parsedBool))
|
||||||
|
{
|
||||||
|
useDivisorCycles = parsedBool;
|
||||||
|
}
|
||||||
|
}
|
||||||
else if (arg.StartsWith("--divisor-cycles-limit=", StringComparison.OrdinalIgnoreCase))
|
else if (arg.StartsWith("--divisor-cycles-limit=", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
if (ulong.TryParse(arg.AsSpan(arg.IndexOf('=') + 1), out parsedLimit))
|
if (ulong.TryParse(arg.AsSpan(arg.IndexOf('=') + 1), out parsedLimit))
|
||||||
@@ -501,6 +509,7 @@ internal static class Program
|
|||||||
_byDivisorTester = new MersenneNumberDivisorByDivisorGpuTester
|
_byDivisorTester = new MersenneNumberDivisorByDivisorGpuTester
|
||||||
{
|
{
|
||||||
GpuBatchSize = scanBatchSize,
|
GpuBatchSize = scanBatchSize,
|
||||||
|
UseDivisorCycles = useDivisorCycles,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1277,6 +1286,7 @@ internal static class Program
|
|||||||
Console.WriteLine(" --divisor-cycles-batch-size=<value> batch size for cycles generation (default 512)");
|
Console.WriteLine(" --divisor-cycles-batch-size=<value> batch size for cycles generation (default 512)");
|
||||||
Console.WriteLine(" --divisor-cycles-continue continue divisor cycles generation");
|
Console.WriteLine(" --divisor-cycles-continue continue divisor cycles generation");
|
||||||
Console.WriteLine(" --divisor-cycles-limit=<value> cycle search iterations when --mersenne=divisor");
|
Console.WriteLine(" --divisor-cycles-limit=<value> cycle search iterations when --mersenne=divisor");
|
||||||
|
Console.WriteLine(" --use-divisor-cycles=true|false enable divisor cycle filtering in --mersenne=bydivisor (default false)");
|
||||||
|
|
||||||
Console.WriteLine(" --use-order test primality via q order");
|
Console.WriteLine(" --use-order test primality via q order");
|
||||||
Console.WriteLine(" --workaround-mod avoid '%' operator on the GPU");
|
Console.WriteLine(" --workaround-mod avoid '%' operator on the GPU");
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ using System.Runtime.CompilerServices;
|
|||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using ILGPU;
|
using ILGPU;
|
||||||
using ILGPU.Runtime;
|
using ILGPU.Runtime;
|
||||||
|
using PerfectNumbers.Core;
|
||||||
|
|
||||||
namespace PerfectNumbers.Core.Gpu;
|
namespace PerfectNumbers.Core.Gpu;
|
||||||
|
|
||||||
@@ -16,6 +17,7 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester
|
|||||||
private ulong _divisorLimit;
|
private ulong _divisorLimit;
|
||||||
private bool _isConfigured;
|
private bool _isConfigured;
|
||||||
private ulong _lastStatusDivisor;
|
private ulong _lastStatusDivisor;
|
||||||
|
private bool _useDivisorCycles;
|
||||||
|
|
||||||
public readonly struct MontgomeryDivisorData
|
public readonly struct MontgomeryDivisorData
|
||||||
{
|
{
|
||||||
@@ -47,6 +49,12 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester
|
|||||||
set => _gpuBatchSize = Math.Max(1, value);
|
set => _gpuBatchSize = Math.Max(1, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool UseDivisorCycles
|
||||||
|
{
|
||||||
|
get => _useDivisorCycles;
|
||||||
|
set => _useDivisorCycles = value;
|
||||||
|
}
|
||||||
|
|
||||||
public void ConfigureFromMaxPrime(ulong maxPrime)
|
public void ConfigureFromMaxPrime(ulong maxPrime)
|
||||||
{
|
{
|
||||||
lock (_sync)
|
lock (_sync)
|
||||||
@@ -91,12 +99,12 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool CheckDivisors(ulong prime, ulong allowedMax, out ulong lastProcessed, out bool coveredRange)
|
private bool CheckDivisors(ulong prime, ulong allowedMax, out ulong lastProcessed, out bool coveredRange)
|
||||||
{
|
{
|
||||||
allowedMax = Math.Min(allowedMax, _divisorLimit);
|
allowedMax = Math.Min(allowedMax, _divisorLimit);
|
||||||
lastProcessed = 0UL;
|
lastProcessed = 0UL;
|
||||||
|
|
||||||
if (allowedMax < 3UL)
|
if (allowedMax < 3UL)
|
||||||
{
|
{
|
||||||
coveredRange = true;
|
coveredRange = true;
|
||||||
return false;
|
return false;
|
||||||
@@ -118,40 +126,56 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester
|
|||||||
bool processedAll = false;
|
bool processedAll = false;
|
||||||
ulong divisor = 3UL;
|
ulong divisor = 3UL;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
while (divisor <= allowedMax)
|
bool useCycles = _useDivisorCycles;
|
||||||
{
|
MersenneDivisorCycles? divisorCycles = useCycles ? MersenneDivisorCycles.Shared : null;
|
||||||
int batchSize = 0;
|
while (divisor <= allowedMax)
|
||||||
bool reachedEndInBatch = false;
|
{
|
||||||
|
int batchSize = 0;
|
||||||
|
bool reachedEndInBatch = false;
|
||||||
|
|
||||||
while (batchSize < batchCapacity && divisor <= allowedMax)
|
while (batchSize < batchCapacity && divisor <= allowedMax)
|
||||||
{
|
{
|
||||||
ulong current = divisor;
|
ulong current = divisor;
|
||||||
divisors[batchSize++] = current;
|
ulong next = current + 2UL;
|
||||||
|
bool include = true;
|
||||||
|
if (useCycles)
|
||||||
|
{
|
||||||
|
ulong cycle = divisorCycles!.GetCycle(current);
|
||||||
|
if (cycle == 0UL || prime % cycle != 0UL)
|
||||||
|
{
|
||||||
|
include = false;
|
||||||
|
lastProcessed = current;
|
||||||
|
ReportStatus(lastProcessed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ulong next = current + 2UL;
|
if (include)
|
||||||
ReportStatus(lastProcessed);
|
{
|
||||||
if (next <= current)
|
divisors[batchSize++] = current;
|
||||||
{
|
}
|
||||||
reachedEndInBatch = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (next > allowedMax)
|
if (next <= current)
|
||||||
{
|
{
|
||||||
divisor = next;
|
reachedEndInBatch = true;
|
||||||
reachedEndInBatch = true;
|
break;
|
||||||
break;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
divisor = next;
|
if (next > allowedMax)
|
||||||
}
|
{
|
||||||
|
divisor = next;
|
||||||
|
reachedEndInBatch = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (batchSize == 0)
|
divisor = next;
|
||||||
{
|
}
|
||||||
break;
|
|
||||||
}
|
if (batchSize == 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
Span<MontgomeryDivisorData> divisorDataSpan = divisorData.AsSpan(0, batchSize);
|
Span<MontgomeryDivisorData> divisorDataSpan = divisorData.AsSpan(0, batchSize);
|
||||||
var divisorView = divisorsBuffer.View.SubView(0, batchSize);
|
var divisorView = divisorsBuffer.View.SubView(0, batchSize);
|
||||||
@@ -269,63 +293,108 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester
|
|||||||
private readonly Accelerator _accelerator;
|
private readonly Accelerator _accelerator;
|
||||||
private readonly Action<Index1D, MontgomeryDivisorData, ArrayView<ulong>, ArrayView<byte>> _kernel;
|
private readonly Action<Index1D, MontgomeryDivisorData, ArrayView<ulong>, ArrayView<byte>> _kernel;
|
||||||
private readonly MemoryBuffer1D<ulong, Stride1D.Dense> _primesBuffer;
|
private readonly MemoryBuffer1D<ulong, Stride1D.Dense> _primesBuffer;
|
||||||
private readonly MemoryBuffer1D<byte, Stride1D.Dense> _hitsBuffer;
|
private readonly MemoryBuffer1D<byte, Stride1D.Dense> _hitsBuffer;
|
||||||
private readonly ulong[] _primesHost;
|
private readonly ulong[] _primesHost;
|
||||||
private readonly byte[] _hitsHost;
|
private readonly byte[] _hitsHost;
|
||||||
private bool _disposed;
|
private readonly int[] _indexHost;
|
||||||
|
private bool _disposed;
|
||||||
|
|
||||||
internal DivisorScanSession(MersenneNumberDivisorByDivisorGpuTester owner)
|
internal DivisorScanSession(MersenneNumberDivisorByDivisorGpuTester owner)
|
||||||
{
|
{
|
||||||
_owner = owner;
|
_owner = owner;
|
||||||
_lease = GpuContextPool.RentPreferred(preferCpu: false);
|
_lease = GpuContextPool.RentPreferred(preferCpu: false);
|
||||||
_accelerator = _lease.Accelerator;
|
_accelerator = _lease.Accelerator;
|
||||||
_kernel = owner.GetKernelByPrime(_accelerator);
|
_kernel = owner.GetKernelByPrime(_accelerator);
|
||||||
_primesBuffer = _accelerator.Allocate1D<ulong>(owner._gpuBatchSize);
|
_primesBuffer = _accelerator.Allocate1D<ulong>(owner._gpuBatchSize);
|
||||||
_hitsBuffer = _accelerator.Allocate1D<byte>(owner._gpuBatchSize);
|
_hitsBuffer = _accelerator.Allocate1D<byte>(owner._gpuBatchSize);
|
||||||
_primesHost = ArrayPool<ulong>.Shared.Rent(owner._gpuBatchSize);
|
_primesHost = ArrayPool<ulong>.Shared.Rent(owner._gpuBatchSize);
|
||||||
_hitsHost = ArrayPool<byte>.Shared.Rent(owner._gpuBatchSize);
|
_hitsHost = ArrayPool<byte>.Shared.Rent(owner._gpuBatchSize);
|
||||||
}
|
_indexHost = ArrayPool<int>.Shared.Rent(owner._gpuBatchSize);
|
||||||
|
}
|
||||||
|
|
||||||
public void CheckDivisor(ulong divisor, ReadOnlySpan<ulong> primes, Span<byte> hits)
|
public void CheckDivisor(ulong divisor, ReadOnlySpan<ulong> primes, Span<byte> hits)
|
||||||
{
|
{
|
||||||
if (_disposed)
|
if (_disposed)
|
||||||
{
|
{
|
||||||
throw new ObjectDisposedException(nameof(DivisorScanSession));
|
throw new ObjectDisposedException(nameof(DivisorScanSession));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (primes.Length == 0)
|
if (primes.Length == 0)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
int consoleStatus = 0;
|
int consoleStatus = 0;
|
||||||
|
bool useCycles = _owner._useDivisorCycles;
|
||||||
|
MersenneDivisorCycles? divisorCycles = useCycles ? MersenneDivisorCycles.Shared : null;
|
||||||
|
ulong cycle = useCycles ? divisorCycles!.GetCycle(divisor) : 0UL;
|
||||||
MontgomeryDivisorData divisorData = CreateMontgomeryDivisorData(divisor);
|
MontgomeryDivisorData divisorData = CreateMontgomeryDivisorData(divisor);
|
||||||
while (offset < primes.Length)
|
while (offset < primes.Length)
|
||||||
{
|
{
|
||||||
int batchSize = Math.Min(_owner._gpuBatchSize, primes.Length - offset);
|
int batchSize = Math.Min(_owner._gpuBatchSize, primes.Length - offset);
|
||||||
Span<ulong> primeSpan = _primesHost.AsSpan(0, batchSize);
|
Span<ulong> primeSpan = _primesHost.AsSpan(0, batchSize);
|
||||||
primes.Slice(offset, batchSize).CopyTo(primeSpan);
|
primes.Slice(offset, batchSize).CopyTo(primeSpan);
|
||||||
|
|
||||||
if (++consoleStatus == PerfectNumberConstants.ConsoleInterval)
|
if (++consoleStatus == PerfectNumberConstants.ConsoleInterval)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"...processed by-divisor candidate = {primes[0]}");
|
Console.WriteLine($"...processed by-divisor candidate = {primes[0]}");
|
||||||
consoleStatus = 0;
|
consoleStatus = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
var primesView = _primesBuffer.View.SubView(0, batchSize);
|
Span<int> indexSpan = _indexHost.AsSpan(0, batchSize);
|
||||||
var hitsView = _hitsBuffer.View.SubView(0, batchSize);
|
Span<byte> hitSpan = _hitsHost.AsSpan(0, batchSize);
|
||||||
|
Span<byte> hitsSlice = hits.Slice(offset, batchSize);
|
||||||
|
int gpuCount = 0;
|
||||||
|
|
||||||
primesView.CopyFromCPU(ref MemoryMarshal.GetReference(primeSpan), batchSize);
|
if (useCycles)
|
||||||
_kernel(batchSize, divisorData, primesView, hitsView);
|
{
|
||||||
_accelerator.Synchronize();
|
for (int i = 0; i < batchSize; i++)
|
||||||
|
{
|
||||||
|
ulong primeValue = primeSpan[i];
|
||||||
|
if (cycle == 0UL || primeValue % cycle != 0UL)
|
||||||
|
{
|
||||||
|
hitsSlice[i] = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
Span<byte> hitSpan = _hitsHost.AsSpan(0, batchSize);
|
indexSpan[gpuCount] = i;
|
||||||
hitsView.CopyToCPU(ref MemoryMarshal.GetReference(hitSpan), batchSize);
|
primeSpan[gpuCount] = primeValue;
|
||||||
hitSpan.CopyTo(hits.Slice(offset, batchSize));
|
gpuCount++;
|
||||||
offset += batchSize;
|
}
|
||||||
}
|
|
||||||
}
|
if (gpuCount > 0)
|
||||||
|
{
|
||||||
|
var primesView = _primesBuffer.View.SubView(0, gpuCount);
|
||||||
|
var hitsView = _hitsBuffer.View.SubView(0, gpuCount);
|
||||||
|
|
||||||
|
primesView.CopyFromCPU(ref MemoryMarshal.GetReference(primeSpan.Slice(0, gpuCount)), gpuCount);
|
||||||
|
_kernel(gpuCount, divisorData, primesView, hitsView);
|
||||||
|
_accelerator.Synchronize();
|
||||||
|
|
||||||
|
hitsView.CopyToCPU(ref MemoryMarshal.GetReference(hitSpan.Slice(0, gpuCount)), gpuCount);
|
||||||
|
for (int i = 0; i < gpuCount; i++)
|
||||||
|
{
|
||||||
|
hitsSlice[indexSpan[i]] = hitSpan[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var primesView = _primesBuffer.View.SubView(0, batchSize);
|
||||||
|
var hitsView = _hitsBuffer.View.SubView(0, batchSize);
|
||||||
|
|
||||||
|
primesView.CopyFromCPU(ref MemoryMarshal.GetReference(primeSpan), batchSize);
|
||||||
|
_kernel(batchSize, divisorData, primesView, hitsView);
|
||||||
|
_accelerator.Synchronize();
|
||||||
|
|
||||||
|
hitsView.CopyToCPU(ref MemoryMarshal.GetReference(hitSpan), batchSize);
|
||||||
|
hitSpan.CopyTo(hitsSlice);
|
||||||
|
}
|
||||||
|
|
||||||
|
offset += batchSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
@@ -334,14 +403,15 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_disposed = true;
|
_disposed = true;
|
||||||
ArrayPool<ulong>.Shared.Return(_primesHost, clearArray: true);
|
ArrayPool<ulong>.Shared.Return(_primesHost, clearArray: true);
|
||||||
ArrayPool<byte>.Shared.Return(_hitsHost, clearArray: true);
|
ArrayPool<byte>.Shared.Return(_hitsHost, clearArray: true);
|
||||||
_primesBuffer.Dispose();
|
ArrayPool<int>.Shared.Return(_indexHost, clearArray: true);
|
||||||
_hitsBuffer.Dispose();
|
_primesBuffer.Dispose();
|
||||||
_lease.Dispose();
|
_hitsBuffer.Dispose();
|
||||||
}
|
_lease.Dispose();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static ulong Pow2Mod(ulong exponent, MontgomeryDivisorData divisor)
|
private static ulong Pow2Mod(ulong exponent, MontgomeryDivisorData divisor)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in new issue
Block a user