3Tips for future agents. Patterned after the sibling `hitandrun-interactive`
4project (same numbl + uihtml two-way bridge, 2D canvas figure).
6## Architecture
8- `app/` — React single-file widget (`npm run build` → `app/dist/index.html`).
9- `*.m` at root — `walnuts_demo.m` (driver) and `walnuts_sampler.m` (figure plumbing).
10- `helpers/` — `walnuts.m` (the sampler) and the target `log_density.m` / `grad_log_density.m`, put on the path by the driver via `addpath('helpers')`.
11- `numbl-project.json` — project metadata; `entry` is the landing page.
13`addpath('helpers')` must be the **first statement** in the driver (numbl
14resolves the search path before running, and addpath can't live inside a
15function file). Run `walnuts_demo.m`, not the sampler directly.
17## Data flow (uihtml bridge)
19- **MATLAB → figure:** `uihtml(..., 'Data', struct)` / `sendEventToHTMLSource(src, name, data)`.
20- **Figure → MATLAB:** `sendToMATLAB(name, value)` (see `app/src/bridge.ts`), received via `HTMLEventReceivedFcn`.
22The script sends the density grid + samples once, then handles two requests
23(`walnuts_sampler.m` `on_event`):
25- `resample` `{n, dt, maxError}` → fresh chain → `samples` event. (Target is
26 fixed, so the density is not re-sent.)
27- `movie` `{dt, maxError}` → `walnuts(..., record=true)` for a few transitions →
28 `movie` event carrying their orbit trajectories.
30The figure's controls (samples / Δt / max error sliders, Resample) drive
31`resample`; the **▶ Movie** button drives `movie` and animates the returned
32orbits (`App.tsx` + `DensityView.tsx`).
34### Trajectory recording
36`walnuts.m` records the orbit path only when called with `record=true`, via
37globals (`WREC_*`): `macro_step` appends each *committed* macro-step's leapfrog
38path (recomputed by `leapfrog_capture`), tagged with a segment id so the figure
39breaks the polyline at orbit direction flips. Plain sampling (`record=false`)
40takes the fast path with no recording overhead.
42## The algorithm
44`helpers/walnuts.m` is a direct port of Brian Ward's `algorithms/WALNUTS.js`
45from chi-feng/mcmc-demo (based on Bob Carpenter's C++,
46flatironinstitute/walnuts; paper arXiv:2506.18746). Spans carry both orbit
47endpoints; `macro_step` does the within-orbit step halving; `build_span`
48recurses (NUTS doubling); selection is Barker within sub-orbits, Metropolis at
49the top. See README for full credits.
51## Performance
53Unlike the hitandrun kernel, WALNUTS uses **recursion + structs**, so it runs in
54the numbl **interpreter** (it does not JS-JIT like a flat numeric loop). It's
55still fine — banana orbits are shallow, ~1–2 ms/transition — so keep `N` modest
56(the demo uses 1000 + 200 burn-in). Don't add a `%!numbl:assert_jit` guard here;
57it would (correctly) fail.
59## Key files
61| File | Purpose |
62|------|---------|
63| `app/src/App.tsx` | Reads data, hosts the info panel |
64| `app/src/render/DensityView.tsx` | Canvas: density heatmap + sample scatter |
65| `app/src/bridge.ts` | `onData` / `onHostEvent` / `sendToMATLAB` (generic) |
66| `helpers/walnuts.m` | The WALNUTS sampler |
67| `helpers/log_density.m` / `grad_log_density.m` | Banana target |
68| `walnuts_sampler.m` | Runs the chain, builds the density grid, opens the figure |
69| `walnuts_demo.m` | Driver: addpath + seed + call the sampler |
71## Local iteration
73```
74cd app && npm install && npm run build # → app/dist/index.html
75cd ..
76npx tsx $NUMBL/src/cli.ts run walnuts_demo.m --plot # quick loop
77# or preview the GitHub Pages bundle:
78( cd $NUMBL && npm run build:site-viewer ) # one-time
79npx tsx $NUMBL/src/cli.ts build-site . --out _site --base /
80( cd _site && python3 -m http.server 8080 )
81```
83`$NUMBL` is a local clone of flatironinstitute/numbl. The real target is GitHub
84Pages, where the deploy builds numbl from `main`.