Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Nonanti/mathcore/llms.txt

Use this file to discover all available pages before exploring further.

The mathcore::transforms module provides frequency-domain signal processing through the FFT struct. It exposes a forward FFT (Cooley-Tukey, with a rustfft backend when the fft feature flag is enabled), an always-available O(n²) DFT, an inverse FFT, a 2-D FFT for image processing, power-spectrum computation, and FFT-accelerated convolution. The sparse submodule additionally provides a Compressed Sparse Row matrix for efficient sparse linear-algebra operations. All FFT and DFT methods operate on Complex64 values from the num-complex crate.

Feature flag: fft

When the fft Cargo feature is enabled, the fft method delegates to a pre-planned rustfft::FftPlanner for high-performance FFTs on arbitrary-length inputs.
# Cargo.toml
[dependencies]
mathcore = { version = "*", features = ["fft"] }
Without the fft feature, fft falls back to the built-in recursive Cooley-Tukey implementation (power-of-two sizes) or the O(n²) DFT for non-power-of-two lengths. dft is always available regardless of the feature flag.

pub struct FFT

A zero-sized unit struct that namespaces all transform operations. No instance is required.
pub struct FFT;
Import with:
use mathcore::transforms::FFT;
use num_complex::Complex64;

fft

Computes the Discrete Fourier Transform using the Cooley-Tukey algorithm. With the fft feature enabled the computation is delegated to a rustfft forward planner. Without the feature, the built-in recursive split-radix implementation is used for power-of-two lengths; non-power-of-two inputs automatically fall back to dft. The output vector has the same length as the input. Output element k is:
X[k] = Σ_{j=0}^{n-1}  x[j] · e^{-2πi·j·k/n}
pub fn fft(input: &[Complex64]) -> Vec<Complex64>
input
&[Complex64]
required
The input signal in the time domain as a slice of complex values. Real-only signals should be passed with imaginary parts set to 0.0. Inputs of length 0 or 1 are returned unchanged.
Returns Vec<Complex64> of the same length as input, containing the frequency-domain representation. The DC component is at index 0.
use mathcore::transforms::FFT;
use num_complex::Complex64;

// Constant signal [1, 1, 1, 1]  →  DC = 4, all other bins = 0
let input = vec![
    Complex64::new(1.0, 0.0),
    Complex64::new(1.0, 0.0),
    Complex64::new(1.0, 0.0),
    Complex64::new(1.0, 0.0),
];
let spectrum = FFT::fft(&input);

assert!((spectrum[0].re - 4.0).abs() < 1e-10);  // DC bin
assert!(spectrum[0].im.abs() < 1e-10);
assert!(spectrum[1].norm() < 1e-10);              // no higher harmonics
assert!(spectrum[2].norm() < 1e-10);
assert!(spectrum[3].norm() < 1e-10);

dft

Computes the Discrete Fourier Transform using a direct O(n²) double-loop algorithm. Always available regardless of the fft feature flag. Useful for reference, small inputs, or non-power-of-two lengths where the fast path is unavailable.
pub fn dft(input: &[Complex64]) -> Vec<Complex64>
input
&[Complex64]
required
The input signal as a complex slice. There is no length restriction; any non-negative length is accepted.
Returns Vec<Complex64> of the same length, containing frequency coefficients identical in definition to the fft output.
use mathcore::transforms::FFT;
use num_complex::Complex64;

// Single-frequency cosine at bin 1
let n = 8;
let input: Vec<Complex64> = (0..n)
    .map(|k| {
        let angle = 2.0 * std::f64::consts::PI * k as f64 / n as f64;
        Complex64::new(angle.cos(), 0.0)
    })
    .collect();

let spectrum = FFT::dft(&input);
// Energy concentrated at bins 1 and n-1
println!("bin 1 magnitude: {:.4}", spectrum[1].norm()); // ≈ 4.0

ifft

Computes the Inverse Fast Fourier Transform by conjugating the input, calling fft, then conjugating and scaling the output by 1/n.
pub fn ifft(input: &[Complex64]) -> Vec<Complex64>
input
&[Complex64]
required
The frequency-domain signal (e.g., output of fft). Must have the same length as the original time-domain signal.
Returns Vec<Complex64> of the same length, approximating the original time-domain signal.
use mathcore::transforms::FFT;
use num_complex::Complex64;

let signal = vec![
    Complex64::new(1.0, 0.0),
    Complex64::new(0.0, 1.0),
    Complex64::new(-1.0, 0.0),
    Complex64::new(0.0, -1.0),
];

let spectrum   = FFT::fft(&signal);
let recovered  = FFT::ifft(&spectrum);

for (orig, rec) in signal.iter().zip(recovered.iter()) {
    assert!((orig.re - rec.re).abs() < 1e-10);
    assert!((orig.im - rec.im).abs() < 1e-10);
}

fft2d

Performs a 2-D FFT on a rectangular grid of complex values. The transform is applied first along each row, then along each column of the intermediate result (separable row-column decomposition).
pub fn fft2d(input: &[Vec<Complex64>]) -> Vec<Vec<Complex64>>
input
&[Vec<Complex64>]
required
A rectangular grid represented as a slice of rows, where each row is a Vec<Complex64> of equal length. An empty input returns an empty output immediately.
Returns Vec<Vec<Complex64>> of the same dimensions containing the 2-D frequency coefficients.
use mathcore::transforms::FFT;
use num_complex::Complex64;

// 4×4 constant image
let row = vec![Complex64::new(1.0, 0.0); 4];
let image = vec![row; 4];

let spectrum_2d = FFT::fft2d(&image);
// DC component at [0][0] = 16 (sum of all 16 ones)
println!("DC = {:.1}", spectrum_2d[0][0].re); // 16.0

power_spectrum

Computes the power spectrum of a real-valued signal. The signal is first wrapped into Complex64 values (imaginary part 0), FFT-transformed, and then the squared magnitude |X[k]|² is computed for each bin.
pub fn power_spectrum(signal: &[f64]) -> Vec<f64>
signal
&[f64]
required
The real-valued time-domain signal. The output has the same length.
Returns Vec<f64> of power values at each frequency bin, where result[k] = re(X[k])² + im(X[k])².
use mathcore::transforms::FFT;

let signal: Vec<f64> = (0..64)
    .map(|k| (2.0 * std::f64::consts::PI * k as f64 / 64.0).sin())
    .collect();

let power = FFT::power_spectrum(&signal);
// Dominant power at bin 1 (and its mirror at bin 63)
let max_bin = power.iter()
    .enumerate()
    .max_by(|a, b| a.1.partial_cmp(b.1).unwrap())
    .map(|(i, _)| i)
    .unwrap();
println!("Peak frequency bin: {}", max_bin); // 1

convolve

Convolves two real-valued sequences using FFT-based fast convolution (O(n log n)). Both inputs are zero-padded to the next power of two, pointwise-multiplied in the frequency domain, and then transformed back.
pub fn convolve(a: &[f64], b: &[f64]) -> Vec<f64>
a
&[f64]
required
First real-valued sequence.
b
&[f64]
required
Second real-valued sequence (filter kernel).
Returns Vec<f64> of length a.len() + b.len() - 1 containing the linear convolution of a and b.
use mathcore::transforms::FFT;

// Convolve [1, 2, 3] with [1, 0, -1]
let a = vec![1.0, 2.0, 3.0];
let b = vec![1.0, 0.0, -1.0];
let result = FFT::convolve(&a, &b);
// Expected: [1, 2, 2, -2, -3]
println!("{:?}", result);

Build docs developers (and LLMs) love