Add PWMA implementation and tests; enhance documentation

This commit is contained in:
Miha Kralj
2025-12-13 20:21:21 -08:00
parent 60227a23c1
commit 4b17984cfd
38 changed files with 3506 additions and 25 deletions
+53
View File
@@ -472,6 +472,59 @@ public class SimdExtensionsTests
Assert.Equal(-1.0, max);
}
// Add/Subtract tests
[Fact]
public void Add_SameLength_CorrectResult()
{
double[] left = [1.0, 2.0, 3.0, 4.0, 5.0];
double[] right = [10.0, 20.0, 30.0, 40.0, 50.0];
double[] result = new double[5];
SimdExtensions.Add(left, right, result);
Assert.Equal(11.0, result[0]);
Assert.Equal(22.0, result[1]);
Assert.Equal(33.0, result[2]);
Assert.Equal(44.0, result[3]);
Assert.Equal(55.0, result[4]);
}
[Fact]
public void Add_DifferentLengths_ThrowsArgumentException()
{
double[] left = [1.0, 2.0];
double[] right = [1.0];
double[] result = new double[2];
Assert.Throws<ArgumentException>(() => SimdExtensions.Add(left, right, result));
}
[Fact]
public void Subtract_SameLength_CorrectResult()
{
double[] left = [10.0, 20.0, 30.0, 40.0, 50.0];
double[] right = [1.0, 2.0, 3.0, 4.0, 5.0];
double[] result = new double[5];
SimdExtensions.Subtract(left, right, result);
Assert.Equal(9.0, result[0]);
Assert.Equal(18.0, result[1]);
Assert.Equal(27.0, result[2]);
Assert.Equal(36.0, result[3]);
Assert.Equal(45.0, result[4]);
}
[Fact]
public void Subtract_DifferentLengths_ThrowsArgumentException()
{
double[] left = [1.0, 2.0];
double[] right = [1.0];
double[] result = new double[2];
Assert.Throws<ArgumentException>(() => SimdExtensions.Subtract(left, right, result));
}
// Integration tests
[Fact]
public void SIMD_WorksWithTSeriesValues()
+56
View File
@@ -381,6 +381,62 @@ public static class SimdExtensions
return MinMaxScalar(span);
}
/// <summary>
/// Element-wise addition of two spans using SIMD.
/// result[i] = left[i] + right[i]
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Add(ReadOnlySpan<double> left, ReadOnlySpan<double> right, Span<double> result)
{
if (left.Length != right.Length || left.Length != result.Length)
throw new ArgumentException("All spans must have the same length");
int i = 0;
if (Vector.IsHardwareAccelerated && left.Length >= Vector<double>.Count)
{
int vectorSize = Vector<double>.Count;
for (; i <= left.Length - vectorSize; i += vectorSize)
{
var vLeft = new Vector<double>(left.Slice(i, vectorSize));
var vRight = new Vector<double>(right.Slice(i, vectorSize));
(vLeft + vRight).CopyTo(result.Slice(i, vectorSize));
}
}
for (; i < left.Length; i++)
{
result[i] = left[i] + right[i];
}
}
/// <summary>
/// Element-wise subtraction of two spans using SIMD.
/// result[i] = left[i] - right[i]
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Subtract(ReadOnlySpan<double> left, ReadOnlySpan<double> right, Span<double> result)
{
if (left.Length != right.Length || left.Length != result.Length)
throw new ArgumentException("All spans must have the same length");
int i = 0;
if (Vector.IsHardwareAccelerated && left.Length >= Vector<double>.Count)
{
int vectorSize = Vector<double>.Count;
for (; i <= left.Length - vectorSize; i += vectorSize)
{
var vLeft = new Vector<double>(left.Slice(i, vectorSize));
var vRight = new Vector<double>(right.Slice(i, vectorSize));
(vLeft - vRight).CopyTo(result.Slice(i, vectorSize));
}
}
for (; i < left.Length; i++)
{
result[i] = left[i] - right[i];
}
}
/// <summary>
/// Calculates the dot product of two spans using SIMD intrinsics.
/// Supports AVX512, AVX2, and NEON (ARM64).