@iyulab/u-numflow 0.6.3 → 0.7.0
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/README.md +53 -22
- package/node/u_numflow.cjs +30 -7
- package/node/u_numflow.d.cts +5 -5
- package/node/u_numflow_bg.wasm +0 -0
- package/package.json +1 -1
- package/u_numflow.d.ts +5 -5
- package/u_numflow_bg.js +30 -7
- package/u_numflow_bg.wasm +0 -0
package/README.md
CHANGED
|
@@ -38,31 +38,34 @@ u-numflow = "0.2"
|
|
|
38
38
|
```
|
|
39
39
|
|
|
40
40
|
```rust
|
|
41
|
-
use u_numflow::
|
|
42
|
-
use u_numflow::
|
|
43
|
-
use u_numflow::
|
|
41
|
+
use u_numflow::distributions::Pert;
|
|
42
|
+
use u_numflow::random::{create_rng, shuffle};
|
|
43
|
+
use u_numflow::stats::WelfordAccumulator;
|
|
44
44
|
|
|
45
|
-
// Online statistics with numerical stability
|
|
46
|
-
let mut stats =
|
|
45
|
+
// Online statistics with numerical stability (Welford)
|
|
46
|
+
let mut stats = WelfordAccumulator::new();
|
|
47
47
|
for x in [1.0, 2.0, 3.0, 4.0, 5.0] {
|
|
48
|
-
stats.
|
|
48
|
+
stats.update(x);
|
|
49
49
|
}
|
|
50
|
-
assert_eq!(stats.mean(), 3.0);
|
|
50
|
+
assert_eq!(stats.mean(), Some(3.0));
|
|
51
51
|
|
|
52
|
-
// PERT distribution
|
|
53
|
-
let pert =
|
|
54
|
-
|
|
55
|
-
let
|
|
52
|
+
// PERT distribution: moments and quantiles; sample by inverting a uniform draw
|
|
53
|
+
let pert = Pert::new(1.0, 4.0, 7.0).unwrap();
|
|
54
|
+
assert_eq!(pert.mean(), 4.0);
|
|
55
|
+
let p90 = pert.quantile(0.9).unwrap();
|
|
56
|
+
assert!(p90 > 4.0 && p90 < 7.0);
|
|
56
57
|
|
|
57
58
|
// Seeded shuffling for reproducibility
|
|
59
|
+
let mut rng = create_rng(42);
|
|
58
60
|
let mut items = vec![1, 2, 3, 4, 5];
|
|
59
|
-
|
|
61
|
+
shuffle(&mut items, &mut rng);
|
|
60
62
|
|
|
61
63
|
// Box-Cox transformation (non-normal data normalization)
|
|
62
|
-
use u_numflow::transforms::{
|
|
64
|
+
use u_numflow::transforms::{box_cox, estimate_lambda};
|
|
63
65
|
let data = [1.0, 2.0, 4.0, 8.0, 16.0];
|
|
64
|
-
let
|
|
65
|
-
let transformed = box_cox(&data, lambda).unwrap();
|
|
66
|
+
let fit = estimate_lambda(&data, -2.0, 2.0).unwrap(); // MLE via golden-section
|
|
67
|
+
let transformed = box_cox(&data, fit.lambda).unwrap();
|
|
68
|
+
assert_eq!(transformed.len(), data.len());
|
|
66
69
|
|
|
67
70
|
// Discrete Fourier transform of any length
|
|
68
71
|
use u_numflow::fourier::rfft;
|
|
@@ -100,12 +103,17 @@ The package resolves per environment via a conditional `exports` map:
|
|
|
100
103
|
| Bundlers (webpack, Vite, …) | ESM + WebAssembly ESM-integration (`default` condition) |
|
|
101
104
|
| Node.js — `require()`, ESM `import`, CJS TS runners (`tsx`, `ts-node`) | CJS glue loading the wasm from the filesystem (`node` condition) — no loader hooks or flags |
|
|
102
105
|
|
|
106
|
+
A browser **without** a bundler is not supported: the package loads its `.wasm`
|
|
107
|
+
file with an ES module import, which browsers refuse (`application/wasm` is not a
|
|
108
|
+
module script type), so `<script type="module">` from a CDN fails, and CDN
|
|
109
|
+
re-bundling services fail on the same import. Use a bundler or Node.
|
|
110
|
+
|
|
103
111
|
Exported functions: `mean`, `std_dev`, `variance`, `normal_cdf`, `normal_sf` (upper tail `P(Z > x)`, computed directly so tail probabilities keep ~15 significant digits), `box_cox`, `estimate_lambda` (returns `{ lambda, at_bound }` — `at_bound` is `true` when the likelihood was still rising at an end of the search range, so `lambda` is that limit), and
|
|
104
112
|
`rfft(data) -> Float64Array` — the DFT of a real sequence of any length, interleaved as
|
|
105
113
|
`[re0, im0, re1, im1, …]` (bins `k` and `n − k` are conjugates, so `0..=n/2` describes the spectrum).
|
|
106
114
|
|
|
107
115
|
Distribution functions for critical values and p-values — each returns a `number` and
|
|
108
|
-
**throws** (
|
|
116
|
+
**throws** (an `Error` naming the argument — see *Errors* below) when an argument is outside the domain,
|
|
109
117
|
rather than returning `NaN`:
|
|
110
118
|
|
|
111
119
|
| Function | Returns |
|
|
@@ -123,22 +131,45 @@ const { t_distribution_quantile } = require("@iyulab/u-numflow");
|
|
|
123
131
|
t_distribution_quantile(0.975, 10); // 2.2281…
|
|
124
132
|
```
|
|
125
133
|
|
|
134
|
+
**Errors.** A refusal throws an `Error` whose `message` is readable text and which
|
|
135
|
+
carries a `code` naming the reason, next to the values behind it:
|
|
136
|
+
|
|
137
|
+
```js
|
|
138
|
+
const { t_distribution_quantile } = require("@iyulab/u-numflow");
|
|
139
|
+
try {
|
|
140
|
+
t_distribution_quantile(1.5, 10);
|
|
141
|
+
} catch (err) {
|
|
142
|
+
console.log(err.code, err.parameter, err.min, err.max, err.got); // parameter_out_of_range p 0 1 1.5
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
| `code` | Fields | Meaning |
|
|
147
|
+
|---|---|---|
|
|
148
|
+
| `parameter_out_of_range` | `parameter`, `min`, `max` (or `null`), `got` | `p` not strictly inside (0, 1), or a degrees of freedom that is not a finite number `> 0` (both bounds excluded) |
|
|
149
|
+
| `value_not_finite` | `parameter` (for a scalar argument) | A NaN argument, or a NaN or infinity in `box_cox`/`estimate_lambda` data |
|
|
150
|
+
| `non_positive_data` | — | Box-Cox data with a value `≤ 0` |
|
|
151
|
+
| `insufficient_data` | — | Box-Cox data with fewer than 2 values |
|
|
152
|
+
| `invalid_transform` | — | A Box-Cox result that is not finite |
|
|
153
|
+
| `invalid_lambda_range` | — | `estimate_lambda` bounds that are not finite with `lambda_min < lambda_max` |
|
|
154
|
+
|
|
126
155
|
### TypeScript
|
|
127
156
|
|
|
128
|
-
Every exported function declares its return
|
|
129
|
-
generated from the same structs the binding
|
|
130
|
-
from what it actually returns:
|
|
157
|
+
Every exported function declares its parameter and return types, and the
|
|
158
|
+
declarations are generated from the same structs the binding reads and
|
|
159
|
+
serialises, so they cannot drift from what it actually accepts and returns:
|
|
131
160
|
|
|
132
161
|
```ts
|
|
133
|
-
export function estimate_lambda(data:
|
|
162
|
+
export function estimate_lambda(data: Float64Array, lambda_min: number, lambda_max: number): LambdaEstimateDto;
|
|
134
163
|
```
|
|
135
164
|
|
|
136
165
|
An absent optional value is declared `T | undefined`, which is what the binding
|
|
137
166
|
sends. Nothing needs an `as` cast -- and a wrong assumption about a result's
|
|
138
167
|
shape is a compile error rather than something that fails at run time.
|
|
139
168
|
|
|
140
|
-
|
|
141
|
-
|
|
169
|
+
Every parameter is a number or a `Float64Array`, so there is nothing to
|
|
170
|
+
declare beyond what wasm-bindgen already does; the publishing workflow keeps it
|
|
171
|
+
that way. The binding still validates every input at the boundary, and a
|
|
172
|
+
rejected one says what was wrong.
|
|
142
173
|
|
|
143
174
|
## Related
|
|
144
175
|
|
package/node/u_numflow.cjs
CHANGED
|
@@ -6,8 +6,9 @@
|
|
|
6
6
|
* All values in `data` must be strictly positive.
|
|
7
7
|
*
|
|
8
8
|
* # Errors
|
|
9
|
-
*
|
|
10
|
-
*
|
|
9
|
+
* Throws `non_positive_data`, `value_not_finite` or `insufficient_data` when
|
|
10
|
+
* data contains a value ≤ 0, a NaN or infinity, or fewer than 2 elements, and
|
|
11
|
+
* `invalid_transform` when a result is not finite.
|
|
11
12
|
* @param {Float64Array} data
|
|
12
13
|
* @param {number} lambda
|
|
13
14
|
* @returns {Float64Array}
|
|
@@ -72,9 +73,8 @@ exports.chi_squared_quantile = chi_squared_quantile;
|
|
|
72
73
|
* interior estimate; widen the range to find the unconstrained optimum.
|
|
73
74
|
*
|
|
74
75
|
* # Errors
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
* `lambda_min < lambda_max`.
|
|
76
|
+
* Throws as [`box_cox`] does for the data, and `invalid_lambda_range` when the
|
|
77
|
+
* range is not finite with `lambda_min < lambda_max`.
|
|
78
78
|
* @param {Float64Array} data
|
|
79
79
|
* @param {number} lambda_min
|
|
80
80
|
* @param {number} lambda_max
|
|
@@ -289,13 +289,21 @@ function __wbg_get_imports() {
|
|
|
289
289
|
getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
|
|
290
290
|
getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
|
|
291
291
|
},
|
|
292
|
-
|
|
292
|
+
__wbg___wbindgen_throw_41e9ee4f547fc59a: function(arg0, arg1) {
|
|
293
293
|
throw new Error(getStringFromWasm0(arg0, arg1));
|
|
294
294
|
},
|
|
295
|
-
|
|
295
|
+
__wbg_new_343a093a3c2ffb4e: function(arg0, arg1) {
|
|
296
|
+
const ret = new Error(getStringFromWasm0(arg0, arg1));
|
|
297
|
+
return ret;
|
|
298
|
+
},
|
|
299
|
+
__wbg_new_617a8cdb8bb1130e: function() {
|
|
296
300
|
const ret = new Object();
|
|
297
301
|
return ret;
|
|
298
302
|
},
|
|
303
|
+
__wbg_set_145a351398b48c65: function() { return handleError(function (arg0, arg1, arg2) {
|
|
304
|
+
const ret = Reflect.set(arg0, arg1, arg2);
|
|
305
|
+
return ret;
|
|
306
|
+
}, arguments); },
|
|
299
307
|
__wbg_set_6be42768c690e380: function(arg0, arg1, arg2) {
|
|
300
308
|
arg0[arg1] = arg2;
|
|
301
309
|
},
|
|
@@ -325,6 +333,12 @@ function __wbg_get_imports() {
|
|
|
325
333
|
};
|
|
326
334
|
}
|
|
327
335
|
|
|
336
|
+
function addToExternrefTable0(obj) {
|
|
337
|
+
const idx = wasm.__externref_table_alloc();
|
|
338
|
+
wasm.__wbindgen_externrefs.set(idx, obj);
|
|
339
|
+
return idx;
|
|
340
|
+
}
|
|
341
|
+
|
|
328
342
|
function getArrayF64FromWasm0(ptr, len) {
|
|
329
343
|
ptr = ptr >>> 0;
|
|
330
344
|
return getFloat64ArrayMemory0().subarray(ptr / 8, ptr / 8 + len);
|
|
@@ -358,6 +372,15 @@ function getUint8ArrayMemory0() {
|
|
|
358
372
|
return cachedUint8ArrayMemory0;
|
|
359
373
|
}
|
|
360
374
|
|
|
375
|
+
function handleError(f, args) {
|
|
376
|
+
try {
|
|
377
|
+
return f.apply(this, args);
|
|
378
|
+
} catch (e) {
|
|
379
|
+
const idx = addToExternrefTable0(e);
|
|
380
|
+
wasm.__wbindgen_exn_store(idx);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
361
384
|
function passArrayF64ToWasm0(arg, malloc) {
|
|
362
385
|
const ptr = malloc(arg.length * 8, 8) >>> 0;
|
|
363
386
|
getFloat64ArrayMemory0().set(arg, ptr / 8);
|
package/node/u_numflow.d.cts
CHANGED
|
@@ -15,8 +15,9 @@ export interface LambdaEstimateDto {
|
|
|
15
15
|
* All values in `data` must be strictly positive.
|
|
16
16
|
*
|
|
17
17
|
* # Errors
|
|
18
|
-
*
|
|
19
|
-
*
|
|
18
|
+
* Throws `non_positive_data`, `value_not_finite` or `insufficient_data` when
|
|
19
|
+
* data contains a value ≤ 0, a NaN or infinity, or fewer than 2 elements, and
|
|
20
|
+
* `invalid_transform` when a result is not finite.
|
|
20
21
|
*/
|
|
21
22
|
export function box_cox(data: Float64Array, lambda: number): Float64Array;
|
|
22
23
|
|
|
@@ -47,9 +48,8 @@ export function chi_squared_quantile(p: number, k: number): number;
|
|
|
47
48
|
* interior estimate; widen the range to find the unconstrained optimum.
|
|
48
49
|
*
|
|
49
50
|
* # Errors
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
* `lambda_min < lambda_max`.
|
|
51
|
+
* Throws as [`box_cox`] does for the data, and `invalid_lambda_range` when the
|
|
52
|
+
* range is not finite with `lambda_min < lambda_max`.
|
|
53
53
|
*/
|
|
54
54
|
export function estimate_lambda(data: Float64Array, lambda_min: number, lambda_max: number): LambdaEstimateDto;
|
|
55
55
|
|
package/node/u_numflow_bg.wasm
CHANGED
|
Binary file
|
package/package.json
CHANGED
package/u_numflow.d.ts
CHANGED
|
@@ -15,8 +15,9 @@ export interface LambdaEstimateDto {
|
|
|
15
15
|
* All values in `data` must be strictly positive.
|
|
16
16
|
*
|
|
17
17
|
* # Errors
|
|
18
|
-
*
|
|
19
|
-
*
|
|
18
|
+
* Throws `non_positive_data`, `value_not_finite` or `insufficient_data` when
|
|
19
|
+
* data contains a value ≤ 0, a NaN or infinity, or fewer than 2 elements, and
|
|
20
|
+
* `invalid_transform` when a result is not finite.
|
|
20
21
|
*/
|
|
21
22
|
export function box_cox(data: Float64Array, lambda: number): Float64Array;
|
|
22
23
|
|
|
@@ -47,9 +48,8 @@ export function chi_squared_quantile(p: number, k: number): number;
|
|
|
47
48
|
* interior estimate; widen the range to find the unconstrained optimum.
|
|
48
49
|
*
|
|
49
50
|
* # Errors
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
* `lambda_min < lambda_max`.
|
|
51
|
+
* Throws as [`box_cox`] does for the data, and `invalid_lambda_range` when the
|
|
52
|
+
* range is not finite with `lambda_min < lambda_max`.
|
|
53
53
|
*/
|
|
54
54
|
export function estimate_lambda(data: Float64Array, lambda_min: number, lambda_max: number): LambdaEstimateDto;
|
|
55
55
|
|
package/u_numflow_bg.js
CHANGED
|
@@ -4,8 +4,9 @@
|
|
|
4
4
|
* All values in `data` must be strictly positive.
|
|
5
5
|
*
|
|
6
6
|
* # Errors
|
|
7
|
-
*
|
|
8
|
-
*
|
|
7
|
+
* Throws `non_positive_data`, `value_not_finite` or `insufficient_data` when
|
|
8
|
+
* data contains a value ≤ 0, a NaN or infinity, or fewer than 2 elements, and
|
|
9
|
+
* `invalid_transform` when a result is not finite.
|
|
9
10
|
* @param {Float64Array} data
|
|
10
11
|
* @param {number} lambda
|
|
11
12
|
* @returns {Float64Array}
|
|
@@ -67,9 +68,8 @@ export function chi_squared_quantile(p, k) {
|
|
|
67
68
|
* interior estimate; widen the range to find the unconstrained optimum.
|
|
68
69
|
*
|
|
69
70
|
* # Errors
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
* `lambda_min < lambda_max`.
|
|
71
|
+
* Throws as [`box_cox`] does for the data, and `invalid_lambda_range` when the
|
|
72
|
+
* range is not finite with `lambda_min < lambda_max`.
|
|
73
73
|
* @param {Float64Array} data
|
|
74
74
|
* @param {number} lambda_min
|
|
75
75
|
* @param {number} lambda_max
|
|
@@ -269,13 +269,21 @@ export function __wbg_String_8564e559799eccda(arg0, arg1) {
|
|
|
269
269
|
getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
|
|
270
270
|
getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
|
|
271
271
|
}
|
|
272
|
-
export function
|
|
272
|
+
export function __wbg___wbindgen_throw_41e9ee4f547fc59a(arg0, arg1) {
|
|
273
273
|
throw new Error(getStringFromWasm0(arg0, arg1));
|
|
274
274
|
}
|
|
275
|
-
export function
|
|
275
|
+
export function __wbg_new_343a093a3c2ffb4e(arg0, arg1) {
|
|
276
|
+
const ret = new Error(getStringFromWasm0(arg0, arg1));
|
|
277
|
+
return ret;
|
|
278
|
+
}
|
|
279
|
+
export function __wbg_new_617a8cdb8bb1130e() {
|
|
276
280
|
const ret = new Object();
|
|
277
281
|
return ret;
|
|
278
282
|
}
|
|
283
|
+
export function __wbg_set_145a351398b48c65() { return handleError(function (arg0, arg1, arg2) {
|
|
284
|
+
const ret = Reflect.set(arg0, arg1, arg2);
|
|
285
|
+
return ret;
|
|
286
|
+
}, arguments); }
|
|
279
287
|
export function __wbg_set_6be42768c690e380(arg0, arg1, arg2) {
|
|
280
288
|
arg0[arg1] = arg2;
|
|
281
289
|
}
|
|
@@ -298,6 +306,12 @@ export function __wbindgen_init_externref_table() {
|
|
|
298
306
|
table.set(offset + 2, true);
|
|
299
307
|
table.set(offset + 3, false);
|
|
300
308
|
}
|
|
309
|
+
function addToExternrefTable0(obj) {
|
|
310
|
+
const idx = wasm.__externref_table_alloc();
|
|
311
|
+
wasm.__wbindgen_externrefs.set(idx, obj);
|
|
312
|
+
return idx;
|
|
313
|
+
}
|
|
314
|
+
|
|
301
315
|
function getArrayF64FromWasm0(ptr, len) {
|
|
302
316
|
ptr = ptr >>> 0;
|
|
303
317
|
return getFloat64ArrayMemory0().subarray(ptr / 8, ptr / 8 + len);
|
|
@@ -331,6 +345,15 @@ function getUint8ArrayMemory0() {
|
|
|
331
345
|
return cachedUint8ArrayMemory0;
|
|
332
346
|
}
|
|
333
347
|
|
|
348
|
+
function handleError(f, args) {
|
|
349
|
+
try {
|
|
350
|
+
return f.apply(this, args);
|
|
351
|
+
} catch (e) {
|
|
352
|
+
const idx = addToExternrefTable0(e);
|
|
353
|
+
wasm.__wbindgen_exn_store(idx);
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
334
357
|
function passArrayF64ToWasm0(arg, malloc) {
|
|
335
358
|
const ptr = malloc(arg.length * 8, 8) >>> 0;
|
|
336
359
|
getFloat64ArrayMemory0().set(arg, ptr / 8);
|
package/u_numflow_bg.wasm
CHANGED
|
Binary file
|