Initial BitTree implementation added.
This commit is contained in:
1 parent
45e3455ff3
commit
d88ad25476
11 files changed
+3817
-367
No files matched your search
@@ -5,19 +5,20 @@ using PerfectNumbers.Core.Gpu;
|
||||
|
||||
namespace EvenPerfectBitScanner;
|
||||
|
||||
internal enum ByDivisorKIncrementMode
|
||||
{
|
||||
Sequential,
|
||||
Pow2Groups,
|
||||
Predictive,
|
||||
Percentile,
|
||||
Additive,
|
||||
TopDown,
|
||||
BitContradiction,
|
||||
internal enum ByDivisorKIncrementMode
|
||||
{
|
||||
Sequential,
|
||||
Pow2Groups,
|
||||
Predictive,
|
||||
Percentile,
|
||||
Additive,
|
||||
TopDown,
|
||||
BitContradiction,
|
||||
BitTree,
|
||||
}
|
||||
|
||||
internal readonly struct CliArguments
|
||||
{
|
||||
internal readonly struct CliArguments
|
||||
{
|
||||
private const string DefaultCyclesPath = "divisor_cycles.bin";
|
||||
|
||||
internal readonly ulong StartPrime;
|
||||
@@ -35,19 +36,19 @@ namespace EvenPerfectBitScanner;
|
||||
internal readonly bool UseLucas;
|
||||
internal readonly bool UseResidue;
|
||||
internal readonly bool UseDivisor;
|
||||
internal readonly bool UseByDivisor;
|
||||
internal readonly ByDivisorKIncrementMode ByDivisorKIncrementMode;
|
||||
internal readonly int ByDivisorSpecialRange;
|
||||
internal readonly bool UseGcdFilter;
|
||||
internal readonly bool TestMode;
|
||||
internal readonly bool UseGpuCycles;
|
||||
internal readonly ComputationDevice MersenneDevice;
|
||||
internal readonly ComputationDevice OrderDevice;
|
||||
internal readonly int ScanBatchSize;
|
||||
internal readonly int SliceSize;
|
||||
internal readonly ulong MaxKLimit;
|
||||
internal readonly bool UseByDivisor;
|
||||
internal readonly ByDivisorKIncrementMode ByDivisorKIncrementMode;
|
||||
internal readonly int ByDivisorSpecialRange;
|
||||
internal readonly bool UseGcdFilter;
|
||||
internal readonly bool TestMode;
|
||||
internal readonly bool UseGpuCycles;
|
||||
internal readonly ComputationDevice MersenneDevice;
|
||||
internal readonly ComputationDevice OrderDevice;
|
||||
internal readonly int ScanBatchSize;
|
||||
internal readonly int SliceSize;
|
||||
internal readonly ulong MaxKLimit;
|
||||
internal readonly bool MaxKConfigured;
|
||||
internal readonly string FilterFile;
|
||||
internal readonly string FilterFile;
|
||||
internal readonly bool ForcePrimeKernelsOnCpu;
|
||||
internal readonly ModReductionMode ModReductionMode;
|
||||
internal readonly NttBackend NttBackend;
|
||||
@@ -66,56 +67,56 @@ namespace EvenPerfectBitScanner;
|
||||
internal readonly double ZeroFractionConjecture;
|
||||
internal readonly int MaxZeroConjecture;
|
||||
internal readonly BigInteger MinK;
|
||||
internal readonly int GpuRatio;
|
||||
internal readonly int GpuRatio;
|
||||
|
||||
private CliArguments(
|
||||
ulong startPrime,
|
||||
bool startPrimeProvided,
|
||||
UInt128 maxPrimeLimit,
|
||||
bool maxPrimeConfigured,
|
||||
int threadCount,
|
||||
int blockSize,
|
||||
int gpuPrimeThreads,
|
||||
int gpuPrimeBatch,
|
||||
GpuKernelType kernelType,
|
||||
bool useOrder,
|
||||
bool showHelp,
|
||||
bool useBitTransform,
|
||||
bool useLucas,
|
||||
bool useResidue,
|
||||
bool useDivisor,
|
||||
bool useByDivisor,
|
||||
bool useGcdFilter,
|
||||
ByDivisorKIncrementMode byDivisorKIncrementMode,
|
||||
int byDivisorSpecialRange,
|
||||
bool testMode,
|
||||
bool useGpuCycles,
|
||||
ComputationDevice mersenneDevice,
|
||||
ComputationDevice orderDevice,
|
||||
int scanBatchSize,
|
||||
int sliceSize,
|
||||
ulong maxKLimit,
|
||||
bool maxKConfigured,
|
||||
string filterFile,
|
||||
bool forcePrimeKernelsOnCpu,
|
||||
ModReductionMode modReductionMode,
|
||||
NttBackend nttBackend,
|
||||
string? resultsDirectory,
|
||||
string? resultsPrefix,
|
||||
int writeBatchSize,
|
||||
string cyclesPath,
|
||||
bool continueCyclesGeneration,
|
||||
int cyclesBatchSize,
|
||||
ulong divisorCyclesSearchLimit,
|
||||
ulong? orderWarmupLimitOverride,
|
||||
string? rleBlacklistPath,
|
||||
ulong rleHardMaxP,
|
||||
bool rleOnlyLast7,
|
||||
double zeroFractionHard,
|
||||
double zeroFractionConjecture,
|
||||
int maxZeroConjecture,
|
||||
BigInteger minK,
|
||||
int gpuRatio)
|
||||
private CliArguments(
|
||||
ulong startPrime,
|
||||
bool startPrimeProvided,
|
||||
UInt128 maxPrimeLimit,
|
||||
bool maxPrimeConfigured,
|
||||
int threadCount,
|
||||
int blockSize,
|
||||
int gpuPrimeThreads,
|
||||
int gpuPrimeBatch,
|
||||
GpuKernelType kernelType,
|
||||
bool useOrder,
|
||||
bool showHelp,
|
||||
bool useBitTransform,
|
||||
bool useLucas,
|
||||
bool useResidue,
|
||||
bool useDivisor,
|
||||
bool useByDivisor,
|
||||
bool useGcdFilter,
|
||||
ByDivisorKIncrementMode byDivisorKIncrementMode,
|
||||
int byDivisorSpecialRange,
|
||||
bool testMode,
|
||||
bool useGpuCycles,
|
||||
ComputationDevice mersenneDevice,
|
||||
ComputationDevice orderDevice,
|
||||
int scanBatchSize,
|
||||
int sliceSize,
|
||||
ulong maxKLimit,
|
||||
bool maxKConfigured,
|
||||
string filterFile,
|
||||
bool forcePrimeKernelsOnCpu,
|
||||
ModReductionMode modReductionMode,
|
||||
NttBackend nttBackend,
|
||||
string? resultsDirectory,
|
||||
string? resultsPrefix,
|
||||
int writeBatchSize,
|
||||
string cyclesPath,
|
||||
bool continueCyclesGeneration,
|
||||
int cyclesBatchSize,
|
||||
ulong divisorCyclesSearchLimit,
|
||||
ulong? orderWarmupLimitOverride,
|
||||
string? rleBlacklistPath,
|
||||
ulong rleHardMaxP,
|
||||
bool rleOnlyLast7,
|
||||
double zeroFractionHard,
|
||||
double zeroFractionConjecture,
|
||||
int maxZeroConjecture,
|
||||
BigInteger minK,
|
||||
int gpuRatio)
|
||||
{
|
||||
StartPrime = startPrime;
|
||||
StartPrimeProvided = startPrimeProvided;
|
||||
@@ -163,7 +164,7 @@ namespace EvenPerfectBitScanner;
|
||||
ZeroFractionConjecture = zeroFractionConjecture;
|
||||
MaxZeroConjecture = maxZeroConjecture;
|
||||
MinK = minK;
|
||||
GpuRatio = gpuRatio;
|
||||
GpuRatio = gpuRatio;
|
||||
}
|
||||
|
||||
internal bool UseFilter => !TestMode && !string.IsNullOrEmpty(FilterFile);
|
||||
@@ -204,7 +205,7 @@ namespace EvenPerfectBitScanner;
|
||||
string? resultsDirectory = null;
|
||||
string? resultsPrefix = null;
|
||||
int writeBatchSize = CalculationResultHandler.DefaultWriteBatchSize;
|
||||
string cyclesPath = DefaultCyclesPath;
|
||||
string cyclesPath = DefaultCyclesPath;
|
||||
bool continueCyclesGeneration = false;
|
||||
int cyclesBatchSize = 512;
|
||||
ulong divisorCyclesSearchLimit = PerfectNumberConstants.ExtraDivisorCycleSearchLimit;
|
||||
@@ -216,7 +217,7 @@ namespace EvenPerfectBitScanner;
|
||||
double zeroFractionConjecture = -1.0;
|
||||
int maxZeroConjecture = -1;
|
||||
BigInteger minK = BigInteger.One;
|
||||
int gpuRatio = PerfectNumberConstants.GpuRatio;
|
||||
int gpuRatio = PerfectNumberConstants.GpuRatio;
|
||||
|
||||
foreach (string argument in args)
|
||||
{
|
||||
@@ -279,6 +280,19 @@ namespace EvenPerfectBitScanner;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (argument.Equals("--use-order", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
useOrder = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (argument.StartsWith("--max-k=", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
maxKLimit = Utf8CliParser.ParseUInt64(argument.AsSpan("--max-k=".Length));
|
||||
maxKConfigured = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (argument.StartsWith("--mersenne=", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
ReadOnlySpan<char> value = argument.AsSpan("--mersenne=".Length);
|
||||
@@ -318,138 +332,46 @@ namespace EvenPerfectBitScanner;
|
||||
|
||||
if (argument.StartsWith("--bydivisor-k-increment=", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
string value = argument["--bydivisor-k-increment=".Length..].Trim();
|
||||
ReadOnlySpan<char> value = argument.AsSpan("--bydivisor-k-increment=".Length);
|
||||
if (value.Equals("pow2groups", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
byDivisorKIncrementMode = ByDivisorKIncrementMode.Pow2Groups;
|
||||
}
|
||||
else if (value.Equals("sequential", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
byDivisorKIncrementMode = ByDivisorKIncrementMode.Sequential;
|
||||
}
|
||||
else if (value.Equals("predictive", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
byDivisorKIncrementMode = ByDivisorKIncrementMode.Predictive;
|
||||
}
|
||||
else if (value.Equals("percentile", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
byDivisorKIncrementMode = ByDivisorKIncrementMode.Percentile;
|
||||
}
|
||||
else if (value.Equals("additive", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
byDivisorKIncrementMode = ByDivisorKIncrementMode.Additive;
|
||||
}
|
||||
else if (value.Equals("topdown", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
byDivisorKIncrementMode = ByDivisorKIncrementMode.TopDown;
|
||||
}
|
||||
else if (value.Equals("bitcontradiction", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
byDivisorKIncrementMode = ByDivisorKIncrementMode.BitContradiction;
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Invalid value for --bydivisor-k-increment. Use sequential, pow2groups, predictive, percentile, additive, topdown, or bitcontradiction.");
|
||||
return default;
|
||||
}
|
||||
else if (value.Equals("percentile", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
byDivisorKIncrementMode = ByDivisorKIncrementMode.Percentile;
|
||||
}
|
||||
else if (value.Equals("additive", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
byDivisorKIncrementMode = ByDivisorKIncrementMode.Additive;
|
||||
}
|
||||
else if (value.Equals("topdown", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
byDivisorKIncrementMode = ByDivisorKIncrementMode.TopDown;
|
||||
}
|
||||
else if (value.Equals("bitcontradiction", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
byDivisorKIncrementMode = ByDivisorKIncrementMode.BitContradiction;
|
||||
}
|
||||
else if (value.Equals("bittree", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
byDivisorKIncrementMode = ByDivisorKIncrementMode.BitTree;
|
||||
}
|
||||
else
|
||||
{
|
||||
byDivisorKIncrementMode = ByDivisorKIncrementMode.Sequential;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (argument.StartsWith("--bydivisor-special-range=", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
if (Utf8CliParser.TryParseInt32(argument.AsSpan("--bydivisor-special-range=".Length), out int parsedRange) && parsedRange >= 0)
|
||||
{
|
||||
byDivisorSpecialRange = parsedRange;
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Invalid value for --bydivisor-special-range. Use a non-negative integer.");
|
||||
return default;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (argument.StartsWith("--divisor-cycles-limit=", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
if (Utf8CliParser.TryParseUInt64(argument.AsSpan("--divisor-cycles-limit=".Length), out ulong parsedLimit))
|
||||
{
|
||||
divisorCyclesSearchLimit = parsedLimit;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (argument.StartsWith("--max-k=", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
if (Utf8CliParser.TryParseUInt64(argument.AsSpan("--max-k=".Length), out ulong parsedMaxK))
|
||||
{
|
||||
maxKLimit = parsedMaxK;
|
||||
maxKConfigured = true;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (argument.StartsWith("--min-k=", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
ReadOnlySpan<char> minKSpan = argument.AsSpan("--min-k=".Length);
|
||||
if (Utf8CliParser.TryParseUInt64(minKSpan, out ulong parsedMinK) && parsedMinK > 0UL)
|
||||
{
|
||||
minK = parsedMinK;
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
BigInteger parsedMinKBig = BigInteger.Parse(minKSpan, CultureInfo.InvariantCulture);
|
||||
if (parsedMinKBig > BigInteger.Zero)
|
||||
{
|
||||
minK = parsedMinKBig;
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Invalid value for --min-k.");
|
||||
return default;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
Console.WriteLine("Invalid value for --min-k.");
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (argument.StartsWith("--mersenne-device=", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
ReadOnlySpan<char> value = argument.AsSpan("--mersenne-device=".Length);
|
||||
mersenneDevice = ParseDevice(value);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (argument.Equals("--test", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
testMode = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (argument.Equals("--use-order", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
useOrder = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (argument.StartsWith("--order-warmup-limit=", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
if (Utf8CliParser.TryParseUInt64(argument.AsSpan("--order-warmup-limit=".Length), out ulong parsedLimit))
|
||||
{
|
||||
orderWarmupLimitOverride = parsedLimit;
|
||||
}
|
||||
|
||||
byDivisorSpecialRange = Utf8CliParser.ParseInt32(argument.AsSpan("--bydivisor-special-range=".Length));
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -459,138 +381,30 @@ namespace EvenPerfectBitScanner;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (argument.StartsWith("--ntt=", StringComparison.OrdinalIgnoreCase))
|
||||
if (argument.Equals("--test-mode", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
ReadOnlySpan<char> value = argument.AsSpan("--ntt=".Length);
|
||||
nttBackend = value.Equals("staged", StringComparison.OrdinalIgnoreCase) ? NttBackend.Staged : NttBackend.Reference;
|
||||
testMode = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (argument.StartsWith("--mod-reduction=", StringComparison.OrdinalIgnoreCase))
|
||||
if (argument.StartsWith("--mersenne-device=", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
ReadOnlySpan<char> value = argument.AsSpan("--mod-reduction=".Length);
|
||||
if (value.Equals("mont64", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
modReductionMode = ModReductionMode.Mont64;
|
||||
}
|
||||
else if (value.Equals("barrett128", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
modReductionMode = ModReductionMode.Barrett128;
|
||||
}
|
||||
else if (value.Equals("uint128", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
modReductionMode = ModReductionMode.GpuUInt128;
|
||||
}
|
||||
else
|
||||
{
|
||||
modReductionMode = ModReductionMode.Auto;
|
||||
}
|
||||
|
||||
mersenneDevice = ParseDevice(argument.AsSpan("--mersenne-device=".Length));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (argument.StartsWith("--primes-device=", StringComparison.OrdinalIgnoreCase))
|
||||
if (argument.StartsWith("--primes=", StringComparison.OrdinalIgnoreCase) ||
|
||||
argument.StartsWith("--gpu-kernels=", StringComparison.OrdinalIgnoreCase) ||
|
||||
argument.StartsWith("--accelerator=", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
forcePrimeKernelsOnCpu = argument.AsSpan("--primes-device=".Length).Equals("cpu", StringComparison.OrdinalIgnoreCase);
|
||||
ReadOnlySpan<char> value = argument.Contains('=') ? argument.AsSpan(argument.IndexOf('=') + 1) : argument.AsSpan();
|
||||
forcePrimeKernelsOnCpu = value.Equals("cpu", StringComparison.OrdinalIgnoreCase);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (argument.StartsWith("--order-device=", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
ReadOnlySpan<char> value = argument.AsSpan("--order-device=".Length);
|
||||
orderDevice = ParseDevice(value);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (argument.StartsWith("--rle-blacklist=", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
rleBlacklistPath = argument["--rle-blacklist=".Length..];
|
||||
continue;
|
||||
}
|
||||
|
||||
if (argument.StartsWith("--rle-hard-max=", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
if (Utf8CliParser.TryParseUInt64(argument.AsSpan("--rle-hard-max=".Length), out ulong parsedMax))
|
||||
{
|
||||
rleHardMaxP = parsedMax;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (argument.StartsWith("--rle-only-last7=", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
ReadOnlySpan<char> value = argument.AsSpan("--rle-only-last7=".Length);
|
||||
rleOnlyLast7 = !value.Equals("false", StringComparison.OrdinalIgnoreCase) && !value.Equals("0", StringComparison.OrdinalIgnoreCase);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (argument.StartsWith("--zero-hard=", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
if (Utf8CliParser.TryParseDouble(argument.AsSpan("--zero-hard=".Length), out double zeroFraction))
|
||||
{
|
||||
zeroFractionHard = zeroFraction;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (argument.StartsWith("--zero-conj=", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
ReadOnlySpan<char> value = argument.AsSpan("--zero-conj=".Length);
|
||||
int colon = value.IndexOf(':');
|
||||
if (colon > 0)
|
||||
{
|
||||
if (Utf8CliParser.TryParseDouble(value[..colon], out double zeroFrac) &&
|
||||
Utf8CliParser.TryParseInt32(value[(colon + 1)..], out int maxZero))
|
||||
{
|
||||
zeroFractionConjecture = zeroFrac;
|
||||
maxZeroConjecture = maxZero;
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (argument.StartsWith("--lucas=", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
mersenneDevice = ParseDevice(argument.AsSpan("--lucas=".Length));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (argument.StartsWith("--primes=", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
forcePrimeKernelsOnCpu = argument.AsSpan("--primes=".Length).Equals("cpu", StringComparison.OrdinalIgnoreCase);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (argument.StartsWith("--gpu-kernels=", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
forcePrimeKernelsOnCpu = argument.AsSpan("--gpu-kernels=".Length).Equals("cpu", StringComparison.OrdinalIgnoreCase);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (argument.StartsWith("--accelerator=", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
forcePrimeKernelsOnCpu = argument.AsSpan("--accelerator=".Length).Equals("cpu", StringComparison.OrdinalIgnoreCase);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (argument.StartsWith("--results-dir=", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
resultsDirectory = argument["--results-dir=".Length..];
|
||||
continue;
|
||||
}
|
||||
|
||||
if (argument.StartsWith("--results-prefix=", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
resultsPrefix = argument["--results-prefix=".Length..];
|
||||
continue;
|
||||
}
|
||||
|
||||
if (argument.StartsWith("--gpu-prime-threads=", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
gpuPrimeThreads = Math.Max(1, Utf8CliParser.ParseInt32(argument.AsSpan("--gpu-prime-threads=".Length)));
|
||||
orderDevice = ParseDevice(argument.AsSpan("--order-device=".Length));
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -600,6 +414,12 @@ namespace EvenPerfectBitScanner;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (argument.StartsWith("--gpu-prime-threads=", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
gpuPrimeThreads = Math.Max(1, Utf8CliParser.ParseInt32(argument.AsSpan("--gpu-prime-threads=".Length)));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (argument.StartsWith("--ll-slice=", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
sliceSize = Math.Max(1, Utf8CliParser.ParseInt32(argument.AsSpan("--ll-slice=".Length)));
|
||||
@@ -618,6 +438,54 @@ namespace EvenPerfectBitScanner;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (argument.StartsWith("--mod-reduction=", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
ReadOnlySpan<char> value = argument.AsSpan("--mod-reduction=".Length);
|
||||
if (value.Equals("uint128", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
modReductionMode = ModReductionMode.GpuUInt128;
|
||||
}
|
||||
else if (value.Equals("mont64", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
modReductionMode = ModReductionMode.Mont64;
|
||||
}
|
||||
else if (value.Equals("barrett128", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
modReductionMode = ModReductionMode.Barrett128;
|
||||
}
|
||||
else
|
||||
{
|
||||
modReductionMode = ModReductionMode.Auto;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (argument.StartsWith("--ntt=", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
ReadOnlySpan<char> value = argument.AsSpan("--ntt=".Length);
|
||||
nttBackend = value.Equals("staged", StringComparison.OrdinalIgnoreCase) ? NttBackend.Staged : NttBackend.Reference;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (argument.StartsWith("--order-warmup-limit=", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
orderWarmupLimitOverride = Utf8CliParser.ParseUInt64(argument.AsSpan("--order-warmup-limit=".Length));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (argument.StartsWith("--divisor-cycles-limit=", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
divisorCyclesSearchLimit = Utf8CliParser.ParseUInt64(argument.AsSpan("--divisor-cycles-limit=".Length));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (argument.StartsWith("--min-k=", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
minK = BigInteger.Parse(argument.AsSpan("--min-k=".Length), NumberStyles.None, CultureInfo.InvariantCulture);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (argument.StartsWith("--filter-p=", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
filterFile = argument["--filter-p=".Length..];
|
||||
@@ -651,6 +519,7 @@ namespace EvenPerfectBitScanner;
|
||||
if (argument.Equals("--divisor-cycles-continue", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
continueCyclesGeneration = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -659,15 +528,15 @@ namespace EvenPerfectBitScanner;
|
||||
startPrimeProvided,
|
||||
maxPrimeLimit,
|
||||
maxPrimeConfigured,
|
||||
threadCount,
|
||||
blockSize,
|
||||
gpuPrimeThreads,
|
||||
gpuPrimeBatch,
|
||||
kernelType,
|
||||
useOrder,
|
||||
showHelp,
|
||||
useBitTransform,
|
||||
useLucas,
|
||||
threadCount,
|
||||
blockSize,
|
||||
gpuPrimeThreads,
|
||||
gpuPrimeBatch,
|
||||
kernelType,
|
||||
useOrder,
|
||||
showHelp,
|
||||
useBitTransform,
|
||||
useLucas,
|
||||
useResidue,
|
||||
useDivisor,
|
||||
useByDivisor,
|
||||
@@ -701,7 +570,7 @@ namespace EvenPerfectBitScanner;
|
||||
zeroFractionConjecture,
|
||||
maxZeroConjecture,
|
||||
minK,
|
||||
gpuRatio);
|
||||
gpuRatio);
|
||||
}
|
||||
|
||||
internal static void PrintHelp()
|
||||
@@ -715,14 +584,14 @@ namespace EvenPerfectBitScanner;
|
||||
Console.WriteLine(" --increment=bit|add exponent increment method (default add)");
|
||||
Console.WriteLine(" --threads=<value> number of worker threads");
|
||||
Console.WriteLine(" --mersenne=pow2mod|incremental|lucas|residue|divisor|bydivisor Mersenne test method");
|
||||
Console.WriteLine(" --bydivisor-k-increment=sequential|pow2groups|predictive|percentile|additive|topdown|bitcontradiction k iteration strategy for --mersenne=bydivisor (default sequential)");
|
||||
Console.WriteLine(" --bydivisor-k-increment=sequential|pow2groups|predictive|percentile|additive|topdown|bitcontradiction|bittree k iteration strategy for --mersenne=bydivisor (default sequential)");
|
||||
Console.WriteLine(" --bydivisor-special-range=<n> widen pow2groups special values to +/- n percent (default 0 = points)");
|
||||
Console.WriteLine(" --max-k=<value> max k for Mersenne tests (q = 2*p*k + 1), including --mersenne=bydivisor");
|
||||
Console.WriteLine(" --mersenne-device=cpu|gpu|hybrid Device for Mersenne method (default gpu)");
|
||||
Console.WriteLine(" --primes-device=cpu|gpu device for prime-scan kernels (default gpu)");
|
||||
Console.WriteLine(" --gpu-prime-batch=<n> batch size for GPU primality sieve (default 262144)");
|
||||
Console.WriteLine($" --gpu-ratio=<n> ratio of GPU operations vs CPU in hybrid device mode (default {PerfectNumberConstants.GpuRatio})");
|
||||
Console.WriteLine($" --gpu-ratio=<n> ratio of GPU operations vs CPU in hybrid device mode (default {PerfectNumberConstants.GpuRatio})");
|
||||
Console.WriteLine(" --gpu-prime-threads=<value> max concurrent GPU prime checks (default 1)");
|
||||
Console.WriteLine(" --gpu-prime-batch=<n> batch size for GPU primality sieve (default 262144)");
|
||||
Console.WriteLine(" --gpu-scan-batch=<value> GPU q-scan batch size (default 2_097_152)");
|
||||
Console.WriteLine(" --order-device=cpu|gpu|hybrid Device for order computations (default gpu)");
|
||||
Console.WriteLine(" --ll-slice=<value> Lucas–Lehmer iterations per slice (default 32)");
|
||||
|
||||
@@ -32,6 +32,9 @@ using ByDivisorGpuOrderTopDown = PerfectNumbers.Core.Cpu.MersenneNumberDivisorBy
|
||||
using ByDivisorCpuOrderBitContradiction = PerfectNumbers.Core.Cpu.MersenneNumberDivisorByDivisorCpuTesterWithForBitContradictionDivisorSetForCpuOrder;
|
||||
using ByDivisorHybridOrderBitContradiction = PerfectNumbers.Core.Cpu.MersenneNumberDivisorByDivisorCpuTesterWithForBitContradictionDivisorSetForHybridOrder;
|
||||
using ByDivisorGpuOrderBitContradiction = PerfectNumbers.Core.Cpu.MersenneNumberDivisorByDivisorCpuTesterWithForBitContradictionDivisorSetForGpuOrder;
|
||||
using ByDivisorCpuOrderBitTree = PerfectNumbers.Core.Cpu.MersenneNumberDivisorByDivisorCpuTesterWithForBitTreeDivisorSetForCpuOrder;
|
||||
using ByDivisorHybridOrderBitTree = PerfectNumbers.Core.Cpu.MersenneNumberDivisorByDivisorCpuTesterWithForBitTreeDivisorSetForHybridOrder;
|
||||
using ByDivisorGpuOrderBitTree = PerfectNumbers.Core.Cpu.MersenneNumberDivisorByDivisorCpuTesterWithForBitTreeDivisorSetForGpuOrder;
|
||||
using System.Globalization;
|
||||
|
||||
namespace EvenPerfectBitScanner;
|
||||
@@ -64,6 +67,9 @@ private static ThreadLocal<object>? MersenneTesters;
|
||||
private static ByDivisorCpuOrderBitContradiction _byDivisorCpuOrderTesterBitContradiction;
|
||||
private static ByDivisorHybridOrderBitContradiction _byDivisorHybridOrderTesterBitContradiction;
|
||||
private static ByDivisorGpuOrderBitContradiction _byDivisorGpuOrderTesterBitContradiction;
|
||||
private static ByDivisorCpuOrderBitTree _byDivisorCpuOrderTesterBitTree;
|
||||
private static ByDivisorHybridOrderBitTree _byDivisorHybridOrderTesterBitTree;
|
||||
private static ByDivisorGpuOrderBitTree _byDivisorGpuOrderTesterBitTree;
|
||||
private static Dictionary<ulong, (bool DetailedCheck, bool PassedAllTests)>? _byDivisorPreviousResults;
|
||||
private static string? _byDivisorModelPath;
|
||||
private static bool _byDivisorModeUsesModel;
|
||||
@@ -335,6 +341,12 @@ private static ThreadLocal<object>? MersenneTesters;
|
||||
case ByDivisorKIncrementMode.TopDown:
|
||||
_byDivisorCpuOrderTesterTopDown = new ByDivisorCpuOrderTopDown();
|
||||
break;
|
||||
case ByDivisorKIncrementMode.BitContradiction:
|
||||
_byDivisorCpuOrderTesterBitContradiction = new ByDivisorCpuOrderBitContradiction();
|
||||
break;
|
||||
case ByDivisorKIncrementMode.BitTree:
|
||||
_byDivisorCpuOrderTesterBitTree = new ByDivisorCpuOrderBitTree();
|
||||
break;
|
||||
default:
|
||||
_byDivisorCpuOrderTester = new MersenneNumberDivisorByDivisorCpuTesterWithCpuOrder();
|
||||
break;
|
||||
@@ -359,6 +371,12 @@ private static ThreadLocal<object>? MersenneTesters;
|
||||
case ByDivisorKIncrementMode.TopDown:
|
||||
_byDivisorHybridOrderTesterTopDown = new ByDivisorHybridOrderTopDown();
|
||||
break;
|
||||
case ByDivisorKIncrementMode.BitContradiction:
|
||||
_byDivisorHybridOrderTesterBitContradiction = new ByDivisorHybridOrderBitContradiction();
|
||||
break;
|
||||
case ByDivisorKIncrementMode.BitTree:
|
||||
_byDivisorHybridOrderTesterBitTree = new ByDivisorHybridOrderBitTree();
|
||||
break;
|
||||
default:
|
||||
_byDivisorHybridOrderTester = new MersenneNumberDivisorByDivisorCpuTesterWithHybridOrder();
|
||||
break;
|
||||
@@ -383,6 +401,12 @@ private static ThreadLocal<object>? MersenneTesters;
|
||||
case ByDivisorKIncrementMode.TopDown:
|
||||
_byDivisorGpuOrderTesterTopDown = new ByDivisorGpuOrderTopDown();
|
||||
break;
|
||||
case ByDivisorKIncrementMode.BitContradiction:
|
||||
_byDivisorGpuOrderTesterBitContradiction = new ByDivisorGpuOrderBitContradiction();
|
||||
break;
|
||||
case ByDivisorKIncrementMode.BitTree:
|
||||
_byDivisorGpuOrderTesterBitTree = new ByDivisorGpuOrderBitTree();
|
||||
break;
|
||||
default:
|
||||
_byDivisorGpuOrderTester = new MersenneNumberDivisorByDivisorCpuTesterWithGpuOrder();
|
||||
break;
|
||||
@@ -545,6 +569,7 @@ private static ThreadLocal<object>? MersenneTesters;
|
||||
ByDivisorKIncrementMode.Additive => "additive.kstate.faster",
|
||||
ByDivisorKIncrementMode.TopDown => "topdown.kstate.faster",
|
||||
ByDivisorKIncrementMode.BitContradiction => "bitcontradiction.kstate.faster",
|
||||
ByDivisorKIncrementMode.BitTree => "bittree.kstate.faster",
|
||||
_ => "sequential.kstate.faster",
|
||||
};
|
||||
string lmdbPath = Path.Combine(checksDir, Path.ChangeExtension(kRepoFile, ".lmdb"));
|
||||
@@ -664,7 +689,7 @@ private static ThreadLocal<object>? MersenneTesters;
|
||||
CalculationResultHandler.InitializeOutputBuffer();
|
||||
|
||||
// Limit GPU concurrency only for prime checks (LL/NTT & GPU order scans).
|
||||
GpuPrimeWorkLimiter.SetLimit(gpuPrimeThreads);
|
||||
GpuPrimeWorkLimiter.SetLimit(gpuPrimeThreads * PerfectNumberConstants.ThreadsByAccelerator);
|
||||
// Configure batch size for GPU primality sieve
|
||||
PrimeTester.GpuBatchSize = gpuPrimeBatch;
|
||||
|
||||
@@ -751,6 +776,19 @@ private static ThreadLocal<object>? MersenneTesters;
|
||||
threadCount,
|
||||
byDivisorPrimeRange);
|
||||
break;
|
||||
case ByDivisorKIncrementMode.BitTree:
|
||||
Console.WriteLine("Using by-divisor bit-tree increment (CPU order).");
|
||||
MersenneNumberDivisorByDivisorTester.Run(
|
||||
byDivisorCandidates,
|
||||
ref _byDivisorCpuOrderTesterBitTree,
|
||||
_byDivisorPreviousResults,
|
||||
_byDivisorStartPrime,
|
||||
static () => _lastCompositeP = true,
|
||||
static () => _lastCompositeP = false,
|
||||
HandleByDivisorResult,
|
||||
threadCount,
|
||||
byDivisorPrimeRange);
|
||||
break;
|
||||
default:
|
||||
MersenneNumberDivisorByDivisorTester.Run(
|
||||
byDivisorCandidates,
|
||||
@@ -834,6 +872,19 @@ private static ThreadLocal<object>? MersenneTesters;
|
||||
threadCount,
|
||||
byDivisorPrimeRange);
|
||||
break;
|
||||
case ByDivisorKIncrementMode.BitTree:
|
||||
Console.WriteLine("Using by-divisor bit-tree increment (Hybrid order).");
|
||||
MersenneNumberDivisorByDivisorTester.Run(
|
||||
byDivisorCandidates,
|
||||
ref _byDivisorHybridOrderTesterBitTree,
|
||||
_byDivisorPreviousResults,
|
||||
_byDivisorStartPrime,
|
||||
static () => _lastCompositeP = true,
|
||||
static () => _lastCompositeP = false,
|
||||
HandleByDivisorResult,
|
||||
threadCount,
|
||||
byDivisorPrimeRange);
|
||||
break;
|
||||
default:
|
||||
MersenneNumberDivisorByDivisorTester.Run(
|
||||
byDivisorCandidates,
|
||||
@@ -917,6 +968,19 @@ private static ThreadLocal<object>? MersenneTesters;
|
||||
threadCount,
|
||||
byDivisorPrimeRange);
|
||||
break;
|
||||
case ByDivisorKIncrementMode.BitTree:
|
||||
Console.WriteLine("Using by-divisor bit-tree increment (GPU order).");
|
||||
MersenneNumberDivisorByDivisorTester.Run(
|
||||
byDivisorCandidates,
|
||||
ref _byDivisorGpuOrderTesterBitTree,
|
||||
_byDivisorPreviousResults,
|
||||
_byDivisorStartPrime,
|
||||
static () => _lastCompositeP = true,
|
||||
static () => _lastCompositeP = false,
|
||||
HandleByDivisorResult,
|
||||
threadCount,
|
||||
byDivisorPrimeRange);
|
||||
break;
|
||||
default:
|
||||
MersenneNumberDivisorByDivisorTester.Run(
|
||||
byDivisorCandidates,
|
||||
@@ -1327,6 +1391,7 @@ private static ThreadLocal<object>? MersenneTesters;
|
||||
ByDivisorKIncrementMode.Additive => _byDivisorCpuOrderTesterAdditive.IsPrime(p, out detailedCheck, out _),
|
||||
ByDivisorKIncrementMode.TopDown => _byDivisorCpuOrderTesterTopDown.IsPrime(p, out detailedCheck, out _),
|
||||
ByDivisorKIncrementMode.BitContradiction => _byDivisorCpuOrderTesterBitContradiction.IsPrime(p, out detailedCheck, out _),
|
||||
ByDivisorKIncrementMode.BitTree => _byDivisorCpuOrderTesterBitTree.IsPrime(p, out detailedCheck, out _),
|
||||
_ => _byDivisorCpuOrderTester.IsPrime(p, out detailedCheck, out _),
|
||||
};
|
||||
}
|
||||
@@ -1341,6 +1406,7 @@ private static ThreadLocal<object>? MersenneTesters;
|
||||
ByDivisorKIncrementMode.Additive => _byDivisorHybridOrderTesterAdditive.IsPrime(p, out detailedCheck, out _),
|
||||
ByDivisorKIncrementMode.TopDown => _byDivisorHybridOrderTesterTopDown.IsPrime(p, out detailedCheck, out _),
|
||||
ByDivisorKIncrementMode.BitContradiction => _byDivisorHybridOrderTesterBitContradiction.IsPrime(p, out detailedCheck, out _),
|
||||
ByDivisorKIncrementMode.BitTree => _byDivisorHybridOrderTesterBitTree.IsPrime(p, out detailedCheck, out _),
|
||||
_ => _byDivisorHybridOrderTester.IsPrime(p, out detailedCheck, out _),
|
||||
};
|
||||
}
|
||||
@@ -1353,6 +1419,7 @@ private static ThreadLocal<object>? MersenneTesters;
|
||||
ByDivisorKIncrementMode.Additive => _byDivisorGpuOrderTesterAdditive.IsPrime(p, out detailedCheck, out _),
|
||||
ByDivisorKIncrementMode.TopDown => _byDivisorGpuOrderTesterTopDown.IsPrime(p, out detailedCheck, out _),
|
||||
ByDivisorKIncrementMode.BitContradiction => _byDivisorGpuOrderTesterBitContradiction.IsPrime(p, out detailedCheck, out _),
|
||||
ByDivisorKIncrementMode.BitTree => _byDivisorGpuOrderTesterBitTree.IsPrime(p, out detailedCheck, out _),
|
||||
_ => _byDivisorGpuOrderTester.IsPrime(p, out detailedCheck, out _),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
using System.Numerics;
|
||||
using FluentAssertions;
|
||||
using PerfectNumbers.Core.Cpu;
|
||||
using Xunit;
|
||||
|
||||
namespace PerfectNumbers.Core.Tests;
|
||||
|
||||
public class BitTreeSolverTests
|
||||
{
|
||||
[Fact]
|
||||
public void BitTree_FindsKnownDivisor()
|
||||
{
|
||||
// 2^11-1 = 2047 = 23 * 89, so k=1 yields divisor 23.
|
||||
var tester = new MersenneNumberDivisorByDivisorCpuTesterWithForBitTreeDivisorSetForCpuOrder
|
||||
{
|
||||
DivisorLimit = new BigInteger(1000),
|
||||
MinK = BigInteger.One,
|
||||
};
|
||||
|
||||
bool isPrime = tester.IsPrime(11, out bool exhausted, out BigInteger divisor);
|
||||
|
||||
isPrime.Should().BeFalse();
|
||||
exhausted.Should().BeTrue();
|
||||
divisor.Should().Be(23);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BitTree_ReportsPrimeWhenNoDivisorFound()
|
||||
{
|
||||
// 2^5-1 = 31 is prime.
|
||||
var tester = new MersenneNumberDivisorByDivisorCpuTesterWithForBitTreeDivisorSetForCpuOrder
|
||||
{
|
||||
DivisorLimit = new BigInteger(10_000),
|
||||
MinK = BigInteger.One,
|
||||
};
|
||||
|
||||
bool isPrime = tester.IsPrime(5, out bool exhausted, out BigInteger divisor);
|
||||
|
||||
isPrime.Should().BeTrue();
|
||||
exhausted.Should().BeTrue();
|
||||
divisor.Should().Be(BigInteger.Zero);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -27,6 +27,10 @@ using TesterGpu = PerfectNumbers.Core.Cpu.MersenneNumberDivisorByDivisorCpuTeste
|
||||
using TesterCpu = PerfectNumbers.Core.Cpu.MersenneNumberDivisorByDivisorCpuTesterWithForBitContradictionDivisorSetForCpuOrder;
|
||||
using TesterHybrid = PerfectNumbers.Core.Cpu.MersenneNumberDivisorByDivisorCpuTesterWithForBitContradictionDivisorSetForHybridOrder;
|
||||
using TesterGpu = PerfectNumbers.Core.Cpu.MersenneNumberDivisorByDivisorCpuTesterWithForBitContradictionDivisorSetForGpuOrder;
|
||||
#elif DivisorSet_BitTree
|
||||
using TesterCpu = PerfectNumbers.Core.Cpu.MersenneNumberDivisorByDivisorCpuTesterWithForBitTreeDivisorSetForCpuOrder;
|
||||
using TesterHybrid = PerfectNumbers.Core.Cpu.MersenneNumberDivisorByDivisorCpuTesterWithForBitTreeDivisorSetForHybridOrder;
|
||||
using TesterGpu = PerfectNumbers.Core.Cpu.MersenneNumberDivisorByDivisorCpuTesterWithForBitTreeDivisorSetForGpuOrder;
|
||||
#else
|
||||
using TesterCpu = PerfectNumbers.Core.Cpu.MersenneNumberDivisorByDivisorCpuTesterWithForSequentialDivisorSetForCpuOrder;
|
||||
using TesterHybrid = PerfectNumbers.Core.Cpu.MersenneNumberDivisorByDivisorCpuTesterWithForSequentialDivisorSetForHybridOrder;
|
||||
@@ -91,6 +95,8 @@ internal struct MersenneNumberDivisorByDivisorPrimeScanSessionWithTemplate
|
||||
extension = ".topdown";
|
||||
#elif DivisorSet_BitContradiction
|
||||
extension = ".bitcontradiction";
|
||||
#elif DivisorSet_BitTree
|
||||
extension = ".bittree";
|
||||
#endif
|
||||
string stateFile = prime.ToString(CultureInfo.InvariantCulture) + extension;
|
||||
|
||||
|
||||
@@ -149,7 +149,7 @@ public sealed class PrimeOrderCalculatorAccelerator
|
||||
|
||||
private sealed class CalculatorKernels(Accelerator accelerator)
|
||||
{
|
||||
public readonly Action<AcceleratorStream, Index1D, ulong, CalculateOrderKernelConfig, ulong, ulong, ulong, ulong, ulong, ArrayView1D<uint, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>, int, OrderKernelBuffers> CalculateOrderKernelLauncher = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<Index1D, ulong, CalculateOrderKernelConfig, ulong, ulong, ulong, ulong, ulong, ArrayView1D<uint, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>, int, OrderKernelBuffers>(PrimeOrderKernels.CalculateOrderKernel)).CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ulong, CalculateOrderKernelConfig, ulong, ulong, ulong, ulong, ulong, ArrayView1D<uint, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>, int, OrderKernelBuffers>>();
|
||||
// public readonly Action<AcceleratorStream, Index1D, ulong, CalculateOrderKernelConfig, ulong, ulong, ulong, ulong, ulong, ArrayView1D<uint, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>, int, OrderKernelBuffers> CalculateOrderKernelLauncher = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<Index1D, ulong, CalculateOrderKernelConfig, ulong, ulong, ulong, ulong, ulong, ArrayView1D<uint, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>, int, OrderKernelBuffers>(PrimeOrderKernels.CalculateOrderKernel)).CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ulong, CalculateOrderKernelConfig, ulong, ulong, ulong, ulong, ulong, ArrayView1D<uint, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>, int, OrderKernelBuffers>>();
|
||||
|
||||
public readonly Kernel CheckFactorsKernel = KernelUtil.GetKernel(accelerator.LoadStreamKernel<int, ulong, ArrayView1D<KeyValuePair<ulong, int>, Stride1D.Dense>, ulong, ulong, ulong, ulong, ulong, ArrayView1D<ulong, Stride1D.Dense>>(PrimeOrderKernels.CheckFactorsKernel));
|
||||
|
||||
@@ -177,7 +177,7 @@ public sealed class PrimeOrderCalculatorAccelerator
|
||||
public readonly Action<AcceleratorStream, Index1D, ulong, ArrayView<ulong>, int, ulong, ArrayView<ulong>> SpecialMaxKernelLauncher = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<Index1D, ulong, ArrayView<ulong>, int, ulong, ArrayView<ulong>>(PrimeOrderGpuHeuristics.EvaluateSpecialMaxCandidatesKernel)).CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ulong, ArrayView<ulong>, int, ulong, ArrayView<ulong>>>();
|
||||
}
|
||||
|
||||
public readonly Action<AcceleratorStream, Index1D, ulong, CalculateOrderKernelConfig, ulong, ulong, ulong, ulong, ulong, ArrayView1D<uint, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>, int, OrderKernelBuffers> CalculateOrderKernelLauncher;
|
||||
// public readonly Action<AcceleratorStream, Index1D, ulong, CalculateOrderKernelConfig, ulong, ulong, ulong, ulong, ulong, ArrayView1D<uint, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>, int, OrderKernelBuffers> CalculateOrderKernelLauncher;
|
||||
public readonly Kernel CheckFactorsKernel;
|
||||
public readonly Action<AcceleratorStream, Index1D, ArrayView1D<ulong, Stride1D.Dense>, ulong, ulong, ulong, ulong, ulong, ArrayView1D<ulong, Stride1D.Dense>> ConvertToStandardKernelLauncher;
|
||||
public readonly Action<AcceleratorStream, Index1D, ArrayView<int>, ulong, ulong, ArrayView<ulong>, ArrayView<ulong>> HeuristicCombinedTrialDivisionKernelLauncher;
|
||||
@@ -421,9 +421,9 @@ public sealed class PrimeOrderCalculatorAccelerator
|
||||
DevicePrimesPow2LastThree = lastDigitSharedTables.DevicePrimesPow2LastThree.View;
|
||||
DevicePrimesPow2LastNine = lastDigitSharedTables.DevicePrimesPow2LastNine.View;
|
||||
|
||||
DivisorTables = HeuristicCombinedGpuTables
|
||||
.GetStaticTables(acceleratorIndex)
|
||||
.CreateViews();
|
||||
// DivisorTables = HeuristicCombinedGpuTables
|
||||
// .GetStaticTables(acceleratorIndex)
|
||||
// .CreateViews();
|
||||
|
||||
var smallPrimeFactorTables = SmallPrimeFactorGpuTables.GetStaticTables(acceleratorIndex);
|
||||
|
||||
@@ -436,7 +436,7 @@ public sealed class PrimeOrderCalculatorAccelerator
|
||||
|
||||
var kernels = _kernels[acceleratorIndex];
|
||||
|
||||
CalculateOrderKernelLauncher = kernels.CalculateOrderKernelLauncher;
|
||||
// CalculateOrderKernelLauncher = kernels.CalculateOrderKernelLauncher;
|
||||
CheckFactorsKernel = kernels.CheckFactorsKernel;
|
||||
ConvertToStandardKernelLauncher = kernels.ConvertToStandardKernelLauncher;
|
||||
HeuristicCombinedTrialDivisionKernelLauncher = kernels.HeuristicCombinedTrialDivisionKernelLauncher;
|
||||
|
||||
@@ -272,27 +272,27 @@ internal static partial class PrimeOrderGpuHeuristics
|
||||
var kernelConfig = new CalculateOrderKernelConfig(previousValue, hasPrevious, limit, config.MaxPowChecks, config.StrictMode);
|
||||
ref var buffers = ref gpu.CalculateOrderKernelBuffers;
|
||||
|
||||
var kernelLauncher = gpu.CalculateOrderKernelLauncher;
|
||||
// var kernelLauncher = gpu.CalculateOrderKernelLauncher;
|
||||
|
||||
AcceleratorStream stream = AcceleratorStreamPool.Rent(acceleratorIndex);
|
||||
// TODO: Remove the cleaning after the order kernel is modified to always set the result.
|
||||
resultBufferView.MemSetToZero(stream);
|
||||
statusBufferView.MemSetToZero(stream);
|
||||
|
||||
kernelLauncher(
|
||||
stream,
|
||||
1,
|
||||
prime,
|
||||
kernelConfig,
|
||||
divisorData.Modulus,
|
||||
divisorData.NPrime,
|
||||
divisorData.MontgomeryOne,
|
||||
divisorData.MontgomeryTwo,
|
||||
divisorData.MontgomeryTwoSquared,
|
||||
smallPrimesView,
|
||||
smallSquaresView,
|
||||
(int)smallPrimesView.Length,
|
||||
buffers);
|
||||
// kernelLauncher(
|
||||
// stream,
|
||||
// 1,
|
||||
// prime,
|
||||
// kernelConfig,
|
||||
// divisorData.Modulus,
|
||||
// divisorData.NPrime,
|
||||
// divisorData.MontgomeryOne,
|
||||
// divisorData.MontgomeryTwo,
|
||||
// divisorData.MontgomeryTwoSquared,
|
||||
// smallPrimesView,
|
||||
// smallSquaresView,
|
||||
// (int)smallPrimesView.Length,
|
||||
// buffers);
|
||||
|
||||
|
||||
byte status = 0;
|
||||
|
||||
@@ -21,6 +21,9 @@ using MersenneNumberDivisorByDivisorCpuTesterWithAdditiveGpuOrder = PerfectNumbe
|
||||
using MersenneNumberDivisorByDivisorCpuTesterWithBitContradictionCpuOrder = PerfectNumbers.Core.Cpu.MersenneNumberDivisorByDivisorCpuTesterWithForBitContradictionDivisorSetForCpuOrder;
|
||||
using MersenneNumberDivisorByDivisorCpuTesterWithBitContradictionHybridOrder = PerfectNumbers.Core.Cpu.MersenneNumberDivisorByDivisorCpuTesterWithForBitContradictionDivisorSetForHybridOrder;
|
||||
using MersenneNumberDivisorByDivisorCpuTesterWithBitContradictionGpuOrder = PerfectNumbers.Core.Cpu.MersenneNumberDivisorByDivisorCpuTesterWithForBitContradictionDivisorSetForGpuOrder;
|
||||
using MersenneNumberDivisorByDivisorCpuTesterWithBitTreeCpuOrder = PerfectNumbers.Core.Cpu.MersenneNumberDivisorByDivisorCpuTesterWithForBitTreeDivisorSetForCpuOrder;
|
||||
using MersenneNumberDivisorByDivisorCpuTesterWithBitTreeHybridOrder = PerfectNumbers.Core.Cpu.MersenneNumberDivisorByDivisorCpuTesterWithForBitTreeDivisorSetForHybridOrder;
|
||||
using MersenneNumberDivisorByDivisorCpuTesterWithBitTreeGpuOrder = PerfectNumbers.Core.Cpu.MersenneNumberDivisorByDivisorCpuTesterWithForBitTreeDivisorSetForGpuOrder;
|
||||
|
||||
namespace PerfectNumbers.Core;
|
||||
|
||||
@@ -88,6 +91,37 @@ public static class MersenneNumberDivisorByDivisorTester
|
||||
Action<ulong, bool, bool, bool, BigInteger> pr) =>
|
||||
RunBitContradictionCpuOrderFiltered(filteredPrimes, prototype, workerCount, partitionSize, mc, cc, pr));
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
public static void Run(
|
||||
List<ulong> candidates,
|
||||
ref MersenneNumberDivisorByDivisorCpuTesterWithBitTreeCpuOrder tester,
|
||||
Dictionary<ulong, (bool DetailedCheck, bool PassedAllTests)>? previousResults,
|
||||
ulong startPrime,
|
||||
Action markComposite,
|
||||
Action clearComposite,
|
||||
Action<ulong, bool, bool, bool, BigInteger> printResult,
|
||||
int threadCount,
|
||||
int primesPerTask)
|
||||
=> RunStructTester(
|
||||
candidates,
|
||||
ref tester,
|
||||
previousResults,
|
||||
startPrime,
|
||||
markComposite,
|
||||
clearComposite,
|
||||
printResult,
|
||||
threadCount,
|
||||
primesPerTask,
|
||||
static (
|
||||
List<ulong> filteredPrimes,
|
||||
in MersenneNumberDivisorByDivisorCpuTesterWithBitTreeCpuOrder prototype,
|
||||
int workerCount,
|
||||
int partitionSize,
|
||||
Action mc,
|
||||
Action cc,
|
||||
Action<ulong, bool, bool, bool, BigInteger> pr) =>
|
||||
RunBitTreeCpuOrderFiltered(filteredPrimes, prototype, workerCount, partitionSize, mc, cc, pr));
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
public static void Run(
|
||||
List<ulong> candidates,
|
||||
@@ -243,6 +277,37 @@ public static class MersenneNumberDivisorByDivisorTester
|
||||
Action<ulong, bool, bool, bool, BigInteger> pr) =>
|
||||
RunBitContradictionHybridOrderFiltered(filteredPrimes, prototype, workerCount, partitionSize, mc, cc, pr));
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
public static void Run(
|
||||
List<ulong> candidates,
|
||||
ref MersenneNumberDivisorByDivisorCpuTesterWithBitTreeHybridOrder tester,
|
||||
Dictionary<ulong, (bool DetailedCheck, bool PassedAllTests)>? previousResults,
|
||||
ulong startPrime,
|
||||
Action markComposite,
|
||||
Action clearComposite,
|
||||
Action<ulong, bool, bool, bool, BigInteger> printResult,
|
||||
int threadCount,
|
||||
int primesPerTask)
|
||||
=> RunStructTester(
|
||||
candidates,
|
||||
ref tester,
|
||||
previousResults,
|
||||
startPrime,
|
||||
markComposite,
|
||||
clearComposite,
|
||||
printResult,
|
||||
threadCount,
|
||||
primesPerTask,
|
||||
static (
|
||||
List<ulong> filteredPrimes,
|
||||
in MersenneNumberDivisorByDivisorCpuTesterWithBitTreeHybridOrder prototype,
|
||||
int workerCount,
|
||||
int partitionSize,
|
||||
Action mc,
|
||||
Action cc,
|
||||
Action<ulong, bool, bool, bool, BigInteger> pr) =>
|
||||
RunBitTreeHybridOrderFiltered(filteredPrimes, prototype, workerCount, partitionSize, mc, cc, pr));
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
public static void Run(
|
||||
List<ulong> candidates,
|
||||
@@ -398,6 +463,37 @@ public static class MersenneNumberDivisorByDivisorTester
|
||||
Action<ulong, bool, bool, bool, BigInteger> pr) =>
|
||||
RunBitContradictionGpuOrderFiltered(filteredPrimes, prototype, workerCount, partitionSize, mc, cc, pr));
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
public static void Run(
|
||||
List<ulong> candidates,
|
||||
ref MersenneNumberDivisorByDivisorCpuTesterWithBitTreeGpuOrder tester,
|
||||
Dictionary<ulong, (bool DetailedCheck, bool PassedAllTests)>? previousResults,
|
||||
ulong startPrime,
|
||||
Action markComposite,
|
||||
Action clearComposite,
|
||||
Action<ulong, bool, bool, bool, BigInteger> printResult,
|
||||
int threadCount,
|
||||
int primesPerTask)
|
||||
=> RunStructTester(
|
||||
candidates,
|
||||
ref tester,
|
||||
previousResults,
|
||||
startPrime,
|
||||
markComposite,
|
||||
clearComposite,
|
||||
printResult,
|
||||
threadCount,
|
||||
primesPerTask,
|
||||
static (
|
||||
List<ulong> filteredPrimes,
|
||||
in MersenneNumberDivisorByDivisorCpuTesterWithBitTreeGpuOrder prototype,
|
||||
int workerCount,
|
||||
int partitionSize,
|
||||
Action mc,
|
||||
Action cc,
|
||||
Action<ulong, bool, bool, bool, BigInteger> pr) =>
|
||||
RunBitTreeGpuOrderFiltered(filteredPrimes, prototype, workerCount, partitionSize, mc, cc, pr));
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
public static void Run(
|
||||
List<ulong> candidates,
|
||||
@@ -2575,6 +2671,150 @@ public static class MersenneNumberDivisorByDivisorTester
|
||||
}));
|
||||
}
|
||||
|
||||
private static void RunBitTreeCpuOrderFiltered(
|
||||
List<ulong> filteredPrimes,
|
||||
in MersenneNumberDivisorByDivisorCpuTesterWithBitTreeCpuOrder prototype,
|
||||
int workerCount,
|
||||
int partitionSize,
|
||||
Action markComposite,
|
||||
Action clearComposite,
|
||||
Action<ulong, bool, bool, bool, BigInteger> printResult)
|
||||
{
|
||||
MersenneNumberDivisorByDivisorCpuTesterWithBitTreeCpuOrder prototypeCopy = prototype;
|
||||
int totalCount = filteredPrimes.Count;
|
||||
if (partitionSize > totalCount)
|
||||
{
|
||||
partitionSize = totalCount;
|
||||
}
|
||||
|
||||
if (workerCount <= 1 || totalCount <= partitionSize)
|
||||
{
|
||||
var session = new Cpu.MersenneNumberDivisorByDivisorPrimeScanSessionWithForBitTreeDivisorSetForCpuOrder(prototypeCopy, markComposite, clearComposite, printResult);
|
||||
for (int i = 0; i < totalCount; i++)
|
||||
{
|
||||
session.ProcessPrime(filteredPrimes[i]);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var options = new ParallelOptions
|
||||
{
|
||||
MaxDegreeOfParallelism = workerCount,
|
||||
};
|
||||
|
||||
Parallel.For(
|
||||
0,
|
||||
(int)Math.Ceiling((double)totalCount / partitionSize),
|
||||
options,
|
||||
new Action<int>(partitionIndex =>
|
||||
{
|
||||
int startIndex = partitionIndex * partitionSize;
|
||||
int count = Math.Min(partitionSize, totalCount - startIndex);
|
||||
var session = new Cpu.MersenneNumberDivisorByDivisorPrimeScanSessionWithForBitTreeDivisorSetForCpuOrder(prototypeCopy, markComposite, clearComposite, printResult);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
session.ProcessPrime(filteredPrimes[startIndex + i]);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
private static void RunBitTreeHybridOrderFiltered(
|
||||
List<ulong> filteredPrimes,
|
||||
in MersenneNumberDivisorByDivisorCpuTesterWithBitTreeHybridOrder prototype,
|
||||
int workerCount,
|
||||
int partitionSize,
|
||||
Action markComposite,
|
||||
Action clearComposite,
|
||||
Action<ulong, bool, bool, bool, BigInteger> printResult)
|
||||
{
|
||||
MersenneNumberDivisorByDivisorCpuTesterWithBitTreeHybridOrder prototypeCopy = prototype;
|
||||
int totalCount = filteredPrimes.Count;
|
||||
if (partitionSize > totalCount)
|
||||
{
|
||||
partitionSize = totalCount;
|
||||
}
|
||||
|
||||
if (workerCount <= 1 || totalCount <= partitionSize)
|
||||
{
|
||||
var session = new Cpu.MersenneNumberDivisorByDivisorPrimeScanSessionWithForBitTreeDivisorSetForHybridOrder(prototypeCopy, markComposite, clearComposite, printResult);
|
||||
for (int i = 0; i < totalCount; i++)
|
||||
{
|
||||
session.ProcessPrime(filteredPrimes[i]);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var options = new ParallelOptions
|
||||
{
|
||||
MaxDegreeOfParallelism = workerCount,
|
||||
};
|
||||
|
||||
Parallel.For(
|
||||
0,
|
||||
(int)Math.Ceiling((double)totalCount / partitionSize),
|
||||
options,
|
||||
new Action<int>(partitionIndex =>
|
||||
{
|
||||
int startIndex = partitionIndex * partitionSize;
|
||||
int count = Math.Min(partitionSize, totalCount - startIndex);
|
||||
var session = new Cpu.MersenneNumberDivisorByDivisorPrimeScanSessionWithForBitTreeDivisorSetForHybridOrder(prototypeCopy, markComposite, clearComposite, printResult);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
session.ProcessPrime(filteredPrimes[startIndex + i]);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
private static void RunBitTreeGpuOrderFiltered(
|
||||
List<ulong> filteredPrimes,
|
||||
in MersenneNumberDivisorByDivisorCpuTesterWithBitTreeGpuOrder prototype,
|
||||
int workerCount,
|
||||
int partitionSize,
|
||||
Action markComposite,
|
||||
Action clearComposite,
|
||||
Action<ulong, bool, bool, bool, BigInteger> printResult)
|
||||
{
|
||||
MersenneNumberDivisorByDivisorCpuTesterWithBitTreeGpuOrder prototypeCopy = prototype;
|
||||
int totalCount = filteredPrimes.Count;
|
||||
if (partitionSize > totalCount)
|
||||
{
|
||||
partitionSize = totalCount;
|
||||
}
|
||||
|
||||
if (workerCount <= 1 || totalCount <= partitionSize)
|
||||
{
|
||||
var session = new Cpu.MersenneNumberDivisorByDivisorPrimeScanSessionWithForBitTreeDivisorSetForGpuOrder(prototypeCopy, markComposite, clearComposite, printResult);
|
||||
for (int i = 0; i < totalCount; i++)
|
||||
{
|
||||
session.ProcessPrime(filteredPrimes[i]);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var options = new ParallelOptions
|
||||
{
|
||||
MaxDegreeOfParallelism = workerCount,
|
||||
};
|
||||
|
||||
Parallel.For(
|
||||
0,
|
||||
(int)Math.Ceiling((double)totalCount / partitionSize),
|
||||
options,
|
||||
new Action<int>(partitionIndex =>
|
||||
{
|
||||
int startIndex = partitionIndex * partitionSize;
|
||||
int count = Math.Min(partitionSize, totalCount - startIndex);
|
||||
var session = new Cpu.MersenneNumberDivisorByDivisorPrimeScanSessionWithForBitTreeDivisorSetForGpuOrder(prototypeCopy, markComposite, clearComposite, printResult);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
session.ProcessPrime(filteredPrimes[startIndex + i]);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
private static void RunBitContradictionHybridOrderFiltered(
|
||||
List<ulong> filteredPrimes,
|
||||
in MersenneNumberDivisorByDivisorCpuTesterWithBitContradictionHybridOrder prototype,
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Numerics;
|
||||
using System.Text;
|
||||
using FASTER.core;
|
||||
|
||||
namespace PerfectNumbers.Core.Persistence;
|
||||
|
||||
/// <summary>
|
||||
/// Stores BitTree frontier batches using Microsoft.FASTER.Core.
|
||||
/// Each batch is a byte[] payload containing a sequence of serialized states.
|
||||
/// Maintains a simple head/tail cursor stored inside the KV store.
|
||||
/// </summary>
|
||||
public sealed class BitTreeFrontierRepository : IDisposable
|
||||
{
|
||||
private readonly FasterKV<string, byte[]> _store;
|
||||
private readonly IDevice _logDevice;
|
||||
private readonly IDevice _objectLogDevice;
|
||||
private long _headIndex;
|
||||
private long _tailIndex;
|
||||
private const string HeadKey = "__head__";
|
||||
private const string TailKey = "__tail__";
|
||||
|
||||
public string DatabasePath { get; }
|
||||
|
||||
public static BitTreeFrontierRepository Open(string directory, string repositoryFileName = "bittree.frontier.faster")
|
||||
{
|
||||
Directory.CreateDirectory(directory);
|
||||
string dbPath = Path.Combine(directory, repositoryFileName);
|
||||
return new BitTreeFrontierRepository(dbPath);
|
||||
}
|
||||
|
||||
private BitTreeFrontierRepository(string path)
|
||||
{
|
||||
DatabasePath = path;
|
||||
_logDevice = Devices.CreateLogDevice(path + ".log");
|
||||
_objectLogDevice = Devices.CreateLogDevice(path + ".obj.log");
|
||||
_store = new FasterKV<string, byte[]>(
|
||||
1L << 20,
|
||||
new LogSettings
|
||||
{
|
||||
LogDevice = _logDevice,
|
||||
ObjectLogDevice = _objectLogDevice,
|
||||
});
|
||||
|
||||
LoadCursors();
|
||||
}
|
||||
|
||||
public void AppendBatch(ReadOnlySpan<byte> batch)
|
||||
{
|
||||
using var session = _store.For(new SimpleFunctions<string, byte[]>()).NewSession<SimpleFunctions<string, byte[]>>();
|
||||
string key = BuildChunkKey(_tailIndex);
|
||||
session.Upsert(key, batch.ToArray());
|
||||
_tailIndex++;
|
||||
PersistCursors(session);
|
||||
session.CompletePending(true);
|
||||
_store.Log.FlushAndEvict(true);
|
||||
}
|
||||
|
||||
public bool TryDequeueBatch(int maxCount, out List<byte[]> batches)
|
||||
{
|
||||
batches = new List<byte[]>();
|
||||
using var session = _store.For(new SimpleFunctions<string, byte[]>()).NewSession<SimpleFunctions<string, byte[]>>();
|
||||
|
||||
while (_headIndex < _tailIndex && batches.Count < maxCount)
|
||||
{
|
||||
string key = BuildChunkKey(_headIndex);
|
||||
if (session.Read(key, out byte[]? stored).Found && stored is not null)
|
||||
{
|
||||
batches.Add(stored);
|
||||
session.Delete(key);
|
||||
}
|
||||
|
||||
_headIndex++;
|
||||
}
|
||||
|
||||
|
||||
if (batches.Count > 0)
|
||||
{
|
||||
PersistCursors(session);
|
||||
session.CompletePending(true);
|
||||
_store.Log.FlushAndEvict(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
session.CompletePending(true);
|
||||
_store.Log.FlushAndEvict(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_store.Dispose();
|
||||
_logDevice.Dispose();
|
||||
_objectLogDevice.Dispose();
|
||||
}
|
||||
|
||||
private void LoadCursors()
|
||||
{
|
||||
using var session = _store.For(new SimpleFunctions<string, byte[]>()).NewSession<SimpleFunctions<string, byte[]>>();
|
||||
_headIndex = ReadCursor(session, HeadKey);
|
||||
_tailIndex = ReadCursor(session, TailKey);
|
||||
session.CompletePending(true);
|
||||
}
|
||||
|
||||
private static long ReadCursor(ClientSession<string, byte[], byte[], byte[], Empty, SimpleFunctions<string, byte[]>> session, string key)
|
||||
{
|
||||
if (session.Read(key, out byte[]? stored).Found && stored is not null)
|
||||
{
|
||||
string text = Encoding.UTF8.GetString(stored);
|
||||
if (long.TryParse(text, NumberStyles.Integer, CultureInfo.InvariantCulture, out long value))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private void PersistCursors(ClientSession<string, byte[], byte[], byte[], Empty, SimpleFunctions<string, byte[]>> session)
|
||||
{
|
||||
session.Upsert(HeadKey, Encoding.UTF8.GetBytes(_headIndex.ToString(CultureInfo.InvariantCulture)));
|
||||
session.Upsert(TailKey, Encoding.UTF8.GetBytes(_tailIndex.ToString(CultureInfo.InvariantCulture)));
|
||||
}
|
||||
|
||||
private static string BuildChunkKey(long index) => $"chunk-{index}";
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
# Bit-Tree Divisor Scan
|
||||
|
||||
Plan and notes for the `DivisorSet.BitTree` / `--bydivisor-k-increment=bittree` mode.
|
||||
|
||||
## Goal
|
||||
- Divisor search via joint reconstruction of unknown bits in both the divisor \(q\) (only LSB=1 is known initially) and the cofactor \(a\), matching column-wise carries in \(q \cdot a = 2^p - 1\).
|
||||
- Explore the full bit tree (all admissible \(q,a\) combinations) with early pruning from parity reachability, carry budgets, and length limits; no recursion (explicit stack/queue).
|
||||
- Report primes \(p\) whose entire search space exhausts with no successful branch first.
|
||||
|
||||
## Operational assumptions
|
||||
- \(p\) is odd; we target prime-like divisors with \(q \equiv 1 \pmod{2p}\) but start from bit patterns (q LSB = 1) and let the tree explore.
|
||||
- Work in joint (a,q) space, not tied to a single \(k\). All admissible \(q\) consistent with \(2pk+1\) should be reachable through the bit tree.
|
||||
- Iterative DFS/BFS (explicit stack/queue), no recursion. Process columns streaming (no full 138M+ bit buffers).
|
||||
|
||||
## Implementation steps
|
||||
- [x] Add `BitTree` mode to CLI (`--bydivisor-k-increment`) and state repositories/files; ensure distinct state extensions.
|
||||
- [x] Wire mode through CPU/Hybrid/GPU paths with `.bittree` state files.
|
||||
- [x] Implement core bit-tree solver (frontier/BFS variant):
|
||||
- Joint state: column index, carry, partial `q` (LSB=1), partial `a`, bounds on `a` length (≤ p - bitlen(q)+1), checks against `allowedMax`.
|
||||
- Branching: choose next `q` bit (0/1), derive `a` bit from parity+carry; prune on length overflow, parity unreachable, carry cannot collapse, or `q` beyond allowedMax.
|
||||
- Termination: success iff at/beyond column `p` with carry=0 and no further contributions from `(a,q)`; otherwise contradiction.
|
||||
- [x] Integrate BitTree solver into `CheckDivisorsBitTree`; legacy per-`k` loop removed for this mode.
|
||||
- [ ] Logging: emit Decided/Divides and contradiction reasons; throw if solver cannot decide.
|
||||
- [ ] Tests:
|
||||
- Unit tests on small \(p\) for success/failure paths.
|
||||
- Integration test selecting `DivisorSet.BitTree` to ensure composites are detected and primes pass.
|
||||
- [ ] Docs/help: mention the new mode in help text and README references.
|
||||
|
||||
## Variants considered
|
||||
|
||||
### Variant A (implemented baseline)
|
||||
- Explicit stack-based DFS over `(a,q)` bits with reachability/pruning on parity and carry budgets.
|
||||
- Processes columns sequentially without recursion; suited to small/medium `p` in current form.
|
||||
|
||||
### Variant B (frontier/windowed exploration — in progress)
|
||||
- Implemented: frontier/BFS over branches with sliding window (suffix) storage for `(a,q)` and per-branch carry, bounded by `allowedMax` and `p`; window slides forward to cap memory and drop obsolete history.
|
||||
- Planned enhancement: tune window size/adaptive policy and add optional frontier compression (baseline/delta) for `p ≥ 138M` and many threads.
|
||||
|
||||
### Variant C (frontier with shared baseline/deltas — planned)
|
||||
- For each processed column maintain a shared baseline state (e.g., minimal carry/bit sums across the frontier).
|
||||
- Each branch stores only its delta relative to the baseline (carry delta and the minimal differing `(a,q)` suffix), shrinking per-branch memory.
|
||||
- When compressing the frontier after a window, pick the baseline that minimises aggregate delta size (e.g., minimal sum of carries/bit-counts across surviving branches).
|
||||
- Objective: reduce memory further for highly parallel runs (many threads) while preserving full branch coverage.
|
||||
|
||||
## Current status
|
||||
- Variant A solver is integrated and invoked from `DivisorSet.BitTree` (branch scan path); legacy per-`k` loop is disabled for this mode.
|
||||
- Variant B is not implemented yet; design notes above.
|
||||
|
||||
## Next steps
|
||||
- Implement frontier/windowed solver (Variant B) and add mode toggle if needed.
|
||||
- Prototype baseline/delta compression for the frontier (Variant C) and measure memory savings under parallel load.
|
||||
- Expand tests to cover both variants on small `p` and ensure integration keeps reporting decisions for all candidates.
|
||||
Reference in new issue
Block a user