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;
|
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)");
|
||||||
|
|||||||
@@ -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}";
|
||||||
|
}
|
||||||
@@ -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