├── .gitattributes ├── .gitignore ├── LICENSE ├── MultipleOutputHelper.ttinclude ├── Proxem.NumNet.Benchmark ├── BaseFunctions.cs ├── Initialization.cs ├── Program.cs ├── Proxem.NumNet.Benchmark.csproj └── Slicing.cs ├── Proxem.NumNet.Test ├── App.config ├── Profiling.cs ├── Properties │ └── AssemblyInfo.cs ├── Proxem.NumNet.Test.csproj ├── TestAssertArray.cs ├── TestBroadcast.cs ├── TestConvolution.cs ├── TestEinsteinSum.cs ├── TestFlags.cs ├── TestLapack.cs ├── TestReshape.cs ├── TestShuffle.cs ├── TestSlicing.cs ├── TestSoftmax.cs ├── TestSparseMatrix.cs ├── TestTensorSum.cs ├── TestVariance.cs ├── UnitTestInitialize.cs ├── UnitTestInt32.cs ├── UnitTestIterable.cs ├── UnitTestSingle.cs ├── UnitTestTensorCombine.cs ├── UnitTestTensorWithBias.cs └── packages.config ├── Proxem.NumNet.sln ├── Proxem.NumNet ├── Array.cs ├── ArrayExtensions.tt ├── Array_.cs ├── AssertArray.cs ├── Double │ ├── ArrayConvolutionExtension.cs │ ├── ArrayExtensions.cs │ └── Operators.cs ├── Int32 │ ├── ArrayExtensions.cs │ └── Operators.cs ├── NN.Dirichlet.cs ├── NN.Double.cs ├── NN.Einstein.cs ├── NN.Int32.cs ├── NN.Single.cs ├── NN.Single_Double.tt ├── NN.cs ├── Operators.cs ├── Operators.tt ├── PCA.cs ├── Proxem.NumNet.csproj ├── Proxem.NumNet.sublime-project ├── Random.cs ├── ShapeUtil.cs ├── Single │ ├── ArrayConvolutionExtension.cs │ ├── ArrayExtensions.cs │ ├── Operators.cs │ └── TensorBias.cs ├── Slice.cs ├── Strided.cs ├── StridedUtil.cs ├── Test.runsettings ├── nuspec │ ├── Proxem.NumNet.Debug.nuspec │ └── Proxem.NumNet.nuspec └── readme.txt ├── README.md ├── Test.runsettings ├── create_package.cmd ├── create_package_debug.cmd └── logo └── proxem.png /.gitattributes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Proxem/NumNet/12c0e1cd8790d68b89aa8935ff88b95e0d4cfa24/.gitattributes -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # ignore build output 2 | build/ 3 | bin 4 | obj 5 | /doc/_build/ 6 | /doc/_doxy/ 7 | /Proxem.NumNet/obsolete/ 8 | /dlls/ 9 | 10 | /doc/*.XML 11 | packages 12 | 13 | # ignore IDE files 14 | .vs 15 | *.suo 16 | *.sln.ide 17 | *.user 18 | *.sublime-workspace 19 | TestResults/ 20 | *.vspx 21 | *.userprefs 22 | 23 | # ignore dlls 24 | *.dll 25 | *.pdb 26 | /dlls/mkl/learn_tensor.bat 27 | 28 | # ignore nuget packages 29 | *.nupkg -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /MultipleOutputHelper.ttinclude: -------------------------------------------------------------------------------- 1 | <#@ assembly name="System.Core" 2 | #><#@ assembly name="System.Data.Linq" 3 | #><#@ assembly name="EnvDTE.dll" 4 | #><#@ assembly name="System.Xml" 5 | #><#@ assembly name="System.Xml.Linq" 6 | #><#@ import namespace="System.Collections.Generic" 7 | #><#@ import namespace="System.IO" 8 | #><#@ import namespace="System.Text" 9 | #><#@ import namespace="Microsoft.VisualStudio.TextTemplating" 10 | #><#+ 11 | // https://raw.github.com/damieng/DamienGKit 12 | // http://damieng.com/blog/2009/11/06/multiple-outputs-from-t4-made-easy-revisited 13 | 14 | // Manager class records the various blocks so it can split them up 15 | class Manager { 16 | private class Block { 17 | public String Name; 18 | public int Start, Length; 19 | public bool IncludeInDefault; 20 | } 21 | 22 | private Block currentBlock; 23 | private readonly List files = new List(); 24 | private readonly Block footer = new Block(); 25 | private readonly Block header = new Block(); 26 | private readonly ITextTemplatingEngineHost host; 27 | private readonly StringBuilder template; 28 | protected readonly List generatedFileNames = new List(); 29 | 30 | public static Manager Create(ITextTemplatingEngineHost host, StringBuilder template) { 31 | return (host is IServiceProvider) ? new VSManager(host, template) : new Manager(host, template); 32 | } 33 | 34 | public void StartNewFile(String name) { 35 | if (name == null) 36 | throw new ArgumentNullException("name"); 37 | CurrentBlock = new Block { Name = name }; 38 | } 39 | 40 | public void StartFooter(bool includeInDefault = true) { 41 | CurrentBlock = footer; 42 | footer.IncludeInDefault = includeInDefault; 43 | } 44 | 45 | public void StartHeader(bool includeInDefault = true) { 46 | CurrentBlock = header; 47 | header.IncludeInDefault = includeInDefault; 48 | } 49 | 50 | public void EndBlock() { 51 | if (CurrentBlock == null) 52 | return; 53 | CurrentBlock.Length = template.Length - CurrentBlock.Start; 54 | if (CurrentBlock != header && CurrentBlock != footer) 55 | files.Add(CurrentBlock); 56 | currentBlock = null; 57 | } 58 | 59 | public virtual void Process(bool split, bool sync = true) { 60 | if (split) { 61 | EndBlock(); 62 | String headerText = template.ToString(header.Start, header.Length); 63 | String footerText = template.ToString(footer.Start, footer.Length); 64 | String outputPath = Path.GetDirectoryName(host.TemplateFile); 65 | files.Reverse(); 66 | if (!footer.IncludeInDefault) 67 | template.Remove(footer.Start, footer.Length); 68 | foreach(Block block in files) { 69 | String fileName = Path.Combine(outputPath, block.Name); 70 | String content = headerText + template.ToString(block.Start, block.Length) + footerText; 71 | generatedFileNames.Add(fileName); 72 | CreateFile(fileName, content); 73 | template.Remove(block.Start, block.Length); 74 | } 75 | if (!header.IncludeInDefault) 76 | template.Remove(header.Start, header.Length); 77 | } 78 | } 79 | 80 | protected virtual void CreateFile(String fileName, String content) { 81 | if (IsFileContentDifferent(fileName, content)) 82 | File.WriteAllText(fileName, content); 83 | } 84 | 85 | public virtual String GetCustomToolNamespace(String fileName) { 86 | return null; 87 | } 88 | 89 | public virtual String DefaultProjectNamespace { 90 | get { return null; } 91 | } 92 | 93 | protected bool IsFileContentDifferent(String fileName, String newContent) { 94 | return !(File.Exists(fileName) && File.ReadAllText(fileName) == newContent); 95 | } 96 | 97 | private Manager(ITextTemplatingEngineHost host, StringBuilder template) { 98 | this.host = host; 99 | this.template = template; 100 | } 101 | 102 | private Block CurrentBlock { 103 | get { return currentBlock; } 104 | set { 105 | if (CurrentBlock != null) 106 | EndBlock(); 107 | if (value != null) 108 | value.Start = template.Length; 109 | currentBlock = value; 110 | } 111 | } 112 | 113 | private class VSManager: Manager { 114 | private readonly EnvDTE.ProjectItem templateProjectItem; 115 | private readonly EnvDTE.DTE dte; 116 | private readonly Action checkOutAction; 117 | private readonly Action> projectSyncAction; 118 | 119 | public override String DefaultProjectNamespace { 120 | get { 121 | return templateProjectItem.ContainingProject.Properties.Item("DefaultNamespace").Value.ToString(); 122 | } 123 | } 124 | 125 | public override String GetCustomToolNamespace(string fileName) { 126 | return dte.Solution.FindProjectItem(fileName).Properties.Item("CustomToolNamespace").Value.ToString(); 127 | } 128 | 129 | public override void Process(bool split, bool sync) { 130 | if (templateProjectItem.ProjectItems == null) 131 | return; 132 | base.Process(split, sync); 133 | if (sync) 134 | projectSyncAction.EndInvoke(projectSyncAction.BeginInvoke(generatedFileNames, null, null)); 135 | } 136 | 137 | protected override void CreateFile(String fileName, String content) { 138 | if (IsFileContentDifferent(fileName, content)) { 139 | CheckoutFileIfRequired(fileName); 140 | File.WriteAllText(fileName, content); 141 | } 142 | } 143 | 144 | internal VSManager(ITextTemplatingEngineHost host, StringBuilder template) 145 | : base(host, template) { 146 | var hostServiceProvider = (IServiceProvider)host; 147 | if (hostServiceProvider == null) 148 | throw new ArgumentNullException("Could not obtain IServiceProvider"); 149 | dte = (EnvDTE.DTE) hostServiceProvider.GetService(typeof(EnvDTE.DTE)); 150 | if (dte == null) 151 | throw new ArgumentNullException("Could not obtain DTE from host"); 152 | templateProjectItem = dte.Solution.FindProjectItem(host.TemplateFile); 153 | checkOutAction = fileName => dte.SourceControl.CheckOutItem(fileName); 154 | projectSyncAction = keepFileNames => ProjectSync(templateProjectItem, keepFileNames); 155 | } 156 | 157 | private static void ProjectSync(EnvDTE.ProjectItem templateProjectItem, List keepFileNames) { 158 | var keepFileNameSet = new HashSet(keepFileNames); 159 | var projectFiles = new Dictionary(); 160 | var originalFilePrefix = Path.GetFileNameWithoutExtension(templateProjectItem.FileNames[0]) + "."; 161 | foreach (EnvDTE.ProjectItem projectItem in templateProjectItem.ProjectItems) 162 | projectFiles.Add(projectItem.FileNames[0], projectItem); 163 | 164 | // Remove unused items from the project 165 | foreach (var pair in projectFiles) 166 | if (!keepFileNames.Contains(pair.Key) && !(Path.GetFileNameWithoutExtension(pair.Key) + ".").StartsWith(originalFilePrefix)) 167 | pair.Value.Delete(); 168 | 169 | // Add missing files to the project 170 | foreach(String fileName in keepFileNameSet) 171 | if (!projectFiles.ContainsKey(fileName)) 172 | templateProjectItem.ProjectItems.AddFromFile(fileName); 173 | } 174 | 175 | private void CheckoutFileIfRequired(String fileName) { 176 | var sc = dte.SourceControl; 177 | if (sc != null && sc.IsItemUnderSCC(fileName) && !sc.IsItemCheckedOut(fileName)) 178 | checkOutAction.EndInvoke(checkOutAction.BeginInvoke(fileName, null, null)); 179 | } 180 | } 181 | } #> -------------------------------------------------------------------------------- /Proxem.NumNet.Benchmark/BaseFunctions.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Attributes; 2 | using BenchmarkDotNet.Configs; 3 | using NumSharp.Core; 4 | using Proxem.BlasNet; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Text; 8 | 9 | namespace Proxem.NumNet.Benchmark 10 | { 11 | [CoreJob] 12 | //[CsvExporter] 13 | [GroupBenchmarksBy(BenchmarkLogicalGroupRule.ByCategory)] 14 | [CategoriesColumn] 15 | public class BaseFunctionsBenchmarkMkl 16 | { 17 | private Array numnet_1; 18 | private Array numnet_2; 19 | 20 | private Array numnet_flat_1; 21 | private Array numnet_flat_2; 22 | 23 | //private NumPy np; 24 | 25 | private NDArray numsharp_1; 26 | private NDArray numsharp_2; 27 | 28 | private NDArray numsharp_flat_1; 29 | private NDArray numsharp_flat_2; 30 | 31 | [Params(100, 500)] 32 | public int N; 33 | 34 | [GlobalSetup] 35 | public void Setup() 36 | { 37 | // Launching mkl for NumNet (path might need to be change) 38 | var path = "C:/data/dlls/mkl"; 39 | StartProvider.LaunchMklRt(1, path); 40 | 41 | numnet_1 = NN.Random.Normal(0, 1, N, N); 42 | numnet_2 = NN.Random.Normal(0, 1, N, N); 43 | numnet_flat_1 = NN.Random.Normal(0, 1, N * N); 44 | numnet_flat_2 = NN.Random.Normal(0, 1, N * N); 45 | 46 | //np = new NumPy(); 47 | numsharp_1 = np.random.normal(0, 1, N, N).reshape(new Shape(N, N)); // need reshaping cause there's a bug in 'np.random.normal' 48 | numsharp_2 = np.random.normal(0, 1, N, N).reshape(new Shape(N, N)); 49 | numsharp_flat_1 = np.random.normal(0, 1, N * N); 50 | numsharp_flat_2 = np.random.normal(0, 1, N * N); 51 | } 52 | 53 | [BenchmarkCategory("Dot"), Benchmark] 54 | public Array NumNetDot() => NN.Dot(numnet_1, numnet_2); 55 | 56 | [BenchmarkCategory("Dot"), Benchmark] 57 | public NDArray NumSharpDot() => np.dot(numsharp_1, numsharp_2); 58 | 59 | [BenchmarkCategory("Dot"), Benchmark] 60 | public Array NumNetDotFlat() => NN.Dot(numnet_flat_1, numnet_flat_2); 61 | 62 | [BenchmarkCategory("Dot"), Benchmark] 63 | public NDArray NumSharpDotFlat() => np.dot(numsharp_flat_1, numsharp_flat_2); 64 | 65 | [BenchmarkCategory("Maths"), Benchmark] 66 | public Array NumNetLog() => NN.Log(numnet_1); 67 | 68 | [BenchmarkCategory("Maths"), Benchmark] 69 | public NDArray NumSharpLog() => np.log(numsharp_1); 70 | 71 | [BenchmarkCategory("Operations"), Benchmark] 72 | public Array NumNetDiff() => numnet_1 - numnet_2; 73 | 74 | [BenchmarkCategory("Operations"), Benchmark] 75 | public NDArray NumSharpDiff() => numsharp_1 - numsharp_2; 76 | 77 | [BenchmarkCategory("Operations"), Benchmark] 78 | public Array NumNetAdd() => numnet_1 + numnet_2; 79 | 80 | [BenchmarkCategory("Operations"), Benchmark] 81 | public NDArray NumSharpAdd() => numsharp_1 + numsharp_2; 82 | 83 | [BenchmarkCategory("Operations"), Benchmark] 84 | public Array NumNetHadamard() => numnet_1 * numnet_2; 85 | 86 | [BenchmarkCategory("Operations"), Benchmark] 87 | public NDArray NumSharpHadamard() => numsharp_1 * numsharp_2; 88 | 89 | [BenchmarkCategory("Operations"), Benchmark] 90 | [Arguments(1.5f)] 91 | [Arguments(-2.8f)] 92 | public Array NumNetScalarMul(float lambda) => numnet_1 * lambda; 93 | 94 | [BenchmarkCategory("Operations"), Benchmark] 95 | [Arguments(1.5f)] 96 | [Arguments(-2.8f)] 97 | public NDArray NumSharpScalarMul(float lambda) => numsharp_1 * lambda; 98 | 99 | [BenchmarkCategory("Base"), Benchmark] 100 | public Array NumNetArgmax() => NN.Argmax(numnet_1); 101 | 102 | [BenchmarkCategory("Base"), Benchmark] 103 | public NDArray NumSharpArgmax() => np.amax(numsharp_1); 104 | 105 | [BenchmarkCategory("Base"), Benchmark] 106 | public void NumNetArgmaxAxis() 107 | { 108 | var a = NN.Argmax(numnet_1, 0); 109 | var b = NN.Argmax(numnet_1, 1); 110 | } 111 | 112 | [BenchmarkCategory("Base"), Benchmark] 113 | public void NumSharpArgmaxAxis() 114 | { 115 | np.amax(numsharp_1, 0); 116 | np.amax(numsharp_1, 1); 117 | } 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /Proxem.NumNet.Benchmark/Initialization.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Attributes; 2 | using BenchmarkDotNet.Configs; 3 | using NumSharp.Core; 4 | using Proxem.BlasNet; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Text; 8 | 9 | namespace Proxem.NumNet.Benchmark 10 | { 11 | [GroupBenchmarksBy(BenchmarkLogicalGroupRule.ByCategory)] 12 | [CategoriesColumn] 13 | [CoreJob] 14 | [CsvExporter] 15 | public class InitBenchmark 16 | { 17 | //private NumPy np; 18 | 19 | [GlobalSetup] 20 | public void Setup() 21 | { 22 | // Launching mkl for NumNet (path might need to be change) 23 | var path = "C:/data/dlls/mkl"; 24 | StartProvider.LaunchMklRt(1, path); 25 | 26 | // Creating NumPy for NumSharp (deprecated) 27 | //np = new NumPy(); 28 | } 29 | 30 | [BenchmarkCategory("Gaussian"), Benchmark(Baseline = true)] 31 | [Arguments(100, 200)] 32 | [Arguments(1000, 2000)] 33 | public void NumNetInitNormal(int n, int m) 34 | { 35 | var a = NN.Random.Normal(-.4f, 1.1f, n, m); 36 | } 37 | 38 | [BenchmarkCategory("Gaussian"), Benchmark] 39 | [Arguments(100, 200)] 40 | [Arguments(1000, 2000)] 41 | public void NumSharpInitNormal(int n, int m) 42 | { 43 | var a = np.random.normal(-.4f, 1.1f, n, m); 44 | } 45 | 46 | [BenchmarkCategory("Arange"), Benchmark(Baseline = true)] 47 | [Arguments(130, 130)] 48 | [Arguments(200, 10)] 49 | public void NumNetInitArange(int n, int m) 50 | { 51 | var a = NN.Range(n * m).Reshape(n, m); 52 | } 53 | 54 | [BenchmarkCategory("Arange"), Benchmark] 55 | [Arguments(130, 130)] 56 | [Arguments(200, 10)] 57 | public void NumSharpInitArange(int n, int m) 58 | { 59 | var a = np.arange(n * m).reshape(n, m); 60 | } 61 | 62 | [BenchmarkCategory("Constant"), Benchmark] 63 | [Arguments(1000, 2000)] 64 | [Arguments(2000, 1000)] 65 | public void NumNetInitOnes(int n, int m) 66 | { 67 | var a = NN.Ones(n, m); 68 | } 69 | 70 | [BenchmarkCategory("Constant"), Benchmark] 71 | [Arguments(1000, 2000)] 72 | [Arguments(2000, 1000)] 73 | public void NumSharpInitOnes(int n, int m) 74 | { 75 | var a = np.ones(n, m); 76 | } 77 | 78 | [BenchmarkCategory("Constant"), Benchmark] 79 | [Arguments(1000, 2000)] 80 | [Arguments(2000, 1000)] 81 | public void NumNetInitZeros(int n, int m) 82 | { 83 | var a = NN.Zeros(n, m); 84 | } 85 | 86 | [BenchmarkCategory("Constant"), Benchmark] 87 | [Arguments(1000, 2000)] 88 | [Arguments(2000, 1000)] 89 | public void NumSharpInitZeros(int n, int m) 90 | { 91 | var a = np.zeros(n, m); 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /Proxem.NumNet.Benchmark/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using BenchmarkDotNet.Running; 3 | 4 | namespace Proxem.NumNet.Benchmark 5 | { 6 | class Program 7 | { 8 | static void Main(string[] args) 9 | { 10 | var summary = BenchmarkRunner.Run(); 11 | Console.ReadLine(); 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Proxem.NumNet.Benchmark/Proxem.NumNet.Benchmark.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | netcoreapp2.1 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /Proxem.NumNet.Benchmark/Slicing.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Attributes; 2 | using BenchmarkDotNet.Configs; 3 | using NumSharp.Core; 4 | using Proxem.BlasNet; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Text; 8 | 9 | namespace Proxem.NumNet.Benchmark 10 | { 11 | [GroupBenchmarksBy(BenchmarkLogicalGroupRule.ByCategory)] 12 | [CategoriesColumn] 13 | [CoreJob] 14 | [CsvExporter] 15 | public class SlicingBenchmark 16 | { 17 | private Array _numnet_3d; 18 | private NDArray _numsharp_3d; 19 | 20 | private Array _numnet_2d; 21 | private NDArray _numsharp_2d; 22 | 23 | [GlobalSetup] 24 | public void Setup() 25 | { 26 | // Launching mkl for NumNet (path might need to be change) 27 | var path = "C:/data/dlls/mkl"; 28 | StartProvider.LaunchMklRt(1, path); 29 | //var np = new NumPy(); deprecated 30 | 31 | _numnet_3d = NN.Random.Normal(0f, 1f, 10, 8, 12); 32 | _numsharp_3d = np.random.normal(0f, 1f, 10, 8, 12); 33 | 34 | _numnet_2d = NN.Random.Normal(-1f, 0.4f, 50, 20); 35 | _numsharp_2d = np.random.normal(-1f, 0.4f, 50, 20); 36 | } 37 | 38 | [BenchmarkCategory("Slicing"), Benchmark] 39 | public void SlicingNumNet() 40 | { 41 | var slice_1 = _numnet_3d[Slicer._, 0, 3]; 42 | var slice_2 = _numnet_3d[1, Slicer._, 2]; 43 | var slice_3 = _numnet_3d[2, 4, Slicer._]; 44 | } 45 | 46 | //[BenchmarkCategory("Slicing"), Benchmark] 47 | //public void SlicingNumSharp() 48 | //{ 49 | // var slice_1 = _numsharp_3d[new Shape(1)]; 50 | //} 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Proxem.NumNet.Test/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Proxem.NumNet.Test/Profiling.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | using System; 21 | using System.Collections.Generic; 22 | using System.Diagnostics; 23 | using System.IO; 24 | using System.Linq; 25 | using System.Text; 26 | using System.Threading.Tasks; 27 | using Microsoft.VisualStudio.TestTools.UnitTesting; 28 | using Proxem.BlasNet; 29 | using Proxem.NumNet.Single; 30 | 31 | namespace Proxem.NumNet.Test 32 | { 33 | [TestClass] 34 | public class Profiling 35 | { 36 | [Ignore] 37 | [TestMethod, TestCategory("Profiling")] 38 | public void CompareElementWisePerformance() 39 | { 40 | Trace.Listeners.Add(new ConsoleTraceListener()); 41 | 42 | Func f = (x, y) => x + y; 43 | var clock = new Stopwatch(); 44 | #if DEBUG 45 | Trace.WriteLine($"Testing on DEBUG"); 46 | #else 47 | Trace.WriteLine($"Testing on RELEASE"); 48 | #endif 49 | Trace.WriteLine($"Testing on {Blas.NThreads} threads"); 50 | 51 | for (int i = 0; i < 300; ++i) 52 | { 53 | int n = i + 1; 54 | var a = NN.Random.Uniform(-1f, 1f, n, n); 55 | var b = NN.Random.Uniform(-1f, 1f, n, n); 56 | var r = NN.Zeros(n, n); 57 | 58 | var size = a.Size; 59 | // estimating loop count for this size 60 | NN.MIN_SIZE_FOR_PARELLELISM = size * 2; 61 | var loopCount = 0; 62 | clock.Restart(); 63 | 64 | while (clock.ElapsedMilliseconds < 1000) 65 | { 66 | NN.Apply(a, b, f, result: r); 67 | ++loopCount; 68 | } 69 | Trace.WriteLine($"doing {loopCount} loops for size {size}"); 70 | 71 | // profiling Normal 72 | clock.Restart(); 73 | for (int _ = 0; _ < loopCount; _++) 74 | NN.Apply(a, b, f, result: r); 75 | var time = clock.ElapsedMilliseconds; 76 | var avg = (double)time / loopCount; 77 | 78 | // profiling Parrellized 79 | NN.MIN_SIZE_FOR_PARELLELISM = 0; 80 | clock.Restart(); 81 | for (int _ = 0; _ < loopCount; _++) 82 | NN.Apply(a, b, f, result: r); 83 | var timePar = clock.ElapsedMilliseconds; 84 | var avgPar = (double)timePar / loopCount; 85 | 86 | clock.Restart(); 87 | for (int _ = 0; _ < loopCount; _++) 88 | a.Add(b, result: r); 89 | var timeAdd = clock.ElapsedMilliseconds; 90 | var avgAdd = (double)timeAdd / loopCount; 91 | 92 | clock.Restart(); 93 | for (int _ = 0; _ < loopCount; _++) 94 | Blas.vadd(size, a.Values, 0, b.Values, 0, r.Values, 0); 95 | var timeBlas = clock.ElapsedMilliseconds; 96 | var avgBlas = (double)timeBlas / loopCount; 97 | 98 | var message = $"On size {size}, avg time: {avg:F4}ms \t with parallelism {avgPar:F4}ms \t with Add {avgAdd:F4}ms \t with Blas {avgBlas:F4}ms."; 99 | Trace.WriteLine(message); 100 | } 101 | 102 | throw new Exception("see output for profiler results"); 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /Proxem.NumNet.Test/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | using System.Reflection; 21 | using System.Runtime.CompilerServices; 22 | using System.Runtime.InteropServices; 23 | 24 | // General Information about an assembly is controlled through the following 25 | // set of attributes. Change these attribute values to modify the information 26 | // associated with an assembly. 27 | [assembly: AssemblyTitle("Proxem.NumNet.Test")] 28 | [assembly: AssemblyDescription("")] 29 | [assembly: AssemblyConfiguration("")] 30 | [assembly: AssemblyCompany("")] 31 | [assembly: AssemblyProduct("Proxem.NumNet.Test")] 32 | [assembly: AssemblyCopyright("Copyright © 2014")] 33 | [assembly: AssemblyTrademark("")] 34 | [assembly: AssemblyCulture("")] 35 | 36 | // Setting ComVisible to false makes the types in this assembly not visible 37 | // to COM components. If you need to access a type in this assembly from 38 | // COM, set the ComVisible attribute to true on that type. 39 | [assembly: ComVisible(false)] 40 | 41 | // The following GUID is for the ID of the typelib if this project is exposed to COM 42 | [assembly: Guid("7a535963-9489-419a-ad36-dc266a38add7")] 43 | 44 | // Version information for an assembly consists of the following four values: 45 | // 46 | // Major Version 47 | // Minor Version 48 | // Build Number 49 | // Revision 50 | // 51 | // You can specify all the values or you can default the Build and Revision Numbers 52 | // by using the '*' as shown below: 53 | // [assembly: AssemblyVersion("1.0.*")] 54 | [assembly: AssemblyVersion("1.0.0.0")] 55 | [assembly: AssemblyFileVersion("1.0.0.0")] 56 | -------------------------------------------------------------------------------- /Proxem.NumNet.Test/Proxem.NumNet.Test.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | {CA9B2BC3-3F6F-47F2-AAC6-E975EE54C9A6} 7 | Library 8 | Properties 9 | Proxem.NumNet.Test 10 | Proxem.NumNet.Test 11 | v4.6.2 12 | 512 13 | {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 14 | 10.0 15 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 16 | $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages 17 | False 18 | UnitTest 19 | 20 | 21 | 22 | true 23 | full 24 | false 25 | ..\build\debug\ 26 | DEBUG;TRACE 27 | prompt 28 | 4 29 | true 30 | AnyCPU 31 | 32 | 33 | pdbonly 34 | true 35 | ..\build\release\ 36 | TRACE 37 | prompt 38 | 4 39 | true 40 | AnyCPU 41 | 42 | 43 | true 44 | full 45 | false 46 | ..\build\debug\ 47 | DEBUG;TRACE 48 | prompt 49 | 4 50 | true 51 | x64 52 | MinimumRecommendedRules.ruleset 53 | 54 | 55 | pdbonly 56 | true 57 | ..\build\release\ 58 | TRACE 59 | prompt 60 | 4 61 | true 62 | x64 63 | MinimumRecommendedRules.ruleset 64 | 65 | 66 | 67 | False 68 | ..\..\BlasNet\build\debug\netstandard2.0\Proxem.BlasNet.dll 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | {3431c1a9-c74a-4053-add8-eaf174bd7a38} 116 | Proxem.NumNet 117 | 118 | 119 | 120 | 121 | 122 | 123 | False 124 | 125 | 126 | False 127 | 128 | 129 | False 130 | 131 | 132 | False 133 | 134 | 135 | 136 | 137 | 138 | 139 | 146 | -------------------------------------------------------------------------------- /Proxem.NumNet.Test/TestAssertArray.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | using System; 21 | using System.Collections.Generic; 22 | using System.Linq; 23 | using System.Text; 24 | using System.Threading.Tasks; 25 | using Microsoft.VisualStudio.TestTools.UnitTesting; 26 | using Proxem.NumNet.Single; 27 | 28 | namespace Proxem.NumNet.Test 29 | { 30 | [TestClass] 31 | public class TestAssertArray 32 | { 33 | [TestMethod] 34 | public void AssertOfDimAcceptCorrects() 35 | { 36 | NN.Empty().AssertOfDim(0); 37 | NN.Zeros(1).AssertOfDim(1); 38 | NN.Zeros(1, 1).AssertOfDim(2); 39 | NN.Zeros(1, 1, 1).AssertOfDim(3); 40 | } 41 | 42 | [TestMethod] 43 | public void AssertOfDimThrowsException() 44 | { 45 | var a = NN.Zeros(1); 46 | var b = NN.Zeros(1, 1); 47 | var c = NN.Zeros(1, 1, 1); 48 | 49 | AssertThrows(() => a.AssertOfDim(2)); 50 | AssertThrows(() => a.AssertOfDim(3)); 51 | AssertThrows(() => b.AssertOfDim(1)); 52 | AssertThrows(() => b.AssertOfDim(3)); 53 | AssertThrows(() => c.AssertOfDim(1)); 54 | AssertThrows(() => c.AssertOfDim(2)); 55 | } 56 | 57 | [TestMethod] 58 | public void AssertOfShapeAcceptCorrects() 59 | { 60 | NN.Zeros(5).AssertOfShape(5); 61 | NN.Zeros(7).AssertOfShape(7); 62 | NN.Zeros(5, 7).AssertOfShape(5, 7); 63 | NN.Zeros(5, 3).AssertOfShape(5, 3); 64 | NN.Zeros(5, 3, 7).AssertOfShape(5, 3, 7); 65 | NN.Zeros(5, 3, 9).AssertOfShape(5, 3, 9); 66 | } 67 | 68 | [TestMethod] 69 | public void AssertOfShapeThrowsException() 70 | { 71 | AssertThrows(() => NN.Zeros(5).AssertOfShape(7)); 72 | AssertThrows(() => NN.Zeros(5).AssertOfShape(5, 1)); 73 | AssertThrows(() => NN.Zeros(5, 7).AssertOfShape(5, 3)); 74 | AssertThrows(() => NN.Zeros(5, 7).AssertOfShape(1, 5, 7)); 75 | AssertThrows(() => NN.Zeros(5, 3, 7).AssertOfShape(5, 9, 7)); 76 | AssertThrows(() => NN.Zeros(5, 3, 7).AssertOfShape(1, 5, 3, 9)); 77 | } 78 | 79 | [TestMethod] 80 | public void AssertAreEqualWorks() 81 | { 82 | var a = NN.Random.Uniform(-1f, 1f, 4, 3); 83 | var b = a.Copy(); 84 | var c = a.T; 85 | AssertArray.AreEqual(a, b); 86 | AssertArray.AreNotEqual(a, c); 87 | Assert.IsTrue(a == a.T.T); 88 | } 89 | 90 | [TestMethod] 91 | public void AssertAreEqualWithBroadcastingWorks() 92 | { 93 | var a = NN.Random.Uniform(-1f, 1f, 5); 94 | var b = a.Reshape(1, 5); 95 | var c = a.Reshape(5, 1); 96 | AssertArray.AreEqual(a, b, allowBroadcasting: true); 97 | AssertArray.AreEqual(a, c, allowBroadcasting: true); 98 | AssertArray.AreEqual(c, b, allowBroadcasting: true); 99 | AssertArray.AreEqual(b, c, allowBroadcasting: true); 100 | 101 | AssertArray.AreNotEqual(b, c, allowBroadcasting: false); 102 | AssertArray.AreNotEqual(a, b, allowBroadcasting: false); 103 | AssertArray.AreNotEqual(a, c, allowBroadcasting: false); 104 | } 105 | 106 | public static T AssertThrows(Action f) where T : Exception 107 | { 108 | try 109 | { 110 | f(); 111 | throw new Exception("Exception not throwed"); 112 | } 113 | catch(T e) 114 | { 115 | return e; 116 | } 117 | } 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /Proxem.NumNet.Test/TestBroadcast.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | using System; 21 | using Microsoft.VisualStudio.TestTools.UnitTesting; 22 | 23 | namespace Proxem.NumNet.Test 24 | { 25 | using static Slicer; 26 | 27 | [TestClass] 28 | public class TestBroadCast 29 | { 30 | [TestMethod] 31 | public void CanBroadcastScalarToArray() 32 | { 33 | // http://www.onlamp.com/pub/a/python/2000/09/27/numerically.html 34 | /* 35 | 36 | a = np.array([[1,2],[3, 4]]) 37 | b = 1 38 | a + b 39 | 40 | */ 41 | var a = NN.Array(new[,] { { 1, 2 }, { 3, 4 } }); 42 | var b = 1; 43 | var r = NN.Array(new[,] { { 2, 3 }, { 4, 5 } }); 44 | 45 | AssertArray.GenerateTests(a, NN.Ones, a1 => AssertArray.AreEqual(r, a1 + b)); 46 | } 47 | 48 | [TestMethod, ExpectedException(typeof(RankException)), TestCategory("Exception")] 49 | public void CantBroadcast_2_3_to_3_2() 50 | { 51 | // http://www.onlamp.com/pub/a/python/2000/09/27/numerically.html?page=2 52 | /* 53 | 54 | a = np.array([[1, 2, 3], [4, 5, 6]]) 55 | b = np.array([[1, 2], [3, 4], [5, 6]]) 56 | a + b 57 | 58 | */ 59 | var a = NN.Array(new[,] { { 1, 2, 3 }, { 4, 5, 6 } }); 60 | var b = NN.Array(new[,] { { 1, 2 }, { 3, 4 }, { 5, 6 } }); 61 | var c = a + b; 62 | } 63 | 64 | [TestMethod] 65 | public void CanBroadcast_3_to_2_3() 66 | { 67 | // http://www.onlamp.com/pub/a/python/2000/09/27/numerically.html?page=2 68 | /* 69 | 70 | a = np.array([[1, 2, 3], [4, 5, 6]]) 71 | b = np.array([[7, 8, 9]]) 72 | a + b 73 | 74 | */ 75 | var a = NN.Array(new[,] { { 1, 2, 3 }, { 4, 5, 6 } }); 76 | var c = NN.Array(new[] { 7, 8, 9 }); 77 | var rAdd = NN.Array(new[,] { { 8, 10, 12 }, { 11, 13, 15 } }); 78 | var rMul = NN.Array(new[,] { { 7, 16, 27 }, { 28, 40, 54 } }); 79 | 80 | a.AssertOfShape(2, 3); 81 | c.AssertOfShape(3); 82 | 83 | AssertArray.GenerateTests(a, c, NN.Ones, (a1, c1) => AssertArray.AreEqual(rAdd, a1 + c1)); 84 | AssertArray.GenerateTests(a, c, NN.Zeros, (a1, c1) => AssertArray.AreEqual(rMul, a1 * c1)); 85 | } 86 | 87 | [TestMethod] 88 | public void CanBroadcast_1_to_5() 89 | { 90 | // http://www.onlamp.com/pub/a/python/2000/09/27/numerically.html?page=2 91 | /* 92 | 93 | x=np.zeros((3,4,5,6,7)) 94 | y=np.zeros((7,)) 95 | z=x+y 96 | 97 | */ 98 | var x = NN.Zeros(3, 4, 5, 6, 7); 99 | var y = NN.Zeros(7); 100 | var z = x + y; // no exception 101 | } 102 | 103 | [TestMethod] 104 | public void CanBroadcast_2_to_3_1() 105 | { 106 | // http://www.onlamp.com/pub/a/python/2000/09/27/numerically.html?page=2 107 | /* 108 | 109 | z=np.array([1, 2]) 110 | v=np.array([[3], [4], [5]]) 111 | z+v 112 | 113 | */ 114 | // When comparing the size of each axis, if either one of the compared axes has a size of one, broadcasting can also occur 115 | var z = NN.Array(new[] { 1, 2 }); 116 | AssertArray.AreEqual(z.Shape, new int[] { 2 }); 117 | 118 | var v = NN.Array(new[,] { { 3 }, { 4 }, { 5 } }); 119 | AssertArray.AreEqual(v.Shape, new int[] { 3, 1 }); 120 | 121 | AssertArray.AreEqual(new[,] { { 4, 5 }, { 5, 6 }, { 6, 7 } }, z + v); 122 | //In this form, the first multiarray z was extended to a (3,2) multiarray and the second multiarray v was extended to a (3,2) multiarray. 123 | //Essentially, broadcasting occurred on both operands! This only occurs when the axis size of one of the multiarrays has the value of one. 124 | } 125 | 126 | [TestMethod] 127 | public void CanBroadcast_2_to_3_1_bis() 128 | { 129 | // http://www.onlamp.com/pub/a/python/2000/09/27/numerically.html?page=3 130 | /* 131 | 132 | z = np.array([1,2]) 133 | w = np.array([3,4,5]) 134 | z+np.reshape(w,(3,1)) 135 | 136 | a=np.zeros((3,4,5,6)) 137 | b=np.zeros((4,6)) 138 | c=a+b[:,np.newaxis,:] 139 | 140 | */ 141 | 142 | var z = NN.Array(new[] { 1, 2 }); 143 | var w = NN.Array(new[] { 3, 4, 5 }); 144 | 145 | AssertArray.AreEqual(new[,] { { 4, 5 }, { 5, 6 }, { 6, 7 } }, z + w.Reshape(3, 1)); 146 | } 147 | 148 | [TestMethod] 149 | public void CanInsertNewAxisAndBroadcast() 150 | { 151 | // http://www.onlamp.com/pub/a/python/2000/09/27/numerically.html?page=3 152 | /* 153 | 154 | a=np.zeros((3,4,5,6)) 155 | b=np.zeros((4,6)) 156 | c=a+b[:,np.newaxis,:] 157 | 158 | */ 159 | 160 | var a = NN.Zeros(new[] { 3, 4, 5, 6 }); 161 | var b = NN.Zeros(new[] { 4, 6 }); 162 | var c = a + b[_, NewAxis, _]; 163 | 164 | AssertArray.AreEqual(c.Shape, new[] { 3, 4, 5, 6 }); 165 | } 166 | 167 | [TestMethod] 168 | public void CanInsertNewAxis() 169 | { 170 | // http://www.onlamp.com/pub/a/python/2000/09/27/numerically.html?page=3 171 | /* 172 | 173 | b=np.arange(2 * 3).reshape(2, 3) 174 | b[:,np.newaxis,:] 175 | 176 | */ 177 | 178 | var b = NN.Range(2 * 3).Reshape(2, 3); 179 | var c = b[_, NewAxis, _]; 180 | 181 | AssertArray.AreEqual(c.Shape, new[] { 2, 1, 3 }); 182 | AssertArray.AreEqual(c.Stride, new[] { 3, 0, 1 }); 183 | } 184 | } 185 | } -------------------------------------------------------------------------------- /Proxem.NumNet.Test/TestEinsteinSum.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | using System; 21 | using System.Collections.Generic; 22 | using System.Linq; 23 | using System.Text; 24 | using System.Threading.Tasks; 25 | using Microsoft.VisualStudio.TestTools.UnitTesting; 26 | using Proxem.NumNet.Single; 27 | 28 | namespace Proxem.NumNet.Test 29 | { 30 | using static EinsteinSumTools; 31 | 32 | [TestClass] 33 | public class TestEinsteinSum 34 | { 35 | [TestMethod] 36 | public void CanReadEinsteinStringForInner() 37 | { 38 | var einstein = EinsteinRead("i,i->"); 39 | Assert.AreEqual(1, einstein.Length); 40 | Assert.AreEqual(Inner(0, 0), einstein[0]); 41 | } 42 | 43 | [TestMethod] 44 | public void CanReadEinsteinStringForOuter() 45 | { 46 | var einstein = EinsteinRead("i,j->ij"); 47 | Assert.AreEqual(2, einstein.Length); 48 | Assert.AreEqual(OuterX(0, 0), einstein[0]); 49 | Assert.AreEqual(OuterY(0, 1), einstein[1]); 50 | 51 | einstein = EinsteinRead("i,j->ji"); 52 | Assert.AreEqual(2, einstein.Length); 53 | Assert.AreEqual(OuterX(0, 1), einstein[0]); 54 | Assert.AreEqual(OuterY(0, 0), einstein[1]); 55 | } 56 | 57 | [TestMethod] 58 | public void CanReadEinsteinStringForSum() 59 | { 60 | var einstein = EinsteinRead("i,->"); 61 | Assert.AreEqual(1, einstein.Length); 62 | Assert.AreEqual(SumX(0), einstein[0]); 63 | 64 | einstein = EinsteinRead(",i->"); 65 | Assert.AreEqual(1, einstein.Length); 66 | Assert.AreEqual(SumY(0), einstein[0]); 67 | } 68 | 69 | 70 | [TestMethod] 71 | public void EinsteinShapeForInnerIsCorrect() 72 | { 73 | var einstein = EinsteinRead("i,i->"); 74 | var shape = EinsteinShape(new[] { 10 }, new[] { 10 }, einstein); 75 | Assert.AreEqual(0, shape.Length); 76 | } 77 | 78 | [TestMethod] 79 | public void EinsteinShapeForOuterIsCorrect() 80 | { 81 | var einstein = EinsteinRead("i,j->ij"); 82 | var shape = EinsteinShape(new[] { 10 }, new[] { 15 }, einstein); 83 | Assert.AreEqual(2, shape.Length); 84 | Assert.AreEqual(10, shape[0]); 85 | Assert.AreEqual(15, shape[1]); 86 | } 87 | 88 | [TestMethod] 89 | public void InnerAsEinsteinSumMatchesInner() 90 | { 91 | var x = NN.Random.Uniform(-1f, 1f, 10); 92 | var y = NN.Random.Uniform(-1f, 1f, 10); 93 | AssertArray.AreEqual(x.Dot(y), NN.EinsteinSum(x, y, "i,i->")); 94 | } 95 | 96 | [TestMethod] 97 | public void OuterAsEinsteinSumMatchesOuter() 98 | { 99 | var x = NN.Random.Uniform(-1f, 1f, 10); 100 | var y = NN.Random.Uniform(-1f, 1f, 15); 101 | AssertArray.AreEqual(x.Outer(y), NN.EinsteinSum(x, y, "i,j->ij")); 102 | } 103 | 104 | [TestMethod] 105 | public void SumAsEinsteinSumMatchesSum() 106 | { 107 | var x = NN.Random.Uniform(-1f, 1f, 10); 108 | var y = NN.Ones(1); 109 | AssertArray.AreEqual(x.Sum(axis: 0), NN.EinsteinSum(x, y, "i,->")); 110 | } 111 | 112 | [TestMethod] 113 | public void DotAsEinsteinSumMatchesDot() 114 | { 115 | var x = NN.Random.Uniform(-1f, 1f, 10, 20); 116 | var y = NN.Random.Uniform(-1f, 1f, 20, 13); 117 | AssertArray.AreAlmostEqual(x.Dot(y), NN.EinsteinSum(x, y, "ij,jk->ik")); 118 | } 119 | 120 | [TestMethod] 121 | public void TensorDotAsEinsteinSumMatchesTensorDot() 122 | { 123 | var x = NN.Random.Uniform(-1f, 1f, 10, 20); 124 | var y = NN.Random.Uniform(-1f, 1f, 20, 13, 5); 125 | AssertArray.AreAlmostEqual(NN.TensorDot(x, new[] { 1 }, y, new[] { 0 }), NN.EinsteinSum(x, y, "ij,jkl->ikl")); 126 | } 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /Proxem.NumNet.Test/TestFlags.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | using System; 21 | using System.Collections.Generic; 22 | using System.Linq; 23 | using Microsoft.VisualStudio.TestTools.UnitTesting; 24 | 25 | namespace Proxem.NumNet.Test 26 | { 27 | using static Slicer; 28 | 29 | [TestClass] 30 | public class TestFlags 31 | { 32 | [TestMethod] 33 | public void TestContiguousOnVec() 34 | { 35 | var a = NN.Array( 0f, 1, 2, 3 ); 36 | 37 | a.AssertIsContiguous(); 38 | a[(1, 3)].AssertIsContiguous(); 39 | a[Upto(3)].AssertIsContiguous(); 40 | a[From(2)].AssertIsContiguous(); 41 | a[Only(2)].AssertIsContiguous(); 42 | 43 | a[Step(-1)].AssertIsContiguous(); 44 | a[Step(2)].AssertIsContiguous(); 45 | } 46 | 47 | [TestMethod] 48 | public void TestContiguousOnMat() 49 | { 50 | var a = NN.Array( 51 | new float[] { 0, 1, 2, 3 }, 52 | new float[] { 1, 2, 3, 4 }, 53 | new float[] { 2, 3, 4, 5 } 54 | ); 55 | 56 | a.AssertIsContiguous(); 57 | a[(1, 3)].AssertIsContiguous(); 58 | a[Upto(3)].AssertIsContiguous(); 59 | a[From(2)].AssertIsContiguous(); 60 | 61 | a[(1, 3), Upto(3)].AssertIsNotContiguous(); 62 | a[Upto(3), From(2)].AssertIsNotContiguous(); 63 | a[From(2), (1, 3)].AssertIsNotContiguous(); 64 | a[Only(2), (1, 3)].AssertIsContiguous(); 65 | 66 | a[From(2), Only(1)].AssertIsContiguous(); 67 | a[(1, 3), Only(2)].AssertIsContiguous(); 68 | 69 | a[Step(-1)].AssertIsNotContiguous(); 70 | a[Step(2)].AssertIsNotContiguous(); 71 | } 72 | 73 | [TestMethod] 74 | public void TestTranspose() 75 | { 76 | var t = NN.Ones(5, 4, 3); 77 | t.AssertOfShape(5, 4, 3); 78 | 79 | t.Transpose(0, 1, 2).AssertIsNotTransposed(); 80 | t.Transpose(0, 2, 1).AssertIsTransposed(); 81 | 82 | t.Transpose(1, 0, 2).AssertIsTransposed(); 83 | t.Transpose(1, 2, 0).AssertIsTransposed(); 84 | 85 | t.Transpose(2, 0, 1).AssertIsTransposed(); 86 | t.Transpose(2, 1, 0).AssertIsTransposed(); 87 | 88 | t.Transpose(0, 2, 1).Transpose(0, 2, 1).AssertIsNotTransposed(); 89 | t.Transpose(2, 0, 1).Transpose(1, 2, 0).AssertIsNotTransposed(); 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /Proxem.NumNet.Test/TestReshape.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | using System; 21 | using Microsoft.VisualStudio.TestTools.UnitTesting; 22 | 23 | namespace Proxem.NumNet.Test 24 | { 25 | using static Slicer; 26 | 27 | [TestClass] 28 | public class TestReshape 29 | { 30 | [TestMethod] 31 | public void TestSimpleReshape() 32 | { 33 | var a = NN.Range(4 * 3).Reshape(4, 3); 34 | var exp = NN.Array(new int[,]{ 35 | {0, 1, 2}, 36 | {3, 4, 5}, 37 | {6, 7, 8}, 38 | {9, 10, 11} 39 | }); 40 | 41 | AssertArray.AreEqual(exp, a); 42 | AssertArray.AreEqual(exp, NN.Range(4 * 3).Reshape(4, -1)); 43 | AssertArray.AreEqual(exp, NN.Range(4 * 3).Reshape(-1, 3)); 44 | AssertArray.AreEqual(NN.Range(12), a.Reshape(-1)); 45 | } 46 | 47 | [TestMethod, TestCategory("Exception"), ExpectedException(typeof(ArgumentException))] 48 | public void ComplexReshapeFailsWithoutCopyFlag() 49 | { 50 | var a = NN.Range(4 * 3).Reshape(4, 3); 51 | 52 | a.T.Reshape(new int[] { -1 }, allowCopy: false); 53 | } 54 | 55 | [TestMethod] 56 | public void ComplexReshapeWorksWithCopyFlag() 57 | { 58 | var a = NN.Range(4 * 3).Reshape(4, 3); 59 | var exp = NN.Array(new int[] { 0, 3, 6, 9, 1, 4, 7, 10, 2, 5, 8, 11 }); 60 | 61 | AssertArray.AreEqual(exp, a.T.Reshape(new int[]{-1}, allowCopy: true)); 62 | } 63 | 64 | [TestMethod] 65 | public void CanReshapeReversedArray() 66 | { 67 | var a = NN.Zeros(6); 68 | a[Step(-1)] = NN.Range(6); 69 | a = a[Step(-1)]; 70 | 71 | var b = NN.Array(new[,] { 72 | { 0, 1, 2 }, 73 | { 3, 4, 5 } 74 | }); 75 | 76 | AssertArray.AreEqual(NN.Range(6), a); 77 | AssertArray.AreEqual(b, a.Reshape(2, 3)); 78 | } 79 | 80 | [TestMethod] 81 | public void CanReshape_6_to_2_3() 82 | { 83 | var a0 = NN.Range(6); 84 | var b = NN.Array(new[,] { 85 | { 0, 1, 2 }, 86 | { 3, 4, 5 } 87 | }); 88 | 89 | AssertArray.GenerateTests(a0, a => AssertArray.AreEqual(b, a.Reshape(2, 3))); 90 | } 91 | 92 | [TestMethod] 93 | public void CanReshape_6_to_2_3_WithForcedCopy() 94 | { 95 | var a0 = NN.Range(6); 96 | var b = NN.Array(new[,] { 97 | { 0, 1, 2 }, 98 | { 3, 4, 5 } 99 | }); 100 | 101 | AssertArray.GenerateTests(a0, a => AssertArray.AreEqual(b, a.Reshape(new[] { 2, 3 }, forceCopy: true))); 102 | } 103 | 104 | [TestMethod] 105 | public void ConcatWorksWithTwoArrays() 106 | { 107 | // Test Concat(1, 2D, 2D) 108 | var a = NN.Range(12).Reshape(3, 4); 109 | var b = NN.Range(9).Reshape(3, 3); 110 | var c = NN.Concat(1, a, b); 111 | 112 | var d = NN.Array(new int[,] 113 | { 114 | { 0, 1, 2, 3, /**/ 0, 1, 2 }, 115 | { 4, 5, 6, 7, /**/ 3, 4, 5 }, 116 | { 8, 9, 10, 11, /**/ 6, 7, 8 }, 117 | }); 118 | AssertArray.AreEqual(d, c); 119 | 120 | // Test Concat(0, 2D, 2D) 121 | a = NN.Range(12).Reshape(4, 3); 122 | c = NN.Concat(0, a, b); 123 | d = NN.Array(new int[,] 124 | { 125 | { 0, 1, 2 }, 126 | { 3, 4, 5 }, 127 | { 6, 7, 8 }, 128 | { 9, 10, 11 }, 129 | /* -------- */ 130 | { 0, 1, 2 }, 131 | { 3, 4, 5 }, 132 | { 6, 7, 8 } 133 | }); 134 | AssertArray.AreEqual(d, c); 135 | } 136 | 137 | [TestMethod] 138 | public void ConcatWorksWithResult() 139 | { 140 | // Test Concat(1, 2D, 2D) 141 | var a = NN.Range(12).Reshape(3, 4); 142 | var b = NN.Range(9).Reshape(3, 3); 143 | var r = NN.Zeros(3, 4 + 3); 144 | var c = NN.Concat(1, new[] { a, b }, result: r); 145 | 146 | var d = NN.Array(new int[,] 147 | { 148 | { 0, 1, 2, 3, /**/ 0, 1, 2 }, 149 | { 4, 5, 6, 7, /**/ 3, 4, 5 }, 150 | { 8, 9, 10, 11, /**/ 6, 7, 8 }, 151 | }); 152 | AssertArray.AreEqual(d, c); 153 | 154 | // Test Concat(0, 2D, 2D) 155 | a = NN.Range(12).Reshape(4, 3); 156 | r = NN.Zeros(4 + 3, 3); 157 | c = NN.Concat(0, new[] { a, b }, result: r); 158 | d = NN.Array(new int[,] 159 | { 160 | { 0, 1, 2 }, 161 | { 3, 4, 5 }, 162 | { 6, 7, 8 }, 163 | { 9, 10, 11 }, 164 | /* -------- */ 165 | { 0, 1, 2 }, 166 | { 3, 4, 5 }, 167 | { 6, 7, 8 } 168 | }); 169 | AssertArray.AreEqual(d, c); 170 | } 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /Proxem.NumNet.Test/TestShuffle.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | using System; 21 | using Microsoft.VisualStudio.TestTools.UnitTesting; 22 | 23 | 24 | namespace Proxem.NumNet.Test 25 | { 26 | [TestClass] 27 | public class TestShuffle 28 | { 29 | [TestMethod] 30 | public void TestShuffleDim1() 31 | { 32 | var a = NN.Range(10); 33 | int[] perm = new int[10] { 1, 2, 3, 8, 9, 0, 4, 6, 7, 5 }; 34 | var expected = NN.Array(new int[10] { 5, 0, 1, 2, 6, 9, 7, 8, 3, 4 }); 35 | var shufA = a.Shuffle(perm); 36 | AssertArray.AreEqual(shufA, expected); 37 | } 38 | 39 | [TestMethod] 40 | public void TestShuffleInPlaceDim1() 41 | { 42 | var a = NN.Range(10); 43 | int[] perm = new int[10] { 1, 2, 3, 8, 9, 0, 4, 6, 7, 5 }; 44 | var expected = NN.Array(new int[10] { 5, 0, 1, 2, 6, 9, 7, 8, 3, 4 }); 45 | a.ShuffleInplace(perm); 46 | AssertArray.AreEqual(a, expected); 47 | } 48 | 49 | [TestMethod] 50 | public void TestShuffleDim2() 51 | { 52 | var a = NN.Range(20).Reshape(4, 5); 53 | 54 | int[] permsRow = new int[4] { 2, 0, 3, 1 }; 55 | int[] permsCol= new int[5] { 0, 3, 1, 4, 2 }; 56 | var expectedRow = NN.Array(new int[20] {5, 6, 7, 8, 9, 15, 16, 17, 18, 19, 0, 1, 2, 3, 4, 10, 11, 12, 13, 14 }).Reshape(4, 5); 57 | var expectedCol = NN.Array(new int[20] {0, 2, 4, 1, 3, 5, 7, 9, 6, 8, 10, 12, 14, 11, 13, 15, 17, 19, 16, 18 }).Reshape(4, 5); 58 | 59 | var shufARow = a.Shuffle(perms: permsRow); 60 | var shufACol = a.Shuffle(perms: permsCol, axis: 1); 61 | 62 | AssertArray.AreEqual(shufARow, expectedRow); 63 | AssertArray.AreEqual(shufACol, expectedCol); 64 | } 65 | 66 | 67 | [TestMethod] 68 | public void TestShuffleInplaceDim2() 69 | { 70 | var a = NN.Range(20).Reshape(4, 5); 71 | var b = NN.Range(20).Reshape(4, 5); 72 | 73 | int[] permsRow = new int[4] { 2, 0, 3, 1 }; 74 | int[] permsCol = new int[5] { 0, 3, 1, 4, 2 }; 75 | var expectedRow = NN.Array(new int[20] { 5, 6, 7, 8, 9, 15, 16, 17, 18, 19, 0, 1, 2, 3, 4, 10, 11, 12, 13, 14 }).Reshape(4, 5); 76 | var expectedCol = NN.Array(new int[20] { 0, 2, 4, 1, 3, 5, 7, 9, 6, 8, 10, 12, 14, 11, 13, 15, 17, 19, 16, 18 }).Reshape(4, 5); 77 | 78 | a.ShuffleInplace(perms: permsRow); 79 | b.ShuffleInplace(perms: permsCol, axis: 1); 80 | 81 | AssertArray.AreEqual(a, expectedRow); 82 | AssertArray.AreEqual(b, expectedCol); 83 | } 84 | 85 | [TestMethod] 86 | public void TestShuffleDim3() 87 | { 88 | var a = NN.Range(24).Reshape(3, 2, 4); 89 | 90 | int[] perms1 = new int[3] { 0, 2, 1 }; 91 | int[] perms2 = new int[2] { 1, 0 }; 92 | int[] perms3 = new int[4] { 3, 1, 0, 2 }; 93 | var expected1 = NN.Array(new int[24] { 0, 1, 2, 3, 4, 5, 6, 7, 16, 17, 18, 19, 20, 21, 22, 23, 8, 9, 10, 11, 12, 13, 14, 15 }).Reshape(3, 2, 4); 94 | var expected2 = NN.Array(new int[24] { 4, 5, 6, 7, 0, 1, 2, 3, 12, 13, 14, 15, 8, 9, 10, 11, 20, 21, 22, 23, 16, 17, 18, 19 }).Reshape(3, 2, 4); 95 | var expected3 = NN.Array(new int[24] { 2, 1, 3, 0, 6, 5, 7, 4, 10, 9, 11, 8, 14, 13, 15, 12, 18, 17, 19, 16, 22, 21, 23, 20 }).Reshape(3, 2, 4); 96 | 97 | var shufA1 = a.Shuffle(perms: perms1); 98 | var shufA2 = a.Shuffle(perms: perms2, axis: 1); 99 | var shufA3 = a.Shuffle(perms: perms3, axis: 2); 100 | 101 | AssertArray.AreEqual(shufA1, expected1); 102 | AssertArray.AreEqual(shufA2, expected2); 103 | AssertArray.AreEqual(shufA3, expected3); 104 | } 105 | 106 | [TestMethod] 107 | public void TestShuffleInplaceDim3() 108 | { 109 | var a = NN.Range(24).Reshape(3, 2, 4); 110 | var b = NN.Range(24).Reshape(3, 2, 4); 111 | var c = NN.Range(24).Reshape(3, 2, 4); 112 | 113 | int[] perms1 = new int[3] { 0, 2, 1 }; 114 | int[] perms2 = new int[2] { 1, 0 }; 115 | int[] perms3 = new int[4] { 3, 1, 0, 2 }; 116 | var expected1 = NN.Array(new int[24] { 0, 1, 2, 3, 4, 5, 6, 7, 16, 17, 18, 19, 20, 21, 22, 23, 8, 9, 10, 11, 12, 13, 14, 15 }).Reshape(3, 2, 4); 117 | var expected2 = NN.Array(new int[24] { 4, 5, 6, 7, 0, 1, 2, 3, 12, 13, 14, 15, 8, 9, 10, 11, 20, 21, 22, 23, 16, 17, 18, 19 }).Reshape(3, 2, 4); 118 | var expected3 = NN.Array(new int[24] { 2, 1, 3, 0, 6, 5, 7, 4, 10, 9, 11, 8, 14, 13, 15, 12, 18, 17, 19, 16, 22, 21, 23, 20 }).Reshape(3, 2, 4); 119 | 120 | a.ShuffleInplace(perms: perms1); 121 | b.ShuffleInplace(perms: perms2, axis: 1); 122 | c.ShuffleInplace(perms: perms3, axis: 2); 123 | 124 | AssertArray.AreEqual(a, expected1); 125 | AssertArray.AreEqual(b, expected2); 126 | AssertArray.AreEqual(c, expected3); 127 | } 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /Proxem.NumNet.Test/TestSoftmax.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | using System; 21 | using System.Collections.Generic; 22 | using System.Diagnostics; 23 | using System.Linq; 24 | using System.Text; 25 | using System.Threading.Tasks; 26 | using Microsoft.VisualStudio.TestTools.UnitTesting; 27 | using Proxem.NumNet; 28 | 29 | 30 | namespace Proxem.Theanet.Test 31 | { 32 | [TestClass] 33 | public class TestSoftmax 34 | { 35 | //Array softmax(Array w) 36 | //{ 37 | // w = NN.Array(w); // lift Array> => Array 38 | // var maxes = NN.Max(w, axis: w.Shape.Length - 1, keepDims: true); 39 | // var e = NN.Exp(w - maxes); 40 | // var sum = NN.Sum(e, axis: w.Shape.Length - 1, keepDims: true); 41 | // var result = e / sum; 42 | // // TODO: result.Shape.Length == 2 43 | // //if (result.Shape.Length == 1) result = result[Slicer.NewAxis, Slicer._]; 44 | // return result; 45 | //} 46 | 47 | [TestMethod] 48 | public void TestSoftmax2D() 49 | { 50 | var X = NN.Array(new float[,] { { 1, 3 }, { 2, 5 } }); 51 | 52 | AssertArray.AreAlmostEqual(new float[,] { { 0.11920292f, 0.88079708f }, { 0.04742587f, 0.95257413f } }, NN.Softmax(X)); 53 | } 54 | 55 | [TestMethod] 56 | public void TestSoftmax1D() 57 | { 58 | var X = NN.Array(new float[] { 1, 3 }); 59 | 60 | AssertArray.AreAlmostEqual(new float[] { 0.11920292f, 0.88079708f }, NN.Softmax(X)); 61 | } 62 | 63 | [TestMethod] 64 | public void TestLogSumExp() 65 | { 66 | var X = NN.Array(new float[,] { { 1, 3 }, { 2, 5 } }); 67 | 68 | AssertArray.AreAlmostEqual(NN.Log(NN.Sum(NN.Exp(X), axis: -1)), NN.LogSumExp(X)); 69 | } 70 | 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /Proxem.NumNet.Test/TestSparseMatrix.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | using System; 21 | using System.Collections.Generic; 22 | using System.Linq; 23 | using System.Text; 24 | using System.Threading.Tasks; 25 | using Microsoft.VisualStudio.TestTools.UnitTesting; 26 | using Proxem.BlasNet; 27 | 28 | namespace Proxem.NumNet.Test 29 | { 30 | [TestClass] 31 | public class TestSparseMatrix 32 | { 33 | IBlas Provider = Blas.Provider; 34 | 35 | [TestMethod] 36 | public void TestSparseMatrixMultiplication() 37 | { 38 | // https://en.wikipedia.org/wiki/Sparse_matrix 39 | var aDense = new float[] 40 | { 41 | 0, 0, 0, 0, 42 | 5, 8, 0, 0, 43 | 0, 0, 3, 0, 44 | 0, 6, 0, 0 45 | }; 46 | 47 | var a = new float[] { 5, 8, 3, 6 }; 48 | var ja = new int[] { 0, 1, 2, 1 }; 49 | var ia = new int[] { 0, 0, 2, 3, 4 }; 50 | 51 | var bDense = new float[] 52 | { 53 | 1, 2, 0, 0, 0, 0, 54 | 0, 3, 0, 4, 0, 0, 55 | 0, 0, 5, 6, 7, 0, 56 | 0, 0, 0, 0, 0, 8, 57 | }; 58 | 59 | var cDense = new float[4 * 6]; 60 | var c = new float[4 * 6]; 61 | 62 | Provider.sgemm(Order.RowMajor, Transpose.NoTrans, Transpose.NoTrans, 4, 6, 4, 1, aDense, 0, 4, bDense, 0, 6, 0, cDense, 0, 6); 63 | Provider.scsrmm(Transpose.NoTrans, 4, 6, 4, 1, a, 0, ja, 0, ia, 0, bDense, 0, 6, 0, c, 0, 6); 64 | 65 | AssertArray.AreEqual(cDense, c); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /Proxem.NumNet.Test/TestTensorSum.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Proxem.NumNet.Test 9 | { 10 | [TestClass] 11 | public class TestTensorSum 12 | { 13 | [TestMethod] 14 | public void TestSum3_1() 15 | { 16 | var a = NN.Range(24).Reshape(2, 3, 4).As(); 17 | var b = NN.Range(4).As(); 18 | 19 | var expected = NN.Array(new float[,,] 20 | { 21 | { 22 | { 0, 2, 4, 6 }, 23 | { 4, 6, 8, 10 }, 24 | { 8, 10, 12, 14 } 25 | }, 26 | { 27 | { 12, 14, 16, 18 }, 28 | { 16, 18, 20, 22 }, 29 | { 20, 22, 24, 26 } 30 | } 31 | }); 32 | 33 | var c = a + b; 34 | AssertArray.AreEqual(expected.Values, c.Values); 35 | } 36 | 37 | [TestMethod] 38 | public void TestSumInt3_1() 39 | { 40 | var a = NN.Range(24).Reshape(2, 3, 4); 41 | var b = NN.Range(4); 42 | 43 | var expected = NN.Array(new int[,,] 44 | { 45 | { 46 | { 0, 2, 4, 6 }, 47 | { 4, 6, 8, 10 }, 48 | { 8, 10, 12, 14 } 49 | }, 50 | { 51 | { 12, 14, 16, 18 }, 52 | { 16, 18, 20, 22 }, 53 | { 20, 22, 24, 26 } 54 | } 55 | }); 56 | 57 | var c = a + b; 58 | AssertArray.AreEqual(expected.Values, c.Values); 59 | } 60 | 61 | [TestMethod] 62 | public void TestSum3_2() 63 | { 64 | var a = NN.Range(24).Reshape(2, 3, 4).As(); 65 | var b = NN.Range(12).Reshape(3, 4).As(); 66 | 67 | var expected = NN.Array(new float[,,] 68 | { 69 | { 70 | { 0, 2, 4, 6 }, 71 | { 8, 10, 12, 14 }, 72 | { 16, 18, 20, 22 } 73 | }, 74 | { 75 | { 12, 14, 16, 18 }, 76 | { 20, 22, 24, 26 }, 77 | { 28, 30, 32, 34 } 78 | } 79 | }); 80 | 81 | var c = a + b; 82 | AssertArray.AreEqual(expected.Values, c.Values); 83 | } 84 | 85 | 86 | [TestMethod] 87 | public void TestSumInt3_2() 88 | { 89 | var a = NN.Range(24).Reshape(2, 3, 4); 90 | var b = NN.Range(12).Reshape(3, 4); 91 | 92 | var expected = NN.Array(new int[,,] 93 | { 94 | { 95 | { 0, 2, 4, 6 }, 96 | { 8, 10, 12, 14 }, 97 | { 16, 18, 20, 22 } 98 | }, 99 | { 100 | { 12, 14, 16, 18 }, 101 | { 20, 22, 24, 26 }, 102 | { 28, 30, 32, 34 } 103 | } 104 | }); 105 | 106 | var c = a + b; 107 | AssertArray.AreEqual(expected.Values, c.Values); 108 | } 109 | 110 | [TestMethod] 111 | public void TestSum4_2() 112 | { 113 | var a = NN.Range(24).Reshape(1, 2, 3, 4).As(); 114 | var b = NN.Range(12).Reshape(3, 4).As(); 115 | 116 | var expected = NN.Array(new float[,,,] 117 | { 118 | { 119 | { 120 | { 0, 2, 4, 6 }, 121 | { 8, 10, 12, 14 }, 122 | { 16, 18, 20, 22 } 123 | }, 124 | { 125 | { 12, 14, 16, 18 }, 126 | { 20, 22, 24, 26 }, 127 | { 28, 30, 32, 34 } 128 | } 129 | } 130 | }); 131 | 132 | var c = a + b; 133 | AssertArray.AreEqual(expected.Values, c.Values); 134 | } 135 | 136 | [TestMethod] 137 | public void TestSumInt4_2() 138 | { 139 | var a = NN.Range(24).Reshape(1, 2, 3, 4); 140 | var b = NN.Range(12).Reshape(3, 4); 141 | 142 | var expected = NN.Array(new int[,,,] 143 | { 144 | { 145 | { 146 | { 0, 2, 4, 6 }, 147 | { 8, 10, 12, 14 }, 148 | { 16, 18, 20, 22 } 149 | }, 150 | { 151 | { 12, 14, 16, 18 }, 152 | { 20, 22, 24, 26 }, 153 | { 28, 30, 32, 34 } 154 | } 155 | } 156 | }); 157 | 158 | var c = a + b; 159 | AssertArray.AreEqual(expected.Values, c.Values); 160 | } 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /Proxem.NumNet.Test/TestVariance.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Proxem.NumNet.Test 9 | { 10 | [TestClass] 11 | public class TestVariance 12 | { 13 | [TestMethod] 14 | public void TestStdSingle() 15 | { 16 | var a = NN.Array(new float[8] { 1, 1, 0, 1, 1, 2, 3, -1 }).Reshape(4,2); 17 | 18 | var stdRowBiased = a.Std(0); 19 | Assert.IsTrue(Math.Abs(stdRowBiased - 9.5 / 4) < 1e-3f); 20 | 21 | var stdRowUnbiased = a.Std(0, ddof: 1); 22 | Assert.IsTrue(Math.Abs(stdRowUnbiased - 9.5 / 3) < 1e-3f); 23 | 24 | var stdColUnbiased = a.Std(1, ddof: 1); 25 | Assert.IsTrue(Math.Abs(stdColUnbiased - 9) < 1e-3f); 26 | 27 | var stdColBiased = a.Std(1); 28 | Assert.IsTrue(Math.Abs(stdColBiased - 4.5) < 1e-3f); 29 | } 30 | 31 | [TestMethod] 32 | public void TestStdDouble() 33 | { 34 | var a = NN.Array(new double[8] { 1, 1, 0, 1, 1, 2, 3, -1 }).Reshape(4, 2); 35 | 36 | var stdRowBiased = a.Std(0); 37 | Assert.IsTrue(Math.Abs(stdRowBiased - 9.5 / 4) < 1e-3f); 38 | 39 | var stdRowUnbiased = a.Std(0, ddof: 1); 40 | Assert.IsTrue(Math.Abs(stdRowUnbiased - 9.5 / 3) < 1e-3f); 41 | 42 | var stdColUnbiased = a.Std(1, ddof: 1); 43 | Assert.IsTrue(Math.Abs(stdColUnbiased - 9) < 1e-3f); 44 | 45 | var stdColBiased = a.Std(1); 46 | Assert.IsTrue(Math.Abs(stdColBiased - 4.5) < 1e-3f); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Proxem.NumNet.Test/UnitTestInitialize.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | using System; 21 | using System.Configuration; 22 | 23 | using Microsoft.VisualStudio.TestTools.UnitTesting; 24 | 25 | using Proxem.BlasNet; 26 | 27 | namespace Proxem.LinearAlgebra.Test 28 | { 29 | [TestClass] 30 | public class UnitTestInitialize 31 | { 32 | [AssemblyInitialize] 33 | public static void InitProvider(TestContext context) 34 | { 35 | #if !NO_MKL 36 | var path = ConfigurationManager.AppSettings["mkl:Path"]; 37 | if (path == null) Blas.Provider = new DefaultBlas(); 38 | else 39 | { 40 | var threads = int.Parse(ConfigurationManager.AppSettings["mkl:Threads"]); 41 | var initialized = false; 42 | var failed = 0; 43 | var maxFailures = 5; 44 | while (!initialized && failed < maxFailures) 45 | { 46 | try 47 | { 48 | StartProvider.LaunchMklRt(threads, path); 49 | initialized = true; 50 | } 51 | catch (NotSupportedException) 52 | { 53 | ++failed; 54 | } 55 | } 56 | } 57 | #endif 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /Proxem.NumNet.Test/UnitTestInt32.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | using System; 21 | using Microsoft.VisualStudio.TestTools.UnitTesting; 22 | 23 | using Proxem.NumNet.Int32; 24 | 25 | namespace Proxem.NumNet.Test 26 | { 27 | [TestClass] 28 | public class UnitTestInt32 29 | { 30 | [TestMethod] 31 | public void TestMin() 32 | { 33 | var a = NN.Range(4 * 2).Reshape(4, 2); 34 | a.Item[2, 1] = -1; 35 | a.Item[0, 1] = 10; 36 | AssertArray.AreEqual(NN.Array(new[] { 0, -1 }), a.Min(axis: 0)); 37 | AssertArray.AreEqual(NN.Array(new[] { 0, 2, -1, 6}), a.Min(axis: 1)); 38 | } 39 | 40 | [TestMethod] 41 | public void TestMax() 42 | { 43 | var a = NN.Range(4 * 2).Reshape(4, 2); 44 | a.Item[2, 1] = -1; 45 | a.Item[0, 1] = 10; 46 | AssertArray.AreEqual(NN.Array(new[] { 6, 10 }), a.Max(axis: 0)); 47 | AssertArray.AreEqual(NN.Array(new[] { 10, 3, 4, 7 }), a.Max(axis: 1)); 48 | } 49 | 50 | [TestMethod] 51 | public void ArgmaxWorksOnVec() 52 | { 53 | Assert.AreEqual(2, NN.Array(0, 1, 5, 1, 0).Argmax()); 54 | 55 | AssertArray.AreEqual( 56 | NN.Array(2), 57 | NN.Array(0, 1, 5, 1, 0).Argmax(axis: 0, keepDims: true)); 58 | } 59 | 60 | [TestMethod] 61 | public void ArgmaxWorksOnMatrix() 62 | { 63 | var a = NN.Array(new [,]{ 64 | {0, 10}, 65 | {2, 3}, 66 | {4, -1}, 67 | {6, 7} 68 | }); 69 | AssertArray.AreEqual(NN.Array(new[] { 3, 0 }), a.Argmax(axis: 0)); 70 | AssertArray.AreEqual(NN.Array(new[] { 1, 1, 0, 1 }), a.Argmax(axis: 1)); 71 | } 72 | 73 | [TestMethod] 74 | public void UnArgmaxWorksOnMatrix() 75 | { 76 | var a = NN.Array(new[,]{ 77 | {0, 10}, 78 | {2, 3}, 79 | {4, -1}, 80 | {6, 7} 81 | }); 82 | var argmax0 = a.Argmax(axis: 0); 83 | var delta0 = NN.Max(a, axis: 0); 84 | var selected0 = NN.UnArgmax(delta0, argmax0, 0, a.Shape[0]); 85 | var expected0 = NN.Array(new[,]{ 86 | {0, 10}, 87 | {0, 0}, 88 | {0, 0}, 89 | {6, 0} 90 | }); 91 | AssertArray.AreEqual(expected0, selected0); 92 | 93 | var argmax1 = a.Argmax(axis: 1); 94 | var delta1 = NN.Max(a, axis: 1); 95 | var selected1 = NN.UnArgmax(delta1, argmax1, 1, a.Shape[1]); 96 | var expected1 = NN.Array(new[,]{ 97 | {0, 10}, 98 | {0, 3}, 99 | {4, 0}, 100 | {0, 7} 101 | }); 102 | AssertArray.AreEqual(expected1, selected1); 103 | 104 | argmax1 = a.Argmax(axis: 1, keepDims: true); 105 | delta1 = NN.Max(a, axis: 1, keepDims: true); 106 | selected1 = NN.UnArgmax(delta1, argmax1, 1, a.Shape[1], keepDims: true); 107 | expected1 = NN.Array(new[,]{ 108 | {0, 10}, 109 | {0, 3}, 110 | {4, 0}, 111 | {0, 7} 112 | }); 113 | AssertArray.AreEqual(expected1, selected1); 114 | } 115 | 116 | [TestMethod] 117 | public void ArgmaxWorksOnTensor() 118 | { 119 | AssertArray.AreEqual( 120 | NN.Array(new[,] { 121 | { 0, 1, 0, 0 }, 122 | { 0, 1, 1, 0 } 123 | }), 124 | NN.Array(new[,,] { 125 | { { 5, 0 }, {0, 5}, { 5, 0 }, { 5, 0 } }, 126 | { { 5, 0 }, {0, 5}, { 0, 5 }, { 5, 0 } }, 127 | }).Argmax(axis: -1) 128 | ); 129 | 130 | AssertArray.AreEqual( 131 | NN.Array(new[,] { 132 | { 2, 1 }, 133 | { 0, 1 } 134 | }), 135 | NN.Array(new[,,] { 136 | { { 1, 0 }, {0, 5}, { 5, 1 }, { 3, 0 } }, 137 | { { 5, 0 }, {0, 5}, { 0, 5 }, { 1, 0 } }, 138 | }).Argmax(axis: 1) 139 | ); 140 | } 141 | 142 | [TestMethod] 143 | public void TestArgmin() 144 | { 145 | var a = NN.Range(4 * 2).Reshape(4, 2); 146 | a.Item[2, 1] = -1; 147 | a.Item[0, 1] = 10; 148 | AssertArray.AreEqual(NN.Array(new[] { 0, 2 }), a.Argmin(axis: 0)); 149 | AssertArray.AreEqual(NN.Array(new[] { 0, 0, 1, 0 }), a.Argmin(axis: 1)); 150 | } 151 | 152 | [TestMethod] 153 | public void TestLtOnInt() 154 | { 155 | AssertArray.AreEqual( 156 | NN.Array(1, 5, 3, 2, 0, -1) < NN.Array(0, 6, 1, 3, 1, 2), 157 | NN.Array(0, 1, 0, 1, 1, 1) 158 | ); 159 | } 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /Proxem.NumNet.Test/UnitTestIterable.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | using System; 21 | using System.Collections.Generic; 22 | using System.Linq; 23 | using System.Text; 24 | using Microsoft.VisualStudio.TestTools.UnitTesting; 25 | using Proxem.NumNet.Single; 26 | 27 | namespace Proxem.NumNet.Test 28 | { 29 | using static Slicer; 30 | 31 | [TestClass] 32 | public class UnitTestIterable 33 | { 34 | [TestMethod] 35 | public void TestIterateOnMatrix() 36 | { 37 | var m1 = NN.Array(new float[,] { 38 | { 0, 1, 2, 3 }, 39 | { 1, 2, 3, 4 }, 40 | { 2, 3, 4, 5 } 41 | }); 42 | 43 | var s1 = string.Join("", m1); 44 | Assert.AreEqual("012312342345", s1); 45 | 46 | var x = new List { 0, 1, 2, 3, 1, 2, 3, 4, 2, 3, 4, 5 }; 47 | var eq = x.Zip(m1, Tuple.Create).Min(xy => xy.Item1 == xy.Item2); 48 | Assert.IsTrue(eq); 49 | 50 | var m2 = m1[From(1), (1, 3)]; 51 | var s2 = string.Join("", m2); 52 | Assert.AreEqual("2334", string.Join("", m2)); 53 | 54 | x = new List() { 2, 3, 3, 4 }; 55 | eq = x.Zip(m2, Tuple.Create).Min(xy => xy.Item1 == xy.Item2); 56 | Assert.IsTrue(eq); 57 | 58 | var m3 = m1[Only(1), (1, 3)]; 59 | x = new List() { 2, 3 }; 60 | eq = x.Zip(m2, Tuple.Create).Min(xy => xy.Item1 == xy.Item2); 61 | Assert.IsTrue(eq); 62 | } 63 | 64 | [TestMethod] 65 | public void TestIterateOnMatrix2() 66 | { 67 | var m1 = NN.Range(3 * 4 * 5).Reshape(3, 4, 5); 68 | Assert.AreEqual(m1.Size, m1.Count()); 69 | 70 | var s1 = string.Join(",", m1) + ","; 71 | var expected1 = new StringBuilder(); 72 | var l1 = new List(); 73 | m1.Apply((f) => { expected1.Append(f); expected1.Append(','); l1.Add(f); return f; }); 74 | Assert.AreEqual(l1.Count, m1.Size); 75 | Assert.AreEqual(expected1.ToString(), s1); 76 | 77 | var m2 = m1[(1, 3), (2, 4), (2, 5)]; 78 | Assert.AreEqual(m2.Size, m2.Count()); 79 | 80 | var s2 = string.Join(",", m2) + ","; 81 | var expected2 = new StringBuilder(); 82 | var l2 = new List(); 83 | m2.Apply((f) => { expected2.Append(f); expected2.Append(','); l2.Add(f); return f; }); 84 | Assert.AreEqual(l2.Count, m2.Size); 85 | 86 | var expected3 = new StringBuilder(); 87 | for (var i = 0; i < m2.Shape[0]; i++) 88 | for (var j = 0; j < m2.Shape[1]; j++) 89 | for (var k = 0; k < m2.Shape[2]; k++) 90 | { 91 | expected3.Append(m2.Item[i, j, k]); 92 | expected3.Append(','); 93 | } 94 | Assert.AreEqual(expected3.ToString(), expected2.ToString()); 95 | Assert.AreEqual(expected2.ToString(), s2); 96 | } 97 | 98 | [TestMethod] 99 | public void TestGetOffsets() 100 | { 101 | // offsets of vec 102 | var v = NN.Range(5); 103 | var offsets = v.GetOffsets(new[] { 5 }).ToArray(); 104 | AssertArray.AreEqual(new[] { 0 }, offsets); 105 | 106 | // offsets of mat 107 | var m = NN.Range(3 * 4).Reshape(3, 4); 108 | offsets = m.GetOffsets(new[] { 3, 4 }).ToArray(); 109 | AssertArray.AreEqual(new[] { 0, 4, 8 }, offsets); 110 | 111 | // offsets of sliced mat 112 | offsets = m[_, (1, 3)].GetOffsets(new[] { 3, 2 }).ToArray(); 113 | AssertArray.AreEqual(new[] { 1, 5, 9 }, offsets); 114 | 115 | // offsets of sliced vec 116 | offsets = v[From(3)].GetOffsets(new[] { 5 }).ToArray(); 117 | AssertArray.AreEqual(new[] { 3 }, offsets); 118 | 119 | // offsets of left broadcasted vec 120 | offsets = v.Reshape(1, 5).GetOffsets(new[] { 4, 5 }).ToArray(); 121 | AssertArray.AreEqual(new[] { 0, 0, 0, 0 }, offsets); 122 | } 123 | } 124 | } -------------------------------------------------------------------------------- /Proxem.NumNet.Test/UnitTestTensorCombine.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | using System; 21 | using Microsoft.VisualStudio.TestTools.UnitTesting; 22 | using Proxem.NumNet.Single; 23 | 24 | namespace Proxem.NumNet.Test 25 | { 26 | using static Slicer; 27 | 28 | [TestClass] 29 | public class UnitTestTensorCombine 30 | { 31 | [TestMethod] 32 | public void TestCombine() 33 | { 34 | var t = NN.Ones(5, 4, 3); 35 | t[2, _, _] *= 2; 36 | t[_, 1, _] *= -1; 37 | t[_, _, 2] *= 3; 38 | 39 | var x = NN.Array(1, -1, 3); 40 | var y = NN.Array(1, -1, 3, 2); 41 | var txy = t.Combine(x, y); 42 | 43 | var z = NN.Zeros(5); 44 | for (int k = 0; k < z.Shape[0]; ++k) 45 | for (int j = 0; j < y.Shape[0]; ++j) 46 | for (int i = 0; i < x.Shape[0]; ++i) 47 | z.Item[k] += t.Item[k, j, i] * y.Item[j] * x.Item[i]; 48 | 49 | var expected = new float[] { 63, 63, 126, 63, 63 }; 50 | AssertArray.AreAlmostEqual(expected, z); 51 | AssertArray.AreAlmostEqual(expected, t.Dot(x).Dot(y)); 52 | AssertArray.AreAlmostEqual(expected, txy); 53 | } 54 | 55 | [TestMethod] 56 | public void TestCombine2() 57 | { 58 | var a = NN.Ones(4, 5, 6); 59 | var x = NN.Ones(6); 60 | var y = NN.Ones(5); 61 | var z = a.Combine(x, y); 62 | 63 | var expected = NN.Array(30, 30, 30, 30); 64 | 65 | AssertArray.AreAlmostEqual(expected, z); 66 | } 67 | 68 | 69 | [TestMethod] 70 | public void TestCombineWithBias3D_1D() 71 | { 72 | var t = NN.Ones(6, 5, 4); 73 | t[2, _, _] *= 2; 74 | t[_, 1, _] *= -1; 75 | t[_, _, 2] *= 3; 76 | 77 | var x = NN.Array(1, -1, -2); 78 | var y = NN.Array(1, -1, 3, 1); 79 | 80 | Array txy2 = null; 81 | txy2 = t[_, Upto(-1), Upto(-1)].Combine(x, y, result: txy2); 82 | 83 | var txy = t.CombineWithBias(x, y); 84 | 85 | var xb = NN.Ones(4); 86 | xb[Upto(-1)] = x; 87 | var yb = NN.Ones(5); 88 | yb[Upto(-1)] = y; 89 | 90 | var txbyb = t.Combine(xb, yb); 91 | 92 | AssertArray.AreAlmostEqual(txbyb, txy); 93 | } 94 | 95 | 96 | 97 | [TestMethod] 98 | public void TestCombineTransposedVersion() 99 | { 100 | float r = 0.5f; 101 | var t = NN.Random.Uniform(-r, r, 5, 4, 3).As(); 102 | 103 | var x = NN.Random.Uniform(-r, r, 3).As(); 104 | var y = NN.Random.Uniform(-r, r, 4).As(); 105 | var z = NN.Random.Uniform(-r, r, 5).As(); 106 | 107 | var txy = t.Combine21(x, y); 108 | var txy_ = t.Dot(x).Dot(y); 109 | AssertArray.AreAlmostEqual(txy_, txy); 110 | 111 | var ztx = t.Combine20(x, z); 112 | var ztx_ = z.Dot(t.Dot(x)); 113 | AssertArray.AreAlmostEqual(ztx_, ztx); 114 | 115 | var zyt = t.Combine10(y, z); 116 | var zyt_ = z.Dot(y.Dot(t)); 117 | AssertArray.AreAlmostEqual(zyt_, zyt); 118 | } 119 | 120 | [TestMethod] 121 | public void TestCombineDispatchOnTranspose() 122 | { 123 | float r = 0.5f; 124 | var t = NN.Random.Uniform(-r, r, 5, 4, 3).As(); 125 | 126 | var x = NN.Random.Uniform(-r, r, 3).As(); 127 | var y = NN.Random.Uniform(-r, r, 4).As(); 128 | var z = NN.Random.Uniform(-r, r, 5).As(); 129 | 130 | var txy = t.Transpose(0, 1, 2).Combine(x, y); 131 | var tyx = t.Transpose(0, 2, 1).Combine(y, x); 132 | var txy_ = t.Dot(x).Dot(y); 133 | AssertArray.AreAlmostEqual(txy, tyx); 134 | 135 | var txz = t.Transpose(1, 0, 2).Combine(x, z); 136 | var tzx = t.Transpose(1, 2, 0).Combine(z, x); 137 | var ztx = z.Dot(t.Dot(x)); 138 | AssertArray.AreAlmostEqual(txz, tzx); 139 | 140 | var tyz = t.Transpose(2, 0, 1).Combine(y, z); 141 | var tzy = t.Transpose(2, 1, 0).Combine(z, y); 142 | var zyt = z.Dot(y.Dot(t)); 143 | AssertArray.AreAlmostEqual(tyz, tzy); 144 | } 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /Proxem.NumNet.Test/UnitTestTensorWithBias.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | using System; 21 | using Microsoft.VisualStudio.TestTools.UnitTesting; 22 | using Proxem.NumNet.Single; 23 | 24 | namespace Proxem.NumNet.Test 25 | { 26 | using static Slicer; 27 | 28 | [TestClass] 29 | public class UnitTestTensorWithBias 30 | { 31 | [TestMethod] 32 | public void TestDotWithBias() 33 | { 34 | var a = NN.Zeros(3, 4); 35 | var id = NN.Eye(3); 36 | a[_, Upto(-1)] = id; 37 | 38 | var expected = NN.Array(new float[,]{ 39 | { 1, 0, 0, 0 }, 40 | { 0, 1, 0, 0 }, 41 | { 0, 0, 1, 0 } 42 | }); 43 | 44 | AssertArray.AreAlmostEqual(expected, a); 45 | //var x = Tensor.Ones(3); 46 | //var y = Tensor.Ones(3).Scale(2); 47 | //Assert.AreEqual(x, y); 48 | } 49 | 50 | [TestMethod] 51 | public void TestDotWithBias1D_1D() 52 | { 53 | var a = NN.Array(1, 2, 1, 3); 54 | var b = NN.Array(1, -1, 1); 55 | 56 | AssertArray.AreAlmostEqual(3, (float)a.DotWithBias(b)); 57 | 58 | a = NN.Random.Uniform(-1, 1, 5).As(); 59 | b = NN.Random.Uniform(-1, 1, 4).As(); 60 | var c = NN.Ones(5); 61 | c[Upto(4)] = b; 62 | 63 | AssertArray.AreAlmostEqual(a.Dot(c), a.DotWithBias(b)); 64 | } 65 | 66 | [TestMethod] 67 | public void TestDotWithIdentity() 68 | { 69 | var a = NN.Ones(4, 5); 70 | a[_, Upto(-1)] = NN.Eye(4); 71 | var b = NN.Random.Uniform(-1, 1, 4).As(); 72 | var c = NN.Ones(5); 73 | c[Upto(4)] = b; 74 | 75 | var ac = a.Dot(c); 76 | var ab = a.DotWithBias(b); 77 | 78 | AssertArray.AreEqual(ac, ab); 79 | } 80 | 81 | [TestMethod] 82 | public void TestDotWithBias2D_1D() 83 | { 84 | var a = NN.Array(new float[,]{ 85 | { 1, 1, 3, 1 }, 86 | { 2, 2, 6, 2 }, 87 | { 1, 1, 3, 1 } 88 | }); 89 | var b = NN.Array(-1, 1, 4); 90 | var c = NN.Ones(4); 91 | c[Upto(-1)] = b; 92 | 93 | var ac = a.Dot(c); 94 | var ab = a.DotWithBias(b); 95 | AssertArray.AreEqual(ac, ab); 96 | } 97 | 98 | [TestMethod] 99 | public void TestCombineWithBias3D_1D() 100 | { 101 | var t = NN.Ones(6, 5, 4); 102 | t[2, _, _] *= 2; 103 | t[_, 1, _] *= -1; 104 | t[_, _, 2] *= 3; 105 | 106 | var x = NN.Array(1, 2, -2); 107 | var y = NN.Array(1, -1, 3, 1); 108 | 109 | var txy = t.CombineWithBias(x, y); 110 | 111 | var xb = NN.Ones(4); 112 | xb[Upto(-1)] = x; 113 | var yb = NN.Ones(5); 114 | yb[Upto(-1)] = y; 115 | 116 | var txbyb = t.Combine(xb, yb); 117 | 118 | AssertArray.AreEqual(txbyb, txy); 119 | } 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /Proxem.NumNet.Test/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /Proxem.NumNet.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.27428.2037 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Proxem.NumNet", "Proxem.NumNet\Proxem.NumNet.csproj", "{3431C1A9-C74A-4053-ADD8-EAF174BD7A38}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Proxem.NumNet.Test", "Proxem.NumNet.Test\Proxem.NumNet.Test.csproj", "{CA9B2BC3-3F6F-47F2-AAC6-E975EE54C9A6}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Proxem.NumNet.Benchmark", "Proxem.NumNet.Benchmark\Proxem.NumNet.Benchmark.csproj", "{879C9ED5-1DC7-4F4C-BB3B-B9EE7F5B9D6B}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|Any CPU = Debug|Any CPU 15 | Debug|x64 = Debug|x64 16 | Release|Any CPU = Release|Any CPU 17 | Release|x64 = Release|x64 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {3431C1A9-C74A-4053-ADD8-EAF174BD7A38}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {3431C1A9-C74A-4053-ADD8-EAF174BD7A38}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {3431C1A9-C74A-4053-ADD8-EAF174BD7A38}.Debug|x64.ActiveCfg = Debug|Any CPU 23 | {3431C1A9-C74A-4053-ADD8-EAF174BD7A38}.Debug|x64.Build.0 = Debug|Any CPU 24 | {3431C1A9-C74A-4053-ADD8-EAF174BD7A38}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {3431C1A9-C74A-4053-ADD8-EAF174BD7A38}.Release|Any CPU.Build.0 = Release|Any CPU 26 | {3431C1A9-C74A-4053-ADD8-EAF174BD7A38}.Release|x64.ActiveCfg = Release|x64 27 | {3431C1A9-C74A-4053-ADD8-EAF174BD7A38}.Release|x64.Build.0 = Release|x64 28 | {CA9B2BC3-3F6F-47F2-AAC6-E975EE54C9A6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 29 | {CA9B2BC3-3F6F-47F2-AAC6-E975EE54C9A6}.Debug|Any CPU.Build.0 = Debug|Any CPU 30 | {CA9B2BC3-3F6F-47F2-AAC6-E975EE54C9A6}.Debug|x64.ActiveCfg = Debug|x64 31 | {CA9B2BC3-3F6F-47F2-AAC6-E975EE54C9A6}.Debug|x64.Build.0 = Debug|x64 32 | {CA9B2BC3-3F6F-47F2-AAC6-E975EE54C9A6}.Release|Any CPU.ActiveCfg = Release|Any CPU 33 | {CA9B2BC3-3F6F-47F2-AAC6-E975EE54C9A6}.Release|Any CPU.Build.0 = Release|Any CPU 34 | {CA9B2BC3-3F6F-47F2-AAC6-E975EE54C9A6}.Release|x64.ActiveCfg = Release|x64 35 | {CA9B2BC3-3F6F-47F2-AAC6-E975EE54C9A6}.Release|x64.Build.0 = Release|x64 36 | {879C9ED5-1DC7-4F4C-BB3B-B9EE7F5B9D6B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 37 | {879C9ED5-1DC7-4F4C-BB3B-B9EE7F5B9D6B}.Debug|Any CPU.Build.0 = Debug|Any CPU 38 | {879C9ED5-1DC7-4F4C-BB3B-B9EE7F5B9D6B}.Debug|x64.ActiveCfg = Debug|Any CPU 39 | {879C9ED5-1DC7-4F4C-BB3B-B9EE7F5B9D6B}.Debug|x64.Build.0 = Debug|Any CPU 40 | {879C9ED5-1DC7-4F4C-BB3B-B9EE7F5B9D6B}.Release|Any CPU.ActiveCfg = Release|Any CPU 41 | {879C9ED5-1DC7-4F4C-BB3B-B9EE7F5B9D6B}.Release|Any CPU.Build.0 = Release|Any CPU 42 | {879C9ED5-1DC7-4F4C-BB3B-B9EE7F5B9D6B}.Release|x64.ActiveCfg = Release|Any CPU 43 | {879C9ED5-1DC7-4F4C-BB3B-B9EE7F5B9D6B}.Release|x64.Build.0 = Release|Any CPU 44 | EndGlobalSection 45 | GlobalSection(SolutionProperties) = preSolution 46 | HideSolutionNode = FALSE 47 | EndGlobalSection 48 | GlobalSection(ExtensibilityGlobals) = postSolution 49 | SolutionGuid = {69398363-AC4E-40B4-8BA5-E4BFC31828EF} 50 | EndGlobalSection 51 | EndGlobal 52 | -------------------------------------------------------------------------------- /Proxem.NumNet/Double/ArrayConvolutionExtension.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | using System; 21 | 22 | using Real = System.Double; 23 | 24 | namespace Proxem.NumNet.Double 25 | { 26 | public static class ArrayConvolutionExtension 27 | { 28 | public static Array Convolve(this Array a, Array kernel, Array result = null, ConvMode mode = ConvMode.Full) 29 | { 30 | a.AssertOfDim(1); 31 | kernel.AssertOfDim(1); 32 | 33 | int na = a.Shape[0], nk = kernel.Shape[0]; 34 | if (nk > na) return kernel.Convolve(a, result: result, mode: mode); 35 | 36 | int nr, nFull = na + nk - 1; 37 | if (mode == ConvMode.Full) nr = nFull; 38 | else if (mode == ConvMode.Same) nr = na; 39 | else /* if (mode == Mode.Valid) */ nr = na - nk + 1; 40 | 41 | if (result == null) 42 | result = NN.Zeros(nr); 43 | 44 | if (mode == ConvMode.Full) 45 | for (int k = 0; k < nk; ++k) 46 | result[(k, k + na)].Acc(a, alpha: kernel.Item[k]); 47 | 48 | else if (mode == ConvMode.Same) 49 | { 50 | int delta = nk - 1; 51 | int d0 = delta / 2; 52 | int d1 = delta - d0; 53 | for (int k = 0; k < nk; ++k) 54 | { 55 | //for (int i = 0; i < na; ++i) 56 | // if (k + i - d0 >= 0 && k + i - d0 < na) 57 | // result[k + i - d0] += kernel[k] * a[i]; 58 | var iMin = Math.Max(d0 - k, 0); 59 | var iMax = Math.Min(nr + d0 - k, na); 60 | var r = result[(iMin + k - d0, iMax + k - d0)]; 61 | r.Add(a[(iMin, iMax)], alpha: kernel.Item[k], result: r); 62 | } 63 | } 64 | else if (mode == ConvMode.Valid) 65 | { 66 | int delta = 2 * nk - 2; 67 | int d0 = delta / 2; 68 | int d1 = delta - d0; 69 | for (int k = 0; k < nk; ++k) 70 | { 71 | var iMin = Math.Max(d0 - k, 0); 72 | var iMax = Math.Min(nr + d0 - k, na); 73 | result.Acc(a[(iMin, iMax)], alpha: kernel.Item[k]); 74 | } 75 | } 76 | 77 | return result; 78 | } 79 | 80 | public static Array Correlate(this Array a, Array kernel, Array result = null, ConvMode mode = ConvMode.Valid) 81 | { 82 | a.AssertOfDim(1); 83 | kernel.AssertOfDim(1); 84 | 85 | int na = a.Shape[0], nk = kernel.Shape[0]; 86 | 87 | int nr, nFull = na + nk - 1; 88 | if (mode == ConvMode.Full) nr = nFull; 89 | else if (mode == ConvMode.Same) nr = Math.Max(na, nk); 90 | else /* if (mode == Mode.Valid) */ nr = Math.Max(na, nk) - Math.Min(na, nk) + 1; 91 | 92 | if (result == null) 93 | result = NN.Zeros(nr); 94 | else 95 | result.Clear(); 96 | 97 | if (mode == ConvMode.Full) 98 | for (int k = 0; k < nk; ++k) 99 | result[(k, k + na)].Acc(a, alpha: kernel.Item[nk - 1 - k]); 100 | 101 | else if (mode == ConvMode.Same || mode == ConvMode.Valid) 102 | { 103 | int delta = nFull - nr; 104 | int d0 = delta / 2; 105 | int d1 = delta - d0; 106 | for (int k = 0; k < nk; ++k) 107 | { 108 | var iMin = Math.Max(d0 - k, 0); 109 | var iMax = Math.Min(nr + d0 - k, na); 110 | var r = result[(iMin + k - d0, iMax + k - d0)]; 111 | r.Acc(a[(iMin, iMax)], alpha: kernel.Item[nk - 1 - k]); 112 | } 113 | } 114 | 115 | return result; 116 | } 117 | 118 | public static Array Convolve2d(this Array a, Array kernel, Array result = null, ConvMode mode = ConvMode.Full) 119 | { 120 | a.AssertOfDim(2); 121 | kernel.AssertOfDim(2); 122 | 123 | int na = a.Shape[0], nk = kernel.Shape[0]; 124 | int ma = a.Shape[1], mk = kernel.Shape[1]; 125 | 126 | int nr, nFull = na + nk - 1; 127 | int mr, mFull = ma + mk - 1; 128 | if (mode == ConvMode.Full) 129 | { 130 | nr = nFull; 131 | mr = mFull; 132 | } 133 | else if (mode == ConvMode.Same) 134 | { 135 | nr = na; 136 | mr = ma; 137 | } 138 | else /* if (mode == Mode.Valid) */ 139 | { 140 | a.AssertOfDimConvolution2dValid(kernel); 141 | if (nk > na && mk > ma) 142 | return kernel.Correlate2d(a, mode: mode); 143 | nr = na - nk + 1; 144 | mr = ma - mk + 1; 145 | } 146 | 147 | if (result == null) 148 | result = NN.Zeros(nr, mr); 149 | 150 | if (mode == ConvMode.Full) 151 | { 152 | for (int k = 0; k < nr; ++k) 153 | for (int j = nk - 1; j >= 0; --j) 154 | if (k - j >= 0 && k - j < na) 155 | { 156 | result[k] += a[k - j].Convolve(kernel[j], mode: ConvMode.Full); 157 | } 158 | } 159 | else if (mode == ConvMode.Same) 160 | { 161 | for (int k = 0; k < nr; ++k) 162 | for (int j = nk - 1; j >= 0; --j) 163 | if (k - j >= 0 && k - j < na) 164 | result[k] += a[k - j].Convolve(kernel[j], mode: ConvMode.Same); 165 | } 166 | else if (mode == ConvMode.Valid) 167 | { 168 | for (int k = 0; k < nr; ++k) 169 | for (int j = nk - 1; j >= 0; --j) 170 | if (k + nk - 1 - j >= 0 && k + nk - 1 - j < na) 171 | result[k] += a[k + nk - 1 - j].Convolve(kernel[j], mode: ConvMode.Valid); 172 | } 173 | 174 | return result; 175 | } 176 | 177 | public static Array Correlate2d(this Array a, Array kernel, Array result = null, ConvMode mode = ConvMode.Valid) 178 | { 179 | a.AssertOfDim(2); 180 | kernel.AssertOfDim(2); 181 | 182 | int nk = kernel.Shape[0]; 183 | int mk = kernel.Shape[1]; 184 | int na = a.Shape[0]; 185 | int ma = a.Shape[1]; 186 | 187 | if (mode == ConvMode.Valid) 188 | { 189 | var nr = na - nk + 1; 190 | var mr = ma - mk + 1; 191 | result = NN.Zeros(nr, mr); 192 | int off_x = -1; 193 | int off_y = -1; 194 | for (int k = 0; k < nr; ++k) 195 | { 196 | ++off_x; 197 | for (int l = 0; l < mr; ++l) 198 | { 199 | ++off_y; 200 | for (int i = 0; i < nk; ++i) 201 | for (int j = 0; j < mk; ++j) 202 | result[k, l] += a[off_x + i, off_y + j] * kernel[i, j]; 203 | }; 204 | off_y = -1; 205 | }; 206 | return result; 207 | } 208 | else if (mode == ConvMode.Full) 209 | { 210 | var nr = na + nk - 1; 211 | var mr = ma + mk - 1; 212 | result = NN.Zeros(nr, mr); 213 | int off_x = -nk; 214 | int off_y = -mk; 215 | for (int k = 0; k < nr; ++k) 216 | { 217 | ++off_x; 218 | for (int l = 0; l < mr; ++l) 219 | { 220 | ++off_y; 221 | for (int i = 0; i < nk; ++i) 222 | for (int j = 0; j < mk; ++j) 223 | if ((0 <= off_x + i) && (0 <= off_y + j)) 224 | { 225 | if ((off_x + i < na) && (off_y + j < ma)) 226 | { 227 | result[k, l] += a[off_x + i, off_y + j] * kernel[i, j]; 228 | } 229 | } 230 | }; 231 | off_y = -mk; 232 | }; 233 | return result; 234 | } 235 | else 236 | { 237 | var nr = na; 238 | var mr = ma; 239 | result = NN.Zeros(nr, mr); 240 | int off_x = -1; 241 | int off_y = -1; 242 | for (int k = 0; k < nr; ++k) 243 | { 244 | ++off_x; 245 | for (int l = 0; l < mr; ++l) 246 | { 247 | ++off_y; 248 | for (int i = 0; i < nk; ++i) 249 | for (int j = 0; j < mk; ++j) 250 | if ((0 <= off_x + i) && (0 <= off_y + j)) 251 | { 252 | if ((off_x + i < na) && (off_y + j < ma)) 253 | { 254 | result[k, l] += a[off_x + i, off_y + j] * kernel[i, j]; 255 | } 256 | } 257 | }; 258 | off_y = -1; 259 | }; 260 | return result; 261 | } 262 | } 263 | } 264 | } 265 | -------------------------------------------------------------------------------- /Proxem.NumNet/Double/Operators.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | using System.Globalization; 21 | using Real = System.Double; 22 | 23 | namespace Proxem.NumNet.Double 24 | { 25 | public class Operators : Operators 26 | { 27 | public override Real Convert(int i) => i; 28 | 29 | public override Real Parse(string s) => Real.Parse(s, CultureInfo.InvariantCulture); 30 | 31 | public override sealed Real Add(Real a, Real b) => a + b; 32 | public override sealed Array Add(Array a, Array b) => a.Add(b); 33 | public sealed override Array Add(Array a, Real b) => a.Add(b); 34 | 35 | public override sealed Real Mul(Real a, Real b) => a * b; 36 | public override sealed Array Mul(Real alpha, Array a) => a.Scale(alpha); 37 | public override sealed Array Mul(Array a, Real alpha) => a.Scale(alpha); 38 | public override sealed Array Mul(Array a, Array b) => a.Mul(b); 39 | 40 | public override sealed Real Sub(Real a, Real b) => a - b; 41 | public override sealed Array Sub(Array a, Array b) => a.Add(b, alpha: -1); 42 | public sealed override Array Sub(Array a, Real b) => a.Sub(b); 43 | 44 | public override sealed Real Div(Real a, Real b) => a / b; 45 | public override sealed Array Div(Array a, Array b) => a.Div(b); 46 | public override sealed Array Div(Array a, Real b) => a * (1 / b); 47 | 48 | 49 | public override Real Neg(Real a) => -a; 50 | 51 | public override Real Gt(Real a, Real b) => a > b ? 1 : 0; 52 | 53 | public override Real GtEq(Real a, Real b) => a >= b ? 1 : 0; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Proxem.NumNet/Int32/Operators.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | using System; 21 | using System.Globalization; 22 | 23 | using Real = System.Int32; 24 | 25 | namespace Proxem.NumNet.Int32 26 | { 27 | public class Operators : Operators 28 | { 29 | public override Real Convert(int i) => i; 30 | 31 | public override Real Parse(string s) => Real.Parse(s, CultureInfo.InvariantCulture); 32 | 33 | public override sealed Real Add(Real a, Real b) => a + b; 34 | 35 | public override sealed Real Mul(Real a, Real b) => a * b; 36 | 37 | public override sealed Real Sub(Real a, Real b) => a - b; 38 | 39 | public override sealed Real Div(Real a, Real b) => a / b; 40 | 41 | public override Real Neg(Real a) => -a; 42 | 43 | public override Real Gt(Real a, Real b) => a > b ? 1 : 0; 44 | 45 | public override Real GtEq(Real a, Real b) => a >= b ? 1 : 0; 46 | } 47 | } -------------------------------------------------------------------------------- /Proxem.NumNet/NN.Dirichlet.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | using System; 21 | using System.Collections.Generic; 22 | using System.Linq; 23 | using System.Text; 24 | using System.Threading.Tasks; 25 | 26 | namespace Proxem.NumNet 27 | { 28 | public partial class NN 29 | { 30 | /// The order of the approximation. 31 | const int GammaN = 10; 32 | 33 | /// Polynomial coefficients for the approximation. 34 | static readonly double[] GammaDk = 35 | { 36 | 2.48574089138753565546e-5, 37 | 1.05142378581721974210, 38 | -3.45687097222016235469, 39 | 4.51227709466894823700, 40 | -2.98285225323576655721, 41 | 1.05639711577126713077, 42 | -1.95428773191645869583e-1, 43 | 1.70970543404441224307e-2, 44 | -5.71926117404305781283e-4, 45 | 4.63399473359905636708e-6, 46 | -2.71994908488607703910e-9 47 | }; 48 | 49 | const double GammaR = 10.900511; 50 | static double LnPi = Math.Log(Math.PI); 51 | /// The number log(2 * sqrt(e / pi)) 52 | const double LogTwoSqrtEOverPi = 0.6207822376352452223455184457816472122518527279025978; 53 | 54 | /// 55 | /// Computes the logarithm of the Gamma function. 56 | /// 57 | /// The argument of the gamma function. 58 | /// The logarithm of the gamma function. 59 | /// 60 | /// This implementation of the computation of the gamma and logarithm of the gamma function follows the derivation in 61 | /// "An Analysis Of The Lanczos Gamma Approximation", Glendon Ralph Pugh, 2004. 62 | /// We use the implementation listed on p. 116 which achieves an accuracy of 16 floating point digits. Although 16 digit accuracy 63 | /// should be sufficient for double values, improving accuracy is possible (see p. 126 in Pugh). 64 | /// Our unit tests suggest that the accuracy of the Gamma function is correct up to 14 floating point digits. 65 | /// 66 | public static double LnGamma(double z) 67 | { 68 | if (z < 0.5) 69 | { 70 | double s = GammaDk[0]; 71 | for (int i = 1; i <= GammaN; i++) 72 | { 73 | s += GammaDk[i] / (i - z); 74 | } 75 | 76 | return LnPi 77 | - Math.Log(Math.Sin(Math.PI * z)) 78 | - Math.Log(s) 79 | - LogTwoSqrtEOverPi 80 | - ((0.5 - z) * Math.Log((0.5 - z + GammaR) / Math.E)); 81 | } 82 | else 83 | { 84 | double s = GammaDk[0]; 85 | for (int i = 1; i <= GammaN; i++) 86 | { 87 | s += GammaDk[i] / (z + i - 1.0); 88 | } 89 | 90 | return Math.Log(s) 91 | + LogTwoSqrtEOverPi 92 | + ((z - 0.5) * Math.Log((z - 0.5 + GammaR) / Math.E)); 93 | } 94 | } 95 | 96 | public static double LnBeta(double alpha, int k) => k * LnGamma(alpha) - LnGamma(k * alpha); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /Proxem.NumNet/NN.Einstein.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | using System; 21 | using System.Collections.Generic; 22 | using System.Linq; 23 | using System.Text; 24 | using System.Threading.Tasks; 25 | using Proxem.BlasNet; 26 | 27 | namespace Proxem.NumNet 28 | { 29 | using static EinsteinSumTools; 30 | 31 | public static class EinsteinSumTools 32 | { 33 | public enum EinsteinMode { INNER, ELEMENTWISE, OUTERX, OUTERY, SUMX, SUMY } 34 | 35 | public struct Einstein 36 | { 37 | public int? axisX, axisY, axisZ; 38 | public EinsteinMode mode; 39 | 40 | public override string ToString() => $"{axisX},{axisY}->{mode}->{axisZ}"; 41 | } 42 | 43 | public static int[] EinsteinShape(int[] shapeX, int[] shapeY, Einstein[] einstein) 44 | { 45 | var ndim = einstein.Sum(e => e.axisZ == null ? 0 : 1); 46 | var shapeZ = new int[ndim]; 47 | 48 | foreach (var e in einstein) 49 | switch (e.mode) 50 | { 51 | case EinsteinMode.INNER: 52 | AssertArray.AreEqual(shapeX[(int)e.axisX], shapeY[(int)e.axisY]); 53 | if (e.axisZ != null) shapeZ[(int)e.axisZ] = 1; 54 | break; 55 | case EinsteinMode.ELEMENTWISE: 56 | AssertArray.AreEqual(shapeX[(int)e.axisX], shapeY[(int)e.axisY]); 57 | shapeZ[(int)e.axisZ] = shapeX[(int)e.axisX]; 58 | break; 59 | case EinsteinMode.OUTERX: 60 | shapeZ[(int)e.axisZ] = shapeX[(int)e.axisX]; 61 | break; 62 | case EinsteinMode.OUTERY: 63 | shapeZ[(int)e.axisZ] = shapeY[(int)e.axisY]; 64 | break; 65 | case EinsteinMode.SUMX: 66 | case EinsteinMode.SUMY: 67 | if (e.axisZ != null) shapeZ[(int)e.axisZ] = 1; 68 | break; 69 | } 70 | 71 | return shapeZ; 72 | } 73 | 74 | public static Tuple EinsteinSplit(string einstein) 75 | { 76 | var coma = einstein.IndexOf(','); 77 | var arrow = einstein.IndexOf("->"); 78 | 79 | var x = einstein.Substring(0, coma); 80 | var y = einstein.Substring(coma + 1, arrow - coma - 1); 81 | var z = einstein.Substring(arrow + 2); 82 | 83 | return Tuple.Create(x, y, z); 84 | } 85 | 86 | public static Einstein[] EinsteinRead(string einstein) 87 | { 88 | var xyz = EinsteinSplit(einstein); 89 | string x = xyz.Item1, y = xyz.Item2, z = xyz.Item3; 90 | 91 | var res = new List(); 92 | bool[] ytreated = new bool[y.Length]; 93 | bool[] ztreated = new bool[z.Length]; 94 | 95 | for (int axisX = 0; axisX < x.Length; ++axisX) 96 | { 97 | var a = x[axisX]; 98 | var axisY = y.IndexOf(a); 99 | if (axisY >= 0) ytreated[axisY] = true; 100 | var axisZ = z.IndexOf(a); 101 | if (axisZ >= 0) ztreated[axisZ] = true; 102 | 103 | if (axisY >= 0 && axisZ >= 0) 104 | res.Add(Elementwise(axisX, axisY, axisZ)); 105 | else if (axisY >= 0 && axisZ < 0) 106 | res.Add(Inner(axisX, axisY)); 107 | else if (axisY < 0 && axisZ >= 0) 108 | res.Add(OuterX(axisX, axisZ)); 109 | else 110 | res.Add(SumX(axisX)); 111 | } 112 | 113 | for (int axisY = 0; axisY < y.Length; ++axisY) 114 | if (!ytreated[axisY]) 115 | { 116 | var a = y[axisY]; 117 | var axisZ = z.IndexOf(a); 118 | if (axisZ >= 0) ztreated[axisZ] = true; 119 | 120 | if (axisZ >= 0) 121 | res.Add(OuterY(axisY, axisZ)); 122 | else 123 | res.Add(SumY(axisY)); 124 | } 125 | 126 | if (!ztreated.All(_ => _)) throw new Exception($"Found unbound axis on result side in {einstein}"); 127 | return res.ToArray(); 128 | } 129 | 130 | public static Einstein Inner(int axisX, int axisY, int? axisZ = null) => 131 | new Einstein { axisX = axisX, axisY = axisY, axisZ = axisZ, mode = EinsteinMode.INNER }; 132 | 133 | public static Einstein Elementwise(int axisX, int axisY, int axisZ) => 134 | new Einstein { axisX = axisX, axisY = axisY, axisZ = axisZ, mode = EinsteinMode.ELEMENTWISE }; 135 | 136 | public static Einstein OuterX(int axisX, int axisZ) => 137 | new Einstein { axisX = axisX, axisZ = axisZ, mode = EinsteinMode.OUTERX }; 138 | 139 | public static Einstein OuterY(int axisY, int axisZ) => 140 | new Einstein { axisY = axisY, axisZ = axisZ, mode = EinsteinMode.OUTERY }; 141 | 142 | public static Einstein SumX(int axisX, int? axisZ = null) => 143 | new Einstein { axisX = axisX, axisZ = axisZ, mode = EinsteinMode.SUMX }; 144 | 145 | public static Einstein SumY(int axisY, int? axisZ = null) => 146 | new Einstein { axisY = axisY, axisZ = axisZ, mode = EinsteinMode.SUMY }; 147 | } 148 | 149 | public partial class NN 150 | { 151 | public static Array EinsteinSum(Array x, Array y, string einstein, Array result = null) => 152 | EinsteinSum(x, y, EinsteinRead(einstein), result); 153 | 154 | public static Array EinsteinSum(Array x, Array y, Einstein[] einstein, Array result = null) 155 | { 156 | var resultShape = EinsteinShape(x.Shape, y.Shape, einstein); 157 | if (result == null) result = NN.Zeros(resultShape); 158 | else result.AssertOfShape(resultShape); 159 | 160 | _EinsteinSum(0, einstein, x, x.Offset, y, y.Offset, result, result.Offset); 161 | return result; 162 | } 163 | 164 | private static void _EinsteinSum(int n, Einstein[] einstein, 165 | Array x, int offX, 166 | Array y, int offY, 167 | Array z, int offZ 168 | ) 169 | { 170 | if (n == einstein.Length) 171 | { 172 | z.Values[offZ] += x.Values[offX] * y.Values[offY]; 173 | return; 174 | } 175 | 176 | var e = einstein[n]; 177 | if (n == einstein.Length - 1) 178 | { 179 | switch (e.mode) 180 | { 181 | case EinsteinMode.ELEMENTWISE: 182 | int axisX = (int)e.axisX, axisY = (int)e.axisY, axisZ = (int)e.axisZ; 183 | if (x.Stride[axisX] == 1 && y.Stride[axisY] == 1 && z.Stride[axisZ] == 1) 184 | { 185 | Blas.vmul(x.Shape[axisX], x.Values, offX, y.Values, offY, z.Values, offZ); 186 | return; 187 | } 188 | break; 189 | case EinsteinMode.OUTERX: 190 | var axis = (int)e.axisX; 191 | Blas.axpy(x.Shape[axis], y.Values[offY], x.Values, offX, x.Stride[axis], z.Values, offZ, z.Stride[(int)e.axisZ]); 192 | return; 193 | case EinsteinMode.OUTERY: 194 | axis = (int)e.axisY; 195 | Blas.axpy(y.Shape[axis], x.Values[offX], y.Values, offY, y.Stride[axis], z.Values, offZ, z.Stride[(int)e.axisZ]); 196 | return; 197 | } 198 | } 199 | 200 | switch (e.mode) 201 | { 202 | case EinsteinMode.INNER: 203 | for (int i = 0; i < x.Shape[(int)e.axisX]; ++i) 204 | { 205 | _EinsteinSum(n + 1, einstein, x, offX, y, offY, z, offZ); 206 | offX += x.Stride[(int)e.axisX]; 207 | offY += y.Stride[(int)e.axisY]; 208 | } 209 | return; 210 | case EinsteinMode.ELEMENTWISE: 211 | for (int i = 0; i < x.Shape[(int)e.axisX]; ++i) 212 | { 213 | _EinsteinSum(n + 1, einstein, x, offX, y, offY, z, offZ); 214 | offX += x.Stride[(int)e.axisX]; 215 | offY += y.Stride[(int)e.axisY]; 216 | offZ += z.Stride[(int)e.axisZ]; 217 | } 218 | return; 219 | case EinsteinMode.OUTERX: 220 | var axis = (int)e.axisX; 221 | for (int i = 0; i < x.Shape[axis]; ++i) 222 | { 223 | _EinsteinSum(n + 1, einstein, x, offX, y, offY, z, offZ); 224 | offX += x.Stride[axis]; 225 | offZ += z.Stride[(int)e.axisZ]; 226 | } 227 | return; 228 | case EinsteinMode.OUTERY: 229 | axis = (int)e.axisY; 230 | for (int i = 0; i < y.Shape[axis]; ++i) 231 | { 232 | _EinsteinSum(n + 1, einstein, x, offX, y, offY, z, offZ); 233 | offY += y.Stride[axis]; 234 | offZ += z.Stride[(int)e.axisZ]; 235 | } 236 | return; 237 | case EinsteinMode.SUMX: 238 | axis = (int)e.axisX; 239 | for (int i = 0; i < x.Shape[axis]; ++i) 240 | { 241 | _EinsteinSum(n + 1, einstein, x, offX, y, offY, z, offZ); 242 | offX += x.Stride[axis]; 243 | } 244 | return; 245 | case EinsteinMode.SUMY: 246 | axis = (int)e.axisY; 247 | for (int i = 0; i < y.Shape[axis]; ++i) 248 | { 249 | _EinsteinSum(n + 1, einstein, x, offX, y, offY, z, offZ); 250 | offY += y.Stride[axis]; 251 | } 252 | return; 253 | } 254 | } 255 | } 256 | } 257 | -------------------------------------------------------------------------------- /Proxem.NumNet/NN.Int32.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | using System; 21 | using System.Collections.Generic; 22 | using System.Linq; 23 | using System.Text; 24 | using System.Threading.Tasks; 25 | using Proxem.NumNet.Int32; 26 | 27 | using Int = System.Int32; 28 | 29 | namespace Proxem.NumNet 30 | { 31 | /// 32 | public static partial class NN 33 | { 34 | public static Int Sum(Array a) 35 | { 36 | return a.Sum(); 37 | } 38 | 39 | public static Int Max(Array a) 40 | { 41 | return a.Max(); 42 | } 43 | 44 | public static Array Max(Array a, int axis, bool keepDims = false) 45 | { 46 | return a.Max(axis, keepDims: keepDims); 47 | } 48 | 49 | public static Int Min(Array a) 50 | { 51 | return a.Min(); 52 | } 53 | 54 | public static Array Min(Array a, int axis) 55 | { 56 | return a.Min(axis); 57 | } 58 | 59 | public static Int Mean(Array a) 60 | { 61 | return a.Mean(); 62 | } 63 | 64 | public static int Argmax(Array a) 65 | { 66 | return a.Argmax(); 67 | } 68 | 69 | public static Array Argmax(Array a, int axis, Array result = null) 70 | { 71 | return a.Argmax(axis, result: result); 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /Proxem.NumNet/Operators.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | using System; 21 | using System.Collections.Generic; 22 | using System.Linq; 23 | using System.Text; 24 | using System.Threading.Tasks; 25 | 26 | namespace Proxem.NumNet 27 | { 28 | /// Default Operators class. Overriden by Double.Operators, Int32.Operators, Single.Operators. 29 | public class Operators 30 | { 31 | public virtual Type Convert(int i) 32 | { 33 | throw new InvalidOperationException(); 34 | } 35 | 36 | public virtual Type Parse(string s) 37 | { 38 | throw new InvalidOperationException(); 39 | } 40 | 41 | public virtual Type Add(Type a, Type b) 42 | { 43 | throw new InvalidOperationException(); 44 | } 45 | 46 | // Default implementation, should be overriden for float and double 47 | public virtual Array Add(Array a, Array b) => NN.Apply(a, b, (a_, b_) => Add(a_, b_)); 48 | public virtual Array Add(Type a, Array b) => NN.Apply(b, b_ => Add(a, b_)); 49 | public virtual Array Add(Array a, Type b) => NN.Apply(a, a_ => Add(a_, b)); 50 | 51 | public virtual Type Mul(Type a, Type b) 52 | { 53 | throw new InvalidOperationException(); 54 | } 55 | 56 | public virtual Array Mul(Array a, Array b) => NN.Apply(a, b, (a_, b_) => Mul(a_, b_)); 57 | public virtual Array Mul(Type a, Array b) => NN.Apply(b, b_ => Mul(a, b_)); 58 | public virtual Array Mul(Array a, Type b) => NN.Apply(a, a_ => Mul(a_, b)); 59 | 60 | public virtual Type Sub(Type a, Type b) 61 | { 62 | throw new InvalidOperationException(); 63 | } 64 | 65 | public virtual Array Sub(Array a, Array b) => NN.Apply(a, b, (a_, b_) => Sub(a_, b_)); 66 | public virtual Array Sub(Type a, Array b) => NN.Apply(b, b_ => Sub(a, b_)); 67 | public virtual Array Sub(Array a, Type b) => Add(a, Neg(b)); 68 | 69 | public virtual Type Div(Type a, Type b) 70 | { 71 | throw new InvalidOperationException(); 72 | } 73 | 74 | public virtual Array Div(Array a, Array b) => NN.Apply(a, b, (a_, b_) => Div(a_, b_)); 75 | public virtual Array Div(Type a, Array b) => NN.Apply(b, b_ => Div(a, b_)); 76 | public virtual Array Div(Array a, Type b) => NN.Apply(a, a_ => Div(a_, b)); 77 | 78 | public virtual Type Neg(Type a) 79 | { 80 | throw new InvalidOperationException(); 81 | } 82 | 83 | public virtual Array Neg(Array a) => Mul(Convert(-1), a); 84 | 85 | public virtual Type Gt(Type a, Type b) 86 | { 87 | throw new InvalidOperationException(); 88 | } 89 | 90 | public virtual Array Gt(Array a, Array b) => NN.Apply(a, b, (a_, b_) => Gt(a_, b_)); 91 | public virtual Array Gt(Type a, Array b) => NN.Apply(b, b_ => Gt(a, b_)); 92 | public virtual Array Gt(Array a, Type b) => NN.Apply(a, a_ => Gt(a_, b)); 93 | 94 | public virtual Type GtEq(Type a, Type b) 95 | { 96 | throw new InvalidOperationException(); 97 | } 98 | 99 | public virtual Array GtEq(Array a, Array b) => NN.Apply(a, b, (a_, b_) => GtEq(a_, b_)); 100 | public virtual Array GtEq(Type a, Array b) => NN.Apply(b, b_ => GtEq(a, b_)); 101 | public virtual Array GtEq(Array a, Type b) => NN.Apply(a, a_ => GtEq(a_, b)); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /Proxem.NumNet/Operators.tt: -------------------------------------------------------------------------------- 1 | <#@ template debug="false" hostspecific="true" language="C#" #> 2 | <#@include file="..\MultipleOutputHelper.ttinclude" #> 3 | <# 4 | var manager = Manager.Create(Host, GenerationEnvironment); 5 | foreach (var type in new [] { "Single", "Double" }) { 6 | manager.StartNewFile($"{type}/Operators.cs"); 7 | #> 8 | /* 9 | * Licensed to the Apache Software Foundation (ASF) under one 10 | * or more contributor license agreements. See the NOTICE file 11 | * distributed with this work for additional information 12 | * regarding copyright ownership. The ASF licenses this file 13 | * to you under the Apache License, Version 2.0 (the 14 | * "License"); you may not use this file except in compliance 15 | * with the License. You may obtain a copy of the License at 16 | * 17 | * http://www.apache.org/licenses/LICENSE-2.0 18 | * 19 | * Unless required by applicable law or agreed to in writing, software 20 | * distributed under the License is distributed on an "AS IS" BASIS, 21 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 22 | 23 | * See the License for the specific language governing permissions and 24 | * limitations under the License. 25 | */ 26 | 27 | using System.Globalization; 28 | using Real = System.<#=type#>; 29 | 30 | namespace Proxem.NumNet.<#=type#> 31 | { 32 | public class Operators : Operators 33 | { 34 | public override Real Convert(int i) => i; 35 | 36 | public override Real Parse(string s) => Real.Parse(s, CultureInfo.InvariantCulture); 37 | 38 | public override sealed Real Add(Real a, Real b) => a + b; 39 | public override sealed Array Add(Array a, Array b) => a.Add(b); 40 | public sealed override Array Add(Array a, Real b) => a.Add(b); 41 | 42 | public override sealed Real Mul(Real a, Real b) => a * b; 43 | public override sealed Array Mul(Real alpha, Array a) => a.Scale(alpha); 44 | public override sealed Array Mul(Array a, Real alpha) => a.Scale(alpha); 45 | public override sealed Array Mul(Array a, Array b) => a.Mul(b); 46 | 47 | public override sealed Real Sub(Real a, Real b) => a - b; 48 | public override sealed Array Sub(Array a, Array b) => a.Add(b, alpha: -1); 49 | public sealed override Array Sub(Array a, Real b) => a.Sub(b); 50 | 51 | public override sealed Real Div(Real a, Real b) => a / b; 52 | public override sealed Array Div(Array a, Array b) => a.Div(b); 53 | public override sealed Array Div(Array a, Real b) => a * (1 / b); 54 | 55 | 56 | public override Real Neg(Real a) => -a; 57 | 58 | public override Real Gt(Real a, Real b) => a > b ? 1 : 0; 59 | 60 | public override Real GtEq(Real a, Real b) => a >= b ? 1 : 0; 61 | } 62 | } 63 | <# 64 | manager.EndBlock(); 65 | } 66 | manager.Process(true); 67 | #> 68 | -------------------------------------------------------------------------------- /Proxem.NumNet/PCA.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | using System; 21 | 22 | namespace Proxem.NumNet 23 | { 24 | using static Slicer; 25 | 26 | public class PCA 27 | { 28 | public int nComponents; 29 | public Array components_; 30 | public Array means; 31 | 32 | public PCA(int nComponents = 0) 33 | { 34 | this.nComponents = nComponents; 35 | } 36 | 37 | public Array Fit(Array X, bool center = true) 38 | { 39 | var m = X.Shape[0]; 40 | var n = X.Shape[1]; 41 | var k = Math.Min(m, n); 42 | this.means = NN.Mean(X, axis: 0); 43 | if (center) 44 | { 45 | X -= means; 46 | } 47 | var copy = (float[])X.Values.Clone(); 48 | 49 | var s = new float[k]; 50 | var u = NN.Zeros(m, m); 51 | components_ = NN.Zeros(n, n); 52 | var superb = new float[k - 1]; 53 | BlasNet.Lapack.gesvd('A', 'A', m, n, copy, n, s, u.Values, m, components_.Values, n, superb); 54 | var components = nComponents == 0 ? k : Math.Min(k, nComponents); 55 | SVDFlip(u, components); 56 | return X; 57 | } 58 | 59 | private void SVDFlip(Array u, int k) 60 | { 61 | // Following svd_flip with u_based_decision from sklearn to flip columns of u : 62 | u = u[_, (0, Math.Min(nComponents, k))]; 63 | var maxAbsCol = NN.Argmax(NN.Abs(u), axis: 0); 64 | var signs = new Array(1, u.Shape[1]); 65 | for (int i = 0; i < u.Shape[1]; i++) 66 | { 67 | signs.Values[i] = (float)(NN.Sign(u[maxAbsCol.Values[i], i])); 68 | } 69 | u *= signs; 70 | components_ = components_[(0, Math.Min(nComponents, k)), _]; 71 | components_ *= signs.Reshape(u.Shape[1], 1); 72 | } 73 | 74 | public Array FirstComponent(Array X, bool center = true) 75 | { 76 | X = Fit(X, center); 77 | var fpc = components_[0, _]; 78 | var mpc = NN.Dot(fpc.Reshape(fpc.Shape[0], 1), fpc.Reshape(1, fpc.Shape[0])); 79 | return mpc; 80 | } 81 | 82 | public Array Transform(Array X) 83 | { 84 | AssertArray.AreEqual(X.Shape[1], components_.Shape[1]); 85 | X -= means; 86 | var reduction = NN.Dot(X, components_.T); 87 | X += means; 88 | return reduction; 89 | } 90 | public Array FitTransform(Array X, bool center = true) 91 | { 92 | X = Fit(X, center); 93 | return NN.Dot(X, components_.T); 94 | } 95 | 96 | public Array InverseTransform(Array X) 97 | { 98 | AssertArray.AreEqual(X.Shape[1], components_.Shape[0]); 99 | var XOriginal = NN.Dot(X, components_); 100 | if (means != null) 101 | { 102 | AssertArray.AreEqual(means.Shape[0], XOriginal.Shape[1]); 103 | XOriginal += means; 104 | } 105 | return XOriginal; 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /Proxem.NumNet/Proxem.NumNet.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | netstandard2.0 4 | Debug;Release 5 | AnyCPU;x64 6 | 7 | 8 | 9 | true 10 | ..\build\debug\ 11 | DEBUG;TRACE 12 | x64 13 | 1591;1573 14 | ..\doc\Proxem.NumNet.XML 15 | 16 | 17 | 18 | true 19 | ..\build\debug\ 20 | DEBUG;TRACE 21 | x64 22 | 1591;1573 23 | ..\doc\Proxem.NumNet.XML 24 | 25 | 26 | 27 | true 28 | ..\build\release\ 29 | TRACE 30 | x64 31 | true 32 | 1591;1573 33 | ..\doc\Proxem.NumNet.XML 34 | 35 | 36 | 37 | true 38 | ..\build\release\ 39 | TRACE 40 | x64 41 | true 42 | 1591;1573 43 | ..\doc\Proxem.NumNet.XML 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | TextTemplatingFileGenerator 52 | ArrayExtensions.cs 53 | 54 | 55 | TextTemplatingFileGenerator 56 | NN.Single_Double.cs 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | True 65 | True 66 | ArrayExtensions.tt 67 | 68 | 69 | True 70 | True 71 | NN.Single_Double.tt 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /Proxem.NumNet/Proxem.NumNet.sublime-project: -------------------------------------------------------------------------------- 1 | { 2 | "build_systems": 3 | [ 4 | { 5 | "name": "Build solution", 6 | "selector": ["source.cs", "source.msbuild"], 7 | "working_dir": "$project_path", 8 | "cmd": 9 | [ 10 | "msbuild", 11 | "./$project_base_name.sln" 12 | ], 13 | "file_regex": "^\\s*(.+?)\\(([0-9]+),?([0-9]+)?\\):\\s*(.*) \\[", 14 | "shell": true, 15 | "windows": 16 | { 17 | "path": "%PATH%;C:\\Program Files (x86)\\MSBuild\\14.0\\Bin" 18 | }, 19 | }, 20 | { 21 | "name": "Rebuild solution", 22 | "selector": ["source.cs", "source.msbuild"], 23 | "working_dir": "$project_path", 24 | "cmd": 25 | [ 26 | "msbuild", 27 | "./$project_base_name.sln", 28 | "/t:Rebuild" 29 | ], 30 | "file_regex": "^\\s*(.+?)\\(([0-9]+),?([0-9]+)?\\):\\s*(.*) \\[", 31 | "shell": true, 32 | "windows": 33 | { 34 | "path": "%PATH%;C:\\Program Files (x86)\\MSBuild\\14.0\\Bin" 35 | }, 36 | }, 37 | { 38 | "name": "Run all unit tests", 39 | "selector": "source.cs", 40 | "working_dir": "$project_path", 41 | "cmd": 42 | [ 43 | "C:/Program Files (x86)/Microsoft Visual Studio 14.0/Common7/IDE/CommonExtensions/Microsoft/TestWindow/vstest.console.exe", 44 | "/Settings:./Test.runsettings", 45 | "../build/debug/$project_base_name.Test.dll" 46 | ], 47 | "file_regex": "^\\s*at .* in (.*):line ([0-9]+)", 48 | "shell": true, 49 | }, 50 | { 51 | "name": "Run unit tests from file", 52 | "selector": "source.cs", 53 | "working_dir": "$project_path", 54 | "cmd": 55 | [ 56 | "C:/Program Files (x86)/Microsoft Visual Studio 14.0/Common7/IDE/CommonExtensions/Microsoft/TestWindow/vstest.console.exe", 57 | "/Settings:./Test.runsettings", 58 | "/Tests:$file_base_name", 59 | "../build/debug/$project_base_name.Test.dll" 60 | ], 61 | "file_regex": "^\\s*at .* in (.*):line ([0-9]+)", 62 | "shell": true, 63 | }, 64 | { 65 | "name": "Sphinx make html", 66 | "selector": "text.restructuredtext", 67 | "working_dir": "$project_path\\..\\doc", 68 | "cmd": ["%SPHINXBUILD%", "-b", "html", "-d", "_build/doctrees", ".", "_build/html"], 69 | "shell": true, 70 | "file_regex": "^\\s*(.*):([0-9]+):", 71 | }, 72 | { 73 | "file_regex": "^[ ]*File \"(...*?)\", line ([0-9]*)", 74 | "name": "Anaconda Python Builder", 75 | "selector": "source.python", 76 | "shell_cmd": "python -u \"$file\"" 77 | } 78 | ], 79 | "folders": 80 | [ 81 | { 82 | "path": ".", 83 | "folder_exclude_patterns": 84 | [ 85 | "obj", 86 | "bin", 87 | ".vs", 88 | "*.sln.ide", 89 | "TestResults" 90 | ], 91 | }, 92 | { 93 | "path": "..\\Proxem.NumNet.Basic", 94 | "folder_exclude_patterns": 95 | [ 96 | "obj", 97 | "bin", 98 | ".vs", 99 | "packages", 100 | "*.sln.ide", 101 | "TestResults" 102 | ], 103 | }, 104 | { 105 | "path": "..\\Proxem.NumNet.Test", 106 | "folder_exclude_patterns": 107 | [ 108 | "obj", 109 | "bin", 110 | ".vs", 111 | "packages", 112 | "*.sln.ide", 113 | "TestResults" 114 | ], 115 | }, 116 | { 117 | "path": "..\\Proxem.NumNet.HDF5", 118 | "folder_exclude_patterns": 119 | [ 120 | "obj", 121 | "bin", 122 | ".vs", 123 | "packages", 124 | "*.sln.ide", 125 | "TestResults" 126 | ], 127 | }, 128 | { 129 | "path": "..\\doc", 130 | "folder_exclude_patterns": 131 | [ 132 | "_*" 133 | ], 134 | }, 135 | ], 136 | 137 | "solution_file": "./Proxem.NumNet.sln" 138 | } 139 | -------------------------------------------------------------------------------- /Proxem.NumNet/Random.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | using System; 21 | using System.Collections.Generic; 22 | using System.Linq; 23 | using System.Text; 24 | using System.Threading.Tasks; 25 | 26 | namespace Proxem.NumNet 27 | { 28 | public class Random 29 | { 30 | internal System.Random Generator = new System.Random(1236); 31 | 32 | public System.Random Seed(int seed) 33 | { 34 | Generator = new System.Random(seed); 35 | return Generator; 36 | } 37 | 38 | public double NextDouble() 39 | { 40 | return Generator.NextDouble(); 41 | } 42 | 43 | private double NextUniform(double min, double max) => Generator.NextDouble() * (max - min) + min; 44 | public Array Uniform(double min, double max, params int[] shape) => NN.Fill(() => NextUniform(min, max), shape); 45 | public Array Uniform(double min, double max, Array result) => NN.Fill(() => NextUniform(min, max), result); 46 | 47 | private float NextUniformF(float min, float max) => (float)NextUniform(max, min); 48 | public Array Uniform(float min, float max, params int[] shape) => NN.Fill(() => NextUniformF(min, max), shape); 49 | public Array Uniform(float min, float max, Array result) => NN.Fill(() => NextUniformF(min, max), result); 50 | 51 | private T NextUniform(double min, double max, Type type) => (T)Convert.ChangeType(NextUniform(max, min), type); 52 | public Array Uniform(double min, double max, params int[] shape) => NN.Fill(() => NextUniform(min, max, typeof(T)), shape); 53 | public Array Uniform(double min, double max, Array result) => NN.Fill(() => NextUniform(min, max, typeof(T)), result); 54 | 55 | public Array Bernoulli(float p, params int[] shape) 56 | { 57 | return Bernoulli(p, new Array(shape)); 58 | } 59 | 60 | public Array Bernoulli(double p, params int[] shape) 61 | { 62 | return Bernoulli(p, new Array(shape)); 63 | } 64 | 65 | public Array Bernoulli(float p, Array result) 66 | { 67 | for (int i = 0; i < result.Values.Length; i++) // TODO: use shape 68 | { 69 | result.Values[i] = Generator.NextDouble() < p ? 1 : 0; 70 | } 71 | return result; 72 | } 73 | 74 | public Array Bernoulli(double p, Array result) 75 | { 76 | for (int i = 0; i < result.Values.Length; i++) // TODO: use shape 77 | { 78 | result.Values[i] = Generator.NextDouble() < p ? 1 : 0; 79 | } 80 | return result; 81 | } 82 | 83 | private double NextNormal(double mean, double std) 84 | { 85 | // these are Uniform(0,1) random doubles 86 | var u1 = Generator.NextDouble(); 87 | var u2 = Generator.NextDouble(); 88 | 89 | // random Normal(0,1) using a Box-Muller transform 90 | var randStdNormal = Math.Sqrt(-2.0 * Math.Log(u1)) * Math.Sin(2.0 * Math.PI * u2); 91 | 92 | // random Normal(mean, stdDev^2) 93 | var randNormal = mean + std * randStdNormal; 94 | return randNormal; 95 | } 96 | 97 | public Array Normal(double mean, double std, params int[] shape) => NN.Fill(() => NextNormal(mean, std), shape); 98 | public Array Normal(double mean, double std, Array result) => NN.Fill(() => NextNormal(mean, std), result); 99 | 100 | private float NextNormalF(float mean, float std) => (float)NextNormal(mean, std); 101 | public Array Normal(float mean, float std, params int[] shape) => NN.Fill(() => NextNormalF(mean, std), shape); 102 | public Array Normal(float mean, float std, Array result) => NN.Fill(() => NextNormalF(mean, std), result); 103 | 104 | public int NextInt(int max) => Generator.Next(max); 105 | 106 | public int Multinomial(Array distribution) 107 | { 108 | distribution.AssertOfDim(1); 109 | var total = distribution.Sum(); 110 | var x = Generator.NextDouble() * total; 111 | var stride = distribution.Stride[0]; 112 | var len = distribution.Shape[0]; 113 | var v = distribution.Values; 114 | var r = 0f; 115 | int off = 0; 116 | for(int i = 0; i < len; ++i) 117 | { 118 | r += v[off]; 119 | if (r > x) return i; 120 | off += stride; 121 | } 122 | return len - 1; 123 | } 124 | 125 | public int Multinomial(IEnumerable distribution, float sum = -1) 126 | { 127 | sum = sum < 0 ? distribution.Sum() : sum; 128 | var x = Generator.NextDouble() * sum; 129 | 130 | int i = 0; 131 | float r = 0; 132 | foreach (var d in distribution) 133 | { 134 | r += d; 135 | if (r > x) return i; 136 | ++i; 137 | } 138 | return i - 1; 139 | } 140 | 141 | /// Returns a label from the given multinomial distribution. 142 | /// The distribution, each value must be positive and represent the probabilty of the i-th label 143 | /// The sum of all values. If less than 0, the sum will be computed. 144 | /// An integer in [0:n[, where n is the size of the distribution. 145 | public int Multinomial(IEnumerable distribution, double sum = -1) 146 | { 147 | sum = sum < 0 ? distribution.Sum() : sum; 148 | var x = Generator.NextDouble() * sum; 149 | 150 | int i = 0; 151 | double r = 0; 152 | foreach(var d in distribution) 153 | { 154 | r += d; 155 | if (r > x) return i; 156 | ++i; 157 | } 158 | return i - 1; 159 | } 160 | 161 | public void Shuffle(T[] perm) 162 | { 163 | for (int i = 0; i < perm.Length; ++i) 164 | { 165 | int j = Generator.Next(perm.Length); 166 | var tmp = perm[j]; 167 | perm[j] = perm[i]; 168 | perm[i] = tmp; 169 | } 170 | } 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /Proxem.NumNet/ShapeUtil.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | using System; 21 | using System.Collections.Generic; 22 | using System.Linq; 23 | using System.Text; 24 | using System.Threading.Tasks; 25 | 26 | namespace Proxem.NumNet 27 | { 28 | public static class ShapeUtil 29 | { 30 | public static int[] RemoveAxis(int[] shape, int axis) 31 | { 32 | var resultShape = new int[shape.Length - 1]; 33 | Array.Copy(shape, 0, resultShape, 0, axis); 34 | if (axis < shape.Length - 1) 35 | Array.Copy(shape, axis + 1, resultShape, axis, shape.Length - axis - 1); 36 | return shape; 37 | } 38 | 39 | public static Array Reshape(this Array a, params int[] shape) 40 | { 41 | return a.Reshape(shape); 42 | } 43 | 44 | public static Array Transpose(this Array a, params int[] axes) 45 | { 46 | return a.Transpose(axes); 47 | } 48 | 49 | internal static int[] BroadcastShapes(int[] a, Array b) 50 | { 51 | return BroadcastShapes(a, b.Shape); 52 | } 53 | 54 | internal static int[] BroadcastShapes(Array a, Array b) 55 | { 56 | return BroadcastShapes(a.Shape, b.Shape); 57 | } 58 | 59 | // broadcasting: http://docs.scipy.org/doc/numpy/user/basics.broadcasting.html 60 | // When operating on two arrays, NumPy compares their shapes element-wise. 61 | // It starts with the trailing dimensions, and works its way forward. Two dimensions are compatible when 62 | // 1. they are equal, or 63 | // 2. one of them is 1 64 | // If these conditions are not met, a ValueError: frames are not aligned exception is thrown, indicating that the arrays have 65 | // incompatible shapes. The size of the resulting array is the maximum size along each dimension of the input arrays. 66 | public static int[] BroadcastShapes(int[] a, int[] b) 67 | { 68 | var lengthA = a.Length; 69 | var lengthB = b.Length; 70 | if (lengthA < lengthB) return BroadcastShapes(b, a); 71 | 72 | // new shape's size is largest shape's size 73 | var newShape = new int[lengthA]; 74 | 75 | // align a and b on the right 76 | // if a has trailing 1s, broadcast b on the right 77 | // a = [x y z 1 1] 78 | // b = [m n o p] 79 | // result = [. . . o p] 80 | while (lengthB > 0 && lengthA > lengthB && a[lengthA - 1] == 1) 81 | { 82 | --lengthA; 83 | --lengthB; 84 | newShape[lengthA] = b[lengthB]; 85 | } 86 | 87 | // broadcast a on the left 88 | // a = [x y z | 1 1] 89 | // b = [m n | o p] 90 | // result = [x . . | o p] 91 | for (int i = 0; i < lengthA - lengthB; i++) newShape[i] = a[i]; 92 | 93 | // for aligned axes, either y == m (resp. z == n) or one of them is 1 94 | for (int i = lengthA - lengthB; i < lengthA; i++) 95 | { 96 | var shapeA = a[i]; 97 | var shapeB = b[i - (lengthA - lengthB)]; 98 | if (shapeA != 1 && shapeB != 1 && shapeA != shapeB) 99 | throw new RankException(string.Format("operands could not be broadcast together with shapes ({0}) and ({1})", 100 | string.Join(", ", a), string.Join(", ", b))); 101 | newShape[i] = shapeA != 1 ? shapeA : shapeB; 102 | } 103 | return newShape; 104 | } 105 | 106 | internal static bool CheckShapes(int[] a, int[] b) 107 | { 108 | var lengthA = a.Length; 109 | var lengthB = b.Length; 110 | if (lengthA < lengthB) return CheckShapes(b, a); 111 | 112 | // align a and b on the right 113 | // if a has trailing 1s, broadcast b on the right 114 | // a = [x y z 1 1] 115 | // b = [m n o p] 116 | while (lengthB > 0 && lengthA > lengthB && a[lengthA - 1] == 1) 117 | { 118 | --lengthA; 119 | --lengthB; 120 | } 121 | 122 | // for aligned axes, either y == m (resp. z == n) or one of them is 1 123 | for (int i = lengthA - lengthB; i < lengthA; i++) 124 | { 125 | var shapeA = a[i]; 126 | var shapeB = b[i - (lengthA - lengthB)]; 127 | if (shapeA != 1 && shapeB != 1 && shapeA != shapeB) return false; 128 | } 129 | return true; 130 | } 131 | 132 | 133 | // check that result.Shape == BroadcastShape(a, b) without creating an intermediate array 134 | internal static bool CheckShapes(Array a, Array b, Array result) 135 | { 136 | return CheckShapes(a.Shape, b.Shape, result.Shape); 137 | } 138 | 139 | internal static bool CheckShapes(int[] a, int[] b, int[] result) 140 | { 141 | var lengthA = a.Length; 142 | var lengthB = b.Length; 143 | if (lengthA < lengthB) return CheckShapes(b, a, result); 144 | 145 | // result shape's size is largest shape's size 146 | if (result.Length != a.Length) return false; 147 | 148 | // align a and b on the right 149 | // if a has trailing 1s, broadcast b on the right 150 | // a = [x y z 1 1] 151 | // b = [m n o p] 152 | // result = [. . . o p] 153 | while (lengthB > 0 && lengthA > lengthB && a[lengthA - 1] == 1) 154 | { 155 | --lengthA; 156 | --lengthB; 157 | if (result[lengthA] != b[lengthB]) return false; 158 | } 159 | 160 | // broadcast a on the left 161 | // a = [x y z | 1 1] 162 | // b = [m n | o p] 163 | // result = [x . . | o p] 164 | for (int i = 0; i < lengthA - lengthB; i++) 165 | { 166 | if (result[i] != a[i]) return false; 167 | } 168 | 169 | // for aligned axes, either y == m (resp. z == n) or one of them is 1 170 | for (int i = lengthA - lengthB; i < lengthA; i++) 171 | { 172 | var shapeA = a[i]; 173 | var shapeB = b[i - (lengthA - lengthB)]; 174 | if (shapeA != 1 && shapeB != 1 && shapeA != shapeB) 175 | throw new RankException(string.Format("operands could not be broadcast together with shapes ({0}) and ({1})", 176 | string.Join(", ", a), string.Join(", ", b))); 177 | if (result[i] != (shapeA != 1 ? shapeA : shapeB)) return false; 178 | } 179 | return true; 180 | } 181 | 182 | public static int[] GetAggregatorResultShape(Array a, int axis, bool keepDims) 183 | { 184 | var extra = keepDims ? 1 : 0; 185 | int[] shape = new int[a.Shape.Length - 1 + extra]; 186 | Array.Copy(a.Shape, 0, shape, 0, axis); 187 | if (keepDims) shape[axis] = 1; 188 | Array.Copy(a.Shape, axis + 1, shape, axis + extra, shape.Length - axis - extra); 189 | return shape; 190 | } 191 | } 192 | } 193 | -------------------------------------------------------------------------------- /Proxem.NumNet/Single/Operators.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | using System.Globalization; 21 | using Real = System.Single; 22 | 23 | namespace Proxem.NumNet.Single 24 | { 25 | public class Operators : Operators 26 | { 27 | public override Real Convert(int i) => i; 28 | 29 | public override Real Parse(string s) => Real.Parse(s, CultureInfo.InvariantCulture); 30 | 31 | public override sealed Real Add(Real a, Real b) => a + b; 32 | public override sealed Array Add(Array a, Array b) => a.Add(b); 33 | public sealed override Array Add(Array a, Real b) => a.Add(b); 34 | 35 | public override sealed Real Mul(Real a, Real b) => a * b; 36 | public override sealed Array Mul(Real alpha, Array a) => a.Scale(alpha); 37 | public override sealed Array Mul(Array a, Real alpha) => a.Scale(alpha); 38 | public override sealed Array Mul(Array a, Array b) => a.Mul(b); 39 | 40 | public override sealed Real Sub(Real a, Real b) => a - b; 41 | public override sealed Array Sub(Array a, Array b) => a.Add(b, alpha: -1); 42 | public sealed override Array Sub(Array a, Real b) => a.Sub(b); 43 | 44 | public override sealed Real Div(Real a, Real b) => a / b; 45 | public override sealed Array Div(Array a, Array b) => a.Div(b); 46 | public override sealed Array Div(Array a, Real b) => a * (1 / b); 47 | 48 | 49 | public override Real Neg(Real a) => -a; 50 | 51 | public override Real Gt(Real a, Real b) => a > b ? 1 : 0; 52 | 53 | public override Real GtEq(Real a, Real b) => a >= b ? 1 : 0; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Proxem.NumNet/Single/TensorBias.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | using System; 21 | using System.Collections.Generic; 22 | using System.Linq; 23 | using System.Text; 24 | using System.Threading.Tasks; 25 | using Proxem.NumNet.Single; 26 | 27 | using Real = System.Single; 28 | using Proxem.BlasNet; 29 | 30 | namespace Proxem.NumNet.Single 31 | { 32 | public static class ArrayBias 33 | { 34 | public static readonly Slice _ = Slicer._; 35 | 36 | public static Array DotWithBias(this Array a, Array b, Array result = null, Real alpha = 1, Real beta = 0) 37 | { 38 | result = a[a.SlicesWithoutBias()].Dot(b, result, alpha: alpha, beta: beta); 39 | result.Acc(a[a.BiasSlice()], alpha); 40 | return result; 41 | } 42 | 43 | public static Array CombineWithBias(this Array t, Array x, Array y, 44 | Array result = null, Real beta = 0) 45 | { 46 | if (t.Shape.Length != 3 && x.Shape.Length != 1 && y.Shape.Length != 1) 47 | throw new ArgumentException(); 48 | if (t.Shape[2] != x.Shape[0] + 1 && t.Shape[1] != y.Shape[0] + 1) 49 | throw new ArgumentException(); 50 | 51 | result = t[_, Slicer.Upto(-1), Slicer.Upto(-1)].Combine21(x, y, result: result); 52 | 53 | // TODO check this mess 54 | //var biasY = t[_, Slicer.Until(-1), -1].Dot(y); 55 | t[_, Slicer.Upto(-1), -1].Dot(y, result: result, beta: 1); //Doesn't work actually 56 | //int offY = y.offset[0]; 57 | //int offT = t.offset[0] + t.offset[1] + t.offset[2] + (t.Shape[2] - 1) * t.Stride[2]; 58 | //for (int j = 0; j < y.Shape[0]; ++j) 59 | //{ 60 | // Blas.axpy(t.Shape[0], y.Values[offY], t.Values, offT, t.Stride[0], result.Values, result.offset[0], result.Stride[0]); 61 | // offY += y.Stride[0]; 62 | // offT += t.Stride[1]; 63 | //} 64 | 65 | //var biasX = t[_, -1, Slicer.Until(-1)].Dot(x); 66 | t[_, -1, Slicer.Upto(-1)].Dot(x, result: result, beta: 1); 67 | 68 | //var biasXY = t[_, -1, -1]; 69 | result.Acc(t[_, -1, -1]); 70 | 71 | //result = result + biasX + biasY + biasXY; 72 | return result; 73 | } 74 | 75 | 76 | public static Slice[] SlicesWithoutBias(this Array a) 77 | { 78 | var slices = a.Slices(); 79 | slices[slices.Length - 1] = Slicer.Upto(-1); 80 | return slices; 81 | } 82 | 83 | public static Slice[] BiasSlice(this Array a) 84 | { 85 | var slices = a.Slices(); 86 | slices[slices.Length - 1] = -1; 87 | return slices; 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /Proxem.NumNet/Slice.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | using System; 21 | using System.Collections.Generic; 22 | using System.Linq; 23 | using System.Text; 24 | using System.Threading.Tasks; 25 | 26 | namespace Proxem.NumNet 27 | { 28 | #if CSharp6 29 | public struct Slice(int start, int stop) 30 | { 31 | public int Start = start; 32 | public int Stop = stop; 33 | #else 34 | public struct Slice 35 | { 36 | public int Start; 37 | public int Stop; // MinValue => singleton, MaxValue => last dim 38 | public int Step; 39 | 40 | public Slice(int start, int stop, int step = 1) 41 | { 42 | this.Start = start; 43 | this.Stop = stop; 44 | this.Step = step; 45 | } 46 | 47 | public static implicit operator Slice(int i) => Slicer.Only(i); 48 | 49 | public static implicit operator Slice((int start, int stop) s) => new Slice(s.start, s.stop); 50 | 51 | public static implicit operator Slice((int start, int stop, int step) s) => new Slice(s.start, s.stop, s.step); 52 | 53 | public static implicit operator Slice((object start, int stop) s) => Slicer.Range(s.start, s.stop); 54 | 55 | public static implicit operator Slice((object start, int stop, int step) s) => Slicer.Range(s.start, s.stop, s.step); 56 | 57 | public static implicit operator Slice((int start, object stop) s) => Slicer.Range(s.start, s.stop); 58 | 59 | public static implicit operator Slice((int start, object stop, int step) s) => Slicer.Range(s.start, s.stop, s.step); 60 | 61 | public bool IsSingleton() 62 | { 63 | return this.Step == 0; 64 | } 65 | 66 | public bool IsNewAxis() 67 | { 68 | return this.Step == int.MaxValue; 69 | } 70 | 71 | public override string ToString() 72 | { 73 | if (this.IsSingleton()) return this.Start.ToString(); 74 | 75 | var result = new StringBuilder(); 76 | if (this.Start != 0) result.Append(this.Start); 77 | result.Append(':'); 78 | if (this.Stop != int.MaxValue) result.Append(this.Stop); 79 | if (this.Step != 1) 80 | { 81 | result.Append(':'); 82 | result.Append(this.Step); 83 | } 84 | return result.ToString(); 85 | } 86 | #endif 87 | } 88 | 89 | public static class Slicer 90 | { 91 | public static readonly Slice _ = Range(0, null); 92 | public static readonly Slice NewAxis = Range(0, 0, int.MaxValue); 93 | 94 | public static Slice Range(int start, int stop, int step = 1) 95 | { 96 | return new Slice(start, stop, step); 97 | } 98 | 99 | public static Slice Range(int start, object stop, int step = 1) 100 | { 101 | if (stop == null) return From(start, step); 102 | throw new Exception("invalid stop value"); 103 | } 104 | 105 | public static Slice Range(object start, int stop, int step = 1) 106 | { 107 | if (start == null) return Upto(stop, step); 108 | throw new Exception("invalid start value"); 109 | } 110 | 111 | public static Slice Only(int i) 112 | { 113 | return new Slice(i, i + 1, 0); 114 | } 115 | 116 | public static Slice Step(int step) 117 | { 118 | if (step < 0) return new Slice(-1, int.MinValue, step); 119 | return new Slice(0, int.MaxValue, step); 120 | } 121 | 122 | [Obsolete("Use Upto")] 123 | public static Slice Until(int stop, int step = 1) 124 | { 125 | if (step < 0) return new Slice(-1, stop, step); 126 | else return new Slice(0, stop, step); 127 | } 128 | 129 | public static Slice Upto(int stop, int step = 1) 130 | { 131 | if (step < 0) return new Slice(-1, stop, step); 132 | else return new Slice(0, stop, step); 133 | } 134 | 135 | public static Slice From(int start, int step = 1) 136 | { 137 | if (step < 0) return new Slice(start, int.MinValue, step); 138 | else return new Slice(start, int.MaxValue, step); 139 | } 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /Proxem.NumNet/Strided.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | using System; 21 | using System.Collections.Generic; 22 | using System.Linq; 23 | 24 | namespace Proxem.NumNet 25 | { 26 | using System.Runtime.CompilerServices; 27 | using static StridedExtension; 28 | using static Slicer; 29 | 30 | public class Strided 31 | { 32 | /// Shape of the arrays, ie the size of each axis of the array. 33 | public int[] Shape; 34 | 35 | /// The index of the first value of this Array in the underlying data 36 | public int Offset; 37 | 38 | /// 39 | /// For each axis the number of step needed in the underlying data array to increase this axis coordinate of 1. 40 | /// Contrary to NumPy the stride isn't measured in byte. 41 | /// See wikipedia for mor details on stride. 42 | /// 43 | public int[] Stride; 44 | 45 | /// Information about the underlying data storage 46 | public Flags Flags; 47 | 48 | /// The number of elements in this Array 49 | public int Size => ComputeSize(this.Shape); 50 | 51 | /// The number of dimensions in this Array 52 | public int NDim { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Shape.Length; } } 53 | 54 | /// Compute absolute values for negative indices 55 | public int GetAbsoluteIndex(int index, int axis) 56 | { 57 | if (index == int.MaxValue) 58 | return this.Shape[axis]; 59 | else if (index == int.MinValue) 60 | return -1; 61 | else 62 | return index >= 0 ? index : this.Shape[axis] + index; 63 | } 64 | 65 | /// Convert coordinates to offset 66 | public int RavelIndices(int i0) 67 | { 68 | if (1 > this.Shape.Length) throw new Exception("too many indices"); 69 | var dim0 = GetAbsoluteIndex(i0, 0); 70 | if (dim0 >= this.Shape[0]) throw new IndexOutOfRangeException($"index {i0} out of range 0<=index<{Shape[0]}"); 71 | return this.Offset + dim0 * this.Stride[0]; 72 | } 73 | 74 | public int RavelIndices(int i0, int i1) 75 | { 76 | if (2 > this.Shape.Length) throw new Exception("too many indices"); 77 | var dim0 = GetAbsoluteIndex(i0, 0); 78 | if (dim0 >= this.Shape[0]) throw new IndexOutOfRangeException($"index {i0} out of range 0<=index<{Shape[0]}"); 79 | var dim1 = GetAbsoluteIndex(i1, 1); 80 | if (dim1 >= this.Shape[1]) throw new IndexOutOfRangeException($"index {i1} out of range 0<=index<{Shape[1]}"); 81 | return this.Offset + dim0 * this.Stride[0] + dim1 * this.Stride[1]; 82 | } 83 | 84 | public int RavelIndices(int i0, int i1, int i2) 85 | { 86 | if (3 > this.Shape.Length) throw new Exception("too many indices"); 87 | var dim0 = GetAbsoluteIndex(i0, 0); 88 | if (dim0 >= this.Shape[0]) throw new IndexOutOfRangeException($"index {i0} out of range 0<=index<{Shape[0]}"); 89 | var dim1 = GetAbsoluteIndex(i1, 1); 90 | if (dim1 >= this.Shape[1]) throw new IndexOutOfRangeException($"index {i1} out of range 0<=index<{Shape[1]}"); 91 | var dim2 = GetAbsoluteIndex(i2, 2); 92 | if (dim2 >= this.Shape[2]) throw new IndexOutOfRangeException($"index {i2} out of range 0<=index<{Shape[2]}"); 93 | return this.Offset + dim0 * this.Stride[0] + dim1 * this.Stride[1] + dim2 * this.Stride[2]; 94 | } 95 | 96 | public int RavelIndices(params int[] indices) 97 | { 98 | if (indices.Length > this.Shape.Length) throw new Exception("too many indices"); 99 | int result = this.Offset; 100 | for (int axis = 0; axis < indices.Length; axis++) 101 | { 102 | var dim = GetAbsoluteIndex(indices[axis], axis); 103 | if (dim >= this.Shape[axis]) throw new IndexOutOfRangeException($"index {indices} out of range 0<=index<{Shape[axis]}"); 104 | result += dim * this.Stride[axis]; 105 | } 106 | return result; 107 | } 108 | 109 | protected int RavelIndicesStart(Slice[] slices) 110 | { 111 | if (slices.Length > this.Shape.Length) throw new Exception("too many indices"); 112 | int result = this.Offset; 113 | for (int axis = 0; axis < slices.Length; axis++) 114 | { 115 | var dim = GetAbsoluteIndex(slices[axis].Start, axis); 116 | if (dim >= this.Shape[axis]) throw new IndexOutOfRangeException($"index {slices} out of range 0<=index<{Shape[axis]}"); 117 | result += dim * this.Stride[axis]; 118 | } 119 | return result; 120 | } 121 | 122 | /// 123 | /// Yields the coordinate of the i-th value traversed by this tensor enumerator. 124 | /// Examples: 125 | /// 126 | /// var t = Tensor.Zeros(20, 15); 127 | /// var coord = t.Unravel(43); // = new int[]{2, 13}; 128 | /// 129 | /// 130 | public int[] UnravelIndex(int i, int[] result = null) 131 | { 132 | if (result == null) result = new int[Shape.Length]; 133 | for (int axis = Shape.Length - 1; axis >= 0; --axis) 134 | { 135 | result[axis] = i % Shape[axis]; 136 | i = i / Shape[axis]; 137 | } 138 | return result; 139 | } 140 | } 141 | 142 | public static class StridedExtension 143 | { 144 | public static Slice[] Slices(this Strided a) => a.Shape.Select(d => Range(0, d)).ToArray(); 145 | 146 | public static int ComputeSize(int[] shape) 147 | { 148 | var result = 1; 149 | for (int i = 0; i < shape.Length; i++) 150 | { 151 | result *= shape[i]; 152 | } 153 | return result; 154 | } 155 | 156 | public static int[] ComputeStride(int[] shape, int[] result = null) 157 | { 158 | result = result ?? new int[shape.Length]; 159 | var last = result.Length - 1; 160 | if (last == -1) return result; 161 | result[last] = 1; 162 | for (int i = last - 1; i >= 0; i--) 163 | { 164 | result[i] = result[i + 1] * shape[i + 1]; 165 | } 166 | return result; 167 | } 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /Proxem.NumNet/StridedUtil.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | using System; 21 | using System.Collections.Generic; 22 | using System.Linq; 23 | using System.Text; 24 | using System.Threading.Tasks; 25 | 26 | namespace Proxem.NumNet 27 | { 28 | public static class StridedUtil 29 | { 30 | public static Action StoreResult(Func f) 31 | { 32 | return (n, a, offA, strideA, b, offB, strideB, r, offR, strideR) => 33 | { 34 | for (int i = 0; i < n; ++i) 35 | { 36 | r[offR] = f(a[offA], b[offB]); 37 | offA += strideA; 38 | offB += strideB; 39 | offR += strideR; 40 | } 41 | }; 42 | } 43 | 44 | public static Action StoreResult(Func f) 45 | { 46 | return (n, a, offA, strideA, r, offR, strideR) => 47 | { 48 | for (int i = 0; i < n; ++i) 49 | { 50 | r[offR] = f(a[offA]); 51 | offA += strideA; 52 | offR += strideR; 53 | } 54 | }; 55 | } 56 | 57 | public static Action StoreResult(Func f) 58 | { 59 | return (n, r, offR, strideR) => 60 | { 61 | for (int i = 0; i < n; ++i) 62 | { 63 | r[offR] = f(); 64 | offR += strideR; 65 | } 66 | }; 67 | } 68 | 69 | public static IEnumerator Traverse(int n, T[] a, int offA, int strideA) 70 | { 71 | for (int i = 0; i < n; ++i) 72 | { 73 | yield return a[offA]; 74 | offA += strideA; 75 | } 76 | } 77 | 78 | public static Action ComputeAndStore(Func f) 79 | { 80 | return (n, a, offA, strideA, b, offB, strideB, c, offC, strideC) => 81 | { 82 | for (int i = 0; i < n; ++i) 83 | { 84 | a[offA] = f(a[offA], b[offB], c[offC]); 85 | offA += strideA; 86 | offB += strideB; 87 | offC += strideC; 88 | } 89 | }; 90 | } 91 | 92 | public static Action ComputeAndStore(Func f) 93 | { 94 | return (n, a, offA, strideA, b, offB, strideB) => 95 | { 96 | for (int i = 0; i < n; ++i) 97 | { 98 | a[offA] = f(a[offA], b[offB]); 99 | offA += strideA; 100 | offB += strideB; 101 | } 102 | }; 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /Proxem.NumNet/Test.runsettings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | .\TestResults 7 | 8 | 10 | x64 11 | 12 | 13 | Framework45 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | .*CPPUnitTestFramework.* 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | True 39 | false 40 | False 41 | False 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /Proxem.NumNet/nuspec/Proxem.NumNet.Debug.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Proxem.NumNet.Debug 5 | 1.6.3 6 | NumNet.Debug 7 | Apache-2.0 8 | https://github.com/Proxem/NumNet/blob/master/logo/proxem.png?raw=true 9 | https://github.com/Proxem/NumNet 10 | Jocelyn Coulmance, Thomas Perrais, Guillaume Wenzek, Amine Benhalloum, Jean-Marc Marty 11 | Proxem 12 | false 13 | 14 | C# scientific package containing among other things : 15 | * an N-dimensional array object and the main functions to operate on it 16 | * the main linear algebra functions on N-dimensional arrays. 17 | The syntax is mainly based on python's numpy library. MKL is used for optimized performances. 18 | 19 | Debug version 20 | 21 | arrays linear-algebra numpy machine-learning matrix 22 | Scientific package for Linear algebra operations on matrices 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /Proxem.NumNet/nuspec/Proxem.NumNet.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Proxem.NumNet 5 | 1.6.4 6 | NumNet 7 | Apache-2.0 8 | https://github.com/Proxem/NumNet/blob/master/logo/proxem.png?raw=true 9 | https://github.com/Proxem/NumNet 10 | Jocelyn Coulmance, Thomas Perrais, Guillaume Wenzek, Amine Benhalloum, Jean-Marc Marty 11 | Proxem 12 | false 13 | 14 | C# scientific package containing among other things : 15 | * an N-dimensional array object and the main functions to operate on it 16 | * the main linear algebra functions on N-dimensional arrays. 17 | The syntax is mainly based on python's numpy library. MKL is used for optimized performances. 18 | 19 | 20 | - fix bug in offset for high order tensor addition 21 | The bug was present when doing addition between tensors of different shapes, starting when one at least was of dim 3. 22 | 23 | 24 | arrays linear-algebra numpy machine-learning matrix 25 | Scientific package for Linear algebra operations on matrices 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /Proxem.NumNet/readme.txt: -------------------------------------------------------------------------------- 1 | ----------------------------------- 2 | ------- Proxem.NumNet -------- 3 | ----------------------------------- 4 | 5 | Scientific package containing : 6 | - an n-dimensional array object 7 | - basic slicing and accessing operations on array 8 | - most numpy functions on multi-dimensional array (dot, sum, mean, norm...) 9 | - higher level mathematics functions on array (PCA, eigen decomposition, etc...) 10 | 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NumNet 2 | NumNet is an optimized library for matrix operations and scientific programming written in C\# and developed at [Proxem](https://proxem.com). 3 | NumNet is inspired by python's [numpy](http://www.numpy.org/) library to facilitate its use by python developers. 4 | 5 | ## Table of contents 6 | 7 | * [Requirements](#requirements) 8 | * [Examples](#examples) 9 | * [Matrix creation](#vector-creation) 10 | * [Accessing values](accessing-values) 11 | * [Base operations](#base-operations) 12 | * [Nuget Package](#nuget-package) 13 | * [Contact](#contact) 14 | * [License](#license) 15 | 16 | ## Requirements 17 | 18 | NumNet is developed in .Net Standard 2.0 and is compatible with both .Net Framework and .Net Core thus working on Windows and Linux platform. 19 | For Mac OS users there shouldn't be any problem but we didn't test extensively. 20 | 21 | NumNet relies on **BlasNet** for the low level operations on arrays. 22 | See [BlasNet](https://github.com/Proxem/BlasNet) documentation for further information on how to use Intel's MKL for low level operations. 23 | 24 | ## Examples 25 | 26 | ### Matrix creations 27 | 28 | To create an empty 2-dimensional array of dimension 3 and 4 you can use 29 | 30 | ``` 31 | var zeroArray = NN.Zeros(3, 4); 32 | ``` 33 | 34 | The following creates a 1-dimensional array with all even number from 0 to 40 35 | 36 | ``` 37 | var range = NN.Range(0, 40, step: 2); 38 | ``` 39 | 40 | To reshape the previous array to a 2-d dimension array use `var 2dRange = range.Reshape(4, 5);`. 41 | This operation will be a O(1) if possible but it might need to copy the values 42 | (if the initial matrix is transposed or more generally if the data in the initial array are not contiguous.) 43 | 44 | Random initializations are also supported, here are a few examples of the supported distributions 45 | 46 | ``` 47 | var bern = NN.Random.Bernouilli(0.5, 2, 3); // 2 x 3 matrix 48 | var norm = NN.Random.Normal(0, 1, 10, 10); // 10 x 10 normally distributed matrix 49 | var unif = NN.Random.Uniform(-1, 1, 5, 6); // 5 x 6 uniform matrix between -1 and 1 50 | ``` 51 | 52 | ### Accessing values 53 | 54 | Let's start with a 2-d array of size (5 x 6) 55 | ``` 56 | var M = NN.Range(30).Reshape(5, 6); 57 | ``` 58 | 59 | To access a single value in the array we will use `M[i, j]`. 60 | NumNet also supports more complex slicing functions. 61 | To select the first column of the array we will use 62 | 63 | ``` 64 | var vector = M[Slicer._, 0]; // 'Slicer._' correspond to ':' in numpy 65 | ``` 66 | 67 | More control on the slices is made using the following 68 | 69 | ``` 70 | var v0 = M[0]; // [0, 1, 2, 3, 4, 5] 71 | var v1 = M[Slicer.Range(0, 3), Slicer.Upto(2)]; // [[0, 1],[6, 7],[12, 13]] 72 | var v2 = M[1, Slicer.From(1)]; // [7, 8, 9, 10, 11] 73 | var v3 = M[Slicer.Range(3, -1), -2]; // [16, 22] 74 | ``` 75 | 76 | ### Simplifying notations 77 | 78 | By using a static Slicer like 79 | 80 | ``` 81 | using static Slicer; 82 | ``` 83 | 84 | the above samples become 85 | 86 | ``` 87 | var vector = M[_, 0]; // '_' correspond to ':' in numpy 88 | ``` 89 | 90 | and 91 | 92 | ``` 93 | var v0 = M[0]; // [0, 1, 2, 3, 4, 5] 94 | var v1 = M[Range(0, 3), Upto(2)]; // numpy's equivalent of M[0:3, :2] 95 | var v2 = M[1, From(1)]; // numpy's equivalent of M[1, 1:] 96 | var v3 = M[Range(3, -1), -2]; // numpy's equivalent of M[3:-1, -2] 97 | ``` 98 | 99 | Range(start, stop) can even be abbreviated as (start, stop): 100 | 101 | ``` 102 | var v1 = M[(0, 3), Upto(2)]; // numpy's equivalent of M[0:3, :2] 103 | var v3 = M[(3, -1), -2]; // numpy's equivalent of M[3:-1, -2] 104 | ``` 105 | 106 | ### Basic operations 107 | 108 | The syntax for operations between multi-dimensional arrays is mostly the same as numpy (with Pascal Case). 109 | For instance, matrix multiplications will be done with the following code 110 | 111 | ``` 112 | var M = NN.Random.Normal(0, 1, 3, 4); 113 | var N = NN.Random.Bernouilli(0.6, 4, 5); 114 | 115 | var MN = NN.Dot(M, N) // gives a (3 x 5) matrix 116 | var MMNTranspose = NN.Dot(MN.T, M) // gives a (5 x 4) matrix 117 | ``` 118 | 119 | where `MN.T` stands for the transpose of `MN`. 120 | 121 | ### More examples 122 | 123 | Please see project NumNet.Test for other examples 124 | 125 | ### Running the tests 126 | 127 | Edit Proxem.NumNet/App.config and set "mkl:path" according to where your MKL dlls are located. 128 | In VisualStudio, either set Test|Test settings|Default Processor Architecture to X64 or load file Test.runsettings from Test|Test settings|Select Test Settings File 129 | 130 | If no "mkl:path" is found, a default managed BLAS provider is used. Note that this provider is slow and does not implement Lapack routines. 131 | 132 | ## Nuget Package 133 | 134 | We provide a Nuget Package of **NumNet** to facilitate its use. It's available on [Nuget.org](https://www.nuget.org/packages/Proxem.NumNet/). 135 | Symbols are also available to facilitate debugging inside the package. 136 | 137 | ## Disclaimer 138 | 139 | This is not an official Proxem product. 140 | 141 | ## Contact information 142 | 143 | If you can't make **NumNet** work on your computer or if you have any tracks of improvement drop us an e-mail at one of the following address: 144 | - thp@proxem.com 145 | - joc@proxem.com 146 | 147 | ## License 148 | 149 | NumNet is Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. 150 | See the NOTICE file distributed with this work for additional information regarding copyright ownership. 151 | The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. 152 | You may obtain a copy of the License at 153 | 154 | http://www.apache.org/licenses/LICENSE-2.0 155 | 156 | Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 157 | See the License for the specific language governing permissions and limitations under the License. 158 | -------------------------------------------------------------------------------- /Test.runsettings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 7 | x64 8 | 9 | 10 | -------------------------------------------------------------------------------- /create_package.cmd: -------------------------------------------------------------------------------- 1 | echo OFF 2 | echo[ 3 | echo[ 4 | echo ########################## 5 | echo ## Building NumNet ## 6 | echo ########################## 7 | echo[ 8 | echo[ 9 | 10 | dotnet build -c Release 11 | 12 | echo NumNet was built in release configuration, ready to create package 13 | pause 14 | echo[ 15 | echo[ 16 | echo ################################# 17 | echo ## Building NumNet Package ## 18 | echo ################################# 19 | echo[ 20 | echo[ 21 | 22 | nuget pack Proxem.NumNet/nuspec/Proxem.NumNet.nuspec -Symbols -OutputDirectory Proxem.NumNet/nuspec/ 23 | 24 | echo Package was created in folder Proxem.NumNet/nuspec/ 25 | pause -------------------------------------------------------------------------------- /create_package_debug.cmd: -------------------------------------------------------------------------------- 1 | echo OFF 2 | echo[ 3 | echo[ 4 | echo ########################## 5 | echo ## Building NumNet ## 6 | echo ########################## 7 | echo[ 8 | echo[ 9 | 10 | dotnet build -c Debug 11 | 12 | echo NumNet was built in debug configuration, ready to create package 13 | pause 14 | echo[ 15 | echo[ 16 | echo ################################# 17 | echo ## Building NumNet Package ## 18 | echo ################################# 19 | echo[ 20 | echo[ 21 | 22 | nuget pack Proxem.NumNet/nuspec/Proxem.NumNet.Debug.nuspec -Symbols -OutputDirectory Proxem.NumNet/nuspec/ 23 | 24 | echo Package was created in Debug mode in folder Proxem.NumNet/nuspec/ 25 | pause -------------------------------------------------------------------------------- /logo/proxem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Proxem/NumNet/12c0e1cd8790d68b89aa8935ff88b95e0d4cfa24/logo/proxem.png --------------------------------------------------------------------------------