FFT & Transforms

AppleAccelerate wraps Apple's vDSP transform functions for FFT, real FFT, DFT, and DCT.

FFT

The FFT API wraps Apple's vDSP FFT functions and follows the same naming conventions as AbstractFFTs.jl. Both 1D vectors and 2D matrices are supported with ComplexF64 and ComplexF32 inputs. A 1D fft/ifft/bfft/rfft/irfft (called without an explicit plan_fft setup) accepts lengths of the form f * 2^k with f ∈ {1, 3, 5, 15} — powers of two use vDSP's fast FFT path, while other supported lengths transparently use Apple's mixed-radix DFT (see is_supported_fft_length; the real-input DFT additionally requires k ≥ 4). 2D transforms remain power-of-2 only. Unsupported lengths throw an ArgumentError.

Choosing between AppleAccelerate and FFTW

AppleAccelerate's FFT is a direct vDSP binding: 1-D transforms support f * 2^k lengths (f ∈ {1, 3, 5, 15}), while 2-D transforms are power-of-2 only. Only 1-D vectors and 2-D matrices are supported, and it is reached exclusively through the AppleAccelerate. prefix. It does not plug into the AbstractFFTs.jl interface — loading AppleAccelerate never changes what fft/plan_fft do in your session, and will never override FFTW.jl.

For general sizes, 3-D and higher arrays, dimension-selective (region) transforms, or the standard Julia FFT interface, use FFTW.jl. vDSP is mainly competitive at small transform sizes; FFTW is typically faster at larger ones.

Real FFT (rfft, irfft, brfft) is likewise available only through the AppleAccelerate. prefix.

x = randn(ComplexF64, 1024)

# Forward FFT (auto-creates plan)
X = AppleAccelerate.fft(x)

# Normalized inverse FFT
x_recovered = AppleAccelerate.ifft(X)

# Unnormalized inverse (backward) FFT
X_back = AppleAccelerate.bfft(X)

# Reusable plan for repeated transforms of the same size
setup = AppleAccelerate.plan_fft(x)
X = AppleAccelerate.fft(x, setup)
x_recovered = AppleAccelerate.ifft(X, setup)

2D FFT works the same way — fft dispatches on the input shape:

x2 = randn(ComplexF64, 16, 32)
X2 = AppleAccelerate.fft(x2)
x2_recovered = AppleAccelerate.ifft(X2)

Batched 1D FFT

Passing a dims argument (1 = each column, 2 = each row) computes a batch of independent 1D transforms over a matrix in a single call, like FFTW's fft(A, dims). This wraps vDSP_fftm_zop. The transform length (size(A, dims)) must be a power of 2:

A = randn(ComplexF64, 16, 8)
F = AppleAccelerate.fft(A, 1)     # FFT of each column
A1 = AppleAccelerate.ifft(F, 1)   # normalized inverse
@assert A1 ≈ A

In-place FFT

In-place variants avoid allocating the output array:

x = randn(ComplexF64, 1024)
y = copy(x)
AppleAccelerate.fft!(y)       # forward, modifies y in-place
AppleAccelerate.ifft!(y)      # inverse, modifies y in-place
@assert y ≈ x
AppleAccelerate.fftFunction
fft(x::VecOrMat{Complex{T}}, [setup::FFTSetup{T}])

Compute the forward FFT of x via Apple vDSP. Supports 1D vectors and 2D matrices with ComplexF32 or ComplexF64 elements.

For a 1D vector with no explicit setup, non-power-of-2 lengths of the form f * 2^k with f ∈ {1, 3, 5, 15} are also supported and transparently use Apple's mixed-radix DFT (see is_supported_fft_length); an unsupported length throws an ArgumentError. When a setup::FFTSetup is supplied, or for 2D inputs, all dimensions must be powers of 2. If setup is omitted, a temporary plan is created automatically. Wraps vDSP_fft_zop (1D) / vDSP_fft2d_zop (2D).

source
fft(x::Matrix{Complex{T}}, dims::Integer, [setup::FFTSetup{T}])

Batched 1D forward FFT: transform each column (dims = 1) or each row (dims = 2) of x independently, like FFTW's fft(x, dims). The transform length (size(x, dims)) must be a power of 2. Wraps vDSP_fftm_zop.

source
AppleAccelerate.ifftFunction
ifft(x::VecOrMat{Complex{T}}, [setup::FFTSetup{T}])

Compute the normalized inverse FFT of x via Apple vDSP. Equivalent to bfft(x) / length(x). Satisfies ifft(fft(x)) ≈ x.

For a 1D vector with no explicit setup, non-power-of-2 lengths of the form f * 2^k with f ∈ {1, 3, 5, 15} are also supported (via Apple's mixed-radix DFT); an unsupported length throws an ArgumentError. With an explicit setup::FFTSetup, or for 2D inputs, all dimensions must be powers of 2. Wraps vDSP_fft_zop (1D) / vDSP_fft2d_zop (2D).

source
ifft(x::Matrix{Complex{T}}, dims::Integer, [setup::FFTSetup{T}])

Batched 1D normalized inverse FFT along dimension dims (1 = columns, 2 = rows). Satisfies ifft(fft(x, dims), dims) ≈ x. Wraps vDSP_fftm_zop.

source
AppleAccelerate.bfftFunction
bfft(x::VecOrMat{Complex{T}}, [setup::FFTSetup{T}])

Compute the unnormalized inverse (backward) FFT of x via Apple vDSP. The result is not divided by length(x); use ifft for the normalized version.

For a 1D vector with no explicit setup, non-power-of-2 lengths of the form f * 2^k with f ∈ {1, 3, 5, 15} are also supported (via Apple's mixed-radix DFT); an unsupported length throws an ArgumentError. With an explicit setup::FFTSetup, or for 2D inputs, all dimensions must be powers of 2. Wraps vDSP_fft_zop (1D) / vDSP_fft2d_zop (2D).

source
bfft(x::Matrix{Complex{T}}, dims::Integer, [setup::FFTSetup{T}])

Batched 1D unnormalized inverse (backward) FFT along dimension dims (1 = columns, 2 = rows). Use ifft for the normalized version. Wraps vDSP_fftm_zop.

source
AppleAccelerate.is_supported_fft_lengthFunction
is_supported_fft_length(n::Integer) -> Bool

Return true if a 1D complex FFT of length n is supported by Apple vDSP via the idiomatic fft/ifft/bfft API. Supported lengths are f * 2^k with f ∈ {1, 3, 5, 15} (this includes all powers of two).

source

Real FFT

rfft computes the FFT of real input, returning only the non-redundant complex coefficients (length N÷2+1). irfft inverts it back to real output.

x = randn(Float64, 1024)
X = AppleAccelerate.rfft(x)          # Complex vector of length 513
x_recovered = AppleAccelerate.irfft(X, 1024)  # Back to real, length 1024
@assert x_recovered ≈ x

1D real transforms called without an explicit setup also accept non-power-of-2 lengths of the form f * 2^k with f ∈ {3, 5, 15} and k ≥ 4 (e.g. 48, 160, 240), via Apple's real-input mixed-radix DFT (vDSP_DFT_zrop_CreateSetup).

2D real FFT is supported for power-of-2 dimensions and matches FFTW's rfft layout — an n1×n2 real matrix transforms to an (n1÷2+1)×n2 complex matrix:

x2 = randn(Float64, 16, 32)
X2 = AppleAccelerate.rfft(x2)                # 9×32 complex matrix
x2_recovered = AppleAccelerate.irfft(X2, 16) # back to real, 16×32
@assert x2_recovered ≈ x2
AppleAccelerate.plan_rfftFunction
plan_rfft(x::VecOrMat{T}) where T <: Union{Float32, Float64}

Create a reusable FFT setup for real-input forward transforms of the same size as x. For a matrix, the setup covers both dimensions (and can also be reused for the matching inverse transforms). Wraps vDSP_create_fftsetup.

source
AppleAccelerate.rfftFunction
rfft(x::VecOrMat{T}, [setup::FFTSetup{T}])

Compute the forward FFT of a real-valued vector or matrix x via Apple vDSP. Returns the non-redundant complex coefficients: length N÷2+1 for a vector of length N, and size (n1÷2+1)×n2 for an n1×n2 matrix (matching FFTW's rfft).

For a 1D vector with no explicit setup, non-power-of-2 lengths supported by Apple's real-input mixed-radix DFT (f * 2^k, f ∈ {3, 5, 15}, k ≥ 4) are also accepted; an unsupported length throws an ArgumentError. With an explicit setup::FFTSetup, or for 2D inputs, all dimensions must be powers of 2. Wraps vDSP_fft_zrop (1D) / vDSP_fft2d_zrop (2D) / vDSP_DFT_zrop_CreateSetup (1D mixed-radix).

source
AppleAccelerate.irfftFunction
irfft(X::Vector{Complex{T}}, n::Int, [setup::FFTSetup{T}])
irfft(X::Matrix{Complex{T}}, n1::Int, [setup::FFTSetup{T}])

Compute the normalized inverse real FFT, returning a real vector of length n or a real matrix of size n1×n2 where n2 = size(X, 2). Satisfies irfft(rfft(x), size(x, 1)) ≈ x.

For a 1D input with no explicit setup, non-power-of-2 lengths supported by Apple's real-input mixed-radix DFT are also accepted (see rfft). Wraps vDSP_fft_zrop (1D) / vDSP_fft2d_zrop (2D).

source
AppleAccelerate.brfftFunction
brfft(X::Vector{Complex{T}}, n::Int, [setup::FFTSetup{T}])
brfft(X::Matrix{Complex{T}}, n1::Int, [setup::FFTSetup{T}])

Compute the unnormalized inverse real FFT, returning a real vector of length n (X must have length n÷2+1) or a real matrix of size n1×n2 where n2 = size(X, 2) (X must have size (n1÷2+1)×n2). The result is not divided by the output length; use irfft for the normalized version.

For a 1D input with no explicit setup, non-power-of-2 lengths supported by Apple's real-input mixed-radix DFT are also accepted (see rfft). Wraps vDSP_fft_zrop (1D) / vDSP_fft2d_zrop (2D).

source

DFT (Complex Discrete Fourier Transform)

Wraps Apple's vDSP_DFT_zop for complex-to-complex DFT. Unlike the FFT functions, DFT supports non-power-of-2 lengths of the form f * 2^n where f ∈ {1, 3, 5, 15} and n ≥ 3. Both Float32 and Float64 are supported.

x = randn(ComplexF64, 120)  # 120 = 15 * 2^3, non-power-of-2

# Forward DFT (auto-creates setup)
X = AppleAccelerate.dft(x)

# Normalized inverse DFT
x_recovered = AppleAccelerate.idft(X)
@assert x_recovered ≈ x

# Reusable setup for repeated transforms
setup_fwd = AppleAccelerate.plan_dft(120, AppleAccelerate.DFT_FORWARD, Float64)
setup_inv = AppleAccelerate.plan_dft(120, AppleAccelerate.DFT_INVERSE, Float64)
X = AppleAccelerate.dft(x, setup_fwd)
x_recovered = AppleAccelerate.idft(X, setup_inv)
AppleAccelerate.plan_dftFunction
plan_dft(length::Int, direction::Int, ::Type{T}=Float32; previous=C_NULL) where T

Create a DFT setup for complex-to-complex DFT of the given length and direction (DFT_FORWARD or DFT_INVERSE). Length must be f * 2^n where f ∈ {1, 3, 5, 15} and n ≥ 3. Optionally pass a previous setup to share underlying data. Wraps vDSP_DFT_zop_CreateSetup.

Returns: DFTSetup{T}

source
AppleAccelerate.dftFunction
dft(Ir::Vector{T}, Ii::Vector{T}, setup::DFTSetup{T})

Execute the complex DFT defined by setup on split-complex input (Ir, Ii). Wraps vDSP_DFT_Execute.

Returns: (Or, Oi) — real and imaginary parts of the output.

source
dft(X::Vector{Complex{T}}, setup::DFTSetup{T})

Execute the complex DFT on an interleaved complex vector. Wraps vDSP_DFT_Execute.

Returns: Vector{Complex{T}}

source
dft(X::Vector{Complex{T}}, direction::Int) where T
dft(X::Vector{Complex{T}}) where T

Compute the DFT of X, auto-creating a setup. Default direction is forward. Wraps vDSP_DFT_Execute.

Returns: Vector{Complex{T}}

source
AppleAccelerate.idftFunction
idft(X::Vector{Complex{T}}, setup::DFTSetup{T})
idft(X::Vector{Complex{T}})

Compute the normalized inverse DFT of X. The setup must have been created with DFT_INVERSE direction. Returns dft(X, setup) ./ length(X). Wraps vDSP_DFT_Execute.

Returns: Vector{Complex{T}}

source

DCT (Discrete Cosine Transform)

Wraps Apple's vDSP DCT functions. Float32 only. Supports DCT types II, III, and IV.

FunctionDescription
plan_dctCreate a DCT setup object
dctCompute the Discrete Cosine Transform
idctCompute the inverse Discrete Cosine Transform
plan_destroyDestroy a DCT setup object
AppleAccelerate.dctFunction
dct(X::Vector{Float32}, setup::DFTSetup)
dct(X::Vector{Float32}, [dct_type=2])

Compute the Discrete Cosine Transform of X. Wraps vDSP_DCT_Execute.

Note

Apple's Accelerate framework provides only a single-precision DCT (vDSP_DCT_CreateSetup/vDSP_DCT_Execute); there is no Float64 variant (no vDSP_DCT_CreateSetupD/vDSP_DCT_ExecuteD exists in vDSP). Calling dct or idct with a Vector{Float64} therefore throws an ArgumentError. Convert the input to Float32, or use FFTW.jl for a double-precision DCT.

source
AppleAccelerate.idctFunction
idct(X::Vector{Float32})

Compute the inverse of the (unnormalized) DCT-II computed by dct, so that idct(dct(x)) ≈ x. Uses the DCT-II/DCT-III duality: vDSP's DCT-III applied to a DCT-II spectrum reproduces the input scaled by N/2, so this returns dct(X, 3) .* (2/N). Wraps vDSP_DCT_Execute.

Not available for Float64 inputs: see the note in dct.

source