diff --git a/lib/node_modules/@stdlib/random/base/xorshift32/README.md b/lib/node_modules/@stdlib/random/base/xorshift32/README.md new file mode 100644 index 000000000000..334e83ec6769 --- /dev/null +++ b/lib/node_modules/@stdlib/random/base/xorshift32/README.md @@ -0,0 +1,282 @@ + + +# Xorshift32 + +> A 32-bit [xorshift32][xorshift32] pseudorandom number generator. + +
+ +## Usage + +```javascript +var xorshift32 = require( '@stdlib/random/base/xorshift32' ); +``` + +#### xorshift32() + +Returns a pseudorandom unsigned 32-bit integer on the interval `[0, 4294967295]` + +```javascript +var r = xorshift32(); +// returns +``` + +#### xorshift32.normalized() + +Returns a pseudorandom number on the interval [0, 1) with 53-bit precision. + +```javascript +var r = xorshift32.normalized(); +// returns +``` + +#### xorshift32.factory( \[options] ) + +Returns a 32-bit [xorshift32][xorshift32] pseudorandom number generator. + +```javascript +var rand = xorshift32.factory(); +``` + +The function accepts the following options: + +- **seed**: pseudorandom number generator seed. Must be an integer on the interval `[1, 4294967295]`. If a seed is not provided, one is automatically generated. +- **state**: a `Uint32Array` containing pseudorandom number generator state. If provided, the `seed` option is ignored. +- **copy**: `boolean` indicating whether to copy a provided pseudorandom number generator state. Setting this option to `false` allows sharing state between two or more pseudorandom number generators. Setting this option to `true` ensures that a returned generator has exclusive control over its internal state. Default: `true` . + +To seed the generator, provide a nonzero integer on the interval `[1, 4294967295]`: + +```javascript +var rand = xorshift32.factory({ + 'seed': 1234 +}); + +var r = rand(); +// returns +``` + +To use a custom generator state, provide a `Uint32Array`: + +```javascript +var rand1 = xorshift32.factory(); +var state = rand1.state; + +var rand2 = xorshift32.factory({ + 'state': state, + 'copy': false +}); + +var r = rand2(); +// returns +``` + +#### xorshift32.NAME + +The generator name. + +```javascript +var str = xorshift32.NAME; +// returns 'xorshift32' +``` + +#### xorshift32.MIN + +Minimum possible value. + +```javascript +var min = xorshift32.MIN; +// returns 1 +``` + +#### xorshift32.MAX + +Maximum possible value. + +```javascript +var max = xorshift32.MAX; +// returns 4294967295 +``` + +#### xorshift32.seed + +The value used to seed `xorshift32()`. + +```javascript +// Generate pseudorandom values... +var r; +var i; +for ( i = 0; i < 100; i++ ) { + r = xorshift32(); +} + +// Generate the same pseudorandom values... +var rand = xorshift32.factory({ + 'seed': xorshift32.seed[ 0 ] +}); +for ( i = 0; i < 100; i++ ) { + r = rand(); +} +``` + +#### xorshift32.seedLength + +Length of generator seed. + +```javascript +var len = xorshift32.seedLength; +// returns 1 +``` + +#### xorshift32.state + +The current pseudorandom number generator state. + +```javascript +var state = xorshift32.state; +// returns +``` + +#### xorshift32.stateLength + +Length of generator state. + +```javascript +var len = xorshift32.stateLength; +// returns 6 +``` + +#### xorshift32.byteLength + +Size of generator state in bytes. + +```javascript +var nbytes = xorshift32.byteLength; +// returns 24 +``` + +#### xorshift32.toJSON() + +Serializes the pseudorandom number generator as a JSON object. + +```javascript +var o = xorshift32.toJSON(); +// returns { 'type': 'PRNG', 'name': '...', 'state': {...}, 'params': [] } +``` + +
+ + + +
+ +## Notes + +- [Xorshift32][xorshift32] is **not** cryptographically secure. Do not use it for cryptographic operations. +- The generator uses a single 32-bit internal state, making it extremely lightweight and fast. +- While the generator is very efficient, its statistical quality is lower than generators like Mersenne Twister. It is suitable for simulations and statistical applications, but not for security-sensitive use cases. +- The period of Xorshift32 is approximately 2^32 - 1. +- The generator state can be explicitly accessed and saved for reproducibility. + +
+ + + +
+ +## Examples + + + +```javascript +var xorshift32 = require( '@stdlib/random/base/xorshift32' ); + +// Generate pseudorandom numbers... +var i; +for ( i = 0; i < 100; i++ ) { + console.log( xorshift32() ); +} + +// Create a new pseudorandom number generator... +var seed = 1234; +var rand = xorshift32.factory({ + 'seed': seed +}); +for ( i = 0; i < 100; i++ ) { + console.log( rand() ); +} + +// Create another pseudorandom number generator using a previous seed... +rand = xorshift32.factory({ + 'seed': xorshift32.seed[ 0 ] +}); +for ( i = 0; i < 100; i++ ) { + console.log( rand() ); +} +``` + +
+ + + +* * * + +
+ +## References + +- George Marsaglia. 2003. "Xorshift RNGs." **Journal of Statistical Software**, 8(14). + +
+ + + + + + + + + + + + + + diff --git a/lib/node_modules/@stdlib/random/base/xorshift32/benchmark/benchmark.factory.js b/lib/node_modules/@stdlib/random/base/xorshift32/benchmark/benchmark.factory.js new file mode 100644 index 000000000000..71f7e0b3cc28 --- /dev/null +++ b/lib/node_modules/@stdlib/random/base/xorshift32/benchmark/benchmark.factory.js @@ -0,0 +1,168 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2026 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +// MODULES // + +var bench = require( '@stdlib/bench' ); +var isnan = require( '@stdlib/math/base/assert/is-nan' ); +var Uint32Array = require( '@stdlib/array/uint32' ); +var pkg = require( './../package.json' ).name; +var factory = require( './../lib' ).factory; + + +// MAIN // + +bench( pkg+':factory', function benchmark( b ) { + var f; + var i; + + b.tic(); + for ( i = 0; i < b.iterations; i++ ) { + f = factory(); + if ( typeof f !== 'function' ) { + b.fail( 'should return a function' ); + } + } + b.toc(); + if ( isnan( f() ) ) { + b.fail( 'should not return NaN' ); + } + b.pass( 'benchmark finished' ); + b.end(); +}); + +bench( pkg+':factory:seed=', function benchmark( b ) { + var opts; + var f; + var i; + + opts = { + 'seed': 1 + }; + b.tic(); + for ( i = 0; i < b.iterations; i++ ) { + opts.seed = i + 1; + f = factory( opts ); + if ( typeof f !== 'function' ) { + b.fail( 'should return a function' ); + } + } + b.toc(); + if ( isnan( f() ) ) { + b.fail( 'should not return NaN' ); + } + b.pass( 'benchmark finished' ); + b.end(); +}); + +bench( pkg+':factory:seed=', function benchmark( b ) { + var seed; + var opts; + var f; + var i; + + opts = {}; + seed = new Uint32Array( 10 ); + for ( i = 0; i < seed.length; i++ ) { + seed[ i ] = 123 + i; + } + opts.seed = seed; + b.tic(); + for ( i = 0; i < b.iterations; i++ ) { + opts.seed[ 0 ] = i + 1; + f = factory( opts ); + if ( typeof f !== 'function' ) { + b.fail( 'should return a function' ); + } + } + b.toc(); + if ( isnan( f() ) ) { + b.fail( 'should not return NaN' ); + } + b.pass( 'benchmark finished' ); + b.end(); +}); + +bench( pkg+':factory:state=', function benchmark( b ) { + var xorshift32; + var state; + var opts; + var f; + var i; + + xorshift32 = factory(); + + // Move to a future state... + for ( i = 0; i < 100; i++ ) { + xorshift32(); + } + state = xorshift32.state; + opts = { + 'state': state + }; + + b.tic(); + for ( i = 0; i < b.iterations; i++ ) { + f = factory( opts ); + if ( typeof f !== 'function' ) { + b.fail( 'should return a function' ); + } + } + b.toc(); + if ( isnan( f() ) ) { + b.fail( 'should not return NaN' ); + } + b.pass( 'benchmark finished' ); + b.end(); +}); + +bench( pkg+':factory:state=,copy=false', function benchmark( b ) { + var xorshift32; + var state; + var opts; + var f; + var i; + + xorshift32 = factory(); + + // Move to a future state... + for ( i = 0; i < 100; i++ ) { + xorshift32(); + } + state = xorshift32.state; + opts = { + 'state': state, + 'copy': false + }; + + b.tic(); + for ( i = 0; i < b.iterations; i++ ) { + f = factory( opts ); + if ( typeof f !== 'function' ) { + b.fail( 'should return a function' ); + } + } + b.toc(); + if ( isnan( f() ) ) { + b.fail( 'should not return NaN' ); + } + b.pass( 'benchmark finished' ); + b.end(); +}); diff --git a/lib/node_modules/@stdlib/random/base/xorshift32/benchmark/benchmark.js b/lib/node_modules/@stdlib/random/base/xorshift32/benchmark/benchmark.js new file mode 100644 index 000000000000..b87e6f407a5c --- /dev/null +++ b/lib/node_modules/@stdlib/random/base/xorshift32/benchmark/benchmark.js @@ -0,0 +1,202 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2026 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +// MODULES // + +var bench = require( '@stdlib/bench' ); +var isnan = require( '@stdlib/math/base/assert/is-nan' ); +var Uint32Array = require( '@stdlib/array/uint32' ); +var pkg = require( './../package.json' ).name; +var factory = require( './../lib' ).factory; +var xorshift32 = require( './../lib' ); + + +// MAIN // + +bench( pkg+':factory', function benchmark( b ) { + var f; + var i; + + b.tic(); + for ( i = 0; i < b.iterations; i++ ) { + f = factory(); + if ( typeof f !== 'function' ) { + b.fail( 'should return a function' ); + } + } + b.toc(); + if ( isnan( f() ) ) { + b.fail( 'should not return NaN' ); + } + b.pass( 'benchmark finished' ); + b.end(); +}); + +bench( pkg+':factory:seed=', function benchmark( b ) { + var opts; + var f; + var i; + + opts = { + 'seed': 1 + }; + b.tic(); + for ( i = 0; i < b.iterations; i++ ) { + opts.seed = i + 1; + f = factory( opts ); + if ( typeof f !== 'function' ) { + b.fail( 'should return a function' ); + } + } + b.toc(); + if ( isnan( f() ) ) { + b.fail( 'should not return NaN' ); + } + b.pass( 'benchmark finished' ); + b.end(); +}); + +bench( pkg+':factory:seed=', function benchmark( b ) { + var seed; + var opts; + var f; + var i; + + opts = {}; + seed = new Uint32Array( 10 ); + for ( i = 0; i < seed.length; i++ ) { + seed[ i ] = 123 + i; + } + opts.seed = seed; + b.tic(); + for ( i = 0; i < b.iterations; i++ ) { + opts.seed[ 0 ] = i + 1; + f = factory( opts ); + if ( typeof f !== 'function' ) { + b.fail( 'should return a function' ); + } + } + b.toc(); + if ( isnan( f() ) ) { + b.fail( 'should not return NaN' ); + } + b.pass( 'benchmark finished' ); + b.end(); +}); + +bench( pkg, function benchmark( b ) { + var v; + var i; + + b.tic(); + for ( i = 0; i < b.iterations; i++ ) { + v = xorshift32(); + if ( v !== v ) { + b.fail( 'should not return NaN' ); + } + } + b.toc(); + if ( isnan( v ) ) { + b.fail( 'should not return NaN' ); + } + b.pass( 'benchmark finished' ); + b.end(); +}); + +bench( pkg+':normalized', function benchmark( b ) { + var v; + var i; + + b.tic(); + for ( i = 0; i < b.iterations; i++ ) { + v = xorshift32.normalized(); + if ( v !== v ) { + b.fail( 'should not return NaN' ); + } + } + b.toc(); + if ( isnan( v ) ) { + b.fail( 'should not return NaN' ); + } + b.pass( 'benchmark finished' ); + b.end(); +}); + +bench( pkg+':state', function benchmark( b ) { + var xorshift32a; + var state; + var i; + + xorshift32a = factory(); + + // Move to a future state... + for ( i = 0; i < 100; i++ ) { + xorshift32a(); + } + state = xorshift32a.state; + + b.tic(); + for ( i = 0; i < b.iterations; i++ ) { + xorshift32a.state = state; + if ( typeof xorshift32a.state !== 'object' ) { + b.fail( 'should return an object' ); + } + } + b.toc(); + if ( isnan( xorshift32a() ) ) { + b.fail( 'should not return NaN' ); + } + b.pass( 'benchmark finished' ); + b.end(); +}); + +bench( pkg+':factory:state=', function benchmark( b ) { + var xorshift32a; + var state; + var opts; + var f; + var i; + + xorshift32a = factory(); + + // Move to a future state... + for ( i = 0; i < 100; i++ ) { + xorshift32a(); + } + state = xorshift32a.state; + opts = { + 'state': state, + 'copy': false + }; + + b.tic(); + for ( i = 0; i < b.iterations; i++ ) { + f = factory( opts ); + if ( typeof f !== 'function' ) { + b.fail( 'should return a function' ); + } + } + b.toc(); + if ( isnan( f() ) ) { + b.fail( 'should not return NaN' ); + } + b.pass( 'benchmark finished' ); + b.end(); +}); diff --git a/lib/node_modules/@stdlib/random/base/xorshift32/benchmark/benchmark.json.js b/lib/node_modules/@stdlib/random/base/xorshift32/benchmark/benchmark.json.js new file mode 100644 index 000000000000..3d8d135ddcdf --- /dev/null +++ b/lib/node_modules/@stdlib/random/base/xorshift32/benchmark/benchmark.json.js @@ -0,0 +1,67 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2026 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +// MODULES // + +var bench = require( '@stdlib/bench' ); +var isObject = require( '@stdlib/assert/is-plain-object' ); +var pkg = require( './../package.json' ).name; +var xorshift32 = require( './../lib' ); + + +// MAIN // + +bench( pkg+':toJSON', function benchmark( b ) { + var o; + var i; + + b.tic(); + for ( i = 0; i < b.iterations; i++ ) { + o = xorshift32.toJSON(); + if ( typeof o !== 'object' ) { + b.fail( 'should return an object' ); + } + } + b.toc(); + if ( !isObject( o ) ) { + b.fail( 'should return a plain object' ); + } + b.pass( 'benchmark finished' ); + b.end(); +}); + +bench( pkg+':toJSON:normalized', function benchmark( b ) { + var o; + var i; + + b.tic(); + for ( i = 0; i < b.iterations; i++ ) { + o = xorshift32.normalized.toJSON(); + if ( typeof o !== 'object' ) { + b.fail( 'should return an object' ); + } + } + b.toc(); + if ( !isObject( o ) ) { + b.fail( 'should return a plain object' ); + } + b.pass( 'benchmark finished' ); + b.end(); +}); diff --git a/lib/node_modules/@stdlib/random/base/xorshift32/docs/repl.txt b/lib/node_modules/@stdlib/random/base/xorshift32/docs/repl.txt new file mode 100644 index 000000000000..7f29946782bb --- /dev/null +++ b/lib/node_modules/@stdlib/random/base/xorshift32/docs/repl.txt @@ -0,0 +1,186 @@ + +{{alias}}() + Returns a pseudorandom integer on the interval `[0, 4294967295]`. + + This pseudorandom number generator (PRNG) is a 32-bit XORShift + pseudorandom number generator. + + The PRNG is not a cryptographically secure PRNG. + + The PRNG has a period of approximately 2^32 - 1. + + Returns + ------- + r: integer + Pseudorandom number. + + Examples + -------- + > var r = {{alias}}() + + + +{{alias}}.normalized() + Returns a pseudorandom number on the interval `[0,1)` with 53-bit precision. + + Returns + ------- + r: number + Pseudorandom number. + + Examples + -------- + > var r = {{alias}}.normalized() + + + +{{alias}}.factory( [options] ) + Returns a 32-bit XORShift pseudorandom number generator. + + Parameters + ---------- + options: Object (optional) + Options. + + options.seed: integer (optional) + Pseudorandom number generator seed. Must be an integer on the interval + [1, 4294967295]. If not provided, a seed is automatically generated. + options.state: Uint32Array (optional) + Pseudorandom number generator state. If provided, the seed option is + ignored. + options.copy: boolean (optional) + Boolean indicating whether to copy a provided pseudorandom number + generator state. Setting this option to false allows sharing state + between two or more pseudorandom number generators. Setting this option + to true ensures that a returned generator has exclusive control over + its internal state. Default: true. + + Returns + ------- + rand: Function + Pseudorandom number generator (PRNG). + + Examples + -------- + // Basic usage: + > var rand = {{alias}}.factory(); + > r = rand() + + > r = rand() + + + + // Provide a seed: + > rand = {{alias}}.factory( { 'seed': 1234 } ); + > r = rand() + + + +{{alias}}.NAME + Generator name. + + Examples + -------- + > var str = {{alias}}.NAME + 'xorshift32' + + +{{alias}}.MIN + Minimum possible value. + + Examples + -------- + > var v = {{alias}}.MIN + 1 + + +{{alias}}.MAX + Maximum possible value. + + Examples + -------- + > var v = {{alias}}.MAX + 4294967295 + + +{{alias}}.seed + Pseudorandom number generator seed. + + Examples + -------- + > var seed = {{alias}}.seed; + + +{{alias}}.seedLength + Length of generator seed. + + Examples + -------- + > var len = {{alias}}.seedLength + 1 + + +{{alias}}.state + Generator state. + + Examples + -------- + > var r = {{alias}}() + + > r = {{alias}}() + + > r = {{alias}}() + + + // Get a copy of the current state: + > var state = {{alias}}.state + + + > r = {{alias}}() + + > r = {{alias}}() + + + // Set the state: + > {{alias}}.state = state; + + // Replay the last two pseudorandom numbers: + > r = {{alias}}() + + > r = {{alias}}() + + + +{{alias}}.stateLength + Length of generator state. + + Examples + -------- + > var len = {{alias}}.stateLength + 6 + + +{{alias}}.byteLength + Size (in bytes) of generator state. + + Examples + -------- + > var sz = {{alias}}.byteLength + 24 + + +{{alias}}.toJSON() + Serializes the pseudorandom number generator as a JSON object. + + Returns + ------- + out: Object + JSON representation. + + Examples + -------- + > var o = {{alias}}.toJSON() + { 'type': 'PRNG', 'name': '...', 'state': {...}, 'params': [] } + + See Also + -------- diff --git a/lib/node_modules/@stdlib/random/base/xorshift32/docs/types/index.d.ts b/lib/node_modules/@stdlib/random/base/xorshift32/docs/types/index.d.ts new file mode 100644 index 000000000000..bacf03a8d8b9 --- /dev/null +++ b/lib/node_modules/@stdlib/random/base/xorshift32/docs/types/index.d.ts @@ -0,0 +1,205 @@ +/* +* @license Apache-2.0 +* +* Copyright (c) 2026 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +// TypeScript Version: 4.1 + +/// + +import * as random from '@stdlib/types/random'; + +/** +* Interface defining `factory` options. +*/ +interface Options { + /** + * Pseudorandom number generator seed. + */ + seed?: random.PRNGSeedXorshift32; + + /** + * Pseudorandom number generator state. + */ + state?: random.PRNGStateXorshift32; + + /** + * Specifies whether to copy a provided pseudorandom number generator state. + */ + copy?: boolean; +} + +/** +* Interface for PRNG properties and methods. +*/ +interface PRNG { + /** + * Generator name. + */ + readonly NAME: string; + + /** + * Minimum possible value. + */ + readonly MIN: number; + + /** + * Maximum possible value. + */ + readonly MAX: number; + + /** + * PRNG seed. + */ + readonly seed: random.PRNGSeedXorshift32; + + /** + * PRNG seed length. + */ + readonly seedLength: number; + + /** + * PRNG state. + */ + state: random.PRNGStateXorshift32; + + /** + * PRNG state length. + */ + readonly stateLength: number; + + /** + * PRNG state size (in bytes). + */ + readonly byteLength: number; + + /** + * Serializes the pseudorandom number generator as a JSON object. + * + * @returns JSON representation + */ + toJSON(): string; +} + +/** +* Interface for generating pseudorandom integers on the interval `[0, 4294967295]`. +*/ +interface NullaryFunction extends PRNG { + /** + * Returns a pseudorandom integer on the interval `[0, 4294967295]`. + * + * @returns pseudorandom number + */ + (): number; + + /** + * Returns a pseudorandom number on the interval `[0, 1)` with 53-bit precision. + * + * @returns pseudorandom number + */ + normalized(): number; +} + +/** +* Interface for generating pseudorandom integers on the interval `[0, 4294967295]`. +*/ +interface Random extends PRNG { + /** + * Returns a pseudorandom integer on the interval `[0, 4294967295]`. + * + * ## Notes + * + * - This pseudorandom number generator (PRNG) is a 32-bit XORShift pseudorandom number generator. + * - The PRNG is *not* a cryptographically secure PRNG. + * - The PRNG has a period of approximately 2^32 - 1. + * + * @returns pseudorandom number + * + * @example + * var v = xorshift32(); + * // returns + */ + (): number; + + /** + * Returns a pseudorandom number on the interval `[0, 1)` with 53-bit precision. + * + * ## Notes + * + * - This pseudorandom number generator (PRNG) is a 32-bit XORShift pseudorandom number generator. + * - The PRNG is *not* a cryptographically secure PRNG. + * + * @returns pseudorandom number + * + * @example + * var v = xorshift32.normalized(); + * // returns + */ + normalized(): number; + + /** + * Returns a 32-bit XORShift pseudorandom number generator. + * + * @param options - function options + * @param options.seed - pseudorandom number generator seed + * @param options.state - pseudorandom number generator state + * @param options.copy - boolean indicating whether to copy a provided pseudorandom number generator state (default: true) + * @throws must provide valid options + * @returns pseudorandom number generator + * + * @example + * var rand = xorshift32.factory(); + * var v = rand(); + * // returns + * + * @example + * var rand = xorshift32.factory({ + * 'seed': 12345 + * }); + * var v = rand(); + * // returns + */ + factory( options?: Options ): NullaryFunction; +} + +/** +* Returns a pseudorandom integer on the interval `[0, 4294967295]`. +* +* ## Notes +* +* - This pseudorandom number generator (PRNG) is a 32-bit XORShift pseudorandom number generator. +* - The PRNG is *not* a cryptographically secure PRNG. +* - The PRNG has a period of approximately 2^32 - 1. +* +* @returns pseudorandom number +* +* @example +* var v = xorshift32(); +* // returns +* +* @example +* var rand = xorshift32.factory({ +* 'seed': 12345 +* }); +* var v = rand(); +* // returns +*/ +declare var xorshift32: Random; + + +// EXPORTS // + +export = xorshift32; diff --git a/lib/node_modules/@stdlib/random/base/xorshift32/docs/types/test.ts b/lib/node_modules/@stdlib/random/base/xorshift32/docs/types/test.ts new file mode 100644 index 000000000000..baf58ea5e8ca --- /dev/null +++ b/lib/node_modules/@stdlib/random/base/xorshift32/docs/types/test.ts @@ -0,0 +1,143 @@ +/* +* @license Apache-2.0 +* +* Copyright (c) 2026 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +import xorshift32 = require( './index' ); + + +// TESTS // + +// The function returns a number... +{ + xorshift32(); // $ExpectType number +} + +// The compiler throws an error if the function is provided any arguments... +{ + xorshift32( true ); // $ExpectError + xorshift32( 2, 3 ); // $ExpectError +} + +// The function has a normalized method which returns a number... +{ + xorshift32.normalized(); // $ExpectType number +} + +// The compiler throws an error if the normalized method is provided any arguments... +{ + xorshift32.normalized( 1 ); // $ExpectError + xorshift32.normalized( 1, 2 ); // $ExpectError +} + +// Attached to main export is a `factory` method which returns a function... +{ + xorshift32.factory(); // $ExpectType NullaryFunction + xorshift32.factory( { 'copy': false } ); // $ExpectType NullaryFunction +} + +// The `factory` method returns a function which returns a number... +{ + const fcn = xorshift32.factory(); + fcn(); // $ExpectType number +} + +// The returned function has a normalized method... +{ + const fcn = xorshift32.factory(); + fcn.normalized(); // $ExpectType number +} + +// The compiler throws an error if the function returned by the `factory` method is provided any number of arguments... +{ + const fcn = xorshift32.factory(); + fcn( 1 ); // $ExpectError + fcn( 2, 1 ); // $ExpectError + fcn( 2, 1, 1 ); // $ExpectError +} + +// The compiler throws an error if the normalized method is provided any arguments... +{ + const fcn = xorshift32.factory(); + fcn.normalized( 1 ); // $ExpectError + fcn.normalized( 1, 2 ); // $ExpectError +} + +// The compiler throws an error if the `factory` method is provided an options argument which is not an object... +{ + xorshift32.factory( null ); // $ExpectError +} + +// The compiler throws an error if the `factory` method is provided a `seed` option which is not a valid seed... +{ + xorshift32.factory( { 'seed': true } ); // $ExpectError + xorshift32.factory( { 'seed': 'abc' } ); // $ExpectError + xorshift32.factory( { 'seed': null } ); // $ExpectError + xorshift32.factory( { 'seed': [ 'a' ] } ); // $ExpectError + xorshift32.factory( { 'seed': {} } ); // $ExpectError + xorshift32.factory( { 'seed': ( x: number ): number => x } ); // $ExpectError +} + +// The compiler throws an error if the `factory` method is provided a `state` option which is not a valid state... +{ + xorshift32.factory( { 'state': 123 } ); // $ExpectError + xorshift32.factory( { 'state': 'abc' } ); // $ExpectError + xorshift32.factory( { 'state': null } ); // $ExpectError + xorshift32.factory( { 'state': [] } ); // $ExpectError + xorshift32.factory( { 'state': {} } ); // $ExpectError + xorshift32.factory( { 'state': true } ); // $ExpectError + xorshift32.factory( { 'state': ( x: number ): number => x } ); // $ExpectError +} + +// The compiler throws an error if the `factory` method is provided a `copy` option which is not a boolean... +{ + xorshift32.factory( { 'copy': 123 } ); // $ExpectError + xorshift32.factory( { 'copy': 'abc' } ); // $ExpectError + xorshift32.factory( { 'copy': null } ); // $ExpectError + xorshift32.factory( { 'copy': [] } ); // $ExpectError + xorshift32.factory( { 'copy': {} } ); // $ExpectError + xorshift32.factory( { 'copy': ( x: number ): number => x } ); // $ExpectError +} + +// The compiler throws an error if the `factory` method is provided more than one argument... +{ + xorshift32.factory( {}, 2 ); // $ExpectError +} + +// Test state property... +{ + const fcn = xorshift32.factory(); + const state = fcn.state; // $ExpectType Uint32Array + fcn.state = state; // Valid assignment +} + +// Test readonly properties... +{ + const fcn = xorshift32.factory(); + fcn.NAME; // $ExpectType string + fcn.MIN; // $ExpectType number + fcn.MAX; // $ExpectType number + fcn.seed; // $ExpectType Uint32Array + fcn.seedLength; // $ExpectType number + fcn.stateLength; // $ExpectType number + fcn.byteLength; // $ExpectType number +} + +// Test toJSON method... +{ + const fcn = xorshift32.factory(); + fcn.toJSON(); // $ExpectType string +} diff --git a/lib/node_modules/@stdlib/random/base/xorshift32/examples/example-normalized.js b/lib/node_modules/@stdlib/random/base/xorshift32/examples/example-normalized.js new file mode 100644 index 000000000000..fcb98360673a --- /dev/null +++ b/lib/node_modules/@stdlib/random/base/xorshift32/examples/example-normalized.js @@ -0,0 +1,52 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2026 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +var xorshift32 = require( './../lib' ); + +// Generate normalized pseudorandom numbers in [0, 1)... +console.log( '\nUsing default instance (normalized):' ); +var i; +for ( i = 0; i < 10; i++ ) { + console.log( xorshift32.normalized() ); +} + +// Create a new PRNG and use the normalized method... +var seed = 5678; +var rand = xorshift32.factory({ + 'seed': seed +}); + +console.log( '\nUsing factory instance with seed %d (normalized):', seed ); +for ( i = 0; i < 10; i++ ) { + console.log( rand.normalized() ); +} + +// Compare raw vs normalized output... +console.log( '\nComparing raw vs normalized (first 5 values):' ); +var rng1 = xorshift32.factory({ + 'seed': 999 +}); +var rng2 = xorshift32.factory({ + 'seed': 999 +}); + +for ( i = 0; i < 5; i++ ) { + console.log( 'Raw: %d, Normalized: %f', rng1(), rng2.normalized() ); +} diff --git a/lib/node_modules/@stdlib/random/base/xorshift32/examples/example-state.js b/lib/node_modules/@stdlib/random/base/xorshift32/examples/example-state.js new file mode 100644 index 000000000000..2a63bd45c5d6 --- /dev/null +++ b/lib/node_modules/@stdlib/random/base/xorshift32/examples/example-state.js @@ -0,0 +1,78 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2026 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +var xorshift32 = require( './../lib' ); + +// Create a PRNG and capture its state... +var seed = 3141; +var rng = xorshift32.factory({ + 'seed': seed +}); + +console.log( '\nInitial state:' ); +console.log( rng.state ); + +// Generate some random numbers... +console.log( '\nGenerating 5 random numbers:' ); +var i; +for ( i = 0; i < 5; i++ ) { + console.log( rng() ); +} + +// Capture the state at this point... +var state = rng.state; +console.log( '\nState after 5 generations:' ); +console.log( state ); + +// Generate more numbers... +console.log( '\nGenerating 5 more random numbers:' ); +var sequence1 = []; +for ( i = 0; i < 5; i++ ) { + sequence1.push( rng() ); + console.log( sequence1[ i ] ); +} + +// Restore the state and regenerate the same sequence... +rng.state = state; +console.log( '\nRestored state and regenerating sequence:' ); +var sequence2 = []; +for ( i = 0; i < 5; i++ ) { + sequence2.push( rng() ); + console.log( sequence2[ i ] ); +} + +// Verify sequences match... +console.log( '\nSequences match:', JSON.stringify( sequence1 ) === JSON.stringify( sequence2 ) ); + +// Demonstrate state with different options... +console.log( '\n\nUsing factory with state copy:' ); +var state1 = xorshift32.state; +var rng1 = xorshift32.factory({ + 'state': state1, + 'copy': true // Creates independent copy of state +}); +var rng2 = xorshift32.factory({ + 'state': state1, + 'copy': false // Shares state reference +}); + +console.log( '\nrng1 (copy=true):', rng1() ); +console.log( 'rng2 (copy=false):', rng2() ); +console.log( 'Are they the same value?', rng1() === rng2() ); diff --git a/lib/node_modules/@stdlib/random/base/xorshift32/examples/index.js b/lib/node_modules/@stdlib/random/base/xorshift32/examples/index.js new file mode 100644 index 000000000000..41aea01ee36d --- /dev/null +++ b/lib/node_modules/@stdlib/random/base/xorshift32/examples/index.js @@ -0,0 +1,48 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2026 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +var xorshift32 = require( './../lib' ); + +// Generate pseudorandom numbers... +console.log( '\nDefault instance:' ); +console.log( '\nseed: %d', xorshift32.seed[ 0 ] ); +var i; +for ( i = 0; i < 100; i++ ) { + console.log( xorshift32() ); +} + +// Create a new pseudorandom number generator... +var seed = 1234; +var rand = xorshift32.factory({ + 'seed': seed +}); +console.log( '\nseed: %d', seed ); +for ( i = 0; i < 100; i++ ) { + console.log( rand() ); +} + +// Create another pseudorandom number generator using a previous seed... +rand = xorshift32.factory({ + 'seed': xorshift32.seed[ 0 ] +}); +console.log( '\nseed: %d', rand.seed[ 0 ] ); +for ( i = 0; i < 100; i++ ) { + console.log( rand() ); +} diff --git a/lib/node_modules/@stdlib/random/base/xorshift32/lib/factory.js b/lib/node_modules/@stdlib/random/base/xorshift32/lib/factory.js new file mode 100644 index 000000000000..7bdc6ed5a929 --- /dev/null +++ b/lib/node_modules/@stdlib/random/base/xorshift32/lib/factory.js @@ -0,0 +1,433 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2026 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +/* eslint-disable max-len */ + +'use strict'; + +// MODULES // + +var setReadOnly = require( '@stdlib/utils/define-nonenumerable-read-only-property' ); +var setReadOnlyAccessor = require( '@stdlib/utils/define-nonenumerable-read-only-accessor' ); +var setReadWriteAccessor = require( '@stdlib/utils/define-nonenumerable-read-write-accessor' ); +var hasOwnProp = require( '@stdlib/assert/has-own-property' ); +var isObject = require( '@stdlib/assert/is-plain-object' ); +var isBoolean = require( '@stdlib/assert/is-boolean' ).isPrimitive; +var isCollection = require( '@stdlib/assert/is-collection' ); +var isNonNegativeInteger = require( '@stdlib/assert/is-nonnegative-integer' ).isPrimitive; +var isUint32Array = require( '@stdlib/assert/is-uint32array' ); +var format = require( '@stdlib/string/format' ); +var UINT32_MAX = require( '@stdlib/constants/uint32/max' ); +var Uint32Array = require( '@stdlib/array/uint32' ); +var gcopy = require( '@stdlib/blas/base/gcopy' ); +var typedarray2json = require( '@stdlib/array/to-json' ); +var randuint32 = require( './rand_uint32.js' ); + + +// VARIABLES // + +var NORMALIZATION_CONSTANT = UINT32_MAX; // 2^32 - 1 +var MAX_SEED = UINT32_MAX; // maximum valid seed value + +// Define the state array schema version: +var STATE_ARRAY_VERSION = 1; // NOTE: anytime the state array schema changes, this value should be incremented!!! + +// Define the number of sections in the state array: +var NUM_STATE_SECTIONS = 2; // state, seed + +// Define the index offset of the "state" section in the state array: +var STATE_SECTION_OFFSET = 2; // | version | num_sections | state_length | ...state | seed_length | ...seed | + +// Define the index offset of the seed section in the state array: +var SEED_SECTION_OFFSET = 4; // | version | num_sections | state_length | ...state | seed_length | ...seed | + +// Define the length of the "fixed" length portion of the state array: +var STATE_FIXED_LENGTH = 5; // 1 (version) + 1 (num_sections) + 1 (state_length) + 1 (state) + 1 (seed_length) + + +// FUNCTIONS // + +/** +* Verifies state array integrity. +* +* @private +* @param {Uint32Array} state - state array +* @param {boolean} FLG - flag indicating whether the state array was provided as an option (true) or an argument (false) +* @returns {(Error|null)} an error or `null` +*/ +function verifyState(state, FLG) { + var s1; + if (FLG) { + s1 = 'option'; + } else { + s1 = 'argument'; + } + // The state array must have a minimum length... + if (state.length < STATE_FIXED_LENGTH + 1) { + return new RangeError(format('invalid %s. State array has insufficient length.', s1)); + } + // The first element of the state array must equal the supported state array schema version... + if (state[0] !== STATE_ARRAY_VERSION) { + return new RangeError(format('invalid %s. State array has an incompatible schema version. Expected: `%s`. Actual: `%s`.', s1, STATE_ARRAY_VERSION, state[0])); + } + // The second element of the state array must contain the number of sections... + if (state[1] !== NUM_STATE_SECTIONS) { + return new RangeError(format('invalid %s. State array has an incompatible number of sections. Expected: `%s`. Actual: `%s`.', s1, NUM_STATE_SECTIONS, state[1])); + } + // The length of the "state" section must equal `1`... + if (state[STATE_SECTION_OFFSET] !== 1) { + return new RangeError(format('invalid %s. State array has an incompatible state length. Expected: `%u`. Actual: `%u`.', s1, 1, state[STATE_SECTION_OFFSET])); + } + // The length of the "seed" section must match the empirical length... + if (state[SEED_SECTION_OFFSET] !== state.length - STATE_FIXED_LENGTH) { + return new RangeError(format('invalid %s. State array length is incompatible with seed section length. Expected: `%u`. Actual: `%u`.', s1, state.length - STATE_FIXED_LENGTH, state[SEED_SECTION_OFFSET])); + } + return null; +} + + +// MAIN // + +/** +* Returns a xorshift32 pseudorandom number generator. +* +* @param {Options} [options] - options +* @param {PRNGSeedXorshift32} [options.seed] - pseudorandom number generator seed +* @param {PRNGStateXorshift32} [options.state] - pseudorandom number generator state +* @param {boolean} [options.copy=true] - boolean indicating whether to copy a provided pseudorandom number generator state +* @throws {TypeError} options argument must be an object +* @throws {TypeError} a seed must be either a non-negative integer less than or equal to the maximum unsigned 32-bit integer or an array-like object containing such integers +* @throws {RangeError} a numeric seed must be a non-negative integer less than or equal to the maximum unsigned 32-bit integer +* @throws {TypeError} state must be a `Uint32Array` +* @throws {Error} must provide a valid state +* @throws {TypeError} `copy` option must be a boolean +* @returns {PRNG} xorshift32 PRNG +* +* @example +* var xorshift32 = factory(); +* +* var v = xorshift32(); +* // returns +* +* @example +* // Return a seeded xorshift32 PRNG: +* var xorshift32 = factory({ +* 'seed': 1234 +* }); +* +* var v = xorshift32(); +* // returns +*/ +function factory(options) { + var STATE; + var state; + var opts; + var seed; + var slen; + var err; + + opts = {}; + if (arguments.length) { + if (!isObject(options)) { + throw new TypeError(format('invalid argument. Options argument must be an object. Value: `%s`.', options)); + } + if (hasOwnProp(options, 'copy')) { + opts.copy = options.copy; + if (!isBoolean(options.copy)) { + throw new TypeError(format('invalid option. `%s` option must be a boolean. Option: `%s`.', 'copy', options.copy)); + } + } + if (hasOwnProp(options, 'state')) { + state = options.state; + opts.state = true; + if (!isUint32Array(state)) { + throw new TypeError(format('invalid option. `%s` option must be a Uint32Array. Option: `%s`.', 'state', state)); + } + err = verifyState(state, true); + if (err) { + throw err; + } + if (opts.copy === false) { + STATE = state; + } else { + STATE = new Uint32Array(state.length); + gcopy(state.length, state, 1, STATE, 1); + } + // Create a state "view": + state = new Uint32Array(STATE.buffer, STATE.byteOffset + ((STATE_SECTION_OFFSET + 1) * STATE.BYTES_PER_ELEMENT), 1); + + // Create a seed "view": + seed = new Uint32Array(STATE.buffer, STATE.byteOffset + ((SEED_SECTION_OFFSET + 1) * STATE.BYTES_PER_ELEMENT), STATE[SEED_SECTION_OFFSET]); + } + // If provided a PRNG state, we ignore the `seed` option... + if (seed === void 0) { + if (hasOwnProp(options, 'seed')) { + seed = options.seed; + opts.seed = true; + if (typeof seed === 'number') { + if (!isNonNegativeInteger(seed) || seed > MAX_SEED) { + throw new RangeError(format('invalid option. `%s` option must be a non-negative integer less than or equal to the maximum unsigned 32-bit integer. Option: `%s`.', 'seed', seed)); + } + + seed >>>= 0; + + // Zero fix + if (seed === 0) { + seed = 1 >>> 0; + } + + // ✅ Case 2: array-like + } else if (isCollection(seed) && seed.length > 0) { + slen = seed.length; + STATE = new Uint32Array(STATE_FIXED_LENGTH + slen); + + STATE[0] = STATE_ARRAY_VERSION; + STATE[1] = NUM_STATE_SECTIONS; + STATE[STATE_SECTION_OFFSET] = 1; + STATE[SEED_SECTION_OFFSET] = slen; + + gcopy.ndarray(slen, seed, 1, 0, STATE, 1, SEED_SECTION_OFFSET + 1); + + state = new Uint32Array(STATE.buffer, STATE.byteOffset + ((STATE_SECTION_OFFSET + 1) * STATE.BYTES_PER_ELEMENT), 1); + + seed = new Uint32Array(STATE.buffer, STATE.byteOffset + ((SEED_SECTION_OFFSET + 1) * STATE.BYTES_PER_ELEMENT), slen); + + state[0] = (seed[0] >>> 0) || 1; + + // ❌ Case 3: everything else + } else { + throw new TypeError(format('invalid option. `%s` option must be either a non-negative integer less than or equal to the maximum unsigned 32-bit integer or an array-like object containing such integer values. Option: `%s`.', 'seed', seed)); + } + } else { + seed = randuint32() >>> 0; // asm type annotation + } + } + } + if (state === void 0) { + STATE = new Uint32Array(STATE_FIXED_LENGTH + 1); + + // Initialize sections: + STATE[0] = STATE_ARRAY_VERSION; + STATE[1] = NUM_STATE_SECTIONS; + STATE[STATE_SECTION_OFFSET] = 1; + STATE[SEED_SECTION_OFFSET] = 1; + STATE[SEED_SECTION_OFFSET + 1] = seed; + + // Create a state "view": + state = new Uint32Array(STATE.buffer, STATE.byteOffset + ((STATE_SECTION_OFFSET + 1) * STATE.BYTES_PER_ELEMENT), 1); + + // Create a seed "view": + seed = new Uint32Array(STATE.buffer, STATE.byteOffset + ((SEED_SECTION_OFFSET + 1) * STATE.BYTES_PER_ELEMENT), 1); + + // Initialize the internal PRNG state: + state[0] = seed[0] || 1; // guard against zero seed + } + setReadOnly(xorshift32, 'NAME', 'xorshift32'); + setReadOnlyAccessor(xorshift32, 'seed', getSeed); + setReadOnlyAccessor(xorshift32, 'seedLength', getSeedLength); + setReadWriteAccessor(xorshift32, 'state', getState, setState); + setReadOnlyAccessor(xorshift32, 'stateLength', getStateLength); + setReadOnlyAccessor(xorshift32, 'byteLength', getStateSize); + setReadOnly(xorshift32, 'toJSON', toJSON); + setReadOnly(xorshift32, 'MIN', 1); + setReadOnly(xorshift32, 'MAX', UINT32_MAX); + setReadOnly(xorshift32, 'normalized', normalized); + + setReadOnly(normalized, 'NAME', xorshift32.NAME); + setReadOnlyAccessor(normalized, 'seed', getSeed); + setReadOnlyAccessor(normalized, 'seedLength', getSeedLength); + setReadWriteAccessor(normalized, 'state', getState, setState); + setReadOnlyAccessor(normalized, 'stateLength', getStateLength); + setReadOnlyAccessor(normalized, 'byteLength', getStateSize); + setReadOnly(normalized, 'toJSON', toJSON); + setReadOnly(normalized, 'MIN', 1.0 / NORMALIZATION_CONSTANT); + setReadOnly(normalized, 'MAX', 1.0); + + return xorshift32; + + /** +* Returns the PRNG seed. +* +* @private +* @returns {PRNGSeedXorshift32} seed +*/ + function getSeed() { + var len = STATE[SEED_SECTION_OFFSET]; + return gcopy(len, seed, 1, new Uint32Array(len), 1); + } + + /** +* Returns the PRNG seed length. +* +* @private +* @returns {PositiveInteger} seed length +*/ + function getSeedLength() { + return STATE[SEED_SECTION_OFFSET]; + } + + /** +* Returns the PRNG state length. +* +* @private +* @returns {PositiveInteger} state length +*/ + function getStateLength() { + return STATE.length; + } + + /** +* Returns the PRNG state size (in bytes). +* +* @private +* @returns {PositiveInteger} state size (in bytes) +*/ + function getStateSize() { + return STATE.byteLength; + } + + /** +* Returns the current PRNG state. +* +* ## Notes +* +* - The PRNG state array is comprised of a preamble followed by `2` sections: +* +* 0. preamble (version + number of sections) +* 1. internal PRNG state +* 2. PRNG seed +* +* - The first element of the PRNG state array preamble is the state array schema version. +* +* - The second element of the PRNG state array preamble is the number of state array sections (i.e., `2`). +* +* - The first element of each section following the preamble specifies the section length. The remaining section elements comprise the section contents. +* +* @private +* @returns {PRNGStateXorshift32} current state +*/ + function getState() { + var len = STATE.length; + return gcopy(len, STATE, 1, new Uint32Array(len), 1); + } + + /** +* Sets the PRNG state. +* +* ## Notes +* +* - 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. +* - 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). +* +* @private +* @param {PRNGStateXorshift32} s - generator state +* @throws {TypeError} must provide a `Uint32Array` +* @throws {Error} must provide a valid state +*/ + function setState(s) { + var err; + if (!isUint32Array(s)) { + throw new TypeError(format('invalid argument. Must provide a Uint32Array. Value: `%s`.', s)); + } + err = verifyState(s, false); + if (err) { + throw err; + } + if (opts.copy === false) { + if (opts.state && s.length === STATE.length) { + gcopy(s.length, s, 1, STATE, 1); // update current shared state + } else { + STATE = s; // point to new shared state + opts.state = true; // setting this flag allows updating a shared state even if a state array was not provided at PRNG creation + } + } else { + // Check if we can reuse allocated memory... + if (s.length !== STATE.length) { + STATE = new Uint32Array(s.length); // reallocate + } + gcopy(s.length, s, 1, STATE, 1); + } + // Create a new state "view": + state = new Uint32Array(STATE.buffer, STATE.byteOffset + ((STATE_SECTION_OFFSET + 1) * STATE.BYTES_PER_ELEMENT), 1); + + // Create a new seed "view": + seed = new Uint32Array(STATE.buffer, STATE.byteOffset + ((SEED_SECTION_OFFSET + 1) * STATE.BYTES_PER_ELEMENT), STATE[SEED_SECTION_OFFSET]); + } + + /** +* Serializes the pseudorandom number generator as a JSON object. +* +* ## Notes +* +* - `JSON.stringify()` implicitly calls this method when stringifying a PRNG. +* +* @private +* @returns {Object} JSON representation +*/ + function toJSON() { + var out = {}; + out.type = 'PRNG'; + out.name = xorshift32.NAME; + out.state = typedarray2json(STATE); + out.params = []; + return out; + } + + /** +* Generates a pseudorandom unsigned 32-bit integer using the xorshift32 algorithm. +* +* ## Method +* +* The xorshift32 algorithm uses the recurrence +* +* ```tex +* x \leftarrow x \oplus (x \ll a_1) +* x \leftarrow x \oplus (x \gg a_2) +* x \leftarrow x \oplus (x \ll a_3) +* ``` +* +* with the shift triplet \\((a_1, a_2, a_3) = (13, 17, 5)\\) proposed by Marsaglia (2003). +* +* @private +* @returns {NonNegativeInteger} pseudorandom unsigned 32-bit integer +*/ + function xorshift32() { + var s = state[0] >>> 0; // asm type annotation + s ^= s << 13; + s ^= s >>> 17; + s ^= s << 5; + s >>>= 0; // force unsigned 32-bit integer + state[0] = s; + return s; + } + + /** +* Generates a pseudorandom number on the interval \\( (0,1] \\). +* +* @private +* @returns {number} pseudorandom number +*/ + function normalized() { + return xorshift32() / NORMALIZATION_CONSTANT; + } +} + + +// EXPORTS // + +module.exports = factory; diff --git a/lib/node_modules/@stdlib/random/base/xorshift32/lib/index.js b/lib/node_modules/@stdlib/random/base/xorshift32/lib/index.js new file mode 100644 index 000000000000..9de8ade47a51 --- /dev/null +++ b/lib/node_modules/@stdlib/random/base/xorshift32/lib/index.js @@ -0,0 +1,57 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2026 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +/** +* XorShift32 pseudorandom number generator. +* +* @module @stdlib/random/base/xorshift32 +* +* @example +* var xorshift32 = require( '@stdlib/random/base/xorshift32' ); +* +* var v = xorshift32(); +* // returns +* +* @example +* var factory = require( '@stdlib/random/base/xorshift32' ).factory; +* +* var xorshift32 = factory({ +* 'seed': 1234 +* }); +* +* var v = xorshift32(); +* // returns +*/ + +// MODULES // + +var setReadOnly = require( '@stdlib/utils/define-nonenumerable-read-only-property' ); +var main = require( './main.js' ); +var factory = require( './factory.js' ); + + +// MAIN // + +setReadOnly( main, 'factory', factory ); + + +// EXPORTS // + +module.exports = main; diff --git a/lib/node_modules/@stdlib/random/base/xorshift32/lib/main.js b/lib/node_modules/@stdlib/random/base/xorshift32/lib/main.js new file mode 100644 index 000000000000..4662a3f94d55 --- /dev/null +++ b/lib/node_modules/@stdlib/random/base/xorshift32/lib/main.js @@ -0,0 +1,90 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2026 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +// MODULES // + +var factory = require( './factory.js' ); +var randuint32 = require( './rand_uint32.js' ); + + +// MAIN // + +/** +* Generates a pseudorandom unsigned 32-bit integer via the xorshift32 algorithm. +* +* ## Method +* +* XorShift generators are a class of pseudorandom number generators discovered +* by George Marsaglia. They operate by repeated application of the exclusive or +* (XOR) operation combined with bit shifts. +* +* The xorshift32 algorithm uses the state recurrence +* +* ```tex +* x \leftarrow x \oplus (x \ll a_1) \\ +* x \leftarrow x \oplus (x \gg a_2) \\ +* x \leftarrow x \oplus (x \ll a_3) +* ``` +* +* where \\(\oplus\\) denotes the bitwise exclusive or operator and the shift +* triplet \\((a_1, a_2, a_3)\\) is chosen to ensure the generator has a full +* period of \\(2^{32} - 1\\). +* +* In this implementation, the shift triplet is +* +* ```tex +* (a_1, a_2, a_3) = (13, 17, 5) +* ``` +* +* as proposed by Marsaglia (2003). The state must be a non-zero unsigned 32-bit +* integer; a zero seed is replaced with \\(1\\) to avoid the degenerate +* all-zeros state. +* +* ## Notes +* +* - The generator has a period of \\(2^{32} - 1\\) (all non-zero 32-bit states +* are visited exactly once before the sequence repeats). +* +* - The output range is between 1 to 2^32 - 1 (zero is never produced). +* +* - The `normalized` property returns values on \\((0, 1]\\) by dividing the +* raw output by \\(2^{32} - 1\\). +* +* ## References +* +* - Marsaglia, George. 2003. "Xorshift RNGs." _Journal of Statistical +* Software_ 8 (14). doi:[10.18637/jss.v008.i14](https://doi.org/10.18637/jss.v008.i14). +* +* @function xorshift32 +* @type {PRNG} +* @returns {NonNegativeInteger} pseudorandom unsigned 32-bit integer +* +* @example +* var v = xorshift32(); +* // returns +*/ +var xorshift32 = factory({ + 'seed': randuint32() +}); + + +// EXPORTS // + +module.exports = xorshift32; diff --git a/lib/node_modules/@stdlib/random/base/xorshift32/lib/rand_uint32.js b/lib/node_modules/@stdlib/random/base/xorshift32/lib/rand_uint32.js new file mode 100644 index 000000000000..dba933e90d61 --- /dev/null +++ b/lib/node_modules/@stdlib/random/base/xorshift32/lib/rand_uint32.js @@ -0,0 +1,52 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2026 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +// MODULES // + +var UINT32_MAX = require( '@stdlib/constants/uint32/max' ); +var floor = require( '@stdlib/math/base/special/floor' ); + + +// VARIABLES // + +var MAX = UINT32_MAX; + + +// MAIN // + +/** +* Returns a pseudorandom unsigned 32-bit integer on the interval between 1 and 2^32 - 1. +* +* @private +* @returns {NonNegativeInteger} pseudorandom unsigned 32-bit integer +* +* @example +* var v = randuint32(); +* // returns +*/ +function randuint32() { + var v = floor( 1.0 + (MAX * Math.random()) ); // eslint-disable-line stdlib/no-builtin-math + return v >>> 0; // asm type annotation +} + + +// EXPORTS // + +module.exports = randuint32; diff --git a/lib/node_modules/@stdlib/random/base/xorshift32/package.json b/lib/node_modules/@stdlib/random/base/xorshift32/package.json new file mode 100644 index 000000000000..e16133b49ebd --- /dev/null +++ b/lib/node_modules/@stdlib/random/base/xorshift32/package.json @@ -0,0 +1,71 @@ +{ + "name": "@stdlib/random/base/xorshift32", + "version": "0.0.0", + "description": "A 32-bit XORShift pseudorandom number generator.", + "license": "Apache-2.0", + "author": { + "name": "The Stdlib Authors", + "url": "https://github.com/stdlib-js/stdlib/graphs/contributors" + }, + "contributors": [ + { + "name": "The Stdlib Authors", + "url": "https://github.com/stdlib-js/stdlib/graphs/contributors" + } + ], + "main": "./lib", + "directories": { + "benchmark": "./benchmark", + "doc": "./docs", + "example": "./examples", + "lib": "./lib", + "test": "./test" + }, + "types": "./docs/types", + "scripts": {}, + "homepage": "https://github.com/stdlib-js/stdlib", + "repository": { + "type": "git", + "url": "git://github.com/stdlib-js/stdlib.git" + }, + "bugs": { + "url": "https://github.com/stdlib-js/stdlib/issues" + }, + "dependencies": {}, + "devDependencies": {}, + "engines": { + "node": ">=0.10.0", + "npm": ">2.7.0" + }, + "os": [ + "aix", + "darwin", + "freebsd", + "linux", + "macos", + "openbsd", + "sunos", + "win32", + "windows" + ], + "keywords": [ + "stdlib", + "stdmath", + "mathematics", + "math", + "statistics", + "stats", + "prng", + "pseudorandom", + "random", + "rand", + "randint", + "randu", + "uniform", + "generator", + "xorshift", + "xorshift32", + "seed", + "seedable" + ] +} diff --git a/lib/node_modules/@stdlib/random/base/xorshift32/test/test.factory.js b/lib/node_modules/@stdlib/random/base/xorshift32/test/test.factory.js new file mode 100644 index 000000000000..51586c0abb42 --- /dev/null +++ b/lib/node_modules/@stdlib/random/base/xorshift32/test/test.factory.js @@ -0,0 +1,682 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2026 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +// MODULES // + +var tape = require( 'tape' ); +var UINT32_MAX = require( '@stdlib/constants/uint32/max' ); +var isNonNegativeInteger = require( '@stdlib/math/base/assert/is-nonnegative-integer' ); +var isUint32Array = require( '@stdlib/assert/is-uint32array' ); +var Uint32Array = require( '@stdlib/array/uint32' ); +var Int32Array = require( '@stdlib/array/int32' ); +var factory = require( './../lib' ).factory; + + +// TESTS // + +tape( 'main export is a function', function test( t ) { + t.ok( true, __filename ); + t.strictEqual( typeof factory, 'function', 'main export is a function' ); + t.end(); +}); + +tape( 'the function throws if provided an options argument which is not an object', function test( t ) { + var values; + var i; + + values = [ + '5', + 5, + NaN, + true, + false, + null, + void 0, + [], + function noop() {} + ]; + + for ( i = 0; i < values.length; i++ ) { + t.throws( badValue( values[ i ] ), TypeError, 'throws a TypeError when provided '+values[ i ] ); + } + t.end(); + + function badValue( value ) { + return function badValue() { + factory( value ); + }; + } +}); + +tape( 'the function throws if provided a `seed` option which is neither a positive integer nor an array-like object', function test( t ) { + var values; + var i; + + values = [ + '5', + -1, + -3.14, + NaN, + true, + false, + null, + void 0, + {}, + [], + function noop() {} + ]; + + for ( i = 0; i < values.length; i++ ) { + t.throws( badValue( values[ i ] ), ( typeof values[ i ] === 'number' ) ? RangeError : TypeError, 'throws when provided '+values[ i ] ); + } + t.end(); + + function badValue( value ) { + return function badValue() { + factory({ + 'seed': value + }); + }; + } +}); + +tape( 'the function throws if provided a `seed` option which exceeds the maximum unsigned 32-bit integer', function test( t ) { + t.throws( badValue, RangeError, 'throws a RangeError' ); + t.end(); + + function badValue() { + factory({ + 'seed': UINT32_MAX + 1 + }); + } +}); + +tape( 'the function throws if provided a `state` option which is not a Uint32Array', function test( t ) { + var values; + var i; + + values = [ + '5', + 5, + NaN, + true, + false, + null, + void 0, + {}, + [], + new Int32Array( 10 ), + function noop() {} + ]; + + for ( i = 0; i < values.length; i++ ) { + t.throws( badValue( values[ i ] ), TypeError, 'throws a TypeError when provided '+values[ i ] ); + } + t.end(); + + function badValue( value ) { + return function badValue() { + factory({ + 'state': value + }); + }; + } +}); + +tape( 'the function throws if provided an invalid `state` option (insufficient length)', function test( t ) { + t.throws( badValue, RangeError, 'throws a RangeError' ); + t.end(); + + function badValue() { + factory({ + 'state': new Uint32Array( 1 ) + }); + } +}); + +tape( 'the function throws if provided an invalid `state` option (incompatible schema version)', function test( t ) { + var state; + t.throws( badValue, RangeError, 'throws a RangeError' ); + t.end(); + + function badValue() { + var prng = factory(); + state = prng.state; + state[ 0 ] = 999; // corrupt schema version + factory({ + 'state': state + }); + } +}); + +tape( 'the function throws if provided a `copy` option which is not a boolean', function test( t ) { + var values; + var i; + + values = [ + '5', + 5, + NaN, + null, + void 0, + {}, + [], + function noop() {} + ]; + + for ( i = 0; i < values.length; i++ ) { + t.throws( badValue( values[ i ] ), TypeError, 'throws a TypeError when provided '+values[ i ] ); + } + t.end(); + + function badValue( value ) { + return function badValue() { + factory({ + 'copy': value + }); + }; + } +}); + +tape( 'the function returns a function', function test( t ) { + var xorshift32 = factory(); + t.strictEqual( typeof xorshift32, 'function', 'returns a function' ); + t.end(); +}); + +tape( 'the function returns a seeded PRNG (integer seed)', function test( t ) { + var xorshift32 = factory({ + 'seed': 12345 + }); + t.strictEqual( typeof xorshift32, 'function', 'returns a function' ); + t.end(); +}); + +tape( 'the function returns a seeded PRNG (array seed)', function test( t ) { + var xorshift32 = factory({ + 'seed': [ 12345, 67890 ] + }); + t.strictEqual( typeof xorshift32, 'function', 'returns a function' ); + t.end(); +}); + +tape( 'attached to the returned function is the generator name', function test( t ) { + var xorshift32 = factory(); + t.strictEqual( xorshift32.NAME, 'xorshift32', 'has property' ); + t.end(); +}); + +tape( 'attached to the returned function is the minimum possible generated number', function test( t ) { + var xorshift32 = factory(); + t.strictEqual( xorshift32.MIN, 1, 'has property' ); + t.end(); +}); + +tape( 'attached to the returned function is the maximum possible generated number', function test( t ) { + var xorshift32 = factory(); + t.strictEqual( xorshift32.MAX, UINT32_MAX, 'has property' ); + t.end(); +}); + +tape( 'attached to the returned function is the generator seed', function test( t ) { + var xorshift32 = factory(); + t.strictEqual( isUint32Array( xorshift32.seed ), true, 'has property' ); + t.end(); +}); + +tape( 'attached to the returned function is the generator seed length', function test( t ) { + var xorshift32 = factory(); + t.strictEqual( typeof xorshift32.seedLength, 'number', 'has property' ); + t.end(); +}); + +tape( 'attached to the returned function is the generator state', function test( t ) { + var xorshift32 = factory(); + t.strictEqual( isUint32Array( xorshift32.state ), true, 'has property' ); + t.end(); +}); + +tape( 'attached to the returned function is the generator state length', function test( t ) { + var xorshift32 = factory(); + t.strictEqual( typeof xorshift32.stateLength, 'number', 'has property' ); + t.end(); +}); + +tape( 'attached to the returned function is the generator state size', function test( t ) { + var xorshift32 = factory(); + t.strictEqual( typeof xorshift32.byteLength, 'number', 'has property' ); + t.end(); +}); + +tape( 'attached to the returned function is a `toJSON` method', function test( t ) { + var xorshift32 = factory(); + t.strictEqual( typeof xorshift32.toJSON, 'function', 'has method' ); + t.end(); +}); + +tape( 'attached to the returned function is a `normalized` method', function test( t ) { + var xorshift32 = factory(); + t.strictEqual( typeof xorshift32.normalized, 'function', 'has method' ); + t.end(); +}); + +tape( 'attached to the `normalized` method is the generator name', function test( t ) { + var xorshift32 = factory(); + t.strictEqual( xorshift32.normalized.NAME, 'xorshift32', 'has property' ); + t.end(); +}); + +tape( 'attached to the `normalized` method is the minimum possible generated number', function test( t ) { + var xorshift32 = factory(); + t.strictEqual( xorshift32.normalized.MIN, 1.0 / UINT32_MAX, 'has property' ); + t.end(); +}); + +tape( 'attached to the `normalized` method is the maximum possible generated number', function test( t ) { + var xorshift32 = factory(); + t.strictEqual( xorshift32.normalized.MAX, 1.0, 'has property' ); + t.end(); +}); + +tape( 'attached to the `normalized` method is the generator seed', function test( t ) { + var xorshift32 = factory(); + t.strictEqual( isUint32Array( xorshift32.normalized.seed ), true, 'has property' ); + t.end(); +}); + +tape( 'attached to the `normalized` method is the generator seed length', function test( t ) { + var xorshift32 = factory(); + t.strictEqual( typeof xorshift32.normalized.seedLength, 'number', 'has property' ); + t.end(); +}); + +tape( 'attached to the `normalized` method is the generator state', function test( t ) { + var xorshift32 = factory(); + t.strictEqual( isUint32Array( xorshift32.normalized.state ), true, 'has property' ); + t.end(); +}); + +tape( 'attached to the `normalized` method is the generator state length', function test( t ) { + var xorshift32 = factory(); + t.strictEqual( typeof xorshift32.normalized.stateLength, 'number', 'has property' ); + t.end(); +}); + +tape( 'attached to the `normalized` method is the generator state size', function test( t ) { + var xorshift32 = factory(); + t.strictEqual( typeof xorshift32.normalized.byteLength, 'number', 'has property' ); + t.end(); +}); + +tape( 'attached to the `normalized` method is a `toJSON` method', function test( t ) { + var xorshift32 = factory(); + t.strictEqual( typeof xorshift32.normalized.toJSON, 'function', 'has method' ); + t.end(); +}); + +tape( 'the returned function returns pseudorandom unsigned 32-bit integers on the interval [1, 2^32-1]', function test( t ) { + var xorshift32; + var v; + var i; + + xorshift32 = factory(); + for ( i = 0; i < 1e3; i++ ) { + v = xorshift32(); + t.strictEqual( typeof v, 'number', 'returns expected value' ); + t.strictEqual( isNonNegativeInteger( v ), true, 'returns a non-negative integer' ); + t.strictEqual( v >= 1 && v <= UINT32_MAX, true, 'returns an integer between 1 and 2^32-1 (inclusive)' ); + } + t.end(); +}); + +tape( 'the returned function never returns zero', function test( t ) { + var xorshift32; + var i; + + xorshift32 = factory(); + for ( i = 0; i < 1e3; i++ ) { + t.notEqual( xorshift32(), 0, 'does not return zero' ); + } + t.end(); +}); + +tape( 'the `normalized` method returns pseudorandom numbers on the interval (0, 1]', function test( t ) { + var xorshift32; + var v; + var i; + + xorshift32 = factory(); + for ( i = 0; i < 1e3; i++ ) { + v = xorshift32.normalized(); + t.strictEqual( typeof v, 'number', 'returns expected value' ); + t.strictEqual( v > 0.0 && v <= 1.0, true, 'returns a number strictly between 0 (exclusive) and 1 (inclusive)' ); + } + t.end(); +}); + +tape( 'two PRNGs with the same seed produce the same output sequence', function test( t ) { + var xorshift32a; + var xorshift32b; + var i; + + xorshift32a = factory({ + 'seed': 42 + }); + xorshift32b = factory({ + 'seed': 42 + }); + + for ( i = 0; i < 1e3; i++ ) { + t.strictEqual( xorshift32a(), xorshift32b(), 'both return the same value. i: '+i+'.' ); + } + t.end(); +}); + +tape( 'two PRNGs with the same seed produce the same normalized output sequence', function test( t ) { + var xorshift32a; + var xorshift32b; + var i; + + xorshift32a = factory({ + 'seed': 42 + }); + xorshift32b = factory({ + 'seed': 42 + }); + + for ( i = 0; i < 1e3; i++ ) { + t.strictEqual( xorshift32a.normalized(), xorshift32b.normalized(), 'both return the same value. i: '+i+'.' ); + } + t.end(); +}); + +tape( 'two PRNGs with different seeds produce different output sequences', function test( t ) { + var xorshift32a; + var xorshift32b; + var diff; + var i; + + xorshift32a = factory({ + 'seed': 1 + }); + xorshift32b = factory({ + 'seed': 2 + }); + + diff = false; + for ( i = 0; i < 1e2; i++ ) { + if ( xorshift32a() !== xorshift32b() ) { + diff = true; + break; + } + } + t.strictEqual( diff, true, 'generators with different seeds produce different sequences' ); + t.end(); +}); + +tape( 'the returned function supports setting the generator state', function test( t ) { + var xorshift32; + var state; + var arr; + var i; + + xorshift32 = factory(); + + // Move to a future state... + for ( i = 0; i < 100; i++ ) { + xorshift32(); + } + // Capture the current state: + state = xorshift32.state; + + // Move to a future state... + arr = []; + for ( i = 0; i < 100; i++ ) { + arr.push( xorshift32() ); + } + // Set the state: + xorshift32.state = state; + + // Replay previously generated values... + for ( i = 0; i < 100; i++ ) { + t.strictEqual( xorshift32(), arr[ i ], 'returns expected value. i: '+i+'.' ); + } + t.end(); +}); + +tape( 'the returned function supports setting the generator state (normalized)', function test( t ) { + var xorshift32; + var state; + var arr; + var i; + + xorshift32 = factory(); + + // Move to a future state... + for ( i = 0; i < 100; i++ ) { + xorshift32.normalized(); + } + // Capture the current state: + state = xorshift32.state; + + // Move to a future state... + arr = []; + for ( i = 0; i < 100; i++ ) { + arr.push( xorshift32.normalized() ); + } + // Set the state: + xorshift32.state = state; + + // Replay previously generated values... + for ( i = 0; i < 100; i++ ) { + t.strictEqual( xorshift32.normalized(), arr[ i ], 'returns expected value. i: '+i+'.' ); + } + t.end(); +}); + +tape( 'the returned function supports setting the generator state via the `normalized` property', function test( t ) { + var xorshift32; + var state; + var arr; + var i; + + xorshift32 = factory(); + + // Move to a future state... + for ( i = 0; i < 100; i++ ) { + xorshift32.normalized(); + } + // Capture the current state: + state = xorshift32.normalized.state; + + // Move to a future state... + arr = []; + for ( i = 0; i < 100; i++ ) { + arr.push( xorshift32.normalized() ); + } + // Set the state: + xorshift32.normalized.state = state; + + // Replay previously generated values... + for ( i = 0; i < 100; i++ ) { + t.strictEqual( xorshift32.normalized(), arr[ i ], 'returns expected value. i: '+i+'.' ); + } + t.end(); +}); + +tape( 'the function supports providing a state from a separate generator instance (copy: true)', function test( t ) { + var xorshift32a; + var xorshift32b; + var state; + var arr; + var i; + + xorshift32a = factory(); + + // Move to a future state... + for ( i = 0; i < 100; i++ ) { + xorshift32a(); + } + // Capture the current state: + state = xorshift32a.state; + + // Create a new PRNG from the captured state: + xorshift32b = factory({ + 'state': state + }); + + // Generate values from both PRNGs; they should agree: + arr = []; + for ( i = 0; i < 100; i++ ) { + arr.push( xorshift32a() ); + } + for ( i = 0; i < 100; i++ ) { + t.strictEqual( xorshift32b(), arr[ i ], 'returns expected value. i: '+i+'.' ); + } + t.end(); +}); + +tape( 'the function supports providing a state from a separate generator instance (copy: false)', function test( t ) { + var xorshift32a; + var xorshift32b; + var state; + var arr; + var i; + + xorshift32a = factory(); + + // Move to a future state... + for ( i = 0; i < 100; i++ ) { + xorshift32a(); + } + // Capture the current state: + state = xorshift32a.state; + + // Create a new PRNG from the captured state (shared, not copied): + xorshift32b = factory({ + 'state': state, + 'copy': false + }); + + // Generate values from both PRNGs; they should agree: + arr = []; + for ( i = 0; i < 100; i++ ) { + arr.push( xorshift32a() ); + } + for ( i = 0; i < 100; i++ ) { + t.strictEqual( xorshift32b(), arr[ i ], 'returns expected value. i: '+i+'.' ); + } + t.end(); +}); + +tape( 'the function supports providing an array seed', function test( t ) { + var xorshift32a; + var xorshift32b; + var i; + + xorshift32a = factory({ + 'seed': [ 12345 ] + }); + xorshift32b = factory({ + 'seed': [ 12345 ] + }); + + for ( i = 0; i < 1e3; i++ ) { + t.strictEqual( xorshift32a(), xorshift32b(), 'both return the same value. i: '+i+'.' ); + } + t.end(); +}); + +tape( 'the `setState` accessor throws if provided an argument which is not a Uint32Array', function test( t ) { + var xorshift32; + var values; + var i; + + xorshift32 = factory(); + + values = [ + '5', + 5, + NaN, + true, + false, + null, + void 0, + {}, + [], + new Int32Array( 10 ), + function noop() {} + ]; + + for ( i = 0; i < values.length; i++ ) { + t.throws( badValue( values[ i ] ), TypeError, 'throws a TypeError when provided '+values[ i ] ); + } + t.end(); + + function badValue( value ) { + return function badValue() { + xorshift32.state = value; + }; + } +}); + +tape( 'the `setState` accessor throws if provided an invalid state array', function test( t ) { + var xorshift32 = factory(); + + t.throws( badValue, RangeError, 'throws a RangeError' ); + t.end(); + + function badValue() { + xorshift32.state = new Uint32Array( 2 ); // too short + } +}); + +tape( 'the `toJSON` method returns an object with expected properties', function test( t ) { + var xorshift32; + var o; + + xorshift32 = factory({ + 'seed': 12345 + }); + o = xorshift32.toJSON(); + + t.strictEqual( typeof o, 'object', 'returns an object' ); + t.strictEqual( o.type, 'PRNG', 'has expected type property' ); + t.strictEqual( o.name, 'xorshift32', 'has expected name property' ); + t.strictEqual( typeof o.state, 'object', 'has expected state property' ); + t.ok( Array.isArray( o.params ), 'has expected params property' ); + t.end(); +}); + +tape( 'a zero seed is replaced with 1 to avoid the degenerate all-zeros fixed point', function test( t ) { + var xorshift32; + var v; + var i; + + xorshift32 = factory({ + 'seed': 0 + }); + + for ( i = 0; i < 1e3; i++ ) { + v = xorshift32(); + t.notEqual( v, 0, 'does not return zero' ); + } + t.end(); +}); diff --git a/lib/node_modules/@stdlib/random/base/xorshift32/test/test.js b/lib/node_modules/@stdlib/random/base/xorshift32/test/test.js new file mode 100644 index 000000000000..6f0e0bcd9ab6 --- /dev/null +++ b/lib/node_modules/@stdlib/random/base/xorshift32/test/test.js @@ -0,0 +1,260 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2026 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +// MODULES // + +var tape = require( 'tape' ); +var UINT32_MAX = require( '@stdlib/constants/uint32/max' ); +var isNonNegativeInteger = require( '@stdlib/math/base/assert/is-nonnegative-integer' ); +var isUint32Array = require( '@stdlib/assert/is-uint32array' ); +var xorshift32 = require( './../lib' ); + + +// TESTS // + +tape( 'main export is a function', function test( t ) { + t.ok( true, __filename ); + t.strictEqual( typeof xorshift32, 'function', 'main export is a function' ); + t.end(); +}); + +tape( 'attached to the main export is a method to generate normalized pseudorandom numbers', function test( t ) { + t.strictEqual( typeof xorshift32.normalized, 'function', 'has method' ); + t.end(); +}); + +tape( 'attached to the main export is a method to create a xorshift32 pseudorandom number generator', function test( t ) { + t.strictEqual( typeof xorshift32.factory, 'function', 'has method' ); + t.end(); +}); + +tape( 'attached to the main export is a method to serialize a pseudorandom number generator as JSON', function test( t ) { + t.strictEqual( typeof xorshift32.toJSON, 'function', 'has method' ); + t.end(); +}); + +tape( 'attached to the main export is the generator name', function test( t ) { + t.strictEqual( xorshift32.NAME, 'xorshift32', 'has property' ); + t.end(); +}); + +tape( 'attached to the main export is the minimum possible generated number', function test( t ) { + t.strictEqual( xorshift32.MIN, 1, 'has property' ); + t.end(); +}); + +tape( 'attached to the main export is the maximum possible generated number', function test( t ) { + t.strictEqual( xorshift32.MAX, UINT32_MAX, 'has property' ); + t.end(); +}); + +tape( 'attached to the main export is the generator seed', function test( t ) { + t.strictEqual( isUint32Array( xorshift32.seed ), true, 'has property' ); + t.end(); +}); + +tape( 'attached to the main export is the generator seed length', function test( t ) { + t.strictEqual( typeof xorshift32.seedLength, 'number', 'has property' ); + t.end(); +}); + +tape( 'attached to the main export is the generator state', function test( t ) { + t.strictEqual( isUint32Array( xorshift32.state ), true, 'has property' ); + t.end(); +}); + +tape( 'attached to the main export is the generator state length', function test( t ) { + t.strictEqual( typeof xorshift32.stateLength, 'number', 'has property' ); + t.end(); +}); + +tape( 'attached to the main export is the generator state size', function test( t ) { + t.strictEqual( typeof xorshift32.byteLength, 'number', 'has property' ); + t.end(); +}); + +tape( 'the function returns pseudorandom unsigned 32-bit integers on the interval [1, 2^32-1]', function test( t ) { + var v; + var i; + for ( i = 0; i < 1e3; i++ ) { + v = xorshift32(); + t.strictEqual( typeof v, 'number', 'returns expected value' ); + t.strictEqual( isNonNegativeInteger( v ), true, 'returns a non-negative integer' ); + t.strictEqual( v >= 1 && v <= UINT32_MAX, true, 'returns an integer between 1 and 2^32-1 (inclusive)' ); + } + t.end(); +}); + +tape( 'the function never returns zero (zero is a fixed point of the xorshift32 recurrence)', function test( t ) { + var v; + var i; + for ( i = 0; i < 1e3; i++ ) { + v = xorshift32(); + t.notEqual( v, 0, 'does not return zero' ); + } + t.end(); +}); + +tape( 'the `normalized` method returns pseudorandom numbers on the interval (0, 1]', function test( t ) { + var v; + var i; + for ( i = 0; i < 1e3; i++ ) { + v = xorshift32.normalized(); + t.strictEqual( typeof v, 'number', 'returns expected value' ); + t.strictEqual( v > 0.0 && v <= 1.0, true, 'returns a number strictly between 0 (exclusive) and 1 (inclusive)' ); + } + t.end(); +}); + +tape( 'attached to the `normalized` method is the generator name', function test( t ) { + t.strictEqual( xorshift32.normalized.NAME, 'xorshift32', 'has property' ); + t.end(); +}); + +tape( 'attached to the `normalized` method is the minimum possible generated number', function test( t ) { + t.strictEqual( xorshift32.normalized.MIN, 1.0 / UINT32_MAX, 'has property' ); + t.end(); +}); + +tape( 'attached to the `normalized` method is the maximum possible generated number', function test( t ) { + t.strictEqual( xorshift32.normalized.MAX, 1.0, 'has property' ); + t.end(); +}); + +tape( 'attached to the `normalized` method is the generator seed', function test( t ) { + t.strictEqual( isUint32Array( xorshift32.normalized.seed ), true, 'has property' ); + t.end(); +}); + +tape( 'attached to the `normalized` method is the generator seed length', function test( t ) { + t.strictEqual( typeof xorshift32.normalized.seedLength, 'number', 'has property' ); + t.end(); +}); + +tape( 'attached to the `normalized` method is the generator state', function test( t ) { + t.strictEqual( isUint32Array( xorshift32.normalized.state ), true, 'has property' ); + t.end(); +}); + +tape( 'attached to the `normalized` method is the generator state length', function test( t ) { + t.strictEqual( typeof xorshift32.normalized.stateLength, 'number', 'has property' ); + t.end(); +}); + +tape( 'attached to the `normalized` method is the generator state size', function test( t ) { + t.strictEqual( typeof xorshift32.normalized.byteLength, 'number', 'has property' ); + t.end(); +}); + +tape( 'attached to the `normalized` method is a method to serialize a pseudorandom number generator as JSON', function test( t ) { + t.strictEqual( typeof xorshift32.normalized.toJSON, 'function', 'has method' ); + t.end(); +}); + +tape( 'the generator supports setting the generator state', function test( t ) { + var state; + var arr; + var i; + + // Move to a future state... + for ( i = 0; i < 100; i++ ) { + xorshift32(); + } + // Capture the current state: + state = xorshift32.state; + + // Move to a future state... + arr = []; + for ( i = 0; i < 100; i++ ) { + arr.push( xorshift32() ); + } + // Set the state: + xorshift32.state = state; + + // Replay previously generated values... + for ( i = 0; i < 100; i++ ) { + t.strictEqual( xorshift32(), arr[ i ], 'returns expected value. i: '+i+'.' ); + } + t.end(); +}); + +tape( 'the generator supports setting the generator state (normalized)', function test( t ) { + var state; + var arr; + var i; + + // Move to a future state... + for ( i = 0; i < 100; i++ ) { + xorshift32.normalized(); + } + // Capture the current state: + state = xorshift32.state; + + // Move to a future state... + arr = []; + for ( i = 0; i < 100; i++ ) { + arr.push( xorshift32.normalized() ); + } + // Set the state: + xorshift32.state = state; + + // Replay previously generated values... + for ( i = 0; i < 100; i++ ) { + t.strictEqual( xorshift32.normalized(), arr[ i ], 'returns expected value. i: '+i+'.' ); + } + t.end(); +}); + +tape( 'the generator supports setting the generator state via the `normalized` property', function test( t ) { + var state; + var arr; + var i; + + // Move to a future state... + for ( i = 0; i < 100; i++ ) { + xorshift32.normalized(); + } + // Capture the current state: + state = xorshift32.normalized.state; + + // Move to a future state... + arr = []; + for ( i = 0; i < 100; i++ ) { + arr.push( xorshift32.normalized() ); + } + // Set the state: + xorshift32.normalized.state = state; + + // Replay previously generated values... + for ( i = 0; i < 100; i++ ) { + t.strictEqual( xorshift32.normalized(), arr[ i ], 'returns expected value. i: '+i+'.' ); + } + t.end(); +}); + +tape( 'the `toJSON` method returns an object with expected properties', function test( t ) { + var o = xorshift32.toJSON(); + t.strictEqual( typeof o, 'object', 'returns an object' ); + t.strictEqual( o.type, 'PRNG', 'has expected type property' ); + t.strictEqual( o.name, xorshift32.NAME, 'has expected name property' ); + t.strictEqual( typeof o.state, 'object', 'has expected state property' ); + t.ok( Array.isArray( o.params ), 'has expected params property' ); + t.end(); +});