time-to-botec

Benchmark sampling in different programming languages
Log | Files | Refs | README

factory.js (25841B)


      1 /* eslint-disable max-lines, max-len */
      2 
      3 /**
      4 * @license Apache-2.0
      5 *
      6 * Copyright (c) 2018 The Stdlib Authors.
      7 *
      8 * Licensed under the Apache License, Version 2.0 (the "License");
      9 * you may not use this file except in compliance with the License.
     10 * You may obtain a copy of the License at
     11 *
     12 *    http://www.apache.org/licenses/LICENSE-2.0
     13 *
     14 * Unless required by applicable law or agreed to in writing, software
     15 * distributed under the License is distributed on an "AS IS" BASIS,
     16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     17 * See the License for the specific language governing permissions and
     18 * limitations under the License.
     19 *
     20 *
     21 * ## Notice
     22 *
     23 * The original C code and copyright notice are from the [source implementation]{@link http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/CODES/mt19937ar.c}. The implementation has been modified for JavaScript.
     24 *
     25 * ```text
     26 * Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,
     27 * All rights reserved.
     28 *
     29 * Redistribution and use in source and binary forms, with or without
     30 * modification, are permitted provided that the following conditions
     31 * are met:
     32 *
     33 *   1. Redistributions of source code must retain the above copyright
     34 *      notice, this list of conditions and the following disclaimer.
     35 *
     36 *   2. Redistributions in binary form must reproduce the above copyright
     37 *      notice, this list of conditions and the following disclaimer in the
     38 *      documentation and/or other materials provided with the distribution.
     39 *
     40 *   3. The names of its contributors may not be used to endorse or promote
     41 *      products derived from this software without specific prior written
     42 *      permission.
     43 *
     44 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     45 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     46 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     47 * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     48 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     49 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     50 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     51 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
     52 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
     53 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     54 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     55 * ```
     56 */
     57 
     58 'use strict';
     59 
     60 // MODULES //
     61 
     62 var setReadOnly = require( '@stdlib/utils/define-nonenumerable-read-only-property' );
     63 var setReadOnlyAccessor = require( '@stdlib/utils/define-nonenumerable-read-only-accessor' );
     64 var setReadWriteAccessor = require( '@stdlib/utils/define-nonenumerable-read-write-accessor' );
     65 var hasOwnProp = require( '@stdlib/assert/has-own-property' );
     66 var isObject = require( '@stdlib/assert/is-plain-object' );
     67 var isCollection = require( '@stdlib/assert/is-collection' );
     68 var isUint32Array = require( '@stdlib/assert/is-uint32array' );
     69 var isBoolean = require( '@stdlib/assert/is-boolean' ).isPrimitive;
     70 var isPositiveInteger = require( '@stdlib/assert/is-positive-integer' ).isPrimitive;
     71 var FLOAT64_MAX_SAFE_INTEGER = require( '@stdlib/constants/float64/max-safe-integer' );
     72 var UINT32_MAX = require( '@stdlib/constants/uint32/max' );
     73 var Uint32Array = require( '@stdlib/array/uint32' );
     74 var max = require( '@stdlib/math/base/special/max' );
     75 var uimul = require( '@stdlib/math/base/special/uimul' );
     76 var gcopy = require( '@stdlib/blas/base/gcopy' );
     77 var typedarray2json = require( '@stdlib/array/to-json' );
     78 var randuint32 = require( './rand_uint32.js' );
     79 
     80 
     81 // VARIABLES //
     82 
     83 // Define the size of the state array (see refs):
     84 var N = 624;
     85 
     86 // Define a (magic) constant used for indexing into the state array:
     87 var M = 397;
     88 
     89 // Define the maximum seed: 11111111111111111111111111111111
     90 var MAX_SEED = UINT32_MAX >>> 0; // asm type annotation
     91 
     92 // For seed arrays, define an initial state (magic) constant: 19650218 => 00000001001010111101011010101010
     93 var SEED_ARRAY_INIT_STATE = 19650218 >>> 0; // asm type annotation
     94 
     95 // Define a mask for the most significant `w-r` bits, where `w` is the word size (32 bits) and `r` is the separation point of one word (see refs): 2147483648 => 0x80000000 => 10000000000000000000000000000000
     96 var UPPER_MASK = 0x80000000 >>> 0; // asm type annotation
     97 
     98 // Define a mask for the least significant `r` bits (see refs): 2147483647 => 0x7fffffff => 01111111111111111111111111111111
     99 var LOWER_MASK = 0x7fffffff >>> 0; // asm type annotation
    100 
    101 // Define a multiplier (see Knuth TAOCP Vol2. 3rd Ed. P.106): 1812433253 => 01101100000001111000100101100101
    102 var KNUTH_MULTIPLIER = 1812433253 >>> 0; // asm type annotation
    103 
    104 // Define a (magic) multiplier: 1664525 => 00000000000110010110011000001101
    105 var MAGIC_MULTIPLIER_1 = 1664525 >>> 0; // asm type annotation
    106 
    107 // Define a (magic) multiplier: 1566083941 => 01011101010110001000101101100101
    108 var MAGIC_MULTIPLIER_2 = 1566083941 >>> 0; // asm type annotation
    109 
    110 // Define a tempering coefficient: 2636928640 => 0x9d2c5680 => 10011101001011000101011010000000
    111 var TEMPERING_COEFFICIENT_1 = 0x9d2c5680 >>> 0; // asm type annotation
    112 
    113 // Define a tempering coefficient: 4022730752 => 0xefc60000 => 11101111110001100000000000000000
    114 var TEMPERING_COEFFICIENT_2 = 0xefc60000 >>> 0; // asm type annotation
    115 
    116 // Define a constant vector `a` (see refs): 2567483615 => 0x9908b0df => 10011001000010001011000011011111
    117 var MATRIX_A = 0x9908b0df >>> 0; // asm type annotation
    118 
    119 // MAG01[x] = x * MATRIX_A; for x = {0,1}
    120 var MAG01 = [ 0x0 >>> 0, MATRIX_A >>> 0 ]; // asm type annotation
    121 
    122 // Define a normalization constant when generating double-precision floating-point numbers: 2^53 => 9007199254740992
    123 var FLOAT64_NORMALIZATION_CONSTANT = 1.0 / ( FLOAT64_MAX_SAFE_INTEGER+1.0 ); // eslint-disable-line id-length
    124 
    125 // 2^26: 67108864
    126 var TWO_26 = 67108864 >>> 0; // asm type annotation
    127 
    128 // 2^32: 2147483648 => 0x80000000 => 10000000000000000000000000000000
    129 var TWO_32 = 0x80000000 >>> 0; // asm type annotation
    130 
    131 // 1 (as a 32-bit unsigned integer): 1 => 0x1 => 00000000000000000000000000000001
    132 var ONE = 0x1 >>> 0; // asm type annotation
    133 
    134 // Define the maximum normalized pseudorandom double-precision floating-point number: ( (((2^32-1)>>>5)*2^26)+( (2^32-1)>>>6) ) / 2^53
    135 var MAX_NORMALIZED = FLOAT64_MAX_SAFE_INTEGER * FLOAT64_NORMALIZATION_CONSTANT;
    136 
    137 // Define the state array schema version:
    138 var STATE_ARRAY_VERSION = 1; // NOTE: anytime the state array schema changes, this value should be incremented!!!
    139 
    140 // Define the number of sections in the state array:
    141 var NUM_STATE_SECTIONS = 3; // state, other, seed
    142 
    143 // Define the index offset of the "state" section in the state array:
    144 var STATE_SECTION_OFFSET = 2; // | version | num_sections | state_length | ...state | other_length | state_index | seed_length | ...seed |
    145 
    146 // Define the index offset of the "other" section in the state array:
    147 var OTHER_SECTION_OFFSET = N + 3; // | version | num_sections | state_length | ...state | other_length | state_index | seed_length | ...seed |
    148 
    149 // Define the index offset of the seed section in the state array:
    150 var SEED_SECTION_OFFSET = N + 5; // | version | num_sections | state_length | ...state | other_length | state_index | seed_length | ...seed |
    151 
    152 // Define the length of the "fixed" length portion of the state array:
    153 var STATE_FIXED_LENGTH = N + 6; // 1 (version) + 1 (num_sections) + 1 (state_length) + N (state) + 1 (other_length) + 1 (state_index) + 1 (seed_length)
    154 
    155 
    156 // FUNCTIONS //
    157 
    158 /**
    159 * Verifies state array integrity.
    160 *
    161 * @private
    162 * @param {Uint32Array} state - state array
    163 * @param {boolean} FLG - flag indicating whether the state array was provided as an option (true) or an argument (false)
    164 * @returns {(Error|null)} an error or `null`
    165 */
    166 function verifyState( state, FLG ) {
    167 	var s1;
    168 	if ( FLG ) {
    169 		s1 = 'option';
    170 	} else {
    171 		s1 = 'argument';
    172 	}
    173 	// The state array must have a minimum length...
    174 	if ( state.length < STATE_FIXED_LENGTH+1 ) {
    175 		return new RangeError( 'invalid '+s1+'. `state` array has insufficient length.' );
    176 	}
    177 	// The first element of the state array must equal the supported state array schema version...
    178 	if ( state[ 0 ] !== STATE_ARRAY_VERSION ) {
    179 		return new RangeError( 'invalid '+s1+'. `state` array has an incompatible schema version. Expected: '+STATE_ARRAY_VERSION+'. Actual: '+state[ 0 ]+'.' );
    180 	}
    181 	// The second element of the state array must contain the number of sections...
    182 	if ( state[ 1 ] !== NUM_STATE_SECTIONS ) {
    183 		return new RangeError( 'invalid '+s1+'. `state` array has an incompatible number of sections. Expected: '+NUM_STATE_SECTIONS+'. Actual: '+state[ 1 ]+'.' );
    184 	}
    185 	// The length of the "state" section must equal `N`...
    186 	if ( state[ STATE_SECTION_OFFSET ] !== N ) {
    187 		return new RangeError( 'invalid '+s1+'. `state` array has an incompatible state length. Expected: '+N+'. Actual: '+state[ STATE_SECTION_OFFSET ]+'.' );
    188 	}
    189 	// The length of the "other" section must equal `1`...
    190 	if ( state[ OTHER_SECTION_OFFSET ] !== 1 ) {
    191 		return new RangeError( 'invalid '+s1+'. `state` array has an incompatible section length. Expected: '+(1).toString()+'. Actual: '+state[ OTHER_SECTION_OFFSET ]+'.' );
    192 	}
    193 	// The length of the "seed" section much match the empirical length...
    194 	if ( state[ SEED_SECTION_OFFSET ] !== state.length-STATE_FIXED_LENGTH ) {
    195 		return new RangeError( 'invalid '+s1+'. `state` array length is incompatible with seed section length. Expected: '+(state.length-STATE_FIXED_LENGTH)+'. Actual: '+state[ SEED_SECTION_OFFSET ]+'.' );
    196 	}
    197 	return null;
    198 }
    199 
    200 /**
    201 * Returns an initial PRNG state.
    202 *
    203 * @private
    204 * @param {Uint32Array} state - state array
    205 * @param {PositiveInteger} N - state size
    206 * @param {uinteger32} s - seed
    207 * @returns {Uint32Array} state array
    208 */
    209 function createState( state, N, s ) {
    210 	var i;
    211 
    212 	// Set the first element of the state array to the provided seed:
    213 	state[ 0 ] = s >>> 0; // equivalent to `s & 0xffffffffUL` in original C implementation
    214 
    215 	// Initialize the remaining state array elements:
    216 	for ( i = 1; i < N; i++ ) {
    217 		/*
    218 		* In the original C implementation (see `init_genrand()`),
    219 		*
    220 		* ```c
    221 		* mt[i] = (KNUTH_MULTIPLIER * (mt[i-1] ^ (mt[i-1] >> 30)) + i)
    222 		* ```
    223 		*
    224 		* In order to replicate this in JavaScript, we must emulate C-like multiplication of unsigned 32-bit integers.
    225 		*/
    226 		s = state[ i-1 ]>>>0; // asm type annotation
    227 		s = ( s^(s>>>30) )>>>0; // asm type annotation
    228 		state[ i ] = ( uimul( s, KNUTH_MULTIPLIER ) + i )>>>0; // asm type annotation
    229 	}
    230 	return state;
    231 }
    232 
    233 /**
    234 * Initializes a PRNG state array according to a seed array.
    235 *
    236 * @private
    237 * @param {Uint32Array} state - state array
    238 * @param {NonNegativeInteger} N - state array length
    239 * @param {Collection} seed - seed array
    240 * @param {NonNegativeInteger} M - seed array length
    241 * @returns {Uint32Array} state array
    242 */
    243 function initState( state, N, seed, M ) {
    244 	var s;
    245 	var i;
    246 	var j;
    247 	var k;
    248 
    249 	i = 1;
    250 	j = 0;
    251 	for ( k = max( N, M ); k > 0; k-- ) {
    252 		/*
    253 		* In the original C implementation (see `init_by_array()`),
    254 		*
    255 		* ```c
    256 		* mt[i] = (mt[i]^((mt[i-1]^(mt[i-1]>>30))*1664525UL)) + seed[j] + j;
    257 		* ```
    258 		*
    259 		* In order to replicate this in JavaScript, we must emulate C-like multiplication of unsigned 32-bit integers.
    260 		*/
    261 		s = state[ i-1 ]>>>0; // asm type annotation
    262 		s = ( s^(s>>>30) )>>>0; // asm type annotation
    263 		s = ( uimul( s, MAGIC_MULTIPLIER_1 ) )>>>0; // asm type annotation
    264 		state[ i ] = ( ((state[i]>>>0)^s) + seed[j] + j )>>>0; /* non-linear */ // asm type annotation
    265 
    266 		i += 1;
    267 		j += 1;
    268 		if ( i >= N ) {
    269 			state[ 0 ] = state[ N-1 ];
    270 			i = 1;
    271 		}
    272 		if ( j >= M ) {
    273 			j = 0;
    274 		}
    275 	}
    276 	for ( k = N-1; k > 0; k-- ) {
    277 		/*
    278 		* In the original C implementation (see `init_by_array()`),
    279 		*
    280 		* ```c
    281 		* mt[i] = (mt[i]^((mt[i-1]^(mt[i-1]>>30))*1566083941UL)) - i;
    282 		* ```
    283 		*
    284 		* In order to replicate this in JavaScript, we must emulate C-like multiplication of unsigned 32-bit integers.
    285 		*/
    286 		s = state[ i-1 ]>>>0; // asm type annotation
    287 		s = ( s^(s>>>30) )>>>0; // asm type annotation
    288 		s = ( uimul( s, MAGIC_MULTIPLIER_2 ) )>>>0; // asm type annotation
    289 		state[ i ] = ( ((state[i]>>>0)^s) - i )>>>0; /* non-linear */ // asm type annotation
    290 
    291 		i += 1;
    292 		if ( i >= N ) {
    293 			state[ 0 ] = state[ N-1 ];
    294 			i = 1;
    295 		}
    296 	}
    297 	// Ensure a non-zero initial state array:
    298 	state[ 0 ] = TWO_32; // MSB (most significant bit) is 1
    299 
    300 	return state;
    301 }
    302 
    303 /**
    304 * Updates a PRNG's internal state by generating the next `N` words.
    305 *
    306 * @private
    307 * @param {Uint32Array} state - state array
    308 * @returns {Uint32Array} state array
    309 */
    310 function twist( state ) {
    311 	var w;
    312 	var i;
    313 	var j;
    314 	var k;
    315 
    316 	k = N - M;
    317 	for ( i = 0; i < k; i++ ) {
    318 		w = ( state[i]&UPPER_MASK ) | ( state[i+1]&LOWER_MASK );
    319 		state[ i ] = state[ i+M ] ^ ( w>>>1 ) ^ MAG01[ w&ONE ];
    320 	}
    321 	j = N - 1;
    322 	for ( ; i < j; i++ ) {
    323 		w = ( state[i]&UPPER_MASK ) | ( state[i+1]&LOWER_MASK );
    324 		state[ i ] = state[ i-k ] ^ ( w>>>1 ) ^ MAG01[ w&ONE ];
    325 	}
    326 	w = ( state[j]&UPPER_MASK ) | ( state[0]&LOWER_MASK );
    327 	state[ j ] = state[ M-1 ] ^ ( w>>>1 ) ^ MAG01[ w&ONE ];
    328 	return state;
    329 }
    330 
    331 
    332 // MAIN //
    333 
    334 /**
    335 * Returns a 32-bit Mersenne Twister pseudorandom number generator.
    336 *
    337 * ## Notes
    338 *
    339 * -   In contrast to the original C implementation, array seeds of length `1` are considered integer seeds. This ensures that the seed `[ 1234 ]` generates the same output as the seed `1234`. In the original C implementation, the two seeds would yield different output, which is **not** obvious from a user perspective.
    340 *
    341 * @param {Options} [options] - options
    342 * @param {PRNGSeedMT19937} [options.seed] - pseudorandom number generator seed
    343 * @param {PRNGStateMT19937} [options.state] - pseudorandom number generator state
    344 * @param {boolean} [options.copy=true] - boolean indicating whether to copy a provided pseudorandom number generator state
    345 * @throws {TypeError} options argument must be an object
    346 * @throws {TypeError} a seed must be either a positive integer less than or equal to the maximum unsigned 32-bit integer or an array-like object containing integers less than or equal to the maximum unsigned 32-bit integer
    347 * @throws {RangeError} a numeric seed must be a positive integer less than or equal to the maximum unsigned 32-bit integer
    348 * @throws {TypeError} state must be a `Uint32Array`
    349 * @throws {Error} must provide a valid state
    350 * @throws {TypeError} `copy` option must be a boolean
    351 * @returns {PRNG} Mersenne Twister PRNG
    352 *
    353 * @example
    354 * var mt19937 = factory();
    355 *
    356 * var v = mt19937();
    357 * // returns <number>
    358 *
    359 * @example
    360 * // Return a seeded Mersenne Twister PRNG:
    361 * var mt19937 = factory({
    362 *     'seed': 1234
    363 * });
    364 *
    365 * var v = mt19937();
    366 * // returns 822569775
    367 */
    368 function factory( options ) {
    369 	var STATE;
    370 	var state;
    371 	var opts;
    372 	var seed;
    373 	var slen;
    374 	var err;
    375 
    376 	opts = {};
    377 	if ( arguments.length ) {
    378 		if ( !isObject( options ) ) {
    379 			throw new TypeError( 'invalid argument. Options argument must be an object. Value: `' + options + '`.' );
    380 		}
    381 		if ( hasOwnProp( options, 'copy' ) ) {
    382 			opts.copy = options.copy;
    383 			if ( !isBoolean( options.copy ) ) {
    384 				throw new TypeError( 'invalid option. `copy` option must be a boolean. Option: `' + options.copy + '`.' );
    385 			}
    386 		}
    387 		if ( hasOwnProp( options, 'state' ) ) {
    388 			state = options.state;
    389 			opts.state = true;
    390 			if ( !isUint32Array( state ) ) {
    391 				throw new TypeError( 'invalid option. `state` option must be a Uint32Array. Option: `' + state + '`.' );
    392 			}
    393 			err = verifyState( state, true );
    394 			if ( err ) {
    395 				throw err;
    396 			}
    397 			if ( opts.copy === false ) {
    398 				STATE = state;
    399 			} else {
    400 				STATE = new Uint32Array( state.length );
    401 				gcopy( state.length, state, 1, STATE, 1 );
    402 			}
    403 			// Create a state "view":
    404 			state = new Uint32Array( STATE.buffer, STATE.byteOffset+((STATE_SECTION_OFFSET+1)*STATE.BYTES_PER_ELEMENT), N );
    405 
    406 			// Create a seed "view":
    407 			seed = new Uint32Array( STATE.buffer, STATE.byteOffset+((SEED_SECTION_OFFSET+1)*STATE.BYTES_PER_ELEMENT), state[ SEED_SECTION_OFFSET ] );
    408 		}
    409 		// If provided a PRNG state, we ignore the `seed` option...
    410 		if ( seed === void 0 ) {
    411 			if ( hasOwnProp( options, 'seed' ) ) {
    412 				seed = options.seed;
    413 				opts.seed = true;
    414 				if ( isPositiveInteger( seed ) ) {
    415 					if ( seed > MAX_SEED ) {
    416 						throw new RangeError( 'invalid option. `seed` option must be a positive integer less than or equal to the maximum unsigned 32-bit integer. Option: `' + seed + '`.' );
    417 					}
    418 					seed >>>= 0; // asm type annotation
    419 				} else if ( isCollection( seed ) === false || seed.length < 1 ) {
    420 					throw new TypeError( 'invalid option. `seed` option must be either a positive integer less than or equal to the maximum unsigned 32-bit integer or an array-like object containing integer values less than or equal to the maximum unsigned 32-bit integer. Option: `' + seed + '`.' );
    421 				} else if ( seed.length === 1 ) {
    422 					seed = seed[ 0 ];
    423 					if ( !isPositiveInteger( seed ) ) {
    424 						throw new TypeError( 'invalid option. `seed` option must be either a positive integer less than or equal to the maximum unsigned 32-bit integer or an array-like object containing integer values less than or equal to the maximum unsigned 32-bit integer. Option: `' + seed + '`.' );
    425 					}
    426 					if ( seed > MAX_SEED ) {
    427 						throw new RangeError( 'invalid option. `seed` option must be either a positive integer less than or equal to the maximum unsigned 32-bit integer or an array-like object containing integer values less than or equal to the maximum unsigned 32-bit integer. Option: `' + seed + '`.' );
    428 					}
    429 					seed >>>= 0; // asm type annotation
    430 				} else {
    431 					slen = seed.length;
    432 					STATE = new Uint32Array( STATE_FIXED_LENGTH+slen );
    433 
    434 					// Initialize sections:
    435 					STATE[ 0 ] = STATE_ARRAY_VERSION;
    436 					STATE[ 1 ] = NUM_STATE_SECTIONS;
    437 					STATE[ STATE_SECTION_OFFSET ] = N;
    438 					STATE[ OTHER_SECTION_OFFSET ] = 1;
    439 					STATE[ OTHER_SECTION_OFFSET+1 ] = N; // state index
    440 					STATE[ SEED_SECTION_OFFSET ] = slen;
    441 
    442 					// Copy the provided seed array to prevent external mutation, as mutation would lead to an inability to reproduce PRNG values according to the PRNG's stated seed:
    443 					gcopy.ndarray( slen, seed, 1, 0, STATE, 1, SEED_SECTION_OFFSET+1 );
    444 
    445 					// Create a state "view":
    446 					state = new Uint32Array( STATE.buffer, STATE.byteOffset+((STATE_SECTION_OFFSET+1)*STATE.BYTES_PER_ELEMENT), N );
    447 
    448 					// Create a seed "view":
    449 					seed = new Uint32Array( STATE.buffer, STATE.byteOffset+((SEED_SECTION_OFFSET+1)*STATE.BYTES_PER_ELEMENT), slen );
    450 
    451 					// Initialize the internal PRNG state:
    452 					state = createState( state, N, SEED_ARRAY_INIT_STATE );
    453 					state = initState( state, N, seed, slen );
    454 				}
    455 			} else {
    456 				seed = randuint32() >>> 0; // asm type annotation
    457 			}
    458 		}
    459 	} else {
    460 		seed = randuint32() >>> 0; // asm type annotation
    461 	}
    462 	if ( state === void 0 ) {
    463 		STATE = new Uint32Array( STATE_FIXED_LENGTH+1 );
    464 
    465 		// Initialize sections:
    466 		STATE[ 0 ] = STATE_ARRAY_VERSION;
    467 		STATE[ 1 ] = NUM_STATE_SECTIONS;
    468 		STATE[ STATE_SECTION_OFFSET ] = N;
    469 		STATE[ OTHER_SECTION_OFFSET ] = 1;
    470 		STATE[ OTHER_SECTION_OFFSET+1 ] = N; // state index
    471 		STATE[ SEED_SECTION_OFFSET ] = 1;
    472 		STATE[ SEED_SECTION_OFFSET+1 ] = seed;
    473 
    474 		// Create a state "view":
    475 		state = new Uint32Array( STATE.buffer, STATE.byteOffset+((STATE_SECTION_OFFSET+1)*STATE.BYTES_PER_ELEMENT), N );
    476 
    477 		// Create a seed "view":
    478 		seed = new Uint32Array( STATE.buffer, STATE.byteOffset+((SEED_SECTION_OFFSET+1)*STATE.BYTES_PER_ELEMENT), 1 );
    479 
    480 		// Initialize the internal PRNG state:
    481 		state = createState( state, N, seed );
    482 	}
    483 	// Note: property order matters in order to maintain consistency of PRNG "shape" (hidden classes).
    484 	setReadOnly( mt19937, 'NAME', 'mt19937' );
    485 	setReadOnlyAccessor( mt19937, 'seed', getSeed );
    486 	setReadOnlyAccessor( mt19937, 'seedLength', getSeedLength );
    487 	setReadWriteAccessor( mt19937, 'state', getState, setState );
    488 	setReadOnlyAccessor( mt19937, 'stateLength', getStateLength );
    489 	setReadOnlyAccessor( mt19937, 'byteLength', getStateSize );
    490 	setReadOnly( mt19937, 'toJSON', toJSON );
    491 	setReadOnly( mt19937, 'MIN', 1 );
    492 	setReadOnly( mt19937, 'MAX', UINT32_MAX );
    493 	setReadOnly( mt19937, 'normalized', normalized );
    494 
    495 	setReadOnly( normalized, 'NAME', mt19937.NAME );
    496 	setReadOnlyAccessor( normalized, 'seed', getSeed );
    497 	setReadOnlyAccessor( normalized, 'seedLength', getSeedLength );
    498 	setReadWriteAccessor( normalized, 'state', getState, setState );
    499 	setReadOnlyAccessor( normalized, 'stateLength', getStateLength );
    500 	setReadOnlyAccessor( normalized, 'byteLength', getStateSize );
    501 	setReadOnly( normalized, 'toJSON', toJSON );
    502 	setReadOnly( normalized, 'MIN', 0.0 );
    503 	setReadOnly( normalized, 'MAX', MAX_NORMALIZED );
    504 
    505 	return mt19937;
    506 
    507 	/**
    508 	* Returns the PRNG seed.
    509 	*
    510 	* @private
    511 	* @returns {PRNGSeedMT19937} seed
    512 	*/
    513 	function getSeed() {
    514 		var len = STATE[ SEED_SECTION_OFFSET ];
    515 		return gcopy( len, seed, 1, new Uint32Array( len ), 1 );
    516 	}
    517 
    518 	/**
    519 	* Returns the PRNG seed length.
    520 	*
    521 	* @private
    522 	* @returns {PositiveInteger} seed length
    523 	*/
    524 	function getSeedLength() {
    525 		return STATE[ SEED_SECTION_OFFSET ];
    526 	}
    527 
    528 	/**
    529 	* Returns the PRNG state length.
    530 	*
    531 	* @private
    532 	* @returns {PositiveInteger} state length
    533 	*/
    534 	function getStateLength() {
    535 		return STATE.length;
    536 	}
    537 
    538 	/**
    539 	* Returns the PRNG state size (in bytes).
    540 	*
    541 	* @private
    542 	* @returns {PositiveInteger} state size (in bytes)
    543 	*/
    544 	function getStateSize() {
    545 		return STATE.byteLength;
    546 	}
    547 
    548 	/**
    549 	* Returns the current PRNG state.
    550 	*
    551 	* ## Notes
    552 	*
    553 	* -   The PRNG state array is comprised of a preamble followed by `3` sections:
    554 	*
    555 	*     0.  preamble (version + number of sections)
    556 	*     1.  internal PRNG state
    557 	*     2.  auxiliary state information
    558 	*     3.  PRNG seed
    559 	*
    560 	* -   The first element of the PRNG state array preamble is the state array schema version.
    561 	*
    562 	* -   The second element of the PRNG state array preamble is the number of state array sections (i.e., `3`).
    563 	*
    564 	* -   The first element of each section following the preamble specifies the section length. The remaining section elements comprise the section contents.
    565 	*
    566 	* @private
    567 	* @returns {PRNGStateMT19937} current state
    568 	*/
    569 	function getState() {
    570 		var len = STATE.length;
    571 		return gcopy( len, STATE, 1, new Uint32Array( len ), 1 );
    572 	}
    573 
    574 	/**
    575 	* Sets the PRNG state.
    576 	*
    577 	* ## Notes
    578 	*
    579 	* -   If PRNG state is "shared" (meaning a state array was provided during PRNG creation and **not** copied) and one sets the generator state to a state array having a different length, the PRNG does **not** update the existing shared state and, instead, points to the newly provided state array. In order to synchronize PRNG output according to the new shared state array, the state array for **each** relevant PRNG must be **explicitly** set.
    580 	* -   If PRNG state is "shared" and one sets the generator state to a state array of the same length, the PRNG state is updated (along with the state of all other PRNGs sharing the PRNG's state array).
    581 	*
    582 	* @private
    583 	* @param {PRNGStateMT19937} s - generator state
    584 	* @throws {TypeError} must provide a `Uint32Array`
    585 	* @throws {Error} must provide a valid state
    586 	*/
    587 	function setState( s ) {
    588 		var err;
    589 		if ( !isUint32Array( s ) ) {
    590 			throw new TypeError( 'invalid argument. Must provide a Uint32Array. Value: `' + s + '`.' );
    591 		}
    592 		err = verifyState( s, false );
    593 		if ( err ) {
    594 			throw err;
    595 		}
    596 		if ( opts.copy === false ) {
    597 			if ( opts.state && s.length === STATE.length ) {
    598 				gcopy( s.length, s, 1, STATE, 1 ); // update current shared state
    599 			} else {
    600 				STATE = s; // point to new shared state
    601 				opts.state = true; // setting this flag allows updating a shared state even if a state array was not provided at PRNG creation
    602 			}
    603 		} else {
    604 			// Check if we can reuse allocated memory...
    605 			if ( s.length !== STATE.length ) {
    606 				STATE = new Uint32Array( s.length ); // reallocate
    607 			}
    608 			gcopy( s.length, s, 1, STATE, 1 );
    609 		}
    610 		// Create a new state "view":
    611 		state = new Uint32Array( STATE.buffer, STATE.byteOffset+((STATE_SECTION_OFFSET+1)*STATE.BYTES_PER_ELEMENT), N );
    612 
    613 		// Create a new seed "view":
    614 		seed = new Uint32Array( STATE.buffer, STATE.byteOffset+((SEED_SECTION_OFFSET+1)*STATE.BYTES_PER_ELEMENT), STATE[ SEED_SECTION_OFFSET ] );
    615 	}
    616 
    617 	/**
    618 	* Serializes the pseudorandom number generator as a JSON object.
    619 	*
    620 	* ## Notes
    621 	*
    622 	* -   `JSON.stringify()` implicitly calls this method when stringifying a PRNG.
    623 	*
    624 	* @private
    625 	* @returns {Object} JSON representation
    626 	*/
    627 	function toJSON() {
    628 		var out = {};
    629 		out.type = 'PRNG';
    630 		out.name = mt19937.NAME;
    631 		out.state = typedarray2json( STATE );
    632 		out.params = [];
    633 		return out;
    634 	}
    635 
    636 	/**
    637 	* Generates a pseudorandom integer on the interval \\( [1,2^{32}-1) \\).
    638 	*
    639 	* @private
    640 	* @returns {uinteger32} pseudorandom integer
    641 	*
    642 	* @example
    643 	* var r = mt19937();
    644 	* // returns <number>
    645 	*/
    646 	function mt19937() {
    647 		var r;
    648 		var i;
    649 
    650 		// Retrieve the current state index:
    651 		i = STATE[ OTHER_SECTION_OFFSET+1 ];
    652 
    653 		// Determine whether we need to update the PRNG state:
    654 		if ( i >= N ) {
    655 			state = twist( state );
    656 			i = 0;
    657 		}
    658 		// Get the next word of "raw"/untempered state:
    659 		r = state[ i ];
    660 
    661 		// Update the state index:
    662 		STATE[ OTHER_SECTION_OFFSET+1 ] = i + 1;
    663 
    664 		// Tempering transform to compensate for the reduced dimensionality of equidistribution:
    665 		r ^= r >>> 11;
    666 		r ^= ( r << 7 ) & TEMPERING_COEFFICIENT_1;
    667 		r ^= ( r << 15 ) & TEMPERING_COEFFICIENT_2;
    668 		r ^= r >>> 18;
    669 
    670 		return r >>> 0;
    671 	}
    672 
    673 	/**
    674 	* Generates a pseudorandom number on the interval \\( [0,1) \\).
    675 	*
    676 	* ## Notes
    677 	*
    678 	* -   The original C implementation credits Isaku Wada for this algorithm (2002/01/09).
    679 	*
    680 	* @private
    681 	* @returns {number} pseudorandom number
    682 	*
    683 	* @example
    684 	* var r = normalized();
    685 	* // returns <number>
    686 	*/
    687 	function normalized() {
    688 		var x = mt19937() >>> 5;
    689 		var y = mt19937() >>> 6;
    690 		return ( (x*TWO_26)+y ) * FLOAT64_NORMALIZATION_CONSTANT;
    691 	}
    692 }
    693 
    694 
    695 // EXPORTS //
    696 
    697 module.exports = factory;