pub fn fft_f32(complex_interleaved: &[f32]) -> Result<Vec<f32>, ForgeError>Expand description
Best-path forward FFT: out = DFT(in) over n = complex_interleaved.len()/2
complex points, input and output interleaved f32 ([re0, im0, re1, im1, …],
length 2*n). The transform is un-normalized and uses the forward sign
convention X[k] = Σ_j x[j] · e^{−2πi kj/N}, identical on both paths.
§Why this differs from the GEMM/GEMV dispatch shape
Unlike gemm_f32/gemm_f64, the FFT has no CUDA/df64 arm — the forge
only ships a WGSL radix-2 kernel today, so the accelerated path is
wgpu-only. There is therefore exactly one accelerator branch:
| path (in order) | when |
|---|---|
WGSL forge (ForgeRuntime::fft) | caps().wgpu and n a power of two, 2 ≤ n ≤ 1024 |
CPU floor (dft_cpu) | otherwise, or if the forge errors at runtime |
The CPU floor is the naive O(N²) DFT dft_cpu — always present, never
broken. The forge kernel runs ONE workgroup of n threads, which is why n
must be a power of two and ≤ 1024 (the single-workgroup cap); inputs outside
that window fall straight to the CPU floor. On any forge build/dispatch error
the call falls through to the CPU floor rather than propagating (mirrors
gemm_f32).
complex_interleaved.len() must be even (it is 2*n); an odd length is the
only hard error.