simple-squiggle

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

range.js (7779B)


      1 import { factory } from '../../utils/factory.js';
      2 import { noBignumber, noMatrix } from '../../utils/noop.js';
      3 var name = 'range';
      4 var dependencies = ['typed', 'config', '?matrix', '?bignumber', 'smaller', 'smallerEq', 'larger', 'largerEq'];
      5 export var createRange = /* #__PURE__ */factory(name, dependencies, _ref => {
      6   var {
      7     typed,
      8     config,
      9     matrix,
     10     bignumber,
     11     smaller,
     12     smallerEq,
     13     larger,
     14     largerEq
     15   } = _ref;
     16 
     17   /**
     18    * Create an array from a range.
     19    * By default, the range end is excluded. This can be customized by providing
     20    * an extra parameter `includeEnd`.
     21    *
     22    * Syntax:
     23    *
     24    *     math.range(str [, includeEnd])               // Create a range from a string,
     25    *                                                  // where the string contains the
     26    *                                                  // start, optional step, and end,
     27    *                                                  // separated by a colon.
     28    *     math.range(start, end [, includeEnd])        // Create a range with start and
     29    *                                                  // end and a step size of 1.
     30    *     math.range(start, end, step [, includeEnd])  // Create a range with start, step,
     31    *                                                  // and end.
     32    *
     33    * Where:
     34    *
     35    * - `str: string`
     36    *   A string 'start:end' or 'start:step:end'
     37    * - `start: {number | BigNumber}`
     38    *   Start of the range
     39    * - `end: number | BigNumber`
     40    *   End of the range, excluded by default, included when parameter includeEnd=true
     41    * - `step: number | BigNumber`
     42    *   Step size. Default value is 1.
     43    * - `includeEnd: boolean`
     44    *   Option to specify whether to include the end or not. False by default.
     45    *
     46    * Examples:
     47    *
     48    *     math.range(2, 6)        // [2, 3, 4, 5]
     49    *     math.range(2, -3, -1)   // [2, 1, 0, -1, -2]
     50    *     math.range('2:1:6')     // [2, 3, 4, 5]
     51    *     math.range(2, 6, true)  // [2, 3, 4, 5, 6]
     52    *
     53    * See also:
     54    *
     55    *     ones, zeros, size, subset
     56    *
     57    * @param {*} args   Parameters describing the ranges `start`, `end`, and optional `step`.
     58    * @return {Array | Matrix} range
     59    */
     60   return typed(name, {
     61     // TODO: simplify signatures when typed-function supports default values and optional arguments
     62     // TODO: a number or boolean should not be converted to string here
     63     string: _strRange,
     64     'string, boolean': _strRange,
     65     'number, number': function numberNumber(start, end) {
     66       return _out(_rangeEx(start, end, 1));
     67     },
     68     'number, number, number': function numberNumberNumber(start, end, step) {
     69       return _out(_rangeEx(start, end, step));
     70     },
     71     'number, number, boolean': function numberNumberBoolean(start, end, includeEnd) {
     72       return includeEnd ? _out(_rangeInc(start, end, 1)) : _out(_rangeEx(start, end, 1));
     73     },
     74     'number, number, number, boolean': function numberNumberNumberBoolean(start, end, step, includeEnd) {
     75       return includeEnd ? _out(_rangeInc(start, end, step)) : _out(_rangeEx(start, end, step));
     76     },
     77     'BigNumber, BigNumber': function BigNumberBigNumber(start, end) {
     78       var BigNumber = start.constructor;
     79       return _out(_bigRangeEx(start, end, new BigNumber(1)));
     80     },
     81     'BigNumber, BigNumber, BigNumber': function BigNumberBigNumberBigNumber(start, end, step) {
     82       return _out(_bigRangeEx(start, end, step));
     83     },
     84     'BigNumber, BigNumber, boolean': function BigNumberBigNumberBoolean(start, end, includeEnd) {
     85       var BigNumber = start.constructor;
     86       return includeEnd ? _out(_bigRangeInc(start, end, new BigNumber(1))) : _out(_bigRangeEx(start, end, new BigNumber(1)));
     87     },
     88     'BigNumber, BigNumber, BigNumber, boolean': function BigNumberBigNumberBigNumberBoolean(start, end, step, includeEnd) {
     89       return includeEnd ? _out(_bigRangeInc(start, end, step)) : _out(_bigRangeEx(start, end, step));
     90     }
     91   });
     92 
     93   function _out(arr) {
     94     if (config.matrix === 'Matrix') {
     95       return matrix ? matrix(arr) : noMatrix();
     96     }
     97 
     98     return arr;
     99   }
    100 
    101   function _strRange(str, includeEnd) {
    102     var r = _parse(str);
    103 
    104     if (!r) {
    105       throw new SyntaxError('String "' + str + '" is no valid range');
    106     }
    107 
    108     var fn;
    109 
    110     if (config.number === 'BigNumber') {
    111       if (bignumber === undefined) {
    112         noBignumber();
    113       }
    114 
    115       fn = includeEnd ? _bigRangeInc : _bigRangeEx;
    116       return _out(fn(bignumber(r.start), bignumber(r.end), bignumber(r.step)));
    117     } else {
    118       fn = includeEnd ? _rangeInc : _rangeEx;
    119       return _out(fn(r.start, r.end, r.step));
    120     }
    121   }
    122   /**
    123    * Create a range with numbers. End is excluded
    124    * @param {number} start
    125    * @param {number} end
    126    * @param {number} step
    127    * @returns {Array} range
    128    * @private
    129    */
    130 
    131 
    132   function _rangeEx(start, end, step) {
    133     var array = [];
    134     var x = start;
    135 
    136     if (step > 0) {
    137       while (smaller(x, end)) {
    138         array.push(x);
    139         x += step;
    140       }
    141     } else if (step < 0) {
    142       while (larger(x, end)) {
    143         array.push(x);
    144         x += step;
    145       }
    146     }
    147 
    148     return array;
    149   }
    150   /**
    151    * Create a range with numbers. End is included
    152    * @param {number} start
    153    * @param {number} end
    154    * @param {number} step
    155    * @returns {Array} range
    156    * @private
    157    */
    158 
    159 
    160   function _rangeInc(start, end, step) {
    161     var array = [];
    162     var x = start;
    163 
    164     if (step > 0) {
    165       while (smallerEq(x, end)) {
    166         array.push(x);
    167         x += step;
    168       }
    169     } else if (step < 0) {
    170       while (largerEq(x, end)) {
    171         array.push(x);
    172         x += step;
    173       }
    174     }
    175 
    176     return array;
    177   }
    178   /**
    179    * Create a range with big numbers. End is excluded
    180    * @param {BigNumber} start
    181    * @param {BigNumber} end
    182    * @param {BigNumber} step
    183    * @returns {Array} range
    184    * @private
    185    */
    186 
    187 
    188   function _bigRangeEx(start, end, step) {
    189     var zero = bignumber(0);
    190     var array = [];
    191     var x = start;
    192 
    193     if (step.gt(zero)) {
    194       while (smaller(x, end)) {
    195         array.push(x);
    196         x = x.plus(step);
    197       }
    198     } else if (step.lt(zero)) {
    199       while (larger(x, end)) {
    200         array.push(x);
    201         x = x.plus(step);
    202       }
    203     }
    204 
    205     return array;
    206   }
    207   /**
    208    * Create a range with big numbers. End is included
    209    * @param {BigNumber} start
    210    * @param {BigNumber} end
    211    * @param {BigNumber} step
    212    * @returns {Array} range
    213    * @private
    214    */
    215 
    216 
    217   function _bigRangeInc(start, end, step) {
    218     var zero = bignumber(0);
    219     var array = [];
    220     var x = start;
    221 
    222     if (step.gt(zero)) {
    223       while (smallerEq(x, end)) {
    224         array.push(x);
    225         x = x.plus(step);
    226       }
    227     } else if (step.lt(zero)) {
    228       while (largerEq(x, end)) {
    229         array.push(x);
    230         x = x.plus(step);
    231       }
    232     }
    233 
    234     return array;
    235   }
    236   /**
    237    * Parse a string into a range,
    238    * The string contains the start, optional step, and end, separated by a colon.
    239    * If the string does not contain a valid range, null is returned.
    240    * For example str='0:2:11'.
    241    * @param {string} str
    242    * @return {{start: number, end: number, step: number} | null} range Object containing properties start, end, step
    243    * @private
    244    */
    245 
    246 
    247   function _parse(str) {
    248     var args = str.split(':'); // number
    249 
    250     var nums = args.map(function (arg) {
    251       // use Number and not parseFloat as Number returns NaN on invalid garbage in the string
    252       return Number(arg);
    253     });
    254     var invalid = nums.some(function (num) {
    255       return isNaN(num);
    256     });
    257 
    258     if (invalid) {
    259       return null;
    260     }
    261 
    262     switch (nums.length) {
    263       case 2:
    264         return {
    265           start: nums[0],
    266           end: nums[1],
    267           step: 1
    268         };
    269 
    270       case 3:
    271         return {
    272           start: nums[0],
    273           end: nums[2],
    274           step: nums[1]
    275         };
    276 
    277       default:
    278         return null;
    279     }
    280   }
    281 });