BitContradiction adjusted for p >= 138 mln, based on carry out analysis of the first 1024 columns.

This commit is contained in:
Marek Lemańczyk committed 2026-02-12 17:04:23 +01:00
1 parent 22cc8f368f
commit fea95509a7
2 files changed
+222 -58

No files matched your search

@@ -9,6 +9,7 @@ internal sealed class PrivateWorkSet
{
// Active hot-path scratch buffer.
public ulong[] KnownOne1 = [];
public int[] CarryDropActiveAIndices = [];
#if false
private const int QPrefixReverseCacheSize = 1024;
@@ -57,13 +58,18 @@ internal sealed class PrivateWorkSet
#endif
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void EnsureCapacity(int wordCount, int qWordCount)
public void EnsureCapacity(int wordCount, int qWordCount, int carryDropActiveCount)
{
if (KnownOne1.Length < wordCount)
{
EnsureUlong(ref KnownOne1, wordCount);
}
if (CarryDropActiveAIndices.Length < carryDropActiveCount)
{
EnsureInt(ref CarryDropActiveAIndices, carryDropActiveCount);
}
#if false
if (KnownOne0.Length < wordCount)
{
@@ -124,10 +130,9 @@ internal sealed class PrivateWorkSet
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void EnsureUlong(ref ulong[] arr, int needed) => Array.Resize(ref arr, needed);
#if false
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void EnsureInt(ref int[] arr, int needed) => Array.Resize(ref arr, needed);
#endif
}
/// <summary>
/// Helper utilities for the BitContradiction divisor search. These methods implement the
@@ -191,6 +196,7 @@ internal static class BitContradictionSolverWithAMultiplier
private static ulong _prunedWithCarryDominance15161718;
private static ulong _prunedWithCarryDominanceReached10AndStayedAbove5;
private static ulong _prunedWithCarryDominance1011121314;
private static ulong _prunedWithHighDensityWithShortLowStreaksCarry;
#endif
@@ -250,7 +256,8 @@ internal static class BitContradictionSolverWithAMultiplier
$"CarryDominance8910AndMore={_prunedWithCarryDominance8910}, " +
$"CarryDominance15161718={_prunedWithCarryDominance15161718}, " +
$"CarryDominanceReached10AndStayedAbove5={_prunedWithCarryDominanceReached10AndStayedAbove5}, " +
$"CarryDominance1011121314={_prunedWithCarryDominance1011121314}"
$"CarryDominance1011121314={_prunedWithCarryDominance1011121314}, " +
$"HighDensityWithShortLowStreaksCarry={_prunedWithHighDensityWithShortLowStreaksCarry}"
);
}
#endif
@@ -2318,13 +2325,36 @@ internal static class BitContradictionSolverWithAMultiplier
Dominance15161718Drop = 4,
DominanceReached10AndStayedAbove5 = 5,
Dominance1011121314 = 6,
HighDensityWithShortLowStreaks = 7,
}
private static readonly BigInteger _testCase = BigInteger.Parse("337429718205079");
// #if WITH_PRUNE_STATS
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void TraceCarryDropHeuristicPrune(
int pLong,
BigInteger qExact,
CarryDropPruneReason pruneReason,
bool reached10,
bool reachedBelow5,
int reached5,
int zeroCount)
{
if (pLong == 138000953 && qExact.Equals(_testCase))
{
Console.WriteLine($"CarryDrop target reached: p={pLong}, q={qExact}, reason={pruneReason}, reached10={reached10}, reachedBelow5={reachedBelow5}, reached5={reached5}, zeroCount={zeroCount}");
}
}
// #endif
private static bool TryCarryDropHeuristicPrune(
BigInteger qExact,
ReadOnlySpan<int> qOneOffsets,
int pLong,
int maxAllowedA,
ulong[] aBitsBuffer,
int[] activeAIndicesBuffer,
out CarryDropPruneReason pruneReason)
{
pruneReason = CarryDropPruneReason.None;
@@ -2350,7 +2380,8 @@ internal static class BitContradictionSolverWithAMultiplier
}
int wordCount = (bitLimit + 63) >> 6;
if ((uint)wordCount > (uint)aBitsBuffer.Length)
int qOneOffsetsLength = qOneOffsets.Length;
if ((uint)wordCount > (uint)aBitsBuffer.Length || (uint)qOneOffsetsLength > (uint)activeAIndicesBuffer.Length)
{
return false;
}
@@ -2360,10 +2391,9 @@ internal static class BitContradictionSolverWithAMultiplier
long carry = 0;
bool hadPositiveCarry = false;
int upperOffsetExclusive = 1;
int qOneOffsetsLength = qOneOffsets.Length;
int totalCarry67Count = 0,
int totalCarry6Count = 0,
totalCarry7Count = 0,
totalCarry8Count = 0,
totalCarry9Count = 0,
totalCarry10Count = 0,
@@ -2371,9 +2401,15 @@ internal static class BitContradictionSolverWithAMultiplier
totalCarry12Count = 0,
totalCarry13Count = 0,
totalCarry14Count = 0,
totalCarry15Count = 0;//, totalCarry16Count = 0, totalCarry17Count = 0, totalCarry18Count = 0;
totalCarry15Count = 0,
totalCarry01234Count = 0,
totalCarryFirst32Count = 0,
totalCarryAbove10 = 0, totalCarryBelow10 = 0,
longestStreakBelow10 = 0, shortestStreakBelow10 = int.MaxValue, lastStreakBelow10 = 0,
lowestCarryAfter10 = int.MaxValue;
// , totalCarry16Count = 0, totalCarry17Count = 0, totalCarry18Count = 0;
int totalCarryOtherPositive67Count = 0,
// totalCarryOtherPositive8910OtherCount = 0,
totalCarryOtherPositive8910OtherCount = 0,
totalCarryOtherPositive1011121314OtherCount = 0,
totalCarryOtherPositive15161718OtherCount = 0;
bool hadZeroBefore = false;
@@ -2381,7 +2417,12 @@ internal static class BitContradictionSolverWithAMultiplier
bool reachedBelow5 = false;
int reached5 = 0;
int zeroCount = 0;
for (int blockStart = 0; blockStart < bitLimit; blockStart += CarryDropHeuristicBlockBits)
bool restoredTo10 = false;
ushort first10 = 0;
ushort totalTransitionsOver10 = 0;
long previousCarryOut = 0;
int activeContributionCount = 0;
for (ushort blockStart = 0; blockStart < bitLimit; blockStart += CarryDropHeuristicBlockBits)
{
int blockEnd = blockStart + CarryDropHeuristicBlockBits;
if (blockEnd > bitLimit)
@@ -2389,22 +2430,25 @@ internal static class BitContradictionSolverWithAMultiplier
blockEnd = bitLimit;
}
int blockCarry67Count = 0;
int blockCarryOtherPositive67Count = 0;
for (int col = blockStart; col < blockEnd; col++)
for (ushort col = blockStart; col < blockEnd; col++)
{
// Optimization: maintain rolling a-indices for active q offsets.
// Each active a-index advances by +1 per column, so we avoid recomputing (col - offset)
// in the hot loop while preserving the exact same contribution set and carry semantics.
while (upperOffsetExclusive < qOneOffsetsLength && qOneOffsets[upperOffsetExclusive] <= col)
{
activeAIndicesBuffer[activeContributionCount] = col - qOneOffsets[upperOffsetExclusive];
activeContributionCount++;
upperOffsetExclusive++;
}
long sumWithoutCurrent = carry;
for (int i = 1; i < upperOffsetExclusive; i++)
for (int i = 0; i < activeContributionCount; i++)
{
int aIndex = col - qOneOffsets[i];
int aIndex = activeAIndicesBuffer[i];
ulong word = aBitsBuffer[aIndex >> 6];
sumWithoutCurrent += (long)((word >> (aIndex & 63)) & 1UL);
activeAIndicesBuffer[i] = aIndex + 1;
}
int aBit = (1 - ((int)sumWithoutCurrent & 1)) & 1;
@@ -2414,29 +2458,46 @@ internal static class BitContradictionSolverWithAMultiplier
}
long carryOut = (sumWithoutCurrent + aBit) >> 1;
if (carryOut == 6 || carryOut == 7)
if (col < 32)
{
blockCarry67Count++;
totalCarryFirst32Count += (int)carryOut;
}
if ((previousCarryOut < 10 && carryOut >= 10) ||
(previousCarryOut >= 10 && carryOut < 10))
{
totalTransitionsOver10++;
}
if (carryOut == 6)
{
totalCarry6Count++;
}
else if (carryOut == 7)
{
totalCarry7Count++;
}
else if (carryOut > 0)
{
blockCarryOtherPositive67Count++;
totalCarryOtherPositive67Count++;
}
// if (carryOut == 8)
// {
// totalCarry8Count++;
// }
// else if (carryOut == 9)
// {
// totalCarry9Count++;
// }
// else
if (carryOut == 8)
{
totalCarry8Count++;
}
else if (carryOut == 9)
{
totalCarry9Count++;
}
else
if (carryOut == 10)
{
if (!reached10)
{
reached10 = true;
first10 = col;
}
totalCarry10Count++;
@@ -2459,7 +2520,7 @@ internal static class BitContradictionSolverWithAMultiplier
}
else if (carryOut > 0)
{
// totalCarryOtherPositive8910OtherCount++;
totalCarryOtherPositive8910OtherCount++;
totalCarryOtherPositive1011121314OtherCount++;
}
@@ -2468,14 +2529,52 @@ internal static class BitContradictionSolverWithAMultiplier
if (carryOut == 5)
{
reached5++;
restoredTo10 = false;
}
else if (carryOut < 5)
{
reachedBelow5 = true;
}
else if (reached5 >= 1 && carryOut >= 10)
{
restoredTo10 = true;
}
if (carryOut < 10)
{
totalCarryBelow10++;
lastStreakBelow10++;
if (carryOut < lowestCarryAfter10)
{
lowestCarryAfter10 = (int)carryOut;
}
}
else if (carryOut >= 10)
{
totalCarryAbove10++;
if (lastStreakBelow10 > longestStreakBelow10)
{
longestStreakBelow10 = lastStreakBelow10;
}
if (lastStreakBelow10 < shortestStreakBelow10)
{
shortestStreakBelow10 = lastStreakBelow10;
}
if (lastStreakBelow10 > 0)
{
lastStreakBelow10 = 0;
}
}
}
if (carryOut >= 15)
if (carryOut <= 4)
{
totalCarry01234Count++;
}
if (carryOut >= 14)
// if (carryOut == 15)
{
totalCarry15Count++;
@@ -2502,6 +2601,9 @@ internal static class BitContradictionSolverWithAMultiplier
if (hadZeroBefore)
{
pruneReason = CarryDropPruneReason.ZeroDrop;
#if WITH_PRUNE_STATS
TraceCarryDropHeuristicPrune(pLong, qExact, pruneReason, reached10, reachedBelow5, reached5, zeroCount);
#endif
return true;
}
@@ -2520,29 +2622,40 @@ internal static class BitContradictionSolverWithAMultiplier
carry = carryOut;
}
totalCarry67Count += blockCarry67Count;
totalCarryOtherPositive67Count += blockCarryOtherPositive67Count;
}
if (reached10 && !reachedBelow5 && reached5 <= 1 && zeroCount <= 5)
if (reached10 && zeroCount <= 5 && !(reached5 == 0 && zeroCount <= 4) &&
!reachedBelow5 && reached5 <= 1 && (reached5 == 0 || restoredTo10)
)
{
pruneReason = CarryDropPruneReason.DominanceReached10AndStayedAbove5;
TraceCarryDropHeuristicPrune(pLong, qExact, pruneReason, reached10, reachedBelow5, reached5, zeroCount);
#if WITH_PRUNE_STATS
#endif
return true;
}
if (totalCarry12Count > totalCarry10Count && totalCarry12Count > totalCarry11Count &&
totalCarry12Count > totalCarry13Count && totalCarry12Count > totalCarry14Count &&
totalCarry11Count > 100 && totalCarry13Count > 100
totalCarry11Count > 100 && totalCarry13Count > 100 && (first10 < 34 || totalCarry01234Count < 21) &&
totalCarryFirst32Count > 118
)
{
pruneReason = CarryDropPruneReason.Dominance1011121314;
#if WITH_PRUNE_STATS
TraceCarryDropHeuristicPrune(pLong, qExact, pruneReason, reached10, reachedBelow5, reached5, zeroCount);
#endif
return true;
}
if (totalCarry67Count > totalCarryOtherPositive67Count)
}
var totalCarry67Count = totalCarry6Count + totalCarry7Count;
if (totalCarry67Count > totalCarryOtherPositive67Count ||
(totalCarry67Count > totalCarry8Count && zeroCount < first10 && lowestCarryAfter10 >= 3 && (totalCarry7Count > totalCarry8Count || (totalCarry7Count & 1) == 1)))
{
pruneReason = CarryDropPruneReason.Dominance67ThenZeroDrop;
#if WITH_PRUNE_STATS
TraceCarryDropHeuristicPrune(pLong, qExact, pruneReason, reached10, reachedBelow5, reached5, zeroCount);
#endif
return true;
}
@@ -2553,15 +2666,49 @@ internal static class BitContradictionSolverWithAMultiplier
)
{
pruneReason = CarryDropPruneReason.Dominance15161718Drop;
#if WITH_PRUNE_STATS
TraceCarryDropHeuristicPrune(pLong, qExact, pruneReason, reached10, reachedBelow5, reached5, zeroCount);
#endif
return true;
}
// if (totalCarry8Count + totalCarry9Count + totalCarry10Count > totalCarryOtherPositive8910OtherCount &&
// totalCarry8Count >= 150 && totalCarry9Count >= 150 && totalCarry10Count >= 150)
// {
// pruneReason = CarryDropPruneReason.Dominance10AndMoreDrop;
// return true;
// }
if (totalCarry8Count + totalCarry9Count + totalCarry10Count > totalCarryOtherPositive8910OtherCount &&
totalCarry8Count >= 150 && totalCarry9Count >= 150 && totalCarry10Count >= 150 &&
(totalCarry10Count >= totalCarry9Count || totalCarry8Count >= totalCarry9Count || totalCarry10Count < 190))
{
pruneReason = CarryDropPruneReason.Dominance10AndMoreDrop;
#if WITH_PRUNE_STATS
TraceCarryDropHeuristicPrune(pLong, qExact, pruneReason, reached10, reachedBelow5, reached5, zeroCount);
#endif
return true;
}
if ((totalCarry8Count & 1) == 0 && (totalCarry9Count & 1) == 0 && (totalCarry10Count & 1) == 0)
{
pruneReason = CarryDropPruneReason.Dominance10AndMoreDrop;
#if WITH_PRUNE_STATS
TraceCarryDropHeuristicPrune(pLong, qExact, pruneReason, reached10, reachedBelow5, reached5, zeroCount);
#endif
return true;
}
if (totalCarryAbove10 >= 850 && totalCarryBelow10 < 100 && shortestStreakBelow10 <= 3 && longestStreakBelow10 <= 12 && totalCarry11Count < 150 && lastStreakBelow10 < 12)
{
pruneReason = CarryDropPruneReason.HighDensityWithShortLowStreaks;
#if WITH_PRUNE_STATS
TraceCarryDropHeuristicPrune(pLong, qExact, pruneReason, reached10, reachedBelow5, reached5, zeroCount);
#endif
return true;
}
if (reached10 && reached5 == 0 && !reachedBelow5 && totalTransitionsOver10 < 35)
{
pruneReason = CarryDropPruneReason.DominanceReached10AndStayedAbove5;
#if WITH_PRUNE_STATS
TraceCarryDropHeuristicPrune(pLong, qExact, pruneReason, reached10, reachedBelow5, reached5, zeroCount);
#endif
return true;
}
return false;
}
@@ -2738,8 +2885,9 @@ internal static class BitContradictionSolverWithAMultiplier
}
int carryDropWordCount = (carryDropBitLimit + 63) >> 6;
workSet.EnsureCapacity(carryDropWordCount, 0);
workSet.EnsureCapacity(carryDropWordCount, 0, qOneOffsetsLength);
ulong[] knownOne1 = workSet.KnownOne1;
int[] carryDropActiveAIndices = workSet.CarryDropActiveAIndices;
Array.Clear(knownOne1, 0, carryDropWordCount);
#if false
Array.Clear(qMaskWords, 0, qWordCount);
@@ -2759,7 +2907,7 @@ internal static class BitContradictionSolverWithAMultiplier
return true;
}
if (TryCarryDropHeuristicPrune(qOneOffsets, pLong, maxAllowedA, knownOne1, out CarryDropPruneReason carryDropPruneReason))
if (TryCarryDropHeuristicPrune(qExact, qOneOffsets, pLong, maxAllowedA, knownOne1, carryDropActiveAIndices, out CarryDropPruneReason carryDropPruneReason))
{
divides = false;
#if WITH_PRUNE_STATS
@@ -2787,13 +2935,22 @@ internal static class BitContradictionSolverWithAMultiplier
{
IncrementPruneCounter(ref _prunedWithCarryDropHeuristic);
}
else if (carryDropPruneReason == CarryDropPruneReason.HighDensityWithShortLowStreaks)
{
IncrementPruneCounter(ref _prunedWithHighDensityWithShortLowStreaksCarry);
}
#endif
#if DETAILED_LOG
reason = ContradictionReason.ParityUnreachable;
#endif
// #if WITH_PRUNE_STATS
#if WITH_PRUNE_STATS
if (pLong == 138000953 && qExact.Equals(_testCase))
{
Console.WriteLine($"Validating heuristic prune: p={pLong}, q={qExact}, reason={carryDropPruneReason}");
}
#endif
ValidateHeuristicPruneAgainstPowmod2OrThrow(qExact, pLong, $"CarryDropHeuristic:{carryDropPruneReason}");
// #endif
return true;
}
#if false
@@ -3084,8 +3241,8 @@ internal static class BitContradictionSolverWithAMultiplier
#if WITH_PRUNE_STATS
IncrementPruneCounter(ref _prunedWithTryPropagateCarry1);
ValidateHeuristicPruneAgainstPowmod2OrThrow(qExact, pLong, "TryPropagateCarry1");
#endif
ValidateHeuristicPruneAgainstPowmod2OrThrow(qExact, pLong, "TryPropagateCarry1");
return true;
}
@@ -5707,11 +5864,3 @@ internal static class BitContradictionSolverWithAMultiplier
return true;
}
}
@@ -62,6 +62,9 @@ public struct MersenneNumberDivisorByDivisorCpuTesterWithTemplate() : IMersenneN
private GpuUInt128WorkSet _divisorScanGpuWorkSet;
private static readonly ConcurrentDictionary<ulong, byte> _checkedPow2MinusOne = new();
private ulong _currentPrime;
#if WITH_PRUNE_STATS
private readonly TimeSpan _slowCalculationThreshold = TimeSpan.FromMilliseconds(700);
#endif
#if DEVICE_GPU && DivisorSet_BitContradiction
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
@@ -5104,6 +5107,10 @@ public struct MersenneNumberDivisorByDivisorCpuTesterWithTemplate() : IMersenneN
BigInteger divisor = (step * currentK) + BigInteger.One;
_qBits = new int[(int)prime];
Stopwatch sw = new Stopwatch();
#if WITH_PRUNE_STATS
var slowCalculationThreshold = _slowCalculationThreshold;
#endif
// sw.Start();
while (true)
{
@@ -5143,6 +5150,13 @@ public struct MersenneNumberDivisorByDivisorCpuTesterWithTemplate() : IMersenneN
}
else
{
#if WITH_PRUNE_STATS
if (sw.Elapsed >= slowCalculationThreshold)
{
Console.WriteLine($"SLOW CALCULATIONS: Prime {prime} ({sw.Elapsed}: {divisor})");
_consolePrintOut = 0;
}
#else
var printToConsole = (_consolePrintOut++) == PerfectNumberConstants.ConsoleInterval;
if (printToConsole)
{
@@ -5152,6 +5166,7 @@ public struct MersenneNumberDivisorByDivisorCpuTesterWithTemplate() : IMersenneN
// sw.Reset();
// sw.Start();
}
#endif
}
#if DETAILED_LOG