@seantalts/stanli 0.9.1 → 0.9.3
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 +27 -12
- package/index.mjs +11 -11
- package/package.json +2 -1
- package/stancjs.bc.js +7394 -7695
- package/stanli-compiler.js +12003 -0
- package/stanli.js +1 -1
- package/stanli.wasm +0 -0
- package/worker.js +28 -9
package/README.md
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
# stanli
|
|
2
2
|
|
|
3
3
|
Full [Stan](https://mc-stan.org) in the browser. stanc3 (the real Stan
|
|
4
|
-
compiler, compiled to JavaScript)
|
|
5
|
-
|
|
6
|
-
lowers
|
|
7
|
-
with NUTS. No server, no C++
|
|
8
|
-
demo:
|
|
4
|
+
compiler, compiled to JavaScript) parses, typechecks, and optimizes the
|
|
5
|
+
model; the shared stanli OCaml pipeline encodes its typed MIR into portable
|
|
6
|
+
MIR. A WebAssembly build of the stanli runtime lowers that to an op graph over
|
|
7
|
+
precompiled stan-math kernels and samples with NUTS. No server, no C++
|
|
8
|
+
toolchain, everything in the tab. Live demo:
|
|
9
|
+
<https://seantalts.github.io/stanli/>.
|
|
9
10
|
|
|
10
11
|
```js
|
|
11
12
|
import { sample } from "@seantalts/stanli";
|
|
@@ -30,13 +31,27 @@ parameters, and generated quantities (RNG draws stream from `seed`).
|
|
|
30
31
|
The heavy work runs in a worker the package owns, so the page never
|
|
31
32
|
blocks; calls queue and run one at a time.
|
|
32
33
|
|
|
33
|
-
The
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
34
|
+
The preferred compiler, `stanli-compiler.js`, is 2,990,736 bytes raw and
|
|
35
|
+
425,026 bytes gzipped in the current measured build. For one rollback cycle
|
|
36
|
+
the package also contains stock `stancjs.bc.js` (2,971,677 bytes raw, 418,847
|
|
37
|
+
bytes gzipped). The worker loads the stock compiler only if the portable
|
|
38
|
+
compiler is unavailable; its O1 legacy MIR remains accepted by the runtime.
|
|
39
|
+
Carrying both temporarily doubles the compiler portion of the installed and
|
|
40
|
+
downloaded package.
|
|
41
|
+
|
|
42
|
+
The compiler loads lazily, only when a call passes Stan source. `preload()`
|
|
43
|
+
starts the compiler and WASM loads in the background; call it at page idle so
|
|
44
|
+
the first `sample()` skips the fetch and parse. An app that ships a fixed model
|
|
45
|
+
can precompile it at build time (`stanc --O1 --debug-optimized-mir model.stan`)
|
|
46
|
+
and pass `mir` instead of `code`; neither browser compiler loads, and the WASM
|
|
47
|
+
runtime alone is ~1.5 MB gzipped.
|
|
48
|
+
|
|
49
|
+
On Eight Schools, compact portable MIR is 6,932 bytes (1,793 gzipped), compared
|
|
50
|
+
with 33,320 bytes (2,000 gzipped) for legacy MIR. Across 51 fresh processes on
|
|
51
|
+
the same Apple arm64 release build, median decoder parsing was 0.074 ms versus
|
|
52
|
+
0.293 ms, and complete preparation was 0.278 ms versus 0.682 ms. These are
|
|
53
|
+
one-time preparation measurements; source compilation still dominates that
|
|
54
|
+
path.
|
|
40
55
|
|
|
41
56
|
118 of 119 posteriordb corpus models verify against CmdStan's log
|
|
42
57
|
density, gradients, and write_array values from inside this WASM build;
|
package/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
// stanli: full Stan in the browser. stanc3 (compiled to JS)
|
|
2
|
-
// source into MIR, and a WASM build of the stanli runtime
|
|
3
|
-
// op graph and runs NUTS. Everything happens client side, off
|
|
4
|
-
// thread, in workers this module owns.
|
|
1
|
+
// stanli: full Stan in the browser. The custom stanc3 build (compiled to JS)
|
|
2
|
+
// turns Stan source into portable MIR, and a WASM build of the stanli runtime
|
|
3
|
+
// lowers it to an op graph and runs NUTS. Everything happens client side, off
|
|
4
|
+
// the main thread, in workers this module owns.
|
|
5
5
|
//
|
|
6
6
|
// import { compile, sample } from "@seantalts/stanli";
|
|
7
7
|
// const { mir } = await compile({ code });
|
|
@@ -10,9 +10,10 @@
|
|
|
10
10
|
//
|
|
11
11
|
// Workers pool up to the hardware's concurrency, so independent calls --
|
|
12
12
|
// one chain each -- run simultaneously. Compiling once and passing `mir`
|
|
13
|
-
// keeps the
|
|
13
|
+
// keeps the 3.0 MB preferred compiler in a single worker (or out of the page
|
|
14
14
|
// entirely, if the model was precompiled at build time with
|
|
15
|
-
// stanc --O1 --debug-optimized-mir).
|
|
15
|
+
// stanc --O1 --debug-optimized-mir). The package carries stock stancjs for one
|
|
16
|
+
// rollback cycle, but the worker loads it only if the portable compiler fails.
|
|
16
17
|
|
|
17
18
|
const pool = [];
|
|
18
19
|
const waiters = [];
|
|
@@ -88,7 +89,7 @@ export function preload(opts) {
|
|
|
88
89
|
return Promise.all(jobs);
|
|
89
90
|
}
|
|
90
91
|
|
|
91
|
-
/** Compile Stan source to
|
|
92
|
+
/** Compile Stan source to portable MIR (one worker loads stanc3).
|
|
92
93
|
* @returns {Promise<{mir: string, ms: {stanc: number}}>} */
|
|
93
94
|
export function compile(opts) {
|
|
94
95
|
return request({ cmd: "compile", code: opts.code }, opts);
|
|
@@ -99,10 +100,9 @@ export function compile(opts) {
|
|
|
99
100
|
* @param {Object} opts
|
|
100
101
|
* @param {string} [opts.code] Stan source (compiled in the worker by
|
|
101
102
|
* stanc3, which loads lazily on first use).
|
|
102
|
-
* @param {string} [opts.mir] Precompiled MIR (from `compile()`
|
|
103
|
-
*
|
|
104
|
-
*
|
|
105
|
-
* ~1.3 MB gzipped.
|
|
103
|
+
* @param {string} [opts.mir] Precompiled MIR (from `compile()` here, or
|
|
104
|
+
* `stanc --O1 --debug-optimized-mir` at build time). When given, neither
|
|
105
|
+
* browser compiler loads: the runtime alone is ~1.5 MB gzipped.
|
|
106
106
|
* @param {Object|string} [opts.data] Data as an object or JSON text.
|
|
107
107
|
* @param {number} [opts.seed=1] Chain seed (sampler and GQ RNG).
|
|
108
108
|
* @param {number} [opts.warmup=1000]
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@seantalts/stanli",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.3",
|
|
4
4
|
"description": "Full Stan in the browser: stanc3 compiles the model in JS, a WASM runtime lowers it to an op graph and runs NUTS. No server, no C++ toolchain.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.mjs",
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
"worker.js",
|
|
13
13
|
"stanli.js",
|
|
14
14
|
"stanli.wasm",
|
|
15
|
+
"stanli-compiler.js",
|
|
15
16
|
"stancjs.bc.js",
|
|
16
17
|
"README.md",
|
|
17
18
|
"LICENSE"
|