Skip to main content

Module compute

Module compute 

Source
Expand description

Cross-layer — where a numerical kernel runs (ComputeBackend: serial, multi-CPU via rayon, or GPU via wgpu), the worker-count policy, and the backend-selection rule. Dispatch only, no kernels. Where a numerical kernel runs — serial, multi-CPU, or GPU.

§What belongs in this module

The dispatch layer and nothing else: the ComputeBackend enum, the worker-count policy ThreadCount, the named backend-selection policy select_backend, and the GPU adapter probe. It is deliberately free of numerical code so that every kernel in the crate answers the question “where do I run?” the same way.

§What does NOT belong here

Kernels. A root finder, a sparse matrix-vector product, a quadrature rule or an ODE ensemble lives in its own module (polynomial/, ldu_matrix/, krylov/, math/, ode/) and takes a ComputeBackend as a parameter. If you find yourself writing physics or arithmetic in this file, it is in the wrong file.

§Hybrid means dispatch, not two APIs

A kernel exposes one public entry point with the backend as a parameter. It does not grow a foo_parallel() sibling beside foo(). Callers that do not care let select_backend resolve one for them; callers that do care name the backend explicitly and get exactly it, or a documented fallback. There is no Auto variant — resolution is a function, not a backend.

§The serial path is the oracle

ComputeBackend::Serial is always compiled, on every target, under every feature combination, and is the #[default]. It is the reference implementation that the other two are checked against, and it is the only one guaranteed to be bit-for-bit reproducible run to run. Verification and validation are judged against it. The other backends are acceleration.

§Cargo features — both OFF by default

FeatureAddsBackend enabled
(none)—ComputeBackend::Serial
parallelrayonComputeBackend::CpuMulti
gpuwgpu (non-Android only)ComputeBackend::Gpu

A default build pulls neither dependency, which keeps the crate dependency-light and Android/Termux clean. Requesting a backend whose feature is off is not an error: it resolves down to the best available one (see ComputeBackend::resolve). That way a caller written on a desktop with --features gpu still runs, correctly and more slowly, on a phone with no features at all.

§Android / Termux

rayon is pure Rust with no system component, so the parallel feature is not target-gated — it works on Android. wgpu is target-gated off Android in Cargo.toml, because Android has no system Vulkan/Metal loader and the workspace Android rule forbids GPU dependencies in a library build. Enabling gpu on an Android target therefore yields a build with no GPU backend rather than a broken one.

§Planned: hybrid CPU+GPU co-execution (NOT implemented)

There is no Hybrid variant and no GPU kernel in this crate — see gpu_adapter_present for the extent of the wgpu use. One policy decision for it is nevertheless already settled, because it constrains how the kernels are written.

For the iterative kernels the shape is coarse-to-fine, not a split batch: a GPU f32 pass produces only the initial guess, and the CPU converges it to the final answer at f64. The result is therefore entirely f64 and the f32 accuracy floors govern the guess, not the answer. This suits batched root finding especially well — RootProblem::guess already guarantees that a bad guess is a performance problem and not a correctness one, and Newton’s quadratic convergence turns an f32-accurate start into a f64 answer in about two iterations.

For the elementwise kernels, where a batch genuinely is split across the two devices, the CPU half runs f32 to match the GPU, so that precision is uniform across one output array rather than varying with the split ratio. Those kernels are an f32-class throughput path sitting roughly 1e-7 relative from the ComputeBackend::Serial oracle.

Numerical differentiation is excluded from both shapes: a finite difference has no fixed point to converge to, so there is no guess to seed and the f32 floor would land directly on the answer.

Full reasoning, the per-kernel floors at f32, the measured iteration savings, and the caveats none of this resolves are in docs/hybrid-precision-policy.md.

§Units

Nothing in this module carries a physical dimension. Sizes are counts of independent work items, which is a pure number. uom typing belongs on the kernels’ own signatures and must not be stripped to get data onto a device — convert at the buffer boundary and convert back.

Modules§

hybrid
Data-level co-execution: split one batch between the CPU and the GPU.

Enums§

ComputeBackend
Which execution backend a numerical kernel should use.
ThreadCount
How many worker threads ComputeBackend::CpuMulti should use.

Constants§

CPU_MULTI_MIN_WORK_ITEMS
The number of work items below which ComputeBackend::CpuMulti is not worth its thread-pool overhead, and select_backend returns ComputeBackend::Serial instead.
GPU_MIN_WORK_ITEMS
The number of work items below which ComputeBackend::Gpu is not worth the host-device transfer, and select_backend falls back to the best available CPU backend.

Functions§

gpu_adapter_present
Whether a usable GPU compute adapter exists, probed once and cached.
select_backend
The backend-selection policy — one named function, so a reader can find the rule instead of hunting for scattered if n > 1024 tests.