main.js (5630B)
1 /** 2 * @license Apache-2.0 3 * 4 * Copyright (c) 2018 The Stdlib Authors. 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 19 'use strict'; 20 21 // MODULES // 22 23 var setReadOnly = require( '@stdlib/utils/define-nonenumerable-read-only-property' ); 24 var setReadOnlyAccessor = require( '@stdlib/utils/define-nonenumerable-read-only-accessor' ); 25 var setReadWriteAccessor = require( '@stdlib/utils/define-nonenumerable-read-write-accessor' ); 26 var copy = require( '@stdlib/utils/copy' ); 27 var isObject = require( '@stdlib/assert/is-plain-object' ); 28 var isNonNegativeInteger = require( '@stdlib/assert/is-nonnegative-integer' ).isPrimitive; 29 var hasOwnProp = require( '@stdlib/assert/has-own-property' ); 30 var MAX_VALUE = require( '@stdlib/constants/float64/max' ); 31 var randu = require( './../../../base/randu' ).factory; 32 var iteratorSymbol = require( '@stdlib/symbol/iterator' ); 33 34 35 // MAIN // 36 37 /** 38 * Returns an iterator for generating uniformly distributed pseudorandom numbers between 0 and 1. 39 * 40 * @param {Options} [options] - function options 41 * @param {string} [options.name='mt19937'] - name of a supported pseudorandom number generator (PRNG), which will serve as the underlying source of pseudorandom numbers 42 * @param {*} [options.seed] - pseudorandom number generator seed 43 * @param {*} [options.state] - pseudorandom number generator state 44 * @param {boolean} [options.copy=true] - boolean indicating whether to copy a provided pseudorandom number generator state 45 * @param {NonNegativeInteger} [options.iter] - number of iterations 46 * @throws {TypeError} options argument must be an object 47 * @throws {TypeError} must provide valid options 48 * @throws {Error} must provide a valid state 49 * @returns {Iterator} iterator 50 * 51 * @example 52 * var iter = iterator(); 53 * 54 * var r = iter.next().value; 55 * // returns <number> 56 * 57 * r = iter.next().value; 58 * // returns <number> 59 * 60 * r = iter.next().value; 61 * // returns <number> 62 * 63 * // ... 64 */ 65 function iterator( options ) { 66 var opts; 67 var iter; 68 var rand; 69 var FLG; 70 var i; 71 if ( arguments.length > 0 ) { 72 if ( !isObject( options ) ) { 73 throw new TypeError( 'invalid argument. Options argument must be an object. Value: `'+options+'`.' ); 74 } 75 opts = copy( options, 1 ); 76 if ( hasOwnProp( opts, 'iter' ) ) { 77 if ( !isNonNegativeInteger( opts.iter ) ) { 78 throw new TypeError( 'invalid option. `iter` option must be a nonnegative integer. Option: `'+opts.iter+'`.' ); 79 } 80 } else { 81 opts.iter = MAX_VALUE; 82 } 83 rand = randu( opts ); 84 if ( opts.copy !== false ) { 85 opts.state = rand.state; // cache a copy of the PRNG state 86 } 87 } else { 88 rand = randu(); 89 opts = { 90 'iter': MAX_VALUE, 91 'state': rand.state // cache a copy of the PRNG state 92 }; 93 } 94 i = 0; 95 96 // Create an iterator protocol-compliant object: 97 iter = {}; 98 setReadOnly( iter, 'next', next ); 99 setReadOnly( iter, 'return', end ); 100 setReadOnlyAccessor( iter, 'seed', getSeed ); 101 setReadOnlyAccessor( iter, 'seedLength', getSeedLength ); 102 setReadWriteAccessor( iter, 'state', getState, setState ); 103 setReadOnlyAccessor( iter, 'stateLength', getStateLength ); 104 setReadOnlyAccessor( iter, 'byteLength', getStateSize ); 105 setReadOnly( iter, 'PRNG', rand.PRNG ); 106 107 // If an environment supports `Symbol.iterator`, make the iterator iterable: 108 if ( iteratorSymbol ) { 109 setReadOnly( iter, iteratorSymbol, factory ); 110 } 111 return iter; 112 113 /** 114 * Returns an iterator protocol-compliant object containing the next iterated value. 115 * 116 * @private 117 * @returns {Object} iterator protocol-compliant object 118 */ 119 function next() { 120 i += 1; 121 if ( FLG || i > opts.iter ) { 122 return { 123 'done': true 124 }; 125 } 126 return { 127 'value': rand(), 128 'done': false 129 }; 130 } 131 132 /** 133 * Finishes an iterator. 134 * 135 * @private 136 * @param {*} [value] - value to return 137 * @returns {Object} iterator protocol-compliant object 138 */ 139 function end( value ) { 140 FLG = true; 141 if ( arguments.length ) { 142 return { 143 'value': value, 144 'done': true 145 }; 146 } 147 return { 148 'done': true 149 }; 150 } 151 152 /** 153 * Returns a new iterator. 154 * 155 * @private 156 * @returns {Iterator} iterator 157 */ 158 function factory() { 159 return iterator( opts ); 160 } 161 162 /** 163 * Returns the PRNG seed. 164 * 165 * @private 166 * @returns {*} seed 167 */ 168 function getSeed() { 169 return rand.PRNG.seed; 170 } 171 172 /** 173 * Returns the PRNG seed length. 174 * 175 * @private 176 * @returns {PositiveInteger} seed length 177 */ 178 function getSeedLength() { 179 return rand.PRNG.seedLength; 180 } 181 182 /** 183 * Returns the PRNG state length. 184 * 185 * @private 186 * @returns {PositiveInteger} state length 187 */ 188 function getStateLength() { 189 return rand.PRNG.stateLength; 190 } 191 192 /** 193 * Returns the PRNG state size (in bytes). 194 * 195 * @private 196 * @returns {PositiveInteger} state size (in bytes) 197 */ 198 function getStateSize() { 199 return rand.PRNG.byteLength; 200 } 201 202 /** 203 * Returns the current pseudorandom number generator state. 204 * 205 * @private 206 * @returns {*} current state 207 */ 208 function getState() { 209 return rand.PRNG.state; 210 } 211 212 /** 213 * Sets the pseudorandom number generator state. 214 * 215 * @private 216 * @param {*} s - generator state 217 * @throws {Error} must provide a valid state 218 */ 219 function setState( s ) { 220 rand.PRNG.state = s; 221 } 222 } 223 224 225 // EXPORTS // 226 227 module.exports = iterator;