Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(262)

Unified Diff: tracing/tracing/base/statistics.html

Issue 2771723003: [tracing] Move math utilities from base into their own subdirectory (attempt 2) (Closed)
Patch Set: rebase Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « tracing/tracing/base/sorted_array_utils_test.html ('k') | tracing/tracing/base/statistics_test.html » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: tracing/tracing/base/statistics.html
diff --git a/tracing/tracing/base/statistics.html b/tracing/tracing/base/statistics.html
deleted file mode 100644
index 071a860fb62c35842bd4df47ef2c6783bcadf277..0000000000000000000000000000000000000000
--- a/tracing/tracing/base/statistics.html
+++ /dev/null
@@ -1,848 +0,0 @@
-<!DOCTYPE html>
-<!--
-Copyright 2014 The Chromium Authors. All rights reserved.
-Use of this source code is governed by a BSD-style license that can be
-found in the LICENSE file.
--->
-
-<link rel="import" href="/tracing/base/math.html">
-<link rel="import" href="/tracing/base/range.html">
-<script src="/mannwhitneyu/mannwhitneyu.js"></script>
-
-<script>
-'use strict';
-
-// In node, the script-src for mannwhitneyu above brings in mannwhitneyui
-// into a module, instead of into the global scope. Whereas this file
-// assumes that mannwhitneyu is in the global scope. So, in Node only, we
-// require() it in, and then take all its exports and shove them into the
-// global scope by hand.
-(function(global) {
- if (tr.isNode) {
- var mwuAbsPath = HTMLImportsLoader.hrefToAbsolutePath(
- '/mannwhitneyu.js');
- var mwuModule = require(mwuAbsPath);
- for (var exportName in mwuModule) {
- global[exportName] = mwuModule[exportName];
- }
- }
-})(this);
-</script>
-
-<script>
-'use strict';
-
-// TODO(charliea): Remove:
-/* eslint-disable catapult-camelcase */
-
-tr.exportTo('tr.b', function() {
- var identity = x => x;
-
- var Statistics = {};
-
- /* Returns the quotient, or zero if the denominator is zero.*/
- Statistics.divideIfPossibleOrZero = function(numerator, denominator) {
- if (denominator === 0)
- return 0;
- return numerator / denominator;
- };
-
- Statistics.sum = function(ary, opt_func, opt_this) {
- var func = opt_func || identity;
- var ret = 0;
- var i = 0;
- for (var elt of ary)
- ret += func.call(opt_this, elt, i++);
- return ret;
- };
-
- Statistics.mean = function(ary, opt_func, opt_this) {
- var func = opt_func || identity;
- var sum = 0;
- var i = 0;
-
- for (var elt of ary)
- sum += func.call(opt_this, elt, i++);
-
- if (i === 0)
- return undefined;
-
- return sum / i;
- };
-
- Statistics.geometricMean = function(ary, opt_func, opt_this) {
- var func = opt_func || identity;
- var i = 0;
- var logsum = 0;
-
- // The geometric mean is expressed as the arithmetic mean of logarithms
- // in order to prevent overflow.
- for (var elt of ary) {
- var x = func.call(opt_this, elt, i++);
- if (x <= 0)
- return 0;
- logsum += Math.log(Math.abs(x));
- }
-
- if (i === 0)
- return 1;
-
- return Math.exp(logsum / i);
- };
-
- // Returns undefined if the sum of the weights is zero.
- Statistics.weightedMean = function(
- ary, weightCallback, opt_valueCallback, opt_this) {
- var valueCallback = opt_valueCallback || identity;
- var numerator = 0;
- var denominator = 0;
- var i = -1;
-
- for (var elt of ary) {
- i++;
- var value = valueCallback.call(opt_this, elt, i);
- if (value === undefined)
- continue;
- var weight = weightCallback.call(opt_this, elt, i, value);
- numerator += weight * value;
- denominator += weight;
- }
-
- if (denominator === 0)
- return undefined;
-
- return numerator / denominator;
- };
-
- Statistics.variance = function(ary, opt_func, opt_this) {
- if (ary.length === 0)
- return undefined;
- if (ary.length === 1)
- return 0;
- var func = opt_func || identity;
- var mean = Statistics.mean(ary, func, opt_this);
- var sumOfSquaredDistances = Statistics.sum(
- ary,
- function(d, i) {
- var v = func.call(this, d, i) - mean;
- return v * v;
- },
- opt_this);
- return sumOfSquaredDistances / (ary.length - 1);
- };
-
- Statistics.stddev = function(ary, opt_func, opt_this) {
- if (ary.length === 0)
- return undefined;
- return Math.sqrt(
- Statistics.variance(ary, opt_func, opt_this));
- };
-
- Statistics.max = function(ary, opt_func, opt_this) {
- var func = opt_func || identity;
- var ret = -Infinity;
- var i = 0;
- for (var elt of ary)
- ret = Math.max(ret, func.call(opt_this, elt, i++));
- return ret;
- };
-
- Statistics.min = function(ary, opt_func, opt_this) {
- var func = opt_func || identity;
- var ret = Infinity;
- var i = 0;
- for (var elt of ary)
- ret = Math.min(ret, func.call(opt_this, elt, i++));
- return ret;
- };
-
- Statistics.range = function(ary, opt_func, opt_this) {
- var func = opt_func || identity;
- var ret = new tr.b.Range();
- var i = 0;
- for (var elt of ary)
- ret.addValue(func.call(opt_this, elt, i++));
- return ret;
- };
-
- Statistics.percentile = function(ary, percent, opt_func, opt_this) {
- if (!(percent >= 0 && percent <= 1))
- throw new Error('percent must be [0,1]');
-
- var func = opt_func || identity;
- var tmp = new Array(ary.length);
- var i = 0;
- for (var elt of ary)
- tmp[i] = func.call(opt_this, elt, i++);
- tmp.sort((a, b) => a - b);
- var idx = Math.floor((ary.length - 1) * percent);
- return tmp[idx];
- };
-
- /**
- * Sorts the samples, and map them linearly to the range [0,1].
- *
- * They're mapped such that for the N samples, the first sample is 0.5/N and
- * the last sample is (N-0.5)/N.
- *
- * Background: The discrepancy of the sample set i/(N-1); i=0, ..., N-1 is
- * 2/N, twice the discrepancy of the sample set (i+1/2)/N; i=0, ..., N-1. In
- * our case we don't want to distinguish between these two cases, as our
- * original domain is not bounded (it is for Monte Carlo integration, where
- * discrepancy was first used).
- **/
- Statistics.normalizeSamples = function(samples) {
- if (samples.length === 0) {
- return {
- normalized_samples: samples,
- scale: 1.0
- };
- }
- // Create a copy to make sure that we don't mutate original |samples| input.
- samples = samples.slice().sort(
- function(a, b) {
- return a - b;
- }
- );
- var low = Math.min.apply(null, samples);
- var high = Math.max.apply(null, samples);
- var newLow = 0.5 / samples.length;
- var newHigh = (samples.length - 0.5) / samples.length;
- if (high - low === 0.0) {
- // Samples is an array of 0.5 in this case.
- samples = Array.apply(null, new Array(samples.length)).map(
- function() { return 0.5;});
- return {
- normalized_samples: samples,
- scale: 1.0
- };
- }
- var scale = (newHigh - newLow) / (high - low);
- for (var i = 0; i < samples.length; i++) {
- samples[i] = (samples[i] - low) * scale + newLow;
- }
- return {
- normalized_samples: samples,
- scale: scale
- };
- };
-
- /**
- * Computes the discrepancy of a set of 1D samples from the interval [0,1].
- *
- * The samples must be sorted. We define the discrepancy of an empty set
- * of samples to be zero.
- *
- * http://en.wikipedia.org/wiki/Low-discrepancy_sequence
- * http://mathworld.wolfram.com/Discrepancy.html
- */
- Statistics.discrepancy = function(samples, opt_locationCount) {
- if (samples.length === 0)
- return 0.0;
-
- var maxLocalDiscrepancy = 0;
- var invSampleCount = 1.0 / samples.length;
- var locations = [];
- // For each location, stores the number of samples less than that location.
- var countLess = [];
- // For each location, stores the number of samples less than or equal to
- // that location.
- var countLessEqual = [];
-
- if (opt_locationCount !== undefined) {
- // Generate list of equally spaced locations.
- var sampleIndex = 0;
- for (var i = 0; i < opt_locationCount; i++) {
- var location = i / (opt_locationCount - 1);
- locations.push(location);
- while (sampleIndex < samples.length &&
- samples[sampleIndex] < location) {
- sampleIndex += 1;
- }
- countLess.push(sampleIndex);
- while (sampleIndex < samples.length &&
- samples[sampleIndex] <= location) {
- sampleIndex += 1;
- }
- countLessEqual.push(sampleIndex);
- }
- } else {
- // Populate locations with sample positions. Append 0 and 1 if necessary.
- if (samples[0] > 0.0) {
- locations.push(0.0);
- countLess.push(0);
- countLessEqual.push(0);
- }
- for (var i = 0; i < samples.length; i++) {
- locations.push(samples[i]);
- countLess.push(i);
- countLessEqual.push(i + 1);
- }
- if (samples[-1] < 1.0) {
- locations.push(1.0);
- countLess.push(samples.length);
- countLessEqual.push(samples.length);
- }
- }
-
- // Compute discrepancy as max(overshoot, -undershoot), where
- // overshoot = max(countClosed(i, j)/N - length(i, j)) for all i < j,
- // undershoot = min(countOpen(i, j)/N - length(i, j)) for all i < j,
- // N = len(samples),
- // countClosed(i, j) is the number of points between i and j
- // including ends,
- // countOpen(i, j) is the number of points between i and j excluding ends,
- // length(i, j) is locations[i] - locations[j].
-
- // The following algorithm is modification of Kadane's algorithm,
- // see https://en.wikipedia.org/wiki/Maximum_subarray_problem.
-
- // The maximum of (countClosed(k, i-1)/N - length(k, i-1)) for any k < i-1.
- var maxDiff = 0;
- // The minimum of (countOpen(k, i-1)/N - length(k, i-1)) for any k < i-1.
- var minDiff = 0;
- for (var i = 1; i < locations.length; i++) {
- var length = locations[i] - locations[i - 1];
- var countClosed = countLessEqual[i] - countLess[i - 1];
- var countOpen = countLess[i] - countLessEqual[i - 1];
- // Number of points that are added if we extend a closed range that
- // ends at location (i-1).
- var countClosedIncrement =
- countLessEqual[i] - countLessEqual[i - 1];
- // Number of points that are added if we extend an open range that
- // ends at location (i-1).
- var countOpenIncrement = countLess[i] - countLess[i - 1];
-
- // Either extend the previous optimal range or start a new one.
- maxDiff = Math.max(
- countClosedIncrement * invSampleCount - length + maxDiff,
- countClosed * invSampleCount - length);
- minDiff = Math.min(
- countOpenIncrement * invSampleCount - length + minDiff,
- countOpen * invSampleCount - length);
-
- maxLocalDiscrepancy = Math.max(
- maxDiff, -minDiff, maxLocalDiscrepancy);
- }
- return maxLocalDiscrepancy;
- };
-
- /**
- * A discrepancy based metric for measuring timestamp jank.
- *
- * timestampsDiscrepancy quantifies the largest area of jank observed in a
- * series of timestamps. Note that this is different from metrics based on
- * the max_time_interval. For example, the time stamp series A = [0,1,2,3,5,6]
- * and B = [0,1,2,3,5,7] have the same max_time_interval = 2, but
- * Discrepancy(B) > Discrepancy(A).
- *
- * Two variants of discrepancy can be computed:
- *
- * Relative discrepancy is following the original definition of
- * discrepancy. It characterized the largest area of jank, relative to the
- * duration of the entire time stamp series. We normalize the raw results,
- * because the best case discrepancy for a set of N samples is 1/N (for
- * equally spaced samples), and we want our metric to report 0.0 in that
- * case.
- *
- * Absolute discrepancy also characterizes the largest area of jank, but its
- * value wouldn't change (except for imprecisions due to a low
- * |interval_multiplier|) if additional 'good' intervals were added to an
- * exisiting list of time stamps. Its range is [0,inf] and the unit is
- * milliseconds.
- *
- * The time stamp series C = [0,2,3,4] and D = [0,2,3,4,5] have the same
- * absolute discrepancy, but D has lower relative discrepancy than C.
- *
- * |timestamps| may be a list of lists S = [S_1, S_2, ..., S_N], where each
- * S_i is a time stamp series. In that case, the discrepancy D(S) is:
- * D(S) = max(D(S_1), D(S_2), ..., D(S_N))
- **/
- Statistics.timestampsDiscrepancy = function(timestamps, opt_absolute,
- opt_locationCount) {
- if (timestamps.length === 0)
- return 0.0;
-
- if (opt_absolute === undefined)
- opt_absolute = true;
-
- if (Array.isArray(timestamps[0])) {
- var rangeDiscrepancies = timestamps.map(function(r) {
- return Statistics.timestampsDiscrepancy(r);
- });
- return Math.max.apply(null, rangeDiscrepancies);
- }
-
- var s = Statistics.normalizeSamples(timestamps);
- var samples = s.normalized_samples;
- var sampleScale = s.scale;
- var discrepancy = Statistics.discrepancy(samples, opt_locationCount);
- var invSampleCount = 1.0 / samples.length;
- if (opt_absolute === true) {
- // Compute absolute discrepancy
- discrepancy /= sampleScale;
- } else {
- // Compute relative discrepancy
- discrepancy = tr.b.clamp(
- (discrepancy - invSampleCount) / (1.0 - invSampleCount), 0.0, 1.0);
- }
- return discrepancy;
- };
-
- /**
- * A discrepancy based metric for measuring duration jank.
- *
- * DurationsDiscrepancy computes a jank metric which measures how irregular a
- * given sequence of intervals is. In order to minimize jank, each duration
- * should be equally long. This is similar to how timestamp jank works,
- * and we therefore reuse the timestamp discrepancy function above to compute
- * a similar duration discrepancy number.
- *
- * Because timestamp discrepancy is defined in terms of timestamps, we first
- * convert the list of durations to monotonically increasing timestamps.
- *
- * Args:
- * durations: List of interval lengths in milliseconds.
- * absolute: See TimestampsDiscrepancy.
- * opt_locationCount: See TimestampsDiscrepancy.
- **/
- Statistics.durationsDiscrepancy = function(
- durations, opt_absolute, opt_locationCount) {
- if (durations.length === 0)
- return 0.0;
-
- var timestamps = durations.reduce(function(prev, curr, index, array) {
- prev.push(prev[prev.length - 1] + curr);
- return prev;
- }, [0]);
- return Statistics.timestampsDiscrepancy(
- timestamps, opt_absolute, opt_locationCount);
- };
-
- /**
- * Modifies |samples| in-place to reduce its length down to |count|.
- *
- * @param {!Array} samples
- * @param {number} count
- * @return {!Array}
- */
- Statistics.uniformlySampleArray = function(samples, count) {
- if (samples.length <= count) {
- return samples;
- }
- while (samples.length > count) {
- var i = parseInt(Math.random() * samples.length);
- samples.splice(i, 1);
- }
- return samples;
- };
-
- /**
- * A mechanism to uniformly sample elements from an arbitrary long stream.
- *
- * Call this method every time a new element is obtained from the stream,
- * passing always the same |samples| array and the |numSamples| you desire.
- * Also pass in the current |streamLength|, which is the same as the index of
- * |newElement| within that stream.
- *
- * The |samples| array will possibly be updated, replacing one of its element
- * with |newElements|. The length of |samples| will not be more than
- * |numSamples|.
- *
- * This method guarantees that after |streamLength| elements have been
- * processed each one has equal probability of being in |samples|. The order
- * of samples is not preserved though.
- *
- * Args:
- * samples: Array of elements that have already been selected. Start with [].
- * streamLength: The current length of the stream, up to |newElement|.
- * newElement: The element that was just extracted from the stream.
- * numSamples: The total number of samples desired.
- **/
- Statistics.uniformlySampleStream = function(samples, streamLength, newElement,
- numSamples) {
- if (streamLength <= numSamples) {
- if (samples.length >= streamLength)
- samples[streamLength - 1] = newElement;
- else
- samples.push(newElement);
- return;
- }
-
- var probToKeep = numSamples / streamLength;
- if (Math.random() > probToKeep)
- return; // New sample was rejected.
-
- // Keeping it, replace an alement randomly.
- var index = Math.floor(Math.random() * numSamples);
- samples[index] = newElement;
- };
-
- /**
- * A mechanism to merge two arrays of uniformly sampled elements in a way that
- * ensures elements in the final array are still sampled uniformly.
- *
- * This works similarly to sampleStreamUniform. The |samplesA| array will be
- * updated, some of its elements replaced by elements from |samplesB| in a
- * way that ensure that elements will be sampled uniformly.
- *
- * Args:
- * samplesA: Array of uniformly sampled elements, will be updated.
- * streamLengthA: The length of the stream from which |samplesA| was sampled.
- * samplesB: Other array of uniformly sampled elements, will NOT be updated.
- * streamLengthB: The length of the stream from which |samplesB| was sampled.
- * numSamples: The total number of samples desired, both in |samplesA| and
- * |samplesB|.
- **/
- Statistics.mergeSampledStreams = function(
- samplesA, streamLengthA,
- samplesB, streamLengthB, numSamples) {
- if (streamLengthB < numSamples) {
- // samplesB has not reached max capacity so every sample of stream B were
- // chosen with certainty. Add them one by one into samplesA.
- var nbElements = Math.min(streamLengthB, samplesB.length);
- for (var i = 0; i < nbElements; ++i) {
- Statistics.uniformlySampleStream(samplesA, streamLengthA + i + 1,
- samplesB[i], numSamples);
- }
- return;
- }
- if (streamLengthA < numSamples) {
- // samplesA has not reached max capacity so every sample of stream A were
- // chosen with certainty. Add them one by one into samplesB.
- var nbElements = Math.min(streamLengthA, samplesA.length);
- var tempSamples = samplesB.slice();
- for (var i = 0; i < nbElements; ++i) {
- Statistics.uniformlySampleStream(tempSamples, streamLengthB + i + 1,
- samplesA[i], numSamples);
- }
- // Copy that back into the first vector.
- for (var i = 0; i < tempSamples.length; ++i) {
- samplesA[i] = tempSamples[i];
- }
- return;
- }
-
- // Both sample arrays are at max capacity, use the power of maths!
- // Elements in samplesA have been selected with probability
- // numSamples / streamLengthA. Same for samplesB. For each index of the
- // array we keep samplesA[i] with probability
- // P = streamLengthA / (streamLengthA + streamLengthB)
- // and replace it with samplesB[i] with probability 1-P.
- // The total probability of keeping it is therefore
- // numSamples / streamLengthA *
- // streamLengthA / (streamLengthA + streamLengthB)
- // = numSamples / (streamLengthA + streamLengthB)
- // A similar computation shows we have the same probability of keeping any
- // element in samplesB. Magic!
- var nbElements = Math.min(numSamples, samplesB.length);
- var probOfSwapping = streamLengthB / (streamLengthA + streamLengthB);
- for (var i = 0; i < nbElements; ++i) {
- if (Math.random() < probOfSwapping) {
- samplesA[i] = samplesB[i];
- }
- }
- };
-
- /* Continuous distributions are defined by probability density functions.
- *
- * Random variables are referred to by capital letters: X, Y, Z.
- * Particular values from these distributions are referred to by lowercase
- * letters like |x|.
- * The probability that |X| ever exactly equals |x| is P(X==x) = 0.
- *
- * For a discrete probability distribution, see tr.v.Histogram.
- */
- function Distribution() {
- }
-
- Distribution.prototype = {
- /* The probability density of the random variable at value |x| is the
- * relative likelihood for this random variable to take on the given value
- * |x|.
- *
- * @param {number} x A value from the random distribution.
- * @return {number} probability density at x.
- */
- computeDensity: function(x) {
- throw Error('Not implemented');
- },
-
- /* A percentile is the probability that a sample from the distribution is
- * less than the given value |x|. This function is monotonically increasing.
- *
- * @param {number} x A value from the random distribution.
- * @return {number} P(X<x).
- */
- computePercentile: function(x) {
- throw Error('Not implemented');
- },
-
- /* A complementary percentile is the probability that a sample from the
- * distribution is greater than the given value |x|. This function is
- * monotonically decreasing.
- *
- * @param {number} x A value from the random distribution.
- * @return {number} P(X>x).
- */
- computeComplementaryPercentile: function(x) {
- return 1 - this.computePercentile(x);
- },
-
- /* Compute the mean of the probability distribution.
- *
- * @return {number} mean.
- */
- get mean() {
- throw Error('Not implemented');
- },
-
- /* The mode of a distribution is the most likely value.
- * The maximum of the computeDensity() function is at this mode.
- * @return {number} mode.
- */
- get mode() {
- throw Error('Not implemented');
- },
-
- /* The median is the center value of the distribution.
- * computePercentile(median) = computeComplementaryPercentile(median) = 0.5
- *
- * @return {number} median.
- */
- get median() {
- throw Error('Not implemented');
- },
-
- /* The standard deviation is a measure of how dispersed or spread out the
- * distribution is (this statistic has the same units as the values).
- *
- * @return {number} standard deviation.
- */
- get standardDeviation() {
- throw Error('Not implemented');
- },
-
- /* An alternative measure of how spread out the distribution is,
- * the variance is the square of the standard deviation.
- * @return {number} variance.
- */
- get variance() {
- throw Error('Not implemented');
- }
- };
-
- Statistics.UniformDistribution = function(opt_range) {
- if (!opt_range)
- opt_range = tr.b.Range.fromExplicitRange(0, 1);
- this.range = opt_range;
- };
-
- Statistics.UniformDistribution.prototype = {
- __proto__: Distribution.prototype,
-
- computeDensity: function(x) {
- return 1 / this.range.range;
- },
-
- computePercentile: function(x) {
- return tr.b.normalize(x, this.range.min, this.range.max);
- },
-
- get mean() {
- return this.range.center;
- },
-
- get mode() {
- return undefined;
- },
-
- get median() {
- return this.mean;
- },
-
- get standardDeviation() {
- return Math.sqrt(this.variance);
- },
-
- get variance() {
- return Math.pow(this.range.range, 2) / 12;
- }
- };
-
- /* The Normal or Gaussian distribution, or bell curve, is common in complex
- * processes such as are found in many of the natural sciences. If Z is the
- * standard normal distribution with mean = 0 and variance = 1, then the
- * general normal distribution is Y = mean + Z*sqrt(variance).
- * https://www.desmos.com/calculator/tqtbjm4s3z
- */
- Statistics.NormalDistribution = function(opt_mean, opt_variance) {
- this.mean_ = opt_mean || 0;
- this.variance_ = opt_variance || 1;
- this.standardDeviation_ = Math.sqrt(this.variance_);
- };
-
- Statistics.NormalDistribution.prototype = {
- __proto__: Distribution.prototype,
-
- computeDensity: function(x) {
- var scale = (1.0 / (this.standardDeviation * Math.sqrt(2.0 * Math.PI)));
- var exponent = -Math.pow(x - this.mean, 2) / (2.0 * this.variance);
- return scale * Math.exp(exponent);
- },
-
- computePercentile: function(x) {
- var standardizedX = ((x - this.mean) /
- Math.sqrt(2.0 * this.variance));
- return (1.0 + tr.b.erf(standardizedX)) / 2.0;
- },
-
- get mean() {
- return this.mean_;
- },
-
- get median() {
- return this.mean;
- },
-
- get mode() {
- return this.mean;
- },
-
- get standardDeviation() {
- return this.standardDeviation_;
- },
-
- get variance() {
- return this.variance_;
- }
- };
-
- /* The log-normal distribution is a continuous probability distribution of a
- * random variable whose logarithm is normally distributed.
- * If Y is the general normal distribution, then X = exp(Y) is the general
- * log-normal distribution.
- * X will have different parameters from Y,
- * so the mean of Y is called the "location" of X,
- * and the standard deviation of Y is called the "shape" of X.
- * The standard lognormal distribution exp(Z) has location = 0 and shape = 1.
- * https://www.desmos.com/calculator/tqtbjm4s3z
- */
- Statistics.LogNormalDistribution = function(opt_location, opt_shape) {
- this.normalDistribution_ = new Statistics.NormalDistribution(
- opt_location, Math.pow(opt_shape || 1, 2));
- };
-
- Statistics.LogNormalDistribution.prototype = {
- __proto__: Statistics.NormalDistribution.prototype,
-
- computeDensity: function(x) {
- return this.normalDistribution_.computeDensity(Math.log(x)) / x;
- },
-
- computePercentile: function(x) {
- return this.normalDistribution_.computePercentile(Math.log(x));
- },
-
- get mean() {
- return Math.exp(this.normalDistribution_.mean +
- (this.normalDistribution_.variance / 2));
- },
-
- get variance() {
- var nm = this.normalDistribution_.mean;
- var nv = this.normalDistribution_.variance;
- return (Math.exp(2 * (nm + nv)) -
- Math.exp(2 * nm + nv));
- },
-
- get standardDeviation() {
- return Math.sqrt(this.variance);
- },
-
- get median() {
- return Math.exp(this.normalDistribution_.mean);
- },
-
- get mode() {
- return Math.exp(this.normalDistribution_.mean -
- this.normalDistribution_.variance);
- }
- };
-
- /**
- * Instead of describing a LogNormalDistribution in terms of its "location"
- * and "shape", it can also be described in terms of its median
- * and the point at which its complementary cumulative distribution
- * function bends between the linear-ish region in the middle and the
- * exponential-ish region. When the distribution is used to compute
- * percentiles for log-normal random processes such as latency, as the latency
- * improves, it hits a point of diminishing returns, when it becomes
- * relatively difficult to improve the score further. This point of
- * diminishing returns is the first x-intercept of the third derivative of the
- * CDF, which is the second derivative of the PDF.
- *
- * https://www.desmos.com/calculator/cg5rnftabn
- *
- * @param {number} median The median of the distribution.
- * @param {number} diminishingReturns The point of diminishing returns.
- * @return {LogNormalDistribution}
- */
- Statistics.LogNormalDistribution.fromMedianAndDiminishingReturns =
- function(median, diminishingReturns) {
- diminishingReturns = Math.log(diminishingReturns / median);
- var shape = Math.sqrt(1 - 3 * diminishingReturns -
- Math.sqrt(Math.pow(diminishingReturns - 3, 2) - 8)) / 2;
- var location = Math.log(median);
- return new Statistics.LogNormalDistribution(location, shape);
- };
-
- // p-values less than this indicate statistical significance.
- Statistics.DEFAULT_ALPHA = 0.01;
-
- // If a statistical significant difference has not been established with
- // this many observations per sample, we'll assume none exists.
- Statistics.MAX_SUGGESTED_SAMPLE_SIZE = 20;
-
- /** @enum */
- Statistics.Significance = {
- SIGNIFICANT: 'REJECT',
- INSIGNIFICANT: 'FAIL_TO_REJECT',
- NEED_MORE_DATA: 'NEED_MORE_DATA',
- DONT_CARE: 'DONT_CARE',
- };
-
-
- /**
- * @typedef {Object} HypothesisTestResult
- * @property {number} p
- * @property {number} U
- * @property {!tr.b.Statistics.Significance} significance
- */
-
- /**
- * @param {!Array.<number>} a
- * @param {!Array.<number>} b
- * @param {number=} opt_alpha
- * @param {number=} opt_reqSampleSize
- * @return {!HypothesisTestResult}
- */
- Statistics.mwu = function(a, b, opt_alpha, opt_reqSampleSize) {
- var result = mannwhitneyu.test(a, b);
- var alpha = opt_alpha || Statistics.DEFAULT_ALPHA;
- if (result.p < alpha) {
- result.significance = Statistics.Significance.SIGNIFICANT;
- } else if (opt_reqSampleSize && (a.length < opt_reqSampleSize ||
- b.length < opt_reqSampleSize)) {
- result.significance = Statistics.Significance.NEED_MORE_DATA;
- } else {
- result.significance = Statistics.Significance.INSIGNIFICANT;
- }
- return result;
- };
-
- return {
- Statistics,
- };
-});
-</script>
« no previous file with comments | « tracing/tracing/base/sorted_array_utils_test.html ('k') | tracing/tracing/base/statistics_test.html » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698