├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md ├── _config.yml ├── benchmarks ├── bench_cpu.nim └── bench_gpu.nim ├── htmldocs ├── neo.html └── neo │ ├── core.html │ ├── cuda.html │ ├── cudadense.html │ ├── cudasparse.html │ ├── dense.html │ ├── private │ └── neocommon.html │ └── sparse.html ├── img ├── neo.png └── neo.svg ├── neo.nim ├── neo.nimble ├── neo ├── core.nim ├── cuda.nim ├── cudadense.nim ├── cudasparse.nim ├── dense.nim ├── private │ └── neocommon.nim ├── sparse.nim └── statics.nim └── tests ├── all.nim ├── allcuda.nim ├── cudadense ├── dclone.nim ├── dcopy.nim ├── dequality.nim ├── diterators.nim ├── dops.nim ├── dslice.nim └── dtrivial_ops.nim ├── cudasparse └── scopy.nim ├── dense ├── daccess.nim ├── dcollection.nim ├── dconversions.nim ├── ddecompositions.nim ├── ddet.nim ├── deigenvalues.nim ├── dequality.nim ├── dinitialize.nim ├── diterators.nim ├── dmixed_ops.nim ├── dops.nim ├── drow_major_ops.nim ├── dshared.nim ├── dslice.nim ├── dsolvers.nim ├── dstack.nim ├── dstacking.nim ├── dtrivial_ops.nim └── dufunc.nim ├── nim.cfg ├── rewrites.nim ├── sparse ├── sconversions.nim └── siterators.nim ├── statics ├── access.nim ├── collection.nim ├── compilation.nim ├── det.nim ├── eigenvalues.nim ├── equality.nim ├── initialize.nim ├── iterators.nim ├── mixed_ops.nim ├── ops.nim ├── row_major_ops.nim ├── slice.nim ├── solvers.nim ├── trivial_ops.nim └── ufunc.nim ├── tcudadense.nim ├── tcudasparse.nim ├── tdense.nim ├── tshared.nim ├── tsparse.nim └── tstatics.nim /.gitattributes: -------------------------------------------------------------------------------- 1 | htmldocs/* linguist-generated=true -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | nimcache 2 | .vscode 3 | tests/tdense 4 | tests/tcudadense 5 | tests/tsparse 6 | tests/tcudasparse 7 | tests/tstatics 8 | tests/tshared 9 | tests/all 10 | tests/allcuda 11 | tests/rewrites 12 | benchmarks/bench_cpu 13 | benchmarks/bench_gpu -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-modernist -------------------------------------------------------------------------------- /benchmarks/bench_cpu.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2017 UniCredit S.p.A. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import times, neo 16 | 17 | proc matrixMult() = 18 | let 19 | m1 = randomMatrix(1000, 987) 20 | m2 = randomMatrix(987, 876) 21 | startTime = epochTime() 22 | 23 | for i in 0 ..< 100: 24 | discard m1 * m2 25 | let endTime = epochTime() 26 | 27 | echo "We have required ", endTime - startTime, " seconds to multiply matrices 100 times." 28 | 29 | proc columnIteration() = 30 | let m = randomMatrix(1000, 987) 31 | var v = randomVector(1000) 32 | let startTime = epochTime() 33 | 34 | for col in m.columns: 35 | v += col 36 | let endTime = epochTime() 37 | 38 | echo "We have required ", endTime - startTime, " seconds to iterate 987 columns." 39 | 40 | proc columnIterationSlow() = 41 | let m = randomMatrix(1000, 987) 42 | var v = randomVector(1000) 43 | let startTime = epochTime() 44 | 45 | for col in m.columnsSlow: 46 | v += col 47 | let endTime = epochTime() 48 | 49 | echo "We have required ", endTime - startTime, " seconds to iterate 987 columns slowly." 50 | 51 | proc main() = 52 | matrixMult() 53 | columnIteration() 54 | columnIterationSlow() 55 | 56 | when isMainModule: 57 | main() -------------------------------------------------------------------------------- /benchmarks/bench_gpu.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2017 UniCredit S.p.A. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import times, neo, neo/cuda 16 | 17 | proc main() = 18 | echo "We are about to perform 100 times matrix/vector multiplication with size 10000x10000" 19 | let 20 | m = randomMatrix(10000, 10000, max = 1'f32) 21 | v = randomVector(10000, max = 1'f32) 22 | m1 = m.gpu() 23 | v1 = v.gpu() 24 | 25 | let startTime = epochTime() 26 | for i in 0 .. < 100: 27 | discard m * v 28 | let endTime = epochTime() 29 | 30 | echo "We have required ", endTime - startTime, " seconds on the CPU." 31 | 32 | let startTime1 = epochTime() 33 | for i in 0 .. < 100: 34 | discard m1 * v1 35 | let endTime1 = epochTime() 36 | 37 | echo "We have required ", endTime1 - startTime1, " seconds on the GPU." 38 | 39 | when isMainModule: 40 | main() -------------------------------------------------------------------------------- /img/neo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreaferretti/neo/6c6a81c8a3acf45a4bb117f9d04d94859b67e8c9/img/neo.png -------------------------------------------------------------------------------- /img/neo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 10 | 11 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /neo.nim: -------------------------------------------------------------------------------- 1 | import neo/dense, neo/sparse 2 | 3 | when defined(nimdoc): 4 | import neo/cuda 5 | 6 | export dense, sparse -------------------------------------------------------------------------------- /neo.nimble: -------------------------------------------------------------------------------- 1 | mode = ScriptMode.Verbose 2 | 3 | packageName = "neo" 4 | version = "0.3.5" 5 | author = "Andrea Ferretti" 6 | description = "Linear Algebra for Nim" 7 | license = "Apache2" 8 | skipDirs = @["tests", "benchmarks", "htmldocs"] 9 | skipFiles = @["_config.yml"] 10 | 11 | requires "nim >= 0.18.0", "nimblas >= 0.2.0", "nimcuda >= 0.1.6", 12 | "nimlapack >= 0.1.1" 13 | 14 | --forceBuild 15 | 16 | when defined(nimdistros): 17 | import distros 18 | if detectOs(Ubuntu) or detectOs(Debian): 19 | foreignDep "libblas-dev" 20 | foreignDep "libopenblas-dev" 21 | foreignDep "liblapack-dev" 22 | elif detectOs(MacOsX): 23 | foreignDep "liblas" 24 | foreignDep "lapack" 25 | else: 26 | foreignDep "libblas" 27 | foreignDep "liblapack" 28 | 29 | proc configForTests() = 30 | --hints: off 31 | --linedir: on 32 | --stacktrace: on 33 | --linetrace: on 34 | --debuginfo 35 | --path: "." 36 | --run 37 | 38 | proc configForBenchmarks() = 39 | --define: release 40 | --path: "." 41 | --run 42 | 43 | task test, "run CPU tests": 44 | configForTests() 45 | setCommand "c", "tests/all.nim" 46 | 47 | task testdense, "run CPU dense tests": 48 | configForTests() 49 | setCommand "c", "tests/tdense.nim" 50 | 51 | task testsparse, "run CPU sparse tests": 52 | configForTests() 53 | setCommand "c", "tests/tsparse.nim" 54 | 55 | task teststatic, "run CPU static tests": 56 | configForTests() 57 | setCommand "c", "tests/tstatics.nim" 58 | 59 | task testshared, "run CPU shared heap tests": 60 | configForTests() 61 | --threads:on 62 | setCommand "c", "tests/tshared.nim" 63 | 64 | task testopenblas, "run CPU tests on openblas": 65 | configForTests() 66 | --define:"blas=openblas" 67 | --define:"lapack=openblas" 68 | setCommand "c", "tests/all.nim" 69 | 70 | task testmkl, "run CPU tests on mkl": 71 | configForTests() 72 | --define:"blas=mkl_intel_lp64" 73 | --clibdir: "/opt/intel/mkl/lib/intel64" 74 | --passl: "/opt/intel/mkl/lib/intel64/libmkl_intel_lp64.a" 75 | --passl: "-lmkl_core" 76 | --passl: "-lmkl_sequential" 77 | --passl: "-lpthread" 78 | --passl: "-lm" 79 | --dynlibOverride:mkl_intel_lp64 80 | setCommand "c", "tests/all.nim" 81 | 82 | task compilecuda, "only compile GPU tests (when not having a GPU)": 83 | --hints: off 84 | --linedir: on 85 | --stacktrace: on 86 | --linetrace: on 87 | --debuginfo 88 | --path: "." 89 | --compileOnly 90 | setCommand "c", "tests/allcuda.nim" 91 | 92 | task testcuda, "run GPU tests": 93 | configForTests() 94 | --gc:markAndSweep # TODO: remove temporary workaround 95 | setCommand "c", "tests/allcuda.nim" 96 | 97 | task testcudadense, "run GPU dense tests": 98 | configForTests() 99 | setCommand "c", "tests/tcudadense.nim" 100 | 101 | task testcudasparse, "run GPU sparse tests": 102 | configForTests() 103 | setCommand "c", "tests/tcudasparse.nim" 104 | 105 | task testrw, "run tests for rewrite macros": 106 | configForTests() 107 | --define:neoCountRewrites 108 | setCommand "c", "tests/rewrites.nim" 109 | 110 | task benchmark, "run CPU benchmarks": 111 | configForBenchmarks() 112 | setCommand "c", "benchmarks/bench_cpu.nim" 113 | 114 | task benchmarkcuda, "run GPU benchmarks": 115 | configForBenchmarks() 116 | setCommand "c", "benchmarks/bench_gpu.nim" 117 | 118 | task docs, "generate documentation": 119 | exec("mkdir -p htmldocs/neo") 120 | --project 121 | --git.url: "https://github.com/andreaferretti/neo" 122 | --git.commit: master 123 | setCommand "doc", "neo.nim" -------------------------------------------------------------------------------- /neo/core.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2017 UniCredit S.p.A. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | type 16 | Complex*[A] = tuple[re, im: A] 17 | Scalar* = float32 or float64 or Complex[float32] or Complex[float64] 18 | CPointer*[A] = ptr UncheckedArray[A] 19 | 20 | type 21 | DimensionError* = object of ValueError 22 | OutOfBoundsError* = object of ValueError 23 | LinearAlgebraError* = object of FloatingPointError 24 | 25 | template checkDim*(cond: untyped, msg = "") = 26 | when compileOption("assertions"): 27 | {.line.}: 28 | if not cond: 29 | raise newException(DimensionError, msg) 30 | 31 | template checkBounds*(cond: untyped, msg = "") = 32 | when compileOption("assertions"): 33 | {.line.}: 34 | if not cond: 35 | raise newException(OutOfBoundsError, msg) -------------------------------------------------------------------------------- /neo/cuda.nim: -------------------------------------------------------------------------------- 1 | import ./cudadense, ./cudasparse 2 | 3 | export cudadense, cudasparse -------------------------------------------------------------------------------- /neo/cudadense.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2017 UniCredit S.p.A. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import nimcuda/[cuda_runtime_api, driver_types, cublas_api, cublas_v2, nimcuda] 16 | import ./core, ./dense, ./private/neocommon 17 | 18 | type 19 | CudaVector*[A] = object 20 | data*: ref[ptr A] 21 | fp*: ptr A 22 | len, step*: int32 23 | CudaMatrix*[A] = object 24 | M*, N*, ld*: int32 25 | data*: ref[ptr A] 26 | fp*: ptr A 27 | shape*: set[MatrixShape] 28 | 29 | proc cudaMalloc[A](size: int): ptr A = 30 | let s = size * sizeof(A) 31 | check cudaMalloc(cast[ptr pointer](addr result), s) 32 | 33 | proc freeDeviceMemory[A](p: ref[ptr A]) = 34 | if not p[].isNil: 35 | check cudaFree(p[]) 36 | 37 | proc isContiguous*(v: CudaVector): bool {.inline.} = 38 | v.step == 1 39 | 40 | proc isContiguous*(m: CudaMatrix): bool {.inline.} = 41 | m.M == m.ld 42 | 43 | # Initializing matrices 44 | 45 | template init*[A](v: CudaVector[A], n: int) = 46 | new v.data, freeDeviceMemory 47 | v.fp = cudaMalloc[A](n) 48 | v.data[] = v.fp 49 | v.len = n.int32 50 | v.step = 1 51 | 52 | template init*[A](v: CudaMatrix[A], m, n: int) = 53 | new v.data, freeDeviceMemory 54 | v.fp = cudaMalloc[A](m * n) 55 | v.data[] = v.fp 56 | v.M = m.int32 57 | v.N = n.int32 58 | v.ld = m.int32 59 | 60 | proc newCudaVector*[A](n: int): CudaVector[A] {.inline.} = 61 | init(result, n) 62 | 63 | proc newCudaMatrix*[A](m, n: int): CudaMatrix[A] {.inline.} = 64 | init(result, m, n) 65 | 66 | # Copying between host and device 67 | 68 | proc gpu*[A](v: Vector[A]): CudaVector[A] = 69 | init(result, v.len) 70 | check cublasSetVector(v.len.int32, sizeof(A).int32, v.fp, v.step.int32, result.fp, result.step) 71 | 72 | proc gpu*[A](m: Matrix[A]): CudaMatrix[A] = 73 | if m.order == rowMajor: 74 | raise newException(ValueError, "m must be column major") 75 | init(result, m.M, m.N) 76 | check cublasSetMatrix(m.M.int32, m.N.int32, sizeof(A).int32, m.fp, m.ld.int32, result.fp, result.ld) 77 | 78 | proc cpu*[A](v: CudaVector[A]): Vector[A] = 79 | result = zeros(v.len, A) 80 | check cublasGetVector(v.len, sizeof(A).int32, v.fp, v.step, result.fp, result.step.int32) 81 | 82 | proc cpu*[A](m: CudaMatrix[A]): Matrix[A] = 83 | result = zeros(m.M, m.N, A, colMajor) 84 | check cublasGetMatrix(m.M, m.N, sizeof(A).int32, m.fp, m.ld, result.fp, result.ld.int32) 85 | 86 | # Printing 87 | 88 | proc `$`*[A](v: CudaVector[A]): string = $(v.cpu()) 89 | 90 | proc `$`*[A](m: CudaMatrix[A]): string = $(m.cpu()) 91 | 92 | # Equality 93 | 94 | proc `==`*[A](m, n: CudaVector[A]): bool = 95 | m.cpu() == n.cpu() 96 | 97 | proc `==`*[A](m, n: CudaMatrix[A]): bool = 98 | m.cpu() == n.cpu() 99 | 100 | # Conversion 101 | 102 | proc clone*[A](v: CudaVector[A]): CudaVector[A] = 103 | init(result, v.len) 104 | check cublasSetVector(v.len, sizeof(A).int32, v.fp, v.step, result.fp, result.step) 105 | 106 | proc clone*[A](m: CudaMatrix[A]): CudaMatrix[A] = 107 | init(result, m.M, m.N) 108 | check cublasSetMatrix(m.M, m.N, sizeof(A).int32, m.fp, m.ld, result.fp, result.ld) 109 | 110 | # CUBLAS overloads 111 | 112 | var defaultHandle: cublasHandle_t 113 | check cublasCreate_v2(addr defaultHandle) 114 | 115 | overload(scal, cublasSscal, cublasDscal) 116 | overload(axpy, cublasSaxpy, cublasDaxpy) 117 | overload(asum, cublasSasum, cublasDasum) 118 | overload(nrm2, cublasSnrm2, cublasDnrm2) 119 | overload(dot, cublasSdot, cublasDdot) 120 | overload(copy, cublasScopy, cublasDcopy) 121 | overload(gemv, cublasSgemv, cublasDgemv) 122 | overload(gemm, cublasSgemm, cublasDgemm) 123 | overload(geam, cublasSgeam, cublasDgeam) 124 | 125 | # Slicing 126 | 127 | proc `[]`*[A](v: CudaVector[A], s: Slice[int]): CudaVector[A] = 128 | checkBounds(s.a >= 0 and s.b < v.len) 129 | let 130 | vp = cast[CPointer[A]](v.fp) 131 | fp = addr(vp[s.a * v.step]) 132 | result = CudaVector[A]( 133 | len: (s.b - s.a + 1).int32, 134 | step: v.step, 135 | data: v.data, 136 | fp: fp 137 | ) 138 | 139 | proc pointerAt[A](v: CudaVector[A], i: int): ptr A {. inline .} = 140 | let s = cast[CPointer[A]](v.fp) 141 | addr s[i * v.step] 142 | 143 | proc `[]=`*[A: SomeFloat](v: var CudaVector[A], s: Slice[int], val: CudaVector[A]) {. inline .} = 144 | checkBounds(s.a >= 0 and s.b < v.len) 145 | checkDim(s.len == val.len) 146 | check copy(defaultHandle, val.len, val.fp, val.step, v.pointerAt(s.a), v.step) 147 | 148 | proc `[]`*[A](m: CudaMatrix[A], rows, cols: Slice[int]): CudaMatrix[A] = 149 | checkBounds(rows.a >= 0 and rows.b < m.M) 150 | checkBounds(cols.a >= 0 and cols.b < m.N) 151 | let 152 | mp = cast[CPointer[A]](m.fp) 153 | fp = addr(mp[cols.a * m.ld + rows.a]) 154 | result = CudaMatrix[A]( 155 | M: (rows.b - rows.a + 1).int32, 156 | N: (cols.b - cols.a + 1).int32, 157 | ld: m.ld, 158 | data: m.data, 159 | fp: fp 160 | ) 161 | 162 | proc `[]`*[A](m: CudaMatrix[A], rows: Slice[int], cols: typedesc[All]): CudaMatrix[A] = 163 | m[rows, 0 ..< m.N.int] 164 | 165 | proc `[]`*[A](m: CudaMatrix[A], rows: typedesc[All], cols: Slice[int]): CudaMatrix[A] = 166 | m[0 ..< m.M.int, cols] 167 | 168 | proc `[]=`*[A: SomeFloat](m: var CudaMatrix[A], rows, cols: Slice[int], val: CudaMatrix[A]) {. inline .} = 169 | checkBounds(rows.a >= 0 and rows.b < m.M) 170 | checkBounds(cols.a >= 0 and cols.b < m.N) 171 | checkDim(rows.len == val.M) 172 | checkDim(cols.len == val.N) 173 | let 174 | mp = cast[CPointer[A]](m.fp) 175 | vp = cast[CPointer[A]](val.fp) 176 | var col = 0 177 | for c in cols: 178 | check copy(defaultHandle, val.M, addr vp[col * val.ld], 1, addr mp[c * m.ld + rows.a], 1) 179 | col += 1 180 | 181 | proc column*[A](m: CudaMatrix[A], j: int): CudaVector[A] {. inline .} = 182 | checkBounds(j >= 0 and j < m.N) 183 | let mp = cast[CPointer[A]](m.fp) 184 | result = CudaVector[A]( 185 | data: m.data, 186 | fp: addr(mp[j * m.ld]), 187 | len: m.M, 188 | step: 1 189 | ) 190 | 191 | proc row*[A](m: CudaMatrix[A], i: int): CudaVector[A] {. inline .} = 192 | checkBounds(i >= 0 and i < m.M) 193 | let mp = cast[CPointer[A]](m.fp) 194 | result = CudaVector[A]( 195 | data: m.data, 196 | fp: addr(mp[i]), 197 | len: m.N, 198 | step: m.ld 199 | ) 200 | 201 | # Iterators 202 | 203 | iterator columns*[A](m: CudaMatrix[A]): auto {. inline .} = 204 | let mp = cast[CPointer[A]](m.fp) 205 | var v = m.column(0) 206 | yield v 207 | for j in 1 ..< m.N: 208 | v.fp = addr(mp[j * m.ld]) 209 | yield v 210 | 211 | iterator rows*[A](m: CudaMatrix[A]): auto {. inline .} = 212 | let mp = cast[CPointer[A]](m.fp) 213 | var v = m.row(0) 214 | yield v 215 | for i in 1 ..< m.M: 216 | v.fp = addr(mp[i]) 217 | yield v 218 | 219 | iterator columnsSlow*[A](m: CudaMatrix[A]): auto {. inline .} = 220 | for i in 0 ..< m.N: 221 | yield m.column(i) 222 | 223 | iterator rowsSlow*[A](m: CudaMatrix[A]): auto {. inline .} = 224 | for i in 0 ..< m.M: 225 | yield m.row(i) 226 | 227 | # Trivial operations 228 | 229 | proc reshape*[A](m: CudaMatrix[A], a, b: int): CudaMatrix[A] = 230 | if m.isContiguous: 231 | checkDim(m.M * m.N == a * b, "The dimensions do not match: M = " & $(m.M) & ", N = " & $(m.N) & ", A = " & $(a) & ", B = " & $(b)) 232 | result = CudaMatrix[A]( 233 | M: a.int32, 234 | N: b.int32, 235 | ld: a.int32, 236 | data: m.data, 237 | fp: m.fp 238 | ) 239 | else: 240 | result = m.clone().reshape(a, b) 241 | 242 | proc asMatrix*[A](v: CudaVector[A], a, b: int): CudaMatrix[A] = 243 | if v.isContiguous: 244 | checkDim(v.len == a * b, "The dimensions do not match: N = " & $(v.len) & ", A = " & $(a) & ", B = " & $(b)) 245 | result = CudaMatrix[A]( 246 | M: a.int32, 247 | N: b.int32, 248 | ld: a.int32, 249 | data: v.data, 250 | fp: v.fp 251 | ) 252 | else: 253 | result = v.clone().asMatrix(a, b) 254 | 255 | proc asVector*[A](m: CudaMatrix[A]): CudaVector[A] = 256 | if m.isContiguous: 257 | CudaVector[A]( 258 | len: m.M * m.N, 259 | step: 1, 260 | data: m.data, 261 | fp: m.fp 262 | ) 263 | else: 264 | m.clone().asVector() 265 | 266 | # BLAS level 1 operations 267 | 268 | proc `*=`*[A: SomeFloat](v: var CudaVector[A], k: A) {. inline .} = 269 | var k1 = k 270 | check scal(defaultHandle, v.len, addr(k1), v.fp, v.step) 271 | 272 | proc `*`*[A: SomeFloat](v: CudaVector[A], k: A): CudaVector[A] {. inline .} = 273 | init(result, v.len) 274 | check copy(defaultHandle, v.len, v.fp, v.step, result.fp, result.step) 275 | result *= k 276 | 277 | proc `+=`*[A: SomeFloat](v: var CudaVector[A], w: CudaVector[A]) {. inline .} = 278 | checkDim(v.len == w.len) 279 | var alpha: A = 1 280 | check axpy(defaultHandle, v.len, addr(alpha), w.fp, w.step, v.fp, v.step) 281 | 282 | proc `+`*[A: SomeFloat](v, w: CudaVector[A]): CudaVector[A] {. inline .} = 283 | checkDim(v.len == w.len) 284 | init(result, v.len) 285 | check copy(defaultHandle, v.len, v.fp, v.step, result.fp, result.step) 286 | result += w 287 | 288 | proc `-=`*[A: SomeFloat](v: var CudaVector[A], w: CudaVector[A]) {. inline .} = 289 | checkDim(v.len == w.len) 290 | var alpha: A = -1 291 | check axpy(defaultHandle, v.len, addr(alpha), w.fp, w.step, v.fp, v.step) 292 | 293 | proc `-`*[A: SomeFloat](v, w: CudaVector[A]): CudaVector[A] {. inline .} = 294 | checkDim(v.len == w.len) 295 | init(result, v.len) 296 | check copy(defaultHandle, v.len, v.fp, v.step, result.fp, result.step) 297 | result -= w 298 | 299 | proc `*`*[A: SomeFloat](v, w: CudaVector[A]): A {. inline .} = 300 | checkDim(v.len == w.len) 301 | check dot(defaultHandle, v.len, v.fp, v.step, w.fp, w.step, addr(result)) 302 | 303 | proc l_2*[A: SomeFloat](v: CudaVector[A]): A {. inline .} = 304 | check nrm2(defaultHandle, v.len, v.fp, v.step, addr(result)) 305 | 306 | proc l_1*[A: SomeFloat](v: CudaVector[A]): A {. inline .} = 307 | check asum(defaultHandle, v.len, v.fp, v.step, addr(result)) 308 | 309 | proc `*=`*[A: SomeFloat](m: var CudaMatrix[A], k: A) {. inline .} = 310 | var k1 = k 311 | if m.isContiguous: 312 | check scal(defaultHandle, m.M * m.N, addr(k1), m.fp, 1) 313 | else: 314 | for c in m.columns: 315 | check scal(defaultHandle, c.len, addr(k1), c.fp, c.step) 316 | 317 | proc `*`*[A: SomeFloat](m: CudaMatrix[A], k: A): CudaMatrix[A] {. inline .} = 318 | if m.isContiguous: 319 | init(result, m.M, m.N) 320 | check copy(defaultHandle, m.M * m.N, m.fp, 1, result.fp, 1) 321 | else: 322 | result = m.clone() 323 | result *= k 324 | 325 | template `*`*[A: SomeFloat](k: A, v: CudaVector[A] or CudaMatrix[A]): auto = 326 | v * k 327 | 328 | template `/`*[A: SomeFloat](v: CudaVector[A] or CudaMatrix[A], k: A): auto = 329 | v * (1 / k) 330 | 331 | template `/=`*[A: SomeFloat](v: var CudaVector[A] or var CudaMatrix[A], k: A) = 332 | v *= (1 / k) 333 | 334 | proc `+=`*[A: SomeFloat](a: var CudaMatrix[A], b: CudaMatrix[A]) {. inline .} = 335 | checkDim(a.M == b.M and a.N == a.N) 336 | var alpha: A = 1 337 | check geam(defaultHandle, CUBLAS_OP_N, CUBLAS_OP_N, a.M, a.N, addr(alpha), 338 | a.fp, a.ld, addr(alpha), b.fp, b.ld, a.fp, a.ld) 339 | 340 | proc `+`*[A: SomeFloat](a, b: CudaMatrix[A]): CudaMatrix[A] {. inline .} = 341 | checkDim(a.M == b.M and a.N == a.N) 342 | init(result, a.M, a.N) 343 | var alpha: A = 1 344 | check geam(defaultHandle, CUBLAS_OP_N, CUBLAS_OP_N, a.M, a.N, addr(alpha), 345 | a.fp, a.ld, addr(alpha), b.fp, b.ld, result.fp, result.ld) 346 | 347 | proc `-=`*[A: SomeFloat](a: var CudaMatrix[A], b: CudaMatrix[A]) {. inline .} = 348 | checkDim(a.M == b.M and a.N == a.N) 349 | var 350 | alpha: A = 1 351 | beta: A = -1 352 | check geam(defaultHandle, CUBLAS_OP_N, CUBLAS_OP_N, a.M, a.N, addr(alpha), 353 | a.fp, a.ld, addr(beta), b.fp, b.ld, a.fp, a.ld) 354 | 355 | proc `-`*[A: SomeFloat](a, b: CudaMatrix[A]): CudaMatrix[A] {. inline .} = 356 | checkDim(a.M == b.M and a.N == a.N) 357 | init(result, a.M, a.N) 358 | var 359 | alpha: A = 1 360 | beta: A = -1 361 | check geam(defaultHandle, CUBLAS_OP_N, CUBLAS_OP_N, a.M, a.N, addr(alpha), 362 | a.fp, a.ld, addr(beta), b.fp, b.ld, result.fp, result.ld) 363 | 364 | proc l_2*[A: SomeFloat](m: CudaMatrix[A]): A {. inline .} = 365 | if m.isContiguous: 366 | check nrm2(defaultHandle, m.M * m.N, m.fp, 1, addr(result)) 367 | else: 368 | result = l_2(m.clone()) 369 | 370 | proc l_1*[A: SomeFloat](m: CudaMatrix[A]): A {. inline .} = 371 | if m.isContiguous: 372 | check asum(defaultHandle, m.M * m.N, m.fp, 1, addr(result)) 373 | else: 374 | result = l_1(m.clone()) 375 | 376 | proc T*[A](m: CudaMatrix[A]): CudaMatrix[A] = 377 | init(result, m.N, m.M) 378 | var 379 | alpha: A = 1 380 | beta: A = 0 381 | check geam(defaultHandle, CUBLAS_OP_T, CUBLAS_OP_T, m.N, m.M, addr(alpha), 382 | m.fp, m.ld, addr(beta), m.fp, m.ld, result.fp, result.ld) 383 | 384 | # BLAS level 2 operations 385 | 386 | proc `*`*[A: SomeFloat](a: CudaMatrix[A], v: CudaVector[A]): CudaVector[A] {. inline .} = 387 | checkDim(a.N == v.len) 388 | init(result, a.M) 389 | var 390 | alpha: A = 1 391 | beta: A = 0 392 | check gemv(defaultHandle, CUBLAS_OP_N, a.M, a.N, addr(alpha), a.fp, a.ld, 393 | v.fp, v.step, addr(beta), result.fp, result.step) 394 | 395 | # BLAS level 3 operations 396 | 397 | proc `*`*[A: SomeFloat](a, b: CudaMatrix[A]): CudaMatrix[A] {. inline .} = 398 | checkDim(a.N == b.M) 399 | init(result, a.M, b.N) 400 | var 401 | alpha: A = 1 402 | beta: A = 0 403 | let x = gemm(defaultHandle, CUBLAS_OP_N, CUBLAS_OP_N, a.M, b.N, a.N, 404 | addr(alpha), a.fp, a.ld, b.fp, b.ld, addr(beta), result.fp, result.ld) 405 | 406 | # Comparison 407 | 408 | template compareApprox(a, b: CudaVector or CudaMatrix): bool = 409 | const epsilon = 0.000001 410 | if a == b: true 411 | else: 412 | let 413 | aNorm = l_1(a) 414 | bNorm = l_1(b) 415 | dNorm = l_1(a - b) 416 | (dNorm / (aNorm + bNorm)) < epsilon 417 | 418 | proc `=~`*[A: SomeFloat](v, w: CudaVector[A]): bool = compareApprox(v, w) 419 | 420 | proc `=~`*[A: SomeFloat](v, w: CudaMatrix[A]): bool = compareApprox(v, w) 421 | 422 | template `!=~`*(a, b: CudaVector or CudaMatrix): bool = not (a =~ b) -------------------------------------------------------------------------------- /neo/cudasparse.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2017 UniCredit S.p.A. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import sequtils 16 | import nimcuda/[cuda_runtime_api, driver_types, cusparse, nimcuda] 17 | import ./core, ./sparse, ./private/neocommon 18 | 19 | type 20 | CudaSparseVectorObj*[A] = object 21 | N*, nnz*: int32 22 | indices*: ptr int32 23 | vals*: ptr A 24 | CudaSparseVector*[A] = ref CudaSparseVectorObj[A] 25 | CudaSparseMatrixObj*[A] = object 26 | kind*: SparseMatrixKind 27 | M*, N*, nnz*: int32 28 | rows*, cols*: ptr int32 29 | vals*: ptr A 30 | CudaSparseMatrix*[A] = ref CudaSparseMatrixObj[A] 31 | 32 | proc dealloc*[A](v: CudaSparseVector[A]) = 33 | if v.indices != nil: check cudaFree(v.indices) 34 | if v.vals != nil: check cudaFree(v.vals) 35 | 36 | proc dealloc*[A](m: CudaSparseMatrix[A]) = 37 | if m.rows != nil: check cudaFree(m.rows) 38 | if m.cols != nil: check cudaFree(m.cols) 39 | if m.vals != nil: check cudaFree(m.vals) 40 | 41 | proc rowLen*(m: CudaSparseMatrix): int32 = 42 | case m.kind 43 | of CSR: m.M + 1 44 | of CSC, COO: m.nnz 45 | 46 | proc colLen*(m: CudaSparseMatrix): int32 = 47 | case m.kind 48 | of CSR, COO: m.nnz 49 | of CSC: m.N + 1 50 | 51 | proc sizes[A](m: SparseVector[A] or CudaSparseVector[A]): tuple[i, v: int32] = 52 | ( 53 | (m.N * sizeof(int32)).int32, 54 | (m.nnz * sizeof(A)).int32 55 | ) 56 | 57 | proc sizes[A](m: SparseMatrix[A] or CudaSparseMatrix[A]): tuple[r, c, v: int32] = 58 | ( 59 | (m.rowLen * sizeof(int32)).int32, 60 | (m.colLen * sizeof(int32)).int32, 61 | (m.nnz * sizeof(A)).int32 62 | ) 63 | 64 | var defaultHandle: cusparseHandle_t 65 | check cusparseCreate(addr defaultHandle) 66 | 67 | const idx = CUSPARSE_INDEX_BASE_ZERO 68 | 69 | template allocateAll(x, r, c, v: untyped) = 70 | check cudaMalloc(pointerTo x.rows, r) 71 | check cudaMalloc(pointerTo x.cols, c) 72 | check cudaMalloc(pointerTo x.vals, v) 73 | 74 | proc gpu*[A: Scalar](v: SparseVector[A]): CudaSparseVector[A] = 75 | new result, dealloc 76 | result.N = v.N 77 | result.nnz = v.nnz 78 | let (iLen, vLen) = v.sizes 79 | check cudaMalloc(pointerTo result.indices, iLen) 80 | check cudaMalloc(pointerTo result.vals, vLen) 81 | check cudaMemcpy(result.indices, v.indices.first, iLen, cudaMemcpyHostToDevice) 82 | check cudaMemcpy(result.vals, v.vals.first, vLen, cudaMemcpyHostToDevice) 83 | 84 | proc gpu*[A: Scalar](m: SparseMatrix[A]): CudaSparseMatrix[A] = 85 | new result, dealloc 86 | result.kind = m.kind 87 | result.M = m.M 88 | result.N = m.N 89 | result.nnz = m.nnz 90 | let (r, c, v) = result.sizes 91 | allocateAll(result, r, c, v) 92 | check cudaMemcpy(result.rows, m.rows.first, r, cudaMemcpyHostToDevice) 93 | check cudaMemcpy(result.cols, m.cols.first, c, cudaMemcpyHostToDevice) 94 | check cudaMemcpy(result.vals, m.vals.first, v, cudaMemcpyHostToDevice) 95 | 96 | proc cpu*[A: Scalar](v: CudaSparseVector[A]): SparseVector[A] = 97 | result = SparseVector[A]( 98 | N: v.N, 99 | indices: newSeq[int32](v.nnz), 100 | vals: newSeq[A](v.nnz) 101 | ) 102 | let (iLen, vLen) = v.sizes 103 | check cudaMemcpy(result.indices.first, v.indices, iLen, cudaMemcpyDeviceToHost) 104 | check cudaMemcpy(result.vals.first, v.vals, vLen, cudaMemcpyDeviceToHost) 105 | 106 | proc cpu*[A: Scalar](m: CudaSparseMatrix[A]): SparseMatrix[A] = 107 | new result 108 | result.kind = m.kind 109 | result.M = m.M 110 | result.N = m.N 111 | result.nnz = m.nnz 112 | let (r, c, v) = result.sizes 113 | result.rows = newSeq[int32](m.rowLen) 114 | result.cols = newSeq[int32](m.colLen) 115 | result.vals = newSeq[A](m.nnz) 116 | check cudaMemcpy(result.rows.first, m.rows, r, cudaMemcpyDeviceToHost) 117 | check cudaMemcpy(result.cols.first, m.cols, c, cudaMemcpyDeviceToHost) 118 | check cudaMemcpy(result.vals.first, m.vals, v, cudaMemcpyDeviceToHost) 119 | 120 | proc toCsr*[A: Scalar](m: CudaSparseMatrix[A], handle = defaultHandle): CudaSparseMatrix[A] = 121 | new result, dealloc 122 | result.kind = CSR 123 | result.M = m.M 124 | result.N = m.N 125 | result.nnz = m.nnz 126 | let (r, c, v) = result.sizes 127 | allocateAll(result, r, c, v) 128 | case m.kind 129 | of CSR: 130 | check cudaMemcpy(result.rows, m.rows, r, cudaMemcpyDeviceToDevice) 131 | check cudaMemcpy(result.cols, m.cols, c, cudaMemcpyDeviceToDevice) 132 | check cudaMemcpy(result.vals, m.vals, v, cudaMemcpyDeviceToDevice) 133 | of CSC: 134 | when A is float32: 135 | check cusparseScsr2csc(handle, m.N, m.M, m.nnz, result.vals, result.cols, result.rows, m.vals, m.cols, m.rows, CUSPARSE_ACTION_NUMERIC, idx) 136 | elif A is float64: 137 | check cusparseDcsr2csc(handle, m.N, m.M, m.nnz, result.vals, result.cols, result.rows, m.vals, m.cols, m.rows, CUSPARSE_ACTION_NUMERIC, idx) 138 | elif A is Complex[float32]: 139 | check cusparseCcsr2csc(handle, m.N, m.M, m.nnz, result.vals, result.cols, result.rows, m.vals, m.cols, m.rows, CUSPARSE_ACTION_NUMERIC, idx) 140 | elif A is Complex[float64]: 141 | check cusparseZcsr2csc(handle, m.N, m.M, m.nnz, result.vals, result.cols, result.rows, m.vals, m.cols, m.rows, CUSPARSE_ACTION_NUMERIC, idx) 142 | of COO: 143 | check cusparseXcoo2csr(handle, m.rows, m.nnz, m.N, result.rows, idx) 144 | check cudaMemcpy(result.cols, m.cols, c, cudaMemcpyDeviceToDevice) 145 | check cudaMemcpy(result.vals, m.vals, v, cudaMemcpyDeviceToDevice) 146 | 147 | proc toCsc*[A: Scalar](m: CudaSparseMatrix[A], handle = defaultHandle): CudaSparseMatrix[A] = 148 | case m.kind 149 | of CSR: 150 | new result, dealloc 151 | result.kind = CSC 152 | result.M = m.M 153 | result.N = m.N 154 | result.nnz = m.nnz 155 | let (r, c, v) = result.sizes 156 | allocateAll(result, r, c, v) 157 | when A is float32: 158 | check cusparseScsr2csc(handle, m.M, m.N, m.nnz, result.vals, result.rows, result.cols, m.vals, m.rows, m.cols, CUSPARSE_ACTION_NUMERIC, idx) 159 | elif A is float64: 160 | check cusparseDcsr2csc(handle, m.M, m.N, m.nnz, result.vals, result.rows, result.cols, m.vals, m.rows, m.cols, CUSPARSE_ACTION_NUMERIC, idx) 161 | elif A is Complex[float32]: 162 | check cusparseCcsr2csc(handle, m.M, m.N, m.nnz, result.vals, result.rows, result.cols, m.vals, m.rows, m.cols, CUSPARSE_ACTION_NUMERIC, idx) 163 | elif A is Complex[float64]: 164 | check cusparseZcsr2csc(handle, m.M, m.N, m.nnz, result.vals, result.rows, result.cols, m.vals, m.rows, m.cols, CUSPARSE_ACTION_NUMERIC, idx) 165 | of CSC: 166 | new result, dealloc 167 | result.kind = CSC 168 | result.M = m.M 169 | result.N = m.N 170 | result.nnz = m.nnz 171 | let (r, c, v) = result.sizes 172 | allocateAll(result, r, c, v) 173 | check cudaMemcpy(result.rows, m.rows, r, cudaMemcpyDeviceToDevice) 174 | check cudaMemcpy(result.cols, m.cols, c, cudaMemcpyDeviceToDevice) 175 | check cudaMemcpy(result.vals, m.vals, v, cudaMemcpyDeviceToDevice) 176 | of COO: 177 | result = m.toCsr().toCsc() 178 | 179 | proc toCoo*[A: Scalar](m: CudaSparseMatrix[A], handle = defaultHandle): CudaSparseMatrix[A] = 180 | new result, dealloc 181 | result.kind = COO 182 | result.M = m.M 183 | result.N = m.N 184 | result.nnz = m.nnz 185 | let (r, c, v) = result.sizes 186 | allocateAll(result, r, c, v) 187 | case m.kind 188 | of CSR: 189 | check cudaMemcpy(result.cols, m.cols, c, cudaMemcpyDeviceToDevice) 190 | check cudaMemcpy(result.vals, m.vals, v, cudaMemcpyDeviceToDevice) 191 | check cusparseXcsr2coo(handle, m.rows, m.nnz, m.M, result.rows, idx) 192 | of CSC: 193 | result = m.toCsr().toCoo() 194 | of COO: 195 | check cudaMemcpy(result.rows, m.rows, r, cudaMemcpyDeviceToDevice) 196 | check cudaMemcpy(result.cols, m.cols, c, cudaMemcpyDeviceToDevice) 197 | check cudaMemcpy(result.vals, m.vals, v, cudaMemcpyDeviceToDevice) -------------------------------------------------------------------------------- /neo/private/neocommon.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2017 UniCredit S.p.A. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | import macros, sequtils 15 | 16 | template pointerTo*(x: untyped) = cast[ptr pointer](addr x) 17 | 18 | proc first*[T](a: var seq[T]): ptr T {.inline.} = addr(a[0]) 19 | 20 | macro overload*(s: untyped, p: typed): auto = 21 | let args = p.getTypeImpl[0] 22 | var j = 0 23 | for c in args.children: 24 | if j > 0: 25 | if $(c[0]) == "result": 26 | c[0] = genSym(nskParam, "res") 27 | inc j 28 | var 29 | params = toSeq(args.children) 30 | callArgs = newSeq[NimNode]() 31 | i = 0 32 | for c in args.children: 33 | if i > 0: 34 | callArgs.add(c[0]) 35 | inc i 36 | let 37 | call = newCall(p, callArgs) 38 | overloadedProc = newProc( 39 | name = s, 40 | params = params, 41 | body = newStmtList(call) 42 | ) 43 | result = newStmtList(overloadedProc) 44 | 45 | template overload*(s: untyped, p, q: typed) = 46 | overload(s, p) 47 | overload(s, q) 48 | 49 | proc getAddress(n: NimNode): NimNode = 50 | let t = n.getTypeImpl 51 | if t.kind == nnkBracketExpr and $(t[0]) == "seq": 52 | result = quote do: 53 | addr `n`[0] 54 | elif t.kind == nnkRefTy and $(t[0]) in ["Vector", "Vector:ObjectType"]: 55 | result = quote do: 56 | `n`.fp 57 | elif t.kind == nnkRefTy and $(t[0]) in ["Matrix", "Matrix:ObjectType"]: 58 | result = quote do: 59 | `n`.fp 60 | elif $t == "cstring": 61 | result = quote do: 62 | `n` 63 | else: 64 | result = quote do: 65 | addr `n` 66 | 67 | macro fortran*(f: untyped, callArgs: varargs[typed]): auto = 68 | var transformedCallArgs = newSeqOfCap[NimNode](callArgs.len) 69 | for x in callArgs: 70 | transformedCallArgs.add(getAddress(x)) 71 | result = newCall(f, transformedCallArgs) -------------------------------------------------------------------------------- /neo/sparse.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2017 UniCredit S.p.A. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import ./core, ./dense 16 | 17 | export core 18 | 19 | type 20 | SparseVector*[A] = ref object 21 | N*: int32 22 | indices*: seq[int32] 23 | vals*: seq[A] 24 | SparseMatrixKind* = enum 25 | CSR, CSC, COO 26 | SparseMatrixObj*[A] = object 27 | kind*: SparseMatrixKind 28 | M*, N*, nnz*: int32 29 | rows*, cols*: seq[int32] 30 | vals*: seq[A] 31 | SparseMatrix*[A] = ref SparseMatrixObj[A] 32 | 33 | proc len*(v: SparseVector): int {.inline.} = v.N.int 34 | 35 | proc nnz*(v: SparseVector): int32 {.inline.} = v.indices.len.int32 36 | 37 | proc rowLen*(m: SparseMatrix): int32 = 38 | case m.kind 39 | of CSR: m.M + 1 40 | of CSC, COO: m.nnz 41 | 42 | proc colLen*(m: SparseMatrix): int32 = 43 | case m.kind 44 | of CSR, COO: m.nnz 45 | of CSC: m.N + 1 46 | 47 | # Initializers 48 | 49 | proc sparseVector*[A](N: int32, indices: seq[int32], vals: seq[A]): SparseVector[A] = 50 | SparseVector[A](N: N, indices: indices, vals: vals) 51 | 52 | proc sparseMatrix*[A: Scalar](kind: SparseMatrixKind, M, N, nnz: int32, rows, cols: seq[int32], vals: seq[A]): SparseMatrix[A] = 53 | SparseMatrix[A]( 54 | kind: kind, 55 | M: M, 56 | N: N, 57 | nnz: nnz, 58 | rows: rows, 59 | cols: cols, 60 | vals: vals 61 | ) 62 | 63 | proc csr*[A: Scalar](rows, cols: seq[int32], vals: seq[A], numCols: int32): SparseMatrix[A] = 64 | sparseMatrix(CSR, rows.len.int32 - 1, numCols, vals.len.int32, rows, cols, vals) 65 | 66 | proc csc*[A: Scalar](rows, cols: seq[int32], vals: seq[A], numRows: int32): SparseMatrix[A] = 67 | sparseMatrix(CSC, numRows, cols.len.int32 - 1, vals.len.int32, rows, cols, vals) 68 | 69 | proc coo*[A: Scalar](rows, cols: seq[int32], vals: seq[A], numRows, numCols: int32): SparseMatrix[A] = 70 | sparseMatrix(COO, numRows, numCols, vals.len.int32, rows, cols, vals) 71 | 72 | # Iterators 73 | 74 | iterator items*[A](v: SparseVector[A]): A = 75 | var 76 | zero: A 77 | next = v.indices[0] 78 | count = 0 79 | for i in 0 ..< v.N: 80 | if i == next: 81 | yield v.vals[count] 82 | inc count 83 | if count < v.indices.len: 84 | next = v.indices[count] 85 | else: 86 | yield zero 87 | 88 | iterator pairs*[A](v: SparseVector[A]): tuple[key: int32, val: A] = 89 | var 90 | zero: A 91 | next = v.indices[0] 92 | count = 0 93 | for i in 0'i32 ..< v.N: 94 | if i == next: 95 | yield (i, v.vals[count]) 96 | inc count 97 | if count < v.indices.len: 98 | next = v.indices[count] 99 | else: 100 | yield (i, zero) 101 | 102 | iterator nonzero*[A](v: SparseVector[A]): tuple[key: int32, val: A] = 103 | for i, j in v.indices: 104 | yield (j, v.vals[i]) 105 | 106 | 107 | iterator items*[A](m: SparseMatrix[A]): A = 108 | var count = 0 109 | var zero: A 110 | case m.kind 111 | of CSR: 112 | var next = m.cols[0] 113 | for i in 0 ..< m.M: 114 | let max = m.rows[i + 1] 115 | for j in 0 ..< m.N: 116 | if count < max and j == next: 117 | yield m.vals[count] 118 | inc count 119 | if count < m.nnz: 120 | next = m.cols[count] 121 | else: 122 | yield zero 123 | of CSC: 124 | var next = m.rows[0] 125 | for j in 0 ..< m.N: 126 | let max = m.cols[j + 1] 127 | for i in 0 ..< m.M: 128 | if count < max and i == next: 129 | yield m.vals[count] 130 | inc count 131 | if count < m.nnz: 132 | next = m.rows[count] 133 | else: 134 | yield zero 135 | of COO: 136 | var 137 | nextR = m.rows[0] 138 | nextC = m.cols[0] 139 | for i in 0 ..< m.M: 140 | for j in 0 ..< m.N: 141 | if i == nextR and j == nextC: 142 | yield m.vals[count] 143 | inc count 144 | if count < m.nnz: 145 | nextR = m.rows[count] 146 | nextC = m.cols[count] 147 | else: 148 | yield zero 149 | 150 | iterator pairs*[A](m: SparseMatrix[A]): tuple[key: (int32, int32), val: A] = 151 | var count = 0 152 | var zero: A 153 | case m.kind 154 | of CSR: 155 | var next = m.cols[0] 156 | for i in 0'i32 ..< m.M: 157 | let max = m.rows[i + 1] 158 | for j in 0'i32 ..< m.N: 159 | if count < max and j == next: 160 | yield ((i, j), m.vals[count]) 161 | inc count 162 | if count < m.nnz: 163 | next = m.cols[count] 164 | else: 165 | yield ((i, j), zero) 166 | of CSC: 167 | var next = m.rows[0] 168 | for j in 0'i32 ..< m.N: 169 | let max = m.cols[j + 1] 170 | for i in 0'i32 ..< m.M: 171 | if count < max and i == next: 172 | yield ((i, j), m.vals[count]) 173 | inc count 174 | if count < m.nnz: 175 | next = m.rows[count] 176 | else: 177 | yield ((i, j), zero) 178 | of COO: 179 | var 180 | nextR = m.rows[0] 181 | nextC = m.cols[0] 182 | for i in 0'i32 ..< m.M: 183 | for j in 0'i32 ..< m.N: 184 | if i == nextR and j == nextC: 185 | yield ((i, j), m.vals[count]) 186 | inc count 187 | if count < m.nnz: 188 | nextR = m.rows[count] 189 | nextC = m.cols[count] 190 | else: 191 | yield ((i, j), zero) 192 | 193 | iterator nonzero*[A](m: SparseMatrix[A]): tuple[key: (int32, int32), val: A] = 194 | case m.kind 195 | of CSR: 196 | var 197 | count = 0 198 | row = 0'i32 199 | while count < m.nnz: 200 | while count >= m.rows[row + 1]: 201 | inc row 202 | let n = m.rows[row + 1] - count 203 | for _ in 1 .. n: 204 | yield ((row, m.cols[count]), m.vals[count]) 205 | inc count 206 | of CSC: 207 | var 208 | count = 0 209 | col = 0'i32 210 | while count < m.nnz: 211 | while count >= m.cols[col + 1]: 212 | inc col 213 | let n = m.cols[col + 1] - count 214 | for _ in 1 .. n: 215 | yield ((m.rows[count], col), m.vals[count]) 216 | inc count 217 | of COO: 218 | let L = m.rows.len 219 | for k in 0 ..< L: 220 | yield ((m.rows[k], m.cols[k]), m.vals[k]) 221 | 222 | # Conversions 223 | 224 | proc dense*[A](v: SparseVector[A]): Vector[A] = 225 | result = zeros(v.N, A) 226 | for i, x in v.nonzero: 227 | result[i] = x 228 | 229 | proc dense*[A](m: SparseMatrix[A], order = colMajor): Matrix[A] = 230 | result = zeros(m.M, m.N, A, order) 231 | for t, x in m.nonzero: 232 | let (i, j) = t 233 | result[i, j] = x 234 | 235 | # Equality 236 | 237 | # TODO: implement a faster way to check equality 238 | proc `==`*[A](v, w: SparseVector[A]): bool = v.dense == w.dense 239 | 240 | proc `==`*[A](m, n: SparseMatrix[A]): bool = m.dense == n.dense 241 | 242 | # Printing 243 | 244 | proc `$`*[A](v: SparseVector[A]): string = $(v.dense) 245 | 246 | proc `$`*[A](m: SparseMatrix[A]): string = $(m.dense) -------------------------------------------------------------------------------- /tests/all.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2017 UniCredit S.p.A. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | {.push warning[ProveInit]: off .} 16 | 17 | import tdense, tsparse, tstatics 18 | 19 | {. pop .} 20 | -------------------------------------------------------------------------------- /tests/allcuda.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2017 UniCredit S.p.A. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | {.push warning[ProveInit]: off .} 16 | 17 | import tcudadense, tcudasparse 18 | 19 | {. pop .} 20 | -------------------------------------------------------------------------------- /tests/cudadense/dclone.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2017 UniCredit S.p.A. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import unittest, neo/dense, neo/cudadense 16 | 17 | proc run() = 18 | suite "cloning": 19 | test "cloning a vector": 20 | let 21 | v1 = randomVector(10) 22 | v2 = v1.gpu() 23 | v3 = v2.clone() 24 | v4 = v3.cpu() 25 | check v1 == v4 26 | test "cloning a matrix": 27 | let 28 | m1 = randomMatrix(10, 7) 29 | m2 = m1.gpu() 30 | m3 = m2.clone() 31 | m4 = m3.cpu() 32 | check m1 == m4 33 | 34 | run() -------------------------------------------------------------------------------- /tests/cudadense/dcopy.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2017 UniCredit S.p.A. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import unittest, neo/dense, neo/cudadense 16 | 17 | proc run() = 18 | suite "copying back and forth": 19 | test "copy of a 32-bit vector": 20 | let 21 | v1 = randomVector(10, max=1'f32) 22 | v2 = v1.gpu() 23 | v3 = v2.cpu() 24 | check v1 == v3 25 | test "copy of a 64-bit vector": 26 | let 27 | v1 = randomVector(10, max=1.0) 28 | v2 = v1.gpu() 29 | v3 = v2.cpu() 30 | check v1 == v3 31 | test "copy of a 32-bit matrix": 32 | let 33 | m1 = randomMatrix(10, 7, max=1'f32) 34 | m2 = m1.gpu() 35 | m3 = m2.cpu() 36 | check m1 == m3 37 | test "copy of a 64- bit matrix": 38 | let 39 | m1 = randomMatrix(10, 7, max=1.0) 40 | m2 = m1.gpu() 41 | m3 = m2.cpu() 42 | check m1 == m3 43 | 44 | run() -------------------------------------------------------------------------------- /tests/cudadense/dequality.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2017 UniCredit S.p.A. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import unittest, neo/dense, neo/cudadense 16 | 17 | proc run() = 18 | suite "vector and matrix equality": 19 | test "strict 32-bit vector equality": 20 | let 21 | u = vector([1'f32, 2'f32, 3'f32, 4'f32]).gpu() 22 | v = vector([1'f32, 2'f32, 3'f32, 4'f32]).gpu() 23 | w = vector([1'f32, 3'f32, 3'f32, 4'f32]).gpu() 24 | check u == v 25 | check v != w 26 | test "approximate 32-bit vector equality": 27 | let 28 | u = vector([1'f32, 2'f32, 3'f32, 4'f32]).gpu() 29 | v = vector([1'f32, 2'f32, 3'f32, 4'f32]).gpu() 30 | w = vector([1'f32, 2'f32, 2.999999'f32, 4.000001'f32]).gpu() 31 | z = vector([1'f32, 3'f32, 3'f32, 4'f32]).gpu() 32 | check u =~ v 33 | check v =~ w 34 | check v != w 35 | check w !=~ z 36 | test "strict 32-bit matrix equality": 37 | let 38 | m = makeMatrix(3, 5, proc(i, j: int): float32 = (i + 3 * j).float32).gpu() 39 | n = makeMatrix(3, 5, proc(i, j: int): float32 = (i + 3 * j).float32).gpu() 40 | p = makeMatrix(3, 5, proc(i, j: int): float32 = (i - 2 * j).float32).gpu() 41 | check m == n 42 | check n != p 43 | test "strict 64-bit vector equality": 44 | let 45 | u = vector([1.0, 2.0, 3.0, 4.0]).gpu() 46 | v = vector([1.0, 2.0, 3.0, 4.0]).gpu() 47 | w = vector([1.0, 3.0, 3.0, 4.0]).gpu() 48 | check u == v 49 | check v != w 50 | test "approximate 64-bit vector equality": 51 | let 52 | u = vector([1.0, 2.0, 3.0, 4.0]).gpu() 53 | v = vector([1.0, 2.0, 3.0, 4.0]).gpu() 54 | w = vector([1.0, 2.0, 2.999999, 4.000001]).gpu() 55 | z = vector([1.0, 3.0, 3.0, 4.0]).gpu() 56 | check u =~ v 57 | check v =~ w 58 | check v != w 59 | check w !=~ z 60 | test "approximate vector equality handles zero vectors": 61 | let 62 | N = 5 63 | u = zeros(N).gpu() 64 | v = zeros(N).gpu() 65 | check u =~ v 66 | test "strict 64-bit matrix equality": 67 | let 68 | m = makeMatrix(3, 5, proc(i, j: int): float64 = (i + 3 * j).float64).gpu() 69 | n = makeMatrix(3, 5, proc(i, j: int): float64 = (i + 3 * j).float64).gpu() 70 | p = makeMatrix(3, 5, proc(i, j: int): float64 = (i - 2 * j).float64).gpu() 71 | check m == n 72 | check n != p 73 | test "approximate matrix equality handles zero vectors": 74 | let 75 | M = 3 76 | N = 5 77 | m = zeros(M, N).gpu() 78 | n = zeros(M, N).gpu() 79 | check m =~ n 80 | 81 | run() -------------------------------------------------------------------------------- /tests/cudadense/diterators.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2017 UniCredit S.p.A. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import unittest, neo/dense, neo/cudadense 16 | 17 | proc run() = 18 | suite "iterators on matrices": 19 | test "rows matrix iterator": 20 | let m = makeMatrix(3, 2, proc(i, j: int): float64 = (i + 2 * j + 1).float64).gpu() 21 | var 22 | sum = zeros(2).gpu() 23 | count = 0 24 | for r in m.rows: 25 | sum += r 26 | count += 1 27 | check sum == vector(6.0, 12.0).gpu() 28 | check count == 3 29 | test "columns matrix iterator": 30 | let m = makeMatrix(3, 2, proc(i, j: int): float64 = (i + 2 * j + 1).float64).gpu() 31 | var 32 | sum = zeros(3).gpu() 33 | count = 0 34 | for c in m.columns: 35 | sum += c 36 | count += 1 37 | check sum == vector(4.0, 6.0, 8.0).gpu() 38 | check count == 2 39 | test "rows matrix iterator": 40 | let m = makeMatrix(3, 2, proc(i, j: int): float64 = (i + 2 * j + 1).float64).gpu() 41 | var 42 | sum = zeros(2).gpu() 43 | count = 0 44 | for r in m.rowsSlow: 45 | sum += r 46 | count += 1 47 | check sum == vector(6.0, 12.0).gpu() 48 | check count == 3 49 | test "columns matrix iterator": 50 | let m = makeMatrix(3, 2, proc(i, j: int): float64 = (i + 2 * j + 1).float64).gpu() 51 | var 52 | sum = zeros(3).gpu() 53 | count = 0 54 | for c in m.columnsSlow: 55 | sum += c 56 | count += 1 57 | check sum == vector(4.0, 6.0, 8.0).gpu() 58 | check count == 2 59 | 60 | run() -------------------------------------------------------------------------------- /tests/cudadense/dslice.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2017 UniCredit S.p.A. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import unittest, neo/dense, neo/cudadense 16 | 17 | proc run() = 18 | suite "slicing CUDA vectors": 19 | test "getting a slice of a vector": 20 | let 21 | v = vector(@[1'f64, 2, 3, 4, 5]).gpu() 22 | w = v[2 .. 3] 23 | 24 | check w.cpu() == vector(3'f64, 4'f64) 25 | 26 | test "assigning to a slice": 27 | var v = vector(@[1'f64, 2, 3, 4, 5]).gpu() 28 | let w = vector(6'f64, 7'f64).gpu() 29 | 30 | v[2 .. 3] = w 31 | check v.cpu() == vector(@[1'f64, 2, 6, 7, 5]) 32 | 33 | test "assigning a slice to another slice": 34 | var v = vector(@[1'f64, 2, 3, 4, 5]).gpu() 35 | let w = vector(@[6'f64, 7, 8, 9, 10]).gpu() 36 | 37 | v[2 .. 3] = w[3 .. 4] 38 | check v.cpu() == vector(@[1'f64, 2, 9, 10, 5]) 39 | 40 | suite "slicing CUDA matrices": 41 | test "slice of a full matrix": 42 | let 43 | m = makeMatrixIJ(int, 5, 5, 3 * i + j).gpu() 44 | s = m[1 .. 3, 2 .. 4] 45 | expected = matrix(@[ 46 | @[5, 6, 7], 47 | @[8, 9, 10], 48 | @[11, 12, 13] 49 | ]).gpu() 50 | 51 | check s == expected 52 | test "slice on columns only": 53 | let 54 | m = makeMatrixIJ(int, 5, 5, 3 * i + j).gpu() 55 | s = m[All, 2 .. 4] 56 | expected = matrix(@[ 57 | @[2, 3, 4], 58 | @[5, 6, 7], 59 | @[8, 9, 10], 60 | @[11, 12, 13], 61 | @[14, 15, 16] 62 | ]).gpu() 63 | 64 | check s == expected 65 | test "slice on rows only": 66 | let 67 | m = makeMatrixIJ(int, 5, 5, 3 * i + j).gpu() 68 | s = m[1 .. 3, All] 69 | expected = matrix(@[ 70 | @[3, 4, 5, 6, 7], 71 | @[6, 7, 8, 9, 10], 72 | @[9, 10, 11, 12, 13], 73 | ]).gpu() 74 | 75 | check s == expected 76 | test "slice a sliced matrix": 77 | let 78 | m = makeMatrixIJ(int, 5, 5, 3 * i + j).gpu() 79 | s1 = m[1 .. 4, 1 .. 4] 80 | s2 = s1[0 .. 2, 1 .. 3] 81 | expected = matrix(@[ 82 | @[5, 6, 7], 83 | @[8, 9, 10], 84 | @[11, 12, 13] 85 | ]).gpu() 86 | 87 | check s2 == expected 88 | test "slice a sliced matrix on rows only": 89 | let 90 | m = makeMatrixIJ(int, 5, 5, 3 * i + j).gpu() 91 | s1 = m[1 .. 4, 1 .. 4] 92 | s2 = s1[0 .. 2, All] 93 | expected = matrix(@[ 94 | @[4, 5, 6, 7], 95 | @[7, 8, 9, 10], 96 | @[10, 11, 12, 13] 97 | ]).gpu() 98 | 99 | check s2 == expected 100 | test "assigning to a slice": 101 | var m = makeMatrixIJ(float64, 5, 5, (3 * i + j).float64).gpu() 102 | let n = matrix(@[ 103 | @[5'f64, 6, 7], 104 | @[8'f64, 9, 10], 105 | @[11'f64, 12, 13] 106 | ]).gpu() 107 | m[1 .. 3, 1 .. 3] = n 108 | let m1 = m.cpu() 109 | check m1[2, 2] == 9'f64 110 | check m1[3, 2] == 12'f64 111 | test "rows of a slice of a matrix": 112 | let 113 | m = makeMatrixIJ(int, 5, 5, 3 * i + j).gpu() 114 | s = m[1 .. 3, 2 .. 4] 115 | r = s.row(1) 116 | 117 | check r == vector(8, 9, 10).gpu() 118 | test "columns of a slice of a matrix": 119 | let 120 | m = makeMatrixIJ(int, 5, 5, 3 * i + j).gpu() 121 | s = m[1 .. 3, 2 .. 4] 122 | r = s.column(1) 123 | 124 | check r == vector(6, 9, 12).gpu() 125 | test "rows of a slice of a sliced matrix": 126 | let 127 | m = makeMatrixIJ(int, 5, 5, 3 * i + j).gpu() 128 | s1 = m[1 .. 4, 1 .. 4] 129 | s2 = s1[0 .. 2, 1 .. 3] 130 | r = s2.row(1) 131 | 132 | check r == vector(8, 9, 10).gpu() 133 | test "matrix/vector multiplication on slices": 134 | let 135 | m = makeMatrixIJ(float64, 5, 5, (3 * i + j).float64).gpu() 136 | s = m[1 .. 3, 2 .. 4] 137 | n = matrix(@[ 138 | @[5.0, 6, 7], 139 | @[8.0, 9, 10], 140 | @[11.0, 12, 13] 141 | ]).gpu() 142 | v = n.column(2) 143 | 144 | check(s * v == n * v) 145 | test "matrix multiplication on slices": 146 | let 147 | m = makeMatrixIJ(float64, 5, 5, (3 * i + j).float64).gpu() 148 | s = m[1 .. 3, 2 .. 4] 149 | n = matrix(@[ 150 | @[5.0, 6, 7], 151 | @[8.0, 9, 10], 152 | @[11.0, 12, 13] 153 | ]).gpu() 154 | 155 | check(s * s == n * n) 156 | test "matrix addition on slices": 157 | let 158 | m = makeMatrixIJ(float64, 5, 5, (3 * i + j).float64).gpu() 159 | s = m[1 .. 3, 2 .. 4] 160 | n = matrix(@[ 161 | @[5.0, 6, 7], 162 | @[8.0, 9, 10], 163 | @[11.0, 12, 13] 164 | ]).gpu() 165 | 166 | check(s + s == n + n) 167 | test "matrix subtraction on slices": 168 | let 169 | m = makeMatrixIJ(float64, 5, 5, (3 * i + j).float64).gpu() 170 | s = m[1 .. 3, 2 .. 4] 171 | n = matrix(@[ 172 | @[5.0, 6, 7], 173 | @[8.0, 9, 10], 174 | @[11.0, 12, 13] 175 | ]).gpu() 176 | 177 | check(s - n == zeros(3, 3).gpu()) 178 | test "scaling slices": 179 | var 180 | m = makeMatrixIJ(float64, 5, 5, (3 * i + j).float64).gpu() 181 | s = m[1 .. 3, 2 .. 4] 182 | s *= 2 183 | let expected = matrix(@[ 184 | @[0.0, 1.0, 2.0, 3.0, 4.0], 185 | @[3.0, 4.0, 10.0, 12.0, 14.0], 186 | @[6.0, 7.0, 16.0, 18.0, 20.0], 187 | @[9.0, 10.0, 22.0, 24.0, 26.0], 188 | @[12.0, 13.0, 14.0, 15.0, 16.0] 189 | ]).gpu() 190 | 191 | check(m == expected) 192 | test "mutable sum on slices": 193 | var 194 | m = makeMatrixIJ(float64, 5, 5, (3 * i + j).float64).gpu() 195 | s = m[1 .. 3, 2 .. 4] 196 | t = makeMatrixIJ(float64, 3, 3, (i - j).float64).gpu() 197 | s += t 198 | let expected = matrix(@[ 199 | @[0.0, 1.0, 2.0, 3.0, 4.0], 200 | @[3.0, 4.0, 5.0, 5.0, 5.0], 201 | @[6.0, 7.0, 9.0, 9.0, 9.0], 202 | @[9.0, 10.0, 13.0, 13.0, 13.0], 203 | @[12.0, 13.0, 14.0, 15.0, 16.0] 204 | ]).gpu() 205 | 206 | check(m == expected) 207 | 208 | run() -------------------------------------------------------------------------------- /tests/cudadense/dtrivial_ops.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2017 UniCredit S.p.A. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import unittest, neo/dense, neo/cudadense 16 | 17 | proc run() = 18 | suite "trivial operations CUDA objects": 19 | test "reshape of matrices": 20 | let 21 | m1 = matrix(@[ 22 | @[1.0, 0.0, 2.0, -1.0], 23 | @[-1.0, 1.0, 3.0, 1.0], 24 | @[3.0, 2.0, 2.0, 4.0] 25 | ]).gpu() 26 | m2 = matrix(@[ 27 | @[1.0, 1.0, 2.0], 28 | @[-1.0, 2.0, -1.0], 29 | @[3.0, 2.0, 1.0], 30 | @[0.0, 3.0, 4.0] 31 | ]).gpu() 32 | check m1.reshape(4, 3) == m2 33 | test "turn vectors into matrices": 34 | let 35 | v = vector([1.0, -1.0, 3.0, 0.0, 1.0, 2.0, 2.0, 3.0, 2.0, -1.0, 1.0, 4.0]).gpu() 36 | m = matrix(@[ 37 | @[1.0, 0.0, 2.0, -1.0], 38 | @[-1.0, 1.0, 3.0, 1.0], 39 | @[3.0, 2.0, 2.0, 4.0] 40 | ]).gpu() 41 | check v.asMatrix(3, 4) == m 42 | test "turn matrices into vectors": 43 | let 44 | v = vector([1.0, -1.0, 3.0, 0.0, 1.0, 2.0, 2.0, 3.0, 2.0, -1.0, 1.0, 4.0]).gpu() 45 | m = matrix(@[ 46 | @[1.0, 0.0, 2.0, -1.0], 47 | @[-1.0, 1.0, 3.0, 1.0], 48 | @[3.0, 2.0, 2.0, 4.0] 49 | ]).gpu() 50 | check m.asVector == v 51 | test "hard transpose of matrices": 52 | var 53 | m1 = matrix(@[ 54 | @[1.0, 0.0, 2.0, -1.0], 55 | @[-1.0, 1.0, 3.0, 1.0], 56 | @[3.0, 2.0, 2.0, 4.0] 57 | ]).gpu() 58 | m2 = matrix(@[ 59 | @[1.0, -1.0, 3.0], 60 | @[0.0, 1.0, 2.0], 61 | @[2.0, 3.0, 2.0], 62 | @[-1.0, 1.0, 4.0] 63 | ]).gpu() 64 | 65 | check(m1.T == m2) 66 | 67 | run() -------------------------------------------------------------------------------- /tests/cudasparse/scopy.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2017 UniCredit S.p.A. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import unittest, neo/sparse, neo/cudasparse 16 | 17 | proc run() = 18 | suite "copying back and forth": 19 | test "copy of a 64-bit vector": 20 | let 21 | v1 = sparseVector(10, @[3'i32, 5, 7], @[2.0, 3, -1]) 22 | v2 = v1.gpu() 23 | v3 = v2.cpu() 24 | check v1 == v3 25 | test "copy of a 64-bit matrix": 26 | let 27 | m1 = csr( 28 | rows = @[0'i32, 3, 4, 7, 9], 29 | cols = @[0'i32, 2, 3, 1, 0, 2, 3, 1, 3], 30 | vals = @[1'f64, 2, 3, 4, 5, 6, 7, 8, 9], 31 | numCols = 4 32 | ) 33 | m2 = m1.gpu() 34 | m3 = m2.cpu() 35 | check m1 == m3 36 | 37 | run() -------------------------------------------------------------------------------- /tests/dense/daccess.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2017 UniCredit S.p.A. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import unittest, neo/dense 16 | 17 | proc run() = 18 | suite "vector accessors": 19 | test "reading vector length": 20 | let v = randomVector(10) 21 | check v.len == 10 22 | test "reading vector elements": 23 | let v = makeVector(5, proc(i: int): float64 = (3 * i - 2).float64) 24 | check v[0] == -2.0 25 | check v[1] == 1.0 26 | check v[2] == 4.0 27 | check v[3] == 7.0 28 | check v[4] == 10.0 29 | test "reading vector elements backwise index": 30 | let v = makeVector(5, proc(i: int): float64 = (3 * i - 2).float64) 31 | check v[^5] == -2.0 32 | check v[^4] == 1.0 33 | check v[^3] == 4.0 34 | check v[^2] == 7.0 35 | check v[^1] == 10.0 36 | test "mutating vector elements": 37 | var v = zeros(3) 38 | v[0] += 2.1 39 | v[1] -= 1.0 40 | check v[0] == 2.1 41 | check v[1] == -1.0 42 | test "writing vector elements": 43 | var v = zeros(3) 44 | v[0] = -2.1 45 | v[1] = 1.0 46 | check v[0] == -2.1 47 | check v[1] == 1.0 48 | 49 | suite "32-bit vector accessors": 50 | test "reading vector length": 51 | let v = randomVector(10, max = 1'f32) 52 | check v.len == 10 53 | test "reading vector elements": 54 | let v = makeVector(5, proc(i: int): float32 = (3 * i - 2).float32) 55 | check v[0] == -2'f32 56 | check v[1] == 1'f32 57 | check v[2] == 4'f32 58 | check v[3] == 7'f32 59 | check v[4] == 10'f32 60 | test "writing vector elements": 61 | var v = zeros(3, float32) 62 | v[0] = -2.5'f32 63 | v[1] = 1'f32 64 | check v[0] == -2.5'f32 65 | check v[1] == 1'f32 66 | 67 | suite "matrix accessors": 68 | test "reading matrix dimensions": 69 | let m = randomMatrix(3, 7) 70 | check m.dim == (3, 7) 71 | test "reading matrix elements": 72 | let m = makeMatrix(2, 2, proc(i, j: int): float64 = (3 * i - 2 * j).float64) 73 | check m[0, 0] == 0.0 74 | check m[0, 1] == -2.0 75 | check m[1, 0] == 3.0 76 | check m[1, 1] == 1.0 77 | test "mutating matrix elements": 78 | var m = zeros(3, 3) 79 | m[0, 2] += 2.1 80 | m[1, 1] -= 1.0 81 | check m[0, 2] == 2.1 82 | check m[1, 1] == -1.0 83 | test "writing matrix elements": 84 | var m = zeros(3, 3) 85 | m[0, 2] = -2.1 86 | m[1, 1] = 1.0 87 | check m[0, 2] == -2.1 88 | check m[1, 1] == 1.0 89 | test "reading matrix rows": 90 | let 91 | m = makeMatrix(2, 2, proc(i, j: int): float64 = (3 * i - 2 * j).float64) 92 | r = m.row(1) 93 | check r == vector([3.0, 1.0]) 94 | test "reading matrix columns": 95 | let 96 | m = makeMatrix(2, 2, proc(i, j: int): float64 = (3 * i - 2 * j).float64) 97 | c = m.column(1) 98 | check c == vector([-2.0, 1.0]) 99 | test "matrix rows should share storage": 100 | var 101 | m = makeMatrix(2, 2, proc(i, j: int): float64 = (3 * i - 2 * j).float64) 102 | r = m.row(1) 103 | r[0] = 12 104 | check m[1, 0] == 12 105 | test "matrix columns should share storage": 106 | var 107 | m = makeMatrix(2, 2, proc(i, j: int): float64 = (3 * i - 2 * j).float64) 108 | r = m.column(1) 109 | r[0] = 12 110 | check m[0, 1] == 12 111 | test "cloning matrices": 112 | var m = randomMatrix(5, 5) 113 | let 114 | n = m.clone 115 | f = n[2, 2] 116 | check m == n 117 | m[2, 2] = m[2, 2] + 1 118 | check n[2, 2] == f 119 | test "mapping matrices": 120 | let 121 | m = makeMatrix(2, 2, proc(i, j: int): float64 = (3 * i - 2 * j).float64) 122 | n = makeMatrix(2, 2, proc(i, j: int): float64 = (6 * i - 4 * j).float64) 123 | proc double(x: float64): float64 = 2 * x 124 | check m.map(double) == n 125 | 126 | suite "32-bit matrix accessors": 127 | test "reading matrix dimensions": 128 | let m = randomMatrix(3, 7, max = 1'f32) 129 | check m.dim == (3, 7) 130 | test "reading matrix elements": 131 | let m = makeMatrix(2, 2, proc(i, j: int): float32 = (3 * i - 2 * j).float32) 132 | check m[0, 0] == 0'f32 133 | check m[0, 1] == -2'f32 134 | check m[1, 0] == 3'f32 135 | check m[1, 1] == 1'f32 136 | test "writing matrix elements": 137 | var m = zeros(3, 3, float32) 138 | m[0, 2] = -2.5'f32 139 | m[1, 1] = 1'f32 140 | check m[0, 2] == -2.5'f32 141 | check m[1, 1] == 1'f32 142 | test "reading matrix rows": 143 | let 144 | m = makeMatrix(2, 2, proc(i, j: int): float32 = (3 * i - 2 * j).float32) 145 | r = m.row(1) 146 | check r == vector([3'f32, 1'f32]) 147 | test "reading matrix columns": 148 | let 149 | m = makeMatrix(2, 2, proc(i, j: int): float32 = (3 * i - 2 * j).float32) 150 | c = m.column(1) 151 | check c == vector([-2'f32, 1'f32]) 152 | test "cloning matrices": 153 | var m = randomMatrix(5, 5, max = 1'f32) 154 | let 155 | n = m.clone 156 | f = n[2, 2] 157 | check m == n 158 | m[2, 2] = m[2, 2] + 1 159 | check n[2, 2] == f 160 | test "mapping matrices": 161 | let 162 | m = makeMatrix(2, 2, proc(i, j: int): float32 = (3 * i - 2 * j).float32) 163 | n = makeMatrix(2, 2, proc(i, j: int): float32 = (6 * i - 4 * j).float32) 164 | proc double(x: float32): float32 = 2 * x 165 | check m.map(double) == n 166 | 167 | run() -------------------------------------------------------------------------------- /tests/dense/dcollection.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2017 UniCredit S.p.A. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import unittest, neo/dense 16 | 17 | proc run() = 18 | suite "collection operations": 19 | test "cumulative sum over 32-bit vectors": 20 | let 21 | v = vector([1'f32, 3.5'f32, 2'f32, 4.5'f32]) 22 | w = cumsum(v) 23 | check w == vector([1'f32, 4.5'f32, 6.5'f32, 11'f32]) 24 | test "cumulative sum over 64-bit vectors": 25 | let 26 | v = vector([1.0, 3.5, 2.0, 4.5]) 27 | w = cumsum(v) 28 | check w == vector([1.0, 4.5, 6.5, 11.0]) 29 | test "sum over 32-bit vectors": 30 | let v = vector([1'f32, 3.5'f32, 2'f32, 4.5'f32]) 31 | check v.sum == 11'f32 32 | test "sum over 64-bit vectors": 33 | let v = vector([1.0, 3.5, 2.0, 4.5]) 34 | check v.sum == 11.0 35 | test "mean over 32-bit vectors": 36 | let v = vector([1'f32, 3.5'f32, 2'f32, 4.5'f32]) 37 | check v.mean == 2.75'f32 38 | test "mean over 64-bit vectors": 39 | let v = vector([1.0, 3.5, 2.0, 4.5]) 40 | check v.mean == 2.75 41 | test "variance over 32-bit vectors": 42 | let v = vector([2'f32, 4'f32, 4'f32, 4'f32, 5'f32, 5'f32, 7'f32, 9'f32]) 43 | check v.variance == 4'f32 44 | test "variance over 64-bit vectors": 45 | let v = vector([2.0, 4.0, 4.0, 4.0, 5.0, 5.0, 7.0, 9.0]) 46 | check v.variance == 4.0 47 | test "standard deviation over 32-bit vectors": 48 | let v = vector([2'f32, 4'f32, 4'f32, 4'f32, 5'f32, 5'f32, 7'f32, 9'f32]) 49 | check v.stddev == 2'f32 50 | test "standard deviation over 64-bit vectors": 51 | let v = vector([2.0, 4.0, 4.0, 4.0, 5.0, 5.0, 7.0, 9.0]) 52 | check v.stddev == 2.0 53 | test "sum over 32-bit matrices": 54 | let m = matrix(@[@[1'f32, 3.5'f32], @[2'f32, 4.5'f32]]) 55 | check m.sum == 11'f32 56 | test "sum over 64-bit matrices": 57 | let m = matrix(@[@[1.0, 3.5], @[2.0, 4.5]]) 58 | check m.sum == 11.0 59 | test "mean over 32-bit matrices": 60 | let m = matrix(@[@[1'f32, 3.5'f32], @[2'f32, 4.5'f32]]) 61 | check m.mean == 2.75'f32 62 | test "mean over 64-bit matrices": 63 | let m = matrix(@[@[1.0, 3.5], @[2.0, 4.5]]) 64 | check m.mean == 2.75 65 | 66 | run() -------------------------------------------------------------------------------- /tests/dense/dconversions.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2017 UniCredit S.p.A. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import unittest, neo/dense 16 | 17 | proc run() = 18 | suite "precision conversions": 19 | test "vectors: 64 to 32 bits": 20 | let v = vector([1.0, 3.5, 2.0, 4.5]) 21 | check v.to32 == vector([1'f32, 3.5'f32, 2'f32, 4.5'f32]) 22 | test "vectors: 32 to 64 bits": 23 | let v = vector([1'f32, 3.5'f32, 2'f32, 4.5'f32]) 24 | check v.to64 == vector([1.0, 3.5, 2.0, 4.5]) 25 | test "matrices: 64 to 32 bits": 26 | let 27 | m = makeMatrix(3, 5, proc(i, j: int): float64 = (i + j).float64) 28 | n = makeMatrix(3, 5, proc(i, j: int): float32 = (i + j).float32) 29 | check m.to32 == n 30 | test "matrices: 32 to 64 bits": 31 | let 32 | m = makeMatrix(3, 5, proc(i, j: int): float64 = (i + j).float64) 33 | n = makeMatrix(3, 5, proc(i, j: int): float32 = (i + j).float32) 34 | check n.to64 == m 35 | 36 | run() -------------------------------------------------------------------------------- /tests/dense/ddecompositions.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2017 UniCredit S.p.A. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import unittest, neo/dense, sequtils 16 | 17 | proc run() = 18 | suite "Matrix Decompositions": 19 | test "SVD": 20 | let a = @[@[ 7.52, -1.10, -7.95, 1.08], 21 | @[ -0.76, 0.62, 9.34, -7.10], 22 | @[ 5.13, 6.62, -5.66, 0.87], 23 | @[ -4.75, 8.52, 5.75, 5.30], 24 | @[ 1.33, 4.91, -5.49, -3.52], 25 | @[ -2.40, -6.77, 2.34, 3.95]].matrix 26 | 27 | let (U, S, Vh) = svd(a) 28 | check U * diag(S.toSeq) * Vh =~ a 29 | 30 | run() 31 | -------------------------------------------------------------------------------- /tests/dense/ddet.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2017 UniCredit S.p.A. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import unittest, neo/dense 16 | 17 | proc run() = 18 | suite "trace and determinant computations": 19 | test "trace of a matrix": 20 | let a = makeMatrixIJ(int, 3, 3, i + i * j - 1) 21 | 22 | check(tr(a) == 5) 23 | test "determinant of a matrix": 24 | let a = matrix(@[ 25 | @[-1.0, -1.0, 0.0], 26 | @[ 0.0, 1.0, 2.0], 27 | @[ 1.0, 3.0, 5.0] 28 | ]) 29 | 30 | check((det(a) + -1) < 1e-6) 31 | 32 | run() -------------------------------------------------------------------------------- /tests/dense/deigenvalues.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2017 UniCredit S.p.A. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import unittest, neo/dense, sequtils 16 | 17 | proc run() = 18 | suite "matrix reductions for eigenvalue computations": 19 | test "balancing matrices": 20 | let 21 | a = matrix(@[ 22 | @[3.0, 1.0, 0.0, 0.0], 23 | @[1.0, 0.0, 0.0, 0.0], 24 | @[2.0, -1.0, 1.5, 0.1], 25 | @[-1.0, 0.0, 1.1, 1.2], 26 | ]) 27 | r = balance(a, BalanceOp.Permute) 28 | 29 | check(r.ilo == 1) 30 | check(r.ihi == 4) 31 | test "computing the upper Hessenberg form": 32 | let 33 | a = matrix(@[ 34 | @[3.0, 1.0, 0.0, 0.0], 35 | @[1.0, 0.0, 0.0, 0.0], 36 | @[2.0, -1.0, 1.5, 0.1], 37 | @[-1.0, 0.0, 1.1, 1.2], 38 | ]) 39 | r = hessenberg(a) 40 | 41 | check(r[0, 0] == 3) 42 | 43 | suite "computing eigenvalues": 44 | test "computing the eigenvalues alone": 45 | let 46 | a = matrix(@[ 47 | @[3.0, 1.0, 0.0, 0.0], 48 | @[1.0, 0.0, 0.0, 0.0], 49 | @[2.0, -1.0, 1.5, 0.1], 50 | @[-1.0, 0.0, 1.1, 1.2], 51 | ]) 52 | e = eigenvalues(a) 53 | 54 | check(e.img == @[0.0, 0.0, 0.0, 0.0]) 55 | test "computing the eigenvalues of a known matrix": 56 | let 57 | a = matrix(@[ 58 | @[2.0, 0.0, 1.0], 59 | @[0.0, 2.0, 0.0], 60 | @[1.0, 0.0, 2.0] 61 | ]) 62 | e = eigenvalues(a) 63 | 64 | check(e.real == @[3.0, 1.0, 2.0]) 65 | check(e.img == @[0.0, 0.0, 0.0]) 66 | 67 | test "computing the Schur factorization": 68 | let 69 | a = matrix(@[ 70 | @[2.0, 0.0, 1.0], 71 | @[0.0, 2.0, 0.0], 72 | @[1.0, 0.0, 2.0] 73 | ]) 74 | s = schur(a) 75 | 76 | check(s.factorization == diag(3.0, 1.0, 2.0)) 77 | check(s.eigenvalues.real == @[3.0, 1.0, 2.0]) 78 | check(s.eigenvalues.img == @[0.0, 0.0, 0.0]) 79 | 80 | suite "computing eigenvalues and eigenvectors of real symmetric matrix": 81 | test "computing the eigenvalues": 82 | let 83 | a = matrix(@[ 84 | @[0.70794509, 0.3582868 , 0.18601989, 0.66848165], 85 | @[0.3582868 , 0.26329229, 0.85542206, 0.62635776], 86 | @[0.18601989, 0.85542206, 0.4399633 , 0.30754615], 87 | @[0.66848165, 0.62635776, 0.30754615, 0.89755355]]) 88 | 89 | let (vals, vecs) = symeig(a) 90 | 91 | let 92 | expected_vals = @[-0.564026237258954, 0.112267309803938, 0.643464411048214, 2.117048755152045] 93 | expected_vecs = @[vector([ 0.029732015676491, -0.777482949372466, 0.597541851617029, 0.193855632482002]), 94 | vector([-0.696167044814947, -0.015641070882148, -0.208509696605442, 0.686753601400669]), 95 | vector([ 0.543396224349132, -0.39730786159535 , -0.655220561273828, 0.342860062651875]), 96 | vector([0.46817517695895, 0.487259769990589, 0.412496615830491, 0.610930816178531])] 97 | 98 | for (val, expected_val) in zip(vals.real, expected_vals): 99 | check abs(val - expected_val) < 1.0e-7 100 | 101 | for (vec, expected_vec) in zip(vecs.real, expected_vecs): 102 | var v: Vector[float64] 103 | if vec * expected_vec < 0: 104 | v = -1.0 * vec - expected_vec 105 | else: 106 | v = vec - expected_vec 107 | check v * v < 1.0e-14 108 | 109 | check(vecs.img == newSeqWith(4, zeros(4))) 110 | check(vals.img == @[0.0, 0.0, 0.0, 0.0]) 111 | 112 | run() 113 | -------------------------------------------------------------------------------- /tests/dense/dequality.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2017 UniCredit S.p.A. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import unittest, neo/dense 16 | 17 | proc run() = 18 | suite "vector and matrix equality": 19 | test "strict vector equality": 20 | let 21 | u = vector([1.0, 2.0, 3.0, 4.0]) 22 | v = vector([1.0, 2.0, 3.0, 4.0]) 23 | w = vector([1.0, 3.0, 3.0, 4.0]) 24 | check u == v 25 | check v != w 26 | test "strict 32-bit vector equality": 27 | let 28 | u = vector([1'f32, 2'f32, 3'f32, 4'f32]) 29 | v = vector([1'f32, 2'f32, 3'f32, 4'f32]) 30 | w = vector([1'f32, 3'f32, 3'f32, 4'f32]) 31 | check u == v 32 | check v != w 33 | test "strict matrix equality": 34 | let 35 | M = 3 36 | N = 5 37 | m = makeMatrix(M, N, proc(i, j: int): float64 = (i + 3 * j).float64) 38 | n = makeMatrix(M, N, proc(i, j: int): float64 = (i + 3 * j).float64) 39 | p = makeMatrix(M, N, proc(i, j: int): float64 = (i - 2 * j).float64) 40 | check m == n 41 | check n != p 42 | test "strict 32-bit matrix equality": 43 | let 44 | M = 3 45 | N = 5 46 | m = makeMatrix(M, N, proc(i, j: int): float32 = (i + 3 * j).float32) 47 | n = makeMatrix(M, N, proc(i, j: int): float32 = (i + 3 * j).float32) 48 | p = makeMatrix(M, N, proc(i, j: int): float32 = (i - 2 * j).float32) 49 | check m == n 50 | check n != p 51 | test "approximate vector equality": 52 | let 53 | u = vector([1.0, 2.0, 3.0, 4.0]) 54 | v = vector([1.0, 2.0, 3.0, 4.0]) 55 | w = vector([1.0, 2.0, 2.999999999, 4.00000001]) 56 | z = vector([1.0, 3.0, 3.0, 4.0]) 57 | check u =~ v 58 | check v =~ w 59 | check v != w 60 | check w !=~ z 61 | test "approximate 32-bit vector equality": 62 | let 63 | u = vector([1'f32, 2'f32, 3'f32, 4'f32]) 64 | v = vector([1'f32, 2'f32, 3'f32, 4'f32]) 65 | w = vector([1'f32, 2'f32, 2.999999'f32, 4.000001'f32]) 66 | z = vector([1'f32, 3'f32, 3'f32, 4'f32]) 67 | check u =~ v 68 | check v =~ w 69 | check v != w 70 | check w !=~ z 71 | test "approximate vector equality handles zero vectors": 72 | let 73 | N = 5 74 | u = zeros(N) 75 | v = zeros(N) 76 | check u =~ v 77 | test "approximate matrix equality": 78 | let 79 | M = 3 80 | N = 5 81 | m = makeMatrix(M, N, proc(i, j: int): float64 = (i + 3 * j).float64) 82 | n = makeMatrix(M, N, proc(i, j: int): float64 = (i + 3 * j).float64) 83 | q = makeMatrix(M, N, proc(i, j: int): float64 = (i - 2 * j).float64) 84 | var p = makeMatrix(M, N, proc(i, j: int): float64 = (i + 3 * j).float64) 85 | p[2, 2] = p[2, 2] - 0.000000001 86 | p[1, 3] = p[1, 3] + 0.000000001 87 | check m =~ n 88 | check n =~ p 89 | check n != p 90 | check p !=~ q 91 | test "approximate 32-bit matrix equality": 92 | let 93 | M = 3 94 | N = 5 95 | m = makeMatrix(M, N, proc(i, j: int): float32 = (i + 3 * j).float32) 96 | n = makeMatrix(M, N, proc(i, j: int): float32 = (i + 3 * j).float32) 97 | q = makeMatrix(M, N, proc(i, j: int): float32 = (i - 2 * j).float32) 98 | var p = makeMatrix(M, N, proc(i, j: int): float32 = (i + 3 * j).float32) 99 | p[2, 2] = p[2, 2] - 0.000001 100 | p[1, 3] = p[1, 3] + 0.000001 101 | check m =~ n 102 | check n =~ p 103 | check n != p 104 | check p !=~ q 105 | test "approximate matrix equality handles zero vectors": 106 | let 107 | M = 3 108 | N = 5 109 | m = zeros(M, N) 110 | n = zeros(M, N) 111 | check m =~ n 112 | 113 | run() -------------------------------------------------------------------------------- /tests/dense/dinitialize.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2017 UniCredit S.p.A. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import unittest, neo/dense 16 | 17 | proc run() = 18 | suite "initializaton of vectors": 19 | test "zero vectors": 20 | let v = zeros(5) 21 | check v == vector([0.0, 0.0, 0.0, 0.0, 0.0]) 22 | test "one vectors": 23 | let v = ones(3) 24 | check v == vector([1.0, 1.0, 1.0]) 25 | test "constant vectors": 26 | let v = constantVector(4, 2.3) 27 | check v == vector([2.3, 2.3, 2.3, 2.3]) 28 | test "vectors generated by a proc": 29 | let v = makeVector(4, proc(i: int): float64 = (i * i).float64) 30 | check v == vector([0.0, 1.0, 4.0, 9.0]) 31 | test "vectors generated by an expression": 32 | let 33 | v = makeVector(4, proc(i: int): float64 = (i * i).float64) 34 | w = makeVectorI[float64](4, (i * i).float64) 35 | check v == w 36 | test "vectors generated randomly": 37 | let v = randomVector(6) 38 | check v.len == 6 39 | for i in 0 .. 5: 40 | check v[i] >= 0 41 | check v[i] <= 1 42 | 43 | suite "initializaton of 32-bit vectors": 44 | test "zero vectors": 45 | let v = zeros(5, float32) 46 | check v == vector([0'f32, 0, 0, 0, 0]) 47 | test "one vectors": 48 | let v = ones(3, float32) 49 | check v == vector([1'f32, 1'f32, 1'f32]) 50 | test "constant vectors": 51 | let v = constantVector(4, 2.5'f32) 52 | check v == vector([2.5'f32, 2.5'f32, 2.5'f32, 2.5'f32]) 53 | test "vectors generated by a proc": 54 | let v = makeVector(4, proc(i: int): float32 = (i * i).float32) 55 | check v == vector([0'f32, 1'f32, 4'f32, 9'f32]) 56 | test "vectors generated by an expression": 57 | let 58 | v = makeVector(4, proc(i: int): float32 = (i * i).float32) 59 | w = makeVectorI[float32](4, (i * i).float32) 60 | check v == w 61 | test "vectors generated randomly": 62 | let v = randomVector(6, max = 1'f32) 63 | check v.len == 6 64 | for i in 0 .. 5: 65 | check v[i] >= 0 66 | check v[i] <= 1 67 | 68 | suite "initializaton of matrices": 69 | test "zero matrices": 70 | let m = zeros(3, 2) 71 | check dim(m) == (3, 2) 72 | check m[0, 0] == 0.0 73 | check m[1, 0] == 0.0 74 | check m[2, 0] == 0.0 75 | check m[0, 1] == 0.0 76 | check m[1, 1] == 0.0 77 | check m[2, 1] == 0.0 78 | test "one matrices": 79 | let m = ones(2, 2) 80 | check dim(m) == (2, 2) 81 | check m[0, 0] == 1.0 82 | check m[1, 0] == 1.0 83 | check m[0, 1] == 1.0 84 | check m[1, 1] == 1.0 85 | test "constant matrices": 86 | let m = constantMatrix(2, 3, 1.5) 87 | check dim(m) == (2, 3) 88 | check m[0, 0] == 1.5 89 | check m[1, 0] == 1.5 90 | check m[0, 1] == 1.5 91 | check m[1, 1] == 1.5 92 | check m[0, 2] == 1.5 93 | check m[1, 2] == 1.5 94 | test "identity matrices": 95 | let m = eye(4) 96 | check dim(m) == (4, 4) 97 | for t, v in m: 98 | let (i, j) = t 99 | if i == j: 100 | check v == 1.0 101 | else: 102 | check v == 0.0 103 | test "matrices generated by a proc": 104 | let m = makeMatrix(3, 5, proc(i, j: int): float64 = (i * j).float64) 105 | check dim(m) == (3, 5) 106 | check m[0, 2] == 0.0 107 | check m[1, 1] == 1.0 108 | check m[2, 3] == 6.0 109 | check m[2, 4] == 8.0 110 | test "matrices generated by an expression": 111 | let 112 | m = makeMatrix(3, 5, proc(i, j: int): float64 = (i * j).float64) 113 | n = makeMatrixIJ(float64, 3, 5, (i * j).float64) 114 | check m == n 115 | test "matrices generated by a sequence": 116 | let 117 | a = @[ 118 | @[1.2, 3.2, 2.6], 119 | @[2.3, 2.8, -1.45], 120 | @[-1.2, 3.1, 3.3] 121 | ] 122 | m = matrix(a) 123 | check dim(m) == (3, 3) 124 | for i in 0 .. 2: 125 | for j in 0 .. 2: 126 | check m[i, j] == a[i][j] 127 | test "matrices generated randomly": 128 | let m = randomMatrix(3, 4) 129 | check dim(m) == (3, 4) 130 | for i in 0 .. 2: 131 | for j in 0 .. 3: 132 | check m[i, j] >= 0 133 | check m[i, j] <= 1 134 | test "diagonal matrices": 135 | let 136 | a = diag(0.0, 1.0, 2.0) 137 | b = makeMatrixIJ(float64, 3, 3, if i == j: i.float64 else: 0.0) 138 | check a == b 139 | 140 | suite "initializaton of 32-bit matrices": 141 | test "zero matrices": 142 | let m = zeros(3, 2, float32) 143 | check dim(m) == (3, 2) 144 | check m[0, 0] == 0'f32 145 | check m[1, 0] == 0'f32 146 | check m[2, 0] == 0'f32 147 | check m[0, 1] == 0'f32 148 | check m[1, 1] == 0'f32 149 | check m[2, 1] == 0'f32 150 | test "one matrices": 151 | let m = ones(2, 2, float32) 152 | check dim(m) == (2, 2) 153 | check m[0, 0] == 1'f32 154 | check m[1, 0] == 1'f32 155 | check m[0, 1] == 1'f32 156 | check m[1, 1] == 1'f32 157 | test "constant matrices": 158 | let m = constantMatrix(2, 3, 1.5'f32) 159 | check dim(m) == (2, 3) 160 | check m[0, 0] == 1.5'f32 161 | check m[1, 0] == 1.5'f32 162 | check m[0, 1] == 1.5'f32 163 | check m[1, 1] == 1.5'f32 164 | check m[0, 2] == 1.5'f32 165 | check m[1, 2] == 1.5'f32 166 | test "identity matrices": 167 | let m = eye(4, float32) 168 | check dim(m) == (4, 4) 169 | for t, v in m: 170 | let (i, j) = t 171 | if i == j: 172 | check v == 1'f32 173 | else: 174 | check v == 0'f32 175 | test "matrices generated by a proc": 176 | let m = makeMatrix(3, 5, proc(i, j: int): float32 = (i * j).float32) 177 | check dim(m) == (3, 5) 178 | check m[0, 2] == 0'f32 179 | check m[1, 1] == 1'f32 180 | check m[2, 3] == 6'f32 181 | check m[2, 4] == 8'f32 182 | test "matrices generated by an expression": 183 | let 184 | m = makeMatrix(3, 5, proc(i, j: int): float32 = (i * j).float32) 185 | n = makeMatrixIJ(float32, 3, 5, (i * j).float32) 186 | check m == n 187 | test "matrices generated by a sequence": 188 | let 189 | a = @[ 190 | @[1.2'f32, 3.2'f32, 2.6'f32], 191 | @[2.3'f32, 2.8'f32, -1.45'f32], 192 | @[-1.2'f32, 3.1'f32, 3.3'f32] 193 | ] 194 | m = matrix(a) 195 | check dim(m) == (3, 3) 196 | for i in 0 .. 2: 197 | for j in 0 .. 2: 198 | check m[i, j] == a[i][j] 199 | test "matrices generated randomly": 200 | let m = randomMatrix(3, 4, max = 1'f32) 201 | check dim(m) == (3, 4) 202 | for i in 0 .. 2: 203 | for j in 0 .. 3: 204 | check m[i, j] >= 0 205 | check m[i, j] <= 1 206 | test "diagonal matrices": 207 | let 208 | a = diag(0'f32, 1'f32, 2'f32) 209 | b = makeMatrixIJ(float32, 3, 3, if i == j: i.float32 else: 0) 210 | check a == b 211 | 212 | run() -------------------------------------------------------------------------------- /tests/dense/diterators.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2017 UniCredit S.p.A. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import unittest, neo/dense 16 | 17 | proc run() = 18 | suite "iterators on vectors": 19 | test "items vector iterator": 20 | let v = @[1.0, 3.0, 2.0, 8.0, -2.0] 21 | var 22 | sum = 0.0 23 | count = 0 24 | for x in v: 25 | sum += x 26 | count += 1 27 | check sum == 12.0 28 | check count == 5 29 | test "pairs vector iterator": 30 | let v = @[1.0, 3.0, 2.0, 8.0, -2.0] 31 | var 32 | sum = 0.0 33 | sumI = 0 34 | for i, x in v: 35 | sum += x 36 | sumI += i 37 | check sum == 12.0 38 | check sumI == 10 39 | 40 | suite "iterators on 32-bit vectors": 41 | test "items vector iterator": 42 | let v = @[1'f32, 3'f32, 2'f32, 8'f32, -2'f32] 43 | var 44 | sum = 0'f32 45 | count = 0 46 | for x in v: 47 | sum += x 48 | count += 1 49 | check sum == 12'f32 50 | check count == 5 51 | test "pairs vector iterator": 52 | let v = @[1'f32, 3'f32, 2'f32, 8'f32, -2'f32] 53 | var 54 | sum = 0'f32 55 | sumI = 0 56 | for i, x in v: 57 | sum += x 58 | sumI += i 59 | check sum == 12'f32 60 | check sumI == 10 61 | 62 | suite "iterators on matrices": 63 | test "items matrix iterator": 64 | let m = makeMatrix(3, 2, proc(i, j: int): float64 = (i + 2 * j + 1).float64) 65 | var 66 | sum = 0.0 67 | count = 0 68 | for x in m: 69 | sum += x 70 | count += 1 71 | check sum == 18.0 72 | check count == 6 73 | test "pairs matrix iterator": 74 | let m = makeMatrix(3, 2, proc(i, j: int): float64 = (i + 2 * j + 1).float64) 75 | var 76 | sum = 0.0 77 | sumI = 0 78 | for t, x in m: 79 | let (i, j) = t 80 | sum += x 81 | sumI += (i + j) 82 | check sum == 18.0 83 | check sumI == 9 84 | test "rows matrix iterator": 85 | let m = makeMatrix(3, 2, proc(i, j: int): float64 = (i + 2 * j + 1).float64) 86 | var 87 | sum = 0.0 88 | count = 0 89 | for r in m.rows: 90 | sum += (r[0] + r[1]) 91 | count += 1 92 | check sum == 18.0 93 | check count == 3 94 | test "columns matrix iterator": 95 | let m = makeMatrix(3, 2, proc(i, j: int): float64 = (i + 2 * j + 1).float64) 96 | var 97 | sum = 0.0 98 | count = 0 99 | for c in m.columns: 100 | sum += (c[0] + c[1] + c[2]) 101 | count += 1 102 | check sum == 18.0 103 | check count == 2 104 | test "rowsSlow matrix iterator": 105 | let m = makeMatrix(3, 2, proc(i, j: int): float64 = (i + 2 * j + 1).float64) 106 | var 107 | sum = 0.0 108 | count = 0 109 | for r in m.rowsSlow: 110 | sum += (r[0] + r[1]) 111 | count += 1 112 | check sum == 18.0 113 | check count == 3 114 | test "columnsSlow matrix iterator": 115 | let m = makeMatrix(3, 2, proc(i, j: int): float64 = (i + 2 * j + 1).float64) 116 | var 117 | sum = 0.0 118 | count = 0 119 | for c in m.columnsSlow: 120 | sum += (c[0] + c[1] + c[2]) 121 | count += 1 122 | check sum == 18.0 123 | check count == 2 124 | 125 | run() -------------------------------------------------------------------------------- /tests/dense/dmixed_ops.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2017 UniCredit S.p.A. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import unittest, neo/dense 16 | 17 | proc run() = 18 | suite "mixed slice assignments": 19 | test "assigning to a slice": 20 | var m = makeMatrixIJ(int, 5, 5, 3 * i + j) 21 | let n = matrix(@[ 22 | @[5, 6, 7], 23 | @[8, 9, 10], 24 | @[11, 12, 13] 25 | ], rowMajor) 26 | m[1 .. 3, 1 .. 3] = n 27 | check m[2, 2] == 9 28 | check m[3, 2] == 12 29 | 30 | test "assigning a slice to another slice": 31 | var m = makeMatrixIJ(int, 5, 5, 3 * i + j, rowMajor) 32 | let n = makeMatrixIJ(int, 5, 5, 2 * i + 2 * j) 33 | m[1 .. 3, 1 .. 3] = n[2 .. 4, 2 .. 4] 34 | check m[2, 2] == 12 35 | check m[3, 2] == 14 36 | 37 | test "assigning to a slice on columns only": 38 | var m = makeMatrixIJ(int, 5, 5, 3 * i + j) 39 | let n = makeMatrixIJ(int, 5, 3, 2 * i + 2 * j, rowMajor) 40 | 41 | m[All, 2 .. 4] = n 42 | check m[2, 2] == 4 43 | check m[3, 2] == 6 44 | 45 | test "assigning to a slice on rows only": 46 | var m = makeMatrixIJ(int, 5, 5, 3 * i + j, rowMajor) 47 | let n = makeMatrixIJ(int, 3, 5, 2 * i + 2 * j) 48 | 49 | m[2 .. 4, All] = n 50 | check m[2, 2] == 4 51 | check m[3, 2] == 6 52 | 53 | test "assigning to a slice with BLAS operations": 54 | var m = makeMatrixIJ(float64, 5, 5, (3 * i + j).float64, rowMajor) 55 | let n = matrix(@[ 56 | @[5'f64, 6, 7], 57 | @[8'f64, 9, 10], 58 | @[11'f64, 12, 13] 59 | ]) 60 | m[1 .. 3, 1 .. 3] = n 61 | check m[2, 2] == 9'f64 62 | check m[3, 2] == 12'f64 63 | 64 | suite "mixed matrix operations": 65 | test "mixed matrix sum": 66 | let 67 | m1 = matrix(@[ 68 | @[1.0, 0.0, 2.0, -1.0], 69 | @[-1.0, 1.0, 3.0, 1.0], 70 | @[3.0, 2.0, 2.0, 4.0] 71 | ], order = rowMajor) 72 | m2 = matrix(@[ 73 | @[3.0, 1.0, -1.0, 1.0], 74 | @[2.0, 1.0, -3.0, 0.0], 75 | @[4.0, 1.0, 2.0, 2.0] 76 | ]) 77 | m3 = matrix(@[ 78 | @[4.0, 1.0, 1.0, 0.0], 79 | @[1.0, 2.0, 0.0, 1.0], 80 | @[7.0, 3.0, 4.0, 6.0] 81 | ]) 82 | check(m1 + m2 == m3) 83 | test "mixed mutating matrix sum": 84 | var m1 = matrix(@[ 85 | @[1.0, 0.0, 2.0, -1.0], 86 | @[-1.0, 1.0, 3.0, 1.0], 87 | @[3.0, 2.0, 2.0, 4.0] 88 | ], order = rowMajor) 89 | let 90 | m2 = matrix(@[ 91 | @[3.0, 1.0, -1.0, 1.0], 92 | @[2.0, 1.0, -3.0, 0.0], 93 | @[4.0, 1.0, 2.0, 2.0] 94 | ]) 95 | m3 = matrix(@[ 96 | @[4.0, 1.0, 1.0, 0.0], 97 | @[1.0, 2.0, 0.0, 1.0], 98 | @[7.0, 3.0, 4.0, 6.0] 99 | ]) 100 | m1 += m2 101 | check m1 == m3 102 | test "mixed matrix difference": 103 | let 104 | m1 = matrix(@[ 105 | @[1.0, 0.0, 2.0, -1.0], 106 | @[-1.0, 1.0, 3.0, 1.0], 107 | @[3.0, 2.0, 2.0, 4.0] 108 | ]) 109 | m2 = matrix(@[ 110 | @[3.0, 1.0, -1.0, 1.0], 111 | @[2.0, 1.0, -3.0, 0.0], 112 | @[4.0, 1.0, 2.0, 2.0] 113 | ], order = rowMajor) 114 | m3 = matrix(@[ 115 | @[-2.0, -1.0, 3.0, -2.0], 116 | @[-3.0, 0.0, 6.0, 1.0], 117 | @[-1.0, 1.0, 0.0, 2.0] 118 | ]) 119 | check(m1 - m2 == m3) 120 | test "mutating matrix sum": 121 | var m1 = matrix(@[ 122 | @[1.0, 0.0, 2.0, -1.0], 123 | @[-1.0, 1.0, 3.0, 1.0], 124 | @[3.0, 2.0, 2.0, 4.0] 125 | ], order = rowMajor) 126 | let 127 | m2 = matrix(@[ 128 | @[3.0, 1.0, -1.0, 1.0], 129 | @[2.0, 1.0, -3.0, 0.0], 130 | @[4.0, 1.0, 2.0, 2.0] 131 | ]) 132 | m3 = matrix(@[ 133 | @[-2.0, -1.0, 3.0, -2.0], 134 | @[-3.0, 0.0, 6.0, 1.0], 135 | @[-1.0, 1.0, 0.0, 2.0] 136 | ]) 137 | m1 -= m2 138 | check m1 == m3 139 | test "mixed matrix multiplication": 140 | let 141 | m1 = matrix(@[ 142 | @[1.0, 1.0, 2.0, -3.0], 143 | @[3.0, 0.0, -7.0, 2.0] 144 | ], order = rowMajor) 145 | m2 = matrix(@[ 146 | @[1.0, 1.0, 2.0], 147 | @[3.0, 1.0, -5.0], 148 | @[-1.0, -1.0, 2.0], 149 | @[4.0, 2.0, 3.0] 150 | ]) 151 | m3 = matrix(@[ 152 | @[-10.0, -6.0, -8.0], 153 | @[18.0, 14.0, -2.0] 154 | ]) 155 | check(m1 * m2 == m3) 156 | test "mixed matrix multiplication take two": 157 | let 158 | m1 = matrix(@[ 159 | @[1.0, 1.0, 2.0, -3.0], 160 | @[3.0, 0.0, -7.0, 2.0] 161 | ]) 162 | m2 = matrix(@[ 163 | @[1.0, 1.0, 2.0], 164 | @[3.0, 1.0, -5.0], 165 | @[-1.0, -1.0, 2.0], 166 | @[4.0, 2.0, 3.0] 167 | ], order = rowMajor) 168 | m3 = matrix(@[ 169 | @[-10.0, -6.0, -8.0], 170 | @[18.0, 14.0, -2.0] 171 | ]) 172 | check(m1 * m2 == m3) 173 | test "mixed matrix Hadamard multiplication": 174 | let 175 | m1 = matrix(@[ 176 | @[1.0, 0.0, 2.0, -1.0], 177 | @[-1.0, 1.0, 3.0, 1.0], 178 | @[3.0, 2.0, 2.0, 4.0] 179 | ]) 180 | m2 = matrix(@[ 181 | @[3.0, 1.0, -1.0, 1.0], 182 | @[2.0, 1.0, -3.0, 0.0], 183 | @[4.0, 1.0, 2.0, 2.0] 184 | ], order = rowMajor) 185 | m3 = matrix(@[ 186 | @[3.0, 0.0, -2.0, -1.0], 187 | @[-2.0, 1.0, -9.0, 0.0], 188 | @[12.0, 2.0, 4.0, 8.0] 189 | ]) 190 | check((m1 |*| m2) == m3) 191 | 192 | run() -------------------------------------------------------------------------------- /tests/dense/drow_major_ops.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2017 UniCredit S.p.A. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import unittest, neo/dense 16 | 17 | proc run() = 18 | suite "row-major matrix/vector operations": 19 | test "multiplication of matrix and vector": 20 | let 21 | m = matrix(@[ 22 | @[1.0, 0.0, 2.0, -1.0], 23 | @[-1.0, 1.0, 3.0, 1.0], 24 | @[3.0, 2.0, 2.0, 4.0] 25 | ], order = rowMajor) 26 | v = vector([1.0, 3.0, 2.0, -2.0]) 27 | check((m * v) == vector([7.0, 6.0, 5.0])) 28 | 29 | suite "row-major matrix operations": 30 | test "scalar matrix multiplication": 31 | let 32 | m1 = matrix(@[ 33 | @[1.0, 3.0], 34 | @[2.0, 8.0], 35 | @[-2.0, 3.0] 36 | ], order = rowMajor) 37 | m2 = matrix(@[ 38 | @[3.0, 9.0], 39 | @[6.0, 24.0], 40 | @[-6.0, 9.0] 41 | ], order = rowMajor) 42 | check(m1 * 3.0 == m2) 43 | check(3.0 * m1 == m2) 44 | test "mutating scalar multiplication": 45 | var m1 = matrix(@[ 46 | @[1.0, 3.0], 47 | @[2.0, 8.0], 48 | @[-2.0, 3.0] 49 | ], order = rowMajor) 50 | let m2 = matrix(@[ 51 | @[3.0, 9.0], 52 | @[6.0, 24.0], 53 | @[-6.0, 9.0] 54 | ], order = rowMajor) 55 | m1 *= 3.0 56 | check(m1 == m2) 57 | test "matrix sum": 58 | let 59 | m1 = matrix(@[ 60 | @[1.0, 0.0, 2.0, -1.0], 61 | @[-1.0, 1.0, 3.0, 1.0], 62 | @[3.0, 2.0, 2.0, 4.0] 63 | ], order = rowMajor) 64 | m2 = matrix(@[ 65 | @[3.0, 1.0, -1.0, 1.0], 66 | @[2.0, 1.0, -3.0, 0.0], 67 | @[4.0, 1.0, 2.0, 2.0] 68 | ], order = rowMajor) 69 | m3 = matrix(@[ 70 | @[4.0, 1.0, 1.0, 0.0], 71 | @[1.0, 2.0, 0.0, 1.0], 72 | @[7.0, 3.0, 4.0, 6.0] 73 | ], order = rowMajor) 74 | check(m1 + m2 == m3) 75 | test "mutating matrix sum": 76 | var m1 = matrix(@[ 77 | @[1.0, 0.0, 2.0, -1.0], 78 | @[-1.0, 1.0, 3.0, 1.0], 79 | @[3.0, 2.0, 2.0, 4.0] 80 | ], order = rowMajor) 81 | let 82 | m2 = matrix(@[ 83 | @[3.0, 1.0, -1.0, 1.0], 84 | @[2.0, 1.0, -3.0, 0.0], 85 | @[4.0, 1.0, 2.0, 2.0] 86 | ], order = rowMajor) 87 | m3 = matrix(@[ 88 | @[4.0, 1.0, 1.0, 0.0], 89 | @[1.0, 2.0, 0.0, 1.0], 90 | @[7.0, 3.0, 4.0, 6.0] 91 | ], order = rowMajor) 92 | m1 += m2 93 | check m1 == m3 94 | test "matrix difference": 95 | let 96 | m1 = matrix(@[ 97 | @[1.0, 0.0, 2.0, -1.0], 98 | @[-1.0, 1.0, 3.0, 1.0], 99 | @[3.0, 2.0, 2.0, 4.0] 100 | ], order = rowMajor) 101 | m2 = matrix(@[ 102 | @[3.0, 1.0, -1.0, 1.0], 103 | @[2.0, 1.0, -3.0, 0.0], 104 | @[4.0, 1.0, 2.0, 2.0] 105 | ], order = rowMajor) 106 | m3 = matrix(@[ 107 | @[-2.0, -1.0, 3.0, -2.0], 108 | @[-3.0, 0.0, 6.0, 1.0], 109 | @[-1.0, 1.0, 0.0, 2.0] 110 | ], order = rowMajor) 111 | check(m1 - m2 == m3) 112 | test "mutating matrix sum": 113 | var m1 = matrix(@[ 114 | @[1.0, 0.0, 2.0, -1.0], 115 | @[-1.0, 1.0, 3.0, 1.0], 116 | @[3.0, 2.0, 2.0, 4.0] 117 | ], order = rowMajor) 118 | let 119 | m2 = matrix(@[ 120 | @[3.0, 1.0, -1.0, 1.0], 121 | @[2.0, 1.0, -3.0, 0.0], 122 | @[4.0, 1.0, 2.0, 2.0] 123 | ], order = rowMajor) 124 | m3 = matrix(@[ 125 | @[-2.0, -1.0, 3.0, -2.0], 126 | @[-3.0, 0.0, 6.0, 1.0], 127 | @[-1.0, 1.0, 0.0, 2.0] 128 | ], order = rowMajor) 129 | m1 -= m2 130 | check m1 == m3 131 | test "matrix ℓ² norm": 132 | let m = matrix(@[ 133 | @[1.0, 1.0, 2.0], 134 | @[3.0, 0.0, -7.0] 135 | ], order = rowMajor) 136 | check l_2(m) == 8.0 137 | test "matrix ℓ¹ norm": 138 | let m = matrix(@[ 139 | @[1.0, 1.0, 2.0], 140 | @[3.0, 0.0, -7.0], 141 | @[2.5, 3.1, -1.4] 142 | ], order = rowMajor) 143 | check l_1(m) == 21.0 144 | test "max and min of matrices": 145 | let m = matrix(@[ 146 | @[1.0, 1.0, 2.0], 147 | @[3.0, 0.0, -7.0] 148 | ], order = rowMajor) 149 | check max(m) == 3.0 150 | check min(m) == -7.0 151 | test "matrix multiplication": 152 | let 153 | m1 = matrix(@[ 154 | @[1.0, 1.0, 2.0, -3.0], 155 | @[3.0, 0.0, -7.0, 2.0] 156 | ], order = rowMajor) 157 | m2 = matrix(@[ 158 | @[1.0, 1.0, 2.0], 159 | @[3.0, 1.0, -5.0], 160 | @[-1.0, -1.0, 2.0], 161 | @[4.0, 2.0, 3.0] 162 | ], order = rowMajor) 163 | m3 = matrix(@[ 164 | @[-10.0, -6.0, -8.0], 165 | @[18.0, 14.0, -2.0] 166 | ], order = rowMajor) 167 | check(m1 * m2 == m3) 168 | test "matrix Hadamard multiplication": 169 | let 170 | m1 = matrix(@[ 171 | @[1.0, 0.0, 2.0, -1.0], 172 | @[-1.0, 1.0, 3.0, 1.0], 173 | @[3.0, 2.0, 2.0, 4.0] 174 | ], order = rowMajor) 175 | m2 = matrix(@[ 176 | @[3.0, 1.0, -1.0, 1.0], 177 | @[2.0, 1.0, -3.0, 0.0], 178 | @[4.0, 1.0, 2.0, 2.0] 179 | ], order = rowMajor) 180 | m3 = matrix(@[ 181 | @[3.0, 0.0, -2.0, -1.0], 182 | @[-2.0, 1.0, -9.0, 0.0], 183 | @[12.0, 2.0, 4.0, 8.0] 184 | ], order = rowMajor) 185 | check((m1 |*| m2) == m3) 186 | 187 | run() -------------------------------------------------------------------------------- /tests/dense/dshared.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2017 UniCredit S.p.A. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import unittest, neo/dense 16 | 17 | proc run() = 18 | suite "shared vectors and matrices": 19 | test "creating and accessing shared vectors": 20 | var v = sharedVector(5, float64) 21 | defer: 22 | dealloc(v) 23 | 24 | check v.len == 5 25 | 26 | v[3] = -1.0 27 | v[2] = 3.0 28 | check v[3] == -1.0 29 | check v.sum == 2.0 30 | 31 | test "operations on shared vectors": 32 | var v = sharedVector(6, float64) 33 | defer: 34 | dealloc(v) 35 | let w = vector(1.0, 2.0, 3.0, 1.0, 2.0, 3.0) 36 | for i in 0 .. 5: 37 | v[i] = (i + 1).float64 38 | 39 | check(v + w == vector(2.0, 4.0, 6.0, 5.0, 7.0, 9.0)) 40 | v += w 41 | 42 | check v[1] == 4.0 43 | 44 | check v + w == w + v 45 | 46 | test "creating and accessing shared matrices": 47 | let data = [ 48 | [1'f64, 2, 3], 49 | [4'f64, 5, 6], 50 | [7'f64, 8, 9] 51 | ] 52 | var m = sharedMatrix(3, 3, float64) 53 | defer: 54 | dealloc(m) 55 | for i in 0 .. 2: 56 | for j in 0 .. 2: 57 | m[i, j] = data[j][i] 58 | 59 | check m.M == 3 60 | check m.N == 3 61 | check m[2, 1] == 6.0 62 | 63 | m[2, 0] = -1.0 64 | check m[2, 0] == -1.0 65 | 66 | test "operations on shared matrices": 67 | let 68 | data = [ 69 | [1'f64, 2, 3], 70 | [4'f64, 5, 6], 71 | [7'f64, 8, 9] 72 | ] 73 | v = vector(1.0, 2.0, 3.0) 74 | var m = sharedMatrix(3, 3, float64) 75 | defer: 76 | dealloc(m) 77 | for i in 0 .. 2: 78 | for j in 0 .. 2: 79 | m[i, j] = data[j][i] 80 | 81 | check m * v == vector(30.0, 36.0, 42.0) 82 | 83 | test "slicing shared matrices": 84 | let 85 | data = [ 86 | [1'f64, 2, 3], 87 | [4'f64, 5, 6], 88 | [7'f64, 8, 9] 89 | ] 90 | v = vector(1.0, 2.0, 3.0) 91 | var m = sharedMatrix(3, 3, float64) 92 | defer: 93 | dealloc(m) 94 | for i in 0 .. 2: 95 | for j in 0 .. 2: 96 | m[i, j] = data[j][i] 97 | 98 | check m * v == vector(30.0, 36.0, 42.0) 99 | 100 | check m[1 .. 2, 1 .. 2] == matrix(@[@[5.0, 8.0], @[6.0, 9.0]]) 101 | check m.column(2) == vector(7.0, 8.0, 9.0) 102 | 103 | test "row major shared matrices": 104 | let 105 | data = [ 106 | [1'f64, 2, 3], 107 | [4'f64, 5, 6], 108 | [7'f64, 8, 9] 109 | ] 110 | var m = sharedMatrix(3, 3, float64, rowMajor) 111 | defer: 112 | dealloc(m) 113 | for i in 0 .. 2: 114 | for j in 0 .. 2: 115 | m[i, j] = data[i][j] 116 | 117 | check m.M == 3 118 | check m.N == 3 119 | check m[2, 1] == 8.0 120 | 121 | m[2, 0] = -1.0 122 | check m[2, 0] == -1.0 123 | 124 | run() -------------------------------------------------------------------------------- /tests/dense/dsolvers.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2017 UniCredit S.p.A. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import unittest, neo/dense 16 | 17 | proc run() = 18 | suite "linear system solving": 19 | test "matrix-matrix solver": 20 | let 21 | a = matrix(@[ 22 | @[3.0, 1.0], 23 | @[1.0, -2.0] 24 | ]) 25 | b = matrix(@[ 26 | @[1.0], 27 | @[0.0] 28 | ]) 29 | x = solve(a, b) 30 | expected = matrix(@[ 31 | @[2.0 / 7.0], 32 | @[1.0 / 7.0] 33 | ]) 34 | check expected =~ x 35 | 36 | test "matrix-matrix solve operator": 37 | let 38 | a = matrix(@[ 39 | @[3.0, 1.0], 40 | @[1.0, -2.0] 41 | ]) 42 | b = matrix(@[ 43 | @[1.0], 44 | @[0.0] 45 | ]) 46 | x = a \ b 47 | expected = matrix(@[ 48 | @[2.0 / 7.0], 49 | @[1.0 / 7.0] 50 | ]) 51 | check expected =~ x 52 | 53 | test "singular matrix error": 54 | let 55 | a = matrix(@[ 56 | @[2.0, 2.0], 57 | @[1.0, 1.0] 58 | ]) 59 | b = matrix(@[ 60 | @[1.0], 61 | @[0.0] 62 | ]) 63 | expect FloatingPointError: 64 | discard solve(a, b) 65 | 66 | test "matrix-matrix solver 32 bit": 67 | let 68 | a = matrix(@[ 69 | @[3'f32, 1'f32], 70 | @[1'f32, -2'f32] 71 | ]) 72 | b = matrix(@[ 73 | @[1'f32], 74 | @[0'f32] 75 | ]) 76 | x = solve(a, b) 77 | expected = matrix(@[ 78 | @[2'f32 / 7'f32], 79 | @[1'f32 / 7'f32] 80 | ]) 81 | check expected =~ x 82 | 83 | test "matrix inverse": 84 | let 85 | a = matrix(@[ 86 | @[4.0, 3.0], 87 | @[3.0, 2.0] 88 | ]) 89 | expected = matrix(@[ 90 | @[-2.0, 3.0], 91 | @[3.0, -4.0] 92 | ]) 93 | ainv = inv(a) 94 | check expected =~ ainv 95 | 96 | test "matrix inverse 32 bit": 97 | let 98 | a = matrix(@[ 99 | @[4.0'f32, 3.0'f32], 100 | @[3.0'f32, 2.0'f32] 101 | ]) 102 | expected = matrix(@[ 103 | @[-2.0'f32, 3.0'f32], 104 | @[3.0'f32, -4.0'f32] 105 | ]) 106 | ainv = inv(a) 107 | check expected =~ ainv 108 | 109 | test "matrix-vector solver": 110 | let 111 | a = matrix(@[ 112 | @[3.0, 1.0], 113 | @[1.0, -2.0] 114 | ]) 115 | b = vector([1.0, 0.0]) 116 | x = solve(a, b) 117 | expected = vector([2.0/7.0, 1.0/7.0]) 118 | check expected =~ x 119 | 120 | test "matrix-vector solve operator": 121 | let 122 | a = matrix(@[ 123 | @[3.0, 1.0], 124 | @[1.0, -2.0] 125 | ]) 126 | b = vector([1.0, 0.0]) 127 | x = a \ b 128 | expected = vector([2.0/7.0, 1.0/7.0]) 129 | check expected =~ x 130 | 131 | test "matrix-vector singular matrix error": 132 | let 133 | a = matrix(@[ 134 | @[0.0, 0.0], 135 | @[0.0, 0.0] 136 | ]) 137 | b = vector([1.0, 0.0]) 138 | expect FloatingPointError: 139 | discard solve(a, b) 140 | 141 | test "matrix-vector solver 32": 142 | let 143 | a = matrix(@[ 144 | @[3.0'f32, 1.0'f32], 145 | @[1.0'f32, -2.0'f32] 146 | ]) 147 | b = vector([1.0'f32, 0.0'f32]) 148 | x = solve(a, b) 149 | expected = vector([2.0'f32/7.0'f32, 1.0'f32/7.0'f32]) 150 | check expected =~ x 151 | 152 | run() -------------------------------------------------------------------------------- /tests/dense/dstack.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2017 UniCredit S.p.A. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import unittest, neo/dense 16 | 17 | proc run() = 18 | suite "vectors and matrices on the stack": 19 | test "creating and accessing vectors on the stack": 20 | var 21 | data = [1'f64, 2, 3, 4, 5, 6] 22 | v = stackVector(data) 23 | 24 | check v.len == 6 25 | check v[4] == 5.0 26 | 27 | v[5] = -1.0 28 | check data[5] == -1.0 29 | 30 | test "operations on vectors on the stack": 31 | var 32 | data = [1'f64, 2, 3, 4, 5, 6] 33 | v = stackVector(data) 34 | w = vector(1.0, 2.0, 3.0, 1.0, 2.0, 3.0) 35 | 36 | check(v + w == vector(2.0, 4.0, 6.0, 5.0, 7.0, 9.0)) 37 | v += w 38 | 39 | check v[1] == 4.0 40 | 41 | check v + w == w + v 42 | 43 | test "creating and accessing matrices on the stack": 44 | var 45 | data = [ 46 | [1'f64, 2, 3], 47 | [4'f64, 5, 6], 48 | [7'f64, 8, 9] 49 | ] 50 | m = stackMatrix(data) 51 | 52 | check m.M == 3 53 | check m.N == 3 54 | check m[2, 1] == 6.0 55 | 56 | m[2, 0] = -1.0 57 | check data[0][2] == -1.0 58 | 59 | test "operations on matrices on the stack": 60 | var 61 | data = [ 62 | [1'f64, 2, 3], 63 | [4'f64, 5, 6], 64 | [7'f64, 8, 9] 65 | ] 66 | m = stackMatrix(data) 67 | v = vector(1.0, 2.0, 3.0) 68 | 69 | check m * v == vector(30.0, 36.0, 42.0) 70 | 71 | test "slicing matrices on the stack": 72 | var 73 | data = [ 74 | [1'f64, 2, 3], 75 | [4'f64, 5, 6], 76 | [7'f64, 8, 9] 77 | ] 78 | m = stackMatrix(data) 79 | 80 | check m[1 .. 2, 1 .. 2] == matrix(@[@[5.0, 8.0], @[6.0, 9.0]]) 81 | check m.column(2) == vector(7.0, 8.0, 9.0) 82 | 83 | test "row major matrices on the stack": 84 | var 85 | data = [ 86 | [1'f64, 2, 3], 87 | [4'f64, 5, 6], 88 | [7'f64, 8, 9] 89 | ] 90 | m = stackMatrix(data, rowMajor) 91 | 92 | check m.M == 3 93 | check m.N == 3 94 | check m[2, 1] == 8.0 95 | 96 | m[2, 0] = -1.0 97 | check data[2][0] == -1.0 98 | 99 | run() -------------------------------------------------------------------------------- /tests/dense/dstacking.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2018 UniCredit S.p.A. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import unittest, neo/dense 16 | 17 | proc run() = 18 | suite "stacking of vectors": 19 | test "concat (horizontal stack) of two vectors": 20 | let 21 | v1 = vector([1.0, 2.0]) 22 | v2 = vector([5.0, 7.0, 9.0]) 23 | v = vector([1.0, 2.0, 5.0, 7.0, 9.0]) 24 | check concat(v1, v2) == v 25 | check hstack(v1, v2) == v 26 | 27 | test "concat (horizontal stack) of three vectors": 28 | let 29 | v1 = vector([1.0, 2.0]) 30 | v2 = vector([5.0, 7.0, 9.0]) 31 | v3 = vector([9.9, 8.8, 7.7, 6.6]) 32 | v = vector([1.0, 2.0, 5.0, 7.0, 9.0, 9.9, 8.8, 7.7, 6.6]) 33 | check concat(v1, v2, v3) == v 34 | check hstack(v1, v2, v3) == v 35 | 36 | test "concat (horizontal stack) of two non-contiguous vectors": 37 | let 38 | v1 = matrix(@[ 39 | @[1.0, 0.0], 40 | @[2.0, 0.0] 41 | ], order=rowMajor).column(0) 42 | v2 = matrix(@[ 43 | @[5.0, 0.0], 44 | @[7.0, 0.0], 45 | @[9.0, 0.0] 46 | ], order=rowMajor).column(0) 47 | v = vector([1.0, 2.0, 5.0, 7.0, 9.0]) 48 | check concat(v1, v2) == v 49 | check hstack(v1, v2) == v 50 | 51 | test "horizontal stack of two matrices": 52 | let 53 | m1 = matrix(@[ 54 | @[1.0, 2.0], 55 | @[3.0, 4.0] 56 | ]) 57 | m2 = matrix(@[ 58 | @[5.0, 7.0, 9.0], 59 | @[6.0, 2.0, 1.0] 60 | ]) 61 | m = matrix(@[ 62 | @[1.0, 2.0, 5.0, 7.0, 9.0], 63 | @[3.0, 4.0, 6.0, 2.0, 1.0] 64 | ]) 65 | check hstack(m1, m2) == m 66 | 67 | test "horizontal stack of three matrices": 68 | let 69 | m1 = matrix(@[ 70 | @[1.0, 2.0], 71 | @[3.0, 4.0] 72 | ]) 73 | m2 = matrix(@[ 74 | @[5.0, 7.0, 9.0], 75 | @[6.0, 2.0, 1.0] 76 | ]) 77 | m3 = matrix(@[ 78 | @[2.0, 2.0], 79 | @[1.0, 3.0] 80 | ]) 81 | m = matrix(@[ 82 | @[1.0, 2.0, 5.0, 7.0, 9.0, 2.0, 2.0], 83 | @[3.0, 4.0, 6.0, 2.0, 1.0, 1.0, 3.0] 84 | ]) 85 | check hstack(m1, m2, m3) == m 86 | 87 | test "vertical stack of two vectors": 88 | let 89 | v1 = vector([1.0, 2.0, 3.0]) 90 | v2 = vector([5.0, 7.0, 9.0]) 91 | m = matrix(@[ 92 | @[1.0, 2.0, 3.0], 93 | @[5.0, 7.0, 9.0] 94 | ]) 95 | check matrix(@[v1, v2]) == m 96 | check vstack(v1, v2) == m 97 | 98 | test "vertical stack of three vectors": 99 | let 100 | v1 = vector([1.0, 2.0, 3.0]) 101 | v2 = vector([5.0, 7.0, 9.0]) 102 | v3 = vector([9.9, 8.8, 7.7]) 103 | m = matrix(@[ 104 | @[1.0, 2.0, 3.0], 105 | @[5.0, 7.0, 9.0], 106 | @[9.9, 8.8, 7.7] 107 | ]) 108 | check matrix(@[v1, v2, v3]) == m 109 | check vstack(v1, v2, v3) == m 110 | 111 | test "vertical stack of three matrices": 112 | let 113 | m1 = matrix(@[ 114 | @[1.0, 2.0], 115 | @[3.0, 4.0] 116 | ]).T 117 | m2 = matrix(@[ 118 | @[5.0, 7.0, 9.0], 119 | @[6.0, 2.0, 1.0] 120 | ]).T 121 | m3 = matrix(@[ 122 | @[2.0, 2.0], 123 | @[1.0, 3.0] 124 | ]).T 125 | m = matrix(@[ 126 | @[1.0, 2.0, 5.0, 7.0, 9.0, 2.0, 2.0], 127 | @[3.0, 4.0, 6.0, 2.0, 1.0, 1.0, 3.0] 128 | ]).T 129 | check vstack(m1, m2, m3) == m 130 | 131 | run() 132 | -------------------------------------------------------------------------------- /tests/dense/dtrivial_ops.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2017 UniCredit S.p.A. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import unittest, neo/dense 16 | 17 | proc run() = 18 | suite "trivial operations on 32-bit matrices": 19 | test "reshape of matrices": 20 | let 21 | m1 = matrix(@[ 22 | @[1'f32, 0'f32, 2'f32, -1'f32], 23 | @[-1'f32, 1'f32, 3'f32, 1'f32], 24 | @[3'f32, 2'f32, 2'f32, 4'f32] 25 | ]) 26 | m2 = matrix(@[ 27 | @[1'f32, 1'f32, 2'f32], 28 | @[-1'f32, 2'f32, -1'f32], 29 | @[3'f32, 2'f32, 1'f32], 30 | @[0'f32, 3'f32, 4'f32] 31 | ]) 32 | check m1.reshape(4, 3) == m2 33 | test "turn vectors into matrices": 34 | let 35 | v = vector([1'f32, -1'f32, 3'f32, 0'f32, 1'f32, 2'f32, 2'f32, 3'f32, 2'f32, -1'f32, 1'f32, 4'f32]) 36 | m = matrix(@[ 37 | @[1'f32, 0'f32, 2'f32, -1'f32], 38 | @[-1'f32, 1'f32, 3'f32, 1'f32], 39 | @[3'f32, 2'f32, 2'f32, 4'f32] 40 | ]) 41 | check v.asMatrix(3, 4) == m 42 | test "turn matrices into vectors": 43 | let 44 | v = vector([1'f32, -1'f32, 3'f32, 0'f32, 1'f32, 2'f32, 2'f32, 3'f32, 2'f32, -1'f32, 1'f32, 4'f32]) 45 | m = matrix(@[ 46 | @[1'f32, 0'f32, 2'f32, -1'f32], 47 | @[-1'f32, 1'f32, 3'f32, 1'f32], 48 | @[3'f32, 2'f32, 2'f32, 4'f32] 49 | ]) 50 | check m.asVector == v 51 | test "transpose of matrices": 52 | let 53 | m1 = matrix(@[ 54 | @[1'f32, 0'f32, 2'f32, -1'f32], 55 | @[-1'f32, 1'f32, 3'f32, 1'f32], 56 | @[3'f32, 2'f32, 2'f32, 4'f32] 57 | ]) 58 | m2 = matrix(@[ 59 | @[1'f32, -1'f32, 3'f32], 60 | @[0'f32, 1'f32, 2'f32], 61 | @[2'f32, 3'f32, 2'f32], 62 | @[-1'f32, 1'f32, 4'f32] 63 | ]) 64 | check m1.t == m2 65 | test "hard transpose of matrices": 66 | let m = matrix(@[ 67 | @[1'f32, 0'f32, 2'f32, -1'f32], 68 | @[-1'f32, 1'f32, 3'f32, 1'f32], 69 | @[3'f32, 2'f32, 2'f32, 4'f32] 70 | ]) 71 | 72 | check(m.t == m.T) 73 | test "hard transpose of row major matrices": 74 | let m = matrix(@[ 75 | @[1'f32, 0'f32, 2'f32, -1'f32], 76 | @[-1'f32, 1'f32, 3'f32, 1'f32], 77 | @[3'f32, 2'f32, 2'f32, 4'f32] 78 | ], order = rowMajor) 79 | 80 | check(m.t == m.T) 81 | 82 | suite "trivial operations should share storage": 83 | test "reshape of matrices": 84 | var 85 | m1 = matrix(@[ 86 | @[1.0, 0.0, 2.0, -1.0], 87 | @[-1.0, 1.0, 3.0, 1.0], 88 | @[3.0, 2.0, 2.0, 4.0] 89 | ]) 90 | m2 = m1.reshape(4, 3) 91 | m2[2, 1] = 0.0 92 | check m1[0, 2] == 0.0 93 | test "turn vectors into matrices": 94 | var 95 | v = vector([1.0, -1.0, 3.0, 0.0, 1.0, 2.0, 2.0, 3.0, 2.0, -1.0, 1.0, 4.0]) 96 | m = v.asMatrix(3, 4) 97 | m[2, 1] = 0.0 98 | check v[5] == 0.0 99 | test "turn matrices into vectors": 100 | var 101 | m = matrix(@[ 102 | @[1.0, 0.0, 2.0, -1.0], 103 | @[-1.0, 1.0, 3.0, 1.0], 104 | @[3.0, 2.0, 2.0, 4.0] 105 | ]) 106 | v = m.asVector 107 | v[5] = 0.0 108 | check m[2, 1] == 0.0 109 | test "transpose of matrices": 110 | var 111 | m1 = matrix(@[ 112 | @[1.0, 0.0, 2.0, -1.0], 113 | @[-1.0, 1.0, 3.0, 1.0], 114 | @[3.0, 2.0, 2.0, 4.0] 115 | ]) 116 | m2 = m1.t 117 | m2[1, 2] = 0.0 118 | check m1[2, 1] == 0.0 119 | 120 | suite "trivial operations on 32-bit matrices should share storage": 121 | test "reshape of matrices": 122 | var 123 | m1 = matrix(@[ 124 | @[1'f32, 0'f32, 2'f32, -1'f32], 125 | @[-1'f32, 1'f32, 3'f32, 1'f32], 126 | @[3'f32, 2'f32, 2'f32, 4'f32] 127 | ]) 128 | m2 = m1.reshape(4, 3) 129 | m2[2, 1] = 0'f32 130 | check m1[0, 2] == 0'f32 131 | test "turn vectors into matrices": 132 | var 133 | v = vector([1'f32, -1'f32, 3'f32, 0'f32, 1'f32, 2'f32, 2'f32, 3'f32, 2'f32, -1'f32, 1'f32, 4'f32]) 134 | m = v.asMatrix(3, 4) 135 | m[2, 1] = 0'f32 136 | check v[5] == 0'f32 137 | test "turn matrices into vectors": 138 | var 139 | m = matrix(@[ 140 | @[1'f32, 0'f32, 2'f32, -1'f32], 141 | @[-1'f32, 1'f32, 3'f32, 1'f32], 142 | @[3'f32, 2'f32, 2'f32, 4'f32] 143 | ]) 144 | v = m.asVector 145 | v[5] = 0'f32 146 | check m[2, 1] == 0'f32 147 | test "transpose of matrices": 148 | var 149 | m1 = matrix(@[ 150 | @[1'f32, 0'f32, 2'f32, -1'f32], 151 | @[-1'f32, 1'f32, 3'f32, 1'f32], 152 | @[3'f32, 2'f32, 2'f32, 4'f32] 153 | ]) 154 | m2 = m1.t 155 | m2[1, 2] = 0'f32 156 | check m1[2, 1] == 0'f32 157 | 158 | run() -------------------------------------------------------------------------------- /tests/dense/dufunc.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2017 UniCredit S.p.A. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import unittest, neo/dense 16 | 17 | proc run() = 18 | suite "universal functions": 19 | test "universal sqrt on vectors": 20 | let u = vector([1.0, 4.0, 9.0, 16.0]) 21 | check sqrt(u) == vector([1.0, 2.0, 3.0, 4.0]) 22 | test "universal natural log": 23 | let u = vector([1.0, 4.0, 9.0, 16.0]) 24 | check ln(u)[0] == 0 25 | test "universal sine on matrices": 26 | let m = matrix(@[@[1.0, 2.0], @[4.0, 8.0]]) 27 | check sin(m) == matrix(@[@[sin(1.0), sin(2.0)], @[sin(4.0), sin(8.0)]]) 28 | test "defining a new universal function": 29 | proc plusFive(x: float64): float64 = x + 5 30 | makeUniversalLocal(plusFive) 31 | let v = vector([1.0, 4.0, 9.0, 16.0]) 32 | check plusFive(v) == vector([6.0, 9.0, 14.0, 21.0]) 33 | 34 | 35 | suite "32-bit universal functions": 36 | test "universal sqrt on vectors": 37 | let u = vector([1'f32, 4'f32, 9'f32, 16'f32]) 38 | check sqrt(u) == vector([1'f32, 2'f32, 3'f32, 4'f32]) 39 | test "universal natural log": 40 | let u = vector([1'f32, 4'f32, 9'f32, 16'f32]) 41 | check ln(u)[0] == 0 42 | test "universal sine on matrices": 43 | let m = matrix(@[@[1'f32, 2'f32], @[4'f32, 8'f32]]) 44 | check sin(m) == matrix(@[@[sin(1'f32), sin(2'f32)], @[sin(4'f32), sin(8'f32)]]) 45 | test "defining a new universal function": 46 | proc plusFive(x: float64): float64 = x + 5 47 | makeUniversalLocal(plusFive) 48 | let v = vector([1'f32, 4'f32, 9'f32, 16'f32]) 49 | check plusFive(v) == vector([6'f32, 9'f32, 14'f32, 21'f32]) 50 | 51 | run() -------------------------------------------------------------------------------- /tests/nim.cfg: -------------------------------------------------------------------------------- 1 | --cincludes: "/usr/local/cuda/include" 2 | --clibdir: "/usr/local/cuda/lib64" 3 | --path:".." -------------------------------------------------------------------------------- /tests/rewrites.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2017 UniCredit S.p.A. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import unittest, neo/dense 16 | 17 | 18 | suite "rewrite macros tests": 19 | test "vector linear combination": 20 | resetRewriteCount() 21 | let 22 | a = vector(1.0, 2.0, 3.0) 23 | b = vector(2.0, -1.0, 3.0) 24 | 25 | discard a + 3.0 * b 26 | 27 | check getRewriteCount() == 1 28 | 29 | test "vector linear combination still checks dimension": 30 | let 31 | a = vector(1.0, 2.0) 32 | b = vector(2.0, -1.0, 3.0) 33 | 34 | expect DimensionError: 35 | discard a + 3.0 * b 36 | 37 | test "mutable vector linear combination": 38 | resetRewriteCount() 39 | var a = vector(1.0, 2.0, 3.0) 40 | let b = vector(2.0, -1.0, 3.0) 41 | 42 | a += 3.0 * b 43 | 44 | check getRewriteCount() == 1 45 | 46 | test "mutable vector linear combination still checks dimension": 47 | var a = vector(1.0, 2.0) 48 | let b = vector(2.0, -1.0, 3.0) 49 | 50 | expect DimensionError: 51 | a += 3.0 * b 52 | 53 | test "vector linear combination after template application": 54 | resetRewriteCount() 55 | let 56 | a = vector(1.0, 2.0, 3.0) 57 | b = vector(2.0, -1.0, 3.0) 58 | 59 | discard a + b / 3.0 60 | 61 | check getRewriteCount() == 1 -------------------------------------------------------------------------------- /tests/sparse/sconversions.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2017 UniCredit S.p.A. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # Copyright 2017 UniCredit S.p.A. 16 | # 17 | # Licensed under the Apache License, Version 2.0 (the "License"); 18 | # you may not use this file except in compliance with the License. 19 | # You may obtain a copy of the License at 20 | # 21 | # http://www.apache.org/licenses/LICENSE-2.0 22 | # 23 | # Unless required by applicable law or agreed to in writing, software 24 | # distributed under the License is distributed on an "AS IS" BASIS, 25 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 26 | # See the License for the specific language governing permissions and 27 | # limitations under the License. 28 | 29 | import unittest, neo 30 | 31 | proc run() = 32 | suite "conversions to dense": 33 | let expected = matrix(@[ 34 | @[1.0, 0.0, 2.0, 3.0], 35 | @[0.0, 4.0, 0.0, 0.0], 36 | @[5.0, 0.0, 6.0, 7.0], 37 | @[0.0, 8.0, 0.0, 9.0] 38 | ]) 39 | 40 | test "sparse vector conversion": 41 | let v = sparseVector(10, @[3'i32, 5, 7], @[2.0, 3, -1]) 42 | check v.dense == vector([0.0, 0, 0, 2, 0, 3, 0, -1, 0, 0]) 43 | test "csr matrix conversion": 44 | let m = csr( 45 | rows = @[0'i32, 3, 4, 7, 9], 46 | cols = @[0'i32, 2, 3, 1, 0, 2, 3, 1, 3], 47 | vals = @[1'f64, 2, 3, 4, 5, 6, 7, 8, 9], 48 | numCols = 4 49 | ) 50 | check m.dense == expected 51 | test "csc matrix conversion": 52 | let m = csc( 53 | rows = @[0'i32, 2, 1, 3, 0, 2, 0, 2, 3], 54 | cols = @[0'i32, 2, 4, 6, 9], 55 | vals = @[1'f64, 5, 4, 8, 2, 6, 3, 7, 9], 56 | numRows = 4 57 | ) 58 | check m.dense == expected 59 | test "coo matrix conversion": 60 | let m = coo( 61 | rows = @[0'i32, 0, 0, 1, 2, 2, 2, 3, 3], 62 | cols = @[0'i32, 2, 3, 1, 0, 2, 3, 1, 3], 63 | vals = @[1'f64, 2, 3, 4, 5, 6, 7, 8, 9], 64 | numRows = 4, 65 | numCols = 4 66 | ) 67 | check m.dense == expected 68 | 69 | run() -------------------------------------------------------------------------------- /tests/sparse/siterators.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2017 UniCredit S.p.A. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # Copyright 2017 UniCredit S.p.A. 16 | # 17 | # Licensed under the Apache License, Version 2.0 (the "License"); 18 | # you may not use this file except in compliance with the License. 19 | # You may obtain a copy of the License at 20 | # 21 | # http://www.apache.org/licenses/LICENSE-2.0 22 | # 23 | # Unless required by applicable law or agreed to in writing, software 24 | # distributed under the License is distributed on an "AS IS" BASIS, 25 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 26 | # See the License for the specific language governing permissions and 27 | # limitations under the License. 28 | 29 | import unittest, sequtils, neo/sparse 30 | 31 | # In the examples, m is 32 | # [ 33 | # 1 0 2 3 34 | # 0 4 0 0 35 | # 5 0 6 7 36 | # 0 8 0 9 37 | # ] 38 | 39 | proc run() = 40 | suite "iterators on matrices": 41 | test "sparse vector iterator": 42 | let 43 | v = sparseVector(10, @[3'i32, 5, 7], @[2.0, 3, -1]) 44 | values = toSeq(v.items) 45 | 46 | check values == @[0.0, 0, 0, 2, 0, 3, 0, -1, 0, 0] 47 | test "sparse vector pairs iterator": 48 | let 49 | v = sparseVector(10, @[3'i32, 5, 7], @[2.0, 3, -1]) 50 | values = toSeq(v.pairs) 51 | 52 | check values == @[ 53 | (0'i32, 0.0), 54 | (1'i32, 0.0), 55 | (2'i32, 0.0), 56 | (3'i32, 2.0), 57 | (4'i32, 0.0), 58 | (5'i32, 3.0), 59 | (6'i32, 0.0), 60 | (7'i32, -1.0), 61 | (8'i32, 0.0), 62 | (9'i32, 0.0) 63 | ] 64 | test "sparse vector nonzero iterator": 65 | let 66 | v = sparseVector(10, @[3'i32, 5, 7], @[2.0, 3, -1]) 67 | values = toSeq(v.nonzero) 68 | 69 | check values == @[ 70 | (3'i32, 2.0), 71 | (5'i32, 3.0), 72 | (7'i32, -1.0) 73 | ] 74 | test "csr matrix iterator": 75 | let 76 | m = csr( 77 | rows = @[0'i32, 3, 4, 7, 9], 78 | cols = @[0'i32, 2, 3, 1, 0, 2, 3, 1, 3], 79 | vals = @[1'f32, 2, 3, 4, 5, 6, 7, 8, 9], 80 | numCols = 4 81 | ) 82 | values = toSeq(m.items) 83 | check values == @[1'f32, 0, 2, 3, 0, 4, 0, 0, 5, 0, 6, 7, 0, 8, 0, 9] 84 | test "csc matrix iterator": 85 | let 86 | m = csc( 87 | rows = @[0'i32, 2, 1, 3, 0, 2, 0, 2, 3], 88 | cols = @[0'i32, 2, 4, 6, 9], 89 | vals = @[1'f32, 5, 4, 8, 2, 6, 3, 7, 9], 90 | numRows = 4 91 | ) 92 | values = toSeq(m.items) 93 | check values == @[1'f32, 0, 5, 0, 0, 4, 0, 8, 2, 0, 6, 0, 3, 0, 7, 9] 94 | test "coo matrix iterator": 95 | let 96 | m = coo( 97 | rows = @[0'i32, 0, 0, 1, 2, 2, 2, 3, 3], 98 | cols = @[0'i32, 2, 3, 1, 0, 2, 3, 1, 3], 99 | vals = @[1'f32, 2, 3, 4, 5, 6, 7, 8, 9], 100 | numRows = 4, 101 | numCols = 4 102 | ) 103 | values = toSeq(m.items) 104 | check values == @[1'f32, 0, 2, 3, 0, 4, 0, 0, 5, 0, 6, 7, 0, 8, 0, 9] 105 | test "csr matrix pairs iterator": 106 | let 107 | m = csr( 108 | rows = @[0'i32, 3, 4, 7, 9], 109 | cols = @[0'i32, 2, 3, 1, 0, 2, 3, 1, 3], 110 | vals = @[1'f32, 2, 3, 4, 5, 6, 7, 8, 9], 111 | numCols = 4 112 | ) 113 | values = toSeq(m.pairs) 114 | check values == @[ 115 | ((0'i32, 0'i32), 1'f32), 116 | ((0'i32, 1'i32), 0'f32), 117 | ((0'i32, 2'i32), 2'f32), 118 | ((0'i32, 3'i32), 3'f32), 119 | ((1'i32, 0'i32), 0'f32), 120 | ((1'i32, 1'i32), 4'f32), 121 | ((1'i32, 2'i32), 0'f32), 122 | ((1'i32, 3'i32), 0'f32), 123 | ((2'i32, 0'i32), 5'f32), 124 | ((2'i32, 1'i32), 0'f32), 125 | ((2'i32, 2'i32), 6'f32), 126 | ((2'i32, 3'i32), 7'f32), 127 | ((3'i32, 0'i32), 0'f32), 128 | ((3'i32, 1'i32), 8'f32), 129 | ((3'i32, 2'i32), 0'f32), 130 | ((3'i32, 3'i32), 9'f32) 131 | ] 132 | test "csc matrix pairs iterator": 133 | let 134 | m = csc( 135 | rows = @[0'i32, 2, 1, 3, 0, 2, 0, 2, 3], 136 | cols = @[0'i32, 2, 4, 6, 9], 137 | vals = @[1'f32, 5, 4, 8, 2, 6, 3, 7, 9], 138 | numRows = 4 139 | ) 140 | values = toSeq(m.pairs) 141 | check values == @[ 142 | ((0'i32, 0'i32), 1'f32), 143 | ((1'i32, 0'i32), 0'f32), 144 | ((2'i32, 0'i32), 5'f32), 145 | ((3'i32, 0'i32), 0'f32), 146 | ((0'i32, 1'i32), 0'f32), 147 | ((1'i32, 1'i32), 4'f32), 148 | ((2'i32, 1'i32), 0'f32), 149 | ((3'i32, 1'i32), 8'f32), 150 | ((0'i32, 2'i32), 2'f32), 151 | ((1'i32, 2'i32), 0'f32), 152 | ((2'i32, 2'i32), 6'f32), 153 | ((3'i32, 2'i32), 0'f32), 154 | ((0'i32, 3'i32), 3'f32), 155 | ((1'i32, 3'i32), 0'f32), 156 | ((2'i32, 3'i32), 7'f32), 157 | ((3'i32, 3'i32), 9'f32) 158 | ] 159 | test "coo matrix pairs iterator": 160 | let 161 | m = coo( 162 | rows = @[0'i32, 0, 0, 1, 2, 2, 2, 3, 3], 163 | cols = @[0'i32, 2, 3, 1, 0, 2, 3, 1, 3], 164 | vals = @[1'f32, 2, 3, 4, 5, 6, 7, 8, 9], 165 | numRows = 4, 166 | numCols = 4 167 | ) 168 | values = toSeq(m.pairs) 169 | check values == @[ 170 | ((0'i32, 0'i32), 1'f32), 171 | ((0'i32, 1'i32), 0'f32), 172 | ((0'i32, 2'i32), 2'f32), 173 | ((0'i32, 3'i32), 3'f32), 174 | ((1'i32, 0'i32), 0'f32), 175 | ((1'i32, 1'i32), 4'f32), 176 | ((1'i32, 2'i32), 0'f32), 177 | ((1'i32, 3'i32), 0'f32), 178 | ((2'i32, 0'i32), 5'f32), 179 | ((2'i32, 1'i32), 0'f32), 180 | ((2'i32, 2'i32), 6'f32), 181 | ((2'i32, 3'i32), 7'f32), 182 | ((3'i32, 0'i32), 0'f32), 183 | ((3'i32, 1'i32), 8'f32), 184 | ((3'i32, 2'i32), 0'f32), 185 | ((3'i32, 3'i32), 9'f32) 186 | ] 187 | 188 | run() -------------------------------------------------------------------------------- /tests/statics/access.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2016 UniCredit S.p.A. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import unittest, neo, neo/statics 16 | 17 | proc run() = 18 | suite "vector accessors": 19 | test "reading vector length": 20 | let v = randomVector(10) 21 | check v.len == 10 22 | test "reading vector elements": 23 | let v = makeVector(5, proc(i: int): float64 = (3 * i - 2).float64) 24 | check v[0] == -2.0 25 | check v[1] == 1.0 26 | check v[2] == 4.0 27 | check v[3] == 7.0 28 | check v[4] == 10.0 29 | test "mutating vector elements": 30 | var v = zeros(3) 31 | v[0] += 2.1 32 | v[1] -= 1.0 33 | check v[0] == 2.1 34 | check v[1] == -1.0 35 | test "writing vector elements": 36 | var v = zeros(3) 37 | v[0] = -2.1 38 | v[1] = 1.0 39 | check v[0] == -2.1 40 | check v[1] == 1.0 41 | test "cloning vectors": 42 | var v = randomVector(5) 43 | let 44 | w = v.clone 45 | f = w[0] 46 | check v == w 47 | v[0] = v[0] + 1 48 | check w[0] == f 49 | test "mapping vectors": 50 | var v = vector([1.0, 2.0, 3.0, 4.0, 5.0]) 51 | check v.map(proc(x: float64): float64 = 2 * x) == 52 | vector([2.0, 4.0, 6.0, 8.0, 10.0]) 53 | 54 | suite "matrix accessors": 55 | test "reading matrix dimensions": 56 | let m = randomMatrix(3, 7) 57 | check m.dim == (3, 7) 58 | test "reading matrix elements": 59 | let m = makeMatrix(2, 2, proc(i, j: int): float64 = (3 * i - 2 * j).float64) 60 | check m[0, 0] == 0.0 61 | check m[0, 1] == -2.0 62 | check m[1, 0] == 3.0 63 | check m[1, 1] == 1.0 64 | test "mutating matrix elements": 65 | var m = zeros(3, 3) 66 | m[0, 2] += 2.1 67 | m[1, 1] -= 1.0 68 | check m[0, 2] == 2.1 69 | check m[1, 1] == -1.0 70 | test "writing matrix elements": 71 | var m = zeros(3, 3) 72 | m[0, 2] = -2.1 73 | m[1, 1] = 1.0 74 | check m[0, 2] == -2.1 75 | check m[1, 1] == 1.0 76 | test "reading matrix rows": 77 | let 78 | m = makeMatrix(2, 2, proc(i, j: int): float64 = (3 * i - 2 * j).float64) 79 | r = m.row(1) 80 | check r[0] == 3.0 81 | check r[1] == 1.0 82 | test "reading matrix columns": 83 | let 84 | m = makeMatrix(2, 2, proc(i, j: int): float64 = (3 * i - 2 * j).float64) 85 | c = m.column(1) 86 | check c[0] == -2.0 87 | check c[1] == 1.0 88 | test "cloning matrices": 89 | var m = randomMatrix(5, 5) 90 | let 91 | n = m.clone 92 | f = n[2, 2] 93 | check m == n 94 | m[2, 2] = m[2, 2] + 1 95 | check n[2, 2] == f 96 | test "mapping matrices": 97 | let 98 | m = makeMatrix(2, 2, proc(i, j: int): float64 = (3 * i - 2 * j).float64) 99 | n = makeMatrix(2, 2, proc(i, j: int): float64 = (6 * i - 4 * j).float64) 100 | proc double(x: float64): float64 = 2 * x 101 | check m.map(double) == n 102 | 103 | run() -------------------------------------------------------------------------------- /tests/statics/collection.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2017 UniCredit S.p.A. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import unittest, neo, neo/statics 16 | 17 | proc run() = 18 | suite "collection operations": 19 | test "cumulative sum over 32-bit vectors": 20 | let 21 | v = statics.vector([1'f32, 3.5'f32, 2'f32, 4.5'f32]) 22 | w = cumsum(v) 23 | check w == statics.vector([1'f32, 4.5'f32, 6.5'f32, 11'f32]) 24 | test "cumulative sum over 64-bit vectors": 25 | let 26 | v = statics.vector([1.0, 3.5, 2.0, 4.5]) 27 | w = cumsum(v) 28 | check w == statics.vector([1.0, 4.5, 6.5, 11.0]) 29 | test "sum over 32-bit vectors": 30 | let v = statics.vector([1'f32, 3.5'f32, 2'f32, 4.5'f32]) 31 | check v.sum == 11'f32 32 | test "sum over 64-bit vectors": 33 | let v = statics.vector([1.0, 3.5, 2.0, 4.5]) 34 | check v.sum == 11.0 35 | test "mean over 32-bit vectors": 36 | let v = statics.vector([1'f32, 3.5'f32, 2'f32, 4.5'f32]) 37 | check v.mean == 2.75'f32 38 | test "mean over 64-bit vectors": 39 | let v = statics.vector([1.0, 3.5, 2.0, 4.5]) 40 | check v.mean == 2.75 41 | test "variance over 32-bit vectors": 42 | let v = statics.vector([2'f32, 4'f32, 4'f32, 4'f32, 5'f32, 5'f32, 7'f32, 9'f32]) 43 | check v.variance == 4'f32 44 | test "variance over 64-bit vectors": 45 | let v = statics.vector([2.0, 4.0, 4.0, 4.0, 5.0, 5.0, 7.0, 9.0]) 46 | check v.variance == 4.0 47 | test "standard deviation over 32-bit vectors": 48 | let v = statics.vector([2'f32, 4'f32, 4'f32, 4'f32, 5'f32, 5'f32, 7'f32, 9'f32]) 49 | check v.stddev == 2'f32 50 | test "standard deviation over 64-bit vectors": 51 | let v = statics.vector([2.0, 4.0, 4.0, 4.0, 5.0, 5.0, 7.0, 9.0]) 52 | check v.stddev == 2.0 53 | test "sum over 32-bit matrices": 54 | let m = statics.matrix([[1'f32, 3.5'f32], [2'f32, 4.5'f32]]) 55 | check m.sum == 11'f32 56 | test "sum over 64-bit matrices": 57 | let m = statics.matrix([[1.0, 3.5], [2.0, 4.5]]) 58 | check m.sum == 11.0 59 | test "mean over 32-bit matrices": 60 | let m = statics.matrix([[1'f32, 3.5'f32], [2'f32, 4.5'f32]]) 61 | check m.mean == 2.75'f32 62 | test "mean over 64-bit matrices": 63 | let m = statics.matrix([[1.0, 3.5], [2.0, 4.5]]) 64 | check m.mean == 2.75 65 | 66 | run() -------------------------------------------------------------------------------- /tests/statics/compilation.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2016 UniCredit S.p.A. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import unittest, neo, neo/statics 16 | 17 | proc run() = 18 | suite "compilation errors": 19 | test "vector dimension should agree in a sum": 20 | let 21 | u = statics.vector([1.0, 2.0, 3.0, 4.0, 5.0]) 22 | v = statics.vector([1.0, 2.0, 3.0, 4.0]) 23 | when compiles(u + v): fail() 24 | when compiles(u - v): fail() 25 | test "vector dimension should agree in a mutating sum": 26 | var u = statics.vector([1.0, 2.0, 3.0, 4.0, 5.0]) 27 | let v = statics.vector([1.0, 2.0, 3.0, 4.0]) 28 | when compiles(u += v): fail() 29 | when compiles(u -= v): fail() 30 | test "in place sum should not work for immutable vectors": 31 | let 32 | u = statics.vector([1.0, 2.0, 3.0, 4.0]) 33 | v = statics.vector([1.0, 2.0, 3.0, 4.0]) 34 | when compiles(u += v): fail() 35 | when compiles(u -= v): fail() 36 | test "vector dimension should agree in a Hadamard product": 37 | let 38 | u = statics.vector([1.0, 2.0, 3.0, 4.0, 5.0]) 39 | v = statics.vector([1.0, 2.0, 3.0, 4.0]) 40 | when compiles(u |*| v): fail() 41 | test "in place sum should not work for immutable dynamic vectors": 42 | let 43 | u = statics.vector([1.0, 2.0, 3.0, 4.0]) 44 | v = statics.vector([1.0, 2.0, 3.0, 4.0]) 45 | when compiles(u += v): fail() 46 | when compiles(u -= v): fail() 47 | test "vector slicing should not work for out of bounds slices": 48 | let v = statics.vector([1, 2, 3, 4, 5]) 49 | when compiles(v[-3 .. 3]): fail() 50 | when compiles(v[3 .. 7]): fail() 51 | test "vector slice assignment should not work for wrong dimensions": 52 | let 53 | u = statics.vector([1, 2, 3]) 54 | v = statics.vector([1, 2, 3, 4, 5]) 55 | when compiles(v[2 .. 3] = u): fail() 56 | test "making an array into a matrix should not work for wrong dimensions": 57 | let u = statics.vector([1.0, 2.0, 3.0, 4.0]) 58 | when compiles(u.asMatrix(3, 5)): fail() 59 | test "reshaping a matrix should not work for wrong dimensions": 60 | let m = statics.randomMatrix(2, 3) 61 | when compiles(m.reshape(3, 5)): fail() 62 | test "matrix/vector multiplication should not work for wrong dimensions": 63 | let 64 | m = statics.randomMatrix(6, 7) 65 | v = statics.randomVector(6) 66 | when compiles(m * v): fail() 67 | test "matrix dimensions should agree in a sum": 68 | let 69 | m = statics.randomMatrix(3, 6) 70 | n = statics.randomMatrix(4, 5) 71 | when compiles(m + n): fail() 72 | when compiles(m - n): fail() 73 | test "matrix dimensions should agree in an in place sum": 74 | var m = statics.randomMatrix(3, 6) 75 | let n = statics.randomMatrix(4, 5) 76 | when compiles(m += n): fail() 77 | when compiles(m -= n): fail() 78 | test "in place sum should not work for immutable matrices": 79 | let 80 | m = statics.randomMatrix(3, 6) 81 | n = statics.randomMatrix(3, 6) 82 | when compiles(m += n): fail() 83 | when compiles(m -= n): fail() 84 | test "matrix multiplication should not work for wrong dimensions": 85 | let 86 | m = statics.randomMatrix(6, 7) 87 | n = statics.randomMatrix(8, 18) 88 | when compiles(m * n): fail() 89 | test "matrix slicing should not work for out of bounds slices": 90 | let m = statics.randomMatrix(3, 4) 91 | when compiles(m[-3 .. 3]): fail() 92 | when compiles(m[2 .. 5]): fail() 93 | test "matrix slice assignment should not work for wrong dimensions": 94 | let 95 | m = statics.randomMatrix(6, 7) 96 | n = statics.randomMatrix(8, 18) 97 | when compiles(n[2 .. 5, 3 .. 10] = m): fail() 98 | 99 | run() -------------------------------------------------------------------------------- /tests/statics/det.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2017 UniCredit S.p.A. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import unittest, neo, neo/statics 16 | 17 | proc run() = 18 | suite "trace and determinant computations": 19 | test "trace of a matrix": 20 | let a = makeMatrixIJ(int, 3, 3, i + i * j - 1) 21 | 22 | check(tr(a) == 5) 23 | test "determinant of a matrix": 24 | let a = matrix([ 25 | [-1.0, -1.0, 0.0], 26 | [ 0.0, 1.0, 2.0], 27 | [ 1.0, 3.0, 5.0] 28 | ]) 29 | 30 | check((det(a) + -1) < 1e-6) 31 | 32 | run() -------------------------------------------------------------------------------- /tests/statics/eigenvalues.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2017 UniCredit S.p.A. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import unittest, neo, neo/statics 16 | 17 | proc run() = 18 | suite "matrix reductions for eigenvalue computations": 19 | test "balancing matrices": 20 | let 21 | a = matrix([ 22 | [3.0, 1.0, 0.0, 0.0], 23 | [1.0, 0.0, 0.0, 0.0], 24 | [2.0, -1.0, 1.5, 0.1], 25 | [-1.0, 0.0, 1.1, 1.2], 26 | ]) 27 | r = balance(a, BalanceOp.Permute) 28 | 29 | check(r.ilo == 1) 30 | check(r.ihi == 4) 31 | test "computing the upper Hessenberg form": 32 | let 33 | a = matrix([ 34 | [3.0, 1.0, 0.0, 0.0], 35 | [1.0, 0.0, 0.0, 0.0], 36 | [2.0, -1.0, 1.5, 0.1], 37 | [-1.0, 0.0, 1.1, 1.2], 38 | ]) 39 | r = hessenberg(a) 40 | 41 | check(r[0, 0] == 3) 42 | 43 | suite "computing eigenvalues": 44 | test "computing the eigenvalues alone": 45 | let 46 | a = matrix([ 47 | [3.0, 1.0, 0.0, 0.0], 48 | [1.0, 0.0, 0.0, 0.0], 49 | [2.0, -1.0, 1.5, 0.1], 50 | [-1.0, 0.0, 1.1, 1.2], 51 | ]) 52 | e = eigenvalues(a) 53 | 54 | check(e.img == @[0.0, 0.0, 0.0, 0.0]) 55 | test "computing the eigenvalues of a known matrix": 56 | let 57 | a = matrix([ 58 | [2.0, 0.0, 1.0], 59 | [0.0, 2.0, 0.0], 60 | [1.0, 0.0, 2.0] 61 | ]) 62 | e = eigenvalues(a) 63 | 64 | check(e.real == @[3.0, 1.0, 2.0]) 65 | check(e.img == @[0.0, 0.0, 0.0]) 66 | 67 | test "computing the Schur factorization": 68 | let 69 | a = matrix([ 70 | [2.0, 0.0, 1.0], 71 | [0.0, 2.0, 0.0], 72 | [1.0, 0.0, 2.0] 73 | ]) 74 | s = schur(a) 75 | 76 | check(s.factorization == diag([3.0, 1.0, 2.0])) 77 | check(s.eigenvalues.real == @[3.0, 1.0, 2.0]) 78 | check(s.eigenvalues.img == @[0.0, 0.0, 0.0]) 79 | 80 | run() -------------------------------------------------------------------------------- /tests/statics/equality.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2017 UniCredit S.p.A. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import unittest, neo, neo/statics 16 | 17 | proc run() = 18 | suite "vector and matrix equality": 19 | test "strict vector equality": 20 | let 21 | u = vector([1.0, 2.0, 3.0, 4.0]) 22 | v = vector([1.0, 2.0, 3.0, 4.0]) 23 | w = vector([1.0, 3.0, 3.0, 4.0]) 24 | check u == v 25 | check v != w 26 | test "strict 32-bit vector equality": 27 | let 28 | u = vector([1'f32, 2'f32, 3'f32, 4'f32]) 29 | v = vector([1'f32, 2'f32, 3'f32, 4'f32]) 30 | w = vector([1'f32, 3'f32, 3'f32, 4'f32]) 31 | check u == v 32 | check v != w 33 | test "strict matrix equality": 34 | let 35 | m = makeMatrix(3, 5, proc(i, j: int): float64 = (i + 3 * j).float64) 36 | n = makeMatrix(3, 5, proc(i, j: int): float64 = (i + 3 * j).float64) 37 | p = makeMatrix(3, 5, proc(i, j: int): float64 = (i - 2 * j).float64) 38 | check m == n 39 | check n != p 40 | test "strict 32-bit matrix equality": 41 | let 42 | m = makeMatrix(3, 5, proc(i, j: int): float32 = (i + 3 * j).float32) 43 | n = makeMatrix(3, 5, proc(i, j: int): float32 = (i + 3 * j).float32) 44 | p = makeMatrix(3, 5, proc(i, j: int): float32 = (i - 2 * j).float32) 45 | check m == n 46 | check n != p 47 | test "approximate vector equality": 48 | let 49 | u = vector([1.0, 2.0, 3.0, 4.0]) 50 | v = vector([1.0, 2.0, 3.0, 4.0]) 51 | w = vector([1.0, 2.0, 2.999999999, 4.00000001]) 52 | z = vector([1.0, 3.0, 3.0, 4.0]) 53 | check u =~ v 54 | check v =~ w 55 | check v != w 56 | check w !=~ z 57 | test "approximate 32-bit vector equality": 58 | let 59 | u = vector([1'f32, 2'f32, 3'f32, 4'f32]) 60 | v = vector([1'f32, 2'f32, 3'f32, 4'f32]) 61 | w = vector([1'f32, 2'f32, 2.999999'f32, 4.000001'f32]) 62 | z = vector([1'f32, 3'f32, 3'f32, 4'f32]) 63 | check u =~ v 64 | check v =~ w 65 | check v != w 66 | check w !=~ z 67 | test "approximate matrix equality": 68 | let 69 | m = makeMatrix(3, 5, proc(i, j: int): float64 = (i + 3 * j).float64) 70 | n = makeMatrix(3, 5, proc(i, j: int): float64 = (i + 3 * j).float64) 71 | q = makeMatrix(3, 5, proc(i, j: int): float64 = (i - 2 * j).float64) 72 | var p = makeMatrix(3, 5, proc(i, j: int): float64 = (i + 3 * j).float64) 73 | p[2, 2] = p[2, 2] - 0.000000001 74 | p[1, 3] = p[1, 3] + 0.000000001 75 | check m =~ n 76 | check n =~ p 77 | check n != p 78 | check p !=~ q 79 | test "approximate 32-bit matrix equality": 80 | let 81 | m = makeMatrix(3, 5, proc(i, j: int): float32 = (i + 3 * j).float32) 82 | n = makeMatrix(3, 5, proc(i, j: int): float32 = (i + 3 * j).float32) 83 | q = makeMatrix(3, 5, proc(i, j: int): float32 = (i - 2 * j).float32) 84 | var p = makeMatrix(3, 5, proc(i, j: int): float32 = (i + 3 * j).float32) 85 | p[2, 2] = p[2, 2] - 0.000001 86 | p[1, 3] = p[1, 3] + 0.000001 87 | check m =~ n 88 | check n =~ p 89 | check n != p 90 | check p !=~ q 91 | 92 | run() -------------------------------------------------------------------------------- /tests/statics/initialize.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2016 UniCredit S.p.A. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import unittest, neo/statics 16 | 17 | proc run() = 18 | suite "initializaton of vectors": 19 | test "zero vectors": 20 | let v = zeros(5) 21 | check len(v) == 5 22 | check v[0] == 0.0 23 | check v[1] == 0.0 24 | check v[2] == 0.0 25 | check v[3] == 0.0 26 | check v[4] == 0.0 27 | test "one vectors": 28 | let v = ones(3) 29 | check len(v) == 3 30 | check v[0] == 1.0 31 | check v[1] == 1.0 32 | check v[2] == 1.0 33 | test "constant vectors": 34 | let v = constantVector(4, 2.3) 35 | check len(v) == 4 36 | check v[0] == 2.3 37 | check v[1] == 2.3 38 | check v[2] == 2.3 39 | check v[3] == 2.3 40 | test "vectors generated by a proc": 41 | let v = makeVector(4, proc(i: int): float64 = (i * i).float64) 42 | check len(v) == 4 43 | check v[0] == 0.0 44 | check v[1] == 1.0 45 | check v[2] == 4.0 46 | check v[3] == 9.0 47 | test "vectors generated by an expression": 48 | let 49 | v = makeVector(4, proc(i: int): float64 = (i * i).float64) 50 | w = makeVectorI[float64](4, (i * i).float64) 51 | check v == w 52 | test "vectors generated by an array": 53 | let 54 | a = [1.2, 3.2, 2.6, 2.8, -1.45] 55 | v = vector(a) 56 | check len(v) == len(a) 57 | for i in 0 .. high(a): 58 | check v[i] == a[i] 59 | test "vectors generated randomly": 60 | let v = randomVector(6) 61 | check len(v) == 6 62 | for i in 0 .. 5: 63 | check v[i] >= 0 64 | check v[i] <= 1 65 | 66 | suite "initializaton of matrices": 67 | test "zero matrices": 68 | let m = zeros(3, 2) 69 | check dim(m) == (3, 2) 70 | check m[0, 0] == 0.0 71 | check m[1, 0] == 0.0 72 | check m[2, 0] == 0.0 73 | check m[0, 1] == 0.0 74 | check m[1, 1] == 0.0 75 | check m[2, 1] == 0.0 76 | test "one matrices": 77 | let m = ones(2, 2) 78 | check dim(m) == (2, 2) 79 | check m[0, 0] == 1.0 80 | check m[1, 0] == 1.0 81 | check m[0, 1] == 1.0 82 | check m[1, 1] == 1.0 83 | test "constant matrices": 84 | let m = constantMatrix(2, 3, 1.5) 85 | check dim(m) == (2, 3) 86 | check m[0, 0] == 1.5 87 | check m[1, 0] == 1.5 88 | check m[0, 1] == 1.5 89 | check m[1, 1] == 1.5 90 | check m[0, 2] == 1.5 91 | check m[1, 2] == 1.5 92 | test "identity matrices": 93 | let m = eye(4) 94 | check dim(m) == (4, 4) 95 | for t, v in m: 96 | let (i, j) = t 97 | if i == j: 98 | check v == 1.0 99 | else: 100 | check v == 0.0 101 | test "matrices generated by a proc": 102 | let m = makeMatrix(3, 5, proc(i, j: int): float64 = (i * j).float64) 103 | check dim(m) == (3, 5) 104 | check m[0, 2] == 0.0 105 | check m[1, 1] == 1.0 106 | check m[2, 3] == 6.0 107 | check m[2, 4] == 8.0 108 | test "matrices generated by an expression": 109 | let 110 | m = makeMatrix(3, 5, proc(i, j: int): float64 = (i * j).float64) 111 | n = makeMatrixIJ(float64, 3, 5, (i * j).float64) 112 | check m == n 113 | test "matrices generated by arrays": 114 | let 115 | a = [ 116 | [1.2, 3.2, 2.6], 117 | [2.3, 2.8, -1.45], 118 | [-1.2, 3.1, 3.3] 119 | ] 120 | m = matrix(a) 121 | check dim(m) == (3, 3) 122 | for i in 0 .. 2: 123 | for j in 0 .. 2: 124 | check m[i, j] == a[i][j] 125 | test "matrices generated randomly": 126 | let m = randomMatrix(3, 4) 127 | check dim(m) == (3, 4) 128 | for i in 0 .. 2: 129 | for j in 0 .. 3: 130 | check m[i, j] >= 0 131 | check m[i, j] <= 1 132 | test "diagonal matrices": 133 | let 134 | a = diag([0.0, 1.0, 2.0]) 135 | b = makeMatrixIJ(float64, 3, 3, if i == j: i.float64 else: 0.0) 136 | check a == b 137 | 138 | run() -------------------------------------------------------------------------------- /tests/statics/iterators.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2016 UniCredit S.p.A. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import unittest, neo, neo/statics 16 | 17 | proc run() = 18 | suite "iterators on vectors": 19 | test "items vector iterator": 20 | let v = vector([1.0, 3.0, 2.0, 8.0, -2.0]) 21 | var 22 | sum = 0.0 23 | count = 0 24 | for x in v: 25 | sum += x 26 | count += 1 27 | check sum == 12.0 28 | check count == 5 29 | test "pairs vector iterator": 30 | let v = vector([1.0, 3.0, 2.0, 8.0, -2.0]) 31 | var 32 | sum = 0.0 33 | sumI = 0 34 | for i, x in v: 35 | sum += x 36 | sumI += i 37 | check sum == 12.0 38 | check sumI == 10 39 | 40 | suite "iterators on matrices": 41 | test "items matrix iterator": 42 | let m = makeMatrix(3, 2, proc(i, j: int): float64 = (i + 2 * j + 1).float64) 43 | var 44 | sum = 0.0 45 | count = 0 46 | for x in m: 47 | sum += x 48 | count += 1 49 | check sum == 18.0 50 | check count == 6 51 | test "pairs matrix iterator": 52 | let m = makeMatrix(3, 2, proc(i, j: int): float64 = (i + 2 * j + 1).float64) 53 | var 54 | sum = 0.0 55 | sumI = 0 56 | for t, x in m: 57 | let (i, j) = t 58 | sum += x 59 | sumI += (i + j) 60 | check sum == 18.0 61 | check sumI == 9 62 | test "rows matrix iterator": 63 | let m = makeMatrix(3, 2, proc(i, j: int): float64 = (i + 2 * j + 1).float64) 64 | var 65 | sum = 0.0 66 | count = 0 67 | for r in m.rows: 68 | sum += (r[0] + r[1]) 69 | count += 1 70 | check sum == 18.0 71 | check count == 3 72 | test "columns matrix iterator": 73 | let m = makeMatrix(3, 2, proc(i, j: int): float64 = (i + 2 * j + 1).float64) 74 | var 75 | sum = 0.0 76 | count = 0 77 | for c in m.columns: 78 | sum += (c[0] + c[1] + c[2]) 79 | count += 1 80 | check sum == 18.0 81 | check count == 2 82 | test "rowsSlow matrix iterator": 83 | let m = makeMatrix(3, 2, proc(i, j: int): float64 = (i + 2 * j + 1).float64) 84 | var 85 | sum = 0.0 86 | count = 0 87 | for r in m.rowsSlow: 88 | sum += (r[0] + r[1]) 89 | count += 1 90 | check sum == 18.0 91 | check count == 3 92 | test "columnsSlow matrix iterator": 93 | let m = makeMatrix(3, 2, proc(i, j: int): float64 = (i + 2 * j + 1).float64) 94 | var 95 | sum = 0.0 96 | count = 0 97 | for c in m.columnsSlow: 98 | sum += (c[0] + c[1] + c[2]) 99 | count += 1 100 | check sum == 18.0 101 | check count == 2 102 | 103 | run() -------------------------------------------------------------------------------- /tests/statics/mixed_ops.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2017 UniCredit S.p.A. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import unittest, neo, neo/statics 16 | 17 | proc run() = 18 | suite "mixed slice assignments": 19 | test "assigning to a slice": 20 | var m = statics.makeMatrixIJ(int, 5, 5, 3 * i + j) 21 | let n = statics.matrix([ 22 | [5, 6, 7], 23 | [8, 9, 10], 24 | [11, 12, 13] 25 | ], rowMajor) 26 | m[1 .. 3, 1 .. 3] = n 27 | check m[2, 2] == 9 28 | check m[3, 2] == 12 29 | 30 | test "assigning a slice to another slice": 31 | var m = statics.makeMatrixIJ(int, 5, 5, 3 * i + j, rowMajor) 32 | let n = statics.makeMatrixIJ(int, 5, 5, 2 * i + 2 * j) 33 | m[1 .. 3, 1 .. 3] = n[2 .. 4, 2 .. 4] 34 | check m[2, 2] == 12 35 | check m[3, 2] == 14 36 | 37 | test "assigning to a slice on columns only": 38 | var m = statics.makeMatrixIJ(int, 5, 5, 3 * i + j) 39 | let n = statics.makeMatrixIJ(int, 5, 3, 2 * i + 2 * j, rowMajor) 40 | 41 | m[All, 2 .. 4] = n 42 | check m[2, 2] == 4 43 | check m[3, 2] == 6 44 | 45 | test "assigning to a slice on rows only": 46 | var m = statics.makeMatrixIJ(int, 5, 5, 3 * i + j, rowMajor) 47 | let n = statics.makeMatrixIJ(int, 3, 5, 2 * i + 2 * j) 48 | 49 | m[2 .. 4, All] = n 50 | check m[2, 2] == 4 51 | check m[3, 2] == 6 52 | 53 | test "assigning to a slice with BLAS operations": 54 | var m = statics.makeMatrixIJ(float64, 5, 5, (3 * i + j).float64, rowMajor) 55 | let n = statics.matrix([ 56 | [5'f64, 6, 7], 57 | [8'f64, 9, 10], 58 | [11'f64, 12, 13] 59 | ]) 60 | m[1 .. 3, 1 .. 3] = n 61 | check m[2, 2] == 9'f64 62 | check m[3, 2] == 12'f64 63 | 64 | suite "mixed matrix operations": 65 | test "mixed matrix sum": 66 | let 67 | m1 = matrix([ 68 | [1.0, 0.0, 2.0, -1.0], 69 | [-1.0, 1.0, 3.0, 1.0], 70 | [3.0, 2.0, 2.0, 4.0] 71 | ], order = rowMajor) 72 | m2 = matrix([ 73 | [3.0, 1.0, -1.0, 1.0], 74 | [2.0, 1.0, -3.0, 0.0], 75 | [4.0, 1.0, 2.0, 2.0] 76 | ]) 77 | m3 = matrix([ 78 | [4.0, 1.0, 1.0, 0.0], 79 | [1.0, 2.0, 0.0, 1.0], 80 | [7.0, 3.0, 4.0, 6.0] 81 | ]) 82 | check(m1 + m2 == m3) 83 | test "mixed mutating matrix sum": 84 | var m1 = matrix([ 85 | [1.0, 0.0, 2.0, -1.0], 86 | [-1.0, 1.0, 3.0, 1.0], 87 | [3.0, 2.0, 2.0, 4.0] 88 | ], order = rowMajor) 89 | let 90 | m2 = matrix([ 91 | [3.0, 1.0, -1.0, 1.0], 92 | [2.0, 1.0, -3.0, 0.0], 93 | [4.0, 1.0, 2.0, 2.0] 94 | ]) 95 | m3 = matrix([ 96 | [4.0, 1.0, 1.0, 0.0], 97 | [1.0, 2.0, 0.0, 1.0], 98 | [7.0, 3.0, 4.0, 6.0] 99 | ]) 100 | m1 += m2 101 | check m1 == m3 102 | test "mixed matrix difference": 103 | let 104 | m1 = matrix([ 105 | [1.0, 0.0, 2.0, -1.0], 106 | [-1.0, 1.0, 3.0, 1.0], 107 | [3.0, 2.0, 2.0, 4.0] 108 | ]) 109 | m2 = matrix([ 110 | [3.0, 1.0, -1.0, 1.0], 111 | [2.0, 1.0, -3.0, 0.0], 112 | [4.0, 1.0, 2.0, 2.0] 113 | ], order = rowMajor) 114 | m3 = matrix([ 115 | [-2.0, -1.0, 3.0, -2.0], 116 | [-3.0, 0.0, 6.0, 1.0], 117 | [-1.0, 1.0, 0.0, 2.0] 118 | ]) 119 | check(m1 - m2 == m3) 120 | test "mutating matrix sum": 121 | var m1 = matrix([ 122 | [1.0, 0.0, 2.0, -1.0], 123 | [-1.0, 1.0, 3.0, 1.0], 124 | [3.0, 2.0, 2.0, 4.0] 125 | ], order = rowMajor) 126 | let 127 | m2 = matrix([ 128 | [3.0, 1.0, -1.0, 1.0], 129 | [2.0, 1.0, -3.0, 0.0], 130 | [4.0, 1.0, 2.0, 2.0] 131 | ]) 132 | m3 = matrix([ 133 | [-2.0, -1.0, 3.0, -2.0], 134 | [-3.0, 0.0, 6.0, 1.0], 135 | [-1.0, 1.0, 0.0, 2.0] 136 | ]) 137 | m1 -= m2 138 | check m1 == m3 139 | test "mixed matrix multiplication": 140 | let 141 | m1 = matrix([ 142 | [1.0, 1.0, 2.0, -3.0], 143 | [3.0, 0.0, -7.0, 2.0] 144 | ], order = rowMajor) 145 | m2 = matrix([ 146 | [1.0, 1.0, 2.0], 147 | [3.0, 1.0, -5.0], 148 | [-1.0, -1.0, 2.0], 149 | [4.0, 2.0, 3.0] 150 | ]) 151 | m3 = matrix([ 152 | [-10.0, -6.0, -8.0], 153 | [18.0, 14.0, -2.0] 154 | ]) 155 | check(m1 * m2 == m3) 156 | test "mixed matrix multiplication take two": 157 | let 158 | m1 = matrix([ 159 | [1.0, 1.0, 2.0, -3.0], 160 | [3.0, 0.0, -7.0, 2.0] 161 | ]) 162 | m2 = matrix([ 163 | [1.0, 1.0, 2.0], 164 | [3.0, 1.0, -5.0], 165 | [-1.0, -1.0, 2.0], 166 | [4.0, 2.0, 3.0] 167 | ], order = rowMajor) 168 | m3 = matrix([ 169 | [-10.0, -6.0, -8.0], 170 | [18.0, 14.0, -2.0] 171 | ]) 172 | check(m1 * m2 == m3) 173 | test "mixed matrix Hadamard multiplication": 174 | let 175 | m1 = matrix([ 176 | [1.0, 0.0, 2.0, -1.0], 177 | [-1.0, 1.0, 3.0, 1.0], 178 | [3.0, 2.0, 2.0, 4.0] 179 | ]) 180 | m2 = matrix([ 181 | [3.0, 1.0, -1.0, 1.0], 182 | [2.0, 1.0, -3.0, 0.0], 183 | [4.0, 1.0, 2.0, 2.0] 184 | ], order = rowMajor) 185 | m3 = matrix([ 186 | [3.0, 0.0, -2.0, -1.0], 187 | [-2.0, 1.0, -9.0, 0.0], 188 | [12.0, 2.0, 4.0, 8.0] 189 | ]) 190 | check((m1 |*| m2) == m3) 191 | 192 | run() -------------------------------------------------------------------------------- /tests/statics/ops.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2017 UniCredit S.p.A. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import unittest, neo, neo/statics 16 | 17 | proc run() = 18 | suite "vector operations": 19 | test "scalar vector multiplication": 20 | let v = vector([1.0, 3.0, 2.0, 8.0, -2.0]) 21 | check((v * 2.0) == vector([2.0, 6.0, 4.0, 16.0, -4.0])) 22 | check((-1.0 * v) == vector([-1.0, -3.0, -2.0, -8.0, 2.0])) 23 | test "in place scalar vector multiplication": 24 | var v = vector([1.0, 3.0, 2.0, 8.0, -2.0]) 25 | v *= 2.0 26 | check v == vector([2.0, 6.0, 4.0, 16.0, -4.0]) 27 | test "scalar vector division": 28 | let v = vector([2.0, 6.0, 4.0, 16.0, -4.0]) 29 | check((v / 2.0) == vector([1.0, 3.0, 2.0, 8.0, -2.0])) 30 | test "in place scalar vector division": 31 | var v = vector([2.0, 6.0, 4.0, 16.0, -4.0]) 32 | v /= 2.0 33 | check v == vector([1.0, 3.0, 2.0, 8.0, -2.0]) 34 | test "vector sum": 35 | let 36 | v = vector([1.0, 3.0, 2.0, 8.0, -2.0]) 37 | w = vector([2.0, -1.0, 2.0, 0.0, 4.0]) 38 | check((v + w) == vector([3.0, 2.0, 4.0, 8.0, 2.0])) 39 | test "in place vector sum": 40 | var v = vector([1.0, 3.0, 2.0, 8.0, -2.0]) 41 | let w = vector([2.0, -1.0, 2.0, 0.0, 4.0]) 42 | v += w 43 | check v == vector([3.0, 2.0, 4.0, 8.0, 2.0]) 44 | test "vector difference": 45 | let 46 | v = vector([1.0, 3.0, 2.0, 8.0, -2.0]) 47 | w = vector([2.0, -1.0, 2.0, 0.0, 4.0]) 48 | check((v - w) == vector([-1.0, 4.0, 0.0, 8.0, -6.0])) 49 | test "in place vector difference": 50 | var v = vector([1.0, 3.0, 2.0, 8.0, -2.0]) 51 | let w = vector([2.0, -1.0, 2.0, 0.0, 4.0]) 52 | v -= w 53 | check v == vector([-1.0, 4.0, 0.0, 8.0, -6.0]) 54 | test "dot product": 55 | let 56 | v = vector([1.0, 3.0, 2.0, 8.0, -2.0]) 57 | w = vector([2.0, -1.0, 2.0, 0.0, 4.0]) 58 | check(v * w == -5.0) 59 | test "ℓ² norm": 60 | let v = vector([1.0, 1.0, 2.0, 3.0, -7.0]) 61 | check l_2(v) == 8.0 62 | test "ℓ¹ norm": 63 | let v = vector([1.0, 1.0, 2.0, 3.0, -7.0]) 64 | check l_1(v) == 14.0 65 | test "max and min of vectors": 66 | let v = vector([1.0, 3.0, 2.0, 8.0, -2.0]) 67 | check max(v) == 8.0 68 | check maxIndex(v) == (3, 8.0) 69 | check min(v) == -2.0 70 | check minIndex(v) == (4, -2.0) 71 | test "vector Hadamard multiplication": 72 | let 73 | v = vector([1.0, 3.0, 2.0, 8.0, -2.0]) 74 | w = vector([2.0, -1.0, 2.0, 0.0, 4.0]) 75 | check((v |*| w) == vector([2.0, -3.0, 4.0, 0.0, -8.0])) 76 | 77 | suite "matrix/vector operations": 78 | test "multiplication of matrix and vector": 79 | let 80 | m = matrix([ 81 | [1.0, 0.0, 2.0, -1.0], 82 | [-1.0, 1.0, 3.0, 1.0], 83 | [3.0, 2.0, 2.0, 4.0] 84 | ]) 85 | v = vector([1.0, 3.0, 2.0, -2.0]) 86 | check((m * v) == vector([7.0, 6.0, 5.0])) 87 | 88 | suite "matrix operations": 89 | test "scalar matrix multiplication": 90 | let 91 | m1 = matrix([ 92 | [1.0, 3.0], 93 | [2.0, 8.0], 94 | [-2.0, 3.0] 95 | ]) 96 | m2 = matrix([ 97 | [3.0, 9.0], 98 | [6.0, 24.0], 99 | [-6.0, 9.0] 100 | ]) 101 | check(m1 * 3.0 == m2) 102 | check(3.0 * m1 == m2) 103 | test "in place scalar multiplication": 104 | var m1 = matrix([ 105 | [1.0, 3.0], 106 | [2.0, 8.0], 107 | [-2.0, 3.0] 108 | ]) 109 | let m2 = matrix([ 110 | [3.0, 9.0], 111 | [6.0, 24.0], 112 | [-6.0, 9.0] 113 | ]) 114 | m1 *= 3.0 115 | check(m1 == m2) 116 | test "scalar matrix division": 117 | let 118 | m1 = matrix([ 119 | [1.0, 3.0], 120 | [2.0, 8.0], 121 | [-2.0, 3.0] 122 | ]) 123 | m2 = matrix([ 124 | [3.0, 9.0], 125 | [6.0, 24.0], 126 | [-6.0, 9.0] 127 | ]) 128 | check(m2 / 3.0 == m1) 129 | test "in place scalar division": 130 | let m1 = matrix([ 131 | [1.0, 3.0], 132 | [2.0, 8.0], 133 | [-2.0, 3.0] 134 | ]) 135 | var m2 = matrix([ 136 | [3.0, 9.0], 137 | [6.0, 24.0], 138 | [-6.0, 9.0] 139 | ]) 140 | m2 /= 3.0 141 | check(m1 == m2) 142 | test "matrix sum": 143 | let 144 | m1 = matrix([ 145 | [1.0, 0.0, 2.0, -1.0], 146 | [-1.0, 1.0, 3.0, 1.0], 147 | [3.0, 2.0, 2.0, 4.0] 148 | ]) 149 | m2 = matrix([ 150 | [3.0, 1.0, -1.0, 1.0], 151 | [2.0, 1.0, -3.0, 0.0], 152 | [4.0, 1.0, 2.0, 2.0] 153 | ]) 154 | m3 = matrix([ 155 | [4.0, 1.0, 1.0, 0.0], 156 | [1.0, 2.0, 0.0, 1.0], 157 | [7.0, 3.0, 4.0, 6.0] 158 | ]) 159 | check(m1 + m2 == m3) 160 | test "in place matrix sum": 161 | var m1 = matrix([ 162 | [1.0, 0.0, 2.0, -1.0], 163 | [-1.0, 1.0, 3.0, 1.0], 164 | [3.0, 2.0, 2.0, 4.0] 165 | ]) 166 | let 167 | m2 = matrix([ 168 | [3.0, 1.0, -1.0, 1.0], 169 | [2.0, 1.0, -3.0, 0.0], 170 | [4.0, 1.0, 2.0, 2.0] 171 | ]) 172 | m3 = matrix([ 173 | [4.0, 1.0, 1.0, 0.0], 174 | [1.0, 2.0, 0.0, 1.0], 175 | [7.0, 3.0, 4.0, 6.0] 176 | ]) 177 | m1 += m2 178 | check m1 == m3 179 | test "matrix difference": 180 | let 181 | m1 = matrix([ 182 | [1.0, 0.0, 2.0, -1.0], 183 | [-1.0, 1.0, 3.0, 1.0], 184 | [3.0, 2.0, 2.0, 4.0] 185 | ]) 186 | m2 = matrix([ 187 | [3.0, 1.0, -1.0, 1.0], 188 | [2.0, 1.0, -3.0, 0.0], 189 | [4.0, 1.0, 2.0, 2.0] 190 | ]) 191 | m3 = matrix([ 192 | [-2.0, -1.0, 3.0, -2.0], 193 | [-3.0, 0.0, 6.0, 1.0], 194 | [-1.0, 1.0, 0.0, 2.0] 195 | ]) 196 | check(m1 - m2 == m3) 197 | test "in place matrix difference": 198 | var m1 = matrix([ 199 | [1.0, 0.0, 2.0, -1.0], 200 | [-1.0, 1.0, 3.0, 1.0], 201 | [3.0, 2.0, 2.0, 4.0] 202 | ]) 203 | let 204 | m2 = matrix([ 205 | [3.0, 1.0, -1.0, 1.0], 206 | [2.0, 1.0, -3.0, 0.0], 207 | [4.0, 1.0, 2.0, 2.0] 208 | ]) 209 | m3 = matrix([ 210 | [-2.0, -1.0, 3.0, -2.0], 211 | [-3.0, 0.0, 6.0, 1.0], 212 | [-1.0, 1.0, 0.0, 2.0] 213 | ]) 214 | m1 -= m2 215 | check m1 == m3 216 | test "matrix ℓ² norm": 217 | let m = matrix([ 218 | [1.0, 1.0, 2.0], 219 | [3.0, 0.0, -7.0] 220 | ]) 221 | check l_2(m) == 8.0 222 | test "matrix ℓ¹ norm": 223 | let m = matrix([ 224 | [1.0, 1.0, 2.0], 225 | [3.0, 0.0, -7.0], 226 | [2.5, 3.1, -1.4] 227 | ]) 228 | check l_1(m) == 21.0 229 | test "max and min of matrices": 230 | let m = matrix([ 231 | [1.0, 1.0, 2.0], 232 | [3.0, 0.0, -7.0] 233 | ]) 234 | check max(m) == 3.0 235 | check min(m) == -7.0 236 | test "matrix multiplication": 237 | let 238 | m1 = matrix([ 239 | [1.0, 1.0, 2.0, -3.0], 240 | [3.0, 0.0, -7.0, 2.0] 241 | ]) 242 | m2 = matrix([ 243 | [1.0, 1.0, 2.0], 244 | [3.0, 1.0, -5.0], 245 | [-1.0, -1.0, 2.0], 246 | [4.0, 2.0, 3.0] 247 | ]) 248 | m3 = matrix([ 249 | [-10.0, -6.0, -8.0], 250 | [18.0, 14.0, -2.0] 251 | ]) 252 | check(m1 * m2 == m3) 253 | test "matrix Hadamard multiplication": 254 | let 255 | m1 = matrix([ 256 | [1.0, 0.0, 2.0, -1.0], 257 | [-1.0, 1.0, 3.0, 1.0], 258 | [3.0, 2.0, 2.0, 4.0] 259 | ]) 260 | m2 = matrix([ 261 | [3.0, 1.0, -1.0, 1.0], 262 | [2.0, 1.0, -3.0, 0.0], 263 | [4.0, 1.0, 2.0, 2.0] 264 | ]) 265 | m3 = matrix([ 266 | [3.0, 0.0, -2.0, -1.0], 267 | [-2.0, 1.0, -9.0, 0.0], 268 | [12.0, 2.0, 4.0, 8.0] 269 | ]) 270 | check((m1 |*| m2) == m3) 271 | 272 | run() -------------------------------------------------------------------------------- /tests/statics/row_major_ops.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2017 UniCredit S.p.A. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import unittest, neo, neo/statics 16 | 17 | proc run() = 18 | suite "row-major matrix/vector operations": 19 | test "multiplication of matrix and vector": 20 | let 21 | m = matrix([ 22 | [1.0, 0.0, 2.0, -1.0], 23 | [-1.0, 1.0, 3.0, 1.0], 24 | [3.0, 2.0, 2.0, 4.0] 25 | ], order = rowMajor) 26 | v = vector([1.0, 3.0, 2.0, -2.0]) 27 | check((m * v) == vector([7.0, 6.0, 5.0])) 28 | 29 | suite "row-major matrix operations": 30 | test "scalar matrix multiplication": 31 | let 32 | m1 = matrix([ 33 | [1.0, 3.0], 34 | [2.0, 8.0], 35 | [-2.0, 3.0] 36 | ], order = rowMajor) 37 | m2 = matrix([ 38 | [3.0, 9.0], 39 | [6.0, 24.0], 40 | [-6.0, 9.0] 41 | ], order = rowMajor) 42 | check(m1 * 3.0 == m2) 43 | check(3.0 * m1 == m2) 44 | test "mutating scalar multiplication": 45 | var m1 = matrix([ 46 | [1.0, 3.0], 47 | [2.0, 8.0], 48 | [-2.0, 3.0] 49 | ], order = rowMajor) 50 | let m2 = matrix([ 51 | [3.0, 9.0], 52 | [6.0, 24.0], 53 | [-6.0, 9.0] 54 | ], order = rowMajor) 55 | m1 *= 3.0 56 | check(m1 == m2) 57 | test "matrix sum": 58 | let 59 | m1 = matrix([ 60 | [1.0, 0.0, 2.0, -1.0], 61 | [-1.0, 1.0, 3.0, 1.0], 62 | [3.0, 2.0, 2.0, 4.0] 63 | ], order = rowMajor) 64 | m2 = matrix([ 65 | [3.0, 1.0, -1.0, 1.0], 66 | [2.0, 1.0, -3.0, 0.0], 67 | [4.0, 1.0, 2.0, 2.0] 68 | ], order = rowMajor) 69 | m3 = matrix([ 70 | [4.0, 1.0, 1.0, 0.0], 71 | [1.0, 2.0, 0.0, 1.0], 72 | [7.0, 3.0, 4.0, 6.0] 73 | ], order = rowMajor) 74 | check(m1 + m2 == m3) 75 | test "mutating matrix sum": 76 | var m1 = matrix([ 77 | [1.0, 0.0, 2.0, -1.0], 78 | [-1.0, 1.0, 3.0, 1.0], 79 | [3.0, 2.0, 2.0, 4.0] 80 | ], order = rowMajor) 81 | let 82 | m2 = matrix([ 83 | [3.0, 1.0, -1.0, 1.0], 84 | [2.0, 1.0, -3.0, 0.0], 85 | [4.0, 1.0, 2.0, 2.0] 86 | ], order = rowMajor) 87 | m3 = matrix([ 88 | [4.0, 1.0, 1.0, 0.0], 89 | [1.0, 2.0, 0.0, 1.0], 90 | [7.0, 3.0, 4.0, 6.0] 91 | ], order = rowMajor) 92 | m1 += m2 93 | check m1 == m3 94 | test "matrix difference": 95 | let 96 | m1 = matrix([ 97 | [1.0, 0.0, 2.0, -1.0], 98 | [-1.0, 1.0, 3.0, 1.0], 99 | [3.0, 2.0, 2.0, 4.0] 100 | ], order = rowMajor) 101 | m2 = matrix([ 102 | [3.0, 1.0, -1.0, 1.0], 103 | [2.0, 1.0, -3.0, 0.0], 104 | [4.0, 1.0, 2.0, 2.0] 105 | ], order = rowMajor) 106 | m3 = matrix([ 107 | [-2.0, -1.0, 3.0, -2.0], 108 | [-3.0, 0.0, 6.0, 1.0], 109 | [-1.0, 1.0, 0.0, 2.0] 110 | ], order = rowMajor) 111 | check(m1 - m2 == m3) 112 | test "mutating matrix sum": 113 | var m1 = matrix([ 114 | [1.0, 0.0, 2.0, -1.0], 115 | [-1.0, 1.0, 3.0, 1.0], 116 | [3.0, 2.0, 2.0, 4.0] 117 | ], order = rowMajor) 118 | let 119 | m2 = matrix([ 120 | [3.0, 1.0, -1.0, 1.0], 121 | [2.0, 1.0, -3.0, 0.0], 122 | [4.0, 1.0, 2.0, 2.0] 123 | ], order = rowMajor) 124 | m3 = matrix([ 125 | [-2.0, -1.0, 3.0, -2.0], 126 | [-3.0, 0.0, 6.0, 1.0], 127 | [-1.0, 1.0, 0.0, 2.0] 128 | ], order = rowMajor) 129 | m1 -= m2 130 | check m1 == m3 131 | test "matrix ℓ² norm": 132 | let m = matrix([ 133 | [1.0, 1.0, 2.0], 134 | [3.0, 0.0, -7.0] 135 | ], order = rowMajor) 136 | check l_2(m) == 8.0 137 | test "matrix ℓ¹ norm": 138 | let m = matrix([ 139 | [1.0, 1.0, 2.0], 140 | [3.0, 0.0, -7.0], 141 | [2.5, 3.1, -1.4] 142 | ], order = rowMajor) 143 | check l_1(m) == 21.0 144 | test "max and min of matrices": 145 | let m = matrix([ 146 | [1.0, 1.0, 2.0], 147 | [3.0, 0.0, -7.0] 148 | ], order = rowMajor) 149 | check max(m) == 3.0 150 | check min(m) == -7.0 151 | test "matrix multiplication": 152 | let 153 | m1 = matrix([ 154 | [1.0, 1.0, 2.0, -3.0], 155 | [3.0, 0.0, -7.0, 2.0] 156 | ], order = rowMajor) 157 | m2 = matrix([ 158 | [1.0, 1.0, 2.0], 159 | [3.0, 1.0, -5.0], 160 | [-1.0, -1.0, 2.0], 161 | [4.0, 2.0, 3.0] 162 | ], order = rowMajor) 163 | m3 = matrix([ 164 | [-10.0, -6.0, -8.0], 165 | [18.0, 14.0, -2.0] 166 | ], order = rowMajor) 167 | check(m1 * m2 == m3) 168 | test "matrix Hadamard multiplication": 169 | let 170 | m1 = matrix([ 171 | [1.0, 0.0, 2.0, -1.0], 172 | [-1.0, 1.0, 3.0, 1.0], 173 | [3.0, 2.0, 2.0, 4.0] 174 | ], order = rowMajor) 175 | m2 = matrix([ 176 | [3.0, 1.0, -1.0, 1.0], 177 | [2.0, 1.0, -3.0, 0.0], 178 | [4.0, 1.0, 2.0, 2.0] 179 | ], order = rowMajor) 180 | m3 = matrix([ 181 | [3.0, 0.0, -2.0, -1.0], 182 | [-2.0, 1.0, -9.0, 0.0], 183 | [12.0, 2.0, 4.0, 8.0] 184 | ], order = rowMajor) 185 | check((m1 |*| m2) == m3) 186 | 187 | run() -------------------------------------------------------------------------------- /tests/statics/slice.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2017 UniCredit S.p.A. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import unittest, neo, neo/statics 16 | 17 | proc run() = 18 | suite "slicing vectors": 19 | test "getting a slice of a vector": 20 | let 21 | v = statics.vector([1, 2, 3, 4, 5]) 22 | w = v[2 .. 3] 23 | 24 | check w == statics.vector([3, 4]) 25 | 26 | test "assigning to a slice": 27 | var v = statics.vector([1, 2, 3, 4, 5]) 28 | let w = statics.vector([6, 7]) 29 | 30 | v[2 .. 3] = w 31 | check v == statics.vector([1, 2, 6, 7, 5]) 32 | 33 | test "assigning to a slice with BLAS operations": 34 | var v = statics.vector([1.0, 2.0, 3.0, 4.0, 5.0]) 35 | let 36 | w = statics.vector([6.0, 7.0]) 37 | expected = statics.vector([1.0, 2.0, 6.0, 7.0, 5.0]) 38 | 39 | v[2 .. 3] = w 40 | check v == expected 41 | 42 | test "assigning a slice to another slice": 43 | var v = statics.vector([1, 2, 3, 4, 5]) 44 | let w = statics.vector([6, 7, 8, 9, 10]) 45 | 46 | v[2 .. 3] = w[3 .. 4] 47 | check v == statics.vector([1, 2, 9, 10, 5]) 48 | 49 | suite "slicing column major matrices": 50 | test "slice of a full matrix": 51 | let 52 | m = statics.makeMatrixIJ(int, 5, 5, 3 * i + j) 53 | s = m[1 .. 3, 2 .. 4] 54 | expected = statics.matrix([ 55 | [5, 6, 7], 56 | [8, 9, 10], 57 | [11, 12, 13] 58 | ]) 59 | 60 | check s == expected 61 | test "slice on columns only": 62 | let 63 | m = statics.makeMatrixIJ(int, 5, 5, 3 * i + j) 64 | s = m[All, 2 .. 4] 65 | expected = matrix([ 66 | [2, 3, 4], 67 | [5, 6, 7], 68 | [8, 9, 10], 69 | [11, 12, 13], 70 | [14, 15, 16] 71 | ]) 72 | 73 | check s == expected 74 | test "slice on rows only": 75 | let 76 | m = statics.makeMatrixIJ(int, 5, 5, 3 * i + j) 77 | s = m[1 .. 3, All] 78 | expected = statics.matrix([ 79 | [3, 4, 5, 6, 7], 80 | [6, 7, 8, 9, 10], 81 | [9, 10, 11, 12, 13], 82 | ]) 83 | 84 | check s == expected 85 | test "slice a sliced matrix": 86 | let 87 | m = statics.makeMatrixIJ(int, 5, 5, 3 * i + j) 88 | s1 = m[1 .. 4, 1 .. 4] 89 | s2 = s1[0 .. 2, 1 .. 3] 90 | expected = statics.matrix([ 91 | [5, 6, 7], 92 | [8, 9, 10], 93 | [11, 12, 13] 94 | ]) 95 | 96 | check s2 == expected 97 | test "slice a sliced matrix on rows only": 98 | let 99 | m = statics.makeMatrixIJ(int, 5, 5, 3 * i + j) 100 | s1 = m[1 .. 4, 1 .. 4] 101 | s2 = s1[0 .. 2, All] 102 | expected = statics.matrix([ 103 | [4, 5, 6, 7], 104 | [7, 8, 9, 10], 105 | [10, 11, 12, 13] 106 | ]) 107 | 108 | check s2 == expected 109 | 110 | test "assigning to a slice": 111 | var m = statics.makeMatrixIJ(int, 5, 5, 3 * i + j) 112 | let n = statics.matrix([ 113 | [5, 6, 7], 114 | [8, 9, 10], 115 | [11, 12, 13] 116 | ]) 117 | m[1 .. 3, 1 .. 3] = n 118 | check m[2, 2] == 9 119 | check m[3, 2] == 12 120 | 121 | test "assigning a slice to another slice": 122 | var m = statics.makeMatrixIJ(int, 5, 5, 3 * i + j) 123 | let n = statics.makeMatrixIJ(int, 5, 5, 2 * i + 2 * j) 124 | m[1 .. 3, 1 .. 3] = n[2 .. 4, 2 .. 4] 125 | check m[2, 2] == 12 126 | check m[3, 2] == 14 127 | 128 | test "assigning to a slice on columns only": 129 | var m = statics.makeMatrixIJ(int, 5, 5, 3 * i + j) 130 | let n = statics.makeMatrixIJ(int, 5, 3, 2 * i + 2 * j) 131 | 132 | m[All, 2 .. 4] = n 133 | check m[2, 2] == 4 134 | check m[3, 2] == 6 135 | 136 | test "assigning to a slice on rows only": 137 | var m = statics.makeMatrixIJ(int, 5, 5, 3 * i + j) 138 | let n = statics.makeMatrixIJ(int, 3, 5, 2 * i + 2 * j) 139 | 140 | m[2 .. 4, All] = n 141 | check m[2, 2] == 4 142 | check m[3, 2] == 6 143 | 144 | test "assigning to a slice with BLAS operations": 145 | var m = statics.makeMatrixIJ(float64, 5, 5, (3 * i + j).float64) 146 | let n = statics.matrix([ 147 | [5'f64, 6, 7], 148 | [8'f64, 9, 10], 149 | [11'f64, 12, 13] 150 | ]) 151 | m[1 .. 3, 1 .. 3] = n 152 | check m[2, 2] == 9'f64 153 | check m[3, 2] == 12'f64 154 | 155 | test "slice of a matrix should share storage": 156 | var 157 | m = statics.makeMatrixIJ(int, 5, 5, 3 * i + j) 158 | s = m[1 .. 3, 2 .. 4] 159 | 160 | s[1, 1] = 0 161 | 162 | check m[2, 3] == 0 163 | test "rows of a slice of a matrix": 164 | let 165 | m = statics.makeMatrixIJ(int, 5, 5, 3 * i + j) 166 | s = m[1 .. 3, 2 .. 4] 167 | r = s.row(1) 168 | 169 | check r == statics.vector([8, 9, 10]) 170 | test "columns of a slice of a matrix": 171 | let 172 | m = statics.makeMatrixIJ(int, 5, 5, 3 * i + j) 173 | s = m[1 .. 3, 2 .. 4] 174 | r = s.column(1) 175 | 176 | check r == statics.vector([6, 9, 12]) 177 | 178 | run() -------------------------------------------------------------------------------- /tests/statics/solvers.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2017 UniCredit S.p.A. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import unittest, neo, neo/statics 16 | 17 | proc run() = 18 | suite "linear system solving": 19 | test "matrix-matrix solver": 20 | let 21 | a = matrix([ 22 | [3.0, 1.0], 23 | [1.0, -2.0] 24 | ]) 25 | b = matrix([ 26 | [1.0], 27 | [0.0] 28 | ]) 29 | x = solve(a, b) 30 | expected = matrix([ 31 | [2.0 / 7.0], 32 | [1.0 / 7.0] 33 | ]) 34 | check expected =~ x 35 | 36 | test "matrix-matrix solve operator": 37 | let 38 | a = matrix([ 39 | [3.0, 1.0], 40 | [1.0, -2.0] 41 | ]) 42 | b = matrix([ 43 | [1.0], 44 | [0.0] 45 | ]) 46 | x = a \ b 47 | expected = matrix([ 48 | [2.0 / 7.0], 49 | [1.0 / 7.0] 50 | ]) 51 | check expected =~ x 52 | 53 | test "singular matrix error": 54 | let 55 | a = matrix([ 56 | [2.0, 2.0], 57 | [1.0, 1.0] 58 | ]) 59 | b = matrix([ 60 | [1.0], 61 | [0.0] 62 | ]) 63 | expect FloatingPointError: 64 | discard solve(a, b) 65 | 66 | test "matrix inverse": 67 | let 68 | a = matrix([ 69 | [4.0, 3.0], 70 | [3.0, 2.0] 71 | ]) 72 | expected = matrix([ 73 | [-2.0, 3.0], 74 | [3.0, -4.0] 75 | ]) 76 | ainv = inv(a) 77 | check expected =~ ainv 78 | 79 | test "matrix-vector solver": 80 | let 81 | a = matrix([ 82 | [3.0, 1.0], 83 | [1.0, -2.0] 84 | ]) 85 | b = vector([1.0, 0.0]) 86 | x = solve(a, b) 87 | expected = vector([2.0/7.0, 1.0/7.0]) 88 | check expected =~ x 89 | 90 | test "matrix-vector solve operator": 91 | let 92 | a = matrix([ 93 | [3.0, 1.0], 94 | [1.0, -2.0] 95 | ]) 96 | b = vector([1.0, 0.0]) 97 | x = a \ b 98 | expected = vector([2.0/7.0, 1.0/7.0]) 99 | check expected =~ x 100 | 101 | test "matrix-vector singular matrix error": 102 | let 103 | a = matrix([ 104 | [0.0, 0.0], 105 | [0.0, 0.0] 106 | ]) 107 | b = vector([1.0, 0.0]) 108 | expect FloatingPointError: 109 | discard solve(a, b) 110 | 111 | run() -------------------------------------------------------------------------------- /tests/statics/trivial_ops.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2017 UniCredit S.p.A. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import unittest, neo, neo/statics 16 | 17 | proc run() = 18 | suite "trivial operations on 32-bit matrices": 19 | test "reshape of matrices": 20 | let 21 | m1 = statics.matrix([ 22 | [1'f32, 0'f32, 2'f32, -1'f32], 23 | [-1'f32, 1'f32, 3'f32, 1'f32], 24 | [3'f32, 2'f32, 2'f32, 4'f32] 25 | ]) 26 | m2 = statics.matrix([ 27 | [1'f32, 1'f32, 2'f32], 28 | [-1'f32, 2'f32, -1'f32], 29 | [3'f32, 2'f32, 1'f32], 30 | [0'f32, 3'f32, 4'f32] 31 | ]) 32 | check m1.reshape(4, 3) == m2 33 | test "turn vectors into matrices": 34 | let 35 | v = statics.vector([1'f32, -1'f32, 3'f32, 0'f32, 1'f32, 2'f32, 2'f32, 3'f32, 2'f32, -1'f32, 1'f32, 4'f32]) 36 | m = statics.matrix([ 37 | [1'f32, 0'f32, 2'f32, -1'f32], 38 | [-1'f32, 1'f32, 3'f32, 1'f32], 39 | [3'f32, 2'f32, 2'f32, 4'f32] 40 | ]) 41 | check v.asMatrix(3, 4) == m 42 | test "turn matrices into vectors": 43 | let 44 | v = statics.vector([1'f32, -1'f32, 3'f32, 0'f32, 1'f32, 2'f32, 2'f32, 3'f32, 2'f32, -1'f32, 1'f32, 4'f32]) 45 | m = statics.matrix([ 46 | [1'f32, 0'f32, 2'f32, -1'f32], 47 | [-1'f32, 1'f32, 3'f32, 1'f32], 48 | [3'f32, 2'f32, 2'f32, 4'f32] 49 | ]) 50 | check m.asVector == v 51 | test "transpose of matrices": 52 | let 53 | m1 = statics.matrix([ 54 | [1'f32, 0'f32, 2'f32, -1'f32], 55 | [-1'f32, 1'f32, 3'f32, 1'f32], 56 | [3'f32, 2'f32, 2'f32, 4'f32] 57 | ]) 58 | m2 = statics.matrix([ 59 | [1'f32, -1'f32, 3'f32], 60 | [0'f32, 1'f32, 2'f32], 61 | [2'f32, 3'f32, 2'f32], 62 | [-1'f32, 1'f32, 4'f32] 63 | ]) 64 | check m1.t == m2 65 | test "hard transpose of matrices": 66 | let m = statics.matrix([ 67 | [1'f32, 0'f32, 2'f32, -1'f32], 68 | [-1'f32, 1'f32, 3'f32, 1'f32], 69 | [3'f32, 2'f32, 2'f32, 4'f32] 70 | ]) 71 | 72 | check(m.t == m.T) 73 | test "hard transpose of row major matrices": 74 | let m = statics.matrix([ 75 | [1'f32, 0'f32, 2'f32, -1'f32], 76 | [-1'f32, 1'f32, 3'f32, 1'f32], 77 | [3'f32, 2'f32, 2'f32, 4'f32] 78 | ], order = rowMajor) 79 | 80 | check(m.t == m.T) 81 | 82 | suite "trivial operations should share storage": 83 | test "reshape of matrices": 84 | var 85 | m1 = statics.matrix([ 86 | [1.0, 0.0, 2.0, -1.0], 87 | [-1.0, 1.0, 3.0, 1.0], 88 | [3.0, 2.0, 2.0, 4.0] 89 | ]) 90 | m2 = m1.reshape(4, 3) 91 | m2[2, 1] = 0.0 92 | check m1[0, 2] == 0.0 93 | test "turn vectors into matrices": 94 | var 95 | v = statics.vector([1.0, -1.0, 3.0, 0.0, 1.0, 2.0, 2.0, 3.0, 2.0, -1.0, 1.0, 4.0]) 96 | m = v.asMatrix(3, 4) 97 | m[2, 1] = 0.0 98 | check v[5] == 0.0 99 | test "turn matrices into vectors": 100 | var 101 | m = statics.matrix([ 102 | [1.0, 0.0, 2.0, -1.0], 103 | [-1.0, 1.0, 3.0, 1.0], 104 | [3.0, 2.0, 2.0, 4.0] 105 | ]) 106 | v = m.asVector 107 | v[5] = 0.0 108 | check m[2, 1] == 0.0 109 | test "transpose of matrices": 110 | var 111 | m1 = statics.matrix([ 112 | [1.0, 0.0, 2.0, -1.0], 113 | [-1.0, 1.0, 3.0, 1.0], 114 | [3.0, 2.0, 2.0, 4.0] 115 | ]) 116 | m2 = m1.t 117 | m2[1, 2] = 0.0 118 | check m1[2, 1] == 0.0 119 | 120 | run() -------------------------------------------------------------------------------- /tests/statics/ufunc.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2017 UniCredit S.p.A. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import unittest, neo, neo/statics 16 | 17 | proc run() = 18 | suite "universal functions": 19 | test "universal sqrt on vectors": 20 | let u = vector([1.0, 4.0, 9.0, 16.0]) 21 | check sqrt(u) == vector([1.0, 2.0, 3.0, 4.0]) 22 | test "universal sine on matrices": 23 | let m = matrix([[1.0, 2.0], [4.0, 8.0]]) 24 | check sin(m) == matrix([[sin(1.0), sin(2.0)], [sin(4.0), sin(8.0)]]) 25 | 26 | run() -------------------------------------------------------------------------------- /tests/tcudadense.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2017 UniCredit S.p.A. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import cudadense/dcopy, cudadense/dequality, cudadense/diterators, 16 | cudadense/dclone, cudadense/dslice, cudadense/dops, cudadense/dtrivial_ops -------------------------------------------------------------------------------- /tests/tcudasparse.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2017 UniCredit S.p.A. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import cudasparse/scopy -------------------------------------------------------------------------------- /tests/tdense.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2017 UniCredit S.p.A. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | {.push warning[ProveInit]: off .} 16 | 17 | import dense/dinitialize, dense/daccess, dense/dslice, dense/dequality, 18 | dense/dconversions, dense/diterators, dense/dcollection, dense/dtrivial_ops, 19 | dense/dops, dense/drow_major_ops, dense/dmixed_ops, dense/dufunc, 20 | dense/dstack, dense/dshared, dense/dsolvers, dense/deigenvalues, dense/ddet, 21 | dense/dstacking, dense/ddecompositions 22 | 23 | {. pop .} 24 | -------------------------------------------------------------------------------- /tests/tshared.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2018 UniCredit S.p.A. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import unittest, threadpool, neo/dense 16 | 17 | type MultiplyData = object 18 | m: Matrix[float64] 19 | firstRow, lastRow: int 20 | k: float64 21 | 22 | proc multiplyMatrix(data: MultiplyData) = 23 | var m = data.m[data.firstRow .. data.lastRow, All] 24 | m *= data.k 25 | 26 | proc run() = 27 | suite "parallel operation on shared matrices": 28 | test "multiplying a shared matrix in parallel": 29 | var m = sharedMatrix(100, 100, float64) 30 | defer: 31 | dealloc(m) 32 | 33 | for i in 0 .. 99: 34 | for j in 0 .. 99: 35 | m[i, j] = (i + j).float64 36 | 37 | check m[20, 10] == 30.0 38 | check m[70, 10] == 80.0 39 | 40 | spawn multiplyMatrix(MultiplyData(m: m, firstRow: 0, lastRow: 49, k: 2)) 41 | spawn multiplyMatrix(MultiplyData(m: m, firstRow: 50, lastRow: 99, k: 3)) 42 | sync() 43 | 44 | check m[20, 10] == 60.0 45 | check m[70, 10] == 240.0 46 | 47 | run() -------------------------------------------------------------------------------- /tests/tsparse.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2017 UniCredit S.p.A. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import sparse/siterators, sparse/sconversions -------------------------------------------------------------------------------- /tests/tstatics.nim: -------------------------------------------------------------------------------- 1 | # Copyright 2017 UniCredit S.p.A. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | {.push warning[ProveInit]: off .} 16 | 17 | import statics/initialize, statics/access, statics/iterators, 18 | statics/collection, statics/trivial_ops, statics/compilation, 19 | statics/equality, statics/ops, statics/row_major_ops, statics/mixed_ops, 20 | statics/solvers, statics/eigenvalues, statics/det, statics/ufunc, 21 | statics/slice 22 | 23 | {. pop .} 24 | --------------------------------------------------------------------------------