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..be4f6e0d057c --- /dev/null +++ b/lib/node_modules/@stdlib/random/base/xorshift32/README.md @@ -0,0 +1,318 @@ + + +# Xorshift32 + +> A 32-bit [xorshift][] pseudorandom number generator based on George Marsaglia. + +
+ +## Usage + +```javascript +var xorshift32 = require( '@stdlib/random/base/xorshift32' ); +``` + +#### xorshift32() + +Returns a pseudorandom integer on the interval `[1, 4294967295]`. + +```javascript +var r = xorshift32(); +// returns +``` + +#### xorshift32.normalized() + +Returns a pseudorandom number on the interval `[0,1)`. + +```javascript +var r = xorshift32.normalized(); +// returns +``` + +#### xorshift32.factory( \[options] ) + +Returns a 32-bit [xorshift][] pseudorandom number generator. + +```javascript +var rand = xorshift32.factory(); +``` + +The function accepts the following `options`: + +- **seed**: pseudorandom number generator seed. +- **state**: an [`Uint32Array`][@stdlib/array/uint32] containing pseudorandom number generator state. If provided, the function ignores the `seed` option. +- **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`. + +By default, a random integer is used to seed the returned generator. To seed the generator, provide either an `integer` on the interval `[1, 4294967295]` + +```javascript +var rand = xorshift32.factory({ + 'seed': 1234 +}); + +var r = rand(); +// returns 332584831 +``` + +or, for arbitrary length seeds, an array-like `object` containing unsigned 32-bit integers + +```javascript +var Uint32Array = require( '@stdlib/array/uint32' ); + +var rand = xorshift32.factory({ + 'seed': new Uint32Array( [ 1234 ] ) +}); + +var r = rand(); +// returns 332584831 +``` + +To return a generator having a specific initial state, set the generator `state` option. + +```javascript +// Generate pseudorandom numbers, thus progressing the generator state: +var r; +var i; +for ( i = 0; i < 1000; i++ ) { + r = xorshift32(); +} + +// Create a new PRNG initialized to the current state of `xorshift32`: +var rand = xorshift32.factory({ + 'state': xorshift32.state +}); + +// Test that the generated pseudorandom numbers are the same: +var bool = ( rand() === xorshift32() ); +// returns true +``` + +#### 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 +}); +for ( i = 0; i < 100; i++ ) { + r = rand(); +} +``` + +#### xorshift32.seedLength + +Length of generator seed. + +```javascript +var len = xorshift32.seedLength; +// returns +``` + +#### xorshift32.state + +Writable property for getting and setting the generator state. + +```javascript +var r = xorshift32(); +// returns + +r = xorshift32(); +// returns + +// ... + +// Get the current state: +var state = xorshift32.state; +// returns + +r = xorshift32(); +// returns + +r = xorshift32(); +// returns + +// Reset the state: +xorshift32.state = state; + +// Replay the last two pseudorandom numbers: +r = xorshift32(); +// returns + +r = xorshift32(); +// returns + +// ... +``` + +#### xorshift32.stateLength + +Length of generator state. + +```javascript +var len = xorshift32.stateLength; +// returns +``` + +#### xorshift32.byteLength + +Size (in bytes) of generator state. + +```javascript +var sz = xorshift32.byteLength; +// returns +``` + +#### xorshift32.toJSON() + +Serializes the pseudorandom number generator as a JSON object. + +```javascript +var o = xorshift32.toJSON(); +// returns { 'type': 'PRNG', 'name': '...', 'state': {...}, 'params': [] } +``` + +
+ + + +
+ +## Notes + +- The generator has a period of `2^32-1`. +- Like all [LFSR][lfsr]s, the parameters have to be chosen very carefully in order to achieve a long period. For execution in software, xorshift generators are among the fastest PRNGs, requiring very small code and state. However, they do not pass every statistical test without further refinement. +- 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). + +
+ + + +
+ +## 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 +}); +for ( i = 0; i < 100; i++ ) { + console.log( rand() ); +} +``` + +
+ + + +* * * + +
+ +## References + +- Marsaglia, G. 2003. "Xorshift RNGs." _Journal of Statistical Software_ 8 (14). Los Angeles, CA, USA: American Statistical Association: 1–6. doi:[10.18637/jss.v008.i14][@marsaglia:2003]. + +
+ + + + + + + + + + + + + + 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..737011e75c50 --- /dev/null +++ b/lib/node_modules/@stdlib/random/base/xorshift32/benchmark/benchmark.factory.js @@ -0,0 +1,104 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2025 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/int32' ); +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(); +}); 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..ad409707541a --- /dev/null +++ b/lib/node_modules/@stdlib/random/base/xorshift32/benchmark/benchmark.js @@ -0,0 +1,67 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2025 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 pkg = require( './../package.json' ).name; +var xorshift32 = require( './../lib' ); + + +// MAIN // + +bench( pkg, function benchmark( b ) { + var z; + var i; + + b.tic(); + for ( i = 0; i < b.iterations; i++ ) { + z = xorshift32(); + if ( isnan( z ) ) { + b.fail( 'should not return NaN' ); + } + } + b.toc(); + if ( isnan( z ) ) { + b.fail( 'should not return NaN' ); + } + b.pass( 'benchmark finished' ); + b.end(); +}); + +bench( pkg+':normalized', function benchmark( b ) { + var z; + var i; + + b.tic(); + for ( i = 0; i < b.iterations; i++ ) { + z = xorshift32.normalized(); + if ( isnan( z ) ) { + b.fail( 'should not return NaN' ); + } + } + b.toc(); + if ( isnan( z ) ) { + b.fail( 'should not return NaN' ); + } + b.pass( 'benchmark finished' ); + b.end(); +}); diff --git a/lib/node_modules/@stdlib/random/base/xorshift32/benchmark/benchmark.to_json.js b/lib/node_modules/@stdlib/random/base/xorshift32/benchmark/benchmark.to_json.js new file mode 100644 index 000000000000..68e6d79d9f68 --- /dev/null +++ b/lib/node_modules/@stdlib/random/base/xorshift32/benchmark/benchmark.to_json.js @@ -0,0 +1,48 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2025 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 rand = require( './../lib' ); + + +// MAIN // + +bench( pkg+':toJSON', function benchmark( b ) { + var o; + var i; + + b.tic(); + for ( i = 0; i < b.iterations; i++ ) { + o = rand.toJSON(); + if ( typeof o !== 'object' ) { + b.fail( 'should return an object' ); + } + } + b.toc(); + if ( !isObject( o ) ) { + b.fail( 'should return an object' ); + } + b.pass( 'benchmark finished' ); + b.end(); +}); diff --git a/lib/node_modules/@stdlib/random/base/xorshift32/benchmark/c/Makefile b/lib/node_modules/@stdlib/random/base/xorshift32/benchmark/c/Makefile new file mode 100644 index 000000000000..5d7e79f50788 --- /dev/null +++ b/lib/node_modules/@stdlib/random/base/xorshift32/benchmark/c/Makefile @@ -0,0 +1,146 @@ +#/ +# @license Apache-2.0 +# +# Copyright (c) 2025 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. +#/ + +# VARIABLES # + +ifndef VERBOSE + QUIET := @ +else + QUIET := +endif + +# Determine the OS ([1][1], [2][2]). +# +# [1]: https://en.wikipedia.org/wiki/Uname#Examples +# [2]: http://stackoverflow.com/a/27776822/2225624 +OS ?= $(shell uname) +ifneq (, $(findstring MINGW,$(OS))) + OS := WINNT +else +ifneq (, $(findstring MSYS,$(OS))) + OS := WINNT +else +ifneq (, $(findstring CYGWIN,$(OS))) + OS := WINNT +else +ifneq (, $(findstring Windows_NT,$(OS))) + OS := WINNT +endif +endif +endif +endif + +# Define the program used for compiling C source files: +ifdef C_COMPILER + CC := $(C_COMPILER) +else + CC := gcc +endif + +# Define the command-line options when compiling C files: +CFLAGS ?= \ + -std=c99 \ + -O3 \ + -Wall \ + -pedantic + +# Determine whether to generate position independent code ([1][1], [2][2]). +# +# [1]: https://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html#Code-Gen-Options +# [2]: http://stackoverflow.com/questions/5311515/gcc-fpic-option +ifeq ($(OS), WINNT) + fPIC ?= +else + fPIC ?= -fPIC +endif + +# List of includes (e.g., `-I /foo/bar -I /beep/boop/include`): +INCLUDE ?= + +# List of source files: +SOURCE_FILES ?= + +# List of libraries (e.g., `-lopenblas -lpthread`): +LIBRARIES ?= + +# List of library paths (e.g., `-L /foo/bar -L /beep/boop`): +LIBPATH ?= + +# List of C targets: +c_targets := benchmark.out + + +# RULES # + +#/ +# Compiles C source files. +# +# @param {string} SOURCE_FILES - list of C source files +# @param {string} [INCLUDE] - list of includes (e.g., `-I /foo/bar -I /beep/boop`) +# @param {string} [LIBRARIES] - list of libraries (e.g., `-lpthread -lblas`) +# @param {string} [LIBPATH] - list of library paths (e.g., `-L /foo/bar -L /beep/boop`) +# @param {string} [C_COMPILER] - C compiler +# @param {string} [CFLAGS] - C compiler flags +# @param {(string|void)} [fPIC] - compiler flag indicating whether to generate position independent code +# +# @example +# make +# +# @example +# make all +#/ +all: $(c_targets) + +.PHONY: all + +#/ +# Compiles C source files. +# +# @private +# @param {string} SOURCE_FILES - list of C source files +# @param {(string|void)} INCLUDE - list of includes (e.g., `-I /foo/bar -I /beep/boop`) +# @param {(string|void)} LIBRARIES - list of libraries (e.g., `-lpthread -lblas`) +# @param {(string|void)} LIBPATH - list of library paths (e.g., `-L /foo/bar -L /beep/boop`) +# @param {string} CC - C compiler +# @param {string} CFLAGS - C compiler flags +# @param {(string|void)} fPIC - compiler flag indicating whether to generate position independent code +#/ +$(c_targets): %.out: %.c + $(QUIET) $(CC) $(CFLAGS) $(fPIC) $(INCLUDE) -o $@ $(SOURCE_FILES) $< $(LIBPATH) -lm $(LIBRARIES) + +#/ +# Runs compiled benchmarks. +# +# @example +# make run +#/ +run: $(c_targets) + $(QUIET) ./$< + +.PHONY: run + +#/ +# Removes generated files. +# +# @example +# make clean +#/ +clean: + $(QUIET) -rm -f *.o *.out + +.PHONY: clean diff --git a/lib/node_modules/@stdlib/random/base/xorshift32/benchmark/c/benchmark.c b/lib/node_modules/@stdlib/random/base/xorshift32/benchmark/c/benchmark.c new file mode 100644 index 000000000000..6a776e17d337 --- /dev/null +++ b/lib/node_modules/@stdlib/random/base/xorshift32/benchmark/c/benchmark.c @@ -0,0 +1,373 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2025 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. +*/ + +#include "stdlib/random/base/xorshift32.h" +#include "stdlib/random/base/shared.h" +#include +#include +#include +#include +#include +#include + +#define NAME "base/xorshift32" +#define ITERATIONS 1000000 +#define REPEATS 3 + +/** +* Prints the TAP version. +*/ +static void print_version( void ) { + printf( "TAP version 13\n" ); +} + +/** +* Prints the TAP summary. +* +* @param total total number of tests +* @param passing total number of passing tests +*/ +static void print_summary( int total, int passing ) { + printf( "#\n" ); + printf( "1..%d\n", total ); // TAP plan + printf( "# total %d\n", total ); + printf( "# pass %d\n", passing ); + printf( "#\n" ); + printf( "# ok\n" ); +} + +/** +* Prints benchmarks results. +* +* @param elapsed elapsed time in seconds +*/ +static void print_results( double elapsed ) { + double rate = (double)ITERATIONS / elapsed; + printf( " ---\n" ); + printf( " iterations: %d\n", ITERATIONS ); + printf( " elapsed: %0.9f\n", elapsed ); + printf( " rate: %0.9f\n", rate ); + printf( " ...\n" ); +} + +/** +* Returns a clock time. +* +* @return clock time +*/ +static double tic( void ) { + struct timeval now; + gettimeofday( &now, NULL ); + return (double)now.tv_sec + (double)now.tv_usec/1.0e6; +} + +/** +* Generates a random number on the interval [0,1). +* +* @return random number +*/ +static double rand_double( void ) { + int r = rand(); + return (double)r / ( (double)RAND_MAX + 1.0 ); +} + +/** +* Runs a benchmark. +* +* @return elapsed time in seconds +*/ +static double benchmark1( void ) { + double elapsed; + double t; + int i; + + struct BasePRNGObject *obj; + + t = tic(); + for ( i = 0; i < ITERATIONS; i++ ) { + obj = stdlib_base_random_xorshift32_allocate( i+1 ); + if ( obj == NULL || obj->prng->min != 1 ) { + printf( "unexpected result\n" ); + break; + } + if ( i < ITERATIONS-1 ) { + stdlib_base_random_xorshift32_free( obj ); + } + } + elapsed = tic() - t; + + if ( obj == NULL || obj->prng->min != 1 ) { + printf( "unexpected result\n" ); + } + stdlib_base_random_xorshift32_free( obj ); + + return elapsed; +} + +/** +* Runs a benchmark. +* +* @return elapsed time in seconds +*/ +static double benchmark2( void ) { + double elapsed; + int8_t status; + uint64_t max; + uint64_t v; + double t; + int i; + + struct BasePRNGObject *obj = stdlib_base_random_xorshift32_allocate( 12345 ); + if ( obj == NULL ) { + printf( "unable to allocate memory\n" ); + exit( 1 ); + } + max = obj->prng->max; + + t = tic(); + for ( i = 0; i < ITERATIONS; i++ ) { + status = obj->prng->next( obj, &v ); + if ( status != 0 || v > max ) { + printf( "unexpected result\n" ); + break; + } + } + elapsed = tic() - t; + + if ( status != 0 || v > max ) { + printf( "unexpected result\n" ); + } + stdlib_base_random_xorshift32_free( obj ); + + return elapsed; +} + +/** +* Runs a benchmark. +* +* @return elapsed time in seconds +*/ +static double benchmark3( void ) { + double elapsed; + int8_t status; + double v; + double t; + int i; + + struct BasePRNGObject *obj = stdlib_base_random_xorshift32_allocate( 12345 ); + if ( obj == NULL ) { + printf( "unable to allocate memory\n" ); + exit( 1 ); + } + + t = tic(); + for ( i = 0; i < ITERATIONS; i++ ) { + status = obj->prng->normalized( obj, &v ); + if ( status != 0 || v != v ) { + printf( "unexpected result\n" ); + break; + } + } + elapsed = tic() - t; + + if ( status != 0 || v != v ) { + printf( "unexpected result\n" ); + } + stdlib_base_random_xorshift32_free( obj ); + + return elapsed; +} + +/** +* Runs a benchmark. +* +* @return elapsed time in seconds +*/ +static double benchmark4( void ) { + double elapsed; + int8_t status; + int32_t v; + double t; + int i; + + struct BasePRNGObject *obj = stdlib_base_random_xorshift32_allocate( 12345 ); + if ( obj == NULL ) { + printf( "unable to allocate memory\n" ); + exit( 1 ); + } + + t = tic(); + for ( i = 0; i < ITERATIONS; i++ ) { + // NOTE: this is likely to be optimized away by a modern compiler, making this benchmark meaningless. + status = stdlib_base_random_xorshift32_seed( obj, &v ); + if ( status != 0 || v != 12345 ) { + printf( "unexpected result\n" ); + break; + } + } + elapsed = tic() - t; + + if ( status != 0 || v != 12345 ) { + printf( "unexpected result\n" ); + } + stdlib_base_random_xorshift32_free( obj ); + + return elapsed; +} + +/** +* Runs a benchmark. +* +* @return elapsed time in seconds +*/ +static double benchmark5( void ) { + double elapsed; + void *state; + double t; + int i; + + struct BasePRNGObject *obj = stdlib_base_random_xorshift32_allocate( 12345 ); + if ( obj == NULL ) { + printf( "unable to allocate memory\n" ); + exit( 1 ); + } + + t = tic(); + for ( i = 0; i < ITERATIONS; i++ ) { + state = stdlib_base_random_xorshift32_state( obj ); + if ( state == NULL ) { + printf( "unexpected result\n" ); + break; + } + if ( i < ITERATIONS-1 ) { + free( state ); + } + } + elapsed = tic() - t; + + if ( state == NULL ) { + printf( "unexpected result\n" ); + } + stdlib_base_random_xorshift32_free( obj ); + free( state ); + + return elapsed; +} + +/** +* Runs a benchmark. +* +* @return elapsed time in seconds +*/ +static double benchmark6( void ) { + stdlib_base_random_xorshift32_state_t *states[2]; + double elapsed; + int8_t status; + double t; + int i; + + struct BasePRNGObject *obj = stdlib_base_random_xorshift32_allocate( 12345 ); + if ( obj == NULL ) { + printf( "unable to allocate memory\n" ); + exit( 1 ); + } + for ( i = 0; i < 2; i++ ) { + states[i] = (stdlib_base_random_xorshift32_state_t *)malloc( sizeof( stdlib_base_random_xorshift32_state_t ) ); + states[i]->seed = 12345; + states[i]->state = 12345; + } + + t = tic(); + for ( i = 0; i < ITERATIONS; i++ ) { + status = stdlib_base_random_xorshift32_set( obj, (void *)states[i%2] ); + if ( status != 0 ) { + printf( "unexpected result\n" ); + break; + } + } + elapsed = tic() - t; + + if ( status != 0 ) { + printf( "unexpected result\n" ); + } + stdlib_base_random_xorshift32_free( obj ); + for ( i = 0; i < 2; i++ ) { + free( states[i] ); + } + + return elapsed; +} + +/** +* Main execution sequence. +*/ +int main( void ) { + double elapsed; + int count; + int i; + + count = 0; + + // Use the current time to seed the random number generator: + srand( time( NULL ) ); + + print_version(); + for ( i = 0; i < REPEATS; i++ ) { + count += 1; + printf( "# c::%s::instantiation\n", NAME ); + elapsed = benchmark1(); + print_results( elapsed ); + printf( "ok %d benchmark finished\n", count ); + } + for ( i = 0; i < REPEATS; i++ ) { + count += 1; + printf( "# c::%s:next\n", NAME ); + elapsed = benchmark2(); + print_results( elapsed ); + printf( "ok %d benchmark finished\n", count ); + } + for ( i = 0; i < REPEATS; i++ ) { + count += 1; + printf( "# c::%s:normalized\n", NAME ); + elapsed = benchmark3(); + print_results( elapsed ); + printf( "ok %d benchmark finished\n", count ); + } + for ( i = 0; i < REPEATS; i++ ) { + count += 1; + printf( "# c::%s::get:seed\n", NAME ); + elapsed = benchmark4(); + print_results( elapsed ); + printf( "ok %d benchmark finished\n", count ); + } + for ( i = 0; i < REPEATS; i++ ) { + count += 1; + printf( "# c::%s::get:state\n", NAME ); + elapsed = benchmark5(); + print_results( elapsed ); + printf( "ok %d benchmark finished\n", count ); + } + for ( i = 0; i < REPEATS; i++ ) { + count += 1; + printf( "# c::%s::set:state\n", NAME ); + elapsed = benchmark6(); + print_results( elapsed ); + printf( "ok %d benchmark finished\n", count ); + } + print_summary( count, count ); +} 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..d2002ffec5e8 --- /dev/null +++ b/lib/node_modules/@stdlib/random/base/xorshift32/docs/repl.txt @@ -0,0 +1,185 @@ + +{{alias}}() + Returns a pseudorandom integer on the interval `[1, 4294967295]`. + + This pseudorandom number generator (PRNG) is a linear-feedback + shift-register (LFSR) PRNG based on George Marsaglia. + + The generator has a period `2^32-1`. + + Like all LFSRs, the parameters have to be chosen very carefully in order + to achieve a long period. For execution in software, xorshift generators + are among the fastest PRNGs, requiring very small code and state. However, + they do not pass every statistical test without further refinement. + + Returns + ------- + r: integer + Pseudorandom number. + + Examples + -------- + > var r = {{alias}}(); + + +{{alias}}.normalized() + Returns a pseudorandom number on the interval `[0,1)`. + + 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|ArrayLikeObject (optional) + Pseudorandom number generator seed. The seed may be either a positive + unsigned 32-bit integer on the interval `[1, 4294967295]` or, for + arbitrary length seeds, an array-like object containing unsigned 32-bit + integers. + + 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() + 332584831 + + +{{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; + + +{{alias}}.state + Generator state. + + Examples + -------- + > var r = {{alias}}() + + > r = {{alias}}() + + > r = {{alias}}() + + + // Get 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; + + +{{alias}}.byteLength + Size (in bytes) of generator state. + + Examples + -------- + > var sz = {{alias}}.byteLength; + + +{{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..c10b81eb373d --- /dev/null +++ b/lib/node_modules/@stdlib/random/base/xorshift32/docs/types/index.d.ts @@ -0,0 +1,197 @@ +/* +* @license Apache-2.0 +* +* Copyright (c) 2025 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 `[1, 4294967295]`. +*/ +interface NullaryFunction extends PRNG { + /** + * Returns a pseudorandom integer on the interval `[1, 4294967295]`. + * + * @returns pseudorandom number + */ + (): number; +} + +/** +* Interface for generating pseudorandom integers on the interval `[1, 4294967295]`. +*/ +interface Random extends PRNG { + /** + * Returns a pseudorandom integer on the interval `[1, 4294967295]`. + * + * ## Notes + * + * - This pseudorandom number generator (PRNG) is a 32-bit xorshift pseudorandom number generator based on George Marsaglia. + * - The generator has a period of `2^32-1`. + * - Like all LFSRs, the parameters have to be chosen very carefully in order to achieve a long period. For execution in software, xorshift generators are among the fastest PRNGs, requiring very small code and state. However, they do not pass every statistical test without further refinement. + * + * @returns pseudorandom number + * + * @example + * var v = xorshift32(); + * // returns + */ + (): number; + + /** + * Returns a pseudorandom number on the interval `[0,1)`. + * + * @returns pseudorandom number + * + * @example + * var r = 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 `[1, 4294967295]`. +* +* ## Notes +* +* - This pseudorandom number generator (PRNG) is a 32-bit xorshift pseudorandom number generator based on George Marsaglia. +* - The generator has a period of `2^32-1`. +* - Like all LFSRs, the parameters have to be chosen very carefully in order to achieve a long period. For execution in software, xorshift generators are among the fastest PRNGs, requiring very small code and state. However, they do not pass every statistical test without further refinement. +* +* @returns pseudorandom number +* +* @example +* var v = xorshift32(); +* // returns +* +* @example +* var v = xorshift32.normalized(); +* // 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..786b038a3a32 --- /dev/null +++ b/lib/node_modules/@stdlib/random/base/xorshift32/docs/types/test.ts @@ -0,0 +1,106 @@ +/* +* @license Apache-2.0 +* +* Copyright (c) 2025 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 +} + +// Attached to main export is a `normalized` method which returns a number... +{ + xorshift32.normalized(); // $ExpectType number +} + +// The compiler throws an error if the `normalized` method is provided any number of arguments... +{ + xorshift32.normalized( true ); // $ExpectError + xorshift32.normalized( 123 ); // $ExpectError + xorshift32.normalized( 'abc' ); // $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 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 `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 +} diff --git a/lib/node_modules/@stdlib/random/base/xorshift32/examples/c/Makefile b/lib/node_modules/@stdlib/random/base/xorshift32/examples/c/Makefile new file mode 100644 index 000000000000..25ced822f96a --- /dev/null +++ b/lib/node_modules/@stdlib/random/base/xorshift32/examples/c/Makefile @@ -0,0 +1,146 @@ +#/ +# @license Apache-2.0 +# +# Copyright (c) 2025 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. +#/ + +# VARIABLES # + +ifndef VERBOSE + QUIET := @ +else + QUIET := +endif + +# Determine the OS ([1][1], [2][2]). +# +# [1]: https://en.wikipedia.org/wiki/Uname#Examples +# [2]: http://stackoverflow.com/a/27776822/2225624 +OS ?= $(shell uname) +ifneq (, $(findstring MINGW,$(OS))) + OS := WINNT +else +ifneq (, $(findstring MSYS,$(OS))) + OS := WINNT +else +ifneq (, $(findstring CYGWIN,$(OS))) + OS := WINNT +else +ifneq (, $(findstring Windows_NT,$(OS))) + OS := WINNT +endif +endif +endif +endif + +# Define the program used for compiling C source files: +ifdef C_COMPILER + CC := $(C_COMPILER) +else + CC := gcc +endif + +# Define the command-line options when compiling C files: +CFLAGS ?= \ + -std=c99 \ + -O3 \ + -Wall \ + -pedantic + +# Determine whether to generate position independent code ([1][1], [2][2]). +# +# [1]: https://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html#Code-Gen-Options +# [2]: http://stackoverflow.com/questions/5311515/gcc-fpic-option +ifeq ($(OS), WINNT) + fPIC ?= +else + fPIC ?= -fPIC +endif + +# List of includes (e.g., `-I /foo/bar -I /beep/boop/include`): +INCLUDE ?= + +# List of source files: +SOURCE_FILES ?= + +# List of libraries (e.g., `-lopenblas -lpthread`): +LIBRARIES ?= + +# List of library paths (e.g., `-L /foo/bar -L /beep/boop`): +LIBPATH ?= + +# List of C targets: +c_targets := example.out + + +# RULES # + +#/ +# Compiles source files. +# +# @param {string} [C_COMPILER] - C compiler (e.g., `gcc`) +# @param {string} [CFLAGS] - C compiler options +# @param {(string|void)} [fPIC] - compiler flag determining whether to generate position independent code (e.g., `-fPIC`) +# @param {string} [INCLUDE] - list of includes (e.g., `-I /foo/bar -I /beep/boop/include`) +# @param {string} [SOURCE_FILES] - list of source files +# @param {string} [LIBPATH] - list of library paths (e.g., `-L /foo/bar -L /beep/boop`) +# @param {string} [LIBRARIES] - list of libraries (e.g., `-lopenblas -lpthread`) +# +# @example +# make +# +# @example +# make all +#/ +all: $(c_targets) + +.PHONY: all + +#/ +# Compiles C source files. +# +# @private +# @param {string} CC - C compiler (e.g., `gcc`) +# @param {string} CFLAGS - C compiler options +# @param {(string|void)} fPIC - compiler flag determining whether to generate position independent code (e.g., `-fPIC`) +# @param {string} INCLUDE - list of includes (e.g., `-I /foo/bar`) +# @param {string} SOURCE_FILES - list of source files +# @param {string} LIBPATH - list of library paths (e.g., `-L /foo/bar`) +# @param {string} LIBRARIES - list of libraries (e.g., `-lopenblas`) +#/ +$(c_targets): %.out: %.c + $(QUIET) $(CC) $(CFLAGS) $(fPIC) $(INCLUDE) -o $@ $(SOURCE_FILES) $< $(LIBPATH) -lm $(LIBRARIES) + +#/ +# Runs compiled examples. +# +# @example +# make run +#/ +run: $(c_targets) + $(QUIET) ./$< + +.PHONY: run + +#/ +# Removes generated files. +# +# @example +# make clean +#/ +clean: + $(QUIET) -rm -f *.o *.out + +.PHONY: clean diff --git a/lib/node_modules/@stdlib/random/base/xorshift32/examples/c/example.c b/lib/node_modules/@stdlib/random/base/xorshift32/examples/c/example.c new file mode 100644 index 000000000000..9aadb7cd1ac5 --- /dev/null +++ b/lib/node_modules/@stdlib/random/base/xorshift32/examples/c/example.c @@ -0,0 +1,75 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2025 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. +*/ + +#include "stdlib/random/base/xorshift32.h" +#include "stdlib/random/base/shared.h" +#include +#include +#include + +int main( void ) { + int8_t status; + uint32_t seed; + uint64_t v; + int32_t i; + double d; + + // Create a PRNG... + struct BasePRNGObject *obj = stdlib_base_random_xorshift32_allocate( 12345 ); + if ( obj == NULL ) { + fprintf( stderr, "Error allocating memory.\n" ); + exit( 1 ); + } + + status = stdlib_base_random_xorshift32_seed( obj, &seed ); + if ( status != 0 ) { + printf( "Unable to retrieve the PRNG seed.\n" ); + exit( 1 ); + } + printf( "seed = %u\n", seed ); + + printf( "name = %s\n", obj->prng->name ); + printf( "min = %"PRIu64"\n", obj->prng->min ); + printf( "max = %"PRIu64"\n", obj->prng->max ); + + printf( "\nPseudorandom integers...\n" ); + for ( i = 0; i < 10; i++ ) { + status = obj->prng->next( obj, &v ); + if ( status != 0 ) { + printf( "Unexpected result.\n" ); + exit( 1 ); + } + printf( "%"PRIu64"\n", v ); + } + + printf( "\n" ); + printf( "min (normalized) = %0.16f\n", obj->prng->normalized_min ); + printf( "max (normalized) = %0.16f\n", obj->prng->normalized_max ); + + printf( "\nPseudorandom doubles...\n" ); + for ( i = 0; i < 10; i++ ) { + status = obj->prng->normalized( obj, &d ); + if ( status != 0 ) { + printf( "Unexpected result.\n" ); + exit( 1 ); + } + printf( "%0.16f\n", d ); + } + + stdlib_base_random_xorshift32_free( obj ); +} 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..47f82f767d2d --- /dev/null +++ b/lib/node_modules/@stdlib/random/base/xorshift32/examples/index.js @@ -0,0 +1,47 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2025 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( '\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 +}); +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/include/stdlib/random/base/xorshift32.h b/lib/node_modules/@stdlib/random/base/xorshift32/include/stdlib/random/base/xorshift32.h new file mode 100644 index 000000000000..ac46dd0c43d2 --- /dev/null +++ b/lib/node_modules/@stdlib/random/base/xorshift32/include/stdlib/random/base/xorshift32.h @@ -0,0 +1,69 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2025 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. +*/ + +#ifndef STDLIB_RANDOM_BASE_XORSHIFT_H +#define STDLIB_RANDOM_BASE_XORSHIFT_H + +#include "stdlib/random/base/shared.h" +#include + +/* +* If C++, prevent name mangling so that the compiler emits a binary file having undecorated names, thus mirroring the behavior of a C compiler. +*/ +#ifdef __cplusplus +extern "C" { +#endif + +/** +* Declare an opaque type definition for the PRNG state. +*/ +typedef struct { + uint32_t seed; + uint32_t state; +} stdlib_base_random_xorshift32_state_t; + +/** +* Returns a pointer to a dynamically allocated PRNG. +*/ +struct BasePRNGObject * stdlib_base_random_xorshift32_allocate( const uint32_t seed ); + +/** +* Frees a PRNG's allocated memory. +*/ +void stdlib_base_random_xorshift32_free( struct BasePRNGObject *obj ); + +/** +* Returns a PRNG seed. +*/ +int8_t stdlib_base_random_xorshift32_seed( const struct BasePRNGObject *obj, uint32_t *out ); + +/** +* Returns a copy of the current PRNG state. +*/ +void * stdlib_base_random_xorshift32_state( const struct BasePRNGObject *obj ); + +/** +* Sets the PRNG state. +*/ +int8_t stdlib_base_random_xorshift32_set( struct BasePRNGObject *obj, const void *state ); + +#ifdef __cplusplus +} +#endif + +#endif // !STDLIB_RANDOM_BASE_XORSHIFT_H 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..d669d45eabe3 --- /dev/null +++ b/lib/node_modules/@stdlib/random/base/xorshift32/lib/factory.js @@ -0,0 +1,417 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2025 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 isPositiveInteger = require( '@stdlib/assert/is-positive-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 >>> 0; // asm type annotation +var MAX_SEED = UINT32_MAX >>> 0; // asm type annotation + +// 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 much 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 32-bit xorshift pseudorandom number generator based on George Marsaglia. +* +* @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 positive 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 positive integer less than or equal to the maximum unsigned 32-bit integer +* @throws {TypeError} state must be an `Uint32Array` +* @throws {Error} must provide a valid state +* @throws {TypeError} `copy` option must be a boolean +* @returns {PRNG} LCG PRNG +* +* @example +* var xorshift32 = factory(); +* +* var v = xorshift32(); +* // returns +* +* @example +* // Return a seeded LCG: +* var xorshift32 = factory({ +* 'seed': 1234 +* }); +* +* var v = xorshift32(); +* // returns 332584831 +*/ +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 an 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 ( isPositiveInteger( seed ) ) { + if ( seed > MAX_SEED ) { + throw new RangeError( format( 'invalid option. `%s` option must be a positive integer less than or equal to the maximum unsigned 32-bit integer. Option: `%u`.', 'seed', seed ) ); + } + seed >>>= 0; // asm type annotation + } else if ( isCollection( seed ) && seed.length > 0 ) { + slen = seed.length; + STATE = new Uint32Array( STATE_FIXED_LENGTH+slen ); + + // Initialize sections: + STATE[ 0 ] = STATE_ARRAY_VERSION; + STATE[ 1 ] = NUM_STATE_SECTIONS; + STATE[ STATE_SECTION_OFFSET ] = 1; + STATE[ SEED_SECTION_OFFSET ] = slen; + + // 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: + gcopy.ndarray( slen, seed, 1, 0, STATE, 1, SEED_SECTION_OFFSET+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), slen ); + + // Initialize the internal PRNG state: + state[ 0 ] = seed[ 0 ]; + } else { + throw new TypeError( format( 'invalid option. `%s` option must be either a positive integer less than or equal to the maximum unsigned 32-bit integer or an array-like object containing such integers. Option: `%s`.', 'seed', seed ) ); + } + } else { + seed = randuint32() >>> 0; // asm type annotation + } + } + } 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 ]; + } + 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', (xorshift32.MIN-1.0) / NORMALIZATION_CONSTANT ); + setReadOnly( normalized, 'MAX', (xorshift32.MAX-1.0) / NORMALIZATION_CONSTANT ); + + 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 an `Uint32Array` + * @throws {Error} must provide a valid state + */ + function setState( s ) { + var err; + if ( !isUint32Array( s ) ) { + throw new TypeError( format( 'invalid argument. Must provide an 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 integer on the interval \\( [1,2^{32}) \\). + * + * @private + * @returns {uinteger32} pseudorandom integer + */ + function xorshift32() { + var s = state[ 0 ] >>> 0; // asm type annotation + s ^= s << 13; + s ^= s >>> 17; + s ^= s << 5; + state[ 0 ] = s; + return s >>> 0; // asm type annotation + } + + /** + * Generates a pseudorandom number on the interval \\( [0,1) \\). + * + * @private + * @returns {number} pseudorandom number + */ + function normalized() { + return (xorshift32()-1) / 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..fe028af91232 --- /dev/null +++ b/lib/node_modules/@stdlib/random/base/xorshift32/lib/index.js @@ -0,0 +1,57 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2025 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'; + +/** +* A 32-bit xorshift pseudorandom number generator based on George Marsaglia. +* +* @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 20739838 +*/ + +// 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..141e1ff8b926 --- /dev/null +++ b/lib/node_modules/@stdlib/random/base/xorshift32/lib/main.js @@ -0,0 +1,90 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2025 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 integer on the interval \\( [1,2^{32}-1) \\). +* +* ## Method +* +* Xorshift generators are a class of shift-register PRNGs that generate the next state by applying a sequence of bitwise XOR and shift operations, avoiding the use of multiplication or division. +* +* ```c +* state ^= state << a; +* state ^= state >> b; +* state ^= state << c; +* ``` +* +* where \\( state \\) is a positive integer and \\( a, b, c \\) are carefully chosen shift constants. +* +* +* +* In this implementation for 32-bit unsigned integers, the constants are: +* +* ```tex +* \begin{align*} +* a &= 13 \\ +* b &= 17 \\ +* c &= 5 +* \end{align*} +* ``` +* +* +* +* The chosen parameters ensure a full-period generator, meaning it cycles through all nonzero 32-bit unsigned values before repeating. +* +* +* +* Unlike linear congruential generators (LCGs), xorshift PRNGs do not rely on modular arithmetic, making them faster in software but requiring careful parameter selection to maintain statistical properties. +* +* +* +* ## Notes +* +* - Xorshift PRNGs are extremely fast but may fail some statistical tests if not combined with additional non-linear operations. +* - This implementation follows the basic xorshift32 algorithm introduced by George Marsaglia. +* +* ## References +* +* - Marsaglia, G. 2003. "Xorshift RNGs." _Journal of Statistical Software_ 8 (14). Los Angeles, CA, USA: American Statistical Association: 1–6. doi:[10.18637/jss.v008.i14](https://doi.org/10.18637/jss.v008.i14). +* +* @function xorshift +* @type {PRNG} +* @returns {PositiveInteger} pseudorandom 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..ed0944c41d78 --- /dev/null +++ b/lib/node_modules/@stdlib/random/base/xorshift32/lib/rand_uint32.js @@ -0,0 +1,52 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2025 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 - 1; + + +// MAIN // + +/** +* Returns a pseudorandom integer on the interval \\( [1, 2^{32}-1) \\). +* +* @private +* @returns {PositiveInteger} pseudorandom 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/manifest.json b/lib/node_modules/@stdlib/random/base/xorshift32/manifest.json new file mode 100644 index 000000000000..e91236537092 --- /dev/null +++ b/lib/node_modules/@stdlib/random/base/xorshift32/manifest.json @@ -0,0 +1,40 @@ +{ + "options": {}, + "fields": [ + { + "field": "src", + "resolve": true, + "relative": true + }, + { + "field": "include", + "resolve": true, + "relative": true + }, + { + "field": "libraries", + "resolve": false, + "relative": false + }, + { + "field": "libpath", + "resolve": true, + "relative": false + } + ], + "confs": [ + { + "src": [ + "./src/main.c" + ], + "include": [ + "./include" + ], + "libraries": [], + "libpath": [], + "dependencies": [ + "@stdlib/random/base/shared" + ] + } + ] +} 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..6a3faed0a1c2 --- /dev/null +++ b/lib/node_modules/@stdlib/random/base/xorshift32/package.json @@ -0,0 +1,74 @@ +{ + "name": "@stdlib/random/base/xorshift32", + "version": "0.0.0", + "description": "A 32-bit xorshift pseudorandom number generator based on George Marsaglia.", + "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", + "include": "./include", + "lib": "./lib", + "src": "./src", + "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", + "lsfr", + "xorshift32", + "marsaglia", + "seed", + "seedable" + ] +} diff --git a/lib/node_modules/@stdlib/random/base/xorshift32/src/main.c b/lib/node_modules/@stdlib/random/base/xorshift32/src/main.c new file mode 100644 index 000000000000..daf8d8b357ac --- /dev/null +++ b/lib/node_modules/@stdlib/random/base/xorshift32/src/main.c @@ -0,0 +1,424 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2025 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. +*/ + +#include "stdlib/random/base/xorshift32.h" +#include "stdlib/random/base/shared.h" +#include +#include +#include + +// Forward declarations: +static inline int8_t next( struct BasePRNGObject *obj, uint64_t *out ); +static inline int8_t normalized( struct BasePRNGObject *obj, double *out ); +static inline void xorshift32_free( struct BasePRNGObject *obj ); + +// Define the maximum unsigned 32-bit integer: 4294967295 => 0xffffffff => 11111111111111111111111111111111 +static const uint32_t MAX_UINT32 = 0xffffffff; + +// Define the normalization constant: +static const double NORMALIZATION_CONSTANT = (double)MAX_UINT32; + +/** +* Xorshift32 PRNG. +* +*/ +static const struct BasePRNG xorshift32_prng = { + "xorshift32", // name + (uint64_t)1, // min + (uint64_t)MAX_UINT32, // max: 2^{32}-1 + 0.0, // min (normalized) + (MAX_UINT32-1) / NORMALIZATION_CONSTANT, // max (normalized): (MAX-1)/MAX + sizeof( stdlib_base_random_xorshift32_state_t ), // state_size + &next, // next() + &normalized, // normalized() + &xorshift32_free // free() +}; + +/** +* Returns a pseudorandom integer. +* +* ## Notes +* +* - The function returns `-1` if unable to generate a pseudorandom integer and `0` otherwise. +* +* @param obj PRNG object +* @param out output address +* @return status code +*/ +static inline int8_t next( struct BasePRNGObject *obj, uint64_t *out ) { + if ( obj == NULL || obj->prng != &xorshift32_prng ) { + return -1; + } + // Retrieve the state object: + stdlib_base_random_xorshift32_state_t *so = (stdlib_base_random_xorshift32_state_t *)( obj->state ); + + // Retrieve the current state: + uint32_t state = so->state; + + state ^= state << 13; + state ^= state >> 17; + state ^= state << 5; + + // Update the PRNG state: + so->state = state; + + // Set the output value: + *out = (uint64_t)state; + + return 0; +} + +/** +* Returns a pseudorandom double-precision floating-point number on the interval `[0,1)`. +* +* ## Notes +* +* - The function returns `-1` if unable to generate a pseudorandom number and `0` otherwise. +* +* @param obj PRNG object +* @param out output address +* @return status code +*/ +static inline int8_t normalized( struct BasePRNGObject *obj, double *out ) { + uint64_t state; + int8_t status = next( obj, &state ); + if ( status != 0 ) { + return -1; + } + // Note: casting `state` to a double here is fine, as `state` will never exceed the maximum "safe" double-precision floating-point number: + *out = ((double)state-1.0) / NORMALIZATION_CONSTANT; + + return 0; +} + +/** +* Frees a PRNG's allocated memory. +* +* @param obj PRNG object +*/ +static inline void xorshift32_free( struct BasePRNGObject *obj ) { + if ( obj == NULL || obj->prng != &xorshift32_prng ) { + return; + } + free( obj->state ); + free( obj ); +} + +/** +* Returns a pointer to a dynamically allocated PRNG. +* +* ## Notes +* +* - The user is responsible for freeing the allocated memory. +* - A provided `seed` is mapped to the interval `[1,4294967295]`. +* +* @param seed PRNG seed +* @return pointer to a dynamically allocated PRNG or, if unable to allocate memory, a null pointer +* +* @example +* #include "stdlib/random/base/xorshift32.h" +* #include "stdlib/random/base/shared.h" +* #include +* #include +* #include +* +* // Create a PRNG: +* struct BasePRNGObject *obj = stdlib_base_random_xorshift32_allocate( 12345 ); +* if ( obj == NULL ) { +* fprintf( stderr, "Error allocating memory.\n" ); +* exit( 1 ); +* } +* +* uint64_t r; +* int8_t status = obj->prng->next( obj, &r ); +* if ( status != 0 ) { +* fprintf( stderr, "Unexpected result.\n" ); +* exit( 1 ); +* } +* +* // ... +* +* status = obj->prng->next( obj, &r ); +* +* // ... +* +* status = obj->prng->next( obj, &r ); +* +* // ... +* +* // Free allocated memory: +* stdlib_base_random_xorshift32_free( obj ); +*/ +struct BasePRNGObject * stdlib_base_random_xorshift32_allocate( const uint32_t seed ) { + uint32_t iseed; + + struct BasePRNGObject *obj = malloc( sizeof( struct BasePRNGObject ) ); + if ( obj == NULL ) { + return NULL; + } + stdlib_base_random_xorshift32_state_t *state = malloc( sizeof( stdlib_base_random_xorshift32_state_t ) ); + if ( state == NULL ) { + free( obj ); // prevent memory leaks + return NULL; + } + // Ensure that the provided seed is within allowed bounds... + if ( seed == 0 ) { + iseed = 1; + } else { + iseed = seed; + } + state->seed = iseed; + state->state = iseed; + + obj->prng = &xorshift32_prng; + obj->state = state; + + return obj; +} + +/** +* Frees a PRNG's allocated memory. +* +* @param obj PRNG object +* +* @example +* #include "stdlib/random/base/xorshift32.h" +* #include "stdlib/random/base/shared.h" +* #include +* #include +* #include +* +* // Create a PRNG: +* struct BasePRNGObject *obj = stdlib_base_random_xorshift32_allocate( 12345 ); +* if ( obj == NULL ) { +* fprintf( stderr, "Error allocating memory.\n" ); +* exit( 1 ); +* } +* +* uint64_t r; +* int8_t status = obj->prng->next( obj, &r ); +* if ( status != 0 ) { +* fprintf( stderr, "Unexpected result.\n" ); +* exit( 1 ); +* } +* +* // ... +* +* status = obj->prng->next( obj, &r ); +* +* // ... +* +* status = obj->prng->next( obj, &r ); +* +* // ... +* +* // Free allocated memory: +* stdlib_base_random_xorshift32_free( obj ); +*/ +void stdlib_base_random_xorshift32_free( struct BasePRNGObject *obj ) { + if ( obj == NULL || obj->prng != &xorshift32_prng ) { + return; + } + obj->prng->free( obj ); +} + +/** +* Returns a PRNG seed. +* +* ## Notes +* +* - The function returns `-1` if unable to resolve a PRNG seed and `0` otherwise. +* +* @param obj PRNG object +* @param out output address +* @return status code +* +* @example +* #include "stdlib/random/base/xorshift32.h" +* #include "stdlib/random/base/shared.h" +* #include +* #include +* #include +* +* // Create a PRNG: +* struct BasePRNGObject *obj = stdlib_base_random_xorshift32_allocate( 12345 ); +* if ( obj == NULL ) { +* fprintf( stderr, "Error allocating memory.\n" ); +* exit( 1 ); +* } +* +* uint32_t seed; +* int8_t status = stdlib_base_random_xorshift32_seed( obj, &seed ); +* if ( status != 0 ) { +* fprintf( stderr, "Error encountered when attempting to retrieve the PRNG seed.\n" ); +* exit( 1 ); +* } +* +* // Use the seed to, e.g., create another PRNG which will generate the same sequence... +* +* // Free allocated memory: +* stdlib_base_random_xorshift32_free( obj ); +*/ +int8_t stdlib_base_random_xorshift32_seed( const struct BasePRNGObject *obj, uint32_t *out ) { + if ( obj == NULL || obj->prng != &xorshift32_prng ) { + return -1; + } + // Retrieve the Xorshift32 state object: + const stdlib_base_random_xorshift32_state_t *state = (stdlib_base_random_xorshift32_state_t *)( obj->state ); + + // Set the output value: + *out = state->seed; + + return 0; +} + +/** +* Returns a **copy** of the current PRNG state. +* +* ## Notes +* +* - The user is responsible for freeing the allocated memory. +* +* @param obj PRNG object +* @return pointer to a copy of the PRNG's internal state or, if unable to allocate memory, a null pointer +* +* @example +* #include "stdlib/random/base/xorshift32.h" +* #include "stdlib/random/base/shared.h" +* #include +* #include +* #include +* +* // Create a PRNG: +* struct BasePRNGObject *obj = stdlib_base_random_xorshift32_allocate( 12345 ); +* if ( obj == NULL ) { +* fprintf( stderr, "Error allocating memory.\n" ); +* exit( 1 ); +* } +* +* void *state = stdlib_base_random_xorshift32_state( obj ); +* if ( state == NULL ) { +* fprintf( stderr, "Unable to retrieve PRNG state.\n" ); +* exit( 1 ); +* } +* +* // Use the captured state to, e.g., sync another PRNG or to reset a PRNG to a particular state in order to "replay" generated values at a later point in time... +* +* // Free allocated memory: +* stdlib_base_random_xorshift32_free( obj ); +* free( state ); +*/ +void * stdlib_base_random_xorshift32_state( const struct BasePRNGObject *obj ) { + if ( obj == NULL || obj->prng != &xorshift32_prng ) { + return NULL; + } + void *state = malloc( obj->prng->state_size ); + if ( state == NULL ) { + return NULL; + } + memcpy( state, obj->state, obj->prng->state_size ); + return state; +} + +/** +* Sets the PRNG state. +* +* ## Notes +* +* - The function returns `-1` if unable to set a PRNG state and `0` otherwise. +* +* @param obj PRNG object +* @param state state +* @return status code +* +* @example +* #include "stdlib/random/base/xorshift32.h" +* #include "stdlib/random/base/shared.h" +* #include +* #include +* #include +* +* // Create a PRNG: +* struct BasePRNGObject *obj = stdlib_base_random_xorshift32_allocate( 12345 ); +* if ( obj == NULL ) { +* fprintf( stderr, "Error allocating memory.\n" ); +* exit( 1 ); +* } +* +* uint64_t r; +* int8_t status = obj->prng->next( obj, &r ); +* if ( status != 0 ) { +* fprintf( stderr, "Unexpected result.\n" ); +* exit( 1 ); +* } +* +* // ... +* +* status = obj->prng->next( obj, &r ); +* +* // ... +* +* status = obj->prng->next( obj, &r ); +* +* // ... +* +* // Retrieve the current PRNG state... +* void *state = stdlib_base_random_xorshift32_state( obj ); +* if ( state == NULL ) { +* fprintf( stderr, "Error encountered when attempting to retrieve PRNG state.\n" ); +* exit( 1 ); +* } +* +* // ... +* +* status = obj->prng->next( obj, &r ); +* +* // ... +* +* status = obj->prng->next( obj, &r ); +* +* // ... +* +* // Reset the PRNG to a previous state... +* status = stdlib_base_random_xorshift32_set( obj, state ); +* if ( status != 0 ) { +* fprintf( stderr, "Error encountered when attempting to set PRNG state.\n" ); +* exit( 1 ); +* } +* +* // ... +* +* status = obj->prng->next( obj, &r ); +* +* // ... +* +* status = obj->prng->next( obj, &r ); +* +* // ... +* +* // Free allocated memory: +* stdlib_base_random_xorshift32_free( obj ); +* free( state ); +*/ +int8_t stdlib_base_random_xorshift32_set( struct BasePRNGObject *obj, const void *state ) { + if ( obj == NULL || state == NULL || obj->prng != &xorshift32_prng ) { + return -1; + } + memcpy( obj->state, state, obj->prng->state_size ); + return 0; +} 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..668aae9c40c3 --- /dev/null +++ b/lib/node_modules/@stdlib/random/base/xorshift32/test/test.factory.js @@ -0,0 +1,1634 @@ +/* eslint-disable max-lines */ + +/** +* @license Apache-2.0 +* +* Copyright (c) 2025 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 ENV = require( '@stdlib/process/env' ); +var UINT32_MAX = require( '@stdlib/constants/uint32/max' ); +var now = require( '@stdlib/time/now' ); +var isPositiveInteger = require( '@stdlib/math/base/assert/is-positive-integer' ); +var isUint32Array = require( '@stdlib/assert/is-uint32array' ); +var Uint32Array = require( '@stdlib/array/uint32' ); +var kstest = require( '@stdlib/stats/kstest' ); +var gcopy = require( '@stdlib/blas/base/gcopy' ); +var typedarray2json = require( '@stdlib/array/to-json' ); +var factory = require( './../lib/factory.js' ); + + +// VARIABLES // + +var opts = { + 'skip': ( ENV.TEST_MODE === 'coverage' ) +}; + + +// 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( 'if provided an options argument which is not an object, the factory function throws an error', function test( t ) { + var values; + var i; + + values = [ + '5', + 3, + NaN, + true, + false, + null, + void 0, + [], + function noop() {} + ]; + + for ( i = 0; i < values.length; i++ ) { + t.throws( badValue( values[i] ), TypeError, 'throws a type error when provided '+values[i] ); + } + t.end(); + + function badValue( value ) { + return function badValue() { + factory( value ); + }; + } +}); + +tape( 'if provided a `copy` option which is not a boolean, the factory function throws an error', 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 type error when provided '+values[i] ); + } + t.end(); + + function badValue( value ) { + return function badValue() { + factory({ + 'copy': value + }); + }; + } +}); + +tape( 'if provided a `seed` which is not a positive integer or a non-empty array-like object, the factory function throws an error', function test( t ) { + var values; + var i; + + values = [ + '5', + 3.14, + 0.0, + -5.0, + NaN, + true, + false, + null, + void 0, + [], + {}, + function noop() {} + ]; + + for ( i = 0; i < values.length; i++ ) { + t.throws( badValue( values[i] ), TypeError, 'throws a type error when provided '+values[i] ); + } + t.end(); + + function badValue( value ) { + return function badValue() { + factory({ + 'seed': value + }); + }; + } +}); + +tape( 'the function throws a range error if provided a `seed` greater than the maximum unsigned 32-bit integer', function test( t ) { + var values; + var i; + + values = [ + UINT32_MAX + 1, + UINT32_MAX + 2, + UINT32_MAX + 3 + ]; + + for ( i = 0; i < values.length; i++ ) { + t.throws( badValue( values[i] ), RangeError, 'throws a range error when provided '+values[i] ); + } + t.end(); + + function badValue( value ) { + return function badValue() { + factory({ + 'seed': value + }); + }; + } +}); + +tape( 'if provided a `state` option which is not an Uint32Array, the factory function throws an error', 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 type error when provided '+values[i] ); + } + t.end(); + + function badValue( value ) { + return function badValue() { + factory({ + 'state': value + }); + }; + } +}); + +tape( 'if provided a `state` option having an insufficient length, the factory function throws an error', function test( t ) { + var values; + var i; + + values = [ + new Uint32Array( 0 ), + new Uint32Array( 1 ) + ]; + + for ( i = 0; i < values.length; i++ ) { + t.throws( badValue( values[i] ), RangeError, 'throws an error when provided '+values[i] ); + } + t.end(); + + function badValue( value ) { + return function badValue() { + factory({ + 'state': value + }); + }; + } +}); + +tape( 'if provided a `state` option containing an unsupported version, the factory function throws an error', function test( t ) { + var values; + var v; + var i; + + values = []; + + v = new Uint32Array( 6 ); + v[ 0 ] = 0; // version + v[ 1 ] = 2; // number of sections + v[ 2 ] = 1; // state length + v[ 3 ] = 1; // state + v[ 4 ] = 1; // seed length + v[ 5 ] = 123; // seed + values.push( v ); + + v = new Uint32Array( 7 ); + v[ 0 ] = 0; // version + v[ 1 ] = 2; // number of sections + v[ 2 ] = 1; // state length + v[ 3 ] = 1; // state + v[ 4 ] = 1; // seed length + v[ 5 ] = 123; // seed + v[ 6 ] = 456; // seed + values.push( v ); + + for ( i = 0; i < values.length; i++ ) { + t.throws( badValue( values[i] ), RangeError, 'throws an error when provided '+values[i] ); + } + t.end(); + + function badValue( value ) { + return function badValue() { + factory({ + 'state': value + }); + }; + } +}); + +tape( 'if provided a `state` option containing an unsupported number of sections, the factory function throws an error', function test( t ) { + var values; + var v; + var i; + + values = []; + + v = new Uint32Array( 6 ); + v[ 0 ] = 1; // version + v[ 1 ] = 3; // number of sections + v[ 2 ] = 1; // state length + v[ 3 ] = 1; // state + v[ 4 ] = 1; // seed length + v[ 5 ] = 123; // seed + values.push( v ); + + v = new Uint32Array( 7 ); + v[ 0 ] = 1; // version + v[ 1 ] = 3; // number of sections + v[ 2 ] = 1; // state length + v[ 3 ] = 1; // state + v[ 4 ] = 1; // seed length + v[ 5 ] = 123; // seed + v[ 6 ] = 456; // seed + values.push( v ); + + for ( i = 0; i < values.length; i++ ) { + t.throws( badValue( values[i] ), RangeError, 'throws an error when provided '+values[i] ); + } + t.end(); + + function badValue( value ) { + return function badValue() { + factory({ + 'state': value + }); + }; + } +}); + +tape( 'if provided a `state` option containing an unsupported state length, the factory function throws an error', function test( t ) { + var values; + var v; + var i; + + values = []; + + v = new Uint32Array( 7 ); + v[ 0 ] = 1; // version + v[ 1 ] = 2; // number of sections + v[ 2 ] = 2; // state length + v[ 3 ] = 1; // state + v[ 4 ] = 1; // state + v[ 5 ] = 1; // seed length + v[ 6 ] = 123; // seed + values.push( v ); + + v = new Uint32Array( 8 ); + v[ 0 ] = 1; // version + v[ 1 ] = 2; // number of sections + v[ 2 ] = 2; // state length + v[ 3 ] = 1; // state + v[ 4 ] = 1; // state + v[ 5 ] = 1; // seed length + v[ 6 ] = 123; // seed + v[ 7 ] = 456; // seed + values.push( v ); + + for ( i = 0; i < values.length; i++ ) { + t.throws( badValue( values[i] ), RangeError, 'throws an error when provided '+values[i] ); + } + t.end(); + + function badValue( value ) { + return function badValue() { + factory({ + 'state': value + }); + }; + } +}); + +tape( 'if provided a `state` option containing an incompatible seed length, the factory function throws an error', function test( t ) { + var values; + var v; + var i; + + values = []; + + v = new Uint32Array( 6 ); + v[ 0 ] = 1; // version + v[ 1 ] = 2; // number of sections + v[ 2 ] = 1; // state length + v[ 3 ] = 1; // state + v[ 4 ] = 9; // seed length + v[ 5 ] = 123; // seed + values.push( v ); + + v = new Uint32Array( 7 ); + v[ 0 ] = 1; // version + v[ 1 ] = 2; // number of sections + v[ 2 ] = 1; // state length + v[ 3 ] = 1; // state + v[ 4 ] = 9; // seed length + v[ 5 ] = 123; // seed + v[ 6 ] = 456; // seed + values.push( v ); + + for ( i = 0; i < values.length; i++ ) { + t.throws( badValue( values[i] ), RangeError, 'throws an error when provided '+values[i] ); + } + t.end(); + + function badValue( value ) { + return function badValue() { + factory({ + 'state': value + }); + }; + } +}); + +tape( 'the function returns a pseudorandom number generator (no options)', function test( t ) { + var xorshift32; + var v; + var i; + + xorshift32 = factory(); + for ( i = 0; i < 1e3; i++ ) { + v = xorshift32(); + t.equal( typeof v, 'number', 'returns a number' ); + t.equal( isPositiveInteger( v ), true, 'returns a positive integer' ); + t.equal( v >= 1 && v <= UINT32_MAX, true, 'returns an integer between 1 and 2^32-1 (inclusive)' ); + } + t.end(); +}); + +tape( 'the function returns a pseudorandom number generator (options; no seed)', function test( t ) { + var xorshift32; + var v; + var i; + + xorshift32 = factory( {} ); + for ( i = 0; i < 1e3; i++ ) { + v = xorshift32(); + t.equal( typeof v, 'number', 'returns a number' ); + t.equal( isPositiveInteger( v ), true, 'returns a positive integer' ); + t.equal( v >= 1 && v <= UINT32_MAX, true, 'returns an integer between 1 and 2^32-1 (inclusive)' ); + } + t.end(); +}); + +tape( 'the function returns a seeded pseudorandom number generator (integer seed)', function test( t ) { + var xorshift1; + var xorshift2; + var seed; + var v1; + var v2; + var i; + + seed = now(); + + xorshift1 = factory({ + 'seed': seed + }); + xorshift2 = factory({ + 'seed': seed + }); + + t.notEqual( xorshift1, xorshift2, 'separate generators' ); + + for ( i = 0; i < 1e3; i++ ) { + v1 = xorshift1(); + v2 = xorshift2(); + t.equal( v1, v2, 'both return same number' ); + } + t.end(); +}); + +tape( 'the function returns a seeded pseudorandom number generator (array seed)', function test( t ) { + var xorshift1; + var xorshift2; + var seed; + var v1; + var v2; + var i; + + seed = [ now() ]; + + xorshift1 = factory({ + 'seed': seed + }); + xorshift2 = factory({ + 'seed': seed + }); + + t.notEqual( xorshift1, xorshift2, 'separate generators' ); + + for ( i = 0; i < 1e3; i++ ) { + v1 = xorshift1(); + v2 = xorshift2(); + t.equal( v1, v2, 'both return same number' ); + } + t.end(); +}); + +tape( 'attached to the returned function is the generator name', function test( t ) { + var xorshift32 = factory(); + t.equal( 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.equal( 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.equal( xorshift32.MAX, UINT32_MAX, 'has property' ); + t.end(); +}); + +tape( 'attached to the returned function is the generator seed (integer seed)', function test( t ) { + var xorshift32; + var actual; + + xorshift32 = factory({ + 'seed': 12345 + }); + actual = xorshift32.seed; + + t.equal( isUint32Array( actual ), true, 'has property' ); + t.equal( actual.length, 1, 'has expected length' ); + t.equal( actual[ 0 ], 12345, 'equal to provided seed' ); + t.end(); +}); + +tape( 'attached to the returned function is the generator seed (array seed)', function test( t ) { + var xorshift32; + var actual; + var seed; + var i; + + seed = [ 12345 ]; + + xorshift32 = factory({ + 'seed': seed + }); + actual = xorshift32.seed; + + t.equal( isUint32Array( actual ), true, 'has property' ); + for ( i = 0; i < seed.length; i++ ) { + t.equal( actual[ i ], seed[ i ], 'returns expected value for word '+i ); + } + t.end(); +}); + +tape( 'attached to the returned function is the generator seed length', function test( t ) { + var xorshift32 = factory(); + t.equal( 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.equal( 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.equal( 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.equal( typeof xorshift32.byteLength, 'number', 'has property' ); + t.end(); +}); + +tape( 'attached to the returned function is a method to serialize the generator as a JSON object', function test( t ) { + var xorshift32; + var o; + + xorshift32 = factory(); + t.equal( typeof xorshift32.toJSON, 'function', 'has method' ); + + o = xorshift32.toJSON(); + t.equal( o.type, 'PRNG', 'has property' ); + t.equal( o.name, xorshift32.NAME, 'has property' ); + t.deepEqual( o.state, typedarray2json( xorshift32.state ), 'has property' ); + t.deepEqual( o.params, [], 'has property' ); + + t.end(); +}); + +tape( 'if the `state` property is set to a value other than an Uint32Array, an error is thrown', function test( t ) { + var xorshift32; + var values; + var i; + + xorshift32 = factory(); + + values = [ + '3', + 3, + -3, + 3.14, + 0, + NaN, + true, + false, + null, + void 0, + [], + {}, + function noop() {} + ]; + for ( i = 0; i < values.length; i++ ) { + t.throws( badValue( values[i] ), TypeError, 'throws a type error when set to '+values[i] ); + } + t.end(); + + function badValue( value ) { + return function badValue() { + xorshift32.state = value; + }; + } +}); + +tape( 'if the `state` property is set to an Uint32Array containing an unsupported version, an error is thrown', function test( t ) { + var xorshift32; + var values; + var v; + var i; + + xorshift32 = factory(); + + values = []; + + v = new Uint32Array( 6 ); + v[ 0 ] = 0; // version + v[ 1 ] = 2; // number of sections + v[ 2 ] = 1; // state length + v[ 3 ] = 1; // state + v[ 4 ] = 1; // seed length + v[ 5 ] = 123; // seed + values.push( v ); + + v = new Uint32Array( 7 ); + v[ 0 ] = 0; // version + v[ 1 ] = 2; // number of sections + v[ 2 ] = 1; // state length + v[ 3 ] = 1; // state + v[ 4 ] = 1; // seed length + v[ 5 ] = 123; // seed + v[ 6 ] = 456; // seed + values.push( v ); + + for ( i = 0; i < values.length; i++ ) { + t.throws( badValue( values[i] ), RangeError, 'throws an error when provided '+values[i] ); + } + t.end(); + + function badValue( value ) { + return function badValue() { + xorshift32.state = value; + }; + } +}); + +tape( 'if the `state` property is set to an Uint32Array containing an unsupported number of sections, an error is thrown', function test( t ) { + var xorshift32; + var values; + var v; + var i; + + xorshift32 = factory(); + + values = []; + + v = new Uint32Array( 6 ); + v[ 0 ] = 1; // version + v[ 1 ] = 3; // number of sections + v[ 2 ] = 1; // state length + v[ 3 ] = 1; // state + v[ 4 ] = 1; // seed length + v[ 5 ] = 123; // seed + values.push( v ); + + v = new Uint32Array( 7 ); + v[ 0 ] = 1; // version + v[ 1 ] = 3; // number of sections + v[ 2 ] = 1; // state length + v[ 3 ] = 1; // state + v[ 4 ] = 1; // seed length + v[ 5 ] = 123; // seed + v[ 6 ] = 456; // seed + values.push( v ); + + for ( i = 0; i < values.length; i++ ) { + t.throws( badValue( values[i] ), RangeError, 'throws an error when provided '+values[i] ); + } + t.end(); + + function badValue( value ) { + return function badValue() { + xorshift32.state = value; + }; + } +}); + +tape( 'if the `state` property is set to an Uint32Array containing an unsupported state length, an error is thrown', function test( t ) { + var xorshift32; + var values; + var v; + var i; + + xorshift32 = factory(); + + values = []; + + v = new Uint32Array( 7 ); + v[ 0 ] = 1; // version + v[ 1 ] = 2; // number of sections + v[ 2 ] = 2; // state length + v[ 3 ] = 1; // state + v[ 4 ] = 1; // state + v[ 5 ] = 1; // seed length + v[ 6 ] = 123; // seed + values.push( v ); + + v = new Uint32Array( 8 ); + v[ 0 ] = 1; // version + v[ 1 ] = 2; // number of sections + v[ 2 ] = 2; // state length + v[ 3 ] = 1; // state + v[ 4 ] = 1; // state + v[ 5 ] = 1; // seed length + v[ 6 ] = 123; // seed + v[ 7 ] = 456; // seed + values.push( v ); + + for ( i = 0; i < values.length; i++ ) { + t.throws( badValue( values[i] ), RangeError, 'throws an error when provided '+values[i] ); + } + t.end(); + + function badValue( value ) { + return function badValue() { + xorshift32.state = value; + }; + } +}); + +tape( 'if the `state` property is set to an Uint32Array containing an incompatible seed length, an error is thrown', function test( t ) { + var xorshift32; + var values; + var v; + var i; + + xorshift32 = factory(); + + values = []; + + v = new Uint32Array( 6 ); + v[ 0 ] = 1; // version + v[ 1 ] = 2; // number of sections + v[ 2 ] = 1; // state length + v[ 3 ] = 1; // state + v[ 4 ] = 9; // seed length + v[ 5 ] = 123; // seed + values.push( v ); + + v = new Uint32Array( 7 ); + v[ 0 ] = 1; // version + v[ 1 ] = 2; // number of sections + v[ 2 ] = 1; // state length + v[ 3 ] = 1; // state + v[ 4 ] = 9; // seed length + v[ 5 ] = 123; // seed + v[ 6 ] = 456; // seed + values.push( v ); + + for ( i = 0; i < values.length; i++ ) { + t.throws( badValue( values[i] ), RangeError, 'throws an error when provided '+values[i] ); + } + t.end(); + + function badValue( value ) { + return function badValue() { + xorshift32.state = value; + }; + } +}); + +tape( 'attached to the returned function is a `normalized` method for generating pseudorandom numbers strictly between 0 (inclusive) and 1 (exclusive)', function test( t ) { + var xorshift32; + var v; + var i; + + xorshift32 = factory(); + for ( i = 0; i < 1e3; i++ ) { + v = xorshift32.normalized(); + t.equal( typeof v, 'number', 'returns a number' ); + t.equal( v >= 0.0 && v < 1.0, true, 'returns a number between 0 (inclusive) and 1 (exclusive)' ); + } + t.end(); +}); + +tape( 'attached to the `normalized` method is the generator name', function test( t ) { + var xorshift32 = factory(); + t.equal( 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.equal( xorshift32.normalized.MIN, 0.0, 'has property' ); + t.end(); +}); + +tape( 'attached to the `normalized` method is the maximum possible generated number', function test( t ) { + var xorshift32 = factory(); + t.equal( xorshift32.normalized.MAX, (UINT32_MAX-1.0)/UINT32_MAX, 'has property' ); + t.end(); +}); + +tape( 'attached to the `normalized` method is the generator seed (integer seed)', function test( t ) { + var xorshift32; + var actual; + + xorshift32 = factory({ + 'seed': 12345 + }); + actual = xorshift32.normalized.seed; + + t.equal( isUint32Array( actual ), true, 'has property' ); + t.equal( actual.length, 1, 'has expected length' ); + t.equal( actual[ 0 ], 12345, 'equal to provided seed' ); + t.end(); +}); + +tape( 'attached to the `normalized` method is the generator seed (array seed)', function test( t ) { + var xorshift32; + var actual; + var seed; + var i; + + seed = [ 12345 ]; + xorshift32 = factory({ + 'seed': seed + }); + actual = xorshift32.normalized.seed; + + t.equal( isUint32Array( actual ), true, 'has property' ); + for ( i = 0; i < seed.length; i++ ) { + t.equal( actual[ i ], seed[ i ], 'returns expected value for word '+i ); + } + t.end(); +}); + +tape( 'attached to the `normalized` method is the generator seed length', function test( t ) { + var xorshift32 = factory(); + t.equal( 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.equal( 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.equal( 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.equal( typeof xorshift32.normalized.byteLength, 'number', 'has property' ); + t.end(); +}); + +tape( 'attached to the `normalized` method is a method to serialize the generator as a JSON object', function test( t ) { + var xorshift32; + var o; + + xorshift32 = factory(); + t.equal( typeof xorshift32.normalized.toJSON, 'function', 'has method' ); + + o = xorshift32.normalized.toJSON(); + t.equal( o.type, 'PRNG', 'has property' ); + t.equal( o.name, xorshift32.normalized.NAME, 'has property' ); + t.deepEqual( o.state, typedarray2json( xorshift32.normalized.state ), 'has property' ); + + t.end(); +}); + +tape( 'if the `state` property is set to a value other than an Uint32Array, an error is thrown (normalized)', function test( t ) { + var xorshift32; + var values; + var i; + + xorshift32 = factory(); + + values = [ + '3', + -3, + 3, + 3.14, + 0, + NaN, + true, + false, + null, + void 0, + [], + {}, + function noop() {} + ]; + for ( i = 0; i < values.length; i++ ) { + t.throws( badValue( values[i] ), TypeError, 'throws an error when set to '+values[i] ); + } + t.end(); + + function badValue( value ) { + return function badValue() { + xorshift32.normalized.state = value; + }; + } +}); + +tape( 'if the `state` property is set to an Uint32Array having an unexpected length, an error is thrown (normalized)', function test( t ) { + var xorshift32; + var values; + var i; + + xorshift32 = factory(); + + values = [ + new Uint32Array( 0 ), + new Uint32Array( 1 ) + ]; + for ( i = 0; i < values.length; i++ ) { + t.throws( badValue( values[i] ), RangeError, 'throws an error when set to '+values[i] ); + } + t.end(); + + function badValue( value ) { + return function badValue() { + xorshift32.normalized.state = value; + }; + } +}); + +tape( 'if the `state` property is set to an Uint32Array containing an unsupported version, an error is thrown (normalized)', function test( t ) { + var xorshift32; + var values; + var v; + var i; + + xorshift32 = factory(); + + values = []; + + v = new Uint32Array( 6 ); + v[ 0 ] = 0; // version + v[ 1 ] = 2; // number of sections + v[ 2 ] = 1; // state length + v[ 3 ] = 1; // state + v[ 4 ] = 1; // seed length + v[ 5 ] = 123; // seed + values.push( v ); + + v = new Uint32Array( 7 ); + v[ 0 ] = 0; // version + v[ 1 ] = 2; // number of sections + v[ 2 ] = 1; // state length + v[ 3 ] = 1; // state + v[ 4 ] = 1; // seed length + v[ 5 ] = 123; // seed + v[ 6 ] = 456; // seed + values.push( v ); + + for ( i = 0; i < values.length; i++ ) { + t.throws( badValue( values[i] ), RangeError, 'throws an error when provided '+values[i] ); + } + t.end(); + + function badValue( value ) { + return function badValue() { + xorshift32.normalized.state = value; + }; + } +}); + +tape( 'if the `state` property is set to an Uint32Array containing an unsupported number of sections, an error is thrown (normalized)', function test( t ) { + var xorshift32; + var values; + var v; + var i; + + xorshift32 = factory(); + + values = []; + + v = new Uint32Array( 6 ); + v[ 0 ] = 0; // version + v[ 1 ] = 3; // number of sections + v[ 2 ] = 1; // state length + v[ 3 ] = 1; // state + v[ 4 ] = 1; // seed length + v[ 5 ] = 123; // seed + values.push( v ); + + v = new Uint32Array( 7 ); + v[ 0 ] = 0; // version + v[ 1 ] = 3; // number of sections + v[ 2 ] = 1; // state length + v[ 3 ] = 1; // state + v[ 4 ] = 1; // seed length + v[ 5 ] = 123; // seed + v[ 6 ] = 456; // seed + values.push( v ); + + for ( i = 0; i < values.length; i++ ) { + t.throws( badValue( values[i] ), RangeError, 'throws an error when provided '+values[i] ); + } + t.end(); + + function badValue( value ) { + return function badValue() { + xorshift32.normalized.state = value; + }; + } +}); + +tape( 'if the `state` property is set to an Uint32Array containing an unsupported state length, an error is thrown (normalized)', function test( t ) { + var xorshift32; + var values; + var v; + var i; + + xorshift32 = factory(); + + values = []; + + v = new Uint32Array( 7 ); + v[ 0 ] = 0; // version + v[ 1 ] = 2; // number of sections + v[ 2 ] = 2; // state length + v[ 3 ] = 1; // state + v[ 4 ] = 1; // state + v[ 5 ] = 1; // seed length + v[ 6 ] = 123; // seed + values.push( v ); + + v = new Uint32Array( 8 ); + v[ 0 ] = 0; // version + v[ 1 ] = 2; // number of sections + v[ 2 ] = 2; // state length + v[ 3 ] = 1; // state + v[ 4 ] = 1; // state + v[ 5 ] = 1; // seed length + v[ 6 ] = 123; // seed + v[ 7 ] = 456; // seed + values.push( v ); + + for ( i = 0; i < values.length; i++ ) { + t.throws( badValue( values[i] ), RangeError, 'throws an error when provided '+values[i] ); + } + t.end(); + + function badValue( value ) { + return function badValue() { + xorshift32.normalized.state = value; + }; + } +}); + +tape( 'if the `state` property is set to an Uint32Array containing an incompatible seed length, an error is thrown (normalized)', function test( t ) { + var xorshift32; + var values; + var v; + var i; + + xorshift32 = factory(); + + values = []; + + v = new Uint32Array( 6 ); + v[ 0 ] = 0; // version + v[ 1 ] = 2; // number of sections + v[ 2 ] = 1; // state length + v[ 3 ] = 1; // state + v[ 4 ] = 9; // seed length + v[ 5 ] = 123; // seed + values.push( v ); + + v = new Uint32Array( 7 ); + v[ 0 ] = 0; // version + v[ 1 ] = 2; // number of sections + v[ 2 ] = 1; // state length + v[ 3 ] = 1; // state + v[ 4 ] = 9; // seed length + v[ 5 ] = 123; // seed + v[ 6 ] = 456; // seed + values.push( v ); + + for ( i = 0; i < values.length; i++ ) { + t.throws( badValue( values[i] ), RangeError, 'throws an error when provided '+values[i] ); + } + t.end(); + + function badValue( value ) { + return function badValue() { + xorshift32.normalized.state = value; + }; + } +}); + +tape( 'the `normalized` method returns pseudorandom numbers drawn from a uniform distribution', opts, function test( t ) { + var threshold; + var count; + var npass; + var N; + var x; + + threshold = 0.10; + + x = new Array( 1e3 ); // eslint-disable-line stdlib/no-new-array + N = 500; + + count = -1; + npass = 0; + + gof(); + + function gof() { + var xorshift32; + var rejected; + var pValue; + var bool; + var i; + var j; + + count += 1; + rejected = 0; + for ( i = 0; i < N; i++ ) { + xorshift32 = factory(); + t.ok( true, 'seed: '+xorshift32.seed ); + for ( j = 0; j < x.length; j++ ) { + x[ j ] = xorshift32.normalized(); + if ( x[ j ] < 0.0 || x[ j ] > 1.0 ) { + t.ok( false, 'returned a number outside support: '+x[ j ] ); + } + } + // Test using Kolmogorov-Smirnov goodness-of-fit test: + pValue = kstest( x, 'uniform', 0.0, 1.0 ).pValue; + t.equal( typeof pValue, 'number', 'returns a p-value: '+pValue ); + if ( pValue < 0.05 ) { + rejected += 1; + } + } + // Account for small sample size and few repeats... + bool = ( rejected / N < threshold ); + + // If we succeed the first time, we are done... + if ( count === 0 && bool ) { + return done( bool, rejected ); + } + // Retry mode... + if ( bool ) { + npass += 1; + } + // Retry twice... + if ( count < 2 ) { + return gof(); + } + // Both retries must succeed for test to pass: + bool = ( npass >= 2 ); + return done( bool, rejected ); + } + + function done( bool, rejected ) { + t.ok( bool, 'null hypothesis (i.e., that numbers are drawn from Uniform(0,1)) is rejected in less than '+(threshold*100)+'% of cases ('+rejected+' of '+N+'). Repeats: '+npass+' of '+count+'.' ); + t.end(); + } +}); + +tape( 'the function supports specifying 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() ); + } + + // Create another PRNG using the captured state: + xorshift32 = factory({ + 'state': state + }); + + // Replay previously generated values... + for ( i = 0; i < 100; i++ ) { + t.equal( xorshift32(), arr[ i ], 'returns expected value. i: '+i+'.' ); + } + t.end(); +}); + +tape( 'the function supports specifying a shared generator state', function test( t ) { + var xorshift32; + var shared; + var state; + var rand1; + var rand2; + var arr; + var v1; + var v2; + var i; + var j; + + 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() ); + } + + // Create a copy of the state (to prevent mutation) which will be shared by more than one PRNG: + shared = new Uint32Array( state ); + + // Create PRNGs using the captured state: + rand1 = factory({ + 'state': shared, + 'copy': false + }); + rand2 = factory({ + 'state': shared, + 'copy': false + }); + + // Replay previously generated values... + j = 0; + for ( i = 0; i < 50; i++ ) { + v1 = rand1(); + v2 = rand2(); + t.equal( v1, arr[ j ], 'returns expected value. i: '+j+'.' ); + t.equal( v2, arr[ j+1 ], 'returns expected value. i: '+(j+1)+'.' ); + j += 2; // stride + } + 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.equal( xorshift32(), arr[ i ], 'returns expected value. i: '+i+'.' ); + } + t.end(); +}); + +tape( 'the returned function supports setting the generator state to a state array having a different length', function test( t ) { + var xorshift32; + var shared; + var state; + var rand1; + var rand2; + var arr; + var v1; + var v2; + var i; + + // Seed length: 2 + xorshift32 = factory({ + 'seed': [ 1234, 5678 ] + }); + + // 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() ); + } + + // Create a copy of the state (to prevent mutation) which will be shared by more than one PRNG: + shared = new Uint32Array( state ); + + // Create PRNGs having seed lengths equal to 1: + rand1 = factory({ + 'seed': [ 6789 ] + }); + rand2 = factory({ + 'seed': [ 4321 ] + }); + + // Move to future states... + for ( i = 0; i < 100; i++ ) { + v1 = rand1(); + v2 = rand2(); + } + + // Reset the PRNG states: + rand1.state = shared; + rand2.state = shared; + + // Replay previously generated values... + for ( i = 0; i < 100; i++ ) { + v1 = rand1(); + t.equal( v1, arr[ i ], 'returns expected value. i: '+i+'.' ); + v2 = rand2(); + t.equal( v2, 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.equal( xorshift32.normalized(), 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.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.equal( xorshift32.normalized(), arr[ i ], 'returns expected value. i: '+i+'.' ); + } + t.end(); +}); + +tape( 'the returned function supports setting a shared generator state (same length)', function test( t ) { + var xorshift32; + var shared; + var state; + var rand1; + var rand2; + var arr; + var v1; + var v2; + var i; + var j; + + 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() ); + } + + // Create a copy of the state (to prevent mutation) which will be shared by more than one PRNG: + shared = new Uint32Array( state ); + + // Create PRNGs using the captured state: + rand1 = factory({ + 'state': shared, + 'copy': false + }); + rand2 = factory({ + 'state': shared, + 'copy': false + }); + + // Replay previously generated values... + j = 0; + for ( i = 0; i < 50; i++ ) { + v1 = rand1(); + v2 = rand2(); + t.equal( v1, arr[ j ], 'returns expected value. i: '+j+'.' ); + t.equal( v2, arr[ j+1 ], 'returns expected value. i: '+(j+1)+'.' ); + j += 2; // stride + } + + // Move to a future state... + for ( i = 0; i < 100; i++ ) { + v2 = rand2(); + } + + // Reset the (shared) state: + rand1.state = new Uint32Array( state ); + + // Replay previously generated values... + j = 0; + for ( i = 0; i < 50; i++ ) { + v1 = rand1(); + v2 = rand2(); + t.equal( v1, arr[ j ], 'returns expected value. i: '+j+'.' ); + t.equal( v2, arr[ j+1 ], 'returns expected value. i: '+(j+1)+'.' ); + j += 2; // stride + } + t.end(); +}); + +tape( 'the returned function supports setting a shared generator state (different length)', function test( t ) { + var xorshift32; + var shared; + var state; + var rand1; + var rand2; + var arr; + var v1; + var v2; + var s; + var i; + var j; + + 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() ); + } + + // Create a copy of the state (to prevent mutation) which will be shared by more than one PRNG: + shared = new Uint32Array( state ); + + // Create PRNGs using the captured state: + rand1 = factory({ + 'state': shared, + 'copy': false + }); + rand2 = factory({ + 'state': shared, + 'copy': false + }); + + // Replay previously generated values... + j = 0; + for ( i = 0; i < 50; i++ ) { + v1 = rand1(); + v2 = rand2(); + t.equal( v1, arr[ j ], 'returns expected value. i: '+j+'.' ); + t.equal( v2, arr[ j+1 ], 'returns expected value. i: '+(j+1)+'.' ); + j += 2; // stride + } + + // Move to a future state... + for ( i = 0; i < 100; i++ ) { + v2 = rand2(); + } + + // Reset the (*previously* shared) state: + s = new Uint32Array( state.length+1 ); + gcopy( state.length, state, 1, s, 1 ); + s[ s.length-3 ] = 2; + s[ s.length-1 ] = 1234; + rand1.state = s; + + // Attempt to replay previously generated values... + j = 0; + for ( i = 0; i < 50; i++ ) { + v1 = rand1(); + v2 = rand2(); + + // `rand1()` state is not affected by `rand2()`: + t.equal( v1, arr[ i ], 'returns expected value. i: '+i+'.' ); + + // `rand2()` state was never reset: + t.notEqual( v2, arr[ j+1 ], 'does not return expected value. i: '+(j+1)+'.' ); + j += 2; // stride + } + + // Reset the (*previously* shared) state: + rand2.state = s; + + // Reset to a shared state: + shared = new Uint32Array( state ); + rand1.state = shared; + rand2.state = shared; + + // Replay previously generated values... + j = 0; + for ( i = 0; i < 50; i++ ) { + v1 = rand1(); + v2 = rand2(); + t.equal( v1, arr[ j ], 'returns expected value. i: '+j+'.' ); + t.equal( v2, arr[ j+1 ], 'returns expected value. i: '+(j+1)+'.' ); + j += 2; // stride + } + t.end(); +}); + +tape( 'the returned function supports setting a shared generator state (no initial shared state)', function test( t ) { + var xorshift32; + var shared; + var state; + var rand1; + var rand2; + var arr; + var v1; + var v2; + var i; + var j; + + xorshift32 = factory(); + + // Move to a future state... + for ( i = 0; i < 100; i++ ) { + xorshift32(); + } + // Capture the current state: + state = xorshift32.state; + + // Create a copy of the state (to prevent mutation) which will be shared by more than one PRNG: + shared = new Uint32Array( state ); + + // Move to a future state... + arr = []; + for ( i = 0; i < 100; i++ ) { + arr.push( xorshift32() ); + } + + // Create PRNGs using the captured state: + rand1 = factory({ + 'copy': false + }); + rand2 = factory({ + 'copy': false + }); + + // Move to a future state... + for ( i = 0; i < 100; i++ ) { + v1 = rand1(); + v2 = rand2(); + } + + // Reset to a shared state: + rand1.state = shared; + rand2.state = shared; + + // Replay previously generated values... + j = 0; + for ( i = 0; i < 50; i++ ) { + v1 = rand1(); + v2 = rand2(); + t.equal( v1, arr[ j ], 'returns expected value. i: '+j+'.' ); + t.equal( v2, arr[ j+1 ], 'returns expected value. i: '+(j+1)+'.' ); + j += 2; // stride + } + + // Create a copy of the state (to prevent mutation) which will be shared by more than one PRNG: + shared = new Uint32Array( state ); + + // Reset the (shared) state: + rand1.state = shared; + rand2.state = shared; + + // Replay previously generated values... + j = 0; + for ( i = 0; i < 50; i++ ) { + v1 = rand1(); + v2 = rand2(); + t.equal( v1, arr[ j ], 'returns expected value. i: '+j+'.' ); + t.equal( v2, arr[ j+1 ], 'returns expected value. i: '+(j+1)+'.' ); + j += 2; // stride + } + 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..643a21ee18b5 --- /dev/null +++ b/lib/node_modules/@stdlib/random/base/xorshift32/test/test.js @@ -0,0 +1,240 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2025 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 isPositiveInteger = require( '@stdlib/math/base/assert/is-positive-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.equal( typeof xorshift32.normalized, 'function', 'has method' ); + t.end(); +}); + +tape( 'attached to the main export is a method to generate 32-bit xorshift pseudorandom number generator', function test( t ) { + t.equal( 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.equal( typeof xorshift32.toJSON, 'function', 'has method' ); + t.end(); +}); + +tape( 'attached to the main export is the generator name', function test( t ) { + t.equal( xorshift32.NAME, 'xorshift32', 'has property' ); + t.end(); +}); + +tape( 'attached to the main export is the minimum possible generated number', function test( t ) { + t.equal( xorshift32.MIN, 1, 'has property' ); + t.end(); +}); + +tape( 'attached to the main export is the maximum possible generated number', function test( t ) { + t.equal( xorshift32.MAX, UINT32_MAX, 'has property' ); + t.end(); +}); + +tape( 'attached to the main export is the generator seed', function test( t ) { + t.equal( isUint32Array( xorshift32.seed ), true, 'has property' ); + t.end(); +}); + +tape( 'attached to the main export is the generator seed length', function test( t ) { + t.equal( typeof xorshift32.seedLength, 'number', 'has property' ); + t.end(); +}); + +tape( 'attached to the main export is the generator state', function test( t ) { + t.equal( isUint32Array( xorshift32.state ), true, 'has property' ); + t.end(); +}); + +tape( 'attached to the main export is the generator state length', function test( t ) { + t.equal( typeof xorshift32.stateLength, 'number', 'has property' ); + t.end(); +}); + +tape( 'attached to the main export is the generator state size', function test( t ) { + t.equal( typeof xorshift32.byteLength, 'number', 'has property' ); + t.end(); +}); + +tape( 'the function returns pseudorandom integers strictly between 1 and 2^32-1 (inclusive)', function test( t ) { + var v; + var i; + for ( i = 0; i < 1e3; i++ ) { + v = xorshift32(); + t.equal( typeof v, 'number', 'returns a number' ); + t.equal( isPositiveInteger( v ), true, 'returns a positive integer' ); + t.equal( v >= 1 && v <= UINT32_MAX, true, 'returns an integer between 1 and 2^32-1 (inclusive)' ); + } + t.end(); +}); + +tape( 'the `normalized` method returns pseudorandom numbers strictly between 0 (inclusive) and 1 (exclusive)', function test( t ) { + var v; + var i; + for ( i = 0; i < 1e3; i++ ) { + v = xorshift32.normalized(); + t.equal( typeof v, 'number', 'returns a number' ); + t.equal( v >= 0.0 && v < 1.0, true, 'returns a number between 0 (inclusive) and 1 (exclusive)' ); + } + t.end(); +}); + +tape( 'attached to the `normalized` method is the generator name', function test( t ) { + t.equal( xorshift32.normalized.NAME, 'xorshift32', 'has property' ); + t.end(); +}); + +tape( 'attached to the `normalized` method is the minimum possible generated number', function test( t ) { + t.equal( xorshift32.normalized.MIN, 0.0, 'has property' ); + t.end(); +}); + +tape( 'attached to the `normalized` method is the maximum possible generated number', function test( t ) { + t.equal( xorshift32.normalized.MAX, (UINT32_MAX-1.0)/UINT32_MAX, 'has property' ); + t.end(); +}); + +tape( 'attached to the `normalized` method is the generator seed', function test( t ) { + t.equal( isUint32Array( xorshift32.normalized.seed ), true, 'has property' ); + t.end(); +}); + +tape( 'attached to the `normalized` method is the generator seed length', function test( t ) { + t.equal( typeof xorshift32.normalized.seedLength, 'number', 'has property' ); + t.end(); +}); + +tape( 'attached to the `normalized` method is the generator state', function test( t ) { + t.equal( isUint32Array( xorshift32.normalized.state ), true, 'has property' ); + t.end(); +}); + +tape( 'attached to the `normalized` method is the generator state length', function test( t ) { + t.equal( typeof xorshift32.normalized.stateLength, 'number', 'has property' ); + t.end(); +}); + +tape( 'attached to the `normalized` method is the generator state size', function test( t ) { + t.equal( 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.equal( 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.equal( 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.equal( xorshift32.normalized(), 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.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.equal( xorshift32.normalized(), arr[ i ], 'returns expected value. i: '+i+'.' ); + } + t.end(); +}); diff --git a/lib/node_modules/@stdlib/types/index.d.ts b/lib/node_modules/@stdlib/types/index.d.ts index 8e01ad12ad4d..95b6919f0e73 100644 --- a/lib/node_modules/@stdlib/types/index.d.ts +++ b/lib/node_modules/@stdlib/types/index.d.ts @@ -4274,6 +4274,26 @@ declare module '@stdlib/types/random' { * const s: PRNGStateMINSTD = new Int32Array( 6 ); */ type PRNGStateMINSTD = Int32Array; + + /** + * A pseudorandom number generator (PRNG) seed for the 32-bit Xorshift32 PRNG. + * + * @example + * const s: PRNGSeedXorshift32 = 12345; + * + * @example + * const s: PRNGSeedXorshift32 = [ 12345, 67891 ]; + */ + type PRNGSeedXorshift32 = number | ArrayLike; + + /** + * A pseudorandom number generator (PRNG) state for the 32-bit Xorshift32 PRNG. + * + * @example + * const s: PRNGStateXorshift32 = new Uint32Array( 6 ); + */ + type PRNGStateXorshift32 = Uint32Array; + } /** diff --git a/lib/node_modules/@stdlib/types/test.ts b/lib/node_modules/@stdlib/types/test.ts index 7f1fd8511abd..3e4e2acfa14a 100644 --- a/lib/node_modules/@stdlib/types/test.ts +++ b/lib/node_modules/@stdlib/types/test.ts @@ -666,6 +666,22 @@ function cmplx128Array(): array.Complex128Array { if ( s6[ 0 ] !== 0 ) { throw new Error( 'something went wrong' ); } + + const s7: random.PRNGSeedXorshift32 = 12345; + if ( s7 !== 12345 ) { + throw new Error( 'something went wrong' ); + } + + const s8: random.PRNGSeedXorshift32 = new Uint32Array( 10 ); + if ( s8[ 0 ] !== 0 ) { + throw new Error( 'something went wrong' ); + } + + const s9: random.PRNGStateXorshift32 = new Uint32Array( 10 ); + if ( s9[ 0 ] !== 0 ) { + throw new Error( 'something went wrong' ); + } + } // The compiler should not throw an error when using slice types...