Eagerly build combined divisors and restore two-A-one-B default

This commit is contained in:
Marek Lemańczyk committed 2025-10-28 23:43:15 +01:00
1 parent e8d163f595
commit f993561cd5
2 files changed
+91 -38

No files matched your search

@@ -13,7 +13,7 @@ public class HeuristicCombinedPrimeTesterTests
[InlineData((byte)1)] [InlineData((byte)1)]
[InlineData((byte)7)] [InlineData((byte)7)]
[InlineData((byte)9)] [InlineData((byte)9)]
public void Enumerator_uses_three_a_two_b_schedule_by_default(byte lastDigit) public void Enumerator_uses_two_a_one_b_schedule_by_default(byte lastDigit)
{ {
Span<HeuristicCombinedPrimeTester.HeuristicGroupBSequenceState> groupBState = Span<HeuristicCombinedPrimeTester.HeuristicGroupBSequenceState> groupBState =
stackalloc HeuristicCombinedPrimeTester.HeuristicGroupBSequenceState[4]; stackalloc HeuristicCombinedPrimeTester.HeuristicGroupBSequenceState[4];
@@ -41,7 +41,7 @@ public class HeuristicCombinedPrimeTesterTests
for (int segment = 0; segment < segmentsToCheck; segment++) for (int segment = 0; segment < segmentsToCheck; segment++)
{ {
for (int i = 0; i < 3; i++) for (int i = 0; i < 2; i++)
{ {
HeuristicCombinedPrimeTester.HeuristicDivisorCandidate groupACandidate = results[index++]; HeuristicCombinedPrimeTester.HeuristicDivisorCandidate groupACandidate = results[index++];
groupACandidate.Value.Should().BeGreaterThan(13UL); groupACandidate.Value.Should().BeGreaterThan(13UL);
@@ -49,7 +49,7 @@ public class HeuristicCombinedPrimeTesterTests
groupACandidate.Group.Should().NotBe(HeuristicCombinedPrimeTester.HeuristicDivisorGroup.GroupB); groupACandidate.Group.Should().NotBe(HeuristicCombinedPrimeTester.HeuristicDivisorGroup.GroupB);
} }
for (int i = 0; i < 2; i++) for (int i = 0; i < 1; i++)
{ {
HeuristicCombinedPrimeTester.HeuristicDivisorCandidate groupBCandidate = results[index++]; HeuristicCombinedPrimeTester.HeuristicDivisorCandidate groupBCandidate = results[index++];
groupBCandidate.Value.Should().BeGreaterThan(13UL); groupBCandidate.Value.Should().BeGreaterThan(13UL);
@@ -59,6 +59,41 @@ public class HeuristicCombinedPrimeTesterTests
} }
} }
[Theory]
[Trait("Category", "Fast")]
[InlineData((byte)1)]
[InlineData((byte)7)]
[InlineData((byte)9)]
public void Two_a_one_b_pattern_interleaves_two_group_a_values_before_group_b(byte lastDigit)
{
ReadOnlySpan<uint> combined = HeuristicCombinedPrimeTester.GetCombinedDivisors(
lastDigit,
HeuristicCombinedPrimeTester.CombinedDivisorPattern.TwoAOneB);
combined.Length.Should().BeGreaterThan(20);
combined[0].Should().Be(3U);
combined[1].Should().Be(7U);
combined[2].Should().Be(11U);
combined[3].Should().Be(13U);
int index = 4;
const int segmentsToCheck = 5;
for (int segment = 0; segment < segmentsToCheck; segment++)
{
for (int i = 0; i < 2; i++)
{
uint groupAValue = combined[index++];
groupAValue.Should().BeGreaterThan(13U);
(groupAValue % 10U).Should().Be(3U);
}
uint groupBValue = combined[index++];
groupBValue.Should().BeGreaterThan(13U);
(groupBValue % 10U).Should().NotBe(3U);
}
}
[Theory] [Theory]
[Trait("Category", "Fast")] [Trait("Category", "Fast")]
[InlineData((byte)1)] [InlineData((byte)1)]
@@ -1,6 +1,4 @@
using System; using System;
using System.Buffers;
using System.Collections.Concurrent;
using Open.Numeric.Primes; using Open.Numeric.Primes;
using System.Collections.Generic; using System.Collections.Generic;
using System.Numerics; using System.Numerics;
@@ -18,31 +16,51 @@ public sealed class HeuristicCombinedPrimeTester
static HeuristicCombinedPrimeTester() static HeuristicCombinedPrimeTester()
{ {
HeuristicPrimeSieves.EnsureInitialized(); HeuristicPrimeSieves.EnsureInitialized();
CombinedDivisorsEnding1TwoAOneB = BuildCombinedDivisors(1, CombinedDivisorPattern.TwoAOneB);
CombinedDivisorsEnding3TwoAOneB = BuildCombinedDivisors(3, CombinedDivisorPattern.TwoAOneB);
CombinedDivisorsEnding7TwoAOneB = BuildCombinedDivisors(7, CombinedDivisorPattern.TwoAOneB);
CombinedDivisorsEnding9TwoAOneB = BuildCombinedDivisors(9, CombinedDivisorPattern.TwoAOneB);
CombinedDivisorsEnding1OneAOneB = BuildCombinedDivisors(1, CombinedDivisorPattern.OneAOneB);
CombinedDivisorsEnding3OneAOneB = BuildCombinedDivisors(3, CombinedDivisorPattern.OneAOneB);
CombinedDivisorsEnding7OneAOneB = BuildCombinedDivisors(7, CombinedDivisorPattern.OneAOneB);
CombinedDivisorsEnding9OneAOneB = BuildCombinedDivisors(9, CombinedDivisorPattern.OneAOneB);
CombinedDivisorsEnding1ThreeAOneB = BuildCombinedDivisors(1, CombinedDivisorPattern.ThreeAOneB);
CombinedDivisorsEnding3ThreeAOneB = BuildCombinedDivisors(3, CombinedDivisorPattern.ThreeAOneB);
CombinedDivisorsEnding7ThreeAOneB = BuildCombinedDivisors(7, CombinedDivisorPattern.ThreeAOneB);
CombinedDivisorsEnding9ThreeAOneB = BuildCombinedDivisors(9, CombinedDivisorPattern.ThreeAOneB);
CombinedDivisorsEnding1ThreeATwoB = BuildCombinedDivisors(1, CombinedDivisorPattern.ThreeATwoB);
CombinedDivisorsEnding3ThreeATwoB = BuildCombinedDivisors(3, CombinedDivisorPattern.ThreeATwoB);
CombinedDivisorsEnding7ThreeATwoB = BuildCombinedDivisors(7, CombinedDivisorPattern.ThreeATwoB);
CombinedDivisorsEnding9ThreeATwoB = BuildCombinedDivisors(9, CombinedDivisorPattern.ThreeATwoB);
} }
private const ulong Wheel210 = 210UL; private const ulong Wheel210 = 210UL;
private static readonly bool UseHeuristicGroupBTrialDivision = false; // Temporary fallback gate for Group B. private static readonly bool UseHeuristicGroupBTrialDivision = false; // Temporary fallback gate for Group B.
private static readonly Lazy<uint[]> CombinedDivisorsEnding1TwoAOneB = new(() => BuildCombinedDivisors(1, CombinedDivisorPattern.TwoAOneB), LazyThreadSafetyMode.ExecutionAndPublication); private static readonly uint[] CombinedDivisorsEnding1TwoAOneB;
private static readonly Lazy<uint[]> CombinedDivisorsEnding3TwoAOneB = new(() => BuildCombinedDivisors(3, CombinedDivisorPattern.TwoAOneB), LazyThreadSafetyMode.ExecutionAndPublication); private static readonly uint[] CombinedDivisorsEnding3TwoAOneB;
private static readonly Lazy<uint[]> CombinedDivisorsEnding7TwoAOneB = new(() => BuildCombinedDivisors(7, CombinedDivisorPattern.TwoAOneB), LazyThreadSafetyMode.ExecutionAndPublication); private static readonly uint[] CombinedDivisorsEnding7TwoAOneB;
private static readonly Lazy<uint[]> CombinedDivisorsEnding9TwoAOneB = new(() => BuildCombinedDivisors(9, CombinedDivisorPattern.TwoAOneB), LazyThreadSafetyMode.ExecutionAndPublication); private static readonly uint[] CombinedDivisorsEnding9TwoAOneB;
private static readonly Lazy<uint[]> CombinedDivisorsEnding1OneAOneB = new(() => BuildCombinedDivisors(1, CombinedDivisorPattern.OneAOneB), LazyThreadSafetyMode.ExecutionAndPublication); private static readonly uint[] CombinedDivisorsEnding1OneAOneB;
private static readonly Lazy<uint[]> CombinedDivisorsEnding3OneAOneB = new(() => BuildCombinedDivisors(3, CombinedDivisorPattern.OneAOneB), LazyThreadSafetyMode.ExecutionAndPublication); private static readonly uint[] CombinedDivisorsEnding3OneAOneB;
private static readonly Lazy<uint[]> CombinedDivisorsEnding7OneAOneB = new(() => BuildCombinedDivisors(7, CombinedDivisorPattern.OneAOneB), LazyThreadSafetyMode.ExecutionAndPublication); private static readonly uint[] CombinedDivisorsEnding7OneAOneB;
private static readonly Lazy<uint[]> CombinedDivisorsEnding9OneAOneB = new(() => BuildCombinedDivisors(9, CombinedDivisorPattern.OneAOneB), LazyThreadSafetyMode.ExecutionAndPublication); private static readonly uint[] CombinedDivisorsEnding9OneAOneB;
private static readonly Lazy<uint[]> CombinedDivisorsEnding1ThreeAOneB = new(() => BuildCombinedDivisors(1, CombinedDivisorPattern.ThreeAOneB), LazyThreadSafetyMode.ExecutionAndPublication); private static readonly uint[] CombinedDivisorsEnding1ThreeAOneB;
private static readonly Lazy<uint[]> CombinedDivisorsEnding3ThreeAOneB = new(() => BuildCombinedDivisors(3, CombinedDivisorPattern.ThreeAOneB), LazyThreadSafetyMode.ExecutionAndPublication); private static readonly uint[] CombinedDivisorsEnding3ThreeAOneB;
private static readonly Lazy<uint[]> CombinedDivisorsEnding7ThreeAOneB = new(() => BuildCombinedDivisors(7, CombinedDivisorPattern.ThreeAOneB), LazyThreadSafetyMode.ExecutionAndPublication); private static readonly uint[] CombinedDivisorsEnding7ThreeAOneB;
private static readonly Lazy<uint[]> CombinedDivisorsEnding9ThreeAOneB = new(() => BuildCombinedDivisors(9, CombinedDivisorPattern.ThreeAOneB), LazyThreadSafetyMode.ExecutionAndPublication); private static readonly uint[] CombinedDivisorsEnding9ThreeAOneB;
private static readonly Lazy<uint[]> CombinedDivisorsEnding1ThreeATwoB = new(() => BuildCombinedDivisors(1, CombinedDivisorPattern.ThreeATwoB), LazyThreadSafetyMode.ExecutionAndPublication); private static readonly uint[] CombinedDivisorsEnding1ThreeATwoB;
private static readonly Lazy<uint[]> CombinedDivisorsEnding3ThreeATwoB = new(() => BuildCombinedDivisors(3, CombinedDivisorPattern.ThreeATwoB), LazyThreadSafetyMode.ExecutionAndPublication); private static readonly uint[] CombinedDivisorsEnding3ThreeATwoB;
private static readonly Lazy<uint[]> CombinedDivisorsEnding7ThreeATwoB = new(() => BuildCombinedDivisors(7, CombinedDivisorPattern.ThreeATwoB), LazyThreadSafetyMode.ExecutionAndPublication); private static readonly uint[] CombinedDivisorsEnding7ThreeATwoB;
private static readonly Lazy<uint[]> CombinedDivisorsEnding9ThreeATwoB = new(() => BuildCombinedDivisors(9, CombinedDivisorPattern.ThreeATwoB), LazyThreadSafetyMode.ExecutionAndPublication); private static readonly uint[] CombinedDivisorsEnding9ThreeATwoB;
private static readonly ulong[] HeuristicSmallCycleSnapshot = MersenneDivisorCycles.Shared.ExportSmallCyclesSnapshot(); private static readonly ulong[] HeuristicSmallCycleSnapshot = MersenneDivisorCycles.Shared.ExportSmallCyclesSnapshot();
@@ -410,7 +428,7 @@ Cleanup:
private static ReadOnlySpan<uint> GetCombinedDivisors(byte nMod10) private static ReadOnlySpan<uint> GetCombinedDivisors(byte nMod10)
{ {
return GetCombinedDivisors(nMod10, CombinedDivisorPattern.ThreeATwoB); return GetCombinedDivisors(nMod10, CombinedDivisorPattern.TwoAOneB);
} }
internal static ReadOnlySpan<uint> GetCombinedDivisors(byte nMod10, CombinedDivisorPattern pattern) internal static ReadOnlySpan<uint> GetCombinedDivisors(byte nMod10, CombinedDivisorPattern pattern)
@@ -419,34 +437,34 @@ Cleanup:
{ {
CombinedDivisorPattern.TwoAOneB => nMod10 switch CombinedDivisorPattern.TwoAOneB => nMod10 switch
{ {
1 => CombinedDivisorsEnding1TwoAOneB.Value, 1 => CombinedDivisorsEnding1TwoAOneB,
3 => CombinedDivisorsEnding3TwoAOneB.Value, 3 => CombinedDivisorsEnding3TwoAOneB,
7 => CombinedDivisorsEnding7TwoAOneB.Value, 7 => CombinedDivisorsEnding7TwoAOneB,
9 => CombinedDivisorsEnding9TwoAOneB.Value, 9 => CombinedDivisorsEnding9TwoAOneB,
_ => ReadOnlySpan<uint>.Empty, _ => ReadOnlySpan<uint>.Empty,
}, },
CombinedDivisorPattern.OneAOneB => nMod10 switch CombinedDivisorPattern.OneAOneB => nMod10 switch
{ {
1 => CombinedDivisorsEnding1OneAOneB.Value, 1 => CombinedDivisorsEnding1OneAOneB,
3 => CombinedDivisorsEnding3OneAOneB.Value, 3 => CombinedDivisorsEnding3OneAOneB,
7 => CombinedDivisorsEnding7OneAOneB.Value, 7 => CombinedDivisorsEnding7OneAOneB,
9 => CombinedDivisorsEnding9OneAOneB.Value, 9 => CombinedDivisorsEnding9OneAOneB,
_ => ReadOnlySpan<uint>.Empty, _ => ReadOnlySpan<uint>.Empty,
}, },
CombinedDivisorPattern.ThreeAOneB => nMod10 switch CombinedDivisorPattern.ThreeAOneB => nMod10 switch
{ {
1 => CombinedDivisorsEnding1ThreeAOneB.Value, 1 => CombinedDivisorsEnding1ThreeAOneB,
3 => CombinedDivisorsEnding3ThreeAOneB.Value, 3 => CombinedDivisorsEnding3ThreeAOneB,
7 => CombinedDivisorsEnding7ThreeAOneB.Value, 7 => CombinedDivisorsEnding7ThreeAOneB,
9 => CombinedDivisorsEnding9ThreeAOneB.Value, 9 => CombinedDivisorsEnding9ThreeAOneB,
_ => ReadOnlySpan<uint>.Empty, _ => ReadOnlySpan<uint>.Empty,
}, },
CombinedDivisorPattern.ThreeATwoB => nMod10 switch CombinedDivisorPattern.ThreeATwoB => nMod10 switch
{ {
1 => CombinedDivisorsEnding1ThreeATwoB.Value, 1 => CombinedDivisorsEnding1ThreeATwoB,
3 => CombinedDivisorsEnding3ThreeATwoB.Value, 3 => CombinedDivisorsEnding3ThreeATwoB,
7 => CombinedDivisorsEnding7ThreeATwoB.Value, 7 => CombinedDivisorsEnding7ThreeATwoB,
9 => CombinedDivisorsEnding9ThreeATwoB.Value, 9 => CombinedDivisorsEnding9ThreeATwoB,
_ => ReadOnlySpan<uint>.Empty, _ => ReadOnlySpan<uint>.Empty,
}, },
_ => ReadOnlySpan<uint>.Empty, _ => ReadOnlySpan<uint>.Empty,