Skip to content

Commit bfa6405

Browse files
committed
Fix and add tests
1 parent 92d83ed commit bfa6405

File tree

2 files changed

+155
-22
lines changed

2 files changed

+155
-22
lines changed

lib/node_modules/@stdlib/random/base/mt19937/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,7 @@ var sz = mt19937.byteLength;
232232

233233
- [Mersenne Twister][mersenne-twister] is **not** a cryptographically secure PRNG, as the PRNG is based on a linear recursion. Any pseudorandom number sequence generated by a linear recursion is **insecure**, due to the fact that one can predict future generated outputs by observing a sufficiently long subsequence of generated values.
234234
- Compared to other PRNGs, [Mersenne Twister][mersenne-twister] has a large state size (`~2.5kB`). Because of the large state size, beware of increased memory consumption when using the `factory()` method to create many [Mersenne Twister][mersenne-twister] PRNGs. When appropriate (e.g., when external state mutation is not a concern), consider sharing PRNG state.
235+
- 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 internally allocates a new fixed block of memory for storing PRNG state. Hence, a created PRNG does **not** support updating **shared** state when state arrays differ in length.
235236
- The PRNG has a period of `2^19937 - 1`.
236237

237238
</section>

lib/node_modules/@stdlib/random/base/mt19937/test/test.factory.js

+154-22
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ var isUint32Array = require( '@stdlib/assert/is-uint32array' );
2929
var Uint32Array = require( '@stdlib/array/uint32' );
3030
var kstest = require( '@stdlib/stats/kstest' );
3131
var minstd = require( '@stdlib/random/base/minstd-shuffle' );
32+
var gcopy = require( '@stdlib/blas/base/gcopy' );
3233
var factory = require( './../lib/factory.js' );
3334

3435

@@ -349,7 +350,7 @@ tape( 'if provided a `state` option containing an unsupported section length, th
349350
values = [];
350351

351352
v = new Uint32Array( 632 ); // >624+7
352-
v[ 0 ] = 0; // version
353+
v[ 0 ] = 1; // version
353354
v[ 1 ] = 3; // number of sections
354355
v[ 2 ] = 624; // state length
355356
v[ 627 ] = 2; // other length
@@ -358,7 +359,7 @@ tape( 'if provided a `state` option containing an unsupported section length, th
358359
values.push( v );
359360

360361
v = new Uint32Array( 633 ); // >624+7
361-
v[ 0 ] = 0; // version
362+
v[ 0 ] = 1; // version
362363
v[ 1 ] = 3; // number of sections
363364
v[ 2 ] = 624; // state length
364365
v[ 627 ] = 2; // other length
@@ -388,7 +389,7 @@ tape( 'if provided a `state` option containing an incompatible seed length, the
388389
values = [];
389390

390391
v = new Uint32Array( 631 ); // 624+7
391-
v[ 0 ] = 0; // version
392+
v[ 0 ] = 1; // version
392393
v[ 1 ] = 3; // number of sections
393394
v[ 2 ] = 624; // state length
394395
v[ 627 ] = 1; // other length
@@ -397,7 +398,7 @@ tape( 'if provided a `state` option containing an incompatible seed length, the
397398
values.push( v );
398399

399400
v = new Uint32Array( 632 ); // >624+7
400-
v[ 0 ] = 0; // version
401+
v[ 0 ] = 1; // version
401402
v[ 1 ] = 3; // number of sections
402403
v[ 2 ] = 624; // state length
403404
v[ 627 ] = 1; // other length
@@ -1387,24 +1388,6 @@ tape( 'the function supports specifying a shared generator state', function test
13871388
'copy': false
13881389
});
13891390

1390-
// Replay previously generated values...
1391-
j = 0;
1392-
for ( i = 0; i < 50; i++ ) {
1393-
v1 = rand1();
1394-
v2 = rand2();
1395-
t.equal( v1, arr[ j ], 'returns expected value. i: '+j+'.' );
1396-
t.equal( v2, arr[ j+1 ], 'returns expected value. i: '+(j+1)+'.' );
1397-
j += 2; // stride
1398-
}
1399-
1400-
// Move to a future state...
1401-
for ( i = 0; i < 100; i++ ) {
1402-
v2 = rand2();
1403-
}
1404-
1405-
// Reset the (shared) state:
1406-
rand1.state = new Uint32Array( state );
1407-
14081391
// Replay previously generated values...
14091392
j = 0;
14101393
for ( i = 0; i < 50; i++ ) {
@@ -1506,3 +1489,152 @@ tape( 'the returned function supports setting the generator state (normalized)',
15061489
}
15071490
t.end();
15081491
});
1492+
1493+
tape( 'the returned function supports setting a compatible shared generator state', function test( t ) {
1494+
var mt19937;
1495+
var shared;
1496+
var state;
1497+
var rand1;
1498+
var rand2;
1499+
var arr;
1500+
var v1;
1501+
var v2;
1502+
var i;
1503+
var j;
1504+
1505+
mt19937 = factory();
1506+
1507+
// Move to a future state...
1508+
for ( i = 0; i < 100; i++ ) {
1509+
mt19937();
1510+
}
1511+
// Capture the current state:
1512+
state = mt19937.state;
1513+
1514+
// Move to a future state...
1515+
arr = [];
1516+
for ( i = 0; i < 100; i++ ) {
1517+
arr.push( mt19937() );
1518+
}
1519+
1520+
// Create a copy of the state (to prevent mutation) which will be shared by more than one PRNG:
1521+
shared = new Uint32Array( state );
1522+
1523+
// Create PRNGs using the captured state:
1524+
rand1 = factory({
1525+
'state': shared,
1526+
'copy': false
1527+
});
1528+
rand2 = factory({
1529+
'state': shared,
1530+
'copy': false
1531+
});
1532+
1533+
// Replay previously generated values...
1534+
j = 0;
1535+
for ( i = 0; i < 50; i++ ) {
1536+
v1 = rand1();
1537+
v2 = rand2();
1538+
t.equal( v1, arr[ j ], 'returns expected value. i: '+j+'.' );
1539+
t.equal( v2, arr[ j+1 ], 'returns expected value. i: '+(j+1)+'.' );
1540+
j += 2; // stride
1541+
}
1542+
1543+
// Move to a future state...
1544+
for ( i = 0; i < 100; i++ ) {
1545+
v2 = rand2();
1546+
}
1547+
1548+
// Reset the (shared) state:
1549+
rand1.state = new Uint32Array( state );
1550+
1551+
// Replay previously generated values...
1552+
j = 0;
1553+
for ( i = 0; i < 50; i++ ) {
1554+
v1 = rand1();
1555+
v2 = rand2();
1556+
t.equal( v1, arr[ j ], 'returns expected value. i: '+j+'.' );
1557+
t.equal( v2, arr[ j+1 ], 'returns expected value. i: '+(j+1)+'.' );
1558+
j += 2; // stride
1559+
}
1560+
t.end();
1561+
});
1562+
1563+
tape( 'the returned function does not support setting an incompatible shared generator state', function test( t ) {
1564+
var mt19937;
1565+
var shared;
1566+
var state;
1567+
var rand1;
1568+
var rand2;
1569+
var arr;
1570+
var v1;
1571+
var v2;
1572+
var s;
1573+
var i;
1574+
var j;
1575+
1576+
mt19937 = factory();
1577+
1578+
// Move to a future state...
1579+
for ( i = 0; i < 100; i++ ) {
1580+
mt19937();
1581+
}
1582+
// Capture the current state:
1583+
state = mt19937.state;
1584+
1585+
// Move to a future state...
1586+
arr = [];
1587+
for ( i = 0; i < 100; i++ ) {
1588+
arr.push( mt19937() );
1589+
}
1590+
1591+
// Create a copy of the state (to prevent mutation) which will be shared by more than one PRNG:
1592+
shared = new Uint32Array( state );
1593+
1594+
// Create PRNGs using the captured state:
1595+
rand1 = factory({
1596+
'state': shared,
1597+
'copy': false
1598+
});
1599+
rand2 = factory({
1600+
'state': shared,
1601+
'copy': false
1602+
});
1603+
1604+
// Replay previously generated values...
1605+
j = 0;
1606+
for ( i = 0; i < 50; i++ ) {
1607+
v1 = rand1();
1608+
v2 = rand2();
1609+
t.equal( v1, arr[ j ], 'returns expected value. i: '+j+'.' );
1610+
t.equal( v2, arr[ j+1 ], 'returns expected value. i: '+(j+1)+'.' );
1611+
j += 2; // stride
1612+
}
1613+
1614+
// Move to a future state...
1615+
for ( i = 0; i < 100; i++ ) {
1616+
v2 = rand2();
1617+
}
1618+
1619+
// Reset the (*previously* shared) state:
1620+
s = new Uint32Array( state.length+1 );
1621+
gcopy( state.length, state, 1, s, 1 );
1622+
s[ s.length-3 ] = 2;
1623+
s[ s.length-1 ] = 1234;
1624+
rand1.state = s;
1625+
1626+
// Attempt to replay previously generated values...
1627+
j = 0;
1628+
for ( i = 0; i < 50; i++ ) {
1629+
v1 = rand1();
1630+
v2 = rand2();
1631+
1632+
// `rand1()` state is not affected by `rand2()`:
1633+
t.equal( v1, arr[ i ], 'returns expected value. i: '+i+'.' );
1634+
1635+
// `rand2()` state was never reset:
1636+
t.notEqual( v2, arr[ j+1 ], 'does not return expected value. i: '+(j+1)+'.' );
1637+
j += 2; // stride
1638+
}
1639+
t.end();
1640+
});

0 commit comments

Comments
 (0)