├── _config.yml ├── images └── matrix_profile.png ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── src ├── main │ └── java │ │ └── io │ │ └── github │ │ └── ensozos │ │ ├── core │ │ ├── order │ │ │ ├── Order.java │ │ │ ├── LinearOrder.java │ │ │ └── RandomOrder.java │ │ ├── distance │ │ │ ├── DistanceProfileFactory.java │ │ │ └── StampDistanceProfile.java │ │ ├── DistanceProfile.java │ │ ├── Complex.java │ │ ├── MPdistance.java │ │ ├── MatrixProfileCalculator.java │ │ ├── Mass.java │ │ └── MatrixProfile.java │ │ └── utils │ │ └── CustomOperations.java └── test │ ├── resources │ ├── data │ │ └── series │ │ │ ├── repeat_4 │ │ │ ├── numenta_art_increase_spike_density │ │ │ ├── numenta_art_load_balancer_spikes │ │ │ └── numenta_art_daily_flatmiddle │ └── results │ │ ├── repeat_4_profile_pair_0_1.exp │ │ └── repeat_4_profile_pair.exp │ └── java │ └── io │ └── github │ └── ensozos │ ├── core │ ├── order │ │ ├── LinearOrderTest.java │ │ └── RandomOrderTest.java │ ├── distance │ │ ├── DistanceProfileFactoryTest.java │ │ └── StampDistanceProfileTest.java │ ├── MatrixProfileAccuracyTest.java │ ├── MatrixProfilePerformanceTest.java │ └── MatrixProfileTest.java │ └── testsupport │ ├── CsvExport.java │ └── FileUtil.java ├── .gitignore ├── LICENSE ├── gradlew.bat ├── gradlew └── README.md /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman -------------------------------------------------------------------------------- /images/matrix_profile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ensozos/Matrix-Profile/HEAD/images/matrix_profile.png -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ensozos/Matrix-Profile/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /src/main/java/io/github/ensozos/core/order/Order.java: -------------------------------------------------------------------------------- 1 | package io.github.ensozos.core.order; 2 | 3 | public interface Order { 4 | 5 | /** 6 | * get the next index 7 | * @return index 8 | */ 9 | int getNext(); 10 | } 11 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /src/test/resources/data/series/repeat_4: -------------------------------------------------------------------------------- 1 | 0.6, 0.5, 2.00, 1.0, -1.01, -0.5, 1.0, 2.3, 4.0, 5.9, 4.2, 3.1, 3.2, 3.4, 2.9, 3.5, 1.05, -1.0, -0.50, 1.01, 2.41, 3.99, 6.01, 4.7, 3.2, 2.6, 4.1, 4.3, 1.1, 1.7, 3.1, 1.9, -0.5, 2.1, 1.9, 2.01, -0.02, 0.48, 2.03, 3.31, 5.1, 7.1, 5.1, 3.2, 2.3, 1.8, 2.1, 1.7, 1.1, -0.1, 2.1, 2.01, 3.9, 3.1, 1.05, -1.0, -0.5, 1.01, 2.41, 3.99, 6.01, 4.7, 4.5, 3.9, 2.1, 3.3, 3.1, 2.7, 1.9 -------------------------------------------------------------------------------- /src/test/java/io/github/ensozos/core/order/LinearOrderTest.java: -------------------------------------------------------------------------------- 1 | package io.github.ensozos.core.order; 2 | 3 | 4 | import org.junit.Test; 5 | 6 | import static org.junit.Assert.assertEquals; 7 | 8 | public class LinearOrderTest { 9 | 10 | 11 | @Test 12 | public void testLinearOrderIndex() { 13 | 14 | LinearOrder order = new LinearOrder(3); 15 | 16 | assertEquals(0, order.getNext()); 17 | assertEquals(1, order.getNext()); 18 | assertEquals(2, order.getNext()); 19 | assertEquals(-1, order.getNext()); 20 | assertEquals(-1, order.getNext()); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/test/java/io/github/ensozos/core/distance/DistanceProfileFactoryTest.java: -------------------------------------------------------------------------------- 1 | package io.github.ensozos.core.distance; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | import io.github.ensozos.core.DistanceProfile; 5 | import org.junit.Test; 6 | 7 | 8 | public class DistanceProfileFactoryTest { 9 | 10 | /* instance under test */ 11 | private DistanceProfileFactory factory = new DistanceProfileFactory(); 12 | 13 | @Test 14 | public void createStampDistanceProfile() { 15 | DistanceProfile profile = factory.getDistanceProfile(DistanceProfileFactory.STAMP); 16 | 17 | assertEquals( 18 | "1.0000", profile.getDistanceProfileIndex(2, 1, 2).toString() 19 | ); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/io/github/ensozos/core/order/LinearOrder.java: -------------------------------------------------------------------------------- 1 | package io.github.ensozos.core.order; 2 | 3 | 4 | public class LinearOrder implements Order { 5 | private int w; 6 | private int index; 7 | 8 | /** 9 | * Indices of length w in linear order 10 | * 11 | * @param w window size 12 | */ 13 | public LinearOrder(int w) { 14 | this.w = w; 15 | this.index = -1; 16 | 17 | } 18 | 19 | /** 20 | * Get the next index 21 | * 22 | * @return the next int index 23 | */ 24 | @Override 25 | public int getNext() { 26 | this.index++; 27 | if (this.index < this.w) 28 | return this.index; 29 | 30 | return -1; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/io/github/ensozos/core/distance/DistanceProfileFactory.java: -------------------------------------------------------------------------------- 1 | package io.github.ensozos.core.distance; 2 | 3 | import io.github.ensozos.core.DistanceProfile; 4 | 5 | public class DistanceProfileFactory { 6 | 7 | public static final String STAMP = "STAMP"; 8 | 9 | /** 10 | * Factory method for creating distance profile objects 11 | * 12 | * @param distanceProfileType the type of distance profile 13 | * @return distance profile object 14 | */ 15 | public DistanceProfile getDistanceProfile(String distanceProfileType) { 16 | if (distanceProfileType == null) return null; 17 | 18 | if (distanceProfileType.equalsIgnoreCase(STAMP)) { 19 | return new StampDistanceProfile(); 20 | } 21 | 22 | return null; 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Java template 3 | # Compiled class file 4 | *.class 5 | 6 | # Log file 7 | *.log 8 | 9 | # BlueJ files 10 | *.ctxt 11 | 12 | # Mobile Tools for Java (J2ME) 13 | .mtj.tmp/ 14 | 15 | # Package Files # 16 | *.jar 17 | *.war 18 | *.nar 19 | *.ear 20 | *.zip 21 | *.tar.gz 22 | *.rar 23 | 24 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 25 | hs_err_pid* 26 | ### Gradle template 27 | .gradle 28 | /build/ 29 | 30 | # Ignore Gradle GUI config 31 | gradle-app.setting 32 | 33 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) 34 | !gradle-wrapper.jar 35 | 36 | # Cache of project 37 | .gradletasknamecache 38 | 39 | # # Work around https://youtrack.jetbrains.com/issue/IDEA-116898 40 | # gradle/wrapper/gradle-wrapper.properties 41 | 42 | ### Intellij 43 | *.iml 44 | /.idea/ 45 | -------------------------------------------------------------------------------- /src/test/java/io/github/ensozos/core/distance/StampDistanceProfileTest.java: -------------------------------------------------------------------------------- 1 | package io.github.ensozos.core.distance; 2 | 3 | import org.junit.Test; 4 | import org.nd4j.linalg.cpu.nativecpu.NDArray; 5 | import static org.junit.Assert.assertEquals; 6 | import static org.junit.Assert.assertNotNull; 7 | 8 | 9 | public class StampDistanceProfileTest { 10 | 11 | /* instance under test */ 12 | private StampDistanceProfile profile = new StampDistanceProfile(); 13 | 14 | @Test 15 | public void testGetDistanceProfileIndex() { 16 | 17 | assertEquals( 18 | "1.0000", profile.getDistanceProfileIndex(1, 1, 1).toString() 19 | ); 20 | } 21 | 22 | @Test 23 | public void testGetDistanceProfile() { 24 | 25 | assertNotNull(profile.getDistanceProfile( 26 | new NDArray(5, 5, 'c'), 27 | new NDArray(5, 5, 'c'), 1, 2)); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/io/github/ensozos/core/DistanceProfile.java: -------------------------------------------------------------------------------- 1 | package io.github.ensozos.core; 2 | 3 | import org.nd4j.linalg.api.ndarray.INDArray; 4 | 5 | public interface DistanceProfile { 6 | 7 | /** 8 | * Returns the distance profile given two time series index and window 9 | * 10 | * @param tsA time series 11 | * @param tsB time series 12 | * @param index current index 13 | * @param window window size 14 | * @return distance profile 15 | */ 16 | INDArray getDistanceProfile(INDArray tsA, INDArray tsB, int index, int window); 17 | 18 | /** 19 | * Returns the distance profile index given index, window and n the size of target 20 | * time series. 21 | * 22 | * @param n size of target time series 23 | * @param index the current index 24 | * @param window the size of window 25 | * @return distance profile index 26 | */ 27 | INDArray getDistanceProfileIndex(int n,int index, int window); 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/io/github/ensozos/core/distance/StampDistanceProfile.java: -------------------------------------------------------------------------------- 1 | package io.github.ensozos.core.distance; 2 | 3 | import io.github.ensozos.core.DistanceProfile; 4 | import io.github.ensozos.core.Mass; 5 | import org.nd4j.linalg.api.ndarray.INDArray; 6 | import org.nd4j.linalg.factory.Nd4j; 7 | import org.nd4j.linalg.indexing.NDArrayIndex; 8 | 9 | 10 | public class StampDistanceProfile implements DistanceProfile { 11 | 12 | /* 13 | * MASS 2.0 the main algorithm of distance profile 14 | */ 15 | private Mass massAlgo; 16 | 17 | public StampDistanceProfile() { 18 | massAlgo = new Mass(); 19 | } 20 | 21 | @Override 22 | public INDArray getDistanceProfile(INDArray tsA, INDArray tsB, int index, int w) { 23 | INDArray query = tsA.get(NDArrayIndex.interval(index, index + w)); 24 | 25 | return massAlgo.mass(tsB, query); 26 | } 27 | 28 | @Override 29 | public INDArray getDistanceProfileIndex(int n, int index, int w) { 30 | return Nd4j.valueArrayOf(new int[]{1, n - w + 1}, (double) index); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Zosimadis Ilias 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/test/resources/results/repeat_4_profile_pair_0_1.exp: -------------------------------------------------------------------------------- 1 | 2.155993938446045,2.9192252159118652,4.118425369262695,4.030115604400635,3.0984253883361816,1.9701749086380005,0.6994492411613464,1.4518600702285767,2.0063538551330566,3.7929635047912598,4.23722505569458,3.752814769744873,2.44401478767395,1.0812915563583374,1.4759129285812378,0.6185596585273743,1.8006385564804077,0.1700761467218399,1.5794134140014648,3.098424196243286,2.8066492080688477,3.123464584350586,3.94564151763916,3.7961041927337646,2.861192464828491,3.3350963592529297,3.5435311794281006,3.6001827716827393,2.498600482940674,3.773308277130127,4.322541236877441,3.0597259998321533,2.162654399871826,0.8370838165283203,0.4880507290363312,1.8832825422286987,0.3964867889881134,2.0967772006988525,1.8554240465164185,2.3148183822631836,2.0153591632843018,2.903790235519409,3.541524648666382,3.084327220916748,2.256115674972534,1.3612076044082642,1.575606346130371,2.22328519821167,2.9859299659729004,2.300144910812378,2.485210657119751,2.806648015975952,1.8720117807388306,0.45467349886894226,1.8006385564804077,0.5162765383720398,1.239101529121399,1.8247357606887817,2.4306223392486572,2.312523603439331,2.525850534439087,3.1843104362487793 2 | 20.0,51.0,51.0,19.0,19.0,19.0,19.0,20.0,51.0,51.0,51.0,51.0,51.0,51.0,1.0,2.0,2.0,4.0,4.0,4.0,51.0,51.0,51.0,51.0,51.0,51.0,51.0,51.0,20.0,51.0,2.0,19.0,20.0,1.0,2.0,4.0,4.0,19.0,19.0,20.0,51.0,51.0,51.0,51.0,51.0,1.0,2.0,4.0,4.0,19.0,20.0,20.0,1.0,2.0,2.0,4.0,4.0,19.0,19.0,51.0,51.0,51.0 3 | -------------------------------------------------------------------------------- /src/test/resources/results/repeat_4_profile_pair.exp: -------------------------------------------------------------------------------- 1 | 1.978220820426941,0.8370792865753174,0.4546787440776825,0.08726994693279266,0.1700817495584488,0.4098934233188629,0.6994492411613464,1.4518600702285767,1.3318941593170166,0.9451253414154053,1.8153070211410522,1.9904367923736572,1.1875959634780884,1.0812915563583374,0.5911672711372375,0.16531619429588318,0.002183660166338086,0.1700761467218399,0.40988412499427795,0.6994478702545166,1.4518624544143677,2.0698282718658447,1.4597182273864746,1.9393233060836792,2.2885994911193848,1.808644413948059,1.697424054145813,2.034470558166504,2.1472036838531494,1.9444102048873901,1.985047698020935,2.553644895553589,1.9782203435897827,0.8370838165283203,0.4880507290363312,0.08724261820316315,0.3964867889881134,0.7430973052978516,1.1167277097702026,1.354939579963684,1.331898808479309,1.1392788887023926,0.9451137185096741,1.6974308490753174,1.9327597618103027,1.330040454864502,1.575606346130371,2.081027030944824,1.8508388996124268,1.116721749305725,1.1875971555709839,1.0812915563583374,0.5911785364151001,0.16531331837177277,0.002183660166338086,0.5018125176429749,0.6484558582305908,1.379483938217163,1.791913390159607,1.469473123550415,1.1392462253570557,1.386409878730774 2 | 32.0,33.0,53.0,35.0,17.0,18.0,19.0,20.0,40.0,42.0,42.0,49.0,50.0,51.0,52.0,53.0,54.0,4.0,5.0,6.0,7.0,40.0,42.0,43.0,50.0,61.0,43.0,44.0,0.0,61.0,22.0,23.0,0.0,1.0,2.0,3.0,4.0,18.0,49.0,50.0,8.0,60.0,9.0,26.0,13.0,33.0,2.0,36.0,37.0,38.0,12.0,13.0,14.0,15.0,16.0,17.0,5.0,6.0,7.0,40.0,41.0,42.0 3 | -------------------------------------------------------------------------------- /src/test/java/io/github/ensozos/core/order/RandomOrderTest.java: -------------------------------------------------------------------------------- 1 | package io.github.ensozos.core.order; 2 | 3 | import org.junit.Test; 4 | 5 | import java.util.LinkedList; 6 | import java.util.List; 7 | import java.util.Random; 8 | 9 | import static org.junit.Assert.assertEquals; 10 | 11 | 12 | public class RandomOrderTest { 13 | 14 | @Test 15 | public void testRandomOrderIndex() { 16 | 17 | RandomOrder order = new RandomOrder(3, 1.0, new Random(2)); 18 | 19 | List indices = new LinkedList<>(); 20 | for (int i = 0; i < 5; i++) { 21 | indices.add(order.getNext()); 22 | } 23 | 24 | assertEquals("[1, 0, 2, -1, -1]", indices.toString()); 25 | } 26 | 27 | @Test 28 | public void testRandomOrderIndexWhenOnly10percentUsed() { 29 | 30 | RandomOrder order = new RandomOrder(30, 0.1, new Random(2)); 31 | 32 | List indices = new LinkedList<>(); 33 | for (int i = 0; i < 5; i++) { 34 | indices.add(order.getNext()); 35 | } 36 | 37 | assertEquals("[28, 27, 6, -1, -1]", indices.toString()); 38 | } 39 | 40 | @Test 41 | public void testRandomOrderIndexWhenOnly20percentUsed() { 42 | 43 | RandomOrder order = new RandomOrder(30, 0.2, new Random(2)); 44 | 45 | List indices = new LinkedList<>(); 46 | for (int i = 0; i < 7; i++) { 47 | indices.add(order.getNext()); 48 | } 49 | 50 | assertEquals("[28, 27, 6, 4, 21, 5, -1]", indices.toString()); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/io/github/ensozos/core/Complex.java: -------------------------------------------------------------------------------- 1 | package io.github.ensozos.core; 2 | 3 | import java.lang.Math; 4 | 5 | public class Complex { 6 | 7 | protected double re; 8 | protected double im; 9 | 10 | /** 11 | * Data type for complex numbers. 12 | * 13 | * @param real real part of complex number 14 | * @param imag imaginary part of complex number 15 | */ 16 | public Complex(double real, double imag) { 17 | re = real; 18 | im = imag; 19 | } 20 | 21 | /** 22 | * Get the real part of complex number 23 | * 24 | * @return real number 25 | */ 26 | public double getReal() { 27 | return re; 28 | } 29 | 30 | /** 31 | * Get imaginary part of complex number 32 | * 33 | * @return imaginary part 34 | */ 35 | public double getImaginary() { 36 | return im; 37 | } 38 | 39 | /** 40 | * Add complex number. 41 | *

42 | * a = 7.0 + 6.0i 43 | * b = -1.0 + 2.0i 44 | *

45 | * a + b = 6.0 + 8.0i 46 | * 47 | * @param b complex number to add 48 | * @return result complex number 49 | */ 50 | public Complex add(Complex b) { 51 | re = re + b.re; 52 | im = im + b.im; 53 | return this; 54 | } 55 | 56 | /** 57 | * Multiply complex number. 58 | *

59 | * a = 1+4i 60 | * b = 5+i 61 | *

62 | * a*b = 1+21i 63 | * 64 | * @param b complex number to multiply 65 | * @return result complex number 66 | */ 67 | public Complex times(Complex b) { 68 | Complex a = this; 69 | double real = a.re * b.re - a.im * b.im; 70 | double imag = a.re * b.im + a.im * b.re; 71 | return new Complex(real, imag); 72 | } 73 | 74 | @Override 75 | public String toString() { 76 | return re + ((Math.signum(im) >= 0) ? " + " : " - ") + Math.abs(im) + "i"; 77 | } 78 | 79 | @Override 80 | public boolean equals(Object obj) { 81 | if (this == obj) 82 | return true; 83 | if (obj == null) 84 | return false; 85 | if (getClass() != obj.getClass()) 86 | return false; 87 | Complex that = (Complex) obj; 88 | return (that.re == this.re) && (that.im == this.im); 89 | } 90 | 91 | 92 | } -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /src/main/java/io/github/ensozos/core/order/RandomOrder.java: -------------------------------------------------------------------------------- 1 | package io.github.ensozos.core.order; 2 | 3 | 4 | import java.util.Random; 5 | import java.util.stream.IntStream; 6 | 7 | public class RandomOrder implements Order { 8 | private int numIndices; 9 | private int index; 10 | private int[] indices; 11 | 12 | /** 13 | * Random indices of length w. Uses all of them. 14 | * 15 | * @param w size w 16 | */ 17 | public RandomOrder(int w) { 18 | this(w, 1.0, new Random()); 19 | } 20 | 21 | /** 22 | * Some fraction of Random indices of length w. 23 | * No matter how small fraction is, we will always use at least 1 random index. 24 | * 25 | * @param w size w 26 | * @param fraction only use this fraction of the random indices. Must be in (0, 1]. 27 | */ 28 | public RandomOrder(int w, double fraction) { 29 | this(w, fraction, new Random()); 30 | } 31 | 32 | /** 33 | * Random indices of length numIndices 34 | * 35 | * @param w size w 36 | * @param fraction only use this fraction of the random indices. Must be in (0, 1]. 37 | * @param rnd the random number generate to use. Call this from unit tests for deterministic results 38 | */ 39 | public RandomOrder(int w, double fraction, Random rnd) { 40 | assert fraction > 0 && fraction <= 1.0; 41 | this.numIndices = (int) Math.max(1, Math.round(fraction * w)); 42 | this.index = -1; 43 | this.indices = new int[w]; 44 | 45 | IntStream.range(0, w).forEach(n -> this.indices[n] = n); 46 | shuffle(indices, rnd, numIndices); 47 | } 48 | 49 | /** 50 | * Get the next random index 51 | * 52 | * @return random int index 53 | */ 54 | @Override 55 | public int getNext() { 56 | this.index++; 57 | if (this.index < numIndices) 58 | return indices[index]; 59 | 60 | return -1; 61 | } 62 | 63 | /** 64 | * Shuffle array with Fisher-Yates algorithm 65 | * 66 | * @param array array to shuffle 67 | * @param rnd random number generator to use 68 | * @param numIndices only need to shuff the first numIndices because that is all that will be used. 69 | */ 70 | private void shuffle(int[] array, Random rnd, int numIndices) { 71 | int n = array.length; 72 | 73 | for (int i = 0; i < numIndices; i++) { 74 | int randomValue = i + rnd.nextInt(n - i); 75 | 76 | int randomElement = array[randomValue]; 77 | array[randomValue] = array[i]; 78 | array[i] = randomElement; 79 | } 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /src/test/java/io/github/ensozos/testsupport/CsvExport.java: -------------------------------------------------------------------------------- 1 | package io.github.ensozos.testsupport; 2 | 3 | import javafx.util.Pair; 4 | import org.nd4j.linalg.api.ndarray.INDArray; 5 | import java.io.*; 6 | import java.net.URL; 7 | 8 | 9 | public class CsvExport { 10 | 11 | /** 12 | * Print the series and profile to a CSV file so that it can be visualized. 13 | * @param target the series that was processed 14 | * @param expResult expected matrix profile and indices 15 | * @param filename name of the file 16 | */ 17 | public static void printToCsvFile(INDArray target, Pair expResult, String filename) { 18 | try{ 19 | printToCsvStream(target, expResult, new PrintStream(new File(filename))); 20 | } catch (FileNotFoundException e) { 21 | throw new IllegalStateException("File, " + filename + " not found.", e); 22 | } 23 | } 24 | 25 | /** 26 | * Print the series and profile as CSV text. 27 | * @param target the series that was processed 28 | * @param expResult expected matrix profile and indices 29 | */ 30 | public static void printAsCsv(INDArray target, Pair expResult) { 31 | printToCsvStream(target, expResult, new PrintStream(System.out)); 32 | } 33 | 34 | /** 35 | * Print the series and profile to a CSV file so that it can be visualized. 36 | * @param result the pair to write to a file 37 | * @param filename name of the file 38 | */ 39 | public static void printPairToFile(Pair result, String filename) { 40 | 41 | PrintStream stream; 42 | try { 43 | File file = new File(filename); 44 | //System.out.println("writing to " + file.getAbsolutePath()); 45 | stream = new PrintStream(file); 46 | } 47 | catch (IOException e) { 48 | throw new IllegalStateException("Could not create " + filename); 49 | } 50 | 51 | printSeries(stream, result.getKey()); 52 | printSeries(stream, result.getValue()); 53 | stream.close(); 54 | } 55 | 56 | private static void printSeries(PrintStream strm, INDArray series) { 57 | long keyLen = series.length(); 58 | for (long i = 0; i < keyLen; i++) { 59 | strm.print(series.getDouble(i)); 60 | if (i < keyLen - 1) { 61 | strm.print(","); 62 | } 63 | } 64 | strm.println(); 65 | } 66 | 67 | /** 68 | * Print the series and profile to a CSV file so that it can be visualized. 69 | * @param target the series that was processed 70 | * @param expResult expected matrix profile and indices 71 | */ 72 | private static void printToCsvStream(INDArray target, Pair expResult, PrintStream stream) { 73 | stream.println("row,series,MP,MPindx"); // csv header row 74 | for (int i = 0; i < target.columns(); i++) { 75 | stream.print(i + "," + target.getDouble(0, i) + ","); 76 | if (i < expResult.getKey().columns()) { 77 | stream.println(expResult.getKey().getDouble(0, i) + "," + expResult.getValue().getDouble(0,i)); 78 | } else { 79 | stream.println(","); 80 | } 81 | } 82 | stream.close(); 83 | } 84 | 85 | } 86 | -------------------------------------------------------------------------------- /src/test/java/io/github/ensozos/testsupport/FileUtil.java: -------------------------------------------------------------------------------- 1 | package io.github.ensozos.testsupport; 2 | 3 | import javafx.util.Pair; 4 | import org.nd4j.linalg.api.ndarray.INDArray; 5 | import org.nd4j.linalg.factory.Nd4j; 6 | 7 | import java.io.*; 8 | import java.net.URL; 9 | 10 | 11 | /** 12 | * Convenience methods for reading and writing test data to/from files. 13 | */ 14 | public class FileUtil { 15 | 16 | public static final String RESOURCE_DIR = "src/test/resources/"; 17 | public static final String DATA_DIR = RESOURCE_DIR + "data/series/"; 18 | public static final String RESULTS_DIR = RESOURCE_DIR + "results/"; 19 | 20 | private static final String DELIMITER = ","; 21 | 22 | 23 | /** 24 | * @param filepath the file containing a comma delimited list of doubles 25 | * @return array of those doubles 26 | */ 27 | public static INDArray readIndArray(String filepath) { 28 | double[] doubleArray = readDoublesFromFile(filepath); 29 | 30 | return Nd4j.create(doubleArray, new int[]{1, doubleArray.length}); 31 | } 32 | 33 | public static Pair readIndArrayPair(String filepath) { 34 | double[][] doubleArray = readTwoRowsOfDoublesFromFile(filepath); 35 | 36 | return new Pair<>( 37 | Nd4j.create(doubleArray[0], new int[]{1, doubleArray[0].length}), 38 | Nd4j.create(doubleArray[1], new int[]{1, doubleArray[1].length}) 39 | ); 40 | } 41 | 42 | /** 43 | * @param filepath file that contains a comma delimited list of doubles on a single line 44 | * @return array of doubles 45 | */ 46 | private static double[] readDoublesFromFile(String filepath) { 47 | double[] array; 48 | try { 49 | BufferedReader fileReader = getReader(filepath); 50 | String line = fileReader.readLine(); 51 | array = parseLineOfDoubles(line); 52 | } 53 | catch (IOException e) { 54 | throw new IllegalStateException("Could not read file " + filepath, e); 55 | } 56 | 57 | return array; 58 | } 59 | 60 | /** 61 | * @param filepath file that contains two comma delimited list of doubles on a single line 62 | * @return two element array containing to arrays of doubles. 63 | */ 64 | private static double[][] readTwoRowsOfDoublesFromFile(String filepath) { 65 | double[][] array = new double[2][]; 66 | try { 67 | BufferedReader fileReader = getReader(filepath); 68 | 69 | array[0] = parseLineOfDoubles(fileReader.readLine()); 70 | array[1] = parseLineOfDoubles(fileReader.readLine()); 71 | } 72 | catch (IOException e) { 73 | throw new IllegalStateException("Could not read file " + filepath, e); 74 | } 75 | 76 | return array; 77 | } 78 | 79 | private static BufferedReader getReader(String filepath) throws FileNotFoundException { 80 | 81 | File file; 82 | file = new File(filepath); 83 | //System.out.println("reading from " + file.getAbsolutePath()); 84 | 85 | return new BufferedReader(new FileReader(file)); 86 | } 87 | 88 | private static double[] parseLineOfDoubles(String line) { 89 | String[] values = line.split(DELIMITER); 90 | double[] array = new double[values.length]; 91 | 92 | for (int i = 0; i < values.length; i++) { 93 | array[i] = Double.parseDouble(values[i]); 94 | } 95 | return array; 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/test/java/io/github/ensozos/core/MatrixProfileAccuracyTest.java: -------------------------------------------------------------------------------- 1 | package io.github.ensozos.core; 2 | 3 | import io.github.ensozos.testsupport.CsvExport; 4 | import io.github.ensozos.testsupport.FileUtil; 5 | import javafx.util.Pair; 6 | import org.junit.Test; 7 | import org.nd4j.linalg.api.ndarray.INDArray; 8 | 9 | import static io.github.ensozos.testsupport.FileUtil.DATA_DIR; 10 | import static io.github.ensozos.testsupport.FileUtil.RESULTS_DIR; 11 | import static org.junit.Assert.assertEquals; 12 | 13 | 14 | /** 15 | * Test that we can trade off accuracy for performance 16 | */ 17 | public class MatrixProfileAccuracyTest { 18 | 19 | private MatrixProfile serialMP = new MatrixProfile(false); 20 | private MatrixProfile concurrentMP = new MatrixProfile(true); 21 | 22 | /** Set this to true if you want to automatically update the results files */ 23 | private static final boolean UPDATE_RESULTS = false; 24 | private static final int STEPS_IN_DAY = 287; 25 | 26 | 27 | @Test 28 | public void testMatrixProfileSelfJoinStampWindow8() { 29 | verifyResult("repeat_4", 30 | "repeat_4_profile_pair_0_1.exp", 31 | 8, 0.1, false); 32 | } 33 | 34 | // Originally ran in 3m 40s on 4 core laptop before making it multi-threaded. - only 21s when 10% of steps used 35 | @Test 36 | public void testMatrixProfileSelfJoinStamp_ArtDailyFlatMiddle() { 37 | verifyResult("numenta_art_daily_flatmiddle", 38 | "numenta_art_daily_flatmiddle_profile_pair_0_1.exp", 39 | STEPS_IN_DAY, 0.1, false); 40 | } 41 | 42 | // Originally ran in 2m 40s on 4 core laptop before making it multi-threaded - only 23s when 10% of steps used 43 | @Test 44 | public void testMatrixProfileSelfJoinStamp_ArtDailyJumpsDown() { 45 | verifyResult("numenta_art_daily_jumps_down", 46 | "numenta_art_daily_jumps_down_profile_pair_0_1.exp", 47 | STEPS_IN_DAY, 0.1, false); 48 | } 49 | 50 | 51 | // ran in 4s 52 | @Test 53 | public void testMatrixProfileSelfJoinStampWindow8_concurrent() { 54 | verifyResult("repeat_4", 55 | "repeat_4_profile_pair_0_1.exp", 56 | 8, 0.1,true); 57 | } 58 | 59 | // Ran in 1m 34s on 4 core laptop after making it multi-threaded, but took 10s using only 10% 60 | @Test 61 | public void testMatrixProfileSelfJoinStamp_ArtDailyFlatMiddle_concurrent() { 62 | verifyResult("numenta_art_daily_flatmiddle", 63 | "numenta_art_daily_flatmiddle_profile_pair_0_1.exp", 64 | STEPS_IN_DAY, 0.1, true); 65 | } 66 | 67 | // Ran in 56s on 4 core laptop after making it multi-threaded, but took only 15 seconds using only 10%; 35s at 20% 68 | @Test 69 | public void testMatrixProfileSelfJoinStamp_ArtDailyJumpsDown_concurrent() { 70 | verifyResult("numenta_art_daily_jumps_down", 71 | "numenta_art_daily_jumps_down_profile_pair_0_1.exp", 72 | STEPS_IN_DAY, 0.1, true); 73 | } 74 | 75 | private void verifyResult(String seriesFile, String expResultFile, 76 | int window, double accuracy, boolean concurrent) { 77 | INDArray series = FileUtil.readIndArray(DATA_DIR + seriesFile); 78 | System.out.println("The series under test has " + series.length() + 79 | " points. Concurrency = " + concurrent + " accuracy = " + accuracy); 80 | 81 | // the length of these arrays is length of the series - window + 1 82 | Pair expectedResultWhenSelfJoin = 83 | FileUtil.readIndArrayPair(RESULTS_DIR + expResultFile); 84 | 85 | Pair pair = 86 | concurrent ? concurrentMP.stamp(series, window, accuracy) : serialMP.stamp(series, window, accuracy); 87 | 88 | // Uncomment this to export results to excel. Plotting in excel can be very instructive. 89 | CsvExport.printToCsvFile(series, pair, "acc_" + seriesFile + ".xls"); 90 | //CsvExport.printPairToFile(pair, "acc_" + seriesFile + ".xls"); 91 | 92 | if (UPDATE_RESULTS) { 93 | CsvExport.printPairToFile(pair, RESULTS_DIR + expResultFile); 94 | } else { 95 | assertEquals(expectedResultWhenSelfJoin.toString(), pair.toString()); 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/main/java/io/github/ensozos/core/MPdistance.java: -------------------------------------------------------------------------------- 1 | package io.github.ensozos.core; 2 | 3 | import io.github.ensozos.utils.CustomOperations; 4 | import org.nd4j.linalg.api.ndarray.INDArray; 5 | import org.nd4j.linalg.factory.Nd4j; 6 | import org.nd4j.linalg.indexing.NDArrayIndex; 7 | 8 | public class MPdistance { 9 | 10 | private double threshold; 11 | private Mass massAlgo; 12 | 13 | /** 14 | * Matrix Profile distance introduced by Shaghayegh Gharghabi, Shima Imani, Anthony Bagnall, 15 | * Amirali Darvishzadeh, Eamonn Keogh at "An Ultra-Fast Time Series Distance Measure to 16 | * allow Data Mining in more Complex Real-World Deployments" 17 | */ 18 | public MPdistance() { 19 | this.threshold = 0.05; 20 | massAlgo = new Mass(); 21 | } 22 | 23 | /** 24 | * Matrix Profile distance introduced by Shaghayegh Gharghabi, Shima Imani, Anthony Bagnall, 25 | * Amirali Darvishzadeh, Eamonn Keogh at "An Ultra-Fast Time Series Distance Measure to 26 | * allow Data Mining in more Complex Real-World Deployments" 27 | * @param threshold some small fraction of the data length (like 0.05 for example) 28 | */ 29 | public MPdistance(int threshold) { 30 | this.threshold = threshold; 31 | massAlgo = new Mass(); 32 | } 33 | 34 | /** 35 | * Calculates MP distance given two time series and a subsequence length. In case 36 | * of different size of time series it works as query by content. This method is based 37 | * on Speeding up MPdist Search section of the paper. 38 | *

39 | * Note: current version is not fully optimized (see centeredMovingMinimum). 40 | * 41 | * @param ts1 first time series 42 | * @param ts2 second time series 43 | * @param subLen subsequence length 44 | * @return MP distance measure 45 | */ 46 | public INDArray getMPdistance(INDArray ts1, INDArray ts2, int subLen) { 47 | if (ts1.length() < ts2.length()) { 48 | INDArray temp = ts1; 49 | ts1 = ts2; 50 | ts2 = temp; 51 | } 52 | 53 | INDArray massDistMatrix = getMassDistMatrix(ts1, ts2, subLen); 54 | int massDistMatrixRow = (int) massDistMatrix.shape()[0]; 55 | int massDistMatrixCol = (int) massDistMatrix.shape()[1]; 56 | 57 | INDArray massDistSlideMin = Nd4j.zeros(massDistMatrixRow, massDistMatrixCol); 58 | INDArray allRightHistogram = massDistMatrix.amin(0); 59 | for (int i = 0; i < massDistMatrixRow; i++) { 60 | massDistSlideMin.putRow(i, CustomOperations.centeredMovingMinimum(massDistMatrix.getRow(i), massDistMatrixRow)); 61 | } 62 | 63 | int MPdistLength = (int) (ts1.length() - ts2.length() + 1); 64 | int rightHistLength = (int) (ts2.length() - subLen + 1); 65 | 66 | INDArray MPdistArray = Nd4j.zeros(MPdistLength); 67 | INDArray leftHist = Nd4j.zeros(rightHistLength); 68 | 69 | INDArray rightHist; 70 | for (int i = 0; i < MPdistLength; i++) { 71 | rightHist = allRightHistogram.get(NDArrayIndex.interval(i, rightHistLength + i)); 72 | leftHist.putRow(0, massDistSlideMin.getColumn((long) (i + Math.floor(massDistMatrixRow / 2)))); 73 | 74 | MPdistArray.put(0, i, calcMPdist(Nd4j.concat(1, leftHist, rightHist), (int) (2 * ts2.length()))); 75 | } 76 | 77 | 78 | return MPdistArray; 79 | } 80 | 81 | /** 82 | * Basic algorithm that finds MP distance given the matrix profile. 83 | * 84 | * @param matrixProfile matrix profile of two time series 85 | * @param dataLength length of the data 86 | * @return mp distance 87 | */ 88 | private double calcMPdist(INDArray matrixProfile, int dataLength) { 89 | int k = (int) Math.ceil(threshold * dataLength); 90 | 91 | INDArray mpSorted = Nd4j.sort(matrixProfile, true); 92 | Nd4j.clearNans(mpSorted); 93 | 94 | if (mpSorted.length() == 0) { 95 | return Double.POSITIVE_INFINITY; 96 | } else if (mpSorted.length() >= k) { 97 | return mpSorted.getDouble(0, k); 98 | } else { 99 | return mpSorted.getDouble(0, mpSorted.length() - 1); 100 | } 101 | 102 | } 103 | 104 | /** 105 | * Calculates distance matrix with MASS V2.0 given 106 | * two time series. 107 | * 108 | * @param ts1 first time series 109 | * @param ts2 second time series 110 | * @param sublen subsequence length 111 | * @return MASS distance matrix 112 | */ 113 | private INDArray getMassDistMatrix(INDArray ts1, INDArray ts2, int sublen) { 114 | int numberOfSubSeq = (int) (ts2.length() - sublen + 1); 115 | 116 | INDArray massDist = Nd4j.zeros(numberOfSubSeq, ts1.length() - sublen + 1); 117 | for (int i = 0; i < numberOfSubSeq; i++) { 118 | massDist.putRow(i, massAlgo.mass(ts1, ts2.get(NDArrayIndex.interval(i, i + sublen)))); 119 | } 120 | 121 | return massDist; 122 | } 123 | 124 | } 125 | -------------------------------------------------------------------------------- /src/main/java/io/github/ensozos/core/MatrixProfileCalculator.java: -------------------------------------------------------------------------------- 1 | package io.github.ensozos.core; 2 | 3 | import io.github.ensozos.core.order.Order; 4 | import io.github.ensozos.utils.CustomOperations; 5 | import javafx.util.Pair; 6 | import org.nd4j.linalg.api.ndarray.INDArray; 7 | import org.nd4j.linalg.factory.Nd4j; 8 | import org.nd4j.linalg.indexing.INDArrayIndex; 9 | import org.nd4j.linalg.indexing.NDArrayIndex; 10 | import java.util.concurrent.*; 11 | 12 | 13 | /** 14 | * Calculates the matrix profile given parameters either serially or concurrently. 15 | */ 16 | class MatrixProfileCalculator { 17 | 18 | /** The maximum number of minutes to wait for processing to complete before forcefully terminating */ 19 | private static final int MAX_MINUTES = 60; 20 | 21 | private INDArray matrixProfile; 22 | private INDArray matrixProfileIndex; 23 | private int n; 24 | 25 | private INDArray timeSeriesA; 26 | private INDArray timeSeriesB; 27 | 28 | private int window; 29 | private Order order; 30 | private DistanceProfile dp; 31 | private boolean trivialMatch; 32 | 33 | 34 | /** 35 | * Algorithm that computes a vector(matrix profile) of distances between each subsequence and its nearest neighbor 36 | * in O(n^2 logn) time complexity and O(n) space complexity. 37 | */ 38 | MatrixProfileCalculator(INDArray timeSeriesA, int window, Order order, DistanceProfile dp, 39 | INDArray timeSeriesB, boolean trivialMatch) { 40 | n = (int) timeSeriesB.length(); 41 | matrixProfile = Nd4j.valueArrayOf(new int[]{1, n - window + 1}, Double.POSITIVE_INFINITY); 42 | matrixProfileIndex = Nd4j.valueArrayOf(new int[]{1, n - window + 1}, Double.NaN); 43 | 44 | this.timeSeriesA = timeSeriesA; 45 | this.timeSeriesB = timeSeriesB; 46 | this.window = window; 47 | this.order = order; 48 | this.dp = dp; 49 | this.trivialMatch = trivialMatch; 50 | } 51 | 52 | /** 53 | * @return a Pair with profile matrix as key and profile index as value. 54 | */ 55 | Pair calculateSerially() { 56 | 57 | int index = order.getNext(); 58 | 59 | while (index != -1) { 60 | new MPRunnable(index).run(); 61 | index = order.getNext(); 62 | } 63 | 64 | return new Pair<>(matrixProfile, matrixProfileIndex); 65 | } 66 | 67 | /** 68 | * Use fixed thread pool to execute concurrently using available processors. 69 | * @return a Pair with profile matrix as key and profile index as value. 70 | */ 71 | Pair calculateConcurrently() { 72 | 73 | int numProcs = Runtime.getRuntime().availableProcessors(); 74 | ExecutorService executor = Executors.newFixedThreadPool(numProcs); 75 | 76 | int index = order.getNext(); 77 | 78 | while (index != -1) { 79 | executor.execute(new MPRunnable(index)); 80 | index = order.getNext(); 81 | } 82 | shutdown(executor); 83 | 84 | return new Pair<>(matrixProfile, matrixProfileIndex); 85 | } 86 | 87 | /** 88 | * Gracefully shuts down the executor service. 89 | * If it does not finish in a reasonable time, it is forcefully terminated. 90 | * @param executor the executor service to shutdown 91 | */ 92 | private void shutdown(ExecutorService executor) { 93 | try { 94 | //System.out.println("attempting to shutdown executor"); 95 | executor.shutdown(); 96 | executor.awaitTermination(MAX_MINUTES, TimeUnit.MINUTES); 97 | } 98 | catch (InterruptedException e) { 99 | System.err.println("tasks interrupted"); 100 | } 101 | finally { 102 | if (!executor.isTerminated()) { 103 | System.err.println("cancel non-finished tasks"); 104 | } 105 | executor.shutdownNow(); 106 | System.out.println("shutdown finished"); 107 | } 108 | } 109 | 110 | 111 | private class MPRunnable implements Runnable{ 112 | 113 | int index; 114 | 115 | MPRunnable(int i){ 116 | this.index = i; 117 | } 118 | 119 | public void run(){ 120 | INDArray distanceProfile = dp.getDistanceProfile(timeSeriesA, timeSeriesB, index, window); 121 | INDArray distanceProfileIndex = dp.getDistanceProfileIndex(n, index, window); 122 | 123 | if (trivialMatch) { 124 | INDArrayIndex[] indices = new INDArrayIndex[]{ 125 | NDArrayIndex.interval(Math.max(0, index - window / 2), Math.min(index + window / 2 + 1, n)) 126 | }; 127 | distanceProfile.put(indices, Double.POSITIVE_INFINITY); 128 | } 129 | 130 | updateProfile(distanceProfile, distanceProfileIndex); 131 | } 132 | } 133 | 134 | private synchronized void updateProfile(INDArray distanceProfile, INDArray distanceProfileIndex) { 135 | INDArray uptIndices = CustomOperations.lessThan(distanceProfile, matrixProfile); 136 | //System.out.println("Now updating these indices " + Arrays.toString(uptIndices.data().asInt())); 137 | 138 | // if the indices array are zero length keep the old matrixProfileIndex 139 | if (uptIndices.shape()[1] > 0) 140 | matrixProfileIndex.put(uptIndices, distanceProfileIndex.get(uptIndices)); 141 | 142 | matrixProfile = CustomOperations.elementWiseMin(matrixProfile, distanceProfile); 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /src/test/java/io/github/ensozos/core/MatrixProfilePerformanceTest.java: -------------------------------------------------------------------------------- 1 | package io.github.ensozos.core; 2 | 3 | import io.github.ensozos.testsupport.CsvExport; 4 | import io.github.ensozos.testsupport.FileUtil; 5 | import javafx.util.Pair; 6 | import org.junit.Test; 7 | import org.nd4j.linalg.api.ndarray.INDArray; 8 | import static io.github.ensozos.testsupport.FileUtil.*; 9 | import static org.junit.Assert.assertEquals; 10 | 11 | 12 | public class MatrixProfilePerformanceTest { 13 | 14 | private MatrixProfile serialMP = new MatrixProfile(false); 15 | private MatrixProfile concurrentMP = new MatrixProfile(true); 16 | 17 | /** Set this to true if you want to automatically update the results files */ 18 | private static final boolean UPDATE_RESULTS = false; 19 | private static final int STEPS_IN_DAY = 287; 20 | 21 | 22 | 23 | @Test 24 | public void testMatrixProfileSelfJoinStmpWindow8() { 25 | verifyResult("repeat_4", 26 | "repeat_4_profile_pair.exp", 27 | 8, false); 28 | } 29 | 30 | // Ran in 3m 40s on 4 core laptop before making it multi-threaded. 31 | @Test 32 | public void testMatrixProfileSelfJoinStmp_ArtDailyFlatMiddle() { 33 | verifyResult("numenta_art_daily_flatmiddle", 34 | "numenta_art_daily_flatmiddle_profile_pair.exp", 35 | STEPS_IN_DAY, false); 36 | } 37 | 38 | // Ran in 2m 40s on 4 core laptop before making it multi-threaded. 39 | @Test 40 | public void testMatrixProfileSelfJoinStmp_ArtDailyJumpsDown() { 41 | verifyResult("numenta_art_daily_jumps_down", 42 | "numenta_art_daily_jumps_down_profile_pair.exp", 43 | STEPS_IN_DAY, false); 44 | } 45 | 46 | /* Commenting some tests to reduce runtime. 47 | * Also noticed that some of these tests fail when run from command line, but not in intellij. 48 | // Ran in 6m 43s on 4 core laptop before making it multi-threaded. 49 | @Test 50 | public void testMatrixProfileSelfJoinStmp_ArtIncreaseSpikeDensity() { 51 | verifyResult("numenta_art_increase_spike_density", 52 | "numenta_art_increase_spike_density_profile_pair.exp", 53 | STEPS_IN_DAY, false); 54 | } 55 | 56 | // Ran in 3m 1s on 4 core laptop before making it multi-threaded. 57 | @Test 58 | public void testMatrixProfileSelfJoinStmp_ArtLoadBalancerSpikes() { 59 | verifyResult("numenta_art_load_balancer_spikes", 60 | "numenta_art_load_balancer_spikes_profile_pair.exp", 61 | STEPS_IN_DAY, false); 62 | }*/ 63 | 64 | 65 | @Test 66 | public void testMatrixProfileSelfJoinStmpWindow8_concurrent() { 67 | verifyResult("repeat_4", 68 | "repeat_4_profile_pair.exp", 69 | 8, true); 70 | } 71 | 72 | // Ran in 1m 34s on 4 core laptop after making it multi-threaded. 73 | @Test 74 | public void testMatrixProfileSelfJoinStmp_ArtDailyFlatMiddle_concurrent() { 75 | verifyResult("numenta_art_daily_flatmiddle", 76 | "numenta_art_daily_flatmiddle_profile_pair.exp", 77 | STEPS_IN_DAY, true); 78 | } 79 | 80 | // Ran in 56s on 4 core laptop after making it multi-threaded. 81 | @Test 82 | public void testMatrixProfileSelfJoinStmp_ArtDailyJumpsDown_concurrent() { 83 | verifyResult("numenta_art_daily_jumps_down", 84 | "numenta_art_daily_jumps_down_profile_pair.exp", 85 | STEPS_IN_DAY, true); 86 | } 87 | 88 | /** 89 | // Ran in 4m 37s on 4 core laptop before making it multi-threaded. 90 | @Test 91 | public void testMatrixProfileSelfJoinStmp_ArtIncreaseSpikeDensity_concurrent() { 92 | verifyResult("numenta_art_increase_spike_density", 93 | "numenta_art_increase_spike_density_profile_pair.exp", 94 | 80, true); 95 | } 96 | 97 | // Ran in 1m 6s on 4 core laptop before making it multi-threaded. 98 | @Test 99 | public void testMatrixProfileSelfJoinStmp_ArtLoadBalancerSpikes_concurrent() { 100 | verifyResult("numenta_art_load_balancer_spikes", 101 | "numenta_art_load_balancer_spikes_profile_pair.exp", 102 | 80, true); 103 | }*/ 104 | 105 | // The width of 190 is roughly the period of one of the repeating patterns in the data. 106 | // This data comes from a electronic vehicle simulation. 107 | @Test 108 | public void testMatrixProfileSelfJoinStmp_BusSignal_concurrent() { 109 | verifyResult("bus_signal", 110 | "bus_signal_pair.exp", 111 | 190, true); 112 | } 113 | 114 | private void verifyResult(String seriesFile, String expResultFile, int window, boolean concurrent) { 115 | INDArray series = FileUtil.readIndArray(DATA_DIR + seriesFile); 116 | System.out.println("The series under test has " + series.length() + " points. Concurrency = " + concurrent); 117 | 118 | // the length of these arrays is length of the series - window + 1 119 | Pair expectedResultWhenSelfJoin = 120 | FileUtil.readIndArrayPair(RESULTS_DIR + expResultFile); 121 | 122 | Pair pair = 123 | concurrent ? concurrentMP.stmp(series, window) : serialMP.stmp(series, window); 124 | 125 | // Uncomment this to export results to excel. Plotting in excel can be very instructive. 126 | CsvExport.printToCsvFile(series, pair, "perf_" + seriesFile + ".xls"); 127 | //CsvExport.printPairToFile(pair, "perf_" + seriesFile + ".xls"); 128 | 129 | if (UPDATE_RESULTS) { 130 | CsvExport.printPairToFile(pair, RESULTS_DIR + expResultFile); 131 | } else { 132 | assertEquals(expectedResultWhenSelfJoin.toString(), pair.toString()); 133 | } 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /src/main/java/io/github/ensozos/core/Mass.java: -------------------------------------------------------------------------------- 1 | package io.github.ensozos.core; 2 | 3 | import io.github.ensozos.utils.CustomOperations; 4 | import org.jtransforms.fft.DoubleFFT_1D; 5 | import org.nd4j.linalg.api.ndarray.INDArray; 6 | import org.nd4j.linalg.factory.Nd4j; 7 | import org.nd4j.linalg.indexing.NDArrayIndex; 8 | import org.nd4j.linalg.indexing.conditions.Conditions; 9 | import org.nd4j.linalg.indexing.BooleanIndexing; 10 | import static org.nd4j.linalg.ops.transforms.Transforms.pow; 11 | import static org.nd4j.linalg.ops.transforms.Transforms.sqrt; 12 | 13 | 14 | public class Mass { 15 | 16 | /** small epsilon value used to avoid dividing by 0 */ 17 | private static final double EPS = 1e-40; 18 | 19 | public Mass() { 20 | } 21 | 22 | /** 23 | * Mueen's algorithm for similarity search (MASS 2.0). Mass uses a convolution based method 24 | * to calculate sliding dot products in O(n logn). In addition MASS 2.0 use half convolution to compute only 25 | * the necessary half. Fast fourier transformation is used as subroutine. The main computation is 26 | * 27 | * dots = ifft( fft(ts) * fft(query)) 28 | * 29 | * www.cs.unm.edu/~mueen/FastestSimilaritySearch.html 30 | * 31 | * @param ts time series 32 | * @param query time series 33 | * @return INDArray with MASS result 34 | */ 35 | public INDArray mass(INDArray ts, INDArray query) { 36 | query = zNormalize(query); 37 | 38 | int m = (int) query.length(); 39 | int n = (int) ts.length(); 40 | 41 | INDArray stdv = movStd(ts, m); 42 | 43 | //padding query (note nd4j pad method is only for two dimension) 44 | 45 | query = Nd4j.reverse(query); 46 | if (n - m > 0) 47 | query = CustomOperations.singlePad(query, n - m); 48 | 49 | Complex[] complexTs = new Complex[n]; 50 | Complex[] complexQuery = new Complex[n]; 51 | 52 | for (int i = 0; i < n; i++) { 53 | complexTs[i] = new Complex(ts.getDouble(i), 0); 54 | complexQuery[i] = new Complex(query.getDouble(i), 0); 55 | } 56 | 57 | complexTs = fft1D(complexTs); 58 | complexQuery = fft1D(complexQuery); 59 | 60 | 61 | //multiply two fft results 62 | Complex[] complexDot = new Complex[n]; 63 | for (int i = 0; i < n; i++) { 64 | complexDot[i] = complexTs[i].times(complexQuery[i]); 65 | } 66 | 67 | // inverse fft for dot computation 68 | complexDot = ifft1D(complexDot); 69 | double[] realDot = new double[complexDot.length]; 70 | 71 | for (int i = 0; i < complexDot.length; i++) { 72 | realDot[i] = complexDot[i].re; 73 | } 74 | 75 | INDArray dot = Nd4j.create(realDot, new int[]{1, realDot.length}); 76 | INDArray divRes = dot.get(NDArrayIndex.interval(m - 1, dot.length())).div(stdv); 77 | INDArray res = divRes.neg().add(m).mul(2); 78 | BooleanIndexing.replaceWhere(res, EPS, Conditions.lessThanOrEqual(EPS)); 79 | return sqrt(res); 80 | } 81 | 82 | 83 | /** 84 | * z-normalization of time series with bias corrected param 85 | * to false. 86 | * 87 | * @param ts time series 88 | * @return INDArray with z normalized time series 89 | */ 90 | private INDArray zNormalize(INDArray ts) { 91 | ts = ts.sub(ts.mean()); 92 | double stdev = ts.stdNumber(false).doubleValue(); 93 | 94 | if (stdev != 0.0) 95 | ts = ts.div(stdev); 96 | 97 | return ts; 98 | } 99 | 100 | /** 101 | * just in time z-normalization. In one pass calculate cumulative sums of ts 102 | * and ts^2 and store. Subtract two cumulative sums to obtain the sum over any 103 | * window. Use the sums to calculate standard deviations of all windows in 104 | * linear time. Calculated in one linear scan. 105 | * 106 | * @param ts the time series to calculate standard deviation 107 | * @param w window 108 | * @return INDArray representing standard deviation of moving window 109 | */ 110 | private INDArray movStd(INDArray ts, int w) { 111 | if (w < 1) 112 | throw new NumberFormatException(); 113 | 114 | INDArray cs = CustomOperations.append(Nd4j.create(new int[]{0}, new int[]{1, 1}), ts.cumsum(0)); 115 | INDArray cs2 = CustomOperations.append(Nd4j.create(new int[]{0}, new int[]{1, 1}), pow(ts, 2).cumsum(0)); 116 | 117 | INDArray wSum = 118 | cs.get(NDArrayIndex.interval(w, cs.length())).sub(cs.get(NDArrayIndex.interval(0, cs.length() - w))); 119 | INDArray wSum2 = 120 | cs2.get(NDArrayIndex.interval(w, cs2.length())).sub(cs2.get(NDArrayIndex.interval(0, cs2.length() - w))); 121 | 122 | INDArray subResult = wSum2.div(w).sub(pow(wSum.div(w),2)); 123 | BooleanIndexing.replaceWhere(subResult, EPS, Conditions.lessThanOrEqual(EPS)); 124 | return sqrt(subResult); 125 | } 126 | 127 | /** 128 | * wrapper method for JTransform's fast fourier transform. 129 | * 130 | * @param signal the series to find fft of. 131 | * @return Complex array of fft 132 | */ 133 | private Complex[] fft1D(Complex[] signal) { 134 | int n = signal.length; 135 | Complex[] fourier = new Complex[n]; 136 | 137 | double[] coeff = new double[2 * n]; 138 | int i = 0; 139 | for (Complex c : signal) { 140 | coeff[i++] = c.getReal(); 141 | coeff[i++] = c.getImaginary(); 142 | } 143 | 144 | DoubleFFT_1D fft = new DoubleFFT_1D(n); 145 | fft.complexForward(coeff); 146 | 147 | for (i = 0; i < 2 * n; i += 2) { 148 | Complex c = new Complex(coeff[i], coeff[i + 1]); 149 | fourier[i / 2] = c; 150 | } 151 | return fourier; 152 | } 153 | 154 | /** 155 | * wrapper method for JTransform's inverse fast fourier 156 | * transform. 157 | * 158 | * @param fourier 159 | * @return Complex array of ifft 160 | */ 161 | private Complex[] ifft1D(Complex[] fourier) { 162 | int n = fourier.length; 163 | double s = (1.0 / (double) n); 164 | 165 | Complex[] signal = new Complex[n]; 166 | double[] coeff = new double[2 * n]; 167 | 168 | int i = 0; 169 | for (Complex c : fourier) { 170 | coeff[i++] = c.getReal(); 171 | coeff[i++] = c.getImaginary(); 172 | } 173 | 174 | DoubleFFT_1D fft = new DoubleFFT_1D(n); 175 | fft.complexInverse(coeff, false); 176 | 177 | for (i = 0; i < 2 * n; i += 2) { 178 | Complex c = new Complex(s * coeff[i], s * coeff[i + 1]); 179 | signal[i / 2] = c; 180 | } 181 | return signal; 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Matrix Profile Library 2 | A Java library for Matrix Profile 3 | 4 | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.github.ensozos/matrix-profile/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.github.ensozos/matrix-profile) 5 | 6 | 7 | Overview 8 | ------------------------- 9 |

10 | matrix profile exmple 11 |

12 | 13 | The Matrix Profile, has the potential to revolutionize time series data mining because 14 | of its generality, versatility, simplicity and scalability. In particular it has implications 15 | for time series motif discovery, time series joins, shapelet discovery (classification), 16 | density estimation, semantic segmentation, visualization, rule discovery, clustering etc 17 | 18 | The advantages of using the Matrix Profile (over hashing, indexing, brute forcing a dimensionality reduced representation etc.) for most time series data mining tasks include: 19 | 20 | - It is **exac**t: For motif discovery, discord discovery, time series joins etc., the Matrix Profile based methods provide no false positives or false dismissals. 21 | - It is **simple and parameter-free**: In contrast, the more general spatial access method algorithms typically require building and tuning spatial access methods and/or hash function. 22 | - It is **space efficien**t: Matrix Profile construction algorithms requires an inconsequential space overhead, just linear in the time series length with a small constant factor, allowing massive datasets to be processed in main memory. 23 | - It allows **anytime algorithms**: While our exact algorithms are extremely scalable, for extremely large datasets we can compute the Matrix Profile in an anytime fashion, allowing ultra-fast approximate solutions. 24 | - It is incrementally **maintainable**: Having computed the Matrix Profile for a dataset, we can incrementally update it very efficiently. In many domains this means we can effectively maintain exact joins/motifs/discords on streaming data forever. 25 | - It does **not require the user to set similarity/distance thresholds**: For time series joins, the Matrix Profile provides full joins, eliminating the need to specify a similarity threshold, which is an unintuitive task for time series. 26 | - It can **leverage hardware**: Matrix Profile construction is embarrassingly parallelizable, both on multicore processors and in distributed systems. 27 | - It has **time complexity that is constant in subsequence length**: This is a very unusual and desirable property; all known time series join/motif/discord algorithms scale poorly as the subsequence length grows. In contrast, we have shown time series joins/motifs with subsequences lengths up to 100,000, at least two orders of magnitude longer than any other work we are aware of. 28 | - It can be **constructed in deterministic time**: All join/motif/discord algorithms we are aware of can radically different times to finish on two (even slightly) different datasets. In contrast, given only the length of the time series, we can precisely predict in advance how long it will take to compute the Matrix Profile 29 | - It can handle **missing data**: Even in the presence of missing data, we can provide answers which are guaranteed to have no false negatives. 30 | 31 | For more information about matrix profile check out [The UCR Matrix Profile Page](http://www.cs.ucr.edu/~eamonn/MatrixProfile.html) 32 | 33 | In version 0.0.2 we implemented MPdist measure. The useful properties of the MPdist include: 34 | - Ability to compare time series of different lengths. 35 | - Robust to spikes, dropouts, wandering baseline, missing values, and other issues that are common 36 | outside of benchmark dataset. 37 | - Invariance to amplitude and offset offered by DTW and Euclidean distance as well as additional invariances, 38 | including phase invariance, order invariance, liner trend invariance, and stutter invariance. 39 | - Allows scalability 40 | 41 | We followed the fast MPdist algorithm that can be found in section 42 | "Speeding up MPdist Search" in the official paper. 43 | 44 | Usage 45 | ------------------------- 46 | - MPdist (query by content) 47 | - STMP (two time series) 48 | - STMP (self join) 49 | - STAMP (with two time series) 50 | - STAMP (self join) 51 | - Misc: 52 | * MASS v2.0 53 | * Fast moving SD 54 | * Fast moving average 55 | 56 | Note: We are using ND4j as time series representation. You can find more information about ND4j [here](https://deeplearning4j.org/docs/latest/nd4j-overview) 57 | 58 | Installation 59 | ------------------------- 60 | You can pull Matrix Profile library from the central maven repository, just add to **pom.xml** file: 61 | ```xml 62 | 63 | io.github.ensozos 64 | matrix-profile 65 | 0.0.3 66 | 67 | ``` 68 | 69 | For gradle users add this to **build.gradle**: 70 | 71 | ```xml 72 | compile 'io.github.ensozos:matrix-profile:0.0.3' 73 | ``` 74 | 75 | Example 76 | -------------------------- 77 | The user needs to create a MatrixProfile profile object and pass the time series (INDArrays) as parameters: 78 | 79 | ```Java 80 | MatrixProfile matrixProfile = new MatrixProfile(); 81 | 82 | int window = 4; 83 | INDArray target = Nd4j.create(new double[]{0.0, 6.0, -1.0, 2.0, 3.0, 1.0, 4.0}, new int[]{1, 7}); 84 | INDArray query = Nd4j.create(new double[]{1.0, 2.0, 0.0, 0.0, -1}, new int[]{1, 5}); 85 | 86 | matrixProfile.stamp(target, query, window); 87 | ``` 88 | 89 | For Matrix Profile distance you need to create MPdistance object: 90 | 91 | ```Java 92 | MPdistance mpDist = new MPdistance(); 93 | 94 | int window = ...; 95 | INDArray target = Nd4j.create(...); 96 | INDArray query = Nd4j.create(...); 97 | 98 | mpDist.getMPdistance(target, query, window); 99 | ``` 100 | 101 | ## Other projects with Matrix Profile 102 | 103 | - R: 104 | - Python: 105 | - Python: 106 | - Python: 107 | - CUDA: 108 | 109 | License 110 | -------------------------- 111 | Distributed under the MIT license. See LICENSE for more information. 112 | 113 | 114 | Paper Citation 115 | ------------------------- 116 | 117 | - Yeh, Chin-Chia Michael & Zhu, Yan & Ulanova, Liudmila & Begum, Nurjahan & Ding, Yifei & Dau, Anh & Silva, Diego & Mueen, Abdullah & Keogh, Eamonn. (2016). Matrix Profile I: All Pairs Similarity Joins for Time Series: A Unifying View That Includes Motifs, Discords and Shapelets. 1317-1322. 10.1109/ICDM.2016.0179. 118 | 119 | - Abdullah Mueen, Yan Zhu, Michael Yeh, Kaveh Kamgar, Krishnamurthy Viswanathan, Chetan Kumar Gupta and Eamonn Keogh (2015), The Fastest Similarity Search Algorithm for Time Series Subsequences under Euclidean Distance 120 | 121 | - Matrix Profile XII: MPdist: A Novel Time Series Distance Measure to Allow Data Mining in More Challenging Scenarios. Shaghayegh Gharghabi, Shima Imani, Anthony Bagnall, Amirali Darvishzadeh, Eamonn Keogh. ICDM 2018. 122 | -------------------------------------------------------------------------------- /src/main/java/io/github/ensozos/core/MatrixProfile.java: -------------------------------------------------------------------------------- 1 | package io.github.ensozos.core; 2 | 3 | import io.github.ensozos.utils.CustomOperations; 4 | import io.github.ensozos.core.distance.DistanceProfileFactory; 5 | import io.github.ensozos.core.order.LinearOrder; 6 | import io.github.ensozos.core.order.Order; 7 | import io.github.ensozos.core.order.RandomOrder; 8 | import javafx.util.Pair; 9 | import org.nd4j.linalg.api.ndarray.INDArray; 10 | import java.util.Random; 11 | 12 | 13 | /** 14 | * Class for matrix profile computation based on Yeh, Chin-Chia Michael Zhu, Yan Ulanova, Liudmila Begum, 15 | * Nurjahan Ding, Yifei Dau, Anh Silva, Diego Mueen, Abdullah Keogh, Eamonn. (2016). 16 | * Matrix Profile I: All Pairs Similarity Joins for Time Series: A Unifying View That Includes Motifs, 17 | * Discords and Shapelets. 1317-1322. 10.1109/ICDM.2016.0179. 18 | */ 19 | public class MatrixProfile { 20 | 21 | private DistanceProfileFactory distanceProfileFactory; 22 | private boolean isConcurrent; 23 | 24 | 25 | public MatrixProfile() { 26 | this(false); 27 | } 28 | 29 | public MatrixProfile(boolean useConcurrency) { 30 | distanceProfileFactory = new DistanceProfileFactory(); 31 | isConcurrent = useConcurrency; 32 | } 33 | 34 | /** 35 | * Scalable time series matrix profile algorithm. Computes a vector (matrix profile) 36 | * of distances between each subsequence and its nearest neighbor in 37 | * O(n^2 logn) time complexity and O(n) space complexity. 38 | * 39 | * @param target target time series 40 | * @param query query time series 41 | * @param window size of window 42 | * @return a Pair with profile matrix as key and profile index as value. 43 | */ 44 | public Pair stmp(INDArray target, INDArray query, int window) { 45 | DistanceProfile stamp = distanceProfileFactory.getDistanceProfile(DistanceProfileFactory.STAMP); 46 | 47 | int target_shape = (int) target.shape()[1]; 48 | int query_shape = (int) query.shape()[1]; 49 | if (target_shape >= query_shape) 50 | return matrixProfile(query, window, 51 | new LinearOrder((int) (query.length() - window + 1)), stamp, target, false); 52 | 53 | INDArray new_target = CustomOperations.singlePad(target, query_shape - target_shape); 54 | 55 | return matrixProfile(query, window, 56 | new LinearOrder((int) (new_target.length() - window + 1)), stamp, new_target, false); 57 | } 58 | 59 | /** 60 | * Scalable time series matrix profile algorithm (self join). Computes a vector(matrix profile) 61 | * of distances between each subsequence and its nearest neighbor in 62 | * O(n^2 logn) time complexity and O(n) space complexity. In case of self join we take into 63 | * account trivial match. To avoid trivial matches we find the first match then we set an exclusion 64 | * zone around the best match. The size of exclusion zone in 1/2 of the query size. 65 | * 66 | * @param target target time series 67 | * @param window size of window 68 | * @return a Pair with profile matrix as key and profile index as value. 69 | */ 70 | public Pair stmp(INDArray target, int window) { 71 | DistanceProfile stamp = distanceProfileFactory.getDistanceProfile(DistanceProfileFactory.STAMP); 72 | 73 | if (target.shape()[1] <= window) 74 | throw new IllegalArgumentException("The length of the target (" + 75 | target.shape()[1] + ") must be > the window width (" + window + ")"); 76 | 77 | return matrixProfile(target, window, 78 | new LinearOrder((int) (target.length() - window + 1)), stamp, target, true); 79 | } 80 | 81 | /** 82 | * Scalable time series anytime matrix profile. Computes a vector(matrix profile) 83 | * of distances between each subsequence and its nearest neighbor in O(n^2 logn) time 84 | * complexity and O(n) space complexity. Each distance profile is independent of other 85 | * distance profiles. The order in which we compute them is random. The random ordering 86 | * allows interrupt resume (not implemented yet) operation anytime. 87 | * 88 | * @param target target time series 89 | * @param query query time series 90 | * @param window size of window 91 | * @param accuracy a value in (0, 1]. Allows trading off accuracy for faster performance. 92 | * A value of 1 means that it will be slow but perfectly accurate. 93 | * @return a Pair with profile matrix as key and profile index as value. 94 | */ 95 | public Pair stamp(INDArray target, INDArray query, int window, double accuracy) { 96 | DistanceProfile stamp = distanceProfileFactory.getDistanceProfile(DistanceProfileFactory.STAMP); 97 | 98 | int target_shape = (int) target.shape()[1]; 99 | int query_shape = (int) query.shape()[1]; 100 | // Using a fixed seed makes it deterministic for tests 101 | Random rnd = new Random(0); 102 | 103 | if (target_shape >= query_shape) { 104 | Order order = new RandomOrder((int) (query.length() - window + 1), accuracy, rnd); 105 | return matrixProfile(query, window, order, stamp, target, false); 106 | } 107 | 108 | INDArray new_target = CustomOperations.singlePad(target, query_shape - target_shape); 109 | 110 | Order order = new RandomOrder((int) (new_target.length() - window + 1), accuracy, rnd); 111 | return matrixProfile(query, window, order, stamp, new_target, false); 112 | } 113 | 114 | /** 115 | * Scalable time series anytime matrix profile (self join). Each distance profile is independent of other 116 | * distance profiles. The order in which we compute them is random. The random ordering 117 | * allows interrupt resume (not implemented yet) operation anytime. In case of self join, we take into 118 | * account trivial match. To avoid trivial matches, we find the first match then we set an exclusion 119 | * zone around the best match. The size of exclusion zone in 1/2 of the query size. 120 | * 121 | * @param target target time series 122 | * @param window size of window 123 | * @param accuracy a value in (0, 1]. Allows trading off accuracy for faster performance. 124 | * A value of 1 means that it will be slow but perfectly accurate. 125 | * @return a Pair with profile matrix as key and profile index as value. 126 | */ 127 | public Pair stamp(INDArray target, int window, double accuracy) { 128 | DistanceProfile stamp = distanceProfileFactory.getDistanceProfile(DistanceProfileFactory.STAMP); 129 | 130 | if (target.shape()[1] <= window) 131 | throw new IllegalArgumentException("The length of the target (" + 132 | target.shape()[1] + ") must be > the window width (" + window + ")"); 133 | 134 | // Using a fixed seed makes it deterministic for tests 135 | Random rnd = new Random(0); 136 | Order order = new RandomOrder((int) (target.length() - window + 1), accuracy, rnd); 137 | return matrixProfile(target, window, order, stamp, target, true); 138 | } 139 | 140 | /** 141 | * Algorithm that computes a vector(matrix profile) of distances between each subsequence and its nearest neighbor 142 | * in O(n^2 logn) time complexity and O(n) space complexity. 143 | * 144 | * @param timeSeriesA the first time series 145 | * @param window size of window 146 | * @param order order 147 | * @param dp distance profile 148 | * @param timeSeriesB the second time series 149 | * @param trivialMatch trivial match 150 | * @return a Pair with profile matrix as key and profile index as value. 151 | */ 152 | private Pair matrixProfile( 153 | INDArray timeSeriesA, int window, Order order, DistanceProfile dp, 154 | INDArray timeSeriesB, boolean trivialMatch) { 155 | 156 | MatrixProfileCalculator calculator = 157 | new MatrixProfileCalculator(timeSeriesA, window, order, dp, timeSeriesB, trivialMatch); 158 | return isConcurrent ? calculator.calculateConcurrently() : calculator.calculateSerially(); 159 | } 160 | 161 | } 162 | -------------------------------------------------------------------------------- /src/main/java/io/github/ensozos/utils/CustomOperations.java: -------------------------------------------------------------------------------- 1 | package io.github.ensozos.utils; 2 | 3 | import com.google.common.base.Function; 4 | import org.nd4j.linalg.api.ndarray.INDArray; 5 | import org.nd4j.linalg.factory.Nd4j; 6 | import org.nd4j.linalg.indexing.BooleanIndexing; 7 | import org.nd4j.linalg.indexing.INDArrayIndex; 8 | import org.nd4j.linalg.indexing.NDArrayIndex; 9 | import org.nd4j.linalg.indexing.conditions.Condition; 10 | import org.nd4j.linalg.indexing.conditions.Conditions; 11 | 12 | 13 | import java.util.ArrayList; 14 | import java.util.Arrays; 15 | import java.util.List; 16 | 17 | /** 18 | * Code from AlexDBlack 19 | *

20 | * These are some functions which I couldn't find in the ND4J library, so I implemented them myself. 21 | * You can see the usages in the file NumpyCheatSheat.java 22 | *

23 | * Refer to 24 | * https://github.com/deeplearning4j/dl4j-examples/tree/master/nd4j-examples/ 25 | * src/main/java/org/nd4j/examples/numpy_cheatsheat 26 | * 27 | * @author Shams Ul Azeem 28 | */ 29 | interface Predicate { 30 | boolean test(T t); 31 | } 32 | 33 | public class CustomOperations { 34 | 35 | public CustomOperations() { 36 | } 37 | 38 | 39 | public static INDArray elementWiseMin(INDArray arr1, INDArray arr2) { 40 | if (arr1.length() != arr2.length()) throw new IllegalArgumentException(); 41 | 42 | double[] a = arr1.data().asDouble(); 43 | double[] b = arr2.data().asDouble(); 44 | 45 | double[] values = new double[a.length]; 46 | for (int i = 0; i < a.length; i++) { 47 | values[i] = a[i] < b[i] ? a[i] : b[i]; 48 | } 49 | 50 | return Nd4j.create(values, new int[]{1, values.length}); 51 | } 52 | 53 | public static INDArray singlePad(INDArray arr, int length) { 54 | double[] pad = new double[length]; 55 | Arrays.fill(pad, 0); 56 | 57 | return append(arr, Nd4j.create(pad, new int[]{1, length})); 58 | } 59 | 60 | public static INDArray centeredMovingMinimum(INDArray arr, int k) { 61 | INDArray resutl = Nd4j.zeros(1, arr.length()); 62 | int arrSize = (int) arr.length(); 63 | 64 | int interval = k / 2; 65 | double minVal; 66 | if (k % 2 != 0) { 67 | for (int i = 0; i < arr.length(); i++) { 68 | minVal = arr.get(NDArrayIndex.interval(Math.max(0, i - interval), Math.min(i + interval, arrSize), true)).minNumber().doubleValue(); 69 | resutl.put(0, i, minVal); 70 | } 71 | } else { 72 | for (int i = 0; i < arr.length(); i++) { 73 | minVal = arr.get(NDArrayIndex.interval(Math.max(0, (i - 1) - (interval - 1)), Math.min((i - 1) + interval, arrSize), true)).minNumber().doubleValue(); 74 | resutl.put(0, i, minVal); 75 | } 76 | } 77 | 78 | return resutl; 79 | } 80 | 81 | public static INDArray lessThan(INDArray arr1, INDArray arr2) { 82 | if (arr1.length() != arr2.length()) throw new IllegalArgumentException(); 83 | 84 | float[] a = arr1.data().asFloat(); 85 | float[] b = arr2.data().asFloat(); 86 | 87 | List indices = new ArrayList<>(); 88 | for (int i = 0; i < a.length; i++) { 89 | if (a[i] <= b[i]) 90 | indices.add(i); 91 | } 92 | 93 | double[][] arrIndices = new double[2][indices.size()]; 94 | for (int i = 0; i < arrIndices[0].length; i++) { 95 | arrIndices[0][i] = 0; 96 | } 97 | 98 | for (int i = 0; i < arrIndices[0].length; i++) { 99 | arrIndices[1][i] = indices.get(i); 100 | } 101 | 102 | 103 | return Nd4j.create(arrIndices); 104 | } 105 | 106 | public static INDArray append(INDArray arr1, INDArray values) { 107 | return append(arr1, values, -1); 108 | } 109 | 110 | public static INDArray append(INDArray arr1, INDArray values, int dimension) { 111 | if (dimension == -1) { 112 | return Nd4j.toFlattened(arr1, values); 113 | } else { 114 | return Nd4j.concat(dimension, arr1, values); 115 | } 116 | } 117 | 118 | public static INDArray insert(INDArray arr1, int index, INDArray values) { 119 | return insert(arr1, index, values, -1); 120 | } 121 | 122 | public static INDArray insert(INDArray arr1, int index, INDArray values, int dimension) { 123 | if (dimension == -1) { 124 | INDArray flat1 = Nd4j.toFlattened(arr1); 125 | INDArray flatValues = Nd4j.toFlattened(values); 126 | INDArray firstSlice = flat1.get(NDArrayIndex.interval(0, index)); 127 | INDArray secondSlice = flat1.get(NDArrayIndex.interval(index, flat1.length())); 128 | return Nd4j.toFlattened(firstSlice, flatValues, secondSlice); 129 | } else { 130 | INDArray firstSlice = arr1.get(createIntervalOnDimension(dimension, false, 131 | 0, index)); 132 | INDArray secondSlice = arr1.get(createIntervalOnDimension(dimension, false, 133 | index, arr1.shape()[dimension])); 134 | return Nd4j.concat(dimension, firstSlice, values, secondSlice); 135 | } 136 | } 137 | 138 | public static INDArray delete(INDArray arr1, int... interval) { 139 | return delete(-1, arr1, interval); 140 | } 141 | 142 | public static INDArray delete(int dimension, INDArray arr1, int... interval) { 143 | int length = interval.length; 144 | int lastIntervalValue = interval[length - 1]; 145 | 146 | if (dimension == -1) { 147 | INDArray array1 = arr1.get(NDArrayIndex.interval(0, interval[0])); 148 | if (lastIntervalValue == arr1.length() - 1) { 149 | return Nd4j.toFlattened(array1); 150 | } else { 151 | INDArray array2 = arr1.get(NDArrayIndex.interval(lastIntervalValue + 1, 152 | arr1.length())); 153 | return Nd4j.toFlattened(array1, array2); 154 | } 155 | } else { 156 | INDArray array1 = arr1.get(createIntervalOnDimension(dimension, false, 0, interval[0])); 157 | if (lastIntervalValue == arr1.shape()[dimension] - 1) { 158 | return array1; 159 | } else { 160 | INDArray array2 = arr1.get(createIntervalOnDimension(dimension, false, 161 | lastIntervalValue + 1, 162 | arr1.shape()[dimension])); 163 | return Nd4j.concat(dimension, array1, array2); 164 | } 165 | } 166 | } 167 | 168 | public static INDArray[] split(INDArray arr1, int numOfSplits) { 169 | return split(arr1, numOfSplits, -1); 170 | } 171 | 172 | public static INDArray[] split(INDArray arr1, int numOfSplits, int dimension) { 173 | dimension = dimension == -1 ? 0 : dimension; 174 | INDArray[] splits = new INDArray[numOfSplits]; 175 | long intervalLength = arr1.shape()[dimension] / numOfSplits; 176 | 177 | for (int i = 0; i < numOfSplits; i++) { 178 | splits[i] = arr1.get(createIntervalOnDimension(dimension, 179 | false, 180 | intervalLength * i, intervalLength * (i + 1))); 181 | } 182 | return splits; 183 | } 184 | 185 | 186 | public static INDArray booleanOp(INDArray arr, Condition condition) { 187 | INDArray dup = arr.dup(); 188 | BooleanIndexing.applyWhere(dup, condition, 189 | new Function() { 190 | @Override 191 | public Number apply(Number number) { 192 | return 1.0; 193 | } 194 | }, new Function() { 195 | @Override 196 | public Number apply(Number number) { 197 | return 0.0; 198 | } 199 | }); 200 | return dup; 201 | } 202 | 203 | public static INDArray invert(INDArray arr1) { 204 | return booleanOp(arr1, Conditions.equals(0)); 205 | } 206 | 207 | 208 | public static INDArrayIndex[] createIntervalOnDimension(int dimension, boolean inclusive, long... interval) { 209 | INDArrayIndex[] indexInterval = new INDArrayIndex[dimension + 1]; 210 | 211 | for (int i = 0; i <= dimension; i++) { 212 | indexInterval[i] = i != dimension ? 213 | NDArrayIndex.all() : 214 | NDArrayIndex.interval((int) interval[0], (int) interval[1], inclusive); 215 | } 216 | 217 | return indexInterval; 218 | } 219 | } -------------------------------------------------------------------------------- /src/test/resources/data/series/numenta_art_increase_spike_density: -------------------------------------------------------------------------------- 1 | 20.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,20.0,20.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 2 | -------------------------------------------------------------------------------- /src/test/java/io/github/ensozos/core/MatrixProfileTest.java: -------------------------------------------------------------------------------- 1 | package io.github.ensozos.core; 2 | 3 | import javafx.util.Pair; 4 | import org.junit.Test; 5 | import org.nd4j.linalg.api.ndarray.INDArray; 6 | import org.nd4j.linalg.factory.Nd4j; 7 | import static org.junit.Assert.assertEquals; 8 | import static java.lang.Double.POSITIVE_INFINITY; 9 | 10 | 11 | public class MatrixProfileTest { 12 | 13 | /* instance under test */ 14 | private MatrixProfile matrixProfile = new MatrixProfile(false); 15 | 16 | private INDArray shortTargetSeries = Nd4j.create( 17 | new double[]{0.0, 6.0, -1.0, 2.0, 3.0, 1.0, 4.0}, 18 | new int[]{1, 7} 19 | ); 20 | 21 | private INDArray targetSeriesWithPattern = Nd4j.create( 22 | new double[]{0.6, 0.5, 2.00, 1.0, -1.01, -0.5, 1.0, 2.3, 4.0, 5.9, 4.2, 3.1, 3.2, 23 | 3.4, 2.9, 3.5, 1.05, -1.0, -0.50, 1.01, 2.41, 3.99, 6.01, 4.7, 3.2, 2.6, 4.1, 4.3, 1.1, 1.7, 3.1, 1.9, 24 | -0.5, 2.1, 1.9, 2.01, -0.02, 0.48, 2.03, 3.31, 5.1, 7.1, 5.1, 3.2, 2.3, 1.8, 2.1, 1.7, 1.1, -0.1, 2.1, 25 | 2.01, 3.9, 3.1, 1.05, -1.0, -0.5, 1.01, 2.41, 3.99, 6.01, 4.7, 4.5, 3.9, 2.1, 3.3, 3.1, 2.7, 1.9 26 | }, 27 | new int[]{1, 69} 28 | ); 29 | 30 | private INDArray targetSeriesWithoutPattern = Nd4j.create( 31 | new double[]{1.2, 1.5, 1.9, 2.1, 2.0, 1.8, 1.2, 0.2, 2.2, 2.8}, 32 | new int[]{1, 10} 33 | ); 34 | 35 | // 10 points all the same value 36 | private INDArray targetStraightLine = Nd4j.create( 37 | new double[]{1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2}, 38 | new int[]{1, 10} 39 | ); 40 | 41 | // starts high and ends low 42 | private INDArray targetTwoLevel = Nd4j.create( 43 | new double[]{3.2, 3.2, 3.2, 3.2, 3.2, 3.2, 3.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2}, 44 | new int[]{1, 16} 45 | ); 46 | 47 | // sawtooth. Up and down 48 | private INDArray targetSawTooth = Nd4j.create( 49 | new double[]{3.2, 5.2, 3.2, 5.2, 3.2, 5.2, 3.2, 5.2, 3.2, 5.2, 3.2, 5.2}, 50 | new int[]{1, 12} 51 | ); 52 | 53 | // 2 humps 54 | private INDArray target2Humps = Nd4j.create( 55 | new double[]{1.2, 1.2, 1.4, 1.7, 2.2, 2.5, 2.6, 2.6, 2.5, 2.2, 1.8, 1.4, 1.3, 1.2, 56 | 1.2, 1.2, 1.4, 1.7, 2.2, 2.5, 2.6, 2.6, 2.5, 2.2, 1.8, 1.4, 1.3, 1.2, 1.2, 1.2}, 57 | new int[]{1, 30} 58 | ); 59 | 60 | // upward trending 61 | private INDArray targetUpward = Nd4j.create( 62 | new double[]{1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4}, 63 | new int[]{1, 12} 64 | ); 65 | 66 | // plateau in the middle of flat 67 | private INDArray targetPlateau = Nd4j.create( 68 | new double[]{1.2, 1.2, 1.2, 2.2, 3.0, 3.0, 3.0, 3.0, 2.3, 1.2, 1.2, 1.2}, 69 | new int[]{1, 12} 70 | ); 71 | 72 | // 2 big sawteeth. 73 | private INDArray target2SawTeeth = Nd4j.create( 74 | new double[]{1.2, 2.2, 3.2, 4.2, 5.2, 4.2, 3.2, 2.2, 1.2, 75 | 1.2, 2.2, 3.2, 4.2, 5.2, 4.2, 3.2, 2.2, 1.2}, 76 | new int[]{1, 18} 77 | ); 78 | 79 | // Random noise. 80 | private INDArray targetRandom = Nd4j.create( 81 | new double[]{1.0948246, 1.6076082, 1.7123721, 1.704220, 1.058641, 1.1384039, 82 | 1.7433883, 1.0335902, 1.1436590, 1.128878, 1.504901, 1.8295812}, 83 | new int[]{1, 12} 84 | ); 85 | 86 | private INDArray query = Nd4j.create(new double[]{1.0, 2.0, 0.0, 0.0, -1}, new int[]{1, 5}); 87 | 88 | private PairexpectedResultWhenQuery = new Pair<>( 89 | Nd4j.create(new double[]{1.3881, 1.7967, 3.0370, 2.6308}, new int[]{1, 4}), 90 | Nd4j.create(new double[]{0, 1.0000, 0, 0}, new int[]{1, 4}) 91 | ); 92 | 93 | 94 | @Test 95 | public void testMatrixProfileStmpWindow4() { 96 | int window = 4; 97 | Pair pair = matrixProfile.stmp(shortTargetSeries, query, window); 98 | assertEquals(expectedResultWhenQuery.toString(), pair.toString()); 99 | } 100 | 101 | /** 102 | * The only difference between this and the above test is that it uses the "anytime" 103 | * interruptable version (ie.e stamp instead of stmp). 104 | */ 105 | @Test 106 | public void testMatrixProfileStampWindow4() { 107 | int window = 4; 108 | Pair pair = matrixProfile.stamp(shortTargetSeries, query, window, 1.0); 109 | assertEquals(expectedResultWhenQuery.toString(), pair.toString()); 110 | } 111 | 112 | @Test 113 | public void testMatrixProfileStmpWindow3() { 114 | 115 | int window = 3; 116 | Pairexpected = new Pair<>( 117 | Nd4j.create(new double[]{0.6732, 0.7582, 2.7278, 0.0014, 2.2059}, new int[]{1, 5}), 118 | Nd4j.create(new double[]{0, 1.0000, 0, 0, 1.0000}, new int[]{1, 5}) 119 | ); 120 | 121 | Pair pair = matrixProfile.stmp(shortTargetSeries, query, window); 122 | assertEquals(expected.toString(), pair.toString()); 123 | } 124 | 125 | 126 | 127 | @Test 128 | public void testMatrixProfileSelfJoinStmpWindow8() { 129 | int window = 8; 130 | 131 | // the length of these arrays is length of the series - window + 1 132 | Pair expectedResultWhenSelfJoin = new Pair<>( 133 | Nd4j.create(new double[]{ 134 | 1.9782, 0.8371, 0.4547, 0.0873, 0.1701, 0.4099, 0.6994, 1.4519, 1.3319, 135 | 0.9451, 1.8153, 1.9904, 1.1876, 1.0813, 0.5912, 0.1653, 0.0022, 0.1701, 136 | 0.4099, 0.6994, 1.4519, 2.0698, 1.4597, 1.9393, 2.2886, 1.8086, 1.6974, 137 | 2.0345, 2.1472, 1.9444, 1.9850, 2.5536, 1.9782, 0.8371, 0.4881, 0.0872, 138 | 0.3965, 0.7431, 1.1167, 1.3549, 1.3319, 1.1393, 0.9451, 1.6974, 1.9328, 139 | 1.3300, 1.5756, 2.0810, 1.8508, 1.1167, 1.1876, 1.0813, 0.5912, 0.1653, 140 | 0.0022, 0.5018, 0.6485, 1.3795, 1.7919, 1.4695, 1.1392, 1.3864 141 | }, new int[]{1, 62}), 142 | Nd4j.create(new double[]{ 143 | 32.0000, 33.0000, 53.0000, 35.0000, 17.0000, 18.0000, 19.0000, 20.0000, 40.0000, 144 | 42.0000, 42.0000, 49.0000, 50.0000, 51.0000, 52.0000, 53.0000, 54.0000, 4.0000, 145 | 5.0000, 6.0000, 7.0000, 40.0000, 42.0000, 43.0000, 50.0000, 61.0000, 43.0000, 146 | 44.0000, 0, 61.0000, 22.0000, 23.0000, 0, 1.0000, 2.0000, 3.0000, 147 | 4.0000, 18.0000, 49.0000, 50.0000, 8.0000, 60.0000, 9.0000, 26.0000, 13.0000, 148 | 33.0000, 2.0000, 36.0000, 37.0000, 38.0000, 12.0000, 13.0000, 14.0000, 15.0000, 149 | 16.0000, 17.0000, 5.0000, 6.0000, 7.0000, 40.0000, 41.0000, 42.0000 150 | }, new int[]{1, 62}) 151 | ); 152 | 153 | Pair pair = matrixProfile.stmp(targetSeriesWithPattern, window); 154 | // Uncomment this to export results to excel. Plotting in excel can be very instructive. 155 | //CsvExport.printAsCsv(targetSeriesWithPattern, expectedResultWhenSelfJoin); 156 | assertEquals(expectedResultWhenSelfJoin.toString(), pair.toString()); 157 | } 158 | 159 | @Test 160 | public void testMatrixProfileSelfJoinStmpWindow5() { 161 | int window = 5; 162 | 163 | // the length of these arrays is length of the series - window + 1 164 | Pair expectedResultWhenSelfJoin = new Pair<>( 165 | Nd4j.create(new double[]{ 166 | 2.8386, 3.8080, 4.2220, 4.1329, 3.9414, 2.8386 167 | }, new int[]{1, 6}), 168 | Nd4j.create(new double[]{ 169 | 5.0000, 5.0000, 5.0000, 0, 0, 0 170 | }, new int[]{1, 6}) 171 | ); 172 | 173 | Pair pair = matrixProfile.stmp(targetSeriesWithoutPattern, window); 174 | assertEquals(expectedResultWhenSelfJoin.toString(), pair.toString()); 175 | } 176 | 177 | @Test 178 | public void testMatrixProfileSelfJoinStmpStraightLine() { 179 | int window = 5; 180 | 181 | // the length of these arrays is length of the series - window + 1 182 | Pair expectedResultWhenSelfJoin = new Pair<>( 183 | Nd4j.create(new double[]{ 184 | 3.1623, 3.1623, 3.1623, 3.1623, 3.1623, 3.1623 185 | }, new int[]{1, 6}), 186 | Nd4j.create(new double[]{ 187 | 5.0000, 5.0000, 5.0000, 0, 1.0000, 2.0000 188 | }, new int[]{1, 6}) 189 | ); 190 | 191 | Pair pair = matrixProfile.stmp(targetStraightLine, window); 192 | assertEquals(expectedResultWhenSelfJoin.toString(), pair.toString()); 193 | } 194 | 195 | @Test 196 | public void testMatrixProfileSelfJoinStmpTwoLevel() { 197 | int window = 5; 198 | 199 | // the length of these arrays is length of the series - window + 1 200 | Pair expectedResultWhenSelfJoin = new Pair<>( 201 | Nd4j.create(new double[]{ 202 | 1e-20, 1e-20, 1e-20, 2.7386, 3.1623, 3.1623, 2.7386, 1e-20, 3.1620, 1e-20, 1e-20, 3.1620 203 | }, new int[]{1, 12}), 204 | Nd4j.create(new double[]{ 205 | 6.0000, 6.0000, 6.0000, 6.0000, 11.0000, 11.0000, 3.0000, 3.0000, 3.0000, 6.0000, 6.0000, 3.0000 206 | }, new int[]{1, 12}) 207 | ); 208 | 209 | Pair pair = matrixProfile.stmp(targetTwoLevel, window); 210 | assertEquals(expectedResultWhenSelfJoin.toString(), pair.toString()); 211 | } 212 | 213 | @Test 214 | public void testMatrixProfileSelfJoinStmpSawTooth() { 215 | int window = 5; 216 | 217 | // the length of these arrays is length of the series - window + 1 218 | Pair expectedResultWhenSelfJoin = new Pair<>( 219 | Nd4j.create(new double[]{ 220 | 1e-20, 0.0051, 1e-20, 0.0051, 1e-20, 0.0024, 1e-20, 0.0051 221 | }, new int[]{1, 8}), 222 | Nd4j.create(new double[]{ 223 | 6.0000, 7.0000, 6.0000, 7.0000, 0, 1.0000, 2.0000, 3.0000 224 | }, new int[]{1, 8}) 225 | ); 226 | 227 | Pair pair = matrixProfile.stmp(targetSawTooth, window); 228 | assertEquals(expectedResultWhenSelfJoin.toString(), pair.toString()); 229 | } 230 | 231 | @Test 232 | public void testMatrixProfileSelfJoinStmp2Humps() { 233 | int window = 5; 234 | 235 | // the length of these arrays is length of the series - window + 1 236 | Pair expectedResultWhenSelfJoin = new Pair<>( 237 | Nd4j.create(new double[]{ 238 | 1e-20, 1e-20, 0.0029, 0.0076, 0.0107, 0.0107, 1e-20, 1e-20, 1e-20, 239 | 1e-20, 1e-20, 1e-20, 1.8728, 0.4574, 1e-20, 0.0034, 0.0029, 1e-20, 240 | 1e-20, 1e-20, 1e-20, 1e-20, 1e-20, 0.0050, 0.0137, 1e-20 241 | }, new int[]{1, 26}), 242 | Nd4j.create(new double[]{ 243 | 14.0000, 15.0000, 16.0000, 17.0000, 18.0000, 19.0000, 20.0000, 21.0000, 22.0000, 244 | 23.0000, 24.0000, 25.0000, 0, 0, 0, 1.0000, 2.0000, 3.0000, 245 | 4.0000, 5.0000, 6.0000, 7.0000, 8.0000, 9.0000, 10.0000, 11.0000 246 | }, new int[]{1, 26}) 247 | ); 248 | 249 | Pair pair = matrixProfile.stmp(target2Humps, window); 250 | assertEquals(expectedResultWhenSelfJoin.toString(), pair.toString()); 251 | } 252 | 253 | @Test 254 | public void testMatrixProfileSelfJoinStmpUpward() { 255 | int window = 5; 256 | 257 | // the length of these arrays is length of the series - window + 1 258 | Pair expectedResultWhenSelfJoin = new Pair<>( 259 | Nd4j.create(new double[]{ 260 | 1e-20, 1e-20, 1e-20, 1e-20, 1e-20, 1e-20, 1e-20, 1e-20 261 | }, new int[]{1, 8}), 262 | Nd4j.create(new double[]{ 263 | 7.0000, 7.0000, 5.0000, 7.0000, 7.0000, 2.0000, 3.0000, 4.0000 264 | }, new int[]{1, 8}) 265 | ); 266 | 267 | Pair pair = matrixProfile.stmp(targetUpward, window); 268 | assertEquals(expectedResultWhenSelfJoin.toString(), pair.toString()); 269 | } 270 | 271 | @Test 272 | public void testMatrixProfileSelfJoinStmpPlateau() { 273 | int window = 5; 274 | 275 | // the length of these arrays is length of the series - window + 1 276 | Pair expectedResultWhenSelfJoin = new Pair<>( 277 | Nd4j.create(new double[]{ 278 | 2.4839, 3.9318, 3.8977, 2.4839, 2.4703, 3.8977, 3.9135, 2.4703 279 | }, new int[]{1, 8}), 280 | Nd4j.create(new double[]{ 281 | 3.0000, 4.0000, 5.0000, 0, 7.0000, 2.0000, 3.0000, 4.0000 282 | }, new int[]{1, 8}) 283 | ); 284 | 285 | Pair pair = matrixProfile.stmp(targetPlateau, window); 286 | assertEquals(expectedResultWhenSelfJoin.toString(), pair.toString()); 287 | } 288 | 289 | @Test 290 | public void testMatrixProfileSelfJoinStmp2SawTeeth() { 291 | int window = 5; 292 | 293 | // the length of these arrays is length of the series - window + 1 294 | Pair expectedResultWhenSelfJoin = new Pair<>( 295 | Nd4j.create(new double[]{ 296 | 1e-20, 0.0028, 0.0017, 1e-20, 1e-20, 0.5464, 2.0810, 2.0810, 0.5464, 1e-20, 1e-20, 0.0017, 0.0046, 1e-20 297 | }, new int[]{1, 14}), 298 | Nd4j.create(new double[]{ 299 | 9.0000, 10.0000, 11.0000, 12.0000, 13.0000, 13.0000, 13.0000, 0, 0, 0, 1.0000, 2.0000, 3.0000, 4.0000 300 | }, new int[]{1, 14}) 301 | ); 302 | 303 | Pair pair = matrixProfile.stmp(target2SawTeeth, window); 304 | assertEquals(expectedResultWhenSelfJoin.toString(), pair.toString()); 305 | } 306 | 307 | @Test 308 | public void testMatrixProfileSelfJoinStmpRandom() { 309 | int window = 5; 310 | 311 | // the length of these arrays is length of the series - window + 1 312 | Pair expectedResultWhenSelfJoin = new Pair<>( 313 | Nd4j.create(new double[]{ 314 | 2.4029, 2.2668, 2.1464, 2.6126, 2.2668, 2.3256, 2.1464, 2.9988 315 | }, new int[]{1, 8}), 316 | Nd4j.create(new double[]{ 317 | 4.0000, 4.0000, 6.0000, 6.0000, 1.0000, 2.0000, 2.0000, 2.0000 318 | }, new int[]{1, 8}) 319 | ); 320 | 321 | Pair pair = matrixProfile.stmp(targetRandom, window); 322 | assertEquals(expectedResultWhenSelfJoin.toString(), pair.toString()); 323 | } 324 | 325 | 326 | 327 | @Test 328 | public void testMatrixProfileSelfJoinStmpWindow4() { 329 | int window = 4; 330 | PairexpectedResultWhenSelfJoin = new Pair<>( 331 | Nd4j.create(new double[]{1.7308, POSITIVE_INFINITY, POSITIVE_INFINITY, 1.7308}, new int[]{1, 4}), 332 | Nd4j.create(new double[]{3.0000, 3.0000, 3.0000, 0}, new int[]{1, 4}) 333 | ); 334 | 335 | Pair pair = matrixProfile.stmp(shortTargetSeries, window); 336 | assertEquals(expectedResultWhenSelfJoin.toString(), pair.toString()); 337 | } 338 | 339 | /* 340 | * Why doesn't stamp give the same result as stmp here? 341 | * Commenting it out until #4 can be resolved. 342 | @Test 343 | public void testMatrixProfileSelfJoinStampWindow4() { 344 | int window = 4; 345 | PairexpectedResultWhenSelfJoin = new Pair<>( 346 | Nd4j.create(new double[]{1.7308, POSITIVE_INFINITY, POSITIVE_INFINITY, 1.7308}, new int[]{1, 4}), 347 | Nd4j.create(new double[]{3.0000, 3.0000, 3.0000, 0}, new int[]{1, 4}) 348 | ); 349 | 350 | Pair pair = matrixProfile.stamp(shortTargetSeries, window); 351 | assertEquals(expectedResultWhenSelfJoin.toString(), pair.toString()); 352 | }*/ 353 | } 354 | -------------------------------------------------------------------------------- /src/test/resources/data/series/numenta_art_load_balancer_spikes: -------------------------------------------------------------------------------- 1 | 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.1465598018,0.1542644635,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.2492116293,0.2258244388,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.1286541252,0.1590833261,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.6516335011,1.2577397349,0.0,0.2459135756,0.2980032575,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.6702377085,2.4870165126,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.3215197921,2.6359340481999998,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.2492618094,0.2633400854,0.22401456190000002,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.5318499336,0.4854816531,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.1868904984,0.1570609747,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.103038706,0.1930948696,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.1689526751,0.1676513386,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.12156751519999999,0.165888547,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.5928722058,0.6210594032,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.333154908,0.4891396294,0.29758737550000003,0.2801537112,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.1393864406,0.1651232977,0.0,0.0,0.0,0.2959576644,0.24878540440000002,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.110659303,0.1657845305,0.0,0.0,0.0,1.1603600282,1.7095425837,0.0,0.4699950743,0.4338044675,0.0,0.0,0.0,0.0,0.0,0.0,0.2109736199,0.2547959489,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.2454377335,0.2844357083,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.0833927958,2.4419664972999997,0.0,0.20980825809999998,0.24882411370000002,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.10043632699999999,0.1166953089,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.6947758611,1.1247881372,0.0,0.0,0.0,0.0,0.0,0.1713046051,0.1666385414,0.0,0.0,0.0,0.0,0.2590637834,0.2661014254,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.1966047505,0.176103779,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.19507727079999998,0.1702540502,0.0,0.0,0.0,0.0,0.2078455816,0.2544496959,0.0,0.0,0.0,0.0,0.0,0.1298052209,0.1105364922,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.6705581002,1.1340330754999999,0.0,0.0,0.0,0.0,0.0,2.950686267,2.6339478145,0.0,0.1781823863,0.1644149221,2.7050948425,2.8759304629000004,0.0,0.0,0.0,0.0,0.0,0.27093208280000003,0.2167321304,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.1702069722,1.771195185,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.1420697781,1.4215862031,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.4587315540999999,1.9382144221000002,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.2785081416,1.0214305954,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.10503495269999999,0.1052765258,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.0885146740000002,2.9515576370999996,0.0,0.3593224964,0.31543750600000003,0.0,0.0,0.0,0.0,1.7382723876,1.7143846680000001,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.2295932029,0.2663824475,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.16920112559999995,0.14579289939999998,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.3339774146,0.3253888828,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.6881832357,2.0410876746,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.1226521626,0.16139703060000002,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.29653027239999996,0.20504167739999998,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.2890384321,0.25768812010000003,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.1252858118,0.15776317539999998,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.1359208747,0.18235522269999999,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.1977283823,0.1242353695,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.166331071,0.18390996989999997,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.43933779759999997,0.4450652781,0.0,0.0,0.0,0.0,0.1550660459,0.11531445,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.17281164370000002,0.160025141,0.17312505890000002,0.1769746623,0.0,0.0,0.6648167522999999,0.6522441901,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.4951203838,0.31305535149999997,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.1341641113,0.1648464557,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.9107898105,2.0360306978000002,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0149262808,1.8453732393,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.4361363224,1.8853874038999998,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.4643678646,0.42926198670000004,0.0,0.0,0.0,0.0,0.0,0.0,0.4887548241,0.3007660581,0.0,0.0,1.0801381727,2.9686439576,0.0,1.7669622452,1.3044564278,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.1050322933,2.4397084584,1.5685765781999998,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.1187346791,0.10324707720000001,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.1743352896,0.1723330304,0.0,0.0,0.0,0.0,0.0,0.0,0.3476249687,0.4876895281000001,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.2063601436,0.2551687968,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.1136056234,0.1836078901,0.0,0.0,0.0,0.0,0.1154786035,0.1301175587,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.7467829158,1.7899805411,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.3538239505,0.4606266178,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.2336450352,0.2211208259,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.1442735928,0.1948916218,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.2313182051,0.2178841069,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.2901916108,0.2397186886,0.0,0.2245279305,0.24484078410000001,0.0,1.6700171399000001,1.4145650450999998,0.0,0.0,0.124599974,0.1532086824,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.2947732804,0.21263701420000009,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.3506796215,0.4010056092,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.30609930960000004,0.3263620747,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.1003020871,0.124793245,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.2973692135,0.22306386399999997,0.0,0.0,0.0,0.0,0.0,0.0,0.2772873936,0.23389699260000002,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.1927791479,0.1932133915,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.1720586419,0.1765763321,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.4773179192,0.45033595340000004,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.1091482958,0.1513875835,0.0,2.7086919656,2.3735355912,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.1782395809,0.1530750602,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.7471192044999997,1.8645425756,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.2874505295,0.27492171649999997,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.2938585596,0.205389829,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.8255261455,2.5284912417,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.15898343939999998,0.12006163710000001,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.2012179835,0.7260495402,0.4161239521,0.0,0.0,0.0,0.0,0.0,0.228935241,0.2253501016,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.1651076741,1.1420135604000001,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.1287330333,0.116189561,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.2330887088,0.22697960579999998,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.17056198039999998,0.1577341725,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.1175920331,2.8230957112,0.4090976296,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.6576905763999998,2.3069778641,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.1889735335,0.1700306354,0.0,0.0,0.0,0.0,0.0,0.2292290173,0.2655777302,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.12016999630000001,0.1429745381,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.559188741,2.4056494833,0.2209486223,0.0,2.5443050096,2.8560174835,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.1494042867,0.1055217627,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.7639751814999998,1.7423482413999998,1.1507097925,2.9166971673,1.8700238549000001,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.11418288289999999,0.10037450949999999,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.2465150193,2.3326106463,2.0930274174,1.4105150594999998,2.5102861002,0.0,0.0,0.0,2.6075039486000002,2.1059511719999997,1.9771223212,1.2278763662999999,1.167903323,1.6791296911000002,1.6216923109999999,2.9073129019,2.5672454849,2.3198485905,0.0,0.0,0.0,0.0,0.0,0.1532157485,0.1107156697,0.0,0.0,0.0,0.0,2.0352961780000003,1.3347350615,2.9569133443999998,1.7500813965000002,1.2138512048999999,0.0,1.9875977913999998,2.7479960232,2.7745820036,1.0219318321,2.7725914895,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.1391727764,0.15892717609999998,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.542968435,1.2055133176000001,2.81310297,2.727733512,2.1924621597,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.1774721623,2.7192956348000004,3.2248149307,2.7807581371,2.9813542145999996,2.1054948952,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.9352941855,1.7751326766,2.2261446198,1.4269230323,1.8527797894999998,2.8789617754,1.8571276756,1.7167352647,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.077074562,2.1426839552000003,2.2639826883,3.0527043886,2.3686888735,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.3432981135,0.3527145902,0.0,0.0,0.0,0.0,0.0,0.0,0.1977632337,0.1004644483,0.0,2.6349618702,2.0674413227,1.6769610206999999,2.3159016562,2.4354445095,0.0,0.0,0.0,0.0,0.0,2.1160979513,1.1132299463,1.3397657503,1.5705954418,1.5652512119,0.0,0.0,0.0,0.0,0.0,2.3468416005,1.0366973233,2.8530690622000003,1.9836976359,1.6200436924000001,0.0,2.0558196559,1.4318512019,2.6988445389,2.2316877888,1.5846590316999998,2.0842654689,2.6544225201,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.1873668656,0.1307325181,0.1938588858,0.1316945289,0.0,0.0,0.0,0.0,2.9465214867,2.7862774368000003,1.6848656168,2.9963957586000003,1.0070093271,0.0,0.0,1.0552595115999999,2.9465200181999998,1.6459055812,1.1215385368000002,1.4742961465,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.852200308,2.4611325409,2.2486710531,1.4752424351,2.0065408962,0.0,0.0,0.0,0.1654306322,0.10800325699999999,2.8524282108,2.630015554,1.6463795696999999,2.9645291226999997,2.4172408009,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.1248987113,1.0703214266,1.336815898,2.4557117361,1.3674778517,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.17386526510000005,0.1958786644,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.38165335479999996,0.3619361129,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.1862271729,0.1167892692,0.0,0.0,0.1326820306,0.117245184,0.0,0.0,0.0,0.2455882588,0.2953254856,0.0,0.0,0.0,2.6649789488,2.7611648862,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.1601308364,0.1712187982,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.35942343159999995,0.49286789340000003,0.1539506574,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.47696061619999996,0.444759046,0.0,0.0,0.2850452918,0.21452328690000005,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.2029780787,0.2933524313,0.0,0.4339446016,0.45974982979999995,0.0,0.0,0.0,0.0,0.0,0.0,0.169092057,0.1421339817,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.185401553,0.17715499350000002,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.35142293259999996,0.4236085624,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.2433727063,0.2457299798,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.1831138964,0.1348697895,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.1400149554,0.1894054613,0.0,0.0,0.0,0.0,0.0,0.0,2.8745240896,2.1725356864,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.2550944194,0.2105582713,0.0,0.0,0.0,0.0,0.0,0.0,0.2991401863,0.2244136821,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.14966238140000002,0.1544253909,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.398386396,2.0503515799,0.0,0.1956498125,0.18867263829999997,0.0,0.0,0.0,0.0,0.0,0.1169466709,0.14732150300000002,0.0,0.0,0.0,0.38296959399999997,0.4069319133,0.0,2.6694759096,1.0662669244,0.0,0.0,0.1971296227,0.1372366298,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.1371573109,0.1195030232,0.0,0.0,0.0,0.0,0.0,0.0,0.3040389846,0.3317196012,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.42833730159999994,0.4433953802,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.21985524039999998,0.2526802919,0.0,1.5367567306,1.9392967128,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.1532072326,2.4118133387,0.0,0.0,0.0,0.0,0.0,0.0,0.11143231140000001,0.1740304791,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.7015064295,1.4297928671,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.2329254978,2.7595338758,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.3578898389,0.4378568164,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.1876223293,0.18837774579999997,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.36762218409999997,0.4935508647,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.2778652151,0.28899974829999997,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.32030077170000004,0.3995493634,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.1108498345,0.1428350284,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.3856095584000001,0.3652046905,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.42910679820000003,0.3262111487,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.4433324836,0.49611842479999996,0.0,0.0,0.1464721956,0.1977615368,0.0,0.0,0.0,0.0,0.4609117429,0.47200335060000004,0.0,0.0,0.0 2 | -------------------------------------------------------------------------------- /src/test/resources/data/series/numenta_art_daily_flatmiddle: -------------------------------------------------------------------------------- 1 | -21.0483826823,-20.2954768676,-18.127229468299998,-20.1716653997,-21.223761612,-19.1044911334,-21.589446495900003,-18.9450416275,-18.305892530599998,-18.6397572378,-21.3480114749,-19.669223676199998,-21.1877822545,-20.124932244,-19.9222364992,-21.227652606,-19.693950446800002,-21.2081309243,-18.4026486599,-20.5452432622,-20.8103482262,-21.5963895846,-18.8972956749,-20.4168795204,-19.7330262548,-19.5310866222,-18.4268542208,-18.5369333224,-21.3479538458,-20.9990137293,-19.529364521199998,-21.3139463256,-18.3230647393,-20.4990956681,-21.472704210899998,-21.3554569241,-19.4911310398,-20.9809354122,-19.7098725821,-21.3605526576,-20.1230478006,-21.059428196400003,-18.3142863292,-20.3601038864,-20.2011367099,-20.4399068869,-20.7825664317,-21.672435880100004,-21.1427283271,-18.878551965699998,-21.3035850772,-18.4883187105,-20.4887943427,-21.531015233,-18.4044882169,-21.3987706132,-21.194482936900002,-20.0151017354,-19.2355904092,-19.6217529123,-21.8746325428,-18.8067902246,-20.3184171513,-18.3329629915,-18.8715722568,-21.0532655523,-19.210396161400002,-21.9430642823,-20.0032681724,-20.0661573012,-18.1452589573,-21.8261069983,-18.6969337635,-20.1533623952,-19.5826984398,-19.662338803,-20.5732006641,-20.6483547084,-18.617154459400002,-19.9983466125,-21.1619097966,-19.773145934200002,-18.6632178833,-19.2528677726,-18.8495182564,-18.503269871700002,-19.510324509700002,-20.1637449728,-18.2910061011,-20.4152934889,-21.972097760700002,-21.8564997281,-21.316693928,-19.065364451199997,-18.089630385899998,-21.3341668115,-18.2228809279,-18.8225123259,-20.1778128618,-18.7135121566,-21.3351533252,-21.108638785,-21.0230780229,-21.2645104636,-18.8788071211,-20.9155695046,-19.4211260104,-20.6673790383,55.46426074359999,62.4670389608,65.66529273479999,54.5232043838,55.125946813999995,55.4836412081,59.166766859300004,57.489362219200004,63.6830418425,59.6854468704,59.81444811229999,62.6044572159,73.9019285345,73.7687501608,79.9052810919,80.2566345367,68.6188613425,70.5856152328,71.6390923535,73.7443271251,72.83001086819999,78.56150473550001,80.9876555538,71.3197221318,80.1976041599,77.1062094171,79.2915215407,81.1128042138,85.4346211279,74.3259158584,72.658184339,81.21503679770001,77.5230326446,73.8603786618,73.1346607309,80.1331310241,76.6539144534,87.7829044292,78.3374242831,75.2457925688,81.8974615524,75.7562620786,79.7455659383,79.5617765017,79.0984082313,84.567896398,75.31487640739999,86.2959790474,84.6275834722,77.2990258448,74.8596842444,76.441971368,77.2912510786,80.8785663286,72.7127939447,86.5950941792,73.5493661875,76.4377869559,73.7190995676,76.0763225183,85.3959488753,81.8362655571,75.6311206277,85.9412606259,84.80460803609999,84.0516638461,85.55527820430001,81.90784175270001,80.0165959236,77.9767217819,75.57417790859999,80.9121130354,86.2304978214,81.5024045645,86.71232236819998,77.70943454260001,83.1208776051,82.377329501,82.7256178739,82.3193550651,75.5452660554,74.2962656133,87.6566495709,72.7235584659,79.4835294443,78.80103291020001,77.7600544985,84.5114712197,83.92533605109999,86.48332202899998,78.32754977,81.0266131609,86.2766366714,87.9012877207,87.50842977,83.4852347867,74.29159337829998,72.3709298713,85.2034391722,85.45501770060001,83.9417208095,76.4787268296,82.2370331218,77.0599257507,79.210321243,78.11891136359999,86.618185953,75.7464688141,-1.03989471325e-05,-9.9552901714e-06,-1.0574e-05,-1.03722253131e-05,-1.11083062914e-05,-9.42410168663e-06,-9.66787243976e-06,-1.07854806299e-05,-9.97127544805e-06,-9.55552519414e-06,-1.02468019389e-05,-1.05515869421e-05,-14.5434473469,-15.3331920086,-16.9901542954,-16.0647846694,-14.513215346199999,-15.3022451756,-16.4452522041,-15.0379522275,-17.047654682,-16.565045023,-15.9084150313,-17.3299983177,-18.7845153611,-18.1826822845,-19.8197879141,-19.4814539355,-18.5673523357,-18.5996723123,-18.8091279864,-18.3979724916,-20.0073274272,-19.7812166974,-18.9725865905,-18.807762356199998,-19.3045235165,-18.980802377699998,-18.1960444345,-18.9202362703,-19.1305270306,-20.0292102196,-20.9263928904,-19.4261461909,-21.604795491599997,-21.1389247422,-21.7636938223,-21.3327737549,-20.4341567679,-20.361286900499998,-18.488475555,-20.8561736575,-20.3681861232,-19.9956840645,-20.7399104713,-19.7445494814,-20.0632859643,-19.5620597805,-20.8360924169,-21.4720335896,-21.3565434785,-21.1373349793,-18.0493731729,-21.6405946521,-19.0933910451,-21.5449991687,-18.7818602963,-19.7522602624,-20.9908759503,-20.5545362274,-19.6573953753,-20.7078667918,-20.1957980402,-19.1029452265,-20.585317782,-18.8169883454,-20.775953137000002,-18.0124435105,-20.195090055,-19.6042705102,-19.2124150952,-20.062831868900002,-20.5812465301,-21.861249064899997,-21.3322579596,-20.8685995323,-19.9158676467,-19.5685764787,-18.1301186183,-19.4363876122,-21.3935085547,-19.5360983279,-19.846339996199998,-19.0873376961,-19.0965310353,-18.2474870436,-20.4552157025,-19.7922776122,-20.42384323,-20.1875476001,-21.195378349200002,-21.0040476492,-21.0858154126,-19.9969560278,-19.4155254054,-21.7337463621,-18.2170790949,-18.610485231400002,-19.6783963687,-20.4558306103,-18.0328014992,-20.8772912772,-20.2349061712,-19.9388110347,-19.6939801553,-20.077948127,-18.6471429379,-18.4348469571,-19.158549915,-20.8380191679,-20.3531515353,-19.9204920705,-20.2860838636,-20.2370320522,-19.228167702,-18.389823789,-21.5871294747,-20.3996450505,-20.790991998699997,-19.8559888975,-21.0259223199,-20.3379890559,-18.215204488399998,-21.560388141599997,-19.2221445872,-18.5515631097,-18.3521640308,-20.8817612554,-20.8158734672,-20.8006484993,-21.663011090700003,-19.395772088,-20.2445322254,-20.477982332,-21.917927314299998,-19.2493845749,-21.8253247996,-18.5949373323,-21.0560058241,-20.5315436001,-21.2675841491,-18.1147422946,-18.3125241718,-18.278783118299998,-20.371837822,-20.411744270299998,-21.624419557399996,-19.8704140581,-18.27219622,-18.838117606500003,-18.0322923793,-21.1068581005,-21.2623977475,-21.991761665100004,-19.648777796199997,-18.0771935016,-18.938919526,-20.3510754707,-21.847771868200002,-18.4143142059,-18.4862920806,-20.8070359411,-20.6688282201,-19.0020254212,-21.252579164100002,-18.5151150219,-21.7029673791,-18.804127721300002,-18.3254094909,-19.3580883459,56.254095462399995,60.3232947004,62.24215844850001,59.8910589417,61.9272879817,58.379046172799995,54.33507116689999,65.6887694907,63.8329620545,54.88102588899999,59.3901167539,61.62022884090001,71.2970329127,77.18542689270001,76.5114589954,71.5656308657,70.546396701,79.9362268022,73.3033139815,72.10941611439999,79.6157509627,79.5882441187,72.6013051763,81.663040611,82.1818826147,76.75690521029999,78.05143605890001,82.7910814251,74.6314879131,78.7051709528,81.6323641414,79.8256570005,80.9159209991,79.9320059917,74.4357627096,77.7776526644,80.3507443918,84.3120418698,82.2975428591,78.6678042127,87.4152165199,73.5772788902,75.1582601411,77.30607975699999,75.5058389253,81.843057805,72.487546046,74.6893105713,76.6628783802,82.9003589883,85.979432586,84.7419579815,74.88332961399999,81.0140735382,72.45137018060001,76.9378009703,84.861782421,79.2749287593,74.369301532,78.9852473622,75.1625133253,78.2848000408,79.7989511371,77.5867223658,86.9845438867,80.9940047221,85.4794438805,84.1649230203,82.5720546554,79.9438239552,72.02901775810001,81.8089363703,77.6940761229,73.8830125217,79.1127543935,83.76751285489999,87.38544652569998,77.9844304871,80.6822818421,85.6185402153,77.3427532153,74.2749275017,76.508885138,86.3845831015,74.5500511745,77.26728972,79.4339907784,85.5535378037,87.0031341275,78.8127127526,86.9109866576,74.58310685100001,74.5093982395,87.1877341125,80.1546256408,74.9742854472,79.8077948522,84.53132438600001,85.23067130390001,85.8234531793,81.113082537,85.87108127239999,80.1604320381,81.712906142,84.1394629871,78.80691424689999,73.17725696069999,77.602612044,-1.04938377559e-05,-9.60989669296e-06,-9.51989322439e-06,-9.816228955260001e-06,-9.28176427469e-06,-1.07385300952e-05,-9.74584955322e-06,-9.47044023626e-06,-1.06478170438e-05,-1.09423165696e-05,-9.256705220269999e-06,-9.69441233042e-06,-17.424745669900002,-15.632815235999999,-17.4034968305,-15.277482078299998,-15.0978183664,-15.0851488484,-14.6727335915,-17.2685855336,-17.535474317000002,-17.4544304174,-17.1264922396,-17.1100434946,-19.818568616700002,-20.4526610902,-18.0800350648,-18.7695849011,-19.7408117874,-20.6391223573,-19.8162031582,-20.5018447574,-19.0999665483,-20.0344467802,-21.0431267454,-17.8693964406,-21.534021396,-19.9287402273,-20.4082892302,-21.3393843075,-19.4815078371,-19.5173722178,-19.947857609,-17.9317971453,-19.8267714878,-19.011034346,-21.5381222847,-18.2041337406,-19.8055422134,-21.7550089031,-21.5695743934,-20.7721051565,-20.324872313900002,-19.092327086199997,-19.4366799414,-18.331162610899998,-21.1106021152,-19.2646063209,-20.6380538089,-19.3992905181,-19.8509674259,-20.2135394897,-21.200623265999997,-18.838595233099998,-19.5887911308,-18.5143997862,-18.2971850492,-20.4121634448,-18.750362144,-18.2333608275,-21.581483443000003,-20.13081376,-18.538512829600002,-18.2137045098,-18.4794402137,-19.8853489613,-20.6738610207,-20.5651202999,-18.5776923451,-20.5339558074,-19.6194624969,-19.8589751372,-21.205721625,-19.3299974907,-18.5879961887,-21.493812534299998,-18.848522303499998,-19.1761194822,-20.8263602356,-20.7342012682,-21.2016000851,-18.7354665658,-19.4091195733,-18.5035329558,-20.1641565887,-19.1702823702,-20.755742564000002,-18.0013774719,-18.238731993800002,-19.7302412021,-21.832736623899997,-21.563405549400002,-21.9760361122,-19.6673208995,-18.186273945099998,-19.2238245681,-20.7030834087,-18.5406552391,-19.199888715,-18.2246646582,-19.8998681536,-18.8356827108,-18.3649921076,-19.6448632379,-19.4049016175,-20.1500709478,-20.9961546213,-18.4502749457,-21.1645023608,-18.1051599195,-19.77240761,-20.3497211475,-21.8279946926,-20.2956921075,-18.6349967731,-20.070167221400002,-19.5831357888,-19.9174222704,-18.7883880586,-20.0033081692,-18.6001590572,-20.9761723228,-20.375625040899997,-18.314110766400002,-21.5584578717,-20.4655184185,-19.2644282205,-18.1825695981,-20.5289067831,-19.4937610454,-21.6304724195,-18.1395113309,-18.1564097414,-21.797197147600002,-21.859495782699998,-18.110968907100002,-20.8641329398,-18.8859794093,-20.8055710651,-21.4749311866,-18.4033259154,-18.955065667,-18.0963106733,-18.1753193818,-18.118471432899998,-21.2027294257,-19.1931707137,-19.9728457583,-21.1513770544,-19.9797746508,-19.716784250499998,-18.046292826,-20.2721580101,-18.4989723125,-21.0585929632,-19.0309508953,-20.6967496432,-20.584894111300002,-20.466702411700002,-19.0678080301,-19.068359108699998,-21.4521921738,-18.0512293305,-18.7260905338,-20.4406836706,-21.2681850176,-19.4333820347,-20.6137738344,-20.2286256785,-18.2581604179,61.461002363199995,63.76684166729999,65.9093798436,54.355680871800004,61.920698071000004,58.974594637799996,54.117454664499995,61.372331324499996,55.469127582700004,58.542802202299995,57.1364051099,58.3339608273,75.8889728388,73.8599848938,76.801524433,72.0274752915,78.0574988649,81.3771976627,71.8058191131,76.119733681,78.2600847252,76.9823171944,73.9578715821,78.1614355617,71.7274199064,77.1393147148,79.7165774799,71.606512436,79.3211574622,81.64339065850001,83.3058499318,73.0758454495,86.9705476183,80.8816963891,77.032989675,75.2256308146,81.0040170874,85.93517158200001,80.1683882456,82.4183857839,77.56769674659999,78.0540157362,76.425644089,83.12361631649999,77.591506853,74.9013595397,77.7545883204,85.48991285470001,83.7785078842,77.32331181,86.47433986,73.168043233,72.7669422384,74.0099098663,73.8337307833,73.3759869006,82.54844919930001,81.5808326833,82.328743494,82.9806513238,84.10334723359999,75.3088056533,81.9502996633,81.2742760871,87.09159252799999,75.7118261571,72.9337317846,82.4493246417,83.8360580226,76.525013602,81.127084209,72.9467408424,87.3593196872,73.757619432,73.0799592804,72.7045992597,78.83508912239999,73.5533790224,83.9130292253,86.3806044582,76.1622843012,82.0590569421,72.6762523135,78.1837805866,76.6868284162,75.65766343770001,82.3153124242,74.0834100741,85.77109390439999,82.6371100623,83.3714960694,86.96523064889999,87.07768729450001,80.8261785365,79.9258213131,77.3658581601,83.4490923558,80.6112906004,86.9259456432,75.81796665590001,76.963993723,77.057397842,84.8959209395,73.58459821529999,79.29033519,78.8412413331,73.1701871073,78.5727016901,-1.02673981097e-05,-9.34933441019e-06,-1.0260197639000001e-05,-1.11805192287e-05,-1.12208165338e-05,-1.03048801865e-05,-1.02709185179e-05,-9.800720724760001e-06,-1.1258092486e-05,-9.7776213422e-06,-1.01435418632e-05,-9.222e-06,-15.5175453172,-14.6286108344,-16.7802414131,-16.1952483227,-16.2309520849,-15.3168380754,-17.007670305799998,-14.410468805599999,-15.467525753199999,-16.5103940828,-17.3053543348,-15.150773001500001,-19.3578246116,-19.3458874676,-20.6368300174,-17.4739852287,-18.909986557899998,-17.9806685748,-17.3626855556,-17.8445991923,-21.0296478324,-18.1050186628,-20.8705186148,-18.0681770612,-21.5513795512,-20.4535359553,-18.3052513911,-20.165039418800003,-19.1198637799,-19.3763518029,-19.6025984416,-19.5333015461,-20.491184162,-20.9048845825,-19.1621771499,-21.5238762888,-21.719059089499996,-18.1337013447,-18.0307397541,-19.6687449122,-20.330000890999997,-19.0810404151,-19.0071947719,-20.680193999300002,-20.3741662479,-18.638717775299998,-21.503543064499997,-20.6867524508,-19.4440809023,-20.727863723800002,-18.444708154100002,-19.8666651337,-18.669961341300002,-18.1599119555,-19.3471120267,-18.5969889956,-20.5275009282,-20.6896487726,-18.5888189018,-18.0926605207,-21.1712422465,-18.0082280829,-19.3756523567,-19.9783331922,-21.2745687542,-21.354234571,-20.8997577624,-18.9887904902,-20.880747737300002,-18.9861567915,-18.858432766900002,-20.1885118169,-20.7154177753,-18.212207063599998,-18.240090404500002,-21.1366827473,-21.4379890039,-20.4177636654,-19.7153120388,-21.3812659184,-20.9152681311,-20.3183767937,-19.279028487799998,-18.7919802466,-19.6746921571,-19.147290303800002,-19.357034350899998,-20.0625242212,-18.6763758278,-21.2247067203,-18.5821178469,-19.9239745577,-20.9838853523,-19.940082830799998,-19.4440882544,-19.899565223299998,-21.3946827955,-21.9617267931,-20.5245731572,-21.1737761706,-18.0579547446,-21.5214576381,-21.8161990397,-20.300677367000002,-21.0152194482,-20.0509789718,-19.1448149618,-21.4089918879,-20.387346848,-20.3175323352,-20.6365288154,-21.4240126633,-20.9276245031,-18.8444967769,-19.8672941776,-21.9211933279,-20.2182428551,-21.7529814139,-21.2534779453,-20.6640937672,-19.3974608106,-19.2172773901,-20.5736842612,-19.7302449634,-21.1950144913,-21.041826958199998,-19.248521947,-20.8109151322,-19.9782007604,-19.293168403299997,-19.6518663711,-21.581407468800002,-19.438070768499998,-19.1495970933,-19.4072288828,-18.8584737448,-20.1785399496,-18.5897457453,-21.2697751457,-18.902320989,-20.3922201102,-18.5001019957,-21.9138125929,-19.8183018356,-21.288685363,-21.0745913426,-20.8547721886,-21.3094594848,-18.4018544346,-20.7139887899,-19.063308941099997,-21.143486656300002,-21.8274750394,-21.6059581194,-18.4598088899,-19.4782096827,-19.4572910288,-18.4891850654,-18.3925042134,-19.539560539900002,-21.968286201999998,-20.2757706043,-20.4871265144,-19.8840756401,-20.6493222092,-21.826648323,-20.3547918145,-18.260153838900003,59.91468683,65.91301527899999,58.6488326471,61.1265748466,55.279641161099995,55.694165984799994,64.4961774378,57.604135539,57.665415280299996,58.646555952,65.59774407489999,55.0126859524,80.8452143588,73.5916797223,81.311913995,83.4746858725,73.6997446352,70.3662167664,70.5945075693,79.93286154239999,70.6028075955,72.3584078417,71.5068548237,73.8063141733,72.4579665504,84.8508009213,84.9047175789,77.820857112,80.9754670933,81.44851288310001,83.1482485471,79.5277309867,79.3637229598,81.2798518329,82.4162865874,76.7715755721,77.13135571720001,76.1628634766,80.6199817952,77.6069660508,80.4837222588,78.3387647407,85.216971427,73.0237436683,80.9930587587,81.04756004939999,77.98319801470001,78.57886164439999,84.7681809334,76.4601830524,85.90808367860001,86.306956269,82.3769449069,84.33197713,81.7744375895,80.3719841616,87.4318573304,76.4918704359,74.43662858020001,76.56912590399999,81.8274630133,74.9569379748,86.53410140959998,78.5701042994,85.59255810020001,75.98170568970001,77.0045328258,72.9417385488,76.1181931323,79.8386335017,87.1312196283,78.2161897865,82.2345862973,78.8421003857,72.7475056336,80.05524111,73.05344947340001,86.1378205664,84.0472466138,78.05717460529999,82.2421827631,73.7912698058,83.23954793729999,85.16235592439999,85.1476579032,76.548195808,76.2196952206,80.3421059109,87.4840746409,86.7280901109,77.7539668946,84.4770017717,86.740806654,76.174579692,85.2844574825,76.2860859143,77.492464419,75.1810829377,80.1132255127,85.4929195927,80.4487827117,73.9749928111,76.0283662574,81.0057380328,81.3309472373,81.2304424692,73.2320090116,84.0590804843,-1.10785089515e-05,-1.02615428049e-05,-1.06881623792e-05,-1.10879037276e-05,-1.05320914021e-05,-1.0597e-05,-1.06934362385e-05,-9.74950902052e-06,-1.04093242874e-05,-1.09407746345e-05,-9.82254127152e-06,-1.10534051831e-05,-16.3852243366,-15.754161541099998,-16.3941875749,-15.685953706,-17.0817161124,-15.943421497000001,-17.2838849636,-16.031387910699998,-16.513180960499998,-17.5927843991,-14.8702925946,-16.7575354209,-17.8132697352,-20.5012472819,-19.5703814012,-20.882533158199998,-20.605273791,-17.5675089987,-17.8072421399,-19.5884967837,-19.2703286285,-17.927290484,-17.7767398158,-19.4457250233,-18.050120776900002,-21.3229817702,-21.0585051127,-20.972348134300002,-17.919476753399998,-18.045039338,-20.0377617155,-21.801881223600002,-19.2143107648,-19.2224793509,-18.388815048399998,-20.531764554000002,-20.553768042,-18.3758412171,-19.837857725899998,-20.6352303728,-19.9421060584,-20.6643384175,-21.2310574766,-20.7100725307,-20.431713829,-21.3800980677,-21.5677905223,-19.524256891500002,-18.6870177941,-21.2646347582,-18.848978828299998,-21.7088536257,-18.0857225001,-21.6781455069,-20.3502178196,-21.0922167996,-19.587700281,-21.959835774400002,-18.9041544475,-19.0512762938,-18.2057297761,-21.7618934522,-19.8241172144,-20.699409658900002,-20.7497629099,-21.4980083691,-20.6597010026,-20.248084729200002,-20.8412740968,-21.003883196,-18.743711785,-18.4386681559,-18.2993954019,-19.4962139781,-19.992000959400002,-20.4625995932,-21.8321380788,-19.323151280799998,-21.0434962083,-20.1254304784,-18.8803597283,-20.461221716500003,-21.868704713200003,-18.497233197,-20.0291190582,-18.2064334166,-19.2848651956,-20.4824107104,-21.364227744100003,-20.9213136869,-19.851427112899998,-21.6368910284,-19.2108586601,-21.0159336409,-19.896036087,-21.594543018699998,-21.1897312866,-21.6058786452,-18.856991395799998,-20.6726017285,-20.9538536323,-20.969657061099998,-20.0160018019,-18.0450020894,-19.0457231355,-19.2932035,-21.4081464691,-21.3635432684,-18.4187204162,-21.7993435271,-18.729829946600002,-19.6574378052,-18.8606278644,-21.4413298753,-20.9976081274,-19.4141152276,-20.7275145041,-18.737467536700002,-19.5291883695,-19.508430353399998,-18.9517467269,-21.5052481983,-20.7153829419,-19.1197572423,-18.9684830425,-18.071813884,-19.3863290152,-20.1070851333,-19.1108437676,-20.8018331057,-19.646998116,-19.265271348,-21.7562306352,-19.0512035092,-19.5930304804,-19.5291631541,-18.964793382699998,-18.8699069592,-19.2095200753,-21.4569446797,-21.0683315489,-20.7239980566,-19.828411970599998,-20.031015938499998,-19.068555382,-18.2972636553,-19.3241622269,-19.982335024,-18.2292521861,-18.3529332082,-19.0521009315,-19.4683214944,-19.573267244500002,-18.4715442652,-18.9032854181,-19.0465890083,-18.2705395048,-19.3043988024,-18.288886291,-20.8138313724,-19.5441910662,-19.3070095575,-18.506088686,-18.9060146218,-18.9308208358,-21.940816859499996,-21.341397518,-18.061049166500002,61.4020390892,57.0709211571,55.2525231458,62.4671971574,55.579266593599996,59.32488935439999,61.5859819781,60.6539370739,65.7315491796,63.4289113575,63.290320513500006,58.267144728999995,68.5276114797,79.56304613100001,83.5959276813,74.56936243770001,83.3798811841,70.55396326489999,72.9069877449,70.9950493625,75.6226747885,80.5141173029,73.5780577114,82.17467984470001,79.9101137471,78.6523227137,83.7466477404,72.8868649931,83.53623914399999,75.12835968270001,75.7280707474,80.7753477694,85.5666412927,80.4419660844,81.5593576849,83.5812582993,75.9968977516,85.06526728729999,78.5299876603,74.6608701137,77.4466854928,75.7862215919,75.50809884680001,76.3679691571,74.7451032498,82.5178616571,81.1173083763,82.21032014720001,77.46859574300001,84.28200814739999,74.0441103593,81.1057320764,76.3766846569,80.4095817078,77.1473235259,84.6143289662,86.2258452816,83.8477470541,74.7794156698,76.3673112261,86.70279227,78.9892024008,87.05192183870001,78.2729646836,87.2214162979,86.8048788578,82.5618247654,72.1354614768,78.39908248319999,86.5728356942,86.1548716846,74.9922049452,78.3856657448,85.3667929555,81.2447457153,85.5554188265,85.2237145499,86.5183277958,73.87434740260001,74.3222530882,73.3237712644,86.96291002870001,79.6013245085,73.0280360684,77.1442315779,77.6223538658,84.9526853262,83.7673622183,83.0299270964,72.349585322,86.57085571520003,75.4486428342,82.0647198671,72.988871123,73.3041828958,72.1530058477,81.0547904376,82.070022189,72.807350255,76.6477091017,85.623215828,73.6208867518,75.4647063354,78.7902089098,85.4763309372,76.0775361819,87.9541359551,77.68413929229999,-1.00074468525e-05,-9.46607350621e-06,-1.0609000000000001e-05,-9.71461669428e-06,-1.05039208351e-05,-9.673e-06,-1.00103624032e-05,-1.09704644443e-05,-1.07292793066e-05,-9.53260216303e-06,-1.04605863267e-05,-1.05034560546e-05,-14.6898209955,-15.8905801279,-15.234140816099998,-15.8948184914,-16.8866293337,-14.906432499400001,-14.7945753516,-15.2618147379,-17.4472836744,-16.7930396253,-14.4622606122,-15.6832175034,-18.2684086294,-19.7304755635,-19.0436834278,-20.9836747831,-18.1208776384,-19.5373690542,-19.9688068836,-20.4501680754,-18.8427691588,-19.917780550299998,-18.4442940436,-18.952228599,-21.409848545,-21.6252334831,-20.7082673181,-19.3414283825,-21.1099893978,-17.9586406544,-18.263695848399998,-20.4803310705,-19.0116744252,-21.6311006039,-19.5862885897,-19.5597196881,-20.679178348900003,-21.036561827699998,-19.8703913929,-18.8258340165,-21.0594854129,-19.2505548671,-18.670522383599998,-20.4937182793,-18.3324357795,-21.8503940612,-20.496741732,-21.908472370300004,-19.349379913499998,-21.8778175057,-18.5763026743,-18.1569670031,-18.1261340252,-19.8531264516,-18.3261505475,-20.0422559651,-19.3038228166,-19.336326367999998,-20.53586241,-18.6464232622,-21.066213481400002,-20.328123679100003,-21.6597785154,-19.4593626151,-21.9308599683,-20.3033105869,-21.8936078248,-18.1082426162,-20.9119052896,-21.2664860972,-18.2126931467,-20.3158786561,-21.2077691744,-20.2441549009,-18.255254361600002,-20.773788963599998,-18.2423876587,-21.2698755801,-18.1721367332,-18.549589524,-19.1004303621,-20.533459169,-21.905436398499997,-18.4712914105,-18.570830676900002,-19.4754815868,-21.344876551,-19.868923811,-19.286442401,-20.2448153288,-19.0420927898,-19.604639629,-19.3304205969,-21.2165640897,-21.6970229058,-21.038288768599998,-19.7563343041,-20.01733991,-18.5002947757,-20.9874588445,-20.3859027176,-21.6097599845,-18.8024445743,-21.038904487699998,-20.7386866469,-19.0633821352,-20.6695145582,-21.6974935223,-21.6737439507,-20.8785062981,-18.1922924501,-21.489057349299998,-20.631114428,-19.2417370127,-18.7490014468,-18.464815452,-18.200947597,-21.0164129918,-18.9433719958,-18.0970117442,-19.5890826074,-19.9304283224,-18.676920923599997,-18.1761933447,-18.7565019324,-20.7164110473,-18.328974709,-20.2201481222,-18.585647951600002,-18.7827566943,-19.5723115331,-18.4033013442,-18.692814011099998,-19.3958096458,-19.318676022000002,-20.9970859427,-18.2991292205,-21.4418029427,-21.264928683,-21.0639665588,-19.2374894499,-21.2915271422,-18.7312083212,-18.4976368234,-18.179825334,-21.757241452,-19.2320435908,-21.6704715207,-19.0904542461,-21.6302638373,-21.6157162114,-21.69470418,-19.9846137571,-21.4637851472,-21.8030635847,-19.2984677676,-19.6754976227,-20.8769607493,-19.2014392869,-21.0152372357,-18.2955685809,-20.0939935372,-18.489253936300003,-19.1732939057,-19.0345015699,-21.3557282943,-18.774069021600003,-21.2337916806,63.5275241509,59.9865966667,56.8061190672,56.722756079499995,59.5790957654,54.1057080887,60.376209055299995,65.4333543092,55.8564825824,60.880147457700005,65.5413442637,64.3262656739,81.325777769,80.892118942,73.0971588121,81.9373758353,82.7083733387,75.9360448341,73.7894799183,74.69628103720001,73.4799379158,71.6287603188,77.8004167478,76.9514726709,78.6073475253,72.7981909251,83.9027845609,74.050947634,73.0946627674,81.1494509044,77.594526682,72.2273662496,76.9122027426,83.5050007802,81.0255474106,77.0265306041,74.9187389128,81.944512473,86.0284830455,82.1756827613,84.8364487511,80.18375652600001,83.3205626324,86.16694912370001,84.2021219248,86.38454792790002,78.7404371666,86.2945890339,81.91229772140001,85.88641194520001,72.6009724772,82.4926278554,85.5333742215,74.75731764529999,82.5555554991,85.1651957173,76.57654703819999,78.45254767,81.0798385826,80.27456034890001,72.6212201262,73.5728672691,73.6015766716,76.1901907851,75.9277510988,83.8688480959,81.1574170634,84.2168794649,73.1124874516,79.7570467253,77.1742348355,85.59218104979999,83.3232933165,85.9067610031,72.7416700732,83.5318393023,80.63884339239999,85.1986372642,80.1132876217,80.6420549529,72.8271128426,82.6950426987,76.3690160859,72.3139457132,73.06276079850001,87.31629033040001,77.5369885141,85.8889352125,87.35455620959999,87.0919963261,86.1073283069,86.3172263834,76.62388351220001,74.4232800889,82.2279378632,79.8094340789,73.579900408,82.8406080383,81.0057082761,85.80902349520001,81.74688841300001,81.1830869183,79.05197698,79.4045422993,87.27004377879999,74.2150886527,79.139450448,82.4931829472,-1.01028058021e-05,-9.796e-06,-9.804507895260001e-06,-9.694527582680001e-06,-9.92031375474e-06,-1.10011899403e-05,-1.0250699879000003e-05,-9.708e-06,-1.00035107164e-05,-9.43274068388e-06,-1.10674651949e-05,-1.0052e-05,-17.5372540995,-15.51212606,-17.0763415369,-15.2204349507,-14.643691133199999,-14.501548613599999,-16.3397410567,-15.3970377202,-15.8192656424,-17.0196726924,-15.193947819000002,-15.3876898952,-20.5260913885,-19.1722075386,-20.4582346779,-18.7179882526,-18.8097411277,-17.921811691600002,-20.7987685215,-20.7236498271,-21.0593937852,-18.8253973699,-20.4234818121,-18.8734227323,-19.6586576756,-21.1494376811,-18.5597914235,-18.7301938653,-19.1048417368,-20.9834944876,-19.3346814277,-19.2772115301,-21.8193033481,-19.3789428558,-18.8391535659,-20.328911959000003,-21.173587793499998,-18.2491858597,-20.442808031,-18.113913131500002,-20.0731608933,-18.9975215246,-19.1958042996,-19.836594458,-21.673696373000002,-20.8093209727,-21.712586591100006,-20.6068602207,-18.0226618934,-19.0562408435,-21.6161709255,-20.567198477,-21.9195724414,-18.617896446,-19.1808514983,-19.4432468107,-19.3000532818,-19.0018835746,-19.7675352302,-20.5626103552,-19.245027691500002,-18.3187996933,-20.8341301076,-19.836066223099998,-20.2259292244,-19.8216026287,-21.561430013800006,-20.234979988699997,-21.6931073594,-20.0423013662,-19.170352649,-19.421770348699997,-20.0885171743,-20.119957751199998,-20.7493508062,-18.8979794887,-20.6353715999,-21.114352033499998,-20.7063679579,-19.9273124393,-21.9667226045,-19.6192526365,-18.426362458299998,-21.2860168616,-18.8488048755,-20.8531422916,-18.715905130899998,-18.067509563399998,-18.6391944152,-19.5079547863,-18.4264729885,-18.7907163369,-21.0585051107,-21.0795344319,-21.2699529088,-21.3646209462,-19.6817435785,-21.4701986428,-20.1037475001,-19.8823884677,-20.874145316,-18.8552736454,-21.1579895073,-19.7178633063,-18.509181656,-18.4772476541,-18.6596269754,-21.562290936999997,-21.963751289,-19.4278951968,-19.168575408800002,-18.8750838904,-21.2952659087,-18.8368299297,-21.696360519699997,-20.6694015159,-21.588511166700002,-20.2160394176,-20.7627194487,-20.4778324026,-21.3247818253,-21.3434432447,-20.3591719994,-20.5300305973,-21.687503682,-21.7194659359,-20.6569991356,-18.0310171127,-18.417644859,-21.431770127100002,-18.3388564655,-18.8540767234,-18.922186720899997,-20.400939079100002,-20.3065311915,-19.1576700937,-18.830445462300002,-21.0581281194,-21.7418246224,-18.2112227197,-18.532721850799998,-20.5686559548,-21.2177658067,-21.1647546751,-20.8787326123,-21.549711818000002,-18.8693955183,-18.429163786,-20.4614518804,-21.2891035661,-20.3281743139,-21.8519899498,-21.1822578456,-20.803167203599997,-18.2410291635,-18.4309689549,-21.139350530399998,-18.7929517023,-18.1153407043,-21.643042743000002,-21.5632214948,-18.873935308900002,-21.1208250323,-18.1919186448,-19.1402320153,-20.494667633,-21.0527159846,-18.0415967552,57.91450335930001,56.5721467208,65.985364869,62.0517867886,58.8680574346,54.9078312238,61.18404309010001,61.7004176512,63.79687113,57.462922235,65.7771369658,59.2735888718,72.8983450708,73.6964298768,76.2977080051,82.6378637805,79.5744137284,77.1720666718,70.8747178973,70.6701703255,76.03339309,79.4763723099,79.8153850259,71.8338986349,72.8655762835,77.36986206979999,85.823853085,79.91861728229999,76.3503803066,76.4064206665,73.3722587963,78.7758639799,83.81518482770001,86.6219696738,79.2252647993,73.92868426689999,82.7613519841,83.940444161,73.0009015988,85.431021622,85.09861992350001,79.40153555090001,80.8048267773,83.2476999613,82.662314061,72.1200464998,73.8110469319,74.45224599470001,84.0571778995,79.0097204715,80.6957508054,84.3292537907,77.4247340185,83.9486507396,79.0451576787,78.00366905119998,77.2976647864,87.4041414011,84.3178339415,72.2942057984,87.3116622925,84.4002815129,74.3808444876,73.2155522938,76.9249510101,81.9803455172,81.85819784659999,76.4074889142,79.1244691945,75.384211272,72.80343422199999,80.2651057566,77.5506173183,80.6848279389,87.14272285370001,74.2927362843,72.0302397907,73.2288797317,79.4020622843,83.30957950220001,81.2909169776,79.917035025,77.6621674829,76.9583553911,78.0203291358,81.7858975484,74.6838243048,84.3415234351,81.2037919885,76.306257861,80.01819134590001,87.40417930870001,72.3276330172,75.1921216389,79.1738304814,82.2147724604,75.3956040074,86.9024075564,82.28109953890001,86.0388561184,77.2690374318,85.2632083804,78.0514575174,76.0439796912,86.5864300113,73.4754485865,87.0861650017,79.3361925187,-1.12488969696e-05,-1.03210898508e-05,-1.07673357764e-05,-9.230481441410001e-06,-1.02331736472e-05,-1.07263047098e-05,-1.08192297368e-05,-9.539683497110001e-06,-1.00740525063e-05,-1.00742593702e-05,-9.42825637575e-06,-1.01233571997e-05,-16.9826996416,-15.360580326500001,-15.7842404904,-17.475070029,-14.501467699,-16.2928717428,-16.7789976414,-16.834825943800002,-16.6910038161,-16.7246467599,-14.5888423975,-16.109239243199998,-20.2866016679,-17.6412101646,-17.326272071600002,-20.4079178687,-20.0152108752,-18.8628730434,-20.8911227468,-20.2237371149,-20.996586463699998,-20.8485710414,-19.128167843499998,-20.1780829085,-20.5113515155,-21.0758146807,-20.9815476668,-18.464024533299998,-18.7834626678,-18.9104229763,-21.1038023701,-21.0730231682,-19.8214907385,-20.160742488,-21.1372271903,-19.0963714863,-18.1715939784,-19.8984971522,-21.620220803400002,-21.1280140643,-19.4353228776,-18.2298709202,-20.5148017535,-21.3038224599,-20.626738611900002,-19.6687781973,-18.4638250047,-21.6084680391,-19.0977200795,-18.891101061700002,-21.2571022158,-21.917863797,-20.6340360332,-20.492682202,-19.2715546085,-18.0758676765,-18.7611859651,-20.331213678599998,-18.5993121652,-21.5284519214,-18.7525787514,-20.088417812,-20.0480529831,-20.4157825205,-19.3097362789,-21.4941368043,-19.777206143900003,-20.8006143149,-20.543643443900002,-18.4686243325,-20.490557410799997,-20.2028107119,-21.594416253000002,-21.523506545900002,-18.6038191496,-18.3267405823,-19.1783688768,-21.9464514267,-18.086295105599998,-20.6915689583,-20.4340549354,-20.5863131218,-18.8731435591,-18.9068693832,-19.7225683287,-18.3834312283,-18.298452836099997,-18.3534378139,-20.2919166852,-19.5909674276,-19.1744671226,-19.2632775186,-18.8291332234,-19.646021341300003,-18.8122322768,-20.792184169200002,-18.4957300506,-21.7929683383,-18.3592757605,-21.7738428571,-21.333179886099998,-20.7228484825,-21.6492066223,-18.5568751741,-18.7052590967,-19.0086103682,-18.9792461071,-19.2433930837,-20.3025235931,-18.1126904452,-19.5290903802,-18.9855405116,-20.4265193922,-21.9406773242,-20.0706184487,-19.7027409565,-19.472974180599998,-21.1397968755,-18.287923726600003,-21.839082057800002,-19.671671544000002,-19.2548029033,-21.8962724656,-21.743515453,-20.567736559100002,-18.0740294994,-20.9941399048,-19.3422296002,-19.553120923399998,-18.6349685159,-20.0938323355,-20.9782103848,-19.0920444724,-21.754931632199998,-18.778947424000002,-18.2650493624,-20.5774554934,-21.3972749275,-21.812531437199997,-21.0686840421,-18.798600046,-21.910644739200002,-21.677743504099997,-18.652669691,-20.2351433077,-20.222069703699997,-19.7701391125,-21.937125321,-18.2384889487,-20.5088356338,-18.8212144907,-20.1093248189,-21.1189630872,-18.9869072127,-19.5734381859,-21.8030722971,-21.0459229509,-20.290892738,-18.8879895512,-19.7012217499,-21.096245276199998,-21.2821723124,-18.9784247926,-20.6482408417,-18.3800119685,-18.0928492298,-20.194695693699998,-18.8975194171,54.9469443749,62.757939754700004,59.9756950604,63.555324131499994,61.9673308762,62.757659278999995,57.688326975600006,57.159309908199994,61.2104987051,56.4009856848,63.784945387600004,60.2750420277,71.8502469717,77.9025571314,82.7645431733,69.6478398442,70.0620471512,81.22635503229999,70.0658253734,68.9985056142,73.68854483189999,75.4939294508,77.05555543770001,76.110963535,85.7448434725,83.4557027102,86.8635544528,78.82705390390001,72.6157810199,86.4156053842,71.3451524796,83.5733608592,71.7755073674,83.33763277989999,86.13695280719999,77.4458831097,75.7037267443,75.4692255073,79.7077473418,74.58472418699999,82.6012445344,77.7378504444,77.0154123747,79.2218080817,80.52003723899999,74.1223424277,83.1575653931,85.9548992913,76.41721154300001,74.8562999275,84.1344195448,74.90669291319999,72.6310185328,81.8751283695,75.8056882518,74.7190669562,87.67056160989998,76.6391717985,86.4205106064,74.8215596541,85.09682582229999,80.0258993846,73.2516557046,83.73098568350001,86.2662720938,74.6023031836,83.60275512189999,79.1145106379,84.0552022979,83.4161733432,72.4198096391,74.8535478125,79.5351633039,86.9361157505,77.4719357373,82.0606625329,72.19218483479999,83.3766966963,81.6477858186,83.4449808048,86.4731862153,74.3427934262,76.1842145692,87.9310873548,74.50030493439999,83.5297648083,83.6009470443,82.9276345705,75.6388073841,75.4419035966,82.6611925719,74.9797630153,82.5847490358,79.880196895,78.185811687,76.8034718182,87.16117515,80.12944724100001,80.97997957300001,87.18804155459999,82.4619843139,87.3255909557,73.7018206792,85.5461793588,77.36658453369998,84.9677460217,85.6901311454,76.34375731819999,-1.00532851026e-05,-1.07028773976e-05,-9.41886593202e-06,-1.07633326783e-05,-9.4422485525e-06,-1.10888053396e-05,-9.78194287261e-06,-1.03948274623e-05,-9.4559303681e-06,-9.767921980689999e-06,-1.0043299929e-05,-1.02134760994e-05,-14.4002178357,-17.2437006468,-14.4245612369,-16.8757927617,-15.9058545555,-16.0764181375,-15.0664514624,-16.3435808131,-16.1191441726,-14.9255584117,-15.1619827451,-14.6140934834,-17.5345292909,-17.3328993878,-18.126621796600002,-19.8898995375,-18.494267485,-18.596099993,-17.786517089500002,-19.4898077796,-18.5938319802,-19.8770569492,-20.1272047897,-19.5252210575,-18.9514440003,-19.8741558298,-18.8556615108,-21.4387582192,-20.8970187426,-19.8122475168,-21.6869340337,-20.0255256953,-19.1596288517,-18.2348143248,-20.0135828013,-21.2701332026,-21.4325279304,-20.3855990542,-19.5424354634,-20.5682233529,-21.0148837372,-19.6150647551,-19.8731686665,-20.6893093021,-21.4721998654,-21.130179063499998,-18.0606221873,-18.4678934073,-21.404261168599998,-21.3284640225,-19.5489694631,-20.330603817,-21.6164604517,-21.6393079325,-21.1256090277,-18.8323274827,-20.9144364709,-18.3985043264,-21.568849600100002,-18.5906443069,-20.6493945604,-20.440973097,-21.1075986235,-20.2063100094,-18.2382663015,-20.8233850162,-19.5326182353,-19.2811400049,-21.9666941981,-20.3615990638,-20.842876293099998,-20.1053045477,-21.0798905838,-21.008290942000002,-20.6285844627,-21.9909722458,-19.839174136300002,-20.8247693932,-21.1911118512,-19.5041388384,-19.8287001102,-21.876669065599998,-18.1291640685,-19.341182615799998,-19.9448518494,-18.0058599723,-21.596508404,-19.1449776008,-19.0308193284,-21.2813047814,-19.111932914,-20.6304903756,-21.2860125756,-21.1699073908,-21.1278029497,-18.3545502795,-18.319387870299998,-19.2270801429,-18.1437915248,-20.0017189461,-19.5791282651,-20.2281036502,-19.1951541547,-19.943016012,-19.3389790634,-18.7808323689,-20.5974667246,-20.693743605999998,-21.316926771,-21.499007132600003,-20.8178476175,-20.7499923468,-18.226702661300003,-18.4391169658,-21.2502508416,-18.9318050465,-19.4222602409,-18.5811894147,-18.7806078743,-21.1016689415,-19.0474384781,-19.7961398651,-18.6066854922,-20.7117196253,-20.9130789365,-19.4467692716,-21.1389865845,-18.9596266077,-20.7676154484,-20.919858325699998,-21.8746295112,-18.9292866607,-18.3748419202,-19.0521416892,-18.4914487863,-18.678777234000002,-19.3364580474,-19.6559629869,-21.614896903,-18.782463086,-21.8870359037,-21.2406128396,-21.5258855596,-21.717775959,-21.012964788599998,-21.1551193265,-19.751273186400002,-20.0418009387,-21.7299417071,-19.5130236462,-18.1677882923,-21.051017541900002,-20.2926300469,-21.2595038494,-18.302205066400003,-20.484927961900002,-18.990823552000002,-21.613074378,-18.439639759000002,-21.3722770909,-18.3542170079,-18.100389422,-18.9402377202,-19.3321781637,-20.5061150872,-18.5268983894,-19.7493197344,-18.8170544084,64.2636398586,54.5395980954,58.2712527203,61.5764889596,64.9570581366,64.4159210723,64.7423039942,54.7542395242,64.0910791376,63.3589509425,64.8291797913,57.7389152071,82.2588296154,74.5201444933,78.03831522,74.8475206663,74.90025614380002,76.70888268569999,73.8100859862,80.4496023129,78.0313087783,78.8842875754,71.9117289634,83.1375443849,81.7371893887,74.4035824942,83.1677654566,74.0316313948,72.2840167574,79.636445795,80.0478194339,74.27321470369998,76.7983224776,86.26098564360001,75.7944511963,73.7441980825,87.705229356,76.6832148049,82.7182906528,75.5535529772,80.6403352735,78.02415076220001,87.2104976422,78.7670442048,81.184093373,86.94202773389999,87.6520933014,73.4792807564,85.3149917401,78.08261836140001,81.48465239560001,77.96956895560001,78.38649214680001,74.5119038875,81.1317976295,80.71515615310001,74.9996807396,80.6354197946,87.53460227,83.3971653186,79.6893452957,86.65041118180002,81.1985333017,74.1548351182,80.7536935527,74.8895782003,84.27333501380002,87.46778944569998,77.7668755049,78.9523693871,78.7376439539,76.5586744287,84.70552412800001,81.8823431855,73.0236565125,85.4195346259,74.9922118039,87.66501592459998,78.0253617983,81.8618845433,73.2440059795,77.5133721612,84.8363059152,79.6340617059,86.473379021,81.2019552097,86.8568771834,87.7214778026,79.26205931289998,81.0422458252,85.3584571441,75.5442863461,85.7857986651,81.4704615397,83.6077346205,73.2774298741,84.2589490095,76.9725412107,84.883662104,80.1463893191,76.393780465,87.2440993161,84.2409444491,87.77092100860001,77.83146856239999,82.3874614087,81.7853665032,83.0008547365,-9.2944723272e-06,-9.813441175239999e-06,-1.10783233511e-05,-1.0084e-05,-1.11833982547e-05,-9.65325449752e-06,-1.12587242976e-05,-1.06446457015e-05,-1.08060537324e-05,-1.00287716806e-05,-1.10735526323e-05,-1.03331080211e-05,-16.5790049388,-14.7033883503,-16.4213803448,-17.2130549657,-14.970508246500001,-16.760725136199998,-14.4812842824,-17.363851875599998,-17.5453370171,-15.533378202,-14.742638206099999,-16.507446491099998,-17.3945649054,-19.1327477283,-18.3236324234,-19.0976223746,-17.3501783467,-17.4781911559,-17.3413475527,-19.6574668003,-19.4307572184,-18.1753271021,-19.7631100366,-20.6753563076,-18.9564141751,-21.157351517000002,-20.484836336199997,-17.9901995928,-19.3445948665,-19.8707807146,-20.7593824715,-18.9953341336,-21.7554731459,-20.5722537753,-19.335324750799998,-18.240995430399998,-18.6955103028,-19.9185103669,-19.9468153859,-21.037161676500002,-20.871258989,-18.775004022,-20.347218776600002,-18.0535552383,-19.5628389102,-21.022730706,-19.5666775342,-21.3082371608,-21.897611685300003,-20.422313182,-18.5740707032,-19.512462848,-18.0321612845,-20.4043722095,-21.2794623997,-20.5131939958,-21.1375787298,-21.1928318356,-21.397201012300002,-19.0605538055,-21.4850740913,-20.6163759939,-19.158902226400002,-21.94917886,-21.800729574899997,-20.2977639328,-21.3728335136,-19.0459779549,-19.6641479864,-18.735887042999998,-20.0804105705,-19.9840057203,-18.851252903800003,-20.6912067749,-18.4711611821,-18.2467658043,-19.5396198746,-19.639299111099998,-19.278962426099998,-19.0317865503,-19.35510538,-18.6535022958,-19.6138098765,-21.618413494099997,-18.8977075248,-20.7378044174,-18.5671380416,-19.415626495999998,-19.2846991222,-21.748117577600002,-19.7119282232,-20.7618637751,-20.4098512359,-18.564120301099997,-21.7581618041,-19.3834771674,-18.179033423099998,-19.2017748274,-19.3425349035,-18.3709813095,-20.4799096255,-19.3870568222,-20.5165384253,-18.0269622544,-21.928193596,-18.682065434200002,-20.637323946800002,-20.8631372131,-18.686433399000002,-18.4468491284,-18.6103087674,-18.9872730234,-18.672928472,-20.6959977078,-19.6833328149,-20.1511663781,-18.1893471552,-21.4449958524,-18.6822862128,-19.4406093258,-18.287606559300002,-18.547172538599998,-20.6631976399,-20.770348009,-20.7078619385,-20.2085471514,-21.810086656,-20.0287086431,-19.7976481172,-18.9901822629,-18.3953981171,-20.1926197199,-19.259560746800002,-20.0961015328,-18.824476312999998,-21.352690688800003,-21.998788838600007,-19.2896140405,-21.369310429000002,-21.4919445456,-21.984295155,-19.3708805191,-21.0241655749,-18.9152360146,-20.4991840052,-20.8193702779,-20.9644827701,-18.8286886743,-21.394902282,-19.6838874416,-18.8654780709,-20.1701243535,-21.4534285184,-21.8683516391,-20.9928312869,-18.0224915451,-18.5388030419,-18.305095945799998,-18.404854972,-19.5321398241,-19.353973259300002,-18.4547399251,-21.5289414065,-20.4617103053,-21.1858532358,-19.4861975554,-19.6409440652,-19.2704848421,59.26111934520001,61.3245271483,59.9158080941,64.0550040743,64.8016700233,59.6362062404,56.8769757642,65.3423090335,62.820463716599996,61.6815250326,62.94496480350001,54.9117813888,69.4279201801,70.7274339192,70.6412547051,74.7941912177,70.79254205069999,81.3887897929,77.18707335010001,73.99758082449999,69.458262581,77.38362249859999,70.171298873,79.6969478061,83.9956882524,79.89658392609999,73.6497092888,83.743905544,76.15599218189999,74.8068257812,78.7336171937,85.8947164635,75.9903929465,85.6243634554,72.1298684104,72.6030154875,83.01062244939999,74.899383618,76.9117990693,74.0336037603,77.1613403615,76.3343851825,83.6138394194,83.0659094626,87.1042771532,83.4235654688,82.95084988020001,82.94104770060001,86.0930282987,76.7090918109,76.7707531576,83.8258771869,75.6290184815,86.55768313829998,80.5242849983,76.7712780499,84.3838318355,76.96633122600001,87.3774880919,87.6927362247,82.6621263723,73.8122367846,76.2052446916,80.2402516617,85.6163093488,74.9521872964,73.6645617078,73.1857843998,80.1050720793,86.14832309629999,72.6719336625,75.39111277229999,83.0907827796,85.2124515413,84.9170337745,84.5597359397,74.0756115843,78.3545476221,87.7545105107,87.82079599020003,81.6375320499,83.3469417031,87.2191452119,79.1975785983,74.18963231859999,82.70291735810001,87.3613573212,83.1550314049,84.85286650229999,78.7637288188,73.54317512739999,74.7018743381,87.722196559,79.8906934209,72.1920984274,87.28559717690003,79.9644274143,85.3802397293,80.7752785764,73.6271894174,81.84906093069999,87.9583481277,72.5557580866,85.46865246029999,75.7676442391,78.30180945020001,77.9633022918,86.38069982459999,-1.02491877147e-05,-1.01318129394e-05,-1.08913154228e-05,-9.316161811e-06,-9.393062533260001e-06,-9.26041877883e-06,-1.0625e-05,-1.02924618487e-05,-1.10100933137e-05,-1.0237e-05,-9.670286484960001e-06,-1.08649418201e-05,-15.3418382973,-17.3942095293,-15.2013583869,-14.9367080011,-15.9786388181,-14.5616502414,-14.5165193893,-15.987248591199998,-15.0883439499,-14.4299302899,-15.347384081,-15.927577570999999,-18.7940690145,-17.8002031298,-19.505951755,-20.007679112799998,-19.8740708067,-18.7920461786,-17.8083696004,-19.1980296198,-20.699258380499998,-19.079896147,-18.0314156157,-17.6373250601,-21.6015009892,-20.8042614203,-19.0978530265,-19.0279584264,-21.4082270437,-18.5605908324,-19.979028047899998,-20.687185049300002,-19.4288769968,-18.0143325696,-18.7597470503,-21.4343747779,-20.0603279224,-21.2277461794,-20.1903858003,-21.7395693473,-21.601917861900002,-19.899661700899998,-19.2422591638,-20.374024485899998,-20.6664314625,-19.961430913,-21.255070289200003,-18.7033407999,-19.3314592785,-20.738866871099997,-18.9806597093,-19.7530559807,-21.8479406112,-20.4969427729,-21.7892541489,-20.883080891400002,-20.8919795086,-20.3609111209,-18.5628923553,-20.0724319325,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,40.0,-8.0,-8.0,-8.0,-8.0,-8.0,-8.0,-8.0,-8.0,-8.0,-8.0,-8.0,-8.0,-20.700042770699998,-18.381303392,-18.74812892,-20.6538403925,-19.9066819846,-20.945190664800002,-19.1231551957,-20.6316701474,-18.7078406721,-20.174841053399998,-21.8311983662,-20.512888929200003,-18.19997447,-21.955048550900003,-18.6274653186,-20.872276410799998,-20.130120156300002,-19.177442751199997,-18.7092419417,-18.7108094571,-21.4335987248,-21.4916500567,-19.860582086500003,-18.4144858517,-21.5366604154,-19.9480659447,-19.755049691500002,-19.629428097799998,-19.4600566954,-20.1040216144,-20.4181649064,-19.865728814300002,-21.5865926538,-19.2706449141,-20.313247427100002,-19.1998156808,-21.0134000952,-18.4084843973,-18.7547959872,-21.2048056397,-18.7327903809,-20.5029853848,-21.880973807600004,-20.0915624551,-18.7495857854,-19.2827641828,-21.2938323058,-19.4066436525,-20.894045436099997,-21.109400251500002,-20.004731389,-21.1328535375,-19.2676120177,-20.0646385869,-20.7462330559,-18.6722925892,-19.0944878695,-20.6081464136,-20.621440479300002,-19.9732105858,-21.1823414271,-19.928219608,-21.5252890617,-20.9436137235,-19.2587794532,-19.581016033900003,-20.6707467431,-21.5778104753,-18.7148349308,-20.058654155,-18.4751376853,-19.1178206213,-20.7439254372,-18.310938541,-20.6494343276,-21.6032444838,-21.877481164099997,-18.8665288041,-20.995591826400002,-21.7054817948,-18.3654772434,-19.656094434,-21.6776390675,-18.811149993,-21.7350427352,-20.1087682844,-18.399572330199998,-19.799509267,-19.3050447819,-19.1288166422,-20.1659023025,-19.934370763,-19.927868638499998,-18.3525669244,-21.2092727241,-19.9257572614,-21.2836233148,-21.2983785662,-19.2685412994,-18.0173852152,-21.6449827098,-21.0427787723,-18.4290078273,-20.806908136,-18.0800930747,-18.111036276900002,-20.1032929584,-18.3841497169,65.57203826979999,64.72597471979999,61.797744375,54.7645076501,57.8980230937,58.4606759749,59.770558029899995,56.02683448810001,60.9301397136,59.229247774899996,65.36756356069999,65.2343427555,76.9952041212,78.1941099071,70.49450631020001,71.7945132304,82.09087414390001,79.027322028,71.2793389987,77.0671966523,82.6083710074,73.6466008137,71.2244697079,82.71878420899999,78.586443307,77.8891132588,75.51826444470001,85.402711072,84.6745695875,77.6633679271,71.76491435359999,78.3549586592,74.1447909826,73.5409076712,77.5066028124,72.8493786875,87.1447932467,72.6151056547,78.2650702103,74.454036746,82.8549391822,73.1144612211,80.58739140899999,84.2008846754,87.0265554461,83.0100881255,73.4446843859,73.26949613779999,83.6720865491,75.4150923719,79.1241666066,87.5908872466,85.084461371,85.5112755193,85.7380095483,81.87996035180001,83.8693816047,77.7122772843,87.9399495693,76.44336513260001,81.4336032434,76.5068658142,73.78723335800001,81.0748865277,77.6473664476,81.3250017597,80.93238051819999,80.6696535777,73.9669001273,79.0365689582,84.9852636653,77.036132545,79.1000384638,79.9000270242,85.8023281423,82.4882764741,73.6020629055,85.8413622891,85.3116905988,84.0569907562,79.4556569822,84.1193802042,79.6585984443,83.78463597359999,86.08148717790002,86.24838936639999,79.2730035126,85.74920847130002,73.62308249350001,73.6288750666,80.77201267859999,82.42925012090001,74.4476621824,79.5546261413,73.5095674537,81.6333305414,85.68144975189999,83.8021699829,78.0526148852,87.9006444897,82.606906755,85.0439205229,82.715105259,87.8306044458,85.14170178479999,80.3107200874,77.8700231686,82.91442420109999,-1.04247742644e-05,-1.05049100104e-05,-9.91848809729e-06,-1.0094e-05,-1.0359e-05,-1.09348524071e-05,-1.07784374635e-05,-9.459e-06,-9.71889510398e-06,-9.270595020610001e-06,-9.232303243139999e-06,-9.675520961030001e-06,-16.9578292042,-17.2951947199,-15.6536607745,-16.202237583,-16.6593704587,-17.4493996711,-17.3213853765,-14.5830172374,-15.1941326431,-14.557264404000001,-16.3729378429,-16.6735807469,-18.4638086973,-20.5587917658,-19.0188013673,-21.1137854684,-17.2815351882,-17.7004408579,-18.438886446199998,-17.377949546900002,-20.2841839504,-17.4826440384,-20.156082221800002,-17.4818632547,-18.858821864,-21.194186492,-21.629946216799997,-19.5008406082,-21.7047179,-20.3434635895,-19.5060338464,-21.0415158197,-19.027863646500002,-18.910679643199998,-20.461181266500002,-19.4054539324,-18.5140022476,-18.238628385,-21.1175281298,-20.6705171155,-19.6157574059,-21.5503747015,-19.6119975426,-20.8078360119,-21.6018427808,-21.3286812734,-20.0123480512,-20.6893895139,-19.6483736179,-20.5822002802,-19.0241200894,-19.7326519884,-18.8321547349,-18.146930937,-20.3476460746,-21.4508509154,-18.0965203613,-18.778108047899998,-19.834391203499997,-20.6569749228,-18.6849167747,-18.2267793159,-20.0761948709,-21.274838852200002,-18.1409396373,-19.3974778014,-20.654058971199998,-18.5229680244,-18.9437871076,-20.1419705751,-21.8129267855,-19.149370473,-19.9501096849,-19.5997234523,-21.5895866881,-18.2875594561,-20.2645903654,-21.3844787968,-21.9524703083,-20.7949019901,-19.519741902699998,-19.6472974101,-19.406728879,-20.4144523992,-20.9576230829,-21.2778702544,-19.666372438699998,-20.866834009,-21.6648903681,-21.683299177800002,-20.8161160109,-20.547608771300002,-20.1261043021,-18.7327906727,-18.4945186104,-19.9428440272,-18.6377766248,-20.3079997027,-20.5828109212,-20.1024623901,-18.1457068501,-18.2309118352,-18.4533647387,-18.61458322,-21.9595304551,-19.3779800675,-19.1678934946,-18.2090665427,-20.5412815627,-20.6087631405,-18.7017947583,-21.676966163699998,-21.2019741864,-18.9212772672,-19.9433989237,-19.8335634248,-19.3940817774,-21.2705388513,-18.4370579425,-19.6612569593,-19.7121245222,-19.8749024185,-21.4453999644,-18.8726674808,-18.411692694,-20.471233851300003,-18.6953378999,-18.299728343399998,-19.7065968823,-18.8785857234,-19.4448664755,-19.0388443204,-18.370545850899997,-20.241388811700002,-18.1080736722,-21.865501392,-19.3653220869,-20.780630042000002,-21.2414514902,-19.1164191822,-20.9949548364,-21.3296834217,-18.9652689352,-21.969978707600003,-18.0827547314,-18.8680019209,-21.1200830251,-18.7765241002,-20.7930394532,-21.4221216199,-21.8368570905,-19.8969900616,-21.8844364919,-19.646489186700002,-18.872512158699998,-20.0556874123,-20.5992929772,-19.8318532642,-20.2678897759,-19.6656367509,-20.0990478161,-21.8103826878,-19.9993246101,-19.012718531199997,-21.0349864861,-19.3503378311,-21.2648286833,-18.2273679559,57.986135725299995,55.1323188991,55.023813891,61.9006747101,58.6240176162,64.4577473038,60.1968616545,57.5441186541,62.650666655500004,61.488201499,63.59513545,61.7230593161,70.93860393989999,78.5887125725,74.3515478038,75.4397740599,82.4077815512,73.8714535037,77.7017789735,73.9249223479,69.8398577774,75.2935851991,77.4753348678,74.594050039,77.4681523653,84.2747956601,71.7502131291,75.9620726844,84.1382350836,85.861197554,77.8108254397,85.3585008122,74.4310531345,74.7874047549,84.6836714051,85.58760262279999,75.4137625028,72.8032886654,73.2982958205,76.0297291793,84.0148188639,79.9995495063,79.1308426329,81.1835464209,86.0710826758,73.2999923009,82.9493548701,86.6549962234,75.3834352279,85.3701953126,83.135128014,72.20260397850001,75.675504571,81.6608387679,80.0063900697,80.4148012484,75.680602439,82.7669355091,76.2321888574,78.1996670799,77.8964224417,82.7457801619,73.4381686634,75.282647323,75.2019364947,73.72889600229999,75.31549393979999,81.7064272496,83.7079935587,82.55824996310001,79.5966419669,72.8331260213,87.3427146652,74.68802834579998,82.69341881060001,86.6048641477,83.1631029048,75.4875864223,77.0515079364,72.4821341395,81.80282298739999,81.8065787679,83.6066715739,72.1747858134,85.08518834770001,83.8191070964,74.253948139,77.5617775498,82.216135194,79.9324942142,73.8412719296,73.3972911301,84.5030303752,74.4952355028,74.7532435717,85.2944970624,81.7941818047,81.6753974582,79.6694813533,81.1038683239,81.6282628038,87.485163767,75.5675245562,75.43295043810001,72.9154491374,82.53112796100001,80.78462319100001,73.7797800425,-9.96257573906e-06,-9.581902244460001e-06,-9.89487460428e-06,-1.11641890189e-05,-1.0615436982e-05,-9.23150151837e-06,-9.73313653505e-06,-9.23722044836e-06,-1.06800506854e-05,-1.01773758505e-05,-1.12517502808e-05,-1.07183785185e-05,-16.057323472,-16.9750595431,-16.6553738158,-15.1800857115,-16.0968285398,-16.1791979904,-15.843943463599999,-14.9734183097,-15.1147829,-15.299353641400002,-14.4328183254,-17.334222673699998,-19.9146090325,-19.9281309177,-19.4777499726,-19.9269539284,-21.0503526406,-18.7590160967,-20.0160986806,-18.6605917749,-20.5604694258,-20.5748302894,-20.744703516199998,-17.3009795342,-19.0392237324,-18.387411901500002,-19.6574173144,-19.821944264000003,-18.8714273199,-20.726635765999998,-18.926446316,-21.2442410648,-18.560952449400002,-19.3131897294,-20.3250395094,-20.2579696432,-18.282817076700002,-21.3508184112,-20.3596321349,-21.445071111300003,-21.436189462799998,-20.1513808984,-21.608496845599998,-21.359401402899998,-21.797559809299997,-21.367750422,-21.2507597168,-19.845638031900002,-18.8420928448,-21.635909228699997,-20.883511886199997,-19.1208708227,-19.357786419700002,-20.7376758703,-19.9048976305,-18.3200659527,-18.5598507327,-20.9758803072,-19.3080975481,-20.0241879256,-21.066485913,-21.0047023748,-18.6680601075,-18.3935754576,-20.3646091719,-20.9665314957,-18.596159688,-19.4878211493,-21.4811119839,-21.776892566199997,-19.8162790438,-18.318063736099997,-19.0307858248,-18.9318796813,-18.9558548822,-19.9755268215,-20.3329026068,-18.4900383547,-21.5574240261,-20.4798952931,-20.3890069211,-21.949115993499998,-20.51257591,-21.7158365972,-19.1450278894,-18.9605179614,-20.0660747473,-20.034435790499998,-18.9059345979,-20.7986226276,-18.1185352769,-20.7625218902,-19.8287115445,-20.7560300434,-19.9083225226,-21.9093351315,-19.3387398044,-21.930291748000002,-18.2598957699,-20.735043099000002,-19.8168768271,-21.2885505021,-21.158464278900002,-21.2008407315,-18.3789543972,-21.2894627994,-18.8561606298,-18.1027210554,-18.870954878699997,-19.917140418800003,-20.9684454396,-18.8745299233,-18.4520301924,-20.5838690201,-21.9355921454,-20.4034812083,-20.7642294565,-20.244669775,-21.1293937769,-21.9032176808,-20.1765169176,-19.667162047,-21.4413722446,-21.878913375,-18.5167265635,-20.312683861900002,-21.169839970199998,-20.1333576206,-19.6367878728,-20.6209192845,-19.0805123781,-19.3965349718,-21.9691066355,-20.5458613375,-21.491709193200002,-21.231074052100002,-20.6090902176,-21.3629163298,-19.1486339817,-20.5484657952,-20.3624139581,-20.4896784032,-18.6745277086,-19.10897216,-19.1466332752,-20.407784650299998,-21.890187521799998,-21.816270204699997,-18.908758212000002,-19.2193809723,-18.1442475691,-19.5952623594,-21.3386964867,-21.663006955900002,-18.9459859183,-19.063177894000003,-18.883399265999998,-19.4004142703,-21.2190375944,-20.5874298795,-21.1437636715,-20.332124425299998,-19.0309323122,-18.9119767209,-18.0360028235,-21.1239285475,-21.3884849047,-21.0731303985,54.8928246927,63.146659526,54.549209437799995,55.267116788500005,59.285704475200006,59.7137641071,63.7934236394,62.1543227045,55.839842143599995,56.7137613987,57.4281022591,55.484071649499995,72.7722022727,79.4746919642,72.06930234560001,81.0974666353,75.5366583259,73.3086235709,74.6687551891,79.184350457,76.25524908930001,68.5106356924,82.4193224681,69.4031392456,86.1477621652,71.72594072609999,83.4923126657,79.7492473776,79.2907027008,72.4328114803,75.0617209638,83.5963495023,85.397555706,79.6612399079,76.8769593984,72.2295004157,82.7490267042,76.3022354794,72.734459001,82.4883204102,79.6119736631,72.0470116064,73.6272350565,83.0208564062,72.8727038464,85.6836982194,76.8272579978,73.27182619989999,84.1224556035,80.35867941689999,76.8754780219,78.4661744373,72.3136612903,82.57013533,77.8212380718,83.3912312752,82.0179180399,82.3870989478,84.6524088627,82.06568984229999,78.6933188987,78.2325818805,73.9074006431,84.4643369229,84.1710008493,75.9346986115,85.79604637029999,81.4175382005,79.6526167592,72.2741584307,78.1176090651,82.2441522332,73.4347904276,79.35180729300001,87.89356890219999,83.4632827615,80.7486422011,80.5272377026,72.6990781123,87.315633926,86.8494529511,82.91714867520001,73.5830090479,75.3241371425,74.9423127578,80.3129987592,75.3246209525,83.1325429597,80.7234198597,72.28229952859999,83.90464729680001,75.0210197184,85.1978892808,77.6804784156,77.41766714239999,72.1888463674,87.8036075324,81.79201707979999,78.7636322502,73.545895402,83.1863157871,76.5236385447,87.812436894,87.20870193280001,83.7646932514,87.5370948608,73.6900946376,76.47859682229999,-9.73464225539e-06,-9.36348192447e-06,-1.12071200726e-05,-9.3388269294e-06,-1.09704988753e-05,-1.07891945975e-05,-9.98577579508e-06,-9.254517478610001e-06,-9.22848441335e-06,-9.63377938568e-06,-1.02274592358e-05,-1.01537996353e-05,-16.2729383279,-16.8702719503,-15.607536765299999,-14.9131657345,-16.9601587048,-15.4646121597,-15.318024033599999,-16.8458006792,-17.3892484277,-17.3278783204,-14.8398176622,-16.0101081404,-17.6366222658,-20.970148129600002,-18.106475468,-18.0381299519,-20.6933214258,-20.9965465796,-19.9589083015,-17.744659708,-19.1456859529,-20.4157639967,-19.478312800999998,-17.7891646217,-18.5380506666,-21.2849142576,-19.947251803900002,-20.6567604036,-19.336312183900002,-19.9689028755,-21.7331453508,-19.1642617298,-20.5335609619,-18.5405021275,-18.3390639404,-20.965484048,-21.3422305649,-20.6401696035,-18.6029709121,-18.9320121151,-21.6100713256,-19.124168505,-21.2414013749,-19.1131191727,-21.723037734699997,-21.6231591704,-18.1439758251,-21.0479253152,-18.6718701329,-18.855050959,-19.8330322507,-20.2987749151,-19.2970218554,-20.2950369748,-18.6766550457,-18.083562028299998,-20.2784063896,-20.0632387516,-20.7519731026,-20.592696479 2 | --------------------------------------------------------------------------------