pickRandom.js 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. import { flatten } from '../../utils/array.js';
  2. import { factory } from '../../utils/factory.js';
  3. import { isMatrix, isNumber } from '../../utils/is.js';
  4. import { createRng } from './util/seededRNG.js';
  5. var name = 'pickRandom';
  6. var dependencies = ['typed', 'config', '?on'];
  7. export var createPickRandom = /* #__PURE__ */factory(name, dependencies, _ref => {
  8. var {
  9. typed,
  10. config,
  11. on
  12. } = _ref;
  13. // seeded pseudo random number generator
  14. var rng = createRng(config.randomSeed);
  15. if (on) {
  16. on('config', function (curr, prev) {
  17. if (curr.randomSeed !== prev.randomSeed) {
  18. rng = createRng(curr.randomSeed);
  19. }
  20. });
  21. }
  22. /**
  23. * Random pick one or more values from a one dimensional array.
  24. * Array elements are picked using a random function with uniform or weighted distribution.
  25. *
  26. * Syntax:
  27. *
  28. * math.pickRandom(array)
  29. * math.pickRandom(array, number)
  30. * math.pickRandom(array, weights)
  31. * math.pickRandom(array, number, weights)
  32. * math.pickRandom(array, weights, number)
  33. * math.pickRandom(array, { weights, number, elementWise })
  34. *
  35. * Examples:
  36. *
  37. * math.pickRandom([3, 6, 12, 2]) // returns one of the values in the array
  38. * math.pickRandom([3, 6, 12, 2], 2) // returns an array of two of the values in the array
  39. * math.pickRandom([3, 6, 12, 2], { number: 2 }) // returns an array of two of the values in the array
  40. * math.pickRandom([3, 6, 12, 2], [1, 3, 2, 1]) // returns one of the values in the array with weighted distribution
  41. * math.pickRandom([3, 6, 12, 2], 2, [1, 3, 2, 1]) // returns an array of two of the values in the array with weighted distribution
  42. * math.pickRandom([3, 6, 12, 2], [1, 3, 2, 1], 2) // returns an array of two of the values in the array with weighted distribution
  43. *
  44. * math.pickRandom([{x: 1.0, y: 2.0}, {x: 1.1, y: 2.0}], { elementWise: false })
  45. * // returns one of the items in the array
  46. *
  47. * See also:
  48. *
  49. * random, randomInt
  50. *
  51. * @param {Array | Matrix} array A one dimensional array
  52. * @param {Int} number An int or float
  53. * @param {Array | Matrix} weights An array of ints or floats
  54. * @return {number | Array} Returns a single random value from array when number is 1 or undefined.
  55. * Returns an array with the configured number of elements when number is > 1.
  56. */
  57. return typed(name, {
  58. 'Array | Matrix': function ArrayMatrix(possibles) {
  59. return _pickRandom(possibles, {});
  60. },
  61. 'Array | Matrix, Object': function ArrayMatrixObject(possibles, options) {
  62. return _pickRandom(possibles, options);
  63. },
  64. 'Array | Matrix, number': function ArrayMatrixNumber(possibles, number) {
  65. return _pickRandom(possibles, {
  66. number
  67. });
  68. },
  69. 'Array | Matrix, Array | Matrix': function ArrayMatrixArrayMatrix(possibles, weights) {
  70. return _pickRandom(possibles, {
  71. weights
  72. });
  73. },
  74. 'Array | Matrix, Array | Matrix, number': function ArrayMatrixArrayMatrixNumber(possibles, weights, number) {
  75. return _pickRandom(possibles, {
  76. number,
  77. weights
  78. });
  79. },
  80. 'Array | Matrix, number, Array | Matrix': function ArrayMatrixNumberArrayMatrix(possibles, number, weights) {
  81. return _pickRandom(possibles, {
  82. number,
  83. weights
  84. });
  85. }
  86. });
  87. /**
  88. * @param {Array | Matrix} possibles
  89. * @param {{
  90. * number?: number,
  91. * weights?: Array | Matrix,
  92. * elementWise: boolean
  93. * }} options
  94. * @returns {number | Array}
  95. * @private
  96. */
  97. function _pickRandom(possibles, _ref2) {
  98. var {
  99. number,
  100. weights,
  101. elementWise = true
  102. } = _ref2;
  103. var single = typeof number === 'undefined';
  104. if (single) {
  105. number = 1;
  106. }
  107. var createMatrix = isMatrix(possibles) ? possibles.create : isMatrix(weights) ? weights.create : null;
  108. possibles = possibles.valueOf(); // get Array
  109. if (weights) {
  110. weights = weights.valueOf(); // get Array
  111. }
  112. if (elementWise === true) {
  113. possibles = flatten(possibles);
  114. weights = flatten(weights);
  115. }
  116. var totalWeights = 0;
  117. if (typeof weights !== 'undefined') {
  118. if (weights.length !== possibles.length) {
  119. throw new Error('Weights must have the same length as possibles');
  120. }
  121. for (var i = 0, len = weights.length; i < len; i++) {
  122. if (!isNumber(weights[i]) || weights[i] < 0) {
  123. throw new Error('Weights must be an array of positive numbers');
  124. }
  125. totalWeights += weights[i];
  126. }
  127. }
  128. var length = possibles.length;
  129. var result = [];
  130. var pick;
  131. while (result.length < number) {
  132. if (typeof weights === 'undefined') {
  133. pick = possibles[Math.floor(rng() * length)];
  134. } else {
  135. var randKey = rng() * totalWeights;
  136. for (var _i = 0, _len = possibles.length; _i < _len; _i++) {
  137. randKey -= weights[_i];
  138. if (randKey < 0) {
  139. pick = possibles[_i];
  140. break;
  141. }
  142. }
  143. }
  144. result.push(pick);
  145. }
  146. return single ? result[0] : createMatrix ? createMatrix(result) : result;
  147. }
  148. });