feanor_math/algorithms/fft/
mod.rs

1use std::ops::Deref;
2
3use crate::ring::*;
4use crate::seq::*;
5
6pub mod cooley_tuckey;
7pub mod bluestein;
8pub mod factor_fft;
9pub mod complex_fft;
10
11///
12/// Trait for objects that can perform a fast fourier transform over some ring. 
13/// 
14/// Usually fast implementations of FFTs have to store a lot of precomputed data
15/// (e.g. powers of roots of unity), hence they should be represented as objects
16/// implementing this trait.
17/// 
18/// # Note on equality
19/// 
20/// If you choose to implement [`PartialEq`] for an FFTTable, and `F == G`, then
21/// `F` and `G` should satisfy the following properties:
22///  - `F` and `G` support the same rings
23///  - `F.len() == G.len()`
24///  - `F.root_of_unity(ring) == G.root_of_unity(ring)` for each supported ring `ring`
25///  - `F.unordered_fft_permutation(i) == G.unordered_fft_permutation(i)` for all `i`
26/// In other words, `F` and `G` must have exactly the same output for `unordered_fft`
27/// (and thus `fft`, `inv_fft`, ...) on same inputs (w.r.t. equality given by the
28/// base rings, which are equal).
29/// 
30pub trait FFTAlgorithm<R: ?Sized + RingBase> {
31
32    ///
33    /// This FFTTable can compute the FFT of arrays of this length.
34    /// 
35    fn len(&self) -> usize;
36
37    ///
38    /// The root of unity used for the FFT. While all primitive `n`-th roots
39    /// of unity can be used equally for computing a Fourier transform, the 
40    /// concrete one used determines the order of the output values.
41    /// 
42    /// See also [`FFTAlgorithm::unordered_fft_permutation()`].
43    /// 
44    fn root_of_unity<S>(&self, ring: S) -> &R::Element
45        where S: RingStore<Type = R> + Copy;
46
47    ///
48    /// On input `i`, returns `j` such that `unordered_fft(values)[i]` contains the evaluation
49    /// at `zeta^(-j)` of values (note the `-`, which is standard convention for Fourier transforms).
50    /// Here `zeta` is the value returned by [`FFTAlgorithm::root_of_unity()`].
51    /// 
52    /// # Example
53    /// ```text
54    /// # use feanor_math::ring::*;
55    /// # use feanor_math::rings::zn::*;
56    /// # use feanor_math::rings::zn::zn_64::*;
57    /// # use feanor_math::algorithms::*;
58    /// # use feanor_math::field::*;
59    /// # use feanor_math::algorithms::fft::*;
60    /// let ring = Zn::new(17);
61    /// let fft = cooley_tuckey::CooleyTuckeyFFT::for_zn(&ring, 3);
62    /// let (zero, one) = (ring.zero(), ring.one());
63    /// let mut values = [zero, one, one, zero, zero, zero, zero, zero];
64    /// fft.unordered_fft(&mut values, &ring);
65    /// for i in 0..8 {
66    ///     let evaluation_at = ring.pow(ring.invert(fft.root_of_unity()).unwrap(), fft.unordered_fft_permutation(i));
67    ///     assert_el_eq!(ring, ring.add(evaluation_at, ring.pow(evaluation_at, 2)), &values[i]);
68    /// }
69    /// ```
70    /// 
71    fn unordered_fft_permutation(&self, i: usize) -> usize;
72
73    ///
74    /// The inverse of [`FFTAlgorithm::unordered_fft_permutation()`], i.e. for all i, have
75    /// `self.unordered_fft_permutation_inv(self.unordered_fft_permutation(i)) == i`.
76    /// 
77    fn unordered_fft_permutation_inv(&self, i: usize) -> usize;
78
79    ///
80    /// Computes the Fourier transform of the given `values` over the specified ring.
81    /// The output is in standard order, i.e. the `i`-th output element is the evaluation
82    /// of the input at `self.root_of_unity()^(-i)` (note the `-`, which is standard
83    /// convention for Fourier transforms).
84    /// 
85    /// # Panics
86    /// 
87    /// This function panics if `values.len() != self.len()`.
88    ///
89    fn fft<V, S>(&self, mut values: V, ring: S)
90        where V: SwappableVectorViewMut<R::Element>,
91            S: RingStore<Type = R> + Copy
92    {
93        self.unordered_fft(&mut values, ring);
94        permute::permute_inv(&mut values, |i| self.unordered_fft_permutation(i));
95    }
96        
97    ///
98    /// Computes the Fourier transform of the given `values` over the specified ring.
99    /// The output is in standard order, i.e. the `i`-th output element is the evaluation
100    /// of the input at `self.root_of_unity()^i`, divided by `self.len()`.
101    /// 
102    /// # Panics
103    /// 
104    /// This function panics if `values.len() != self.len()`.
105    ///
106    fn inv_fft<V, S>(&self, mut values: V, ring: S)
107        where V: SwappableVectorViewMut<R::Element>,
108            S: RingStore<Type = R> + Copy
109    {
110        permute::permute(&mut values, |i| self.unordered_fft_permutation(i));
111        self.unordered_inv_fft(&mut values, ring);
112    }
113
114    ///
115    /// Computes the Fourier transform of the given values, but the output values are arbitrarily permuted
116    /// (in a way compatible with [`FFTAlgorithm::unordered_inv_fft()`]).
117    /// 
118    /// Note that the FFT of a sequence `a_0, ..., a_(N - 1)` is defined as `Fa_k = sum_i a_i z^(-ik)`
119    /// where `z` is an N-th root of unity.
120    /// 
121    fn unordered_fft<V, S>(&self, values: V, ring: S)
122        where V: SwappableVectorViewMut<R::Element>,
123            S: RingStore<Type = R> + Copy;
124    
125    ///
126    /// Inverse to [`FFTAlgorithm::unordered_fft()`], with basically the same contract.
127    /// 
128    fn unordered_inv_fft<V, S>(&self, values: V, ring: S)
129        where V: SwappableVectorViewMut<R::Element>,
130           S: RingStore<Type = R> + Copy;
131}
132
133impl<T, R> FFTAlgorithm<R> for T
134    where R: ?Sized + RingBase,
135        T: Deref, 
136        T::Target: FFTAlgorithm<R>
137{
138    fn len(&self) -> usize {
139        self.deref().len()
140    }
141
142    fn root_of_unity<S>(&self, ring: S) -> &R::Element
143        where S: RingStore<Type = R> + Copy
144    {
145        self.deref().root_of_unity(ring)
146    }
147
148    fn unordered_fft_permutation(&self, i: usize) -> usize {
149        self.deref().unordered_fft_permutation(i)
150    }
151
152    fn unordered_fft_permutation_inv(&self, i: usize) -> usize {
153        self.deref().unordered_fft_permutation_inv(i)
154    }
155
156    fn fft<V, S>(&self, values: V, ring: S)
157        where V: SwappableVectorViewMut<<R as RingBase>::Element>,
158            S: RingStore<Type = R> + Copy 
159    {
160        self.deref().fft(values, ring)
161    }
162
163    fn inv_fft<V, S>(&self, values: V, ring: S)
164        where V: SwappableVectorViewMut<<R as RingBase>::Element>,
165            S: RingStore<Type = R> + Copy 
166    {
167        self.deref().inv_fft(values, ring)
168    }
169
170    fn unordered_fft<V, S>(&self, values: V, ring: S)
171        where V: SwappableVectorViewMut<<R as RingBase>::Element>,
172            S: RingStore<Type = R> + Copy 
173    {
174        self.deref().unordered_fft(values, ring)
175    }
176
177    fn unordered_inv_fft<V, S>(&self, values: V, ring: S)
178        where V: SwappableVectorViewMut<<R as RingBase>::Element>,
179            S: RingStore<Type = R> + Copy 
180    {
181        self.deref().unordered_inv_fft(values, ring)
182    }
183}