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 |