arnaucube
arnaucube/poulpyPublic Self-hosted repository
poulpy/poulpy-hal/src/reference/fft64/reim/fft_ref.rs
poulpy-hal/src/reference/fft64/reim/fft_ref.rsRaw
  1use std::fmt::Debug;
  2
  3use rand_distr::num_traits::{Float, FloatConst};
  4
  5use crate::reference::fft64::reim::{as_arr, as_arr_mut};
  6
  7#[inline(always)]
  8pub fn fft_ref<R: Float + FloatConst + Debug>(m: usize, omg: &[R], data: &mut [R]) {
  9    assert!(data.len() == 2 * m);
 10    let (re, im) = data.split_at_mut(m);
 11
 12    if m <= 16 {
 13        match m {
 14            1 => {}
 15            2 => fft2_ref(as_arr_mut::<2, R>(re), as_arr_mut::<2, R>(im), *as_arr::<2, R>(omg)),
 16            4 => fft4_ref(as_arr_mut::<4, R>(re), as_arr_mut::<4, R>(im), *as_arr::<4, R>(omg)),
 17            8 => fft8_ref(as_arr_mut::<8, R>(re), as_arr_mut::<8, R>(im), *as_arr::<8, R>(omg)),
 18            16 => fft16_ref(as_arr_mut::<16, R>(re), as_arr_mut::<16, R>(im), *as_arr::<16, R>(omg)),
 19            _ => {}
 20        }
 21    } else if m <= 2048 {
 22        fft_bfs_16_ref(m, re, im, omg, 0);
 23    } else {
 24        fft_rec_16_ref(m, re, im, omg, 0);
 25    }
 26}
 27
 28#[inline(always)]
 29fn fft_rec_16_ref<R: Float + FloatConst + Debug>(m: usize, re: &mut [R], im: &mut [R], omg: &[R], mut pos: usize) -> usize {
 30    if m <= 2048 {
 31        return fft_bfs_16_ref(m, re, im, omg, pos);
 32    };
 33
 34    let h = m >> 1;
 35    twiddle_fft_ref(h, re, im, as_arr::<2, R>(&omg[pos..]));
 36    pos += 2;
 37    pos = fft_rec_16_ref(h, re, im, omg, pos);
 38    pos = fft_rec_16_ref(h, &mut re[h..], &mut im[h..], omg, pos);
 39    pos
 40}
 41
 42#[inline(always)]
 43fn cplx_twiddle<R: Float + FloatConst>(ra: &mut R, ia: &mut R, rb: &mut R, ib: &mut R, omg_re: R, omg_im: R) {
 44    let dr: R = *rb * omg_re - *ib * omg_im;
 45    let di: R = *rb * omg_im + *ib * omg_re;
 46    *rb = *ra - dr;
 47    *ib = *ia - di;
 48    *ra = *ra + dr;
 49    *ia = *ia + di;
 50}
 51
 52#[inline(always)]
 53fn cplx_i_twiddle<R: Float + FloatConst>(ra: &mut R, ia: &mut R, rb: &mut R, ib: &mut R, omg_re: R, omg_im: R) {
 54    let dr: R = *rb * omg_im + *ib * omg_re;
 55    let di: R = *rb * omg_re - *ib * omg_im;
 56    *rb = *ra + dr;
 57    *ib = *ia - di;
 58    *ra = *ra - dr;
 59    *ia = *ia + di;
 60}
 61
 62#[inline(always)]
 63fn fft2_ref<R: Float + FloatConst>(re: &mut [R; 2], im: &mut [R; 2], omg: [R; 2]) {
 64    let [ra, rb] = re;
 65    let [ia, ib] = im;
 66    let [romg, iomg] = omg;
 67    cplx_twiddle(ra, ia, rb, ib, romg, iomg);
 68}
 69
 70#[inline(always)]
 71fn fft4_ref<R: Float + FloatConst>(re: &mut [R; 4], im: &mut [R; 4], omg: [R; 4]) {
 72    let [re_0, re_1, re_2, re_3] = re;
 73    let [im_0, im_1, im_2, im_3] = im;
 74
 75    {
 76        let omg_0 = omg[0];
 77        let omg_1 = omg[1];
 78        cplx_twiddle(re_0, im_0, re_2, im_2, omg_0, omg_1);
 79        cplx_twiddle(re_1, im_1, re_3, im_3, omg_0, omg_1);
 80    }
 81
 82    {
 83        let omg_0 = omg[2];
 84        let omg_1 = omg[3];
 85        cplx_twiddle(re_0, im_0, re_1, im_1, omg_0, omg_1);
 86        cplx_i_twiddle(re_2, im_2, re_3, im_3, omg_0, omg_1);
 87    }
 88}
 89
 90#[inline(always)]
 91fn fft8_ref<R: Float + FloatConst>(re: &mut [R; 8], im: &mut [R; 8], omg: [R; 8]) {
 92    let [re_0, re_1, re_2, re_3, re_4, re_5, re_6, re_7] = re;
 93    let [im_0, im_1, im_2, im_3, im_4, im_5, im_6, im_7] = im;
 94
 95    {
 96        let omg_0 = omg[0];
 97        let omg_1 = omg[1];
 98        cplx_twiddle(re_0, im_0, re_4, im_4, omg_0, omg_1);
 99        cplx_twiddle(re_1, im_1, re_5, im_5, omg_0, omg_1);
100        cplx_twiddle(re_2, im_2, re_6, im_6, omg_0, omg_1);
101        cplx_twiddle(re_3, im_3, re_7, im_7, omg_0, omg_1);
102    }
103
104    {
105        let omg_2 = omg[2];
106        let omg_3 = omg[3];
107        cplx_twiddle(re_0, im_0, re_2, im_2, omg_2, omg_3);
108        cplx_twiddle(re_1, im_1, re_3, im_3, omg_2, omg_3);
109        cplx_i_twiddle(re_4, im_4, re_6, im_6, omg_2, omg_3);
110        cplx_i_twiddle(re_5, im_5, re_7, im_7, omg_2, omg_3);
111    }
112
113    {
114        let omg_4 = omg[4];
115        let omg_5 = omg[5];
116        let omg_6 = omg[6];
117        let omg_7 = omg[7];
118        cplx_twiddle(re_0, im_0, re_1, im_1, omg_4, omg_6);
119        cplx_i_twiddle(re_2, im_2, re_3, im_3, omg_4, omg_6);
120        cplx_twiddle(re_4, im_4, re_5, im_5, omg_5, omg_7);
121        cplx_i_twiddle(re_6, im_6, re_7, im_7, omg_5, omg_7);
122    }
123}
124
125#[inline(always)]
126fn fft16_ref<R: Float + FloatConst + Debug>(re: &mut [R; 16], im: &mut [R; 16], omg: [R; 16]) {
127    let [
128        re_0,
129        re_1,
130        re_2,
131        re_3,
132        re_4,
133        re_5,
134        re_6,
135        re_7,
136        re_8,
137        re_9,
138        re_10,
139        re_11,
140        re_12,
141        re_13,
142        re_14,
143        re_15,
144    ] = re;
145    let [
146        im_0,
147        im_1,
148        im_2,
149        im_3,
150        im_4,
151        im_5,
152        im_6,
153        im_7,
154        im_8,
155        im_9,
156        im_10,
157        im_11,
158        im_12,
159        im_13,
160        im_14,
161        im_15,
162    ] = im;
163
164    {
165        let omg_0: R = omg[0];
166        let omg_1: R = omg[1];
167        cplx_twiddle(re_0, im_0, re_8, im_8, omg_0, omg_1);
168        cplx_twiddle(re_1, im_1, re_9, im_9, omg_0, omg_1);
169        cplx_twiddle(re_2, im_2, re_10, im_10, omg_0, omg_1);
170        cplx_twiddle(re_3, im_3, re_11, im_11, omg_0, omg_1);
171
172        cplx_twiddle(re_4, im_4, re_12, im_12, omg_0, omg_1);
173        cplx_twiddle(re_5, im_5, re_13, im_13, omg_0, omg_1);
174        cplx_twiddle(re_6, im_6, re_14, im_14, omg_0, omg_1);
175        cplx_twiddle(re_7, im_7, re_15, im_15, omg_0, omg_1);
176    }
177
178    {
179        let omg_2: R = omg[2];
180        let omg_3: R = omg[3];
181        cplx_twiddle(re_0, im_0, re_4, im_4, omg_2, omg_3);
182        cplx_twiddle(re_1, im_1, re_5, im_5, omg_2, omg_3);
183        cplx_twiddle(re_2, im_2, re_6, im_6, omg_2, omg_3);
184        cplx_twiddle(re_3, im_3, re_7, im_7, omg_2, omg_3);
185
186        cplx_i_twiddle(re_8, im_8, re_12, im_12, omg_2, omg_3);
187        cplx_i_twiddle(re_9, im_9, re_13, im_13, omg_2, omg_3);
188        cplx_i_twiddle(re_10, im_10, re_14, im_14, omg_2, omg_3);
189        cplx_i_twiddle(re_11, im_11, re_15, im_15, omg_2, omg_3);
190    }
191
192    {
193        let omg_0: R = omg[4];
194        let omg_1: R = omg[5];
195        let omg_2: R = omg[6];
196        let omg_3: R = omg[7];
197        cplx_twiddle(re_0, im_0, re_2, im_2, omg_0, omg_1);
198        cplx_twiddle(re_1, im_1, re_3, im_3, omg_0, omg_1);
199        cplx_twiddle(re_8, im_8, re_10, im_10, omg_2, omg_3);
200        cplx_twiddle(re_9, im_9, re_11, im_11, omg_2, omg_3);
201
202        cplx_i_twiddle(re_4, im_4, re_6, im_6, omg_0, omg_1);
203        cplx_i_twiddle(re_5, im_5, re_7, im_7, omg_0, omg_1);
204        cplx_i_twiddle(re_12, im_12, re_14, im_14, omg_2, omg_3);
205        cplx_i_twiddle(re_13, im_13, re_15, im_15, omg_2, omg_3);
206    }
207
208    {
209        let omg_0: R = omg[8];
210        let omg_1: R = omg[9];
211        let omg_2: R = omg[10];
212        let omg_3: R = omg[11];
213        let omg_4: R = omg[12];
214        let omg_5: R = omg[13];
215        let omg_6: R = omg[14];
216        let omg_7: R = omg[15];
217        cplx_twiddle(re_0, im_0, re_1, im_1, omg_0, omg_4);
218        cplx_twiddle(re_4, im_4, re_5, im_5, omg_1, omg_5);
219        cplx_twiddle(re_8, im_8, re_9, im_9, omg_2, omg_6);
220        cplx_twiddle(re_12, im_12, re_13, im_13, omg_3, omg_7);
221
222        cplx_i_twiddle(re_2, im_2, re_3, im_3, omg_0, omg_4);
223        cplx_i_twiddle(re_6, im_6, re_7, im_7, omg_1, omg_5);
224        cplx_i_twiddle(re_10, im_10, re_11, im_11, omg_2, omg_6);
225        cplx_i_twiddle(re_14, im_14, re_15, im_15, omg_3, omg_7);
226    }
227}
228
229#[inline(always)]
230fn fft_bfs_16_ref<R: Float + FloatConst + Debug>(m: usize, re: &mut [R], im: &mut [R], omg: &[R], mut pos: usize) -> usize {
231    let log_m: usize = (usize::BITS - (m - 1).leading_zeros()) as usize;
232    let mut mm: usize = m;
233
234    if !log_m.is_multiple_of(2) {
235        let h: usize = mm >> 1;
236        twiddle_fft_ref(h, re, im, as_arr::<2, R>(&omg[pos..]));
237        pos += 2;
238        mm = h
239    }
240
241    while mm > 16 {
242        let h: usize = mm >> 2;
243        for off in (0..m).step_by(mm) {
244            bitwiddle_fft_ref(h, &mut re[off..], &mut im[off..], as_arr::<4, R>(&omg[pos..]));
245            pos += 4;
246        }
247        mm = h
248    }
249
250    for off in (0..m).step_by(16) {
251        fft16_ref(
252            as_arr_mut::<16, R>(&mut re[off..]),
253            as_arr_mut::<16, R>(&mut im[off..]),
254            *as_arr::<16, R>(&omg[pos..]),
255        );
256        pos += 16;
257    }
258
259    pos
260}
261
262#[inline(always)]
263fn twiddle_fft_ref<R: Float + FloatConst>(h: usize, re: &mut [R], im: &mut [R], omg: &[R; 2]) {
264    let romg = omg[0];
265    let iomg = omg[1];
266
267    let (re_lhs, re_rhs) = re.split_at_mut(h);
268    let (im_lhs, im_rhs) = im.split_at_mut(h);
269
270    for i in 0..h {
271        cplx_twiddle(&mut re_lhs[i], &mut im_lhs[i], &mut re_rhs[i], &mut im_rhs[i], romg, iomg);
272    }
273}
274
275#[inline(always)]
276fn bitwiddle_fft_ref<R: Float + FloatConst>(h: usize, re: &mut [R], im: &mut [R], omg: &[R; 4]) {
277    let (r0, r2) = re.split_at_mut(2 * h);
278    let (r0, r1) = r0.split_at_mut(h);
279    let (r2, r3) = r2.split_at_mut(h);
280
281    let (i0, i2) = im.split_at_mut(2 * h);
282    let (i0, i1) = i0.split_at_mut(h);
283    let (i2, i3) = i2.split_at_mut(h);
284
285    let omg_0: R = omg[0];
286    let omg_1: R = omg[1];
287    let omg_2: R = omg[2];
288    let omg_3: R = omg[3];
289
290    for i in 0..h {
291        cplx_twiddle(&mut r0[i], &mut i0[i], &mut r2[i], &mut i2[i], omg_0, omg_1);
292        cplx_twiddle(&mut r1[i], &mut i1[i], &mut r3[i], &mut i3[i], omg_0, omg_1);
293    }
294
295    for i in 0..h {
296        cplx_twiddle(&mut r0[i], &mut i0[i], &mut r1[i], &mut i1[i], omg_2, omg_3);
297        cplx_i_twiddle(&mut r2[i], &mut i2[i], &mut r3[i], &mut i3[i], omg_2, omg_3);
298    }
299}