├── .github └── workflows │ ├── Build.yml │ ├── Test.yml │ └── codecov.yml ├── .gitignore ├── Benchmark ├── Agg.cs ├── Benchmark.csproj ├── FastBenchmark.cs ├── Iterating.cs ├── Matrix.cs ├── OneVsMulti.cs ├── Program.cs ├── matrixmultiplication.png └── piecewisemultiplication.PNG ├── GenericTensor.sln ├── GenericTensor.sln.licenseheader ├── GenericTensor ├── Core │ ├── Exceptions.cs │ ├── Expressions │ │ └── IteratorCompiler.cs │ ├── IOperations.cs │ ├── Operators.cs │ ├── Tensor │ │ ├── GenTensor.Axes.cs │ │ ├── GenTensor.Iterate.cs │ │ ├── GenTensor.Subtensor.cs │ │ └── Tensor.cs │ ├── TensorShape.cs │ └── ThreadUtils.cs ├── Declaration.cs ├── Functions │ ├── Composition.cs │ ├── Constructors.cs │ ├── CopyAndForward.cs │ ├── DefaultWrappers.cs │ ├── Determinant.cs │ ├── EchelonForm.cs │ ├── ElementaryRowOperations.cs │ ├── Inverse.cs │ ├── LuDecomposition.cs │ ├── MatrixMultiplication.cs │ ├── PiecewiseArithmetics.cs │ ├── PluDecomposition.cs │ ├── Power.cs │ ├── Serialization.cs │ ├── SquareMatrixFactory.cs │ ├── ToString.cs │ ├── Vector.CrossProduct.cs │ └── Vector.DotProduct.cs ├── GenericTensor.csproj └── keypair.snk ├── LICENSE ├── README.md ├── Sample ├── MatrixWrapper.cs ├── Program.cs └── Sample.csproj ├── UnitTests ├── Aggregate.cs ├── Concat.cs ├── Constructors.cs ├── Copying.cs ├── Determinant.cs ├── EchelonForms.cs ├── ElementaryRowOperations.cs ├── ForEach.cs ├── GetMatrixFactoryTest.cs ├── Identity.cs ├── Inverse.cs ├── LuDecompositions.cs ├── MatrixProduct.cs ├── Piecewise.cs ├── Power.cs ├── ReferenceWrapperTest.cs ├── Serialization.cs ├── SetGet.cs ├── Slicing.cs ├── Subtensor.cs ├── Transposition.cs ├── UnitTests.csproj └── VectorProduct.cs └── ico1.png /.github/workflows/Build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: [push, pull_request] 4 | jobs: 5 | UnitTests: 6 | runs-on: ${{ matrix.os }} 7 | strategy: 8 | matrix: 9 | os: [windows-latest, ubuntu-latest, macos-latest] 10 | steps: 11 | - uses: actions/checkout@v2 12 | with: 13 | submodules: 'recursive' 14 | - name: Setup .NET 15 | uses: actions/setup-dotnet@v1 16 | with: 17 | dotnet-version: '6.0.201' 18 | - name: Build 19 | run: dotnet build GenericTensor.sln 20 | -------------------------------------------------------------------------------- /.github/workflows/Test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | 3 | on: [push, pull_request] 4 | jobs: 5 | UnitTests: 6 | runs-on: ubuntu-latest 7 | steps: 8 | - uses: actions/checkout@v2 9 | with: 10 | submodules: 'recursive' 11 | - name: Setup .NET 6 12 | uses: actions/setup-dotnet@v1 13 | with: 14 | dotnet-version: '6.0.201' 15 | - name: Test 16 | run: | 17 | dotnet add "UnitTests" package Microsoft.NET.Test.Sdk 18 | dotnet add "UnitTests" package GitHubActionsTestLogger 19 | dotnet add "UnitTests" package coverlet.msbuild 20 | dotnet test "UnitTests" -c Release -l GitHubActions /p:CollectCoverage=true /p:CoverletOutputFormat=opencover 21 | - uses: codecov/codecov-action@v1 22 | with: 23 | file: ./UnitTests/coverage.opencover.xml 24 | -------------------------------------------------------------------------------- /.github/workflows/codecov.yml: -------------------------------------------------------------------------------- 1 | codecov: 2 | require_ci_to_pass: yes 3 | 4 | coverage: 5 | precision: 2 6 | round: down 7 | range: "50...100" 8 | patch: no 9 | changes: no 10 | 11 | parsers: 12 | gcov: 13 | branch_detection: 14 | conditional: yes 15 | loop: yes 16 | method: no 17 | macro: no 18 | 19 | comment: 20 | layout: "reach,diff,flags,tree" 21 | behavior: default 22 | require_changes: no 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | */_ReSharper.Caches/* 2 | /GenericTensor/GenericTensor.xml 3 | *.vs* 4 | */bin/* 5 | */obj/* 6 | */packages/* 7 | GenericTensor.sln.DotSettings.user -------------------------------------------------------------------------------- /Benchmark/Agg.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Attributes; 2 | using GenericTensor.Core; 3 | using GenericTensor.Functions; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | 10 | namespace Benchmark 11 | { 12 | public class Agg 13 | { 14 | // 3 x 2 x 2 x 2 15 | private static readonly GenTensor frog = GenTensor.CreateTensor(new[, , ,] { 16 | { 17 | { { 1, 2 }, { 3, 4 } }, 18 | { { 10, 20 }, { 30, 40 } }, 19 | }, 20 | { 21 | { { 100, 200 }, { 300, 400 } }, 22 | { { 1000, 2000 }, { 3000, 4000 } }, 23 | }, 24 | { 25 | { { 10000, 20000 }, { 30000, 40000 } }, 26 | { { 100000, 200000 }, { 300000, 400000 } }, 27 | } 28 | }); 29 | 30 | private static readonly GenTensor frogCopy = frog.Copy(true); 31 | 32 | [Benchmark] 33 | public void SumAx0() 34 | { 35 | var acc = GenTensor.CreateTensor(new TensorShape(2, 2, 2), id => 0); 36 | GenTensor.Aggregate(frog, acc, new HonkPerf.NET.Core.PureValueDelegate((a, b) => a + b), axis: 0); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Benchmark/Benchmark.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net5.0 6 | 7 | 8 | 9 | true 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /Benchmark/FastBenchmark.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Attributes; 2 | using GenericTensor.Core; 3 | using GenericTensor.Functions; 4 | 5 | namespace Benchmark 6 | { 7 | using TS = GenTensor; 8 | 9 | public class FastBenchmark 10 | { 11 | static TS CreateMatrix(int size) 12 | => TS.CreateMatrix(size, size, (x, y) => (x + y)); 13 | 14 | private static readonly TS createdMatrix6 = CreateMatrix(6); 15 | private static readonly TS createdMatrix9 = CreateMatrix(9); 16 | private static readonly TS createdMatrix20 = CreateMatrix(20); 17 | 18 | [Benchmark] public void MatrixAndGaussian6() 19 | => createdMatrix6.DeterminantGaussianSafeDivision(); 20 | 21 | [Benchmark] public void CreatingMatrix20() 22 | => CreateMatrix(20); 23 | 24 | [Benchmark] public void MatrixAndMultiply20() 25 | => TS.MatrixMultiply(createdMatrix20, createdMatrix20); 26 | 27 | [Benchmark] public void MatrixAndAdd20() 28 | => TS.PiecewiseAdd(createdMatrix20, createdMatrix20); 29 | 30 | [Benchmark] public void SafeIndexing() 31 | { 32 | for (int i = 0; i < createdMatrix9.Shape[0]; i++) 33 | for (int j = 0; j < createdMatrix9.Shape[1]; j++) 34 | { 35 | var c = createdMatrix9[i, j]; 36 | } 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Benchmark/Iterating.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Attributes; 2 | using GenericTensor.Core; 3 | using GenericTensor.Functions; 4 | using HonkPerf.NET.Core; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | using System.Text; 9 | using System.Threading.Tasks; 10 | 11 | namespace Benchmark 12 | { 13 | /* 14 | 15 | | Method | Mean | Error | StdDev | Median | 16 | |-------- |---------:|----------:|----------:|---------:| 17 | | Iterate | 7.129 us | 0.1396 us | 0.3234 us | 7.019 us | 18 | | ForEach | 2.342 us | 0.0495 us | 0.1459 us | 2.287 us | 19 | 20 | */ 21 | public class Iterating 22 | { 23 | public GenTensor tensor = GenTensor.CreateTensor(new TensorShape(10, 4, 5), _ => 3); 24 | 25 | [Benchmark] 26 | public void Iterate() 27 | { 28 | foreach (var (index, value) in tensor.Iterate()) 29 | tensor[index] = value * 2; 30 | } 31 | 32 | public struct Multiply : IValueAction 33 | { 34 | private GenTensor tensor; 35 | public Multiply(GenTensor t) => tensor = t; 36 | public void Invoke(int[] arg1, int arg2) 37 | { 38 | tensor[arg1] = arg2 * 2; 39 | } 40 | } 41 | 42 | 43 | [Benchmark] 44 | public void ForEach() 45 | { 46 | tensor.ForEach(new Multiply(tensor)); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Benchmark/Matrix.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using System.Numerics; 3 | using BenchmarkDotNet.Attributes; 4 | using GenericTensor.Functions; 5 | using GenericTensor.Core; 6 | 7 | namespace Benchmark 8 | { 9 | using TS = GenTensor; 10 | public class MatrixBenchmark 11 | { 12 | [GlobalSetup] 13 | public void Setup() 14 | { 15 | 16 | } 17 | 18 | static TS CreateMatrix(int size) 19 | => TS.CreateMatrix(size, size, (x, y) => x + y); 20 | 21 | static TS CreateTensor(int W, int size) 22 | => TS.Stack(Enumerable.Range(0, W).Select(c => CreateMatrix(size)).ToArray()); 23 | 24 | private static readonly TS createdMatrix3 = CreateMatrix(3); 25 | private static readonly TS createdMatrix4x4 = CreateMatrix(4); 26 | private static readonly TS createdMatrix4x4_dupl = CreateMatrix(4); 27 | private static readonly TS createdMatrix6 = CreateMatrix(6); 28 | private static readonly TS createdMatrix9 = CreateMatrix(9); 29 | private static readonly TS createdMatrix20 = CreateMatrix(20); 30 | private static readonly TS createdMatrix20_dupl = CreateMatrix(20); 31 | private static readonly TS createdTensorMatrix15 = CreateTensor(40, 15); 32 | private static readonly TS createdMatrix100 = CreateMatrix(100); 33 | private static readonly TS createdMatrix100_dupl = CreateMatrix(100); 34 | 35 | private static readonly TS createdMatrix250 = CreateMatrix(250); 36 | private static readonly TS createdMatrix250_dupl = CreateMatrix(250); 37 | 38 | /* 39 | [Benchmark] public void MatrixAndAdd250() 40 | => TS.PiecewiseAdd(createdMatrix250, createdMatrix250_dupl); 41 | 42 | [Benchmark] public void MatrixAndAdd250Par() 43 | => TS.PiecewiseAdd(createdMatrix250, createdMatrix250_dupl, Threading.Multi); 44 | */ 45 | 46 | 47 | [Benchmark] public void MatrixAndLaplace3() 48 | => createdMatrix3.DeterminantLaplace(); 49 | [Benchmark] public void MatrixAndLaplace6() 50 | => createdMatrix6.DeterminantLaplace(); 51 | [Benchmark] public void MatrixAndLaplace9() 52 | => createdMatrix9.DeterminantLaplace(); 53 | 54 | [Benchmark] public void MatrixAndGaussian3() 55 | => createdMatrix3.DeterminantGaussianSafeDivision(); 56 | 57 | [Benchmark] public void MatrixAndGaussian6() 58 | => createdMatrix6.DeterminantGaussianSafeDivision(); 59 | 60 | [Benchmark] public void MatrixAndGaussian9() 61 | => createdMatrix9.DeterminantGaussianSafeDivision(); 62 | 63 | [Benchmark] public void CreatingMatrix20() 64 | => CreateMatrix(20); 65 | 66 | [Benchmark] public void CreatingMatrix50() 67 | => CreateMatrix(50); 68 | 69 | [Benchmark] public void Transpose20() 70 | => createdMatrix20.TransposeMatrix(); 71 | 72 | [Benchmark] public void MatrixAndMultiply6() 73 | => TS.MatrixMultiply(createdMatrix6, createdMatrix6); 74 | 75 | [Benchmark] public void MatrixAndMultiply20() 76 | => TS.MatrixMultiply(createdMatrix20, createdMatrix20_dupl); 77 | 78 | [Benchmark] public void TensorAndMultiply15() 79 | => TS.TensorMatrixMultiply(createdTensorMatrix15, createdTensorMatrix15); 80 | 81 | [Benchmark] public void MatrixAndMultiply6Parallel() 82 | => TS.MatrixMultiply(createdMatrix20, createdMatrix20_dupl, Threading.Multi); 83 | 84 | [Benchmark] public void MatrixAndMultiply20Parallel() 85 | => TS.MatrixMultiply(createdMatrix20, createdMatrix20_dupl, Threading.Multi); 86 | 87 | [Benchmark] public void TensorAndMultiply15Parallel() 88 | => TS.TensorMatrixMultiply(createdTensorMatrix15, createdTensorMatrix15, Threading.Multi); 89 | 90 | [Benchmark] public void MatrixAndAdd20() 91 | => TS.PiecewiseAdd(createdMatrix20, createdMatrix20_dupl); 92 | 93 | [Benchmark] public void MatrixAndAdd100() 94 | => TS.PiecewiseAdd(createdMatrix100, createdMatrix100_dupl); 95 | 96 | [Benchmark] public void MatrixAndAdd20Parallel() 97 | => TS.PiecewiseAdd(createdMatrix20, createdMatrix20_dupl, Threading.Multi); 98 | 99 | [Benchmark] public void MatrixAndAdd100Parallel() 100 | => TS.PiecewiseAdd(createdMatrix100, createdMatrix100_dupl, Threading.Multi); 101 | 102 | 103 | [Benchmark] public void SafeIndexing() 104 | { 105 | for (int i = 0; i < createdMatrix9.Shape[0]; i++) 106 | for (int j = 0; j < createdMatrix9.Shape[1]; j++) 107 | { 108 | var c = createdMatrix9[i, j]; 109 | } 110 | } 111 | 112 | [Benchmark] public void FastIndexing() 113 | { 114 | for (int i = 0; i < createdMatrix9.Shape[0]; i++) 115 | for (int j = 0; j < createdMatrix9.Shape[1]; j++) 116 | { 117 | var c = createdMatrix9.GetValueNoCheck(i, j); 118 | } 119 | } 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /Benchmark/OneVsMulti.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using BenchmarkDotNet.Attributes; 3 | using GenericTensor.Core; 4 | using GenericTensor.Functions; 5 | 6 | namespace Benchmark 7 | { 8 | using TS = GenTensor; 9 | 10 | public class OneVsMulti 11 | { 12 | static TS CreateTensor(int width, int size) 13 | => TS.CreateTensor(new TensorShape(width, size, size), (ind) => ind[0] + ind[1] + ind[2]); 14 | 15 | #pragma warning disable IDE0044 // Add readonly modifier 16 | #pragma warning disable IDE0051 // Remove unused private members 17 | 18 | static TS CreateTensorPar(int width, int size) 19 | => TS.CreateTensor(new TensorShape(width, size, size), (ind) => ind[0] + ind[1] + ind[2], Threading.Multi); 20 | 21 | private TS created; 22 | #pragma warning restore IDE0051 // Remove unused private members 23 | #pragma warning restore IDE0044 // Add readonly modifier 24 | 25 | private readonly Dictionary<(int width, int height), TS> storage = new Dictionary<(int width, int height), TS>(); 26 | 27 | private TS GetT(int width, int height) 28 | { 29 | var key = (width, height); 30 | if (!storage.ContainsKey(key)) 31 | storage[key] = CreateTensor(width, height); 32 | return storage[key]; 33 | } 34 | 35 | /* 36 | [Benchmark] 37 | public void CreatingTensor() 38 | => CreateTensor(Width, Height); 39 | 40 | [Benchmark] 41 | public void CreatingTensorPar() 42 | => CreateTensorPar(Width, Height); 43 | */ 44 | 45 | #region matrix multiplication single 46 | [Benchmark] 47 | public void Multiply5x5x5() 48 | => TS.TensorMatrixMultiply(GetT(5, 5), GetT(5, 5)); 49 | 50 | [Benchmark] 51 | public void Multiply15x5x5() 52 | => TS.TensorMatrixMultiply(GetT(15, 5), GetT(15, 5)); 53 | 54 | [Benchmark] 55 | public void Multiply5x15x15() 56 | => TS.TensorMatrixMultiply(GetT(5, 15), GetT(5, 15)); 57 | 58 | [Benchmark] 59 | public void Multiply15x15x15() 60 | => TS.TensorMatrixMultiply(GetT(15, 15), GetT(15, 15)); 61 | 62 | #endregion 63 | 64 | #region matrix multiplication multi 65 | 66 | [Benchmark] 67 | public void Multiply5x5x5Par() 68 | => TS.TensorMatrixMultiply(GetT(5, 5), GetT(5, 5), Threading.Multi); 69 | 70 | [Benchmark] 71 | public void Multiply15x5x5Par() 72 | => TS.TensorMatrixMultiply(GetT(15, 5), GetT(15, 5), Threading.Multi); 73 | 74 | [Benchmark] 75 | public void Multiply5x15x15Par() 76 | => TS.TensorMatrixMultiply(GetT(5, 15), GetT(5, 15), Threading.Multi); 77 | 78 | [Benchmark] 79 | public void Multiply15x15x15Par() 80 | => TS.TensorMatrixMultiply(GetT(15, 15), GetT(15, 15), Threading.Multi); 81 | 82 | #endregion 83 | 84 | 85 | #region piecewise single 86 | 87 | 88 | [Benchmark] 89 | public void Piecewise10x10x10() 90 | => TS.PiecewiseAdd(GetT(10, 10), GetT(10, 10)); 91 | 92 | [Benchmark] 93 | public void Piecewise30x10x10() 94 | => TS.PiecewiseAdd(GetT(30, 10), GetT(30, 10)); 95 | 96 | [Benchmark] 97 | public void Piecewise10x30x30() 98 | => TS.PiecewiseAdd(GetT(10, 30), GetT(10, 30)); 99 | 100 | [Benchmark] 101 | public void Piecewise30x30x30() 102 | => TS.PiecewiseAdd(GetT(30, 30), GetT(30, 30)); 103 | 104 | 105 | #endregion 106 | 107 | #region piecewise multi 108 | 109 | 110 | [Benchmark] 111 | public void Piecewise10x10x10Par() 112 | => TS.PiecewiseAdd(GetT(10, 10), GetT(10, 10), Threading.Multi); 113 | 114 | [Benchmark] 115 | public void Piecewise30x10x10Par() 116 | => TS.PiecewiseAdd(GetT(30, 10), GetT(30, 10), Threading.Multi); 117 | 118 | [Benchmark] 119 | public void Piecewise10x30x30Par() 120 | => TS.PiecewiseAdd(GetT(10, 30), GetT(10, 30), Threading.Multi); 121 | 122 | [Benchmark] 123 | public void Piecewise30x30x30Par() 124 | => TS.PiecewiseAdd(GetT(30, 30), GetT(30, 30), Threading.Multi); 125 | 126 | #endregion 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /Benchmark/Program.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Running; 2 | 3 | namespace Benchmark 4 | { 5 | class Program 6 | { 7 | static void Main(string[] args) 8 | { 9 | // BenchmarkRunner.Run(); 10 | // BenchmarkRunner.Run(); 11 | BenchmarkRunner.Run(); 12 | // new Iterating().ForEach(); 13 | // new Iterating().Iterate(); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Benchmark/matrixmultiplication.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asc-community/GenericTensor/da0c01d2acb17530ee6bc39da79692148c92069b/Benchmark/matrixmultiplication.png -------------------------------------------------------------------------------- /Benchmark/piecewisemultiplication.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asc-community/GenericTensor/da0c01d2acb17530ee6bc39da79692148c92069b/Benchmark/piecewisemultiplication.PNG -------------------------------------------------------------------------------- /GenericTensor.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.30011.22 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GenericTensor", "GenericTensor\GenericTensor.csproj", "{D4ED9D4A-82AB-419C-B3AD-BF35104A6613}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sample", "Sample\Sample.csproj", "{DF4C5CB0-7D93-4126-B967-5BA2A2BB6489}" 9 | EndProject 10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitTests", "UnitTests\UnitTests.csproj", "{3104462C-7792-4003-AC2A-A34F74F52701}" 11 | EndProject 12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Benchmark", "Benchmark\Benchmark.csproj", "{E307577A-08C0-468E-BC6A-79398B1D6AAD}" 13 | EndProject 14 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{3DD9FA32-C26B-4630-ADB1-4DE2E36AA672}" 15 | ProjectSection(SolutionItems) = preProject 16 | GenericTensor.sln.licenseheader = GenericTensor.sln.licenseheader 17 | EndProjectSection 18 | EndProject 19 | Global 20 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 21 | Debug|Any CPU = Debug|Any CPU 22 | Release|Any CPU = Release|Any CPU 23 | EndGlobalSection 24 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 25 | {D4ED9D4A-82AB-419C-B3AD-BF35104A6613}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 26 | {D4ED9D4A-82AB-419C-B3AD-BF35104A6613}.Debug|Any CPU.Build.0 = Debug|Any CPU 27 | {D4ED9D4A-82AB-419C-B3AD-BF35104A6613}.Release|Any CPU.ActiveCfg = Release|Any CPU 28 | {D4ED9D4A-82AB-419C-B3AD-BF35104A6613}.Release|Any CPU.Build.0 = Release|Any CPU 29 | {DF4C5CB0-7D93-4126-B967-5BA2A2BB6489}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 30 | {DF4C5CB0-7D93-4126-B967-5BA2A2BB6489}.Debug|Any CPU.Build.0 = Debug|Any CPU 31 | {DF4C5CB0-7D93-4126-B967-5BA2A2BB6489}.Release|Any CPU.ActiveCfg = Release|Any CPU 32 | {DF4C5CB0-7D93-4126-B967-5BA2A2BB6489}.Release|Any CPU.Build.0 = Release|Any CPU 33 | {3104462C-7792-4003-AC2A-A34F74F52701}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 34 | {3104462C-7792-4003-AC2A-A34F74F52701}.Debug|Any CPU.Build.0 = Debug|Any CPU 35 | {3104462C-7792-4003-AC2A-A34F74F52701}.Release|Any CPU.ActiveCfg = Release|Any CPU 36 | {3104462C-7792-4003-AC2A-A34F74F52701}.Release|Any CPU.Build.0 = Release|Any CPU 37 | {E307577A-08C0-468E-BC6A-79398B1D6AAD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 38 | {E307577A-08C0-468E-BC6A-79398B1D6AAD}.Debug|Any CPU.Build.0 = Debug|Any CPU 39 | {E307577A-08C0-468E-BC6A-79398B1D6AAD}.Release|Any CPU.ActiveCfg = Release|Any CPU 40 | {E307577A-08C0-468E-BC6A-79398B1D6AAD}.Release|Any CPU.Build.0 = Release|Any CPU 41 | EndGlobalSection 42 | GlobalSection(SolutionProperties) = preSolution 43 | HideSolutionNode = FALSE 44 | EndGlobalSection 45 | GlobalSection(ExtensibilityGlobals) = postSolution 46 | SolutionGuid = {F3AE1B7D-B3AB-4B03-97CC-EC583184E39D} 47 | EndGlobalSection 48 | EndGlobal 49 | -------------------------------------------------------------------------------- /GenericTensor.sln.licenseheader: -------------------------------------------------------------------------------- 1 | extensions: .cs 2 | #region copyright 3 | /* 4 | * MIT License 5 | * 6 | * Copyright (c) 2020-2021 WhiteBlackGoose 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in all 16 | * copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | * SOFTWARE. 25 | */ 26 | #endregion 27 | 28 | -------------------------------------------------------------------------------- /GenericTensor/Core/Exceptions.cs: -------------------------------------------------------------------------------- 1 | #region copyright 2 | /* 3 | * MIT License 4 | * 5 | * Copyright (c) 2020-2021 WhiteBlackGoose 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | #endregion 26 | 27 | 28 | using System; 29 | using System.Data; 30 | 31 | namespace GenericTensor.Core 32 | { 33 | /// 34 | /// Occurs when an axis mismatch happens 35 | /// 36 | public class InvalidShapeException : ArgumentException 37 | { 38 | internal InvalidShapeException(string msg) : base(msg) {} 39 | internal InvalidShapeException() : base() {} 40 | 41 | internal static void NeedTensorSquareMatrix(GenTensor m) where TWrapper : struct, IOperations 42 | { 43 | if (m.Shape.Length <= 2) 44 | throw new InvalidShapeException("Should be 3+ dimensional"); 45 | if (m.Shape.shape[m.Shape.Length - 1] != m.Shape.shape[m.Shape.Length - 2]) 46 | throw new InvalidShapeException("The last two dimensions should be equal"); 47 | } 48 | } 49 | 50 | /// 51 | /// Thrown when a wrong determinant tensor was provided 52 | /// 53 | public class InvalidDeterminantException : DataException 54 | { 55 | internal InvalidDeterminantException(string msg) : base(msg) {} 56 | internal InvalidDeterminantException() : base() {} 57 | } 58 | 59 | /// 60 | /// Thrown when there is no decomposition for provided matrix 61 | /// 62 | public class ImpossibleDecomposition : DataException 63 | { 64 | internal ImpossibleDecomposition(string msg) : base(msg) {} 65 | internal ImpossibleDecomposition() : base() {} 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /GenericTensor/Core/IOperations.cs: -------------------------------------------------------------------------------- 1 | #region copyright 2 | /* 3 | * MIT License 4 | * 5 | * Copyright (c) 2020-2021 WhiteBlackGoose 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | #endregion 26 | 27 | 28 | using System; 29 | using System.Diagnostics; 30 | 31 | namespace GenericTensor.Core 32 | { 33 | /// 34 | /// This the structure responsible for operations on the 35 | /// elements on your tensor 36 | /// 37 | /// 38 | /// The type of primitive in your tensor. 39 | /// 40 | public interface IOperations 41 | { 42 | /// 43 | /// Rules of adding elements. Must return a new one. 44 | /// Should not modify the old ones. 45 | /// 46 | /// 47 | /// A primitive of the same type 48 | /// 49 | T Add(T a, T b); 50 | 51 | /// 52 | /// Rules of subtracting elements. Must return a new one. 53 | /// Should not modify the old ones. 54 | /// 55 | /// 56 | /// A primitive of the same type 57 | /// 58 | T Subtract(T a, T b); 59 | 60 | /// 61 | /// Rules of multiplying elements. Must return a new one. 62 | /// Should not modify the old ones. 63 | /// 64 | /// 65 | /// A primitive of the same type 66 | /// 67 | T Multiply(T a, T b); 68 | 69 | /// 70 | /// Rules of multiplying an element by -1. Must return a new one. 71 | /// Should not modify the old ones. 72 | /// 73 | /// 74 | /// A primitive of the same type 75 | /// 76 | T Negate(T a); 77 | 78 | /// 79 | /// Rules of dividing elements. Must return a new one. 80 | /// Should not modify the old ones. 81 | /// 82 | /// 83 | /// A primitive of the same type 84 | /// 85 | T Divide(T a, T b); 86 | 87 | /// 88 | /// 1 (one). A primitive of the same type 89 | /// 90 | T CreateOne(); 91 | 92 | /// 93 | /// 0 (zero). A primitive of the same type 94 | /// 95 | T CreateZero(); 96 | 97 | /// 98 | /// If your elements are mutable, it 99 | /// might be useful to be able to copy 100 | /// them as well. 101 | /// 102 | T Copy(T a); 103 | 104 | /// 105 | /// Determines whether the instances 106 | /// of your objects are equal 107 | /// 108 | bool AreEqual(T a, T b); 109 | 110 | /// 111 | /// Whether the given instance is zero 112 | /// 113 | bool IsZero(T a); 114 | 115 | /// 116 | /// Get the string representation of the instance 117 | /// 118 | string ToString(T a); 119 | 120 | /// 121 | /// Rules of serialization of one instance 122 | /// 123 | byte[] Serialize(T a); 124 | 125 | /// 126 | /// Rules of deserialization of one instance 127 | /// 128 | T Deserialize(byte[] data); 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /GenericTensor/Core/Operators.cs: -------------------------------------------------------------------------------- 1 | #region copyright 2 | /* 3 | * MIT License 4 | * 5 | * Copyright (c) 2020-2021 WhiteBlackGoose 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | #endregion 26 | 27 | 28 | namespace GenericTensor.Core 29 | { 30 | public partial class GenTensor : System.IEquatable> 31 | { 32 | /// 33 | /// A tensor is a matrix if has two dimensions, e. g. [3 x 4] 34 | /// 35 | public bool IsMatrix => Shape.Count == 2; 36 | 37 | /// 38 | /// A tensor is a vector if has one dimension 39 | /// 40 | public bool IsVector => Shape.Count == 1; 41 | 42 | /// 43 | /// Determines wether one is a matrix AND its width and height are equal 44 | /// 45 | public bool IsSquareMatrix => IsMatrix && Shape.shape[0] == Shape.shape[1]; 46 | 47 | /// 48 | /// Calls your default(TWrapper).Equals 49 | /// Be sure to override it when using this function or ==, != operators 50 | /// 51 | public override bool Equals(object obj) 52 | { 53 | if (obj is null || obj is not GenTensor ten) 54 | return false; 55 | return Equals(ten); 56 | } 57 | 58 | /// 59 | /// Calls your default(TWrapper).Equals 60 | /// Be sure to override it when using this function or ==, != operators 61 | /// 62 | public bool Equals(GenTensor obj) 63 | { 64 | if (obj is null) 65 | return false; 66 | if (obj.Shape != Shape) 67 | return false; 68 | foreach (var (index, _) in obj.Iterate()) 69 | if (!default(TWrapper).AreEqual(this.GetValueNoCheck(index), obj.GetValueNoCheck(index))) 70 | return false; 71 | return true; 72 | } 73 | 74 | #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member 75 | public static bool operator ==(GenTensor a, GenTensor b) 76 | => object.ReferenceEquals(a, b) || (a is {} && a.Equals(b)); 77 | 78 | public static bool operator !=(GenTensor a, GenTensor b) 79 | => !(a == b); 80 | #pragma warning restore CS1591 // Missing XML comment for publicly visible type or member 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /GenericTensor/Core/Tensor/GenTensor.Axes.cs: -------------------------------------------------------------------------------- 1 | #region copyright 2 | /* 3 | * MIT License 4 | * 5 | * Copyright (c) 2020-2021 WhiteBlackGoose 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | #endregion 26 | 27 | 28 | using System; 29 | using System.Runtime.CompilerServices; 30 | 31 | namespace GenericTensor.Core 32 | { 33 | public partial class GenTensor 34 | { 35 | /// 36 | /// Shape represents axes' lengths of the tensor 37 | /// 38 | public TensorShape Shape { get; } 39 | 40 | /// 41 | /// Swaps axes in tensor. 42 | /// 0 - the first dimension 43 | /// 44 | public void Transpose(int axis1, int axis2) 45 | { 46 | (blocks[axis1], blocks[axis2]) = (blocks[axis2], blocks[axis1]); 47 | UpdateBlockCache(); 48 | Shape.Swap(axis1, axis2); 49 | } 50 | 51 | /// 52 | /// Swaps two last axes or throws InvalidShapeException if a tensor is too low-dimensional 53 | /// 54 | public void TransposeMatrix() 55 | { 56 | #if ALLOW_EXCEPTIONS 57 | if (Shape.Count < 2) 58 | throw new InvalidShapeException("this should be at least matrix"); 59 | #endif 60 | Transpose(Shape.Count - 2, Shape.Count - 1); 61 | } 62 | 63 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 64 | private void ReactIfBadBound(int index, int axisId) 65 | { 66 | if (index < 0 || index >= Shape.shape[axisId]) 67 | throw new IndexOutOfRangeException($"Bound vialoting: axis {axisId} is {Shape[axisId]} long, your input is {index}"); 68 | } 69 | 70 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 71 | private void ReactIfBadIndexCount(int count) 72 | { 73 | if (count != Shape.Count) 74 | throw new ArgumentException($"There should be {Shape.Count} indices, not {count}"); 75 | } 76 | 77 | private int GetFlattenedIndexWithCheck(int[] indices) 78 | { 79 | #if ALLOW_EXCEPTIONS 80 | ReactIfBadIndexCount(indices.Length); 81 | #endif 82 | var res = 0; 83 | for (int i = 0; i < indices.Length; i++) 84 | { 85 | #if ALLOW_EXCEPTIONS 86 | ReactIfBadBound(indices[i], i); 87 | #endif 88 | res += blocks[i] * indices[i]; 89 | } 90 | return res + LinOffset; 91 | } 92 | 93 | private int GetFlattenedIndexWithCheck(int x, int y, int z, int[] indices) 94 | { 95 | #if ALLOW_EXCEPTIONS 96 | ReactIfBadIndexCount(indices.Length + 3); 97 | #endif 98 | var res = GetFlattenedIndexWithCheck(x, y, z, checkNumberOfDims: false); 99 | for (int i = 0; i < indices.Length; i++) 100 | { 101 | #if ALLOW_EXCEPTIONS 102 | ReactIfBadBound(indices[i], i + 3); 103 | #endif 104 | res += blocks[i + 3] * indices[i]; 105 | } 106 | return res; 107 | } 108 | 109 | private int GetFlattenedIndexWithCheck(int x) 110 | { 111 | #if ALLOW_EXCEPTIONS 112 | ReactIfBadIndexCount(1); 113 | ReactIfBadBound(x, 0); 114 | #endif 115 | return LinOffset + cached_blocks0 * x; 116 | } 117 | 118 | private int GetFlattenedIndexWithCheck(int x, int y) 119 | { 120 | #if ALLOW_EXCEPTIONS 121 | ReactIfBadIndexCount(2); 122 | ReactIfBadBound(x, 0); 123 | ReactIfBadBound(y, 1); 124 | #endif 125 | return LinOffset + cached_blocks0 * x + cached_blocks1 * y; 126 | } 127 | 128 | private int GetFlattenedIndexWithCheck(int x, int y, int z, bool checkNumberOfDims = true) 129 | { 130 | #if ALLOW_EXCEPTIONS 131 | if (checkNumberOfDims) 132 | ReactIfBadIndexCount(3); 133 | ReactIfBadBound(x, 0); 134 | ReactIfBadBound(y, 1); 135 | ReactIfBadBound(z, 2); 136 | #endif 137 | return LinOffset + cached_blocks0 * x + cached_blocks1 * y + cached_blocks2 * z; 138 | } 139 | 140 | 141 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 142 | internal int GetFlattenedIndexSilent(int x) 143 | => cached_blocks0 * x + 144 | LinOffset; 145 | 146 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 147 | internal int GetFlattenedIndexSilent(int x, int y) 148 | => cached_blocks0 * x + 149 | cached_blocks1 * y + 150 | LinOffset; 151 | 152 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 153 | internal int GetFlattenedIndexSilent(int x, int y, int z) 154 | => cached_blocks0 * x + 155 | cached_blocks1 * y + 156 | cached_blocks2 * z + 157 | LinOffset; 158 | 159 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 160 | internal int GetFlattenedIndexSilent(int x, int y, int z, int[] other) 161 | { 162 | var res = GetFlattenedIndexSilent(x, y, z); 163 | for (int i = 0; i < other.Length; i++) 164 | res += other[i] * blocks[i + 3]; 165 | return res; 166 | } 167 | 168 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 169 | private int GetFlattenedIndexSilent(int[] other) 170 | { 171 | var res = 0; 172 | for (int i = 0; i < other.Length; i++) 173 | res += other[i] * blocks[i]; 174 | return res + LinOffset; 175 | } 176 | } 177 | } 178 | -------------------------------------------------------------------------------- /GenericTensor/Core/Tensor/GenTensor.Subtensor.cs: -------------------------------------------------------------------------------- 1 | #region copyright 2 | /* 3 | * MIT License 4 | * 5 | * Copyright (c) 2020-2021 WhiteBlackGoose 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | #endregion 26 | 27 | 28 | using System; 29 | using System.Linq; 30 | 31 | namespace GenericTensor.Core 32 | { 33 | public partial class GenTensor 34 | { 35 | /// 36 | /// Linear offset (as in offset in the initial array) 37 | /// 38 | public int LinOffset; 39 | 40 | /// 41 | /// Slice with data sharing like in python 42 | /// A[3:5] in python 43 | /// same as 44 | /// A.Slice(3, 5) in GT 45 | /// 46 | /// O(N) 47 | /// 48 | // TODO: Make it O(1) 49 | public GenTensor Slice(int leftIncluding, int rightExcluding) 50 | { 51 | #if ALLOW_EXCEPTIONS 52 | ReactIfBadBound(leftIncluding, 0); 53 | ReactIfBadBound(rightExcluding - 1, 0); 54 | if (leftIncluding >= rightExcluding) 55 | throw new InvalidShapeException("Slicing cannot be performed"); 56 | #endif 57 | var newLength = rightExcluding - leftIncluding; 58 | var toStack = new GenTensor[newLength]; 59 | for (int i = 0; i < newLength; i++) 60 | toStack[i] = GetSubtensor(i + leftIncluding); 61 | return Stack(toStack); 62 | } 63 | 64 | /// 65 | /// This Subtensor is sequential Subtensor(int) 66 | /// 67 | /// O(1) 68 | /// 69 | public GenTensor GetSubtensor(int[] indices) 70 | => GetSubtensor(indices, 0); 71 | 72 | internal GenTensor GetSubtensor(int[] indices, int id) 73 | => id == indices.Length ? this : this.GetSubtensor(indices[id]).GetSubtensor(indices, id + 1); 74 | 75 | /// 76 | /// Get a subtensor of a tensor 77 | /// If you have a t = Tensor[2 x 3 x 4], 78 | /// t.GetSubtensor(0) will return the proper matrix [3 x 4] 79 | /// 80 | /// O(1) 81 | /// 82 | public GenTensor GetSubtensor(int index) 83 | { 84 | #if ALLOW_EXCEPTIONS 85 | ReactIfBadBound(index, 0); 86 | #endif 87 | var newLinIndexDelta = GetFlattenedIndexSilent(index); 88 | var newBlocks = blocks.ToList(); 89 | var rootAxis = 0; 90 | newBlocks.RemoveAt(rootAxis); 91 | var newShape = Shape.CutOffset1(); 92 | var result = new GenTensor(newShape, newBlocks.ToArray(), data) 93 | { 94 | LinOffset = newLinIndexDelta 95 | }; 96 | return result; 97 | } 98 | 99 | /// 100 | /// Suppose you have t = tensor [2 x 3 x 4] 101 | /// and m = matrix[3 x 4] 102 | /// You need to set this matrix to t's second matrix 103 | /// t.SetSubtensor(m, 1); 104 | /// 105 | /// O(V) 106 | /// 107 | public void SetSubtensor(GenTensor sub, params int[] indices) 108 | { 109 | #if ALLOW_EXCEPTIONS 110 | if (indices.Length >= Shape.Count) 111 | throw new InvalidShapeException($"Number of {nameof(indices)} should be less than number of {nameof(Shape)}"); 112 | for (int i = 0; i < indices.Length; i++) 113 | if (indices[i] < 0 || indices[i] >= Shape[i]) 114 | throw new IndexOutOfRangeException(); 115 | if (Shape.Count - indices.Length != sub.Shape.Count) 116 | throw new InvalidShapeException($"Number of {nameof(sub.Shape.Length)} + {nameof(indices.Length)} should be equal to {Shape.Count}"); 117 | #endif 118 | var thisSub = GetSubtensor(indices); 119 | #if ALLOW_EXCEPTIONS 120 | if (thisSub.Shape != sub.Shape) 121 | throw new InvalidShapeException($"{nameof(sub.Shape)} must be equal to {nameof(Shape)}"); 122 | #endif 123 | thisSub.Assign(sub); 124 | } 125 | 126 | internal void Assign(GenTensor genTensor) 127 | { 128 | foreach (var (index, value) in genTensor.Iterate()) 129 | this.SetValueNoCheck(value, index); 130 | } 131 | } 132 | 133 | } 134 | -------------------------------------------------------------------------------- /GenericTensor/Core/Tensor/Tensor.cs: -------------------------------------------------------------------------------- 1 | #region copyright 2 | /* 3 | * MIT License 4 | * 5 | * Copyright (c) 2020-2021 WhiteBlackGoose 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | #endregion 26 | 27 | 28 | using System.Runtime.CompilerServices; 29 | 30 | namespace GenericTensor.Core 31 | { 32 | public partial class GenTensor 33 | { 34 | #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member 35 | public readonly T[] data; 36 | public readonly int[] blocks; // 3 x 4 x 5 37 | #pragma warning restore CS1591 // Missing XML comment for publicly visible type or member 38 | internal int cached_blocks0; 39 | internal int cached_blocks1; 40 | internal int cached_blocks2; 41 | private int volume = -1; 42 | /// 43 | /// Number of elements in tensor overall 44 | /// 45 | public int Volume 46 | { 47 | get 48 | { 49 | if (volume == -1) 50 | { 51 | volume = 1; 52 | for (var i = 0; i < Shape.Length; i++) 53 | volume *= Shape[i]; 54 | } 55 | return volume; 56 | } 57 | } 58 | 59 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 60 | private void UpdateBlockCache() 61 | { 62 | if (blocks.Length >= 3) 63 | goto More3; 64 | if (blocks.Length >= 2) 65 | goto More2; 66 | if (blocks.Length >= 1) 67 | goto More1; 68 | return; 69 | More3: 70 | cached_blocks2 = blocks[2]; 71 | More2: 72 | cached_blocks1 = blocks[1]; 73 | More1: 74 | cached_blocks0 = blocks[0]; 75 | } 76 | 77 | private void BlockRecompute() 78 | { 79 | int len = 1; 80 | for (int i = Shape.Count - 1; i >= 0; i--) 81 | { 82 | blocks[i] = len; 83 | len *= Shape[i]; 84 | } 85 | UpdateBlockCache(); 86 | } 87 | 88 | private GenTensor(TensorShape dimensions, int[] blocks, T[] data) 89 | { 90 | Shape = dimensions; 91 | this.blocks = blocks; 92 | this.data = data; 93 | UpdateBlockCache(); 94 | } 95 | 96 | /// 97 | /// Clones with copying the elements 98 | /// 99 | public object Clone() 100 | => Copy(copyElements: true); 101 | 102 | /// 103 | /// Creates a tensor from the given shape 104 | /// 105 | public GenTensor(TensorShape dimensions) 106 | { 107 | Shape = dimensions; 108 | int len = 1; 109 | for (int i = 0; i < dimensions.Length; i++) 110 | { 111 | len *= dimensions[i]; 112 | } 113 | var data = new T[len]; 114 | this.data = data; 115 | LinOffset = 0; 116 | blocks = new int[dimensions.Count]; 117 | BlockRecompute(); 118 | } 119 | 120 | /// 121 | /// Creates a tensor from the given dimensions 122 | /// 123 | public GenTensor(params int[] dimensions) : this(new TensorShape(dimensions)) { } 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /GenericTensor/Core/TensorShape.cs: -------------------------------------------------------------------------------- 1 | #region copyright 2 | /* 3 | * MIT License 4 | * 5 | * Copyright (c) 2020-2021 WhiteBlackGoose 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | #endregion 26 | 27 | 28 | using System; 29 | using System.Linq; 30 | using System.Runtime.CompilerServices; 31 | 32 | namespace GenericTensor.Core 33 | { 34 | /// 35 | /// This structure represents a shape of a tensor 36 | /// 37 | public struct TensorShape : IEquatable 38 | { 39 | /// 40 | /// Internal variable. Not recommended to change 41 | /// 42 | public readonly int[] shape; 43 | 44 | /// 45 | /// Length of a shape is basically number of dimensions 46 | /// 47 | public int Length => shape.Length; 48 | 49 | /// 50 | /// Synonym for Length 51 | /// 52 | public int DimensionCount => shape.Length; 53 | 54 | /// 55 | /// Synonym for Length 56 | /// 57 | public int Count => shape.Length; 58 | 59 | /// 60 | /// Create a TensorShape for further operations 61 | /// just listing necessary dimensions 62 | /// 63 | /// 64 | public TensorShape(params int[] shape) 65 | { 66 | this.shape = shape; 67 | } 68 | 69 | internal TensorShape CutOffset1() 70 | { 71 | var newShape = new int[Length - 1]; 72 | for (int i = 0; i < newShape.Length; i++) 73 | newShape[i] = shape[i + 1]; 74 | return new TensorShape(newShape); 75 | } 76 | 77 | /// 78 | /// Gets a subshape as a subsequence with the given 79 | /// left and right offsets 80 | /// 81 | public TensorShape SubShape(int offsetFromLeft, int offsetFromRight) 82 | { 83 | var newShape = new int[Length - offsetFromLeft - offsetFromRight]; 84 | for (int i = offsetFromLeft; i < Length - offsetFromRight; i++) 85 | newShape[i - offsetFromLeft] = shape[i]; 86 | return new TensorShape(newShape); 87 | } 88 | 89 | /// 90 | /// Copies the shape, including the internal array 91 | /// 92 | public TensorShape Copy() 93 | { 94 | var resI = shape.ToArray(); 95 | return new TensorShape(resI); 96 | } 97 | 98 | internal void Swap(int id1, int id2) 99 | => (shape[id1], shape[id2]) = (shape[id2], shape[id1]); 100 | 101 | /// 102 | /// You can only read some dimensions, 103 | /// otherwise it will cause unintended behaviour 104 | /// 105 | /// 106 | /// 107 | public int this[int axisId] => shape[axisId]; 108 | 109 | /// 110 | /// Returns the shape's internal array's copy 111 | /// 112 | public int[] ToArray() => shape.ToArray(); 113 | 114 | /// 115 | public override string ToString() 116 | => string.Join(" x ", shape.Select(c => c.ToString())); 117 | 118 | 119 | #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member 120 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 121 | public bool Equals(TensorShape sh) 122 | { 123 | if (sh.Length != Length) 124 | return false; 125 | for (int i = 0; i < sh.Length; i++) 126 | if (sh.shape[i] != this.shape[i]) 127 | return false; 128 | return true; 129 | } 130 | 131 | public override int GetHashCode() 132 | => shape.GetHashCode(); 133 | 134 | public override bool Equals(object obj) 135 | => obj is TensorShape ts ? Equals(ts) : false; 136 | 137 | public static bool operator ==(TensorShape a, TensorShape b) 138 | => a.Equals(b); 139 | 140 | public static bool operator !=(TensorShape a, TensorShape b) 141 | => !a.Equals(b); 142 | #pragma warning restore CS1591 // Missing XML comment for publicly visible type or member 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /GenericTensor/Core/ThreadUtils.cs: -------------------------------------------------------------------------------- 1 | #region copyright 2 | /* 3 | * MIT License 4 | * 5 | * Copyright (c) 2020-2021 WhiteBlackGoose 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | #endregion 26 | 27 | 28 | using System; 29 | 30 | namespace GenericTensor.Core 31 | { 32 | /// 33 | /// Use this enum to set the mode of execution 34 | /// 35 | public enum Threading 36 | { 37 | /// 38 | /// Will guarantee the single-thread execution 39 | /// 40 | Single, 41 | 42 | /// 43 | /// Will unconditionally run in multithreading mode, 44 | /// using as many cores as possible (in normal priority) 45 | /// 46 | Multi, 47 | 48 | /// 49 | /// Will select the necessary mode depending on the input. 50 | /// Is recommended for cases where the performance is 51 | /// needed, but you do not want to manage it manually 52 | /// 53 | Auto 54 | } 55 | 56 | internal static class ThreadUtils 57 | { 58 | internal static T GetOrDefault(ref T field, Func Default) where T : new() 59 | { 60 | if (field is null) 61 | field = Default(); 62 | return field; 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /GenericTensor/Functions/Composition.cs: -------------------------------------------------------------------------------- 1 | #region copyright 2 | /* 3 | * MIT License 4 | * 5 | * Copyright (c) 2020-2021 WhiteBlackGoose 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | #endregion 26 | 27 | 28 | using GenericTensor.Core; 29 | using HonkPerf.NET.Core; 30 | 31 | namespace GenericTensor.Functions 32 | { 33 | internal static class Composition where TWrapper : struct, IOperations 34 | { 35 | public static GenTensor Stack(params GenTensor[] elements) 36 | { 37 | #if ALLOW_EXCEPTIONS 38 | if (elements.Length < 1) 39 | throw new InvalidShapeException("Shoud be at least one element to stack"); 40 | #endif 41 | var desiredShape = elements[0].Shape; 42 | #if ALLOW_EXCEPTIONS 43 | for (int i = 1; i < elements.Length; i++) 44 | if (elements[i].Shape != desiredShape) 45 | throw new InvalidShapeException($"Tensors in {nameof(elements)} should be of the same shape"); 46 | #endif 47 | var newShape = new int[desiredShape.Count + 1]; 48 | newShape[0] = elements.Length; 49 | for (int i = 1; i < newShape.Length; i++) 50 | newShape[i] = desiredShape[i - 1]; 51 | var res = new GenTensor(newShape); 52 | for (int i = 0; i < elements.Length; i++) 53 | res.SetSubtensor(elements[i], i); 54 | return res; 55 | } 56 | 57 | public static GenTensor Concat(GenTensor a, GenTensor b) 58 | { 59 | #if ALLOW_EXCEPTIONS 60 | if (a.Shape.SubShape(1, 0) != b.Shape.SubShape(1, 0)) 61 | throw new InvalidShapeException("Excluding the first dimension, all others should match"); 62 | #endif 63 | 64 | if (a.IsVector) 65 | { 66 | var resultingVector = GenTensor.CreateVector(a.Shape.shape[0] + b.Shape.shape[0]); 67 | for (int i = 0; i < a.Shape.shape[0]; i++) 68 | resultingVector.SetValueNoCheck(a.GetValueNoCheck(i), i); 69 | 70 | for (int i = 0; i < b.Shape.shape[0]; i++) 71 | resultingVector.SetValueNoCheck(b.GetValueNoCheck(i), i + a.Shape.shape[0]); 72 | 73 | return resultingVector; 74 | } 75 | else 76 | { 77 | var newShape = a.Shape.Copy(); 78 | newShape.shape[0] = a.Shape.shape[0] + b.Shape.shape[0]; 79 | 80 | var res = new GenTensor(newShape); 81 | for (int i = 0; i < a.Shape.shape[0]; i++) 82 | res.SetSubtensor(a.GetSubtensor(i), i); 83 | 84 | for (int i = 0; i < b.Shape.shape[0]; i++) 85 | res.SetSubtensor(b.GetSubtensor(i), i + a.Shape.shape[0]); 86 | 87 | return res; 88 | } 89 | } 90 | 91 | private struct AggregateFunctor : IValueAction 92 | where TAggregatorFunc : struct, HonkPerf.NET.Core.IValueDelegate 93 | where UWrapper : struct, IOperations 94 | { 95 | private TAggregatorFunc collapse; 96 | private GenTensor acc; 97 | public AggregateFunctor(TAggregatorFunc collapse, GenTensor acc) 98 | { 99 | this.collapse = collapse; 100 | this.acc = acc; 101 | } 102 | public void Invoke(int[] arg1, T arg2) 103 | { 104 | acc.SetValueNoCheck(collapse.Invoke(acc.GetValueNoCheck(arg1), arg2), arg1); 105 | } 106 | } 107 | 108 | public static void Aggregate(GenTensor t, GenTensor acc, TAggregatorFunc collapse, int axis) 109 | where TAggregatorFunc : struct, HonkPerf.NET.Core.IValueDelegate 110 | where UWrapper : struct, IOperations 111 | { 112 | for (int i = axis; i > 0; i--) 113 | t.Transpose(i, i - 1); // Move the axis we want to reduce to the front for GetSubtensor. Order is important since it is directly reflected in the output shape. 114 | /* 115 | // old code with iterate 116 | // not removing for now 117 | for (int i = 0; i < t.Shape[0]; i++) 118 | foreach (var (id, value) in t.GetSubtensor(i).Iterate()) 119 | acc[id] = collapse.Invoke(acc[id], value); 120 | */ 121 | for (int i = 0; i < t.Shape[0]; i++) 122 | t.GetSubtensor(i).ForEach(new AggregateFunctor(collapse, acc)); 123 | for (int i = 0; i < axis; i++) 124 | t.Transpose(i, i + 1); 125 | } 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /GenericTensor/Functions/CopyAndForward.cs: -------------------------------------------------------------------------------- 1 | #region copyright 2 | /* 3 | * MIT License 4 | * 5 | * Copyright (c) 2020-2021 WhiteBlackGoose 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | #endregion 26 | 27 | 28 | using GenericTensor.Core; 29 | 30 | namespace GenericTensor.Functions 31 | { 32 | internal static class CopyAndForward where TWrapper : struct, IOperations 33 | { 34 | public static GenTensor Copy(GenTensor t, bool copyElements) 35 | { 36 | var res = new GenTensor(t.Shape.Copy()); 37 | if (!copyElements) 38 | { 39 | foreach (var index in res.IterateOverElements()) 40 | res.SetValueNoCheck(t.GetValueNoCheck(index), index); 41 | } 42 | else 43 | foreach (var index in res.IterateOverElements()) 44 | res.SetValueNoCheck(default(TWrapper).Copy(t.GetValueNoCheck(index)), index); 45 | return res; 46 | } 47 | 48 | public static GenTensor Forward(GenTensor t) 49 | { 50 | var res = new GenTensor(t.Shape); 51 | foreach (var index in res.IterateOverElements()) 52 | res.SetValueNoCheck(t.GetValueNoCheck(index), index); 53 | return res; 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /GenericTensor/Functions/Determinant.cs: -------------------------------------------------------------------------------- 1 | #region copyright 2 | /* 3 | * MIT License 4 | * 5 | * Copyright (c) 2020-2021 WhiteBlackGoose 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | #endregion 26 | 27 | 28 | using GenericTensor.Core; 29 | 30 | namespace GenericTensor.Functions 31 | { 32 | internal static class Determinant where TWrapper : struct, IOperations 33 | { 34 | #region Matrix Determinant 35 | #region Laplace 36 | internal static T DeterminantLaplace(GenTensor t, int diagLength) 37 | { 38 | if (diagLength == 1) 39 | return t.GetValueNoCheck(0, 0); 40 | var det = default(TWrapper).CreateZero(); 41 | var sign = default(TWrapper).CreateOne(); 42 | var temp = SquareMatrixFactory.GetMatrix(diagLength - 1); 43 | for (int i = 0; i < diagLength; i++) 44 | { 45 | Inversion.GetCofactorMatrix(t, temp, 0, i, diagLength); 46 | det = default(TWrapper).Add(det, 47 | default(TWrapper).Multiply( 48 | sign, 49 | default(TWrapper).Multiply( 50 | t.GetValueNoCheck(0, i), 51 | DeterminantLaplace(temp, diagLength - 1) 52 | )) 53 | ); 54 | sign = default(TWrapper).Negate(sign); 55 | } 56 | return det; 57 | } 58 | 59 | public static T DeterminantLaplace(GenTensor t) 60 | { 61 | #if ALLOW_EXCEPTIONS 62 | if (!t.IsMatrix) 63 | throw new InvalidShapeException("Determinant function should be only called from a matrix"); 64 | if (t.Shape[0] != t.Shape[1]) 65 | throw new InvalidShapeException("Matrix should be square"); 66 | #endif 67 | return DeterminantLaplace(t, t.Shape[0]); 68 | } 69 | #endregion 70 | 71 | #region Gaussian 72 | 73 | 74 | public static T DeterminantGaussianSafeDivision(GenTensor t) 75 | => DeterminantGaussianSafeDivision(t, t.Shape[0]); 76 | 77 | internal static T DeterminantGaussianSafeDivision(GenTensor t, int diagLength) 78 | { 79 | #if ALLOW_EXCEPTIONS 80 | if (!t.IsMatrix) 81 | throw new InvalidShapeException("this should be matrix"); 82 | if (t.Shape[0] != t.Shape[1]) 83 | throw new InvalidShapeException("this should be square matrix"); 84 | #endif 85 | 86 | if (t.Shape[0] == 1) 87 | return t.GetValueNoCheck(0, 0); 88 | 89 | var n = diagLength; 90 | var elemMatrix = EchelonForm.InnerGaussianEliminationSafeDivision(t, n, n, null, out var swapCount); 91 | 92 | var det = default(EchelonForm.WrapperSafeDivisionWrapper).CreateOne(); 93 | for (int i = 0; i < n; i++) 94 | { 95 | det = default(EchelonForm.WrapperSafeDivisionWrapper).Multiply(det, elemMatrix.GetValueNoCheck(i, i)); 96 | } 97 | 98 | if (default(TWrapper).IsZero(det.den)) 99 | return default(TWrapper).CreateZero(); 100 | return swapCount % 2 is 0 ? det.Count() : default(TWrapper).Negate(det.Count()); 101 | } 102 | 103 | public static T DeterminantGaussianSimple(GenTensor t) 104 | { 105 | #if ALLOW_EXCEPTIONS 106 | if (!t.IsMatrix) 107 | throw new InvalidShapeException("this should be matrix"); 108 | if (t.Shape[0] != t.Shape[1]) 109 | throw new InvalidShapeException("this should be square matrix"); 110 | #endif 111 | if (t.Shape[0] == 1) 112 | return t.GetValueNoCheck(0, 0); 113 | 114 | var n = t.Shape[0]; 115 | 116 | var elemMatrix = t.Forward(); 117 | for (int k = 1; k < n; k++) 118 | for (int j = k; j < n; j++) 119 | { 120 | var m = default(TWrapper).Divide( 121 | elemMatrix.GetValueNoCheck(j, k - 1), 122 | elemMatrix.GetValueNoCheck(k - 1, k - 1) 123 | ); 124 | for (int i = 0; i < n; i++) 125 | { 126 | var curr = elemMatrix.GetValueNoCheck(j, i); 127 | elemMatrix.SetValueNoCheck(default(TWrapper).Subtract( 128 | curr, 129 | default(TWrapper).Multiply( 130 | m, 131 | elemMatrix.GetValueNoCheck(k - 1, i) 132 | ) 133 | ), j, i); 134 | } 135 | } 136 | 137 | var det = default(TWrapper).CreateOne(); 138 | for (int i = 0; i < n; i++) 139 | { 140 | det = default(TWrapper).Multiply(det, elemMatrix.GetValueNoCheck(i, i)); 141 | } 142 | 143 | return det; 144 | } 145 | #endregion 146 | #endregion 147 | 148 | #region Tensor Determinant 149 | 150 | public static GenTensor TensorDeterminantLaplace(GenTensor t) 151 | { 152 | #if ALLOW_EXCEPTIONS 153 | InvalidShapeException.NeedTensorSquareMatrix(t); 154 | #endif 155 | 156 | var res = GenTensor.CreateTensor(t.Shape.SubShape(0, 2), 157 | ind => t.GetSubtensor(ind).DeterminantLaplace()); 158 | return res; 159 | } 160 | 161 | public static GenTensor TensorDeterminantGaussianSafeDivision(GenTensor t) 162 | { 163 | #if ALLOW_EXCEPTIONS 164 | InvalidShapeException.NeedTensorSquareMatrix(t); 165 | #endif 166 | 167 | var res = GenTensor.CreateTensor(t.Shape.SubShape(0, 2), 168 | ind => t.GetSubtensor(ind).DeterminantGaussianSafeDivision()); 169 | return res; 170 | } 171 | 172 | public static GenTensor TensorDeterminantGaussianSimple(GenTensor t) 173 | { 174 | #if ALLOW_EXCEPTIONS 175 | InvalidShapeException.NeedTensorSquareMatrix(t); 176 | #endif 177 | 178 | var res = GenTensor.CreateTensor(t.Shape.SubShape(0, 2), 179 | ind => t.GetSubtensor(ind).DeterminantGaussianSimple()); 180 | return res; 181 | } 182 | 183 | #endregion 184 | } 185 | } 186 | -------------------------------------------------------------------------------- /GenericTensor/Functions/ElementaryRowOperations.cs: -------------------------------------------------------------------------------- 1 | #region copyright 2 | /* 3 | * MIT License 4 | * 5 | * Copyright (c) 2020-2021 WhiteBlackGoose 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | #endregion 26 | 27 | 28 | using GenericTensor.Core; 29 | using System; 30 | using System.Collections.Generic; 31 | using System.Text; 32 | 33 | namespace GenericTensor.Functions 34 | { 35 | internal static class ElementaryRowOperations where TWrapper : struct, IOperations 36 | { 37 | public static void RowMultiply(GenTensor t, int rowId, T coef) 38 | { 39 | #if ALLOW_EXCEPTIONS 40 | if (!t.IsMatrix) 41 | throw new InvalidShapeException("this should be matrix"); 42 | #endif 43 | for (int i = 0; i < t.Shape[1]; i++) 44 | t.SetValueNoCheck(default(TWrapper).Multiply(coef, t.GetValueNoCheck(rowId, i)), rowId, i); 45 | } 46 | 47 | public static void RowAdd(GenTensor t, int dstRowId, int srcRowId, T coef) 48 | { 49 | #if ALLOW_EXCEPTIONS 50 | if (!t.IsMatrix) 51 | throw new InvalidShapeException("this should be matrix"); 52 | #endif 53 | for (int i = 0; i < t.Shape[1]; i++) 54 | t.SetValueNoCheck( 55 | default(TWrapper).Add( 56 | t.GetValueNoCheck(dstRowId, i), 57 | default(TWrapper).Multiply(coef, t.GetValueNoCheck(srcRowId, i)) 58 | ), 59 | dstRowId, i); 60 | } 61 | 62 | public static void RowSwap(GenTensor t, int row1Id, int row2Id) 63 | { 64 | #if ALLOW_EXCEPTIONS 65 | if (!t.IsMatrix) 66 | throw new InvalidShapeException("this should be matrix"); 67 | #endif 68 | for (int i = 0; i < t.Shape[1]; i++) 69 | { 70 | var tmp = t.GetValueNoCheck(row1Id, i); 71 | t.SetValueNoCheck(t.GetValueNoCheck(row2Id, i), row1Id, i); 72 | t.SetValueNoCheck(tmp, row2Id, i); 73 | } 74 | } 75 | 76 | public static void RowSubtract(GenTensor t, int dstRowId, int srcRowId, T coef) 77 | => RowAdd(t, dstRowId, srcRowId, default(TWrapper).Negate(coef)); 78 | 79 | public static (int id, T value)? LeadingElement(GenTensor t, int row) 80 | { 81 | for (int i = 0; i < t.Shape[1]; i++) 82 | { 83 | var value = t.GetValueNoCheck(row, i); 84 | if (!default(TWrapper).IsZero(value)) 85 | return (i, value); 86 | } 87 | return null; 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /GenericTensor/Functions/Inverse.cs: -------------------------------------------------------------------------------- 1 | #region copyright 2 | /* 3 | * MIT License 4 | * 5 | * Copyright (c) 2020-2021 WhiteBlackGoose 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | #endregion 26 | 27 | 28 | using System.Runtime.CompilerServices; 29 | using GenericTensor.Core; 30 | 31 | namespace GenericTensor.Functions 32 | { 33 | internal static class Inversion where TWrapper : struct, IOperations 34 | { 35 | /// 36 | /// Borrowed from here: https://www.geeksforgeeks.org/adjoint-inverse-matrix/ 37 | /// 38 | /// O(N^2) 39 | /// 40 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 41 | internal static void GetCofactorMatrix(GenTensor a, GenTensor temp, int rowId, 42 | int colId, int diagLength) 43 | { 44 | int i = 0, j = 0; 45 | for (int row = 0; row < diagLength; row++) 46 | { 47 | for (int col = 0; col < diagLength; col++) 48 | { 49 | if (row != rowId && col != colId) 50 | { 51 | temp.SetValueNoCheck(a.GetValueNoCheck(row, col), i, j); 52 | j++; 53 | if (j == diagLength - 1) 54 | { 55 | j = 0; 56 | i++; 57 | } 58 | } 59 | } 60 | } 61 | } 62 | 63 | 64 | public static GenTensor Adjoint(GenTensor t) 65 | { 66 | #if ALLOW_EXCEPTIONS 67 | if (!t.IsSquareMatrix) 68 | throw new InvalidShapeException("Matrix should be square"); 69 | #endif 70 | var diagLength = t.Shape.shape[0]; 71 | 72 | if (diagLength is 1) 73 | return GenTensor.CreateIdentityMatrix(1); 74 | 75 | var res = GenTensor.CreateSquareMatrix(diagLength); 76 | var temp = SquareMatrixFactory.GetMatrix(diagLength - 1); 77 | 78 | if (diagLength == 1) 79 | { 80 | res.SetValueNoCheck(default(TWrapper).CreateOne(), 0, 0); 81 | return res; 82 | } 83 | 84 | var toNegate = false; 85 | 86 | for (int x = 0; x < diagLength; x++) 87 | for (int y = 0; y < diagLength; y++) 88 | { 89 | GetCofactorMatrix(t, temp, x, y, diagLength); 90 | 91 | var cofactor = Determinant.DeterminantGaussianSafeDivision(temp, diagLength - 1); 92 | // TODO: is this statement correct? 93 | toNegate = (x + y) % 2 == 1; 94 | var minor = toNegate ? default(TWrapper).Negate(cofactor) : cofactor; 95 | 96 | res.SetValueNoCheck(minor, y, x); 97 | } 98 | 99 | return res; 100 | } 101 | 102 | public static void InvertMatrix(GenTensor t) 103 | { 104 | #if ALLOW_EXCEPTIONS 105 | if (!t.IsSquareMatrix) 106 | throw new InvalidShapeException("this should be a square matrix"); 107 | #endif 108 | 109 | var diagLength = t.Shape.shape[0]; 110 | 111 | if (diagLength is 1) 112 | { 113 | t.SetValueNoCheck( 114 | default(TWrapper).Divide( 115 | default(TWrapper).CreateOne(), 116 | t.GetValueNoCheck(0, 0) 117 | ), 0, 0); 118 | return; 119 | } 120 | 121 | var det = Determinant.DeterminantGaussianSafeDivision(t); 122 | #if ALLOW_EXCEPTIONS 123 | if (default(TWrapper).IsZero(det)) 124 | throw new InvalidDeterminantException("Cannot invert a singular matrix"); 125 | #endif 126 | 127 | var adj = Adjoint(t); 128 | for (int x = 0; x < diagLength; x++) 129 | for (int y = 0; y < diagLength; y++) 130 | t.SetValueNoCheck( 131 | default(TWrapper).Divide( 132 | adj.GetValueNoCheck(x, y), 133 | det 134 | ), 135 | x, y 136 | ); 137 | } 138 | 139 | public static GenTensor MatrixDivide(GenTensor a, GenTensor b) 140 | { 141 | #if ALLOW_EXCEPTIONS 142 | if (!a.IsSquareMatrix || !b.IsSquareMatrix) 143 | throw new InvalidShapeException("Both should be square matrices"); 144 | if (a.Shape != b.Shape) 145 | throw new InvalidShapeException("Given matrices should be of the same shape"); 146 | #endif 147 | var fwd = b.Forward(); 148 | fwd.InvertMatrix(); 149 | return MatrixMultiplication.Multiply(a, fwd); 150 | } 151 | 152 | public static GenTensor TensorMatrixDivide(GenTensor a, GenTensor b) 153 | { 154 | #if ALLOW_EXCEPTIONS 155 | InvalidShapeException.NeedTensorSquareMatrix(a); 156 | InvalidShapeException.NeedTensorSquareMatrix(b); 157 | if (a.Shape != b.Shape) 158 | throw new InvalidShapeException("Should be of the same shape"); 159 | #endif 160 | 161 | var res = new GenTensor(a.Shape); 162 | foreach (var ind in res.IterateOverMatrices()) 163 | res.SetSubtensor( 164 | MatrixDivide( 165 | a.GetSubtensor(ind), 166 | b.GetSubtensor(ind) 167 | ), ind); 168 | 169 | return res; 170 | } 171 | 172 | public static void TensorMatrixInvert(GenTensor t) 173 | { 174 | #if ALLOW_EXCEPTIONS 175 | InvalidShapeException.NeedTensorSquareMatrix(t); 176 | #endif 177 | 178 | foreach (var ind in t.IterateOverMatrices()) 179 | t.GetSubtensor(ind).InvertMatrix(); 180 | } 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /GenericTensor/Functions/LuDecomposition.cs: -------------------------------------------------------------------------------- 1 | #region copyright 2 | 3 | /* 4 | * MIT License 5 | * 6 | * Copyright (c) 2020-2021 WhiteBlackGoose 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in all 16 | * copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | * SOFTWARE. 25 | */ 26 | 27 | #endregion 28 | 29 | 30 | using GenericTensor.Core; 31 | 32 | namespace GenericTensor.Functions 33 | { 34 | internal static class LuDecomposition where TWrapper : struct, IOperations 35 | { 36 | public static (GenTensor, GenTensor) Decompose(GenTensor t) 37 | { 38 | #if ALLOW_EXCEPTIONS 39 | if (!t.IsSquareMatrix) 40 | throw new InvalidShapeException("this should be a square matrix"); 41 | #endif 42 | 43 | var n = t.Shape[0]; 44 | var lower = GenTensor.CreateMatrix(n, n); 45 | var upper = GenTensor.CreateMatrix(n, n); 46 | 47 | var tw = default(TWrapper); 48 | var zero = tw.CreateZero(); 49 | var one = tw.CreateOne(); 50 | 51 | for (var i = 0; i < n; i++) 52 | { 53 | // Upper triangular 54 | for (var k = i; k < n; k++) 55 | { 56 | var sum = zero; 57 | for (var j = 0; j < i; j++) 58 | sum = tw.Add(sum, tw.Multiply(lower[i, j], upper[j, k])); 59 | 60 | upper[i, k] = tw.Subtract(t[i, k], sum); 61 | } 62 | 63 | // Lower triangular 64 | for (var k = i; k < n; k++) 65 | { 66 | if (i == k) 67 | lower[i, i] = one; // 1 at diagonals 68 | else 69 | { 70 | var sum = zero; 71 | for (var j = 0; j < i; j++) 72 | sum = tw.Add(sum, tw.Multiply(lower[k, j], upper[j, i])); 73 | 74 | #if ALLOW_EXCEPTIONS 75 | if (Equals(upper[i, i], zero)) 76 | { 77 | throw new ImpossibleDecomposition("There is no LU decomposition for given matrix"); 78 | } 79 | #endif 80 | 81 | lower[k, i] 82 | = tw.Divide(tw.Subtract(t[k, i], sum), upper[i, i]); 83 | } 84 | } 85 | } 86 | 87 | return (lower, upper); 88 | } 89 | } 90 | } -------------------------------------------------------------------------------- /GenericTensor/Functions/MatrixMultiplication.cs: -------------------------------------------------------------------------------- 1 | #region copyright 2 | /* 3 | * MIT License 4 | * 5 | * Copyright (c) 2020-2021 WhiteBlackGoose 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | #endregion 26 | 27 | 28 | using System.Linq; 29 | using System.Threading.Tasks; 30 | using GenericTensor.Core; 31 | 32 | namespace GenericTensor.Functions 33 | { 34 | internal static class MatrixMultiplication where TWrapper : struct, IOperations 35 | { 36 | internal static GenTensor Multiply(GenTensor a, 37 | GenTensor b, Threading threading = Threading.Single) 38 | { 39 | #if ALLOW_EXCEPTIONS 40 | if (!a.IsMatrix || !b.IsMatrix) 41 | throw new InvalidShapeException($"Both {nameof(a)} and {nameof(b)} should be matrices"); 42 | if (a.Shape[1] != b.Shape[0]) 43 | throw new InvalidShapeException($"{nameof(a)}'s height must be equal to {nameof(b)}'s width"); 44 | #endif 45 | 46 | var width = a.Shape[0]; 47 | var height = b.Shape[1]; 48 | var row = a.Shape[1]; 49 | var res = Constructors.CreateMatrix(width, height); 50 | 51 | var parallel = threading == Threading.Multi || (threading == Threading.Auto && a.Volume > 125); 52 | 53 | 54 | var aBlocks0 = a.blocks[0]; 55 | var aBlocks1 = a.blocks[1]; 56 | var bBlocks0 = b.blocks[0]; 57 | var bBlocks1 = b.blocks[1]; 58 | var aLinoffset = a.LinOffset; 59 | var bLinoffset = b.LinOffset; 60 | 61 | if (!parallel) 62 | { 63 | for (int x = 0; x < width; x++) 64 | { 65 | for (int y = 0; y < height; y++) 66 | { 67 | var s = default(TWrapper).CreateZero(); 68 | for (int i = 0; i < row; i++) 69 | { 70 | var v1 = a.data[x * aBlocks0 + i * aBlocks1 + aLinoffset]; 71 | var v2 = b.data[i * bBlocks0 + y * bBlocks1 + bLinoffset]; 72 | s = default(TWrapper).Add(s, default(TWrapper).Multiply(v1, v2)); 73 | } 74 | res.data[x * height + y] = s; 75 | } 76 | } 77 | } 78 | else 79 | { 80 | Parallel.For(0, width, x => 81 | { 82 | for (int y = 0; y < height; y++) 83 | { 84 | var s = default(TWrapper).CreateZero(); 85 | for (int i = 0; i < row; i++) 86 | { 87 | var v1 = a.data[x * aBlocks0 + i * aBlocks1 + aLinoffset]; 88 | var v2 = b.data[i * bBlocks0 + y * bBlocks1 + bLinoffset]; 89 | s = default(TWrapper).Add(s, default(TWrapper).Multiply(v1, v2)); 90 | } 91 | res.data[x * height + y] = s; 92 | } 93 | }); 94 | } 95 | 96 | return res; 97 | } 98 | 99 | public static GenTensor TensorMultiply(GenTensor a, 100 | GenTensor b, Threading threading = Threading.Single) 101 | { 102 | #if ALLOW_EXCEPTIONS 103 | if (a.Shape.Count < 2 || b.Shape.Count < 2) 104 | throw new InvalidShapeException($"Arguments should be at least matrices while their shapes are {a.Shape} and {b.Shape}"); 105 | if (a.Shape.SubShape(0, 2) != b.Shape.SubShape(0, 2)) 106 | throw new InvalidShapeException("Other dimensions of tensors should be equal"); 107 | #endif 108 | var oldShape = a.Shape.SubShape(0, 2).ToArray(); 109 | var newShape = new int[oldShape.Length + 2]; 110 | for (int i = 0; i < oldShape.Length; i++) 111 | newShape[i] = oldShape[i]; 112 | newShape[newShape.Length - 2] = a.Shape[a.Shape.Length - 2]; 113 | newShape[newShape.Length - 1] = b.Shape[b.Shape.Length - 1]; 114 | var resTensor = new GenTensor(newShape); 115 | 116 | var parallel = threading == Threading.Multi || (threading == Threading.Auto && a.Volume > 300 && a.Shape[0] > 2); 117 | 118 | if (!parallel) 119 | { 120 | foreach (var subDimensions in a.IterateOverMatrices()) 121 | { 122 | var product = Multiply(a.GetSubtensor(subDimensions), b.GetSubtensor(subDimensions)); 123 | resTensor.SetSubtensor(product, subDimensions); 124 | } 125 | } 126 | else 127 | { 128 | var subdims = a.IterateOverCopy(2).ToArray(); 129 | 130 | Parallel.For(0, subdims.Length, subId => 131 | { 132 | var subDimensions = subdims[subId]; 133 | var product = Multiply(a.GetSubtensor(subDimensions), b.GetSubtensor(subDimensions), Threading.Single); 134 | resTensor.SetSubtensor(product, subDimensions); 135 | }); 136 | } 137 | return resTensor; 138 | } 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /GenericTensor/Functions/PiecewiseArithmetics.cs: -------------------------------------------------------------------------------- 1 | #region copyright 2 | /* 3 | * MIT License 4 | * 5 | * Copyright (c) 2020-2021 WhiteBlackGoose 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | #endregion 26 | 27 | 28 | using GenericTensor.Core; 29 | using GenericTensor.Core.Expressions; 30 | 31 | namespace GenericTensor.Functions 32 | { 33 | internal interface IZipOperator 34 | { 35 | T Operation(T a, T b); 36 | } 37 | 38 | internal static class WrapperStorage where TWrapper : struct, IOperations 39 | { 40 | internal struct AddWrapper : IZipOperator 41 | { 42 | public T Operation(T a, T b) => default(TWrapper).Add(a, b); 43 | } 44 | 45 | internal struct SubtractWrapper : IZipOperator 46 | { 47 | public T Operation(T a, T b) => default(TWrapper).Subtract(a, b); 48 | } 49 | 50 | internal struct MultiplyWrapper : IZipOperator 51 | { 52 | public T Operation(T a, T b) => default(TWrapper).Multiply(a, b); 53 | } 54 | 55 | internal struct DivideWrapper : IZipOperator 56 | { 57 | public T Operation(T a, T b) => default(TWrapper).Divide(a, b); 58 | } 59 | } 60 | 61 | internal static class PiecewiseArithmetics where TWrapper : struct, IOperations 62 | { 63 | 64 | private static bool DetermineThreading(GenTensor a, 65 | GenTensor b, Threading threading) 66 | { 67 | var parallel = threading == Threading.Multi || (threading == Threading.Auto && a.Volume > 3000); 68 | return parallel && !a.IsVector; 69 | } 70 | 71 | public static GenTensor PiecewiseAdd(GenTensor a, 72 | GenTensor b, Threading threading) 73 | => ExpressionCompiler.PiecewiseAdd(a, b, DetermineThreading(a, b, threading)); 74 | 75 | public static GenTensor PiecewiseSubtract(GenTensor a, 76 | GenTensor b, Threading threading) 77 | => ExpressionCompiler.PiecewiseSubtract(a, b, DetermineThreading(a, b, threading)); 78 | 79 | public static GenTensor PiecewiseMultiply(GenTensor a, 80 | GenTensor b, Threading threading) 81 | => ExpressionCompiler.PiecewiseMultiply(a, b, DetermineThreading(a, b, threading)); 82 | 83 | public static GenTensor PiecewiseDivide(GenTensor a, 84 | GenTensor b, Threading threading) 85 | => ExpressionCompiler.PiecewiseDivision(a, b, DetermineThreading(a, b, threading)); 86 | 87 | public static GenTensor PiecewiseAdd(GenTensor a, 88 | T b, Threading threading) 89 | => Constructors.CreateTensor(a.Shape, ind => 90 | default(TWrapper).Add(a[ind], b), threading); 91 | 92 | public static GenTensor PiecewiseSubtract(GenTensor a, 93 | T b, Threading threading) 94 | => Constructors.CreateTensor(a.Shape, ind => 95 | default(TWrapper).Subtract(a[ind], b), threading); 96 | 97 | public static GenTensor PiecewiseSubtract( 98 | T a, GenTensor b, Threading threading) 99 | => Constructors.CreateTensor(b.Shape, ind => 100 | default(TWrapper).Subtract(a, b[ind]), threading); 101 | 102 | public static GenTensor PiecewiseMultiply(GenTensor a, 103 | T b, Threading threading) 104 | => Constructors.CreateTensor(a.Shape, ind => 105 | default(TWrapper).Multiply(a[ind], b), threading); 106 | 107 | public static GenTensor PiecewiseDivide(GenTensor a, 108 | T b, Threading threading) 109 | => Constructors.CreateTensor(a.Shape, ind => 110 | default(TWrapper).Divide(a[ind], b), threading); 111 | 112 | public static GenTensor PiecewiseDivide( 113 | T a, GenTensor b, Threading threading) 114 | => Constructors.CreateTensor(b.Shape, ind => 115 | default(TWrapper).Divide(a, b[ind]), threading); 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /GenericTensor/Functions/PluDecomposition.cs: -------------------------------------------------------------------------------- 1 | #region copyright 2 | 3 | /* 4 | * MIT License 5 | * 6 | * Copyright (c) 2020-2021 WhiteBlackGoose 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in all 16 | * copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | * SOFTWARE. 25 | */ 26 | 27 | #endregion 28 | 29 | 30 | using GenericTensor.Core; 31 | 32 | namespace GenericTensor.Functions 33 | { 34 | internal static class PluDecomposition where TWrapper : struct, IOperations 35 | { 36 | public static (GenTensor, GenTensor, GenTensor) Decompose(GenTensor original) 37 | { 38 | var t = original.Copy(copyElements: true); 39 | 40 | #if ALLOW_EXCEPTIONS 41 | if (!t.IsSquareMatrix) 42 | throw new InvalidShapeException("this should be a square matrix"); 43 | #endif 44 | 45 | var n = t.Shape[0]; 46 | var m = t.Shape[1]; 47 | var tw = default(TWrapper); 48 | 49 | var identity = GenTensor.CreateIdentityMatrix(m); 50 | 51 | t.TransposeMatrix(); 52 | var adj = GenTensor.Concat(t, identity); 53 | adj.TransposeMatrix(); 54 | 55 | var (echelon, permute) = adj.RowEchelonFormPermuteSafeDivision(); 56 | var upper = GenTensor.CreateMatrix(n, m, (i, j) => echelon[i, j]); 57 | var lowerZero = GenTensor.CreateMatrix(m, m, (i, j) => echelon[i, m + j]); 58 | 59 | lowerZero.InvertMatrix(); 60 | 61 | var permuteMatrix = 62 | GenTensor.CreateMatrix(m, m, (i, j) => j == permute[i] - 1 ? tw.CreateOne() : tw.CreateZero()); 63 | 64 | var lower = GenTensor.MatrixMultiply(permuteMatrix, lowerZero); 65 | return (permuteMatrix, lower, upper); 66 | } 67 | } 68 | } -------------------------------------------------------------------------------- /GenericTensor/Functions/Power.cs: -------------------------------------------------------------------------------- 1 | #region copyright 2 | /* 3 | * MIT License 4 | * 5 | * Copyright (c) 2020-2021 WhiteBlackGoose 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | #endregion 26 | 27 | 28 | using GenericTensor.Core; 29 | 30 | namespace GenericTensor.Functions 31 | { 32 | internal static class Power where TWrapper : struct, IOperations 33 | { 34 | public static GenTensor MatrixPower(GenTensor m, int power, Threading threading) 35 | { 36 | #if ALLOW_EXCEPTIONS 37 | if (!m.IsSquareMatrix) 38 | throw new InvalidShapeException("Square matrix required"); 39 | #endif 40 | if (power == 0) 41 | return Constructors.CreateIdentityMatrix(m.Shape.shape[0]); 42 | if (power < 0) 43 | { 44 | m = m.Forward(); 45 | m.InvertMatrix(); 46 | power *= -1; 47 | } 48 | if (power == 1) 49 | return m; 50 | if (power == 2) 51 | return MatrixMultiplication.Multiply(m, m, threading); 52 | var half = power / 2; 53 | var m1 = MatrixPower(m, half, threading); 54 | var dotted = MatrixMultiplication.Multiply(m1, m1, threading); 55 | if (power % 2 == 0) 56 | return dotted; 57 | else 58 | return MatrixMultiplication.Multiply(dotted, m, threading); 59 | } 60 | 61 | public static GenTensor TensorMatrixPower(GenTensor m, int power, Threading threading) 62 | { 63 | #if ALLOW_EXCEPTIONS 64 | InvalidShapeException.NeedTensorSquareMatrix(m); 65 | #endif 66 | 67 | var res = new GenTensor(m.Shape); 68 | foreach (var ind in res.IterateOverMatrices()) 69 | res.SetSubtensor( 70 | MatrixPower(m.GetSubtensor(ind), power, threading), 71 | ind 72 | ); 73 | 74 | return res; 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /GenericTensor/Functions/Serialization.cs: -------------------------------------------------------------------------------- 1 | #region copyright 2 | /* 3 | * MIT License 4 | * 5 | * Copyright (c) 2020-2021 WhiteBlackGoose 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | #endregion 26 | 27 | 28 | using System; 29 | using System.Collections.Generic; 30 | using System.IO; 31 | using System.Numerics; 32 | using GenericTensor.Core; 33 | 34 | namespace GenericTensor.Functions 35 | { 36 | internal static class Serializer where TWrapper : struct, IOperations 37 | { 38 | public static byte[] Serialize(GenTensor tensor) 39 | { 40 | var bb = new SerializationUtils.ByteBuilder(); 41 | bb.AddInt(tensor.Shape.Length); 42 | foreach (var sh in tensor.Shape.shape) 43 | bb.AddInt(sh); 44 | foreach (var (_, value) in tensor.Iterate()) 45 | { 46 | var ser = default(TWrapper).Serialize(value); 47 | bb.AddInt(ser.Length); 48 | bb.AddBytes(ser); 49 | } 50 | return bb.ToArray(); 51 | } 52 | 53 | public static GenTensor Deserialize(byte[] data) 54 | { 55 | var bp = new SerializationUtils.ByteParser(data); 56 | var dimCount = bp.PopInt(); 57 | var dimensions = new int[dimCount]; 58 | for (int i = 0; i < dimCount; i++) 59 | dimensions[i] = bp.PopInt(); 60 | var res = new GenTensor(dimensions); 61 | foreach (var index in res.IterateOver(0)) 62 | { 63 | var serializedCellLength = bp.PopInt(); 64 | var serData = bp.PopBytes(serializedCellLength); 65 | var unser = default(TWrapper).Deserialize(serData); 66 | res.SetValueNoCheck(unser, index); 67 | } 68 | return res; 69 | } 70 | } 71 | 72 | // Span is the only thing used from 73 | // System.Memory, so why not to replace 74 | // it with my own ByteSpan, since I use one 75 | // single method of Span, which makes it 76 | // not worth making an external dependency. 77 | internal struct ByteSpan 78 | { 79 | private readonly byte[] arr; 80 | private readonly int start; 81 | private readonly int length; 82 | public ByteSpan(byte[] arr, int start, int length) 83 | => (this.arr, this.start, this.length) = (arr, start, length); 84 | public byte[] ToArray() 85 | { 86 | var res = new byte[length]; 87 | Array.Copy(arr, start, res, 0, length); 88 | return res; 89 | } 90 | } 91 | 92 | internal static class SerializationUtils 93 | { 94 | // TODO: replace with an existing solution 95 | internal class ByteBuilder 96 | { 97 | private readonly List bytes = new List(); 98 | 99 | public void AddInt(int val) 100 | => bytes.AddRange(BitConverter.GetBytes(val)); 101 | 102 | public void AddBytes(byte[] data) 103 | => bytes.AddRange(data); 104 | 105 | public byte[] ToArray() 106 | => bytes.ToArray(); 107 | } 108 | 109 | 110 | // TODO: replace with an existing solution 111 | internal class ByteParser 112 | { 113 | private readonly byte[] bytes; 114 | private int currId = 0; 115 | 116 | public ByteParser(byte[] data) 117 | => bytes = data; 118 | 119 | public int PopInt() 120 | { 121 | try 122 | { 123 | var bytesInt = new ByteSpan(bytes, currId, 4); 124 | var res = BitConverter.ToInt32(bytesInt.ToArray(), 0); 125 | currId += sizeof(int); 126 | return res; 127 | } 128 | catch (ArgumentOutOfRangeException e) 129 | { 130 | throw new InvalidDataException("End of array reached", e); 131 | } 132 | } 133 | 134 | public byte[] PopBytes(int numberOfBytes) 135 | { 136 | try 137 | { 138 | var bytesn = new ByteSpan(bytes, currId, numberOfBytes); 139 | currId += numberOfBytes; 140 | return bytesn.ToArray(); 141 | } 142 | catch (ArgumentOutOfRangeException e) 143 | { 144 | throw new InvalidDataException("End of array reached", e); 145 | } 146 | } 147 | } 148 | 149 | // TODO: There surely is a faster method than that 150 | public static byte[] SerializeComplex(Complex c) 151 | { 152 | var list = new List(); 153 | list.AddRange(BitConverter.GetBytes(c.Real)); 154 | list.AddRange(BitConverter.GetBytes(c.Imaginary)); 155 | return list.ToArray(); 156 | } 157 | 158 | // TODO: There surely is a faster method than that 159 | public static Complex DeserializeComplex(byte[] data) 160 | { 161 | var realBytes = new ByteSpan(data, 0, sizeof(double)); 162 | var imagBytes = new ByteSpan(data, sizeof(double), sizeof(double)); 163 | return new Complex( 164 | BitConverter.ToDouble(realBytes.ToArray(), 0), 165 | BitConverter.ToDouble(imagBytes.ToArray(), 0) 166 | ); 167 | } 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /GenericTensor/Functions/SquareMatrixFactory.cs: -------------------------------------------------------------------------------- 1 | #region copyright 2 | /* 3 | * MIT License 4 | * 5 | * Copyright (c) 2020-2021 WhiteBlackGoose 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | #endregion 26 | 27 | 28 | using System.Collections.Generic; 29 | using GenericTensor.Core; 30 | using GenericTensor.Functions; 31 | 32 | namespace GenericTensor.Core 33 | { 34 | internal static class SquareMatrixFactory where TWrapper : struct, IOperations 35 | { 36 | // [0] is 1x1 matrix, [1] is 2x2 matrix, etc. 37 | static readonly List> tensorTempFactorySquareMatrices = new List>(); 38 | 39 | internal static GenTensor GetMatrix(int diagLength) 40 | { 41 | if (diagLength >= tensorTempFactorySquareMatrices.Count + 1) 42 | lock (tensorTempFactorySquareMatrices) 43 | if (diagLength >= tensorTempFactorySquareMatrices.Count + 1) 44 | for (int i = tensorTempFactorySquareMatrices.Count + 1; i <= diagLength; i++) 45 | tensorTempFactorySquareMatrices.Add(new GenTensor(i, i)); 46 | return tensorTempFactorySquareMatrices[diagLength - 1]; 47 | } 48 | } 49 | 50 | // It is here just for a test to avoid InternalsToVisible 51 | internal static class TestSquareMatrixFactoryExposed 52 | { 53 | internal static GenTensor TestGetMatrixExposed(int diagLength) 54 | => SquareMatrixFactory.GetMatrix(diagLength); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /GenericTensor/Functions/ToString.cs: -------------------------------------------------------------------------------- 1 | #region copyright 2 | /* 3 | * MIT License 4 | * 5 | * Copyright (c) 2020-2021 WhiteBlackGoose 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | #endregion 26 | 27 | 28 | using System; 29 | using System.Collections.Generic; 30 | using System.Text; 31 | using GenericTensor.Core; 32 | 33 | namespace GenericTensor.Functions 34 | { 35 | internal static class DefaultOverridings where TWrapper : struct, IOperations 36 | { 37 | public static string InToString(GenTensor t) 38 | { 39 | if (t.IsMatrix) 40 | { 41 | var maxLength = -1; 42 | var stringArray = new string[t.Shape[0], t.Shape[1]]; 43 | for (int i = 0; i < t.Shape[0]; i++) 44 | for (int j = 0; j < t.Shape[1]; j++) 45 | { 46 | stringArray[i, j] = default(TWrapper).ToString(t.GetValueNoCheck(i, j)); 47 | maxLength = Math.Max(maxLength, stringArray[i, j].Length); 48 | } 49 | var rows = new List(); 50 | rows.Add("Matrix[" + t.Shape + "]"); 51 | for (int i = 0; i < t.Shape[0]; i++) 52 | { 53 | var s = ""; 54 | for (int j = 0; j < t.Shape[1]; j++) 55 | { 56 | var count = maxLength + 3 - stringArray[i, j].Length; 57 | count = Math.Max(0, count); 58 | s += stringArray[i, j]; 59 | for (int k = 0; k < count; k++) 60 | s += " "; 61 | } 62 | rows.Add(s); 63 | } 64 | return string.Join("\n", rows); 65 | } 66 | if (t.IsVector) 67 | { 68 | var els = new List(); 69 | for (int i = 0; i < t.Shape[0]; i++) 70 | els.Add(default(TWrapper).ToString(t.GetValueNoCheck(i))); 71 | return string.Join(" ", els); 72 | } 73 | var sb = new StringBuilder(); 74 | sb.Append("Tensor[" + t.Shape + "] {\n"); 75 | foreach (var index in t.IterateOverMatrices()) 76 | { 77 | sb.Append(" "); 78 | sb.Append(t.GetSubtensor(index).ToString().Replace("\n", "\n ")); 79 | sb.Append("\n\n"); 80 | } 81 | sb.Append("}"); 82 | return sb.ToString(); 83 | } 84 | 85 | // TODO: make it faster 86 | public static int GetHashCode(GenTensor t) 87 | { 88 | var res = 0; 89 | unchecked 90 | { 91 | res += t.Shape.GetHashCode(); 92 | foreach (var (_, value) in t.Iterate()) 93 | res += value?.GetHashCode() ?? 0; 94 | } 95 | return res; 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /GenericTensor/Functions/Vector.CrossProduct.cs: -------------------------------------------------------------------------------- 1 | #region copyright 2 | /* 3 | * MIT License 4 | * 5 | * Copyright (c) 2020-2021 WhiteBlackGoose 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | #endregion 26 | 27 | 28 | using System; 29 | using GenericTensor.Core; 30 | 31 | namespace GenericTensor.Functions 32 | { 33 | internal static partial class VectorProduct where TWrapper : struct, IOperations 34 | { 35 | public static GenTensor VectorCrossProduct(GenTensor a, GenTensor b) 36 | { 37 | #if ALLOW_EXCEPTIONS 38 | if (!a.IsVector || !b.IsVector) 39 | throw new InvalidShapeException($"Both {nameof(a)} and {nameof(b)} should be vectors"); 40 | if (a.Shape[0] != b.Shape[0]) 41 | throw new InvalidShapeException($"Length of {nameof(a)} and {nameof(b)} should be equal"); 42 | if (a.Shape[0] != 3) 43 | throw new NotImplementedException("Other than vectors of the length of 3 aren't supported for VectorCrossProduct yet"); 44 | #endif 45 | return GenTensor.CreateVector( 46 | default(TWrapper).Subtract( 47 | default(TWrapper).Multiply(a[1], b[2]), 48 | default(TWrapper).Multiply(a[2], b[1])), 49 | 50 | default(TWrapper).Subtract( 51 | default(TWrapper).Multiply(a[2], b[0]), 52 | default(TWrapper).Multiply(a[0], b[2])), 53 | 54 | default(TWrapper).Subtract( 55 | default(TWrapper).Multiply(a[0], b[1]), 56 | default(TWrapper).Multiply(a[1], b[0])) 57 | ); 58 | } 59 | 60 | public static GenTensor TensorVectorCrossProduct(GenTensor a, 61 | GenTensor b) 62 | { 63 | #if ALLOW_EXCEPTIONS 64 | if (a.Shape != b.Shape) 65 | throw new InvalidShapeException($"Pre-shapes of {nameof(a)} and {nameof(b)} should be equal"); 66 | #endif 67 | var res = new GenTensor(a.Shape); 68 | foreach (var index in a.IterateOverVectors()) 69 | res.SetSubtensor( 70 | VectorCrossProduct(a.GetSubtensor(index), b.GetSubtensor(index)), 71 | index 72 | ); 73 | return res; 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /GenericTensor/Functions/Vector.DotProduct.cs: -------------------------------------------------------------------------------- 1 | #region copyright 2 | /* 3 | * MIT License 4 | * 5 | * Copyright (c) 2020-2021 WhiteBlackGoose 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | #endregion 26 | 27 | 28 | using GenericTensor.Core; 29 | 30 | namespace GenericTensor.Functions 31 | { 32 | internal static partial class VectorProduct where TWrapper : struct, IOperations 33 | { 34 | public static GenTensor TensorVectorDotProduct(GenTensor a, 35 | GenTensor b) 36 | { 37 | #if ALLOW_EXCEPTIONS 38 | if (a.Shape.SubShape(0, 1) != b.Shape.SubShape(0, 1)) 39 | throw new InvalidShapeException("Other dimensions of tensors should be equal"); 40 | #endif 41 | var resTensor = new GenTensor(a.Shape.SubShape(0, 1)); 42 | foreach (var index in resTensor.IterateOverElements()) 43 | { 44 | var scal = VectorDotProduct(a.GetSubtensor(index), b.GetSubtensor(index)); 45 | resTensor.SetValueNoCheck(scal, index); 46 | } 47 | return resTensor; 48 | } 49 | 50 | public static T VectorDotProduct(GenTensor a, 51 | GenTensor b) 52 | { 53 | #if ALLOW_EXCEPTIONS 54 | if (!a.IsVector || !b.IsVector) 55 | throw new InvalidShapeException($"{nameof(a)} and {nameof(b)} should be vectors"); 56 | if (a.Shape[0] != b.Shape[0]) 57 | throw new InvalidShapeException($"{nameof(a)}'s length should be the same as {nameof(b)}'s"); 58 | #endif 59 | var res = default(TWrapper).CreateZero(); 60 | for (int i = 0; i < a.Shape[0]; i++) 61 | { 62 | res = default(TWrapper).Add(res, 63 | default(TWrapper).Multiply(a.GetValueNoCheck(i), b.GetValueNoCheck(i))); 64 | } 65 | return res; 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /GenericTensor/GenericTensor.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net472;netstandard2.0 5 | 9.0 6 | true 7 | 1.0.5 8 | WhiteBlackGoose 9 | Angouri 10 | The only .NET tensor & matrix library for generic types. It is also faster than other generic-typed matrix libraries. 11 | WhiteBlackGoose 12 | LICENSE 13 | https://github.com/WhiteBlackGoose/GenericTensor 14 | https://github.com/asc-community/GenericTensor 15 | public 16 | Added 0D tensor support, Aggregate, ForEach. 17 | ico1.png 18 | tensor, generic, matrix, vector, performance 19 | true 20 | keypair.snk 21 | enable 22 | 23 | 24 | 25 | TRACE;ALLOW_EXCEPTIONS 26 | full 27 | true 28 | true 29 | D:\main\vs_prj\GenericTensor\GenericTensor\GenericTensor\GenericTensor.xml 30 | 31 | 32 | 33 | TRACE;ALLOW_EXCEPTIONS 34 | true 35 | full 36 | true 37 | 38 | 39 | 40 | 41 | True 42 | 43 | 44 | 45 | True 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /GenericTensor/keypair.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asc-community/GenericTensor/da0c01d2acb17530ee6bc39da79692148c92069b/GenericTensor/keypair.snk -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020-2021 WhiteBlackGoose 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Sample/MatrixWrapper.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * This file shows how the user of this library is supposed to write their own 4 | * wrappers for GenTensors. 5 | * 6 | */ 7 | 8 | using GenericTensor.Core; 9 | 10 | namespace Sample 11 | { 12 | /// 13 | /// This class is only supposed to be used for matrix multiplication 14 | /// 15 | public sealed class MyMatrix 16 | { 17 | // if you want to use a built-in type with the same operations as they provide, 18 | // you can use default wrappers like IntWrapper, FloatWrapper, DoubleWrapper, 19 | // and other in DefaultWrappers.cs 20 | private readonly GenTensor inner; 21 | 22 | public MyMatrix(int width, int height) 23 | // Many constructors and functions may be directly redirected in one 24 | // defined in GenericTensor, but you are free to write your own new method 25 | : this(GenTensor.CreateMatrix(width, height)) 26 | { 27 | 28 | } 29 | 30 | private MyMatrix(GenTensor newInner) 31 | => inner = newInner; 32 | 33 | public double this[int x, int y] 34 | { 35 | // You may add bound check here, but they all are checked for you in inner tensor 36 | get => inner[x, y]; 37 | set => inner[x, y] = value; 38 | } 39 | 40 | // MatrixMultiply only requires Add, Multiply, and CreateZero defined for your primitives 41 | public static MyMatrix operator *(MyMatrix a, MyMatrix b) 42 | => new MyMatrix(GenTensor.MatrixMultiply(a.inner, b.inner)); 43 | 44 | 45 | // this will require ToString to be defined in your primitive wrapper 46 | public override string ToString() 47 | => inner.ToString(); 48 | 49 | 50 | // Make sure that all required operations are implemented 51 | // as there is no compile-time check on whether a method is implemented 52 | // and it will throw NotImplementedException if not 53 | private struct MyCustomDoubleTypeWrapper : IOperations 54 | { 55 | public double Add(double a, double b) => a + b; 56 | public double Multiply(double a, double b) => a * b; 57 | public double CreateZero() => 0; 58 | 59 | // It's better to somehow define it as it will make your debug-time easier :) 60 | public string ToString(double a) => a.ToString(); 61 | 62 | public double Subtract(double a, double b) 63 | { 64 | throw new System.NotImplementedException(); 65 | } 66 | 67 | public double Negate(double a) 68 | { 69 | throw new System.NotImplementedException(); 70 | } 71 | 72 | public double Divide(double a, double b) 73 | { 74 | throw new System.NotImplementedException(); 75 | } 76 | 77 | public double CreateOne() 78 | { 79 | throw new System.NotImplementedException(); 80 | } 81 | 82 | public double Copy(double a) 83 | { 84 | throw new System.NotImplementedException(); 85 | } 86 | 87 | public bool AreEqual(double a, double b) 88 | { 89 | throw new System.NotImplementedException(); 90 | } 91 | 92 | public bool IsZero(double a) 93 | { 94 | throw new System.NotImplementedException(); 95 | } 96 | 97 | public byte[] Serialize(double a) 98 | { 99 | throw new System.NotImplementedException(); 100 | } 101 | 102 | public double Deserialize(byte[] data) 103 | { 104 | throw new System.NotImplementedException(); 105 | } 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /Sample/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using GenericTensor.Core; 3 | using GenericTensor.Functions; 4 | using Sample; 5 | 6 | var sdfoks = GenTensor.CreateMatrix(new double[,] 7 | { 8 | { 6, 3 }, 9 | { 7, 5 } 10 | } 11 | ); 12 | 13 | sdfoks.InvertMatrix(); 14 | Console.WriteLine(sdfoks); 15 | return; 16 | var m2 = GenTensor.CreateMatrix(new double[,] 17 | { 18 | { 1, 0, 70 }, 19 | { 0, 1, 0 }, 20 | { 0, 0, 1 } 21 | } 22 | ); 23 | 24 | // Console.WriteLine(m2.RowEchelonFormLeadingOnesSimple()); 25 | // Console.WriteLine(m2.RowEchelonFormLeadingOnesSafeDivision()); 26 | // Console.WriteLine(m2.ReducedRowEchelonFormSimple()); 27 | m2.InvertMatrix(); 28 | Console.WriteLine(m2); 29 | return; 30 | 31 | var m = GenTensor.CreateMatrix(new double[,] 32 | { 33 | { 1, 2, 3 }, 34 | { 1, 3, 3 } 35 | } 36 | ); 37 | 38 | Console.WriteLine(m); 39 | 40 | var n = m.Copy(false); 41 | n.TransposeMatrix(); 42 | 43 | Console.WriteLine(m); 44 | 45 | return; 46 | 47 | var M = GenTensor.CreateMatrix(new double[,] 48 | { 49 | { -3, 0, 0, 0, 1, -130 }, 50 | { 0, -2, 1, 0, 0, -39 }, 51 | { 0, 0, -3, 2, 0, 0 }, 52 | { 0, 0, 0, -7, 3, -273 }, 53 | { 0, 0, 0, 0, -26, -1729 } 54 | } 55 | ); 56 | 57 | Console.WriteLine(M.RowEchelonFormLeadingOnesSafeDivision()); 58 | return; 59 | 60 | var A = new MyMatrix(3, 2); 61 | A[0, 0] = 5; A[0, 1] = 6; 62 | A[1, 0] = 3; A[1, 1] = 8; 63 | A[2, 0] = 2; A[2, 1] = 9; 64 | 65 | var B = new MyMatrix(2, 2); 66 | B[0, 0] = 5; B[1, 0] = 6; 67 | B[0, 1] = 3; B[1, 1] = 8; 68 | 69 | Console.WriteLine(A); 70 | Console.WriteLine("\nmultiplied by \n"); 71 | Console.WriteLine(B); 72 | Console.WriteLine("\nis \n"); 73 | Console.WriteLine(A * B); 74 | 75 | public static class Samples 76 | { 77 | public static void CreatingMatrix() 78 | { 79 | var myMatrix = GenTensor.CreateMatrix( 80 | new float[,] 81 | { 82 | {1, 2, 3}, 83 | {4, 5, 6}, 84 | {7, 8, 9} 85 | } 86 | ); 87 | Console.WriteLine(myMatrix); 88 | } 89 | 90 | public static void CreatingMatrixAndMultiply() 91 | { 92 | var myMatrix = GenTensor.CreateMatrix( 93 | new float[,] 94 | { 95 | {1, 2, 3}, 96 | {4, 5, 6}, 97 | {7, 8, 9} 98 | } 99 | ); 100 | var multipled = GenTensor.MatrixMultiply(myMatrix, myMatrix); 101 | Console.WriteLine(GenTensor.MatrixMultiply(myMatrix, multipled)); 102 | var t = GenTensor.Stack(myMatrix, myMatrix); 103 | t.Transpose(0, 2); 104 | Console.WriteLine(t); 105 | } 106 | 107 | public static GenTensor> LazyWrapperMultiply(T[,] a, T[,] b) 108 | { 109 | return GenTensor>.MatrixMultiply( 110 | GenTensor>.CreateMatrix(a), 111 | GenTensor>.CreateMatrix(b) 112 | ); 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /Sample/Sample.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net5.0 6 | 7 | 8 | 9 | full 10 | true 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /UnitTests/Aggregate.cs: -------------------------------------------------------------------------------- 1 | #region copyright 2 | /* 3 | * MIT License 4 | * 5 | * Copyright (c) 2020-2021 WhiteBlackGoose 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | #endregion 26 | 27 | 28 | using GenericTensor.Core; 29 | using GenericTensor.Functions; 30 | using Microsoft.VisualStudio.TestTools.UnitTesting; 31 | 32 | namespace UnitTests 33 | { 34 | [TestClass] 35 | public class Aggregate 36 | { 37 | // 3 x 2 x 2 x 2 38 | private static readonly GenTensor frog = GenTensor.CreateTensor(new[,,,] { 39 | { 40 | { { 1, 2 }, { 3, 4 } }, 41 | { { 10, 20 }, { 30, 40 } }, 42 | }, 43 | { 44 | { { 100, 200 }, { 300, 400 } }, 45 | { { 1000, 2000 }, { 3000, 4000 } }, 46 | }, 47 | { 48 | { { 10000, 20000 }, { 30000, 40000 } }, 49 | { { 100000, 200000 }, { 300000, 400000 } }, 50 | } 51 | }); 52 | 53 | private static readonly GenTensor frogCopy = frog.Copy(true); 54 | 55 | [TestMethod] 56 | public void SumAx0() 57 | { 58 | var acc = GenTensor.CreateTensor(new TensorShape(2, 2, 2), id => 0); 59 | GenTensor.Aggregate(frog, acc, new HonkPerf.NET.Core.PureValueDelegate((a, b) => a + b), axis: 0); 60 | var expected = 61 | GenTensor.CreateTensor(new[,,] { 62 | { { 10101, 20202 }, { 30303, 40404 } }, 63 | { { 101010, 202020 }, { 303030, 404040 } }, 64 | }); 65 | Assert.AreEqual(expected, acc); 66 | Assert.AreEqual(frogCopy, frog); 67 | } 68 | 69 | [TestMethod] 70 | public void SumAx1() 71 | { 72 | var acc = GenTensor.CreateTensor(new TensorShape(3, 2, 2), id => 0); 73 | GenTensor.Aggregate(frog, acc, new HonkPerf.NET.Core.PureValueDelegate((a, b) => a + b), axis: 1); 74 | var expected = 75 | GenTensor.CreateTensor(new[, ,] { 76 | { 77 | { 11, 22 }, { 33, 44 } 78 | }, 79 | { 80 | { 1100, 2200 }, { 3300, 4400 } 81 | }, 82 | { 83 | { 110000, 220000 }, { 330000, 440000 } 84 | } 85 | }); 86 | Assert.AreEqual(expected, acc); 87 | Assert.AreEqual(frogCopy, frog); 88 | } 89 | 90 | [TestMethod] 91 | public void SumAx2() 92 | { 93 | var acc = GenTensor.CreateTensor(new TensorShape(3, 2, 2), id => 0); 94 | GenTensor.Aggregate(frog, acc, new HonkPerf.NET.Core.PureValueDelegate((a, b) => a + b), axis: 2); 95 | var expected = 96 | GenTensor.CreateTensor(new [,,] { 97 | { 98 | { 4, 6 }, 99 | { 40, 60 } 100 | }, 101 | { 102 | { 400, 600 }, 103 | { 4000, 6000 } 104 | }, 105 | { 106 | { 40000, 60000 }, 107 | { 400000, 600000 } 108 | } 109 | }); 110 | Assert.AreEqual(expected, acc); 111 | Assert.AreEqual(frogCopy, frog); 112 | } 113 | 114 | [TestMethod] 115 | public void SumAx3() 116 | { 117 | var acc = GenTensor.CreateTensor(new TensorShape(3, 2, 2), id => 0); 118 | GenTensor.Aggregate(frog, acc, new HonkPerf.NET.Core.PureValueDelegate((a, b) => a + b), axis: 3); 119 | var expected = 120 | GenTensor.CreateTensor(new[, ,] { 121 | { 122 | { 3, 7 }, 123 | { 30, 70 } 124 | }, 125 | { 126 | { 300, 700 }, 127 | { 3000, 7000 } 128 | }, 129 | { 130 | { 30000, 70000 }, 131 | { 300000, 700000 } 132 | } 133 | }); 134 | Assert.AreEqual(expected, acc); 135 | Assert.AreEqual(frogCopy, frog); 136 | } 137 | } 138 | } -------------------------------------------------------------------------------- /UnitTests/Concat.cs: -------------------------------------------------------------------------------- 1 | #region copyright 2 | /* 3 | * MIT License 4 | * 5 | * Copyright (c) 2020-2021 WhiteBlackGoose 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | #endregion 26 | 27 | 28 | using GenericTensor.Core; 29 | using GenericTensor.Functions; 30 | using Microsoft.VisualStudio.TestTools.UnitTesting; 31 | 32 | namespace UnitTests 33 | { 34 | [TestClass] 35 | public class Concat 36 | { 37 | [TestMethod] 38 | public void Matrices() 39 | { 40 | var mat1 = GenTensor.CreateMatrix( 41 | new[,] 42 | { 43 | {1, 2}, 44 | {3, 4}, 45 | {5, 6} 46 | } 47 | ); 48 | 49 | var mat2 = GenTensor.CreateMatrix( 50 | new[,] 51 | { 52 | {7, 8}, 53 | {9, 10}, 54 | } 55 | ); 56 | 57 | Assert.AreEqual( 58 | GenTensor.CreateMatrix(new [,] 59 | { 60 | {1, 2}, 61 | {3, 4}, 62 | {5, 6}, 63 | {7, 8}, 64 | {9, 10} 65 | }), 66 | GenTensor.Concat(mat1, mat2) 67 | ); 68 | } 69 | 70 | [TestMethod] 71 | public void Vecs() 72 | { 73 | var vec1 = GenTensor.CreateVector(1, 2, 3); 74 | var vec2 = GenTensor.CreateVector(4, 5); 75 | Assert.AreEqual( 76 | GenTensor.CreateVector(1, 2, 3, 4, 5), 77 | GenTensor.Concat(vec1, vec2) 78 | ); 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /UnitTests/Copying.cs: -------------------------------------------------------------------------------- 1 | #region copyright 2 | /* 3 | * MIT License 4 | * 5 | * Copyright (c) 2020-2021 WhiteBlackGoose 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | #endregion 26 | 27 | 28 | using GenericTensor.Core; 29 | using GenericTensor.Functions; 30 | using Microsoft.VisualStudio.TestTools.UnitTesting; 31 | 32 | namespace UnitTests 33 | { 34 | [TestClass] 35 | public class Copy 36 | { 37 | [TestMethod] 38 | public void NoChangeInShapeAfterTranspose1() 39 | { 40 | var m = GenTensor.CreateMatrix(new[,] { { 1, 2 } }); 41 | Assert.AreEqual(m.Shape[0], 1); 42 | Assert.AreEqual(m.Shape[1], 2); 43 | var n = m.Copy(false); 44 | n.TransposeMatrix(); 45 | Assert.AreEqual(m.Shape[0], 1); 46 | Assert.AreEqual(m.Shape[1], 2); 47 | } 48 | 49 | [TestMethod] 50 | public void NoChangeInShapeAfterTranspose2() 51 | { 52 | var m = GenTensor.CreateTensor(new[,,] { { { 1, 2 } } }); 53 | Assert.AreEqual(m.Shape[0], 1); 54 | Assert.AreEqual(m.Shape[1], 1); 55 | Assert.AreEqual(m.Shape[2], 2); 56 | var n = m.Copy(false); 57 | n.Transpose(0, 2); 58 | Assert.AreEqual(m.Shape[0], 1); 59 | Assert.AreEqual(m.Shape[1], 1); 60 | Assert.AreEqual(m.Shape[2], 2); 61 | 62 | Assert.AreEqual(n.Shape[0], 2); 63 | Assert.AreEqual(n.Shape[1], 1); 64 | Assert.AreEqual(n.Shape[2], 1); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /UnitTests/Determinant.cs: -------------------------------------------------------------------------------- 1 | #region copyright 2 | /* 3 | * MIT License 4 | * 5 | * Copyright (c) 2020-2021 WhiteBlackGoose 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | #endregion 26 | 27 | 28 | using GenericTensor.Core; 29 | using GenericTensor.Functions; 30 | using Microsoft.VisualStudio.TestTools.UnitTesting; 31 | using System.Numerics; 32 | 33 | namespace UnitTests 34 | { 35 | using TS = GenTensor; 36 | 37 | [TestClass] 38 | public class Determinant 39 | { 40 | public Determinant() 41 | { 42 | 43 | 44 | } 45 | 46 | [TestMethod] 47 | public void SimpleLaplace1() 48 | { 49 | var M = GenTensor.CreateMatrix(new[,] 50 | { 51 | {1, 2}, 52 | {3, 4} 53 | }); 54 | Assert.AreEqual(-2, M.DeterminantLaplace()); 55 | } 56 | 57 | [TestMethod] 58 | public void SimpleLaplace2() 59 | { 60 | var M = GenTensor.CreateMatrix(new[,] 61 | { 62 | {6, 1, 1}, 63 | {4, -2, 5}, 64 | {2, 8, 7} 65 | }); 66 | Assert.AreEqual(-306, M.DeterminantLaplace()); 67 | } 68 | 69 | 70 | // safe division 71 | 72 | 73 | [TestMethod] 74 | public void SimpleGaussian1() 75 | { 76 | var M = GenTensor.CreateMatrix(new[,] 77 | { 78 | {1, 2}, 79 | {3, 4} 80 | }); 81 | Assert.AreEqual(-2, M.DeterminantGaussianSafeDivision()); 82 | } 83 | 84 | [TestMethod] 85 | public void SimpleGaussian2() 86 | { 87 | var M = GenTensor.CreateMatrix(new int[,] 88 | { 89 | {6, 1, 1}, 90 | {4, -2, 5}, 91 | {2, 8, 7} 92 | }); 93 | Assert.AreEqual(-306, M.DeterminantGaussianSafeDivision()); 94 | } 95 | 96 | [TestMethod] 97 | public void SimpleGaussian2Long() 98 | { 99 | var M = GenTensor.CreateMatrix(new long[,] 100 | { 101 | {6, 1, 1}, 102 | {4, -2, 5}, 103 | {2, 8, 7} 104 | }); 105 | Assert.AreEqual(-306, M.DeterminantGaussianSafeDivision()); 106 | } 107 | 108 | 109 | // unsafe 110 | 111 | 112 | [TestMethod] 113 | public void SimpleGaussian3() 114 | { 115 | var M = GenTensor.CreateMatrix(new float[,] 116 | { 117 | {1, 2}, 118 | {3, 4} 119 | }); 120 | Assert.AreEqual(-2, M.DeterminantGaussianSimple()); 121 | } 122 | 123 | [TestMethod] 124 | public void SimpleGaussian4() 125 | { 126 | var M = GenTensor.CreateMatrix(new float[,] 127 | { 128 | {6, 1, 1}, 129 | {4, -2, 5}, 130 | {2, 8, 7} 131 | }); 132 | Assert.AreEqual(-306, M.DeterminantGaussianSimple()); 133 | } 134 | 135 | [TestMethod] 136 | public void TensorLaplace() 137 | { 138 | var T = GenTensor.CreateTensor(new float[,,] 139 | { 140 | { 141 | {1, 2}, // -2 142 | {3, 4} 143 | }, 144 | { 145 | {5, 7}, // -4 146 | {7, 9} 147 | }, 148 | { 149 | {3, 1}, // 15 150 | {6, 7} 151 | } 152 | }); 153 | Assert.AreEqual( 154 | GenTensor.CreateVector(-2, -4, 15), 155 | T.TensorDeterminantLaplace() 156 | ); 157 | } 158 | 159 | [TestMethod] 160 | public void TensorGaussian() 161 | { 162 | var T = GenTensor.CreateTensor(new float[,,] 163 | { 164 | { 165 | {1, 2}, // -2 166 | {3, 4} 167 | }, 168 | { 169 | {5, 7}, // -4 170 | {7, 9} 171 | }, 172 | { 173 | {3, 1}, // 15 174 | {6, 7} 175 | } 176 | }); 177 | Assert.AreEqual( 178 | GenTensor.CreateVector(-2, -4, 15), 179 | T.TensorDeterminantGaussianSafeDivision() 180 | ); 181 | } 182 | 183 | [TestMethod] 184 | public void SimpleGaussianGWInt() 185 | { 186 | var M = GenTensor>.CreateMatrix(new int[,] 187 | { 188 | {6, 1, 1}, 189 | {4, -2, 5}, 190 | {2, 8, 7} 191 | }); 192 | Assert.AreEqual(-306, M.DeterminantGaussianSafeDivision()); 193 | } 194 | 195 | [TestMethod] 196 | public void SimpleGaussianGWFloat() 197 | { 198 | var M = GenTensor>.CreateMatrix(new float[,] 199 | { 200 | {6, 1, 1}, 201 | {4, -2, 5}, 202 | {2, 8, 7} 203 | }); 204 | Assert.AreEqual(-306, M.DeterminantGaussianSimple()); 205 | } 206 | 207 | [TestMethod] 208 | public void SimpleGaussianGWDouble() 209 | { 210 | var M = GenTensor>.CreateMatrix(new double[,] 211 | { 212 | {6, 1, 1}, 213 | {4, -2, 5}, 214 | {2, 8, 7} 215 | }); 216 | Assert.AreEqual(-306, M.DeterminantGaussianSimple()); 217 | } 218 | 219 | [TestMethod] 220 | public void SimpleGaussianGWComplex() 221 | { 222 | var M = GenTensor>.CreateMatrix(new Complex[,] 223 | { 224 | {6, 1, 1}, 225 | {4, -2, 5}, 226 | {2, 8, 7} 227 | }); 228 | Assert.AreEqual(-306, M.DeterminantGaussianSimple()); 229 | } 230 | 231 | [TestMethod] 232 | public void TestDeterminantOfOneMatrix1() 233 | { 234 | var m = GenTensor.CreateMatrix(new[,]{{3d}}); 235 | Assert.AreEqual(3d, m.DeterminantGaussianSafeDivision()); 236 | } 237 | 238 | [TestMethod] 239 | public void TestDeterminantOfOneMatrix2() 240 | { 241 | var m = GenTensor.CreateMatrix(new[,]{{3d}}); 242 | Assert.AreEqual(3d, m.DeterminantGaussianSimple()); 243 | } 244 | } 245 | } 246 | -------------------------------------------------------------------------------- /UnitTests/ElementaryRowOperations.cs: -------------------------------------------------------------------------------- 1 | #region copyright 2 | /* 3 | * MIT License 4 | * 5 | * Copyright (c) 2020-2021 WhiteBlackGoose 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | #endregion 26 | 27 | 28 | using GenericTensor.Core; 29 | using GenericTensor.Functions; 30 | using Microsoft.VisualStudio.TestTools.UnitTesting; 31 | 32 | namespace UnitTests 33 | { 34 | [TestClass] 35 | public class ElementaryRowOperations 36 | { 37 | [TestMethod] 38 | public void RowMultiply1() 39 | { 40 | var m = GenTensor.CreateMatrix( 41 | new[,] 42 | { 43 | { 1, 2 }, 44 | { 4, 5 }, 45 | { 4, 8 }, 46 | } 47 | ); 48 | m.RowMultiply(1, 10); 49 | var exp = GenTensor.CreateMatrix( 50 | new[,] 51 | { 52 | { 1, 2 }, 53 | { 4 * 10, 5 * 10 }, 54 | { 4, 8 }, 55 | } 56 | ); 57 | Assert.AreEqual(exp, m); 58 | } 59 | 60 | [TestMethod] 61 | public void RowMultiply2() 62 | { 63 | var m = GenTensor.CreateMatrix( 64 | new[,] 65 | { 66 | { 1, 2 }, 67 | { 4, 5 }, 68 | { 4, 8 }, 69 | } 70 | ); 71 | m.RowMultiply(1, 10); 72 | m.RowMultiply(2, 0); 73 | var exp = GenTensor.CreateMatrix( 74 | new[,] 75 | { 76 | { 1, 2 }, 77 | { 4 * 10, 5 * 10 }, 78 | { 0, 0 }, 79 | } 80 | ); 81 | Assert.AreEqual(exp, m); 82 | } 83 | 84 | [TestMethod] 85 | public void RowAdd1() 86 | { 87 | var m = GenTensor.CreateMatrix( 88 | new[,] 89 | { 90 | { 1, 2 }, 91 | { 4, 5 }, 92 | { 4, 8 }, 93 | } 94 | ); 95 | m.RowAdd(0, 1, 1); 96 | var exp = GenTensor.CreateMatrix( 97 | new[,] 98 | { 99 | { 1 + 4, 2 + 5 }, 100 | { 4, 5 }, 101 | { 4, 8 }, 102 | } 103 | ); 104 | Assert.AreEqual(exp, m); 105 | } 106 | 107 | [TestMethod] 108 | public void RowAdd2() 109 | { 110 | var m = GenTensor.CreateMatrix( 111 | new[,] 112 | { 113 | { 1, 2 }, 114 | { 4, 5 }, 115 | { 4, 8 }, 116 | } 117 | ); 118 | m.RowAdd(0, 1, 10); 119 | var exp = GenTensor.CreateMatrix( 120 | new[,] 121 | { 122 | { 1 + 4 * 10, 2 + 5 * 10 }, 123 | { 4, 5 }, 124 | { 4, 8 }, 125 | } 126 | ); 127 | Assert.AreEqual(exp, m); 128 | } 129 | 130 | [TestMethod] 131 | public void RowAdd3() 132 | { 133 | var m = GenTensor.CreateMatrix( 134 | new[,] 135 | { 136 | { 1, 2 }, 137 | { 4, 5 }, 138 | { 4, 8 }, 139 | } 140 | ); 141 | m.RowAdd(0, 1, 10); 142 | m.RowAdd(2, 1, 3); 143 | var exp = GenTensor.CreateMatrix( 144 | new[,] 145 | { 146 | { 1 + 4 * 10, 2 + 5 * 10 }, 147 | { 4, 5 }, 148 | { 4 + 4 * 3, 8 + 5 * 3 }, 149 | } 150 | ); 151 | Assert.AreEqual(exp, m); 152 | } 153 | 154 | [TestMethod] 155 | public void RowSubtract1() 156 | { 157 | var m = GenTensor.CreateMatrix( 158 | new[,] 159 | { 160 | { 1, 2 }, 161 | { 4, 5 }, 162 | { 4, 8 }, 163 | } 164 | ); 165 | m.RowSubtract(0, 1, 1); 166 | var exp = GenTensor.CreateMatrix( 167 | new[,] 168 | { 169 | { 1 - 4, 2 - 5 }, 170 | { 4, 5 }, 171 | { 4, 8 }, 172 | } 173 | ); 174 | Assert.AreEqual(exp, m); 175 | } 176 | 177 | [TestMethod] 178 | public void RowSwap1() 179 | { 180 | var m = GenTensor.CreateMatrix( 181 | new[,] 182 | { 183 | { 1, 2 }, 184 | { 4, 5 }, 185 | { 4, 8 }, 186 | } 187 | ); 188 | m.RowSwap(0, 1); 189 | var exp = GenTensor.CreateMatrix( 190 | new[,] 191 | { 192 | { 4, 5 }, 193 | { 1, 2 }, 194 | { 4, 8 }, 195 | } 196 | ); 197 | Assert.AreEqual(exp, m); 198 | } 199 | 200 | [TestMethod] 201 | public void RowSwap2() 202 | { 203 | var m = GenTensor.CreateMatrix( 204 | new[,] 205 | { 206 | { 1, 2 }, 207 | { 4, 5 }, 208 | { 4, 8 }, 209 | } 210 | ); 211 | m.RowSwap(0, 1); 212 | m.RowSwap(0, 1); 213 | m.RowSwap(2, 1); 214 | m.RowSwap(2, 1); 215 | var exp = GenTensor.CreateMatrix( 216 | new[,] 217 | { 218 | { 1, 2 }, 219 | { 4, 5 }, 220 | { 4, 8 }, 221 | } 222 | ); 223 | Assert.AreEqual(exp, m); 224 | } 225 | } 226 | } 227 | -------------------------------------------------------------------------------- /UnitTests/ForEach.cs: -------------------------------------------------------------------------------- 1 | using GenericTensor.Core; 2 | using GenericTensor.Functions; 3 | using Microsoft.VisualStudio.TestTools.UnitTesting; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using HonkPerf.NET.Core; 10 | 11 | namespace UnitTests 12 | { 13 | [TestClass] 14 | public class ForEach 15 | { 16 | [TestMethod] 17 | public void Test1D() 18 | { 19 | var tensor = GenTensor.CreateTensor(new [] { 1, 2, 3 }); 20 | tensor.ForEach(new CapturingValueAction>((index, value, t) => t[index] = value * value, tensor)); 21 | var expected = GenTensor.CreateTensor(new[] { 1, 4, 9 }); 22 | Assert.AreEqual(expected, tensor); 23 | } 24 | 25 | [TestMethod] 26 | public void Test2D() 27 | { 28 | var tensor = GenTensor.CreateTensor(new[,] { { 1, 2 }, { 3, 4 } }); 29 | tensor.ForEach(new CapturingValueAction>((index, value, t) => t[index] = value * value, tensor)); 30 | var expected = GenTensor.CreateTensor(new[,] { { 1, 4 }, { 9, 16 } }); 31 | Assert.AreEqual(expected, tensor); 32 | } 33 | 34 | [TestMethod] 35 | public void Test3D() 36 | { 37 | var tensor = GenTensor.CreateTensor(new[,,] { { { 1, 2, 3 }, { 4, 5, 6 } }, { { 7, 8, 9 }, { 10, 11, 12 } } }); 38 | tensor.ForEach(new CapturingValueAction>((index, value, t) => t[index] = value * value, tensor)); 39 | var expected = GenTensor.CreateTensor(new[,,] { { { 1, 4, 9 }, { 16, 25, 36 } }, { { 49, 64, 81 }, { 100, 121, 144 } } }); 40 | Assert.AreEqual(expected, tensor); 41 | } 42 | 43 | [TestMethod] 44 | public void Test4D() 45 | { 46 | var tensor = GenTensor.CreateTensor(new[,,,] { 47 | { { { 1, 2, 3 }, { 4, 5, 6 } }, { { 7, 8, 9 }, { 10, 11, 12 } } }, 48 | { { { 13, 14, 15 }, { 16, 17, 18 } }, { { 19, 20, 21 }, { 22, 23, 24 } } }, 49 | }); 50 | tensor.ForEach(new CapturingValueAction>((index, value, t) => t[index] = value * value, tensor)); 51 | var expected = GenTensor.CreateTensor(new[, , ,] { 52 | { { { 1, 4, 9 }, { 16, 25, 36 } }, { { 49, 64, 81 }, { 100, 121, 144 } } }, 53 | { { { 169, 196, 225 }, { 256, 289, 324 } }, { { 361, 400, 441 }, { 484, 529, 576 } } }, 54 | }); 55 | Assert.AreEqual(expected, tensor); 56 | } 57 | 58 | [TestMethod] 59 | public void Test5D() 60 | { 61 | var tensor = GenTensor.CreateTensor(new[,,,,] { 62 | { 63 | { { { 1, 2, 3 }, { 4, 5, 6 } }, { { 7, 8, 9 }, { 10, 11, 12 } } }, 64 | { { { 13, 14, 15 }, { 16, 17, 18 } }, { { 19, 20, 21 }, { 22, 23, 24 } } }, 65 | }, 66 | { 67 | { { { 10, 20, 30 }, { 40, 50, 60 } }, { { 70, 80, 90 }, { 100, 110, 120 } } }, 68 | { { { 130, 140, 150 }, { 160, 170, 180 } }, { { 190, 200, 210 }, { 220, 230, 240 } } }, 69 | } 70 | }); 71 | tensor.ForEach(new CapturingValueAction>((index, value, t) => t[index] = value * value, tensor)); 72 | var expected = GenTensor.CreateTensor(new[,,,,] { 73 | { 74 | { { { 1, 4, 9 }, { 16, 25, 36 } }, { { 49, 64, 81 }, { 100, 121, 144 } } }, 75 | { { { 169, 196, 225 }, { 256, 289, 324 } }, { { 361, 400, 441 }, { 484, 529, 576 } } }, 76 | }, 77 | { 78 | { { { 100, 400, 900 }, { 1600, 2500, 3600 } }, { { 4900, 6400, 8100 }, { 10000, 12100, 14400 } } }, 79 | { { { 16900, 19600, 22500 }, { 25600, 28900, 32400 } }, { { 36100, 40000, 44100 }, { 48400, 52900, 57600 } } }, 80 | }, 81 | }); 82 | Assert.AreEqual(expected, tensor); 83 | } 84 | } 85 | } -------------------------------------------------------------------------------- /UnitTests/GetMatrixFactoryTest.cs: -------------------------------------------------------------------------------- 1 | using GenericTensor.Core; 2 | using GenericTensor.Functions; 3 | using Microsoft.VisualStudio.TestTools.UnitTesting; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | 10 | namespace UnitTests 11 | { 12 | [TestClass] 13 | public class GetMatrixFactoryTest 14 | { 15 | private static Func> GetMatrix = GetMatrixFactoryHelper.Get(); 16 | 17 | [DataTestMethod] 18 | [DataRow(5)] 19 | [DataRow(3)] 20 | [DataRow(1)] 21 | [DataRow(2)] 22 | [DataRow(4)] 23 | public void TestMatrix(int diagLength) 24 | { 25 | Assert.AreEqual(new TensorShape(diagLength, diagLength), GetMatrix(diagLength).Shape); 26 | Assert.AreEqual(new TensorShape(diagLength, diagLength), GetMatrix(diagLength).Shape); 27 | } 28 | } 29 | 30 | static class GetMatrixFactoryHelper 31 | { 32 | internal static Func> Get() 33 | { 34 | var assem = typeof(GenTensor<,>).Assembly; 35 | var type = assem.GetType("GenericTensor.Core.TestSquareMatrixFactoryExposed"); 36 | var method = type.GetMethod("TestGetMatrixExposed", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic); 37 | return (d => (GenTensor)method.Invoke(null, new object[]{ d })); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /UnitTests/Identity.cs: -------------------------------------------------------------------------------- 1 | #region copyright 2 | /* 3 | * MIT License 4 | * 5 | * Copyright (c) 2020-2021 WhiteBlackGoose 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | #endregion 26 | 27 | 28 | using GenericTensor.Core; 29 | using GenericTensor.Functions; 30 | using Microsoft.VisualStudio.TestTools.UnitTesting; 31 | 32 | namespace UnitTests 33 | { 34 | using TS = GenTensor; 35 | [TestClass] 36 | public class Identity 37 | { 38 | [TestMethod] 39 | public void IdenMatrix1() 40 | { 41 | Assert.AreEqual(TS.CreateIdentityMatrix(1), TS.CreateMatrix(new int[,]{{1}})); 42 | } 43 | 44 | [TestMethod] 45 | public void IdenMatrix2() 46 | { 47 | Assert.AreEqual(TS.CreateIdentityMatrix(3), TS.CreateMatrix(new int[,] 48 | { 49 | {1, 0, 0}, 50 | {0, 1, 0}, 51 | {0, 0, 1} 52 | })); 53 | } 54 | 55 | [TestMethod] 56 | public void IdenTensor() 57 | { 58 | var t = TS.CreateIdentityTensor(new []{4, 5}, 8); 59 | var k = t.Copy(false); 60 | k.TransposeMatrix(); 61 | Assert.AreEqual(t, k); 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /UnitTests/LuDecompositions.cs: -------------------------------------------------------------------------------- 1 | #region copyright 2 | 3 | /* 4 | * MIT License 5 | * 6 | * Copyright (c) 2020-2021 WhiteBlackGoose 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in all 16 | * copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | * SOFTWARE. 25 | */ 26 | 27 | #endregion 28 | 29 | using System; 30 | using GenericTensor.Core; 31 | using GenericTensor.Functions; 32 | using Microsoft.VisualStudio.TestTools.UnitTesting; 33 | 34 | namespace UnitTests 35 | { 36 | [TestClass] 37 | public class LuDecompositions 38 | { 39 | private void AssertMatrixIsLowerTriangular(GenTensor t) where TW : struct, IOperations 40 | { 41 | Assert.IsTrue(t.IsSquareMatrix); 42 | t.IterateOver2((i, j) => 43 | { 44 | if (i < j) Assert.AreEqual(t[i, j], default(TW).CreateZero()); 45 | }); 46 | } 47 | 48 | private void AssertMatrixIsUpperTriangular(GenTensor t) where TW : struct, IOperations 49 | { 50 | Assert.IsTrue(t.IsSquareMatrix); 51 | t.IterateOver2((i, j) => 52 | { 53 | if (i > j) Assert.AreEqual(t[i, j], default(TW).CreateZero()); 54 | }); 55 | } 56 | 57 | private void TestProvidedLu(T[,] data) where TW : struct, IOperations 58 | { 59 | var m = GenTensor.CreateMatrix(data); 60 | var (lower, upper) = m.LuDecomposition(); 61 | 62 | AssertMatrixIsLowerTriangular(lower); 63 | AssertMatrixIsUpperTriangular(upper); 64 | 65 | Assert.AreEqual(GenTensor.MatrixMultiply(lower, upper), m); 66 | } 67 | 68 | private void TestProvidedPlu(T[,] data) where TW : struct, IOperations 69 | { 70 | var m = GenTensor.CreateMatrix(data); 71 | var (p, l, u) = m.PluDecomposition(); 72 | 73 | AssertMatrixIsLowerTriangular(l); 74 | AssertMatrixIsUpperTriangular(u); 75 | 76 | Assert.AreEqual(GenTensor.MatrixMultiply(p, m), GenTensor.MatrixMultiply(l, u)); 77 | } 78 | 79 | private static void TestNoLu(T[,] data) where TW : struct, IOperations => 80 | Assert.ThrowsException(() => 81 | GenTensor.CreateMatrix(data).LuDecomposition()); 82 | 83 | [TestMethod] 84 | public void LuArbitrary_1() => 85 | TestProvidedLu(new[,] 86 | { 87 | { 1, 2, 4 }, 88 | { 3, 8, 14 }, 89 | { 2, 6, 13 }, 90 | }); 91 | 92 | [TestMethod] 93 | public void LuArbitrary_2() => 94 | TestProvidedLu(new[,] 95 | { 96 | { -6, -4 }, 97 | { -6, -4 } 98 | }); 99 | 100 | [TestMethod] 101 | public void LuArbitrary_3() => 102 | TestNoLu(new[,] 103 | { 104 | { 0, 0, 0 }, 105 | { 0, 0, 0 }, 106 | { 0, 0, 0 } 107 | }); 108 | 109 | [TestMethod] 110 | public void PluArbitrary_1() => 111 | TestProvidedPlu(new[,] 112 | { 113 | { 1, 2, 4 }, 114 | { 3, 8, 14 }, 115 | { 2, 6, 13 } 116 | }); 117 | 118 | [TestMethod] 119 | public void PluArbitrary_2() => 120 | TestProvidedPlu(new[,] 121 | { 122 | { 0D, 1, 0 }, 123 | { -8, 8, 1 }, 124 | { 2, -2, 0 } 125 | }); 126 | 127 | [TestMethod] 128 | public void PluArbitrary_3() => 129 | TestProvidedPlu(new[,] 130 | { 131 | {1, 0, 4}, 132 | {0, 0, 1}, 133 | {3, 2, 13} 134 | }); 135 | } 136 | } -------------------------------------------------------------------------------- /UnitTests/MatrixProduct.cs: -------------------------------------------------------------------------------- 1 | #region copyright 2 | /* 3 | * MIT License 4 | * 5 | * Copyright (c) 2020-2021 WhiteBlackGoose 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | #endregion 26 | 27 | 28 | using GenericTensor.Core; 29 | using GenericTensor.Functions; 30 | using Microsoft.VisualStudio.TestTools.UnitTesting; 31 | 32 | namespace UnitTests 33 | { 34 | [TestClass] 35 | public class MatrixProduct 36 | { 37 | public MatrixProduct() 38 | { 39 | 40 | } 41 | 42 | [TestMethod] 43 | public void MatrixDotProduct1() 44 | { 45 | var A = GenTensor.CreateMatrix( 46 | new [,] 47 | { 48 | { 12, -1, 1 }, 49 | { 0, 1, 4 }, 50 | }); 51 | var B = GenTensor.CreateMatrix( 52 | new [,] 53 | { 54 | { 1, -1 }, 55 | { 0, 1 }, 56 | { 3, 0 }, 57 | { 0, 3 }, 58 | }); 59 | 60 | A.TransposeMatrix(); 61 | B.TransposeMatrix(); 62 | Assert.AreEqual(GenTensor.MatrixMultiply(A, B), GenTensor.CreateMatrix( 63 | new [,] 64 | { 65 | { 12, 0, 36, 0 }, 66 | { -2, 1, -3, 3 }, 67 | {-3, 4, 3, 12} 68 | } 69 | )); 70 | } 71 | 72 | [TestMethod] 73 | public void MatrixTensorMp() 74 | { 75 | var a = GenTensor.CreateMatrix( 76 | new [,] 77 | { 78 | { 1, 2 }, 79 | { 3, 4 } 80 | } 81 | ); 82 | var b = GenTensor.CreateMatrix( 83 | new [,] 84 | { 85 | { 5, 7 }, 86 | { 6, 8 } 87 | } 88 | ); 89 | var T1 = GenTensor.Stack(a, b); 90 | 91 | var c = GenTensor.CreateMatrix( 92 | new [,] 93 | { 94 | { -3, 2 }, 95 | { 3, 5 } 96 | } 97 | ); 98 | 99 | var d = GenTensor.CreateMatrix( 100 | new [,] 101 | { 102 | { -3, 2 }, 103 | { 23, 5 } 104 | } 105 | ); 106 | 107 | var T2 = GenTensor.Stack(c, d); 108 | 109 | var exp1 = GenTensor.CreateMatrix( 110 | new [,] 111 | { 112 | { 3, 12 }, 113 | { 3, 26 } 114 | } 115 | ); 116 | 117 | var exp2 = GenTensor.CreateMatrix( 118 | new [,] 119 | { 120 | { 146, 45 }, 121 | { 166, 52 } 122 | } 123 | ); 124 | 125 | var exp = GenTensor.Stack(exp1, exp2); 126 | 127 | Assert.AreEqual(exp, GenTensor.TensorMatrixMultiply(T1, T2)); 128 | } 129 | 130 | [TestMethod] 131 | public void MatrixDotProduct1Par() 132 | { 133 | var A = GenTensor.CreateMatrix( 134 | new [,] 135 | { 136 | { 12, -1, 1 }, 137 | { 0, 1, 4 }, 138 | }); 139 | var B = GenTensor.CreateMatrix( 140 | new [,] 141 | { 142 | { 1, -1 }, 143 | { 0, 1 }, 144 | { 3, 0 }, 145 | { 0, 3 }, 146 | }); 147 | 148 | A.TransposeMatrix(); 149 | B.TransposeMatrix(); 150 | Assert.AreEqual(GenTensor.MatrixMultiply(A, B, Threading.Multi), GenTensor.CreateMatrix( 151 | new [,] 152 | { 153 | { 12, 0, 36, 0 }, 154 | { -2, 1, -3, 3 }, 155 | {-3, 4, 3, 12} 156 | } 157 | )); 158 | } 159 | 160 | [TestMethod] 161 | public void MatrixTensorMpPar() 162 | { 163 | var a = GenTensor.CreateMatrix( 164 | new [,] 165 | { 166 | { 1, 2 }, 167 | { 3, 4 } 168 | } 169 | ); 170 | var b = GenTensor.CreateMatrix( 171 | new [,] 172 | { 173 | { 5, 7 }, 174 | { 6, 8 } 175 | } 176 | ); 177 | var T1 = GenTensor.Stack(a, b); 178 | 179 | var c = GenTensor.CreateMatrix( 180 | new [,] 181 | { 182 | { -3, 2 }, 183 | { 3, 5 } 184 | } 185 | ); 186 | 187 | var d = GenTensor.CreateMatrix( 188 | new [,] 189 | { 190 | { -3, 2 }, 191 | { 23, 5 } 192 | } 193 | ); 194 | 195 | var T2 = GenTensor.Stack(c, d); 196 | 197 | var exp1 = GenTensor.CreateMatrix( 198 | new [,] 199 | { 200 | { 3, 12 }, 201 | { 3, 26 } 202 | } 203 | ); 204 | 205 | var exp2 = GenTensor.CreateMatrix( 206 | new [,] 207 | { 208 | { 146, 45 }, 209 | { 166, 52 } 210 | } 211 | ); 212 | 213 | var exp = GenTensor.Stack(exp1, exp2); 214 | 215 | Assert.AreEqual(exp, GenTensor.TensorMatrixMultiply(T1, T2, Threading.Multi)); 216 | } 217 | } 218 | } 219 | -------------------------------------------------------------------------------- /UnitTests/Power.cs: -------------------------------------------------------------------------------- 1 | #region copyright 2 | /* 3 | * MIT License 4 | * 5 | * Copyright (c) 2020-2021 WhiteBlackGoose 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | #endregion 26 | 27 | 28 | using GenericTensor.Core; 29 | using GenericTensor.Functions; 30 | using Microsoft.VisualStudio.TestTools.UnitTesting; 31 | 32 | namespace UnitTests 33 | { 34 | using TS = GenTensor; 35 | 36 | [TestClass] 37 | public class Power 38 | { 39 | 40 | [TestMethod] 41 | public void Test1() 42 | { 43 | var M = GenTensor.CreateMatrix(new float[,] 44 | { 45 | {6, 1, 1}, 46 | {4, -2, 5}, 47 | {2, 8, 7} 48 | }); 49 | var powered = M.MatrixPower(4); 50 | var I = GenTensor.CreateIdentityMatrix(3); 51 | for (int i = 0; i < 4; i++) 52 | I = GenTensor.MatrixMultiply(I, M); 53 | 54 | Assert.AreEqual(I, powered); 55 | } 56 | 57 | [TestMethod] 58 | public void Test2() 59 | { 60 | var M = GenTensor.CreateMatrix(new float[,] 61 | { 62 | {6, 1, 1}, 63 | {4, -2, 5}, 64 | {2, 8, 7} 65 | }); 66 | var powered = M.MatrixPower(3); 67 | var I = GenTensor.CreateIdentityMatrix(3); 68 | for (int i = 0; i < 3; i++) 69 | I = GenTensor.MatrixMultiply(I, M); 70 | 71 | Assert.AreEqual(I, powered); 72 | } 73 | 74 | [TestMethod] 75 | public void Test3() 76 | { 77 | var M = GenTensor.CreateMatrix(new float[,] 78 | { 79 | {6, 1, 1}, 80 | {4, -2, 5}, 81 | {2, 8, 7} 82 | }); 83 | var powered = M.MatrixPower(-4); 84 | M = M.Forward(); 85 | M.InvertMatrix(); 86 | var I = GenTensor.CreateIdentityMatrix(3); 87 | for (int i = 0; i < 4; i++) 88 | I = GenTensor.MatrixMultiply(I, M); 89 | 90 | Assert.AreEqual(I, powered); 91 | } 92 | 93 | [TestMethod] 94 | public void Test4Tensor() 95 | { 96 | var power = 3; 97 | 98 | var M1 = GenTensor.CreateMatrix(new float[,] 99 | { 100 | {6, 1, 1}, 101 | {4, -2, 5}, 102 | {2, 8, 7} 103 | }); 104 | var M2 = GenTensor.CreateMatrix(new float[,] 105 | { 106 | {1, 2, 9}, 107 | {2, 3, 5}, 108 | {3, 8, 5} 109 | }); 110 | 111 | Assert.AreEqual( 112 | GenTensor.Stack( 113 | M1.MatrixPower(power), 114 | M2.MatrixPower(power)), 115 | GenTensor.Stack(M1, M2).TensorMatrixPower(power) 116 | ); 117 | } 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /UnitTests/ReferenceWrapperTest.cs: -------------------------------------------------------------------------------- 1 | using GenericTensor.Core; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Text; 6 | 7 | namespace UnitTests 8 | { 9 | internal sealed class MyDouble 10 | { 11 | public double Value { get; } 12 | public MyDouble(double v) => Value = v; 13 | public override string ToString() => Value.ToString(); 14 | public override bool Equals(object obj) 15 | => obj is MyDouble { Value: var val } && val == Value; 16 | } 17 | 18 | internal struct MyDoubleWrapper : IOperations 19 | { 20 | public MyDouble Add(MyDouble a, MyDouble b) => new(a.Value + b.Value); 21 | public MyDouble Subtract(MyDouble a, MyDouble b) => new(a.Value - b.Value); 22 | public MyDouble Multiply(MyDouble a, MyDouble b) => new(a.Value * b.Value); 23 | public MyDouble Negate(MyDouble a) => new(-a.Value); 24 | public MyDouble Divide(MyDouble a, MyDouble b) => new(a.Value / b.Value); 25 | public MyDouble CreateOne() => new(1); 26 | public MyDouble CreateZero() => new(0); 27 | public MyDouble Copy(MyDouble a) => a; 28 | public bool AreEqual(MyDouble a, MyDouble b) => a.Value == b.Value; 29 | public bool IsZero(MyDouble a) => a.Value == 0; 30 | public string ToString(MyDouble a) => a.Value.ToString(); 31 | public byte[] Serialize(MyDouble a) => throw new(); 32 | public MyDouble Deserialize(byte[] data) => throw new(); 33 | } 34 | 35 | [TestClass] 36 | public class ReferenceWrapperTest 37 | { 38 | [TestMethod] 39 | public void TestValidDetOfDefaultMatrix() 40 | { 41 | var m = GenTensor.CreateMatrix(new MyDouble[,] 42 | { 43 | { new(1), new(0) }, 44 | { new(0), new(1) } 45 | }); 46 | var adj = m.Adjoint(); 47 | Assert.AreEqual(m, adj); 48 | m.InvertMatrix(); 49 | Assert.AreEqual(m, adj); 50 | Assert.AreEqual(new(1), m.DeterminantGaussianSafeDivision()); 51 | Assert.AreEqual(new(1), m.DeterminantGaussianSimple()); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /UnitTests/Serialization.cs: -------------------------------------------------------------------------------- 1 | #region copyright 2 | /* 3 | * MIT License 4 | * 5 | * Copyright (c) 2020-2021 WhiteBlackGoose 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | #endregion 26 | 27 | 28 | using System; 29 | using System.Numerics; 30 | using GenericTensor.Core; 31 | using GenericTensor.Functions; 32 | using Microsoft.VisualStudio.TestTools.UnitTesting; 33 | 34 | namespace UnitTests 35 | { 36 | [TestClass] 37 | public class Serialization 38 | { 39 | public void CircleTest(GenTensor tensor) 40 | where TWrapper : struct, IOperations 41 | { 42 | var serialized = tensor.Serialize(); 43 | var deserialized = GenTensor.Deserialize(serialized); 44 | Assert.AreEqual(tensor, deserialized); 45 | } 46 | 47 | [TestMethod] 48 | public void TestVecInt() 49 | => CircleTest(GenTensor.CreateVector(3, 4, 5)); 50 | 51 | [TestMethod] 52 | public void TestVecFloat() 53 | => CircleTest(GenTensor.CreateVector(3.5f, 4, -5.1f, 6.4f)); 54 | 55 | [TestMethod] 56 | public void TestVecDouble() 57 | => CircleTest(GenTensor.CreateVector(3.5d, 4, -5.1d, 6.4d)); 58 | 59 | [TestMethod] 60 | public void TestMatrixInt() 61 | => CircleTest(GenTensor.CreateMatrix( 62 | new[,] 63 | { 64 | {1, 2, 3}, 65 | {4, 5, 6} 66 | })); 67 | 68 | [TestMethod] 69 | public void TestMatrixFloat() 70 | => CircleTest(GenTensor.CreateMatrix( 71 | new[,] 72 | { 73 | {1f, 2f, 3.3f}, 74 | {4, 5.5f, 6.6f} 75 | })); 76 | 77 | [TestMethod] 78 | public void TestMatrixDouble() 79 | => CircleTest(GenTensor.CreateMatrix( 80 | new[,] 81 | { 82 | {1d, 2d, 3.3d}, 83 | {4, 5.5d, 6.6d} 84 | })); 85 | 86 | [TestMethod] 87 | public void TestTensorInt() 88 | => CircleTest(GenTensor.CreateTensor( 89 | new[,,] 90 | { 91 | { 92 | {1, 3, 3}, 93 | {4, 5, 6} 94 | }, 95 | { 96 | {-4, 2, 3}, 97 | {7, 8, 11} 98 | } 99 | } 100 | )); 101 | 102 | [TestMethod] 103 | public void TestTensorFloat() 104 | => CircleTest(GenTensor.CreateTensor( 105 | new[, ,] 106 | { 107 | { 108 | {1.1f, 3f, 3f}, 109 | {4f, 5.5f, 6f} 110 | }, 111 | { 112 | {-4f, 2.5f, 3f}, 113 | {7f, 8f, 11.4f} 114 | } 115 | } 116 | )); 117 | 118 | [TestMethod] 119 | public void TestTensorDouble() 120 | => CircleTest(GenTensor.CreateTensor( 121 | new[, ,] 122 | { 123 | { 124 | {1.1d, 3d, 3d}, 125 | {4d, 5.5d, 6d} 126 | }, 127 | { 128 | {-4d, 2.5d, 3d}, 129 | {7d, 8d, 11.4d} 130 | } 131 | } 132 | )); 133 | 134 | [TestMethod] 135 | public void TestTensorGWInt() 136 | => CircleTest(GenTensor>.CreateTensor( 137 | new[, ,] 138 | { 139 | { 140 | {1, 3, 3}, 141 | {4, 5, 6} 142 | }, 143 | { 144 | {-4, 2, 3}, 145 | {7, 8, 11} 146 | } 147 | } 148 | )); 149 | 150 | [TestMethod] 151 | public void TestTensorGWFloat() 152 | => CircleTest(GenTensor>.CreateTensor( 153 | new[, ,] 154 | { 155 | { 156 | {1f, 3f, 3f}, 157 | {4f, 5f, 6f} 158 | }, 159 | { 160 | {-4f, 2f, 3f}, 161 | { 7f, 8f, 11f} 162 | } 163 | } 164 | )); 165 | 166 | [TestMethod] 167 | public void TestTensorGWDouble() 168 | => CircleTest(GenTensor>.CreateTensor( 169 | new[, ,] 170 | { 171 | { 172 | {1d, 3d, 3d}, 173 | {4d, 5d, 6d} 174 | }, 175 | { 176 | {-4d, 2d, 3d}, 177 | { 7d, 8d, 11d} 178 | } 179 | } 180 | )); 181 | 182 | [TestMethod] 183 | public void TestTensorGWComplex() 184 | => CircleTest(GenTensor>.CreateTensor( 185 | new[, ,] 186 | { 187 | { 188 | {new Complex(1, 0), new Complex(3, 0), new Complex(3, 0)}, 189 | {new Complex(4, 0), new Complex(5, 0), new Complex(6, 0)} 190 | }, 191 | { 192 | {new Complex(-4, 0), new Complex(2, 0), new Complex(3, 0)}, 193 | {new Complex(7, 0), new Complex(8, 0), new Complex(11, 0)} 194 | } 195 | } 196 | )); 197 | 198 | [TestMethod] 199 | public void TestTensorGWByte() 200 | { 201 | Assert.ThrowsException(() => 202 | CircleTest(GenTensor>.CreateTensor( 203 | new[, ,] 204 | { 205 | { 206 | {(byte)1, (byte)3, (byte)3}, 207 | {(byte)4, (byte)5, (byte)6} 208 | }, 209 | { 210 | {(byte)4, (byte)2, (byte)3}, 211 | {(byte)7, (byte)8, (byte)11} 212 | } 213 | } 214 | ))); 215 | } 216 | 217 | [TestMethod] 218 | public void TestTensorComplex() 219 | => CircleTest(GenTensor.CreateTensor( 220 | new[, ,] 221 | { 222 | { 223 | {new Complex(4, 6), 3d, 3d}, 224 | {4d, 5.5d, new Complex(-1, 5)} 225 | }, 226 | { 227 | {-4d, new Complex(5, 6), 3d}, 228 | {7d, 8d, new Complex(4, 5.4d)} 229 | } 230 | } 231 | )); 232 | } 233 | } 234 | -------------------------------------------------------------------------------- /UnitTests/SetGet.cs: -------------------------------------------------------------------------------- 1 | #region copyright 2 | /* 3 | * MIT License 4 | * 5 | * Copyright (c) 2020-2021 WhiteBlackGoose 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | #endregion 26 | 27 | 28 | using System; 29 | using GenericTensor.Core; 30 | using GenericTensor.Functions; 31 | using Microsoft.VisualStudio.TestTools.UnitTesting; 32 | 33 | namespace UnitTests 34 | { 35 | [TestClass] 36 | public class GetSet 37 | { 38 | public GetSet() 39 | { 40 | 41 | } 42 | 43 | private GenTensor GetT() => new GenTensor(2, 3, 4); 44 | 45 | [TestMethod] 46 | public void SetGet1() 47 | { 48 | var tensor = GetT(); 49 | for (int i = 0; i < tensor.Shape[0]; i++) 50 | for (int j = 0; j < tensor.Shape[1]; j++) 51 | for (int k = 0; k < tensor.Shape[2]; k++) 52 | { 53 | tensor[i, j, k] = i + j + k; 54 | } 55 | 56 | for (int i = 0; i < tensor.Shape[0]; i++) 57 | for (int j = 0; j < tensor.Shape[1]; j++) 58 | for (int k = 0; k < tensor.Shape[2]; k++) 59 | { 60 | Assert.AreEqual(tensor[i, j, k], i + j + k); 61 | } 62 | } 63 | 64 | [TestMethod] 65 | public void Violate1() 66 | { 67 | var tensor = GetT(); 68 | Assert.ThrowsException(() => tensor[tensor.Shape[0], 0, 0]); 69 | } 70 | 71 | [TestMethod] 72 | public void Violate2() 73 | { 74 | var tensor = GetT(); 75 | Assert.ThrowsException(() => tensor[0, 0, -1]); 76 | } 77 | 78 | [TestMethod] 79 | public void Violate3() 80 | { 81 | var tensor = GetT(); 82 | Assert.ThrowsException(() => tensor[tensor.Shape[0] + 100, 0, 0]); 83 | } 84 | 85 | [TestMethod] 86 | public void Violate4() 87 | { 88 | var tensor = GetT(); 89 | Assert.ThrowsException(() => tensor[tensor.Shape[0], -1, -1]); 90 | } 91 | 92 | [TestMethod] 93 | public void ViolateArg1() 94 | { 95 | var tensor = GetT(); 96 | Assert.ThrowsException(() => tensor[1]); 97 | } 98 | 99 | [TestMethod] 100 | public void ViolateArg2() 101 | { 102 | var tensor = GetT(); 103 | Assert.ThrowsException(() => tensor[1, 2]); 104 | } 105 | 106 | [TestMethod] 107 | public void ViolateArg3() 108 | { 109 | var tensor = GetT(); 110 | Assert.ThrowsException(() => tensor[0, 0]); 111 | } 112 | 113 | [TestMethod] 114 | public void ViolateArg4() 115 | { 116 | var tensor = GetT(); 117 | Assert.ThrowsException(() => tensor[1, 4, 5, 6, 7]); 118 | } 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /UnitTests/Slicing.cs: -------------------------------------------------------------------------------- 1 | #region copyright 2 | /* 3 | * MIT License 4 | * 5 | * Copyright (c) 2020-2021 WhiteBlackGoose 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | #endregion 26 | 27 | 28 | using GenericTensor.Core; 29 | using GenericTensor.Functions; 30 | using Microsoft.VisualStudio.TestTools.UnitTesting; 31 | 32 | namespace UnitTests 33 | { 34 | [TestClass] 35 | public class Slicing 36 | { 37 | public Slicing() 38 | { 39 | 40 | } 41 | 42 | [TestMethod] 43 | public void Test1() 44 | { 45 | var A = GenTensor.CreateMatrix( 46 | new float[,] 47 | { 48 | {1, 2, 3, 4}, 49 | {5, 6, 7, 8}, 50 | {9, 10, 11, 12}, 51 | {13, 14, 15, 16}, 52 | } 53 | ); 54 | var sl1 = A.Slice(1, 3); 55 | A.TransposeMatrix(); 56 | var sl2 = A.Slice(1, 3); 57 | Assert.AreEqual( 58 | GenTensor.CreateMatrix( 59 | new float[,] 60 | { 61 | {5, 6, 7, 8}, 62 | {9, 10, 11, 12}, 63 | } 64 | ), sl1 65 | ); 66 | Assert.AreEqual( 67 | GenTensor.CreateMatrix( 68 | new float[,] 69 | { 70 | {2, 6, 10, 14}, 71 | {3, 7, 11, 15}, 72 | } 73 | ), sl2 74 | ); 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /UnitTests/Subtensor.cs: -------------------------------------------------------------------------------- 1 | #region copyright 2 | /* 3 | * MIT License 4 | * 5 | * Copyright (c) 2020-2021 WhiteBlackGoose 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | #endregion 26 | 27 | 28 | using GenericTensor.Core; 29 | using GenericTensor.Functions; 30 | using Microsoft.VisualStudio.TestTools.UnitTesting; 31 | 32 | namespace UnitTests 33 | { 34 | [TestClass] 35 | public class Subtensor 36 | { 37 | public Subtensor() 38 | { 39 | 40 | } 41 | 42 | private GenTensor GetSmall() 43 | { 44 | var res = new GenTensor(2, 3); 45 | foreach (var (index, _) in res.Iterate()) 46 | { 47 | res[index] = 3 * index[0] + index[1]; 48 | } 49 | return res; 50 | } 51 | 52 | private GenTensor GetBig() 53 | { 54 | var res = new GenTensor(2, 3, 4); 55 | foreach (var (index, _) in res.Iterate()) 56 | { 57 | res[index] = index[0] * 12 + index[1] * 4 + index[2]; 58 | } 59 | return res; 60 | } 61 | 62 | [TestMethod] 63 | public void SubMatrix1() 64 | { 65 | var t = GetSmall(); 66 | Assert.AreEqual(t.GetSubtensor(0), GenTensor.CreateVector(0, 1, 2)); 67 | t.Transpose(0, 1); 68 | Assert.AreEqual(t.GetSubtensor(0), GenTensor.CreateVector(0, 3)); 69 | t.Transpose(0, 1); 70 | Assert.AreEqual(t.GetSubtensor(0), GenTensor.CreateVector(0, 1, 2)); 71 | } 72 | 73 | [TestMethod] 74 | public void SubMatrix2() 75 | { 76 | var t = GetSmall(); 77 | Assert.AreEqual(t.GetSubtensor(1), GenTensor.CreateVector(3, 4, 5)); 78 | t.Transpose(0, 1); 79 | Assert.AreEqual(t.GetSubtensor(1), GenTensor.CreateVector(1, 4)); 80 | t.Transpose(0, 1); 81 | Assert.AreEqual(t.GetSubtensor(1), GenTensor.CreateVector(3, 4, 5)); 82 | } 83 | 84 | [TestMethod] 85 | public void SubTensor() 86 | { 87 | var t = GetBig(); 88 | Assert.AreEqual(t.GetSubtensor(new []{0, 0}), GenTensor.CreateVector(0, 1, 2, 3)); 89 | t.Transpose(1, 2); 90 | Assert.AreEqual(t.GetSubtensor(new []{0, 0}), GenTensor.CreateVector(0, 4, 8)); 91 | t.Transpose(1, 2); 92 | Assert.AreEqual(t.GetSubtensor(new []{0, 0}), GenTensor.CreateVector(0, 1, 2, 3)); 93 | 94 | t.Transpose(0, 1); 95 | Assert.AreEqual(t.GetSubtensor(new []{0, 0}), GenTensor.CreateVector(0, 1, 2, 3)); 96 | Assert.AreEqual(t.GetSubtensor(new []{0, 1}), GenTensor.CreateVector(12 + 0, 12 + 1, 12 + 2, 12 + 3)); 97 | } 98 | 99 | [TestMethod] 100 | public void SubMatrixSet() 101 | { 102 | var t = GetSmall(); 103 | t.SetSubtensor(GenTensor.CreateVector(10, 10, 10), 1); 104 | var k = t.ToString(); 105 | t.Transpose(0, 1); 106 | Assert.AreEqual(t.GetSubtensor(0), GenTensor.CreateVector(0, 10)); 107 | Assert.AreEqual(t.GetSubtensor(1), GenTensor.CreateVector(1, 10)); 108 | } 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /UnitTests/Transposition.cs: -------------------------------------------------------------------------------- 1 | #region copyright 2 | /* 3 | * MIT License 4 | * 5 | * Copyright (c) 2020-2021 WhiteBlackGoose 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | #endregion 26 | 27 | 28 | using GenericTensor.Core; 29 | using GenericTensor.Functions; 30 | using Microsoft.VisualStudio.TestTools.UnitTesting; 31 | 32 | namespace UnitTests 33 | { 34 | [TestClass] 35 | public class Transposition 36 | { 37 | public Transposition() 38 | { 39 | 40 | } 41 | 42 | private GenTensor GetBig() 43 | { 44 | var res = new GenTensor(2, 3, 4); 45 | foreach (var (index, _) in res.Iterate()) 46 | { 47 | res[index] = index[0] * 12 + index[1] * 4 + index[2]; 48 | } 49 | return res; 50 | } 51 | 52 | private GenTensor GetSmall() 53 | { 54 | var res = new GenTensor(2, 3); 55 | foreach (var (index, _) in res.Iterate()) 56 | { 57 | res[index] = 3 * index[0] + index[1]; 58 | } 59 | return res; 60 | } 61 | 62 | [TestMethod] 63 | public void SimpleShape1() 64 | { 65 | var sm = GetSmall(); 66 | Assert.IsTrue(sm.Shape == new TensorShape(2, 3)); 67 | } 68 | 69 | [TestMethod] 70 | public void SimpleShape2() 71 | { 72 | var sm = GetSmall(); 73 | sm.Transpose(0, 1); 74 | Assert.IsTrue(sm.Shape == new TensorShape(3, 2)); 75 | } 76 | 77 | [TestMethod] 78 | public void BigShape1() 79 | { 80 | var sm = GetBig(); 81 | Assert.IsTrue(sm.Shape == new TensorShape(2, 3, 4)); 82 | } 83 | 84 | [TestMethod] 85 | public void BigShape2() 86 | { 87 | var sm = GetBig(); 88 | sm.Transpose(0, 1); 89 | Assert.IsTrue(sm.Shape == new TensorShape(3, 2, 4)); 90 | } 91 | 92 | [TestMethod] 93 | public void BigShape3() 94 | { 95 | var sm = GetBig(); 96 | sm.Transpose(0, 2); 97 | Assert.IsTrue(sm.Shape == new TensorShape(4, 3, 2)); 98 | } 99 | 100 | [TestMethod] 101 | public void BigShape4() 102 | { 103 | var sm = GetBig(); 104 | sm.Transpose(0, 1); 105 | sm.Transpose(0, 1); 106 | Assert.IsTrue(sm.Shape == new TensorShape(2, 3, 4)); 107 | } 108 | 109 | [TestMethod] 110 | public void SmallFull1() 111 | { 112 | var sm = GetSmall(); 113 | sm.Transpose(0, 1); 114 | Assert.AreEqual(sm[0, 0], 0); 115 | Assert.AreEqual(sm[1, 0], 1); 116 | Assert.AreEqual(sm[2, 0], 2); 117 | Assert.AreEqual(sm[0, 1], 3); 118 | Assert.AreEqual(sm[1, 1], 4); 119 | Assert.AreEqual(sm[2, 1], 5); 120 | } 121 | 122 | [TestMethod] 123 | public void InvalidShape() 124 | => Assert.ThrowsException(() => GenTensor.CreateVector(1, 2, 3).TransposeMatrix()); 125 | 126 | [TestMethod] 127 | public void Transpose4D() 128 | { 129 | var t4 = GenTensor.CreateTensor(new TensorShape(2, 2, 2, 2), 130 | ids => ids[0] + ids[1] + ids[2] + ids[3]); 131 | foreach (var (index, value) in t4.Iterate()) 132 | { 133 | Assert.AreEqual(index[0] + index[1] + index[2] + index[3], value); 134 | } 135 | 136 | } 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /UnitTests/UnitTests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net6.0 5 | 6 | false 7 | 8 | 9 9 | 10 | 11 | 12 | 13 | all 14 | runtime; build; native; contentfiles; analyzers; buildtransitive 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /UnitTests/VectorProduct.cs: -------------------------------------------------------------------------------- 1 | #region copyright 2 | /* 3 | * MIT License 4 | * 5 | * Copyright (c) 2020-2021 WhiteBlackGoose 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | */ 25 | #endregion 26 | 27 | 28 | using GenericTensor.Core; 29 | using GenericTensor.Functions; 30 | using Microsoft.VisualStudio.TestTools.UnitTesting; 31 | 32 | namespace UnitTests 33 | { 34 | [TestClass] 35 | public class VectorProduct 36 | { 37 | public VectorProduct() 38 | { 39 | 40 | } 41 | 42 | [TestMethod] 43 | public void TestVectorDotProduct1() 44 | { 45 | var v1 = GenTensor.CreateVector(1, 2, 3); 46 | var v2 = GenTensor.CreateVector(-3, 5, 3); 47 | Assert.AreEqual(16, GenTensor.VectorDotProduct(v1, v2)); 48 | } 49 | 50 | [TestMethod] 51 | public void TestVectorDotProduct2() 52 | { 53 | var v1 = GenTensor.CreateVector(1, 2, 3); 54 | var v2 = GenTensor.CreateVector(-3, 5); 55 | Assert.ThrowsException(() => GenTensor.VectorDotProduct(v1, v2)); 56 | } 57 | 58 | [TestMethod] 59 | public void TestTensorVectorDotProduct1() 60 | { 61 | var v1_1 = GenTensor.CreateVector(1, 2, 3); 62 | var v1_2 = GenTensor.CreateVector(1, 2, 3); 63 | var v2_1 = GenTensor.CreateVector(-3, 5, 3); 64 | var v2_2 = GenTensor.CreateVector(-3, 5, 3); 65 | var v1 = GenTensor.Stack(v1_1, v1_2); 66 | var v2 = GenTensor.Stack(v2_1, v2_2); 67 | Assert.AreEqual(GenTensor.CreateVector(16, 16), GenTensor.TensorVectorDotProduct(v1, v2)); 68 | } 69 | 70 | [TestMethod] 71 | public void TestTensorVectorDotProduct2() 72 | { 73 | var v1_1 = GenTensor.CreateVector(1, 2, 3); 74 | var v1_2 = GenTensor.CreateVector(1, 2, 3); 75 | var v2_1 = GenTensor.CreateVector(-3, 5); 76 | var v2_2 = GenTensor.CreateVector(3, 5); 77 | var v1 = GenTensor.Stack(v1_1, v1_2); 78 | var v2 = GenTensor.Stack(v2_1, v2_2); 79 | Assert.ThrowsException(() => GenTensor.TensorVectorDotProduct(v1, v2)); 80 | } 81 | 82 | [TestMethod] 83 | public void TestVectorCrossProduct1() 84 | { 85 | var v1 = GenTensor.CreateVector(1, 2, 3); 86 | var v2 = GenTensor.CreateVector(-3, 5, 3); 87 | Assert.AreEqual(GenTensor.CreateVector(-9, -12, 11), GenTensor.VectorCrossProduct(v1, v2)); 88 | } 89 | 90 | [TestMethod] 91 | public void TestTensorVectorCrossProduct1() 92 | { 93 | var v1_1 = GenTensor.CreateVector(1, 2, 3); 94 | var v1_2 = GenTensor.CreateVector(-3, 5, 3); 95 | var v2_1 = GenTensor.CreateVector(-3, 5, 3); 96 | var v2_2 = GenTensor.CreateVector(1, 2, 3); 97 | var T1 = GenTensor.Stack(v1_1, v1_2); 98 | var T2 = GenTensor.Stack(v2_1, v2_2); 99 | 100 | var exp = GenTensor.CreateVector(-9, -12, 11); 101 | var res = GenTensor.Stack(exp, GenTensor.PiecewiseMultiply(exp, -1)); 102 | Assert.AreEqual(res, GenTensor.TensorVectorCrossProduct(T1, T2)); 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /ico1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asc-community/GenericTensor/da0c01d2acb17530ee6bc39da79692148c92069b/ico1.png --------------------------------------------------------------------------------