Expand description
Native GPU sampling: the same chromatic sweep the browser runs, on Vulkan, Metal or DX12.
§Why this is a separate crate
ferrotherm is std-only with zero dependencies, and that is load-bearing rather than
decorative: it is what lets the same source compile to wasm32-unknown-unknown and to a
microcontroller. A GPU backend needs a driver stack. So it lives out here beside silicon,
serve and cloud, each of which exists for exactly the same reason.
§Why it does not have its own shader
The WGSL comes from ferrotherm::wgsl::sweep_shader — the same string the browser fetches
through ft_shader. A second copy would be a second implementation of the update rule, and the
two would drift the first time one was tuned. The core crate already pins the sigmoid with a
test (the_shader_states_the_same_update_as_the_kernel); binding that same text here means a
native run and a browser run cannot disagree about the arithmetic, only about the hardware.
§What it does not promise
Not bit-identical to the CPU sampler. The shader’s RNG is a counter-based hash of
(step, node), chosen so a lane needs no state and the result does not depend on the order
lanes happen to execute in. The CPU sampler draws from its own stream. Both sample the same
distribution; neither reproduces the other’s individual flips, and a test that asserted they did
would be asserting something false.
What they DO agree on is physics, and that is what Gpu::sweep’s tests check: the same
magnetisation at the same temperature, and the exact mean energy from variable elimination.
§Verified on two vendors and two APIs
| adapter | API | tests | |
|---|---|---|---|
| Apple M5 Max | IntegratedGpu | Metal | 6/6 |
| NVIDIA L4 (EC2 g6.xlarge) | DiscreteGpu | Vulkan 1.4 | 6/6 |
| Microsoft Basic Render Driver (EC2 Windows) | Cpu | DX12 | 6/6 |
All three run the same WGSL from the core crate and all three reproduce the exact mean energy computed by variable elimination. A shader can pass on Metal and fail on Vulkan, whose validation is stricter and whose f32 behaviour differs, so this was worth checking rather than assuming.
The DX12 row is WARP, a software rasteriser, and that is a real limit on what it proves. It
establishes that the shader compiles under DX12 and that the physics is right; it says nothing
about DX12 on hardware, because there was none on that instance. Gpu::is_hardware reported
Cpu and the benchmark refused to quote a speedup, which is the guard working rather than a
caveat added afterwards. DX12 correctness: checked. DX12 on a real GPU: still not.
use ferrotherm::{ising::lattice2d, wgsl::GpuModel};
let g = lattice2d(8, 1.0);
let m = GpuModel::from_graph(&g);
let mut spins = vec![1i8; 64];
let gpu = ferrotherm_gpu::Gpu::new().ok_or("no adapter")?;
gpu.sweep(&m, &mut spins, 0.44, 100)?;Structs§
- Gpu
- A GPU that can run the sweep.