2024-10-30 08:45:46 -08:00
|
|
|
"use strict";
|
|
|
|
|
/*
|
|
|
|
|
* Copyright (C) 2018 Apple Inc. All rights reserved.
|
|
|
|
|
*
|
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
|
* are met:
|
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
|
*
|
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
|
|
|
|
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
|
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
|
|
|
|
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
|
|
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
|
|
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
|
|
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
|
|
|
|
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
|
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
// Statistics.js
|
|
|
|
|
var Statistics = new (function () {
|
|
|
|
|
|
|
|
|
|
this.min = function (values) {
|
|
|
|
|
return Math.min.apply(Math, values);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.max = function (values) {
|
|
|
|
|
return Math.max.apply(Math, values);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.sum = function (values) {
|
|
|
|
|
return values.length ? values.reduce(function (a, b) { return a + b; }) : 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.mean = function (values) {
|
|
|
|
|
return this.sum(values) / values.length;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.median = function (values) {
|
|
|
|
|
return values.sort(function (a, b) { return a - b; })[Math.floor(values.length / 2)];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.squareSum = function (values) {
|
|
|
|
|
return values.length ? values.reduce(function (sum, value) { return sum + value * value;}, 0) : 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// With sum and sum of squares, we can compute the sample standard deviation in O(1).
|
|
|
|
|
// See https://rniwa.com/2012-11-10/sample-standard-deviation-in-terms-of-sum-and-square-sum-of-samples/
|
|
|
|
|
this.sampleStandardDeviation = function (numberOfSamples, sum, squareSum) {
|
|
|
|
|
if (numberOfSamples < 2)
|
|
|
|
|
return 0;
|
|
|
|
|
return Math.sqrt(squareSum / (numberOfSamples - 1) - sum * sum / (numberOfSamples - 1) / numberOfSamples);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.supportedConfidenceIntervalProbabilities = function () {
|
|
|
|
|
var supportedProbabilities = [];
|
|
|
|
|
for (var probability in tDistributionByOneSidedProbability)
|
|
|
|
|
supportedProbabilities.push(oneSidedToTwoSidedProbability(probability).toFixed(2));
|
|
|
|
|
return supportedProbabilities
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.supportedOneSideTTestProbabilities = function () {
|
|
|
|
|
return Object.keys(tDistributionByOneSidedProbability);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Computes the delta d s.t. (mean - d, mean + d) is the confidence interval with the specified probability in O(1).
|
|
|
|
|
this.confidenceIntervalDelta = function (probability, numberOfSamples, sum, squareSum) {
|
|
|
|
|
var oneSidedProbability = twoSidedToOneSidedProbability(probability);
|
|
|
|
|
if (!(oneSidedProbability in tDistributionByOneSidedProbability)) {
|
|
|
|
|
throw 'We only support ' + this.supportedConfidenceIntervalProbabilities().map(function (probability)
|
|
|
|
|
{ return probability * 100 + '%'; } ).join(', ') + ' confidence intervals.';
|
|
|
|
|
}
|
|
|
|
|
if (numberOfSamples - 2 < 0)
|
|
|
|
|
return NaN;
|
|
|
|
|
var deltas = tDistributionByOneSidedProbability[oneSidedProbability];
|
|
|
|
|
var degreesOfFreedom = numberOfSamples - 1;
|
|
|
|
|
if (degreesOfFreedom > deltas.length)
|
|
|
|
|
throw 'We only support up to ' + deltas.length + ' degrees of freedom';
|
|
|
|
|
|
|
|
|
|
// d = c * S/sqrt(numberOfSamples) where c ~ t-distribution(degreesOfFreedom) and S is the sample standard deviation.
|
|
|
|
|
return deltas[degreesOfFreedom - 1] * this.sampleStandardDeviation(numberOfSamples, sum, squareSum) / Math.sqrt(numberOfSamples);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.confidenceInterval = function (values, probability) {
|
|
|
|
|
var sum = this.sum(values);
|
|
|
|
|
var mean = sum / values.length;
|
|
|
|
|
var delta = this.confidenceIntervalDelta(probability || 0.95, values.length, sum, this.squareSum(values));
|
|
|
|
|
return [mean - delta, mean + delta];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Welch's t-test (http://en.wikipedia.org/wiki/Welch%27s_t_test)
|
|
|
|
|
this.testWelchsT = function (values1, values2, probability) {
|
|
|
|
|
return this.computeWelchsT(values1, 0, values1.length, values2, 0, values2.length, probability).significantlyDifferent;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.probabilityRangeForWelchsT = function (values1, values2) {
|
|
|
|
|
var result = this.computeWelchsT(values1, 0, values1.length, values2, 0, values2.length);
|
|
|
|
|
if (isNaN(result.t) || isNaN(result.degreesOfFreedom))
|
|
|
|
|
return {t: NaN, degreesOfFreedom:NaN, range: [null, null]};
|
|
|
|
|
|
|
|
|
|
var lowerBound = null;
|
|
|
|
|
var upperBound = null;
|
|
|
|
|
for (var probability in tDistributionByOneSidedProbability) {
|
|
|
|
|
var twoSidedProbability = oneSidedToTwoSidedProbability(probability);
|
|
|
|
|
if (result.t > tDistributionByOneSidedProbability[probability][Math.round(result.degreesOfFreedom - 1)])
|
|
|
|
|
lowerBound = twoSidedProbability;
|
|
|
|
|
else if (lowerBound) {
|
|
|
|
|
upperBound = twoSidedProbability;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return {t: result.t, degreesOfFreedom: result.degreesOfFreedom, range: [lowerBound, upperBound]};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.computeWelchsT = function (values1, startIndex1, length1, values2, startIndex2, length2, probability) {
|
|
|
|
|
var stat1 = sampleMeanAndVarianceForValues(values1, startIndex1, length1);
|
|
|
|
|
var stat2 = sampleMeanAndVarianceForValues(values2, startIndex2, length2);
|
|
|
|
|
var sumOfSampleVarianceOverSampleSize = stat1.variance / stat1.size + stat2.variance / stat2.size;
|
|
|
|
|
var t = Math.abs((stat1.mean - stat2.mean) / Math.sqrt(sumOfSampleVarianceOverSampleSize));
|
|
|
|
|
|
2025-09-03 03:23:43 -08:00
|
|
|
// http://en.wikipedia.org/wiki/Welch-Satterthwaite_equation
|
2024-10-30 08:45:46 -08:00
|
|
|
var degreesOfFreedom = sumOfSampleVarianceOverSampleSize * sumOfSampleVarianceOverSampleSize
|
|
|
|
|
/ (stat1.variance * stat1.variance / stat1.size / stat1.size / stat1.degreesOfFreedom
|
|
|
|
|
+ stat2.variance * stat2.variance / stat2.size / stat2.size / stat2.degreesOfFreedom);
|
|
|
|
|
var minT = tDistributionByOneSidedProbability[twoSidedToOneSidedProbability(probability || 0.8)][Math.round(degreesOfFreedom - 1)];
|
|
|
|
|
return {
|
|
|
|
|
t: t,
|
|
|
|
|
degreesOfFreedom: degreesOfFreedom,
|
|
|
|
|
significantlyDifferent: t > minT,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.findRangesForChangeDetectionsWithWelchsTTest = function (values, segmentations, oneSidedPossibility=0.99) {
|
|
|
|
|
if (!values.length)
|
|
|
|
|
return [];
|
|
|
|
|
|
|
|
|
|
const selectedRanges = [];
|
|
|
|
|
const twoSidedFromOneSidedPossibility = 2 * oneSidedPossibility - 1;
|
|
|
|
|
|
|
|
|
|
for (let i = 1; i + 2 < segmentations.length; i += 2) {
|
|
|
|
|
let found = false;
|
|
|
|
|
const previousMean = segmentations[i].value;
|
|
|
|
|
const currentMean = segmentations[i + 1].value;
|
|
|
|
|
console.assert(currentMean != previousMean);
|
|
|
|
|
const currentChangePoint = segmentations[i].seriesIndex;
|
|
|
|
|
const start = segmentations[i - 1].seriesIndex;
|
|
|
|
|
const end = segmentations[i + 2].seriesIndex;
|
|
|
|
|
|
|
|
|
|
for (let leftEdge = currentChangePoint - 2, rightEdge = currentChangePoint + 2; leftEdge >= start && rightEdge <= end; leftEdge--, rightEdge++) {
|
|
|
|
|
const result = this.computeWelchsT(values, leftEdge, currentChangePoint - leftEdge, values, currentChangePoint, rightEdge - currentChangePoint, twoSidedFromOneSidedPossibility);
|
|
|
|
|
if (result.significantlyDifferent) {
|
|
|
|
|
selectedRanges.push({
|
|
|
|
|
startIndex: leftEdge,
|
|
|
|
|
endIndex: rightEdge - 1,
|
|
|
|
|
segmentationStartValue: previousMean,
|
|
|
|
|
segmentationEndValue: currentMean
|
|
|
|
|
});
|
|
|
|
|
found = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!found && Statistics.debuggingTestingRangeNomination)
|
|
|
|
|
console.log('Failed to find a testing range at', currentChangePoint, 'changing from', previousMean, 'to', currentMean);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return selectedRanges;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
function sampleMeanAndVarianceForValues(values, startIndex, length) {
|
|
|
|
|
var sum = 0;
|
|
|
|
|
for (var i = 0; i < length; i++)
|
|
|
|
|
sum += values[startIndex + i];
|
|
|
|
|
var squareSum = 0;
|
|
|
|
|
for (var i = 0; i < length; i++)
|
|
|
|
|
squareSum += values[startIndex + i] * values[startIndex + i];
|
|
|
|
|
var sampleMean = sum / length;
|
|
|
|
|
// FIXME: Maybe we should be using the biased sample variance.
|
|
|
|
|
var unbiasedSampleVariance = (squareSum - sum * sum / length) / (length - 1);
|
|
|
|
|
return {
|
|
|
|
|
mean: sampleMean,
|
|
|
|
|
variance: unbiasedSampleVariance,
|
|
|
|
|
size: length,
|
|
|
|
|
degreesOfFreedom: length - 1,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.movingAverage = function (values, backwardWindowSize, forwardWindowSize) {
|
|
|
|
|
var averages = new Array(values.length);
|
|
|
|
|
// We use naive O(n^2) algorithm for simplicy as well as to avoid accumulating round-off errors.
|
|
|
|
|
for (var i = 0; i < values.length; i++) {
|
|
|
|
|
var sum = 0;
|
|
|
|
|
var count = 0;
|
|
|
|
|
for (var j = i - backwardWindowSize; j <= i + forwardWindowSize; j++) {
|
|
|
|
|
if (j >= 0 && j < values.length) {
|
|
|
|
|
sum += values[j];
|
|
|
|
|
count++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
averages[i] = sum / count;
|
|
|
|
|
}
|
|
|
|
|
return averages;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.cumulativeMovingAverage = function (values) {
|
|
|
|
|
var averages = new Array(values.length);
|
|
|
|
|
var sum = 0;
|
|
|
|
|
for (var i = 0; i < values.length; i++) {
|
|
|
|
|
sum += values[i];
|
|
|
|
|
averages[i] = sum / (i + 1);
|
|
|
|
|
}
|
|
|
|
|
return averages;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.exponentialMovingAverage = function (values, smoothingFactor) {
|
|
|
|
|
var averages = new Array(values.length);
|
|
|
|
|
var movingAverage = values[0];
|
|
|
|
|
averages[0] = movingAverage;
|
|
|
|
|
for (var i = 1; i < values.length; i++) {
|
|
|
|
|
movingAverage = smoothingFactor * values[i] + (1 - smoothingFactor) * movingAverage;
|
|
|
|
|
averages[i] = movingAverage;
|
|
|
|
|
}
|
|
|
|
|
return averages;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// The return value is the starting indices of each segment.
|
|
|
|
|
this.segmentTimeSeriesGreedyWithStudentsTTest = function (values, minLength) {
|
|
|
|
|
if (values.length < 2)
|
|
|
|
|
return [0];
|
|
|
|
|
var segments = new Array;
|
|
|
|
|
recursivelySplitIntoTwoSegmentsAtMaxTIfSignificantlyDifferent(values, 0, values.length, minLength, segments);
|
|
|
|
|
segments.push(values.length);
|
|
|
|
|
return segments;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.debuggingSegmentation = false;
|
|
|
|
|
this.segmentTimeSeriesByMaximizingSchwarzCriterion = function (values, segmentCountWeight, gridSize) {
|
|
|
|
|
// Split the time series into grids since splitIntoSegmentsUntilGoodEnough is O(n^2).
|
|
|
|
|
var gridLength = gridSize || 500;
|
|
|
|
|
var totalSegmentation = [0];
|
|
|
|
|
for (var gridCount = 0; gridCount < Math.ceil(values.length / gridLength); gridCount++) {
|
|
|
|
|
var gridValues = values.slice(gridCount * gridLength, (gridCount + 1) * gridLength);
|
|
|
|
|
var segmentation = splitIntoSegmentsUntilGoodEnough(gridValues, segmentCountWeight);
|
|
|
|
|
|
|
|
|
|
if (Statistics.debuggingSegmentation)
|
|
|
|
|
console.log('grid=' + gridCount, segmentation);
|
|
|
|
|
|
|
|
|
|
for (var i = 1; i < segmentation.length - 1; i++)
|
|
|
|
|
totalSegmentation.push(gridCount * gridLength + segmentation[i]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Statistics.debuggingSegmentation)
|
|
|
|
|
console.log('Final Segmentation', totalSegmentation);
|
|
|
|
|
|
|
|
|
|
totalSegmentation.push(values.length);
|
|
|
|
|
|
|
|
|
|
return totalSegmentation;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function recursivelySplitIntoTwoSegmentsAtMaxTIfSignificantlyDifferent(values, startIndex, length, minLength, segments) {
|
|
|
|
|
var tMax = 0;
|
|
|
|
|
var argTMax = null;
|
|
|
|
|
for (var i = 1; i < length - 1; i++) {
|
|
|
|
|
var firstLength = i;
|
|
|
|
|
var secondLength = length - i;
|
|
|
|
|
if (firstLength < minLength || secondLength < minLength)
|
|
|
|
|
continue;
|
|
|
|
|
var result = Statistics.computeWelchsT(values, startIndex, firstLength, values, startIndex + i, secondLength, 0.9);
|
|
|
|
|
if (result.significantlyDifferent && result.t > tMax) {
|
|
|
|
|
tMax = result.t;
|
|
|
|
|
argTMax = i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!tMax) {
|
|
|
|
|
segments.push(startIndex);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
recursivelySplitIntoTwoSegmentsAtMaxTIfSignificantlyDifferent(values, startIndex, argTMax, minLength, segments);
|
|
|
|
|
recursivelySplitIntoTwoSegmentsAtMaxTIfSignificantlyDifferent(values, startIndex + argTMax, length - argTMax, minLength, segments);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var tDistributionByOneSidedProbability = {
|
|
|
|
|
0.9: [
|
|
|
|
|
3.077684, 1.885618, 1.637744, 1.533206, 1.475884, 1.439756, 1.414924, 1.396815, 1.383029, 1.372184,
|
|
|
|
|
1.363430, 1.356217, 1.350171, 1.345030, 1.340606, 1.336757, 1.333379, 1.330391, 1.327728, 1.325341,
|
|
|
|
|
1.323188, 1.321237, 1.319460, 1.317836, 1.316345, 1.314972, 1.313703, 1.312527, 1.311434, 1.310415,
|
|
|
|
|
1.309464, 1.308573, 1.307737, 1.306952, 1.306212, 1.305514, 1.304854, 1.304230, 1.303639, 1.303077,
|
|
|
|
|
1.302543, 1.302035, 1.301552, 1.301090, 1.300649, 1.300228, 1.299825, 1.299439, 1.299069, 1.298714,
|
|
|
|
|
|
|
|
|
|
1.298373, 1.298045, 1.297730, 1.297426, 1.297134, 1.296853, 1.296581, 1.296319, 1.296066, 1.295821,
|
|
|
|
|
1.295585, 1.295356, 1.295134, 1.294920, 1.294712, 1.294511, 1.294315, 1.294126, 1.293942, 1.293763,
|
|
|
|
|
1.293589, 1.293421, 1.293256, 1.293097, 1.292941, 1.292790, 1.292643, 1.292500, 1.292360, 1.292224,
|
|
|
|
|
1.292091, 1.291961, 1.291835, 1.291711, 1.291591, 1.291473, 1.291358, 1.291246, 1.291136, 1.291029,
|
|
|
|
|
1.290924, 1.290821, 1.290721, 1.290623, 1.290527, 1.290432, 1.290340, 1.290250, 1.290161, 1.290075],
|
|
|
|
|
0.95: [
|
|
|
|
|
6.313752, 2.919986, 2.353363, 2.131847, 2.015048, 1.943180, 1.894579, 1.859548, 1.833113, 1.812461,
|
|
|
|
|
1.795885, 1.782288, 1.770933, 1.761310, 1.753050, 1.745884, 1.739607, 1.734064, 1.729133, 1.724718,
|
|
|
|
|
1.720743, 1.717144, 1.713872, 1.710882, 1.708141, 1.705618, 1.703288, 1.701131, 1.699127, 1.697261,
|
|
|
|
|
1.695519, 1.693889, 1.692360, 1.690924, 1.689572, 1.688298, 1.687094, 1.685954, 1.684875, 1.683851,
|
|
|
|
|
1.682878, 1.681952, 1.681071, 1.680230, 1.679427, 1.678660, 1.677927, 1.677224, 1.676551, 1.675905,
|
|
|
|
|
|
|
|
|
|
1.675285, 1.674689, 1.674116, 1.673565, 1.673034, 1.672522, 1.672029, 1.671553, 1.671093, 1.670649,
|
|
|
|
|
1.670219, 1.669804, 1.669402, 1.669013, 1.668636, 1.668271, 1.667916, 1.667572, 1.667239, 1.666914,
|
|
|
|
|
1.666600, 1.666294, 1.665996, 1.665707, 1.665425, 1.665151, 1.664885, 1.664625, 1.664371, 1.664125,
|
|
|
|
|
1.663884, 1.663649, 1.663420, 1.663197, 1.662978, 1.662765, 1.662557, 1.662354, 1.662155, 1.661961,
|
|
|
|
|
1.661771, 1.661585, 1.661404, 1.661226, 1.661052, 1.660881, 1.660715, 1.660551, 1.660391, 1.660234],
|
|
|
|
|
0.975: [
|
|
|
|
|
12.706205, 4.302653, 3.182446, 2.776445, 2.570582, 2.446912, 2.364624, 2.306004, 2.262157, 2.228139,
|
|
|
|
|
2.200985, 2.178813, 2.160369, 2.144787, 2.131450, 2.119905, 2.109816, 2.100922, 2.093024, 2.085963,
|
|
|
|
|
2.079614, 2.073873, 2.068658, 2.063899, 2.059539, 2.055529, 2.051831, 2.048407, 2.045230, 2.042272,
|
|
|
|
|
2.039513, 2.036933, 2.034515, 2.032245, 2.030108, 2.028094, 2.026192, 2.024394, 2.022691, 2.021075,
|
|
|
|
|
2.019541, 2.018082, 2.016692, 2.015368, 2.014103, 2.012896, 2.011741, 2.010635, 2.009575, 2.008559,
|
|
|
|
|
|
|
|
|
|
2.007584, 2.006647, 2.005746, 2.004879, 2.004045, 2.003241, 2.002465, 2.001717, 2.000995, 2.000298,
|
|
|
|
|
1.999624, 1.998972, 1.998341, 1.997730, 1.997138, 1.996564, 1.996008, 1.995469, 1.994945, 1.994437,
|
|
|
|
|
1.993943, 1.993464, 1.992997, 1.992543, 1.992102, 1.991673, 1.991254, 1.990847, 1.990450, 1.990063,
|
|
|
|
|
1.989686, 1.989319, 1.988960, 1.988610, 1.988268, 1.987934, 1.987608, 1.987290, 1.986979, 1.986675,
|
|
|
|
|
1.986377, 1.986086, 1.985802, 1.985523, 1.985251, 1.984984, 1.984723, 1.984467, 1.984217, 1.983972],
|
|
|
|
|
0.99: [
|
|
|
|
|
31.820516, 6.964557, 4.540703, 3.746947, 3.364930, 3.142668, 2.997952, 2.896459, 2.821438, 2.763769,
|
|
|
|
|
2.718079, 2.680998, 2.650309, 2.624494, 2.602480, 2.583487, 2.566934, 2.552380, 2.539483, 2.527977,
|
|
|
|
|
2.517648, 2.508325, 2.499867, 2.492159, 2.485107, 2.478630, 2.472660, 2.467140, 2.462021, 2.457262,
|
|
|
|
|
2.452824, 2.448678, 2.444794, 2.441150, 2.437723, 2.434494, 2.431447, 2.428568, 2.425841, 2.423257,
|
|
|
|
|
2.420803, 2.418470, 2.416250, 2.414134, 2.412116, 2.410188, 2.408345, 2.406581, 2.404892, 2.403272,
|
|
|
|
|
|
|
|
|
|
2.401718, 2.400225, 2.398790, 2.397410, 2.396081, 2.394801, 2.393568, 2.392377, 2.391229, 2.390119,
|
|
|
|
|
2.389047, 2.388011, 2.387008, 2.386037, 2.385097, 2.384186, 2.383302, 2.382446, 2.381615, 2.380807,
|
|
|
|
|
2.380024, 2.379262, 2.378522, 2.377802, 2.377102, 2.376420, 2.375757, 2.375111, 2.374482, 2.373868,
|
|
|
|
|
2.373270, 2.372687, 2.372119, 2.371564, 2.371022, 2.370493, 2.369977, 2.369472, 2.368979, 2.368497,
|
|
|
|
|
2.368026, 2.367566, 2.367115, 2.366674, 2.366243, 2.365821, 2.365407, 2.365002, 2.364606, 2.364217]
|
|
|
|
|
};
|
|
|
|
|
function oneSidedToTwoSidedProbability(probability) { return 2 * probability - 1; }
|
|
|
|
|
function twoSidedToOneSidedProbability(probability) { return (1 - (1 - probability) / 2); }
|
|
|
|
|
|
|
|
|
|
function splitIntoSegmentsUntilGoodEnough(values, BirgeAndMassartC) {
|
|
|
|
|
if (values.length < 2)
|
|
|
|
|
return [0, values.length];
|
|
|
|
|
|
|
|
|
|
var matrix = new SampleVarianceUpperTriangularMatrix(values);
|
|
|
|
|
|
|
|
|
|
var SchwarzCriterionBeta = Math.log1p(values.length - 1) / values.length;
|
|
|
|
|
|
|
|
|
|
BirgeAndMassartC = BirgeAndMassartC || 2.5; // Suggested by the authors.
|
|
|
|
|
var BirgeAndMassartPenalization = function (segmentCount) {
|
|
|
|
|
return segmentCount * (1 + BirgeAndMassartC * Math.log1p(values.length / segmentCount - 1));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var segmentation;
|
|
|
|
|
var minTotalCost = Infinity;
|
|
|
|
|
var maxK = Math.min(50, values.length);
|
|
|
|
|
|
|
|
|
|
for (var k = 1; k < maxK; k++) {
|
|
|
|
|
var start = Date.now();
|
|
|
|
|
var result = findOptimalSegmentation(values, matrix, k);
|
|
|
|
|
var cost = result.cost / values.length;
|
|
|
|
|
var penalty = SchwarzCriterionBeta * BirgeAndMassartPenalization(k);
|
|
|
|
|
if (cost + penalty < minTotalCost) {
|
|
|
|
|
minTotalCost = cost + penalty;
|
|
|
|
|
segmentation = result.segmentation;
|
|
|
|
|
} else
|
|
|
|
|
maxK = Math.min(maxK, k + 3);
|
|
|
|
|
if (Statistics.debuggingSegmentation)
|
|
|
|
|
console.log('splitIntoSegmentsUntilGoodEnough', k, Date.now() - start, cost + penalty);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return segmentation;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function allocateCostUpperTriangularForSegmentation(values, segmentCount)
|
|
|
|
|
{
|
|
|
|
|
// Dynamic programming. cost[i][k] = The cost to segmenting values up to i into k segments.
|
|
|
|
|
var cost = new Array(values.length);
|
|
|
|
|
for (var segmentEnd = 0; segmentEnd < values.length; segmentEnd++)
|
|
|
|
|
cost[segmentEnd] = new Float32Array(segmentCount + 1);
|
|
|
|
|
return cost;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function allocatePreviousNodeForSegmentation(values, segmentCount)
|
|
|
|
|
{
|
|
|
|
|
// previousNode[i][k] = The start of the last segment in an optimal segmentation that ends at i with k segments.
|
|
|
|
|
var previousNode = new Array(values.length);
|
|
|
|
|
for (var i = 0; i < values.length; i++)
|
|
|
|
|
previousNode[i] = new Array(segmentCount + 1);
|
|
|
|
|
return previousNode;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function findOptimalSegmentationInternal(cost, previousNode, values, costMatrix, segmentCount)
|
|
|
|
|
{
|
|
|
|
|
cost[0] = new Float32Array([0]); // The cost of segmenting single value is always 0.
|
|
|
|
|
previousNode[0] = [-1];
|
|
|
|
|
for (var segmentStart = 0; segmentStart < values.length; segmentStart++) {
|
|
|
|
|
var costOfOptimalSegmentationThatEndAtCurrentStart = cost[segmentStart];
|
|
|
|
|
for (var k = 0; k < segmentCount; k++) {
|
|
|
|
|
var noSegmentationOfLenghtKEndsAtCurrentStart = previousNode[segmentStart][k] === undefined;
|
|
|
|
|
if (noSegmentationOfLenghtKEndsAtCurrentStart)
|
|
|
|
|
continue;
|
|
|
|
|
for (var segmentEnd = segmentStart + 1; segmentEnd < values.length; segmentEnd++) {
|
|
|
|
|
var costOfOptimalSegmentationOfLengthK = costOfOptimalSegmentationThatEndAtCurrentStart[k];
|
|
|
|
|
var costOfCurrentSegment = costMatrix.costBetween(segmentStart, segmentEnd);
|
|
|
|
|
var totalCost = costOfOptimalSegmentationOfLengthK + costOfCurrentSegment;
|
|
|
|
|
if (previousNode[segmentEnd][k + 1] === undefined || totalCost < cost[segmentEnd][k + 1]) {
|
|
|
|
|
cost[segmentEnd][k + 1] = totalCost;
|
|
|
|
|
previousNode[segmentEnd][k + 1] = segmentStart;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function findOptimalSegmentation(values, costMatrix, segmentCount) {
|
|
|
|
|
var cost = allocateCostUpperTriangularForSegmentation(values, segmentCount);
|
|
|
|
|
var previousNode = allocatePreviousNodeForSegmentation(values, segmentCount);
|
|
|
|
|
|
|
|
|
|
findOptimalSegmentationInternal(cost, previousNode, values, costMatrix, segmentCount);
|
|
|
|
|
|
|
|
|
|
if (Statistics.debuggingSegmentation) {
|
|
|
|
|
console.log('findOptimalSegmentation with', segmentCount, 'segments');
|
|
|
|
|
for (var end = 0; end < values.length; end++) {
|
|
|
|
|
for (var k = 0; k <= segmentCount; k++) {
|
|
|
|
|
var start = previousNode[end][k];
|
|
|
|
|
if (start === undefined)
|
|
|
|
|
continue;
|
|
|
|
|
console.log(`C(segment=[${start}, ${end + 1}], segmentCount=${k})=${cost[end][k]}`);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var segmentEnd = values.length - 1;
|
|
|
|
|
var segmentation = new Array(segmentCount + 1);
|
|
|
|
|
segmentation[segmentCount] = values.length;
|
|
|
|
|
for (var k = segmentCount; k > 0; k--) {
|
|
|
|
|
segmentEnd = previousNode[segmentEnd][k];
|
|
|
|
|
segmentation[k - 1] = segmentEnd;
|
|
|
|
|
}
|
|
|
|
|
var costOfOptimalSegmentation = cost[values.length - 1][segmentCount];
|
|
|
|
|
|
|
|
|
|
if (Statistics.debuggingSegmentation)
|
|
|
|
|
console.log('Optimal segmentation:', segmentation, 'with cost =', costOfOptimalSegmentation);
|
|
|
|
|
|
|
|
|
|
return {segmentation: segmentation, cost: costOfOptimalSegmentation};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function SampleVarianceUpperTriangularMatrix(values) {
|
|
|
|
|
// The cost of segment (i, j].
|
|
|
|
|
var costMatrix = new Array(values.length - 1);
|
|
|
|
|
for (var i = 0; i < values.length - 1; i++) {
|
|
|
|
|
var remainingValueCount = values.length - i - 1;
|
|
|
|
|
costMatrix[i] = new Float32Array(remainingValueCount);
|
|
|
|
|
var sum = values[i];
|
|
|
|
|
var squareSum = sum * sum;
|
|
|
|
|
costMatrix[i][0] = 0;
|
|
|
|
|
for (var j = i + 1; j < values.length; j++) {
|
|
|
|
|
var currentValue = values[j];
|
|
|
|
|
sum += currentValue;
|
|
|
|
|
squareSum += currentValue * currentValue;
|
|
|
|
|
var sampleSize = j - i + 1;
|
|
|
|
|
var stdev = Statistics.sampleStandardDeviation(sampleSize, sum, squareSum);
|
|
|
|
|
costMatrix[i][j - i - 1] = stdev > 0 ? sampleSize * Math.log(stdev * stdev) : 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
this.costMatrix = costMatrix;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SampleVarianceUpperTriangularMatrix.prototype.costBetween = function(from, to) {
|
|
|
|
|
if (from >= this.costMatrix.length || from == to)
|
|
|
|
|
return 0; // The cost of the segment that starts at the last data point is 0.
|
|
|
|
|
return this.costMatrix[from][to - from - 1];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
})();
|
|
|
|
|
|
|
|
|
|
// AsyncTask
|
|
|
|
|
class AsyncTask {
|
|
|
|
|
|
|
|
|
|
constructor(method, args)
|
|
|
|
|
{
|
|
|
|
|
this._method = method;
|
|
|
|
|
this._args = args;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
execute()
|
|
|
|
|
{
|
|
|
|
|
if (!(this._method in Statistics))
|
|
|
|
|
throw `${this._method} is not a valid method of Statistics`;
|
|
|
|
|
|
|
|
|
|
AsyncTask._asyncMessageId++;
|
|
|
|
|
|
|
|
|
|
var startTime = Date.now();
|
|
|
|
|
var method = this._method;
|
|
|
|
|
var args = this._args;
|
|
|
|
|
return new Promise(function (resolve, reject) {
|
|
|
|
|
AsyncTaskWorker.waitForAvailableWorker(function (worker) {
|
|
|
|
|
worker.sendTask({id: AsyncTask._asyncMessageId, method: method, args: args}).then(function (data) {
|
|
|
|
|
var startLatency = data.workerStartTime - startTime;
|
|
|
|
|
var totalTime = Date.now() - startTime;
|
|
|
|
|
var callback = data.status == 'resolve' ? resolve : reject;
|
|
|
|
|
callback({result: data.result, workerId: worker.id(), startLatency: startLatency, totalTime: totalTime, workerTime: data.workerTime});
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static isAvailable()
|
|
|
|
|
{
|
|
|
|
|
return typeof Worker !== 'undefined';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AsyncTask._asyncMessageId = 0;
|
|
|
|
|
|
|
|
|
|
class AsyncTaskWorker {
|
|
|
|
|
|
|
|
|
|
// Takes a callback instead of returning a promise because a worker can become unavailable before the end of the current microtask.
|
|
|
|
|
static waitForAvailableWorker(callback)
|
|
|
|
|
{
|
|
|
|
|
var worker = this._makeWorkerEventuallyAvailable();
|
|
|
|
|
if (worker)
|
|
|
|
|
callback(worker);
|
|
|
|
|
else
|
|
|
|
|
this._queue.push(callback);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static _makeWorkerEventuallyAvailable()
|
|
|
|
|
{
|
|
|
|
|
var worker = this._findAvailableWorker();
|
|
|
|
|
if (worker)
|
|
|
|
|
return worker;
|
|
|
|
|
|
|
|
|
|
var canStartMoreWorker = this._workerSet.size < this._maxWorkerCount;
|
|
|
|
|
if (!canStartMoreWorker)
|
|
|
|
|
return null;
|
|
|
|
|
|
|
|
|
|
if (this._latestStartTime > Date.now() - 50) {
|
|
|
|
|
setTimeout(function () {
|
|
|
|
|
if (!AsyncTaskWorker._queue.length)
|
|
|
|
|
return;
|
|
|
|
|
var worker = AsyncTaskWorker._findAvailableWorker();
|
|
|
|
|
if (worker)
|
|
|
|
|
AsyncTaskWorker._queue.pop()(worker);
|
|
|
|
|
}, 50);
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
return new AsyncTaskWorker;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static _findAvailableWorker()
|
|
|
|
|
{
|
|
|
|
|
for (var worker of this._workerSet) {
|
|
|
|
|
if (!worker._currentTaskId)
|
|
|
|
|
return worker;
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
constructor()
|
|
|
|
|
{
|
2025-09-03 03:23:43 -08:00
|
|
|
this._webWorker = new Worker(JetStream.preload.asyncTaskBlob);
|
2024-10-30 08:45:46 -08:00
|
|
|
this._webWorker.onmessage = this._didRecieveMessage.bind(this);
|
|
|
|
|
this._id = AsyncTaskWorker._workerId;
|
|
|
|
|
this._startTime = Date.now();
|
|
|
|
|
this._currentTaskId = null;
|
|
|
|
|
this._callback = null;
|
|
|
|
|
|
|
|
|
|
AsyncTaskWorker._latestStartTime = this._startTime;
|
|
|
|
|
AsyncTaskWorker._workerId++;
|
|
|
|
|
AsyncTaskWorker._workerSet.add(this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
id() { return this._id; }
|
|
|
|
|
|
|
|
|
|
sendTask(task)
|
|
|
|
|
{
|
|
|
|
|
console.assert(!this._currentTaskId);
|
|
|
|
|
console.assert(task.id);
|
|
|
|
|
var self = this;
|
|
|
|
|
this._currentTaskId = task.id;
|
|
|
|
|
return new Promise(function (resolve) {
|
|
|
|
|
self._webWorker.postMessage(task);
|
|
|
|
|
self._callback = resolve;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_didRecieveMessage(event)
|
|
|
|
|
{
|
|
|
|
|
var callback = this._callback;
|
|
|
|
|
|
|
|
|
|
console.assert(this._currentTaskId);
|
|
|
|
|
this._currentTaskId = null;
|
|
|
|
|
this._callback = null;
|
|
|
|
|
|
|
|
|
|
if (AsyncTaskWorker._queue.length)
|
|
|
|
|
AsyncTaskWorker._queue.pop()(this);
|
|
|
|
|
else {
|
|
|
|
|
var self = this;
|
|
|
|
|
setTimeout(function () {
|
2025-09-23 06:47:00 -08:00
|
|
|
if (self._currentTaskId == null)
|
2024-10-30 08:45:46 -08:00
|
|
|
AsyncTaskWorker._workerSet.delete(self);
|
|
|
|
|
}, 1000);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
callback(event.data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static workerDidRecieveMessage(event)
|
|
|
|
|
{
|
|
|
|
|
var data = event.data;
|
|
|
|
|
var id = data.id;
|
|
|
|
|
var method = Statistics[data.method];
|
|
|
|
|
var startTime = Date.now();
|
|
|
|
|
try {
|
|
|
|
|
var returnValue = method.apply(Statistics, data.args);
|
|
|
|
|
postMessage({'id': id, 'status': 'resolve', 'result': returnValue, 'workerStartTime': startTime, 'workerTime': Date.now() - startTime});
|
|
|
|
|
} catch (error) {
|
|
|
|
|
postMessage({'id': id, 'status': 'reject', 'result': error.toString(), 'workerStartTime': startTime, 'workerTime': Date.now() - startTime});
|
|
|
|
|
throw error;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AsyncTaskWorker._maxWorkerCount = 4;
|
|
|
|
|
AsyncTaskWorker._workerSet = new Set;
|
|
|
|
|
AsyncTaskWorker._queue = [];
|
|
|
|
|
AsyncTaskWorker._workerId = 1;
|
|
|
|
|
AsyncTaskWorker._latestStartTime = 0;
|
|
|
|
|
|
|
|
|
|
if (!Array.prototype.includes)
|
|
|
|
|
Array.prototype.includes = function (value) { return this.indexOf(value) >= 0; }
|
|
|
|
|
|
|
|
|
|
class MeasurementSet {
|
|
|
|
|
constructor(platformId, metricId, lastModified)
|
|
|
|
|
{
|
|
|
|
|
this._platformId = platformId;
|
|
|
|
|
this._metricId = metricId;
|
|
|
|
|
this._lastModified = +lastModified;
|
|
|
|
|
|
|
|
|
|
this._sortedClusters = [];
|
|
|
|
|
this._primaryClusterEndTime = null;
|
|
|
|
|
this._clusterCount = null;
|
|
|
|
|
this._clusterStart = null;
|
|
|
|
|
this._clusterSize = null;
|
|
|
|
|
this._allFetches = {};
|
|
|
|
|
this._callbackMap = new Map;
|
|
|
|
|
this._primaryClusterPromise = null;
|
|
|
|
|
this._segmentationCache = new Map;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
platformId() { return this._platformId; }
|
|
|
|
|
metricId() { return this._metricId; }
|
|
|
|
|
|
|
|
|
|
_invokeSegmentationAlgorithm(segmentationName, parameters, timeSeriesValues)
|
|
|
|
|
{
|
|
|
|
|
var args = [timeSeriesValues].concat(parameters || []);
|
|
|
|
|
var task = new AsyncTask(segmentationName, args);
|
|
|
|
|
return task.execute().then(function (response) {
|
|
|
|
|
return response.result;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class Benchmark {
|
|
|
|
|
constructor() {
|
|
|
|
|
this.d1 = [103.63428467218,100.65698512757,103.41681901544,101.73297541769,106.1637181408,98.412208909224,102.1910683922,100.6529954993,100.2060895554,102.79763572285,101.58124402819,104.83646850886,105.68205557779,101.37268411726,101.21856897174,103.29471813954,105.99085083645,104.00152807402,102.5515579466,100.95765471931,101.30414879687,101.28842115694,103.18365782867,104.32770094781,101.04841668133,103.48198436419,100.89825149314,101.96224301484,102.57514127219,101.88941623092,102.55684506087,103.32436792906,102.14059443954,101.34202300433,100.71509510859,102.84019181314,103.90795641251,103.79317123977,102.33281400385,101.05661999771,99.527245552223,104.04756755696,100.08258193089,102.32602929128,101.12649175316,98.59777764562,100.51219905198,100.3384460803,101.15283289168,104.45829696358,103.08640647121,101.15646661427,104.87981301026,102.96022354121,102.91057904096,102.94557493889,104.19286657388,101.49564839627,104.56628696589,102.64328394303,102.98955045659,100.30795615252,101.9596010783,102.7787577747,105.08450703012,105.6083617604,100.58871732306,102.29447246575,103.93156436242,100.15444968522,100.33027723674,99.709998115277,104.77614797428,101.80467295351,103.83722962812,103.8922179754,99.668513176783,103.54088096393,99.79641717842,99.217827453945,100.63604774585,99.397345569613,103.41566155646,102.86730291818,101.3466271856,101.0430581605,101.75352329686,101.79205972782,103.58235064873,102.70955387997,103.513441865,103.55358827182,101.27954344729,100.72000812989,100.50572692724,103.29725364285,99.878238665041,101.33136147166,107.82148653962,106.33087978795,105.76698605645,106.73722912118,105.09474645086,106.93812007831,104.58796212158,108.74454496591,108.77609339631,106.36234738479,107.08594417641,103.14990449109,103.08799682189,106.42944302492,104.95681265496,104.19185455295,103.37266620831,106.88393619713,103.77307460747,107.22959460967,102.92373151821,102.27169909087,105.35352579142,108.55485303073,106.86928831633,107.6604165255,106.08100829687,105.69860408885,104.15919883914,103.43072470928,107.61607415001,105.12730526857,108.26003924405,102.52392958652,103.49742913465,106.40355299133,106.6205839791,103.75599735706,104.02717048675,102.8616712232,107.31403440793,105.71715870348,108.62026687466,103.89002871878,101.02136648518,105.71922937008,107.65246680959,106.90056953891,103.116341753,107.4819154547,104.30217606275,106.2163429931,108.76888355744,106.25769430792,105.62856894786,106.5974802856,107.4572456313,103.76930483468,109.22117086979,103.95101290047,103.04369239044,105.8978020889,108.08880932927,107.09476068374,107.84718462015,104.3185702112,108.58358811573,103.08208736102,106.30281582081,105.5071989199,106.69382657222,105.5661979062,107.55317794727,106.81112895681,103.49181806572,108.11406008626,105.82558000937,110.7280951536,110.57391099468,96.195798803035,98.050055515401,98.34258752078,96.437461839433,107.86695915352,107.50220866371,96.408603678811,96.183884592145,93.874527361487,106.01388920009,106.68752585206,95.748639659824,97.620195660744,95.709384830238,94.844312788627,97.194219302695,95.228621910585,95.299983299732,95.878520884831,95.494218128339,95.721877181905,95.30324004452,93.761957719231,99.052683337698,97.414624016474,98.955647001503,96.944084189531,94.98363688231,97.084748591591,96.56489094851,96.602599613176,99.011103877236,108.56332396293,96.328721476217,112.59520822831,111.4457635202,109.57249840458,112.52658585356,111.79387339089,107.83633335508,110.46783549074,113.07325087266,114.03320142819,108.91999302834,113.28679171319,112.84647681497,112.30446173472,107.70596309315,113.90782983196,110.52702067922,110.77146399218,108.82316306309,112.31704998895,112.04572347677,102.01583120296,102.26933512167,101.04034529285,102.82388967602,103.5215835497,103.60628281381,100.24147995637,102.56920667296,111.65264599649,109.90970916739,110.91610377373,110.86460228468,110.66591901693,110.08877264895,110.07273691588,108.50573934243,111.74386044451,109.613011316,111.00131231439,112.36541199185,107.7696667543,108.22526773007,110.72718495033,110.60353399069,110.27959438874,109.58777079374,111
|
|
|
|
|
this.d2 = [372535296,382377984,391487488,372695040,384020480,388427776,385986560,401125376,389529600,394014720,383983616,383504384,388804608,391004160,379936768,390008832,392830976,385937408,386101248,391065600,383262720,383717376,405553152,411299840,395431936,400896000,411578368,413659136,393289728,397176832,415444992,383922176,380809216,402214912,420286464,408412160,392343552,406532096,405950464,405266432,405266432,399302656,392708096,403107840,396943360,413351936,394735616,414461952,391102464,415363072,394797056,394432512,399646720,393465856,395780096,395829248,393895936,420745216,401338368,396079104,407846912,401051648,396705792,396345344,401694720,395808768,408088576,393785344,400572416,392282112,397897728,393547776,394969088,398417920,409014272,394620928,401031168,402567168,399011840,398532608,410574848,391426048,419282944,415105024,400883712,399093760,398114816,408608768,408432640,394809344,410787840,394522624,392658944,394158080,409600000,415043584,396181504,413138944,392978432,390225920,396677120,405676032,403087360,405594112,399937536,395894784,394608640,398200832,406245376,392458240,418922496,401690624,389500928,411136000,386760704,413073408,385392640,394715136,389586944,395960320,392036352,387768320,381210624,405696512,389230592,384266240,392065024,397029376,408678400,385114112,388362240,395304960,383799296,384253952,383303680,396394496,402731008,401383424,394399744,410091520,393256960,408727552,390725632,388235264,395939840,390950912,385069056,387432448,399179776,390594560,391823360,408346624,394641408,403292160,395751424,381997056,396726272,386023424,402124800,382537728,391188480,398589952,382857216,403599360,390873088,394309632,397361152,383676416,380076032,385716224,401346560,399822848,399826944,381673472,398479360,385056768,377995264,376963072,391421952,376049664,392478720,399884288,376856576,393891840,376143872,384397312,395837440,392298496,374730752,383254528,385105920,400908288,387526656,377487360,388812800,381935616,385187840,377909248,376717312,391622656,376836096,384651264,377069568,379535360,382607360,378822656,395116544,378396672,380440576,399740928,381788160,397438976,390111232,386150400,379228160,375971840,385290240,383262720,377401344,398135296,386297856,384110592,386359296,383848448,385998848,376852480,384012288,384344064,399777792,396468224,376623104,375128064,387264512,375648256,392667136,389255168,373874688,386101248,382988288,390455296,397877248,389328896,404615168,383582208,386965504,384815104,381370368,384880640,383262720,383463424,374714368,385224704,376725504,387416064,384774144,383967232,386433024,386834432,392900608,383627264,383184896,375844864,388706304,387858432,394989568,385040384,379428864,376778752,388112384,382734336,402206720,376815616,377913344,380018688,382402560,381964288,382722048,396218368,386211840,380309504,381325312,390418432,383815680,398917632,384167936,377221120,384434176,385839104,395571200,379887616,376418304,380084224,385200128,378437632,378007552,391417856,391852032,376610816,390393856,380276736,386224128,376111104,384335872,377425920,379564032,400736256,376180736,382963712,385146880,385929216,377671680,379469824,398663680,381931520,379908096,375885824,383655936,384159744,379043840,380432384,380719104,377397248,377303040,381177856,396369920,377040896,379293696,382693376,390258688,377618432,381018112,379682816,386469888,385335296,376221696,378331136,388902912,376958976,370102272,377380864,370663424,385691648,378560512,397266944,370716672,377184256,392278016,377294848,369430528,370847744,378265600,370515968,387846144,371118080,375603200,375427072,370831360,377589760,371916800,368480256,369254400,399187968,394952704,371372032,369049600,370802688,370241536,370724864,376610816,379260928,387842048,375123968,369745920,371642368,366592000,374640640,366833664,368275456,367886336,392151040,374788096,382320640,399278080,394911744,370671616,383025152,379637760,372101120,379641856,378572800,381874176,401866752,391942144,388337664,397881344,381849600,381624320,388698112,393519104,400277504,384905216,392511488,383672320,384270336,393269248,390021120,383795200,391340
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async runIteration() {
|
|
|
|
|
const params = [2.5, 500];
|
|
|
|
|
let data = [this.d1, this.d2];
|
|
|
|
|
let promises = [];
|
|
|
|
|
for (let d of data)
|
|
|
|
|
promises.push(MeasurementSet.prototype._invokeSegmentationAlgorithm("segmentTimeSeriesByMaximizingSchwarzCriterion", params, d));
|
|
|
|
|
|
|
|
|
|
const expectedResults = [
|
|
|
|
|
[0, 97, 174, 211, 301, 1270, 1278, 2696, 3613, 3700],
|
|
|
|
|
[0, 175, 1194, 1237, 2310]
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
for (let i = 0; i < promises.length; ++i) {
|
|
|
|
|
let promise = promises[i];
|
|
|
|
|
let result = await promise;
|
|
|
|
|
if (result.toString() !== expectedResults[i].toString())
|
|
|
|
|
throw new Error("Bad result");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|