semiflow 0.14.0-beta

no_std Rust PDE solver: evolution equations via Chernoff approximation of operator semigroups (heat, diffusion, Schrodinger)
Documentation

semiflow

CI Crates.io Docs.rs License DOI

Status: beta (0.14.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.

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.

Install

[dependencies]
semiflow = "0.14.0-beta"

MSRV: Rust 1.81. The default build is #![no_std] + alloc with AVX2/NEON kernels (feature simd, scalar lanes elsewhere); std is needed only for parallel. See below.

Quickstart

Solve ∂ₜu = ½·∂ₓₓu from u₀(x) = e^{-x²} to t = 1 and compare with the closed-form solution u(1,x) = 3^{-1/2}·e^{-x²/3}:

use semiflow::{ChernoffSemigroup, DiffusionChernoff, Grid1D, GridFn1D, State};

let grid = Grid1D::new(-10.0, 10.0, 1000).expect("valid grid");
let u0 = GridFn1D::from_fn(grid, |x| (-x * x).exp());

// L = a(x)·∂²ₓ with a ≡ ½ (a' = a'' = 0), bound ‖a‖ = ½.
let diffusion = DiffusionChernoff::new(|_| 0.5_f64, |_| 0.0, |_| 0.0, 0.5, grid);
let semigroup = ChernoffSemigroup::new(diffusion, 100).expect("n >= 1");
let u1 = semigroup.evolve(1.0, &u0).expect("evolve");

let exact = GridFn1D::from_fn(grid, |x| (-x * x / 3.0).exp() / 3.0_f64.sqrt());
let mut err = u1.clone();
err.axpy(-1.0, &exact);
assert!(err.norm_sup() < 1e-5, "sup-norm error {}", err.norm_sup());

More: Quickstart, User Guide and the runnable examples (cargo run -p semiflow --example heat_2d_demo).

no_std

[dependencies]
semiflow = "0.14.0-beta"   # no_std + alloc, SIMD kernels

The crate is #![no_std] by default and needs only alloc; the std feature is needed only for parallel. What that means in practice:

  • Your binary provides a #[global_allocator] and a #[panic_handler], as for any no_std + alloc program (a std program already has both).
  • The target needs pointer-sized atomics (the engines share coefficient closures through alloc::sync::Arc): Cortex-M3/M4/M7/M33, RISC-V with the a extension, x86_64-unknown-none and similar work; thumbv6m does not.
  • SemiflowError implements Debug, Display and core::error::Error (the same trait as std::error::Error) in every build.
  • f32/f64 transcendentals come from the pure-Rust libm in every build, and the SIMD kernels use the same lane arithmetic with or without intrinsics, so std, no_std, simd and non-simd builds give bit-identical results on every CPU.
  • simd works without std (the intrinsics come from core::arch); parallel requires std.

This is verified on every pull request, not just type-checked:

CI job What it proves
no-std the default and the featureless build for the host, thumbv7em-none-eabihf, thumbv7m-none-eabi, riscv32imac-unknown-none-elf, and at MSRV 1.81
no-std-test the full semiflow test suite passes in the default (no_std) configuration
no-std-libm semiflow-nostd-check — closed-form oracle checks plus per-scenario output digests: the default no_std build (the job fails if anything enables num-traits/std), the std build and its AVX2 lanes must all produce the committed bits
no-std-libm-neon the same digests from the std build on aarch64 (NEON lanes)
no-std-qemu the same checks and digests as a bare-metal #![no_main] binary on Cortex-M3 (soft float) and Cortex-M4F (hard float) under QEMU — see nostd-qemu

Feature flags

Feature Default Effect
simd yes AVX2 (x86_64) / NEON (aarch64) kernels via core::arch, scalar lanes elsewhere. Works in no_std. Results are bit-identical to a non-simd build.
std no Links std. Needed only by parallel; math is libm either way, so results do not change. Without it the crate is no_std + alloc (the default).
parallel no Multi-threaded apply for 1D kernels and 2D/3D compositions via std::thread::scope; bit-identical across thread counts. Implies std; not for wasm32.
linear-interp no Enables InterpKind::Linear grid sampling (otherwise it returns SemiflowError::Unsupported).
s3-poc no Experimental S³ evolvers with a proven-boundary API (ADR-0169).
slow-tests no Internal: enables the long convergence gates. Not needed by users.
diff-scipy no Internal: SciPy differential test (needs Python). Not needed by users.
tracking-alloc no Internal: allocation counting in the latency_tail example. Not needed by users.

Engine catalogue

1D Chernoff functions

Type Order Description
DiffusionChernoff 2 5-point formula for a(x)∂²_x
Diffusion4thChernoff 4 4th-order spatial diffusion
Diffusion6thChernoff 6 6th-order spatial diffusion
Diffusion4thZeta4Chernoff 4 ζ⁴ Richardson
Diffusion6thZeta6Chernoff 6 ζ⁶ nested-Richardson
Diffusion8thZeta8Chernoff 8 ζ⁸ Chebyshev M=64
DiffusionExpmvChernoff<F> — Al-Mohy–Higham expmv action
TruncatedExpDiffusionChernoff 2 Truncated-exponential diffusion
TruncatedExp4thDiffusionChernoff 4 Truncated-exponential 4th-order
DriftReactionChernoff exact Characteristic-flow formula for b(x)∂_x + c(x)
DriftReactionZeta4Chernoff 4 ζ⁴ WITH drift via Richardson
ShiftChernoff1D 2 Formula (6) of Theorem 6, Remizov 2025

Compositions

Type Description
StrangSplit<D, R> Strang 2nd-order splitting: D(τ/2) ∘ R(τ) ∘ D(τ/2)
AxisLift<C> Lift a 1D ChernoffFunction to a 2D grid row or column

2D tensor-product

Type Description
Strang2D<X, Y> Palindromic Strang: Sx(τ/2) ∘ Sy(τ) ∘ Sx(τ/2), global order 2
NonSeparable2DChernoff Non-separable isotropic 2D operator
NonSeparable2DAnisotropicChernoff Non-separable anisotropic 2D operator

3D tensor-product

Type Description
AxisLift3D<C> Lift a 1D ChernoffFunction to a 3D grid along Axis::X/Y/Z
Strang3D<X, Y, Z> 3D palindromic Strang

Adaptive

Type Description
AdaptivePI<C> PI step-size controller wrapping any ChernoffFunction

Boundary conditions

Type Description
BoundaryPolicy::Dirichlet { value } Fixed-value stencil BC
BoundaryPolicy::Neumann Clamp-to-boundary stencil BC
BoundaryPolicy::Robin { alpha, beta } Robin stencil BC
BoundaryPolicy::OddReflect Odd-image stencil BC (used by DirichletHeat2ndChernoff)
KillingChernoff<C, R, F> Operator-level Dirichlet via Feynman-Kac killing
Killing2ndChernoff<C, K, F> Order-2 soft-killing e^{-τκ/2}·C(τ)·e^{-τκ/2}
ReflectedHeatChernoff<C, R, F> Neumann via Walsh 1986 image method
DirichletHeat2ndChernoff<C, R, F> Order-2 absorbing wall via odd-image method (math §21.9)
ObstacleChernoff<C, O, F> Projective-splitting obstacle / variational-inequality evolver

Resolvent and nonautonomous

Type Description
LaplaceChernoffResolvent<C, F> (λI − A)⁻¹ g via Gauss-Laguerre 32-pt quadrature — unique to Remizov
HowlandLift<C, F> Nonautonomous Howland lift on L²([0,T], X)
HdrSnapshot<F> NIST nearest-rank percentile library (no_std + alloc)

Riemannian manifold

Type Description
ManifoldChernoff<M, F> Curvature-corrected Gaussian on T_xM; order 1 (base) or 2 (with R/12)
Torus<F, D> Flat torus backend
Sphere2<F> Round 2-sphere backend
Hyperbolic2<F> Poincaré disk backend (also the SABR volatility manifold)
FubiniStudyCp1 Kähler CP¹ / Fubini-Study backend

High-dimensional and sparse-grid

Type Description
AnisotropicShiftChernoffND<F, D> d-D Gaussian shift via Gauss-Hermite tensor quadrature
AnisotropicShiftZeta2ND Order-2 ζ²-correction variant
AnisotropicShiftAdaptiveQ Adaptive per-point GH quadrature (41% fewer nodes/axis)
SmolyakGridND<F, const D> Smolyak sparse-grid backend for D ≥ 5

Matrix-valued operators

Type Description
MatrixDiffusionChernoff<F, M> Coupled M-component 1D diffusion; Padé[13/13] expm
MatrixDiffusionChernoff2D<F, M> Palindromic Strang 2D for M-component diffusion
MatrixDiffusionChernoff3D<F, M> Same for 3D
MatrixDiffusionChernoffComplex<F, M> Complex-valued Padé[13/13] coupled diffusion

Quantum graphs

Type Description
QuantumGraphHeatChernoff<F> Heat on quantum graphs with Kirchhoff vertex condition
QuantumSchrödingerChernoff<C> Complex Schrödinger on quantum graphs

Reverse-mode AD

Type Description
ReverseChernoff<F> Reverse-mode AD over (F_θ(τ))ⁿ u₀ via binomial checkpointing
CheckpointSchedule O(√n) default schedule (Griewank-Walther)
RegionMap DoF-aligned region partition enabling K>1 per-region parameter sensitivity

Scope: constant-a DiffusionChernoff<F> only. Multi-parameter (K>1) sensitivity via ReverseChernoff::with_region_map. Variable-coefficient kernels are deferred.

Tensor-train carrier

Type Description
TtChernoff<F> TT-Chernoff evolver; storage O(d·n·r²)
TtState<F> Tensor-train state u(i₁,…,i_d) = G₁[i₁]·…·G_d[i_d]
VarCoefTt<F> Variable-coefficient TT carrier for separable diagonal a_j(x_j)

Scope: linear diagonal-A Gaussian class (TtChernoff); separable diagonal variable coefficients (VarCoefTt). Non-separable variable coefficients and off-diagonal A are research-track. VarCoefTt::new returns SemiflowError::VarCoefOutOfClass when inputs fall outside the separable diagonal class.

Gridless / particle-ensemble

Type Description
GridlessChernoff<F, const D> Particle-ensemble Chernoff; implements ChernoffFunction<F>
MeasureState<F, D> Particle-ensemble state; exposes first_moment, variance, variance_per_axis diagnostics (math §38.12)
ParticleReduction Particle cap policy: WeightedVoronoi { cap } or GaussianBackground

Schrödinger, graph and quantum-graph operators

Type Description
SchrödingerChernoffComplex / SchrodingerChernoff Schrödinger equation on a native complex (or real-pair) carrier
GraphHeatChernoff Heat semigroup of a graph Laplacian
GraphKrylovChernoff, graph_expmv_frechet Depth-independent e^{−tL}·v (Chebyshev / Lanczos) and its edge-weight Fréchet gradient
QuantumGraphHeatChernoff / QuantumSchrödingerChernoff Metric graphs with Kirchhoff vertex conditions

Conservative, stiff and semilinear problems

Type Description
ConservativeDiffusionChernoff, assemble_conservative_csr_1d, assemble_conservative_csr_nd Divergence-form ∂ₓ(k(x)∂ₓu) with harmonic-mean faces (sharp material interfaces, optional contact resistance)
MultilayerStack, multilayer_evolve, MassWeightedConservativeChernoff Stiff multilayer conduction in one depth-flat Krylov action
SymmetricOperator, MassKOperator, EntrySensitivity, mass_lumped_evolve Externally assembled symmetric PSD sparse operators (FEM), the (M, K) problem without forming M⁻¹K, entry-wise gradients
general_operator::GeneralOperator Possibly non-symmetric CSR operators via Taylor expmv
phi_action, phi_action_batched, Etdrk4, Nonlinearity Semilinear ∂ₜu = Lu + N(u) by exponential time differencing (order 4)
SubordinatedChernoff Bochner–Phillips subordination of any engine
HypoellipticChernoff Kolmogorov, Heisenberg and Engel (step-2/3 Carnot) operators

Executor

ChernoffSemigroup<C, S> — wraps a ChernoffFunction and a step count; call .evolve(t, &f) to compute (S(t/n))ⁿ f.

Examples

Example Description
heat_2d_demo.rs 2D tensor heat equation (Gaussian oracle, convergence table)
strang_advdiff_demo.rs Strang splitting for 1D advection-diffusion
cev_european_call.rs CEV European option pricing vs Schroder (1989) closed form
boundary_demo.rs Boundary policy showcase (Dirichlet, Neumann, periodic)
latency_tail.rs HFT-style p99.9 latency benchmark
resolvent_perf.rs LaplaceChernoffResolvent L-gate bench harness
heston_pricer.rs Heston ρ→0 pricer via palindromic Strang
sabr_pricer.rs SABR-on-H² via ManifoldChernoff<Hyperbolic2>
graph_par_speedup.rs Parallel graph-heat speedup (--features parallel)
rough_heston_pricer.rs Oracle-validated risk-neutral rough-Heston pricer (--rate/--price); honest scope: solver of a 4-factor Markov approximation, not validated vs true rough-Heston
cargo run -p semiflow --example heat_2d_demo

Bindings

Language Package Notes
Rust semiflow (docs.rs) The full engine catalogue; no_std + alloc
Python semiflow-pde 85 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(), shift1d_coeff_grad(); 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.14.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.