@cloudglides/nox 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/build-on-tag.yml +67 -0
- package/IMPROVEMENTS.md +58 -0
- package/LICENSE +15 -0
- package/README.md +119 -0
- package/docs/API.md +70 -0
- package/example/README.md +26 -0
- package/example/index.html +13 -0
- package/example/package-lock.json +1636 -0
- package/example/package.json +20 -0
- package/example/src/App.css +161 -0
- package/example/src/App.jsx +176 -0
- package/example/src/index.css +55 -0
- package/example/src/main.jsx +10 -0
- package/example/vite.config.js +11 -0
- package/package.json +25 -0
- package/src/core.js +8 -0
- package/src/generators/index.js +7 -0
- package/src/generators/logistic.js +19 -0
- package/src/generators/mixer.js +20 -0
- package/src/generators/mt19937.js +74 -0
- package/src/generators/pcg64.js +44 -0
- package/src/generators/splitmix64.js +32 -0
- package/src/generators/tent.js +24 -0
- package/src/generators/xorshift64.js +38 -0
- package/src/index.d.ts +114 -0
- package/src/index.js +32 -0
- package/src/presets.js +15 -0
- package/src/rng.js +142 -0
- package/src/utils/bits.js +25 -0
- package/src/utils/categorical.js +57 -0
- package/src/utils/combinatorics.js +85 -0
- package/src/utils/distributions-extra.js +32 -0
- package/src/utils/distributions-special.js +21 -0
- package/src/utils/distributions.js +69 -0
- package/src/utils/entropy.js +95 -0
- package/src/utils/index.js +30 -0
- package/src/utils/noise.js +81 -0
- package/src/utils/sampling.js +106 -0
- package/src/utils/seed.js +14 -0
- package/src/utils/seeding.js +37 -0
- package/src/utils/sequence.js +53 -0
- package/src/utils/state.js +39 -0
- package/src/utils/statistics.js +127 -0
- package/src/utils/stochastic.js +32 -0
- package/test/advanced.js +71 -0
- package/test/basic.js +13 -0
- package/test/benchmark.js +35 -0
- package/test/comprehensive.js +100 -0
- package/test/profile.js +73 -0
package/test/basic.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { rng, deterministic, normal, exponential, shuffle } from '../src/index.js';
|
|
2
|
+
|
|
3
|
+
const r = rng();
|
|
4
|
+
console.log('Default:', r.int(1, 100), r.bool());
|
|
5
|
+
|
|
6
|
+
const d = deterministic(42);
|
|
7
|
+
console.log('Deterministic:', d.nextFloat());
|
|
8
|
+
|
|
9
|
+
const arr = [1, 2, 3, 4, 5];
|
|
10
|
+
console.log('Shuffle:', shuffle(arr, r));
|
|
11
|
+
|
|
12
|
+
const r2 = rng();
|
|
13
|
+
console.log('Distributions:', normal(r2), exponential(r2));
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Xorshift64, Logistic, Tent, Splitmix64, PCG64, MT19937 } from '../src/index.js';
|
|
2
|
+
import { chiSquareTest, entropy, autocorrelation, runTest } from '../src/utils/statistics.js';
|
|
3
|
+
|
|
4
|
+
const SAMPLES = 10000;
|
|
5
|
+
|
|
6
|
+
const benchmarkGenerator = (name, GeneratorClass, seed) => {
|
|
7
|
+
console.log(`\n=== ${name} ===`);
|
|
8
|
+
|
|
9
|
+
const rng = new GeneratorClass(seed);
|
|
10
|
+
const data = [];
|
|
11
|
+
|
|
12
|
+
const start = performance.now();
|
|
13
|
+
for (let i = 0; i < SAMPLES; i++) {
|
|
14
|
+
data.push(rng.nextFloat());
|
|
15
|
+
}
|
|
16
|
+
const elapsed = performance.now() - start;
|
|
17
|
+
|
|
18
|
+
const { chi2, histogram } = chiSquareTest(data, 20);
|
|
19
|
+
const ent = entropy(data, 20);
|
|
20
|
+
const autocorr = autocorrelation(data, 1);
|
|
21
|
+
const runs = runTest(data);
|
|
22
|
+
|
|
23
|
+
console.log(`Time: ${elapsed.toFixed(2)}ms (${(SAMPLES/elapsed*1000).toFixed(0)} ops/sec)`);
|
|
24
|
+
console.log(`Chi2: ${chi2.toFixed(2)} (good: <31.4)`);
|
|
25
|
+
console.log(`Entropy: ${ent.toFixed(4)} (max: ~${Math.log2(20).toFixed(4)})`);
|
|
26
|
+
console.log(`Autocorr(lag=1): ${autocorr.toFixed(6)} (good: close to 0)`);
|
|
27
|
+
console.log(`Runs: ${runs} (expect ~${Math.ceil(SAMPLES/2)})`);
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
benchmarkGenerator('Xorshift64', Xorshift64, 42);
|
|
31
|
+
benchmarkGenerator('Splitmix64', Splitmix64, 42);
|
|
32
|
+
benchmarkGenerator('PCG64', PCG64, 42);
|
|
33
|
+
benchmarkGenerator('MT19937', MT19937, 42);
|
|
34
|
+
benchmarkGenerator('Logistic', Logistic, 0.5);
|
|
35
|
+
benchmarkGenerator('Tent', Tent, 0.5);
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import {
|
|
2
|
+
rng,
|
|
3
|
+
deterministic,
|
|
4
|
+
RNG,
|
|
5
|
+
PCG64,
|
|
6
|
+
normal,
|
|
7
|
+
exponential,
|
|
8
|
+
shuffle,
|
|
9
|
+
pick,
|
|
10
|
+
sample,
|
|
11
|
+
saveState,
|
|
12
|
+
restoreState,
|
|
13
|
+
cloneGenerator,
|
|
14
|
+
weightedPick,
|
|
15
|
+
reservoirSample,
|
|
16
|
+
meanTest,
|
|
17
|
+
varianceTest,
|
|
18
|
+
kolmogorovSmirnovTest
|
|
19
|
+
} from '../src/index.js';
|
|
20
|
+
|
|
21
|
+
console.log('=== Comprehensive nox Test Suite ===\n');
|
|
22
|
+
|
|
23
|
+
console.log('1. Core RNG Methods');
|
|
24
|
+
const r = rng();
|
|
25
|
+
console.log(` nextFloat(): ${r.nextFloat().toFixed(6)}`);
|
|
26
|
+
console.log(` nextInt(100): ${r.nextInt(100)}`);
|
|
27
|
+
console.log(` int(1, 100): ${r.int(1, 100)}`);
|
|
28
|
+
console.log(` bool(0.7): ${r.bool(0.7)}`);
|
|
29
|
+
|
|
30
|
+
console.log('\n2. Utility Methods');
|
|
31
|
+
console.log(` range(5, 15, 3): ${r.range(5, 15, 3)}`);
|
|
32
|
+
console.log(` choice(['red', 'blue', 'green']): ${r.choice(['red', 'blue', 'green'])}`);
|
|
33
|
+
|
|
34
|
+
console.log('\n3. Batch Operations');
|
|
35
|
+
const floats = r.floats(3).map(x => x.toFixed(6));
|
|
36
|
+
console.log(` floats(3): [${floats.join(', ')}]`);
|
|
37
|
+
const ints = r.ints(3, 10);
|
|
38
|
+
console.log(` ints(3, 10): [${ints.join(', ')}]`);
|
|
39
|
+
const bools = r.bools(3, 0.5);
|
|
40
|
+
console.log(` bools(3): [${bools.join(', ')}]`);
|
|
41
|
+
|
|
42
|
+
console.log('\n4. Sequence Operations');
|
|
43
|
+
const arr = [1, 2, 3, 4, 5];
|
|
44
|
+
console.log(` shuffle(${JSON.stringify(arr)}): ${JSON.stringify(shuffle([...arr], r))}`);
|
|
45
|
+
console.log(` pick(['a','b','c']): ${pick(['a','b','c'], r)}`);
|
|
46
|
+
console.log(` sample([1,2,3,4,5], 3): ${JSON.stringify(sample([...arr], 3, r))}`);
|
|
47
|
+
|
|
48
|
+
console.log('\n5. Statistical Distributions');
|
|
49
|
+
const r2 = rng();
|
|
50
|
+
console.log(` normal(0, 1): ${normal(r2).toFixed(6)}`);
|
|
51
|
+
console.log(` exponential(1): ${exponential(r2).toFixed(6)}`);
|
|
52
|
+
|
|
53
|
+
console.log('\n6. State Management');
|
|
54
|
+
const r3 = rng();
|
|
55
|
+
const val1 = r3.nextFloat();
|
|
56
|
+
const state = saveState(r3);
|
|
57
|
+
const val2 = r3.nextFloat();
|
|
58
|
+
restoreState(r3, state);
|
|
59
|
+
const val2_restored = r3.nextFloat();
|
|
60
|
+
console.log(` State restored correctly: ${val2 === val2_restored}`);
|
|
61
|
+
|
|
62
|
+
console.log('\n7. Generator Cloning');
|
|
63
|
+
const orig = deterministic(12345);
|
|
64
|
+
const origSeq = orig.floats(3);
|
|
65
|
+
const cloned = cloneGenerator(orig);
|
|
66
|
+
const clonedSeq = cloned.floats(3);
|
|
67
|
+
console.log(` Clone has same sequence: ${JSON.stringify(origSeq) === JSON.stringify(clonedSeq)}`);
|
|
68
|
+
|
|
69
|
+
console.log('\n8. Weighted Sampling');
|
|
70
|
+
const items = ['A', 'B', 'C'];
|
|
71
|
+
const weights = [0.6, 0.3, 0.1];
|
|
72
|
+
console.log(` weightedPick(['A','B','C'], [0.6,0.3,0.1]): ${weightedPick(items, weights, rng())}`);
|
|
73
|
+
|
|
74
|
+
console.log('\n9. Reservoir Sampling');
|
|
75
|
+
const largeStream = Array.from({length: 1000}, (_, i) => i);
|
|
76
|
+
const sample5 = reservoirSample(largeStream, 5, rng());
|
|
77
|
+
console.log(` reservoirSample(0..999, k=5): [${sample5.join(', ')}]`);
|
|
78
|
+
|
|
79
|
+
console.log('\n10. Statistical Tests');
|
|
80
|
+
const testData = rng().floats(500);
|
|
81
|
+
const meanRes = meanTest(testData);
|
|
82
|
+
const varRes = varianceTest(testData);
|
|
83
|
+
const ksRes = kolmogorovSmirnovTest(testData);
|
|
84
|
+
console.log(` Mean: ${meanRes.mean.toFixed(6)} (expected: 0.5)`);
|
|
85
|
+
console.log(` Variance: ${varRes.variance.toFixed(6)} (expected: 0.083333)`);
|
|
86
|
+
console.log(` KS Test passes (α=0.05): ${ksRes.pass_0_05}`);
|
|
87
|
+
|
|
88
|
+
console.log('\n11. Deterministic Mode');
|
|
89
|
+
const d1 = deterministic(42);
|
|
90
|
+
const seq1 = d1.ints(5, 100);
|
|
91
|
+
const d2 = deterministic(42);
|
|
92
|
+
const seq2 = d2.ints(5, 100);
|
|
93
|
+
console.log(` Sequences identical: ${JSON.stringify(seq1) === JSON.stringify(seq2)}`);
|
|
94
|
+
console.log(` Sequence: ${JSON.stringify(seq1)}`);
|
|
95
|
+
|
|
96
|
+
console.log('\n12. Custom Generators');
|
|
97
|
+
const custom = new RNG(PCG64, 999n);
|
|
98
|
+
console.log(` Custom PCG64 RNG initialized: ${custom.nextFloat().toFixed(6)}`);
|
|
99
|
+
|
|
100
|
+
console.log('\n✓ All tests completed successfully');
|
package/test/profile.js
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { rng, quality, MT19937, Xorshift64, Splitmix64, PCG64 } from '../src/index.js';
|
|
2
|
+
|
|
3
|
+
const ITERATIONS = 100000;
|
|
4
|
+
|
|
5
|
+
const profile = (name, fn) => {
|
|
6
|
+
const start = performance.now();
|
|
7
|
+
fn();
|
|
8
|
+
const elapsed = performance.now() - start;
|
|
9
|
+
const opsPerSec = (ITERATIONS / elapsed * 1000).toFixed(0);
|
|
10
|
+
console.log(`${name}: ${elapsed.toFixed(2)}ms (${opsPerSec} ops/sec)`);
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
console.log(`\n=== Generating ${ITERATIONS} values ===\n`);
|
|
14
|
+
|
|
15
|
+
profile('RNG.nextFloat()', () => {
|
|
16
|
+
const r = rng();
|
|
17
|
+
for (let i = 0; i < ITERATIONS; i++) r.nextFloat();
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
profile('RNG.nextInt()', () => {
|
|
21
|
+
const r = rng();
|
|
22
|
+
for (let i = 0; i < ITERATIONS; i++) r.nextInt(100);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
profile('RNG.int(1,100)', () => {
|
|
26
|
+
const r = rng();
|
|
27
|
+
for (let i = 0; i < ITERATIONS; i++) r.int(1, 100);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
profile('RNG.bool()', () => {
|
|
31
|
+
const r = rng();
|
|
32
|
+
for (let i = 0; i < ITERATIONS; i++) r.bool();
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
console.log('\n=== Generator comparison (nextFloat) ===\n');
|
|
36
|
+
|
|
37
|
+
profile('Xorshift64', () => {
|
|
38
|
+
const r = new Xorshift64(42);
|
|
39
|
+
for (let i = 0; i < ITERATIONS; i++) r.nextFloat();
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
profile('Splitmix64', () => {
|
|
43
|
+
const r = new Splitmix64(42);
|
|
44
|
+
for (let i = 0; i < ITERATIONS; i++) r.nextFloat();
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
profile('PCG64', () => {
|
|
48
|
+
const r = new PCG64(42n);
|
|
49
|
+
for (let i = 0; i < ITERATIONS; i++) r.nextFloat();
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
profile('MT19937', () => {
|
|
53
|
+
const r = new MT19937(42);
|
|
54
|
+
for (let i = 0; i < ITERATIONS; i++) r.nextFloat();
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
console.log('\n=== Batch operations ===\n');
|
|
58
|
+
|
|
59
|
+
profile('floats(100) x1000', () => {
|
|
60
|
+
const r = rng();
|
|
61
|
+
for (let i = 0; i < 1000; i++) r.floats(100);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
profile('ints(100, 100) x1000', () => {
|
|
65
|
+
const r = rng();
|
|
66
|
+
for (let i = 0; i < 1000; i++) r.ints(100, 100);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
profile('shuffle([1..10]) x10000', () => {
|
|
70
|
+
const r = rng();
|
|
71
|
+
const arr = Array.from({ length: 10 }, (_, i) => i);
|
|
72
|
+
for (let i = 0; i < 10000; i++) r.shuffle(arr);
|
|
73
|
+
});
|