├── .docs └── Readme.hbs ├── .gitignore ├── .gitmodules ├── .prettierignore ├── History.md ├── LICENSE ├── Makefile ├── README.md ├── benchmark ├── bin.js ├── iris │ ├── Makefile │ ├── cross-validation-benchmark.js │ ├── cross-validation.cpp │ ├── data-kernel-rbf-gamma-2e-1.txt │ ├── data.txt │ ├── grid-search-benchmark-ml-svm.js │ ├── grid-search-benchmark.js │ ├── grid-search.cpp │ ├── precomputed-cv-benchmark.js │ ├── precomputed-cv.cpp │ ├── util.cpp │ ├── util.h │ └── util.js ├── saveData.js └── worker.js ├── build ├── libsvm.js └── libsvm.wasm ├── demos ├── .eslintrc.yml ├── actions │ ├── SVC.js │ ├── SVR.js │ ├── index.js │ └── types.js ├── bootstrap.jsx ├── components │ ├── Benchmark.jsx │ ├── Canvas.jsx │ ├── ConfigField.jsx │ ├── ControlBar.jsx │ ├── Navigation.jsx │ ├── OneClassSVC.jsx │ ├── SVC.jsx │ ├── SVR.jsx │ └── TableConfigField.jsx ├── constants.js ├── containers │ ├── App.jsx │ ├── Benchmarks.jsx │ ├── ChooseLabel.jsx │ ├── OneClassSVCConfig.jsx │ ├── SVCCanvas.jsx │ ├── SVCConfig.jsx │ ├── SVRCanvas.jsx │ ├── SVRConfig.jsx │ └── connectStyle.js ├── hooks │ └── useCanvasPoints.js ├── index.html ├── libsvm.wasm ├── public │ └── manifest.json ├── reducers │ ├── reducers.js │ └── styleReducer.js ├── selectors │ └── index.js ├── store.js ├── style.css ├── util.js ├── util │ └── fields.js └── vite.config.mjs ├── examples ├── bodyfat.js ├── bodyfat_scale.txt ├── oneClass.js ├── precomputed.js ├── probabilities.js ├── svr.js └── xor.js ├── js-interfaces.c ├── js-interfaces.h ├── package-lock.json ├── package.json ├── src ├── loadSVM.js └── util.js ├── test └── util.js ├── tools └── iris.js └── wasm.js /.docs/Readme.hbs: -------------------------------------------------------------------------------- 1 | # [DEMO](https://mljs.github.io/libsvm/) 2 | 3 | Port of to port libsvm v3.22 using [emscripten](https://github.com/kripken/emscripten) , for usage in the browser or nodejs. 4 | 5 | What is libsvm? 6 | libsvm is a [c++ library](https://github.com/cjlin1/libsvm) developped by Chih-Chung Chang and Chih-Jen Lin that allows to do support vector machine (aka SVM) classification and regression. 7 | 8 | Resources about libsvm: 9 | - [libsvm website](https://www.csie.ntu.edu.tw/~cjlin/libsvm/) 10 | - [libsvm github repository](https://github.com/cjlin1/libsvm) 11 | - [Wikipedia article](https://en.wikipedia.org/wiki/Support_vector_machine) 12 | - Chih-Chung Chang and Chih-Jen Lin, LIBSVM : a library for support vector machines. ACM Transactions on Intelligent Systems and Technology, 2:27:1--27:27, 2011. 13 | 14 | 15 | 16 | # Usage 17 | ## Install 18 | ```bash 19 | npm install libsvm-js 20 | ``` 21 | 22 | ## Basic usage 23 | This example illustrates how to use the library to train and use an SVM classifier. 24 | ```js 25 | import { loadSVM } from 'libsvm-js'; 26 | 27 | const SVM = await loadSVM(); 28 | const svm = new SVM({ 29 | kernel: SVM.KERNEL_TYPES.RBF, // The type of kernel I want to use 30 | type: SVM.SVM_TYPES.C_SVC, // The type of SVM I want to run 31 | gamma: 1, // RBF kernel gamma parameter 32 | cost: 1 // C_SVC cost parameter 33 | }); 34 | 35 | // This is the xor problem 36 | // 37 | // 1 0 38 | // 0 1 39 | const features = [[0, 0], [1, 1], [1, 0], [0, 1]]; 40 | const labels = [0, 0, 1, 1]; 41 | svm.train(features, labels); // train the model 42 | const predictedLabel = svm.predictOne([0.7, 0.8]); 43 | console.log(predictedLabel) // 0 44 | ``` 45 | 46 | # Benchmarks 47 | You can compare the performance of the library in various environments. Run `npm run benchmark` to run the benchmarks with native c/c++ code and with the compiled code with your local version of node.js. For browser performance, go to the [web benchmark page](https://mljs.github.io/libsvm/#benchmarks). 48 | 49 | Speed is mainly affected by the javascript engine that compiles it. Since WebAssembly has been stabilized and is an optimization phase, more recent engines are almost always faster. 50 | 51 | Speed is also affected by the version of emscripten that generated the build or the options used in the build. I will try to keep up with any improvement that might significantly impact the performance. 52 | 53 | ## Cross-validation benchmark 54 | There is a benchmark on the iris dataset to get a feeling for how performance compares on different platforms. 55 | 56 | After installing the dependencies and compiling the project you can run `npm run benchmark` to run the benchmarks with native code and in node.js. The benchmarks are also available on our demo page to test performance in web browsers. 57 | 58 | The benchmarks only consider runtime performance, not load and parse performance. 59 | 60 | # What is WebAssembly ? 61 | 62 | From [webassembly.org](http://webassembly.org) 63 | > WebAssembly or wasm is a new portable, size- and load-time-efficient format suitable for compilation to the web 64 | 65 | WebAssembly is currently supported in the latest stable versions of Chrome / Chromium, Firefox and Safari. 66 | 67 | # API Documentation 68 | {{>main}} 69 | 70 | # LICENSE 71 | BSD-3-Clause 72 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | demo-dist 4 | benchmark/**/bin 5 | svm.o 6 | examples/bodyfat.model -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "libsvm"] 2 | path = libsvm 3 | url = https://github.com/cjlin1/libsvm.git 4 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | package.json -------------------------------------------------------------------------------- /History.md: -------------------------------------------------------------------------------- 1 | 2 | ## [0.2.1](https://github.com/mljs/libsvm/compare/v0.2.0...v0.2.1) (2018-05-24) 3 | 4 | 5 | ### Bug Fixes 6 | 7 | * use prepare instead of preinstall for git submodule installation ([d61f5f8](https://github.com/mljs/libsvm/commit/d61f5f8)) 8 | 9 | 10 | 11 | 12 | # [0.2.0](https://github.com/mljs/libsvm/compare/v0.1.3...v0.2.0) (2018-04-04) 13 | 14 | 15 | 16 | 17 | ## [0.1.3](https://github.com/mljs/libsvm/compare/v0.1.2...v0.1.3) (2017-12-12) 18 | 19 | 20 | 21 | 22 | ## [0.1.2](https://github.com/mljs/libsvm/compare/v0.1.1...v0.1.2) (2017-07-25) 23 | 24 | 25 | 26 | 27 | ## [0.1.1](https://github.com/mljs/libsvm/compare/v0.1.0...v0.1.1) (2017-07-06) 28 | 29 | 30 | 31 | 32 | # 0.1.0 (2017-06-02) 33 | 34 | 35 | ### Bug Fixes 36 | 37 | * this binding in canvas click callback ([870f4b6](https://github.com/mljs/libsvm/commit/870f4b6)) 38 | 39 | 40 | ### Features 41 | 42 | * add crossValidation ([1799a64](https://github.com/mljs/libsvm/commit/1799a64)) 43 | * serialize and deserialize model ([fcf1dc3](https://github.com/mljs/libsvm/commit/fcf1dc3)) 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2000-2014 Chih-Chung Chang and Chih-Jen Lin 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright 12 | notice, this list of conditions and the following disclaimer in the 13 | documentation and/or other materials provided with the distribution. 14 | 15 | 3. Neither name of copyright holders nor the names of its contributors 16 | may be used to endorse or promote products derived from this software 17 | without specific prior written permission. 18 | 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR 24 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 25 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 26 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 27 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 28 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 29 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC = emcc 2 | CXX = em++ 3 | 4 | CFLAGS = -Wall -Wconversion -O3 -fPIC 5 | BUILD_DIR=build 6 | EXPORTED_FUNCTIONS="['_malloc', '_free', '_parse_command_line', '_create_svm_nodes', '_add_instance', '_libsvm_train_problem', '_libsvm_train', '_libsvm_predict_one', '_libsvm_predict_one_probability', '_get_svr_epsilon', '_svm_free_model', '_svm_get_svm_type', '_svm_get_nr_sv', '_svm_get_nr_class', '_svm_get_sv_indices', '_svm_get_labels', '_svm_get_svr_probability', '_libsvm_cross_validation', '_free_problem', '_serialize_model', '_deserialize_model']" 7 | 8 | all: wasm 9 | 10 | svm.o: libsvm/svm.cpp libsvm/svm.h 11 | $(CXX) $(CFLAGS) -c libsvm/svm.cpp -o svm.o 12 | 13 | wasm: js-interfaces.c svm.o libsvm/svm.h 14 | mkdir -p $(BUILD_DIR); $(CC) $(CFLAGS) js-interfaces.c svm.o -o $(BUILD_DIR)/libsvm.js -s DISABLE_EXCEPTION_CATCHING=0 -s NODEJS_CATCH_EXIT=0 -s "EXPORT_NAME=\"SVM\"" -s MODULARIZE=1 -s EXPORT_ES6=1 -s WASM=1 -s ALLOW_MEMORY_GROWTH=1 -s EXPORTED_FUNCTIONS=$(EXPORTED_FUNCTIONS) -s EXPORTED_RUNTIME_METHODS='["cwrap", "HEAPF64", 'HEAP32', 'UTF8ToString']' 15 | 16 | clean: 17 | rm -f *~ ./svm.o 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [DEMO](https://mljs.github.io/libsvm/) 2 | 3 | Port of to port libsvm v3.22 using [emscripten](https://github.com/kripken/emscripten) , for usage in the browser or nodejs. 4 | 5 | What is libsvm? 6 | libsvm is a [c++ library](https://github.com/cjlin1/libsvm) developped by Chih-Chung Chang and Chih-Jen Lin that allows to do support vector machine (aka SVM) classification and regression. 7 | 8 | Resources about libsvm: 9 | - [libsvm website](https://www.csie.ntu.edu.tw/~cjlin/libsvm/) 10 | - [libsvm github repository](https://github.com/cjlin1/libsvm) 11 | - [Wikipedia article](https://en.wikipedia.org/wiki/Support_vector_machine) 12 | - Chih-Chung Chang and Chih-Jen Lin, LIBSVM : a library for support vector machines. ACM Transactions on Intelligent Systems and Technology, 2:27:1--27:27, 2011. 13 | 14 | 15 | 16 | # Usage 17 | ## Install 18 | ```bash 19 | npm install libsvm-js 20 | ``` 21 | 22 | ## Basic usage 23 | This example illustrates how to use the library to train and use an SVM classifier. 24 | ```js 25 | import { loadSVM } from 'libsvm-js'; 26 | 27 | const SVM = await loadSVM(); 28 | const svm = new SVM({ 29 | kernel: SVM.KERNEL_TYPES.RBF, // The type of kernel I want to use 30 | type: SVM.SVM_TYPES.C_SVC, // The type of SVM I want to run 31 | gamma: 1, // RBF kernel gamma parameter 32 | cost: 1 // C_SVC cost parameter 33 | }); 34 | 35 | // This is the xor problem 36 | // 37 | // 1 0 38 | // 0 1 39 | const features = [[0, 0], [1, 1], [1, 0], [0, 1]]; 40 | const labels = [0, 0, 1, 1]; 41 | svm.train(features, labels); // train the model 42 | const predictedLabel = svm.predictOne([0.7, 0.8]); 43 | console.log(predictedLabel) // 0 44 | ``` 45 | 46 | # Benchmarks 47 | You can compare the performance of the library in various environments. Run `npm run benchmark` to run the benchmarks with native c/c++ code and with the compiled code with your local version of node.js. For browser performance, go to the [web benchmark page](https://mljs.github.io/libsvm/#benchmarks). 48 | 49 | Speed is mainly affected by the javascript engine that compiles it. Since WebAssembly has been stabilized and is an optimization phase, more recent engines are almost always faster. 50 | 51 | Speed is also affected by the version of emscripten that generated the build or the options used in the build. I will try to keep up with any improvement that might significantly impact the performance. 52 | 53 | ## Cross-validation benchmark 54 | There is a benchmark on the iris dataset to get a feeling for how performance compares on different platforms. 55 | 56 | After installing the dependencies and compiling the project you can run `npm run benchmark` to run the benchmarks with native code and in node.js. The benchmarks are also available on our demo page to test performance in web browsers. 57 | 58 | The benchmarks only consider runtime performance, not load and parse performance. 59 | 60 | # What is WebAssembly ? 61 | 62 | From [webassembly.org](http://webassembly.org) 63 | > WebAssembly or wasm is a new portable, size- and load-time-efficient format suitable for compilation to the web 64 | 65 | WebAssembly is currently supported in the latest stable versions of Chrome / Chromium, Firefox and Safari. 66 | 67 | # API Documentation 68 | 69 | 70 | ## SVM 71 | **Kind**: global class 72 | 73 | * [SVM](#SVM) 74 | * [new SVM(options)](#new_SVM_new) 75 | * _instance_ 76 | * [.train(samples, labels)](#SVM+train) 77 | * [.crossValidation(samples, labels, kFold)](#SVM+crossValidation) ⇒ Array.<number> 78 | * [.free()](#SVM+free) 79 | * [.predictOne(sample)](#SVM+predictOne) ⇒ number 80 | * [.predict(samples)](#SVM+predict) ⇒ Array.<number> 81 | * [.predictProbability(samples)](#SVM+predictProbability) ⇒ Array.<object> 82 | * [.predictOneProbability(sample)](#SVM+predictOneProbability) ⇒ object 83 | * [.predictOneInterval(sample, confidence)](#SVM+predictOneInterval) ⇒ object 84 | * [.predictInterval(samples, confidence)](#SVM+predictInterval) ⇒ Array.<object> 85 | * [.getLabels()](#SVM+getLabels) ⇒ Array.<number> 86 | * [.getSVIndices()](#SVM+getSVIndices) ⇒ Array.<number> 87 | * [.serializeModel()](#SVM+serializeModel) ⇒ string 88 | * _static_ 89 | * [.SVM_TYPES](#SVM.SVM_TYPES) : Object 90 | * [.KERNEL_TYPES](#SVM.KERNEL_TYPES) : Object 91 | * [.load(serializedModel)](#SVM.load) ⇒ [SVM](#SVM) 92 | 93 | 94 | 95 | ### new SVM(options) 96 | 97 | | Param | Type | Default | Description | 98 | | --- | --- | --- | --- | 99 | | options | object | | | 100 | | [options.type] | number | SVM_TYPES.C_SVC | Type of SVM to perform, | 101 | | [options.kernel] | number | KERNEL_TYPES.RBF | Kernel function, | 102 | | [options.degree] | number | 3 | Degree of polynomial, for polynomial kernel | 103 | | [options.gamma] | number | | Gamma parameter of the RBF, Polynomial and Sigmoid kernels. Default value is 1/num_features | 104 | | [options.coef0] | number | 0 | coef0 parameter for Polynomial and Sigmoid kernels | 105 | | [options.cost] | number | 1 | Cost parameter, for C SVC, Epsilon SVR and NU SVR | 106 | | [options.nu] | number | 0.5 | For NU SVC and NU SVR | 107 | | [options.epsilon] | number | 0.1 | For epsilon SVR | 108 | | [options.cacheSize] | number | 100 | Cache size in MB | 109 | | [options.tolerance] | number | 0.001 | Tolerance | 110 | | [options.shrinking] | boolean | true | Use shrinking euristics (faster), | 111 | | [options.probabilityEstimates] | boolean | false | weather to train SVC/SVR model for probability estimates, | 112 | | [options.weight] | object | | Set weight for each possible class | 113 | | [options.quiet] | boolean | true | Print info during training if false | 114 | 115 | 116 | 117 | ### svM.train(samples, labels) 118 | Trains the SVM model. 119 | 120 | **Kind**: instance method of [SVM](#SVM) 121 | **Throws**: 122 | 123 | - if SVM instance was instantiated from SVM.load. 124 | 125 | 126 | | Param | Type | Description | 127 | | --- | --- | --- | 128 | | samples | Array.<Array.<number>> | The training samples. First level of array are the samples, second level are the individual features | 129 | | labels | Array.<number> | The training labels. It should have the same size as the samples. If you are training a classification model, the labels should be distinct integers for each class. If you are training a regression model, each label should be the value of the predicted variable. | 130 | 131 | 132 | 133 | ### svM.crossValidation(samples, labels, kFold) ⇒ Array.<number> 134 | Performs k-fold cross-validation (KF-CV). KF-CV separates the data-set into kFold random equally sized partitions, 135 | and uses each as a validation set, with all other partitions used in the training set. Observations left over 136 | from if kFold does not divide the number of observations are left out of the cross-validation process. If 137 | kFold is one, this is equivalent to a leave-on-out cross-validation 138 | 139 | **Kind**: instance method of [SVM](#SVM) 140 | **Returns**: Array.<number> - The array of predicted labels produced by the cross validation. Has a size equal to 141 | the number of samples provided as input. 142 | **Throws**: 143 | 144 | - if SVM instance was instantiated from SVM.load. 145 | 146 | 147 | | Param | Type | Description | 148 | | --- | --- | --- | 149 | | samples | Array.<Array.<number>> | The training samples. | 150 | | labels | Array.<number> | The training labels. | 151 | | kFold | number | Number of datasets into which to split the training set. | 152 | 153 | 154 | 155 | ### svM.free() 156 | Free the memory allocated for the model. Since this memory is stored in the memory model of emscripten, it is 157 | allocated within an ArrayBuffer and WILL NOT BE GARBARGE COLLECTED, you have to explicitly free it. So 158 | not calling this will result in memory leaks. As of today in the browser, there is no way to hook the 159 | garbage collection of the SVM object to free it automatically. 160 | Free the memory that was created by the compiled libsvm library to. 161 | store the model. This model is reused every time the predict method is called. 162 | 163 | **Kind**: instance method of [SVM](#SVM) 164 | 165 | 166 | ### svM.predictOne(sample) ⇒ number 167 | Predict the label of one sample. 168 | 169 | **Kind**: instance method of [SVM](#SVM) 170 | **Returns**: number - - The predicted label. 171 | 172 | | Param | Type | Description | 173 | | --- | --- | --- | 174 | | sample | Array.<number> | The sample to predict. | 175 | 176 | 177 | 178 | ### svM.predict(samples) ⇒ Array.<number> 179 | Predict the label of many samples. 180 | 181 | **Kind**: instance method of [SVM](#SVM) 182 | **Returns**: Array.<number> - - The predicted labels. 183 | 184 | | Param | Type | Description | 185 | | --- | --- | --- | 186 | | samples | Array.<Array.<number>> | The samples to predict. | 187 | 188 | 189 | 190 | ### svM.predictProbability(samples) ⇒ Array.<object> 191 | Predict the label with probability estimate of many samples. 192 | 193 | **Kind**: instance method of [SVM](#SVM) 194 | **Returns**: Array.<object> - - An array of objects containing the prediction label and the probability estimates for each label 195 | 196 | | Param | Type | Description | 197 | | --- | --- | --- | 198 | | samples | Array.<Array.<number>> | The samples to predict. | 199 | 200 | 201 | 202 | ### svM.predictOneProbability(sample) ⇒ object 203 | Predict the label with probability estimate. 204 | 205 | **Kind**: instance method of [SVM](#SVM) 206 | **Returns**: object - - An object containing the prediction label and the probability estimates for each label 207 | 208 | | Param | Type | 209 | | --- | --- | 210 | | sample | Array.<number> | 211 | 212 | 213 | 214 | ### svM.predictOneInterval(sample, confidence) ⇒ object 215 | Predict a regression value with a confidence interval 216 | 217 | **Kind**: instance method of [SVM](#SVM) 218 | **Returns**: object - - An object containing the prediction value and the lower and upper bounds of the confidence interval 219 | 220 | | Param | Type | Description | 221 | | --- | --- | --- | 222 | | sample | Array.<number> | | 223 | | confidence | number | A value between 0 and 1. For example, a value 0.95 will give you the 95% confidence interval of the predicted value. | 224 | 225 | 226 | 227 | ### svM.predictInterval(samples, confidence) ⇒ Array.<object> 228 | Predict regression values with confidence intervals 229 | 230 | **Kind**: instance method of [SVM](#SVM) 231 | **Returns**: Array.<object> - - An array of objects each containing the prediction label and the probability estimates for each label 232 | 233 | | Param | Type | Description | 234 | | --- | --- | --- | 235 | | samples | Array.<Array.<number>> | An array of samples. | 236 | | confidence | number | A value between 0 and 1. For example, a value 0.95 will give you the 95% confidence interval of the predicted value. | 237 | 238 | 239 | 240 | ### svM.getLabels() ⇒ Array.<number> 241 | Get the array of labels from the model. Useful when creating an SVM instance with SVM.load 242 | 243 | **Kind**: instance method of [SVM](#SVM) 244 | **Returns**: Array.<number> - - The list of labels. 245 | 246 | 247 | ### svM.getSVIndices() ⇒ Array.<number> 248 | Get the indices of the support vectors from the training set passed to the train method. 249 | 250 | **Kind**: instance method of [SVM](#SVM) 251 | **Returns**: Array.<number> - - The list of indices from the training samples. 252 | 253 | 254 | ### svM.serializeModel() ⇒ string 255 | Uses libsvm's serialization method of the model. 256 | 257 | **Kind**: instance method of [SVM](#SVM) 258 | **Returns**: string - The serialization string. 259 | 260 | 261 | ### SVM.SVM\_TYPES : Object 262 | SVM classification and regression types 263 | 264 | **Kind**: static property of [SVM](#SVM) 265 | **Properties** 266 | 267 | | Name | Description | 268 | | --- | --- | 269 | | C_SVC | The C support vector classifier type | 270 | | NU_SVC | The nu support vector classifier type | 271 | | ONE_CLASS | The one-class support vector classifier type | 272 | | EPSILON_SVR | The epsilon support vector regression type | 273 | | NU_SVR | The nu support vector regression type | 274 | 275 | 276 | 277 | ### SVM.KERNEL\_TYPES : Object 278 | SVM kernel types 279 | 280 | **Kind**: static property of [SVM](#SVM) 281 | **Properties** 282 | 283 | | Name | Description | 284 | | --- | --- | 285 | | LINEAR | Linear kernel | 286 | | POLYNOMIAL | Polynomial kernel | 287 | | RBF | Radial basis function (gaussian) kernel | 288 | | SIGMOID | Sigmoid kernel | 289 | 290 | 291 | 292 | ### SVM.load(serializedModel) ⇒ [SVM](#SVM) 293 | Create a SVM instance from the serialized model. 294 | 295 | **Kind**: static method of [SVM](#SVM) 296 | **Returns**: [SVM](#SVM) - - SVM instance that contains the model. 297 | 298 | | Param | Type | Description | 299 | | --- | --- | --- | 300 | | serializedModel | string | The serialized model. | 301 | 302 | 303 | # LICENSE 304 | BSD-3-Clause 305 | -------------------------------------------------------------------------------- /benchmark/bin.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import Table from 'cli-table'; 4 | import { spawn } from 'node:child_process'; 5 | import { loadSVM } from '../wasm.js'; 6 | 7 | const argv = process.argv.slice(2); 8 | let benchmarks = argv[0]; 9 | let modes = argv[1]; 10 | if (benchmarks === 'all' || !benchmarks) { 11 | benchmarks = [ 12 | 'iris/cross-validation', 13 | 'iris/grid-search', 14 | 'iris/precomputed-cv', 15 | ]; 16 | } else { 17 | benchmarks = benchmarks.split(','); 18 | } 19 | if (modes === 'all' || !modes) { 20 | modes = ['native', 'wasm']; 21 | } else { 22 | modes = modes.split(','); 23 | } 24 | 25 | const time = +argv[2] || 5; 26 | 27 | if (modes.includes('wasm')) { 28 | console.log('Running benchmark on nodejs version', process.version, '\n'); 29 | } 30 | 31 | const table = new Table({ 32 | head: [`Benchmark: # iterations in ${time} seconds`].concat(modes), 33 | }); 34 | 35 | function toPercent(n, max) { 36 | const perc = (n / max) * 100; 37 | return '' + n + ' (' + perc.toFixed(1) + '%)'; 38 | } 39 | 40 | async function exec() { 41 | for (let benchmark of benchmarks) { 42 | let counts = []; 43 | for (let mode of modes) { 44 | counts.push(await run(mode, time, benchmark)); //eslint-disable-line no-await-in-loop 45 | console.log('\n'); 46 | } 47 | const max = Math.max.apply( 48 | null, 49 | counts.filter((c) => typeof c === 'number'), 50 | ); 51 | counts = counts.map((c) => (typeof c === 'number' ? toPercent(c, max) : c)); 52 | table.push([benchmark, ...counts]); 53 | } 54 | console.log(table.toString()); 55 | } 56 | 57 | async function run(mode, time, benchmark) { 58 | let count = 0; 59 | console.log(mode, benchmark); 60 | const runBenchmark = (await import(`./${benchmark}-benchmark.js`)).default; 61 | let SVM; 62 | if (mode === 'wasm') { 63 | try { 64 | SVM = await loadSVM(); 65 | } catch (e) { 66 | console.log(e.message); 67 | return 'error'; 68 | } 69 | } else if (mode === 'native') { 70 | let str = ''; 71 | const prom = new Promise((resolve, reject) => { 72 | const [dir, exec] = benchmark.split('/'); 73 | const cmd = `${import.meta.dirname}/${dir}/bin/${exec}`; 74 | const args = []; 75 | if (benchmark === 'iris/precomputed-cv') { 76 | args.push( 77 | `${import.meta.dirname}/${dir}/data-kernel-rbf-gamma-2e-1.txt`, 78 | ); 79 | } else { 80 | args.push(`${import.meta.dirname}/${dir}/data.txt`); 81 | } 82 | args.push(time); 83 | console.log(cmd); 84 | const child = spawn(cmd, args); 85 | child.on('close', function () { 86 | resolve(); 87 | }); 88 | child.on('error', function () { 89 | reject(new Error(`Could not execute ${cmd} ${args}`)); 90 | }); 91 | child.stdout.on('data', (data) => { 92 | str += data; 93 | }); 94 | child.stdout.pipe(process.stdout); 95 | }); 96 | 97 | try { 98 | await prom; 99 | count = +/(\d+) iteration/.exec(str)[1]; 100 | } catch (e) { 101 | console.error('error executing benchmark', e, e.message); 102 | return e.message; 103 | } 104 | return count; 105 | } else { 106 | console.log(`Unknown mode ${mode}`); 107 | return 0; 108 | } 109 | 110 | try { 111 | count = await runBenchmark(SVM, time); 112 | } catch (e) { 113 | console.error('error executing benchmark', e.message); 114 | return e.message; 115 | } 116 | console.log(`Done. ${count} iterations in ${time} seconds.`); 117 | return count; 118 | } 119 | 120 | exec(); 121 | -------------------------------------------------------------------------------- /benchmark/iris/Makefile: -------------------------------------------------------------------------------- 1 | CXX ?= g++ 2 | CFLAGS = -Wall -Wconversion -O3 -fPIC 3 | 4 | all: mkdir bin/cross-validation bin/grid-search bin/precomputed-cv 5 | 6 | mkdir: 7 | mkdir -p bin 8 | 9 | bin/svm.o: ../../libsvm/svm.cpp ../../libsvm/svm.h 10 | $(CXX) $(CFLAGS) -c ../../libsvm/svm.cpp -o bin/svm.o 11 | 12 | 13 | bin/util.o: util.h util.cpp 14 | $(CXX) $(CFLAGS) -c util.cpp -o bin/util.o 15 | 16 | bin/js-interfaces.o: ../../js-interfaces.c 17 | $(CXX) $(CFLAGS) -c ../../js-interfaces.c -o bin/js-interfaces.o 18 | 19 | bin/grid-search: bin/js-interfaces.o grid-search.cpp bin/util.o bin/svm.o 20 | $(CXX) $(CFLAGS) grid-search.cpp bin/util.o bin/svm.o bin/js-interfaces.o -o bin/grid-search -lm 21 | 22 | bin/cross-validation: bin/js-interfaces.o cross-validation.cpp bin/util.o bin/svm.o 23 | $(CXX) $(CFLAGS) cross-validation.cpp bin/util.o bin/svm.o bin/js-interfaces.o -o bin/cross-validation -lm 24 | 25 | bin/precomputed-cv: bin/js-interfaces.o precomputed-cv.cpp bin/util.o bin/svm.o 26 | $(CXX) $(CFLAGS) precomputed-cv.cpp bin/util.o bin/svm.o bin/js-interfaces.o -o bin/precomputed-cv -lm 27 | clean: 28 | rm -r bin/* 29 | -------------------------------------------------------------------------------- /benchmark/iris/cross-validation-benchmark.js: -------------------------------------------------------------------------------- 1 | const gamma = 0.2; 2 | const cost = 1; 3 | 4 | export default async function exec(SVM, time) { 5 | const data = await import('ml-dataset-iris'); 6 | const MILISECONDS = time * 1000; 7 | 8 | const features = data.getNumbers(); 9 | let labels = data.getClasses(); 10 | const classes = data.getDistinctClasses(); 11 | 12 | const c = {}; 13 | classes.forEach((v, idx) => (c[v] = idx)); 14 | labels = labels.map((l) => c[l]); 15 | 16 | const t1 = performance.now(); 17 | let t2 = performance.now(); 18 | let count = 0; 19 | while (t2 - t1 < MILISECONDS) { 20 | const svm = new SVM({ 21 | quiet: true, 22 | cost: cost, 23 | gamma: gamma, 24 | }); 25 | svm.crossValidation(features, labels, labels.length); 26 | count++; 27 | t2 = performance.now(); 28 | } 29 | 30 | // console.log('accuracy: ', result.reduce((prev, current, idx) => current === labels[idx] ? prev + 1 : prev, 0)/ labels.length); 31 | return count; 32 | } 33 | -------------------------------------------------------------------------------- /benchmark/iris/cross-validation.cpp: -------------------------------------------------------------------------------- 1 | #include "../../js-interfaces.h" 2 | #include "./util.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define COST 1.0 11 | #define GAMMA 0.2 12 | 13 | int main(int argc, char** argv) { 14 | using namespace std::chrono; 15 | char* filename = argv[1]; 16 | double time = atof(argv[2]); 17 | 18 | double data[NB_SAMPLES*NB_FEATURES]; 19 | double labels[NB_SAMPLES]; 20 | if(!load_iris(data, labels, NB_SAMPLES, NB_FEATURES, filename)) { 21 | std::cout << "Could not load data file" << std::endl; 22 | return 1; 23 | } 24 | 25 | duration time_span; 26 | auto t1 = steady_clock::now(); 27 | double target[NB_SAMPLES]; 28 | int count = 0; 29 | do { 30 | svm_problem* problem = create_svm_nodes(NB_SAMPLES, NB_FEATURES); 31 | for(int k=0; k>(t2 - t1); 44 | count++; 45 | } while(time_span.count() < time); 46 | 47 | 48 | int correct = 0; 49 | for(int i=0; i (c[v] = idx)); 14 | labels = labels.map((l) => c[l]); 15 | 16 | const startTime = performance.now(); 17 | let endTime = performance.now(); 18 | let count = 0; 19 | while (endTime - startTime < MILISECONDS) { 20 | for (let c of cost) { 21 | for (let g of gamma) { 22 | const svm = new SVM({ 23 | C: c, 24 | kernel: 'rbf', 25 | kernelOptions: { 26 | sigma: g, 27 | }, 28 | tolerance: 0.001, 29 | maxPasses: 1, 30 | maxIterations: 10000, 31 | }); 32 | svm.train(features, labels); 33 | } 34 | } 35 | count++; 36 | endTime = performance.now(); 37 | } 38 | 39 | return count; 40 | } 41 | 42 | const count = exec(5); 43 | console.log('#iterations: ', count); 44 | -------------------------------------------------------------------------------- /benchmark/iris/grid-search-benchmark.js: -------------------------------------------------------------------------------- 1 | import { gamma, cost } from './util.js'; 2 | 3 | export default async function exec(SVM, time) { 4 | const data = await import('ml-dataset-iris'); 5 | const MILISECONDS = time * 1000; 6 | 7 | const features = data.getNumbers(); 8 | let labels = data.getClasses(); 9 | const classes = data.getDistinctClasses(); 10 | 11 | const c = {}; 12 | classes.forEach((v, idx) => (c[v] = idx)); 13 | labels = labels.map((l) => c[l]); 14 | 15 | const startTime = performance.now(); 16 | let endTime = performance.now(); 17 | let count = 0; 18 | while (endTime - startTime < MILISECONDS) { 19 | for (let c of cost) { 20 | for (let g of gamma) { 21 | const svm = new SVM({ 22 | quiet: true, 23 | cost: c, 24 | gamma: g, 25 | }); 26 | svm.train(features, labels); 27 | svm.free(); 28 | } 29 | } 30 | count++; 31 | endTime = performance.now(); 32 | } 33 | 34 | return count; 35 | } 36 | -------------------------------------------------------------------------------- /benchmark/iris/grid-search.cpp: -------------------------------------------------------------------------------- 1 | #include "../../js-interfaces.h" 2 | #include "./util.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define COST_GRID_SIZE 6 10 | #define GAMMA_GRID_SIZE 6 11 | #define COST_MIN -3 12 | #define COST_MAX 3 13 | #define GAMMA_MIN -3 14 | #define GAMMA_MAX 3 15 | 16 | 17 | int main(int argc, char** argv) { 18 | using namespace std::chrono; 19 | char* filename = argv[1]; 20 | double time = atof(argv[2]); 21 | 22 | double data[NB_SAMPLES * NB_FEATURES]; 23 | double labels[NB_SAMPLES]; 24 | 25 | if(!load_iris(data, labels, NB_SAMPLES, NB_FEATURES, filename)) { 26 | std::cout << "Could not load data file" << std::endl; 27 | return 1; 28 | } 29 | 30 | 31 | double cost[COST_GRID_SIZE]; 32 | double gamma[GAMMA_GRID_SIZE]; 33 | 34 | 35 | for(int i=0; i time_span; 45 | auto t1 = steady_clock::now(); 46 | auto t2 = t1; 47 | int count = 0; 48 | do { 49 | for(int i=0; i >(t2 - t1); 65 | count++; 66 | } while(time_span.count() < time); 67 | 68 | std::cout << count << " iterations in " << time << " seconds." << std::endl; 69 | } 70 | -------------------------------------------------------------------------------- /benchmark/iris/precomputed-cv-benchmark.js: -------------------------------------------------------------------------------- 1 | import Kernel from 'ml-kernel'; 2 | import range from 'lodash.range'; 3 | 4 | const gamma = 0.2; 5 | const cost = 1; 6 | 7 | export default async function exec(SVM, time) { 8 | const data = await import('ml-dataset-iris'); 9 | const MILISECONDS = time * 1000; 10 | 11 | const features = data.getNumbers(); 12 | let labels = data.getClasses(); 13 | const classes = data.getDistinctClasses(); 14 | const c = {}; 15 | classes.forEach((v, idx) => (c[v] = idx)); 16 | labels = labels.map((l) => c[l]); 17 | 18 | // We precompute the gaussian kernel 19 | const kernel = new Kernel('gaussian', { sigma: 1 / Math.sqrt(gamma) }); 20 | const gaussianKernel = kernel 21 | .compute(features) 22 | .addColumn(0, range(1, labels.length + 1)); 23 | 24 | const t1 = performance.now(); 25 | let t2 = performance.now(); 26 | let count = 0; 27 | while (t2 - t1 < MILISECONDS) { 28 | const svm = new SVM({ 29 | quiet: true, 30 | cost: cost, 31 | kernel: SVM.KERNEL_TYPES.PRECOMPUTED, 32 | }); 33 | svm.crossValidation(gaussianKernel.data, labels, labels.length); 34 | svm.free(); 35 | count++; 36 | t2 = performance.now(); 37 | } 38 | 39 | // console.log('accuracy: ', result.reduce((prev, current, idx) => current === labels[idx] ? prev + 1 : prev, 0)/ labels.length); 40 | return count; 41 | } 42 | -------------------------------------------------------------------------------- /benchmark/iris/precomputed-cv.cpp: -------------------------------------------------------------------------------- 1 | #include "../../js-interfaces.h" 2 | #include "./util.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define COST 1.0 11 | #define GAMMA 0.2 12 | 13 | int main(int argc, char** argv) { 14 | using namespace std::chrono; 15 | char* filename = argv[1]; 16 | double time = atof(argv[2]); 17 | 18 | double data[NB_SAMPLES * (NB_SAMPLES + 1)]; 19 | double labels[NB_SAMPLES]; 20 | if(!load_iris(data, labels, NB_SAMPLES, NB_SAMPLES + 1, filename)) { 21 | std::cout << "Could not load data file" << std::endl; 22 | return 1; 23 | } 24 | 25 | 26 | duration time_span; 27 | auto t1 = steady_clock::now(); 28 | double target[NB_SAMPLES]; 29 | int count = 0; 30 | do { 31 | svm_problem* problem = create_svm_nodes(NB_SAMPLES, NB_SAMPLES + 1); 32 | for(int k=0; k >(t2 - t1); 46 | count++; 47 | } while(time_span.count() < time); 48 | 49 | 50 | int correct = 0; 51 | for(int i=0; i 3 | #include 4 | 5 | bool load_iris(double* data, double* labels, int nb_samples, int nb_features, const char* filename) { 6 | std::ifstream ifstr(filename, std::ifstream::in); 7 | int count = 0; 8 | if(!ifstr.good()) { 9 | return false; 10 | } 11 | while(ifstr.good()) { 12 | if(count >= nb_samples) { 13 | std::cout << "Stop reading data because reached size limit" << std::endl; 14 | break; 15 | } 16 | for(int i = 0; i < nb_features; i++) { 17 | ifstr >> data[count * nb_features + i]; 18 | } 19 | ifstr >> labels[count]; 20 | 21 | count++; 22 | } 23 | return true; 24 | } 25 | -------------------------------------------------------------------------------- /benchmark/iris/util.h: -------------------------------------------------------------------------------- 1 | #ifndef IRIS_UTIL_H 2 | #define IRIS_UTIL_H 3 | 4 | #define NB_SAMPLES 150 5 | #define NB_FEATURES 4 6 | 7 | bool load_iris(double*, double[NB_SAMPLES], int nb_samples, int nb_features, const char* filename); 8 | 9 | #endif -------------------------------------------------------------------------------- /benchmark/iris/util.js: -------------------------------------------------------------------------------- 1 | const COST_GRID_SIZE = 6; 2 | const GAMMA_GRID_SIZE = 6; 3 | const COST_MIN = -3; 4 | const COST_MAX = 3; 5 | const GAMMA_MIN = -3; 6 | const GAMMA_MAX = 3; 7 | 8 | export const gamma = Array.from({ length: GAMMA_GRID_SIZE }) 9 | .map(normalize(GAMMA_GRID_SIZE, GAMMA_MIN, GAMMA_MAX)) 10 | .map(pow10); 11 | export const cost = Array.from({ length: COST_GRID_SIZE }) 12 | .map(normalize(COST_GRID_SIZE, COST_MIN, COST_MAX)) 13 | .map(pow10); 14 | 15 | function normalize(n, min, max) { 16 | return (val, idx) => min + (idx / (n - 1)) * (max - min); 17 | } 18 | 19 | function pow10(val) { 20 | return 10 ** val; 21 | } 22 | -------------------------------------------------------------------------------- /benchmark/saveData.js: -------------------------------------------------------------------------------- 1 | import fs from 'node:fs'; 2 | 3 | // Save data and labels readable by benchmark 4 | export default function saveData(data, labels, filepath) { 5 | let str = ''; 6 | for (let i = 0; i < data.length; i++) { 7 | const line = data[i]; 8 | for (let j = 0; j < line.length; j++) { 9 | str += line[j]; 10 | if (j === line.length - 1) { 11 | str += ' ' + labels[i]; 12 | } else { 13 | str += ' '; 14 | } 15 | } 16 | if (i !== data.length - 1) { 17 | str += '\r\n'; 18 | } 19 | } 20 | 21 | fs.writeFileSync(filepath, str); 22 | } 23 | -------------------------------------------------------------------------------- /benchmark/worker.js: -------------------------------------------------------------------------------- 1 | import gridSearchBenchmark from './iris/grid-search-benchmark'; 2 | import crossValidationBenchmark from './iris/cross-validation-benchmark.js'; 3 | import precomputedBenchmark from './iris/precomputed-cv-benchmark.js'; 4 | import { loadSVM } from '../wasm.js'; 5 | 6 | const benchmarks = { 7 | 'iris/grid-search': gridSearchBenchmark, 8 | 'iris/cross-validation': crossValidationBenchmark, 9 | 'iris/precomputed-cv': precomputedBenchmark, 10 | }; 11 | 12 | onmessage = async function (event) { 13 | postMessage({ 14 | method: event.data.method, 15 | result: 'running', 16 | }); 17 | const SVM = await loadSVM(); 18 | const benchmark = benchmarks[event.data.benchmark]; 19 | if (!benchmark) { 20 | throw new Error(`Benchmark ${event.data.benchmark} not found`); 21 | } 22 | 23 | const result = await benchmark(SVM, event.data.time); 24 | event.data.result = result; 25 | postMessage(event.data); 26 | }; 27 | -------------------------------------------------------------------------------- /build/libsvm.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mljs/libsvm/a76132e70a6deec389cbae79758387abc4c5b658/build/libsvm.wasm -------------------------------------------------------------------------------- /demos/.eslintrc.yml: -------------------------------------------------------------------------------- 1 | extends: eslint-config-neptun-react 2 | rules: 3 | no-console: 2 4 | import/no-unassigned-import: 0 -------------------------------------------------------------------------------- /demos/actions/SVC.js: -------------------------------------------------------------------------------- 1 | import { 2 | SVC_ADD_POINT, 3 | SVC_LABEL_CHANGED, 4 | SVC_CLEAR_POINTS, 5 | SVC_UNDO_POINT, 6 | SVC_REDO_POINT 7 | } from './types'; 8 | 9 | export function addPoint(pointData) { 10 | return { 11 | type: SVC_ADD_POINT, 12 | payload: pointData 13 | }; 14 | } 15 | 16 | export function changeLabel(label) { 17 | return { 18 | type: SVC_LABEL_CHANGED, 19 | payload: label 20 | }; 21 | } 22 | 23 | export function clearPoints() { 24 | return { 25 | type: SVC_CLEAR_POINTS 26 | }; 27 | } 28 | 29 | export function undoPoint() { 30 | return { 31 | type: SVC_UNDO_POINT 32 | }; 33 | } 34 | 35 | export function redoPoint() { 36 | return { 37 | type: SVC_REDO_POINT 38 | }; 39 | } 40 | -------------------------------------------------------------------------------- /demos/actions/SVR.js: -------------------------------------------------------------------------------- 1 | import { 2 | SVR_ADD_POINT, 3 | SVR_CLEAR_POINTS, 4 | SVR_UNDO_POINT, 5 | SVR_REDO_POINT 6 | } from './types'; 7 | 8 | export function addPoint(pointData) { 9 | return { 10 | type: SVR_ADD_POINT, 11 | payload: pointData 12 | }; 13 | } 14 | 15 | export function clearPoints() { 16 | return { 17 | type: SVR_CLEAR_POINTS 18 | }; 19 | } 20 | 21 | export function undoPoint() { 22 | return { 23 | type: SVR_UNDO_POINT 24 | }; 25 | } 26 | 27 | export function redoPoint() { 28 | return { 29 | type: SVR_REDO_POINT 30 | }; 31 | } 32 | -------------------------------------------------------------------------------- /demos/actions/index.js: -------------------------------------------------------------------------------- 1 | import { 2 | STYLE_BREAKPOINT_UPDATE, 3 | } from './types'; 4 | 5 | export function updateStyleBreakpoint(bp) { 6 | return { 7 | type: STYLE_BREAKPOINT_UPDATE, 8 | payload: bp 9 | }; 10 | } 11 | -------------------------------------------------------------------------------- /demos/actions/types.js: -------------------------------------------------------------------------------- 1 | export const STYLE_BREAKPOINT_UPDATE = 'STYLE_BREAKPOINT_UPDATE'; 2 | 3 | export const ADD_POINT = 'ADD_POINT'; 4 | export const LABEL_CHANGED = 'LABEL_CHANGED'; 5 | export const CLEAR_POINTS = 'CLEAR_POINTS'; 6 | export const UNDO_POINTS = 'UNDO_POINTS'; 7 | export const REDO_POINTS = 'REDO_POINTS'; 8 | export const SET_ACTIVE_LABEL = 'SET_ACTIVE_LABEL'; 9 | export const SVC_ADD_POINT = 'SVC_ADD_POINT'; 10 | export const SVC_LABEL_CHANGED = 'SVC_LABEL_CHANGED'; 11 | export const SVC_CLEAR_POINTS = 'SVC_CLEAR_POINTS'; 12 | export const SVC_UNDO_POINT = 'SVC_UNDO_POINT'; 13 | export const SVC_REDO_POINT = 'SVC_REDO_POINT'; 14 | export const SVR_ADD_POINT = 'SVR_ADD_POINT'; 15 | export const SVR_CLEAR_POINTS = 'SVR_CLEAR_POINTS'; 16 | export const SVR_UNDO_POINT = 'SVR_UNDO_POINT'; 17 | export const SVR_REDO_POINT = 'SVR_REDO_POINT'; 18 | -------------------------------------------------------------------------------- /demos/bootstrap.jsx: -------------------------------------------------------------------------------- 1 | import React, { Suspense } from 'react'; 2 | import { createRoot } from 'react-dom/client'; 3 | import { Provider } from 'react-redux'; 4 | import 'bootstrap'; 5 | import { loadSVM } from '../wasm.js'; 6 | 7 | import '../node_modules/bootstrap/dist/css/bootstrap.min.css'; 8 | 9 | import store from './store'; 10 | import './style.css'; 11 | 12 | const App = React.lazy(async () => { 13 | const SVM = await loadSVM(); 14 | window.SVM = SVM; 15 | return import('./containers/App'); 16 | }); 17 | 18 | const app = document.getElementById('app'); 19 | const root = createRoot(app); 20 | 21 | root.render( 22 | 23 | 24 | 25 | 26 | , 27 | ); 28 | -------------------------------------------------------------------------------- /demos/components/Benchmark.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import Worker from '../../benchmark/worker.js?worker'; 3 | 4 | export default class Benchmarks extends Component { 5 | constructor(props) { 6 | super(props); 7 | this.state = { 8 | wasmTime: '-', 9 | }; 10 | } 11 | 12 | componentDidMount() { 13 | this.worker = new Worker(); 14 | this.worker.onmessage = (event) => { 15 | if (event.data.method !== 'wasm') { 16 | throw new Error('wrong method'); 17 | } 18 | this.setState({ 19 | wasmTime: event.data.result, 20 | }); 21 | }; 22 | } 23 | 24 | onRun() { 25 | this.worker.postMessage({ 26 | benchmark: this.props.benchmark, 27 | method: 'wasm', 28 | time: 5, 29 | }); 30 | this.setState({ 31 | wasmTime: 'sent', 32 | }); 33 | } 34 | 35 | render() { 36 | const { wasmTime } = this.state; 37 | const disabled = wasmTime === 'running'; 38 | let WasmRender = getResultComponent(wasmTime); 39 | 40 | const Description = this.props.description || (() => null); 41 | return ( 42 |
43 |
44 |

{this.props.name}

45 | 46 |
47 | wasm:     48 | 55 |
56 |
57 | ); 58 | } 59 | } 60 | 61 | function getResultComponent(time) { 62 | switch (time) { 63 | case 'running': 64 | return () => ; 65 | case 'sent': 66 | return () =>
; 67 | default: 68 | return () =>
{time}
; 69 | } 70 | } 71 | 72 | // TODO: replace with actual loading animation 73 | function MySpinner() { 74 | return ( 75 |
76 |
...
77 |
78 | ); 79 | } 80 | -------------------------------------------------------------------------------- /demos/components/Canvas.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | 3 | import chroma from 'chroma-js'; 4 | 5 | class Canvas extends Component { 6 | componentDidMount() { 7 | this.ctx = this.canvas.getContext('2d'); 8 | this.ctx.imageSmoothingEnabled = false; 9 | this.draw(); 10 | } 11 | 12 | componentDidUpdate() { 13 | this.draw(); 14 | } 15 | 16 | onCanvasClick(event) { 17 | const targetRect = event.target.getBoundingClientRect(); 18 | const normalized = { 19 | x: 20 | (event.clientX - targetRect.left) / 21 | (this.props.width * this.props.scale), 22 | y: 23 | (event.clientY - targetRect.top) / 24 | (this.props.height * this.props.scale), 25 | }; 26 | this.props.addPoint({ 27 | point: normalized, 28 | }); 29 | } 30 | 31 | render() { 32 | const realWidth = this.props.width * this.props.scale; 33 | const realHeight = this.props.height * this.props.scale; 34 | return ( 35 |
38 | (this.canvas = c)} 43 | style={this.props.style} 44 | /> 45 |
46 | ); 47 | } 48 | 49 | convertXCoordinates(x) { 50 | return x * this.props.width * this.props.scale; 51 | } 52 | 53 | convertYCoordinates(y) { 54 | return y * this.props.height * this.props.scale; 55 | } 56 | 57 | drawCross() { 58 | this.ctx.lineWidth = 2; 59 | this.ctx.strokeStyle = 'gray'; 60 | this.ctx.beginPath(); 61 | this.ctx.moveTo(0, this.convertYCoordinates(0.5)); 62 | this.ctx.lineTo(this.convertXCoordinates(1), this.convertYCoordinates(0.5)); 63 | this.ctx.moveTo(this.convertXCoordinates(0.5), 0); 64 | this.ctx.lineTo(this.convertXCoordinates(0.5), this.convertYCoordinates(1)); 65 | this.ctx.stroke(); 66 | } 67 | 68 | drawText(info) { 69 | if (!info) return; 70 | this.ctx.font = '14px serif'; 71 | this.ctx.fillStyle = 'black'; 72 | this.ctx.fillText( 73 | info, 74 | this.props.width * this.props.scale - info.length * 7, 75 | this.props.height * this.props.scale - 5, 76 | ); 77 | } 78 | 79 | fillBackground() { 80 | this.ctx.fillStyle = 'lightgray'; 81 | this.ctx.fillRect( 82 | 0, 83 | 0, 84 | this.props.width * this.props.scale, 85 | this.props.height * this.props.scale, 86 | ); 87 | this.ctx.fillStyle = 'black'; 88 | } 89 | 90 | drawBackground() { 91 | const { width, height, scale } = this.props; 92 | const realWidth = width * scale; 93 | const realHeight = height * scale; 94 | 95 | const colorsRgb = this.props.labelColors.map((c) => chroma(c).rgb()); 96 | 97 | const data = this.ctx.createImageData(realWidth, realHeight); 98 | for (let i = 0; i < width; i++) { 99 | for (let j = 0; j < height; j++) { 100 | const px = j * width + i; 101 | const label = this.props.background[px]; 102 | 103 | for (let k = 0; k < scale; k++) { 104 | const idx = 4 * scale * (width * (j * scale + k) + i); 105 | // const idx = (j * width * scale * scale + k * scale * width + i * scale ) * 4; 106 | for (let l = 0; l < scale; l++) { 107 | const idxx = idx + l * 4; 108 | data.data[idxx] = colorsRgb[label][0]; 109 | data.data[idxx + 1] = colorsRgb[label][1]; 110 | data.data[idxx + 2] = colorsRgb[label][2]; 111 | data.data[idxx + 3] = 255; 112 | } 113 | } 114 | } 115 | } 116 | this.ctx.putImageData(data, 0, 0); 117 | } 118 | 119 | drawLine() { 120 | const { width, height, scale, line } = this.props; 121 | this.ctx.beginPath(); 122 | this.ctx.moveTo(0, line[0] * height * scale); 123 | for (let i = 1; i < width; i++) { 124 | this.ctx.lineTo(i * scale, line[i] * height * scale); 125 | this.ctx.moveTo(i * scale, line[i] * height * scale); 126 | } 127 | this.ctx.stroke(); 128 | } 129 | 130 | drawPoints() { 131 | const colorsBrighter = this.props.labelColors.map((c) => 132 | chroma(c).brighten().hex(), 133 | ); 134 | const { width, height, scale, SVs } = this.props; 135 | const SVIdx = {}; 136 | SVs.forEach((idx) => (SVIdx[idx] = 1)); 137 | const radius = (scale * Math.min(height, width)) / 80; 138 | this.ctx.imageSmoothingEnabled = false; 139 | for (let i = 0; i < this.props.points.length; i++) { 140 | const point = this.props.points[i]; 141 | let lineFactor = 4; 142 | if (SVIdx[i]) lineFactor = 2; 143 | this.ctx.beginPath(); 144 | this.ctx.arc( 145 | point.x * scale, 146 | point.y * scale, 147 | radius, 148 | 0, 149 | 2 * Math.PI, 150 | false, 151 | ); 152 | this.ctx.fillStyle = colorsBrighter[point.label]; 153 | this.ctx.fill(); 154 | this.ctx.lineWidth = radius / lineFactor; 155 | this.ctx.strokeStyle = '#003300'; 156 | this.ctx.stroke(); 157 | } 158 | } 159 | 160 | draw() { 161 | const { width, height, info } = this.props; 162 | if (this.props.background.length !== width * height) { 163 | this.fillBackground(); 164 | } else { 165 | this.drawBackground(); 166 | } 167 | if (this.props.line.length === width) { 168 | this.drawLine(); 169 | } 170 | this.drawPoints(); 171 | this.drawCross(); 172 | this.drawText(info); 173 | } 174 | } 175 | 176 | export default Canvas; 177 | -------------------------------------------------------------------------------- /demos/components/ConfigField.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export default function ConfigField(props) { 4 | switch (props.type) { 5 | case 'range': { 6 | return ( 7 |
8 |
9 | {props.format(props.normalize(props.values[props.name]))} 10 |
11 | 21 |
22 | ); 23 | } 24 | case 'number': { 25 | return ( 26 | 32 | ); 33 | } 34 | case 'select': { 35 | return ( 36 | 45 | ); 46 | } 47 | default: { 48 | return null; 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /demos/components/ControlBar.jsx: -------------------------------------------------------------------------------- 1 | import { Popover } from 'bootstrap'; 2 | import React, { useLayoutEffect } from 'react'; 3 | import { FaUndo, FaRedo, FaBroom, FaQuestion } from 'react-icons/fa'; 4 | 5 | export default function ControlBar(props) { 6 | useLayoutEffect(() => { 7 | const popoverTriggerList = document.querySelectorAll( 8 | '[data-bs-toggle="popover"]', 9 | ); 10 | const popoverList = [...popoverTriggerList].map( 11 | (popoverTriggerEl) => new Popover(popoverTriggerEl), 12 | ); 13 | 14 | return () => { 15 | popoverList.forEach((popover) => { 16 | popover.dispose(); 17 | }); 18 | }; 19 | }, []); 20 | return ( 21 |
22 | 31 | 40 | 48 | 59 |
60 | ); 61 | } 62 | -------------------------------------------------------------------------------- /demos/components/Navigation.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { NavLink } from 'react-router-dom'; 3 | import { FaGithub } from 'react-icons/fa'; 4 | export default function Navigation() { 5 | return ( 6 | 57 | ); 58 | } 59 | -------------------------------------------------------------------------------- /demos/components/OneClassSVC.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import SVCCanvas from '../containers/SVCCanvas'; 4 | import ControlBar from '../components/ControlBar'; 5 | import OneClassSVCConfig from '../containers/OneClassSVCConfig'; 6 | import { 7 | ONE_CLASS_LABEL_COLORS, 8 | ONE_CLASS_SVC_INIT_LABELS, 9 | SVC_INIT_POINTS, 10 | } from '../constants'; 11 | import useCanvasPoints from '../hooks/useCanvasPoints'; 12 | 13 | import { useForm, FormProvider } from 'react-hook-form'; 14 | 15 | export default function SVC() { 16 | const methods = useForm({ 17 | shouldUseNativeValidation: true, 18 | defaultValues: { 19 | type: '2', 20 | kernel: '2', 21 | cost: 1, 22 | nu: 0.5, 23 | gamma: 0.01, 24 | degree: 1, 25 | epsilon: 0.1, 26 | }, 27 | }); 28 | const [state, actions] = useCanvasPoints( 29 | SVC_INIT_POINTS, 30 | ONE_CLASS_SVC_INIT_LABELS, 31 | ONE_CLASS_LABEL_COLORS, 32 | ); 33 | return ( 34 | 35 |

One-class support vector classification

36 |
37 |
38 | 43 | 0} 51 | canRedo={state.history.after.length > 0} 52 | /> 53 |
54 |
55 | 56 |
57 |
58 |
59 | ); 60 | } 61 | -------------------------------------------------------------------------------- /demos/components/SVC.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import SVCCanvas from '../containers/SVCCanvas'; 4 | import ControlBar from '../components/ControlBar'; 5 | import SVCConfig from '../containers/SVCConfig'; 6 | import { 7 | SVC_INIT_LABELS, 8 | SVC_INIT_POINTS, 9 | SVC_LABEL_COLORS, 10 | } from '../constants'; 11 | import useCanvasPoints from '../hooks/useCanvasPoints'; 12 | import ChooseLabel from '../containers/ChooseLabel'; 13 | 14 | import { useForm, FormProvider } from 'react-hook-form'; 15 | 16 | export default function SVC() { 17 | const methods = useForm({ 18 | shouldUseNativeValidation: true, 19 | defaultValues: { 20 | type: '0', 21 | kernel: '2', 22 | cost: 1, 23 | nu: 0.5, 24 | gamma: 0.01, 25 | degree: 1, 26 | epsilon: 0.1, 27 | }, 28 | }); 29 | const [state, actions] = useCanvasPoints( 30 | SVC_INIT_POINTS, 31 | SVC_INIT_LABELS, 32 | SVC_LABEL_COLORS, 33 | ); 34 | return ( 35 | 36 |

Support vector classification

37 |
38 |
39 | 44 | 0} 52 | canRedo={state.history.after.length > 0} 53 | /> 54 | 60 |
61 |
62 | 63 |
64 |
65 |
66 | ); 67 | } 68 | -------------------------------------------------------------------------------- /demos/components/SVR.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import SVCConfig from '../containers/SVRConfig'; 4 | import useCanvasPoints from '../hooks/useCanvasPoints'; 5 | import { FormProvider, useForm } from 'react-hook-form'; 6 | import { 7 | SVR_INIT_LABELS, 8 | SVR_INIT_POINTS, 9 | SVR_LABEL_COLORS, 10 | } from '../constants'; 11 | import SVRCanvas from '../containers/SVRCanvas'; 12 | import ControlBar from './ControlBar'; 13 | 14 | export default function SVR() { 15 | const methods = useForm({ 16 | shouldUseNativeValidation: true, 17 | defaultValues: { 18 | type: '3', 19 | kernel: '2', 20 | cost: 1, 21 | gamma: 1, 22 | nu: 0.5, 23 | epsilon: -2, 24 | degree: 1, 25 | }, 26 | }); 27 | const [state, actions] = useCanvasPoints( 28 | SVR_INIT_POINTS, 29 | SVR_INIT_LABELS, 30 | SVR_LABEL_COLORS, 31 | ); 32 | 33 | return ( 34 | 35 |

Support vector regression

36 |
37 |
38 | 43 | 0} 51 | canRedo={state.history.after.length > 0} 52 | /> 53 |
54 |
55 | 56 |
57 |
58 |
59 | ); 60 | } 61 | -------------------------------------------------------------------------------- /demos/components/TableConfigField.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import ConfigField from './ConfigField'; 4 | 5 | export default function TableConfigField(props) { 6 | switch (props.type) { 7 | case 'range': { 8 | return ( 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | ); 18 | } 19 | case 'select': 20 | case 'number': { 21 | return ( 22 | 23 | 24 | 25 | 26 | 27 | 28 | ); 29 | } 30 | default: { 31 | throw new Error('Unreachable'); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /demos/constants.js: -------------------------------------------------------------------------------- 1 | import { getDistinctColors } from './util'; 2 | 3 | // Large screens are considered to use more powerful devices 4 | // So they have a larger resolution (and a smaller scale factor) 5 | export const CANVAS_RESOLUTION = { 6 | xs: 100, 7 | sm: 100, 8 | md: 100, 9 | lg: 200, 10 | xl: 250, 11 | }; 12 | 13 | export const CANVAS_SCALE_FACTOR = { 14 | xs: 4, 15 | sm: 4, 16 | md: 4, 17 | lg: 2, 18 | xl: 2, 19 | }; 20 | 21 | export const LABELS_DISTINCT_COLORS = 5; 22 | 23 | export const SVC_LABEL_COLORS = getDistinctColors(LABELS_DISTINCT_COLORS); 24 | export const SVR_LABEL_COLORS = getDistinctColors(1); 25 | export const ONE_CLASS_LABEL_COLORS = getDistinctColors(2); 26 | 27 | export const SVC_INIT_POINTS = [ 28 | [0.098727294921875, 0.6596761474609375], 29 | [0.380727294921875, 0.6196761474609375], 30 | [0.388727294921875, 0.8516761474609374], 31 | [0.222727294921875, 0.8356761474609375], 32 | [0.650727294921875, 0.7756761474609375], 33 | [0.622727294921875, 0.6276761474609375], 34 | [0.894727294921875, 0.6696761474609375], 35 | [0.826727294921875, 0.8776761474609375], 36 | [0.292727294921875, 0.3796761474609375], 37 | [0.324727294921875, 0.1996761474609375], 38 | [0.120727294921875, 0.1776761474609375], 39 | [0.172727294921875, 0.3596761474609375], 40 | [0.578727294921875, 0.4176761474609375], 41 | [0.572727294921875, 0.3316761474609375], 42 | [0.860727294921875, 0.1736761474609375], 43 | [0.774727294921875, 0.2816761474609375], 44 | ]; 45 | 46 | export const SVC_INIT_LABELS = [0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0]; 47 | export const ONE_CLASS_SVC_INIT_LABELS = [ 48 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 49 | ]; 50 | 51 | export const SVR_INIT_POINTS = [ 52 | [0.036727294921875, 0.4996761474609375], 53 | [0.112727294921875, 0.5036761474609375], 54 | [0.190727294921875, 0.4956761474609375], 55 | [0.256727294921875, 0.3636761474609375], 56 | [0.312727294921875, 0.2676761474609375], 57 | [0.400727294921875, 0.1376761474609375], 58 | [0.464727294921875, 0.1116761474609375], 59 | [0.540727294921875, 0.2176761474609375], 60 | [0.596727294921875, 0.3616761474609375], 61 | [0.640727294921875, 0.4856761474609375], 62 | [0.714727294921875, 0.6316761474609375], 63 | [0.792727294921875, 0.6976761474609375], 64 | [0.842727294921875, 0.6116761474609375], 65 | [0.898727294921875, 0.4976761474609375], 66 | [0.962727294921875, 0.4956761474609375], 67 | ]; 68 | 69 | export const SVR_INIT_LABELS = new Array(15).fill(0); 70 | -------------------------------------------------------------------------------- /demos/containers/App.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { throttle } from 'lodash-es'; 3 | import { connect } from 'react-redux'; 4 | import { 5 | Route, 6 | Routes, 7 | HashRouter as Router, 8 | Navigate, 9 | } from 'react-router-dom'; 10 | 11 | import { updateStyleBreakpoint } from '../actions/index'; 12 | import SVC from '../components/SVC'; 13 | import SVR from '../components/SVR'; 14 | import OneClassSVC from '../components/OneClassSVC'; 15 | import Navigation from '../components/Navigation'; 16 | 17 | import Benchmarks from './Benchmarks'; 18 | 19 | class App extends Component { 20 | componentWillMount() { 21 | const onResize = () => { 22 | const breakpoint = window 23 | .getComputedStyle(document.querySelector('body'), ':before') 24 | .getPropertyValue('content') 25 | .replace(/"/g, ''); 26 | this.props.updateStyleBreakpoint(breakpoint); 27 | }; 28 | 29 | window.addEventListener('resize', throttle(onResize, 150)); 30 | onResize(); 31 | } 32 | 33 | render() { 34 | return ( 35 | 36 |
37 | 38 | 39 | } /> 40 | } /> 41 | } /> 42 | } /> 43 | } /> 44 | 45 |
46 |
47 | ); 48 | } 49 | } 50 | 51 | export default connect(null, { updateStyleBreakpoint })(App); 52 | -------------------------------------------------------------------------------- /demos/containers/Benchmarks.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import Benchmark from '../components/Benchmark'; 4 | 5 | export default function Benchmarks() { 6 | return ( 7 |
8 |
9 | This will run a few typical SVM scenarios. The scenario will be run as 10 | many times as possibles for 5 seconds. The reported score is the number 11 | of iteration. Higher is better. Those benchmarks can be compared with 12 | their native counterparts from the command line with{' '} 13 | npm run benchmark. 14 |
15 | { 19 | return ( 20 |

21 | C_SVC leave-one-out cross-validation with RBF kernel 22 | (gamma=0.2) on the{' '} 23 | 27 | iris dataset 28 | 29 | . 30 |

31 | ); 32 | }} 33 | /> 34 | { 38 | return ( 39 |

40 | C_SVC 6-by-6 grid grid search of gamma and C 41 | parameters on the{' '} 42 | 46 | iris dataset 47 | 48 | . 49 |

50 | ); 51 | }} 52 | /> 53 | { 57 | return ( 58 |

59 | C_SVC leave-on-one cross-validation with a 60 | precomputed RBF kernel (gamma=0.2) 61 | 65 | iris dataset 66 | 67 | . 68 |

69 | ); 70 | }} 71 | /> 72 |
73 | ); 74 | } 75 | -------------------------------------------------------------------------------- /demos/containers/ChooseLabel.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { CANVAS_RESOLUTION, CANVAS_SCALE_FACTOR } from '../constants'; 4 | import connectStyle from './connectStyle'; 5 | 6 | function ChooseLabel(props) { 7 | const { colors, setActiveLabel, activeLabel, currentBreakpoint } = props; 8 | 9 | const width = 10 | CANVAS_RESOLUTION[currentBreakpoint] * 11 | CANVAS_SCALE_FACTOR[currentBreakpoint]; 12 | 13 | function renderColorButton(color, idx) { 14 | return ( 15 |
setActiveLabel(idx)} 22 | /> 23 | ); 24 | } 25 | 26 | return ( 27 |
28 |
29 |
30 | {colors.map(renderColorButton)} 31 |
32 |
33 |
34 | ); 35 | } 36 | 37 | export default connectStyle(ChooseLabel); 38 | -------------------------------------------------------------------------------- /demos/containers/OneClassSVCConfig.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | // import {findHyperParameters} from '../actions/SVC'; 4 | import { getHyperParameters, KERNEL } from '../util/fields'; 5 | import TableConfigField from '../components/TableConfigField'; 6 | import { useFormContext, useWatch } from 'react-hook-form'; 7 | 8 | export default function OneClassSVCConfig() { 9 | const { register } = useFormContext(); 10 | const values = useWatch(); 11 | 12 | return ( 13 |
14 | 15 | 16 | 17 | 20 | 21 | 22 | 23 | {getHyperParameters('2', values.kernel).map((param) => { 24 | return ( 25 | 31 | ); 32 | })} 33 | 34 |
18 | 19 | One-class SVC
35 |
36 | ); 37 | } 38 | -------------------------------------------------------------------------------- /demos/containers/SVCCanvas.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { getSVCCanvasData } from '../selectors/index'; 4 | import Canvas from '../components/Canvas'; 5 | import { useWatch } from 'react-hook-form'; 6 | import { connect } from 'react-redux'; 7 | import connectStyle from './connectStyle'; 8 | 9 | function SVCCanvas(props) { 10 | const { state, actions, currentBreakpoint, ...otherProps } = props; 11 | const config = useWatch(); 12 | const canvasProps = getSVCCanvasData(state, config, currentBreakpoint); 13 | return ( 14 | 20 | ); 21 | } 22 | 23 | export default connectStyle(SVCCanvas); 24 | -------------------------------------------------------------------------------- /demos/containers/SVCConfig.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { getHyperParameters, KERNEL } from '../util/fields'; 4 | import TableConfigField from '../components/TableConfigField'; 5 | import { useFormContext, useWatch } from 'react-hook-form'; 6 | 7 | export default function SVCConfig() { 8 | const { register } = useFormContext(); 9 | const values = useWatch(); 10 | 11 | return ( 12 |
13 | 14 | 15 | 16 | 19 | 25 | 26 | 27 | {getHyperParameters(values.type, values.kernel).map((param) => { 28 | return ( 29 | 35 | ); 36 | })} 37 | 38 |
17 | 18 | 20 | 24 |
39 |
40 | ); 41 | } 42 | -------------------------------------------------------------------------------- /demos/containers/SVRCanvas.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { getSVRCanvasData } from '../selectors/index'; 3 | import Canvas from '../components/Canvas'; 4 | import { useWatch } from 'react-hook-form'; 5 | 6 | export default function SVRCanvas(props) { 7 | const { state, actions, ...otherProps } = props; 8 | const config = useWatch(); 9 | 10 | const canvasProps = getSVRCanvasData(state, config); 11 | return ( 12 | 18 | ); 19 | } 20 | -------------------------------------------------------------------------------- /demos/containers/SVRConfig.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { KERNEL, getHyperParameters } from '../util/fields'; 4 | import TableConfigField from '../components/TableConfigField'; 5 | import { useFormContext, useWatch } from 'react-hook-form'; 6 | 7 | export default function SVRConfig() { 8 | const { register } = useFormContext(); 9 | const values = useWatch(); 10 | 11 | return ( 12 |
13 | 14 | 15 | 16 | 19 | 25 | 26 | 27 | {getHyperParameters(values.type, values.kernel).map((param) => { 28 | return ( 29 | 35 | ); 36 | })} 37 | 38 |
17 | 18 | 20 | 24 |
39 |
40 | ); 41 | } 42 | -------------------------------------------------------------------------------- /demos/containers/connectStyle.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux'; 2 | 3 | const mapStateToProps = (state) => state.style; 4 | 5 | export default connect(mapStateToProps); 6 | -------------------------------------------------------------------------------- /demos/hooks/useCanvasPoints.js: -------------------------------------------------------------------------------- 1 | import { useCallback, useMemo, useReducer } from 'react'; 2 | import { 3 | ADD_POINT, 4 | LABEL_CHANGED, 5 | CLEAR_POINTS, 6 | SET_ACTIVE_LABEL, 7 | UNDO_POINTS, 8 | REDO_POINTS, 9 | } from '../actions/types'; 10 | 11 | const initialState = { 12 | history: { 13 | before: [], 14 | after: [], 15 | }, 16 | activeLabel: 0, 17 | }; 18 | 19 | function canvasPointsReducer(state = initialState, action) { 20 | switch (action.type) { 21 | case ADD_POINT: { 22 | const newBefore = [ 23 | ...state.history.before, 24 | { 25 | points: state.points, 26 | labels: state.labels, 27 | }, 28 | ]; 29 | const newPoint = [action.payload.point.x, action.payload.point.y]; 30 | return { 31 | ...state, 32 | points: state.points.concat([newPoint]), 33 | labels: [...state.labels, state.activeLabel], 34 | history: { 35 | after: [], 36 | before: newBefore, 37 | }, 38 | }; 39 | } 40 | case LABEL_CHANGED: { 41 | return { 42 | ...state, 43 | activeLabel: action.payload, 44 | }; 45 | } 46 | case CLEAR_POINTS: { 47 | return { 48 | ...state, 49 | points: [], 50 | labels: [], 51 | }; 52 | } 53 | case SET_ACTIVE_LABEL: { 54 | return { 55 | ...state, 56 | activeLabel: action.payload, 57 | }; 58 | } 59 | case UNDO_POINTS: { 60 | const before = state.history.before.slice(); 61 | const newData = before.pop(); 62 | const newAfterItem = { 63 | points: state.points.slice(), 64 | labels: state.labels.slice(), 65 | }; 66 | return { 67 | ...state, 68 | history: { 69 | before, 70 | after: [...state.history.after, newAfterItem], 71 | }, 72 | points: newData.points, 73 | labels: newData.labels, 74 | }; 75 | } 76 | case REDO_POINTS: { 77 | const after = state.history.after.slice(); 78 | const newData = after.pop(); 79 | const newBeforeItem = { 80 | points: state.points.slice(), 81 | labels: state.labels.slice(), 82 | }; 83 | return { 84 | ...state, 85 | history: { 86 | after, 87 | before: [...state.history.before, newBeforeItem], 88 | }, 89 | points: newData.points, 90 | labels: newData.labels, 91 | }; 92 | } 93 | default: 94 | return state; 95 | } 96 | } 97 | 98 | export default function useCanvasPoints(points, labels, colors) { 99 | const [state, dispatch] = useReducer(canvasPointsReducer, { 100 | ...initialState, 101 | points, 102 | labels, 103 | colors, 104 | }); 105 | const addPoint = useCallback((points) => { 106 | return dispatch({ 107 | type: 'ADD_POINT', 108 | payload: points, 109 | }); 110 | }, []); 111 | 112 | const clearPoints = useCallback(() => { 113 | dispatch({ 114 | type: 'CLEAR_POINTS', 115 | }); 116 | }); 117 | 118 | const setActiveLabel = useCallback((value) => { 119 | if (value >= colors.length) { 120 | throw new Error('color out of range'); 121 | } 122 | dispatch({ 123 | type: SET_ACTIVE_LABEL, 124 | payload: value, 125 | }); 126 | }); 127 | 128 | const undoPoints = useCallback(() => { 129 | dispatch({ 130 | type: UNDO_POINTS, 131 | }); 132 | }); 133 | 134 | const redoPoints = useCallback(() => { 135 | dispatch({ 136 | type: REDO_POINTS, 137 | }); 138 | }); 139 | 140 | const actions = useMemo(() => { 141 | return { 142 | addPoint, 143 | clearPoints, 144 | setActiveLabel, 145 | undoPoints, 146 | redoPoints, 147 | }; 148 | }, [addPoint, clearPoints]); 149 | return [state, actions]; 150 | } 151 | -------------------------------------------------------------------------------- /demos/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | libsvm demos 10 | 11 | 12 |
13 | 14 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /demos/libsvm.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mljs/libsvm/a76132e70a6deec389cbae79758387abc4c5b658/demos/libsvm.wasm -------------------------------------------------------------------------------- /demos/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "libsvm-js", 3 | "short_name": "libsvm-j-", 4 | "start_url": "https://mljs.github.io/libsvm/", 5 | "display": "standalone", 6 | "background_color": "#fff", 7 | "description": "A javascript library to do Support Vector Machines", 8 | "icons": [] 9 | } -------------------------------------------------------------------------------- /demos/reducers/reducers.js: -------------------------------------------------------------------------------- 1 | import { combineReducers } from 'redux'; 2 | 3 | import styleReducer from './styleReducer'; 4 | 5 | export default combineReducers({ 6 | style: styleReducer, 7 | }); 8 | -------------------------------------------------------------------------------- /demos/reducers/styleReducer.js: -------------------------------------------------------------------------------- 1 | import { STYLE_BREAKPOINT_UPDATE } from '../actions/types'; 2 | 3 | const defaultState = { 4 | currentBreakpoint: 'md' 5 | }; 6 | 7 | export default function styleReducer(state = defaultState, action) { 8 | switch (action.type) { 9 | case STYLE_BREAKPOINT_UPDATE: { 10 | if (action.payload === state.currentBreakpoint) { 11 | return state; 12 | } else { 13 | return { ...state, currentBreakpoint: action.payload }; 14 | } 15 | } 16 | default: { 17 | return state; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /demos/selectors/index.js: -------------------------------------------------------------------------------- 1 | import { CANVAS_RESOLUTION, CANVAS_SCALE_FACTOR } from '../constants'; 2 | import { getHyperParameters } from '../util/fields'; 3 | 4 | export function getSVCCanvasData(SVCPoints, config, currentBreakpoint = 'md') { 5 | let startTime, endTime; 6 | const canvasSize = CANVAS_RESOLUTION[currentBreakpoint]; 7 | let points = []; 8 | let background = []; 9 | let SVs = []; 10 | const line = []; 11 | if (config) { 12 | startTime = performance.now(); 13 | points = SVCPoints.points.map((p, idx) => { 14 | return { 15 | label: SVCPoints.labels[idx], 16 | x: p[0] * canvasSize, 17 | y: p[1] * canvasSize, 18 | }; 19 | }); 20 | if (points.length) { 21 | const realConfig = Object.assign({}, config); 22 | const parameters = getHyperParameters(config.type, config.kernel); 23 | for (let param of parameters) { 24 | realConfig[param.name] = param.normalize(config[param.name]); 25 | } 26 | const svm = new SVM({ ...realConfig, quiet: true }); 27 | svm.train(SVCPoints.points, SVCPoints.labels); 28 | 29 | SVs = svm.getSVIndices(); 30 | 31 | for (let i = 0; i < canvasSize; i++) { 32 | for (let j = 0; j < canvasSize; j++) { 33 | let val = svm.predictOne([j / canvasSize, i / canvasSize]); 34 | if (config.type === SVM.SVM_TYPES.ONE_CLASS) { 35 | if (val < 0) { 36 | val = 1; 37 | } else { 38 | val = 0; 39 | } 40 | } 41 | background.push(val); 42 | } 43 | } 44 | } 45 | endTime = performance.now(); 46 | } 47 | 48 | return { 49 | width: canvasSize, 50 | height: canvasSize, 51 | background, 52 | points, 53 | scale: CANVAS_SCALE_FACTOR[currentBreakpoint], 54 | info: startTime ? `${(endTime - startTime).toFixed(1)} ms` : '', 55 | SVs, 56 | line, 57 | }; 58 | } 59 | 60 | export function getSVRCanvasData( 61 | canvasPoints, 62 | config, 63 | currentBreakpoint = 'md', 64 | ) { 65 | let startTime, endTime; 66 | const canvasSize = CANVAS_RESOLUTION[currentBreakpoint]; 67 | let points = []; 68 | let background = []; 69 | let line = []; 70 | let SVs = []; 71 | if (config) { 72 | const realConfig = Object.assign({}, config); 73 | for (let param of getHyperParameters(config.type, config.kernel)) { 74 | realConfig[param.name] = param.normalize(config[param.name]); 75 | } 76 | startTime = performance.now(); 77 | points = canvasPoints.points.map((p) => { 78 | return { 79 | label: 0, 80 | x: p[0] * canvasSize, 81 | y: p[1] * canvasSize, 82 | }; 83 | }); 84 | if (points.length) { 85 | const svm = new SVM({ ...realConfig, quiet: true }); 86 | svm.train( 87 | canvasPoints.points.map((p) => [p[0]]), 88 | canvasPoints.points.map((p) => p[1]), 89 | ); 90 | SVs = svm.getSVIndices(); 91 | 92 | line = svm.predict( 93 | Array.from({ length: canvasSize }).map((v, i) => [i / canvasSize]), 94 | ); 95 | } 96 | } 97 | 98 | endTime = performance.now(); 99 | return { 100 | width: canvasSize, 101 | height: canvasSize, 102 | background, 103 | points, 104 | scale: CANVAS_SCALE_FACTOR[currentBreakpoint], 105 | info: startTime ? `${(endTime - startTime).toFixed(1)} ms` : '', 106 | SVs, 107 | line, 108 | }; 109 | } 110 | -------------------------------------------------------------------------------- /demos/store.js: -------------------------------------------------------------------------------- 1 | import { createStore } from 'redux'; 2 | 3 | import reducers from './reducers/reducers'; 4 | 5 | export default createStore( 6 | reducers, 7 | window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__(), 8 | ); 9 | -------------------------------------------------------------------------------- /demos/style.css: -------------------------------------------------------------------------------- 1 | body:before { 2 | content: "xs"; 3 | display: none; 4 | } 5 | 6 | @media (min-width: 576px) { 7 | body:before { 8 | content: "sm"; 9 | display: none; 10 | } 11 | } 12 | 13 | @media (min-width: 768px) { 14 | body:before { 15 | content: "md"; 16 | display: none; 17 | } 18 | } 19 | 20 | @media (min-width: 992px) { 21 | body:before { 22 | content: "lg"; 23 | display: none; 24 | } 25 | } 26 | 27 | @media (min-width: 1200px) { 28 | body:before { 29 | content: "xl"; 30 | display: none; 31 | } 32 | } 33 | 34 | .choose-label-element { 35 | flex: 1; 36 | height: 25px; 37 | } 38 | 39 | .choose-label-element-active { 40 | background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAIVJREFUeNpiYBhsgJFMffxAXABlN5JruT4Q3wfi/0DsT64h8UD8HmpIPCWG/KemIfOJCUB+Aoacx6EGBZyHBqI+WsDCwuQ9mhxeg2A210Ntfo8klk9sOMijaURm7yc1UP2RNCMbKE9ODK1HM6iegYLkfx8pligC9lCD7KmRof0ZhjQACDAAceovrtpVBRkAAAAASUVORK5CYII=); 41 | background-repeat: no-repeat; 42 | background-position: center; 43 | } 44 | 45 | .choose-label-container { 46 | display: flex; 47 | justify-content: center; 48 | } 49 | 50 | .flex-align { 51 | display: flex; 52 | align-items: center; 53 | justify-content: center; 54 | } 55 | 56 | .svm-config-table { 57 | table-layout: fixed; 58 | width: 100%; 59 | } 60 | 61 | .svm-config-table td { 62 | padding: 5px 10px 5px 10px; 63 | } 64 | 65 | .svm-config-table td:nth-child(1) { 66 | width: 175px; 67 | } 68 | 69 | .svm-config-table td:nth-child(2) { 70 | width: 100%; 71 | } 72 | 73 | .svm-config-table td input[type="range"] { 74 | width: 100%; 75 | height: 40px; 76 | } 77 | -------------------------------------------------------------------------------- /demos/util.js: -------------------------------------------------------------------------------- 1 | import chroma from 'chroma-js'; 2 | 3 | export function getDistinctColors(numColors) { 4 | var colors = new Array(numColors); 5 | var j = 0; 6 | for (var i = 0; i < 360; i += 360 / numColors) { 7 | j++; 8 | var color = hsl2rgb(i, 100, 30 + j % 4 * 15); 9 | colors[j - 1] = [Math.round(color.r * 255), Math.round(color.g * 255), Math.round(color.b * 255)]; 10 | } 11 | return colors.map((c) => chroma(c).hex()).map((c) => chroma(c).brighten().hex()); 12 | } 13 | 14 | 15 | function hsl2rgb(h, s, l) { 16 | var m1, m2, hue, r, g, b; 17 | s /= 100; 18 | l /= 100; 19 | 20 | if (s === 0) { 21 | r = g = b = (l * 255); 22 | } else { 23 | if (l <= 0.5) { 24 | m2 = l * (s + 1); 25 | } else { 26 | m2 = l + s - l * s; 27 | } 28 | 29 | m1 = l * 2 - m2; 30 | hue = h / 360; 31 | r = hue2rgb(m1, m2, hue + 1 / 3); 32 | g = hue2rgb(m1, m2, hue); 33 | b = hue2rgb(m1, m2, hue - 1 / 3); 34 | } 35 | return { r: r, g: g, b: b }; 36 | } 37 | 38 | function hue2rgb(p, q, t) { 39 | if (t < 0) { 40 | t += 1; 41 | } 42 | if (t > 1) { 43 | t -= 1; 44 | } 45 | if (t < 1 / 6) { 46 | return p + (q - p) * 6 * t; 47 | } 48 | if (t < 1 / 2) { 49 | return q; 50 | } 51 | if (t < 2 / 3) { 52 | return p + (q - p) * (2 / 3 - t) * 6; 53 | } 54 | return p; 55 | } 56 | -------------------------------------------------------------------------------- /demos/util/fields.js: -------------------------------------------------------------------------------- 1 | import { identity, omitBy } from 'lodash-es'; 2 | 3 | export const KERNEL = { 4 | id: 'HP_KERNEL', 5 | name: 'kernel', 6 | type: 'select', 7 | options: omitBy( 8 | SVM.KERNEL_TYPES, 9 | (val) => val === SVM.KERNEL_TYPES.PRECOMPUTED, 10 | ), 11 | }; 12 | 13 | export const COST = { 14 | id: 'HP_COST', 15 | name: 'cost', 16 | type: 'range', 17 | min: -3, 18 | max: 3, 19 | normalize: pow10, 20 | format: (num) => num.toExponential(2), 21 | step: 0.2, 22 | gridSearch: true, 23 | }; 24 | 25 | export const GAMMA = { 26 | id: 'HP_GAMMA', 27 | name: 'gamma', 28 | type: 'range', 29 | min: -3, 30 | max: 3, 31 | normalize: pow10, 32 | format: (num) => num.toExponential(2), 33 | step: 0.2, 34 | gridSearch: true, 35 | }; 36 | 37 | export const NU = { 38 | id: 'HP_NU', 39 | name: 'nu', 40 | type: 'range', 41 | min: 0, 42 | max: 1, 43 | format: identity, 44 | normalize: toNumber, 45 | step: 0.05, 46 | gridSearch: true, 47 | }; 48 | 49 | export const EPSILON = { 50 | id: 'HP_EPSILON', 51 | name: 'epsilon', 52 | type: 'range', 53 | min: -3, 54 | max: 0, 55 | format: (num) => num.toExponential(2), 56 | normalize: pow10, 57 | step: 0.1, 58 | gridSearch: true, 59 | }; 60 | 61 | export const DEGREE = { 62 | id: 'HP_DEGREE', 63 | name: 'degree', 64 | type: 'number', 65 | normalize: toNumber, 66 | gridSearch: false, 67 | }; 68 | 69 | export function getHyperParameters(type, kernel) { 70 | const fields = []; 71 | if (isNu(type)) { 72 | fields.push(NU); 73 | } 74 | if (isCost(type)) { 75 | fields.push(COST); 76 | } 77 | if (hasGamma(kernel)) { 78 | fields.push(GAMMA); 79 | } 80 | 81 | if (kernel === SVM.KERNEL_TYPES.POLYNOMIAL) { 82 | fields.push(DEGREE); 83 | } 84 | 85 | if (type === SVM.SVM_TYPES.EPSILON_SVR) { 86 | fields.push(EPSILON); 87 | } 88 | return fields; 89 | } 90 | 91 | function pow10(value) { 92 | return Math.pow(10, value); 93 | } 94 | 95 | function isNu(type) { 96 | return ( 97 | type === SVM.SVM_TYPES.NU_SVC || 98 | type === SVM.SVM_TYPES.NU_SVR || 99 | type === SVM.SVM_TYPES.ONE_CLASS 100 | ); 101 | } 102 | 103 | function isCost(type) { 104 | return type === SVM.SVM_TYPES.C_SVC || type === SVM.SVM_TYPES.EPSILON_SVR; 105 | } 106 | 107 | function hasGamma(kernel) { 108 | return ( 109 | kernel === SVM.KERNEL_TYPES.RBF || 110 | kernel === SVM.KERNEL_TYPES.SIGMOID || 111 | kernel === SVM.KERNEL_TYPES.POLYNOMIAL 112 | ); 113 | } 114 | 115 | // function isClassification(type) { 116 | // return type === SVM.SVM_TYPES.C_SVC || type === SVM.SVM_TYPES.ONE_CLASS || type === SVM.SVM_TYPES.NU_SVC; 117 | // } 118 | // 119 | // function isRegression(type) { 120 | // return type === SVM.SVM_TYPES.EPSILON_SVR || type === SVM.SVM_TYPES.NU_SVR; 121 | // } 122 | 123 | function toNumber(value) { 124 | return +value; 125 | } 126 | -------------------------------------------------------------------------------- /demos/vite.config.mjs: -------------------------------------------------------------------------------- 1 | import reactRefresh from '@vitejs/plugin-react-refresh'; 2 | import { defineConfig } from 'vite'; 3 | 4 | export default defineConfig({ 5 | plugins: [reactRefresh()], 6 | worker: { 7 | format: 'es', 8 | }, 9 | }); 10 | -------------------------------------------------------------------------------- /examples/bodyfat.js: -------------------------------------------------------------------------------- 1 | import fs from 'node:fs'; 2 | import path from 'node:path'; 3 | 4 | import { loadSVM } from '../wasm.js'; 5 | const SVM = await loadSVM(); 6 | let data = fs.readFileSync( 7 | path.join(import.meta.dirname, './bodyfat_scale.txt'), 8 | 'utf-8', 9 | ); 10 | data = data.split('\n').map((line) => line.split(' ').filter((el) => el)); 11 | let labels = data.map((line) => +line.splice(0, 1)[0]); 12 | const features = data.map((line) => line.map((el) => +el.split(':')[1])); 13 | 14 | const svm = new SVM({ 15 | type: SVM.SVM_TYPES.EPSILON_SVR, 16 | kernel: SVM.KERNEL_TYPES.RBF, 17 | epsilon: 0.001, 18 | quiet: false, 19 | probabilityEstimates: true, 20 | }); 21 | 22 | svm.train(features, labels); 23 | console.log(svm.predictInterval(features, 0.99)); 24 | fs.writeFileSync( 25 | path.join(import.meta.dirname, 'bodyfat.model'), 26 | svm.serializeModel(), 27 | ); 28 | 29 | // svm.crossValidation(features, labels); 30 | -------------------------------------------------------------------------------- /examples/bodyfat_scale.txt: -------------------------------------------------------------------------------- 1 | 1.0708 1:-0.482105 2:-0.966102 3:-0.707746 4:0.585492 5:-0.492537 6:-0.514938 7:-0.598475 8:-0.69697 9:-0.411471 10:-0.465839 11:-0.621622 12:-0.287129 13:-0.0791367 14:-0.535714 2 | 1.0853 1:-0.743158 2:-1 3:-0.552422 4:0.772021 5:-0.263682 6:-0.497364 7:-0.654384 8:-0.562998 9:-0.426434 10:-0.465839 11:-0.418919 12:-0.435644 13:0.136691 14:-0.142857 3 | 1.0414 1:0.0652632 2:-1 3:-0.709789 4:0.523316 5:-0.711443 6:-0.420035 7:-0.52986 8:-0.547049 9:-0.381546 10:-0.267081 11:-0.337838 12:-0.60396 13:-0.395683 14:-0.714286 4 | 1.0751 1:-0.562105 2:-0.864407 3:-0.45841 4:0.772021 5:-0.373134 6:-0.209139 7:-0.56798 8:-0.483254 9:-0.356608 10:-0.465839 11:-0.5 12:-0.247525 13:0.208633 14:-0.142857 5 | 1.034 1:0.208421 2:-0.932203 3:-0.462497 4:0.73057 5:-0.671642 6:-0.367311 7:-0.222363 8:-0.460925 9:-0.201995 10:0.142857 11:-0.337838 12:-0.267327 13:-0.0359712 14:-0.321429 6 | 1.0502 1:-0.12 2:-0.932203 3:-0.249949 4:0.875648 5:-0.21393 6:-0.114236 7:-0.364676 8:-0.272727 9:-0.0623441 10:0.118012 11:-0.121622 12:0.0792079 13:0.381295 14:0.0714286 7 | 1.0549 1:-0.191579 2:-0.864407 3:-0.489066 4:0.668394 5:-0.472637 6:-0.0931459 7:-0.458704 8:-0.511962 9:-0.441397 10:-0.341615 11:-0.486486 12:-0.29703 13:-0.0215827 14:-0.321429 8 | 1.0704 1:-0.477895 2:-0.898305 3:-0.529941 4:0.782383 5:-0.333333 6:-0.286467 7:-0.514612 8:-0.614035 9:-0.361596 10:-0.204969 11:-0.445946 12:-0.435644 13:0.151079 14:0.0714286 9 | 1.09 1:-0.827368 2:-0.898305 3:-0.407317 4:0.84456 5:-0.303483 6:-0.240773 7:-0.66709 8:-0.524721 9:-0.216958 10:-0.341615 11:-0.364865 12:0.0990099 13:0.453237 14:-0.142857 10 | 1.0722 1:-0.507368 2:-0.966102 3:-0.348048 4:0.823834 5:0.0945274 6:-0.286467 7:-0.512071 8:-0.39075 9:-0.206983 10:0.0807453 11:-0.202703 12:0.0693069 13:0.294964 14:0.214286 11 | 1.083 1:-0.701053 2:-0.864407 3:-0.446148 4:0.865285 5:-0.263682 6:-0.219684 7:-0.639136 8:-0.578947 9:-0.376559 10:-0.167702 11:-0.175676 12:-0.207921 13:0.208633 14:-0.0357143 12 | 1.0812 1:-0.671579 2:-0.830508 3:-0.202943 4:0.927461 5:-0.174129 6:-0.14587 7:-0.453621 8:-0.275917 9:-0.0523691 10:-0.229814 11:-0.0810811 12:0.227723 13:0.323741 14:0.142857 13 | 1.0513 1:-0.124211 2:-0.661017 3:-0.493153 4:0.658031 5:-0.273632 6:-0.202109 7:-0.435832 8:-0.397129 9:-0.19202 10:-0.341615 11:-0.675676 12:-0.237624 13:0.0935252 14:-0.321429 14 | 1.0505 1:-0.107368 2:-0.728814 3:-0.290824 4:0.73057 5:-0.174129 6:-0.128295 7:-0.17662 8:-0.247209 9:-0.0623441 10:0.0559006 11:-0.378378 12:0.19802 13:0.52518 14:0.0714286 15 | 1.0484 1:-0.0694737 2:-0.559322 3:-0.433885 4:0.658031 5:-0.0646766 6:-0.226714 7:-0.31385 8:-0.518341 9:0.0872818 10:-0.254658 11:-0.459459 12:0.118812 13:0.366906 14:-0.142857 16 | 1.0512 1:-0.12 2:-0.559322 3:-0.638259 4:0.512953 5:-0.472637 6:-0.304042 7:-0.405337 8:-0.547049 9:-0.206983 10:-0.291925 11:-0.648649 12:-0.376238 13:-0.223022 14:-0.607143 17 | 1.0333 1:0.221053 2:-0.59322 3:-0.368486 4:0.720207 5:-0.223881 6:-0.205624 7:-0.31385 8:-0.355662 9:-0.122195 10:-0.0310559 11:-0.459459 12:0.128713 13:0.410072 14:-0.464286 18 | 1.0468 1:-0.0357895 2:-0.661017 3:-0.258124 4:0.720207 5:0.0945274 6:-0.00527241 7:-0.285896 8:-0.298246 9:-0.0174564 10:-0.130435 11:-0.283784 12:0.326733 13:0.52518 14:0.25 19 | 1.0622 1:-0.326316 2:-0.79661 3:-0.466585 4:0.585492 5:-0.313433 6:-0.0333919 7:-0.486658 8:-0.444976 9:-0.15212 10:-0.291925 11:-0.486486 12:0.227723 13:0.366906 14:-0.0357143 20 | 1.061 1:-0.305263 2:-0.627119 3:-0.237686 4:0.823834 5:-0.114428 6:-0.0544815 7:-0.209657 8:-0.23445 9:-0.0723192 10:-0.0559006 11:-0.337838 12:0.217822 13:0.309353 14:-0.142857 21 | 1.0551 1:-0.195789 2:-0.79661 3:-0.505416 4:0.595855 5:-0.20398 6:-0.156415 7:-0.326557 8:-0.365231 9:-0.187032 10:-0.378882 11:-0.594595 12:-0.237624 13:0.338129 14:-0.0714286 22 | 1.064 1:-0.36 2:-0.79661 3:-0.329655 4:0.668394 5:0.0149254 6:0.128295 7:-0.252859 8:-0.368421 9:-0.19202 10:-0.0559006 11:-0.256757 12:-0.188119 13:0.697842 14:0.464286 23 | 1.0631 1:-0.343158 2:-0.694915 3:-0.822195 4:0.606218 5:-0.721393 6:-0.764499 7:-0.822109 8:-0.69378 9:-0.491272 10:-0.714286 11:-0.581081 12:-0.693069 13:-0.294964 14:-0.678571 24 | 1.0584 1:-0.254737 2:-0.661017 3:-0.752708 4:0.678756 5:-0.562189 6:-0.739895 7:-0.730623 8:-0.732057 9:-0.61596 10:-0.602484 11:-0.594595 12:-0.50495 13:-0.179856 14:-0.535714 25 | 1.0668 1:-0.410526 2:-0.79661 3:-0.732271 4:0.585492 5:-0.661692 6:-0.616872 7:-0.824651 8:-0.655502 9:-0.441397 10:-0.689441 11:-0.486486 12:-0.376238 13:0.00719424 14:-0.357143 26 | 1.0911 1:-0.844211 2:-0.830508 3:-0.666871 4:0.740933 5:-0.542289 6:-0.637961 7:-0.738247 8:-0.633174 9:-0.610973 10:-0.540373 11:-0.540541 12:-0.49505 13:0.0359712 14:-0.321429 27 | 1.0811 1:-0.667368 2:-0.59322 3:-0.893726 4:0.57513 5:-0.492537 6:-0.673111 7:-0.867853 8:-0.990431 9:-0.775561 10:-0.78882 11:-0.689189 12:-0.613861 13:-0.136691 14:-0.75 28 | 1.0468 1:-0.0357895 2:-0.694915 3:-0.758839 4:0.57513 5:-0.233831 6:-0.363796 7:-0.50953 8:-0.69059 9:-0.486284 10:-0.627329 11:-0.743243 12:-0.564356 13:-0.194245 14:-0.571429 29 | 1.091 1:-0.844211 2:-0.830508 3:-0.87942 4:0.46114 5:-0.472637 6:-0.500879 7:-0.885642 8:-0.888357 9:-0.855362 10:-0.813665 11:-0.702703 12:-0.435644 13:-0.00719424 14:-0.5 30 | 1.079 1:-0.629474 2:-0.762712 3:-0.654609 4:0.637306 5:-0.442786 6:-0.363796 7:-0.641677 8:-0.562998 9:-0.416459 10:-0.714286 11:-0.527027 12:-0.475248 13:-0.179856 14:-0.357143 31 | 1.0716 1:-0.498947 2:-0.661017 3:-0.480891 4:0.834197 5:-0.243781 6:-0.254833 7:-0.50953 8:-0.527911 9:-0.486284 10:-0.291925 11:1 12:-0.237624 13:-0.0359712 14:-0.0714286 32 | 1.0862 1:-0.76 2:-0.762712 3:-0.658696 4:0.73057 5:-0.383085 6:-0.500879 7:-0.616264 8:-0.502392 9:-0.436409 10:-0.279503 11:-0.675676 12:-0.475248 13:-0.223022 14:-0.25 33 | 1.0719 1:-0.503158 2:-0.830508 3:-0.59534 4:0.73057 5:-0.303483 6:-0.518453 7:-0.753494 8:-0.69697 9:-0.496259 10:-0.602484 11:-0.27027 12:-0.584158 13:0.294964 14:0.0714286 34 | 1.0502 1:-0.103158 2:-0.355932 3:-0.182506 4:0.720207 5:-0.134328 6:0.13884 7:-0.209657 8:-0.256778 9:-0.0074813 10:0.391304 11:-0.175676 12:0.257426 13:0.510791 14:0.0357143 35 | 1.0263 1:0.36 2:-0.355932 3:0.052524 4:0.823834 5:0.0945274 6:0.325132 7:0.174079 8:-0.00797448 9:0.197007 10:0.279503 11:-0.027027 12:0.237624 13:0.539568 14:0.392857 36 | 1.0101 1:0.688421 2:-0.0847458 3:-0.401185 4:0.471503 5:-0.273632 6:0.377856 7:0.110546 8:-0.0813397 9:-0.266833 10:-0.341615 11:-0.621622 12:-0.287129 13:0.266187 14:-0.571429 37 | 1.0438 1:0.0189474 2:-0.389831 3:-0.315348 4:0.678756 5:-0.263682 6:-0.0439367 7:-0.199492 8:-0.323764 9:-0.187032 10:-0.142857 11:-0.527027 12:0.019802 13:0.381295 14:0.142857 38 | 1.0346 1:0.195789 2:-0.0508475 3:-0.360311 4:0.606218 5:0.0945274 6:-0.0755712 7:-0.252859 8:-0.368421 9:-0.0623441 10:0.0559006 11:-0.243243 12:-0.168317 13:0.366906 14:0.285714 39 | 1.0202 1:0.482105 2:-0.186441 3:1 4:0.772021 5:1 6:1 7:1 8:1 9:1 10:1 11:0.418919 12:1 13:0.151079 14:1 40 | 1.0258 1:0.372632 2:-0.0508475 3:-0.309217 4:0.554404 5:-0.0945274 6:0.247803 7:-0.0165184 8:-0.441786 9:-0.296758 10:0.00621118 11:-0.243243 12:-0.0792079 13:0.438849 14:-0.107143 41 | 1.0217 1:0.452632 2:-0.220339 3:0.179236 4:0.626943 5:0.20398 6:0.72232 7:0.443456 8:0.295056 9:0.261845 10:-0.180124 11:0.0135135 12:0.148515 13:0.683453 14:1 42 | 1.025 1:0.385263 2:-0.254237 3:-0.292867 4:-1 5:-0.452736 6:-0.0615114 7:-0.113088 8:-0.0271132 9:0.167082 10:0.180124 11:-0.378378 12:-0.128713 13:0.107914 14:-0.428571 43 | 1.0279 1:0.330526 2:-0.118644 3:-0.194768 4:0.678756 5:-0.383085 6:0.195079 7:0.0622618 8:-0.0717703 9:0.0224439 10:-0.0186335 11:-0.202703 12:0.178218 13:0.266187 14:-0.0714286 44 | 1.0269 1:0.347368 2:-0.355932 3:-0.235643 4:0.740933 5:0.0348259 6:-0.0404218 7:-0.113088 8:-0.330144 9:-0.112219 10:-0.10559 11:-0.472973 12:0.0891089 13:0.510791 14:0.0714286 45 | 1.0814 1:-0.675789 2:-0.423729 3:-0.944819 4:0.595855 5:-0.960199 6:-0.796134 7:-0.832274 8:-0.897927 9:-0.860349 10:-0.78882 11:-0.743243 12:-0.871287 13:-0.697842 14:-0.892857 46 | 1.067 1:-0.414737 2:-0.288136 3:-0.625996 4:0.813472 5:-0.542289 6:-0.391916 7:-0.692503 8:-0.610845 9:-0.441397 10:-0.354037 11:-0.418919 12:-0.514851 13:-0.0791367 14:-0.107143 47 | 1.0742 1:-0.545263 2:-0.389831 3:-0.877376 4:0.57513 5:-0.751244 6:-0.68717 7:-0.890724 8:-0.888357 9:-0.695761 10:-0.813665 11:-0.540541 12:-0.693069 13:-0.251799 14:-0.464286 48 | 1.0665 1:-0.764211 2:-0.423729 3:-0.754752 4:0.73057 5:-0.651741 6:-0.630931 7:-0.743329 8:-0.754386 9:-0.725686 10:-0.440994 11:-0.621622 12:-0.60396 13:-0.165468 14:-0.25 49 | 1.0678 1:-0.427368 2:-0.220339 3:-0.858982 4:0.61658 5:-0.830846 6:-0.543058 7:-0.644219 8:-0.827751 9:-0.760599 10:-0.652174 11:-0.797297 12:-0.60396 13:-0.352518 14:-0.821429 50 | 1.0903 1:-0.831579 2:-0.152542 3:-0.926426 4:0.544041 5:-0.711443 6:-0.855888 7:-0.974587 8:-0.929825 9:-0.830424 10:-0.826087 11:-0.621622 12:-0.80198 13:-0.309353 14:-0.642857 51 | 1.0756 1:-0.570526 2:-0.152542 3:-0.675046 4:0.772021 5:-0.621891 6:-0.616872 7:-0.560356 8:-0.575758 9:-0.730673 10:-0.478261 11:-0.554054 12:-0.881188 13:-0.309353 14:-0.464286 52 | 1.084 1:-0.722105 2:-0.389831 3:-0.83037 4:0.637306 5:-0.681592 6:-0.652021 7:-0.78399 8:-0.808612 9:-0.790524 10:-0.763975 11:-0.743243 12:-0.811881 13:-0.266187 14:-0.5 53 | 1.0807 1:-0.663158 2:-0.0169492 3:-0.84672 4:0.585492 5:-0.462687 6:-0.634446 7:-0.679797 8:-0.869219 9:-0.895262 10:-0.913043 11:-0.689189 12:-0.524752 13:-0.280576 14:-0.607143 54 | 1.0848 1:-0.734737 2:-0.0847458 3:-0.720008 4:0.823834 5:-0.60199 6:-0.507909 7:-0.740788 8:-0.789474 9:-0.730673 10:-0.428571 11:-0.527027 12:0.356436 13:-0.0791367 14:-0.0357143 55 | 1.0906 1:-0.835789 2:-0.322034 3:-0.854895 4:0.57513 5:-0.333333 6:-0.70826 7:-0.791614 8:-0.885167 9:-0.765586 10:-0.763975 11:-0.540541 12:-0.712871 13:-0.0647482 14:-0.0357143 56 | 1.0473 1:-0.0484211 2:0.0847458 3:-0.350092 4:0.761658 5:-0.124378 6:-0.00527241 7:-0.222363 8:-0.53429 9:-0.501247 10:-0.378882 11:-0.608108 12:0.0990099 13:0.323741 14:0.107143 57 | 1.0524 1:-0.141053 2:0.220339 3:-0.484979 4:0.595855 5:-0.20398 6:-0.272408 7:-0.227446 8:-0.441786 9:-0.256858 10:-0.180124 11:-0.540541 12:-0.178218 13:0.0503597 14:-0.0357143 58 | 1.0356 1:0.178947 2:0.355932 3:-0.323523 4:0.658031 5:-0.0646766 6:0.13181 7:-0.115629 8:-0.336523 9:-0.27182 10:-0.15528 11:-0.513514 12:0.277228 13:0.42446 14:0.214286 59 | 1.028 1:0.326316 2:0.0847458 3:-0.313305 4:0.709845 5:-0.0646766 6:0.268893 7:-0.0876747 8:-0.617225 9:-0.406484 10:-0.378882 11:-0.540541 12:-0.326733 13:0.122302 14:-0.142857 60 | 1.043 1:0.0357895 2:0.322034 3:-0.499285 4:0.502591 5:-0.273632 6:-0.103691 7:-0.265565 8:-0.53429 9:-0.331671 10:-0.416149 11:-0.486486 12:-0.039604 13:0.23741 14:-0.0357143 61 | 1.0396 1:0.0989474 2:0.355932 3:-0.202943 4:0.813472 5:0.0248756 6:0.15993 7:-0.100381 8:-0.422648 9:-0.281796 10:-0.0186335 11:-0.459459 12:0.128713 13:0.553957 14:0.571429 62 | 1.0317 1:0.254737 2:0.152542 3:-0.50746 4:0.61658 5:-0.552239 6:-0.170475 7:-0.357052 8:-0.496013 9:-0.316708 10:-0.378882 11:-0.594595 12:-0.237624 13:0.266187 14:-0.107143 63 | 1.0298 1:0.292632 2:0.0847458 3:-0.388923 4:0.689119 5:-0.313433 6:-0.00527241 7:-0.161372 8:-0.54067 9:-0.311721 10:-0.204969 11:-0.391892 12:-0.217822 13:0.280576 14:0.178571 64 | 1.0403 1:0.0863158 2:0.322034 3:-0.513591 4:0.554404 5:-0.373134 6:-0.086116 7:-0.229987 8:-0.5311 9:-0.321696 10:-0.118012 11:-0.513514 12:-0.128713 13:0.151079 14:0.0714286 65 | 1.0264 1:0.36 2:0.186441 3:-0.28878 4:0.678756 5:-0.104478 6:-0.086116 7:-0.0825921 8:-0.256778 9:-0.112219 10:0.0186335 11:-0.243243 12:0.039604 13:0.453237 14:-0.0714286 66 | 1.0313 1:0.263158 2:0.118644 3:-0.468629 4:0.57513 5:-0.0248756 6:-0.16696 7:-0.21474 8:-0.38756 9:-0.122195 10:-0.10559 11:-0.513514 12:-0.00990099 13:0.309353 14:0.0357143 67 | 1.0499 1:-0.0947368 2:0.0847458 3:-0.730227 4:0.709845 5:-0.552239 6:-0.623902 7:-0.631512 8:-0.716108 9:-0.610973 10:-0.614907 11:-0.648649 12:-0.524752 13:-0.0791367 14:-0.428571 68 | 1.0673 1:-0.418947 2:0.118644 3:-0.703658 4:0.740933 5:-0.422886 6:-0.434095 7:-0.562897 8:-0.783094 9:-0.645885 10:-0.701863 11:-0.675676 12:-0.207921 13:-0.0791367 14:0.0357143 69 | 1.0847 1:-0.734737 2:0.0847458 3:-0.699571 4:0.647668 5:-0.363184 6:-0.648506 7:-0.771283 8:-0.645933 9:-0.561097 10:-0.453416 11:-0.554054 12:-0.227723 13:0.0215827 14:-0.178571 70 | 1.0693 1:-0.456842 2:0.118644 3:-0.687308 4:0.740933 5:-0.482587 6:-0.469244 7:-0.613723 8:-0.703349 9:-0.800499 10:-0.453416 11:-0.662162 12:-0.752475 13:-0.122302 14:-0.464286 71 | 1.0439 1:0.0231579 2:0.355932 3:-0.599428 4:0.740933 5:-0.562189 6:-0.356766 7:-0.438374 8:-0.569378 9:-0.531172 10:-0.304348 11:-0.554054 12:-0.336634 13:-0.0935252 14:6.66134e-16 72 | 1.0788 1:-0.629474 2:0.118644 3:-0.769058 4:0.626943 5:-0.243781 6:-0.676626 7:-0.659466 8:-0.665072 9:-0.416459 10:-0.428571 11:-0.662162 12:-0.455446 13:-0.0935252 14:-0.107143 73 | 1.0796 1:-0.642105 2:0.152542 3:-0.654609 4:0.834197 5:-0.472637 6:-0.497364 7:-0.656925 8:-0.639553 9:-0.715711 10:-0.440994 11:-0.459459 12:-0.514851 13:-0.0935252 14:-0.142857 74 | 1.068 1:-0.431579 2:0.118644 3:-0.946863 4:0.430052 5:-0.791045 6:-0.704745 7:-0.832274 8:-0.885167 9:-0.815461 10:-0.701863 11:-1 12:-0.554455 13:-0.323741 14:-0.607143 75 | 1.072 1:-0.503158 2:0.322034 3:-0.799714 4:0.502591 5:-0.462687 6:-0.504394 7:-0.64676 8:-0.744817 9:-0.586035 10:-0.726708 11:-0.756757 12:-0.544554 13:-0.136691 14:-0.642857 76 | 1.0666 1:-0.221053 2:0.322034 3:-0.756795 4:0.57513 5:-0.512438 6:-0.567663 7:-0.684879 8:-0.6874 9:-0.63591 10:-0.503106 11:-0.689189 12:-0.554455 13:-0.136691 14:-0.107143 77 | 1.079 1:-0.629474 2:0.186441 3:-0.640302 4:0.658031 5:-0.243781 6:-0.567663 7:-0.761118 8:-0.703349 9:-0.526185 10:-0.167702 11:-0.310811 12:-0.465347 13:0.179856 14:-0.178571 78 | 1.0483 1:-0.0652632 2:0.59322 3:-0.515635 4:0.61658 5:-0.243781 6:-0.202109 7:-0.349428 8:-0.575758 9:-0.610973 10:-0.341615 11:-0.635135 12:-0.405941 13:-0.323741 14:0.0714286 79 | 1.0498 1:-0.0947368 2:1 3:-0.650521 4:0.689119 5:-0.333333 6:-0.398946 7:-0.339263 8:-0.54386 9:-0.685786 10:-0.440994 11:-0.675676 12:-0.346535 13:-0.165468 14:-0.107143 80 | 1.056 1:-0.208421 2:0.491525 3:-0.568772 4:0.647668 5:-0.373134 6:-0.177504 7:-0.257942 8:-0.515152 9:-0.53616 10:-0.217391 11:-0.513514 12:-0.455446 13:0.107914 14:0.142857 81 | 1.0283 1:0.322105 2:0.525424 3:-0.630084 4:0.585492 5:-0.273632 6:-0.353251 7:-0.329098 8:-0.614035 9:-0.620948 10:-0.354037 11:-0.378378 12:-0.544554 13:-0.107914 14:0.142857 82 | 1.0382 1:0.128421 2:0.423729 3:-0.740446 4:0.564767 5:-0.303483 6:-0.374341 7:-0.501906 8:-0.620415 9:-0.620948 10:-0.378882 11:-0.608108 12:-0.49505 13:-0.395683 14:-0.321429 83 | 1.0568 1:-0.225263 2:0.423729 3:-0.413448 4:0.792746 5:-0.18408 6:-0.163445 7:-0.278272 8:-0.53429 9:-0.416459 10:-0.254658 11:-0.472973 12:-0.0594059 13:0.23741 14:0.142857 84 | 1.0377 1:0.136842 2:0.627119 3:-0.572859 4:0.678756 5:-0.243781 6:-0.209139 7:-0.35197 8:-0.681021 9:-0.561097 10:-0.565217 11:-0.324324 12:-0.366337 13:-0.0935252 14:0.214286 85 | 1.0378 1:0.136842 2:0.694915 3:-0.59534 4:0.647668 5:-0.263682 6:-0.223199 7:-0.227446 8:-0.642743 9:-0.546135 10:-0.552795 11:-0.608108 12:-0.514851 13:-0.23741 14:-0.214286 86 | 1.0386 1:0.12 2:0.525424 3:-0.603515 4:0.57513 5:-0.462687 6:-0.311072 7:-0.484117 8:-0.642743 9:-0.625935 10:-0.403727 11:0.972973 12:-0.247525 13:-0.0359712 14:-0.142857 87 | 1.0648 1:-0.372632 2:0.694915 3:-0.679133 4:0.564767 5:-0.343284 6:-0.360281 7:-0.524778 8:-0.620415 9:-0.501247 10:-0.416149 11:-0.635135 12:-0.227723 13:0.00719424 14:0.0714286 88 | 1.0462 1:-0.0273684 2:0.423729 3:-0.66074 4:0.502591 5:-0.462687 6:-0.121265 7:-0.453621 8:-0.719298 9:-0.471322 10:-0.192547 11:-0.432432 12:-0.564356 13:0.0647482 14:-0.178571 89 | 1.08 1:-0.650526 2:-0.186441 3:-0.52381 4:0.782383 5:-0.313433 6:-0.367311 7:-0.578145 8:-0.54386 9:-0.311721 10:-0.329193 11:-0.364865 12:-0.465347 13:0.194245 14:0.0714286 90 | 1.0666 1:-0.406316 2:-0.118644 3:-0.529941 4:0.803109 5:-0.442786 6:-0.388401 7:-0.565438 8:-0.575758 9:-0.341646 10:-0.142857 11:-0.283784 12:-0.60396 13:0.23741 14:0.0357143 91 | 1.052 1:-0.136842 2:-0.186441 3:-0.521766 4:0.678756 5:-0.393035 6:-0.282953 7:-0.33418 8:-0.451356 9:-0.446384 10:-0.354037 11:-0.540541 12:-0.574257 13:-0.0359712 14:-0.321429 92 | 1.0573 1:-0.233684 2:-0.254237 3:-0.499285 4:0.658031 5:-0.19403 6:-0.205624 7:-0.395172 8:-0.502392 9:-0.416459 10:-0.167702 11:-0.459459 12:-0.346535 13:0.0647482 14:0.0714286 93 | 1.0795 1:-0.642105 2:-0.152542 3:-0.617821 4:0.699482 5:-0.363184 6:-0.370826 7:-0.651842 8:-0.668262 9:-0.516209 10:-0.341615 11:-0.594595 12:-0.475248 13:0.0359712 14:-0.0714286 94 | 1.0424 1:0.0484211 2:-0.186441 3:-0.395054 4:0.751295 5:-0.313433 6:-0.0404218 7:-0.285896 8:-0.502392 9:-0.416459 10:-0.068323 11:-0.27027 12:-0.158416 13:0.23741 14:0.178571 95 | 1.0785 1:-0.621053 2:-0.152542 3:-0.462497 4:0.865285 5:-0.383085 6:-0.286467 7:-0.506989 8:-0.476874 9:-0.491272 10:-0.180124 11:-0.256757 12:-0.455446 13:-0.00719424 14:-0.285714 96 | 1.0991 1:-0.267368 2:0.0508475 3:-0.133456 4:1 5:-0.00497512 6:0.191564 7:-0.242694 8:-0.282297 9:-0.276808 10:0.15528 11:-0.445946 12:-0.19802 13:0.410072 14:0.642857 97 | 1.077 1:-0.595789 2:-0.457627 3:-0.42571 4:0.813472 5:-0.363184 6:-0.304042 7:-0.435832 8:-0.444976 9:-0.331671 10:-0.204969 11:-0.486486 12:-0.326733 13:0.309353 14:-0.0357143 98 | 1.073 1:-0.524211 2:-0.0508475 3:-0.640302 4:0.533679 5:-0.243781 6:-0.293497 7:-0.560356 8:-0.642743 9:-0.256858 10:-0.217391 11:-0.432432 12:-0.425743 13:-0.0215827 14:-0.142857 99 | 1.0582 1:-0.250526 2:-0.186441 3:-0.689352 4:0.606218 5:-0.522388 6:-0.44464 7:-0.522236 8:-0.751196 9:-0.625935 10:-0.465839 11:-0.621622 12:-0.326733 13:-0.0647482 14:-0.142857 100 | 1.0484 1:-0.0652632 2:-0.152542 3:-0.358267 4:0.761658 5:-0.114428 6:-0.00878735 7:-0.374841 8:-0.403509 9:-0.226933 10:-0.254658 11:-0.567568 12:0.039604 13:0.42446 14:-0.107143 101 | 1.0506 1:-0.107368 2:-0.0847458 3:-0.346004 4:0.823834 5:-0.104478 6:-0.0439367 7:-0.349428 8:-0.467305 9:-0.411471 10:-0.204969 11:-0.567568 12:-0.267327 13:0.438849 14:6.66134e-16 102 | 1.0524 1:-0.141053 2:-0.118644 3:-0.548334 4:0.761658 5:-0.412935 6:-0.304042 7:-0.425667 8:-0.575758 9:-0.396509 10:-0.329193 11:-0.554054 12:-0.693069 13:-0.251799 14:-0.571429 103 | 1.053 1:-0.153684 2:-0.355932 3:-0.556509 4:0.73057 5:-0.482587 6:-0.388401 7:-0.496823 8:-0.575758 9:-0.361596 10:-0.329193 11:-0.445946 12:-0.386139 13:0.179856 14:-0.0714286 104 | 1.048 1:-0.0610526 2:-0.0847458 3:-0.360311 4:0.834197 5:-0.0447761 6:-0.149385 7:-0.336722 8:-0.470494 9:-0.406484 10:-0.15528 11:-0.148649 12:-0.386139 13:0.338129 14:0.392857 105 | 1.0412 1:0.0694737 2:-0.288136 3:-0.521766 4:0.647668 5:-0.154229 6:-0.13181 7:-0.257942 8:-0.53748 9:-0.386534 10:-0.614907 11:-0.608108 12:-0.475248 13:-0.107914 14:-0.321429 106 | 1.0578 1:-0.242105 2:-0.288136 3:-0.615778 4:0.61658 5:-1 6:-0.514938 7:-0.545108 8:-0.629984 9:-0.625935 10:-0.254658 11:-0.22973 12:-0.386139 13:0.208633 14:0.0714286 107 | 1.0547 1:-0.187368 2:-0.288136 3:-0.331698 4:0.823834 5:-0.253731 6:-0.0896309 7:-0.151207 8:-0.406699 9:-0.301746 10:-0.217391 11:-0.405405 12:-0.435644 13:0.0791367 14:-0.178571 108 | 1.0569 1:-0.229474 2:0.0169492 3:-0.307174 4:0.854922 5:0.0845771 6:0.0790861 7:-0.181703 8:-0.499203 9:-0.571072 10:-0.291925 11:-0.418919 12:0.019802 13:0.23741 14:0.178571 109 | 1.0593 1:-0.271579 2:-0.288136 3:-0.382792 4:0.906736 5:-0.263682 6:0.0826011 7:-0.50953 8:-0.454545 9:-0.486284 10:-0.130435 11:-0.22973 12:0.019802 13:0.395683 14:0.214286 110 | 1.05 1:-0.0989474 2:-0.389831 3:-0.591253 4:0.647668 5:-0.691542 6:-0.349736 7:-0.418043 8:-0.502392 9:-0.486284 10:-0.52795 11:-0.5 12:-0.277228 13:-0.280576 14:-0.464286 111 | 1.0538 1:-0.170526 2:-0.288136 3:-0.572859 4:0.61658 5:-0.393035 6:-0.40246 7:-0.461245 8:-0.54386 9:-0.266833 10:-0.378882 11:-0.567568 12:-0.158416 13:0.0359712 14:-0.178571 112 | 1.0355 1:0.178947 2:-0.288136 3:-0.470672 4:0.678756 5:-0.402985 6:0.00878735 7:-0.0952986 8:-0.425837 9:-0.177057 10:-0.130435 11:-0.391892 12:-0.138614 13:-0.0215827 14:-0.428571 113 | 1.0486 1:-0.0694737 2:-0.152542 3:-0.511547 4:0.678756 5:-0.0945274 6:-0.282953 7:-0.349428 8:-0.566188 9:-0.246883 10:-0.36646 11:-0.351351 12:0.039604 13:0.453237 14:0.428571 114 | 1.0503 1:-0.103158 2:-0.322034 3:-0.636215 4:0.689119 5:-0.58209 6:-0.500879 7:-0.486658 8:-0.527911 9:-0.286783 10:-0.403727 11:-0.621622 12:-0.415842 13:-0.0503597 14:-0.428571 115 | 1.0384 1:0.124211 2:-0.118644 3:-0.536072 4:0.751295 5:-0.313433 6:-0.247803 7:-0.415502 8:-0.601276 9:-0.396509 10:-0.36646 11:-0.635135 12:-0.306931 13:-0.0935252 14:-0.392857 116 | 1.0607 1:-0.296842 2:-0.389831 3:-0.67709 4:0.647668 5:-0.482587 6:-0.377856 7:-0.562897 8:-0.757576 9:-0.566085 10:-0.590062 11:-0.594595 12:-0.50495 13:-0.23741 14:-0.464286 117 | 1.0529 1:-0.153684 2:-0.118644 3:-0.519722 4:0.792746 5:-0.432836 6:-0.413005 7:-0.476493 8:-0.5311 9:-0.421446 10:-0.329193 11:-0.5 12:-0.49505 13:0.00719424 14:-0.178571 118 | 1.0671 1:-0.414737 2:-0.0169492 3:-0.505416 4:0.761658 5:-0.0149254 6:-0.300527 7:-0.476493 8:-0.636364 9:-0.521197 10:-0.279503 11:-0.432432 12:-0.148515 13:0.266187 14:0.321429 119 | 1.0404 1:0.0863158 2:-0.389831 3:-0.407317 4:0.84456 5:-0.283582 6:-0.434095 7:-0.415502 8:-0.38437 9:-0.13217 10:0.00621118 11:-0.22973 12:-0.128713 13:0.223022 14:-0.0357143 120 | 1.0575 1:-0.237895 2:-0.254237 3:-0.435929 4:0.772021 5:-0.313433 6:-0.209139 7:-0.540025 8:-0.489633 9:-0.436409 10:-0.229814 11:-0.27027 12:-0.277228 13:0.0935252 14:-0.214286 121 | 1.0358 1:0.174737 2:0.0169492 3:-0.280605 4:0.865285 5:-0.0348259 6:-0.121265 7:-0.242694 8:-0.39075 9:-0.436409 10:-0.217391 11:-0.256757 12:-0.0990099 13:0.467626 14:0.321429 122 | 1.0414 1:0.0652632 2:-0.254237 3:-0.454323 4:0.740933 5:-0.164179 6:-0.300527 7:-0.270648 8:-0.476874 9:-0.506234 10:-0.068323 11:-0.445946 12:-0.188119 13:0.23741 14:-0.0714286 123 | 1.0652 1:-0.381053 2:-0.389831 3:-0.658696 4:0.626943 5:-0.422886 6:-0.297012 7:-0.64676 8:-0.601276 9:-0.336658 10:-0.291925 11:-0.527027 12:-0.049505 13:0.00719424 14:-0.357143 124 | 1.0623 1:-0.326316 2:-0.152542 3:-0.730227 4:0.544041 5:-0.422886 6:-0.483304 7:-0.575604 8:-0.674641 9:-0.456359 10:-0.565217 11:-0.594595 12:-0.425743 13:-0.0647482 14:-0.357143 125 | 1.0674 1:-0.418947 2:-0.0508475 3:-0.652565 4:0.533679 5:-0.343284 6:-0.311072 7:-0.626429 8:-0.712919 9:-0.436409 10:-0.552795 11:-0.405405 12:-0.049505 13:0.179856 14:-0.214286 126 | 1.0587 1:-0.263158 2:-0.186441 3:-0.603515 4:0.554404 5:-0.452736 6:-0.237258 7:-0.479034 8:-0.521531 9:-0.326683 10:-0.627329 11:-0.621622 12:0.0693069 13:0.323741 14:-0.357143 127 | 1.0373 1:0.145263 2:-0.322034 3:-0.517678 4:0.626943 5:-0.223881 6:-0.318102 7:-0.423126 8:-0.569378 9:-0.326683 10:-0.52795 11:-0.581081 12:-0.108911 13:0.338129 14:-0.5 128 | 1.059 1:-0.267368 2:-0.288136 3:-0.724096 4:0.585492 5:-0.363184 6:-0.41652 7:-0.781449 8:-0.738437 9:-0.685786 10:-0.652174 11:-0.77027 12:-0.0990099 13:0.0359712 14:-0.428571 129 | 1.0515 1:-0.124211 2:-0.389831 3:-0.397098 4:0.813472 5:-0.134328 6:-0.135325 7:-0.387548 8:-0.53748 9:-0.276808 10:-0.254658 11:-0.635135 12:-0.158416 13:0.23741 14:-0.178571 130 | 1.0648 1:-0.372632 2:-0.322034 3:-0.617821 4:0.668394 5:-0.283582 6:-0.405975 7:-0.552732 8:-0.591707 9:-0.491272 10:-0.515528 11:-0.581081 12:-0.326733 13:-0.0215827 14:-0.321429 131 | 1.0575 1:-0.237895 2:-0.0847458 3:-0.564684 4:0.740933 5:-0.562189 6:-0.349736 7:-0.473952 8:-0.655502 9:-0.511222 10:-0.291925 11:-0.445946 12:-0.732673 13:-0.208633 14:-0.357143 132 | 1.0472 1:-0.0442105 2:-0.389831 3:-0.568772 4:0.699482 5:-0.482587 6:-0.462214 7:-0.468869 8:-0.550239 9:-0.346633 10:-0.31677 11:-0.472973 12:-0.366337 13:0.0647482 14:-0.535714 133 | 1.0452 1:-0.00631579 2:-0.152542 3:-0.358267 4:0.813472 5:-0.333333 6:-0.14587 7:-0.227446 8:-0.419458 9:-0.301746 10:-0.36646 11:-0.527027 12:-0.138614 13:0.0935252 14:-0.25 134 | 1.0398 1:0.0989474 2:-0.0508475 3:-0.685265 4:0.544041 5:-0.333333 6:-0.258348 7:-0.491741 8:-0.767145 9:-0.55611 10:-0.677019 11:-0.810811 12:-0.128713 13:0.194245 14:-0.464286 135 | 1.0435 1:0.0273684 2:-0.355932 3:-0.593297 4:0.658031 5:-0.462687 6:-0.328647 7:-0.547649 8:-0.572568 9:-0.561097 10:-0.515528 11:-0.472973 12:-0.0891089 13:0.266187 14:-0.178571 136 | 1.0374 1:0.141053 2:-0.254237 3:-0.448191 4:0.668394 5:-0.333333 6:-0.110721 7:-0.194409 8:-0.454545 9:-0.416459 10:-0.391304 11:-0.513514 12:-0.39604 13:0.122302 14:-0.357143 137 | 1.0491 1:-0.0821053 2:-0.423729 3:-0.605559 4:0.709845 5:-0.412935 6:-0.521968 7:-0.575604 8:-0.661882 9:-0.421446 10:-0.614907 11:-0.554054 12:-0.217822 13:0.0503597 14:-0.535714 138 | 1.0325 1:0.237895 2:-0.288136 3:-0.433885 4:0.84456 5:-0.343284 6:-0.349736 7:-0.257942 8:-0.502392 9:-0.182045 10:-0.229814 11:-0.364865 12:-0.0594059 13:0.0647482 14:-0.321429 139 | 1.0481 1:-0.0568421 2:-0.389831 3:-0.593297 4:0.73057 5:-0.681592 6:-0.332162 7:-0.514612 8:-0.575758 9:-0.456359 10:-0.329193 11:-0.540541 12:-0.316832 13:-0.0791367 14:-0.357143 140 | 1.0522 1:-0.141053 2:-0.0847458 3:-0.229512 4:0.88601 5:-0.0348259 6:-0.107206 7:-0.0546379 8:-0.275917 9:-0.0374065 10:0.180124 11:-0.27027 12:0.0594059 13:0.266187 14:0.0357143 141 | 1.0422 1:0.0484211 2:-0.389831 3:-0.52381 4:0.720207 5:-0.373134 6:-0.321617 7:-0.397713 8:-0.470494 9:-0.406484 10:-0.180124 11:-0.662162 12:-0.405941 13:-0.00719424 14:-0.714286 142 | 1.0571 1:-0.229474 2:-0.389831 3:-0.552422 4:0.658031 5:-0.462687 6:-0.289982 7:-0.400254 8:-0.54386 9:-0.341646 10:-0.354037 11:-0.608108 12:-0.287129 13:0.0791367 14:-0.285714 143 | 1.0459 1:-0.0189474 2:0.0169492 3:-0.603515 4:0.585492 5:-0.363184 6:-0.177504 7:-0.45108 8:-0.556619 9:-0.506234 10:-0.540373 11:-0.567568 12:-0.326733 13:-0.0647482 14:-0.25 144 | 1.0775 1:-0.604211 2:-0.966102 3:-0.662784 4:0.772021 5:-0.562189 6:-0.550088 7:-0.80432 8:-0.716108 9:-0.55611 10:-0.614907 11:-0.513514 12:-0.435644 13:-0.107914 14:-0.142857 145 | 1.0754 1:-0.566316 2:-0.966102 3:-0.430615 4:0.989637 5:-0.313433 6:-0.391916 7:-0.595934 8:-0.441786 9:-0.406484 10:-0.428571 11:-0.445946 12:-0.306931 13:0.251799 14:-0.107143 146 | 1.0664 1:-0.402105 2:-0.932203 3:-0.69344 4:0.709845 5:-0.542289 6:-0.528998 7:-0.682338 8:-0.671451 9:-0.541147 10:-0.565217 11:-0.608108 12:-0.138614 13:0.0503597 14:-0.464286 147 | 1.055 1:-0.191579 2:-0.932203 3:-0.264255 4:0.792746 5:-0.19403 6:-0.202109 7:-0.245235 8:-0.199362 9:0.197007 10:0.304348 11:-0.175676 12:0.118812 13:0.338129 14:0.0357143 148 | 1.0322 1:0.246316 2:-0.898305 3:-0.280605 4:0.668394 5:-0.0248756 6:0.110721 7:-0.209657 8:-0.323764 9:0.0573566 10:-0.0310559 11:-0.256757 12:-0.158416 13:0.251799 14:-0.0714286 149 | 1.0873 1:-0.776842 2:-0.898305 3:-0.793583 4:0.782383 5:-0.59204 6:-0.543058 7:-0.819568 8:-0.773525 9:-0.765586 10:-0.664596 11:-0.608108 12:-0.90099 13:-0.395683 14:-0.607143 150 | 1.0416 1:0.0610526 2:-0.864407 3:-0.145718 4:0.689119 5:-0.0547264 6:0.223199 7:-0.0495553 8:-0.0781499 9:0.0174564 10:0.204969 11:-0.243243 12:0.108911 13:0.352518 14:-0.0714286 151 | 1.0776 1:-0.604211 2:-0.864407 3:-0.724096 4:0.637306 5:-0.572139 6:-0.521968 7:-0.791614 8:-0.728868 9:-0.516209 10:-0.639752 11:-0.824324 12:-0.326733 13:0.151079 14:-0.285714 152 | 1.0542 1:-0.174737 2:-0.864407 3:0.00756182 4:0.865285 5:0.0646766 6:0.0193322 7:-0.148666 8:-0.062201 9:0.281796 10:0.304348 11:-0.189189 12:0.356436 13:0.841727 14:0.357143 153 | 1.0758 1:-0.574737 2:-0.830508 3:-0.775189 4:0.772021 5:-0.701493 6:-0.676626 7:-0.913596 8:-0.805423 9:-0.680798 10:-0.52795 11:-0.364865 12:-0.70297 13:-0.23741 14:-0.428571 154 | 1.061 1:-0.305263 2:-0.830508 3:-0.687308 4:0.564767 5:-0.323383 6:-0.483304 7:-0.522236 8:-0.674641 9:-0.521197 10:-0.453416 11:-0.5 12:-0.425743 13:0.0503597 14:-0.25 155 | 1.051 1:-0.115789 2:-0.830508 3:-0.331698 4:0.823834 5:-0.293532 6:-0.233743 7:-0.219822 8:-0.362041 9:-0.256858 10:-0.130435 11:-0.216216 12:-0.118812 13:0.179856 14:0.285714 156 | 1.0594 1:-0.271579 2:-0.79661 3:-0.566728 4:0.896373 5:-0.552239 6:-0.550088 7:-0.641677 8:-0.575758 9:-0.496259 10:-0.403727 11:-0.648649 12:-0.267327 13:-0.0359712 14:-0.321429 157 | 1.0287 1:0.313684 2:-0.79661 3:-0.286736 4:0.637306 5:-0.263682 6:-0.0755712 7:-0.0952986 8:-0.317384 9:0.0673317 10:-0.130435 11:-0.175676 12:0.029703 13:0.395683 14:0.178571 158 | 1.0761 1:-0.578947 2:-0.79661 3:-0.476804 4:0.772021 5:-0.412935 6:-0.325132 7:-0.456163 8:-0.441786 9:-0.321696 10:-0.31677 11:-0.202703 12:-0.326733 13:0.00719424 14:6.66134e-16 159 | 1.0704 1:-0.473684 2:-0.728814 3:-0.852851 4:0.626943 5:-0.522388 6:-0.669596 7:-0.817027 8:-0.84689 9:-0.855362 10:-0.776398 11:-0.635135 12:-0.782178 13:1 14:-0.607143 160 | 1.0477 1:-0.0526316 2:-0.694915 3:-0.519722 4:0.740933 5:-0.492537 6:-0.233743 7:-0.415502 8:-0.54386 9:-0.391521 10:-0.254658 11:-0.256757 12:-0.475248 13:0.0359712 14:-0.142857 161 | 1.0775 1:-0.604211 2:-0.694915 3:-0.732271 4:0.772021 5:-0.61194 6:-0.483304 7:-0.700127 8:-0.792663 9:-0.735661 10:-0.552795 11:-0.743243 12:-0.782178 13:-0.23741 14:-0.75 162 | 1.0653 1:-0.385263 2:-0.627119 3:-0.366442 4:0.803109 5:-0.263682 6:-0.13884 7:-0.33418 8:-0.358852 9:-0.291771 10:-0.0559006 11:-0.202703 12:-0.356436 13:0.179856 14:0.178571 163 | 1.069 1:-0.452632 2:-0.627119 3:-0.462497 4:0.626943 5:-0.0447761 6:-0.311072 7:-0.423126 8:-0.409888 9:-0.162095 10:-0.465839 11:-0.405405 12:-0.138614 13:0.381295 14:0.392857 164 | 1.0644 1:-0.364211 2:-0.59322 3:-0.824239 4:0.699482 5:-0.512438 6:-0.652021 7:-0.644219 8:-0.85327 9:-0.740648 10:-0.677019 11:-0.824324 12:-0.653465 13:-0.251799 14:-0.75 165 | 1.037 1:0.149474 2:-0.59322 3:-0.180462 4:0.761658 5:-0.164179 6:0.128295 7:-0.0698856 8:-0.240829 9:-0.17207 10:0.118012 11:-0.418919 12:-0.0891089 13:0.467626 14:-0.0357143 166 | 1.0549 1:-0.191579 2:-0.559322 3:-0.194768 4:0.834197 5:-0.0646766 6:-0.00878735 7:-0.346887 8:-0.37799 9:-0.122195 10:0.0310559 11:-0.121622 12:0.148515 13:0.827338 14:0.285714 167 | 1.0492 1:-0.0821053 2:-0.559322 3:-0.609646 4:0.595855 5:-0.263682 6:-0.304042 7:-0.466328 8:-0.661882 9:-0.586035 10:-0.850932 11:-0.621622 12:-0.465347 13:0.107914 14:-0.321429 168 | 1.0525 1:-0.145263 2:-0.559322 3:-0.131412 4:0.772021 5:0.273632 6:0.0158172 7:-0.212198 8:-0.304625 9:-0.197007 10:0.0807453 11:-0.256757 12:0.227723 13:0.741007 14:0.428571 169 | 1.018 1:0.444211 2:-0.559322 3:-0.1028 4:0.658031 5:-0.0746269 6:0.251318 7:0.181703 8:-0.141946 9:0.356608 10:-0.0559006 11:-0.337838 12:0.118812 13:0.553957 14:0.0714286 170 | 1.061 1:-0.305263 2:-0.559322 3:-0.556509 4:0.658031 5:-0.353234 6:-0.304042 7:-0.456163 8:-0.582137 9:-0.356608 10:-0.242236 11:-0.418919 12:-0.237624 13:0.266187 14:-0.428571 171 | 1.0926 1:-0.873684 2:-0.559322 3:-0.724096 4:0.585492 5:-0.412935 6:-0.546573 7:-0.682338 8:-0.751196 9:-0.625935 10:-0.602484 11:-0.594595 12:-0.445545 13:-0.0791367 14:-0.321429 172 | 1.0983 1:-0.970526 2:-0.559322 3:-0.940732 4:0.492228 5:-0.711443 6:-0.595782 7:-0.857687 8:-0.866029 9:-0.860349 10:-0.776398 11:-0.608108 12:-1 13:-0.294964 14:-0.607143 173 | 1.0521 1:-0.136842 2:-0.559322 3:-0.519722 4:0.720207 5:-0.273632 6:-0.254833 7:-0.468869 8:-0.562998 9:-0.471322 10:-0.465839 11:-0.554054 12:-0.386139 13:0.107914 14:-0.321429 174 | 1.0603 1:-0.288421 2:-0.525424 3:-0.527897 4:0.740933 5:-0.243781 6:-0.335677 7:-0.468869 8:-0.524721 9:-0.401496 10:-0.416149 11:-0.675676 12:-0.247525 13:0.0647482 14:-0.285714 175 | 1.0414 1:0.0652632 2:-0.525424 3:-0.115062 4:0.751295 5:0.0348259 6:0.265378 7:0.00127065 8:-0.062201 9:0.0972569 10:0.167702 11:-0.337838 12:0.049505 13:-1 14:0.535714 176 | 1.0763 1:-0.583158 2:-0.491525 3:-0.78132 4:0.647668 5:-0.512438 6:-0.384886 7:-0.74587 8:-0.866029 9:-0.845387 10:-0.776398 11:-0.581081 12:-0.386139 13:-0.151079 14:-0.607143 177 | 1.0689 1:-0.448421 2:-0.491525 3:-0.734314 4:0.554404 5:-0.58209 6:-0.532513 7:-0.649301 8:-0.636364 9:-0.361596 10:-0.36646 11:-0.608108 12:-0.336634 13:-0.194245 14:-0.678571 178 | 1.0316 1:0.258947 2:-0.491525 3:0.00347435 4:0.740933 5:0.0945274 6:0.40246 7:0.0393901 8:-0.0781499 9:0.127182 10:0.192547 11:-0.22973 12:-0.049505 13:0.223022 14:-0.0714286 179 | 1.0477 1:-0.0526316 2:-0.457627 3:-0.437973 4:0.647668 5:-0.313433 6:-0.177504 7:-0.407878 8:-0.460925 9:-0.127182 10:-0.192547 11:-0.243243 12:-0.00990099 13:0.338129 14:-0.178571 180 | 1.0603 1:-0.288421 2:-0.423729 3:-0.0496628 4:0.865285 5:0.164179 6:0.0615114 7:-0.108005 8:-0.205742 9:0.112219 10:0.254658 11:-0.0945946 12:0.415842 13:0.654676 14:0.464286 181 | 1.0387 1:0.12 2:-0.423729 3:-0.176374 4:0.854922 5:-0.114428 6:0.026362 7:-0.105464 8:-0.208931 9:0.042394 10:0.217391 11:-0.324324 12:0.0693069 13:0.151079 14:0.142857 182 | 1.1089 1:-1 2:-0.389831 3:-1 4:0.595855 5:-0.731343 6:-1 7:-1 8:-1 9:-1 10:-0.937888 11:-0.851351 12:-0.712871 13:-0.482014 14:-0.75 183 | 1.0725 1:-0.515789 2:-0.389831 3:-0.777233 4:0.564767 5:-0.562189 6:-0.43058 7:-0.639136 8:-0.789474 9:-0.65586 10:-0.602484 11:-0.635135 12:-0.346535 13:0.0503597 14:-0.5 184 | 1.0713 1:-0.490526 2:-0.389831 3:-0.666871 4:0.668394 5:-0.58209 6:-0.543058 7:-0.557814 8:-0.645933 9:-0.461347 10:-0.204969 11:-0.513514 12:-0.485149 13:-0.223022 14:-0.428571 185 | 1.0587 1:-0.263158 2:-0.389831 3:-0.574903 4:0.854922 5:-0.343284 6:-0.311072 7:-0.466328 8:-0.665072 9:-0.591022 10:-0.267081 11:-0.554054 12:-0.435644 13:0.136691 14:-0.321429 186 | 1.0794 1:-0.637895 2:-0.389831 3:-0.599428 4:0.740933 5:-0.174129 6:-0.641476 7:-0.636595 8:-0.582137 9:-0.496259 10:-0.167702 11:-0.527027 12:-0.19802 13:0.194245 14:-0.142857 187 | 1.0453 1:-0.00631579 2:-0.355932 3:-0.0660127 4:0.854922 5:0.0746269 6:0.342707 7:0.0139771 8:-0.240829 9:0.0224439 10:0.0310559 11:-0.243243 12:0.227723 13:0.553957 14:0.5 188 | 1.0524 1:-0.141053 2:-0.355932 3:-0.247905 4:0.761658 5:-0.263682 6:-0.0123023 7:-0.250318 8:-0.39075 9:-0.187032 10:-0.15528 11:-0.405405 12:0.148515 13:0.352518 14:0.178571 189 | 1.052 1:-0.136842 2:-0.355932 3:-0.315348 4:0.782383 5:-0.0348259 6:0.0509666 7:-0.273189 8:-0.464115 9:-0.221945 10:0.0310559 11:-0.22973 12:0.168317 13:0.640288 14:0.0714286 190 | 1.0434 1:0.0273684 2:-0.355932 3:-0.456366 4:0.606218 5:-0.313433 6:-0.1529 7:-0.191868 8:-0.422648 9:-0.286783 10:-0.0807453 11:-0.486486 12:-0.148515 13:0.179856 14:-0.0357143 191 | 1.0728 1:-0.52 2:-0.355932 3:-0.717964 4:0.647668 5:-0.472637 6:-0.574692 7:-0.715375 8:-0.767145 9:-0.645885 10:-0.590062 11:-0.635135 12:-0.524752 13:-0.0935252 14:-0.25 192 | 1.014 1:0.604211 2:-0.322034 3:0.0279992 4:0.927461 5:0.0646766 6:0.261863 7:0.125794 8:-0.125997 9:0.0623441 10:0.490683 11:-0.135135 12:0.217822 13:0.467626 14:0.464286 193 | 1.0624 1:-0.330526 2:-0.322034 3:-0.386879 4:0.699482 5:-0.0447761 6:-0.100176 7:-0.3723 8:-0.435407 9:-0.331671 10:-0.304348 11:-0.243243 12:-0.0891089 13:0.309353 14:0.0357143 194 | 1.0429 1:0.04 2:-0.322034 3:-0.131412 4:0.875648 5:-0.263682 6:-0.0369069 7:-0.0775095 8:-0.145136 9:-0.0972569 10:0.279503 11:-0.0675676 12:-0.118812 13:0.280576 14:-0.0357143 195 | 1.047 1:-0.04 2:-0.322034 3:-0.638259 4:0.792746 5:-0.572139 6:-0.546573 7:-0.58831 8:-0.633174 9:-0.351621 10:-0.267081 11:-0.554054 12:-0.316832 13:-0.122302 14:-0.535714 196 | 1.0411 1:0.0736842 2:-0.322034 3:-0.497241 4:0.606218 5:-0.263682 6:-0.216169 7:-0.308767 8:-0.502392 9:-0.306733 10:-0.329193 11:-0.324324 12:-0.19802 13:0.266187 14:0.0714286 197 | 1.0488 1:-0.0736842 2:-0.322034 3:-0.691396 4:0.637306 5:-0.562189 6:-0.349736 7:-0.578145 8:-0.642743 9:-0.476309 10:-0.304348 11:-0.337838 12:-0.366337 13:-0.0935252 14:-0.428571 198 | 1.0583 1:-0.254737 2:-0.322034 3:-0.59534 4:0.740933 5:-0.462687 6:-0.553603 7:-0.484117 8:-0.489633 9:-0.246883 10:-0.378882 11:-0.567568 12:-0.405941 13:-0.0215827 14:-0.607143 199 | 1.0841 1:-0.722105 2:-0.322034 3:-0.601471 4:0.792746 5:-0.353234 6:-0.483304 7:-0.781449 8:-0.553429 9:-0.486284 10:-0.130435 11:-0.540541 12:-0.425743 13:0.294964 14:-0.0357143 200 | 1.0462 1:-0.00631579 2:-0.288136 3:-0.572859 4:0.57513 5:-0.373134 6:-0.142355 7:-0.484117 8:-0.706539 9:-0.436409 10:-0.254658 11:-0.324324 12:-0.108911 13:0.122302 14:0.0714286 201 | 1.0709 1:-0.486316 2:-0.288136 3:-0.511547 4:0.689119 5:-0.333333 6:-0.177504 7:-0.496823 8:-0.547049 9:-0.351621 10:-0.229814 11:-0.364865 12:-0.316832 13:0.0647482 14:6.66134e-16 202 | 1.0484 1:-0.0694737 2:-0.288136 3:-0.742489 4:0.647668 5:-0.59204 6:-0.585237 7:-0.585769 8:-0.620415 9:-0.586035 10:-0.664596 11:-0.608108 12:-0.544554 13:-0.194245 14:-0.428571 203 | 1.034 1:0.208421 2:-0.288136 3:-0.329655 4:0.740933 5:-0.323383 6:-0.0193322 7:-0.143583 8:-0.346093 9:0.0773067 10:-0.341615 11:-0.378378 12:-0.277228 13:0.136691 14:0.0357143 204 | 1.0854 1:-0.747368 2:-0.254237 3:-0.464541 4:0.84456 5:-0.323383 6:-0.244288 7:-0.499365 8:-0.438596 9:-0.331671 10:-0.254658 11:-0.337838 12:-0.19802 13:0.179856 14:-0.0714286 205 | 1.0209 1:0.465263 2:-0.254237 3:-0.145718 4:0.668394 5:-0.0248756 6:0.486819 7:0.130877 8:-0.295056 9:-0.187032 10:-0.0931677 11:-0.635135 12:-0.00990099 13:0.395683 14:-0.428571 206 | 1.061 1:-0.301053 2:-0.254237 3:-0.262211 4:0.803109 5:0.0746269 6:-0.0755712 7:-0.316391 8:-0.457735 9:-0.197007 10:-0.15528 11:-0.324324 12:0.237624 13:-0.697842 14:0.285714 207 | 1.025 1:0.385263 2:-0.254237 3:-0.61169 4:0.492228 5:-0.20398 6:-0.251318 7:-0.377382 8:-0.518341 9:-0.416459 10:-0.428571 11:-0.689189 12:-0.178218 13:0.223022 14:-0.464286 208 | 1.0254 1:0.381053 2:-0.152542 3:-0.374617 4:0.782383 5:-0.0945274 6:-0.177504 7:-0.189327 8:-0.467305 9:-0.326683 10:-0.204969 11:-0.432432 12:0.178218 13:0.52518 14:-0.0714286 209 | 1.0771 1:-0.595789 2:-0.152542 3:-0.656652 4:0.689119 5:-0.512438 6:-0.279438 7:-0.631512 8:-0.783094 9:-0.710723 10:-0.602484 11:-0.540541 12:-0.346535 13:-0.0647482 14:-0.321429 210 | 1.0742 1:-0.545263 2:-0.152542 3:-0.662784 4:0.709845 5:-0.661692 6:-0.521968 7:-0.618806 8:-0.712919 9:-0.561097 10:-0.354037 11:-0.527027 12:-0.584158 13:-0.251799 14:-0.357143 211 | 1.0829 1:-0.701053 2:-0.0847458 3:-0.820151 4:0.595855 5:-0.532338 6:-0.581722 7:-0.74587 8:-0.872408 9:-0.805486 10:-0.751553 11:-0.648649 12:-0.39604 13:0.122302 14:-0.428571 212 | 1.0373 1:0.145263 2:-0.0847458 3:-0.200899 4:0.865285 5:-0.0945274 6:0.275923 7:-0.120712 8:-0.23445 9:-0.177057 10:-0.0931677 11:-0.445946 12:0.188119 13:0.438849 14:0.107143 213 | 1.0543 1:-0.178947 2:-0.0847458 3:-0.593297 4:0.751295 5:-0.283582 6:-0.332162 7:-0.484117 8:-0.550239 9:-0.546135 10:-0.279503 11:-0.472973 12:-0.534653 13:-0.00719424 14:6.66134e-16 214 | 1.0561 1:-0.212632 2:-0.0508475 3:-0.376661 4:0.709845 5:-0.21393 6:-0.142355 7:-0.283355 8:-0.38756 9:-0.361596 10:-0.0186335 11:-0.135135 12:-0.217822 13:0.294964 14:0.142857 215 | 1.0543 1:-0.178947 2:-0.0508475 3:-0.556509 4:0.803109 5:-0.373134 6:-0.318102 7:-0.537484 8:-0.645933 9:-0.506234 10:-0.36646 11:-0.635135 12:-0.623762 13:-0.179856 14:-0.214286 216 | 0.995 1:1 2:-0.0169492 3:-0.178418 4:0.430052 5:0.00497512 6:0.42355 7:0.339263 8:-0.113238 9:-0.236908 10:-0.515528 11:-0.391892 12:-0.019802 13:0.165468 14:-0.0714286 217 | 1.0678 1:-0.427368 2:-0.0169492 3:-0.74862 4:0.668394 5:-0.631841 6:-0.525483 7:-0.702668 8:-0.639553 9:-0.670823 10:-0.565217 11:-0.675676 12:-0.356436 13:-0.23741 14:-0.285714 218 | 1.0819 1:-0.684211 2:-0.0169492 3:-0.705702 4:0.678756 5:-0.422886 6:-0.507909 7:-0.692503 8:-0.700159 9:-0.625935 10:-0.254658 11:-0.527027 12:-0.732673 13:-0.294964 14:6.66134e-16 219 | 1.0433 1:0.0315789 2:0.0169492 3:-0.339873 4:0.751295 5:-0.174129 6:-0.0333919 7:-0.222363 8:-0.362041 9:-0.167082 10:-0.229814 11:-0.486486 12:0.0792079 13:0.352518 14:0.214286 220 | 1.0646 1:-0.368421 2:0.0508475 3:-0.705702 4:0.647668 5:-0.353234 6:-0.486819 7:-0.50953 8:-0.69697 9:-0.67581 10:-0.602484 11:-0.608108 12:-0.633663 13:-0.323741 14:-0.535714 221 | 1.0706 1:-0.477895 2:0.0847458 3:-0.715921 4:0.699482 5:-0.263682 6:-0.307557 7:-0.43075 8:-0.642743 9:-0.476309 10:-0.36646 11:-0.351351 12:-0.346535 13:0.280576 14:0.107143 222 | 1.0399 1:0.0947368 2:0.0847458 3:-0.0884938 4:0.772021 5:0.134328 6:0.427065 7:0.0419314 8:-0.346093 9:-0.15212 10:0.204969 11:0.0675676 12:0.346535 13:0.582734 14:0.357143 223 | 1.0726 1:-0.515789 2:0.0847458 3:-0.646434 4:0.57513 5:-0.373134 6:-0.476274 7:-0.537484 8:-0.661882 9:-0.376559 10:-0.10559 11:-0.418919 12:-0.693069 13:-0.136691 14:-0.285714 224 | 1.0874 1:-0.781053 2:0.118644 3:-0.805845 4:0.564767 5:-0.59204 6:-0.528998 7:-0.659466 8:-0.779904 9:-0.640898 10:-0.726708 11:-0.540541 12:-0.544554 13:-0.165468 14:-0.571429 225 | 1.074 1:-0.541053 2:0.118644 3:-0.499285 4:0.626943 5:-0.00497512 6:-0.029877 7:-0.341804 8:-0.578947 9:-0.491272 10:-0.490683 11:-0.635135 12:-0.0792079 13:0.453237 14:0.214286 226 | 1.0703 1:-0.473684 2:0.118644 3:-0.9346 4:0.544041 5:-0.771144 6:-0.666081 7:-0.776366 8:-0.920255 9:-0.820449 10:-1 11:-0.918919 12:-0.950495 13:-0.856115 14:-1 227 | 1.065 1:-0.376842 2:0.118644 3:-0.583078 4:0.606218 5:-0.393035 6:-0.212654 7:-0.448539 8:-0.614035 9:-0.531172 10:-0.31677 11:-0.527027 12:-0.148515 13:0.194245 14:0.0714286 228 | 1.0418 1:0.0610526 2:0.118644 3:-0.346004 4:0.854922 5:-0.283582 6:-0.086116 7:-0.306226 8:-0.311005 9:-0.162095 10:0.192547 11:-0.418919 12:-0.168317 13:0.294964 14:-0.0714286 229 | 1.0647 1:-0.372632 2:0.152542 3:-0.542203 4:0.658031 5:-0.303483 6:-0.13181 7:-0.491741 8:-0.572568 9:-0.441397 10:-0.453416 11:-0.540541 12:-0.029703 13:0.309353 14:0.0714286 230 | 1.0601 1:-0.284211 2:0.152542 3:-0.597384 4:0.61658 5:-0.373134 6:-0.321617 7:-0.400254 8:-0.617225 9:-0.591022 10:-0.279503 11:-0.445946 12:-0.247525 13:0.251799 14:0.142857 231 | 1.0745 1:-0.553684 2:0.186441 3:-0.760883 4:0.502591 5:-0.59204 6:-0.286467 7:-0.56798 8:-0.837321 9:-0.710723 10:-0.751553 11:-0.702703 12:-0.316832 13:-0.0935252 14:-0.607143 232 | 1.062 1:-0.322105 2:0.186441 3:-0.478847 4:0.751295 5:-0.174129 6:-0.1529 7:-0.306226 8:-0.499203 9:-0.396509 10:-0.304348 11:-0.5 12:-0.306931 13:0.165468 14:0.142857 233 | 1.0636 1:-0.351579 2:0.220339 3:-0.534028 4:0.740933 5:-0.313433 6:-0.265378 7:-0.524778 8:-0.591707 9:-0.506234 10:-0.267081 11:-0.391892 12:-0.39604 13:0.23741 14:-0.214286 234 | 1.0384 1:0.124211 2:0.220339 3:-0.646434 4:0.564767 5:-0.60199 6:-0.45167 7:-0.35197 8:-0.515152 9:-0.521197 10:-0.639752 11:-0.743243 12:-0.70297 13:-0.266187 14:-0.357143 235 | 1.0403 1:0.0863158 2:0.288136 3:-0.679133 4:0.57513 5:-0.0746269 6:-0.370826 7:-0.39263 8:-0.712919 9:-0.645885 10:-0.664596 11:-0.743243 12:-0.356436 13:0.107914 14:-0.107143 236 | 1.0563 1:-0.216842 2:0.355932 3:-0.589209 4:0.57513 5:-0.283582 6:-0.107206 7:-0.33418 8:-0.722488 9:-0.640898 10:-0.490683 11:-0.513514 12:-0.455446 13:-0.23741 14:-0.107143 237 | 1.0424 1:0.0442105 2:0.355932 3:-0.403229 4:0.772021 5:-0.0547264 6:-0.13181 7:-0.268107 8:-0.486443 9:-0.396509 10:-0.0931677 11:-0.472973 12:-0.227723 13:0.0791367 14:0.142857 238 | 1.0372 1:0.149474 2:0.389831 3:-0.177192 4:0.658031 5:-0.0945274 6:0.346221 7:0.128335 8:-0.145136 9:-0.19202 10:0.00621118 11:-0.567568 12:0.019802 13:0.23741 14:-0.0357143 239 | 1.0705 1:-0.477895 2:0.423729 3:-0.699571 4:0.658031 5:-0.323383 6:-0.420035 7:-0.659466 8:-0.69697 9:-0.301746 10:-0.242236 11:-0.567568 12:-0.50495 13:0.136691 14:-0.107143 240 | 1.0316 1:0.258947 2:0.457627 3:-0.417535 4:0.502591 5:-0.0348259 6:-0.0474517 7:-0.209657 8:-0.505582 9:-0.401496 10:-0.36646 11:-0.337838 12:0.0990099 13:0.366906 14:0.178571 241 | 1.0599 1:-0.284211 2:0.457627 3:-0.926426 4:0.502591 5:-0.641791 6:-0.518453 7:-0.738247 8:-0.917065 9:-0.825436 10:-0.950311 11:-0.864865 12:-0.633663 13:-0.453237 14:-0.75 242 | 1.0207 1:0.473684 2:0.457627 3:-0.133456 4:0.606218 5:-0.233831 6:0.41652 7:0.23507 8:-0.0653907 9:-0.296758 10:0.130435 11:-0.418919 12:-2.22045e-16 13:0.309353 14:0.285714 243 | 1.0304 1:0.28 2:0.491525 3:-0.0537503 4:0.761658 5:0.0248756 6:0.420035 7:0.00635324 8:-0.23126 9:-0.177057 10:0.167702 11:-0.256757 12:0.0693069 13:0.395683 14:0.321429 244 | 1.0256 1:0.372632 2:0.525424 3:-0.106887 4:0.792746 5:0.0149254 6:0.282953 7:0.11817 8:-0.208931 9:-0.0822943 10:0.614907 11:-0.148649 12:0.039604 13:0.266187 14:0.321429 245 | 1.0334 1:0.221053 2:0.525424 3:-0.33783 4:0.61658 5:-0.0447761 6:0.370826 7:-0.0673443 8:-0.470494 9:-0.451372 10:-0.279503 11:-0.324324 12:-0.277228 13:0.194245 14:-0.0357143 246 | 1.0641 1:-0.36 2:0.559322 3:-0.697527 4:0.647668 5:-0.482587 6:-0.363796 7:-0.621347 8:-0.700159 9:-0.645885 10:-0.440994 11:-0.527027 12:-0.564356 13:-0.0935252 14:-0.0357143 247 | 1.0308 1:0.271579 2:0.59322 3:-0.20703 4:0.699482 5:-0.0348259 6:0.209139 7:-0.0292249 8:-0.202552 9:-0.197007 10:0.36646 11:-0.527027 12:0.257426 13:0.669065 14:0.0714286 248 | 1.0736 1:-0.536842 2:0.627119 3:-0.871245 4:0.554404 5:-0.621891 6:-0.652021 7:-0.639136 8:-0.878788 9:-0.880299 10:-0.776398 11:-0.675676 12:-0.920792 13:-0.323741 14:-0.0357143 249 | 1.0236 1:0.414737 2:0.694915 3:-0.325567 4:0.668394 5:-0.0248756 6:0.026362 7:-0.0952986 8:-0.37799 9:-0.381546 10:-0.0310559 11:-0.445946 12:0.029703 13:0.0935252 14:0.535714 250 | 1.0328 1:0.233684 2:0.694915 3:-0.44206 4:0.512953 5:-0.223881 6:0.11775 7:0.0698856 8:-0.467305 9:-0.346633 10:-0.465839 11:-0.675676 12:-0.356436 13:-0.107914 14:-0.214286 251 | 1.0399 1:0.0947368 2:0.694915 3:-0.40936 4:0.699482 5:-0.223881 6:0.0193322 7:-0.189327 8:-0.591707 9:-0.561097 10:0.068323 11:-0.513514 12:-0.435644 13:0.208633 14:0.428571 252 | 1.0271 1:0.343158 2:0.762712 3:-0.27243 4:0.678756 5:-0.0348259 6:0.163445 7:-0.00635324 8:-0.295056 9:-0.396509 10:0.142857 11:-0.256757 12:-0.118812 13:0.294964 14:0.821429 -------------------------------------------------------------------------------- /examples/oneClass.js: -------------------------------------------------------------------------------- 1 | import { loadSVM } from '../wasm.js'; 2 | const SVM = await loadSVM(); 3 | 4 | let svm = new SVM({ 5 | kernel: SVM.KERNEL_TYPES.RBF, 6 | type: SVM.SVM_TYPES.ONE_CLASS, 7 | gamma: 1, 8 | cost: 1, 9 | nu: 0.1, 10 | }); 11 | const features = [ 12 | [0, 0], 13 | [1, 1], 14 | [1, 0], 15 | [0, 1], 16 | ]; 17 | const toPredict = [ 18 | [0.5, 0.5], 19 | [1.5, 1], 20 | ]; 21 | const expected = [1, -1]; 22 | const labels = [0, 0, 0, 0]; 23 | svm.train(features, labels); 24 | for (let i = 0; i < toPredict.length; i++) { 25 | const pred = svm.predictOne(toPredict[i]); 26 | console.log(`pred: ${pred}, expected: ${expected[i]}`); 27 | } 28 | -------------------------------------------------------------------------------- /examples/precomputed.js: -------------------------------------------------------------------------------- 1 | import Kernel from 'ml-kernel'; 2 | import range from 'lodash.range'; 3 | import { loadSVM } from '../wasm.js'; 4 | import data from 'ml-dataset-iris'; 5 | 6 | const SVM = await loadSVM(); 7 | 8 | const gamma = 0.2; 9 | const cost = 1; 10 | 11 | function exec(time, precomputed) { 12 | const MILISECONDS = time * 1000; 13 | var trainData; 14 | 15 | const features = data.getNumbers(); 16 | let labels = data.getClasses(); 17 | const classes = data.getDistinctClasses(); 18 | const c = {}; 19 | classes.forEach((v, idx) => (c[v] = idx)); 20 | labels = labels.map((l) => c[l]); 21 | 22 | let result; 23 | const t1 = performance.now(); 24 | let t2 = performance.now(); 25 | let count = 0; 26 | while (t2 - t1 < MILISECONDS) { 27 | if (precomputed) { 28 | const kernel = new Kernel('gaussian', { sigma: 1 / Math.sqrt(gamma) }); 29 | trainData = kernel 30 | .compute(features) 31 | .addColumn(0, range(1, labels.length + 1)); 32 | } else { 33 | trainData = features; 34 | } 35 | 36 | const svm = new SVM({ 37 | quiet: true, 38 | cost: cost, 39 | kernel: precomputed ? SVM.KERNEL_TYPES.PRECOMPUTED : SVM.KERNEL_TYPES.RBF, 40 | gamma, 41 | }); 42 | result = svm.crossValidation(trainData, labels, labels.length); 43 | svm.free(); 44 | count++; 45 | t2 = performance.now(); 46 | } 47 | 48 | console.log( 49 | 'accuracy: ', 50 | result.reduce( 51 | (prev, current, idx) => (current === labels[idx] ? prev + 1 : prev), 52 | 0, 53 | ) / labels.length, 54 | ); 55 | return count; 56 | } 57 | 58 | let count; 59 | count = exec(5, false); 60 | console.log('not precomputed count', count); 61 | count = exec(5, true); 62 | console.log('precomputed count', count); 63 | -------------------------------------------------------------------------------- /examples/probabilities.js: -------------------------------------------------------------------------------- 1 | import Kernel from 'ml-kernel'; 2 | import range from 'lodash.range'; 3 | import data from 'ml-dataset-iris'; 4 | import { loadSVM } from '../wasm.js'; 5 | 6 | const SVM = await loadSVM(); 7 | 8 | const gamma = 0.2; 9 | const cost = 1; 10 | 11 | async function exec(precomputed) { 12 | var trainData; 13 | 14 | const features = data.getNumbers(); 15 | let labels = data.getClasses(); 16 | const classes = data.getDistinctClasses(); 17 | const c = {}; 18 | classes.forEach((v, idx) => (c[v] = idx)); 19 | labels = labels.map((l) => c[l]); 20 | 21 | if (precomputed) { 22 | const kernel = new Kernel('gaussian', { sigma: 1 / Math.sqrt(gamma) }); 23 | trainData = kernel 24 | .compute(features) 25 | .addColumn(0, range(1, labels.length + 1)); 26 | } else { 27 | trainData = features; 28 | } 29 | 30 | const svm = new SVM({ 31 | quiet: true, 32 | cost: cost, 33 | kernel: precomputed ? SVM.KERNEL_TYPES.PRECOMPUTED : SVM.KERNEL_TYPES.RBF, 34 | gamma, 35 | probabilityEstimates: true, 36 | }); 37 | svm.train(trainData, labels); 38 | var pred = svm.predictProbability(trainData); 39 | console.log(JSON.stringify(pred, null, 2)); 40 | } 41 | 42 | await exec(true); 43 | -------------------------------------------------------------------------------- /examples/svr.js: -------------------------------------------------------------------------------- 1 | import { loadSVM } from '../wasm.js'; 2 | 3 | const SVM = await loadSVM(); 4 | const svm = new SVM({ 5 | type: SVM.SVM_TYPES.EPSILON_SVR, 6 | }); 7 | const l = 20; 8 | const data = Array.from({ length: l }).map((val, idx) => { 9 | const x = (idx / l) * 2 * Math.PI; 10 | const y = Math.sin(x) + 1; 11 | return [[x], y]; 12 | }); 13 | 14 | const x = data.map((d) => d[0]); 15 | const y = data.map((d) => d[1]); 16 | 17 | svm.train(x, y); 18 | const pred = svm.predict(x); 19 | 20 | y.forEach((v, idx) => console.log(v, pred[idx])); 21 | -------------------------------------------------------------------------------- /examples/xor.js: -------------------------------------------------------------------------------- 1 | import { loadSVM } from '../wasm.js'; 2 | 3 | const SVM = await loadSVM(); 4 | 5 | let svm = new SVM({ 6 | kernel: SVM.KERNEL_TYPES.RBF, 7 | type: SVM.SVM_TYPES.C_SVC, 8 | gamma: 1, 9 | cost: 1, 10 | }); 11 | const features = [ 12 | [0, 0], 13 | [1, 1], 14 | [1, 0], 15 | [0, 1], 16 | ]; 17 | const labels = [0, 0, 1, 1]; 18 | svm.train(features, labels); 19 | for (let i = 0; i < features.length; i++) { 20 | const pred = svm.predictOne(features[i]); 21 | console.log(`actual: ${labels[i]}, predicted: ${pred}`); 22 | } 23 | 24 | console.log('sv indices', svm.getSVIndices()); 25 | console.log('labels', svm.getLabels()); 26 | console.log('save model', svm.serializeModel()); 27 | -------------------------------------------------------------------------------- /js-interfaces.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "js-interfaces.h" 7 | #include "libsvm/svm.h" 8 | #define Malloc(type, n) (type *)malloc((n) * sizeof(type)) 9 | 10 | void print_null(const char *s) {} 11 | 12 | void exit_with_help() { exit(1); } 13 | 14 | #ifdef __cplusplus 15 | extern "C" { 16 | #endif 17 | 18 | void parse_command_line(const char *input_command, struct svm_parameter *param) 19 | { 20 | void (*print_func)(const char *) = NULL; // default printing to stdout 21 | char command[256]; 22 | char *curr = NULL; 23 | char *prev = NULL; 24 | 25 | strcpy(command, input_command); 26 | curr = strtok(command, " \t\n"); // label 27 | 28 | // default values 29 | param->svm_type = C_SVC; 30 | param->kernel_type = RBF; 31 | param->degree = 3; 32 | param->gamma = 0; // 1/num_features 33 | param->coef0 = 0; 34 | param->nu = 0.5; 35 | param->cache_size = 100; 36 | param->C = 1; 37 | param->eps = 1e-3; 38 | param->p = 0.1; 39 | param->shrinking = 1; 40 | param->probability = 0; 41 | param->nr_weight = 0; 42 | param->weight_label = NULL; 43 | param->weight = NULL; 44 | 45 | if (curr == NULL) 46 | return; 47 | 48 | do 49 | { 50 | if (curr[0] != '-') 51 | break; 52 | 53 | prev = curr; 54 | if ((curr = strtok(NULL, " \t\n")) == NULL) 55 | exit_with_help(); 56 | 57 | switch (prev[1]) 58 | { 59 | case 's': 60 | param->svm_type = atoi(curr); 61 | break; 62 | case 't': 63 | param->kernel_type = atoi(curr); 64 | break; 65 | case 'd': 66 | param->degree = atoi(curr); 67 | break; 68 | case 'g': 69 | param->gamma = atof(curr); 70 | break; 71 | case 'r': 72 | param->coef0 = atof(curr); 73 | break; 74 | case 'n': 75 | param->nu = atof(curr); 76 | break; 77 | case 'm': 78 | param->cache_size = atof(curr); 79 | break; 80 | case 'c': 81 | param->C = atof(curr); 82 | break; 83 | case 'e': 84 | param->eps = atof(curr); 85 | break; 86 | case 'q': 87 | print_func = &print_null; 88 | break; 89 | case 'p': 90 | param->p = atof(curr); 91 | break; 92 | case 'h': 93 | param->shrinking = atoi(curr); 94 | break; 95 | case 'b': 96 | param->probability = atoi(curr); 97 | break; 98 | case 'w': 99 | ++param->nr_weight; 100 | param->weight_label = (int *)realloc(param->weight_label, sizeof(int) * param->nr_weight); 101 | param->weight = (double *)realloc(param->weight, sizeof(double) * param->nr_weight); 102 | param->weight_label[param->nr_weight - 1] = atoi(&prev[2]); 103 | param->weight[param->nr_weight - 1] = atof(curr); 104 | break; 105 | default: 106 | fprintf(stderr, "Unknown option: -%c\n", prev[1]); 107 | exit_with_help(); 108 | } 109 | } while ((curr = strtok(NULL, " \t\n")) != NULL); 110 | 111 | svm_set_print_string_function(print_func); 112 | } 113 | 114 | void add_instance(struct svm_problem *prob, double *features, int nb_dimensions, double y, int i) 115 | { 116 | for (int j = 0; j < nb_dimensions; j++) 117 | { 118 | prob->x[i][j].index = j + 1; 119 | prob->x[i][j].value = features[j]; 120 | } 121 | prob->x[i][nb_dimensions].index = -1; 122 | prob->y[i] = y; 123 | } 124 | 125 | char *serialize_model(struct svm_model *model) 126 | { 127 | int success = svm_save_model("testfile.txt", model); 128 | if (success < 0) 129 | return NULL; 130 | FILE *f = fopen("testfile.txt", "rb"); 131 | fseek(f, 0, SEEK_END); 132 | long fsize = ftell(f); 133 | fseek(f, 0, SEEK_SET); //same as rewind(f); 134 | 135 | char *string = Malloc(char, fsize + 1); 136 | fread(string, fsize, 1, f); 137 | fclose(f); 138 | 139 | string[fsize] = 0; 140 | return string; 141 | } 142 | 143 | struct svm_model *deserialize_model(const char *serialized) 144 | { 145 | FILE *f = fopen("testfile.txt", "w"); 146 | fprintf(f, "%s", serialized); 147 | fclose(f); 148 | return svm_load_model("testfile.txt"); 149 | } 150 | 151 | struct svm_problem *create_svm_nodes(int nb_features, int nb_dimensions) 152 | { 153 | struct svm_problem *prob = Malloc(struct svm_problem, 1); 154 | prob->l = nb_features; 155 | prob->y = Malloc(double, prob->l); 156 | prob->x = Malloc(struct svm_node *, prob->l); 157 | struct svm_node *x_space = Malloc(struct svm_node, prob->l * (nb_dimensions + 1)); 158 | 159 | for (int i = 0; i < prob->l; ++i) 160 | prob->x[i] = x_space + i * (nb_dimensions + 1); 161 | 162 | return prob; 163 | } 164 | 165 | void svm_free_model(struct svm_model *model) 166 | { 167 | svm_free_and_destroy_model(&model); 168 | } 169 | 170 | struct svm_model *libsvm_train_problem(struct svm_problem *prob, const char *command) 171 | { 172 | struct svm_parameter param; 173 | parse_command_line(command, ¶m); 174 | 175 | if (param.svm_type == EPSILON_SVR || param.svm_type == NU_SVR) 176 | { 177 | if (param.gamma == 0) 178 | param.gamma = .1; 179 | } 180 | else 181 | { 182 | if (param.gamma == 0) 183 | param.gamma = .5; 184 | } 185 | 186 | struct svm_model *model = svm_train(prob, ¶m); 187 | 188 | svm_destroy_param(¶m); 189 | return model; 190 | } 191 | 192 | void libsvm_cross_validation(struct svm_problem *prob, const char *command, int kFold, double *target) 193 | { 194 | struct svm_parameter param; 195 | parse_command_line(command, ¶m); 196 | svm_cross_validation(prob, ¶m, kFold, target); 197 | svm_destroy_param(¶m); 198 | } 199 | 200 | void free_problem(struct svm_problem *prob) 201 | { 202 | free(prob->y); 203 | if (prob->l > 0) 204 | { 205 | free(prob->x[0]); 206 | } 207 | free(prob->x); 208 | free(prob); 209 | } 210 | 211 | struct svm_node *init_node(double *data, int size) 212 | { 213 | struct svm_node *node = Malloc(struct svm_node, size + 1); 214 | for (int i = 0; i < size; i++) 215 | { 216 | node[i].index = i + 1; 217 | node[i].value = data[i]; 218 | } 219 | node[size].index = -1; 220 | return node; 221 | } 222 | 223 | double libsvm_predict_one(struct svm_model *model, double *data, int size) 224 | { 225 | struct svm_node *node = init_node(data, size); 226 | double pred = svm_predict(model, node); 227 | free(node); 228 | return pred; 229 | } 230 | 231 | double libsvm_predict_one_probability(struct svm_model *model, double *data, int size, double *prob_estimates) 232 | { 233 | struct svm_node *node = init_node(data, size); 234 | double pred = svm_predict_probability(model, node, prob_estimates); 235 | return pred; 236 | } 237 | 238 | struct svm_model *libsvm_train(double *data, double *labels, int nb_features, int nb_dimensions, const char *command) 239 | { 240 | struct svm_problem *prob = create_svm_nodes(nb_features, nb_dimensions); 241 | for (int i = 0; i < nb_features; i++) 242 | { 243 | for (int j = 0; j < nb_dimensions; j++) 244 | { 245 | prob->x[i][j].index = j + 1; 246 | prob->x[i][j].value = data[i * nb_dimensions + j]; 247 | } 248 | prob->x[i][nb_dimensions].index = -1; 249 | prob->y[i] = labels[i]; 250 | } 251 | 252 | return libsvm_train_problem(prob, command); 253 | } 254 | 255 | double get_svr_epsilon(struct svm_model *model) 256 | { 257 | return model->param.p; 258 | } 259 | 260 | #ifdef __cplusplus 261 | } 262 | #endif 263 | -------------------------------------------------------------------------------- /js-interfaces.h: -------------------------------------------------------------------------------- 1 | #ifndef JS_INTERFACES 2 | #define JS_INTERFACES 3 | 4 | #include "libsvm/svm.h" 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | void print_null(const char *s); 11 | void exit_with_help(); 12 | void parse_command_line(const char* input_command, struct svm_parameter* param); 13 | void add_instance(struct svm_problem* prob, double* features, int nb_dimensions, double y, int i); 14 | char* serialize_model(struct svm_model* model); 15 | struct svm_model* deserialize_model(const char* serialized); 16 | struct svm_problem* create_svm_nodes(int nb_features, int nb_dimensions); 17 | void svm_free_model(struct svm_model *model); 18 | struct svm_model* libsvm_train_problem(struct svm_problem* prob, const char* command); 19 | double libsvm_predict_one(struct svm_model* model, double* data, int size); 20 | struct svm_model* libsvm_train(double *data, double *labels, int nb_features, int nb_dimensions, const char* command); 21 | double get_svr_epsilon(struct svm_model* model); 22 | void free_problem(struct svm_problem* prob); 23 | void libsvm_cross_validation(struct svm_problem* problem, const char* command, int kFold, double* target); 24 | 25 | #ifdef __cplusplus 26 | } 27 | #endif 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "libsvm-js", 3 | "version": "0.2.1", 4 | "description": "A port of libsvm to javascript using emscripten", 5 | "type": "module", 6 | "module": "wasm.js", 7 | "files": [ 8 | "src", 9 | "build", 10 | "wasm.js", 11 | "LICENSE" 12 | ], 13 | "scripts": { 14 | "benchmark": "node benchmark/bin", 15 | "build": "run-s build-emscripten-wasm build-emscripten-clean", 16 | "build-benchmark": "(cd benchmark/iris; make clean && make)", 17 | "build-emscripten-clean": "make clean", 18 | "build-emscripten-wasm": "rm -rf build && make wasm", 19 | "demo-build": "vite build demos", 20 | "docs": "jsdoc2md src/loadSVM.js -t .docs/Readme.hbs --no-cache > README.md", 21 | "prepare": "git submodule init && git submodule update", 22 | "dev": "vite demos", 23 | "test": "npm run test-mocha", 24 | "test-mocha": "mocha --require should --recursive test" 25 | }, 26 | "repository": { 27 | "type": "git", 28 | "url": "git+https://github.com/mljs/libsvm.git" 29 | }, 30 | "keywords": [ 31 | "svm", 32 | "libsvm", 33 | "machine", 34 | "learning", 35 | "support", 36 | "vector", 37 | "machines" 38 | ], 39 | "author": "Daniel Kostro ", 40 | "license": "BSD-3-Clause", 41 | "bugs": { 42 | "url": "https://github.com/mljs/libsvm/issues" 43 | }, 44 | "homepage": "https://github.com/mljs/libsvm#readme", 45 | "devDependencies": { 46 | "@types/react": "^18.3.23", 47 | "@types/react-dom": "^18.3.7", 48 | "@vitejs/plugin-react-refresh": "^1.3.6", 49 | "bootstrap": "^5.3.7", 50 | "chroma-js": "^3.1.2", 51 | "cli-table": "^0.3.1", 52 | "jsdoc-to-markdown": "^9.1.1", 53 | "lodash-es": "^4.17.4", 54 | "lodash.range": "^3.2.0", 55 | "ml-dataset-iris": "^1.0.0", 56 | "ml-kernel": "^3.0.0", 57 | "ml-svm": "^2.1.2", 58 | "mocha": "^11.7.1", 59 | "npm-run-all": "^4.1.2", 60 | "react": "^18.3.1", 61 | "react-dom": "^18.3.1", 62 | "react-icons": "^5.5.0", 63 | "react-hook-form": "^7.29.0", 64 | "react-redux": "^9.2.0", 65 | "react-router": "^7.6.3", 66 | "react-router-dom": "^7.6.3", 67 | "redux": "^5.0.1", 68 | "redux-undo": "^1.0.0", 69 | "should": "^13.2.3", 70 | "vite": "^7.0.4" 71 | }, 72 | "volta": { 73 | "node": "24.4.0" 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/loadSVM.js: -------------------------------------------------------------------------------- 1 | import { getCommand } from './util.js'; 2 | 3 | export default function loadSVM(libsvm) { 4 | /* eslint-disable camelcase */ 5 | const predict_one = libsvm.cwrap('libsvm_predict_one', 'number', [ 6 | 'number', 7 | 'array', 8 | 'number', 9 | ]); 10 | const predict_one_probability = libsvm.cwrap( 11 | 'libsvm_predict_one_probability', 12 | 'number', 13 | ['number', 'array', 'number', 'number'], 14 | ); 15 | const add_instance = libsvm.cwrap('add_instance', null, [ 16 | 'number', 17 | 'array', 18 | 'number', 19 | 'number', 20 | 'number', 21 | ]); 22 | const create_svm_nodes = libsvm.cwrap('create_svm_nodes', 'number', [ 23 | 'number', 24 | 'number', 25 | ]); 26 | const train_problem = libsvm.cwrap('libsvm_train_problem', 'number', [ 27 | 'number', 28 | 'string', 29 | ]); 30 | const svm_get_nr_sv = libsvm.cwrap('svm_get_nr_sv', 'number', ['number']); 31 | const svm_get_nr_class = libsvm.cwrap('svm_get_nr_class', 'number', [ 32 | 'number', 33 | ]); 34 | const svm_get_sv_indices = libsvm.cwrap('svm_get_sv_indices', null, [ 35 | 'number', 36 | 'number', 37 | ]); 38 | const svm_get_labels = libsvm.cwrap('svm_get_labels', null, [ 39 | 'number', 40 | 'number', 41 | ]); 42 | const svm_free_model = libsvm.cwrap('svm_free_model', null, ['number']); 43 | const svm_cross_validation = libsvm.cwrap('libsvm_cross_validation', null, [ 44 | 'number', 45 | 'string', 46 | 'number', 47 | 'number', 48 | ]); 49 | const svm_get_svr_probability = libsvm.cwrap( 50 | 'svm_get_svr_probability', 51 | null, 52 | ['number'], 53 | ); 54 | const free_problem = libsvm.cwrap('free_problem', null, ['number']); 55 | const serialize_model = libsvm.cwrap('serialize_model', 'number', ['number']); 56 | const deserialize_model = libsvm.cwrap('deserialize_model', 'number', [ 57 | 'string', 58 | ]); 59 | 60 | /* eslint-enable camelcase */ 61 | 62 | class SVM { 63 | /** 64 | * @constructor 65 | * @param {object} options 66 | * @param {number} [options.type=SVM_TYPES.C_SVC] - Type of SVM to perform, 67 | * @param {number} [options.kernel=KERNEL_TYPES.RBF] - Kernel function, 68 | * @param {number} [options.degree=3] - Degree of polynomial, for polynomial kernel 69 | * @param {number} [options.gamma] - Gamma parameter of the RBF, Polynomial and Sigmoid kernels. Default value is 1/num_features 70 | * @param {number} [options.coef0=0] - coef0 parameter for Polynomial and Sigmoid kernels 71 | * @param {number} [options.cost=1] - Cost parameter, for C SVC, Epsilon SVR and NU SVR 72 | * @param {number} [options.nu=0.5] - For NU SVC and NU SVR 73 | * @param {number} [options.epsilon=0.1] - For epsilon SVR 74 | * @param {number} [options.cacheSize=100] - Cache size in MB 75 | * @param {number} [options.tolerance=0.001] - Tolerance 76 | * @param {boolean} [options.shrinking=true] - Use shrinking euristics (faster), 77 | * @param {boolean} [options.probabilityEstimates=false] - weather to train SVC/SVR model for probability estimates, 78 | * @param {object} [options.weight] - Set weight for each possible class 79 | * @param {boolean} [options.quiet=true] - Print info during training if false 80 | */ 81 | constructor(options) { 82 | this.options = Object.assign({}, options); 83 | this.model = null; 84 | } 85 | 86 | /** 87 | * Trains the SVM model. 88 | * @param {Array>} samples - The training samples. First level of array are the samples, second 89 | * level are the individual features 90 | * @param {Array} labels - The training labels. It should have the same size as the samples. If you are 91 | * training a classification model, the labels should be distinct integers for each class. If you are training 92 | * a regression model, each label should be the value of the predicted variable. 93 | * @throws if SVM instance was instantiated from SVM.load. 94 | */ 95 | train(samples, labels) { 96 | if (this._deserialized) 97 | throw new Error( 98 | 'Train cannot be called on instance created with SVM.load', 99 | ); 100 | this.free(); 101 | this.problem = createProblem(samples, labels); 102 | const command = this.getCommand(samples); 103 | this.model = train_problem(this.problem, command); 104 | } 105 | 106 | /** 107 | * Performs k-fold cross-validation (KF-CV). KF-CV separates the data-set into kFold random equally sized partitions, 108 | * and uses each as a validation set, with all other partitions used in the training set. Observations left over 109 | * from if kFold does not divide the number of observations are left out of the cross-validation process. If 110 | * kFold is one, this is equivalent to a leave-on-out cross-validation 111 | * @param {Array>} samples - The training samples. 112 | * @param {Array} labels - The training labels. 113 | * @param {number} kFold - Number of datasets into which to split the training set. 114 | * @throws if SVM instance was instantiated from SVM.load. 115 | * @return {Array} The array of predicted labels produced by the cross validation. Has a size equal to 116 | * the number of samples provided as input. 117 | */ 118 | crossValidation(samples, labels, kFold) { 119 | if (this._deserialized) 120 | throw new Error( 121 | 'crossValidation cannot be called on instance created with SVM.load', 122 | ); 123 | const problem = createProblem(samples, labels); 124 | const target = libsvm._malloc(labels.length * 8); 125 | svm_cross_validation(problem, this.getCommand(samples), kFold, target); 126 | const data = libsvm.HEAPF64.subarray( 127 | target / 8, 128 | target / 8 + labels.length, 129 | ); 130 | const arr = Array.from(data); 131 | libsvm._free(target); 132 | free_problem(problem); 133 | return arr; 134 | } 135 | 136 | /** 137 | * Free the memory allocated for the model. Since this memory is stored in the memory model of emscripten, it is 138 | * allocated within an ArrayBuffer and WILL NOT BE GARBARGE COLLECTED, you have to explicitly free it. So 139 | * not calling this will result in memory leaks. As of today in the browser, there is no way to hook the 140 | * garbage collection of the SVM object to free it automatically. 141 | * Free the memory that was created by the compiled libsvm library to. 142 | * store the model. This model is reused every time the predict method is called. 143 | */ 144 | free() { 145 | if (this.problem) { 146 | free_problem(this.problem); 147 | this.problem = null; 148 | } 149 | if (this.model !== null) { 150 | svm_free_model(this.model); 151 | this.model = null; 152 | } 153 | } 154 | 155 | getCommand(samples) { 156 | const options = {}; 157 | Object.assign(options, this.options, { 158 | gamma: this.options.gamma ? this.options.gamma : 1 / samples[0].length, 159 | }); 160 | return getCommand(options); 161 | } 162 | 163 | /** 164 | * Predict the label of one sample. 165 | * @param {Array} sample - The sample to predict. 166 | * @return {number} - The predicted label. 167 | */ 168 | predictOne(sample) { 169 | if (this.model === null) { 170 | throw new Error('Cannot predict, you must train first'); 171 | } 172 | return predict_one( 173 | this.model, 174 | new Uint8Array(new Float64Array(sample).buffer), 175 | sample.length, 176 | ); 177 | } 178 | 179 | /** 180 | * Predict the label of many samples. 181 | * @param {Array>} samples - The samples to predict. 182 | * @return {Array} - The predicted labels. 183 | */ 184 | predict(samples) { 185 | let arr = []; 186 | for (let i = 0; i < samples.length; i++) { 187 | arr.push(this.predictOne(samples[i])); 188 | } 189 | return arr; 190 | } 191 | 192 | /** 193 | * Predict the label with probability estimate of many samples. 194 | * @param {Array>} samples - The samples to predict. 195 | * @return {Array} - An array of objects containing the prediction label and the probability estimates for each label 196 | */ 197 | predictProbability(samples) { 198 | let arr = []; 199 | for (let i = 0; i < samples.length; i++) { 200 | arr.push(this.predictOneProbability(samples[i])); 201 | } 202 | return arr; 203 | } 204 | 205 | /** Predict the label with probability estimate. 206 | * @param {Array} sample 207 | * @return {object} - An object containing the prediction label and the probability estimates for each label 208 | */ 209 | 210 | predictOneProbability(sample) { 211 | const labels = this.getLabels(); 212 | const nbLabels = labels.length; 213 | const estimates = libsvm._malloc(nbLabels * 8); 214 | const prediction = predict_one_probability( 215 | this.model, 216 | new Uint8Array(new Float64Array(sample).buffer), 217 | sample.length, 218 | estimates, 219 | ); 220 | const estimatesArr = Array.from( 221 | libsvm.HEAPF64.subarray(estimates / 8, estimates / 8 + nbLabels), 222 | ); 223 | const result = { 224 | prediction, 225 | estimates: labels.map((label, idx) => ({ 226 | label, 227 | probability: estimatesArr[idx], 228 | })), 229 | }; 230 | libsvm._free(estimates); 231 | return result; 232 | } 233 | 234 | /** Predict a regression value with a confidence interval 235 | * @param {Array} sample 236 | * @param {number} confidence - A value between 0 and 1. For example, a value 0.95 will give you the 95% confidence interval of the predicted value. 237 | * @return {object} - An object containing the prediction value and the lower and upper bounds of the confidence interval 238 | */ 239 | predictOneInterval(sample, confidence) { 240 | const interval = this._getInterval(confidence); 241 | const predicted = this.predictOne(sample); 242 | return { 243 | predicted, 244 | interval: [predicted - interval, predicted + interval], 245 | }; 246 | } 247 | 248 | /** Predict regression values with confidence intervals 249 | * @param {Array>} samples - An array of samples. 250 | * @param {number} confidence - A value between 0 and 1. For example, a value 0.95 will give you the 95% confidence interval of the predicted value. 251 | * @return {Array} - An array of objects each containing the prediction label and the probability estimates for each label 252 | */ 253 | predictInterval(samples, confidence) { 254 | const interval = this._getInterval(confidence); 255 | const predicted = this.predict(samples); 256 | return predicted.map((pred) => ({ 257 | predicted: pred, 258 | interval: [pred - interval, pred + interval], 259 | })); 260 | } 261 | 262 | _getInterval(confidence) { 263 | const sigma = svm_get_svr_probability(this.model); 264 | if (sigma === 0) 265 | throw new Error( 266 | 'the model is not a regression with probability estimates', 267 | ); 268 | if (confidence <= 0 || confidence >= 1) 269 | throw new Error('confidence must be greater than 0 and less than 1'); 270 | const p = (1 - confidence) / 2; 271 | return sigma * Math.sign(p - 0.5) * Math.log2(1 - 2 * Math.abs(p - 0.5)); 272 | } 273 | 274 | /** 275 | * Get the array of labels from the model. Useful when creating an SVM instance with SVM.load 276 | * @return {Array} - The list of labels. 277 | */ 278 | getLabels() { 279 | const nbLabels = svm_get_nr_class(this.model); 280 | return getIntArrayFromModel(svm_get_labels, this.model, nbLabels); 281 | } 282 | 283 | /** 284 | * Get the indices of the support vectors from the training set passed to the train method. 285 | * @return {Array} - The list of indices from the training samples. 286 | */ 287 | getSVIndices() { 288 | const nSV = svm_get_nr_sv(this.model); 289 | return getIntArrayFromModel(svm_get_sv_indices, this.model, nSV).map( 290 | (i) => i - 1, 291 | ); 292 | } 293 | 294 | /** 295 | * Uses libsvm's serialization method of the model. 296 | * @return {string} The serialization string. 297 | */ 298 | serializeModel() { 299 | if (!this.model) 300 | throw new Error('Cannot serialize model. No model was trained'); 301 | const result = serialize_model(this.model); 302 | const str = libsvm.UTF8ToString(result); 303 | libsvm._free(result); 304 | return str; 305 | } 306 | 307 | /** 308 | * Create a SVM instance from the serialized model. 309 | * @param {string} serializedModel - The serialized model. 310 | * @return {SVM} - SVM instance that contains the model. 311 | */ 312 | static load(serializedModel) { 313 | const svm = new SVM(); 314 | svm.model = deserialize_model(serializedModel); 315 | svm._deserialized = true; 316 | return svm; 317 | } 318 | } 319 | 320 | /** 321 | * SVM classification and regression types 322 | * @memberof SVM 323 | * @type {{C_SVC: string, NU_SVC: string, ONE_CLASS: string, EPSILON_SVR: string, NU_SVR: string}} 324 | * @property C_SVC - The C support vector classifier type 325 | * @property NU_SVC - The nu support vector classifier type 326 | * @property ONE_CLASS - The one-class support vector classifier type 327 | * @property EPSILON_SVR - The epsilon support vector regression type 328 | * @property NU_SVR - The nu support vector regression type 329 | */ 330 | SVM.SVM_TYPES = { 331 | C_SVC: '0', // C support vector classification 332 | NU_SVC: '1', // NU support vector classification 333 | ONE_CLASS: '2', // ONE CLASS classification 334 | EPSILON_SVR: '3', // Epsilon support vector regression 335 | NU_SVR: '4', // Nu support vector regression 336 | }; 337 | 338 | /** 339 | * SVM kernel types 340 | * @memberof SVM 341 | * @type {{LINEAR: string, POLYNOMIAL: string, RBF: string, SIGMOID: string}} 342 | * @property LINEAR - Linear kernel 343 | * @property POLYNOMIAL - Polynomial kernel 344 | * @property RBF - Radial basis function (gaussian) kernel 345 | * @property SIGMOID - Sigmoid kernel 346 | */ 347 | SVM.KERNEL_TYPES = { 348 | LINEAR: '0', 349 | POLYNOMIAL: '1', 350 | RBF: '2', // Radial basis function 351 | SIGMOID: '3', 352 | PRECOMPUTED: '4', 353 | }; 354 | 355 | function getIntArrayFromModel(fn, model, size) { 356 | const offset = libsvm._malloc(size * 4); 357 | fn(model, offset); 358 | const data = libsvm.HEAP32.subarray(offset / 4, offset / 4 + size); 359 | const arr = Array.from(data); 360 | libsvm._free(offset); 361 | return arr; 362 | } 363 | 364 | function createProblem(samples, labels) { 365 | const nbSamples = samples.length; 366 | const nbFeatures = samples[0].length; 367 | const problem = create_svm_nodes(nbSamples, nbFeatures); 368 | for (let i = 0; i < nbSamples; i++) { 369 | add_instance( 370 | problem, 371 | new Uint8Array(new Float64Array(samples[i]).buffer), 372 | nbFeatures, 373 | labels[i], 374 | i, 375 | ); 376 | } 377 | return problem; 378 | } 379 | 380 | return SVM; 381 | } 382 | -------------------------------------------------------------------------------- /src/util.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const mapOptionToCommand = { 4 | quiet: 'q', 5 | type: 's', 6 | kernel: 't', 7 | degree: 'd', 8 | gamma: 'g', 9 | coef0: 'r', 10 | cost: 'c', 11 | nu: 'n', 12 | epsilon: 'p', 13 | cacheSize: 'm', 14 | tolerance: 'e', 15 | shrinking: 'h', 16 | probabilityEstimates: 'b', 17 | weight: 'w', 18 | }; 19 | 20 | export function getCommand(options) { 21 | var str = ''; 22 | var keys = Object.keys(options); 23 | for (var i = 0; i < keys.length; i++) { 24 | var key = keys[i]; 25 | if (options[key] == null) continue; 26 | if (mapOptionToCommand[key] == null) throw new Error('Bad option'); 27 | if (str) str += ' '; 28 | switch (key) { 29 | case 'probabilityEstimates': 30 | case 'shrinking': 31 | str += `-${mapOptionToCommand[key]} ${options[key] ? 1 : 0}`; 32 | break; 33 | case 'quiet': { 34 | if (options[key]) { 35 | str += `-${mapOptionToCommand[key]} 1`; 36 | } 37 | break; 38 | } 39 | case 'weight': { 40 | const weightKeys = Object.keys(options.weight); 41 | for (let j = 0; j < weightKeys.length; j++) { 42 | if (j !== 0) str += ' '; 43 | str += `-w${weightKeys[j]} ${options.weight[weightKeys[j]]}`; 44 | } 45 | break; 46 | } 47 | default: { 48 | str += `-${mapOptionToCommand[key]} ${options[key]}`; 49 | break; 50 | } 51 | } 52 | } 53 | 54 | return str; 55 | } 56 | -------------------------------------------------------------------------------- /test/util.js: -------------------------------------------------------------------------------- 1 | import { getCommand } from '../src/util.js'; 2 | 3 | describe('util', function () { 4 | it('should return proper command string', function () { 5 | getCommand({ 6 | weight: { 7 | 1: 3, 8 | 2: 5, 9 | }, 10 | }).should.equal('-w1 3 -w2 5'); 11 | getCommand({ quiet: true }).should.equal('-q 1'); 12 | getCommand({ quiet: false }).should.equal(''); 13 | getCommand({ probabilityEstimates: true }).should.equal('-b 1'); 14 | getCommand({ probabilityEstimates: false }).should.equal('-b 0'); 15 | getCommand({ type: 0 }).should.equal('-s 0'); 16 | getCommand({ kernel: 2 }).should.equal('-t 2'); 17 | getCommand({ degree: 2 }).should.equal('-d 2'); 18 | getCommand({ cost: 0.01 }).should.equal('-c 0.01'); 19 | getCommand({ coef0: 0 }).should.equal('-r 0'); 20 | getCommand({ epsilon: 1 }).should.equal('-p 1'); 21 | getCommand({ cacheSize: 300 }).should.equal('-m 300'); 22 | getCommand({ shrinking: true }).should.equal('-h 1'); 23 | getCommand({ shrinking: false }).should.equal('-h 0'); 24 | getCommand({ nu: 0.5 }).should.equal('-n 0.5'); 25 | getCommand({ tolerance: 0.001 }).should.equal('-e 0.001'); 26 | getCommand({ 27 | degree: 2, 28 | shrinking: true, 29 | }).should.equal('-d 2 -h 1'); 30 | }); 31 | 32 | it('should throw if bad option', function () { 33 | (function () { 34 | getCommand({ bad: true }); 35 | }).should.throw(/Bad option/); 36 | }); 37 | }); 38 | -------------------------------------------------------------------------------- /tools/iris.js: -------------------------------------------------------------------------------- 1 | import fs from 'node:fs'; 2 | import path from 'node:path'; 3 | import data from 'ml-dataset-iris'; 4 | 5 | const dataset = data.getDataset(); 6 | const distinctClasses = data.getDistinctClasses(); 7 | dataset.forEach((d) => { 8 | d[4] = distinctClasses.indexOf(d[4]); 9 | }); 10 | const str = dataset.map((d) => d.join(' ')).join('\n'); 11 | fs.writeFileSync( 12 | path.resolve(import.meta.dirname, '../benchmark/iris/data.txt'), 13 | str, 14 | ); 15 | -------------------------------------------------------------------------------- /wasm.js: -------------------------------------------------------------------------------- 1 | import load from './src/loadSVM.js'; 2 | import libsvm from './build/libsvm.js'; 3 | 4 | export async function loadSVM() { 5 | const module = await libsvm(); 6 | return load(module); 7 | } 8 | --------------------------------------------------------------------------------