| OLD | NEW |
| 1 <!DOCTYPE html> | 1 <!DOCTYPE html> |
| 2 <!-- | 2 <!-- |
| 3 Copyright 2014 The Chromium Authors. All rights reserved. | 3 Copyright 2014 The Chromium Authors. All rights reserved. |
| 4 Use of this source code is governed by a BSD-style license that can be | 4 Use of this source code is governed by a BSD-style license that can be |
| 5 found in the LICENSE file. | 5 found in the LICENSE file. |
| 6 --> | 6 --> |
| 7 | 7 |
| 8 <link rel="import" href="/tracing/base/math.html"> | 8 <link rel="import" href="/tracing/base/math/math.html"> |
| 9 <link rel="import" href="/tracing/base/range.html"> | 9 <link rel="import" href="/tracing/base/math/range.html"> |
| 10 <script src="/mannwhitneyu/mannwhitneyu.js"></script> | 10 <script src="/mannwhitneyu/mannwhitneyu.js"></script> |
| 11 | 11 |
| 12 <script> | 12 <script> |
| 13 'use strict'; | 13 'use strict'; |
| 14 | 14 |
| 15 // In node, the script-src for mannwhitneyu above brings in mannwhitneyui | 15 // In node, the script-src for mannwhitneyu above brings in mannwhitneyui |
| 16 // into a module, instead of into the global scope. Whereas this file | 16 // into a module, instead of into the global scope. Whereas this file |
| 17 // assumes that mannwhitneyu is in the global scope. So, in Node only, we | 17 // assumes that mannwhitneyu is in the global scope. So, in Node only, we |
| 18 // require() it in, and then take all its exports and shove them into the | 18 // require() it in, and then take all its exports and shove them into the |
| 19 // global scope by hand. | 19 // global scope by hand. |
| 20 (function(global) { | 20 (function(global) { |
| 21 if (tr.isNode) { | 21 if (tr.isNode) { |
| 22 var mwuAbsPath = HTMLImportsLoader.hrefToAbsolutePath( | 22 var mwuAbsPath = HTMLImportsLoader.hrefToAbsolutePath( |
| 23 '/mannwhitneyu.js'); | 23 '/mannwhitneyu.js'); |
| 24 var mwuModule = require(mwuAbsPath); | 24 var mwuModule = require(mwuAbsPath); |
| 25 for (var exportName in mwuModule) { | 25 for (var exportName in mwuModule) { |
| 26 global[exportName] = mwuModule[exportName]; | 26 global[exportName] = mwuModule[exportName]; |
| 27 } | 27 } |
| 28 } | 28 } |
| 29 })(this); | 29 })(this); |
| 30 </script> | 30 </script> |
| 31 | 31 |
| 32 <script> | 32 <script> |
| 33 'use strict'; | 33 'use strict'; |
| 34 | 34 |
| 35 // TODO(charliea): Remove: | 35 // TODO(charliea): Remove: |
| 36 /* eslint-disable catapult-camelcase */ | 36 /* eslint-disable catapult-camelcase */ |
| 37 | 37 |
| 38 tr.exportTo('tr.b', function() { | 38 tr.exportTo('tr.b.math', function() { |
| 39 var identity = x => x; | 39 var identity = x => x; |
| 40 | 40 |
| 41 var Statistics = {}; | 41 var Statistics = {}; |
| 42 | 42 |
| 43 /* Returns the quotient, or zero if the denominator is zero.*/ | 43 /* Returns the quotient, or zero if the denominator is zero.*/ |
| 44 Statistics.divideIfPossibleOrZero = function(numerator, denominator) { | 44 Statistics.divideIfPossibleOrZero = function(numerator, denominator) { |
| 45 if (denominator === 0) | 45 if (denominator === 0) |
| 46 return 0; | 46 return 0; |
| 47 return numerator / denominator; | 47 return numerator / denominator; |
| 48 }; | 48 }; |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 151 var func = opt_func || identity; | 151 var func = opt_func || identity; |
| 152 var ret = Infinity; | 152 var ret = Infinity; |
| 153 var i = 0; | 153 var i = 0; |
| 154 for (var elt of ary) | 154 for (var elt of ary) |
| 155 ret = Math.min(ret, func.call(opt_this, elt, i++)); | 155 ret = Math.min(ret, func.call(opt_this, elt, i++)); |
| 156 return ret; | 156 return ret; |
| 157 }; | 157 }; |
| 158 | 158 |
| 159 Statistics.range = function(ary, opt_func, opt_this) { | 159 Statistics.range = function(ary, opt_func, opt_this) { |
| 160 var func = opt_func || identity; | 160 var func = opt_func || identity; |
| 161 var ret = new tr.b.Range(); | 161 var ret = new tr.b.math.Range(); |
| 162 var i = 0; | 162 var i = 0; |
| 163 for (var elt of ary) | 163 for (var elt of ary) |
| 164 ret.addValue(func.call(opt_this, elt, i++)); | 164 ret.addValue(func.call(opt_this, elt, i++)); |
| 165 return ret; | 165 return ret; |
| 166 }; | 166 }; |
| 167 | 167 |
| 168 Statistics.percentile = function(ary, percent, opt_func, opt_this) { | 168 Statistics.percentile = function(ary, percent, opt_func, opt_this) { |
| 169 if (!(percent >= 0 && percent <= 1)) | 169 if (!(percent >= 0 && percent <= 1)) |
| 170 throw new Error('percent must be [0,1]'); | 170 throw new Error('percent must be [0,1]'); |
| 171 | 171 |
| (...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 376 var s = Statistics.normalizeSamples(timestamps); | 376 var s = Statistics.normalizeSamples(timestamps); |
| 377 var samples = s.normalized_samples; | 377 var samples = s.normalized_samples; |
| 378 var sampleScale = s.scale; | 378 var sampleScale = s.scale; |
| 379 var discrepancy = Statistics.discrepancy(samples, opt_locationCount); | 379 var discrepancy = Statistics.discrepancy(samples, opt_locationCount); |
| 380 var invSampleCount = 1.0 / samples.length; | 380 var invSampleCount = 1.0 / samples.length; |
| 381 if (opt_absolute === true) { | 381 if (opt_absolute === true) { |
| 382 // Compute absolute discrepancy | 382 // Compute absolute discrepancy |
| 383 discrepancy /= sampleScale; | 383 discrepancy /= sampleScale; |
| 384 } else { | 384 } else { |
| 385 // Compute relative discrepancy | 385 // Compute relative discrepancy |
| 386 discrepancy = tr.b.clamp( | 386 discrepancy = tr.b.math.clamp( |
| 387 (discrepancy - invSampleCount) / (1.0 - invSampleCount), 0.0, 1.0); | 387 (discrepancy - invSampleCount) / (1.0 - invSampleCount), 0.0, 1.0); |
| 388 } | 388 } |
| 389 return discrepancy; | 389 return discrepancy; |
| 390 }; | 390 }; |
| 391 | 391 |
| 392 /** | 392 /** |
| 393 * A discrepancy based metric for measuring duration jank. | 393 * A discrepancy based metric for measuring duration jank. |
| 394 * | 394 * |
| 395 * DurationsDiscrepancy computes a jank metric which measures how irregular a | 395 * DurationsDiscrepancy computes a jank metric which measures how irregular a |
| 396 * given sequence of intervals is. In order to minimize jank, each duration | 396 * given sequence of intervals is. In order to minimize jank, each duration |
| (...skipping 230 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 627 * the variance is the square of the standard deviation. | 627 * the variance is the square of the standard deviation. |
| 628 * @return {number} variance. | 628 * @return {number} variance. |
| 629 */ | 629 */ |
| 630 get variance() { | 630 get variance() { |
| 631 throw Error('Not implemented'); | 631 throw Error('Not implemented'); |
| 632 } | 632 } |
| 633 }; | 633 }; |
| 634 | 634 |
| 635 Statistics.UniformDistribution = function(opt_range) { | 635 Statistics.UniformDistribution = function(opt_range) { |
| 636 if (!opt_range) | 636 if (!opt_range) |
| 637 opt_range = tr.b.Range.fromExplicitRange(0, 1); | 637 opt_range = tr.b.math.Range.fromExplicitRange(0, 1); |
| 638 this.range = opt_range; | 638 this.range = opt_range; |
| 639 }; | 639 }; |
| 640 | 640 |
| 641 Statistics.UniformDistribution.prototype = { | 641 Statistics.UniformDistribution.prototype = { |
| 642 __proto__: Distribution.prototype, | 642 __proto__: Distribution.prototype, |
| 643 | 643 |
| 644 computeDensity: function(x) { | 644 computeDensity: function(x) { |
| 645 return 1 / this.range.range; | 645 return 1 / this.range.range; |
| 646 }, | 646 }, |
| 647 | 647 |
| 648 computePercentile: function(x) { | 648 computePercentile: function(x) { |
| 649 return tr.b.normalize(x, this.range.min, this.range.max); | 649 return tr.b.math.normalize(x, this.range.min, this.range.max); |
| 650 }, | 650 }, |
| 651 | 651 |
| 652 get mean() { | 652 get mean() { |
| 653 return this.range.center; | 653 return this.range.center; |
| 654 }, | 654 }, |
| 655 | 655 |
| 656 get mode() { | 656 get mode() { |
| 657 return undefined; | 657 return undefined; |
| 658 }, | 658 }, |
| 659 | 659 |
| (...skipping 27 matching lines...) Expand all Loading... |
| 687 | 687 |
| 688 computeDensity: function(x) { | 688 computeDensity: function(x) { |
| 689 var scale = (1.0 / (this.standardDeviation * Math.sqrt(2.0 * Math.PI))); | 689 var scale = (1.0 / (this.standardDeviation * Math.sqrt(2.0 * Math.PI))); |
| 690 var exponent = -Math.pow(x - this.mean, 2) / (2.0 * this.variance); | 690 var exponent = -Math.pow(x - this.mean, 2) / (2.0 * this.variance); |
| 691 return scale * Math.exp(exponent); | 691 return scale * Math.exp(exponent); |
| 692 }, | 692 }, |
| 693 | 693 |
| 694 computePercentile: function(x) { | 694 computePercentile: function(x) { |
| 695 var standardizedX = ((x - this.mean) / | 695 var standardizedX = ((x - this.mean) / |
| 696 Math.sqrt(2.0 * this.variance)); | 696 Math.sqrt(2.0 * this.variance)); |
| 697 return (1.0 + tr.b.erf(standardizedX)) / 2.0; | 697 return (1.0 + tr.b.math.erf(standardizedX)) / 2.0; |
| 698 }, | 698 }, |
| 699 | 699 |
| 700 get mean() { | 700 get mean() { |
| 701 return this.mean_; | 701 return this.mean_; |
| 702 }, | 702 }, |
| 703 | 703 |
| 704 get median() { | 704 get median() { |
| 705 return this.mean; | 705 return this.mean; |
| 706 }, | 706 }, |
| 707 | 707 |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 810 INSIGNIFICANT: 'FAIL_TO_REJECT', | 810 INSIGNIFICANT: 'FAIL_TO_REJECT', |
| 811 NEED_MORE_DATA: 'NEED_MORE_DATA', | 811 NEED_MORE_DATA: 'NEED_MORE_DATA', |
| 812 DONT_CARE: 'DONT_CARE', | 812 DONT_CARE: 'DONT_CARE', |
| 813 }; | 813 }; |
| 814 | 814 |
| 815 | 815 |
| 816 /** | 816 /** |
| 817 * @typedef {Object} HypothesisTestResult | 817 * @typedef {Object} HypothesisTestResult |
| 818 * @property {number} p | 818 * @property {number} p |
| 819 * @property {number} U | 819 * @property {number} U |
| 820 * @property {!tr.b.Statistics.Significance} significance | 820 * @property {!tr.b.math.Statistics.Significance} significance |
| 821 */ | 821 */ |
| 822 | 822 |
| 823 /** | 823 /** |
| 824 * @param {!Array.<number>} a | 824 * @param {!Array.<number>} a |
| 825 * @param {!Array.<number>} b | 825 * @param {!Array.<number>} b |
| 826 * @param {number=} opt_alpha | 826 * @param {number=} opt_alpha |
| 827 * @param {number=} opt_reqSampleSize | 827 * @param {number=} opt_reqSampleSize |
| 828 * @return {!HypothesisTestResult} | 828 * @return {!HypothesisTestResult} |
| 829 */ | 829 */ |
| 830 Statistics.mwu = function(a, b, opt_alpha, opt_reqSampleSize) { | 830 Statistics.mwu = function(a, b, opt_alpha, opt_reqSampleSize) { |
| 831 var result = mannwhitneyu.test(a, b); | 831 var result = mannwhitneyu.test(a, b); |
| 832 var alpha = opt_alpha || Statistics.DEFAULT_ALPHA; | 832 var alpha = opt_alpha || Statistics.DEFAULT_ALPHA; |
| 833 if (result.p < alpha) { | 833 if (result.p < alpha) { |
| 834 result.significance = Statistics.Significance.SIGNIFICANT; | 834 result.significance = Statistics.Significance.SIGNIFICANT; |
| 835 } else if (opt_reqSampleSize && (a.length < opt_reqSampleSize || | 835 } else if (opt_reqSampleSize && (a.length < opt_reqSampleSize || |
| 836 b.length < opt_reqSampleSize)) { | 836 b.length < opt_reqSampleSize)) { |
| 837 result.significance = Statistics.Significance.NEED_MORE_DATA; | 837 result.significance = Statistics.Significance.NEED_MORE_DATA; |
| 838 } else { | 838 } else { |
| 839 result.significance = Statistics.Significance.INSIGNIFICANT; | 839 result.significance = Statistics.Significance.INSIGNIFICANT; |
| 840 } | 840 } |
| 841 return result; | 841 return result; |
| 842 }; | 842 }; |
| 843 | 843 |
| 844 return { | 844 return { |
| 845 Statistics, | 845 Statistics, |
| 846 }; | 846 }; |
| 847 }); | 847 }); |
| 848 </script> | 848 </script> |
| OLD | NEW |