# math-webgpu-sandbox Write a MATLAB script, run it on your GPU. The sandbox compiles MATLAB-syntax scripts to fused WebGPU compute kernels, times them with the script's own `tic`/`toc`, and — because everything you write is plain MATLAB — you can paste the same script into real MATLAB and compare the numbers. An optional in-browser CPU run through [numbl](https://numbl.org)'s normal engine gives a third column without leaving the page. **Live page:** https://concept-collection.github.io/math-webgpu-sandbox/ ```matlab n = 8000000; x = rand(n, 1); y = zeros(n, 1); tic; for k = 1:600 y = y + 0.1*sin(x + k) .* exp(-x) + x.^2; end toc fprintf('checksum %.4f\n', mean(y)); ``` That loop body is **one** GPU kernel, compiled once and replayed 600 times — about five billion element-updates, a few seconds on an integrated GPU. ## How it works The script is parsed and lowered by numbl's JIT pipeline (reached through a `numbl-src` vite alias, the same arrangement [turing-surface](https://github.com/concept-collection/turing-surface) uses), which fixes every type and shape at compile time — `n = 2048; A = rand(n);` pins static shapes via exact-value propagation. The back end is this repo's: a planner maps the typed IR onto WebGPU, and an executor replays the resulting op sequence. - **Fusion.** numbl's inline pass folds single-use temps back into their consumer, and a sandbox-side pass (`src/mgpu/fuse.ts`) folds the rest — transcendentals, comparisons, logicals — which numbl's C backend declines but WGSL handles. One source line becomes one kernel. Generators fuse too: `x = 2*rand(n,1) - 1` is a single kernel that hashes its way to uniform variates per element, touching no other buffer. - **Reductions** (`sum`/`mean`/`prod`/`max`/`min`/`norm`/`dot`) take a fused *loader*, so `sum(a.*b + c)` reads its operands exactly once. Vectors (and `X(:)`) reduce fully in two passes; matrices reduce per column, which in MATLAB's column-major layout is the contiguous direction. - **`A * B`** is a 16×16-tiled shared-memory GEMM (column-major, adapted from [matmul-bench](https://github.com/concept-collection/matmul-bench)); matrix transpose is a tiled relayout; vector transpose, `X(:)` and `reshape` are views of the same buffer (free) when the source is never reassigned. - **`for` loops replay, they don't unroll.** The body is planned once; the loop variable lives in a dynamic-offset uniform with one slot per iteration, and all iterations are encoded into one submit. `rand` inside a loop mixes the iteration counter into its stream, so every pass draws fresh values. - **`tic`/`toc` are synchronization points**: pending GPU work is submitted and awaited, then wall-clock time is taken on the host. That is the same thing MATLAB's synchronous tic/toc measures, which is what makes the number comparable when you paste the script there. ## What is (and isn't) supported Supported: elementwise math on real arrays (including comparisons, `&`/`|`/`~`, two-arg `max`/`min`, `mod`/`rem`, `.^`), `zeros`/`ones`/`eye`/`rand`/`randn`/ `linspace`/ranges, `A*B`, transpose, the reductions above, `A(:)`/`reshape`, counted `for` loops, `tic`/`toc`, `disp`/`fprintf`, semicolon-suppressed or echoed assignments, and literal row/matrix constants. Deliberately rejected, with a source-located error rather than a wrong answer: indexing/slicing beyond `(:)`, `if`/`while`, complex numbers, user-defined functions, variables that change size, and printing inside `for` loops (the body has nowhere to run host I/O — it replays on the GPU). ## The comparison is honest, with two caveats - The GPU computes in **f32**; WebGPU has no f64. MATLAB defaults to double. Timing comparisons are still meaningful; for the closest apples-to-apples, use `single` arrays in MATLAB. Values agree to single precision, and the scripts print checksums so you can see that they do. - `rand`/`randn` here are deterministic counter-based generators (PCG-flavored hash of element index and call site). Statistics match MATLAB's; individual draws do not, so checksums of random data are close but not equal. ## Development ``` npm install # numbl must be checked out as a sibling: ../../numbl npm run dev npm run test:node # correctness suite on desktop WebGPU (Dawn) npm run test:gpu # same suite in headless Chrome (SwiftShader fallback) ``` The GPU compiler runs from numbl's TypeScript sources directly (through the `numbl-src` alias), so no numbl build is needed. ## License Apache-2.0