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
| Feature | Adds | Backend enabled |
|---|---|---|
| (none) | — | ComputeBackend::Serial |
parallel | rayon | ComputeBackend::CpuMulti |
gpu | wgpu (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§
- Compute
Backend - Which execution backend a numerical kernel should use.
- Thread
Count - How many worker threads
ComputeBackend::CpuMultishould use.
Constants§
- CPU_
MULTI_ MIN_ WORK_ ITEMS - The number of work items below which
ComputeBackend::CpuMultiis not worth its thread-pool overhead, andselect_backendreturnsComputeBackend::Serialinstead. - GPU_
MIN_ WORK_ ITEMS - The number of work items below which
ComputeBackend::Gpuis not worth the host-device transfer, andselect_backendfalls 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 > 1024tests.