Skip to content

Commit e923098

Browse files
committed
feat(prng): add tinymt32 fixtures for testing
1 parent ae1434f commit e923098

File tree

9 files changed

+1186
-8
lines changed

9 files changed

+1186
-8
lines changed

lib/node_modules/@stdlib/random/base/tinymt32/lib/factory.js

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ var NUM_STATE_SECTIONS = 2; // state, seed
6262
var STATE_SECTION_OFFSET = 2; // | version | num_sections | state_length | ...state | state_index | seed_length | ...seed |
6363

6464
// Define the index offset of the seed section in the state array:
65-
var SEED_SECTION_OFFSET = 4; // | version | num_sections | state_length | ...state | state_index | seed_length | ...seed |
65+
var SEED_SECTION_OFFSET = N + 4; // | version | num_sections | state_length | ...state | state_index | seed_length | ...seed |
6666

6767
// Define the length of the "fixed" length portion of the state array:
6868
var STATE_FIXED_LENGTH = N + 5; // 1 (version) + 1 (num_sections) + 1 (state_length) + N (state) + 1 (state_index) + 1 (seed_length)
@@ -119,6 +119,19 @@ function verifyState( state, FLG ) {
119119
return null;
120120
}
121121

122+
function multiplyUnsigned(a, b) {
123+
let aLow = a & 0xFFFF, aHigh = a >>> 16;
124+
let bLow = b & 0xFFFF, bHigh = b >>> 16;
125+
126+
let low = aLow * bLow;
127+
let mid1 = aHigh * bLow;
128+
let mid2 = aLow * bHigh;
129+
let high = aHigh * bHigh;
130+
131+
let result = (low + ((mid1 + mid2) << 16)) >>> 0;
132+
return result;
133+
}
134+
122135
/**
123136
* Returns an initial PRNG state.
124137
*
@@ -139,8 +152,8 @@ function createState( state, N, s ) {
139152

140153
// Initialize using the algorithm from tinymt32_init
141154
for ( i = 1; i < MIN_LOOP; i++ ) {
142-
state[ i & 3 ] ^= i + KNUTH_MULTIPLIER *
143-
(state[(i - 1) & 3] ^ (state[(i - 1) & 3] >>> 30));
155+
state[ i & 3 ] ^= i + multiplyUnsigned(KNUTH_MULTIPLIER ,
156+
(state[(i - 1) & 3] ^ (state[(i - 1) & 3] >>> 30)));
144157
}
145158

146159
// Pre-run the algorithm to improve randomness of the initial state
@@ -166,7 +179,7 @@ function nextState( state ) {
166179
y = state[3];
167180
x = (state[0] & MASK) ^ state[1] ^ state[2];
168181
x ^= (x << SH0);
169-
y ^= (y >> SH0) ^ x;
182+
y ^= (y >>> SH0) ^ x;
170183
state[0] = state[1];
171184
state[1] = state[2];
172185
state[2] = x ^ (y << SH1);
@@ -193,10 +206,10 @@ function temper( state ) {
193206

194207
// Tempering
195208
t0 = state[3];
196-
t1 = state[0] + (state[2] >> SH8);
209+
t1 = (state[0] + (state[2] >>> SH8)) >>> 0;
197210
t0 ^= t1;
198211

199-
if (t1 & 1) {
212+
if ((t1 & 1) !== 0) {
200213
t0 ^= TMAT;
201214
}
202215

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
#/
2+
# @license Apache-2.0
3+
#
4+
# Copyright (c) 2024 The Stdlib Authors.
5+
#
6+
# Licensed under the Apache License, Version 2.0 (the "License");
7+
# you may not use this file except in compliance with the License.
8+
# You may obtain a copy of the License at
9+
#
10+
# http://www.apache.org/licenses/LICENSE-2.0
11+
#
12+
# Unless required by applicable law or agreed to in writing, software
13+
# distributed under the License is distributed on an "AS IS" BASIS,
14+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
# See the License for the specific language governing permissions and
16+
# limitations under the License.
17+
#/
18+
19+
# VARIABLES #
20+
21+
# Determine the OS:
22+
UNAME := $(shell uname -s)
23+
24+
# Define the program used for compiling C source files:
25+
ifdef CC
26+
CC := $(CC)
27+
else
28+
CC := gcc
29+
endif
30+
31+
# Define the command-line options when compiling C source files:
32+
CFLAGS ?= -O3 -std=c99
33+
34+
# Define the program for removing files:
35+
REMOVE ?= rm -f
36+
37+
# Determine extension for shared libraries based on the OS:
38+
ifeq ($(UNAME), Darwin)
39+
SHARED_EXT := dylib
40+
else
41+
SHARED_EXT := so
42+
endif
43+
44+
# Define the command for running the test runner:
45+
RUNNER ?= ./runner
46+
47+
# TARGETS #
48+
49+
# Default target.
50+
#
51+
# This target is the default target.
52+
53+
all: clean build run
54+
55+
.PHONY: all
56+
57+
# Compile C source.
58+
#
59+
# This target compiles C source files.
60+
61+
build: runner.c tinymt32.c tinymt32.h
62+
$(CC) $(CFLAGS) -o runner runner.c tinymt32.c
63+
64+
.PHONY: build
65+
66+
# Run compiled tests.
67+
#
68+
# This target runs compiled test files.
69+
70+
run: build
71+
$(RUNNER)
72+
73+
.PHONY: run
74+
75+
# Remove generated files.
76+
#
77+
# This target removes any generated files.
78+
79+
clean:
80+
$(REMOVE) runner *.o *.$(SHARED_EXT) *.json
81+
82+
.PHONY: clean

lib/node_modules/@stdlib/random/base/tinymt32/test/fixtures/c/float64_integer_seed.json

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.
Binary file not shown.
Lines changed: 239 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,239 @@
1+
/**
2+
* @license Apache-2.0
3+
*
4+
* Copyright (c) 2024 The Stdlib Authors.
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
/**
20+
* Generate C test fixtures for tinymt32.
21+
*
22+
* ## Notes
23+
*
24+
* - Run this script from the directory in which fixtures should be written.
25+
*
26+
*/
27+
28+
#include <stdlib.h>
29+
#include <stdio.h>
30+
#include "tinymt32.h"
31+
32+
// Helper functions remain the same as MT19937...
33+
// ... (linspace, write functions, etc.)
34+
35+
/**
36+
* Writes an array of doubles to a file as a series of comma-separated values.
37+
*
38+
* @param f file to write to
39+
* @param x array of doubles
40+
* @param len array length
41+
*/
42+
void write_array_f64(FILE *f, const double *x, const unsigned int len) {
43+
unsigned int i;
44+
45+
for (i = 0; i < len; i++) {
46+
fprintf(f, "%.17g", x[i]);
47+
if (i < len-1) {
48+
fprintf(f, ",");
49+
}
50+
}
51+
}
52+
53+
/**
54+
* Writes an array of integers to a file as a series of comma-separated values.
55+
*
56+
* @param f file to write to
57+
* @param x array of integers
58+
* @param len array length
59+
*/
60+
void write_array_ui32(FILE *f, const unsigned int *x, const unsigned int len) {
61+
unsigned int i;
62+
63+
for (i = 0; i < len; i++) {
64+
fprintf(f, "%u", x[i]);
65+
if (i < len-1) {
66+
fprintf(f, ",");
67+
}
68+
}
69+
}
70+
71+
/**
72+
* Writes a named array of doubles to a file as JSON.
73+
*
74+
* @param f file to write to
75+
* @param name array name
76+
* @param x data
77+
* @param len array length
78+
*/
79+
void write_named_array_f64(FILE *f, const char *name, const double *x, const unsigned int len) {
80+
fprintf(f, "\"%s\":[", name);
81+
write_array_f64(f, x, len);
82+
fprintf(f, "]");
83+
}
84+
85+
/**
86+
* Writes a named array of integers to a file as JSON.
87+
*
88+
* @param f file to write to
89+
* @param name array name
90+
* @param x data
91+
* @param len array length
92+
*/
93+
void write_named_array_ui32(FILE *f, const char *name, const unsigned int *x, const unsigned int len) {
94+
fprintf(f, "\"%s\":[", name);
95+
write_array_ui32(f, x, len);
96+
fprintf(f, "]");
97+
}
98+
99+
/**
100+
* Writes data to a file as JSON.
101+
*
102+
* @param f file to write to
103+
* @param y results
104+
* @param len array length
105+
*/
106+
void write_data_as_json_ui32(FILE *f, const unsigned int *y, const unsigned int len) {
107+
fprintf(f, "{");
108+
write_named_array_ui32(f, "expected", y, len);
109+
fprintf(f, "}");
110+
}
111+
112+
/**
113+
* Writes data to a file as JSON.
114+
*
115+
* @param f file to write to
116+
* @param y results
117+
* @param len array length
118+
*/
119+
void write_data_as_json_f64(FILE *f, const double *y, const unsigned int len) {
120+
fprintf(f, "{");
121+
write_named_array_f64(f, "expected", y, len);
122+
fprintf(f, "}");
123+
}
124+
125+
/**
126+
* Generates test fixtures for uint32 values with integer seed.
127+
*
128+
* @param seed PRNG seed
129+
* @param len number of output values
130+
* @param name output filename
131+
*/
132+
void generate_ui32_integer_seed(const uint32_t seed, const unsigned int len, const char *name) {
133+
tinymt32_t state;
134+
unsigned int *y;
135+
unsigned int i;
136+
FILE *f;
137+
138+
// Allocate an output array:
139+
y = (unsigned int*) malloc(len * sizeof(unsigned int));
140+
if (y == NULL) {
141+
printf("Error allocating memory.\n");
142+
exit(1);
143+
}
144+
145+
// Set TinyMT parameters (these are default values from the original implementation)
146+
state.mat1 = 0x8f7011ee;
147+
state.mat2 = 0xfc78ff1f;
148+
state.tmat = 0x3793fdff;
149+
150+
// Initialize the PRNG:
151+
tinymt32_init(&state, seed);
152+
153+
// Generate fixture data:
154+
for (i = 0; i < len; i++) {
155+
y[i] = tinymt32_generate_uint32(&state);
156+
}
157+
158+
// Open a new file:
159+
f = fopen(name, "w");
160+
if (f == NULL) {
161+
printf("Error opening file.\n");
162+
exit(1);
163+
}
164+
165+
// Write data as JSON:
166+
write_data_as_json_ui32(f, y, len);
167+
168+
// Close the file:
169+
fclose(f);
170+
171+
// Free allocated memory:
172+
free(y);
173+
}
174+
175+
/**
176+
* Generates test fixtures for float64 values with integer seed.
177+
*
178+
* @param seed PRNG seed
179+
* @param len number of output values
180+
* @param name output filename
181+
*/
182+
void generate_f64_integer_seed(const uint32_t seed, const unsigned int len, const char *name) {
183+
tinymt32_t state;
184+
double *y;
185+
unsigned int i;
186+
FILE *f;
187+
188+
// Allocate an output array:
189+
y = (double*) malloc(len * sizeof(double));
190+
if (y == NULL) {
191+
printf("Error allocating memory.\n");
192+
exit(1);
193+
}
194+
195+
// Set TinyMT parameters (these are default values from the original implementation)
196+
state.mat1 = 0x8f7011ee;
197+
state.mat2 = 0xfc78ff1f;
198+
state.tmat = 0x3793fdff;
199+
200+
// Initialize the PRNG:
201+
tinymt32_init(&state, seed);
202+
203+
// Generate fixture data:
204+
for (i = 0; i < len; i++) {
205+
y[i] = tinymt32_generate_double(&state);
206+
}
207+
208+
// Open a new file:
209+
f = fopen(name, "w");
210+
if (f == NULL) {
211+
printf("Error opening file.\n");
212+
exit(1);
213+
}
214+
215+
// Write data as JSON:
216+
write_data_as_json_f64(f, y, len);
217+
218+
// Close the file:
219+
fclose(f);
220+
221+
// Free allocated memory:
222+
free(y);
223+
}
224+
225+
/**
226+
* Main execution sequence.
227+
*/
228+
int main(void) {
229+
unsigned int len;
230+
231+
// Define the array length:
232+
len = 1000;
233+
234+
// Generate fixture data:
235+
generate_ui32_integer_seed(1234, len, "uint32_integer_seed.json");
236+
generate_f64_integer_seed(1234, len, "float64_integer_seed.json");
237+
238+
return 0;
239+
}

0 commit comments

Comments
 (0)