diff --git a/.appveyor.yml b/.appveyor.yml
index b03ac3d..d340d46 100644
--- a/.appveyor.yml
+++ b/.appveyor.yml
@@ -1,7 +1,7 @@
version: 0.1.{build}.0
pull_requests:
do_not_increment_build_number: true
-image: Visual Studio 2017
+image: Visual Studio 2017 Preview
clone_depth: 1
clone_folder: c:\projects\gfoidl
environment:
diff --git a/.circleci/config.yml b/.circleci/config.yml
index 0799b79..64bc8ef 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -2,7 +2,7 @@ version: 2
defaults: &defaults
working_directory: ~/repo
docker:
- - image: microsoft/dotnet:2.0.5-sdk-2.1.4
+ - image: microsoft/dotnet:2.1-sdk
environment:
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1
DOTNET_CLI_TELEMETRY_OPTOUT: 1
diff --git a/gfoidl.Stochastics.sln b/gfoidl.Stochastics.sln
index c17287c..df3b19b 100644
--- a/gfoidl.Stochastics.sln
+++ b/gfoidl.Stochastics.sln
@@ -15,6 +15,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{D9E63A0E
.appveyor.yml = .appveyor.yml
build.sh = build.sh
Directory.Build.props = Directory.Build.props
+ nuget.config = nuget.config
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "source", "source", "{0B4051AE-E1F2-4601-B0A8-B4CA660CC4B2}"
diff --git a/nuget.config b/nuget.config
new file mode 100644
index 0000000..095110b
--- /dev/null
+++ b/nuget.config
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/perf/gfoidl.Stochastics.Benchmarks/gfoidl.Stochastics.Benchmarks.csproj b/perf/gfoidl.Stochastics.Benchmarks/gfoidl.Stochastics.Benchmarks.csproj
index b3027c3..58dc48d 100644
--- a/perf/gfoidl.Stochastics.Benchmarks/gfoidl.Stochastics.Benchmarks.csproj
+++ b/perf/gfoidl.Stochastics.Benchmarks/gfoidl.Stochastics.Benchmarks.csproj
@@ -9,11 +9,11 @@
- netcoreapp2.0;net471
+ netcoreapp2.1;netcoreapp2.0;net471
- netcoreapp2.0
+ netcoreapp2.1;netcoreapp2.0
@@ -21,7 +21,10 @@
-
+
+
+
+
diff --git a/source/gfoidl.Stochastics/Statistics/Sample.AverageVarianceCore.cs b/source/gfoidl.Stochastics/Statistics/Sample.AverageVarianceCore.cs
index 948e560..8b8855d 100644
--- a/source/gfoidl.Stochastics/Statistics/Sample.AverageVarianceCore.cs
+++ b/source/gfoidl.Stochastics/Statistics/Sample.AverageVarianceCore.cs
@@ -101,7 +101,7 @@ private unsafe (double avg, double variance) CalculateAverageAndVarianceCoreImpl
}
// Reduction -- https://github.com/gfoidl/Stochastics/issues/43
- avg += Vector.Dot(avgVec, Vector.One);
+ avg += avgVec.ReduceSum();
}
for (; i < n; ++i)
diff --git a/source/gfoidl.Stochastics/Statistics/Sample.Delta.cs b/source/gfoidl.Stochastics/Statistics/Sample.Delta.cs
index 3c6a657..f28c887 100644
--- a/source/gfoidl.Stochastics/Statistics/Sample.Delta.cs
+++ b/source/gfoidl.Stochastics/Statistics/Sample.Delta.cs
@@ -94,7 +94,7 @@ private unsafe double CalculateDeltaImpl((int start, int end) range)
}
// Reduction -- https://github.com/gfoidl/Stochastics/issues/43
- delta += Vector.Dot(deltaVec, Vector.One);
+ delta += deltaVec.ReduceSum();
}
for (; i < n; ++i)
diff --git a/source/gfoidl.Stochastics/Statistics/Sample.MinMax.cs b/source/gfoidl.Stochastics/Statistics/Sample.MinMax.cs
index 1218dfd..75fc864 100644
--- a/source/gfoidl.Stochastics/Statistics/Sample.MinMax.cs
+++ b/source/gfoidl.Stochastics/Statistics/Sample.MinMax.cs
@@ -107,11 +107,7 @@ private unsafe (double min, double max) GetMinMaxImpl((int start, int end) range
}
// Reduction
- for (int j = 0; j < Vector.Count; ++j)
- {
- if (minVec[j] < min) min = minVec[j];
- if (maxVec[j] > max) max = maxVec[j];
- }
+ VectorHelper.ReduceMinMax(minVec, maxVec, ref min, ref max);
}
for (; i < n; ++i)
diff --git a/source/gfoidl.Stochastics/Statistics/Sample.SkewnessAndKurtosis.cs b/source/gfoidl.Stochastics/Statistics/Sample.SkewnessAndKurtosis.cs
index b5266d0..8afd331 100644
--- a/source/gfoidl.Stochastics/Statistics/Sample.SkewnessAndKurtosis.cs
+++ b/source/gfoidl.Stochastics/Statistics/Sample.SkewnessAndKurtosis.cs
@@ -105,8 +105,8 @@ private unsafe (double skewness, double kurtosis) CalculateSkewnessAndKurtosisIm
}
// Reduction -- https://github.com/gfoidl/Stochastics/issues/43
- skewness += Vector.Dot(skewVec, Vector.One);
- kurtosis += Vector.Dot(kurtVec, Vector.One);
+ skewness += skewVec.ReduceSum();
+ kurtosis += kurtVec.ReduceSum();
}
for (; i < n; ++i)
diff --git a/source/gfoidl.Stochastics/ThrowHelper.cs b/source/gfoidl.Stochastics/ThrowHelper.cs
index 127a341..c5a66ce 100644
--- a/source/gfoidl.Stochastics/ThrowHelper.cs
+++ b/source/gfoidl.Stochastics/ThrowHelper.cs
@@ -6,7 +6,7 @@ namespace gfoidl.Stochastics
{
internal static class ThrowHelper
{
-#if NETSTANDARD2_0
+#if !NET471
public static void ThrowArgumentNull(ExceptionArgument argument) => throw new ArgumentNullException(GetArgumentName(argument));
public static void ThrowArgumentOutOfRange(ExceptionArgument argument) => throw new ArgumentOutOfRangeException(GetArgumentName(argument));
public static void ThrowArgumentOutOfRange(ExceptionArgument argument, ExceptionResource resource) => throw new ArgumentOutOfRangeException(GetArgumentName(argument), GetResourceText(resource));
diff --git a/source/gfoidl.Stochastics/VectorHelper.cs b/source/gfoidl.Stochastics/VectorHelper.cs
index 7ca165b..fed0887 100644
--- a/source/gfoidl.Stochastics/VectorHelper.cs
+++ b/source/gfoidl.Stochastics/VectorHelper.cs
@@ -3,6 +3,11 @@
using System.Numerics;
using System.Runtime.CompilerServices;
+#if NETCOREAPP2_1
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.X86;
+#endif
+
namespace gfoidl.Stochastics
{
[DebuggerNonUserCode]
@@ -33,5 +38,67 @@ public static void WriteVectorWithAdvance(this Vector vector, ref double
Unsafe.WriteUnaligned(arr, vector);
arr += Vector.Count;
}
+ //---------------------------------------------------------------------
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static double ReduceSum(this Vector vector)
+ {
+#if NETCOREAPP2_1
+ if (Avx.IsSupported && Sse2.IsSupported && 256 / 8 == sizeof(double) * Vector.Count)
+ {
+ Vector256 a = Unsafe.As, Vector256>(ref vector);
+ Vector256 tmp = Avx.HorizontalAdd(a, a);
+ Vector128 hi128 = Avx.ExtractVector128(tmp, 1);
+ Vector128 s = Sse2.Add(Unsafe.As, Vector128>(ref tmp), hi128);
+
+ return Sse2.ConvertToDouble(s);
+ }
+#endif
+ return Vector.Dot(Vector.One, vector);
+ }
+ //---------------------------------------------------------------------
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void ReduceMinMax(Vector minVec, Vector maxVec, ref double min, ref double max)
+ {
+#if NETCOREAPP2_1
+ if (Avx.IsSupported && Sse2.IsSupported && 256 / 8 == sizeof(double) * Vector.Count)
+ {
+ min = MinMaxCore(minVec, true);
+ max = MinMaxCore(maxVec, false);
+ return;
+ }
+#endif
+ for (int j = 0; j < Vector.Count; ++j)
+ {
+ if (minVec[j] < min) min = minVec[j];
+ if (maxVec[j] > max) max = maxVec[j];
+ }
+ }
+ //---------------------------------------------------------------------
+#if NETCOREAPP2_1
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static double MinMaxCore(Vector vector, bool doMin)
+ {
+ Vector256 vec256 = Unsafe.As, Vector256>(ref vector);
+ Vector128 hi128 = Avx.ExtractVector128(vec256, 1);
+ Vector128 lo128 = Avx.ExtractVector128(vec256, 0);
+ Vector128 tmp1 = Avx.Permute(hi128, 0b_01);
+ Vector128 tmp2 = Avx.Permute(lo128, 0b_01);
+
+ if (doMin)
+ {
+ hi128 = Sse2.Min(hi128, tmp1);
+ lo128 = Sse2.Min(lo128, tmp2);
+ lo128 = Sse2.Min(lo128, hi128);
+ }
+ else
+ {
+ hi128 = Sse2.Max(hi128, tmp1);
+ lo128 = Sse2.Max(lo128, tmp2);
+ lo128 = Sse2.Max(lo128, hi128);
+ }
+
+ return Sse2.ConvertToDouble(lo128);
+ }
+#endif
}
-}
\ No newline at end of file
+}
diff --git a/source/gfoidl.Stochastics/gfoidl.Stochastics.csproj b/source/gfoidl.Stochastics/gfoidl.Stochastics.csproj
index 610ecbf..1a45f6c 100644
--- a/source/gfoidl.Stochastics/gfoidl.Stochastics.csproj
+++ b/source/gfoidl.Stochastics/gfoidl.Stochastics.csproj
@@ -1,7 +1,7 @@
- netstandard2.0
+ netstandard2.0;netcoreapp2.1
latest
true
@@ -19,11 +19,16 @@
bin\Release\netstandard2.0\gfoidl.Stochastics.xml
-
+
+
+
+
+
+
diff --git a/tests/gfoidl.Stochastics.Tests/VectorHelperTests/ReduceMinMax.cs b/tests/gfoidl.Stochastics.Tests/VectorHelperTests/ReduceMinMax.cs
new file mode 100644
index 0000000..075b4cb
--- /dev/null
+++ b/tests/gfoidl.Stochastics.Tests/VectorHelperTests/ReduceMinMax.cs
@@ -0,0 +1,40 @@
+using System;
+using System.Numerics;
+using NUnit.Framework;
+
+namespace gfoidl.Stochastics.Tests.VectorHelperTests
+{
+ [TestFixture]
+ public class ReduceMinMax
+ {
+ [Test, Repeat(10)]
+ public void Min_Max_Vectors_given___correct_Min_Max()
+ {
+ var rnd = new Random();
+ var minArr = new double[Vector.Count];
+ var maxArr = new double[Vector.Count];
+ double min = double.MaxValue;
+ double max = double.MinValue;
+
+ for (int j = 0; j < Vector.Count; ++j)
+ {
+ minArr[j] = rnd.NextDouble();
+ maxArr[j] = rnd.NextDouble();
+
+ if (minArr[j] < min) min = minArr[j];
+ if (maxArr[j] > max) max = maxArr[j];
+ }
+
+ double expectedMin = min;
+ double expectedMax = max;
+
+ var minVec = new Vector(minArr);
+ var maxVec = new Vector(maxArr);
+
+ VectorHelper.ReduceMinMax(minVec, maxVec, ref min, ref max);
+
+ Assert.AreEqual(expectedMin, min, 1e-10);
+ Assert.AreEqual(expectedMax, max, 1e-10);
+ }
+ }
+}
diff --git a/tests/gfoidl.Stochastics.Tests/VectorHelperTests/ReduceSum.cs b/tests/gfoidl.Stochastics.Tests/VectorHelperTests/ReduceSum.cs
new file mode 100644
index 0000000..1d1ef9d
--- /dev/null
+++ b/tests/gfoidl.Stochastics.Tests/VectorHelperTests/ReduceSum.cs
@@ -0,0 +1,37 @@
+using System;
+using System.Numerics;
+using NUnit.Framework;
+
+namespace gfoidl.Stochastics.Tests.VectorHelperTests
+{
+ [TestFixture]
+ public class ReduceSum
+ {
+ [Test, Repeat(10)]
+ public void Random_Vector_given___Correct_Sum_Reduction()
+ {
+ if (Vector.IsHardwareAccelerated)
+ {
+ var rnd = new Random();
+ var arr = new double[Vector.Count];
+ double expected = 0;
+
+ for (int j = 0; j < arr.Length; ++j)
+ {
+ arr[j] = rnd.NextDouble();
+ expected += arr[j];
+ }
+
+ var vector = new Vector(arr);
+
+ double actual = vector.ReduceSum();
+
+ Assert.AreEqual(expected, actual, 1e-10);
+ }
+ else
+ {
+ Assert.Ignore("Vector.IsHardwareAccelerated is false");
+ }
+ }
+ }
+}
diff --git a/tests/gfoidl.Stochastics.Tests/gfoidl.Stochastics.Tests.csproj b/tests/gfoidl.Stochastics.Tests/gfoidl.Stochastics.Tests.csproj
index 662c611..97d1535 100644
--- a/tests/gfoidl.Stochastics.Tests/gfoidl.Stochastics.Tests.csproj
+++ b/tests/gfoidl.Stochastics.Tests/gfoidl.Stochastics.Tests.csproj
@@ -1,7 +1,7 @@
- netcoreapp2.0
+ netcoreapp2.1;netcoreapp2.0