├── .github └── workflows │ └── build.yml ├── .gitignore ├── CHANGELOG.md ├── Gemfile ├── LICENSE.txt ├── README.md ├── Rakefile ├── khiva.gemspec ├── lib ├── khiva.rb └── khiva │ ├── array.rb │ ├── clustering.rb │ ├── dimensionality.rb │ ├── distances.rb │ ├── features.rb │ ├── ffi.rb │ ├── library.rb │ ├── linalg.rb │ ├── matrix.rb │ ├── normalization.rb │ ├── polynomial.rb │ ├── regression.rb │ ├── regularization.rb │ ├── statistics.rb │ ├── utils.rb │ └── version.rb └── test ├── array_test.rb ├── clustering_test.rb ├── dimensionality_test.rb ├── distances_test.rb ├── features_test.rb ├── library_test.rb ├── linalg_test.rb ├── matrix_test.rb ├── normalization_test.rb ├── polynomial_test.rb ├── regression_test.rb ├── regularization_test.rb ├── statistics_test.rb ├── support ├── array.py ├── clustering.py ├── dimensionality.py ├── distances.py ├── features.py ├── library.py ├── linalg.py ├── matrix.py ├── normalization.py ├── polynomial.py ├── regression.py ├── regularization.py └── statistics.py └── test_helper.rb /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | on: [push, pull_request] 3 | jobs: 4 | build: 5 | strategy: 6 | fail-fast: false 7 | matrix: 8 | os: [ubuntu-latest, macos-latest] 9 | runs-on: ${{ matrix.os }} 10 | steps: 11 | - uses: actions/checkout@v4 12 | - uses: ruby/setup-ruby@v1 13 | with: 14 | ruby-version: 3.3 15 | bundler-cache: true 16 | - if: ${{ startsWith(matrix.os, 'ubuntu') }} 17 | name: Install Khiva on Linux 18 | run: | 19 | sudo apt-key adv --fetch-key https://repo.arrayfire.com/GPG-PUB-KEY-ARRAYFIRE-2020.PUB 20 | echo "deb [arch=amd64] https://repo.arrayfire.com/debian all main" | sudo tee /etc/apt/sources.list.d/arrayfire.list 21 | sudo apt-get update 22 | sudo apt-get install arrayfire-unified3 arrayfire-cpu3-openblas arrayfire-opencl3-openblas 23 | 24 | wget -q https://github.com/shapelets/khiva/releases/download/v0.5.0/khiva-khiva_0.5.0_amd64.deb 25 | sudo dpkg -i khiva-khiva_0.5.0_amd64.deb 26 | sudo ldconfig 27 | - if: ${{ startsWith(matrix.os, 'macos') }} 28 | name: Install Khiva on Mac 29 | run: brew install khiva 30 | - run: bundle exec rake test 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.bundle/ 2 | /.yardoc 3 | /_yardoc/ 4 | /coverage/ 5 | /doc/ 6 | /pkg/ 7 | /spec/reports/ 8 | /tmp/ 9 | *.lock 10 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 0.3.0 (unreleased) 2 | 3 | - Dropped support for Ruby < 3.1 4 | 5 | ## 0.2.1 (2023-06-07) 6 | 7 | - Improved support for Mac ARM 8 | 9 | ## 0.2.0 (2022-12-28) 10 | 11 | - Dropped support for Ruby < 2.7 12 | 13 | ## 0.1.3 (2021-02-18) 14 | 15 | - Added `chains` method 16 | 17 | ## 0.1.2 (2020-12-19) 18 | 19 | - Added `find_best_n_occurrences` and `mass` methods 20 | - Added more dimensionality methods 21 | - Added more feature methods 22 | 23 | ## 0.1.1 (2020-12-18) 24 | 25 | - Added many more methods 26 | 27 | ## 0.1.0 (2020-12-17) 28 | 29 | - First release 30 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gemspec 4 | 5 | gem "rake" 6 | gem "minitest", ">= 5" 7 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Mozilla Public License, version 2.0 2 | 3 | 1. Definitions 4 | 5 | 1.1. "Contributor" 6 | 7 | means each individual or legal entity that creates, contributes to the 8 | creation of, or owns Covered Software. 9 | 10 | 1.2. "Contributor Version" 11 | 12 | means the combination of the Contributions of others (if any) used by a 13 | Contributor and that particular Contributor's Contribution. 14 | 15 | 1.3. "Contribution" 16 | 17 | means Covered Software of a particular Contributor. 18 | 19 | 1.4. "Covered Software" 20 | 21 | means Source Code Form to which the initial Contributor has attached the 22 | notice in Exhibit A, the Executable Form of such Source Code Form, and 23 | Modifications of such Source Code Form, in each case including portions 24 | thereof. 25 | 26 | 1.5. "Incompatible With Secondary Licenses" 27 | means 28 | 29 | a. that the initial Contributor has attached the notice described in 30 | Exhibit B to the Covered Software; or 31 | 32 | b. that the Covered Software was made available under the terms of 33 | version 1.1 or earlier of the License, but not also under the terms of 34 | a Secondary License. 35 | 36 | 1.6. "Executable Form" 37 | 38 | means any form of the work other than Source Code Form. 39 | 40 | 1.7. "Larger Work" 41 | 42 | means a work that combines Covered Software with other material, in a 43 | separate file or files, that is not Covered Software. 44 | 45 | 1.8. "License" 46 | 47 | means this document. 48 | 49 | 1.9. "Licensable" 50 | 51 | means having the right to grant, to the maximum extent possible, whether 52 | at the time of the initial grant or subsequently, any and all of the 53 | rights conveyed by this License. 54 | 55 | 1.10. "Modifications" 56 | 57 | means any of the following: 58 | 59 | a. any file in Source Code Form that results from an addition to, 60 | deletion from, or modification of the contents of Covered Software; or 61 | 62 | b. any new file in Source Code Form that contains any Covered Software. 63 | 64 | 1.11. "Patent Claims" of a Contributor 65 | 66 | means any patent claim(s), including without limitation, method, 67 | process, and apparatus claims, in any patent Licensable by such 68 | Contributor that would be infringed, but for the grant of the License, 69 | by the making, using, selling, offering for sale, having made, import, 70 | or transfer of either its Contributions or its Contributor Version. 71 | 72 | 1.12. "Secondary License" 73 | 74 | means either the GNU General Public License, Version 2.0, the GNU Lesser 75 | General Public License, Version 2.1, the GNU Affero General Public 76 | License, Version 3.0, or any later versions of those licenses. 77 | 78 | 1.13. "Source Code Form" 79 | 80 | means the form of the work preferred for making modifications. 81 | 82 | 1.14. "You" (or "Your") 83 | 84 | means an individual or a legal entity exercising rights under this 85 | License. For legal entities, "You" includes any entity that controls, is 86 | controlled by, or is under common control with You. For purposes of this 87 | definition, "control" means (a) the power, direct or indirect, to cause 88 | the direction or management of such entity, whether by contract or 89 | otherwise, or (b) ownership of more than fifty percent (50%) of the 90 | outstanding shares or beneficial ownership of such entity. 91 | 92 | 93 | 2. License Grants and Conditions 94 | 95 | 2.1. Grants 96 | 97 | Each Contributor hereby grants You a world-wide, royalty-free, 98 | non-exclusive license: 99 | 100 | a. under intellectual property rights (other than patent or trademark) 101 | Licensable by such Contributor to use, reproduce, make available, 102 | modify, display, perform, distribute, and otherwise exploit its 103 | Contributions, either on an unmodified basis, with Modifications, or 104 | as part of a Larger Work; and 105 | 106 | b. under Patent Claims of such Contributor to make, use, sell, offer for 107 | sale, have made, import, and otherwise transfer either its 108 | Contributions or its Contributor Version. 109 | 110 | 2.2. Effective Date 111 | 112 | The licenses granted in Section 2.1 with respect to any Contribution 113 | become effective for each Contribution on the date the Contributor first 114 | distributes such Contribution. 115 | 116 | 2.3. Limitations on Grant Scope 117 | 118 | The licenses granted in this Section 2 are the only rights granted under 119 | this License. No additional rights or licenses will be implied from the 120 | distribution or licensing of Covered Software under this License. 121 | Notwithstanding Section 2.1(b) above, no patent license is granted by a 122 | Contributor: 123 | 124 | a. for any code that a Contributor has removed from Covered Software; or 125 | 126 | b. for infringements caused by: (i) Your and any other third party's 127 | modifications of Covered Software, or (ii) the combination of its 128 | Contributions with other software (except as part of its Contributor 129 | Version); or 130 | 131 | c. under Patent Claims infringed by Covered Software in the absence of 132 | its Contributions. 133 | 134 | This License does not grant any rights in the trademarks, service marks, 135 | or logos of any Contributor (except as may be necessary to comply with 136 | the notice requirements in Section 3.4). 137 | 138 | 2.4. Subsequent Licenses 139 | 140 | No Contributor makes additional grants as a result of Your choice to 141 | distribute the Covered Software under a subsequent version of this 142 | License (see Section 10.2) or under the terms of a Secondary License (if 143 | permitted under the terms of Section 3.3). 144 | 145 | 2.5. Representation 146 | 147 | Each Contributor represents that the Contributor believes its 148 | Contributions are its original creation(s) or it has sufficient rights to 149 | grant the rights to its Contributions conveyed by this License. 150 | 151 | 2.6. Fair Use 152 | 153 | This License is not intended to limit any rights You have under 154 | applicable copyright doctrines of fair use, fair dealing, or other 155 | equivalents. 156 | 157 | 2.7. Conditions 158 | 159 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in 160 | Section 2.1. 161 | 162 | 163 | 3. Responsibilities 164 | 165 | 3.1. Distribution of Source Form 166 | 167 | All distribution of Covered Software in Source Code Form, including any 168 | Modifications that You create or to which You contribute, must be under 169 | the terms of this License. You must inform recipients that the Source 170 | Code Form of the Covered Software is governed by the terms of this 171 | License, and how they can obtain a copy of this License. You may not 172 | attempt to alter or restrict the recipients' rights in the Source Code 173 | Form. 174 | 175 | 3.2. Distribution of Executable Form 176 | 177 | If You distribute Covered Software in Executable Form then: 178 | 179 | a. such Covered Software must also be made available in Source Code Form, 180 | as described in Section 3.1, and You must inform recipients of the 181 | Executable Form how they can obtain a copy of such Source Code Form by 182 | reasonable means in a timely manner, at a charge no more than the cost 183 | of distribution to the recipient; and 184 | 185 | b. You may distribute such Executable Form under the terms of this 186 | License, or sublicense it under different terms, provided that the 187 | license for the Executable Form does not attempt to limit or alter the 188 | recipients' rights in the Source Code Form under this License. 189 | 190 | 3.3. Distribution of a Larger Work 191 | 192 | You may create and distribute a Larger Work under terms of Your choice, 193 | provided that You also comply with the requirements of this License for 194 | the Covered Software. If the Larger Work is a combination of Covered 195 | Software with a work governed by one or more Secondary Licenses, and the 196 | Covered Software is not Incompatible With Secondary Licenses, this 197 | License permits You to additionally distribute such Covered Software 198 | under the terms of such Secondary License(s), so that the recipient of 199 | the Larger Work may, at their option, further distribute the Covered 200 | Software under the terms of either this License or such Secondary 201 | License(s). 202 | 203 | 3.4. Notices 204 | 205 | You may not remove or alter the substance of any license notices 206 | (including copyright notices, patent notices, disclaimers of warranty, or 207 | limitations of liability) contained within the Source Code Form of the 208 | Covered Software, except that You may alter any license notices to the 209 | extent required to remedy known factual inaccuracies. 210 | 211 | 3.5. Application of Additional Terms 212 | 213 | You may choose to offer, and to charge a fee for, warranty, support, 214 | indemnity or liability obligations to one or more recipients of Covered 215 | Software. However, You may do so only on Your own behalf, and not on 216 | behalf of any Contributor. You must make it absolutely clear that any 217 | such warranty, support, indemnity, or liability obligation is offered by 218 | You alone, and You hereby agree to indemnify every Contributor for any 219 | liability incurred by such Contributor as a result of warranty, support, 220 | indemnity or liability terms You offer. You may include additional 221 | disclaimers of warranty and limitations of liability specific to any 222 | jurisdiction. 223 | 224 | 4. Inability to Comply Due to Statute or Regulation 225 | 226 | If it is impossible for You to comply with any of the terms of this License 227 | with respect to some or all of the Covered Software due to statute, 228 | judicial order, or regulation then You must: (a) comply with the terms of 229 | this License to the maximum extent possible; and (b) describe the 230 | limitations and the code they affect. Such description must be placed in a 231 | text file included with all distributions of the Covered Software under 232 | this License. Except to the extent prohibited by statute or regulation, 233 | such description must be sufficiently detailed for a recipient of ordinary 234 | skill to be able to understand it. 235 | 236 | 5. Termination 237 | 238 | 5.1. The rights granted under this License will terminate automatically if You 239 | fail to comply with any of its terms. However, if You become compliant, 240 | then the rights granted under this License from a particular Contributor 241 | are reinstated (a) provisionally, unless and until such Contributor 242 | explicitly and finally terminates Your grants, and (b) on an ongoing 243 | basis, if such Contributor fails to notify You of the non-compliance by 244 | some reasonable means prior to 60 days after You have come back into 245 | compliance. Moreover, Your grants from a particular Contributor are 246 | reinstated on an ongoing basis if such Contributor notifies You of the 247 | non-compliance by some reasonable means, this is the first time You have 248 | received notice of non-compliance with this License from such 249 | Contributor, and You become compliant prior to 30 days after Your receipt 250 | of the notice. 251 | 252 | 5.2. If You initiate litigation against any entity by asserting a patent 253 | infringement claim (excluding declaratory judgment actions, 254 | counter-claims, and cross-claims) alleging that a Contributor Version 255 | directly or indirectly infringes any patent, then the rights granted to 256 | You by any and all Contributors for the Covered Software under Section 257 | 2.1 of this License shall terminate. 258 | 259 | 5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user 260 | license agreements (excluding distributors and resellers) which have been 261 | validly granted by You or Your distributors under this License prior to 262 | termination shall survive termination. 263 | 264 | 6. Disclaimer of Warranty 265 | 266 | Covered Software is provided under this License on an "as is" basis, 267 | without warranty of any kind, either expressed, implied, or statutory, 268 | including, without limitation, warranties that the Covered Software is free 269 | of defects, merchantable, fit for a particular purpose or non-infringing. 270 | The entire risk as to the quality and performance of the Covered Software 271 | is with You. Should any Covered Software prove defective in any respect, 272 | You (not any Contributor) assume the cost of any necessary servicing, 273 | repair, or correction. This disclaimer of warranty constitutes an essential 274 | part of this License. No use of any Covered Software is authorized under 275 | this License except under this disclaimer. 276 | 277 | 7. Limitation of Liability 278 | 279 | Under no circumstances and under no legal theory, whether tort (including 280 | negligence), contract, or otherwise, shall any Contributor, or anyone who 281 | distributes Covered Software as permitted above, be liable to You for any 282 | direct, indirect, special, incidental, or consequential damages of any 283 | character including, without limitation, damages for lost profits, loss of 284 | goodwill, work stoppage, computer failure or malfunction, or any and all 285 | other commercial damages or losses, even if such party shall have been 286 | informed of the possibility of such damages. This limitation of liability 287 | shall not apply to liability for death or personal injury resulting from 288 | such party's negligence to the extent applicable law prohibits such 289 | limitation. Some jurisdictions do not allow the exclusion or limitation of 290 | incidental or consequential damages, so this exclusion and limitation may 291 | not apply to You. 292 | 293 | 8. Litigation 294 | 295 | Any litigation relating to this License may be brought only in the courts 296 | of a jurisdiction where the defendant maintains its principal place of 297 | business and such litigation shall be governed by laws of that 298 | jurisdiction, without reference to its conflict-of-law provisions. Nothing 299 | in this Section shall prevent a party's ability to bring cross-claims or 300 | counter-claims. 301 | 302 | 9. Miscellaneous 303 | 304 | This License represents the complete agreement concerning the subject 305 | matter hereof. If any provision of this License is held to be 306 | unenforceable, such provision shall be reformed only to the extent 307 | necessary to make it enforceable. Any law or regulation which provides that 308 | the language of a contract shall be construed against the drafter shall not 309 | be used to construe this License against a Contributor. 310 | 311 | 312 | 10. Versions of the License 313 | 314 | 10.1. New Versions 315 | 316 | Mozilla Foundation is the license steward. Except as provided in Section 317 | 10.3, no one other than the license steward has the right to modify or 318 | publish new versions of this License. Each version will be given a 319 | distinguishing version number. 320 | 321 | 10.2. Effect of New Versions 322 | 323 | You may distribute the Covered Software under the terms of the version 324 | of the License under which You originally received the Covered Software, 325 | or under the terms of any subsequent version published by the license 326 | steward. 327 | 328 | 10.3. Modified Versions 329 | 330 | If you create software not governed by this License, and you want to 331 | create a new license for such software, you may create and use a 332 | modified version of this License if you rename the license and remove 333 | any references to the name of the license steward (except to note that 334 | such modified license differs from this License). 335 | 336 | 10.4. Distributing Source Code Form that is Incompatible With Secondary 337 | Licenses If You choose to distribute Source Code Form that is 338 | Incompatible With Secondary Licenses under the terms of this version of 339 | the License, the notice described in Exhibit B of this License must be 340 | attached. 341 | 342 | Exhibit A - Source Code Form License Notice 343 | 344 | This Source Code Form is subject to the 345 | terms of the Mozilla Public License, v. 346 | 2.0. If a copy of the MPL was not 347 | distributed with this file, You can 348 | obtain one at 349 | http://mozilla.org/MPL/2.0/. 350 | 351 | If it is not possible or desirable to put the notice in a particular file, 352 | then You may include the notice in a location (such as a LICENSE file in a 353 | relevant directory) where a recipient would be likely to look for such a 354 | notice. 355 | 356 | You may add additional accurate notices of copyright ownership. 357 | 358 | Exhibit B - "Incompatible With Secondary Licenses" Notice 359 | 360 | This Source Code Form is "Incompatible 361 | With Secondary Licenses", as defined by 362 | the Mozilla Public License, v. 2.0. 363 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Khiva Ruby 2 | 3 | [Khiva](https://github.com/shapelets/khiva) - high-performance time series algorithms - for Ruby 4 | 5 | :fire: Runs on GPUs (even on Mac) and CPUs 6 | 7 | [![Build Status](https://github.com/ankane/khiva-ruby/actions/workflows/build.yml/badge.svg)](https://github.com/ankane/khiva-ruby/actions) 8 | 9 | ## Installation 10 | 11 | First, [install Khiva](#khiva-installation). For Homebrew, use: 12 | 13 | ```sh 14 | brew install khiva 15 | ``` 16 | 17 | Add this line to your application’s Gemfile: 18 | 19 | ```ruby 20 | gem "khiva" 21 | ``` 22 | 23 | ## Getting Started 24 | 25 | Calculate the [matrix profile](https://stumpy.readthedocs.io/en/latest/Tutorial_The_Matrix_Profile.html) between two time series 26 | 27 | ```ruby 28 | a = Khiva::Array.new([11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11], type: :f32) 29 | b = Khiva::Array.new([9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9], type: :f32) 30 | m = 3 # subsequence length 31 | profile, index = Khiva::Matrix.stomp(a, b, m) 32 | ``` 33 | 34 | Find motifs (repeated patterns) 35 | 36 | ```ruby 37 | n = 2 # number of motifs to extract 38 | distances, indices, subsequences = Khiva::Matrix.find_best_n_motifs(profile, index, m, n) 39 | ``` 40 | 41 | Find discords (anomalies) 42 | 43 | ```ruby 44 | n = 2 # number of discords to extract 45 | distances, indices, subsequences = Khiva::Matrix.find_best_n_discords(profile, index, m, n) 46 | ``` 47 | 48 | ## Examples 49 | 50 | - [Anomaly Detection](#anomaly-detection) 51 | - [Similarity Search](#similarity-search) 52 | 53 | ### Anomaly Detection 54 | 55 | Detect anomalies in a time series 56 | 57 | ```ruby 58 | # generate a random time series with anomalies from position 100-109 59 | series = 1000.times.map { |i| i >= 100 && i <= 109 ? 0.5 : rand } 60 | 61 | # calculate the matrix profile with subsequence length 10 62 | a = Khiva::Array.new(series, type: :f32) 63 | m = 10 64 | profile, index = Khiva::Matrix.stomp_self_join(a, m) 65 | 66 | # find and print the position of the most anomalous subsequence 67 | _, _, subsequences = Khiva::Matrix.find_best_n_discords(profile, index, m, 1) 68 | pos = subsequences.to_a.first 69 | p pos 70 | ``` 71 | 72 | Use [matplotlib.rb](https://github.com/mrkn/matplotlib.rb) for visualization 73 | 74 | ```ruby 75 | require "matplotlib/pyplot" 76 | plt = Matplotlib::Pyplot 77 | 78 | # series 79 | plt.figure(0) 80 | plt.title("Series") 81 | plt.plot(series) 82 | 83 | # matrix profile 84 | plt.figure(1) 85 | plt.title("Matrix Profile") 86 | plt.plot(profile.to_a) 87 | 88 | # most anomalous subsequence and its closest subsequence 89 | plt.figure(2) 90 | plt.title("Subsequences") 91 | plt.plot(series[pos, m], label: "Anomalous") 92 | plt.plot(series[index.to_a[pos], m], label: "Closest") 93 | plt.legend 94 | ``` 95 | 96 | ### Similarity Search 97 | 98 | Find a similar pattern in time series 99 | 100 | ```ruby 101 | series = [1, 1, 1, 3, 4, 1, 1, 1, 1] 102 | query = [1, 2, 3] 103 | 104 | s = Khiva::Array.new(series, type: :f32) 105 | q = Khiva::Array.new(query, type: :f32) 106 | _, indices = Khiva::Matrix.find_best_n_occurrences(q, s, 1) 107 | pos = indices.to_a.first 108 | similar_subsequence = series[pos, query.size] # [1, 3, 4] 109 | ``` 110 | 111 | ## Modules 112 | 113 | - [Array](#array) 114 | - [Clustering](#clustering) 115 | - [Dimensionality](#dimensionality) 116 | - [Distances](#distances) 117 | - [Features](#features) 118 | - [Library](#library) 119 | - [Linalg](#linalg) 120 | - [Matrix](#matrix) 121 | - [Normalization](#normalization) 122 | - [Polynomial](#polynomial) 123 | - [Regression](#regression) 124 | - [Regularization](#regularization) 125 | - [Statistics](#statistics) 126 | 127 | ## Array 128 | 129 | Create an array from a Ruby array 130 | 131 | ```ruby 132 | Khiva::Array.new([1, 2, 3]) 133 | ``` 134 | 135 | Specify the type - `:b8`, `:f32`, `:f64`, `:s16`, `:s32`, `:s64`, `:u8`, `:u16`, `:u32`, `:u64` 136 | 137 | ```ruby 138 | Khiva::Array.new([1, 2, 3], type: :s64) 139 | ``` 140 | 141 | Get the type and dimensions 142 | 143 | ```ruby 144 | a.type 145 | a.dims 146 | ``` 147 | 148 | Perform operations on arrays 149 | 150 | ```ruby 151 | a + b 152 | a - b 153 | a * b 154 | a / b 155 | a % b 156 | a ** b 157 | ``` 158 | 159 | Compare arrays 160 | 161 | ```ruby 162 | a.eq(b) 163 | a.ne(b) 164 | a.lt(b) 165 | a.gt(b) 166 | a.le(b) 167 | a.ge(b) 168 | ``` 169 | 170 | ## Clustering 171 | 172 | k-means algorithm 173 | 174 | ```ruby 175 | centroids, labels = Khiva::Clustering.k_means(tss, k) 176 | ``` 177 | 178 | k-Shape algorithm 179 | 180 | ```ruby 181 | centroids, labels = Khiva::Clustering.k_shape(tss, k) 182 | ``` 183 | 184 | ## Dimensionality 185 | 186 | Piecewise Aggregate Approximation (PAA) 187 | 188 | ```ruby 189 | Khiva::Dimensionality.paa(a, bins) 190 | ``` 191 | 192 | Perceptually Important Points (PIP) 193 | 194 | ```ruby 195 | Khiva::Dimensionality.pip(a, number_ips) 196 | ``` 197 | 198 | Piecewise Linear Approximation (PLA Bottom Up) 199 | 200 | ```ruby 201 | Khiva::Dimensionality.pla_bottom_up(a, max_error) 202 | ``` 203 | 204 | Piecewise Linear Approximation (PLA Sliding Window) 205 | 206 | ```ruby 207 | Khiva::Dimensionality.pla_sliding_window(a, max_error) 208 | ``` 209 | 210 | Ramer-Douglas-Peucker (RDP) 211 | 212 | ```ruby 213 | Khiva::Dimensionality.ramer_douglas_peucker(a, epsilon) 214 | ``` 215 | 216 | Symbolic Aggregate ApproXimation (SAX) 217 | 218 | ```ruby 219 | Khiva::Dimensionality.sax(a, alphabet_size) 220 | ``` 221 | 222 | Visvalingam 223 | 224 | ```ruby 225 | Khiva::Dimensionality.visvalingam(a, num_points) 226 | ``` 227 | 228 | ## Distances 229 | 230 | Dynamic time warping (DTW) distance 231 | 232 | ```ruby 233 | Khiva::Distances.dtw(tss) 234 | ``` 235 | 236 | Euclidean distance 237 | 238 | ```ruby 239 | Khiva::Distances.euclidean(tss) 240 | ``` 241 | 242 | Hamming distance 243 | 244 | ```ruby 245 | Khiva::Distances.hamming(tss) 246 | ``` 247 | 248 | Manhattan distance 249 | 250 | ```ruby 251 | Khiva::Distances.manhattan(tss) 252 | ``` 253 | 254 | Shape-based distance (SBD) 255 | 256 | ```ruby 257 | Khiva::Distances.sbd(tss) 258 | ``` 259 | 260 | Squared Euclidean distance 261 | 262 | ```ruby 263 | Khiva::Distances.squared_euclidean(tss) 264 | ``` 265 | 266 | ## Features 267 | 268 | Sum of square values 269 | 270 | ```ruby 271 | Khiva::Features.abs_energy(tss) 272 | ``` 273 | 274 | Absolute sum of changes 275 | 276 | ```ruby 277 | Khiva::Features.absolute_sum_of_changes(tss) 278 | ``` 279 | 280 | Aggregated autocorrelation 281 | 282 | ```ruby 283 | Khiva::Features.aggregated_autocorrelation(tss, aggregation_function) 284 | ``` 285 | 286 | Approximate entropy 287 | 288 | ```ruby 289 | Khiva::Features.approximate_entropy(tss, m, r) 290 | ``` 291 | 292 | Autocorrelation 293 | 294 | ```ruby 295 | Khiva::Features.auto_correlation(tss, max_lag, unbiased) 296 | ``` 297 | 298 | Auto-covariance 299 | 300 | ```ruby 301 | Khiva::Features.auto_covariance(tss, unbiased: false) 302 | ``` 303 | 304 | Binned entropy 305 | 306 | ```ruby 307 | Khiva::Features.binned_entropy(tss, max_bins) 308 | ``` 309 | 310 | Schreiber, T. and Schmitz, A. (1997) measure of non-linearity 311 | 312 | ```ruby 313 | Khiva::Features.c3(tss, lag) 314 | ``` 315 | 316 | Estimate of complexity defined by Batista, Gustavo EAPA, et al (2014) 317 | 318 | ```ruby 319 | Khiva::Features.cid_ce(tss, z_normalize) 320 | ``` 321 | 322 | Number of values above the mean 323 | 324 | ```ruby 325 | Khiva::Features.count_above_mean(tss) 326 | ``` 327 | 328 | Number of values below the mean 329 | 330 | ```ruby 331 | Khiva::Features.count_below_mean(tss) 332 | ``` 333 | 334 | Cross-correlation 335 | 336 | ```ruby 337 | Khiva::Features.cross_correlation(xss, yss, unbiased) 338 | ``` 339 | 340 | Cross-covariance 341 | 342 | ```ruby 343 | Khiva::Features.cross_covariance(xss, yss, unbiased) 344 | ``` 345 | 346 | Energy ratio by chunks 347 | 348 | ```ruby 349 | Khiva::Features.energy_ratio_by_chunks(arr, num_segments, segment_focus) 350 | ``` 351 | 352 | The spectral centroid (mean), variance, skew, and kurtosis of the absolute fourier transform spectrum 353 | 354 | ```ruby 355 | Khiva::Features.fft_aggregated(tss) 356 | ``` 357 | 358 | First location of the maximum value 359 | 360 | ```ruby 361 | Khiva::Features.first_location_of_maximum(tss) 362 | ``` 363 | 364 | First location of the minimum value 365 | 366 | ```ruby 367 | Khiva::Features.first_location_of_minimum(tss) 368 | ``` 369 | 370 | Maximum is duplicated 371 | 372 | ```ruby 373 | Khiva::Features.has_duplicate_max(tss) 374 | ``` 375 | 376 | Minimum is duplicated 377 | 378 | ```ruby 379 | Khiva::Features.has_duplicate_min(tss) 380 | ``` 381 | 382 | Any elements are duplicated 383 | 384 | ```ruby 385 | Khiva::Features.has_duplicates(tss) 386 | ``` 387 | 388 | Index of the mass quantile 389 | 390 | ```ruby 391 | Khiva::Features.index_mass_quantile(tss, q) 392 | ``` 393 | 394 | Kurtosis 395 | 396 | ```ruby 397 | Khiva::Features.kurtosis(tss) 398 | ``` 399 | 400 | Standard deviation above threshold 401 | 402 | ```ruby 403 | Khiva::Features.large_standard_deviation(tss, r) 404 | ``` 405 | 406 | Last location of the maximum value 407 | 408 | ```ruby 409 | Khiva::Features.last_location_of_maximum(tss) 410 | ``` 411 | 412 | Last location of the minimum value 413 | 414 | ```ruby 415 | Khiva::Features.last_location_of_minimum(tss) 416 | ``` 417 | 418 | Length of the series 419 | 420 | ```ruby 421 | Khiva::Features.length(tss) 422 | ``` 423 | 424 | Local maximals 425 | 426 | ```ruby 427 | Khiva::Features.local_maximals(tss) 428 | ``` 429 | 430 | Length of the longest consecutive subsequence above the mean 431 | 432 | ```ruby 433 | Khiva::Features.longest_strike_above_mean(tss) 434 | ``` 435 | 436 | Length of the longest consecutive subsequence below the mean 437 | 438 | ```ruby 439 | Khiva::Features.longest_strike_below_mean(tss) 440 | ``` 441 | 442 | Maximum 443 | 444 | ```ruby 445 | Khiva::Features.maximum(tss) 446 | ``` 447 | 448 | Mean 449 | 450 | ```ruby 451 | Khiva::Features.mean(tss) 452 | ``` 453 | 454 | Mean absolute change 455 | 456 | ```ruby 457 | Khiva::Features.mean_absolute_change(tss) 458 | ``` 459 | 460 | Mean change 461 | 462 | ```ruby 463 | Khiva::Features.mean_change(tss) 464 | ``` 465 | 466 | Mean of a central approximation of the second derivative 467 | 468 | ```ruby 469 | Khiva::Features.mean_second_derivative_central(tss) 470 | ``` 471 | 472 | Median 473 | 474 | ```ruby 475 | Khiva::Features.median(tss) 476 | ``` 477 | 478 | Minimum 479 | 480 | ```ruby 481 | Khiva::Features.minimum(tss) 482 | ``` 483 | 484 | Number of m-crossings 485 | 486 | ```ruby 487 | Khiva::Features.number_crossing_m(tss, m) 488 | ``` 489 | 490 | Number of peaks of at least support `n` 491 | 492 | ```ruby 493 | Khiva::Features.number_peaks(tss, n) 494 | ``` 495 | 496 | Partial autocorrelation 497 | 498 | ```ruby 499 | Khiva::Features.partial_autocorrelation(tss, lags) 500 | ``` 501 | 502 | Percentage of unique values present more than once 503 | 504 | ```ruby 505 | Khiva::Features.percentage_of_reoccurring_datapoints_to_all_datapoints(tss, sorted) 506 | ``` 507 | 508 | Percentage of values present more than once 509 | 510 | ```ruby 511 | Khiva::Features.percentage_of_reoccurring_values_to_all_values(tss, sorted) 512 | ``` 513 | 514 | Quantile 515 | 516 | ```ruby 517 | Khiva::Features.quantile(tss, q, precision: 100000000) 518 | ``` 519 | 520 | Count of values within the interval [min, max] 521 | 522 | ```ruby 523 | Khiva::Features.range_count(tss, min, max) 524 | ``` 525 | 526 | Ratio of values more than `r` sigma away from the mean 527 | 528 | ```ruby 529 | Khiva::Features.ratio_beyond_r_sigma(tss, coeff) 530 | ``` 531 | 532 | Ratio of unique values 533 | 534 | ```ruby 535 | Khiva::Features.ratio_value_number_to_time_series_length(tss) 536 | ``` 537 | 538 | Sample entropy 539 | 540 | ```ruby 541 | Khiva::Features.sample_entropy(tss) 542 | ``` 543 | 544 | Skewness 545 | 546 | ```ruby 547 | Khiva::Features.skewness(tss) 548 | ``` 549 | 550 | Cross power spectral density at different frequencies 551 | 552 | ```ruby 553 | Khiva::Features.spkt_welch_density(tss, coeff) 554 | ``` 555 | 556 | Standard deviation 557 | 558 | ```ruby 559 | Khiva::Features.standard_deviation(tss) 560 | ``` 561 | 562 | Sum of all data points present more than once 563 | 564 | ```ruby 565 | Khiva::Features.sum_of_reoccurring_datapoints(tss, sorted: false) 566 | ``` 567 | 568 | Sum of all values present more than once 569 | 570 | ```ruby 571 | Khiva::Features.sum_of_reoccurring_values(tss, sorted: false) 572 | ``` 573 | 574 | Sum of values 575 | 576 | ```ruby 577 | Khiva::Features.sum_values(tss) 578 | ``` 579 | 580 | If looks symmetric 581 | 582 | ```ruby 583 | Khiva::Features.symmetry_looking(tss, r) 584 | ``` 585 | 586 | Time reversal asymmetry 587 | 588 | ```ruby 589 | Khiva::Features.time_reversal_asymmetry_statistic(tss, lag) 590 | ``` 591 | 592 | Number of occurrences of a value 593 | 594 | ```ruby 595 | Khiva::Features.value_count(tss, v) 596 | ``` 597 | 598 | Variance 599 | 600 | ```ruby 601 | Khiva::Features.variance(tss) 602 | ``` 603 | 604 | If variance is larger than one 605 | 606 | ```ruby 607 | Khiva::Features.variance_larger_than_standard_deviation(tss) 608 | ``` 609 | 610 | ## Library 611 | 612 | Get backend info 613 | 614 | ```ruby 615 | Khiva::Library.backend_info 616 | ``` 617 | 618 | Get current backend 619 | 620 | ```ruby 621 | Khiva::Library.backend 622 | ``` 623 | 624 | Get available backends 625 | 626 | ```ruby 627 | Khiva::Library.backends 628 | ``` 629 | 630 | Set backend - `:default`, `:cpu`, `:cuda`, `:opencl` 631 | 632 | ```ruby 633 | Khiva::Library.set_backend(:cpu) 634 | ``` 635 | 636 | Set device 637 | 638 | ```ruby 639 | Khiva::Library.set_device(device_id) 640 | ``` 641 | 642 | Get device id 643 | 644 | ```ruby 645 | Khiva::Library.device_id 646 | ``` 647 | 648 | Get device count 649 | 650 | ```ruby 651 | Khiva::Library.device_count 652 | ``` 653 | 654 | Set device memory in GB 655 | 656 | ```ruby 657 | Khiva::Library.set_device_memory_in_gb(1.5) 658 | ``` 659 | 660 | Get version 661 | 662 | ```ruby 663 | Khiva::Library.version 664 | ``` 665 | 666 | ## Linalg 667 | 668 | ```ruby 669 | Khiva::Linalg.lls(a, b) 670 | ``` 671 | 672 | ## Matrix 673 | 674 | Find discords 675 | 676 | ```ruby 677 | distances, indices, subsequences = Khiva::Matrix.find_best_n_discords(profile, index, m, n) 678 | ``` 679 | 680 | Find motifs 681 | 682 | ```ruby 683 | distances, indices, subsequences = Khiva::Matrix.find_best_n_motifs(profile, index, m, n) 684 | ``` 685 | 686 | Find best occurences 687 | 688 | ```ruby 689 | distances, indices = Khiva::Matrix.find_best_n_occurrences(q, t, n) 690 | ``` 691 | 692 | Mueen’s Algorithm for Similarity Search (MASS) 693 | 694 | ```ruby 695 | distances = Khiva::Matrix.mass(q, t) 696 | ``` 697 | 698 | Calculate the matrix profile between `ta` and `tb` using a subsequence length of `m` with the STOMP algorithm 699 | 700 | ```ruby 701 | profile, index = Khiva::Matrix.stomp(ta, tb, m) 702 | ``` 703 | 704 | Calculate the matrix profile between `t` and itself using a subsequence length of `m` with the STOMP algorithm 705 | 706 | ```ruby 707 | profile, index = Khiva::Matrix.stomp_self_join(t, m) 708 | ``` 709 | 710 | Calculate the matrix profile between `ta` and `tb` using a subsequence length of `m` 711 | 712 | ```ruby 713 | profile, index = Khiva::Matrix.matrix_profile(ta, tb, m) 714 | ``` 715 | 716 | Calculate the matrix profile between `t` and itself using a subsequence length of `m` 717 | 718 | ```ruby 719 | profile, index = Khiva::Matrix.matrix_profile_self_join(t, m) 720 | ``` 721 | 722 | Get chains 723 | 724 | ```ruby 725 | Khiva::Matrix.chains(tss, m) 726 | ``` 727 | 728 | ## Normalization 729 | 730 | Decimal scaling 731 | 732 | ```ruby 733 | Khiva::Normalization.decimal_scaling_norm(tss) 734 | Khiva::Normalization.decimal_scaling_norm!(tss) 735 | ``` 736 | 737 | Max min 738 | 739 | ```ruby 740 | Khiva::Normalization.max_min_norm(tss) 741 | Khiva::Normalization.max_min_norm!(tss) 742 | ``` 743 | 744 | Mean 745 | 746 | ```ruby 747 | Khiva::Normalization.mean_norm(tss) 748 | Khiva::Normalization.mean_norm!(tss) 749 | ``` 750 | 751 | Znorm 752 | 753 | ```ruby 754 | Khiva::Normalization.znorm(tss) 755 | Khiva::Normalization.znorm!(tss) 756 | ``` 757 | 758 | ## Polynomial 759 | 760 | Least squares polynomial fit 761 | 762 | ```ruby 763 | Khiva::Polynomial.polyfit(x, y, deg) 764 | ``` 765 | 766 | ## Regression 767 | 768 | Linear least squares regression 769 | 770 | ```ruby 771 | slope, intercept, rvalue, pvalue, stderrest = Khiva::Regression.linear(xss, yss) 772 | ``` 773 | 774 | ## Regularization 775 | 776 | ```ruby 777 | Khiva::Regularization.group_by(tss, aggregation_function, columns_key: 1, n_columns_value: 1) 778 | ``` 779 | 780 | ## Statistics 781 | 782 | Covariance 783 | 784 | ```ruby 785 | Khiva::Statistics.covariance(tss, unbiased: false) 786 | ``` 787 | 788 | Kurtosis 789 | 790 | ```ruby 791 | Khiva::Statistics.kurtosis(tss) 792 | ``` 793 | 794 | Ljung-Box 795 | 796 | ```ruby 797 | Khiva::Statistics.ljung_box(tss, lags) 798 | ``` 799 | 800 | Moment 801 | 802 | ```ruby 803 | Khiva::Statistics.moment(tss, k) 804 | ``` 805 | 806 | Quantile 807 | 808 | ```ruby 809 | Khiva::Statistics.quantile(tss, q, precision: 1e-8) 810 | ``` 811 | 812 | Quantiles cut 813 | 814 | ```ruby 815 | Khiva::Statistics.quantiles_cut(tss, quantiles, precision: 1e-8) 816 | ``` 817 | 818 | Standard deviation 819 | 820 | ```ruby 821 | Khiva::Statistics.sample_stdev(tss) 822 | ``` 823 | 824 | Skewness 825 | 826 | ```ruby 827 | Khiva::Statistics.skewness(tss) 828 | ``` 829 | 830 | ## Khiva Installation 831 | 832 | ### Linux - Ubuntu 833 | 834 | Install ArrayFire: 835 | 836 | ```sh 837 | sudo apt-key adv --fetch-key https://repo.arrayfire.com/GPG-PUB-KEY-ARRAYFIRE-2020.PUB 838 | echo "deb [arch=amd64] https://repo.arrayfire.com/debian all main" | sudo tee /etc/apt/sources.list.d/arrayfire.list 839 | sudo apt-get update 840 | sudo apt-get install arrayfire-unified3 arrayfire-cpu3-openblas arrayfire-opencl3-openblas 841 | ``` 842 | 843 | And install Khiva: 844 | 845 | ```sh 846 | wget https://github.com/shapelets/khiva/releases/download/v0.5.0/khiva-khiva_0.5.0_amd64.deb 847 | sudo dpkg -i khiva-khiva_0.5.0_amd64.deb 848 | sudo ldconfig 849 | ``` 850 | 851 | ### Linux - Other 852 | 853 | See [instructions](https://khiva.readthedocs.io/en/latest/gettingStarted.html). 854 | 855 | ### Mac 856 | 857 | Run: 858 | 859 | ```sh 860 | brew install khiva 861 | ``` 862 | 863 | ### Windows 864 | 865 | See [instructions](https://khiva.readthedocs.io/en/latest/gettingStarted.html). 866 | 867 | ## Credits 868 | 869 | This library is modeled after the [Khiva-Python API](https://github.com/shapelets/khiva-python). 870 | 871 | ## History 872 | 873 | View the [changelog](https://github.com/ankane/khiva-ruby/blob/master/CHANGELOG.md) 874 | 875 | ## Contributing 876 | 877 | Everyone is encouraged to help improve this project. Here are a few ways you can help: 878 | 879 | - [Report bugs](https://github.com/ankane/khiva-ruby/issues) 880 | - Fix bugs and [submit pull requests](https://github.com/ankane/khiva-ruby/pulls) 881 | - Write, clarify, or fix documentation 882 | - Suggest or add new features 883 | 884 | To get started with development: 885 | 886 | ```sh 887 | git clone https://github.com/ankane/khiva-ruby.git 888 | cd khiva-ruby 889 | bundle install 890 | bundle exec rake test 891 | ``` 892 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | require "rake/testtask" 3 | 4 | Rake::TestTask.new(:test) do |t| 5 | t.libs << "test" 6 | t.test_files = FileList["test/**/*_test.rb"] 7 | end 8 | 9 | task default: :test 10 | -------------------------------------------------------------------------------- /khiva.gemspec: -------------------------------------------------------------------------------- 1 | require_relative "lib/khiva/version" 2 | 3 | Gem::Specification.new do |spec| 4 | spec.name = "khiva" 5 | spec.version = Khiva::VERSION 6 | spec.summary = "High-performance time series algorithms for Ruby" 7 | spec.homepage = "https://github.com/ankane/khiva-ruby" 8 | spec.license = "MPL-2.0" 9 | 10 | spec.author = "Andrew Kane" 11 | spec.email = "andrew@ankane.org" 12 | 13 | spec.files = Dir["*.{md,txt}", "{lib}/**/*"] 14 | spec.require_path = "lib" 15 | 16 | spec.required_ruby_version = ">= 3.1" 17 | 18 | spec.add_dependency "fiddle" 19 | end 20 | -------------------------------------------------------------------------------- /lib/khiva.rb: -------------------------------------------------------------------------------- 1 | # stdlib 2 | require "fiddle/import" 3 | 4 | # modules 5 | require_relative "khiva/array" 6 | require_relative "khiva/clustering" 7 | require_relative "khiva/dimensionality" 8 | require_relative "khiva/distances" 9 | require_relative "khiva/features" 10 | require_relative "khiva/library" 11 | require_relative "khiva/linalg" 12 | require_relative "khiva/matrix" 13 | require_relative "khiva/normalization" 14 | require_relative "khiva/polynomial" 15 | require_relative "khiva/regression" 16 | require_relative "khiva/regularization" 17 | require_relative "khiva/statistics" 18 | require_relative "khiva/utils" 19 | require_relative "khiva/version" 20 | 21 | module Khiva 22 | class Error < StandardError; end 23 | 24 | class << self 25 | attr_accessor :ffi_lib 26 | end 27 | self.ffi_lib = 28 | if Gem.win_platform? 29 | ["khiva_c.dll"] 30 | elsif RbConfig::CONFIG["host_os"] =~ /darwin/i 31 | if RbConfig::CONFIG["host_cpu"] =~ /arm|aarch64/i 32 | ["libkhiva_c.dylib", "/opt/homebrew/lib/libkhiva_c.dylib"] 33 | else 34 | ["libkhiva_c.dylib"] 35 | end 36 | else 37 | ["libkhiva_c.so"] 38 | end 39 | 40 | # friendlier error message 41 | autoload :FFI, "khiva/ffi" 42 | 43 | def self.lib_version 44 | Library.version 45 | end 46 | end 47 | -------------------------------------------------------------------------------- /lib/khiva/array.rb: -------------------------------------------------------------------------------- 1 | module Khiva 2 | class Array 3 | TYPES = [:f32, :c32, :f64, :c64, :b8, :s32, :u32, :u8, :s64, :u64, :s16, :u16] 4 | # TODO support complex 5 | TYPE_FORMAT = { 6 | f32: "f", 7 | c32: "", 8 | f64: "d", 9 | c64: "", 10 | b8: "c", 11 | s32: "l", 12 | u32: "L", 13 | u8: "C", 14 | s64: "q", 15 | u64: "Q", 16 | s16: "s", 17 | u16: "S" 18 | } 19 | 20 | def initialize(obj, type: nil) 21 | if obj.is_a?(Fiddle::Pointer) 22 | @ptr = obj 23 | else 24 | # TODO make more performant for Numo 25 | obj = obj.to_a 26 | dims = [] 27 | o = obj 28 | 4.times do 29 | break unless o.is_a?(::Array) 30 | dims << o.size 31 | o = o.first 32 | end 33 | dims.reverse! 34 | 35 | flat_obj = obj.flatten(dims.size) 36 | 37 | # TODO check each dimension 38 | expected_size = dims.inject(1, &:*) 39 | raise Error, "Unexpected size" if flat_obj.size != expected_size 40 | 41 | # TODO check integer range 42 | type ||= flat_obj.all? { |v| v.is_a?(Integer) } ? :s64 : :f64 43 | 44 | data = Fiddle::Pointer[flat_obj.pack("#{TYPE_FORMAT[type]}*")] 45 | ndims = dims.size 46 | dims = Fiddle::Pointer[dims.pack("q!*")] 47 | @ptr = Fiddle::Pointer.malloc(Fiddle::SIZEOF_VOIDP) 48 | FFI.call(:create_array, data, ndims, dims, @ptr, TYPES.index(type)) 49 | ObjectSpace.define_finalizer(@ptr, self.class.finalize(@ptr.to_i)) 50 | end 51 | end 52 | 53 | def display 54 | FFI.call(:display, @ptr) 55 | end 56 | 57 | # TODO add bit operations 58 | [ 59 | [:+, :khiva_add], 60 | [:-, :khiva_sub], 61 | [:*, :khiva_mul], 62 | [:/, :khiva_div], 63 | [:%, :khiva_mod], 64 | [:**, :khiva_pow], 65 | [:lt, :khiva_lt], 66 | [:gt, :khiva_gt], 67 | [:le, :khiva_le], 68 | [:ge, :khiva_ge], 69 | [:eq, :khiva_eq], 70 | [:ne, :khiva_ne] 71 | ].each do |ruby_method, ffi_method| 72 | define_method(ruby_method) do |other| 73 | result = Utils.create_ptr 74 | FFI.call(ffi_method, @ptr, other, result) 75 | self.class.new(result) 76 | end 77 | end 78 | 79 | def to_a 80 | d = dims 81 | d.pop while d.last == 1 && d.size > 1 82 | d.reverse! 83 | 84 | elements = dims.inject(1, &:*) 85 | data = Fiddle::Pointer.malloc(elements * element_size) 86 | FFI.call(:get_data, @ptr, data) 87 | result = data.to_s(data.size).unpack("#{TYPE_FORMAT[type]}*") 88 | result.map! { |r| r > 0 ? true : false } if type == :b8 89 | Utils.reshape(result, d) 90 | end 91 | 92 | def dims 93 | dims = Fiddle::Pointer.malloc(Fiddle::SIZEOF_LONG_LONG * 4) 94 | FFI.call(:get_dims, @ptr, dims) 95 | dims.to_s(dims.size).unpack("q!*") 96 | end 97 | 98 | def type 99 | type = Fiddle::Pointer.malloc(Fiddle::SIZEOF_INT) 100 | FFI.call(:get_type, @ptr, type) 101 | TYPES[type.to_s(type.size).unpack1("i")] 102 | end 103 | 104 | def to_ptr 105 | @ptr 106 | end 107 | 108 | def element_size 109 | case type 110 | when :b8, :u8 111 | 1 112 | when :s16, :u16 113 | 2 114 | when :f32, :c32, :s32, :u32 115 | 4 116 | when :f64, :c64, :s64, :u64 117 | 8 118 | else 119 | raise Error, "Unknown type: #{type}" 120 | end 121 | end 122 | 123 | def copy 124 | result = Utils.create_ptr 125 | FFI.call(:copy, @ptr, result) 126 | self.class.new(result) 127 | end 128 | alias_method :dup, :copy 129 | alias_method :clone, :copy 130 | 131 | def self.finalize(addr) 132 | # must use proc instead of stabby lambda 133 | proc { FFI.call(:delete_array, addr) } 134 | end 135 | end 136 | end 137 | -------------------------------------------------------------------------------- /lib/khiva/clustering.rb: -------------------------------------------------------------------------------- 1 | module Khiva 2 | module Clustering 3 | class << self 4 | def k_means(tss, k, tolerance: 1e-10, max_iterations: 100) 5 | centroids = Utils.create_ptr 6 | labels = Utils.create_ptr 7 | FFI.call(:k_means, tss, Utils.int_ptr(k), centroids, labels, Utils.float_ptr(tolerance), Utils.int_ptr(max_iterations)) 8 | [Array.new(centroids), Array.new(labels)] 9 | end 10 | 11 | def k_shape(tss, k, tolerance: 1e-10, max_iterations: 100) 12 | centroids = Utils.create_ptr 13 | labels = Utils.create_ptr 14 | FFI.call(:k_shape, tss, Utils.int_ptr(k), centroids, labels, Utils.float_ptr(tolerance), Utils.int_ptr(max_iterations)) 15 | [Array.new(centroids), Array.new(labels)] 16 | end 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /lib/khiva/dimensionality.rb: -------------------------------------------------------------------------------- 1 | module Khiva 2 | module Dimensionality 3 | class << self 4 | def paa(a, bins) 5 | result = Utils.create_ptr 6 | FFI.call(:paa, a, Utils.int_ptr(bins), result) 7 | Array.new(result) 8 | end 9 | 10 | def pip(a, number_ips) 11 | result = Utils.create_ptr 12 | FFI.call(:pip, a, Utils.int_ptr(number_ips), result) 13 | Array.new(result) 14 | end 15 | 16 | def pla_bottom_up(a, max_error) 17 | result = Utils.create_ptr 18 | FFI.call(:pla_bottom_up, a, Utils.float_ptr(max_error), result) 19 | Array.new(result) 20 | end 21 | 22 | def pla_sliding_window(a, max_error) 23 | result = Utils.create_ptr 24 | FFI.call(:pla_sliding_window, a, Utils.float_ptr(max_error), result) 25 | Array.new(result) 26 | end 27 | 28 | def ramer_douglas_peucker(a, epsilon) 29 | result = Utils.create_ptr 30 | FFI.call(:ramer_douglas_peucker, a, Utils.double_ptr(epsilon), result) 31 | Array.new(result) 32 | end 33 | 34 | def sax(a, alphabet_size) 35 | result = Utils.create_ptr 36 | FFI.call(:sax, a, Utils.int_ptr(alphabet_size), result) 37 | Array.new(result) 38 | end 39 | 40 | def visvalingam(a, num_points) 41 | result = Utils.create_ptr 42 | FFI.call(:visvalingam, a, Utils.int_ptr(num_points), result) 43 | Array.new(result) 44 | end 45 | end 46 | end 47 | end 48 | -------------------------------------------------------------------------------- /lib/khiva/distances.rb: -------------------------------------------------------------------------------- 1 | module Khiva 2 | module Distances 3 | class << self 4 | def dtw(tss) 5 | result = Utils.create_ptr 6 | FFI.call(:dtw, tss, result) 7 | Array.new(result) 8 | end 9 | 10 | def euclidean(tss) 11 | result = Utils.create_ptr 12 | FFI.call(:euclidean, tss, result) 13 | Array.new(result) 14 | end 15 | 16 | def hamming(tss) 17 | result = Utils.create_ptr 18 | FFI.call(:hamming, tss, result) 19 | Array.new(result) 20 | end 21 | 22 | def manhattan(tss) 23 | result = Utils.create_ptr 24 | FFI.call(:manhattan, tss, result) 25 | Array.new(result) 26 | end 27 | 28 | def sbd(tss) 29 | result = Utils.create_ptr 30 | FFI.call(:sbd, tss, result) 31 | Array.new(result) 32 | end 33 | 34 | def squared_euclidean(tss) 35 | result = Utils.create_ptr 36 | FFI.call(:squared_euclidean, tss, result) 37 | Array.new(result) 38 | end 39 | end 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /lib/khiva/features.rb: -------------------------------------------------------------------------------- 1 | module Khiva 2 | module Features 3 | class << self 4 | def abs_energy(arr) 5 | result = Utils.create_ptr 6 | FFI.call(:abs_energy, arr, result) 7 | Array.new(result) 8 | end 9 | 10 | def absolute_sum_of_changes(arr) 11 | result = Utils.create_ptr 12 | FFI.call(:absolute_sum_of_changes, arr, result) 13 | Array.new(result) 14 | end 15 | 16 | def aggregated_autocorrelation(arr, aggregation_function) 17 | result = Utils.create_ptr 18 | FFI.call(:aggregated_autocorrelation, arr, Utils.int_ptr(aggregation_function), result) 19 | Array.new(result) 20 | end 21 | 22 | # TODO aggregated_linear_trend 23 | 24 | def approximate_entropy(arr, m, r) 25 | result = Utils.create_ptr 26 | FFI.call(:approximate_entropy, arr, Utils.int_ptr(m), Utils.float_ptr(r), result) 27 | Array.new(result) 28 | end 29 | 30 | def auto_correlation(arr, max_lag, unbiased) 31 | result = Utils.create_ptr 32 | FFI.call(:auto_correlation, arr, Utils.long_ptr(max_lag), Utils.bool_ptr(unbiased), result) 33 | Array.new(result) 34 | end 35 | 36 | def auto_covariance(arr, unbiased: false) 37 | result = Utils.create_ptr 38 | FFI.call(:auto_covariance, arr, Utils.bool_ptr(unbiased), result) 39 | Array.new(result) 40 | end 41 | 42 | def binned_entropy(arr, max_bins) 43 | result = Utils.create_ptr 44 | FFI.call(:binned_entropy, arr, Utils.int_ptr(max_bins), result) 45 | Array.new(result) 46 | end 47 | 48 | def c3(arr, lag) 49 | result = Utils.create_ptr 50 | FFI.call(:c3, arr, Utils.long_ptr(lag), result) 51 | Array.new(result) 52 | end 53 | 54 | def cid_ce(arr, z_normalize) 55 | result = Utils.create_ptr 56 | FFI.call(:cid_ce, arr, Utils.bool_ptr(z_normalize), result) 57 | Array.new(result) 58 | end 59 | 60 | def count_above_mean(arr) 61 | result = Utils.create_ptr 62 | FFI.call(:count_above_mean, arr, result) 63 | Array.new(result) 64 | end 65 | 66 | def count_below_mean(arr) 67 | result = Utils.create_ptr 68 | FFI.call(:count_below_mean, arr, result) 69 | Array.new(result) 70 | end 71 | 72 | def cross_correlation(xss, yss, unbiased) 73 | result = Utils.create_ptr 74 | FFI.call(:cross_correlation, xss, yss, Utils.bool_ptr(unbiased), result) 75 | Array.new(result) 76 | end 77 | 78 | def cross_covariance(xss, yss, unbiased) 79 | result = Utils.create_ptr 80 | FFI.call(:cross_covariance, xss, yss, Utils.bool_ptr(unbiased), result) 81 | Array.new(result) 82 | end 83 | 84 | # TODO cwt_coefficients 85 | 86 | def energy_ratio_by_chunks(arr, num_segments, segment_focus) 87 | result = Utils.create_ptr 88 | FFI.call(:energy_ratio_by_chunks, arr, Utils.long_ptr(num_segments), Utils.long_ptr(segment_focus), result) 89 | Array.new(result) 90 | end 91 | 92 | def fft_aggregated(arr) 93 | result = Utils.create_ptr 94 | FFI.call(:fft_aggregated, arr, result) 95 | Array.new(result) 96 | end 97 | 98 | # TODO fft_coefficient 99 | 100 | def first_location_of_maximum(arr) 101 | result = Utils.create_ptr 102 | FFI.call(:first_location_of_maximum, arr, result) 103 | Array.new(result) 104 | end 105 | 106 | def first_location_of_minimum(arr) 107 | result = Utils.create_ptr 108 | FFI.call(:first_location_of_minimum, arr, result) 109 | Array.new(result) 110 | end 111 | 112 | def has_duplicate_max(arr) 113 | result = Utils.create_ptr 114 | FFI.call(:has_duplicate_max, arr, result) 115 | Array.new(result) 116 | end 117 | 118 | def has_duplicate_min(arr) 119 | result = Utils.create_ptr 120 | FFI.call(:has_duplicate_min, arr, result) 121 | Array.new(result) 122 | end 123 | 124 | def has_duplicates(arr) 125 | result = Utils.create_ptr 126 | FFI.call(:has_duplicates, arr, result) 127 | Array.new(result) 128 | end 129 | 130 | def index_mass_quantile(arr, q) 131 | result = Utils.create_ptr 132 | FFI.call(:index_mass_quantile, arr, Utils.float_ptr(q), result) 133 | Array.new(result) 134 | end 135 | 136 | def kurtosis(arr) 137 | result = Utils.create_ptr 138 | FFI.call(:kurtosis, arr, result) 139 | Array.new(result) 140 | end 141 | 142 | def large_standard_deviation(arr, r) 143 | result = Utils.create_ptr 144 | FFI.call(:large_standard_deviation, arr, Utils.float_ptr(r), result) 145 | Array.new(result) 146 | end 147 | 148 | def last_location_of_maximum(arr) 149 | result = Utils.create_ptr 150 | FFI.call(:last_location_of_maximum, arr, result) 151 | Array.new(result) 152 | end 153 | 154 | def last_location_of_minimum(arr) 155 | result = Utils.create_ptr 156 | FFI.call(:last_location_of_minimum, arr, result) 157 | Array.new(result) 158 | end 159 | 160 | def length(arr) 161 | result = Utils.create_ptr 162 | FFI.call(:length, arr, result) 163 | Array.new(result) 164 | end 165 | 166 | def local_maximals(arr) 167 | result = Utils.create_ptr 168 | FFI.call(:local_maximals, arr, result) 169 | Array.new(result) 170 | end 171 | 172 | def longest_strike_above_mean(arr) 173 | result = Utils.create_ptr 174 | FFI.call(:longest_strike_above_mean, arr, result) 175 | Array.new(result) 176 | end 177 | 178 | def longest_strike_below_mean(arr) 179 | result = Utils.create_ptr 180 | FFI.call(:longest_strike_below_mean, arr, result) 181 | Array.new(result) 182 | end 183 | 184 | def maximum(arr) 185 | result = Utils.create_ptr 186 | FFI.call(:maximum, arr, result) 187 | Array.new(result) 188 | end 189 | 190 | def mean(arr) 191 | result = Utils.create_ptr 192 | FFI.call(:mean, arr, result) 193 | Array.new(result) 194 | end 195 | 196 | def mean_absolute_change(arr) 197 | result = Utils.create_ptr 198 | FFI.call(:mean_absolute_change, arr, result) 199 | Array.new(result) 200 | end 201 | 202 | def mean_change(arr) 203 | result = Utils.create_ptr 204 | FFI.call(:mean_change, arr, result) 205 | Array.new(result) 206 | end 207 | 208 | def mean_second_derivative_central(arr) 209 | result = Utils.create_ptr 210 | FFI.call(:mean_second_derivative_central, arr, result) 211 | Array.new(result) 212 | end 213 | 214 | def median(arr) 215 | result = Utils.create_ptr 216 | FFI.call(:median, arr, result) 217 | Array.new(result) 218 | end 219 | 220 | def minimum(arr) 221 | result = Utils.create_ptr 222 | FFI.call(:minimum, arr, result) 223 | Array.new(result) 224 | end 225 | 226 | def number_crossing_m(arr, m) 227 | result = Utils.create_ptr 228 | FFI.call(:number_crossing_m, arr, Utils.int_ptr(m), result) 229 | Array.new(result) 230 | end 231 | 232 | # TODO number_cwt_peaks 233 | 234 | def number_peaks(arr, n) 235 | result = Utils.create_ptr 236 | FFI.call(:number_peaks, arr, Utils.int_ptr(n), result) 237 | Array.new(result) 238 | end 239 | 240 | def partial_autocorrelation(arr, lags) 241 | result = Utils.create_ptr 242 | FFI.call(:partial_autocorrelation, arr, lags, result) 243 | Array.new(result) 244 | end 245 | 246 | def percentage_of_reoccurring_datapoints_to_all_datapoints(arr, sorted) 247 | result = Utils.create_ptr 248 | FFI.call(:percentage_of_reoccurring_datapoints_to_all_datapoints, arr, Utils.bool_ptr(sorted), result) 249 | Array.new(result) 250 | end 251 | 252 | def percentage_of_reoccurring_values_to_all_values(arr, sorted) 253 | result = Utils.create_ptr 254 | FFI.call(:percentage_of_reoccurring_values_to_all_values, arr, Utils.bool_ptr(sorted), result) 255 | Array.new(result) 256 | end 257 | 258 | def quantile(arr, q, precision: 100000000) 259 | result = Utils.create_ptr 260 | FFI.call(:quantile, arr, q, Utils.float_ptr(precision), result) 261 | Array.new(result) 262 | end 263 | 264 | def range_count(arr, min, max) 265 | result = Utils.create_ptr 266 | FFI.call(:range_count, arr, Utils.float_ptr(min), Utils.float_ptr(max), result) 267 | Array.new(result) 268 | end 269 | 270 | def ratio_beyond_r_sigma(arr, r) 271 | result = Utils.create_ptr 272 | FFI.call(:ratio_beyond_r_sigma, arr, Utils.float_ptr(r), result) 273 | Array.new(result) 274 | end 275 | 276 | def ratio_value_number_to_time_series_length(arr) 277 | result = Utils.create_ptr 278 | FFI.call(:ratio_value_number_to_time_series_length, arr, result) 279 | Array.new(result) 280 | end 281 | 282 | def sample_entropy(arr) 283 | result = Utils.create_ptr 284 | FFI.call(:sample_entropy, arr, result) 285 | Array.new(result) 286 | end 287 | 288 | def skewness(arr) 289 | result = Utils.create_ptr 290 | FFI.call(:skewness, arr, result) 291 | Array.new(result) 292 | end 293 | 294 | def spkt_welch_density(arr, coeff) 295 | result = Utils.create_ptr 296 | FFI.call(:spkt_welch_density, arr, Utils.int_ptr(coeff), result) 297 | Array.new(result) 298 | end 299 | 300 | def standard_deviation(arr) 301 | result = Utils.create_ptr 302 | FFI.call(:standard_deviation, arr, result) 303 | Array.new(result) 304 | end 305 | 306 | def sum_of_reoccurring_datapoints(arr, sorted: false) 307 | result = Utils.create_ptr 308 | FFI.call(:sum_of_reoccurring_datapoints, arr, Utils.bool_ptr(sorted), result) 309 | Array.new(result) 310 | end 311 | 312 | def sum_of_reoccurring_values(arr, sorted: false) 313 | result = Utils.create_ptr 314 | FFI.call(:sum_of_reoccurring_values, arr, Utils.bool_ptr(sorted), result) 315 | Array.new(result) 316 | end 317 | 318 | def sum_values(arr) 319 | result = Utils.create_ptr 320 | FFI.call(:sum_values, arr, result) 321 | Array.new(result) 322 | end 323 | 324 | def symmetry_looking(arr, r) 325 | result = Utils.create_ptr 326 | FFI.call(:symmetry_looking, arr, Utils.float_ptr(r), result) 327 | Array.new(result) 328 | end 329 | 330 | def time_reversal_asymmetry_statistic(arr, lag) 331 | result = Utils.create_ptr 332 | FFI.call(:time_reversal_asymmetry_statistic, arr, Utils.int_ptr(lag), result) 333 | Array.new(result) 334 | end 335 | 336 | def value_count(arr, v) 337 | result = Utils.create_ptr 338 | FFI.call(:value_count, arr, Utils.float_ptr(v), result) 339 | Array.new(result) 340 | end 341 | 342 | def variance(arr) 343 | result = Utils.create_ptr 344 | FFI.call(:variance, arr, result) 345 | Array.new(result) 346 | end 347 | 348 | def variance_larger_than_standard_deviation(arr) 349 | result = Utils.create_ptr 350 | FFI.call(:variance_larger_than_standard_deviation, arr, result) 351 | Array.new(result) 352 | end 353 | end 354 | end 355 | end 356 | -------------------------------------------------------------------------------- /lib/khiva/ffi.rb: -------------------------------------------------------------------------------- 1 | module Khiva 2 | module FFI 3 | extend Fiddle::Importer 4 | 5 | libs = Khiva.ffi_lib.dup 6 | begin 7 | dlload Fiddle.dlopen(libs.shift) 8 | rescue Fiddle::DLError => e 9 | retry if libs.any? 10 | raise e if ENV["KHIVA_DEBUG"] 11 | raise LoadError, "Khiva not found" 12 | end 13 | 14 | typealias "bool", "char" 15 | 16 | # array.h 17 | extern "void create_array(const void *data, unsigned int ndims, const long long *dims, khiva_array *result, int type, int *error_code, char *error_message)" 18 | extern "void delete_array(khiva_array *array, int *error_code, char *error_message)" 19 | extern "void display(const khiva_array *array, int *error_code, char *error_message)" 20 | extern "void get_data(const khiva_array *array, void *data, int *error_code, char *error_message)" 21 | extern "void get_dims(const khiva_array *array, long long *dims, int *error_code, char *error_message)" 22 | extern "void get_type(const khiva_array *array, int *t, int *error_code, char *error_message)" 23 | extern "void join(int dim, const khiva_array *first, const khiva_array *second, khiva_array *result, int *error_code, char *error_message)" 24 | extern "void khiva_add(const khiva_array *lhs, const khiva_array *rhs, khiva_array *result, int *error_code, char *error_message)" 25 | extern "void khiva_mul(const khiva_array *lhs, const khiva_array *rhs, khiva_array *result, int *error_code, char *error_message)" 26 | extern "void khiva_sub(const khiva_array *lhs, const khiva_array *rhs, khiva_array *result, int *error_code, char *error_message)" 27 | extern "void khiva_div(const khiva_array *lhs, const khiva_array *rhs, khiva_array *result, int *error_code, char *error_message)" 28 | extern "void khiva_mod(const khiva_array *lhs, const khiva_array *rhs, khiva_array *result, int *error_code, char *error_message)" 29 | extern "void khiva_pow(const khiva_array *lhs, const khiva_array *rhs, khiva_array *result, int *error_code, char *error_message)" 30 | extern "void khiva_lt(const khiva_array *lhs, const khiva_array *rhs, khiva_array *result, int *error_code, char *error_message)" 31 | extern "void khiva_gt(const khiva_array *lhs, const khiva_array *rhs, khiva_array *result, int *error_code, char *error_message)" 32 | extern "void khiva_le(const khiva_array *lhs, const khiva_array *rhs, khiva_array *result, int *error_code, char *error_message)" 33 | extern "void khiva_ge(const khiva_array *lhs, const khiva_array *rhs, khiva_array *result, int *error_code, char *error_message)" 34 | extern "void khiva_eq(const khiva_array *lhs, const khiva_array *rhs, khiva_array *result, int *error_code, char *error_message)" 35 | extern "void khiva_ne(const khiva_array *lhs, const khiva_array *rhs, khiva_array *result, int *error_code, char *error_message)" 36 | extern "void khiva_bitand(const khiva_array *lhs, const khiva_array *rhs, khiva_array *result, int *error_code, char *error_message)" 37 | extern "void khiva_bitor(const khiva_array *lhs, const khiva_array *rhs, khiva_array *result, int *error_code, char *error_message)" 38 | extern "void khiva_bitxor(const khiva_array *lhs, const khiva_array *rhs, khiva_array *result, int *error_code, char *error_message)" 39 | extern "void khiva_bitshiftl(const khiva_array *array, int n, khiva_array *result, int *error_code, char *error_message)" 40 | extern "void khiva_bitshiftr(const khiva_array *array, int n, khiva_array *result, int *error_code, char *error_message)" 41 | extern "void khiva_not(const khiva_array *array, khiva_array *result, int *error_code, char *error_message)" 42 | extern "void copy(const khiva_array *array, khiva_array *result, int *error_code, char *error_message)" 43 | 44 | # clustering.h 45 | extern "void k_means(const khiva_array *tss, const int *k, khiva_array *centroids, khiva_array *labels, const float *tolerance, const int *max_iterations, int *error_code, char *error_message)" 46 | extern "void k_shape(const khiva_array *tss, const int *k, khiva_array *centroids, khiva_array *labels, const float *tolerance, const int *max_iterations, int *error_code, char *error_message)" 47 | 48 | # dimensionality.h 49 | extern "void paa(const khiva_array *a, const int *bins, khiva_array *result, int *error_code, char *error_message)" 50 | extern "void pip(const khiva_array *a, const int *number_ips, khiva_array *result, int *error_code, char *error_message)" 51 | extern "void pla_bottom_up(const khiva_array *ts, const float *max_error, khiva_array *result, int *error_code, char *error_message)" 52 | extern "void pla_sliding_window(const khiva_array *ts, const float *max_error, khiva_array *result, int *error_code, char *error_message)" 53 | extern "void ramer_douglas_peucker(const khiva_array *points, const double *epsilon, khiva_array *res_points, int *error_code, char *error_message)" 54 | extern "void sax(const khiva_array *a, const int *alphabet_size, khiva_array *result, int *error_code, char *error_message)" 55 | extern "void visvalingam(const khiva_array *points, const int *num_points, khiva_array *res_points, int *error_code, char *error_message)" 56 | 57 | # features.h 58 | extern "void abs_energy(const khiva_array *array, khiva_array *result, int *error_code, char *error_message)" 59 | extern "void absolute_sum_of_changes(const khiva_array *array, khiva_array *result, int *error_code, char *error_message)" 60 | extern "void aggregated_autocorrelation(const khiva_array *array, const int *aggregation_function, khiva_array *result, int *error_code, char *error_message)" 61 | extern "void aggregated_linear_trend(const khiva_array *array, const long *chunkSize, const int *aggregation_function, khiva_array *slope, khiva_array *intercept, khiva_array *rvalue, khiva_array *pvalue, khiva_array *stderrest, int *error_code, char *error_message)" 62 | extern "void approximate_entropy(const khiva_array *array, const int *m, const float *r, khiva_array *result, int *error_code, char *error_message)" 63 | extern "void cross_covariance(const khiva_array *xss, const khiva_array *yss, const bool *unbiased, khiva_array *result, int *error_code, char *error_message)" 64 | extern "void auto_covariance(const khiva_array *array, const bool *unbiased, khiva_array *result, int *error_code, char *error_message)" 65 | extern "void cross_correlation(const khiva_array *xss, const khiva_array *yss, const bool *unbiased, khiva_array *result, int *error_code, char *error_message)" 66 | extern "void auto_correlation(const khiva_array *array, const long *max_lag, const bool *unbiased, khiva_array *result, int *error_code, char *error_message)" 67 | extern "void binned_entropy(const khiva_array *array, const int *max_bins, khiva_array *result, int *error_code, char *error_message)" 68 | extern "void c3(const khiva_array *array, const long *lag, khiva_array *result, int *error_code, char *error_message)" 69 | extern "void cid_ce(const khiva_array *array, const bool *zNormalize, khiva_array *result, int *error_code, char *error_message)" 70 | extern "void count_above_mean(const khiva_array *array, khiva_array *result, int *error_code, char *error_message)" 71 | extern "void count_below_mean(const khiva_array *array, khiva_array *result, int *error_code, char *error_message)" 72 | extern "void cwt_coefficients(const khiva_array *array, const khiva_array *width, const int *coeff, const int *w, khiva_array *result, int *error_code, char *error_message)" 73 | extern "void energy_ratio_by_chunks(const khiva_array *array, const long *num_segments, const long *segment_focus, khiva_array *result, int *error_code, char *error_message)" 74 | extern "void fft_aggregated(const khiva_array *array, khiva_array *result, int *error_code, char *error_message)" 75 | extern "void fft_coefficient(const khiva_array *array, const long *coefficient, khiva_array *real, khiva_array *imag, khiva_array *absolute, khiva_array *angle, int *error_code, char *error_message)" 76 | extern "void first_location_of_maximum(const khiva_array *array, khiva_array *result, int *error_code, char *error_message)" 77 | extern "void first_location_of_minimum(const khiva_array *array, khiva_array *result, int *error_code, char *error_message)" 78 | extern "void friedrich_coefficients(const khiva_array *array, const int *m, const float *r, khiva_array *result, int *error_code, char *error_message)" 79 | extern "void has_duplicates(const khiva_array *array, khiva_array *result, int *error_code, char *error_message)" 80 | extern "void has_duplicate_max(const khiva_array *array, khiva_array *result, int *error_code, char *error_message)" 81 | extern "void has_duplicate_min(const khiva_array *array, khiva_array *result, int *error_code, char *error_message)" 82 | extern "void index_mass_quantile(const khiva_array *array, const float *q, khiva_array *result, int *error_code, char *error_message)" 83 | extern "void kurtosis(const khiva_array *array, khiva_array *result, int *error_code, char *error_message)" 84 | extern "void large_standard_deviation(const khiva_array *array, const float *r, khiva_array *result, int *error_code, char *error_message)" 85 | extern "void last_location_of_maximum(const khiva_array *array, khiva_array *result, int *error_code, char *error_message)" 86 | extern "void last_location_of_minimum(const khiva_array *array, khiva_array *result, int *error_code, char *error_message)" 87 | extern "void length(const khiva_array *array, khiva_array *result, int *error_code, char *error_message)" 88 | extern "void linear_trend(const khiva_array *array, khiva_array *pvalue, khiva_array *rvalue, khiva_array *intercept, khiva_array *slope, khiva_array *stdrr, int *error_code, char *error_message)" 89 | extern "void local_maximals(const khiva_array *array, khiva_array *result, int *error_code, char *error_message)" 90 | extern "void longest_strike_above_mean(const khiva_array *array, khiva_array *result, int *error_code, char *error_message)" 91 | extern "void longest_strike_below_mean(const khiva_array *array, khiva_array *result, int *error_code, char *error_message)" 92 | extern "void max_langevin_fixed_point(const khiva_array *array, const int *m, const float *r, khiva_array *result, int *error_code, char *error_message)" 93 | extern "void maximum(const khiva_array *array, khiva_array *result, int *error_code, char *error_message)" 94 | extern "void mean(const khiva_array *array, khiva_array *result, int *error_code, char *error_message)" 95 | extern "void mean_absolute_change(const khiva_array *array, khiva_array *result, int *error_code, char *error_message)" 96 | extern "void mean_change(const khiva_array *array, khiva_array *result, int *error_code, char *error_message)" 97 | extern "void mean_second_derivative_central(const khiva_array *array, khiva_array *result, int *error_code, char *error_message)" 98 | extern "void median(const khiva_array *array, khiva_array *result, int *error_code, char *error_message)" 99 | extern "void minimum(const khiva_array *array, khiva_array *result, int *error_code, char *error_message)" 100 | extern "void number_crossing_m(const khiva_array *array, const int *m, khiva_array *result, int *error_code, char *error_message)" 101 | extern "void number_cwt_peaks(const khiva_array *array, const int *max_w, khiva_array *result, int *error_code, char *error_message)" 102 | extern "void number_peaks(const khiva_array *array, const int *n, khiva_array *result, int *error_code, char *error_message)" 103 | extern "void partial_autocorrelation(const khiva_array *array, const khiva_array *lags, khiva_array *result, int *error_code, char *error_message)" 104 | extern "void percentage_of_reoccurring_datapoints_to_all_datapoints(const khiva_array *array, const bool *is_sorted, khiva_array *result, int *error_code, char *error_message)" 105 | extern "void percentage_of_reoccurring_values_to_all_values(const khiva_array *array, const bool *is_sorted, khiva_array *result, int *error_code, char *error_message)" 106 | extern "void quantile(const khiva_array *array, const khiva_array *q, const float *precision, khiva_array *result, int *error_code, char *error_message)" 107 | extern "void range_count(const khiva_array *array, const float *min, const float *max, khiva_array *result, int *error_code, char *error_message)" 108 | extern "void ratio_beyond_r_sigma(const khiva_array *array, const float *r, khiva_array *result, int *error_code,vchar *error_message)" 109 | extern "void ratio_value_number_to_time_series_length(const khiva_array *array, khiva_array *result, int *error_code, char *error_message)" 110 | extern "void sample_entropy(const khiva_array *array, khiva_array *result, int *error_code, char *error_message)" 111 | extern "void skewness(const khiva_array *array, khiva_array *result, int *error_code, char *error_message)" 112 | extern "void spkt_welch_density(const khiva_array *array, const int *coeff, khiva_array *result, int *error_code, char *error_message)" 113 | extern "void standard_deviation(const khiva_array *array, khiva_array *result, int *error_code, char *error_message)" 114 | extern "void sum_of_reoccurring_datapoints(const khiva_array *array, const bool *is_sorted, khiva_array *result, int *error_code, char *error_message)" 115 | extern "void sum_of_reoccurring_values(const khiva_array *array, const bool *is_sorted, khiva_array *result, int *error_code, char *error_message)" 116 | extern "void sum_values(const khiva_array *array, khiva_array *result, int *error_code, char *error_message)" 117 | extern "void symmetry_looking(const khiva_array *array, const float *r, khiva_array *result, int *error_code, char *error_message)" 118 | extern "void time_reversal_asymmetry_statistic(const khiva_array *array, const int *lag, khiva_array *result, int *error_code, char *error_message)" 119 | extern "void value_count(const khiva_array *array, const float *v, khiva_array *result, int *error_code, char *error_message)" 120 | extern "void variance(const khiva_array *array, khiva_array *result, int *error_code, char *error_message)" 121 | extern "void variance_larger_than_standard_deviation(const khiva_array *array, khiva_array *result, int *error_code, char *error_message)" 122 | 123 | # library.h 124 | extern "void backend_info(char **info, int *error_code, char *error_message)" 125 | extern "void set_backend(const int *backend, int *error_code, char *error_message)" 126 | extern "void get_backend(int *backend, int *error_code, char *error_message)" 127 | extern "void get_backends(int *backends, int *error_code, char *error_message)" 128 | extern "void set_device(const int *device, int *error_code, char *error_message)" 129 | extern "void get_device_id(int *device_id, int *error_code, char *error_message)" 130 | extern "void get_device_count(int *device_count, int *error_code, char *error_message)" 131 | extern "void set_device_memory_in_gb(const double *memory, int *error_code, char *error_message)" 132 | extern "void version(char **v, int *error_code, char *error_message)" 133 | 134 | # linalg.h 135 | extern "void lls(const khiva_array *a, const khiva_array *b, khiva_array *result, int *error_code, char *error_message)" 136 | 137 | # distances.h 138 | extern "void dtw(const khiva_array *tss, khiva_array *result, int *error_code, char *error_message)" 139 | extern "void euclidean(const khiva_array *tss, khiva_array *result, int *error_code, char *error_message)" 140 | extern "void hamming(const khiva_array *tss, khiva_array *result, int *error_code, char *error_message)" 141 | extern "void manhattan(const khiva_array *tss, khiva_array *result, int *error_code, char *error_message)" 142 | extern "void sbd(const khiva_array *tss, khiva_array *result, int *error_code, char *error_message)" 143 | extern "void squared_euclidean(const khiva_array *tss, khiva_array *result, int *error_code, char *error_message)" 144 | 145 | # matrix.h 146 | extern "void find_best_n_discords(const khiva_array *profile, const khiva_array *index, long m, long n, khiva_array *discord_distances, khiva_array *discord_indices, khiva_array *subsequence_indices, bool self_join, int *error_code, char *error_message)" 147 | extern "void find_best_n_motifs(const khiva_array *profile, const khiva_array *index, long m, long n, khiva_array *motif_distances, khiva_array *motif_indices, khiva_array *subsequence_indices, bool self_join, int *error_code, char *error_message)" 148 | extern "void find_best_n_occurrences(const khiva_array *q, const khiva_array *t, long n, khiva_array *distances, khiva_array *indexes, int *error_code, char *error_message)" 149 | extern "void mass(const khiva_array *q, const khiva_array *t, khiva_array *distances, int *error_code, char *error_message)" 150 | extern "void stomp(const khiva_array *tssa, const khiva_array *tssb, long m, khiva_array *p, khiva_array *i, int *error_code, char *error_message)" 151 | extern "void stomp_self_join(const khiva_array *tss, long m, khiva_array *p, khiva_array *i, int *error_code, char *error_message)" 152 | extern "void matrix_profile(const khiva_array *tssa, const khiva_array *tssb, long m, khiva_array *p, khiva_array *i, int *error_code, char *error_message)" 153 | extern "void matrix_profile_self_join(const khiva_array *tss, long m, khiva_array *p, khiva_array *i, int *error_code, char *error_message)" 154 | extern "void matrix_profile_lr(const khiva_array *tss, long m, khiva_array *pleft, khiva_array *ileft, khiva_array *pright, khiva_array *iright, int *error_code, char *error_message)" 155 | extern "void get_chains(const khiva_array *tss, long m, khiva_array *chains, int *error_code, char *error_message)" 156 | 157 | # normalization.h 158 | extern "void decimal_scaling_norm(const khiva_array *tss, khiva_array *result, int *error_code, char *error_message)" 159 | extern "void decimal_scaling_norm_in_place(khiva_array *tss, int *error_code, char *error_message)" 160 | extern "void max_min_norm(const khiva_array *tss, const double *high, const double *low, const double *epsilon, khiva_array *result, int *error_code, char *error_message)" 161 | extern "void max_min_norm_in_place(khiva_array *tss, const double *high, const double *low, const double *epsilon, int *error_code, char *error_message)" 162 | extern "void mean_norm(const khiva_array *tss, khiva_array *result, int *error_code, char *error_message)" 163 | extern "void mean_norm_in_place(khiva_array *tss, int *error_code, char *error_message)" 164 | extern "void znorm(const khiva_array *tss, const double *epsilon, khiva_array *result, int *error_code, char *error_message)" 165 | extern "void znorm_in_place(khiva_array *tss, const double *epsilon, int *error_code, char *error_message)" 166 | 167 | # polynomial.h 168 | extern "void polyfit(const khiva_array *x, const khiva_array *y, const int *deg, khiva_array *result, int *error_code, char *error_message)" 169 | extern "void roots(const khiva_array *p, khiva_array *result, int *error_code, char *error_message)" 170 | 171 | # regression.h 172 | extern "void linear(const khiva_array *xss, const khiva_array *yss, khiva_array *slope, khiva_array *intercept, khiva_array *rvalue, khiva_array *pvalue, khiva_array *stderrest, int *error_code, char *error_message)" 173 | 174 | # regularization.h 175 | extern "void group_by(const khiva_array *array, const int *aggregation_function, const int *n_columns_key, const int *n_columns_value, khiva_array *result, int *error_code, char *error_message)" 176 | 177 | # statistics.h 178 | extern "void covariance_statistics(const khiva_array *tss, const bool *unbiased, khiva_array *result, int *error_code, char *error_message)" 179 | extern "void kurtosis_statistics(const khiva_array *tss, khiva_array *result, int *error_code, char *error_message)" 180 | extern "void ljung_box(const khiva_array *tss, const long *lags, khiva_array *result, int *error_code, char *error_message)" 181 | extern "void moment_statistics(const khiva_array *tss, const int *k, khiva_array *result, int *error_code, char *error_message)" 182 | extern "void quantile_statistics(const khiva_array *tss, const khiva_array *q, const float *precision, khiva_array *result, int *error_code, char *error_message)" 183 | extern "void quantiles_cut_statistics(const khiva_array *tss, const float *quantiles, const float *precision, khiva_array *result, int *error_code, char *error_message)" 184 | extern "void sample_stdev_statistics(const khiva_array *tss, khiva_array *result, int *error_code, char *error_message)" 185 | extern "void skewness_statistics(const khiva_array *tss, khiva_array *result, int *error_code, char *error_message)" 186 | 187 | class << self 188 | # thread-safe 189 | def error_code 190 | Thread.current[:khiva_error_code] ||= Fiddle::Pointer.malloc(Fiddle::SIZEOF_INT) 191 | end 192 | 193 | # thread-safe 194 | def error_message 195 | Thread.current[:khiva_error_message] ||= Fiddle::Pointer.malloc(256) 196 | end 197 | 198 | def call(method, *args) 199 | FFI.send(method, *args, error_code, error_message) 200 | if error_code.to_s(error_code.size).unpack1("i*") != 0 201 | raise Error, error_message.to_s 202 | end 203 | end 204 | end 205 | end 206 | end 207 | -------------------------------------------------------------------------------- /lib/khiva/library.rb: -------------------------------------------------------------------------------- 1 | module Khiva 2 | module Library 3 | BACKENDS = { 4 | default: 0, 5 | cpu: 1, 6 | cuda: 2, 7 | opencl: 4 8 | } 9 | 10 | class << self 11 | def backend_info 12 | info = Fiddle::Pointer.malloc(1000) 13 | FFI.call(:backend_info, info.ref) 14 | info.to_s 15 | end 16 | 17 | def backend 18 | backend = Fiddle::Pointer.malloc(Fiddle::SIZEOF_INT) 19 | FFI.call(:get_backend, backend) 20 | BACKENDS.map(&:reverse).to_h[backend.to_s(backend.size).unpack1("i")] 21 | end 22 | 23 | def backends 24 | backends = Fiddle::Pointer.malloc(Fiddle::SIZEOF_INT) 25 | FFI.call(:get_backends, backends) 26 | mask = backends.to_s(backends.size).unpack1("i") 27 | BACKENDS.select { |_, v| mask & v != 0 }.map(&:first) 28 | end 29 | 30 | def set_backend(backend) 31 | b = BACKENDS[backend] 32 | raise Error, "Invalid backend: #{backend}" unless b 33 | FFI.call(:set_backend, Utils.int_ptr(b)) 34 | end 35 | 36 | def set_device(device) 37 | FFI.call(:set_device, Utils.int_ptr(device)) 38 | end 39 | 40 | def device_id 41 | device_id = Fiddle::Pointer.malloc(Fiddle::SIZEOF_INT) 42 | FFI.call(:get_device_id, device_id) 43 | device_id.to_s(device_id.size).unpack1("i") 44 | end 45 | 46 | def device_count 47 | device_count = Fiddle::Pointer.malloc(Fiddle::SIZEOF_INT) 48 | FFI.call(:get_device_count, device_count) 49 | device_count.to_s(device_count.size).unpack1("i") 50 | end 51 | 52 | def set_device_memory_in_gb(memory) 53 | FFI.call(:set_device_memory_in_gb, Utils.double_ptr(memory)) 54 | end 55 | 56 | def version 57 | v = Fiddle::Pointer.malloc(20) 58 | FFI.call(:version, v.ref) 59 | v.to_s 60 | end 61 | end 62 | end 63 | end 64 | -------------------------------------------------------------------------------- /lib/khiva/linalg.rb: -------------------------------------------------------------------------------- 1 | module Khiva 2 | module Linalg 3 | class << self 4 | def lls(a, b) 5 | result = Utils.create_ptr 6 | FFI.call(:lls, a, b, result) 7 | Array.new(result) 8 | end 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /lib/khiva/matrix.rb: -------------------------------------------------------------------------------- 1 | module Khiva 2 | module Matrix 3 | class << self 4 | def find_best_n_discords(profile, index, m, n, self_join: false) 5 | discord_distances = Fiddle::Pointer.malloc(Fiddle::SIZEOF_VOIDP) 6 | discord_indices = Fiddle::Pointer.malloc(Fiddle::SIZEOF_VOIDP) 7 | subsequence_indices = Fiddle::Pointer.malloc(Fiddle::SIZEOF_VOIDP) 8 | FFI.call(:find_best_n_discords, profile, index, m, n, discord_distances, discord_indices, subsequence_indices, self_join ? 1 : 0) 9 | [Array.new(discord_distances), Array.new(discord_indices), Array.new(subsequence_indices)] 10 | end 11 | 12 | def find_best_n_motifs(profile, index, m, n, self_join: false) 13 | motif_distances = Fiddle::Pointer.malloc(Fiddle::SIZEOF_VOIDP) 14 | motif_indices = Fiddle::Pointer.malloc(Fiddle::SIZEOF_VOIDP) 15 | subsequence_indices = Fiddle::Pointer.malloc(Fiddle::SIZEOF_VOIDP) 16 | FFI.call(:find_best_n_motifs, profile, index, m, n, motif_distances, motif_indices, subsequence_indices, self_join ? 1 : 0) 17 | [Array.new(motif_distances), Array.new(motif_indices), Array.new(subsequence_indices)] 18 | end 19 | 20 | def find_best_n_occurrences(q, t, n) 21 | distances = Fiddle::Pointer.malloc(Fiddle::SIZEOF_VOIDP) 22 | indices = Fiddle::Pointer.malloc(Fiddle::SIZEOF_VOIDP) 23 | FFI.call(:find_best_n_occurrences, q, t, n, distances, indices) 24 | [Array.new(distances), Array.new(indices)] 25 | end 26 | 27 | def mass(q, t) 28 | distances = Fiddle::Pointer.malloc(Fiddle::SIZEOF_VOIDP) 29 | FFI.call(:mass, q, t, distances) 30 | Array.new(distances) 31 | end 32 | 33 | def stomp(tssa, tssb, m) 34 | profile = Fiddle::Pointer.malloc(Fiddle::SIZEOF_VOIDP) 35 | index = Fiddle::Pointer.malloc(Fiddle::SIZEOF_VOIDP) 36 | FFI.call(:stomp, tssa, tssb, m, profile, index) 37 | [Array.new(profile), Array.new(index)] 38 | end 39 | 40 | def stomp_self_join(tss, m) 41 | profile = Fiddle::Pointer.malloc(Fiddle::SIZEOF_VOIDP) 42 | index = Fiddle::Pointer.malloc(Fiddle::SIZEOF_VOIDP) 43 | FFI.call(:stomp_self_join, tss, m, profile, index) 44 | [Array.new(profile), Array.new(index)] 45 | end 46 | 47 | def matrix_profile(tssa, tssb, m) 48 | profile = Fiddle::Pointer.malloc(Fiddle::SIZEOF_VOIDP) 49 | index = Fiddle::Pointer.malloc(Fiddle::SIZEOF_VOIDP) 50 | FFI.call(:matrix_profile, tssa, tssb, m, profile, index) 51 | [Array.new(profile), Array.new(index)] 52 | end 53 | 54 | def matrix_profile_self_join(tss, m) 55 | profile = Fiddle::Pointer.malloc(Fiddle::SIZEOF_VOIDP) 56 | index = Fiddle::Pointer.malloc(Fiddle::SIZEOF_VOIDP) 57 | FFI.call(:matrix_profile_self_join, tss, m, profile, index) 58 | [Array.new(profile), Array.new(index)] 59 | end 60 | 61 | def chains(tss, m) 62 | chains = Fiddle::Pointer.malloc(Fiddle::SIZEOF_VOIDP) 63 | FFI.call(:get_chains, tss, m, chains) 64 | Array.new(chains) 65 | end 66 | end 67 | end 68 | end 69 | -------------------------------------------------------------------------------- /lib/khiva/normalization.rb: -------------------------------------------------------------------------------- 1 | module Khiva 2 | module Normalization 3 | class << self 4 | def decimal_scaling_norm(tss) 5 | result = Utils.create_ptr 6 | FFI.call(:decimal_scaling_norm, tss, result) 7 | Array.new(result) 8 | end 9 | 10 | def decimal_scaling_norm!(tss) 11 | FFI.call(:decimal_scaling_norm_in_place, tss) 12 | tss 13 | end 14 | 15 | def max_min_norm(tss, high: 1, low: 0, epsilon: 0.00000001) 16 | result = Utils.create_ptr 17 | FFI.call(:max_min_norm, tss, Utils.double_ptr(high), Utils.double_ptr(low), Utils.double_ptr(epsilon), result) 18 | Array.new(result) 19 | end 20 | 21 | def max_min_norm!(tss, high: 1, low: 0, epsilon: 0.00000001) 22 | FFI.call(:max_min_norm_in_place, tss, Utils.double_ptr(high), Utils.double_ptr(low), Utils.double_ptr(epsilon)) 23 | tss 24 | end 25 | 26 | def mean_norm(tss) 27 | result = Utils.create_ptr 28 | FFI.call(:mean_norm, tss, result) 29 | Array.new(result) 30 | end 31 | 32 | def mean_norm!(tss) 33 | FFI.call(:mean_norm_in_place, tss) 34 | tss 35 | end 36 | 37 | def znorm(tss, epsilon: 0.00000001) 38 | result = Utils.create_ptr 39 | FFI.call(:znorm, tss, Utils.double_ptr(epsilon), result) 40 | Array.new(result) 41 | end 42 | 43 | def znorm!(tss, epsilon: 0.00000001) 44 | FFI.call(:znorm_in_place, tss, Utils.double_ptr(epsilon)) 45 | tss 46 | end 47 | end 48 | end 49 | end 50 | -------------------------------------------------------------------------------- /lib/khiva/polynomial.rb: -------------------------------------------------------------------------------- 1 | module Khiva 2 | module Polynomial 3 | class << self 4 | def polyfit(x, y, deg) 5 | result = Utils.create_ptr 6 | FFI.call(:polyfit, x, y, Utils.int_ptr(deg), result) 7 | Array.new(result) 8 | end 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /lib/khiva/regression.rb: -------------------------------------------------------------------------------- 1 | module Khiva 2 | module Regression 3 | class << self 4 | def linear(xss, yss) 5 | slope = Utils.create_ptr 6 | intercept = Utils.create_ptr 7 | rvalue = Utils.create_ptr 8 | pvalue = Utils.create_ptr 9 | stderrest = Utils.create_ptr 10 | FFI.call(:linear, xss, yss, slope, intercept, rvalue, pvalue, stderrest) 11 | [Array.new(slope), Array.new(intercept), Array.new(rvalue), Array.new(pvalue), Array.new(stderrest)] 12 | end 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /lib/khiva/regularization.rb: -------------------------------------------------------------------------------- 1 | module Khiva 2 | module Regularization 3 | class << self 4 | def group_by(tss, aggregation_function, n_columns_key: 1, n_columns_value: 1) 5 | result = Utils.create_ptr 6 | FFI.call(:group_by, tss, Utils.int_ptr(aggregation_function), Utils.int_ptr(n_columns_key), Utils.int_ptr(n_columns_value), result) 7 | Array.new(result) 8 | end 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /lib/khiva/statistics.rb: -------------------------------------------------------------------------------- 1 | module Khiva 2 | module Statistics 3 | class << self 4 | def covariance(tss, unbiased: false) 5 | result = Utils.create_ptr 6 | FFI.call(:covariance_statistics, tss, Utils.bool_ptr(unbiased), result) 7 | Array.new(result) 8 | end 9 | 10 | def kurtosis(tss) 11 | result = Utils.create_ptr 12 | FFI.call(:kurtosis_statistics, tss, result) 13 | Array.new(result) 14 | end 15 | 16 | def ljung_box(tss, lags) 17 | result = Utils.create_ptr 18 | FFI.call(:ljung_box, tss, Utils.long_ptr(lags), result) 19 | Array.new(result) 20 | end 21 | 22 | def moment(tss, k) 23 | result = Utils.create_ptr 24 | FFI.call(:moment_statistics, tss, Utils.int_ptr(k), result) 25 | Array.new(result) 26 | end 27 | 28 | def quantile(tss, q, precision: 1e-8) 29 | result = Utils.create_ptr 30 | FFI.call(:quantile_statistics, tss, q, Utils.float_ptr(precision), result) 31 | Array.new(result) 32 | end 33 | 34 | def quantiles_cut(tss, quantiles, precision: 1e-8) 35 | result = Utils.create_ptr 36 | FFI.call(:quantiles_cut_statistics, tss, Utils.float_ptr(quantiles), Utils.float_ptr(precision), result) 37 | Array.new(result) 38 | end 39 | 40 | def sample_stdev(tss) 41 | result = Utils.create_ptr 42 | FFI.call(:sample_stdev_statistics, tss, result) 43 | Array.new(result) 44 | end 45 | 46 | def skewness(tss) 47 | result = Utils.create_ptr 48 | FFI.call(:skewness_statistics, tss, result) 49 | Array.new(result) 50 | end 51 | end 52 | end 53 | end 54 | -------------------------------------------------------------------------------- /lib/khiva/utils.rb: -------------------------------------------------------------------------------- 1 | module Khiva 2 | module Utils 3 | class << self 4 | def create_ptr 5 | Fiddle::Pointer.malloc(Fiddle::SIZEOF_VOIDP) 6 | end 7 | 8 | def int_ptr(v) 9 | Fiddle::Pointer[[v].pack("i")] 10 | end 11 | 12 | def long_ptr(v) 13 | Fiddle::Pointer[[v].pack("L!")] 14 | end 15 | 16 | def float_ptr(v) 17 | Fiddle::Pointer[[v].pack("f")] 18 | end 19 | 20 | def double_ptr(v) 21 | Fiddle::Pointer[[v].pack("d")] 22 | end 23 | 24 | def bool_ptr(v) 25 | Fiddle::Pointer[[v ? 1 : 0].pack("c")] 26 | end 27 | 28 | # TODO make more efficient 29 | def reshape(arr, dims) 30 | arr = arr.flatten 31 | dims[1..-1].reverse.each do |dim| 32 | arr = arr.each_slice(dim) 33 | end 34 | arr.to_a 35 | end 36 | end 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /lib/khiva/version.rb: -------------------------------------------------------------------------------- 1 | module Khiva 2 | VERSION = "0.2.1" 3 | end 4 | -------------------------------------------------------------------------------- /test/array_test.rb: -------------------------------------------------------------------------------- 1 | require_relative "test_helper" 2 | 3 | class ArrayTest < Minitest::Test 4 | def test_from_array 5 | a = Khiva::Array.new([[1, 2, 3], [4, 5, 6]]) 6 | assert_equal [3, 2, 1, 1], a.dims 7 | assert_equal :s64, a.type 8 | end 9 | 10 | def test_from_array_float 11 | a = Khiva::Array.new([[1.0, 2, 3], [4, 5, 6]]) 12 | assert_equal :f64, a.type 13 | end 14 | 15 | def test_copy 16 | a = Khiva::Array.new([1, 2, 3]) 17 | b = a.copy 18 | assert_equal [1, 2, 3], b.to_a 19 | c = a.dup 20 | assert_equal [1, 2, 3], c.to_a 21 | d = a.clone 22 | assert_equal [1, 2, 3], d.to_a 23 | end 24 | 25 | def test_operations 26 | a = Khiva::Array.new([10, 20, 30]) 27 | b = Khiva::Array.new([5, 10, 15]) 28 | c = Khiva::Array.new([1, 2, 1]) 29 | assert_equal [15, 30, 45], (a + b).to_a 30 | assert_equal [5, 10, 15], (a - b).to_a 31 | assert_equal [50, 200, 450], (a * b).to_a 32 | assert_equal [2, 2, 2], (a / b).to_a 33 | assert_equal [0, 0, 0], (a % b).to_a 34 | assert_equal [10, 400, 30], (a ** c).to_a 35 | end 36 | 37 | def test_comparison 38 | a = Khiva::Array.new([1, 2, 3]) 39 | b = Khiva::Array.new([2, 2, 2]) 40 | assert_equal [true, false, false], a.lt(b).to_a 41 | assert_equal [false, false, true], a.gt(b).to_a 42 | assert_equal [true, true, false], a.le(b).to_a 43 | assert_equal [false, true, true], a.ge(b).to_a 44 | assert_equal [false, true, false], a.eq(b).to_a 45 | assert_equal [true, false, true], a.ne(b).to_a 46 | end 47 | end 48 | -------------------------------------------------------------------------------- /test/clustering_test.rb: -------------------------------------------------------------------------------- 1 | require_relative "test_helper" 2 | 3 | class ClusteringTest < Minitest::Test 4 | def test_k_means 5 | tss = Khiva::Array.new([1, 2, 3, 4, 5], type: :f32) 6 | centroids, labels = Khiva::Clustering.k_means(tss, 2) 7 | expected = [[0.0, 0.0, 0.0, 0.0, 0.0], [1.0, 2.0, 3.0, 4.0, 5.0]] 8 | assert_elements_in_delta expected, centroids 9 | assert_elements_in_delta [1], labels 10 | end 11 | 12 | def test_k_shape 13 | tss = Khiva::Array.new([1, 2, 3, 4, 5], type: :f32) 14 | centroids, labels = Khiva::Clustering.k_shape(tss, 2) 15 | expected = [[2.0, -0.5, -0.5, -0.5, -0.5], [0.0, 0.0, 0.0, 0.0, 0.0]] 16 | assert_elements_in_delta expected, centroids 17 | assert_elements_in_delta [0], labels 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /test/dimensionality_test.rb: -------------------------------------------------------------------------------- 1 | require_relative "test_helper" 2 | 3 | class DimensionalityTest < Minitest::Test 4 | def test_paa 5 | expected = [[1.0, 2.5], [4.0, 5.5]] 6 | assert_elements_in_delta expected, Khiva::Dimensionality.paa(tss, 2) 7 | end 8 | 9 | def test_pip 10 | expected = [[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]] 11 | assert_elements_in_delta expected, Khiva::Dimensionality.pip(tss, 3) 12 | end 13 | 14 | def test_pla_bottom_up 15 | expected = [[1.0, 2.0], [4.0, 5.0]] 16 | assert_elements_in_delta expected, Khiva::Dimensionality.pla_bottom_up(tss, 0.1) 17 | end 18 | 19 | def test_pla_sliding_window 20 | expected = [[1.0, 3.0], [4.0, 6.0]] 21 | assert_elements_in_delta expected, Khiva::Dimensionality.pla_sliding_window(tss, 0.1) 22 | end 23 | 24 | def test_ramer_douglas_peucker 25 | expected = [[1.0, 3.0], [4.0, 6.0]] 26 | assert_elements_in_delta expected, Khiva::Dimensionality.ramer_douglas_peucker(tss, 0.1) 27 | end 28 | 29 | def test_sax 30 | expected = [[1.0, 2.0, 3.0], [0.0, 0.0, 1.0]] 31 | assert_elements_in_delta expected, Khiva::Dimensionality.sax(tss, 2) 32 | end 33 | 34 | def test_visvalingam 35 | expected = [[1.0, 3.0], [4.0, 6.0]] 36 | assert_elements_in_delta expected, Khiva::Dimensionality.visvalingam(tss, 2) 37 | end 38 | 39 | def tss 40 | Khiva::Array.new([[1, 2, 3], [4, 5, 6]], type: :f32) 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /test/distances_test.rb: -------------------------------------------------------------------------------- 1 | require_relative "test_helper" 2 | 3 | class DistancesTest < Minitest::Test 4 | def test_dtw 5 | expected = [[0, 0, 0], [5, 0, 0], [10, 5, 0]] 6 | assert_elements_in_delta expected, Khiva::Distances.dtw(tss) 7 | end 8 | 9 | def test_euclidean 10 | expected = [[0.0, 0.0, 0.0], [2.2360680103302, 0.0, 0.0], [4.4721360206604, 2.2360680103302, 0.0]] 11 | assert_elements_in_delta expected, Khiva::Distances.euclidean(tss) 12 | end 13 | 14 | def test_hamming 15 | expected = [[0, 0, 0], [5, 0, 0], [5, 5, 0]] 16 | assert_elements_in_delta expected, Khiva::Distances.hamming(tss) 17 | end 18 | 19 | def test_manhattan 20 | expected = [[0, 0, 0], [5, 0, 0], [10, 5, 0]] 21 | assert_elements_in_delta expected, Khiva::Distances.manhattan(tss) 22 | end 23 | 24 | def test_sbd 25 | expected = [[0, 0, 0], [-9223372036854775808, 0, 0], [-9223372036854775808, -9223372036854775808, 0]] 26 | assert_elements_in_delta expected, Khiva::Distances.sbd(tss) 27 | end 28 | 29 | def test_squared_euclidean 30 | expected = [[0, 0, 0], [5, 0, 0], [20, 5, 0]] 31 | assert_elements_in_delta expected, Khiva::Distances.squared_euclidean(tss) 32 | end 33 | 34 | def tss 35 | Khiva::Array.new([[1, 1, 1, 1, 1], [2, 2, 2, 2, 2], [3, 3, 3, 3, 3]]) 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /test/features_test.rb: -------------------------------------------------------------------------------- 1 | require_relative "test_helper" 2 | 3 | class FeaturesTest < Minitest::Test 4 | def test_abs_energy 5 | expected = [55] 6 | assert_elements_in_delta expected, Khiva::Features.abs_energy(tss) 7 | end 8 | 9 | def test_absolute_sum_of_changes 10 | expected = [4] 11 | assert_elements_in_delta expected, Khiva::Features.absolute_sum_of_changes(tss) 12 | end 13 | 14 | def test_aggregated_autocorrelation 15 | expected = [-0.6666666666666666] 16 | assert_elements_in_delta expected, Khiva::Features.aggregated_autocorrelation(tss, 0) 17 | end 18 | 19 | def test_aggregated_linear_trend 20 | # TODO 21 | end 22 | 23 | def test_approximate_entropy 24 | expected = [0.2703100720721096] 25 | assert_elements_in_delta expected, Khiva::Features.approximate_entropy(tss, 3, 1) 26 | end 27 | 28 | def test_auto_correlation 29 | expected = [1.0, 0.4, -0.1] 30 | assert_elements_in_delta expected, Khiva::Features.auto_correlation(tss, 3, false) 31 | end 32 | 33 | def test_auto_covariance 34 | expected = [2.0, 0.8, -0.2, -0.8, -0.8] 35 | assert_elements_in_delta expected, Khiva::Features.auto_covariance(tss) 36 | end 37 | 38 | def test_binned_entropy 39 | expected = [1.0549201965332031] 40 | assert_elements_in_delta expected, Khiva::Features.binned_entropy(tss, 3) 41 | end 42 | 43 | def test_c3 44 | expected = [21.0] 45 | assert_elements_in_delta expected, Khiva::Features.c3(tss, 3) 46 | end 47 | 48 | def test_cid_ce 49 | expected = [1.414213562373095] 50 | assert_elements_in_delta expected, Khiva::Features.cid_ce(tss, true) 51 | end 52 | 53 | def test_count_above_mean 54 | expected = [2] 55 | assert_elements_in_delta expected, Khiva::Features.count_above_mean(tss) 56 | end 57 | 58 | def test_count_below_mean 59 | expected = [2] 60 | assert_elements_in_delta expected, Khiva::Features.count_below_mean(tss) 61 | end 62 | 63 | def test_cross_correlation 64 | expected = [0.9999999999999998, 0.4999999999999999, -0.16666666666666663, -0.9999999999999998, -1.9999999999999996] 65 | assert_elements_in_delta expected, Khiva::Features.cross_correlation(tss, tss, true) 66 | end 67 | 68 | def test_cross_covariance 69 | expected = [2.0, 1.0, -0.3333333333333333, -2.0, -4.0] 70 | assert_elements_in_delta expected, Khiva::Features.cross_covariance(tss, tss, true) 71 | end 72 | 73 | def test_cwt_coefficients 74 | # TODO 75 | end 76 | 77 | def test_energy_ratio_by_chunks 78 | expected = [0.45454545454545453] 79 | assert_elements_in_delta expected, Khiva::Features.energy_ratio_by_chunks(tss, 2, 1) 80 | end 81 | 82 | def test_fft_aggregated 83 | expected = [0.434631407211718, 0.485985279952239, Float::NAN, Float::NAN] 84 | assert_elements_in_delta expected, Khiva::Features.fft_aggregated(tss) 85 | end 86 | 87 | def test_fft_coefficient 88 | # TODO 89 | end 90 | 91 | def test_first_location_of_maximum 92 | expected = [0.8] 93 | assert_elements_in_delta expected, Khiva::Features.first_location_of_maximum(tss) 94 | end 95 | 96 | def test_first_location_of_minimum 97 | expected = [0] 98 | assert_elements_in_delta expected, Khiva::Features.first_location_of_minimum(tss) 99 | end 100 | 101 | def test_friedrich_coefficients 102 | # TODO 103 | end 104 | 105 | def test_has_duplicate_max 106 | expected = [false] 107 | assert_equal expected, Khiva::Features.has_duplicate_max(tss).to_a 108 | end 109 | 110 | def test_has_duplicate_min 111 | expected = [false] 112 | assert_equal expected, Khiva::Features.has_duplicate_min(tss).to_a 113 | end 114 | 115 | def test_has_duplicates 116 | expected = [false] 117 | assert_equal expected, Khiva::Features.has_duplicates(tss).to_a 118 | end 119 | 120 | def test_index_mass_quantile 121 | expected = [0.8] 122 | assert_elements_in_delta expected, Khiva::Features.index_mass_quantile(tss, 0.5) 123 | end 124 | 125 | def test_kurtosis 126 | expected = [-1.2] 127 | assert_elements_in_delta expected, Khiva::Features.kurtosis(tss) 128 | end 129 | 130 | def test_large_standard_deviation 131 | expected = [false] 132 | assert_equal expected, Khiva::Features.large_standard_deviation(tss, 1).to_a 133 | end 134 | 135 | def test_last_location_of_maximum 136 | expected = [1] 137 | assert_elements_in_delta expected, Khiva::Features.last_location_of_maximum(tss) 138 | end 139 | 140 | def test_last_location_of_minimum 141 | expected = [0.2] 142 | assert_elements_in_delta expected, Khiva::Features.last_location_of_minimum(tss) 143 | end 144 | 145 | def test_length 146 | expected = [5] 147 | assert_elements_in_delta expected, Khiva::Features.length(tss) 148 | end 149 | 150 | # TODO 151 | def test_linear_trend 152 | end 153 | 154 | def test_local_maximals 155 | expected = [1.0, 0.0, 0.0, 0.0, 1.0] 156 | assert_elements_in_delta expected, Khiva::Features.local_maximals(tss) 157 | end 158 | 159 | def test_longest_strike_above_mean 160 | expected = [2] 161 | assert_elements_in_delta expected, Khiva::Features.longest_strike_above_mean(tss) 162 | end 163 | 164 | def test_longest_strike_below_mean 165 | expected = [2] 166 | assert_elements_in_delta expected, Khiva::Features.longest_strike_below_mean(tss) 167 | end 168 | 169 | def test_max_langevin_fixed_point 170 | # TODO 171 | end 172 | 173 | def test_maximum 174 | expected = [5] 175 | assert_elements_in_delta expected, Khiva::Features.maximum(tss) 176 | end 177 | 178 | def test_mean 179 | expected = [3] 180 | assert_elements_in_delta expected, Khiva::Features.mean(tss) 181 | end 182 | 183 | def test_mean_absolute_change 184 | expected = [0.8] 185 | assert_elements_in_delta expected, Khiva::Features.mean_absolute_change(tss) 186 | end 187 | 188 | def test_mean_change 189 | expected = [0.8] 190 | assert_elements_in_delta expected, Khiva::Features.mean_change(tss) 191 | end 192 | 193 | def test_mean_second_derivative_central 194 | expected = [0] 195 | assert_elements_in_delta expected, Khiva::Features.mean_second_derivative_central(tss) 196 | end 197 | 198 | def test_median 199 | expected = [3] 200 | assert_elements_in_delta expected, Khiva::Features.median(tss) 201 | end 202 | 203 | def test_minimum 204 | expected = [1] 205 | assert_elements_in_delta expected, Khiva::Features.minimum(tss) 206 | end 207 | 208 | def test_number_crossing_m 209 | expected = [1.0] 210 | assert_elements_in_delta expected, Khiva::Features.number_crossing_m(tss, 3) 211 | end 212 | 213 | def test_number_cwt_peaks 214 | # TODO 215 | end 216 | 217 | def test_number_peaks 218 | expected = [0] 219 | assert_elements_in_delta expected, Khiva::Features.number_peaks(tss, 2) 220 | end 221 | 222 | def test_partial_autocorrelation 223 | lags = Khiva::Array.new([1], type: :s32) 224 | expected = [1.0, 0.5] 225 | assert_elements_in_delta expected, Khiva::Features.partial_autocorrelation(tss, lags) 226 | end 227 | 228 | def test_percentage_of_reoccurring_datapoints_to_all_datapoints 229 | expected = [0] 230 | assert_elements_in_delta expected, Khiva::Features.percentage_of_reoccurring_datapoints_to_all_datapoints(tss, false) 231 | end 232 | 233 | def test_percentage_of_reoccurring_values_to_all_values 234 | expected = [0] 235 | assert_elements_in_delta expected, Khiva::Features.percentage_of_reoccurring_values_to_all_values(tss, false) 236 | end 237 | 238 | def test_quantile 239 | q = Khiva::Array.new([0.5]) 240 | expected = [3] 241 | assert_elements_in_delta expected, Khiva::Features.quantile(tss, q) 242 | end 243 | 244 | def test_range_count 245 | skip # TODO debug 246 | 247 | expected = [3] 248 | assert_elements_in_delta expected, Khiva::Features.range_count(tss, 2, 4) 249 | end 250 | 251 | def test_ratio_beyond_r_sigma 252 | expected = [0.4] 253 | assert_elements_in_delta expected, Khiva::Features.ratio_beyond_r_sigma(tss, 1) 254 | end 255 | 256 | def test_ratio_value_number_to_time_series_length 257 | expected = [1] 258 | assert_elements_in_delta expected, Khiva::Features.ratio_value_number_to_time_series_length(tss) 259 | end 260 | 261 | def test_sample_entropy 262 | expected = [Float::INFINITY] 263 | assert_elements_in_delta expected, Khiva::Features.sample_entropy(tss) 264 | end 265 | 266 | def test_skewness 267 | expected = [0] 268 | assert_elements_in_delta expected, Khiva::Features.skewness(tss) 269 | end 270 | 271 | def test_spkt_welch_density 272 | expected = [2.872678279876709] 273 | assert_elements_in_delta expected, Khiva::Features.spkt_welch_density(tss, 1) 274 | end 275 | 276 | def test_standard_deviation 277 | expected = [1.4142135623730951] 278 | assert_elements_in_delta expected, Khiva::Features.standard_deviation(tss) 279 | end 280 | 281 | def test_sum_of_reoccurring_datapoints 282 | expected = [0] 283 | assert_elements_in_delta expected, Khiva::Features.sum_of_reoccurring_datapoints(tss) 284 | end 285 | 286 | def test_sum_of_reoccurring_values 287 | expected = [0] 288 | assert_elements_in_delta expected, Khiva::Features.sum_of_reoccurring_values(tss) 289 | end 290 | 291 | def test_sum_values 292 | expected = [15] 293 | assert_elements_in_delta expected, Khiva::Features.sum_values(tss) 294 | end 295 | 296 | def test_symmetry_looking 297 | expected = [true] 298 | assert_equal expected, Khiva::Features.symmetry_looking(tss, 0.5).to_a 299 | end 300 | 301 | def test_time_reversal_asymmetry_statistic 302 | expected = [72] 303 | assert_elements_in_delta expected, Khiva::Features.time_reversal_asymmetry_statistic(tss, 2) 304 | end 305 | 306 | def test_value_count 307 | expected = [1] 308 | assert_elements_in_delta expected, Khiva::Features.value_count(tss, 3) 309 | end 310 | 311 | def test_variance 312 | expected = [2.5] 313 | assert_elements_in_delta expected, Khiva::Features.variance(tss) 314 | end 315 | 316 | def test_variance_larger_than_standard_deviation 317 | expected = [true] 318 | assert_equal expected, Khiva::Features.variance_larger_than_standard_deviation(tss).to_a 319 | end 320 | 321 | def tss 322 | Khiva::Array.new([1, 2, 3, 4, 5], type: :f64) 323 | end 324 | end 325 | -------------------------------------------------------------------------------- /test/library_test.rb: -------------------------------------------------------------------------------- 1 | require_relative "test_helper" 2 | 3 | class LibraryTest < Minitest::Test 4 | def test_backend_info 5 | assert_match "ArrayFire", Khiva::Library.backend_info 6 | end 7 | 8 | def test_backend 9 | assert_equal :cpu, Khiva::Library.backend 10 | end 11 | 12 | def test_backends 13 | expected = mac? && !ci? ? [:cpu, :opencl] : [:cpu] 14 | assert_equal expected, Khiva::Library.backends 15 | end 16 | 17 | def test_device_id 18 | assert_equal 0, Khiva::Library.device_id 19 | end 20 | 21 | def test_device_count 22 | assert_equal 1, Khiva::Library.device_count 23 | end 24 | 25 | def test_set_device_memory_in_gb 26 | Khiva::Library.set_device_memory_in_gb(0.5) 27 | end 28 | 29 | def test_version 30 | assert_equal "0.5.0", Khiva::Library.version 31 | assert_equal "0.5.0", Khiva.lib_version # legacy 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /test/linalg_test.rb: -------------------------------------------------------------------------------- 1 | require_relative "test_helper" 2 | 3 | class LinalgTest < Minitest::Test 4 | def test_lls 5 | a = Khiva::Array.new([1, 2, 3, 4, 5], type: :f32) 6 | b = Khiva::Array.new([10, 20, 30, 40, 50], type: :f32) 7 | expected = [10] 8 | assert_elements_in_delta expected, Khiva::Linalg.lls(a, b) 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /test/matrix_test.rb: -------------------------------------------------------------------------------- 1 | require_relative "test_helper" 2 | 3 | class MatrixTest < Minitest::Test 4 | def test_find_best_n_discords 5 | profile, index = Khiva::Matrix.stomp(a1, a2, 3) 6 | discord_distances, discord_indices, subsequence_indices = Khiva::Matrix.find_best_n_discords(profile, index, 3, 2) 7 | assert_elements_in_delta [3.24950385, 3.24950385], discord_distances 8 | assert_equal [9, 0], discord_indices.to_a 9 | assert_equal [0, 9], subsequence_indices.to_a 10 | end 11 | 12 | def test_find_best_n_motifs 13 | profile, index = Khiva::Matrix.stomp(a1, a2, 3) 14 | motif_distances, motif_indices, subsequence_indices = Khiva::Matrix.find_best_n_motifs(profile, index, 3, 2) 15 | assert_elements_in_delta [0, 0], motif_distances 16 | assert_equal [9, 9], motif_indices.to_a 17 | assert_equal [1, 3], subsequence_indices.to_a 18 | end 19 | 20 | def test_find_best_n_occurrences 21 | distances, indices = Khiva::Matrix.find_best_n_occurrences(a1, a2, 1) 22 | assert_elements_in_delta [3.750405788421631], distances 23 | assert_equal [0], indices.to_a 24 | end 25 | 26 | def test_mass 27 | distances = Khiva::Matrix.mass(a1, a2) 28 | assert_elements_in_delta [3.750405788421631], distances 29 | end 30 | 31 | def test_stomp 32 | profile, index = Khiva::Matrix.stomp(a1, a2, 3) 33 | expected = [3.2495038509368896, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 3.2495038509368896] 34 | assert_elements_in_delta expected, profile 35 | assert_elements_in_delta [9, 9, 9, 9, 9, 9, 9, 9, 9, 0], index 36 | end 37 | 38 | def test_stomp_self_join 39 | profile, index = Khiva::Matrix.stomp_self_join(a1, 3) 40 | expected = [2.135256290435791, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 2.135256290435791] 41 | assert_elements_in_delta expected, profile 42 | assert_elements_in_delta [9, 9, 9, 9, 9, 9, 9, 4, 5, 0], index 43 | end 44 | 45 | def test_matrix_profile 46 | skip if ci? # TODO debug 47 | 48 | profile, index = Khiva::Matrix.matrix_profile(a1, a2, 3) 49 | expected = [1.7320508075688772, 2.449489742783178, 2.449489742783178, 2.449489742783178, 2.449489742783178, 2.449489742783178, 2.449489742783178, 2.449489742783178, 2.449489742783178, 1.7320508075688772] 50 | assert_elements_in_delta expected, profile 51 | assert_elements_in_delta [9, 0, 1, 2, 3, 4, 5, 6, 7, 0], index 52 | end 53 | 54 | def test_matrix_profile_self_join 55 | skip if ci? # TODO debug 56 | 57 | profile, index = Khiva::Matrix.matrix_profile_self_join(a1, 3) 58 | expected = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] 59 | assert_elements_in_delta expected, profile 60 | assert_elements_in_delta [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], index 61 | end 62 | 63 | def test_chains 64 | expected = [[0, 8, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 0, 0, 0, 0]] 65 | assert_elements_in_delta expected, Khiva::Matrix.chains(a1, 4) 66 | end 67 | 68 | def a1 69 | Khiva::Array.new([11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11]) 70 | end 71 | 72 | def a2 73 | Khiva::Array.new([9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9]) 74 | end 75 | end 76 | -------------------------------------------------------------------------------- /test/normalization_test.rb: -------------------------------------------------------------------------------- 1 | require_relative "test_helper" 2 | 3 | class NormalizationTest < Minitest::Test 4 | def test_decimal_scaling_norm 5 | tss = Khiva::Array.new([1, 2, 3, 4, 5], type: :f32) 6 | expected = [0.1, 0.2, 0.3, 0.4, 0.5] 7 | assert_elements_in_delta expected, Khiva::Normalization.decimal_scaling_norm(tss).to_a 8 | end 9 | 10 | def test_decimal_scaling_norm_in_place 11 | tss = Khiva::Array.new([1, 2, 3, 4, 5], type: :f32) 12 | expected = [0.1, 0.2, 0.3, 0.4, 0.5] 13 | Khiva::Normalization.decimal_scaling_norm!(tss) 14 | assert_elements_in_delta expected, tss.to_a 15 | end 16 | 17 | def test_max_min_norm 18 | tss = Khiva::Array.new([1, 2, 3, 4, 5], type: :f32) 19 | expected = [0.0, 0.25, 0.5, 0.75, 1.0] 20 | assert_elements_in_delta expected, Khiva::Normalization.max_min_norm(tss).to_a 21 | end 22 | 23 | def test_max_min_norm_in_place 24 | tss = Khiva::Array.new([1, 2, 3, 4, 5], type: :f32) 25 | expected = [0.0, 0.25, 0.5, 0.75, 1.0] 26 | Khiva::Normalization.max_min_norm!(tss) 27 | assert_elements_in_delta expected, tss.to_a 28 | end 29 | 30 | def test_mean_norm 31 | tss = Khiva::Array.new([1, 2, 3, 4, 5], type: :f32) 32 | expected = [-0.5, -0.25, 0.0, 0.25, 0.5] 33 | assert_elements_in_delta expected, Khiva::Normalization.mean_norm(tss).to_a 34 | end 35 | 36 | def test_mean_norm_norm_in_place 37 | tss = Khiva::Array.new([1, 2, 3, 4, 5], type: :f32) 38 | expected = [-0.5, -0.25, 0.0, 0.25, 0.5] 39 | Khiva::Normalization.mean_norm!(tss) 40 | assert_elements_in_delta expected, tss.to_a 41 | end 42 | 43 | def test_znorm 44 | tss = Khiva::Array.new([1, 2, 3, 4, 5], type: :f32) 45 | expected = [-1.4142135381698608, -0.7071067690849304, 0.0, 0.7071067690849304, 1.4142135381698608] 46 | assert_elements_in_delta expected, Khiva::Normalization.znorm(tss).to_a 47 | end 48 | 49 | def test_znorm_in_place 50 | tss = Khiva::Array.new([1, 2, 3, 4, 5], type: :f32) 51 | expected = [-1.4142135381698608, -0.7071067690849304, 0.0, 0.7071067690849304, 1.4142135381698608] 52 | Khiva::Normalization.znorm!(tss) 53 | assert_elements_in_delta expected, tss.to_a 54 | end 55 | end 56 | -------------------------------------------------------------------------------- /test/polynomial_test.rb: -------------------------------------------------------------------------------- 1 | require_relative "test_helper" 2 | 3 | class PolynomialTest < Minitest::Test 4 | def test_polyfit 5 | a = Khiva::Array.new([1, 2, 3, 4, 5], type: :f32) 6 | b = Khiva::Array.new([10, 20, 30, 40, 50], type: :f32) 7 | expected = [0, 10, 0] 8 | assert_elements_in_delta expected, Khiva::Polynomial.polyfit(a, b, 2) 9 | end 10 | 11 | # TODO requires complex 12 | def test_roots 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /test/regression_test.rb: -------------------------------------------------------------------------------- 1 | require_relative "test_helper" 2 | 3 | class RegressionTest < Minitest::Test 4 | def test_linear 5 | a = Khiva::Array.new([1, 2, 3, 4, 5], type: :f32) 6 | b = Khiva::Array.new([10, 20, 30, 40, 50], type: :f32) 7 | slope, intercept, rvalue, pvalue, stderrest = Khiva::Regression.linear(a, b) 8 | assert_elements_in_delta [10], slope 9 | assert_elements_in_delta [0], intercept 10 | assert_elements_in_delta [1], rvalue 11 | assert_elements_in_delta [0], pvalue 12 | assert_elements_in_delta [0], stderrest 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /test/regularization_test.rb: -------------------------------------------------------------------------------- 1 | require_relative "test_helper" 2 | 3 | class RegularizationTest < Minitest::Test 4 | def test_group_by 5 | tss = Khiva::Array.new([[1, 2, 3], [4, 5, 6]]) 6 | expected = [4, 5, 6] 7 | assert_elements_in_delta expected, Khiva::Regularization.group_by(tss, 0) 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /test/statistics_test.rb: -------------------------------------------------------------------------------- 1 | require_relative "test_helper" 2 | 3 | class StatisticsTest < Minitest::Test 4 | def test_covariance 5 | expected = [2] 6 | assert_elements_in_delta expected, Khiva::Statistics.covariance(tss).to_a 7 | end 8 | 9 | def test_kurtosis 10 | expected = [-1.2] 11 | assert_elements_in_delta expected, Khiva::Statistics.kurtosis(tss).to_a 12 | end 13 | 14 | def test_ljung_box 15 | expected = [4.316667079925537] 16 | assert_elements_in_delta expected, Khiva::Statistics.ljung_box(tss, 3).to_a 17 | end 18 | 19 | def test_moment 20 | expected = [45] 21 | assert_elements_in_delta expected, Khiva::Statistics.moment(tss, 3).to_a 22 | end 23 | 24 | def test_quantile 25 | q = Khiva::Array.new([0.5]) 26 | expected = [3] 27 | assert_elements_in_delta expected, Khiva::Statistics.quantile(tss, q).to_a 28 | end 29 | 30 | def test_quantiles_cut 31 | expected = [[0.9999999900000001, 0.9999999900000001, 2.333333373069763, 3.6666667461395264, 3.6666667461395264], [2.333333373069763, 2.333333373069763, 3.6666667461395264, 5.0, 5.0]] 32 | assert_elements_in_delta expected, Khiva::Statistics.quantiles_cut(tss, 3).to_a 33 | end 34 | 35 | def test_sample_stdev 36 | expected = [1.5811388492584229] 37 | assert_elements_in_delta expected, Khiva::Statistics.sample_stdev(tss).to_a 38 | end 39 | 40 | def test_skewness 41 | expected = [0] 42 | assert_elements_in_delta expected, Khiva::Statistics.skewness(tss).to_a 43 | end 44 | 45 | def tss 46 | Khiva::Array.new([1, 2, 3, 4, 5], type: :f32) 47 | end 48 | end 49 | -------------------------------------------------------------------------------- /test/support/array.py: -------------------------------------------------------------------------------- 1 | from khiva.array import * 2 | 3 | a = Array.from_list([[1, 2, 3], [4, 5, 6]], dtype.s32) 4 | print(a.get_dims()) 5 | print(a.get_type()) 6 | 7 | a = Array.from_list([1, 2, 3], dtype.s64) 8 | b = Array.from_list([4, 5, 6], dtype.s64) 9 | print((a + b).to_list()) 10 | -------------------------------------------------------------------------------- /test/support/clustering.py: -------------------------------------------------------------------------------- 1 | from khiva.array import * 2 | from khiva.clustering import * 3 | from khiva.library import * 4 | 5 | set_backend(KHIVABackend.KHIVA_BACKEND_CPU) 6 | 7 | a = Array.from_list([1, 2, 3, 4, 5], dtype.f64) 8 | 9 | print('k_means') 10 | res = k_means(a, 2) 11 | print(res[0].to_list()) 12 | print(res[1].to_list()) 13 | print() 14 | 15 | print('k_shape') 16 | res = k_shape(a, 2) 17 | print(res[0].to_list()) 18 | print(res[1].to_list()) 19 | print() 20 | -------------------------------------------------------------------------------- /test/support/dimensionality.py: -------------------------------------------------------------------------------- 1 | from khiva.array import * 2 | from khiva.dimensionality import * 3 | from khiva.library import * 4 | 5 | set_backend(KHIVABackend.KHIVA_BACKEND_CPU) 6 | 7 | a = Array.from_list([[1, 2, 3], [4, 5, 6]], dtype.f32) 8 | 9 | print('paa') 10 | print(paa(a, 2).to_list()) 11 | print() 12 | 13 | print('pip') 14 | print(pip(a, 3).to_list()) 15 | print() 16 | 17 | print('pla_bottom_up') 18 | print(pla_bottom_up(a, 0.1).to_list()) 19 | print() 20 | 21 | print('pla_sliding_window') 22 | print(pla_sliding_window(a, 0.1).to_list()) 23 | print() 24 | 25 | print('ramer_douglas_peucker') 26 | print(ramer_douglas_peucker(a, 0.1).to_list()) 27 | print() 28 | 29 | print('sax') 30 | print(sax(a, 2).to_list()) 31 | print() 32 | 33 | print('visvalingam') 34 | print(visvalingam(a, 2).to_list()) 35 | print() 36 | -------------------------------------------------------------------------------- /test/support/distances.py: -------------------------------------------------------------------------------- 1 | from khiva.array import * 2 | from khiva.distances import * 3 | from khiva.library import * 4 | 5 | set_backend(KHIVABackend.KHIVA_BACKEND_CPU) 6 | set_device(0) 7 | 8 | a = Array.from_list([[1, 1, 1, 1, 1], [2, 2, 2, 2, 2], [3, 3, 3, 3, 3]], dtype.s64) 9 | 10 | print('dtw') 11 | print(dtw(a).to_list()) 12 | print() 13 | 14 | print('euclidean') 15 | print(euclidean(a).to_list()) 16 | print() 17 | 18 | print('hamming') 19 | print(hamming(a).to_list()) 20 | print() 21 | 22 | print('manhattan') 23 | print(manhattan(a).to_list()) 24 | print() 25 | 26 | print('sbd') 27 | print(sbd(a).to_list()) 28 | print() 29 | 30 | print('squared_euclidean') 31 | print(squared_euclidean(a).to_list()) 32 | print() 33 | -------------------------------------------------------------------------------- /test/support/features.py: -------------------------------------------------------------------------------- 1 | from khiva.array import * 2 | from khiva.features import * 3 | from khiva.library import * 4 | 5 | set_backend(KHIVABackend.KHIVA_BACKEND_CPU) 6 | 7 | a = Array.from_list([1, 2, 3, 4, 5], dtype.f64) 8 | 9 | print('abs_energy') 10 | print(abs_energy(a).to_list()) 11 | print() 12 | 13 | print('absolute_sum_of_changes') 14 | print(absolute_sum_of_changes(a).to_list()) 15 | print() 16 | 17 | print('aggregated_autocorrelation') 18 | print(aggregated_autocorrelation(a, 0).to_list()) 19 | print() 20 | 21 | print('aggregated_linear_trend') 22 | print(aggregated_linear_trend(a, 2, 0)) 23 | print() 24 | 25 | print('approximate_entropy') 26 | print(approximate_entropy(a, 3, 1).to_list()) 27 | print() 28 | 29 | print('auto_correlation') 30 | print(auto_correlation(a, 3, False).to_list()) 31 | print() 32 | 33 | print('auto_covariance') 34 | print(auto_covariance(a).to_list()) 35 | print() 36 | 37 | print('binned_entropy') 38 | print(binned_entropy(a, 3).to_list()) 39 | print() 40 | 41 | print('c3') 42 | print(c3(a, 3).to_list()) 43 | print() 44 | 45 | print('cid_ce') 46 | print(cid_ce(a, True).to_list()) 47 | print() 48 | 49 | print('count_above_mean') 50 | print(count_above_mean(a).to_list()) 51 | print() 52 | 53 | print('count_below_mean') 54 | print(count_below_mean(a).to_list()) 55 | print() 56 | 57 | print('cross_correlation') 58 | print(cross_correlation(a, a, True).to_list()) 59 | print() 60 | 61 | print('cross_covariance') 62 | print(cross_covariance(a, a, True).to_list()) 63 | print() 64 | 65 | print('cwt_coefficients') 66 | # TODO 67 | # print(cwt_coefficients(a, [1], 1, 2).to_list()) 68 | print() 69 | 70 | print('energy_ratio_by_chunks') 71 | print(energy_ratio_by_chunks(a, 2, 1).to_list()) 72 | print() 73 | 74 | print('fft_aggregated') 75 | print(fft_aggregated(a).to_list()) 76 | print() 77 | 78 | print('fft_coefficient') 79 | print(fft_coefficient(a, 1)) 80 | print() 81 | 82 | print('first_location_of_maximum') 83 | print(first_location_of_maximum(a).to_list()) 84 | print() 85 | 86 | print('first_location_of_minimum') 87 | print(first_location_of_minimum(a).to_list()) 88 | print() 89 | 90 | print('friedrich_coefficients') 91 | print(friedrich_coefficients(a, 1, 2).to_list()) 92 | print() 93 | 94 | print('has_duplicate_max') 95 | print(has_duplicate_max(a).to_list()) 96 | print() 97 | 98 | print('has_duplicate_min') 99 | print(has_duplicate_min(a).to_list()) 100 | print() 101 | 102 | print('has_duplicates') 103 | print(has_duplicates(a).to_list()) 104 | print() 105 | 106 | print('index_mass_quantile') 107 | print(index_mass_quantile(a, 0.5).to_list()) 108 | print() 109 | 110 | print('kurtosis') 111 | print(kurtosis(a).to_list()) 112 | print() 113 | 114 | print('large_standard_deviation') 115 | print(large_standard_deviation(a, 1).to_list()) 116 | print() 117 | 118 | print('last_location_of_maximum') 119 | print(last_location_of_maximum(a).to_list()) 120 | print() 121 | 122 | print('last_location_of_minimum') 123 | print(last_location_of_minimum(a).to_list()) 124 | print() 125 | 126 | print('length') 127 | print(length(a).to_list()) 128 | print() 129 | 130 | print('linear_trend') 131 | print(linear_trend(a)) 132 | print() 133 | 134 | print('local_maximals') 135 | print(local_maximals(a).to_list()) 136 | print() 137 | 138 | print('longest_strike_above_mean') 139 | print(longest_strike_above_mean(a).to_list()) 140 | print() 141 | 142 | print('longest_strike_below_mean') 143 | print(longest_strike_below_mean(a).to_list()) 144 | print() 145 | 146 | print('max_langevin_fixed_point') 147 | print(max_langevin_fixed_point(a, 1, 2).to_list()) 148 | print() 149 | 150 | print('maximum') 151 | print(maximum(a).to_list()) 152 | print() 153 | 154 | print('mean') 155 | print(mean(a).to_list()) 156 | print() 157 | 158 | print('mean_absolute_change') 159 | print(mean_absolute_change(a).to_list()) 160 | print() 161 | 162 | print('mean_change') 163 | print(mean_change(a).to_list()) 164 | print() 165 | 166 | print('mean_second_derivative_central') 167 | print(mean_second_derivative_central(a).to_list()) 168 | print() 169 | 170 | print('median') 171 | print(median(a).to_list()) 172 | print() 173 | 174 | print('minimum') 175 | print(minimum(a).to_list()) 176 | print() 177 | 178 | print('number_crossing_m') 179 | print(number_crossing_m(a, 3).to_list()) 180 | print() 181 | 182 | print('number_cwt_peaks') 183 | # print(number_cwt_peaks(a, 3).to_list()) 184 | print() 185 | 186 | print('number_peaks') 187 | print(number_peaks(a, 2).to_list()) 188 | print() 189 | 190 | print('partial_autocorrelation') 191 | lags = Array.from_list([1], dtype.s32) 192 | print(partial_autocorrelation(a, lags).to_list()) 193 | print() 194 | 195 | print('percentage_of_reoccurring_datapoints_to_all_datapoints') 196 | print(percentage_of_reoccurring_datapoints_to_all_datapoints(a, False).to_list()) 197 | print() 198 | 199 | print('percentage_of_reoccurring_values_to_all_values') 200 | print(percentage_of_reoccurring_values_to_all_values(a, False).to_list()) 201 | print() 202 | 203 | print('quantile') 204 | q = Array.from_list([0.5], dtype.f64) 205 | print(quantile(a, q).to_list()) 206 | print() 207 | 208 | print('range_count') 209 | print(range_count(a, 2, 4).to_list()) 210 | print() 211 | 212 | print('ratio_beyond_r_sigma') 213 | print(ratio_beyond_r_sigma(a, 1).to_list()) 214 | print() 215 | 216 | print('ratio_value_number_to_time_series_length') 217 | print(ratio_value_number_to_time_series_length(a).to_list()) 218 | print() 219 | 220 | print('sample_entropy') 221 | print(sample_entropy(a).to_list()) 222 | print() 223 | 224 | print('skewness') 225 | print(skewness(a).to_list()) 226 | print() 227 | 228 | print('spkt_welch_density') 229 | print(spkt_welch_density(a, 1).to_list()) 230 | print() 231 | 232 | print('standard_deviation') 233 | print(standard_deviation(a).to_list()) 234 | print() 235 | 236 | print('sum_of_reoccurring_datapoints') 237 | print(sum_of_reoccurring_datapoints(a).to_list()) 238 | print() 239 | 240 | print('sum_of_reoccurring_values') 241 | print(sum_of_reoccurring_values(a).to_list()) 242 | print() 243 | 244 | print('sum_values') 245 | print(sum_values(a).to_list()) 246 | print() 247 | 248 | print('symmetry_looking') 249 | print(symmetry_looking(a, 0.5).to_list()) 250 | print() 251 | 252 | print('time_reversal_asymmetry_statistic') 253 | print(time_reversal_asymmetry_statistic(a, 2).to_list()) 254 | print() 255 | 256 | print('value_count') 257 | print(value_count(a, 3).to_list()) 258 | print() 259 | 260 | print('variance') 261 | print(variance(a).to_list()) 262 | print() 263 | 264 | print('variance_larger_than_standard_deviation') 265 | print(variance_larger_than_standard_deviation(a).to_list()) 266 | print() 267 | -------------------------------------------------------------------------------- /test/support/library.py: -------------------------------------------------------------------------------- 1 | from khiva.library import * 2 | 3 | print('backend_info') 4 | print(get_backend_info()) 5 | 6 | print('backend') 7 | print(get_backend()) 8 | 9 | print('backends') 10 | print(get_backends()) 11 | 12 | print('device_id') 13 | print(get_device_id()) 14 | 15 | print('device_count') 16 | print(get_device_count()) 17 | -------------------------------------------------------------------------------- /test/support/linalg.py: -------------------------------------------------------------------------------- 1 | from khiva.array import * 2 | from khiva.library import * 3 | from khiva.linalg import * 4 | 5 | set_backend(KHIVABackend.KHIVA_BACKEND_CPU) 6 | 7 | a = Array.from_list([1, 2, 3, 4, 5], dtype.f64) 8 | b = Array.from_list([10, 20, 30, 40, 50], dtype.f64) 9 | 10 | print('lls') 11 | print(lls(a, b).to_list()) 12 | print() 13 | -------------------------------------------------------------------------------- /test/support/matrix.py: -------------------------------------------------------------------------------- 1 | from khiva.array import * 2 | from khiva.library import * 3 | from khiva.matrix import * 4 | 5 | set_backend(KHIVABackend.KHIVA_BACKEND_CPU) 6 | 7 | a1 = Array.from_list([11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11], dtype.s32) 8 | a2 = Array.from_list([9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9], dtype.s32) 9 | stomp_result = stomp(a1, a2, 3) 10 | 11 | find_best_n_discords_result = find_best_n_discords(stomp_result[0], stomp_result[1], 3, 2) 12 | 13 | print('find_best_n_discords_result') 14 | print(find_best_n_discords_result[0].to_list()) 15 | print(find_best_n_discords_result[1].to_list()) 16 | print(find_best_n_discords_result[2].to_list()) 17 | print() 18 | 19 | find_best_n_motifs_result = find_best_n_motifs(stomp_result[0], stomp_result[1], 3, 2) 20 | 21 | print('find_best_n_motifs_result') 22 | print(find_best_n_motifs_result[0].to_list()) 23 | print(find_best_n_motifs_result[1].to_list()) 24 | print(find_best_n_motifs_result[2].to_list()) 25 | print() 26 | 27 | print('find_best_n_occurrences') 28 | res = find_best_n_occurrences(a1, a2, 1) 29 | print(res[0].to_list()) 30 | print(res[1].to_list()) 31 | print() 32 | 33 | print('mass') 34 | print(mass(a1, a2).to_list()) 35 | print() 36 | 37 | print('stomp') 38 | res = stomp(a1, a2, 3) 39 | print(res[0].to_list()) 40 | print(res[1].to_list()) 41 | print() 42 | 43 | print('stomp_self_join') 44 | res = stomp_self_join(a1, 3) 45 | print(res[0].to_list()) 46 | print(res[1].to_list()) 47 | print() 48 | 49 | print('matrix_profile') 50 | res = matrix_profile(a1, a2, 3) 51 | print(res[0].to_list()) 52 | print(res[1].to_list()) 53 | print() 54 | 55 | print('matrix_profile_self_join') 56 | res = matrix_profile_self_join(a1, 3) 57 | print(res[0].to_list()) 58 | print(res[1].to_list()) 59 | print() 60 | 61 | print('chains') 62 | print(get_chains(a1, 4).to_list()) 63 | print() 64 | -------------------------------------------------------------------------------- /test/support/normalization.py: -------------------------------------------------------------------------------- 1 | from khiva.array import * 2 | from khiva.library import * 3 | from khiva.normalization import * 4 | 5 | set_backend(KHIVABackend.KHIVA_BACKEND_CPU) 6 | 7 | a = Array.from_list([1, 2, 3, 4, 5], dtype.f32) 8 | 9 | print('decimal_scaling_norm') 10 | print(decimal_scaling_norm(a).to_list()) 11 | print() 12 | 13 | print('decimal_scaling_norm_in_place') 14 | b = a.copy() 15 | decimal_scaling_norm_in_place(b) 16 | print(b.to_list()) 17 | print() 18 | 19 | print('max_min_norm') 20 | print(max_min_norm(a).to_list()) 21 | print() 22 | 23 | print('max_min_norm_in_place') 24 | b = a.copy() 25 | max_min_norm_in_place(b) 26 | print(b.to_list()) 27 | print() 28 | 29 | print('mean_norm') 30 | print(mean_norm(a).to_list()) 31 | print() 32 | 33 | print('mean_norm_in_place') 34 | b = a.copy() 35 | mean_norm_in_place(b) 36 | print(b.to_list()) 37 | print() 38 | 39 | print('znorm') 40 | print(znorm(a).to_list()) 41 | print() 42 | 43 | print('znorm_in_place') 44 | b = a.copy() 45 | znorm_in_place(b) 46 | print(b.to_list()) 47 | print() 48 | -------------------------------------------------------------------------------- /test/support/polynomial.py: -------------------------------------------------------------------------------- 1 | from khiva.array import * 2 | from khiva.library import * 3 | from khiva.polynomial import * 4 | 5 | set_backend(KHIVABackend.KHIVA_BACKEND_CPU) 6 | 7 | a = Array.from_list([1, 2, 3, 4, 5], dtype.f64) 8 | b = Array.from_list([10, 20, 30, 40, 50], dtype.f64) 9 | 10 | print('polyfit') 11 | print(polyfit(a, b, 2).to_list()) 12 | print() 13 | 14 | print('roots') 15 | print(roots(a).to_list()) 16 | print() 17 | -------------------------------------------------------------------------------- /test/support/regression.py: -------------------------------------------------------------------------------- 1 | from khiva.array import * 2 | from khiva.library import * 3 | from khiva.regression import * 4 | 5 | set_backend(KHIVABackend.KHIVA_BACKEND_CPU) 6 | 7 | a = Array.from_list([1, 2, 3, 4, 5], dtype.f64) 8 | b = Array.from_list([10, 20, 30, 40, 50], dtype.f64) 9 | 10 | print('linear') 11 | res = linear(a, b) 12 | print(res[0].to_list()) 13 | print(res[1].to_list()) 14 | print(res[2].to_list()) 15 | print(res[3].to_list()) 16 | print(res[4].to_list()) 17 | print() 18 | -------------------------------------------------------------------------------- /test/support/regularization.py: -------------------------------------------------------------------------------- 1 | from khiva.array import * 2 | from khiva.library import * 3 | from khiva.regularization import * 4 | 5 | set_backend(KHIVABackend.KHIVA_BACKEND_CPU) 6 | 7 | a = Array.from_list([[1, 2, 3], [4, 5, 6]], dtype.f64) 8 | 9 | print('group_by') 10 | print(group_by(a, 0).to_list()) 11 | print() 12 | -------------------------------------------------------------------------------- /test/support/statistics.py: -------------------------------------------------------------------------------- 1 | from khiva.array import * 2 | from khiva.library import * 3 | from khiva.statistics import * 4 | 5 | set_backend(KHIVABackend.KHIVA_BACKEND_CPU) 6 | 7 | a = Array.from_list([1, 2, 3, 4, 5], dtype.f64) 8 | 9 | print('covariance') 10 | print(covariance(a).to_list()) 11 | print() 12 | 13 | print('kurtosis') 14 | print(kurtosis(a).to_list()) 15 | print() 16 | 17 | print('ljung_box') 18 | print(ljung_box(a, 3).to_list()) 19 | print() 20 | 21 | print('moment') 22 | print(moment(a, 3).to_list()) 23 | print() 24 | 25 | print('quantile') 26 | q = Array.from_list([0.5], dtype.f64) 27 | print(quantile(a, q).to_list()) 28 | print() 29 | 30 | print('quantiles_cut') 31 | print(quantiles_cut(a, 3).to_list()) 32 | print() 33 | 34 | print('sample_stdev') 35 | print(sample_stdev(a).to_list()) 36 | print() 37 | 38 | print('skewness') 39 | print(skewness(a).to_list()) 40 | print() 41 | -------------------------------------------------------------------------------- /test/test_helper.rb: -------------------------------------------------------------------------------- 1 | require "bundler/setup" 2 | Bundler.require(:default) 3 | require "minitest/autorun" 4 | require "minitest/pride" 5 | 6 | class Minitest::Test 7 | def assert_elements_in_delta(expected, actual) 8 | actual = actual.to_a 9 | assert_equal expected.size, actual.size 10 | expected.zip(actual) do |exp, act| 11 | if exp.is_a?(Array) 12 | assert_elements_in_delta exp, act 13 | else 14 | if exp.finite? 15 | assert_in_delta exp, act 16 | elsif exp.respond_to?(:nan?) && exp.nan? 17 | assert act.nan? 18 | else 19 | assert_equal exp, act 20 | end 21 | end 22 | end 23 | end 24 | 25 | def mac? 26 | RbConfig::CONFIG["host_os"] =~ /darwin/i 27 | end 28 | 29 | def ci? 30 | ENV["CI"] 31 | end 32 | end 33 | 34 | Khiva::Library.set_backend(:cpu) 35 | Khiva::Library.set_device(0) 36 | --------------------------------------------------------------------------------