OLD | NEW |
1 <!DOCTYPE html> | 1 <!DOCTYPE html> |
2 <!-- | 2 <!-- |
3 Copyright 2016 The Chromium Authors. All rights reserved. | 3 Copyright 2016 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/iteration_helpers.html"> | 8 <link rel="import" href="/tracing/base/iteration_helpers.html"> |
9 <link rel="import" href="/tracing/base/range.html"> | 9 <link rel="import" href="/tracing/base/math/range.html"> |
10 <link rel="import" href="/tracing/base/running_statistics.html"> | 10 <link rel="import" href="/tracing/base/math/running_statistics.html"> |
| 11 <link rel="import" href="/tracing/base/math/sorted_array_utils.html"> |
| 12 <link rel="import" href="/tracing/base/math/statistics.html"> |
11 <link rel="import" href="/tracing/base/scalar.html"> | 13 <link rel="import" href="/tracing/base/scalar.html"> |
12 <link rel="import" href="/tracing/base/sorted_array_utils.html"> | |
13 <link rel="import" href="/tracing/base/statistics.html"> | |
14 <link rel="import" href="/tracing/base/unit.html"> | 14 <link rel="import" href="/tracing/base/unit.html"> |
15 <link rel="import" href="/tracing/value/diagnostics/diagnostic_map.html"> | 15 <link rel="import" href="/tracing/value/diagnostics/diagnostic_map.html"> |
16 | 16 |
17 <script> | 17 <script> |
18 'use strict'; | 18 'use strict'; |
19 | 19 |
20 tr.exportTo('tr.v', function() { | 20 tr.exportTo('tr.v', function() { |
21 const MAX_DIAGNOSTIC_MAPS = 16; | 21 const MAX_DIAGNOSTIC_MAPS = 16; |
22 | 22 |
23 const DEFAULT_SAMPLE_VALUES_PER_BIN = 10; | 23 const DEFAULT_SAMPLE_VALUES_PER_BIN = 10; |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
56 * Converts the given string to a percent between 0 and 1. | 56 * Converts the given string to a percent between 0 and 1. |
57 * @param {string} | 57 * @param {string} |
58 * @return {number} | 58 * @return {number} |
59 */ | 59 */ |
60 function percentFromString(s) { | 60 function percentFromString(s) { |
61 return parseFloat(s[0] + '.' + s.substr(1).replace(/_/g, '')); | 61 return parseFloat(s[0] + '.' + s.substr(1).replace(/_/g, '')); |
62 } | 62 } |
63 | 63 |
64 class HistogramBin { | 64 class HistogramBin { |
65 /** | 65 /** |
66 * @param {!tr.b.Range} range | 66 * @param {!tr.b.math.Range} range |
67 */ | 67 */ |
68 constructor(range) { | 68 constructor(range) { |
69 this.range = range; | 69 this.range = range; |
70 this.count = 0; | 70 this.count = 0; |
71 this.diagnosticMaps = []; | 71 this.diagnosticMaps = []; |
72 } | 72 } |
73 | 73 |
74 /** | 74 /** |
75 * @param {*} value | 75 * @param {*} value |
76 */ | 76 */ |
77 addSample(value) { | 77 addSample(value) { |
78 this.count += 1; | 78 this.count += 1; |
79 } | 79 } |
80 | 80 |
81 /** | 81 /** |
82 * @param {!tr.v.d.DiagnosticMap} diagnostics | 82 * @param {!tr.v.d.DiagnosticMap} diagnostics |
83 */ | 83 */ |
84 addDiagnosticMap(diagnostics) { | 84 addDiagnosticMap(diagnostics) { |
85 tr.b.Statistics.uniformlySampleStream( | 85 tr.b.math.Statistics.uniformlySampleStream( |
86 this.diagnosticMaps, this.count, diagnostics, MAX_DIAGNOSTIC_MAPS); | 86 this.diagnosticMaps, this.count, diagnostics, MAX_DIAGNOSTIC_MAPS); |
87 } | 87 } |
88 | 88 |
89 addBin(other) { | 89 addBin(other) { |
90 if (!this.range.equals(other.range)) { | 90 if (!this.range.equals(other.range)) { |
91 throw new Error('Merging incompatible Histogram bins.'); | 91 throw new Error('Merging incompatible Histogram bins.'); |
92 } | 92 } |
93 tr.b.Statistics.mergeSampledStreams(this.diagnosticMaps, this.count, | 93 tr.b.math.Statistics.mergeSampledStreams(this.diagnosticMaps, this.count, |
94 other.diagnosticMaps, other.count, MAX_DIAGNOSTIC_MAPS); | 94 other.diagnosticMaps, other.count, MAX_DIAGNOSTIC_MAPS); |
95 this.count += other.count; | 95 this.count += other.count; |
96 } | 96 } |
97 | 97 |
98 fromDict(dict) { | 98 fromDict(dict) { |
99 this.count = dict[0]; | 99 this.count = dict[0]; |
100 if (dict.length > 1) { | 100 if (dict.length > 1) { |
101 for (let map of dict[1]) { | 101 for (let map of dict[1]) { |
102 this.diagnosticMaps.push(tr.v.d.DiagnosticMap.fromDict(map)); | 102 this.diagnosticMaps.push(tr.v.d.DiagnosticMap.fromDict(map)); |
103 } | 103 } |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
186 get running() { | 186 get running() { |
187 return this.running_; | 187 return this.running_; |
188 } | 188 } |
189 | 189 |
190 get maxNumSampleValues() { | 190 get maxNumSampleValues() { |
191 return this.maxNumSampleValues_; | 191 return this.maxNumSampleValues_; |
192 } | 192 } |
193 | 193 |
194 set maxNumSampleValues(n) { | 194 set maxNumSampleValues(n) { |
195 this.maxNumSampleValues_ = n; | 195 this.maxNumSampleValues_ = n; |
196 tr.b.Statistics.uniformlySampleArray( | 196 tr.b.math.Statistics.uniformlySampleArray( |
197 this.sampleValues_, this.maxNumSampleValues_); | 197 this.sampleValues_, this.maxNumSampleValues_); |
198 } | 198 } |
199 | 199 |
200 get name() { | 200 get name() { |
201 return this.name_; | 201 return this.name_; |
202 } | 202 } |
203 | 203 |
204 get guid() { | 204 get guid() { |
205 if (this.guid_ === undefined) { | 205 if (this.guid_ === undefined) { |
206 this.guid_ = tr.b.GUID.allocateUUID4(); | 206 this.guid_ = tr.b.GUID.allocateUUID4(); |
(...skipping 28 matching lines...) Expand all Loading... |
235 for (let i = 0; i < dict.allBins.length; ++i) { | 235 for (let i = 0; i < dict.allBins.length; ++i) { |
236 hist.allBins[i].fromDict(dict.allBins[i]); | 236 hist.allBins[i].fromDict(dict.allBins[i]); |
237 } | 237 } |
238 } else { | 238 } else { |
239 for (var [i, binDict] of Object.entries(dict.allBins)) { | 239 for (var [i, binDict] of Object.entries(dict.allBins)) { |
240 hist.allBins[i].fromDict(binDict); | 240 hist.allBins[i].fromDict(binDict); |
241 } | 241 } |
242 } | 242 } |
243 } | 243 } |
244 if (dict.running) { | 244 if (dict.running) { |
245 hist.running_ = tr.b.RunningStatistics.fromDict(dict.running); | 245 hist.running_ = tr.b.math.RunningStatistics.fromDict(dict.running); |
246 } | 246 } |
247 if (dict.summaryOptions) { | 247 if (dict.summaryOptions) { |
248 hist.customizeSummaryOptions(dict.summaryOptions); | 248 hist.customizeSummaryOptions(dict.summaryOptions); |
249 } | 249 } |
250 if (dict.maxNumSampleValues !== undefined) { | 250 if (dict.maxNumSampleValues !== undefined) { |
251 hist.maxNumSampleValues = dict.maxNumSampleValues; | 251 hist.maxNumSampleValues = dict.maxNumSampleValues; |
252 } | 252 } |
253 if (dict.sampleValues) { | 253 if (dict.sampleValues) { |
254 hist.sampleValues_ = dict.sampleValues; | 254 hist.sampleValues_ = dict.sampleValues; |
255 } | 255 } |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
294 | 294 |
295 /** | 295 /** |
296 * Requires that units agree. | 296 * Requires that units agree. |
297 * Returns DONT_CARE if that is the units' improvementDirection. | 297 * Returns DONT_CARE if that is the units' improvementDirection. |
298 * Returns SIGNIFICANT if the Mann-Whitney U test returns a | 298 * Returns SIGNIFICANT if the Mann-Whitney U test returns a |
299 * p-value less than opt_alpha or DEFAULT_ALPHA. Returns INSIGNIFICANT if | 299 * p-value less than opt_alpha or DEFAULT_ALPHA. Returns INSIGNIFICANT if |
300 * the p-value is greater than alpha. | 300 * the p-value is greater than alpha. |
301 * | 301 * |
302 * @param {!tr.v.Histogram} other | 302 * @param {!tr.v.Histogram} other |
303 * @param {number=} opt_alpha | 303 * @param {number=} opt_alpha |
304 * @return {!tr.b.Statistics.Significance} | 304 * @return {!tr.b.math.Statistics.Significance} |
305 */ | 305 */ |
306 getDifferenceSignificance(other, opt_alpha) { | 306 getDifferenceSignificance(other, opt_alpha) { |
307 if (this.unit !== other.unit) { | 307 if (this.unit !== other.unit) { |
308 throw new Error('Cannot compare Histograms with different units'); | 308 throw new Error('Cannot compare Histograms with different units'); |
309 } | 309 } |
310 | 310 |
311 if (this.unit.improvementDirection === | 311 if (this.unit.improvementDirection === |
312 tr.b.ImprovementDirection.DONT_CARE) { | 312 tr.b.ImprovementDirection.DONT_CARE) { |
313 return tr.b.Statistics.Significance.DONT_CARE; | 313 return tr.b.math.Statistics.Significance.DONT_CARE; |
314 } | 314 } |
315 | 315 |
316 if (!(other instanceof Histogram)) { | 316 if (!(other instanceof Histogram)) { |
317 throw new Error('Unable to compute a p-value'); | 317 throw new Error('Unable to compute a p-value'); |
318 } | 318 } |
319 | 319 |
320 let testResult = tr.b.Statistics.mwu( | 320 let testResult = tr.b.math.Statistics.mwu( |
321 this.sampleValues, other.sampleValues, opt_alpha); | 321 this.sampleValues, other.sampleValues, opt_alpha); |
322 return testResult.significance; | 322 return testResult.significance; |
323 } | 323 } |
324 | 324 |
325 /* | 325 /* |
326 * Compute an approximation of percentile based on the counts in the bins. | 326 * Compute an approximation of percentile based on the counts in the bins. |
327 * If the real percentile lies within |this.range| then the result of | 327 * If the real percentile lies within |this.range| then the result of |
328 * the function will deviate from the real percentile by at most | 328 * the function will deviate from the real percentile by at most |
329 * the maximum width of the bin(s) within which the point(s) | 329 * the maximum width of the bin(s) within which the point(s) |
330 * from which the real percentile would be calculated lie. | 330 * from which the real percentile would be calculated lie. |
(...skipping 25 matching lines...) Expand all Loading... |
356 return bin.range.max; | 356 return bin.range.max; |
357 if (bin.range.max === Number.MAX_VALUE) | 357 if (bin.range.max === Number.MAX_VALUE) |
358 return bin.range.min; | 358 return bin.range.min; |
359 return bin.range.center; | 359 return bin.range.center; |
360 } | 360 } |
361 return this.allBins[this.allBins.length - 1].range.min; | 361 return this.allBins[this.allBins.length - 1].range.min; |
362 } | 362 } |
363 | 363 |
364 getBinForValue(value) { | 364 getBinForValue(value) { |
365 // Don't use subtraction to avoid arithmetic overflow. | 365 // Don't use subtraction to avoid arithmetic overflow. |
366 let binIndex = tr.b.findHighIndexInSortedArray( | 366 let binIndex = tr.b.math.findHighIndexInSortedArray( |
367 this.allBins, b => ((value < b.range.max) ? -1 : 1)); | 367 this.allBins, b => ((value < b.range.max) ? -1 : 1)); |
368 return this.allBins[binIndex] || this.allBins[this.allBins.length - 1]; | 368 return this.allBins[binIndex] || this.allBins[this.allBins.length - 1]; |
369 } | 369 } |
370 | 370 |
371 /** | 371 /** |
372 * @param {number|*} value | 372 * @param {number|*} value |
373 * @param {(!Object|!tr.v.d.DiagnosticMap)=} opt_diagnostics | 373 * @param {(!Object|!tr.v.d.DiagnosticMap)=} opt_diagnostics |
374 */ | 374 */ |
375 addSample(value, opt_diagnostics) { | 375 addSample(value, opt_diagnostics) { |
376 if (opt_diagnostics && | 376 if (opt_diagnostics && |
377 !(opt_diagnostics instanceof tr.v.d.DiagnosticMap)) { | 377 !(opt_diagnostics instanceof tr.v.d.DiagnosticMap)) { |
378 opt_diagnostics = tr.v.d.DiagnosticMap.fromObject(opt_diagnostics); | 378 opt_diagnostics = tr.v.d.DiagnosticMap.fromObject(opt_diagnostics); |
379 } | 379 } |
380 | 380 |
381 if (typeof(value) !== 'number' || isNaN(value)) { | 381 if (typeof(value) !== 'number' || isNaN(value)) { |
382 this.numNans++; | 382 this.numNans++; |
383 if (opt_diagnostics) { | 383 if (opt_diagnostics) { |
384 tr.b.Statistics.uniformlySampleStream(this.nanDiagnosticMaps, | 384 tr.b.math.Statistics.uniformlySampleStream(this.nanDiagnosticMaps, |
385 this.numNans, opt_diagnostics, MAX_DIAGNOSTIC_MAPS); | 385 this.numNans, opt_diagnostics, MAX_DIAGNOSTIC_MAPS); |
386 } | 386 } |
387 } else { | 387 } else { |
388 if (this.running_ === undefined) { | 388 if (this.running_ === undefined) { |
389 this.running_ = new tr.b.RunningStatistics(); | 389 this.running_ = new tr.b.math.RunningStatistics(); |
390 } | 390 } |
391 this.running_.add(value); | 391 this.running_.add(value); |
392 | 392 |
393 let bin = this.getBinForValue(value); | 393 let bin = this.getBinForValue(value); |
394 bin.addSample(value); | 394 bin.addSample(value); |
395 if (opt_diagnostics) { | 395 if (opt_diagnostics) { |
396 bin.addDiagnosticMap(opt_diagnostics); | 396 bin.addDiagnosticMap(opt_diagnostics); |
397 } | 397 } |
398 } | 398 } |
399 | 399 |
400 tr.b.Statistics.uniformlySampleStream(this.sampleValues_, | 400 tr.b.math.Statistics.uniformlySampleStream(this.sampleValues_, |
401 this.numValues + this.numNans, value, this.maxNumSampleValues); | 401 this.numValues + this.numNans, value, this.maxNumSampleValues); |
402 } | 402 } |
403 | 403 |
404 sampleValuesInto(samples) { | 404 sampleValuesInto(samples) { |
405 for (let sampleValue of this.sampleValues) { | 405 for (let sampleValue of this.sampleValues) { |
406 samples.push(sampleValue); | 406 samples.push(sampleValue); |
407 } | 407 } |
408 } | 408 } |
409 | 409 |
410 /** | 410 /** |
(...skipping 14 matching lines...) Expand all Loading... |
425 return false; | 425 return false; |
426 } | 426 } |
427 for (let i = 0; i < this.binBoundariesDict_.length; ++i) { | 427 for (let i = 0; i < this.binBoundariesDict_.length; ++i) { |
428 let slice = this.binBoundariesDict_[i]; | 428 let slice = this.binBoundariesDict_[i]; |
429 let otherSlice = other.binBoundariesDict_[i]; | 429 let otherSlice = other.binBoundariesDict_[i]; |
430 if (slice instanceof Array) { | 430 if (slice instanceof Array) { |
431 if (!(otherSlice instanceof Array)) { | 431 if (!(otherSlice instanceof Array)) { |
432 return false; | 432 return false; |
433 } | 433 } |
434 if (slice[0] !== otherSlice[0] || | 434 if (slice[0] !== otherSlice[0] || |
435 !tr.b.approximately(slice[1], otherSlice[1]) || | 435 !tr.b.math.approximately(slice[1], otherSlice[1]) || |
436 slice[2] !== otherSlice[2]) { | 436 slice[2] !== otherSlice[2]) { |
437 return false; | 437 return false; |
438 } | 438 } |
439 } else { | 439 } else { |
440 if (otherSlice instanceof Array) { | 440 if (otherSlice instanceof Array) { |
441 return false; | 441 return false; |
442 } | 442 } |
443 if (!tr.b.approximately(slice, otherSlice)) { | 443 if (!tr.b.math.approximately(slice, otherSlice)) { |
444 return false; | 444 return false; |
445 } | 445 } |
446 } | 446 } |
447 } | 447 } |
448 return true; | 448 return true; |
449 } | 449 } |
450 | 450 |
451 /** | 451 /** |
452 * Add |other| to this Histogram in-place if they can be added. | 452 * Add |other| to this Histogram in-place if they can be added. |
453 * | 453 * |
454 * @param {!tr.v.Histogram} other | 454 * @param {!tr.v.Histogram} other |
455 */ | 455 */ |
456 addHistogram(other) { | 456 addHistogram(other) { |
457 if (!this.canAddHistogram(other)) { | 457 if (!this.canAddHistogram(other)) { |
458 throw new Error('Merging incompatible Histograms'); | 458 throw new Error('Merging incompatible Histograms'); |
459 } | 459 } |
460 | 460 |
461 tr.b.Statistics.mergeSampledStreams(this.nanDiagnosticMaps, this.numNans, | 461 tr.b.math.Statistics.mergeSampledStreams(this.nanDiagnosticMaps, |
462 other.nanDiagnosticMaps, other.numNans, MAX_DIAGNOSTIC_MAPS); | 462 this.numNans, other.nanDiagnosticMaps, other.numNans, |
463 tr.b.Statistics.mergeSampledStreams( | 463 MAX_DIAGNOSTIC_MAPS); |
| 464 tr.b.math.Statistics.mergeSampledStreams( |
464 this.sampleValues, this.numValues + this.numNans, | 465 this.sampleValues, this.numValues + this.numNans, |
465 other.sampleValues, other.numValues + other.numNans, | 466 other.sampleValues, other.numValues + other.numNans, |
466 (this.maxNumSampleValues + other.maxNumSampleValues) / 2); | 467 (this.maxNumSampleValues + other.maxNumSampleValues) / 2); |
467 this.numNans += other.numNans; | 468 this.numNans += other.numNans; |
468 | 469 |
469 if (other.running_ !== undefined) { | 470 if (other.running_ !== undefined) { |
470 if (this.running_ === undefined) { | 471 if (this.running_ === undefined) { |
471 this.running_ = new tr.b.RunningStatistics(); | 472 this.running_ = new tr.b.math.RunningStatistics(); |
472 } | 473 } |
473 this.running_ = this.running_.merge(other.running_); | 474 this.running_ = this.running_.merge(other.running_); |
474 } | 475 } |
475 | 476 |
476 for (let i = 0; i < this.allBins.length; ++i) { | 477 for (let i = 0; i < this.allBins.length; ++i) { |
477 this.allBins[i].addBin(other.allBins[i]); | 478 this.allBins[i].addBin(other.allBins[i]); |
478 } | 479 } |
479 | 480 |
480 let mergedFrom = this.diagnostics.get(tr.v.d.MERGED_FROM_DIAGNOSTIC_KEY); | 481 let mergedFrom = this.diagnostics.get(tr.v.d.MERGED_FROM_DIAGNOSTIC_KEY); |
481 if (!mergedFrom) { | 482 if (!mergedFrom) { |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
543 } | 544 } |
544 if (statName === 'std') { | 545 if (statName === 'std') { |
545 if (this.standardDeviation === undefined) return undefined; | 546 if (this.standardDeviation === undefined) return undefined; |
546 return new tr.b.Scalar(this.unit, this.standardDeviation); | 547 return new tr.b.Scalar(this.unit, this.standardDeviation); |
547 } | 548 } |
548 if (statName === 'geometricMean') { | 549 if (statName === 'geometricMean') { |
549 return new tr.b.Scalar(this.unit, this.geometricMean); | 550 return new tr.b.Scalar(this.unit, this.geometricMean); |
550 } | 551 } |
551 if (statName === 'min' || statName === 'max' || statName === 'sum') { | 552 if (statName === 'min' || statName === 'max' || statName === 'sum') { |
552 if (this.running_ === undefined) { | 553 if (this.running_ === undefined) { |
553 this.running_ = new tr.b.RunningStatistics(); | 554 this.running_ = new tr.b.math.RunningStatistics(); |
554 } | 555 } |
555 return new tr.b.Scalar(this.unit, this.running_[statName]); | 556 return new tr.b.Scalar(this.unit, this.running_[statName]); |
556 } | 557 } |
557 if (statName === 'nans') { | 558 if (statName === 'nans') { |
558 return new tr.b.Scalar( | 559 return new tr.b.Scalar( |
559 tr.b.Unit.byName.count_smallerIsBetter, this.numNans); | 560 tr.b.Unit.byName.count_smallerIsBetter, this.numNans); |
560 } | 561 } |
561 if (statName === 'count') { | 562 if (statName === 'count') { |
562 return new tr.b.Scalar( | 563 return new tr.b.Scalar( |
563 tr.b.Unit.byName.count_smallerIsBetter, this.numValues); | 564 tr.b.Unit.byName.count_smallerIsBetter, this.numValues); |
(...skipping 30 matching lines...) Expand all Loading... |
594 thisStat.unit.correspondingDeltaUnit, deltaValue); | 595 thisStat.unit.correspondingDeltaUnit, deltaValue); |
595 } | 596 } |
596 | 597 |
597 if (statName === Z_SCORE_NAME) { | 598 if (statName === Z_SCORE_NAME) { |
598 return new tr.b.Scalar( | 599 return new tr.b.Scalar( |
599 tr.b.Unit.byName['sigmaDelta' + suffix], | 600 tr.b.Unit.byName['sigmaDelta' + suffix], |
600 (this.average - opt_referenceHistogram.average) / | 601 (this.average - opt_referenceHistogram.average) / |
601 opt_referenceHistogram.standardDeviation); | 602 opt_referenceHistogram.standardDeviation); |
602 } | 603 } |
603 | 604 |
604 let mwu = opt_mwu || tr.b.Statistics.mwu( | 605 let mwu = opt_mwu || tr.b.math.Statistics.mwu( |
605 this.sampleValues, opt_referenceHistogram.sampleValues); | 606 this.sampleValues, opt_referenceHistogram.sampleValues); |
606 if (statName === P_VALUE_NAME) { | 607 if (statName === P_VALUE_NAME) { |
607 return new tr.b.Scalar(tr.b.Unit.byName.unitlessNumber, mwu.p); | 608 return new tr.b.Scalar(tr.b.Unit.byName.unitlessNumber, mwu.p); |
608 } | 609 } |
609 if (statName === U_STATISTIC_NAME) { | 610 if (statName === U_STATISTIC_NAME) { |
610 return new tr.b.Scalar(tr.b.Unit.byName.unitlessNumber, mwu.U); | 611 return new tr.b.Scalar(tr.b.Unit.byName.unitlessNumber, mwu.U); |
611 } | 612 } |
612 | 613 |
613 throw new Error('Unrecognized statistic name: ' + statName); | 614 throw new Error('Unrecognized statistic name: ' + statName); |
614 } | 615 } |
(...skipping 330 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
945 * If no other bin boundaries are added, then |minBinBoundary| will be the | 946 * If no other bin boundaries are added, then |minBinBoundary| will be the |
946 * boundary between the underflow bin and the overflow bin. | 947 * boundary between the underflow bin and the overflow bin. |
947 * If no other bin boundaries are added and |minBinBoundary| is either | 948 * If no other bin boundaries are added and |minBinBoundary| is either |
948 * -Number.MAX_VALUE or +Number.MAX_VALUE, then only a single binRange will | 949 * -Number.MAX_VALUE or +Number.MAX_VALUE, then only a single binRange will |
949 * be built. | 950 * be built. |
950 * | 951 * |
951 * @param {number} minBinBoundary The minimum boundary between bins. | 952 * @param {number} minBinBoundary The minimum boundary between bins. |
952 */ | 953 */ |
953 constructor(minBinBoundary) { | 954 constructor(minBinBoundary) { |
954 this.builder_ = [minBinBoundary]; | 955 this.builder_ = [minBinBoundary]; |
955 this.range_ = new tr.b.Range(); | 956 this.range_ = new tr.b.math.Range(); |
956 this.range_.addValue(minBinBoundary); | 957 this.range_.addValue(minBinBoundary); |
957 this.binRanges_ = undefined; | 958 this.binRanges_ = undefined; |
958 } | 959 } |
959 | 960 |
960 get range() { | 961 get range() { |
961 return this.range_; | 962 return this.range_; |
962 } | 963 } |
963 | 964 |
964 asDict() { | 965 asDict() { |
965 if (this.builder_.length === 1 && this.builder_[0] === Number.MAX_VALUE) { | 966 if (this.builder_.length === 1 && this.builder_[0] === Number.MAX_VALUE) { |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1009 | 1010 |
1010 default: | 1011 default: |
1011 throw new Error('Unrecognized HistogramBinBoundaries slice type'); | 1012 throw new Error('Unrecognized HistogramBinBoundaries slice type'); |
1012 } | 1013 } |
1013 } | 1014 } |
1014 HISTOGRAM_BIN_BOUNDARIES_CACHE.set(cacheKey, binBoundaries); | 1015 HISTOGRAM_BIN_BOUNDARIES_CACHE.set(cacheKey, binBoundaries); |
1015 return binBoundaries; | 1016 return binBoundaries; |
1016 } | 1017 } |
1017 | 1018 |
1018 /** | 1019 /** |
1019 * @return {!Array.<!tr.b.Range>} | 1020 * @return {!Array.<!tr.b.math.Range>} |
1020 */ | 1021 */ |
1021 get binRanges() { | 1022 get binRanges() { |
1022 if (this.binRanges_ === undefined) { | 1023 if (this.binRanges_ === undefined) { |
1023 this.build_(); | 1024 this.build_(); |
1024 } | 1025 } |
1025 return this.binRanges_; | 1026 return this.binRanges_; |
1026 } | 1027 } |
1027 | 1028 |
1028 build_() { | 1029 build_() { |
1029 if (typeof this.builder_[0] !== 'number') { | 1030 if (typeof this.builder_[0] !== 'number') { |
1030 throw new Error('Invalid start of builder_'); | 1031 throw new Error('Invalid start of builder_'); |
1031 } | 1032 } |
1032 this.binRanges_ = []; | 1033 this.binRanges_ = []; |
1033 let prevBoundary = this.builder_[0]; | 1034 let prevBoundary = this.builder_[0]; |
1034 | 1035 |
1035 if (prevBoundary > -Number.MAX_VALUE) { | 1036 if (prevBoundary > -Number.MAX_VALUE) { |
1036 // underflow bin | 1037 // underflow bin |
1037 this.binRanges_.push(tr.b.Range.fromExplicitRange(-Number.MAX_VALUE, | 1038 this.binRanges_.push(tr.b.math.Range.fromExplicitRange( |
1038 prevBoundary)); | 1039 -Number.MAX_VALUE, prevBoundary)); |
1039 } | 1040 } |
1040 | 1041 |
1041 for (let slice of this.builder_.slice(1)) { | 1042 for (let slice of this.builder_.slice(1)) { |
1042 if (!(slice instanceof Array)) { | 1043 if (!(slice instanceof Array)) { |
1043 this.binRanges_.push( | 1044 this.binRanges_.push( |
1044 tr.b.Range.fromExplicitRange(prevBoundary, slice)); | 1045 tr.b.math.Range.fromExplicitRange(prevBoundary, slice)); |
1045 prevBoundary = slice; | 1046 prevBoundary = slice; |
1046 continue; | 1047 continue; |
1047 } | 1048 } |
1048 let nextMaxBinBoundary = slice[1]; | 1049 let nextMaxBinBoundary = slice[1]; |
1049 let binCount = slice[2]; | 1050 let binCount = slice[2]; |
1050 let sliceMinBinBoundary = prevBoundary; | 1051 let sliceMinBinBoundary = prevBoundary; |
1051 | 1052 |
1052 switch (slice[0]) { | 1053 switch (slice[0]) { |
1053 case HistogramBinBoundaries.SLICE_TYPE.LINEAR: | 1054 case HistogramBinBoundaries.SLICE_TYPE.LINEAR: |
1054 { | 1055 { |
1055 let binWidth = (nextMaxBinBoundary - prevBoundary) / binCount; | 1056 let binWidth = (nextMaxBinBoundary - prevBoundary) / binCount; |
1056 for (let i = 1; i < binCount; i++) { | 1057 for (let i = 1; i < binCount; i++) { |
1057 let boundary = sliceMinBinBoundary + i * binWidth; | 1058 let boundary = sliceMinBinBoundary + i * binWidth; |
1058 this.binRanges_.push(tr.b.Range.fromExplicitRange( | 1059 this.binRanges_.push(tr.b.math.Range.fromExplicitRange( |
1059 prevBoundary, boundary)); | 1060 prevBoundary, boundary)); |
1060 prevBoundary = boundary; | 1061 prevBoundary = boundary; |
1061 } | 1062 } |
1062 break; | 1063 break; |
1063 } | 1064 } |
1064 | 1065 |
1065 case HistogramBinBoundaries.SLICE_TYPE.EXPONENTIAL: | 1066 case HistogramBinBoundaries.SLICE_TYPE.EXPONENTIAL: |
1066 { | 1067 { |
1067 let binExponentWidth = | 1068 let binExponentWidth = |
1068 Math.log(nextMaxBinBoundary / prevBoundary) / binCount; | 1069 Math.log(nextMaxBinBoundary / prevBoundary) / binCount; |
1069 for (let i = 1; i < binCount; i++) { | 1070 for (let i = 1; i < binCount; i++) { |
1070 let boundary = sliceMinBinBoundary * Math.exp( | 1071 let boundary = sliceMinBinBoundary * Math.exp( |
1071 i * binExponentWidth); | 1072 i * binExponentWidth); |
1072 this.binRanges_.push(tr.b.Range.fromExplicitRange( | 1073 this.binRanges_.push(tr.b.math.Range.fromExplicitRange( |
1073 prevBoundary, boundary)); | 1074 prevBoundary, boundary)); |
1074 prevBoundary = boundary; | 1075 prevBoundary = boundary; |
1075 } | 1076 } |
1076 break; | 1077 break; |
1077 } | 1078 } |
1078 | 1079 |
1079 default: | 1080 default: |
1080 throw new Error('Unrecognized HistogramBinBoundaries slice type'); | 1081 throw new Error('Unrecognized HistogramBinBoundaries slice type'); |
1081 } | 1082 } |
1082 this.binRanges_.push(tr.b.Range.fromExplicitRange( | 1083 this.binRanges_.push(tr.b.math.Range.fromExplicitRange( |
1083 prevBoundary, nextMaxBinBoundary)); | 1084 prevBoundary, nextMaxBinBoundary)); |
1084 prevBoundary = nextMaxBinBoundary; | 1085 prevBoundary = nextMaxBinBoundary; |
1085 } | 1086 } |
1086 if (prevBoundary < Number.MAX_VALUE) { | 1087 if (prevBoundary < Number.MAX_VALUE) { |
1087 // overflow bin | 1088 // overflow bin |
1088 this.binRanges_.push(tr.b.Range.fromExplicitRange( | 1089 this.binRanges_.push(tr.b.math.Range.fromExplicitRange( |
1089 prevBoundary, Number.MAX_VALUE)); | 1090 prevBoundary, Number.MAX_VALUE)); |
1090 } | 1091 } |
1091 } | 1092 } |
1092 | 1093 |
1093 /** | 1094 /** |
1094 * Add a bin boundary |nextMaxBinBoundary| to the builder. | 1095 * Add a bin boundary |nextMaxBinBoundary| to the builder. |
1095 * | 1096 * |
1096 * This operation effectively corresponds to appending a new central bin | 1097 * This operation effectively corresponds to appending a new central bin |
1097 * with the range [this.range.max, nextMaxBinBoundary]. | 1098 * with the range [this.range.max, nextMaxBinBoundary]. |
1098 * | 1099 * |
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1259 Histogram, | 1260 Histogram, |
1260 HistogramBinBoundaries, | 1261 HistogramBinBoundaries, |
1261 P_VALUE_NAME, | 1262 P_VALUE_NAME, |
1262 U_STATISTIC_NAME, | 1263 U_STATISTIC_NAME, |
1263 Z_SCORE_NAME, | 1264 Z_SCORE_NAME, |
1264 percentFromString, | 1265 percentFromString, |
1265 percentToString, | 1266 percentToString, |
1266 }; | 1267 }; |
1267 }); | 1268 }); |
1268 </script> | 1269 </script> |
OLD | NEW |