quantileSeq.js 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  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 (Array.isArray(probOrN)) {
  112. // quantileSeq([a, b, c, d, ...], [prob1, prob2, ...][,sorted])
  113. probArr = new Array(probOrN.length);
  114. for (var _i2 = 0; _i2 < probArr.length; ++_i2) {
  115. var currProb = probOrN[_i2];
  116. if ((0, _is.isNumber)(currProb)) {
  117. if (currProb < 0 || currProb > 1) {
  118. throw new Error('Probability must be between 0 and 1, inclusive');
  119. }
  120. } else if ((0, _is.isBigNumber)(currProb)) {
  121. one = new currProb.constructor(1);
  122. if (currProb.isNegative() || currProb.gt(one)) {
  123. throw new Error('Probability must be between 0 and 1, inclusive');
  124. }
  125. } else {
  126. throw new TypeError('Unexpected type of argument in function quantileSeq'); // FIXME: becomes redundant when converted to typed-function
  127. }
  128. probArr[_i2] = _quantileSeq(dataArr, currProb, sorted);
  129. }
  130. return probArr;
  131. }
  132. throw new TypeError('Unexpected type of argument in function quantileSeq'); // FIXME: becomes redundant when converted to typed-function
  133. }
  134. throw new TypeError('Unexpected type of argument in function quantileSeq'); // FIXME: becomes redundant when converted to typed-function
  135. }
  136. throw new TypeError('Unexpected type of argument in function quantileSeq'); // FIXME: becomes redundant when converted to typed-function
  137. }
  138. /**
  139. * Calculate the prob order quantile of an n-dimensional array.
  140. *
  141. * @param {Array} array
  142. * @param {Number, BigNumber} prob
  143. * @param {Boolean} sorted
  144. * @return {Number, BigNumber, Unit} prob order quantile
  145. * @private
  146. */
  147. function _quantileSeq(array, prob, sorted) {
  148. var flat = (0, _array.flatten)(array);
  149. var len = flat.length;
  150. if (len === 0) {
  151. throw new Error('Cannot calculate quantile of an empty sequence');
  152. }
  153. if ((0, _is.isNumber)(prob)) {
  154. var _index = prob * (len - 1);
  155. var _fracPart = _index % 1;
  156. if (_fracPart === 0) {
  157. var value = sorted ? flat[_index] : partitionSelect(flat, _index);
  158. validate(value);
  159. return value;
  160. }
  161. var _integerPart = Math.floor(_index);
  162. var _left;
  163. var _right;
  164. if (sorted) {
  165. _left = flat[_integerPart];
  166. _right = flat[_integerPart + 1];
  167. } else {
  168. _right = partitionSelect(flat, _integerPart + 1);
  169. // max of partition is kth largest
  170. _left = flat[_integerPart];
  171. for (var i = 0; i < _integerPart; ++i) {
  172. if (compare(flat[i], _left) > 0) {
  173. _left = flat[i];
  174. }
  175. }
  176. }
  177. validate(_left);
  178. validate(_right);
  179. // Q(prob) = (1-f)*A[floor(index)] + f*A[floor(index)+1]
  180. return add(multiply(_left, 1 - _fracPart), multiply(_right, _fracPart));
  181. }
  182. // If prob is a BigNumber
  183. var index = prob.times(len - 1);
  184. if (index.isInteger()) {
  185. index = index.toNumber();
  186. var _value = sorted ? flat[index] : partitionSelect(flat, index);
  187. validate(_value);
  188. return _value;
  189. }
  190. var integerPart = index.floor();
  191. var fracPart = index.minus(integerPart);
  192. var integerPartNumber = integerPart.toNumber();
  193. var left;
  194. var right;
  195. if (sorted) {
  196. left = flat[integerPartNumber];
  197. right = flat[integerPartNumber + 1];
  198. } else {
  199. right = partitionSelect(flat, integerPartNumber + 1);
  200. // max of partition is kth largest
  201. left = flat[integerPartNumber];
  202. for (var _i3 = 0; _i3 < integerPartNumber; ++_i3) {
  203. if (compare(flat[_i3], left) > 0) {
  204. left = flat[_i3];
  205. }
  206. }
  207. }
  208. validate(left);
  209. validate(right);
  210. // Q(prob) = (1-f)*A[floor(index)] + f*A[floor(index)+1]
  211. var one = new fracPart.constructor(1);
  212. return add(multiply(left, one.minus(fracPart)), multiply(right, fracPart));
  213. }
  214. /**
  215. * Check if array value types are valid, throw error otherwise.
  216. * @param {number | BigNumber | Unit} x
  217. * @param {number | BigNumber | Unit} x
  218. * @private
  219. */
  220. var validate = typed({
  221. 'number | BigNumber | Unit': function numberBigNumberUnit(x) {
  222. return x;
  223. }
  224. });
  225. return quantileSeq;
  226. });
  227. exports.createQuantileSeq = createQuantileSeq;