Chromium Code Reviews| Index: tracing/tracing/base/piecewise_linear_function.html |
| diff --git a/tracing/tracing/base/piecewise_linear_function.html b/tracing/tracing/base/piecewise_linear_function.html |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..01daaf8a079ef2b1d28a7e2194679dd9dca649be |
| --- /dev/null |
| +++ b/tracing/tracing/base/piecewise_linear_function.html |
| @@ -0,0 +1,144 @@ |
| +<!DOCTYPE html> |
| +<!-- |
| +Copyright 2016 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/base.html"> |
| + |
| +<script> |
| +'use strict'; |
| + |
| +tr.exportTo('tr.b', function() { |
| + var PERCENTILE_PRECISION = 1e-7; |
| + /** |
| + * A function that consists of linear pieces. |
| + * See https://en.wikipedia.org/wiki/Piecewise_linear_function. |
| + * @constructor |
| + */ |
| + function PiecewiseLinearFunction() { |
| + this.pieces = []; |
| + } |
| + |
| + PiecewiseLinearFunction.prototype = { |
| + /** |
| + * Push a linear piece defined by linear interpolation between. |
| + * (x1, y1) and (x2, y2). |
| + * Pieces must be pushed in the order of increasing x coordinate. |
| + */ |
| + push: function(x1, y1, x2, y2) { |
| + if (x1 >= x2) |
| + throw new Error('Invalid segment'); |
| + if (this.pieces.length > 0 && |
| + this.pieces[this.pieces.length - 1].x2 > x1) { |
| + throw new Error('Potentially overlapping segments'); |
| + } |
| + if (x1 < x2) |
| + this.pieces.push(new Piece(x1, y1, x2, y2)); |
| + }, |
| + |
| + /** |
| + * Returns the size of the set A such that for all x in A: f(x) < y. |
| + */ |
| + partBelow: function(y) { |
| + return this.pieces.reduce((acc, p) => (acc + p.partBelow(y)), 0); |
| + }, |
| + |
| + get min() { |
| + return this.pieces.reduce((acc, p) => Math.min(acc, p.min), Infinity); |
| + }, |
| + |
| + get max() { |
| + return this.pieces.reduce((acc, p) => Math.max(acc, p.max), -Infinity); |
| + }, |
| + |
| + get average() { |
| + var weightedSum = 0; |
| + var totalWeight = 0; |
| + this.pieces.forEach(function(piece) { |
| + weightedSum += piece.width * piece.average; |
| + totalWeight += piece.width; |
| + }); |
| + if (totalWeight === 0) |
| + return 0; |
| + return weightedSum / totalWeight; |
| + }, |
| + |
| + /** |
| + * Returns the minimum possible value y such that the percentage of x points |
| + * that have f(x) <= y is approximately equal to the given |percent|. |
| + */ |
| + percentile: function(percent) { |
| + if (!(percent >= 0 && percent <= 1)) |
| + throw new Error('percent must be [0,1]'); |
| + var lower = this.min; |
| + var upper = this.max; |
| + var total = this.partBelow(upper); |
| + if (total === 0) |
| + return 0; |
| + while (upper - lower > PERCENTILE_PRECISION) { |
| + var middle = (lower + upper) / 2; |
| + var below = this.partBelow(middle); |
| + if (below / total < percent) { |
|
petrcermak
2016/04/25 12:31:17
nit: no need for braces:
if (below / total < perc
ulan
2016/04/25 12:46:26
Done.
|
| + lower = middle; |
| + } else { |
| + upper = middle; |
| + } |
| + } |
| + return (lower + upper) / 2; |
| + } |
| + }; |
| + |
| + /** |
| + * A linear segment from (x1, y1) to (x2, y2). |
| + * @constructor |
| + */ |
| + function Piece(x1, y1, x2, y2) { |
| + this.x1 = x1; |
| + this.y1 = y1; |
| + this.x2 = x2; |
| + this.y2 = y2; |
| + } |
| + |
| + Piece.prototype = { |
| + /** |
| + * The total length of all x points such that f(x) < y. |
| + * More formally: |
| + * max(x2 - x1) such that for all x in [x1 .. x2]: f(x) < y. |
| + */ |
| + partBelow: function(y) { |
| + var width = this.width; |
| + if (width === 0) |
| + return 0; |
| + var minY = this.min; |
| + var maxY = this.max; |
| + if (y >= maxY) |
| + return width; |
| + if (y < minY) |
| + return 0; |
| + return (y - minY) / (maxY - minY) * width; |
| + }, |
| + |
| + get min() { |
| + return Math.min(this.y1, this.y2); |
| + }, |
| + |
| + get max() { |
| + return Math.max(this.y1, this.y2); |
| + }, |
| + |
| + get average() { |
| + return (this.y1 + this.y2) / 2; |
| + }, |
| + |
| + get width() { |
| + return this.x2 - this.x1; |
| + } |
| + }; |
| + |
| + return { |
| + PiecewiseLinearFunction: PiecewiseLinearFunction |
| + }; |
| +}); |
| +</script> |