diff --git a/NetFabric.Numerics.sln b/NetFabric.Numerics.sln
index 4e84bf1..6e45bd8 100644
--- a/NetFabric.Numerics.sln
+++ b/NetFabric.Numerics.sln
@@ -58,6 +58,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NetFabric.Numerics.Geodesy.
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetFabric.Numerics.Tensors", "src\NetFabric.Numerics.Tensors\NetFabric.Numerics.Tensors.csproj", "{8D2EE0A5-32A2-4019-AD55-7E9B70B76D67}"
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{EC0C1351-970E-48A9-BDA3-3E5E2B095402}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetFabric.Numerics.Tensors.UnitTests", "src\NetFabric.Numerics.Tensors.UnitTests\NetFabric.Numerics.Tensors.UnitTests.csproj", "{31E6CCB0-E04A-4947-BF74-E8E70D5594E5}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetFabric.Numerics.Tensors.Benchmarks", "src\NetFabric.Numerics.Tensors.Benchmarks\NetFabric.Numerics.Tensors.Benchmarks.csproj", "{A8467A84-F9DD-4B6C-91BB-CF39029331A4}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -96,6 +102,14 @@ Global
{8D2EE0A5-32A2-4019-AD55-7E9B70B76D67}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8D2EE0A5-32A2-4019-AD55-7E9B70B76D67}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8D2EE0A5-32A2-4019-AD55-7E9B70B76D67}.Release|Any CPU.Build.0 = Release|Any CPU
+ {31E6CCB0-E04A-4947-BF74-E8E70D5594E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {31E6CCB0-E04A-4947-BF74-E8E70D5594E5}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {31E6CCB0-E04A-4947-BF74-E8E70D5594E5}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {31E6CCB0-E04A-4947-BF74-E8E70D5594E5}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A8467A84-F9DD-4B6C-91BB-CF39029331A4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A8467A84-F9DD-4B6C-91BB-CF39029331A4}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A8467A84-F9DD-4B6C-91BB-CF39029331A4}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A8467A84-F9DD-4B6C-91BB-CF39029331A4}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -104,6 +118,8 @@ Global
{A04C4E36-5F33-43F8-A7EE-15D81C7F8A58} = {762517CA-3F22-4DC6-955C-4F4FC69EB670}
{BA0837F2-730C-4537-B08B-5FFD2D91AF30} = {762517CA-3F22-4DC6-955C-4F4FC69EB670}
{83BDB68A-4F4B-4D7D-A7C7-55CC9F03657B} = {762517CA-3F22-4DC6-955C-4F4FC69EB670}
+ {31E6CCB0-E04A-4947-BF74-E8E70D5594E5} = {EC0C1351-970E-48A9-BDA3-3E5E2B095402}
+ {A8467A84-F9DD-4B6C-91BB-CF39029331A4} = {EC0C1351-970E-48A9-BDA3-3E5E2B095402}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {AACC30AE-BE57-461F-817B-2AE0F001A33F}
diff --git a/src/NetFabric.Numerics.Benchmarks/TensorAddBenchmarks.cs b/src/NetFabric.Numerics.Tensors.Benchmarks/AddBenchmarks.cs
similarity index 94%
rename from src/NetFabric.Numerics.Benchmarks/TensorAddBenchmarks.cs
rename to src/NetFabric.Numerics.Tensors.Benchmarks/AddBenchmarks.cs
index 2a98d16..ede20ab 100644
--- a/src/NetFabric.Numerics.Benchmarks/TensorAddBenchmarks.cs
+++ b/src/NetFabric.Numerics.Tensors.Benchmarks/AddBenchmarks.cs
@@ -1,8 +1,8 @@
using BenchmarkDotNet.Attributes;
-namespace NetFabric.Numerics.Rectangular2D.Benchmarks;
+namespace NetFabric.Numerics.Tensors.Benchmarks;
-public class TensorAddBenchmarks
+public class AddBenchmarks
{
short[]? arrayShort;
int[]? arrayInt;
diff --git a/src/NetFabric.Numerics.Benchmarks/TensorAddValueBenchmarks.cs b/src/NetFabric.Numerics.Tensors.Benchmarks/AddValueBenchmarks.cs
similarity index 94%
rename from src/NetFabric.Numerics.Benchmarks/TensorAddValueBenchmarks.cs
rename to src/NetFabric.Numerics.Tensors.Benchmarks/AddValueBenchmarks.cs
index 8d7f0ec..c559135 100644
--- a/src/NetFabric.Numerics.Benchmarks/TensorAddValueBenchmarks.cs
+++ b/src/NetFabric.Numerics.Tensors.Benchmarks/AddValueBenchmarks.cs
@@ -1,8 +1,8 @@
using BenchmarkDotNet.Attributes;
-namespace NetFabric.Numerics.Rectangular2D.Benchmarks;
+namespace NetFabric.Numerics.Tensors.Benchmarks;
-public class TensorAddValueBenchmarks
+public class AddValueBenchmarks
{
short[]? arrayShort;
int[]? arrayInt;
diff --git a/src/NetFabric.Numerics.Tensors.Benchmarks/NetFabric.Numerics.Tensors.Benchmarks.csproj b/src/NetFabric.Numerics.Tensors.Benchmarks/NetFabric.Numerics.Tensors.Benchmarks.csproj
new file mode 100644
index 0000000..f35cf89
--- /dev/null
+++ b/src/NetFabric.Numerics.Tensors.Benchmarks/NetFabric.Numerics.Tensors.Benchmarks.csproj
@@ -0,0 +1,19 @@
+
+
+
+ Exe
+ net8.0
+
+ false
+ NetFabric.Numerics.Tensors.Benchmarks
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/NetFabric.Numerics.Tensors.Benchmarks/Program.cs b/src/NetFabric.Numerics.Tensors.Benchmarks/Program.cs
new file mode 100644
index 0000000..e9c9373
--- /dev/null
+++ b/src/NetFabric.Numerics.Tensors.Benchmarks/Program.cs
@@ -0,0 +1,36 @@
+using BenchmarkDotNet.Columns;
+using BenchmarkDotNet.Configs;
+using BenchmarkDotNet.Jobs;
+using BenchmarkDotNet.Reports;
+using BenchmarkDotNet.Running;
+using System.Runtime.Intrinsics;
+
+var config = DefaultConfig.Instance
+ .WithSummaryStyle(SummaryStyle.Default.WithRatioStyle(RatioStyle.Trend))
+ .HideColumns(Column.EnvironmentVariables, Column.RatioSD, Column.Error)
+ // .AddDiagnoser(new DisassemblyDiagnoser(new DisassemblyDiagnoserConfig
+ // (exportGithubMarkdown: true, printInstructionAddresses: false)))
+ .AddJob(Job.Default.WithId("Scalar")
+ .WithEnvironmentVariable("DOTNET_EnableHWIntrinsic", "0")
+ .AsBaseline());
+
+if (Vector128.IsHardwareAccelerated)
+{
+ config = config
+ .AddJob(Job.Default.WithId("Vector128")
+ .WithEnvironmentVariable("DOTNET_EnableAVX2", "0")
+ .WithEnvironmentVariable("DOTNET_EnableAVX512F", "0"));
+}
+if (Vector256.IsHardwareAccelerated)
+{
+ config = config
+ .AddJob(Job.Default.WithId("Vector256")
+ .WithEnvironmentVariable("DOTNET_EnableAVX512F", "0"));
+}
+if (Vector512.IsHardwareAccelerated)
+{
+ config = config
+ .AddJob(Job.Default.WithId("Vector512"));
+}
+
+BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args, config);
\ No newline at end of file
diff --git a/src/NetFabric.Numerics.Benchmarks/TensorSumBenchmarks.cs b/src/NetFabric.Numerics.Tensors.Benchmarks/SumBenchmarks.cs
similarity index 94%
rename from src/NetFabric.Numerics.Benchmarks/TensorSumBenchmarks.cs
rename to src/NetFabric.Numerics.Tensors.Benchmarks/SumBenchmarks.cs
index 9e1afd9..6c8d6bc 100644
--- a/src/NetFabric.Numerics.Benchmarks/TensorSumBenchmarks.cs
+++ b/src/NetFabric.Numerics.Tensors.Benchmarks/SumBenchmarks.cs
@@ -1,8 +1,8 @@
using BenchmarkDotNet.Attributes;
-namespace NetFabric.Numerics.Rectangular2D.Benchmarks;
+namespace NetFabric.Numerics.Tensors.Benchmarks;
-public class TensorSumBenchmarks
+public class SumBenchmarks
{
short[]? arrayShort;
int[]? arrayInt;
diff --git a/src/NetFabric.Numerics.Tensors.UnitTests/AddMultiplyTests.cs b/src/NetFabric.Numerics.Tensors.UnitTests/AddMultiplyTests.cs
new file mode 100644
index 0000000..9c584d9
--- /dev/null
+++ b/src/NetFabric.Numerics.Tensors.UnitTests/AddMultiplyTests.cs
@@ -0,0 +1,100 @@
+using System.Linq;
+
+namespace NetFabric.Numerics.Tensors.UnitTests;
+
+public class AddMultiplyTests
+{
+ public static TheoryData AddData
+ => new() { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37 };
+
+ [Theory]
+ [MemberData(nameof(AddData))]
+ public void AddMultiply_Short_Should_Succeed(int count)
+ {
+ // arrange
+ var x = Enumerable.Range(0, count).Select(value => (short)value).ToArray();
+ var y = Enumerable.Range(0, count).Select(value => (short)(value + 1)).ToArray();
+ var z = Enumerable.Range(0, count).Select(value => (short)(value + 2)).ToArray();
+ var result = new short[count];
+ var expected = Enumerable.Range(0, count).Select(value => (short)((value + value + 1) * (value + 2))).ToArray();
+
+ // act
+ Tensor.AddMultiply(x, y, z, result);
+
+ // assert
+ result.Should().Equal(expected);
+ }
+
+ [Theory]
+ [MemberData(nameof(AddData))]
+ public void AddMultiply_Int_Should_Succeed(int count)
+ {
+ // arrange
+ var x = Enumerable.Range(0, count).ToArray();
+ var y = Enumerable.Range(0, count).Select(value => value + 1).ToArray();
+ var z = Enumerable.Range(0, count).Select(value => value + 2).ToArray();
+ var result = new int[count];
+ var expected = Enumerable.Range(0, count).Select(value => (value + value + 1) * (value + 2)).ToArray();
+
+ // act
+ Tensor.AddMultiply(x, y, z, result);
+
+ // assert
+ result.Should().Equal(expected);
+ }
+
+ [Theory]
+ [MemberData(nameof(AddData))]
+ public void AddMultiply_Long_Should_Succeed(int count)
+ {
+ // arrange
+ var x = Enumerable.Range(0, count).Select(value => (long)value).ToArray();
+ var y = Enumerable.Range(0, count).Select(value => (long)(value + 1)).ToArray();
+ var z = Enumerable.Range(0, count).Select(value => (long)(value + 2)).ToArray();
+ var result = new long[count];
+ var expected = Enumerable.Range(0, count).Select(value => (long)((value + value + 1) * (value + 2))).ToArray();
+
+ // act
+ Tensor.AddMultiply(x, y, z, result);
+
+ // assert
+ result.Should().Equal(expected);
+ }
+
+ [Theory]
+ [MemberData(nameof(AddData))]
+ public void AddMultiply_Float_Should_Succeed(int count)
+ {
+ // arrange
+ var x = Enumerable.Range(0, count).Select(value => (float)value).ToArray();
+ var y = Enumerable.Range(0, count).Select(value => (float)(value + 1)).ToArray();
+ var z = Enumerable.Range(0, count).Select(value => (float)(value + 2)).ToArray();
+ var result = new float[count];
+ var expected = Enumerable.Range(0, count).Select(value => (float)((value + value + 1) * (value + 2))).ToArray();
+
+ // act
+ Tensor.AddMultiply(x, y, z, result);
+
+ // assert
+ result.Should().Equal(expected);
+ }
+
+ [Theory]
+ [MemberData(nameof(AddData))]
+ public void AddMultiply_Double_Should_Succeed(int count)
+ {
+ // arrange
+ var x = Enumerable.Range(0, count).Select(value => (double)value).ToArray();
+ var y = Enumerable.Range(0, count).Select(value => (double)(value + 1)).ToArray();
+ var z = Enumerable.Range(0, count).Select(value => (double)(value + 2)).ToArray();
+ var result = new double[count];
+ var expected = Enumerable.Range(0, count).Select(value => (double)((value + value + 1) * (value + 2))).ToArray();
+
+ // act
+ Tensor.AddMultiply(x, y, z, result);
+
+ // assert
+ result.Should().Equal(expected);
+ }
+
+}
diff --git a/src/NetFabric.Numerics.Tensors.UnitTests/AddTests.cs b/src/NetFabric.Numerics.Tensors.UnitTests/AddTests.cs
new file mode 100644
index 0000000..36b3d9b
--- /dev/null
+++ b/src/NetFabric.Numerics.Tensors.UnitTests/AddTests.cs
@@ -0,0 +1,95 @@
+using System.Linq;
+
+namespace NetFabric.Numerics.Tensors.UnitTests;
+
+public class AddTests
+{
+ public static TheoryData AddData
+ => new() { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37 };
+
+ [Theory]
+ [MemberData(nameof(AddData))]
+ public void Add_Short_Should_Succeed(int count)
+ {
+ // arrange
+ var x = Enumerable.Range(0, count).Select(value => (short)value).ToArray();
+ var y = Enumerable.Range(0, count).Select(value => (short)(value + 1)).ToArray();
+ var result = new short[count];
+ var expected = Enumerable.Range(0, count).Select(value => (short)(value + value + 1)).ToArray();
+
+ // act
+ Tensor.Add(x, y, result);
+
+ // assert
+ result.Should().Equal(expected);
+ }
+
+ [Theory]
+ [MemberData(nameof(AddData))]
+ public void Add_Int_Should_Succeed(int count)
+ {
+ // arrange
+ var x = Enumerable.Range(0, count).ToArray();
+ var y = Enumerable.Range(0, count).Select(value => value + 1).ToArray();
+ var result = new int[count];
+ var expected = Enumerable.Range(0, count).Select(value => value + value + 1).ToArray();
+
+ // act
+ Tensor.Add(x, y, result);
+
+ // assert
+ result.Should().Equal(expected);
+ }
+
+ [Theory]
+ [MemberData(nameof(AddData))]
+ public void Add_Long_Should_Succeed(int count)
+ {
+ // arrange
+ var x = Enumerable.Range(0, count).Select(value => (long)value).ToArray();
+ var y = Enumerable.Range(0, count).Select(value => (long)(value + 1)).ToArray();
+ var result = new long[count];
+ var expected = Enumerable.Range(0, count).Select(value => (long)(value + value + 1)).ToArray();
+
+ // act
+ Tensor.Add(x, y, result);
+
+ // assert
+ result.Should().Equal(expected);
+ }
+
+ [Theory]
+ [MemberData(nameof(AddData))]
+ public void Add_Float_Should_Succeed(int count)
+ {
+ // arrange
+ var x = Enumerable.Range(0, count).Select(value => (float)value).ToArray();
+ var y = Enumerable.Range(0, count).Select(value => (float)(value + 1)).ToArray();
+ var result = new float[count];
+ var expected = Enumerable.Range(0, count).Select(value => (float)(value + value + 1)).ToArray();
+
+ // act
+ Tensor.Add(x, y, result);
+
+ // assert
+ result.Should().Equal(expected);
+ }
+
+ [Theory]
+ [MemberData(nameof(AddData))]
+ public void Add_Double_Should_Succeed(int count)
+ {
+ // arrange
+ var x = Enumerable.Range(0, count).Select(value => (double)value).ToArray();
+ var y = Enumerable.Range(0, count).Select(value => (double)(value + 1)).ToArray();
+ var result = new double[count];
+ var expected = Enumerable.Range(0, count).Select(value => (double)(value + value + 1)).ToArray();
+
+ // act
+ Tensor.Add(x, y, result);
+
+ // assert
+ result.Should().Equal(expected);
+ }
+
+}
diff --git a/src/NetFabric.Numerics.Tensors.UnitTests/AddValueTests.cs b/src/NetFabric.Numerics.Tensors.UnitTests/AddValueTests.cs
new file mode 100644
index 0000000..56aca90
--- /dev/null
+++ b/src/NetFabric.Numerics.Tensors.UnitTests/AddValueTests.cs
@@ -0,0 +1,92 @@
+using System.Linq;
+
+namespace NetFabric.Numerics.Tensors.UnitTests;
+
+public class AddValueTests
+{
+ public const int constValue = 42;
+
+ public static TheoryData AddData
+ => new() { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37 };
+
+ [Theory]
+ [MemberData(nameof(AddData))]
+ public void Add_Value_Short_Should_Succeed(int count)
+ {
+ // arrange
+ var x = Enumerable.Range(0, count).Select(value => (short)value).ToArray();
+ var result = new short[count];
+ var expected = Enumerable.Range(0, count).Select(value => (short)(value + constValue)).ToArray();
+
+ // act
+ Tensor.Add(x, constValue, result);
+
+ // assert
+ result.Should().Equal(expected);
+ }
+
+ [Theory]
+ [MemberData(nameof(AddData))]
+ public void Add_Value_Int_Should_Succeed(int count)
+ {
+ // arrange
+ var x = Enumerable.Range(0, count).ToArray();
+ var result = new int[count];
+ var expected = Enumerable.Range(0, count).Select(value => value + constValue).ToArray();
+
+ // act
+ Tensor.Add(x, constValue, result);
+
+ // assert
+ result.Should().Equal(expected);
+ }
+
+ [Theory]
+ [MemberData(nameof(AddData))]
+ public void Add_Value_Long_Should_Succeed(int count)
+ {
+ // arrange
+ var x = Enumerable.Range(0, count).Select(value => (long)value).ToArray();
+ var result = new long[count];
+ var expected = Enumerable.Range(0, count).Select(value => (long)(value + constValue)).ToArray();
+
+ // act
+ Tensor.Add(x, constValue, result);
+
+ // assert
+ result.Should().Equal(expected);
+ }
+
+ [Theory]
+ [MemberData(nameof(AddData))]
+ public void Add_Value_Float_Should_Succeed(int count)
+ {
+ // arrange
+ var x = Enumerable.Range(0, count).Select(value => (float)value).ToArray();
+ var result = new float[count];
+ var expected = Enumerable.Range(0, count).Select(value => (float)(value + constValue)).ToArray();
+
+ // act
+ Tensor.Add(x, constValue, result);
+
+ // assert
+ result.Should().Equal(expected);
+ }
+
+ [Theory]
+ [MemberData(nameof(AddData))]
+ public void Add_Value_Double_Should_Succeed(int count)
+ {
+ // arrange
+ var x = Enumerable.Range(0, count).Select(value => (double)value).ToArray();
+ var result = new double[count];
+ var expected = Enumerable.Range(0, count).Select(value => (double)(value + constValue)).ToArray();
+
+ // act
+ Tensor.Add(x, constValue, result);
+
+ // assert
+ result.Should().Equal(expected);
+ }
+
+}
diff --git a/src/NetFabric.Numerics.Tensors.UnitTests/NetFabric.Numerics.Tensors.UnitTests.csproj b/src/NetFabric.Numerics.Tensors.UnitTests/NetFabric.Numerics.Tensors.UnitTests.csproj
new file mode 100644
index 0000000..928ffb5
--- /dev/null
+++ b/src/NetFabric.Numerics.Tensors.UnitTests/NetFabric.Numerics.Tensors.UnitTests.csproj
@@ -0,0 +1,34 @@
+
+
+
+ net8.0
+
+ false
+ true
+ NetFabric.Numerics.Tensors.UnitsTests
+
+
+
+
+
+
+
+
+
+
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+
+
+
+
+
+
diff --git a/src/NetFabric.Numerics.Tensors.UnitTests/SquareTests.cs b/src/NetFabric.Numerics.Tensors.UnitTests/SquareTests.cs
new file mode 100644
index 0000000..ac66f08
--- /dev/null
+++ b/src/NetFabric.Numerics.Tensors.UnitTests/SquareTests.cs
@@ -0,0 +1,91 @@
+using System.Linq;
+
+namespace NetFabric.Numerics.Tensors.UnitTests;
+
+public class SquareTests
+{
+ public static TheoryData SquareData
+ => new() { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37 };
+
+ [Theory]
+ [MemberData(nameof(SquareData))]
+ public void Square_Short_Should_Succeed(int count)
+ {
+ // arrange
+ var x = Enumerable.Range(0, count).Select(value => (short)value).ToArray();
+ var result = new short[count];
+ var expected = Enumerable.Range(0, count).Select(value => (short)(value * value)).ToArray();
+
+ // act
+ Tensor.Square(x, result);
+
+ // assert
+ result.Should().Equal(expected);
+ }
+
+ [Theory]
+ [MemberData(nameof(SquareData))]
+ public void Square_Int_Should_Succeed(int count)
+ {
+ // arrange
+ var x = Enumerable.Range(0, count).ToArray();
+ var result = new int[count];
+ var expected = Enumerable.Range(0, count).Select(value => value * value).ToArray();
+
+ // act
+ Tensor.Square(x, result);
+
+ // assert
+ result.Should().Equal(expected);
+ }
+
+ [Theory]
+ [MemberData(nameof(SquareData))]
+ public void Square_Long_Should_Succeed(int count)
+ {
+ // arrange
+ var x = Enumerable.Range(0, count).Select(value => (long)value).ToArray();
+ var y = Enumerable.Range(0, count).Select(value => (long)(value + 1)).ToArray();
+ var result = new long[count];
+ var expected = Enumerable.Range(0, count).Select(value => (long)(value * value)).ToArray();
+
+ // act
+ Tensor.Square(x, result);
+
+ // assert
+ result.Should().Equal(expected);
+ }
+
+ [Theory]
+ [MemberData(nameof(SquareData))]
+ public void Square_Float_Should_Succeed(int count)
+ {
+ // arrange
+ var x = Enumerable.Range(0, count).Select(value => (float)value).ToArray();
+ var result = new float[count];
+ var expected = Enumerable.Range(0, count).Select(value => (float)(value * value)).ToArray();
+
+ // act
+ Tensor.Square(x, result);
+
+ // assert
+ result.Should().Equal(expected);
+ }
+
+ [Theory]
+ [MemberData(nameof(SquareData))]
+ public void Square_Double_Should_Succeed(int count)
+ {
+ // arrange
+ var x = Enumerable.Range(0, count).Select(value => (double)value).ToArray();
+ var result = new double[count];
+ var expected = Enumerable.Range(0, count).Select(value => (double)(value * value)).ToArray();
+
+ // act
+ Tensor.Square(x, result);
+
+ // assert
+ result.Should().Equal(expected);
+ }
+
+}
diff --git a/src/NetFabric.Numerics.Tensors.UnitTests/SumTests.cs b/src/NetFabric.Numerics.Tensors.UnitTests/SumTests.cs
new file mode 100644
index 0000000..b5d1d89
--- /dev/null
+++ b/src/NetFabric.Numerics.Tensors.UnitTests/SumTests.cs
@@ -0,0 +1,85 @@
+using System.Linq;
+
+namespace NetFabric.Numerics.Tensors.UnitTests;
+
+public class SumTests
+{
+ public static TheoryData SumData
+ => new() { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37 };
+
+ [Theory]
+ [MemberData(nameof(SumData))]
+ public void Sum_Short_Should_Succeed(int count)
+ {
+ // arrange
+ var source = Enumerable.Range(0, count).Select(value => (short)value).ToArray();
+ var expected = Enumerable.Range(0, count).Sum();
+
+ // act
+ var result = Tensor.Sum(source);
+
+ // assert
+ result.Should().Be((short)expected);
+ }
+
+ [Theory]
+ [MemberData(nameof(SumData))]
+ public void Sum_Int_Should_Succeed(int count)
+ {
+ // arrange
+ var source = Enumerable.Range(0, count).ToArray();
+ var expected = source.Sum();
+
+ // act
+ var result = Tensor.Sum(source);
+
+ // assert
+ result.Should().Be(expected);
+ }
+
+ [Theory]
+ [MemberData(nameof(SumData))]
+ public void Sum_Long_Should_Succeed(int count)
+ {
+ // arrange
+ var source = Enumerable.Range(0, count).Select(value => (long)value).ToArray();
+ var expected = source.Sum();
+
+ // act
+ var result = Tensor.Sum(source);
+
+ // assert
+ result.Should().Be(expected);
+ }
+
+ [Theory]
+ [MemberData(nameof(SumData))]
+ public void Sum_Float_Should_Succeed(int count)
+ {
+ // arrange
+ var source = Enumerable.Range(0, count).Select(value => (float)value).ToArray();
+ var expected = source.Sum();
+
+ // act
+ var result = Tensor.Sum(source);
+
+ // assert
+ result.Should().Be(expected);
+ }
+
+ [Theory]
+ [MemberData(nameof(SumData))]
+ public void Sum_Double_Should_Succeed(int count)
+ {
+ // arrange
+ var source = Enumerable.Range(0, count).Select(value => (double)value).ToArray();
+ var expected = source.Sum();
+
+ // act
+ var result = Tensor.Sum(source);
+
+ // assert
+ result.Should().Be(expected);
+ }
+
+}
diff --git a/src/NetFabric.Numerics.Tensors/Add.cs b/src/NetFabric.Numerics.Tensors/Add.cs
index 7734fd4..54de76f 100644
--- a/src/NetFabric.Numerics.Tensors/Add.cs
+++ b/src/NetFabric.Numerics.Tensors/Add.cs
@@ -4,29 +4,11 @@ namespace NetFabric.Numerics;
public static partial class Tensor
{
- ///
- /// Adds a value to each element in the source span and stores the result in the destination span.
- ///
- /// The type of the elements in the spans.
- /// The source span.
- /// The value to add to each element.
- /// The destination span to store the result.
- /// Thrown when the source and destination spans have different lengths.
- /// Thrown when the type does not implement the interface.
- public static void Add(ReadOnlySpan left, T right, Span destination)
+ public static void Add(ReadOnlySpan x, T y, Span destination)
where T : struct, IAdditionOperators
- => Apply>(left, right, destination);
+ => Apply>(x, y, destination);
- ///
- /// Adds corresponding elements in the left and right spans and stores the result in the destination span.
- ///
- /// The type of the elements in the spans.
- /// The left span.
- /// The right span.
- /// The destination span to store the result.
- /// Thrown when the left, right, and destination spans have different lengths.
- /// Thrown when the type does not implement the interface.
- public static void Add(ReadOnlySpan left, ReadOnlySpan right, Span destination)
+ public static void Add(ReadOnlySpan x, ReadOnlySpan y, Span destination)
where T : struct, IAdditionOperators
- => Apply>(left, right, destination);
+ => Apply>(x, y, destination);
}
diff --git a/src/NetFabric.Numerics.Tensors/AddMultiply.cs b/src/NetFabric.Numerics.Tensors/AddMultiply.cs
new file mode 100644
index 0000000..d3ef772
--- /dev/null
+++ b/src/NetFabric.Numerics.Tensors/AddMultiply.cs
@@ -0,0 +1,22 @@
+using System.Runtime.InteropServices;
+
+namespace NetFabric.Numerics;
+
+public static partial class Tensor
+{
+ public static void AddMultiply(ReadOnlySpan x, T y, T z, Span destination)
+ where T : struct, IAdditionOperators, IMultiplyOperators
+ => Apply>(x, y, z, destination);
+
+ public static void AddMultiply(ReadOnlySpan x, T y, ReadOnlySpan z, Span destination)
+ where T : struct, IAdditionOperators, IMultiplyOperators
+ => Apply>(x, y, z, destination);
+
+ public static void AddMultiply(ReadOnlySpan x, ReadOnlySpan y, T z, Span destination)
+ where T : struct, IAdditionOperators, IMultiplyOperators
+ => Apply>(x, y, z, destination);
+
+ public static void AddMultiply(ReadOnlySpan x, ReadOnlySpan y, ReadOnlySpan z, Span destination)
+ where T : struct, IAdditionOperators, IMultiplyOperators
+ => Apply>(x, y, z, destination);
+}
diff --git a/src/NetFabric.Numerics.Tensors/Apply.cs b/src/NetFabric.Numerics.Tensors/Apply.cs
index 122fce2..d510c42 100644
--- a/src/NetFabric.Numerics.Tensors/Apply.cs
+++ b/src/NetFabric.Numerics.Tensors/Apply.cs
@@ -333,4 +333,55 @@ public static void Apply(ReadOnlySpan x, ReadOnlySpan y, T z
}
}
+ public static void Apply(ReadOnlySpan x, T y, T z, Span destination)
+ where T : struct
+ where TOperator : struct, ITernaryOperator
+ {
+ if (x.Length > destination.Length)
+ Throw.ArgumentException(nameof(destination), "Destination span is too small.");
+ if(SpansOverlapAndAreNotSame(x, destination))
+ Throw.ArgumentException(nameof(destination), "Destination span overlaps with x.");
+
+ // Initialize the index to 0.
+ nint index = 0;
+
+ // Check if hardware acceleration and Vector support are available,
+ // and if the length of the x is greater than the Vector.Count.
+ if (Vector.IsHardwareAccelerated &&
+ Vector.IsSupported &&
+ x.Length >= Vector.Count)
+ {
+ // Cast the spans to vectors for hardware acceleration.
+ var xVectors = MemoryMarshal.Cast>(x);
+ var yVector = new Vector(y);
+ var zVector = new Vector(z);
+ var destinationVectors = MemoryMarshal.Cast>(destination);
+
+ // Iterate through the vectors.
+ ref var xVectorsRef = ref MemoryMarshal.GetReference(xVectors);
+ ref var destinationVectorsRef = ref MemoryMarshal.GetReference(destinationVectors);
+ for (nint indexVector = 0; indexVector < xVectors.Length; indexVector++)
+ {
+ Unsafe.Add(ref destinationVectorsRef, indexVector) = TOperator.Invoke(
+ Unsafe.Add(ref xVectorsRef, indexVector),
+ yVector,
+ zVector);
+ }
+
+ // Update the index to the end of the last complete vector.
+ index = x.Length - x.Length % Vector.Count;
+ }
+
+ // Iterate through the remaining elements.
+ ref var xRef = ref MemoryMarshal.GetReference(x);
+ ref var destinationRef = ref MemoryMarshal.GetReference(destination);
+ for (; index < x.Length; index++)
+ {
+ Unsafe.Add(ref destinationRef, index) = TOperator.Invoke(
+ Unsafe.Add(ref xRef, index),
+ y,
+ z);
+ }
+ }
+
}
\ No newline at end of file
diff --git a/src/NetFabric.Numerics.Tensors/Negate.cs b/src/NetFabric.Numerics.Tensors/Negate.cs
new file mode 100644
index 0000000..c75179e
--- /dev/null
+++ b/src/NetFabric.Numerics.Tensors/Negate.cs
@@ -0,0 +1,10 @@
+using System.Runtime.InteropServices;
+
+namespace NetFabric.Numerics;
+
+public static partial class Tensor
+{
+ public static void Negate(ReadOnlySpan left, Span destination)
+ where T : struct, IUnaryNegationOperators
+ => Apply>(left, destination);
+}
diff --git a/src/NetFabric.Numerics.Tensors/Operators/AddMultiplyOperator.cs b/src/NetFabric.Numerics.Tensors/Operators/AddMultiplyOperator.cs
new file mode 100644
index 0000000..6c15f37
--- /dev/null
+++ b/src/NetFabric.Numerics.Tensors/Operators/AddMultiplyOperator.cs
@@ -0,0 +1,14 @@
+using System.Runtime.InteropServices;
+
+namespace NetFabric.Numerics;
+
+public readonly struct AddMultiplyOperator
+ : ITernaryOperator
+ where T : struct, IAdditionOperators, IMultiplyOperators
+{
+ public static T Invoke(T x, T y, T z)
+ => (x + y) * z;
+
+ public static Vector Invoke(Vector x, Vector y, Vector z)
+ => (x + y) * z;
+}
\ No newline at end of file
diff --git a/src/NetFabric.Numerics.Tensors/Operators/MultiplyAddOperator.cs b/src/NetFabric.Numerics.Tensors/Operators/MultiplyAddOperator.cs
new file mode 100644
index 0000000..3ae472e
--- /dev/null
+++ b/src/NetFabric.Numerics.Tensors/Operators/MultiplyAddOperator.cs
@@ -0,0 +1,14 @@
+using System.Runtime.InteropServices;
+
+namespace NetFabric.Numerics;
+
+public readonly struct MultiplyAddOperator
+ : ITernaryOperator
+ where T : struct, IAdditionOperators, IMultiplyOperators
+{
+ public static T Invoke(T x, T y, T z)
+ => (x * y) + z;
+
+ public static Vector Invoke(Vector x, Vector y, Vector z)
+ => (x * y) + z;
+}
\ No newline at end of file
diff --git a/src/NetFabric.Numerics.Tensors/Operators/NegateOperator.cs b/src/NetFabric.Numerics.Tensors/Operators/NegateOperator.cs
new file mode 100644
index 0000000..06a1f14
--- /dev/null
+++ b/src/NetFabric.Numerics.Tensors/Operators/NegateOperator.cs
@@ -0,0 +1,14 @@
+using System.Runtime.InteropServices;
+
+namespace NetFabric.Numerics;
+
+public readonly struct NegateOperator
+ : IUnaryOperator
+ where T : struct, IUnaryNegationOperators
+{
+ public static T Invoke(T x)
+ => -x;
+
+ public static Vector Invoke(Vector x)
+ => -x;
+}
\ No newline at end of file
diff --git a/src/NetFabric.Numerics.Tensors/Operators/SquareOperator.cs b/src/NetFabric.Numerics.Tensors/Operators/SquareOperator.cs
new file mode 100644
index 0000000..9f0f0a2
--- /dev/null
+++ b/src/NetFabric.Numerics.Tensors/Operators/SquareOperator.cs
@@ -0,0 +1,14 @@
+using System.Runtime.InteropServices;
+
+namespace NetFabric.Numerics;
+
+public readonly struct SquareOperator
+ : IUnaryOperator
+ where T : struct, IMultiplyOperators
+{
+ public static T Invoke(T x)
+ => x * x;
+
+ public static Vector Invoke(Vector x)
+ => x * x;
+}
\ No newline at end of file
diff --git a/src/NetFabric.Numerics.Tensors/Square.cs b/src/NetFabric.Numerics.Tensors/Square.cs
new file mode 100644
index 0000000..6dfc8e6
--- /dev/null
+++ b/src/NetFabric.Numerics.Tensors/Square.cs
@@ -0,0 +1,10 @@
+using System.Runtime.InteropServices;
+
+namespace NetFabric.Numerics;
+
+public static partial class Tensor
+{
+ public static void Square(ReadOnlySpan left, Span destination)
+ where T : struct, IMultiplyOperators
+ => Apply>(left, destination);
+}