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;