Show t-test results based on individual measurements to analysis task page.
[WebKit-https.git] / Websites / perf.webkit.org / unit-tests / statistics-tests.js
1 "use strict";
2
3 var assert = require('assert');
4 var Statistics = require('../public/shared/statistics.js');
5 if (!assert.almostEqual)
6     assert.almostEqual = require('./resources/almost-equal.js');
7
8
9 describe('assert.almostEqual', function () {
10     it('should not throw when values are identical', function () {
11         assert.doesNotThrow(function () { assert.almostEqual(1, 1); });
12     });
13
14     it('should not throw when values are close', function () {
15         assert.doesNotThrow(function () { assert.almostEqual(1.10, 1.107, 2); });
16         assert.doesNotThrow(function () { assert.almostEqual(1256.7, 1256.72, 4); });
17     });
18
19     it('should throw when values are not close', function () {
20         assert.throws(function () { assert.almostEqual(1.10, 1.27, 2); });
21         assert.throws(function () { assert.almostEqual(735.4, 735.6, 4); });
22     });
23 });
24
25 describe('Statistics', function () {
26     describe('min', function () {
27         it('should find the mininum value', function () {
28             assert.equal(Statistics.min([1, 2, 3, 4]), 1);
29             assert.equal(Statistics.min([4, 3, 2, 1]), 1);
30             assert.equal(Statistics.min([2000, 20, 200]), 20);
31             assert.equal(Statistics.min([0.3, 0.06, 0.5]), 0.06);
32             assert.equal(Statistics.min([-0.3, 0.06, 0.5]), -0.3);
33             assert.equal(Statistics.min([-0.3, 0.06, 0.5, Infinity]), -0.3);
34             assert.equal(Statistics.min([-0.3, 0.06, 0.5, -Infinity]), -Infinity);
35             assert.equal(Statistics.min([]), Infinity);
36         });
37     });
38
39     describe('max', function () {
40         it('should find the mininum value', function () {
41             assert.equal(Statistics.max([1, 2, 3, 4]), 4);
42             assert.equal(Statistics.max([4, 3, 2, 1]), 4);
43             assert.equal(Statistics.max([2000, 20, 200]), 2000);
44             assert.equal(Statistics.max([0.3, 0.06, 0.5]), 0.5);
45             assert.equal(Statistics.max([-0.3, 0.06, 0.5]), 0.5);
46             assert.equal(Statistics.max([-0.3, 0.06, 0.5, Infinity]), Infinity);
47             assert.equal(Statistics.max([-0.3, 0.06, 0.5, -Infinity]), 0.5);
48             assert.equal(Statistics.max([]), -Infinity);
49         });
50     });
51
52     describe('sum', function () {
53         it('should find the sum of values', function () {
54             assert.equal(Statistics.sum([1, 2, 3, 4]), 10);
55             assert.equal(Statistics.sum([4, 3, 2, 1]), 10);
56             assert.equal(Statistics.sum([2000, 20, 200]), 2220);
57             assert.equal(Statistics.sum([0.3, 0.06, 0.5]), 0.86);
58             assert.equal(Statistics.sum([-0.3, 0.06, 0.5]), 0.26);
59             assert.equal(Statistics.sum([-0.3, 0.06, 0.5, Infinity]), Infinity);
60             assert.equal(Statistics.sum([-0.3, 0.06, 0.5, -Infinity]), -Infinity);
61             assert.equal(Statistics.sum([]), 0);
62         });
63     });
64
65     describe('squareSum', function () {
66         it('should find the square sum of values', function () {
67             assert.equal(Statistics.squareSum([1, 2, 3, 4]), 30);
68             assert.equal(Statistics.squareSum([4, 3, 2, 1]), 30);
69             assert.equal(Statistics.squareSum([2000, 20, 200]), 2000 * 2000 + 20 * 20 + 200* 200);
70             assert.equal(Statistics.squareSum([0.3, 0.06, 0.5]), 0.09 + 0.0036 + 0.25);
71             assert.equal(Statistics.squareSum([-0.3, 0.06, 0.5]), 0.09 + 0.0036 + 0.25);
72             assert.equal(Statistics.squareSum([-0.3, 0.06, 0.5, Infinity]), Infinity);
73             assert.equal(Statistics.squareSum([-0.3, 0.06, 0.5, -Infinity]), Infinity);
74             assert.equal(Statistics.squareSum([]), 0);
75         });
76     });
77
78     describe('sampleStandardDeviation', function () {
79         function stdev(values) {
80             return Statistics.sampleStandardDeviation(values.length,
81                 Statistics.sum(values), Statistics.squareSum(values));
82         }
83
84         it('should find the standard deviation of values', function () {
85             assert.almostEqual(stdev([1, 2, 3, 4]), 1.2909944);
86             assert.almostEqual(stdev([4, 3, 2, 1]), 1.2909944);
87             assert.almostEqual(stdev([2000, 20, 200]), 1094.89726);
88             assert.almostEqual(stdev([0.3, 0.06, 0.5]), 0.220302822);
89             assert.almostEqual(stdev([-0.3, 0.06, 0.5]), 0.40066611203);
90             assert.almostEqual(stdev([-0.3, 0.06, 0.5, Infinity]), NaN);
91             assert.almostEqual(stdev([-0.3, 0.06, 0.5, -Infinity]), NaN);
92             assert.almostEqual(stdev([]), 0);
93         });
94     });
95
96     describe('confidenceIntervalDelta', function () {
97         it('should find the p-value of values using Student\'s t distribution', function () {
98             function delta(values, probabilty) {
99                 return Statistics.confidenceIntervalDelta(probabilty, values.length,
100                     Statistics.sum(values), Statistics.squareSum(values));
101             }
102
103             // https://onlinecourses.science.psu.edu/stat414/node/199
104             var values = [118, 115, 125, 110, 112, 130, 117, 112, 115, 120, 113, 118, 119, 122, 123, 126];
105             assert.almostEqual(delta(values, 0.95), 3.015, 3);
106
107             // Following values are computed using Excel Online's STDEV and CONFIDENCE.T
108             assert.almostEqual(delta([1, 2, 3, 4], 0.8), 1.057159, 4);
109             assert.almostEqual(delta([1, 2, 3, 4], 0.9), 1.519090, 4);
110             assert.almostEqual(delta([1, 2, 3, 4], 0.95), 2.054260, 4);
111
112             assert.almostEqual(delta([0.3, 0.06, 0.5], 0.8), 0.2398353, 4);
113             assert.almostEqual(delta([0.3, 0.06, 0.5], 0.9), 0.3713985, 4);
114             assert.almostEqual(delta([0.3, 0.06, 0.5], 0.95), 0.5472625, 4);
115
116             assert.almostEqual(delta([-0.3, 0.06, 0.5], 0.8), 0.4361900, 4);
117             assert.almostEqual(delta([-0.3, 0.06, 0.5], 0.9), 0.6754647, 4);
118             assert.almostEqual(delta([-0.3, 0.06, 0.5], 0.95), 0.9953098, 4);
119
120             assert.almostEqual(delta([123, 107, 109, 104, 111], 0.8), 5.001167, 4);
121             assert.almostEqual(delta([123, 107, 109, 104, 111], 0.9), 6.953874, 4);
122             assert.almostEqual(delta([123, 107, 109, 104, 111], 0.95), 9.056490, 4);
123
124             assert.almostEqual(delta([6785, 7812, 6904, 7503, 6943, 7207, 6812], 0.8), 212.6155, 4);
125             assert.almostEqual(delta([6785, 7812, 6904, 7503, 6943, 7207, 6812], 0.9), 286.9585, 4);
126             assert.almostEqual(delta([6785, 7812, 6904, 7503, 6943, 7207, 6812], 0.95), 361.3469, 4);
127
128         });
129     });
130
131     // https://en.wikipedia.org/wiki/Welch%27s_t_test
132
133     var example1 = {
134         A1: [27.5, 21.0, 19.0, 23.6, 17.0, 17.9, 16.9, 20.1, 21.9, 22.6, 23.1, 19.6, 19.0, 21.7, 21.4],
135         A2: [27.1, 22.0, 20.8, 23.4, 23.4, 23.5, 25.8, 22.0, 24.8, 20.2, 21.9, 22.1, 22.9, 20.5, 24.4],
136         expectedT: 2.46,
137         expectedDegreesOfFreedom: 25.0,
138         expectedRange: [0.95, 0.98] // P = 0.021 so 1 - P = 0.979 is between 0.95 and 0.98
139     };
140
141     var example2 = {
142         A1: [17.2, 20.9, 22.6, 18.1, 21.7, 21.4, 23.5, 24.2, 14.7, 21.8],
143         A2: [21.5, 22.8, 21.0, 23.0, 21.6, 23.6, 22.5, 20.7, 23.4, 21.8, 20.7, 21.7, 21.5, 22.5, 23.6, 21.5, 22.5, 23.5, 21.5, 21.8],
144         expectedT: 1.57,
145         expectedDegreesOfFreedom: 9.9,
146         expectedRange: [0.8, 0.9] // P = 0.149 so 1 - P = 0.851 is between 0.8 and 0.9
147     };
148
149     var example3 = {
150         A1: [19.8, 20.4, 19.6, 17.8, 18.5, 18.9, 18.3, 18.9, 19.5, 22.0],
151         A2: [28.2, 26.6, 20.1, 23.3, 25.2, 22.1, 17.7, 27.6, 20.6, 13.7, 23.2, 17.5, 20.6, 18.0, 23.9, 21.6, 24.3, 20.4, 24.0, 13.2],
152         expectedT: 2.22,
153         expectedDegreesOfFreedom: 24.5,
154         expectedRange: [0.95, 0.98] // P = 0.036 so 1 - P = 0.964 is beteween 0.95 and 0.98
155     };
156
157     describe('computeWelchsT', function () {
158         function computeWelchsT(values1, values2, probability) {
159             return Statistics.computeWelchsT(values1, 0, values1.length, values2, 0, values2.length, probability);
160         }
161
162         it('should detect the statistically significant difference using Welch\'s t-test', function () {
163             assert.equal(computeWelchsT(example1.A1, example1.A2, 0.8).significantlyDifferent, true);
164             assert.equal(computeWelchsT(example1.A1, example1.A2, 0.9).significantlyDifferent, true);
165             assert.equal(computeWelchsT(example1.A1, example1.A2, 0.95).significantlyDifferent, true);
166             assert.equal(computeWelchsT(example1.A1, example1.A2, 0.98).significantlyDifferent, false);
167
168             assert.equal(computeWelchsT(example2.A1, example2.A2, 0.8).significantlyDifferent, true);
169             assert.equal(computeWelchsT(example2.A1, example2.A2, 0.9).significantlyDifferent, false);
170             assert.equal(computeWelchsT(example2.A1, example2.A2, 0.95).significantlyDifferent, false);
171             assert.equal(computeWelchsT(example2.A1, example2.A2, 0.98).significantlyDifferent, false);
172
173             assert.equal(computeWelchsT(example3.A1, example3.A2, 0.8).significantlyDifferent, true);
174             assert.equal(computeWelchsT(example3.A1, example3.A2, 0.9).significantlyDifferent, true);
175             assert.equal(computeWelchsT(example3.A1, example3.A2, 0.95).significantlyDifferent, true);
176             assert.equal(computeWelchsT(example3.A1, example3.A2, 0.98).significantlyDifferent, false);
177         });
178
179         it('should find the t-value of values using Welch\'s t-test', function () {
180             assert.almostEqual(computeWelchsT(example1.A1, example1.A2).t, example1.expectedT, 2);
181             assert.almostEqual(computeWelchsT(example2.A1, example2.A2).t, example2.expectedT, 2);
182             assert.almostEqual(computeWelchsT(example3.A1, example3.A2).t, example3.expectedT, 2);
183         });
184
185         it('should find the degreees of freedom using Welch–Satterthwaite equation', function () {
186             assert.almostEqual(computeWelchsT(example1.A1, example1.A2).degreesOfFreedom, example1.expectedDegreesOfFreedom, 2);
187             assert.almostEqual(computeWelchsT(example2.A1, example2.A2).degreesOfFreedom, example2.expectedDegreesOfFreedom, 2);
188             assert.almostEqual(computeWelchsT(example3.A1, example3.A2).degreesOfFreedom, example3.expectedDegreesOfFreedom, 2);
189         });
190
191         it('should respect the start and the end indices', function () {
192             var A1 = example2.A1.slice();
193             var A2 = example2.A2.slice();
194
195             var expectedT = Statistics.computeWelchsT(A1, 0, A1.length, A2, 0, A2.length).t;
196
197             A1.unshift(21);
198             A1.push(15);
199             A1.push(24);
200             assert.almostEqual(Statistics.computeWelchsT(A1, 1, A1.length - 3, A2, 0, A2.length).t, expectedT);
201
202             A2.unshift(24.3);
203             A2.unshift(25.8);
204             A2.push(23);
205             A2.push(24);
206             A2 = A2.reverse();
207             assert.almostEqual(Statistics.computeWelchsT(A1, 1, A1.length - 3, A2, 2, A2.length - 4).t, expectedT);
208         });
209     });
210
211     describe('probabilityRangeForWelchsT', function () {
212         it('should find the t-value of values using Welch\'s t-test', function () {
213             assert.almostEqual(Statistics.probabilityRangeForWelchsT(example1.A1, example1.A2).t, example1.expectedT, 2);
214             assert.almostEqual(Statistics.probabilityRangeForWelchsT(example2.A1, example2.A2).t, example2.expectedT, 2);
215             assert.almostEqual(Statistics.probabilityRangeForWelchsT(example3.A1, example3.A2).t, example3.expectedT, 2);
216         });
217
218         it('should find the degreees of freedom using Welch–Satterthwaite equation', function () {
219             assert.almostEqual(Statistics.probabilityRangeForWelchsT(example1.A1, example1.A2).degreesOfFreedom,
220                 example1.expectedDegreesOfFreedom, 2);
221             assert.almostEqual(Statistics.probabilityRangeForWelchsT(example2.A1, example2.A2).degreesOfFreedom,
222                 example2.expectedDegreesOfFreedom, 2);
223             assert.almostEqual(Statistics.probabilityRangeForWelchsT(example3.A1, example3.A2).degreesOfFreedom,
224                 example3.expectedDegreesOfFreedom, 2);
225         });
226
227         it('should compute the range of probabilites using the p-value of Welch\'s t-test', function () {
228             assert.almostEqual(Statistics.probabilityRangeForWelchsT(example1.A1, example1.A2).range[0], example1.expectedRange[0]);
229             assert.almostEqual(Statistics.probabilityRangeForWelchsT(example1.A1, example1.A2).range[1], example1.expectedRange[1]);
230
231             assert.almostEqual(Statistics.probabilityRangeForWelchsT(example2.A1, example2.A2).range[0], example2.expectedRange[0]);
232             assert.almostEqual(Statistics.probabilityRangeForWelchsT(example2.A1, example2.A2).range[1], example2.expectedRange[1]);
233
234             assert.almostEqual(Statistics.probabilityRangeForWelchsT(example3.A1, example3.A2).range[0], example3.expectedRange[0]);
235             assert.almostEqual(Statistics.probabilityRangeForWelchsT(example3.A1, example3.A2).range[1], example3.expectedRange[1]);
236         });
237     });
238
239     describe('minimumTForOneSidedProbability', () => {
240         it('should not infinite loop when lookup t-value for any degrees of freedom', () => {
241             for(const probability of [0.9, 0.95, 0.975, 0.99]) {
242                 for (let degreesOfFreedom = 1; degreesOfFreedom < 100000; degreesOfFreedom += 1)
243                     Statistics.minimumTForOneSidedProbability(probability, degreesOfFreedom);
244             }
245         })
246     });
247
248     describe('probabilityRangeForWelchsTForMultipleSamples', () => {
249         function splitSample(samples) {
250             const mid = samples.length / 2;
251             return splitSampleByIndices(samples, mid);
252         }
253
254         function splitSampleByIndices(samples, ...indices) {
255             const sampleSize = samples.length;
256             const splittedSamples = [];
257             let previousIndex = 0;
258             for (const index of indices) {
259                 if (index == previousIndex)
260                     continue;
261                 console.assert(index > previousIndex);
262                 console.assert(index <= sampleSize);
263                 splittedSamples.push(samples.slice(previousIndex, index));
264                 previousIndex = index;
265             }
266             if (previousIndex < sampleSize)
267                 splittedSamples.push(samples.slice(previousIndex, sampleSize));
268             return splittedSamples.map((values) => ({sum: Statistics.sum(values), squareSum: Statistics.squareSum(values), sampleSize: values.length}));
269         }
270
271         it('should find the t-value of values using Welch\'s t-test', () => {
272             assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSample(example1.A1), splitSample(example1.A2)).t, example1.expectedT, 2);
273             assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSample(example2.A1), splitSample(example2.A2)).t, example2.expectedT, 2);
274             assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSample(example3.A1), splitSample(example3.A2)).t, example3.expectedT, 2);
275
276             assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example1.A1, 1), splitSampleByIndices(example1.A2, 1)).t, example1.expectedT, 2);
277             assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example2.A1, 1), splitSampleByIndices(example2.A2, 1)).t, example2.expectedT, 2);
278             assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example3.A1, 1), splitSampleByIndices(example3.A2, 1)).t, example3.expectedT, 2);
279
280             assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example1.A1, 0), splitSampleByIndices(example1.A2, 0)).t, example1.expectedT, 2);
281             assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example2.A1, 0), splitSampleByIndices(example2.A2, 0)).t, example2.expectedT, 2);
282             assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example3.A1, 0), splitSampleByIndices(example3.A2, 0)).t, example3.expectedT, 2);
283
284             assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example1.A1, 1, 4), splitSampleByIndices(example1.A2, 1, 4)).t, example1.expectedT, 2);
285             assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example2.A1, 1, 4), splitSampleByIndices(example2.A2, 1, 4)).t, example2.expectedT, 2);
286             assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example3.A1, 1, 4), splitSampleByIndices(example3.A2, 1, 4)).t, example3.expectedT, 2);
287         });
288
289         it('should find the degreees of freedom using Welch–Satterthwaite equation when split evenly', () => {
290             assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSample(example1.A1), splitSample(example1.A2)).degreesOfFreedom,
291                 example1.expectedDegreesOfFreedom, 2);
292             assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSample(example2.A1), splitSample(example2.A2)).degreesOfFreedom,
293                 example2.expectedDegreesOfFreedom, 2);
294             assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSample(example3.A1), splitSample(example3.A2)).degreesOfFreedom,
295                 example3.expectedDegreesOfFreedom, 2);
296
297             assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example1.A1, 1), splitSampleByIndices(example1.A2, 1)).degreesOfFreedom,
298                 example1.expectedDegreesOfFreedom, 2);
299             assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example2.A1, 1), splitSampleByIndices(example2.A2, 1)).degreesOfFreedom,
300                 example2.expectedDegreesOfFreedom, 2);
301             assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example3.A1, 1), splitSampleByIndices(example3.A2, 1)).degreesOfFreedom,
302                 example3.expectedDegreesOfFreedom, 2);
303
304             assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example1.A1, 0), splitSampleByIndices(example1.A2, 0)).degreesOfFreedom,
305                 example1.expectedDegreesOfFreedom, 2);
306             assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example2.A1, 0), splitSampleByIndices(example2.A2, 0)).degreesOfFreedom,
307                 example2.expectedDegreesOfFreedom, 2);
308             assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example3.A1, 0), splitSampleByIndices(example3.A2, 0)).degreesOfFreedom,
309                 example3.expectedDegreesOfFreedom, 2);
310
311             assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example1.A1, 1, 4), splitSampleByIndices(example1.A2, 1, 4)).degreesOfFreedom,
312                 example1.expectedDegreesOfFreedom, 2);
313             assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example2.A1, 1, 4), splitSampleByIndices(example2.A2, 1, 4)).degreesOfFreedom,
314                 example2.expectedDegreesOfFreedom, 2);
315             assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example3.A1, 1, 4), splitSampleByIndices(example3.A2, 1, 4)).degreesOfFreedom,
316                 example3.expectedDegreesOfFreedom, 2);
317         });
318
319         it('should compute the range of probabilites using the p-value of Welch\'s t-test when split evenly', function () {
320             assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSample(example1.A1), splitSample(example1.A2)).range[0], example1.expectedRange[0]);
321             assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSample(example1.A1), splitSample(example1.A2)).range[1], example1.expectedRange[1]);
322
323             assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSample(example2.A1), splitSample(example2.A2)).range[0], example2.expectedRange[0]);
324             assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSample(example2.A1), splitSample(example2.A2)).range[1], example2.expectedRange[1]);
325
326             assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSample(example3.A1), splitSample(example3.A2)).range[0], example3.expectedRange[0]);
327             assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSample(example3.A1), splitSample(example3.A2)).range[1], example3.expectedRange[1]);
328
329             assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example1.A1, 1), splitSampleByIndices(example1.A2, 1)).range[0], example1.expectedRange[0]);
330             assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example1.A1, 1), splitSampleByIndices(example1.A2, 1)).range[1], example1.expectedRange[1]);
331
332             assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example2.A1, 1), splitSampleByIndices(example2.A2, 1)).range[0], example2.expectedRange[0]);
333             assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example2.A1, 1), splitSampleByIndices(example2.A2, 1)).range[1], example2.expectedRange[1]);
334
335             assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example3.A1, 1), splitSampleByIndices(example3.A2, 1)).range[0], example3.expectedRange[0]);
336             assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example3.A1, 1), splitSampleByIndices(example3.A2, 1)).range[1], example3.expectedRange[1]);
337
338             assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example1.A1, 0), splitSampleByIndices(example1.A2, 0)).range[0], example1.expectedRange[0]);
339             assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example1.A1, 0), splitSampleByIndices(example1.A2, 0)).range[1], example1.expectedRange[1]);
340
341             assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example2.A1, 0), splitSampleByIndices(example2.A2, 0)).range[0], example2.expectedRange[0]);
342             assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example2.A1, 0), splitSampleByIndices(example2.A2, 0)).range[1], example2.expectedRange[1]);
343
344             assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example3.A1, 0), splitSampleByIndices(example3.A2, 0)).range[0], example3.expectedRange[0]);
345             assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example3.A1, 0), splitSampleByIndices(example3.A2, 0)).range[1], example3.expectedRange[1]);
346
347
348             assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example1.A1, 1, 4), splitSampleByIndices(example1.A2, 1, 4)).range[0], example1.expectedRange[0]);
349             assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example1.A1, 1, 4), splitSampleByIndices(example1.A2, 1, 4)).range[1], example1.expectedRange[1]);
350
351             assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example2.A1, 1, 4), splitSampleByIndices(example2.A2, 1, 4)).range[0], example2.expectedRange[0]);
352             assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example2.A1, 1, 4), splitSampleByIndices(example2.A2, 1, 4)).range[1], example2.expectedRange[1]);
353
354             assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example3.A1, 1, 4), splitSampleByIndices(example3.A2, 1, 4)).range[0], example3.expectedRange[0]);
355             assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example3.A1, 1, 4), splitSampleByIndices(example3.A2, 1, 4)).range[1], example3.expectedRange[1]);
356
357         });
358     });
359
360     describe('movingAverage', function () {
361         it('should return the origian values when both forward and backward window size is 0', function () {
362             assert.deepEqual(Statistics.movingAverage([1, 2, 3, 4, 5], 0, 0), [1, 2, 3, 4, 5]);
363         });
364
365         it('should find the moving average with a positive backward window', function () {
366             assert.deepEqual(Statistics.movingAverage([1, 2, 3, 4, 5], 1, 0),
367                 [1, (1 + 2) / 2, (2 + 3) / 2, (3 + 4) / 2, (4 + 5) / 2]);
368
369             assert.deepEqual(Statistics.movingAverage([1, 2, 3, 4, 5], 2, 0),
370                 [1, (1 + 2) / 2, (1 + 2 + 3) / 3, (2 + 3 + 4) / 3, (3 + 4 + 5) / 3]);
371
372             assert.deepEqual(Statistics.movingAverage([1, 2, 3, 4, 5], 3, 0),
373                 [1, (1 + 2) / 2, (1 + 2 + 3) / 3, (1 + 2 + 3 + 4) / 4, (2 + 3 + 4 + 5) / 4]);
374
375             assert.deepEqual(Statistics.movingAverage([1, 2, 3, 4, 5], 4, 0),
376                 [1, (1 + 2) / 2, (1 + 2 + 3) / 3, (1 + 2 + 3 + 4) / 4, (1 + 2 + 3 + 4 + 5) / 5]);
377
378             assert.deepEqual(Statistics.movingAverage([1, 2, 3, 4, 5], 5, 0),
379                 [1, (1 + 2) / 2, (1 + 2 + 3) / 3, (1 + 2 + 3 + 4) / 4, (1 + 2 + 3 + 4 + 5) / 5]);
380         });
381
382         it('should find the moving average with a positive forward window', function () {
383             assert.deepEqual(Statistics.movingAverage([1, 2, 3, 4, 5], 0, 1),
384                 [(1 + 2) / 2, (2 + 3) / 2, (3 + 4) / 2, (4 + 5) / 2, 5]);
385
386             assert.deepEqual(Statistics.movingAverage([1, 2, 3, 4, 5], 0, 2),
387                 [(1 + 2 + 3) / 3, (2 + 3 + 4) / 3, (3 + 4 + 5) / 3, (4 + 5) / 2, 5]);
388
389             assert.deepEqual(Statistics.movingAverage([1, 2, 3, 4, 5], 0, 3),
390                 [(1 + 2 + 3 + 4) / 4, (2 + 3 + 4 + 5) / 4, (3 + 4 + 5) / 3, (4 + 5) / 2, 5]);
391
392             assert.deepEqual(Statistics.movingAverage([1, 2, 3, 4, 5], 0, 4),
393                 [(1 + 2 + 3 + 4 + 5) / 5, (2 + 3 + 4 + 5) / 4, (3 + 4 + 5) / 3, (4 + 5) / 2, 5]);
394
395             assert.deepEqual(Statistics.movingAverage([1, 2, 3, 4, 5], 0, 5),
396                 [(1 + 2 + 3 + 4 + 5) / 5, (2 + 3 + 4 + 5) / 4, (3 + 4 + 5) / 3, (4 + 5) / 2, 5]);
397         });
398
399         it('should find the moving average when both backward and forward window sizes are specified', function () {
400             assert.deepEqual(Statistics.movingAverage([1, 2, 3, 4, 5], 1, 1),
401                 [(1 + 2) / 2, (1 + 2 + 3) / 3, (2 + 3 + 4) / 3, (3 + 4 + 5) / 3, (4 + 5) / 2]);
402
403             assert.deepEqual(Statistics.movingAverage([1, 2, 3, 4, 5], 1, 2),
404                 [(1 + 2 + 3) / 3, (1 + 2 + 3 + 4) / 4, (2 + 3 + 4 + 5) / 4, (3 + 4 + 5) / 3, (4 + 5) / 2]);
405
406             assert.deepEqual(Statistics.movingAverage([1, 2, 3, 4, 5], 2, 1),
407                 [(1 + 2) / 2, (1 + 2 + 3) / 3, (1 + 2 + 3 + 4) / 4, (2 + 3 + 4 + 5) / 4, (3 + 4 + 5) / 3]);
408
409             assert.deepEqual(Statistics.movingAverage([1, 2, 3, 4, 5], 2, 2),
410                 [(1 + 2 + 3) / 3, (1 + 2 + 3 + 4) / 4, (1 + 2 + 3 + 4 + 5) / 5, (2 + 3 + 4 + 5) / 4, (3 + 4 + 5) / 3]);
411
412             assert.deepEqual(Statistics.movingAverage([1, 2, 3, 4, 5], 2, 3),
413                 [(1 + 2 + 3 + 4) / 4, (1 + 2 + 3 + 4 + 5) / 5, (1 + 2 + 3 + 4 + 5) / 5, (2 + 3 + 4 + 5) / 4, (3 + 4 + 5) / 3]);
414
415             assert.deepEqual(Statistics.movingAverage([1, 2, 3, 4, 5], 3, 2),
416                 [(1 + 2 + 3) / 3, (1 + 2 + 3 + 4) / 4, (1 + 2 + 3 + 4 + 5) / 5, (1 + 2 + 3 + 4 + 5) / 5, (2 + 3 + 4 + 5) / 4]);
417
418             assert.deepEqual(Statistics.movingAverage([1, 2, 3, 4, 5], 3, 3),
419                 [(1 + 2 + 3 + 4) / 4, (1 + 2 + 3 + 4 + 5) / 5, (1 + 2 + 3 + 4 + 5) / 5, (1 + 2 + 3 + 4 + 5) / 5, (2 + 3 + 4 + 5) / 4]);
420         });
421     });
422
423     describe('cumulativeMovingAverage', function () {
424         it('should find the cumulative moving average', function () {
425             assert.deepEqual(Statistics.cumulativeMovingAverage([1, 2, 3, 4, 5]),
426                 [1, (1 + 2) / 2, (1 + 2 + 3) / 3, (1 + 2 + 3 + 4) / 4, (1 + 2 + 3 + 4 + 5) / 5]);
427
428             assert.deepEqual(Statistics.cumulativeMovingAverage([-1, 7, 0, 8.5, 2]),
429                 [-1, (-1 + 7) / 2, (-1 + 7 + 0) / 3, (-1 + 7 + 0 + 8.5) / 4, (-1 + 7 + 0 + 8.5 + 2) / 5]);
430         });
431     });
432
433     describe('exponentialMovingAverage', function () {
434         it('should find the exponential moving average', function () {
435             var averages = Statistics.exponentialMovingAverage([1, 2, 3, 4, 5], 0.2);
436             assert.equal(averages[0], 1);
437             assert.almostEqual(averages[1], 0.2 * 2 + 0.8 * averages[0]);
438             assert.almostEqual(averages[2], 0.2 * 3 + 0.8 * averages[1]);
439             assert.almostEqual(averages[3], 0.2 * 4 + 0.8 * averages[2]);
440             assert.almostEqual(averages[4], 0.2 * 5 + 0.8 * averages[3]);
441
442             averages = Statistics.exponentialMovingAverage([0.8, -0.2, 0.4, -0.3, 0.5], 0.1);
443             assert.almostEqual(averages[0], 0.8);
444             assert.almostEqual(averages[1], 0.1 * -0.2 + 0.9 * averages[0]);
445             assert.almostEqual(averages[2], 0.1 * 0.4 + 0.9 * averages[1]);
446             assert.almostEqual(averages[3], 0.1 * -0.3 + 0.9 * averages[2]);
447             assert.almostEqual(averages[4], 0.1 * 0.5 + 0.9 * averages[3]);
448         });
449     });
450
451     describe('segmentTimeSeriesGreedyWithStudentsTTest', function () {
452         it('should segment time series', function () {
453             assert.deepEqual(Statistics.segmentTimeSeriesGreedyWithStudentsTTest([1, 1, 1, 3, 3, 3], 1), [0, 2, 6]);
454             assert.deepEqual(Statistics.segmentTimeSeriesGreedyWithStudentsTTest([1, 1.2, 0.9, 1.1, 1.5, 1.7, 1.8], 1), [0, 4, 7]);
455         });
456     });
457
458     describe('segmentTimeSeriesByMaximizingSchwarzCriterion', function () {
459         it('should segment time series of length 0 into a single segment', function () {
460             var values = [];
461             assert.deepEqual(Statistics.segmentTimeSeriesByMaximizingSchwarzCriterion(values), [0, 0]);
462         });
463
464         it('should not segment time series of length two into two pieces', function () {
465             var values = [1, 2];
466             assert.deepEqual(Statistics.segmentTimeSeriesByMaximizingSchwarzCriterion(values), [0, 2]);
467         });
468
469         it('should segment time series [1, 2, 3] into three pieces', function () {
470             var values = [1, 2, 3];
471             assert.deepEqual(Statistics.segmentTimeSeriesByMaximizingSchwarzCriterion(values), [0, 1, 3]);
472         });
473
474         it('should segment time series for platform=47 metric=4875 between 1453938553772 and 1454630903100 into two parts', function () {
475             var values = [
476                 1546.5603, 1548.1536, 1563.5452, 1539.7823, 1546.4184, 1548.9299, 1532.5444, 1546.2800, 1547.1760, 1551.3507,
477                 1548.3277, 1544.7673, 1542.7157, 1538.1700, 1538.0948, 1543.0364, 1537.9737, 1542.2611, 1543.9685, 1546.4901,
478                 1544.4080, 1540.8671, 1537.3353, 1549.4331, 1541.4436, 1544.1299, 1550.1770, 1553.1872, 1549.3417, 1542.3788,
479                 1543.5094, 1541.7905, 1537.6625, 1547.3840, 1538.5185, 1549.6764, 1556.6138, 1552.0476, 1541.7629, 1544.7006,
480                 /* segments changes here */
481                 1587.1390, 1594.5451, 1586.2430, 1596.7310, 1548.1423];
482             assert.deepEqual(Statistics.segmentTimeSeriesByMaximizingSchwarzCriterion(values), [0, 39, values.length]);
483         });
484
485         it('should segment time series for platform=51 metric=4565 betweeen 1452191332230 and 1454628206453 into two parts', function () {
486             var values = [
487                 147243216, 147736350, 146670090, 146629723, 142749220, 148234161, 147303822, 145112097, 145852468, 147094741,
488                 147568897, 145160531, 148028242, 141272279, 144323236, 147492567, 146219156, 144895726, 144418925, 145455873,
489                 141924694, 141025833, 142082139, 144154698, 145312939, 148282554, 151852126, 149303740, 149431703, 150300257,
490                 148752468, 150449779, 150030118, 150553542, 151775421, 146666762, 149492535, 147143284, 150356837, 147799616,
491                 149889520,
492                 258634751, 147397840, 256106147, 261100534, 255903392, 259658019, 259501433, 257685682, 258460322, 255563633,
493                 259050663, 255567490, 253274911];
494             assert.deepEqual(Statistics.segmentTimeSeriesByMaximizingSchwarzCriterion(values), [0, 40, values.length]);
495         });
496
497         it('should not segment time series for platform=51 metric=4817 betweeen 1453926047749 and 1454635479052 into multiple parts', function () {
498             var values = [
499                 5761.3, 5729.4, 5733.49, 5727.4, 5726.56, 5727.48, 5716.79, 5721.23, 5682.5, 5735.71,
500                 5750.99, 5755.51, 5756.02, 5725.76, 5710.14, 5776.17, 5774.29, 5769.99, 5739.65, 5756.05,
501                 5722.87, 5726.8, 5779.23, 5772.2, 5763.1, 5807.05];
502             assert.deepEqual(Statistics.segmentTimeSeriesByMaximizingSchwarzCriterion(values), [0, values.length]);
503         });
504
505         it('should not segment time series for platform=51 metric=4817 betweeen 1453926047749 and 1454635479052 into multiple parts', function () {
506             var values = new Array(37);
507             for (let i = 0; i < 37; i++)
508                 values[i] = 1;
509             assert.deepEqual(Statistics.segmentTimeSeriesByMaximizingSchwarzCriterion(values), [ 0, 6, 16, 26, 37 ]);
510         });
511     });
512
513     describe('findRangesForChangeDetectionsWithWelchsTTest', () => {
514         it('should return an empty array if the value is empty list', () => {
515             assert.deepEqual(Statistics.findRangesForChangeDetectionsWithWelchsTTest([], [], 0.975), []);
516         });
517
518         it('should return an empty array if segmentation is empty list', () => {
519             assert.deepEqual(Statistics.findRangesForChangeDetectionsWithWelchsTTest([1,2,3], [], 0.975), []);
520         });
521
522         it('should return the range if computeWelchsT shows a significant change', () => {
523             const values = [
524                 747.30337423744,
525                 731.47392585276,
526                 743.66763513161,
527                 738.02055323487,
528                 738.25426340842,
529                 742.38680046471,
530                 733.13921703284,
531                 739.22069966147,
532                 735.69295749633,
533                 743.01705472504,
534                 745.45778145306,
535                 731.04841157169,
536                 729.4372674973,
537                 735.4497416527,
538                 739.0230668644,
539                 730.91782989909,
540                 722.18725411279,
541                 731.96223451728,
542                 730.04119216192,
543                 730.78087646284,
544                 729.63155210365,
545                 730.17585200878,
546                 733.93766054706,
547                 740.74920717197,
548                 752.14718023647,
549                 764.49990164847,
550                 766.36100828473,
551                 756.2291883252,
552                 750.14522451097,
553                 749.57595092266,
554                 748.03624881866,
555                 769.41522176386,
556                 744.04660430456,
557                 751.17927808265,
558                 753.29996854062,
559                 757.01813756936,
560                 746.62413820741,
561                 742.64420062736,
562                 758.12726352772,
563                 778.2278439089,
564                 775.11818554541,
565                 775.11818554541];
566             const segmentation = [{
567                     seriesIndex: 0,
568                     time: 1505176030671,
569                     value: 736.5366704896555,
570                     x: 370.4571789404566,
571                     y: 185.52613334520248,
572                 },
573                 {
574                     seriesIndex: 18,
575                     time: 1515074391534,
576                     value: 736.5366704896555,
577                     x: 919.4183852714947,
578                     y: 185.52613334520248
579                 },
580                 {
581                     seriesIndex: 18,
582                     time: 1515074391534,
583                     value: 750.3483428383142,
584                     x: 919.4183852714947,
585                     y: 177.9710953409673,
586                 },
587                 {
588                     seriesIndex: 41,
589                     time: 1553851695869,
590                     value: 750.3483428383142,
591                     x: 3070.000290764446,
592                     y: 177.9710953409673,
593                 }];
594             assert.deepEqual(Statistics.findRangesForChangeDetectionsWithWelchsTTest(values, segmentation, 0.975), [
595                 {
596                   "endIndex": 29,
597                   "segmentationEndValue": 750.3483428383142,
598                   "segmentationStartValue": 736.5366704896555,
599                   "startIndex": 6
600                 }
601             ]);
602         })
603     });
604 });