simple-squiggle

A restricted subset of Squiggle
Log | Files | Refs | README

pickRandom.js (5294B)


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