COOLJAPAN
← All posts

OxiFFT 0.4.0 Released — Distributed Real FFTs and Wisdom That Actually Learns

Pure Rust FFT and the rustfft replacement. OxiFFT 0.4.0 adds distributed real (r2c/c2r) MPI transforms, wires wisdom-based auto-tuning into MEASURE/PATIENT/EXHAUSTIVE planning so it really compares candidate algorithms, corrects the MSRV to 1.87, and ships a breaking cleanup of dead planner code plus a v2 wisdom binary format.

release oxifft fft mpi wisdom simd rust rustfft

Distributed real transforms land, and auto-tuning finally does what its name promises.

Today we released OxiFFT 0.4.0 — a release that adds distributed real (r2c/c2r) FFTs to the MPI adapter, wires the wisdom cache into MEASURE/PATIENT/EXHAUSTIVE planning so those flags genuinely benchmark competing algorithms, and cleans up a batch of dead code and packaging debt along the way.

No C. No Fortran. No FFTW. No FFI. OxiFFT is Pure Rust to the core, with default features that are 100% Rust — it compiles to a single static binary or to WASM, and displaces FFTW3 and rustfft for in-process transforms (and FFTW-MPI for distributed ones). The spectral backbone for the SciRS2 signal and audio stack, and now for 21 other COOLJAPAN projects, carries no native baggage.

Why 0.4.0 matters

This release ships one major capability, one long-standing correctness gap closed, and a breaking cleanup that’s overdue:

Technical Deep Dive

Distributed real transforms

MpiRealPlan2D and MpiRealPlan3D bring slab-decomposed r2c/c2r to oxifft-adapter-mpi, in the same half-complex layout FFTW-MPI uses: a real last dimension of size n is stored as n/2 + 1 complex coefficients, with odd last dimensions supported. c2r is normalized by 1 / product(dims) — deliberately unlike FFTW, which leaves c2r unnormalized — so an r2c → c2r round trip is the identity without any manual scaling. r2c honors MpiFlags::transposed_out, and new local_size_2d_r2c / local_size_3d_r2c helpers size your buffers correctly for the half-complex layout, mirroring fftw_mpi_local_size_*. Alongside this, MpiPlanND::distributed_fft_dim0 moved from one blocking all_gather_v per fiber to a single alltoallv-based transpose — two collectives total regardless of fiber count — validated under mpirun -n 1/2/3/4.

Wisdom-driven auto-tuning

Plan::dft_1d is now flag-aware and wisdom-cached. ESTIMATE keeps the pure heuristic, but MEASURE/PATIENT/EXHAUSTIVE now consult the runtime wisdom cache first, and on a miss, actually benchmark real candidate algorithms and cache the winner — so repeated MEASURE planning of the same size no longer re-benchmarks on every call. algorithm_from_solver_name was extended to reconstruct all stateful solvers, so imported or measured wisdom genuinely feeds back into plan selection rather than being recorded and ignored. Two new algorithms — Algorithm::Rader and Algorithm::CacheOblivious — are part of that candidate set, and Rader is now selected automatically by the ESTIMATE heuristic for prime sizes in 17..=1021.

Breaking cleanup and MSRV correction

oxifft::kernel::{Solver, ProblemHash, hash_problem} — dead code with zero implementors — is gone; kernel::planner::Planner / kernel::wisdom::WisdomEntry are the real, wired-in model. The wisdom binary format moved to v2 (BINARY_FORMAT_VERSION = 2): the v1 layout used a fixed 30-byte entry and a u16-bounded factor count, which could silently truncate MixedRadix solver names with many factors; v2 uses variable-length factor lists with an explicit u32 count, and from_binary still reads old v1 files. Separately, the workspace rust-version was corrected from 1.75 to 1.87hashbrown 0.17 alone requires edition2024/1.85 at dependency-resolution time, and oxifft’s own ntt/nufft modules use u32::is_multiple_of, stabilized in 1.87. This was verified empirically across rustup 1.75.0 through 1.88.0, not asserted.

Getting Started

cargo add oxifft

A minimal forward FFT — unchanged from prior releases:

use oxifft::{Complex, Direction, Flags, Plan};

let plan = Plan::dft_1d(1024, Direction::Forward, Flags::MEASURE)
    .expect("1024-pt plan");
let input = vec![Complex::new(1.0_f64, 0.0); 1024];
let mut output = vec![Complex::new(0.0_f64, 0.0); 1024];
plan.execute(&input, &mut output);

A distributed real forward transform, new in 0.4.0 (oxifft-adapter-mpi, requires a system MPI implementation):

use oxifft::kernel::Complex;
use oxifft_adapter_mpi::{local_size_2d_r2c, MpiFlags, MpiPool, MpiRealPlan2D};

let universe = mpi::initialize().expect("MPI_Init failed");
let pool = MpiPool::new(universe.world());

let (n0, n1) = (64, 32);
let (local_n0, local_0_start, real_alloc, complex_alloc) =
    local_size_2d_r2c(n0, n1, &pool);

let mut r2c = MpiRealPlan2D::<f64, _>::r2c(n0, n1, MpiFlags::estimate(), &pool)
    .expect("failed to create distributed r2c plan");

// Fill this rank's local_n0 rows of n1 real samples, starting at global
// row local_0_start, then:
let input = vec![0.0f64; real_alloc];
let mut spectrum = vec![Complex::new(0.0, 0.0); complex_alloc];
r2c.execute_r2c(&input, &mut spectrum)
    .expect("distributed r2c failed");

What’s New in 0.4.0

Tips

The foundation

OxiFFT is the spectral layer of the COOLJAPAN ecosystem. As of this release it’s a direct dependency of 21 other COOLJAPAN projects — including SciRS2, NumRS2, OxiBLAS, OxiCUDA (its GPU backend), ToRSh, OxiWhisper, SkleaRS, TenfloweRS, OxiMedia, and OxiPhysics — every transform staying Pure Rust from a single laptop to an MPI cluster. The new distributed real transforms extend that reach directly into MPI-scale signal and image pipelines that were previously complex-only.

Repository: https://github.com/cool-japan/oxifft

Star the repo if Pure Rust spectral computing belongs in your stack — and tell us how the new distributed real transforms perform on your cluster.

Pure Rust spectral computing — fast, safe, and sovereign, from a laptop to an MPI cluster.

KitaSan at COOLJAPAN OÜ July 27, 2026

↑ Back to all posts