simple-squiggle

A restricted subset of Squiggle
Log | Files | Refs | README

quantileSeq.js (8908B)


      1 "use strict";
      2 
      3 Object.defineProperty(exports, "__esModule", {
      4   value: true
      5 });
      6 exports.createQuantileSeq = void 0;
      7 
      8 var _is = require("../../utils/is.js");
      9 
     10 var _number = require("../../utils/number.js");
     11 
     12 var _array = require("../../utils/array.js");
     13 
     14 var _factory = require("../../utils/factory.js");
     15 
     16 var name = 'quantileSeq';
     17 var dependencies = ['typed', 'add', 'multiply', 'partitionSelect', 'compare'];
     18 var createQuantileSeq = /* #__PURE__ */(0, _factory.factory)(name, dependencies, function (_ref) {
     19   var typed = _ref.typed,
     20       add = _ref.add,
     21       multiply = _ref.multiply,
     22       partitionSelect = _ref.partitionSelect,
     23       compare = _ref.compare;
     24 
     25   /**
     26    * Compute the prob order quantile of a matrix or a list with values.
     27    * The sequence is sorted and the middle value is returned.
     28    * Supported types of sequence values are: Number, BigNumber, Unit
     29    * Supported types of probability are: Number, BigNumber
     30    *
     31    * In case of a (multi dimensional) array or matrix, the prob order quantile
     32    * of all elements will be calculated.
     33    *
     34    * Syntax:
     35    *
     36    *     math.quantileSeq(A, prob[, sorted])
     37    *     math.quantileSeq(A, [prob1, prob2, ...][, sorted])
     38    *     math.quantileSeq(A, N[, sorted])
     39    *
     40    * Examples:
     41    *
     42    *     math.quantileSeq([3, -1, 5, 7], 0.5)         // returns 4
     43    *     math.quantileSeq([3, -1, 5, 7], [1/3, 2/3])  // returns [3, 5]
     44    *     math.quantileSeq([3, -1, 5, 7], 2)           // returns [3, 5]
     45    *     math.quantileSeq([-1, 3, 5, 7], 0.5, true)   // returns 4
     46    *
     47    * See also:
     48    *
     49    *     median, mean, min, max, sum, prod, std, variance
     50    *
     51    * @param {Array, Matrix} data                A single matrix or Array
     52    * @param {Number, BigNumber, Array} probOrN  prob is the order of the quantile, while N is
     53    *                                            the amount of evenly distributed steps of
     54    *                                            probabilities; only one of these options can
     55    *                                            be provided
     56    * @param {Boolean} sorted=false              is data sorted in ascending order
     57    * @return {Number, BigNumber, Unit, Array}   Quantile(s)
     58    */
     59   function quantileSeq(data, probOrN, sorted) {
     60     var probArr, dataArr, one;
     61 
     62     if (arguments.length < 2 || arguments.length > 3) {
     63       throw new SyntaxError('Function quantileSeq requires two or three parameters');
     64     }
     65 
     66     if ((0, _is.isCollection)(data)) {
     67       sorted = sorted || false;
     68 
     69       if (typeof sorted === 'boolean') {
     70         dataArr = data.valueOf();
     71 
     72         if ((0, _is.isNumber)(probOrN)) {
     73           if (probOrN < 0) {
     74             throw new Error('N/prob must be non-negative');
     75           }
     76 
     77           if (probOrN <= 1) {
     78             // quantileSeq([a, b, c, d, ...], prob[,sorted])
     79             return _quantileSeq(dataArr, probOrN, sorted);
     80           }
     81 
     82           if (probOrN > 1) {
     83             // quantileSeq([a, b, c, d, ...], N[,sorted])
     84             if (!(0, _number.isInteger)(probOrN)) {
     85               throw new Error('N must be a positive integer');
     86             }
     87 
     88             var nPlusOne = probOrN + 1;
     89             probArr = new Array(probOrN);
     90 
     91             for (var i = 0; i < probOrN;) {
     92               probArr[i] = _quantileSeq(dataArr, ++i / nPlusOne, sorted);
     93             }
     94 
     95             return probArr;
     96           }
     97         }
     98 
     99         if ((0, _is.isBigNumber)(probOrN)) {
    100           var BigNumber = probOrN.constructor;
    101 
    102           if (probOrN.isNegative()) {
    103             throw new Error('N/prob must be non-negative');
    104           }
    105 
    106           one = new BigNumber(1);
    107 
    108           if (probOrN.lte(one)) {
    109             // quantileSeq([a, b, c, d, ...], prob[,sorted])
    110             return new BigNumber(_quantileSeq(dataArr, probOrN, sorted));
    111           }
    112 
    113           if (probOrN.gt(one)) {
    114             // quantileSeq([a, b, c, d, ...], N[,sorted])
    115             if (!probOrN.isInteger()) {
    116               throw new Error('N must be a positive integer');
    117             } // largest possible Array length is 2^32-1
    118             // 2^32 < 10^15, thus safe conversion guaranteed
    119 
    120 
    121             var intN = probOrN.toNumber();
    122 
    123             if (intN > 4294967295) {
    124               throw new Error('N must be less than or equal to 2^32-1, as that is the maximum length of an Array');
    125             }
    126 
    127             var _nPlusOne = new BigNumber(intN + 1);
    128 
    129             probArr = new Array(intN);
    130 
    131             for (var _i = 0; _i < intN;) {
    132               probArr[_i] = new BigNumber(_quantileSeq(dataArr, new BigNumber(++_i).div(_nPlusOne), sorted));
    133             }
    134 
    135             return probArr;
    136           }
    137         }
    138 
    139         if (Array.isArray(probOrN)) {
    140           // quantileSeq([a, b, c, d, ...], [prob1, prob2, ...][,sorted])
    141           probArr = new Array(probOrN.length);
    142 
    143           for (var _i2 = 0; _i2 < probArr.length; ++_i2) {
    144             var currProb = probOrN[_i2];
    145 
    146             if ((0, _is.isNumber)(currProb)) {
    147               if (currProb < 0 || currProb > 1) {
    148                 throw new Error('Probability must be between 0 and 1, inclusive');
    149               }
    150             } else if ((0, _is.isBigNumber)(currProb)) {
    151               one = new currProb.constructor(1);
    152 
    153               if (currProb.isNegative() || currProb.gt(one)) {
    154                 throw new Error('Probability must be between 0 and 1, inclusive');
    155               }
    156             } else {
    157               throw new TypeError('Unexpected type of argument in function quantileSeq'); // FIXME: becomes redundant when converted to typed-function
    158             }
    159 
    160             probArr[_i2] = _quantileSeq(dataArr, currProb, sorted);
    161           }
    162 
    163           return probArr;
    164         }
    165 
    166         throw new TypeError('Unexpected type of argument in function quantileSeq'); // FIXME: becomes redundant when converted to typed-function
    167       }
    168 
    169       throw new TypeError('Unexpected type of argument in function quantileSeq'); // FIXME: becomes redundant when converted to typed-function
    170     }
    171 
    172     throw new TypeError('Unexpected type of argument in function quantileSeq'); // FIXME: becomes redundant when converted to typed-function
    173   }
    174   /**
    175    * Calculate the prob order quantile of an n-dimensional array.
    176    *
    177    * @param {Array} array
    178    * @param {Number, BigNumber} prob
    179    * @param {Boolean} sorted
    180    * @return {Number, BigNumber, Unit} prob order quantile
    181    * @private
    182    */
    183 
    184 
    185   function _quantileSeq(array, prob, sorted) {
    186     var flat = (0, _array.flatten)(array);
    187     var len = flat.length;
    188 
    189     if (len === 0) {
    190       throw new Error('Cannot calculate quantile of an empty sequence');
    191     }
    192 
    193     if ((0, _is.isNumber)(prob)) {
    194       var _index = prob * (len - 1);
    195 
    196       var _fracPart = _index % 1;
    197 
    198       if (_fracPart === 0) {
    199         var value = sorted ? flat[_index] : partitionSelect(flat, _index);
    200         validate(value);
    201         return value;
    202       }
    203 
    204       var _integerPart = Math.floor(_index);
    205 
    206       var _left;
    207 
    208       var _right;
    209 
    210       if (sorted) {
    211         _left = flat[_integerPart];
    212         _right = flat[_integerPart + 1];
    213       } else {
    214         _right = partitionSelect(flat, _integerPart + 1); // max of partition is kth largest
    215 
    216         _left = flat[_integerPart];
    217 
    218         for (var i = 0; i < _integerPart; ++i) {
    219           if (compare(flat[i], _left) > 0) {
    220             _left = flat[i];
    221           }
    222         }
    223       }
    224 
    225       validate(_left);
    226       validate(_right); // Q(prob) = (1-f)*A[floor(index)] + f*A[floor(index)+1]
    227 
    228       return add(multiply(_left, 1 - _fracPart), multiply(_right, _fracPart));
    229     } // If prob is a BigNumber
    230 
    231 
    232     var index = prob.times(len - 1);
    233 
    234     if (index.isInteger()) {
    235       index = index.toNumber();
    236 
    237       var _value = sorted ? flat[index] : partitionSelect(flat, index);
    238 
    239       validate(_value);
    240       return _value;
    241     }
    242 
    243     var integerPart = index.floor();
    244     var fracPart = index.minus(integerPart);
    245     var integerPartNumber = integerPart.toNumber();
    246     var left;
    247     var right;
    248 
    249     if (sorted) {
    250       left = flat[integerPartNumber];
    251       right = flat[integerPartNumber + 1];
    252     } else {
    253       right = partitionSelect(flat, integerPartNumber + 1); // max of partition is kth largest
    254 
    255       left = flat[integerPartNumber];
    256 
    257       for (var _i3 = 0; _i3 < integerPartNumber; ++_i3) {
    258         if (compare(flat[_i3], left) > 0) {
    259           left = flat[_i3];
    260         }
    261       }
    262     }
    263 
    264     validate(left);
    265     validate(right); // Q(prob) = (1-f)*A[floor(index)] + f*A[floor(index)+1]
    266 
    267     var one = new fracPart.constructor(1);
    268     return add(multiply(left, one.minus(fracPart)), multiply(right, fracPart));
    269   }
    270   /**
    271    * Check if array value types are valid, throw error otherwise.
    272    * @param {number | BigNumber | Unit} x
    273    * @param {number | BigNumber | Unit} x
    274    * @private
    275    */
    276 
    277 
    278   var validate = typed({
    279     'number | BigNumber | Unit': function numberBigNumberUnit(x) {
    280       return x;
    281     }
    282   });
    283   return quantileSeq;
    284 });
    285 exports.createQuantileSeq = createQuantileSeq;