tapewasm 0.3.0 → 0.3.2

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/index.d.ts CHANGED
@@ -11,3 +11,30 @@ export {
11
11
  sharedMemory,
12
12
  } from "./pkg/tapewasm.js";
13
13
  export { default } from "./pkg/tapewasm.js";
14
+
15
+ /** What `"auto"` uses: right for SpiderMonkey and JavaScriptCore. */
16
+ export const RE_ROLL_ABOVE: number;
17
+ /** For an engine that prefers straight-line, as V8 does. */
18
+ export const V8_RE_ROLL_ABOVE: number;
19
+
20
+ export interface Calibration {
21
+ /** Threshold to pass to `compileTape`. */
22
+ above: number;
23
+ /** False when the measurement could not run; `above` is the built-in value. */
24
+ measured: boolean;
25
+ prefersStraight?: boolean;
26
+ straightMs?: number;
27
+ loopedMs?: number;
28
+ error?: string;
29
+ }
30
+
31
+ /**
32
+ * Measure which shape this engine prefers and return a threshold for
33
+ * `compileTape`'s `reroll` argument. Call after `init()`. Cached; pass
34
+ * `{ force: true }` to measure again. Never throws — on failure it returns
35
+ * the built-in threshold.
36
+ */
37
+ export function calibrateReroll(options?: { force?: boolean; rounds?: number }): Promise<number>;
38
+
39
+ /** What the last `calibrateReroll` measured, or `null` before the first call. */
40
+ export function lastCalibration(): Calibration | null;
package/index.js CHANGED
@@ -14,4 +14,11 @@ export {
14
14
  clearAotExports,
15
15
  sharedMemory,
16
16
  } from "./pkg/tapewasm.js";
17
+ export {
18
+ calibrateReroll,
19
+ compileTapeCalibrated,
20
+ lastCalibration,
21
+ RE_ROLL_ABOVE,
22
+ V8_RE_ROLL_ABOVE,
23
+ } from "./calibrate.js";
17
24
  export default init;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tapewasm",
3
- "version": "0.3.0",
3
+ "version": "0.3.2",
4
4
  "description": "Compile an autodiff tape to a WebAssembly module and sample it with nuts-rs, in the browser.",
5
5
  "type": "module",
6
6
  "main": "./index.js",
package/pkg/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "tapewasm",
3
3
  "type": "module",
4
4
  "description": "Compile an autodiff tape to a wasm module and sample it with nuts-rs, in the browser. The wasm-bindgen API over tapewasm-codegen.",
5
- "version": "0.3.0",
5
+ "version": "0.3.2",
6
6
  "license": "MIT OR Apache-2.0",
7
7
  "repository": {
8
8
  "type": "git",
@@ -1,11 +1,16 @@
1
1
  // Bridge between tapewasm.wasm and a per-model compiled wasm, which imports
2
- // tapewasm's memory and exports `log_prob_grad`, `tapewasm_layout_id` and
3
- // `tapewasm_abi_version`.
2
+ // tapewasm's memory and exports `log_prob_grad`, `tapewasm_layout_id`,
3
+ // `tapewasm_abi_version` and `tapewasm_n_outputs` — plus `evaluate` when the
4
+ // tape named any outputs.
4
5
  //
5
6
  // The binding is per page while the scratch buffer belongs to one model, so
6
7
  // the sampler reads the id back to refuse a mismatched pair.
7
8
 
8
9
  let aotLogProbGrad = null;
10
+ let aotEvaluate = null;
11
+ // How many values `evaluate` writes. 0 when the tape named none, and for a
12
+ // module built before outputs existed, which exports neither.
13
+ let aotNOutputs = 0;
9
14
  // NaN means nothing is bound, or no id is exported; no u32 id collides with it.
10
15
  let aotLayoutId = NaN;
11
16
  // Likewise: a module from before the global existed reads as unknown, not as 0.
@@ -13,6 +18,9 @@ let aotAbiVersion = NaN;
13
18
 
14
19
  export function set_aot_exports(exports) {
15
20
  aotLogProbGrad = exports.log_prob_grad;
21
+ aotEvaluate = exports.evaluate ?? null;
22
+ const n = exports.tapewasm_n_outputs;
23
+ aotNOutputs = n ? n.value >>> 0 : 0;
16
24
  const g = exports.tapewasm_layout_id;
17
25
  aotLayoutId = g ? g.value >>> 0 : NaN;
18
26
  const v = exports.tapewasm_abi_version;
@@ -21,6 +29,8 @@ export function set_aot_exports(exports) {
21
29
 
22
30
  export function clear_aot_exports() {
23
31
  aotLogProbGrad = null;
32
+ aotEvaluate = null;
33
+ aotNOutputs = 0;
24
34
  aotLayoutId = NaN;
25
35
  aotAbiVersion = NaN;
26
36
  }
@@ -39,3 +49,17 @@ export function aot_logp(paramsPtr, gradsPtr, nParams, scratchPtr) {
39
49
  }
40
50
  return aotLogProbGrad(paramsPtr, gradsPtr, nParams, scratchPtr);
41
51
  }
52
+
53
+ export function aot_n_outputs() {
54
+ return aotNOutputs;
55
+ }
56
+
57
+ export function aot_evaluate(paramsPtr, outPtr, nParams, scratchPtr) {
58
+ if (!aotEvaluate) {
59
+ throw new Error(
60
+ "the bound module exports no evaluate — compile the tape with an " +
61
+ "`outputs` line naming what it should report",
62
+ );
63
+ }
64
+ return aotEvaluate(paramsPtr, outPtr, nParams, scratchPtr);
65
+ }
package/pkg/tapewasm.d.ts CHANGED
@@ -67,8 +67,25 @@ export class AotSampler {
67
67
  * once it returns.
68
68
  */
69
69
  advi(init: Float64Array, num_iters: number, mc_samples: number, learning_rate: number, seed: bigint, snapshot_every: number, on_snapshot?: ((iter: number, mu: Float64Array, elbo: Float64Array) => void) | null): AdviResult;
70
+ /**
71
+ * What the module's `outputs` named, at one point in the parameter space.
72
+ *
73
+ * The forward pass alone, so this is the way to a pointwise
74
+ * log-likelihood — one call per draw, a term per observation — or to a
75
+ * deterministic quantity the density does not return. It shares the
76
+ * scratch buffer with `logProbGrad`, whose own call recomputes what it
77
+ * needs, so the two interleave freely.
78
+ *
79
+ * Throws when the bound module was compiled from a tape that named no
80
+ * outputs.
81
+ */
82
+ evaluate(params: Float64Array): Float64Array;
70
83
  /**
71
84
  * `[log_prob, d/dparam...]`.
85
+ *
86
+ * The evaluator behind it is built on the first call and reused, so
87
+ * calling this in a row costs one `scratch_init` copy rather than one per
88
+ * call — the same evaluator `sample` and `advi` keep for a whole run.
72
89
  */
73
90
  logProbGrad(params: Float64Array): Float64Array;
74
91
  /**
@@ -116,6 +133,11 @@ export class CompiledTape {
116
133
  free(): void;
117
134
  [Symbol.dispose](): void;
118
135
  readonly layoutId: number;
136
+ /**
137
+ * How many values `AotSampler.evaluate` returns — what the tape's
138
+ * `outputs` line named, and 0 when it had none.
139
+ */
140
+ readonly nOutputs: number;
119
141
  readonly nParams: number;
120
142
  readonly scratchInit: Float64Array;
121
143
  /**
@@ -172,12 +194,22 @@ export function clearAotExports(): void;
172
194
  * The format is not an artifact and carries no compatibility promise: a tape
173
195
  * is written and consumed inside one call.
174
196
  *
197
+ * An `outputs` line names nodes the module reports through
198
+ * `AotSampler.evaluate` — a pointwise log-likelihood's per-observation terms,
199
+ * or a deterministic quantity. Without one the module is what it always was.
200
+ *
175
201
  * `reroll` says when a vectorised statement becomes a wasm loop: `"auto"`
176
- * (the default, straight-line below a size threshold), `"always"` or
177
- * `"never"`. Which is faster is an engine's preference, not the model's —
178
- * on one real model straight-line was faster on V8 and slower on
179
- * SpiderMonkey and JavaScriptCore — and `"always"` is also the smallest
180
- * module, often by an order of magnitude.
202
+ * (the default, straight-line below a size threshold), `"always"`, `"never"`,
203
+ * or a node count to re-roll past, written as a number.
204
+ *
205
+ * **Which is faster is an engine's preference, not the model's.** Measured
206
+ * across three engines, straight-line and re-rolled cross over between 8,026
207
+ * and 24,564 nodes in V8 and around 2,000 in SpiderMonkey and JavaScriptCore
208
+ * — an order of magnitude apart, so no single threshold serves all three. `"auto"` takes the
209
+ * lower one: near-optimal for two of the three, and up to 7.6x off on V8 for
210
+ * a trace between them. A caller that knows its engine passes the number.
211
+ *
212
+ * `"always"` is also the smallest module, often by an order of magnitude.
181
213
  */
182
214
  export function compileTape(tape: string, reroll?: string | null): CompiledTape;
183
215
 
@@ -220,6 +252,7 @@ export interface InitOutput {
220
252
  readonly adviresult_sigma: (a: number) => [number, number];
221
253
  readonly adviresult_snapshotIters: (a: number) => [number, number];
222
254
  readonly aotsampler_advi: (a: number, b: number, c: number, d: number, e: number, f: number, g: bigint, h: number, i: number) => [number, number, number];
255
+ readonly aotsampler_evaluate: (a: number, b: number, c: number) => [number, number, number, number];
223
256
  readonly aotsampler_logProbGrad: (a: number, b: number, c: number) => [number, number, number, number];
224
257
  readonly aotsampler_nParams: (a: number) => number;
225
258
  readonly aotsampler_new: (a: number, b: number, c: number, d: number, e: number, f: number) => [number, number, number];
@@ -230,6 +263,7 @@ export interface InitOutput {
230
263
  readonly clearAotExports: () => void;
231
264
  readonly compileTape: (a: number, b: number, c: number, d: number) => [number, number, number];
232
265
  readonly compiledtape_layoutId: (a: number) => number;
266
+ readonly compiledtape_nOutputs: (a: number) => number;
233
267
  readonly compiledtape_nParams: (a: number) => number;
234
268
  readonly compiledtape_scratchInit: (a: number) => [number, number];
235
269
  readonly compiledtape_wasm: (a: number) => [number, number];
@@ -245,10 +279,10 @@ export interface InitOutput {
245
279
  readonly tapewasmVersion: () => [number, number];
246
280
  readonly __wbindgen_malloc: (a: number, b: number) => number;
247
281
  readonly __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
248
- readonly __wbindgen_free: (a: number, b: number, c: number) => void;
249
282
  readonly __wbindgen_exn_store: (a: number) => void;
250
283
  readonly __externref_table_alloc: () => number;
251
284
  readonly __wbindgen_externrefs: WebAssembly.Table;
285
+ readonly __wbindgen_free: (a: number, b: number, c: number) => void;
252
286
  readonly __externref_table_dealloc: (a: number) => void;
253
287
  readonly __wbindgen_start: () => void;
254
288
  }
package/pkg/tapewasm.js CHANGED
@@ -1,9 +1,10 @@
1
1
  /* @ts-self-types="./tapewasm.d.ts" */
2
- import { aot_logp } from './snippets/tapewasm-6c5813ce65cccbcf/js/aot_bridge.js';
3
- import * as import1 from "./snippets/tapewasm-6c5813ce65cccbcf/js/aot_bridge.js"
4
- import * as import2 from "./snippets/tapewasm-6c5813ce65cccbcf/js/aot_bridge.js"
5
- import * as import3 from "./snippets/tapewasm-6c5813ce65cccbcf/js/aot_bridge.js"
6
- import * as import4 from "./snippets/tapewasm-6c5813ce65cccbcf/js/aot_bridge.js"
2
+ import { aot_evaluate, aot_logp } from './snippets/tapewasm-c400eec12145fd93/js/aot_bridge.js';
3
+ import * as import1 from "./snippets/tapewasm-c400eec12145fd93/js/aot_bridge.js"
4
+ import * as import2 from "./snippets/tapewasm-c400eec12145fd93/js/aot_bridge.js"
5
+ import * as import3 from "./snippets/tapewasm-c400eec12145fd93/js/aot_bridge.js"
6
+ import * as import4 from "./snippets/tapewasm-c400eec12145fd93/js/aot_bridge.js"
7
+ import * as import5 from "./snippets/tapewasm-c400eec12145fd93/js/aot_bridge.js"
7
8
 
8
9
 
9
10
  /**
@@ -144,8 +145,37 @@ export class AotSampler {
144
145
  }
145
146
  return AdviResult.__wrap(ret[0]);
146
147
  }
148
+ /**
149
+ * What the module's `outputs` named, at one point in the parameter space.
150
+ *
151
+ * The forward pass alone, so this is the way to a pointwise
152
+ * log-likelihood — one call per draw, a term per observation — or to a
153
+ * deterministic quantity the density does not return. It shares the
154
+ * scratch buffer with `logProbGrad`, whose own call recomputes what it
155
+ * needs, so the two interleave freely.
156
+ *
157
+ * Throws when the bound module was compiled from a tape that named no
158
+ * outputs.
159
+ * @param {Float64Array} params
160
+ * @returns {Float64Array}
161
+ */
162
+ evaluate(params) {
163
+ const ptr0 = passArrayF64ToWasm0(params, wasm.__wbindgen_malloc);
164
+ const len0 = WASM_VECTOR_LEN;
165
+ const ret = wasm.aotsampler_evaluate(this.__wbg_ptr, ptr0, len0);
166
+ if (ret[3]) {
167
+ throw takeFromExternrefTable0(ret[2]);
168
+ }
169
+ var v2 = getArrayF64FromWasm0(ret[0], ret[1]).slice();
170
+ wasm.__wbindgen_free(ret[0], ret[1] * 8, 8);
171
+ return v2;
172
+ }
147
173
  /**
148
174
  * `[log_prob, d/dparam...]`.
175
+ *
176
+ * The evaluator behind it is built on the first call and reused, so
177
+ * calling this in a row costs one `scratch_init` copy rather than one per
178
+ * call — the same evaluator `sample` and `advi` keep for a whole run.
149
179
  * @param {Float64Array} params
150
180
  * @returns {Float64Array}
151
181
  */
@@ -285,6 +315,15 @@ export class CompiledTape {
285
315
  const ret = wasm.compiledtape_layoutId(this.__wbg_ptr);
286
316
  return ret >>> 0;
287
317
  }
318
+ /**
319
+ * How many values `AotSampler.evaluate` returns — what the tape's
320
+ * `outputs` line named, and 0 when it had none.
321
+ * @returns {number}
322
+ */
323
+ get nOutputs() {
324
+ const ret = wasm.compiledtape_nOutputs(this.__wbg_ptr);
325
+ return ret >>> 0;
326
+ }
288
327
  /**
289
328
  * @returns {number}
290
329
  */
@@ -416,12 +455,22 @@ export function clearAotExports() {
416
455
  * The format is not an artifact and carries no compatibility promise: a tape
417
456
  * is written and consumed inside one call.
418
457
  *
458
+ * An `outputs` line names nodes the module reports through
459
+ * `AotSampler.evaluate` — a pointwise log-likelihood's per-observation terms,
460
+ * or a deterministic quantity. Without one the module is what it always was.
461
+ *
419
462
  * `reroll` says when a vectorised statement becomes a wasm loop: `"auto"`
420
- * (the default, straight-line below a size threshold), `"always"` or
421
- * `"never"`. Which is faster is an engine's preference, not the model's —
422
- * on one real model straight-line was faster on V8 and slower on
423
- * SpiderMonkey and JavaScriptCore — and `"always"` is also the smallest
424
- * module, often by an order of magnitude.
463
+ * (the default, straight-line below a size threshold), `"always"`, `"never"`,
464
+ * or a node count to re-roll past, written as a number.
465
+ *
466
+ * **Which is faster is an engine's preference, not the model's.** Measured
467
+ * across three engines, straight-line and re-rolled cross over between 8,026
468
+ * and 24,564 nodes in V8 and around 2,000 in SpiderMonkey and JavaScriptCore
469
+ * — an order of magnitude apart, so no single threshold serves all three. `"auto"` takes the
470
+ * lower one: near-optimal for two of the three, and up to 7.6x off on V8 for
471
+ * a trace between them. A caller that knows its engine passes the number.
472
+ *
473
+ * `"always"` is also the smallest module, often by an order of magnitude.
425
474
  * @param {string} tape
426
475
  * @param {string | null} [reroll]
427
476
  * @returns {CompiledTape}
@@ -514,11 +563,15 @@ function __wbg_get_imports() {
514
563
  __wbg___wbindgen_throw_5d9e815e6fdf150f: function(arg0, arg1) {
515
564
  throw new Error(getStringFromWasm0(arg0, arg1));
516
565
  },
517
- __wbg_aot_logp_73e1e4a75800334a: function(arg0, arg1, arg2, arg3) {
566
+ __wbg_aot_evaluate_3748b6e27554efe5: function() { return handleError(function (arg0, arg1, arg2, arg3) {
567
+ const ret = aot_evaluate(arg0 >>> 0, arg1 >>> 0, arg2 >>> 0, arg3 >>> 0);
568
+ return ret;
569
+ }, arguments); },
570
+ __wbg_aot_logp_d2c28ba4c292a1e0: function(arg0, arg1, arg2, arg3) {
518
571
  const ret = aot_logp(arg0 >>> 0, arg1 >>> 0, arg2 >>> 0, arg3 >>> 0);
519
572
  return ret;
520
573
  },
521
- __wbg_call_5c65f3296b077120: function() { return handleError(function (arg0, arg1, arg2, arg3, arg4, arg5, arg6) {
574
+ __wbg_call_ccf57e66805df431: function() { return handleError(function (arg0, arg1, arg2, arg3, arg4, arg5, arg6) {
522
575
  var v0 = getArrayF64FromWasm0(arg3, arg4).slice();
523
576
  wasm.__wbindgen_free(arg3, arg4 * 8, 8);
524
577
  var v1 = getArrayF64FromWasm0(arg5, arg6).slice();
@@ -561,10 +614,11 @@ function __wbg_get_imports() {
561
614
  return {
562
615
  __proto__: null,
563
616
  "./tapewasm_bg.js": import0,
564
- "./snippets/tapewasm-6c5813ce65cccbcf/js/aot_bridge.js": import1,
565
- "./snippets/tapewasm-6c5813ce65cccbcf/js/aot_bridge.js": import2,
566
- "./snippets/tapewasm-6c5813ce65cccbcf/js/aot_bridge.js": import3,
567
- "./snippets/tapewasm-6c5813ce65cccbcf/js/aot_bridge.js": import4,
617
+ "./snippets/tapewasm-c400eec12145fd93/js/aot_bridge.js": import1,
618
+ "./snippets/tapewasm-c400eec12145fd93/js/aot_bridge.js": import2,
619
+ "./snippets/tapewasm-c400eec12145fd93/js/aot_bridge.js": import3,
620
+ "./snippets/tapewasm-c400eec12145fd93/js/aot_bridge.js": import4,
621
+ "./snippets/tapewasm-c400eec12145fd93/js/aot_bridge.js": import5,
568
622
  };
569
623
  }
570
624
 
Binary file
@@ -11,6 +11,7 @@ export const adviresult_muSnapshots: (a: number) => [number, number];
11
11
  export const adviresult_sigma: (a: number) => [number, number];
12
12
  export const adviresult_snapshotIters: (a: number) => [number, number];
13
13
  export const aotsampler_advi: (a: number, b: number, c: number, d: number, e: number, f: number, g: bigint, h: number, i: number) => [number, number, number];
14
+ export const aotsampler_evaluate: (a: number, b: number, c: number) => [number, number, number, number];
14
15
  export const aotsampler_logProbGrad: (a: number, b: number, c: number) => [number, number, number, number];
15
16
  export const aotsampler_nParams: (a: number) => number;
16
17
  export const aotsampler_new: (a: number, b: number, c: number, d: number, e: number, f: number) => [number, number, number];
@@ -21,6 +22,7 @@ export const aotsampler_setTargetAccept: (a: number, b: number) => [number, numb
21
22
  export const clearAotExports: () => void;
22
23
  export const compileTape: (a: number, b: number, c: number, d: number) => [number, number, number];
23
24
  export const compiledtape_layoutId: (a: number) => number;
25
+ export const compiledtape_nOutputs: (a: number) => number;
24
26
  export const compiledtape_nParams: (a: number) => number;
25
27
  export const compiledtape_scratchInit: (a: number) => [number, number];
26
28
  export const compiledtape_wasm: (a: number) => [number, number];
@@ -36,9 +38,9 @@ export const sharedMemory: () => any;
36
38
  export const tapewasmVersion: () => [number, number];
37
39
  export const __wbindgen_malloc: (a: number, b: number) => number;
38
40
  export const __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
39
- export const __wbindgen_free: (a: number, b: number, c: number) => void;
40
41
  export const __wbindgen_exn_store: (a: number) => void;
41
42
  export const __externref_table_alloc: () => number;
42
43
  export const __wbindgen_externrefs: WebAssembly.Table;
44
+ export const __wbindgen_free: (a: number, b: number, c: number) => void;
43
45
  export const __externref_table_dealloc: (a: number) => void;
44
46
  export const __wbindgen_start: () => void;