quantileSeq.js 8.7 KB

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