quantileSeq.js 8.4 KB

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