{"version":3,"sources":["jsdelivr-header.js","/npm/tdigest@0.1.2/tdigest.js"],"names":[],"mappings":"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","file":"/npm/tdigest@0.1.2/tdigest.js","sourceRoot":"","sourcesContent":["/**\n * Minified by jsDelivr using Terser v5.39.0.\n * Original file: /npm/tdigest@0.1.2/tdigest.js\n *\n * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files\n */\n","//\n// TDigest:\n//\n// approximate distribution percentiles from a stream of reals\n//\nvar RBTree = require('bintrees').RBTree;\n\nfunction TDigest(delta, K, CX) {\n    // allocate a TDigest structure.\n    //\n    // delta is the compression factor, the max fraction of mass that\n    // can be owned by one centroid (bigger, up to 1.0, means more\n    // compression). delta=false switches off TDigest behavior and treats\n    // the distribution as discrete, with no merging and exact values\n    // reported.\n    //\n    // K is a size threshold that triggers recompression as the TDigest\n    // grows during input.  (Set it to 0 to disable automatic recompression)\n    //\n    // CX specifies how often to update cached cumulative totals used\n    // for quantile estimation during ingest (see cumulate()).  Set to\n    // 0 to use exact quantiles for each new point.\n    //\n    this.discrete = (delta === false);\n    this.delta = delta || 0.01;\n    this.K = (K === undefined) ? 25 : K;\n    this.CX = (CX === undefined) ? 1.1 : CX;\n    this.centroids = new RBTree(compare_centroid_means);\n    this.nreset = 0;\n    this.reset();\n}\n\nTDigest.prototype.reset = function() {\n    // prepare to digest new points.\n    //\n    this.centroids.clear();\n    this.n = 0;\n    this.nreset += 1;\n    this.last_cumulate = 0;\n};\n\nTDigest.prototype.size = function() {\n    return this.centroids.size;\n};\n\nTDigest.prototype.toArray = function(everything) {\n    // return {mean,n} of centroids as an array ordered by mean.\n    //\n    var result = [];\n    if (everything) {\n        this._cumulate(true); // be sure cumns are exact\n        this.centroids.each(function(c) { result.push(c); });\n    } else {\n        this.centroids.each(function(c) { result.push({mean:c.mean, n:c.n}); });\n    }\n    return result;\n};\n\nTDigest.prototype.summary = function() {\n    var approx = (this.discrete) ? \"exact \" : \"approximating \";\n    var s = [approx + this.n + \" samples using \" + this.size() + \" centroids\",\n             \"min = \"+this.percentile(0),\n             \"Q1  = \"+this.percentile(0.25),\n             \"Q2  = \"+this.percentile(0.5),\n             \"Q3  = \"+this.percentile(0.75),\n             \"max = \"+this.percentile(1.0)];\n    return s.join('\\n');\n};\n\nfunction compare_centroid_means(a, b) {\n    // order two centroids by mean.\n    //\n    return (a.mean > b.mean) ? 1 : (a.mean < b.mean) ? -1 : 0;\n}\n\nfunction compare_centroid_mean_cumns(a, b) {\n    // order two centroids by mean_cumn.\n    //\n    return (a.mean_cumn - b.mean_cumn);\n}\n\nTDigest.prototype.push = function(x, n) {\n    // incorporate value or array of values x, having count n into the\n    // TDigest. n defaults to 1.\n    //\n    n = n || 1;\n    x = Array.isArray(x) ? x : [x];\n    for (var i = 0 ; i < x.length ; i++) {\n        this._digest(x[i], n);\n    }\n};\n\nTDigest.prototype.push_centroid = function(c) {\n    // incorporate centroid or array of centroids c\n    //\n    c = Array.isArray(c) ? c : [c];\n    for (var i = 0 ; i < c.length ; i++) {\n        this._digest(c[i].mean, c[i].n);\n    }\n};\n\nTDigest.prototype._cumulate = function(exact) {\n    // update cumulative counts for each centroid\n    //\n    // exact: falsey means only cumulate after sufficient\n    // growth. During ingest, these counts are used as quantile\n    // estimates, and they work well even when somewhat out of\n    // date. (this is a departure from the publication, you may set CX\n    // to 0 to disable).\n    //\n    if (this.n === this.last_cumulate ||\n        !exact && this.CX && this.CX > (this.n / this.last_cumulate)) {\n        return;\n    }\n    var cumn = 0;\n    this.centroids.each(function(c) {\n        c.mean_cumn = cumn + c.n / 2; // half of n at the mean\n        cumn = c.cumn = cumn + c.n;\n    });\n    this.n = this.last_cumulate = cumn;\n};\n\nTDigest.prototype.find_nearest = function(x) {\n    // find the centroid closest to x. The assumption of\n    // unique means and a unique nearest centroid departs from the\n    // paper, see _digest() below\n    //\n    if (this.size() === 0) {\n        return null;\n    }\n    var iter = this.centroids.lowerBound({mean:x}); // x <= iter || iter==null\n    var c = (iter.data() === null) ? iter.prev() : iter.data();\n    if (c.mean === x || this.discrete) {\n        return c; // c is either x or a neighbor (discrete: no distance func)\n    }\n    var prev = iter.prev();\n    if (prev && Math.abs(prev.mean - x) < Math.abs(c.mean - x)) {\n        return prev;\n    } else {\n        return c;\n    }\n};\n\nTDigest.prototype._new_centroid = function(x, n, cumn) {\n    // create and insert a new centroid into the digest (don't update\n    // cumulatives).\n    //\n    var c = {mean:x, n:n, cumn:cumn};\n    this.centroids.insert(c);\n    this.n += n;\n    return c;\n};\n\nTDigest.prototype._addweight = function(nearest, x, n) {\n    // add weight at location x to nearest centroid.  adding x to\n    // nearest will not shift its relative position in the tree and\n    // require reinsertion.\n    //\n    if (x !== nearest.mean) {\n        nearest.mean += n * (x - nearest.mean) / (nearest.n + n);\n    }\n    nearest.cumn += n;\n    nearest.mean_cumn += n / 2;\n    nearest.n += n;\n    this.n += n;\n};\n\nTDigest.prototype._digest = function(x, n) {\n    // incorporate value x, having count n into the TDigest.\n    //\n    var min = this.centroids.min();\n    var max = this.centroids.max();\n    var nearest = this.find_nearest(x);\n    if (nearest && nearest.mean === x) {\n        // accumulate exact matches into the centroid without\n        // limit. this is a departure from the paper, made so\n        // centroids remain unique and code can be simple.\n        this._addweight(nearest, x, n);\n    } else if (nearest === min) {\n        this._new_centroid(x, n, 0); // new point around min boundary\n    } else if (nearest === max ) {\n        this._new_centroid(x, n, this.n); // new point around max boundary\n    } else if (this.discrete) {\n        this._new_centroid(x, n, nearest.cumn); // never merge\n    } else {\n        // conider a merge based on nearest centroid's capacity. if\n        // there's not room for all of n, don't bother merging any of\n        // it into nearest, as we'll have to make a new centroid\n        // anyway for the remainder (departure from the paper).\n        var p = nearest.mean_cumn / this.n;\n        var max_n = Math.floor(4 * this.n * this.delta * p * (1 - p));\n        if (max_n - nearest.n >= n) {\n            this._addweight(nearest, x, n);\n        } else {\n            this._new_centroid(x, n, nearest.cumn);\n        }\n    }\n    this._cumulate(false);\n    if (!this.discrete && this.K && this.size() > this.K / this.delta) {\n        // re-process the centroids and hope for some compression.\n        this.compress();\n    }\n};\n\nTDigest.prototype.bound_mean = function(x) {\n    // find centroids lower and upper such that lower.mean < x <\n    // upper.mean or lower.mean === x === upper.mean. Don't call\n    // this for x out of bounds.\n    //\n    var iter = this.centroids.upperBound({mean:x}); // x < iter\n    var lower = iter.prev();      // lower <= x\n    var upper = (lower.mean === x) ? lower : iter.next();\n    return [lower, upper];\n};\n\nTDigest.prototype.p_rank = function(x_or_xlist) {\n    // return approximate percentile-ranks (0..1) for data value x.\n    // or list of x.  calculated according to\n    // https://en.wikipedia.org/wiki/Percentile_rank\n    //\n    // (Note that in continuous mode, boundary sample values will\n    // report half their centroid weight inward from 0/1 as the\n    // percentile-rank. X values outside the observed range return\n    // 0/1)\n    //\n    // this triggers cumulate() if cumn's are out of date.\n    //\n    var xs = Array.isArray(x_or_xlist) ? x_or_xlist : [x_or_xlist];\n    var ps = xs.map(this._p_rank, this);\n    return Array.isArray(x_or_xlist) ? ps : ps[0];\n};\n\nTDigest.prototype._p_rank = function(x) {\n    if (this.size() === 0) {\n        return undefined;\n    } else if (x < this.centroids.min().mean) {\n        return 0.0;\n    } else if (x > this.centroids.max().mean) {\n        return 1.0;\n    }\n    // find centroids that bracket x and interpolate x's cumn from\n    // their cumn's.\n    this._cumulate(true); // be sure cumns are exact\n    var bound = this.bound_mean(x);\n    var lower = bound[0], upper = bound[1];\n    if (this.discrete) {\n        return lower.cumn / this.n;\n    } else {\n        var cumn = lower.mean_cumn;\n        if (lower !== upper) {\n            cumn += (x - lower.mean) * (upper.mean_cumn - lower.mean_cumn) / (upper.mean - lower.mean);\n        }\n        return cumn / this.n;\n    }\n};\n\nTDigest.prototype.bound_mean_cumn = function(cumn) {\n    // find centroids lower and upper such that lower.mean_cumn < x <\n    // upper.mean_cumn or lower.mean_cumn === x === upper.mean_cumn. Don't call\n    // this for cumn out of bounds.\n    //\n    // XXX because mean and mean_cumn give rise to the same sort order\n    // (up to identical means), use the mean rbtree for our search.\n    this.centroids._comparator = compare_centroid_mean_cumns;\n    var iter = this.centroids.upperBound({mean_cumn:cumn}); // cumn < iter\n    this.centroids._comparator = compare_centroid_means;\n    var lower = iter.prev();      // lower <= cumn\n    var upper = (lower && lower.mean_cumn === cumn) ? lower : iter.next();\n    return [lower, upper];\n};\n\nTDigest.prototype.percentile = function(p_or_plist) {\n    // for percentage p (0..1), or for each p in a list of ps, return\n    // the smallest data value q at which at least p percent of the\n    // observations <= q.\n    //\n    // for discrete distributions, this selects q using the Nearest\n    // Rank Method\n    // (https://en.wikipedia.org/wiki/Percentile#The_Nearest_Rank_method)\n    // (in scipy, same as percentile(...., interpolation='higher')\n    //\n    // for continuous distributions, interpolates data values between\n    // count-weighted bracketing means.\n    //\n    // this triggers cumulate() if cumn's are out of date.\n    //\n    var ps = Array.isArray(p_or_plist) ? p_or_plist : [p_or_plist];\n    var qs = ps.map(this._percentile, this);\n    return Array.isArray(p_or_plist) ? qs : qs[0];\n};\n\nTDigest.prototype._percentile = function(p) {\n    if (this.size() === 0) {\n        return undefined;\n    }\n    this._cumulate(true); // be sure cumns are exact\n    var h = this.n * p;\n    var bound = this.bound_mean_cumn(h);\n    var lower = bound[0], upper = bound[1];\n\n    if (upper === lower || lower === null || upper === null) {\n        return (lower || upper).mean;\n    } else if (!this.discrete) {\n        return lower.mean + (h - lower.mean_cumn) * (upper.mean - lower.mean) / (upper.mean_cumn - lower.mean_cumn);\n    } else if (h <= lower.cumn) {\n        return lower.mean;\n    } else {\n        return upper.mean;\n    }\n};\n\nfunction pop_random(choices) {\n    // remove and return an item randomly chosen from the array of choices\n    // (mutates choices)\n    //\n    var idx = Math.floor(Math.random() * choices.length);\n    return choices.splice(idx, 1)[0];\n}\n\nTDigest.prototype.compress = function() {\n    // TDigests experience worst case compression (none) when input\n    // increases monotonically.  Improve on any bad luck by\n    // reconsuming digest centroids as if they were weighted points\n    // while shuffling their order (and hope for the best).\n    //\n    if (this.compressing) {\n        return;\n    }\n    var points = this.toArray();\n    this.reset();\n    this.compressing = true;\n    while (points.length > 0) {\n        this.push_centroid(pop_random(points));\n    }\n    this._cumulate(true);\n    this.compressing = false;\n};\n\nfunction Digest(config) {\n    // allocate a distribution digest structure. This is an extension\n    // of a TDigest structure that starts in exact histogram (discrete)\n    // mode, and automatically switches to TDigest mode for large\n    // samples that appear to be from a continuous distribution.\n    //\n    this.config = config || {};\n    this.mode = this.config.mode || 'auto'; // disc, cont, auto\n    TDigest.call(this, this.mode === 'cont' ? config.delta : false);\n    this.digest_ratio = this.config.ratio || 0.9;\n    this.digest_thresh = this.config.thresh || 1000;\n    this.n_unique = 0;\n}\nDigest.prototype = Object.create(TDigest.prototype);\nDigest.prototype.constructor = Digest;\n\nDigest.prototype.push = function(x_or_xlist) {\n    TDigest.prototype.push.call(this, x_or_xlist);\n    this.check_continuous();\n};\n\nDigest.prototype._new_centroid = function(x, n, cumn) {\n    this.n_unique += 1;\n    TDigest.prototype._new_centroid.call(this, x, n, cumn);\n};\n\nDigest.prototype._addweight = function(nearest, x, n) {\n    if (nearest.n === 1) {\n        this.n_unique -= 1;\n    }\n    TDigest.prototype._addweight.call(this, nearest, x, n);\n};\n\nDigest.prototype.check_continuous = function() {\n    // while in 'auto' mode, if there are many unique elements, assume\n    // they are from a continuous distribution and switch to 'cont'\n    // mode (tdigest behavior). Return true on transition from\n    // disctete to continuous.\n    if (this.mode !== 'auto' || this.size() < this.digest_thresh) {\n        return false;\n    }\n    if (this.n_unique / this.size() > this.digest_ratio) {\n        this.mode = 'cont';\n        this.discrete = false;\n        this.delta = this.config.delta || 0.01;\n        this.compress();\n        return true;\n    }\n    return false;\n};\n\nmodule.exports = {\n    'TDigest': TDigest,\n    'Digest': Digest\n};\n"]}