@semiflow/wasm
v0.15.0-beta
Published
WebAssembly bindings for semiflow — Chernoff approximation of operator semigroups (experimental, API unstable pre-1.0).
Maintainers
Readme
@semiflow/wasm — WebAssembly bindings for SemiFlow
Status: beta (0.15.0-beta). The API is stabilising toward 1.0; minor versions may still make breaking changes. Bug reports and feedback are welcome.
SemiFlow solves evolution equations ∂ₜu = Lu (heat, diffusion,
Schrödinger, graph and manifold PDEs, …) by Chernoff approximation of operator
semigroups: no matrix exponentials, no linear solves, a flat memory footprint.
The core is a no_std + alloc Rust library with 3 runtime
dependencies (num-traits, libm, num-complex); the same engines are available from Python,
JavaScript/WebAssembly and C.
This package is the WebAssembly binding (wasm-bindgen) of the Rust crate
semiflow, for Node.js (CommonJS) and
browsers/bundlers (ES modules). TypeScript declarations are included.
The method evaluates e^{tL}f by iterating an explicit step operator S(τ):
(S(t/n))ⁿ f → e^{tL} f as n → ∞. Each step is an explicit stencil over a
Vec-backed grid with reused scratch buffers, so steady-state evolution does
not allocate.
Mathematical foundation: Theorem 6 of I. D. Remizov (2025), Vladikavkaz Math. J. 27(4), 124–135 (doi:10.46698/a3908-1212-5385-q).
Honest performance note. The primary measured advantage is memory frugality: a flat ~3 MB working set across the 1D/2D/3D families versus 50–418 MB for heavy frameworks. Wall-clock speed is not a general strength — for matched-accuracy PDE solving SemiFlow is slower than adaptive ODE solvers and spectral methods, and parallelism pays off only on large 3D grids. Two measured niches: tail-latency-sensitive pricing (
Diffusion4thChernoff≈ 41 ns p99.9 per tick) and L1-resident low-rank carriers (TtChernoff,ReverseChernoff). Treat memory and latency as measured properties of the concrete grid types, not guarantees of the traits. The 2026-10 overhaul (docs/perf/overhaul-v0_15.md) made the grid engines 2.6–39× faster bit-for-bit, the stiff Chebyshev graph actionO(√(λt))instead ofO(λt)(559× on issue #16), ETDRK4 2.1× and the general Taylor action 2.1× faster; Richardson extrapolation (richardson=) raises any engine's order bylevels − 1. Head-to-head comparisons quoted in the user guide predate it.
Install
npm install @semiflow/wasmNode.js ≥ 18 loads the CommonJS build (require); bundlers and browsers load
the ES-module build (import). To build from a source checkout (needs a Rust
toolchain and wasm-pack):
wasm-pack build crates/semiflow-wasm --target nodejs --out-dir pkg-node
wasm-pack build crates/semiflow-wasm --target web --out-dir pkg-web
# heavy-grid engines (see "Full build" below):
wasm-pack build crates/semiflow-wasm --target web --out-dir pkg-web -- --features fullQuickstart
Solve ∂ₜu = ∂ₓₓu from u₀(x) = e^{-x²} to t = 1 and compare with the
closed-form solution u(1,x) = 5^{-1/2}·e^{-x²/5} (Node.js):
const { Heat1D, panic_hook_init } = require('@semiflow/wasm');
panic_hook_init(); // readable Rust panic messages (optional)
const n = 1000;
const x = (i) => -10 + (20 * i) / (n - 1);
const u0 = Float64Array.from({ length: n }, (_, i) => Math.exp(-(x(i) ** 2)));
const state = new Heat1D(-10, 10, n, u0);
state.evolve(1.0, 100);
const u = state.values(); // Float64Array (copy)
let err = 0;
for (let i = 0; i < n; i++) {
err = Math.max(err, Math.abs(u[i] - Math.exp(-(x(i) ** 2) / 5) / Math.sqrt(5)));
}
if (!(err < 5e-4)) throw new Error(`sup-norm error ${err}`);In a browser or with a bundler, import the ES-module build and initialise it once:
import init, { Heat1D } from '@semiflow/wasm';
await init(); // fetches and compiles the .wasm module
const state = new Heat1D(-10, 10, 1000, new Float64Array(1000));Node.js examples on this page are executed by the project's CI against the current build.
API
The authoritative signatures are the TypeScript declarations shipped in the
package (web/semiflow_wasm.d.ts). The tables below are generated from the
Rust sources, so every name listed is exported under exactly that JS name.
npm build ("lite")
The published package contains:
| Class | Description |
|-------|-------------|
| AdjointFokkerPlanckV8 | Adjoint Fokker-Planck Chernoff on M(ℝ) — flat two-buffer interface. |
| EvolverHeat1DGreeksV3 | Hyper-dual Greeks evolver for unit-diffusion heat. |
| EvolverHeat1DUnitV3 | Evolver for the unit-diffusion heat equation. |
| GammaFamily | Ergonomic γ-schedule family for WentzellV8. |
| GraphHeat | Order-2 graph heat Chernoff state for ∂ₜu = −L_G u. |
| GraphHeat6 | Order-6 graph heat Chernoff state for ∂ₜu = −L_G u. |
| GraphPath | Path graph 0 − 1 − … − (n_nodes − 1) with unit edge weights. |
| GridlessEvolver | Gridless particle-ensemble Chernoff evolver (D=1). |
| GrowthV3 | Growth bound ‖S(τ)‖ ≤ M · exp(ω · τ). |
| Heat1D | 1-D heat equation state for JavaScript/WebAssembly. |
| MeasureState | Weighted-Dirac particle carrier for adjoint FP Chernoff (D=1). |
| ResolventJump2DV8 | Resolvent time-jump evaluator for 2D unit-diffusion heat. |
| ResolventJump3DV8 | Resolvent time-jump evaluator for 3D unit-diffusion heat. |
| ResolventJumpV8 | Resolvent time-jump evaluator for 1D unit-diffusion heat. |
| ReverseHeat1D | Reverse-mode AD evolver for constant-a 1-D heat. |
| TtCoupledEvolver | Cross-axis TT-Chernoff evolver with CouplingTopology. |
| TtEvolver | Separable diagonal-A TT-Chernoff evolver. |
| TtState | Tensor-train carrier state (rank-1 separable construction). |
| VarCoefTtEvolver | Additive-separable variable-coefficient TT evolver. |
| WentzellV8 | Dynamic Wentzell/Robin BC evolver for 1D unit-diffusion heat. |
Full build
The heavy-grid, multi-dimensional, boundary-condition and hypoelliptic
engines are compiled only with the full Cargo feature, which the npm package
does not enable. Build it yourself to use them (see Install above):
| Class | Description |
|-------|-------------|
| AdaptivePI1D | PI-controller adaptive-step integrator for any supported 1-D kernel. |
| Adjoint1D | Adjoint semigroup wrapper for any supported 1-D Chernoff kernel. |
| AnisotropicShiftND2 | Anisotropic shift Chernoff kernel on a 2-D tensor-product grid. |
| AnisotropicShiftND3 | Anisotropic shift Chernoff kernel on a 3-D tensor-product grid (D=3). |
| ComplexTripleJumpV8 | Order-4 complex triple-jump, filiform-N5 Carnot, D=5 only. |
| DiffusionExpmv1D | 1-D diffusion via tolerance-driven expmv (Al-Mohy & Higham 2011). |
| DirichletHeat2nd1D | 1-D heat with Dirichlet BC via the odd image method. |
| DriftReaction1D | 1-D drift+reaction state (RK2 characteristic-flow Chernoff). |
| DriftReaction4th1D | 1-D drift-reaction with order-4 palindromic Strang kernel. |
| GraphHeat4th | Order-4 graph heat Chernoff: ∂ₜu = −L_G u via Padé[0,4] Taylor truncation. |
| GraphTraj | Degenerate fixed-topology graph trajectory (1 segment, constant Laplacian). |
| Heat1D4th | 1-D diffusion with 4th-order Chernoff kernel (unit a = 1). |
| Heat1D6th | 1-D diffusion with 6th-order Chernoff kernel (unit a = 1). |
| Heat1DZeta4 | 1-D diffusion with ζ⁴ Chernoff kernel — temporal order 4. |
| Heat1DZeta6 | 1-D diffusion with ζ⁶ Chernoff kernel — temporal order 6. |
| Heat1DZeta8 | 1-D diffusion with ζ⁸ Chernoff kernel — temporal order 8. |
| Heat2D | 2-D heat equation (a = 1, palindromic Strang splitting). |
| Heat2DVarA | 2-D heat with per-axis variable diffusion coefficient. |
| Heat3D | 3-D heat equation (a = 1, palindromic Strang splitting). |
| Heat3DVarA | 3-D heat with per-axis variable diffusion coefficient. |
| Howland1D | 1-D nonautonomous heat via Howland lift. |
| HypoellipticChernoffEngel | Engel step-3 Carnot group hypoelliptic Chernoff approximation. |
| HypoellipticChernoffHeisenberg | Heisenberg group H₁ Chernoff approximation (palindromic Strang-Hörmander). |
| HypoellipticChernoffKolmogorov | Kolmogorov phase-space hypoelliptic Chernoff approximation. |
| KilledDirichlet1D | 1-D heat with absorbing Dirichlet BC via Crank–Nicolson Cayley map. |
| Killing1D | 1-D heat with absorbing Dirichlet BC via Feynman-Kac killing. |
| Killing2nd1D | Order-2 soft-killing 1-D Feynman-Kac Chernoff. |
| Laplacian | Sparse Laplacian in CSR layout assembled from a GraphPath. |
| MagnusGraphHeat | Magnus K=4 graph heat: ∂ₜu = −L_G(t) u with time-varying edge weights. |
| MagnusGraphHeat6 | Magnus K=6 graph heat: ∂ₜu = −L_G(t) u — sixth-order GL₃ expansion. |
| Manifold2D | 2-D Riemannian manifold Chernoff approximation. |
| MatrixDiffusion1D | Coupled 2-component 1D diffusion state. |
| MatrixDiffusion2D | Coupled 2-component 2D diffusion state. |
| MatrixDiffusion3D | Coupled 2-component 3D diffusion state. |
| NonSeparable2D | 2-D non-separable diffusion with constant scalar coupling c. |
| NonSeparable2DAniso | 2-D non-separable diffusion with spatially-varying coupling β(x, y). |
| Obstacle1D | 1-D obstacle / variational-inequality Chernoff evolver. |
| ObstacleGammaV8 | Inactive-set Γ = V″ primitive. |
| ObstacleND2 | D=2 projective-splitting obstacle evolver. |
| PointEval | Pointwise evaluation via DiffusionChernoff<f64> Backend A. |
| QuantumGraph | Metric graph for quantum graph PDE solvers. |
| QuantumGraphHeat | Quantum graph heat Chernoff: ∂_t u = ½∂²_x u per edge, Kirchhoff BCs. |
| Reflected1D | 1-D heat with Neumann BC via the image method. |
| Resolvent1D | 1-D Laplace-Chernoff resolvent (λI − ∂²)⁻¹ g. |
| Robin1D | 1-D heat with Robin BC via the skew image method. |
| Schrodinger1D | 1-D Schrödinger equation state: iψ_t = (−Δ + V(x))ψ (free particle, V=0). |
| SchrodingerComplex1D | 1-D Schrödinger equation with native complex state: iψ_t = (−½Δ + V)ψ. |
| Shift1D | 1-D CDR state via formula (6) — kernel L = a(x)∂² + b(x)∂ + c(x). |
| SmolyakD6 | Sparse-grid Smolyak Chernoff step, D = 6, unit diffusion. |
| Strang1D | 1-D advection-diffusion via Strang splitting D(τ/2) ∘ R(τ) ∘ D(τ/2). |
| StrangGraph | Palindromic Strang split for graph heat Chernoff kernels. |
| Subordinated1D | 1-D subordinated heat semigroup. |
| TruncatedExp1D | 1-D diffusion with K=4 truncated-exp Chernoff kernel (unit a = 1). |
| TruncatedExp4th1D | 1-D diffusion with 4th-order truncated-exp Chernoff kernel (unit a = 1). |
| VarCoefGraphHeat | Variable-coefficient graph heat: ∂ₜu = −L_a u, L_a = A^{1/2} L_G A^{1/2}, A = diag(a). |
| VarCoefMagnusGraph | Variable-coefficient × time-dependent graph Magnus K=4: ∂_t u = −L_a(t) u, L_a(t) = sqrt(a(t)) ⊙ L_G(t) ⊙ sqrt(a(t)). |
Heat1D
| Member | Description |
|--------|-------------|
| new Heat1D(xmin, xmax, n, u0) | Unit diffusion on [xmin, xmax] with n ≥ 4 nodes; u0 is a Float64Array of length n |
| .evolve(t, nSteps) | Advance by time t with nSteps Chernoff steps |
| .values() | Current values as a Float64Array (copy) |
| .len() | Number of grid nodes |
ReverseHeat1D
Reverse-mode AD over constant-coefficient 1D heat (the diffusivity θ is the parameter):
| Member | Description |
|--------|-------------|
| new ReverseHeat1D(theta, xmin, xmax, nGrid, nSteps) | theta > 0, xmin < xmax, nGrid ≥ 4, nSteps ≥ 1 |
| .valueAndGrad(tau, u0, target) | Returns Float64Array [J, ∂J/∂θ] with J = ‖(F_θ(τ))ⁿ u₀ − target‖² |
| .theta(), .nSteps(), .nGrid() | Configuration accessors |
const { ReverseHeat1D } = require('@semiflow/wasm');
const nGrid = 24;
const u0 = Float64Array.from({ length: nGrid }, (_, i) => {
const x = -4 + (8 * i) / (nGrid - 1);
return Math.exp(-x * x);
});
const target = new Float64Array(nGrid); // all zeros
const rc = new ReverseHeat1D(0.4, -4.0, 4.0, nGrid, 8);
const [loss, grad] = rc.valueAndGrad(0.05, u0, target);
if (!(Number.isFinite(loss) && Number.isFinite(grad))) throw new Error('non-finite');Utilities and errors
| Function | Description |
|----------|-------------|
| version() | Version string of the Rust crate |
| panic_hook_init() | Installs console_error_panic_hook so Rust panics show a readable message instead of RuntimeError: unreachable |
Errors are thrown as JS Error objects with a .kind string:
GridMismatch, NanInf, OutOfDomain, BoundaryFailure, CflViolated,
ConvergenceFailed, Unsupported or Panic.
Bindings
| Language | Package | Notes |
|----------|---------|-------|
| Rust | semiflow (docs.rs) | The full engine catalogue; no_std + alloc |
| Python | semiflow-pde | 90 classes and the functions version(), heisenberg_heat_kernel(), sample_gridfn2d(), edge_weight_grad(), edge_weight_grad_batched(), graph_expmv_frechet(), symmetric_op_expmv_frechet(), assemble_conservative_csr_1d(), mass_lumped_evolve(), phi_action(), phi_action_batched(), phi_combination(), shift1d_coeff_grad(), richardson_weights(); NumPy in/out; complete .pyi stubs; see the PyPI page |
| JavaScript / WASM | @semiflow/wasm | Lite build on npm; the heavy-grid engines need a --features full build; see the npm page |
| C / C++ | semiflow-ffi | extern "C" ABI with catch_unwind on every entry point; header semiflow.h |
The bindings mirror the user-facing engines, not the internal composition types
(AxisLift, StrangSplit, … are Rust-side building blocks). Variable
coefficients cross the language boundary as pre-sampled arrays (evaluated in
Rust, no call back into the host language during evolve); some classes also
accept a host-language callback (e.g. Heat1D.with_a_function in Python,
Heat1D.withAFunction in JS, smf_state_new_with_closure in C).
The Bindings guide has side-by-side examples.
Documentation
| If you want to… | Read |
|-----------------|------|
| Get started | Quickstart · User Guide · Install |
| Use a binding | Bindings guide (C / Python / WASM) |
| Browse the Rust API | docs.rs/semiflow |
| See worked examples | crates/semiflow/examples |
| Understand accuracy and stability policy | Precision policy · API stability |
| Read design decisions | Architecture Decision Records |
| Follow changes | CHANGELOG · GitHub Releases |
Accuracy and design
Every numerical claim is gated in CI against a closed-form or high-order
reference oracle (convergence-order and sup-norm tests). Design principles:
no_std + alloc core; 3 runtime dependencies; SIMD hot
paths isolated to src/simd/ (AVX2 on x86_64, NEON on aarch64, scalar
fallback elsewhere); bit-reproducible parallelism across thread counts; no
unsafe in the math kernels. Builds with and without simd agree to rounding
but not always bit for bit, so golden files are tied to one configuration.
How to cite
If you use SemiFlow in academic work, cite both the software and the theorem.
@software{volkov2026semiflow,
author = {Volkov, Ilia},
title = {{SemiFlow}: {Chernoff} Approximation of Operator Semigroups},
year = {2026},
version = {0.15.0-beta},
doi = {10.5281/zenodo.20837851},
url = {https://doi.org/10.5281/zenodo.20837851}
}
@article{Remizov2025,
author = {I. D. Remizov},
title = {Chernoff Approximations of the Solution of Linear ODE with Variable Coefficients},
journal = {Vladikavkaz Math. J.},
volume = {27},
number = {4},
pages = {124--135},
year = {2025},
doi = {10.46698/a3908-1212-5385-q}
}The concept DOI 10.5281/zenodo.20837851
always resolves to the latest version; CITATION.cff has the
full entry (GitHub's "Cite this repository" reads it).
License
Dual-licensed under MIT or Apache-2.0, at your option.
Author, contributing, security
SemiFlow is created and maintained by Ilia Volkov. See CONTRIBUTING.md and CODE_OF_CONDUCT.md. Report vulnerabilities privately as described in SECURITY.md — not in public issues.
