concision_core/ops/fft/
utils.rs1use super::FftPlan;
6use crate::AsComplex;
7use num::complex::{Complex, ComplexFloat};
8use num::traits::{Float, FloatConst, NumAssignOps, NumCast, NumOps};
9
10pub(crate) fn fft_angle<T>(n: usize) -> T
11where
12 T: FloatConst + NumCast + NumOps,
13{
14 T::TAU() / T::from(n).unwrap()
15}
16
17pub fn fft<S, T>(input: impl AsRef<[S]>, permute: &FftPlan) -> Vec<Complex<S::Real>>
19where
20 S: ComplexFloat<Real = T>,
21 S::Real: Float + FloatConst,
22 Complex<S::Real>: ComplexFloat<Real = S::Real> + NumOps<S> + NumOps<S::Real>,
23{
24 let input = input.as_ref();
26 let n = input.len();
28 let mut result = Vec::with_capacity(n);
30 for position in permute.clone().into_iter() {
32 let arg = input[position];
33 result.push(Complex::new(arg.re(), arg.im()));
34 }
35 let mut segment: usize = 1;
36 while segment < n {
37 segment <<= 1;
38 let angle = fft_angle::<T>(segment);
40 let radius = Complex::new(angle.cos(), angle.sin());
42 for start in (0..n).step_by(segment) {
44 let mut w = Complex::new(T::one(), T::zero());
45 for position in start..(start + segment / 2) {
46 let a = result[position];
47 let b = result[position + segment / 2] * w;
48 result[position] = a + b;
49 result[position + segment / 2] = a - b;
50 w = w * radius;
51 }
52 }
53 }
54 result
55}
56
57pub fn rfft<T>(input: impl AsRef<[T]>, input_permutation: impl AsRef<[usize]>) -> Vec<Complex<T>>
60where
61 T: Float + FloatConst,
62 Complex<T>: ComplexFloat<Real = T> + NumAssignOps,
63{
64 let input = input.as_ref();
66 let n = input.len();
68 let size = (n - (n % 2)) / 2 + 1;
70 let mut store = Vec::with_capacity(size);
72 for position in input_permutation.as_ref() {
74 store.push(input[*position].as_re());
75 }
76 let mut segment: usize = 1;
77 while segment < n {
78 segment <<= 1;
79 let angle = fft_angle::<T>(segment);
81 let radius = Complex::new(angle.cos(), angle.sin());
83 for start in (0..n).step_by(segment) {
84 let mut w = Complex::new(T::one(), T::zero());
85 for position in start..(start + segment / 2) {
86 let a = store[position];
87 let b = store[position + segment / 2] * w;
88 store[position] = a + b;
89 store[position + segment / 2] = a - b;
90 w *= radius;
91 }
92 }
93 }
94 store
95 .iter()
96 .cloned()
97 .filter(|x| x.im() >= T::zero())
98 .collect()
99}
100pub fn ifft<S, T>(input: &[S], input_permutation: &FftPlan) -> Vec<Complex<T>>
102where
103 S: ComplexFloat<Real = T>,
104 T: Float + FloatConst,
105 Complex<T>: ComplexFloat<Real = T> + NumOps<S> + NumOps<T>,
106{
107 let n = input.len();
108 let mut result = Vec::with_capacity(n);
109 for position in input_permutation.clone().into_iter() {
110 let arg = input[position];
111 result.push(Complex::new(arg.re(), arg.im()));
112 }
113 let mut length: usize = 1;
114 while length < n {
115 length <<= 1;
116 let angle = fft_angle::<T>(length).neg();
117 let radius = Complex::new(T::cos(angle), T::sin(angle)); for start in (0..n).step_by(length) {
119 let mut w = Complex::new(T::one(), T::zero());
120 for position in start..(start + length / 2) {
121 let a = result[position];
122 let b = result[position + length / 2] * w;
123 result[position] = a + b;
124 result[position + length / 2] = a - b;
125 w = w * radius;
126 }
127 }
128 }
129 let scale = T::from(n).unwrap().recip();
130 result.iter().map(|x| *x * scale).collect()
131}
132pub fn irfft<T>(input: &[Complex<T>], plan: &FftPlan) -> Vec<T>
135where
136 T: Float + FloatConst,
137 Complex<T>: ComplexFloat<Real = T> + NumAssignOps,
138{
139 let n = input.len();
140 let mut result = vec![Complex::new(T::zero(), T::zero()); n];
141
142 for position in plan.clone().into_iter() {
143 result.push(input[position]);
144 }
145 let mut segment: usize = 1;
152 while segment < n {
153 segment <<= 1;
154 let angle = fft_angle::<T>(segment).neg();
156 let radius = Complex::new(T::cos(angle), T::sin(angle));
158 for start in (0..n).step_by(segment) {
159 let mut w = Complex::new(T::one(), T::zero());
160 for position in start..(start + segment / 2) {
161 let a = result[position];
162 let b = result[position + segment / 2] * w;
163 result[position] = a + b;
164 result[position + segment / 2] = a - b;
165 w *= radius;
166 }
167 }
168 }
169 let scale = T::from(n).unwrap().recip();
170 result.iter().map(|x| x.re() * scale).collect()
171}
172
173#[doc(hidden)]
174pub fn fft_permutation(length: usize) -> Vec<usize> {
176 let mut result = Vec::new();
177 result.reserve_exact(length);
178 for i in 0..length {
179 result.push(i);
180 }
181 let mut reverse = 0_usize;
182 let mut position = 1_usize;
183 while position < length {
184 let mut bit = length >> 1;
185 while bit & reverse != 0 {
186 reverse ^= bit;
187 bit >>= 1;
188 }
189 reverse ^= bit;
190 if position < reverse {
192 result.swap(position, reverse);
194 }
195 position += 1;
196 }
197 result
198}