PrimeOrderCalculator.ExponentLoweringCpu optimized to reuse factors & exponents span instead of its own buffers
This commit is contained in:
1 parent
6d427c6906
commit
b7773adad8
3 files changed
+49
-58
No files matched your search
@@ -11,8 +11,6 @@ namespace PerfectNumbers.Core
|
|||||||
public readonly int[] Exponents = new int[PrimeOrderConstants.GpuSmallPrimeFactorSlots];
|
public readonly int[] Exponents = new int[PrimeOrderConstants.GpuSmallPrimeFactorSlots];
|
||||||
public readonly FixedCapacityStack<ulong> CompositeStack = new (PrimeOrderConstants.GpuSmallPrimeFactorSlots);
|
public readonly FixedCapacityStack<ulong> CompositeStack = new (PrimeOrderConstants.GpuSmallPrimeFactorSlots);
|
||||||
public readonly List<PartialFactorPendingEntry> PendingFactors = new (PrimeOrderConstants.GpuSmallPrimeFactorSlots);
|
public readonly List<PartialFactorPendingEntry> PendingFactors = new (PrimeOrderConstants.GpuSmallPrimeFactorSlots);
|
||||||
public readonly ulong[] TempFactorsArray = new ulong[PrimeOrderConstants.GpuSmallPrimeFactorSlots << 3];
|
|
||||||
public readonly int[] TempExponentsArray = new int[PrimeOrderConstants.GpuSmallPrimeFactorSlots << 3];
|
|
||||||
public readonly ulong[] StackCandidates = new ulong[PrimeOrderConstants.GpuSmallPrimeFactorSlots << 3];
|
public readonly ulong[] StackCandidates = new ulong[PrimeOrderConstants.GpuSmallPrimeFactorSlots << 3];
|
||||||
public readonly bool[] StackEvaluations = new bool[PrimeOrderConstants.GpuSmallPrimeFactorSlots << 3];
|
public readonly bool[] StackEvaluations = new bool[PrimeOrderConstants.GpuSmallPrimeFactorSlots << 3];
|
||||||
private PartialFactorResult? _next;
|
private PartialFactorResult? _next;
|
||||||
|
|||||||
@@ -123,7 +123,7 @@ internal static partial class PrimeOrderCalculator
|
|||||||
}
|
}
|
||||||
|
|
||||||
ulong candidateOrder = InitializeStartingOrderCpu(prime, phi, divisorData);
|
ulong candidateOrder = InitializeStartingOrderCpu(prime, phi, divisorData);
|
||||||
candidateOrder = ExponentLoweringCpu(candidateOrder, prime, phiFactors, divisorData);
|
candidateOrder = ExponentLoweringCpu(candidateOrder, phiFactors, divisorData);
|
||||||
|
|
||||||
if (TryConfirmOrderCpu(prime, candidateOrder, divisorData, config, out PartialFactorResult? orderFactors))
|
if (TryConfirmOrderCpu(prime, candidateOrder, divisorData, config, out PartialFactorResult? orderFactors))
|
||||||
{
|
{
|
||||||
@@ -542,39 +542,34 @@ internal static partial class PrimeOrderCalculator
|
|||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||||
private static ulong ExponentLoweringCpu(ulong order, ulong prime, PartialFactorResult factors, in MontgomeryDivisorData divisorData)
|
private static ulong ExponentLoweringCpu(ulong order, PartialFactorResult factors, in MontgomeryDivisorData divisorData)
|
||||||
{
|
{
|
||||||
int length = factors.Count;
|
int factorCount = factors.Count;
|
||||||
ReadOnlySpan<ulong> factorSpan = new(factors.Factors, 0, length);
|
int newFactorCount = factorCount + 1;
|
||||||
ReadOnlySpan<int> exponentsSpan = new(factors.Exponents, 0, length);
|
Span<ulong> factorsSpan = new(factors.Factors, 0, newFactorCount);
|
||||||
|
Span<int> exponentsSpan = new(factors.Exponents, 0, newFactorCount);
|
||||||
int newLength = length + 1;
|
|
||||||
ulong[] tempFactorsArray = factors.TempFactorsArray;
|
|
||||||
int[] tempExponentsArray = factors.TempExponentsArray;
|
|
||||||
|
|
||||||
Span<ulong> ulongBuffer = tempFactorsArray;
|
|
||||||
factorSpan.CopyTo(ulongBuffer);
|
|
||||||
Span<int> intBuffer = tempExponentsArray;
|
|
||||||
exponentsSpan.CopyTo(intBuffer);
|
|
||||||
|
|
||||||
if (!factors.FullyFactored && factors.Cofactor > 1UL && factors.CofactorIsPrime)
|
if (!factors.FullyFactored && factors.Cofactor > 1UL && factors.CofactorIsPrime)
|
||||||
{
|
{
|
||||||
ulongBuffer[length] = factors.Cofactor;
|
factorsSpan[factorCount] = factors.Cofactor;
|
||||||
intBuffer[length] = 1;
|
exponentsSpan[factorCount] = 1;
|
||||||
length = newLength;
|
factors.Count = factorCount = newFactorCount;
|
||||||
|
factors.Cofactor = 1UL;
|
||||||
|
factors.FullyFactored = true;
|
||||||
|
factors.CofactorIsPrime = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Array.Sort(tempFactorsArray, tempExponentsArray, 0, length);
|
SortFactorExponentSpans(factorsSpan, exponentsSpan, factorCount);
|
||||||
|
|
||||||
ExponentRemainderStepperCpu stepper = ThreadStaticPools.RentExponentStepperCpu(divisorData);
|
ExponentRemainderStepperCpu stepper = ThreadStaticPools.RentExponentStepperCpu(divisorData);
|
||||||
|
|
||||||
Span<ulong> stackCandidates = new(factors.StackCandidates);
|
Span<ulong> stackCandidates = new(factors.StackCandidates);
|
||||||
Span<bool> stackEvaluations = new(factors.StackEvaluations);
|
Span<bool> stackEvaluations = new(factors.StackEvaluations);
|
||||||
|
|
||||||
for (int i = 0; i < length; i++)
|
for (int i = 0; i < factorCount; i++)
|
||||||
{
|
{
|
||||||
ulong primeFactor = ulongBuffer[i];
|
ulong primeFactor = factorsSpan[i];
|
||||||
int exponent = intBuffer[i];
|
int exponent = exponentsSpan[i];
|
||||||
// Factor exponents produced by Pollard-Rho and trial division are always positive in the scanner flow.
|
// Factor exponents produced by Pollard-Rho and trial division are always positive in the scanner flow.
|
||||||
// if (exponent <= 0)
|
// if (exponent <= 0)
|
||||||
// {
|
// {
|
||||||
@@ -588,6 +583,29 @@ internal static partial class PrimeOrderCalculator
|
|||||||
return order;
|
return order;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||||
|
private static void SortFactorExponentSpans(Span<ulong> factorsSpan, Span<int> exponentsSpan, int length)
|
||||||
|
{
|
||||||
|
if (length <= 1)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 1; i < length; i++)
|
||||||
|
{
|
||||||
|
int current = i;
|
||||||
|
int previous = current - 1;
|
||||||
|
while (current > 0 && factorsSpan[current] < factorsSpan[previous])
|
||||||
|
{
|
||||||
|
(factorsSpan[current], factorsSpan[previous]) = (factorsSpan[previous], factorsSpan[current]);
|
||||||
|
(exponentsSpan[current], exponentsSpan[previous]) = (exponentsSpan[previous], exponentsSpan[current]);
|
||||||
|
current--;
|
||||||
|
previous--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
|
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
|
||||||
private static void ProcessExponentLoweringPrime(Span<ulong> candidateBuffer, Span<bool> evaluationBuffer, ref ulong order, ulong primeFactor, int exponent, ref ExponentRemainderStepperCpu stepper)
|
private static void ProcessExponentLoweringPrime(Span<ulong> candidateBuffer, Span<bool> evaluationBuffer, ref ulong order, ulong primeFactor, int exponent, ref ExponentRemainderStepperCpu stepper)
|
||||||
{
|
{
|
||||||
@@ -696,11 +714,9 @@ internal static partial class PrimeOrderCalculator
|
|||||||
int length = factorization.Count;
|
int length = factorization.Count;
|
||||||
|
|
||||||
const int StackExponentCapacity = 32;
|
const int StackExponentCapacity = 32;
|
||||||
const int ExponentHardLimit = 256;
|
|
||||||
|
|
||||||
Span<ulong> stackBuffer = stackalloc ulong[StackExponentCapacity];
|
Span<ulong> stackBuffer = stackalloc ulong[StackExponentCapacity];
|
||||||
|
|
||||||
ulong[]? heapCandidateArray = null;
|
|
||||||
ExponentRemainderStepperCpu stepper = ThreadStaticPools.RentExponentStepperCpu(divisorData);
|
ExponentRemainderStepperCpu stepper = ThreadStaticPools.RentExponentStepperCpu(divisorData);
|
||||||
bool violates = false;
|
bool violates = false;
|
||||||
|
|
||||||
@@ -715,37 +731,15 @@ internal static partial class PrimeOrderCalculator
|
|||||||
// continue;
|
// continue;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
if (exponent > ExponentHardLimit)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException($"Factor exponent {exponent} exceeds the supported limit of {ExponentHardLimit}.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (exponent <= StackExponentCapacity)
|
|
||||||
{
|
|
||||||
if (ValidateOrderForFactor(stackBuffer[..exponent], primeFactor, exponent, order, ref stepper))
|
if (ValidateOrderForFactor(stackBuffer[..exponent], primeFactor, exponent, order, ref stepper))
|
||||||
{
|
{
|
||||||
violates = true;
|
violates = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
heapCandidateArray ??= FixedCapacityPools.ExclusiveUlongArray.Rent(ExponentHardLimit);
|
|
||||||
if (ValidateOrderForFactor(heapCandidateArray.AsSpan(0, exponent), primeFactor, exponent, order, ref stepper))
|
|
||||||
{
|
|
||||||
violates = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ThreadStaticPools.ReturnExponentStepperCpu(stepper);
|
ThreadStaticPools.ReturnExponentStepperCpu(stepper);
|
||||||
|
|
||||||
if (heapCandidateArray is not null)
|
|
||||||
{
|
|
||||||
FixedCapacityPools.ExclusiveUlongArray.Return(heapCandidateArray);
|
|
||||||
}
|
|
||||||
|
|
||||||
return !violates;
|
return !violates;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -946,10 +940,10 @@ internal static partial class PrimeOrderCalculator
|
|||||||
|
|
||||||
bool leftIsGe = !hasPrevious || left >= previous;
|
bool leftIsGe = !hasPrevious || left >= previous;
|
||||||
bool rightIsGe = !hasPrevious || right >= previous;
|
bool rightIsGe = !hasPrevious || right >= previous;
|
||||||
int leftPrimary = ComputePrimary(leftGroup, leftIsGe, previousGroup);
|
|
||||||
int rightPrimary = ComputePrimary(rightGroup, rightIsGe, previousGroup);
|
int rightPrimary = ComputePrimary(rightGroup, rightIsGe, previousGroup);
|
||||||
|
|
||||||
int compare = leftPrimary.CompareTo(rightPrimary);
|
int compare = ComputePrimary(leftGroup, leftIsGe, previousGroup);
|
||||||
|
compare = compare.CompareTo(rightPrimary);
|
||||||
if (compare != 0)
|
if (compare != 0)
|
||||||
{
|
{
|
||||||
return compare;
|
return compare;
|
||||||
@@ -957,15 +951,15 @@ internal static partial class PrimeOrderCalculator
|
|||||||
|
|
||||||
long leftSecondary;
|
long leftSecondary;
|
||||||
long leftTertiary;
|
long leftTertiary;
|
||||||
|
ulong tempReference;
|
||||||
if (leftGroup == 3)
|
if (leftGroup == 3)
|
||||||
{
|
{
|
||||||
leftSecondary = -(long)left;
|
leftSecondary = leftTertiary = -(long)left;
|
||||||
leftTertiary = -(long)left;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ulong leftReference = hasPrevious ? (left > previous ? left - previous : previous - left) : left;
|
tempReference = hasPrevious ? (left > previous ? left - previous : previous - left) : left;
|
||||||
leftSecondary = (long)leftReference;
|
leftSecondary = (long)tempReference;
|
||||||
leftTertiary = (long)left;
|
leftTertiary = (long)left;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -973,13 +967,12 @@ internal static partial class PrimeOrderCalculator
|
|||||||
long rightTertiary;
|
long rightTertiary;
|
||||||
if (rightGroup == 3)
|
if (rightGroup == 3)
|
||||||
{
|
{
|
||||||
rightSecondary = -(long)right;
|
rightSecondary = rightTertiary = -(long)right;
|
||||||
rightTertiary = -(long)right;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ulong rightReference = hasPrevious ? (right > previous ? right - previous : previous - right) : right;
|
tempReference = hasPrevious ? (right > previous ? right - previous : previous - right) : right;
|
||||||
rightSecondary = (long)rightReference;
|
rightSecondary = (long)tempReference;
|
||||||
rightTertiary = (long)right;
|
rightTertiary = (long)right;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -304,7 +304,7 @@ internal static partial class PrimeOrderCalculator
|
|||||||
}
|
}
|
||||||
|
|
||||||
ulong candidateOrder = InitializeStartingOrderHybrid(gpu, prime, phi, divisorData);
|
ulong candidateOrder = InitializeStartingOrderHybrid(gpu, prime, phi, divisorData);
|
||||||
candidateOrder = ExponentLoweringCpu(candidateOrder, prime, phiFactors, divisorData);
|
candidateOrder = ExponentLoweringCpu(candidateOrder, phiFactors, divisorData);
|
||||||
|
|
||||||
if (TryConfirmOrderHybrid(gpu, prime, candidateOrder, divisorData, config, out PartialFactorResult? orderFactors))
|
if (TryConfirmOrderHybrid(gpu, prime, candidateOrder, divisorData, config, out PartialFactorResult? orderFactors))
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in new issue
Block a user