Initial BitTree implementation added.

This commit is contained in:
mlemanczyk committed 2026-01-09 16:13:16 +01:00
1 parent 45e3455ff3
commit d88ad25476
11 files changed
+3817 -367

No files matched your search

+193 -324
View File
@@ -5,19 +5,20 @@ using PerfectNumbers.Core.Gpu;
namespace EvenPerfectBitScanner; namespace EvenPerfectBitScanner;
internal enum ByDivisorKIncrementMode internal enum ByDivisorKIncrementMode
{ {
Sequential, Sequential,
Pow2Groups, Pow2Groups,
Predictive, Predictive,
Percentile, Percentile,
Additive, Additive,
TopDown, TopDown,
BitContradiction, BitContradiction,
BitTree,
} }
internal readonly struct CliArguments internal readonly struct CliArguments
{ {
private const string DefaultCyclesPath = "divisor_cycles.bin"; private const string DefaultCyclesPath = "divisor_cycles.bin";
internal readonly ulong StartPrime; internal readonly ulong StartPrime;
@@ -35,19 +36,19 @@ namespace EvenPerfectBitScanner;
internal readonly bool UseLucas; internal readonly bool UseLucas;
internal readonly bool UseResidue; internal readonly bool UseResidue;
internal readonly bool UseDivisor; internal readonly bool UseDivisor;
internal readonly bool UseByDivisor; internal readonly bool UseByDivisor;
internal readonly ByDivisorKIncrementMode ByDivisorKIncrementMode; internal readonly ByDivisorKIncrementMode ByDivisorKIncrementMode;
internal readonly int ByDivisorSpecialRange; internal readonly int ByDivisorSpecialRange;
internal readonly bool UseGcdFilter; internal readonly bool UseGcdFilter;
internal readonly bool TestMode; internal readonly bool TestMode;
internal readonly bool UseGpuCycles; internal readonly bool UseGpuCycles;
internal readonly ComputationDevice MersenneDevice; internal readonly ComputationDevice MersenneDevice;
internal readonly ComputationDevice OrderDevice; internal readonly ComputationDevice OrderDevice;
internal readonly int ScanBatchSize; internal readonly int ScanBatchSize;
internal readonly int SliceSize; internal readonly int SliceSize;
internal readonly ulong MaxKLimit; internal readonly ulong MaxKLimit;
internal readonly bool MaxKConfigured; internal readonly bool MaxKConfigured;
internal readonly string FilterFile; internal readonly string FilterFile;
internal readonly bool ForcePrimeKernelsOnCpu; internal readonly bool ForcePrimeKernelsOnCpu;
internal readonly ModReductionMode ModReductionMode; internal readonly ModReductionMode ModReductionMode;
internal readonly NttBackend NttBackend; internal readonly NttBackend NttBackend;
@@ -66,56 +67,56 @@ namespace EvenPerfectBitScanner;
internal readonly double ZeroFractionConjecture; internal readonly double ZeroFractionConjecture;
internal readonly int MaxZeroConjecture; internal readonly int MaxZeroConjecture;
internal readonly BigInteger MinK; internal readonly BigInteger MinK;
internal readonly int GpuRatio; internal readonly int GpuRatio;
private CliArguments( private CliArguments(
ulong startPrime, ulong startPrime,
bool startPrimeProvided, bool startPrimeProvided,
UInt128 maxPrimeLimit, UInt128 maxPrimeLimit,
bool maxPrimeConfigured, bool maxPrimeConfigured,
int threadCount, int threadCount,
int blockSize, int blockSize,
int gpuPrimeThreads, int gpuPrimeThreads,
int gpuPrimeBatch, int gpuPrimeBatch,
GpuKernelType kernelType, GpuKernelType kernelType,
bool useOrder, bool useOrder,
bool showHelp, bool showHelp,
bool useBitTransform, bool useBitTransform,
bool useLucas, bool useLucas,
bool useResidue, bool useResidue,
bool useDivisor, bool useDivisor,
bool useByDivisor, bool useByDivisor,
bool useGcdFilter, bool useGcdFilter,
ByDivisorKIncrementMode byDivisorKIncrementMode, ByDivisorKIncrementMode byDivisorKIncrementMode,
int byDivisorSpecialRange, int byDivisorSpecialRange,
bool testMode, bool testMode,
bool useGpuCycles, bool useGpuCycles,
ComputationDevice mersenneDevice, ComputationDevice mersenneDevice,
ComputationDevice orderDevice, ComputationDevice orderDevice,
int scanBatchSize, int scanBatchSize,
int sliceSize, int sliceSize,
ulong maxKLimit, ulong maxKLimit,
bool maxKConfigured, bool maxKConfigured,
string filterFile, string filterFile,
bool forcePrimeKernelsOnCpu, bool forcePrimeKernelsOnCpu,
ModReductionMode modReductionMode, ModReductionMode modReductionMode,
NttBackend nttBackend, NttBackend nttBackend,
string? resultsDirectory, string? resultsDirectory,
string? resultsPrefix, string? resultsPrefix,
int writeBatchSize, int writeBatchSize,
string cyclesPath, string cyclesPath,
bool continueCyclesGeneration, bool continueCyclesGeneration,
int cyclesBatchSize, int cyclesBatchSize,
ulong divisorCyclesSearchLimit, ulong divisorCyclesSearchLimit,
ulong? orderWarmupLimitOverride, ulong? orderWarmupLimitOverride,
string? rleBlacklistPath, string? rleBlacklistPath,
ulong rleHardMaxP, ulong rleHardMaxP,
bool rleOnlyLast7, bool rleOnlyLast7,
double zeroFractionHard, double zeroFractionHard,
double zeroFractionConjecture, double zeroFractionConjecture,
int maxZeroConjecture, int maxZeroConjecture,
BigInteger minK, BigInteger minK,
int gpuRatio) int gpuRatio)
{ {
StartPrime = startPrime; StartPrime = startPrime;
StartPrimeProvided = startPrimeProvided; StartPrimeProvided = startPrimeProvided;
@@ -163,7 +164,7 @@ namespace EvenPerfectBitScanner;
ZeroFractionConjecture = zeroFractionConjecture; ZeroFractionConjecture = zeroFractionConjecture;
MaxZeroConjecture = maxZeroConjecture; MaxZeroConjecture = maxZeroConjecture;
MinK = minK; MinK = minK;
GpuRatio = gpuRatio; GpuRatio = gpuRatio;
} }
internal bool UseFilter => !TestMode && !string.IsNullOrEmpty(FilterFile); internal bool UseFilter => !TestMode && !string.IsNullOrEmpty(FilterFile);
@@ -204,7 +205,7 @@ namespace EvenPerfectBitScanner;
string? resultsDirectory = null; string? resultsDirectory = null;
string? resultsPrefix = null; string? resultsPrefix = null;
int writeBatchSize = CalculationResultHandler.DefaultWriteBatchSize; int writeBatchSize = CalculationResultHandler.DefaultWriteBatchSize;
string cyclesPath = DefaultCyclesPath; string cyclesPath = DefaultCyclesPath;
bool continueCyclesGeneration = false; bool continueCyclesGeneration = false;
int cyclesBatchSize = 512; int cyclesBatchSize = 512;
ulong divisorCyclesSearchLimit = PerfectNumberConstants.ExtraDivisorCycleSearchLimit; ulong divisorCyclesSearchLimit = PerfectNumberConstants.ExtraDivisorCycleSearchLimit;
@@ -216,7 +217,7 @@ namespace EvenPerfectBitScanner;
double zeroFractionConjecture = -1.0; double zeroFractionConjecture = -1.0;
int maxZeroConjecture = -1; int maxZeroConjecture = -1;
BigInteger minK = BigInteger.One; BigInteger minK = BigInteger.One;
int gpuRatio = PerfectNumberConstants.GpuRatio; int gpuRatio = PerfectNumberConstants.GpuRatio;
foreach (string argument in args) foreach (string argument in args)
{ {
@@ -279,6 +280,19 @@ namespace EvenPerfectBitScanner;
continue; 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)) if (argument.StartsWith("--mersenne=", StringComparison.OrdinalIgnoreCase))
{ {
ReadOnlySpan<char> value = argument.AsSpan("--mersenne=".Length); ReadOnlySpan<char> value = argument.AsSpan("--mersenne=".Length);
@@ -318,138 +332,46 @@ namespace EvenPerfectBitScanner;
if (argument.StartsWith("--bydivisor-k-increment=", StringComparison.OrdinalIgnoreCase)) 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)) if (value.Equals("pow2groups", StringComparison.OrdinalIgnoreCase))
{ {
byDivisorKIncrementMode = ByDivisorKIncrementMode.Pow2Groups; byDivisorKIncrementMode = ByDivisorKIncrementMode.Pow2Groups;
} }
else if (value.Equals("sequential", StringComparison.OrdinalIgnoreCase))
{
byDivisorKIncrementMode = ByDivisorKIncrementMode.Sequential;
}
else if (value.Equals("predictive", StringComparison.OrdinalIgnoreCase)) else if (value.Equals("predictive", StringComparison.OrdinalIgnoreCase))
{ {
byDivisorKIncrementMode = ByDivisorKIncrementMode.Predictive; byDivisorKIncrementMode = ByDivisorKIncrementMode.Predictive;
} }
else if (value.Equals("percentile", StringComparison.OrdinalIgnoreCase)) else if (value.Equals("percentile", StringComparison.OrdinalIgnoreCase))
{ {
byDivisorKIncrementMode = ByDivisorKIncrementMode.Percentile; byDivisorKIncrementMode = ByDivisorKIncrementMode.Percentile;
} }
else if (value.Equals("additive", StringComparison.OrdinalIgnoreCase)) else if (value.Equals("additive", StringComparison.OrdinalIgnoreCase))
{ {
byDivisorKIncrementMode = ByDivisorKIncrementMode.Additive; byDivisorKIncrementMode = ByDivisorKIncrementMode.Additive;
} }
else if (value.Equals("topdown", StringComparison.OrdinalIgnoreCase)) else if (value.Equals("topdown", StringComparison.OrdinalIgnoreCase))
{ {
byDivisorKIncrementMode = ByDivisorKIncrementMode.TopDown; byDivisorKIncrementMode = ByDivisorKIncrementMode.TopDown;
} }
else if (value.Equals("bitcontradiction", StringComparison.OrdinalIgnoreCase)) else if (value.Equals("bitcontradiction", StringComparison.OrdinalIgnoreCase))
{ {
byDivisorKIncrementMode = ByDivisorKIncrementMode.BitContradiction; byDivisorKIncrementMode = ByDivisorKIncrementMode.BitContradiction;
} }
else else if (value.Equals("bittree", StringComparison.OrdinalIgnoreCase))
{ {
Console.WriteLine("Invalid value for --bydivisor-k-increment. Use sequential, pow2groups, predictive, percentile, additive, topdown, or bitcontradiction."); byDivisorKIncrementMode = ByDivisorKIncrementMode.BitTree;
return default; }
} else
{
byDivisorKIncrementMode = ByDivisorKIncrementMode.Sequential;
}
continue; continue;
} }
if (argument.StartsWith("--bydivisor-special-range=", StringComparison.OrdinalIgnoreCase)) if (argument.StartsWith("--bydivisor-special-range=", StringComparison.OrdinalIgnoreCase))
{ {
if (Utf8CliParser.TryParseInt32(argument.AsSpan("--bydivisor-special-range=".Length), out int parsedRange) && parsedRange >= 0) byDivisorSpecialRange = Utf8CliParser.ParseInt32(argument.AsSpan("--bydivisor-special-range=".Length));
{
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;
}
continue; continue;
} }
@@ -459,138 +381,30 @@ namespace EvenPerfectBitScanner;
continue; continue;
} }
if (argument.StartsWith("--ntt=", StringComparison.OrdinalIgnoreCase)) if (argument.Equals("--test-mode", StringComparison.OrdinalIgnoreCase))
{ {
ReadOnlySpan<char> value = argument.AsSpan("--ntt=".Length); testMode = true;
nttBackend = value.Equals("staged", StringComparison.OrdinalIgnoreCase) ? NttBackend.Staged : NttBackend.Reference;
continue; continue;
} }
if (argument.StartsWith("--mod-reduction=", StringComparison.OrdinalIgnoreCase)) if (argument.StartsWith("--mersenne-device=", StringComparison.OrdinalIgnoreCase))
{ {
ReadOnlySpan<char> value = argument.AsSpan("--mod-reduction=".Length); mersenneDevice = ParseDevice(argument.AsSpan("--mersenne-device=".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;
}
continue; 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; continue;
} }
if (argument.StartsWith("--order-device=", StringComparison.OrdinalIgnoreCase)) if (argument.StartsWith("--order-device=", StringComparison.OrdinalIgnoreCase))
{ {
ReadOnlySpan<char> value = argument.AsSpan("--order-device=".Length); orderDevice = ParseDevice(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)));
continue; continue;
} }
@@ -600,6 +414,12 @@ namespace EvenPerfectBitScanner;
continue; 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)) if (argument.StartsWith("--ll-slice=", StringComparison.OrdinalIgnoreCase))
{ {
sliceSize = Math.Max(1, Utf8CliParser.ParseInt32(argument.AsSpan("--ll-slice=".Length))); sliceSize = Math.Max(1, Utf8CliParser.ParseInt32(argument.AsSpan("--ll-slice=".Length)));
@@ -618,6 +438,54 @@ namespace EvenPerfectBitScanner;
continue; 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)) if (argument.StartsWith("--filter-p=", StringComparison.OrdinalIgnoreCase))
{ {
filterFile = argument["--filter-p=".Length..]; filterFile = argument["--filter-p=".Length..];
@@ -651,6 +519,7 @@ namespace EvenPerfectBitScanner;
if (argument.Equals("--divisor-cycles-continue", StringComparison.OrdinalIgnoreCase)) if (argument.Equals("--divisor-cycles-continue", StringComparison.OrdinalIgnoreCase))
{ {
continueCyclesGeneration = true; continueCyclesGeneration = true;
continue;
} }
} }
@@ -659,15 +528,15 @@ namespace EvenPerfectBitScanner;
startPrimeProvided, startPrimeProvided,
maxPrimeLimit, maxPrimeLimit,
maxPrimeConfigured, maxPrimeConfigured,
threadCount, threadCount,
blockSize, blockSize,
gpuPrimeThreads, gpuPrimeThreads,
gpuPrimeBatch, gpuPrimeBatch,
kernelType, kernelType,
useOrder, useOrder,
showHelp, showHelp,
useBitTransform, useBitTransform,
useLucas, useLucas,
useResidue, useResidue,
useDivisor, useDivisor,
useByDivisor, useByDivisor,
@@ -701,7 +570,7 @@ namespace EvenPerfectBitScanner;
zeroFractionConjecture, zeroFractionConjecture,
maxZeroConjecture, maxZeroConjecture,
minK, minK,
gpuRatio); gpuRatio);
} }
internal static void PrintHelp() internal static void PrintHelp()
@@ -715,14 +584,14 @@ namespace EvenPerfectBitScanner;
Console.WriteLine(" --increment=bit|add exponent increment method (default add)"); Console.WriteLine(" --increment=bit|add exponent increment method (default add)");
Console.WriteLine(" --threads=<value> number of worker threads"); Console.WriteLine(" --threads=<value> number of worker threads");
Console.WriteLine(" --mersenne=pow2mod|incremental|lucas|residue|divisor|bydivisor Mersenne test method"); 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(" --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(" --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(" --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(" --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-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(" --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(" --order-device=cpu|gpu|hybrid Device for order computations (default gpu)");
Console.WriteLine(" --ll-slice=<value> Lucas–Lehmer iterations per slice (default 32)"); Console.WriteLine(" --ll-slice=<value> Lucas–Lehmer iterations per slice (default 32)");
+68 -1
View File
@@ -32,6 +32,9 @@ using ByDivisorGpuOrderTopDown = PerfectNumbers.Core.Cpu.MersenneNumberDivisorBy
using ByDivisorCpuOrderBitContradiction = PerfectNumbers.Core.Cpu.MersenneNumberDivisorByDivisorCpuTesterWithForBitContradictionDivisorSetForCpuOrder; using ByDivisorCpuOrderBitContradiction = PerfectNumbers.Core.Cpu.MersenneNumberDivisorByDivisorCpuTesterWithForBitContradictionDivisorSetForCpuOrder;
using ByDivisorHybridOrderBitContradiction = PerfectNumbers.Core.Cpu.MersenneNumberDivisorByDivisorCpuTesterWithForBitContradictionDivisorSetForHybridOrder; using ByDivisorHybridOrderBitContradiction = PerfectNumbers.Core.Cpu.MersenneNumberDivisorByDivisorCpuTesterWithForBitContradictionDivisorSetForHybridOrder;
using ByDivisorGpuOrderBitContradiction = PerfectNumbers.Core.Cpu.MersenneNumberDivisorByDivisorCpuTesterWithForBitContradictionDivisorSetForGpuOrder; 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; using System.Globalization;
namespace EvenPerfectBitScanner; namespace EvenPerfectBitScanner;
@@ -64,6 +67,9 @@ private static ThreadLocal<object>? MersenneTesters;
private static ByDivisorCpuOrderBitContradiction _byDivisorCpuOrderTesterBitContradiction; private static ByDivisorCpuOrderBitContradiction _byDivisorCpuOrderTesterBitContradiction;
private static ByDivisorHybridOrderBitContradiction _byDivisorHybridOrderTesterBitContradiction; private static ByDivisorHybridOrderBitContradiction _byDivisorHybridOrderTesterBitContradiction;
private static ByDivisorGpuOrderBitContradiction _byDivisorGpuOrderTesterBitContradiction; 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 Dictionary<ulong, (bool DetailedCheck, bool PassedAllTests)>? _byDivisorPreviousResults;
private static string? _byDivisorModelPath; private static string? _byDivisorModelPath;
private static bool _byDivisorModeUsesModel; private static bool _byDivisorModeUsesModel;
@@ -335,6 +341,12 @@ private static ThreadLocal<object>? MersenneTesters;
case ByDivisorKIncrementMode.TopDown: case ByDivisorKIncrementMode.TopDown:
_byDivisorCpuOrderTesterTopDown = new ByDivisorCpuOrderTopDown(); _byDivisorCpuOrderTesterTopDown = new ByDivisorCpuOrderTopDown();
break; break;
case ByDivisorKIncrementMode.BitContradiction:
_byDivisorCpuOrderTesterBitContradiction = new ByDivisorCpuOrderBitContradiction();
break;
case ByDivisorKIncrementMode.BitTree:
_byDivisorCpuOrderTesterBitTree = new ByDivisorCpuOrderBitTree();
break;
default: default:
_byDivisorCpuOrderTester = new MersenneNumberDivisorByDivisorCpuTesterWithCpuOrder(); _byDivisorCpuOrderTester = new MersenneNumberDivisorByDivisorCpuTesterWithCpuOrder();
break; break;
@@ -359,6 +371,12 @@ private static ThreadLocal<object>? MersenneTesters;
case ByDivisorKIncrementMode.TopDown: case ByDivisorKIncrementMode.TopDown:
_byDivisorHybridOrderTesterTopDown = new ByDivisorHybridOrderTopDown(); _byDivisorHybridOrderTesterTopDown = new ByDivisorHybridOrderTopDown();
break; break;
case ByDivisorKIncrementMode.BitContradiction:
_byDivisorHybridOrderTesterBitContradiction = new ByDivisorHybridOrderBitContradiction();
break;
case ByDivisorKIncrementMode.BitTree:
_byDivisorHybridOrderTesterBitTree = new ByDivisorHybridOrderBitTree();
break;
default: default:
_byDivisorHybridOrderTester = new MersenneNumberDivisorByDivisorCpuTesterWithHybridOrder(); _byDivisorHybridOrderTester = new MersenneNumberDivisorByDivisorCpuTesterWithHybridOrder();
break; break;
@@ -383,6 +401,12 @@ private static ThreadLocal<object>? MersenneTesters;
case ByDivisorKIncrementMode.TopDown: case ByDivisorKIncrementMode.TopDown:
_byDivisorGpuOrderTesterTopDown = new ByDivisorGpuOrderTopDown(); _byDivisorGpuOrderTesterTopDown = new ByDivisorGpuOrderTopDown();
break; break;
case ByDivisorKIncrementMode.BitContradiction:
_byDivisorGpuOrderTesterBitContradiction = new ByDivisorGpuOrderBitContradiction();
break;
case ByDivisorKIncrementMode.BitTree:
_byDivisorGpuOrderTesterBitTree = new ByDivisorGpuOrderBitTree();
break;
default: default:
_byDivisorGpuOrderTester = new MersenneNumberDivisorByDivisorCpuTesterWithGpuOrder(); _byDivisorGpuOrderTester = new MersenneNumberDivisorByDivisorCpuTesterWithGpuOrder();
break; break;
@@ -545,6 +569,7 @@ private static ThreadLocal<object>? MersenneTesters;
ByDivisorKIncrementMode.Additive => "additive.kstate.faster", ByDivisorKIncrementMode.Additive => "additive.kstate.faster",
ByDivisorKIncrementMode.TopDown => "topdown.kstate.faster", ByDivisorKIncrementMode.TopDown => "topdown.kstate.faster",
ByDivisorKIncrementMode.BitContradiction => "bitcontradiction.kstate.faster", ByDivisorKIncrementMode.BitContradiction => "bitcontradiction.kstate.faster",
ByDivisorKIncrementMode.BitTree => "bittree.kstate.faster",
_ => "sequential.kstate.faster", _ => "sequential.kstate.faster",
}; };
string lmdbPath = Path.Combine(checksDir, Path.ChangeExtension(kRepoFile, ".lmdb")); string lmdbPath = Path.Combine(checksDir, Path.ChangeExtension(kRepoFile, ".lmdb"));
@@ -664,7 +689,7 @@ private static ThreadLocal<object>? MersenneTesters;
CalculationResultHandler.InitializeOutputBuffer(); CalculationResultHandler.InitializeOutputBuffer();
// Limit GPU concurrency only for prime checks (LL/NTT & GPU order scans). // 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 // Configure batch size for GPU primality sieve
PrimeTester.GpuBatchSize = gpuPrimeBatch; PrimeTester.GpuBatchSize = gpuPrimeBatch;
@@ -751,6 +776,19 @@ private static ThreadLocal<object>? MersenneTesters;
threadCount, threadCount,
byDivisorPrimeRange); byDivisorPrimeRange);
break; 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: default:
MersenneNumberDivisorByDivisorTester.Run( MersenneNumberDivisorByDivisorTester.Run(
byDivisorCandidates, byDivisorCandidates,
@@ -834,6 +872,19 @@ private static ThreadLocal<object>? MersenneTesters;
threadCount, threadCount,
byDivisorPrimeRange); byDivisorPrimeRange);
break; 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: default:
MersenneNumberDivisorByDivisorTester.Run( MersenneNumberDivisorByDivisorTester.Run(
byDivisorCandidates, byDivisorCandidates,
@@ -917,6 +968,19 @@ private static ThreadLocal<object>? MersenneTesters;
threadCount, threadCount,
byDivisorPrimeRange); byDivisorPrimeRange);
break; 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: default:
MersenneNumberDivisorByDivisorTester.Run( MersenneNumberDivisorByDivisorTester.Run(
byDivisorCandidates, byDivisorCandidates,
@@ -1327,6 +1391,7 @@ private static ThreadLocal<object>? MersenneTesters;
ByDivisorKIncrementMode.Additive => _byDivisorCpuOrderTesterAdditive.IsPrime(p, out detailedCheck, out _), ByDivisorKIncrementMode.Additive => _byDivisorCpuOrderTesterAdditive.IsPrime(p, out detailedCheck, out _),
ByDivisorKIncrementMode.TopDown => _byDivisorCpuOrderTesterTopDown.IsPrime(p, out detailedCheck, out _), ByDivisorKIncrementMode.TopDown => _byDivisorCpuOrderTesterTopDown.IsPrime(p, out detailedCheck, out _),
ByDivisorKIncrementMode.BitContradiction => _byDivisorCpuOrderTesterBitContradiction.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 _), _ => _byDivisorCpuOrderTester.IsPrime(p, out detailedCheck, out _),
}; };
} }
@@ -1341,6 +1406,7 @@ private static ThreadLocal<object>? MersenneTesters;
ByDivisorKIncrementMode.Additive => _byDivisorHybridOrderTesterAdditive.IsPrime(p, out detailedCheck, out _), ByDivisorKIncrementMode.Additive => _byDivisorHybridOrderTesterAdditive.IsPrime(p, out detailedCheck, out _),
ByDivisorKIncrementMode.TopDown => _byDivisorHybridOrderTesterTopDown.IsPrime(p, out detailedCheck, out _), ByDivisorKIncrementMode.TopDown => _byDivisorHybridOrderTesterTopDown.IsPrime(p, out detailedCheck, out _),
ByDivisorKIncrementMode.BitContradiction => _byDivisorHybridOrderTesterBitContradiction.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 _), _ => _byDivisorHybridOrderTester.IsPrime(p, out detailedCheck, out _),
}; };
} }
@@ -1353,6 +1419,7 @@ private static ThreadLocal<object>? MersenneTesters;
ByDivisorKIncrementMode.Additive => _byDivisorGpuOrderTesterAdditive.IsPrime(p, out detailedCheck, out _), ByDivisorKIncrementMode.Additive => _byDivisorGpuOrderTesterAdditive.IsPrime(p, out detailedCheck, out _),
ByDivisorKIncrementMode.TopDown => _byDivisorGpuOrderTesterTopDown.IsPrime(p, out detailedCheck, out _), ByDivisorKIncrementMode.TopDown => _byDivisorGpuOrderTesterTopDown.IsPrime(p, out detailedCheck, out _),
ByDivisorKIncrementMode.BitContradiction => _byDivisorGpuOrderTesterBitContradiction.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 _), _ => _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 TesterCpu = PerfectNumbers.Core.Cpu.MersenneNumberDivisorByDivisorCpuTesterWithForBitContradictionDivisorSetForCpuOrder;
using TesterHybrid = PerfectNumbers.Core.Cpu.MersenneNumberDivisorByDivisorCpuTesterWithForBitContradictionDivisorSetForHybridOrder; using TesterHybrid = PerfectNumbers.Core.Cpu.MersenneNumberDivisorByDivisorCpuTesterWithForBitContradictionDivisorSetForHybridOrder;
using TesterGpu = PerfectNumbers.Core.Cpu.MersenneNumberDivisorByDivisorCpuTesterWithForBitContradictionDivisorSetForGpuOrder; 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 #else
using TesterCpu = PerfectNumbers.Core.Cpu.MersenneNumberDivisorByDivisorCpuTesterWithForSequentialDivisorSetForCpuOrder; using TesterCpu = PerfectNumbers.Core.Cpu.MersenneNumberDivisorByDivisorCpuTesterWithForSequentialDivisorSetForCpuOrder;
using TesterHybrid = PerfectNumbers.Core.Cpu.MersenneNumberDivisorByDivisorCpuTesterWithForSequentialDivisorSetForHybridOrder; using TesterHybrid = PerfectNumbers.Core.Cpu.MersenneNumberDivisorByDivisorCpuTesterWithForSequentialDivisorSetForHybridOrder;
@@ -91,6 +95,8 @@ internal struct MersenneNumberDivisorByDivisorPrimeScanSessionWithTemplate
extension = ".topdown"; extension = ".topdown";
#elif DivisorSet_BitContradiction #elif DivisorSet_BitContradiction
extension = ".bitcontradiction"; extension = ".bitcontradiction";
#elif DivisorSet_BitTree
extension = ".bittree";
#endif #endif
string stateFile = prime.ToString(CultureInfo.InvariantCulture) + extension; string stateFile = prime.ToString(CultureInfo.InvariantCulture) + extension;
@@ -149,7 +149,7 @@ public sealed class PrimeOrderCalculatorAccelerator
private sealed class CalculatorKernels(Accelerator accelerator) 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)); 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, 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 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, 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; 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; DevicePrimesPow2LastThree = lastDigitSharedTables.DevicePrimesPow2LastThree.View;
DevicePrimesPow2LastNine = lastDigitSharedTables.DevicePrimesPow2LastNine.View; DevicePrimesPow2LastNine = lastDigitSharedTables.DevicePrimesPow2LastNine.View;
DivisorTables = HeuristicCombinedGpuTables // DivisorTables = HeuristicCombinedGpuTables
.GetStaticTables(acceleratorIndex) // .GetStaticTables(acceleratorIndex)
.CreateViews(); // .CreateViews();
var smallPrimeFactorTables = SmallPrimeFactorGpuTables.GetStaticTables(acceleratorIndex); var smallPrimeFactorTables = SmallPrimeFactorGpuTables.GetStaticTables(acceleratorIndex);
@@ -436,7 +436,7 @@ public sealed class PrimeOrderCalculatorAccelerator
var kernels = _kernels[acceleratorIndex]; var kernels = _kernels[acceleratorIndex];
CalculateOrderKernelLauncher = kernels.CalculateOrderKernelLauncher; // CalculateOrderKernelLauncher = kernels.CalculateOrderKernelLauncher;
CheckFactorsKernel = kernels.CheckFactorsKernel; CheckFactorsKernel = kernels.CheckFactorsKernel;
ConvertToStandardKernelLauncher = kernels.ConvertToStandardKernelLauncher; ConvertToStandardKernelLauncher = kernels.ConvertToStandardKernelLauncher;
HeuristicCombinedTrialDivisionKernelLauncher = kernels.HeuristicCombinedTrialDivisionKernelLauncher; HeuristicCombinedTrialDivisionKernelLauncher = kernels.HeuristicCombinedTrialDivisionKernelLauncher;
@@ -272,27 +272,27 @@ internal static partial class PrimeOrderGpuHeuristics
var kernelConfig = new CalculateOrderKernelConfig(previousValue, hasPrevious, limit, config.MaxPowChecks, config.StrictMode); var kernelConfig = new CalculateOrderKernelConfig(previousValue, hasPrevious, limit, config.MaxPowChecks, config.StrictMode);
ref var buffers = ref gpu.CalculateOrderKernelBuffers; ref var buffers = ref gpu.CalculateOrderKernelBuffers;
var kernelLauncher = gpu.CalculateOrderKernelLauncher; // var kernelLauncher = gpu.CalculateOrderKernelLauncher;
AcceleratorStream stream = AcceleratorStreamPool.Rent(acceleratorIndex); AcceleratorStream stream = AcceleratorStreamPool.Rent(acceleratorIndex);
// TODO: Remove the cleaning after the order kernel is modified to always set the result. // TODO: Remove the cleaning after the order kernel is modified to always set the result.
resultBufferView.MemSetToZero(stream); resultBufferView.MemSetToZero(stream);
statusBufferView.MemSetToZero(stream); statusBufferView.MemSetToZero(stream);
kernelLauncher( // kernelLauncher(
stream, // stream,
1, // 1,
prime, // prime,
kernelConfig, // kernelConfig,
divisorData.Modulus, // divisorData.Modulus,
divisorData.NPrime, // divisorData.NPrime,
divisorData.MontgomeryOne, // divisorData.MontgomeryOne,
divisorData.MontgomeryTwo, // divisorData.MontgomeryTwo,
divisorData.MontgomeryTwoSquared, // divisorData.MontgomeryTwoSquared,
smallPrimesView, // smallPrimesView,
smallSquaresView, // smallSquaresView,
(int)smallPrimesView.Length, // (int)smallPrimesView.Length,
buffers); // buffers);
byte status = 0; byte status = 0;
@@ -21,6 +21,9 @@ using MersenneNumberDivisorByDivisorCpuTesterWithAdditiveGpuOrder = PerfectNumbe
using MersenneNumberDivisorByDivisorCpuTesterWithBitContradictionCpuOrder = PerfectNumbers.Core.Cpu.MersenneNumberDivisorByDivisorCpuTesterWithForBitContradictionDivisorSetForCpuOrder; using MersenneNumberDivisorByDivisorCpuTesterWithBitContradictionCpuOrder = PerfectNumbers.Core.Cpu.MersenneNumberDivisorByDivisorCpuTesterWithForBitContradictionDivisorSetForCpuOrder;
using MersenneNumberDivisorByDivisorCpuTesterWithBitContradictionHybridOrder = PerfectNumbers.Core.Cpu.MersenneNumberDivisorByDivisorCpuTesterWithForBitContradictionDivisorSetForHybridOrder; using MersenneNumberDivisorByDivisorCpuTesterWithBitContradictionHybridOrder = PerfectNumbers.Core.Cpu.MersenneNumberDivisorByDivisorCpuTesterWithForBitContradictionDivisorSetForHybridOrder;
using MersenneNumberDivisorByDivisorCpuTesterWithBitContradictionGpuOrder = PerfectNumbers.Core.Cpu.MersenneNumberDivisorByDivisorCpuTesterWithForBitContradictionDivisorSetForGpuOrder; 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; namespace PerfectNumbers.Core;
@@ -88,6 +91,37 @@ public static class MersenneNumberDivisorByDivisorTester
Action<ulong, bool, bool, bool, BigInteger> pr) => Action<ulong, bool, bool, bool, BigInteger> pr) =>
RunBitContradictionCpuOrderFiltered(filteredPrimes, prototype, workerCount, partitionSize, mc, cc, 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)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public static void Run( public static void Run(
List<ulong> candidates, List<ulong> candidates,
@@ -243,6 +277,37 @@ public static class MersenneNumberDivisorByDivisorTester
Action<ulong, bool, bool, bool, BigInteger> pr) => Action<ulong, bool, bool, bool, BigInteger> pr) =>
RunBitContradictionHybridOrderFiltered(filteredPrimes, prototype, workerCount, partitionSize, mc, cc, 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)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public static void Run( public static void Run(
List<ulong> candidates, List<ulong> candidates,
@@ -398,6 +463,37 @@ public static class MersenneNumberDivisorByDivisorTester
Action<ulong, bool, bool, bool, BigInteger> pr) => Action<ulong, bool, bool, bool, BigInteger> pr) =>
RunBitContradictionGpuOrderFiltered(filteredPrimes, prototype, workerCount, partitionSize, mc, cc, 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)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public static void Run( public static void Run(
List<ulong> candidates, 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( private static void RunBitContradictionHybridOrderFiltered(
List<ulong> filteredPrimes, List<ulong> filteredPrimes,
in MersenneNumberDivisorByDivisorCpuTesterWithBitContradictionHybridOrder prototype, 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}";
}
+52
View File
@@ -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.