UNPKG

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