A pythonic wrapper around FFTW, the FFT library, presenting a unified interface for all the supported transforms.
—
Utilities for creating and managing aligned arrays to maximize SIMD performance, plus functions for checking alignment and converting existing arrays. Proper alignment is crucial for optimal FFT performance as it enables efficient use of vector instructions.
Functions to create new arrays with optimal alignment for SIMD operations.
def empty_aligned(shape, dtype='float64', order='C', n=None):
"""
Create an empty aligned array.
Parameters:
- shape: Shape of the array (int or tuple)
- dtype: Array data type (default: 'float64')
- order: Array order 'C' or 'F' (default: 'C')
- n: Byte alignment (default: optimal SIMD alignment)
Returns:
- Aligned numpy array
"""
def zeros_aligned(shape, dtype='float64', order='C', n=None):
"""
Create a zero-filled aligned array.
Parameters:
- shape: Shape of the array (int or tuple)
- dtype: Array data type (default: 'float64')
- order: Array order 'C' or 'F' (default: 'C')
- n: Byte alignment (default: optimal SIMD alignment)
Returns:
- Aligned numpy array filled with zeros
"""
def ones_aligned(shape, dtype='float64', order='C', n=None):
"""
Create a ones-filled aligned array.
Parameters:
- shape: Shape of the array (int or tuple)
- dtype: Array data type (default: 'float64')
- order: Array order 'C' or 'F' (default: 'C')
- n: Byte alignment (default: optimal SIMD alignment)
Returns:
- Aligned numpy array filled with ones
"""
def n_byte_align_empty(shape, n, dtype='float64', order='C'):
"""
Create an empty array aligned to n bytes.
Parameters:
- shape: Shape of the array (int or tuple)
- n: Desired byte alignment
- dtype: Array data type (default: 'float64')
- order: Array order 'C' or 'F' (default: 'C')
Returns:
- Aligned numpy array
"""Functions to align existing arrays and create aligned copies.
def n_byte_align(array, n, dtype=None):
"""
Align an existing array to n bytes, creating a copy if necessary.
Parameters:
- array: Input array to align
- n: Desired byte alignment
- dtype: Target data type (default: preserve original)
Returns:
- Aligned array (may be a copy)
"""
def byte_align(array, n=None, dtype=None):
"""
Align an array to optimal byte boundary.
Parameters:
- array: Input array to align
- n: Byte alignment (default: optimal SIMD alignment)
- dtype: Target data type (default: preserve original)
Returns:
- Aligned array (may be a copy)
"""Functions to verify array alignment.
def is_byte_aligned(array, n=None):
"""
Check if an array is byte aligned.
Parameters:
- array: Array to check
- n: Alignment to check (default: optimal SIMD alignment)
Returns:
- bool: True if aligned, False otherwise
"""
def is_n_byte_aligned(array, n):
"""
Check if an array is aligned to n bytes.
Parameters:
- array: Array to check
- n: Byte alignment to verify
Returns:
- bool: True if aligned to n bytes, False otherwise
"""
def n_byte_align_empty(shape, n, dtype='float64', order='C'):
"""
Create an n-byte aligned empty array with the given shape and data type.
Parameters:
- shape: array shape
- n: int, byte alignment boundary
- dtype: data type specifier (default: 'float64')
- order: array memory layout ('C' or 'F', default: 'C')
Returns:
- numpy.ndarray: n-byte aligned empty array
"""# Optimal SIMD alignment for the current CPU
simd_alignment: intimport numpy as np
import pyfftw
# Create aligned arrays with default optimal alignment
a = pyfftw.empty_aligned((1024, 512), dtype='complex128')
b = pyfftw.zeros_aligned((1024, 512), dtype='complex128')
c = pyfftw.ones_aligned((1024, 512), dtype='float64')
# Create with specific alignment
d = pyfftw.n_byte_align_empty((1024,), 32, dtype='float64')
print(f"Optimal SIMD alignment: {pyfftw.simd_alignment} bytes")
print(f"Array a is aligned: {pyfftw.is_byte_aligned(a)}")import numpy as np
import pyfftw
# Create unaligned array
original = np.random.randn(1024, 512)
print(f"Original aligned: {pyfftw.is_byte_aligned(original)}")
# Align the array
aligned = pyfftw.byte_align(original)
print(f"Aligned array: {pyfftw.is_byte_aligned(aligned)}")
# Check specific alignment
aligned_32 = pyfftw.n_byte_align(original, 32)
print(f"32-byte aligned: {pyfftw.is_n_byte_aligned(aligned_32, 32)}")import numpy as np
import pyfftw
import time
# Create aligned and unaligned arrays
N = 1024 * 1024
aligned = pyfftw.empty_aligned(N, dtype='complex128')
unaligned = np.empty(N, dtype='complex128')
# Fill with data
aligned[:] = np.random.randn(N) + 1j * np.random.randn(N)
unaligned[:] = aligned.copy()
# Create FFTW objects
fft_aligned = pyfftw.FFTW(aligned, pyfftw.empty_aligned(N, dtype='complex128'))
fft_unaligned = pyfftw.FFTW(unaligned, np.empty(N, dtype='complex128'))
# Time the transforms
start = time.time()
for _ in range(100):
result_aligned = fft_aligned()
time_aligned = time.time() - start
start = time.time()
for _ in range(100):
result_unaligned = fft_unaligned()
time_unaligned = time.time() - start
print(f"Aligned: {time_aligned:.3f}s")
print(f"Unaligned: {time_unaligned:.3f}s")
print(f"Speedup: {time_unaligned/time_aligned:.2f}x")import pyfftw
# Different precision levels
float32_array = pyfftw.empty_aligned((1024,), dtype='float32')
float64_array = pyfftw.empty_aligned((1024,), dtype='float64')
longdouble_array = pyfftw.empty_aligned((1024,), dtype='longdouble')
# Complex types
complex64_array = pyfftw.empty_aligned((1024,), dtype='complex64')
complex128_array = pyfftw.empty_aligned((1024,), dtype='complex128')
clongdouble_array = pyfftw.empty_aligned((1024,), dtype='clongdouble')
print("All arrays are aligned:")
for arr in [float32_array, float64_array, longdouble_array,
complex64_array, complex128_array, clongdouble_array]:
print(f"{arr.dtype}: {pyfftw.is_byte_aligned(arr)}")Install with Tessl CLI
npx tessl i tessl/pypi-pyfftw