@cloudglides/nox 1.1.3 → 1.1.4

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.
@@ -80,27 +80,30 @@ const weightedPickIndex = (weights, rng) => {
80
80
  };
81
81
 
82
82
  export const reservoirSample = (stream, k, rng) => {
83
- if (!Array.isArray(stream) || stream.length === 0) {
84
- throw new TypeError('stream must be a non-empty array');
85
- }
86
- if (typeof k !== 'number' || !Number.isInteger(k)) {
87
- throw new TypeError('k must be an integer');
88
- }
89
- if (k <= 0) {
90
- throw new RangeError('k must be positive');
91
- }
92
- if (!rng || typeof rng.nextInt !== 'function') {
93
- throw new TypeError('rng must be an RNG instance');
94
- }
95
-
96
- const reservoir = stream.slice(0, Math.min(k, stream.length));
97
-
98
- for (let i = k; i < stream.length; i++) {
99
- const j = rng.nextInt(i + 1);
100
- if (j < k) {
101
- reservoir[j] = stream[i];
102
- }
103
- }
104
-
105
- return reservoir;
106
- };
83
+ if (!Array.isArray(stream) || stream.length === 0) {
84
+ throw new TypeError('stream must be a non-empty array');
85
+ }
86
+ if (typeof k !== 'number' || !Number.isInteger(k)) {
87
+ throw new TypeError('k must be an integer');
88
+ }
89
+ if (k <= 0) {
90
+ throw new RangeError('k must be positive');
91
+ }
92
+ if (k > stream.length) {
93
+ throw new RangeError('k cannot exceed stream length');
94
+ }
95
+ if (!rng || typeof rng.nextInt !== 'function') {
96
+ throw new TypeError('rng must be an RNG instance');
97
+ }
98
+
99
+ const reservoir = stream.slice(0, k);
100
+
101
+ for (let i = k; i < stream.length; i++) {
102
+ const j = rng.nextInt(i + 1);
103
+ if (j < k) {
104
+ reservoir[j] = stream[i];
105
+ }
106
+ }
107
+
108
+ return reservoir;
109
+ };
@@ -1,36 +1,49 @@
1
1
  export const chiSquareTest = (data, bins = 10) => {
2
- const histogram = new Array(bins).fill(0);
3
- for (const val of data) {
4
- const idx = Math.floor(val * bins);
5
- histogram[Math.min(idx, bins - 1)]++;
6
- }
7
-
8
- const expected = data.length / bins;
9
- let chi2 = 0;
10
- for (const count of histogram) {
11
- chi2 += ((count - expected) ** 2) / expected;
12
- }
13
-
14
- return { chi2, expected, histogram };
15
- };
2
+ if (!Array.isArray(data) || data.length === 0) {
3
+ throw new Error('Data must be non-empty array');
4
+ }
5
+ if (bins <= 0 || !Number.isInteger(bins)) {
6
+ throw new Error('Bins must be positive integer');
7
+ }
8
+
9
+ const histogram = new Array(bins).fill(0);
10
+ for (const val of data) {
11
+ const idx = Math.floor(val * bins);
12
+ histogram[Math.min(idx, bins - 1)]++;
13
+ }
14
+
15
+ const expected = data.length / bins;
16
+ let chi2 = 0;
17
+ for (const count of histogram) {
18
+ chi2 += ((count - expected) ** 2) / expected;
19
+ }
20
+
21
+ return { chi2, expected, histogram };
22
+ };
16
23
 
17
24
  export const entropy = (data, bins = 10) => {
18
- const histogram = new Array(bins).fill(0);
19
- for (const val of data) {
20
- const idx = Math.floor(val * bins);
21
- histogram[Math.min(idx, bins - 1)]++;
22
- }
23
-
24
- let ent = 0;
25
- const p = 1 / data.length;
26
- for (const count of histogram) {
27
- if (count > 0) {
28
- const pi = count / data.length;
29
- ent -= pi * Math.log2(pi);
30
- }
31
- }
32
- return ent;
33
- };
25
+ if (!Array.isArray(data) || data.length === 0) {
26
+ throw new Error('Data must be non-empty array');
27
+ }
28
+ if (bins <= 0) {
29
+ throw new Error('Bins must be positive');
30
+ }
31
+
32
+ const histogram = new Array(bins).fill(0);
33
+ for (const val of data) {
34
+ const idx = Math.floor(val * bins);
35
+ histogram[Math.min(idx, bins - 1)]++;
36
+ }
37
+
38
+ let ent = 0;
39
+ for (const count of histogram) {
40
+ if (count > 0) {
41
+ const pi = count / data.length;
42
+ ent -= pi * Math.log2(pi);
43
+ }
44
+ }
45
+ return ent;
46
+ };
34
47
 
35
48
  export const autocorrelation = (data, lag) => {
36
49
  if (lag < 0 || lag >= data.length) throw new Error('Lag out of range');
@@ -110,18 +123,21 @@ export const meanTest = (data, expectedMean = 0.5) => {
110
123
  };
111
124
 
112
125
  export const varianceTest = (data, expectedVariance = 1 / 12) => {
113
- if (!Array.isArray(data) || data.length === 0) {
114
- throw new Error('Data must be non-empty array');
115
- }
116
-
117
- const mean = data.reduce((a, b) => a + b, 0) / data.length;
118
- const variance = data.reduce((a, v) => a + (v - mean) ** 2, 0) / data.length;
119
- const chi2 = (data.length - 1) * variance / expectedVariance;
120
-
121
- return {
122
- variance,
123
- expectedVariance,
124
- chi2Statistic: chi2,
125
- degreesOfFreedom: data.length - 1
126
- };
127
- };
126
+ if (!Array.isArray(data) || data.length === 0) {
127
+ throw new Error('Data must be non-empty array');
128
+ }
129
+ if (data.length < 2) {
130
+ throw new Error('Data must have at least 2 elements');
131
+ }
132
+
133
+ const mean = data.reduce((a, b) => a + b, 0) / data.length;
134
+ const sampleVariance = data.reduce((a, v) => a + (v - mean) ** 2, 0) / (data.length - 1);
135
+ const chi2 = (data.length - 1) * sampleVariance / expectedVariance;
136
+
137
+ return {
138
+ variance: sampleVariance,
139
+ expectedVariance,
140
+ chi2Statistic: chi2,
141
+ degreesOfFreedom: data.length - 1
142
+ };
143
+ };