Fast Fourier transforms for the dihedral group over prime finite fields
Project description
fft-dihedral
Fast Fourier transforms for the dihedral group over prime finite fields.
This package computes the Fourier transform of functions on
D_{2n} = <r, s | r^n = s^2 = e, srs^{-1} = r^{-1}>.
The fast path reduces the nonabelian dihedral transform to four cyclic number-theoretic transforms (NTTs). The inverse transform reconstructs two cyclic spectra and applies two inverse NTTs.
Install
From PyPI:
python -m pip install fft-dihedral
From a checkout:
python -m pip install -e ".[plot,dev]"
Quick Start
from fft_dihedral import (
DEFAULT_MODULUS,
dihedral_dft_fft,
dihedral_inverse_fft,
flatten_transform,
root_of_unity,
)
n = 16
omega = root_of_unity(n, DEFAULT_MODULUS)
rotations = list(range(n))
reflections = [2 * k for k in range(n)]
transform = dihedral_dft_fft(rotations, reflections, DEFAULT_MODULUS, omega)
assert len(flatten_transform(transform)) == 2 * n
assert dihedral_inverse_fft(transform, omega) == (rotations, reflections)
Conventions
A function f: D_{2n} -> GF(p) is represented by two length-n arrays:
rotations[k] = f(r^k)
reflections[k] = f(s r^k)
For a primitive nth root of unity omega, the two-dimensional irreducible
representations satisfy
rho_j(r^k) = [[omega^(j k), 0], [0, omega^(-j k)]]
rho_j(s r^k) = [[0, omega^(-j k)], [omega^(j k), 0]]
With the normalized finite-group DFT convention
fhat(rho) = (1 / |D_{2n}|) sum_g f(g) rho(g),
each two-dimensional Fourier coefficient is assembled from four cyclic transforms:
fhat(rho_j) = 1/(2n) * [
[DFT_omega(rotations)[j], DFT_omega^{-1}(reflections)[j]],
[DFT_omega(reflections)[j], DFT_omega^{-1}(rotations)[j]]
]
The one-dimensional representations are computed by direct character sums.
What The Four NTTs Do
The input vector is really two vectors:
rotations = [f(1), f(r), ..., f(r^{n-1})]
reflections = [f(s), f(sr), ..., f(sr^{n-1})]
The FFT applies cyclic NTTs to those two vectors with both orientations of the root:
A^+ = NTT_omega(rotations)
A^- = NTT_omega^{-1}(rotations)
B^+ = NTT_omega(reflections)
B^- = NTT_omega^{-1}(reflections)
For each two-dimensional irrep rho_j, the matrix coefficient is assembled as:
1/(2n) * [[A^+[j], B^-[j]],
[B^+[j], A^-[j]]]
The inverse FFT reverses this packing. The one-dimensional coefficients recover
the j = 0 cyclic frequencies, and, for even n, the j = n/2 frequencies.
The two-dimensional matrices recover the paired frequencies j and n-j.
Once the full A^+ and B^+ spectra have been rebuilt, two inverse NTTs give
back the rotation and reflection coefficient vectors.
Group Algebra Multiplication
Elements of the group algebra are represented by the same two arrays:
x = sum_k rotations[k] r^k + sum_k reflections[k] s r^k
The package provides both a quadratic reference product and an FFT product:
from fft_dihedral import (
DEFAULT_MODULUS,
dihedral_multiply_fft,
dihedral_multiply_naive,
root_of_unity,
)
n = 16
omega = root_of_unity(n, DEFAULT_MODULUS)
lhs_rotations = [1] * n
lhs_reflections = [2] * n
rhs_rotations = [3] * n
rhs_reflections = [4] * n
fast = dihedral_multiply_fft(
lhs_rotations,
lhs_reflections,
rhs_rotations,
rhs_reflections,
DEFAULT_MODULUS,
omega,
)
slow = dihedral_multiply_naive(
lhs_rotations,
lhs_reflections,
rhs_rotations,
rhs_reflections,
DEFAULT_MODULUS,
)
assert fast == slow
Because the transform is normalized by 1 / |D_{2n}|, multiplication in
Fourier space is
(x y)^hat(rho) = |D_{2n}| xhat(rho) yhat(rho).
So the FFT product computes two transforms, multiplies each scalar or matrix
block with the extra factor 2n, and then applies the inverse dihedral FFT.
Supported Fields
The implementation supports prime fields GF(p) when:
nis a power of two for the fast transform.pis prime.n | p - 1, soGF(p)contains a primitiventh root of unity.gcd(2n, p) = 1, so the normalization by1/(2n)is defined.
The default field is GF(2013265921), where
2013265921 = 15 * 2^27 + 1
so it supports power-of-two rotation orders up to 2^27.
True extension fields GF(p^k) are not implemented yet. This is intentionally
stricter than integer quotient rings like Z/p^kZ; those are not fields when
k > 1.
Arbitrary Compatible Primes
Roots are selected automatically using Sympy:
from fft_dihedral import root_of_unity
omega = root_of_unity(16, 97)
CLI verification over a non-default prime:
fft-dihedral verify --n 16 --modulus 97
You can also pass an explicit root:
fft-dihedral verify --n 16 --modulus 97 --omega 8
Verify
python -m pytest
fft-dihedral verify --n 128
fft-dihedral verify --n 16 --modulus 97
Benchmark
fft-dihedral bench --min-exp 4 --max-exp 15 --repetitions 5 --naive-limit 512
fft-dihedral bench --min-exp 4 --max-exp 6 --modulus 257 --repetitions 3
fft-dihedral bench-mul --min-exp 4 --max-exp 12 --repetitions 5 --naive-limit 512
The benchmark prints FFT time / (2n log2(2n)). For an O(2n log(2n))
algorithm this ratio should stay roughly flat as n grows, modulo Python
timing noise and cache effects.
The bench-mul command compares group-algebra multiplication by FFT against
the direct quadratic product. The fast path computes two forward dihedral FFTs,
multiplies the Fourier blocks, and applies one inverse dihedral FFT.
Plot
Install the plotting extra:
python -m pip install "fft-dihedral[plot]"
Then generate PNG and SVG timing plots:
fft-dihedral-plot --min-exp 4 --max-exp 14 --repetitions 3 --naive-limit 1024
Limitations
- No true extension-field
GF(p^k)implementation yet. - The radix-2 NTT is implemented in pure Python, so the Rust crate is much faster for production workloads.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file fft_dihedral-0.1.1.tar.gz.
File metadata
- Download URL: fft_dihedral-0.1.1.tar.gz
- Upload date:
- Size: 17.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4f625a2d008799c2608398a0175fbc99977299932f103caed3b81c39552ddbbb
|
|
| MD5 |
60386295afe8b5457bd57cc8de32b9c9
|
|
| BLAKE2b-256 |
e101201276da0725a0748bf5070eed33c10872187f71181c583e9d7677638296
|
File details
Details for the file fft_dihedral-0.1.1-py3-none-any.whl.
File metadata
- Download URL: fft_dihedral-0.1.1-py3-none-any.whl
- Upload date:
- Size: 14.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
13aea8a099601069a1c9ddc9c8736083d9edf6ea49bebc314c08aba6ae59f8e8
|
|
| MD5 |
1b599673efcec7dff2a5b4b8e9a9c6fe
|
|
| BLAKE2b-256 |
876ae85a950c617b8fb18425e97729ec0ca8ad896e68c30664ed601277dd91c6
|