arnaucube
arnaucube/poulpyPublic Self-hosted repository
poulpy/poulpy-hal/src/reference/fft64/reim/table_fft.rs
poulpy-hal/src/reference/fft64/reim/table_fft.rsRaw
  1use std::fmt::Debug;
  2
  3use rand_distr::num_traits::{Float, FloatConst};
  4
  5use crate::{
  6    alloc_aligned,
  7    reference::fft64::reim::{ReimDFTExecute, fft_ref, frac_rev_bits},
  8};
  9
 10pub struct ReimFFTRef;
 11
 12impl ReimDFTExecute<ReimFFTTable<f64>, f64> for ReimFFTRef {
 13    fn reim_dft_execute(table: &ReimFFTTable<f64>, data: &mut [f64]) {
 14        fft_ref(table.m, &table.omg, data);
 15    }
 16}
 17
 18pub struct ReimFFTTable<R: Float + FloatConst + Debug> {
 19    m: usize,
 20    omg: Vec<R>,
 21}
 22
 23impl<R: Float + FloatConst + Debug + 'static> ReimFFTTable<R> {
 24    pub fn new(m: usize) -> Self {
 25        assert!(m & (m - 1) == 0, "m must be a power of two but is {}", m);
 26        let mut omg: Vec<R> = alloc_aligned::<R>(2 * m);
 27
 28        let quarter: R = R::from(1. / 4.).unwrap();
 29
 30        if m <= 16 {
 31            match m {
 32                1 => {}
 33                2 => {
 34                    fill_fft2_omegas(quarter, &mut omg, 0);
 35                }
 36                4 => {
 37                    fill_fft4_omegas(quarter, &mut omg, 0);
 38                }
 39                8 => {
 40                    fill_fft8_omegas(quarter, &mut omg, 0);
 41                }
 42                16 => {
 43                    fill_fft16_omegas(quarter, &mut omg, 0);
 44                }
 45                _ => {}
 46            }
 47        } else if m <= 2048 {
 48            fill_fft_bfs_16_omegas(m, quarter, &mut omg, 0);
 49        } else {
 50            fill_fft_rec_16_omegas(m, quarter, &mut omg, 0);
 51        }
 52
 53        Self { m, omg }
 54    }
 55
 56    pub fn m(&self) -> usize {
 57        self.m
 58    }
 59
 60    pub fn omg(&self) -> &[R] {
 61        &self.omg
 62    }
 63}
 64
 65#[inline(always)]
 66fn fill_fft2_omegas<R: Float + FloatConst>(j: R, omg: &mut [R], pos: usize) -> usize {
 67    let omg_pos: &mut [R] = &mut omg[pos..];
 68    assert!(omg_pos.len() >= 2);
 69    let angle: R = j / R::from(2).unwrap();
 70    let two_pi: R = R::from(2).unwrap() * R::PI();
 71    omg_pos[0] = R::cos(two_pi * angle);
 72    omg_pos[1] = R::sin(two_pi * angle);
 73    pos + 2
 74}
 75
 76#[inline(always)]
 77fn fill_fft4_omegas<R: Float + FloatConst>(j: R, omg: &mut [R], pos: usize) -> usize {
 78    let omg_pos: &mut [R] = &mut omg[pos..];
 79    assert!(omg_pos.len() >= 4);
 80    let angle_1: R = j / R::from(2).unwrap();
 81    let angle_2: R = j / R::from(4).unwrap();
 82    let two_pi: R = R::from(2).unwrap() * R::PI();
 83    omg_pos[0] = R::cos(two_pi * angle_1);
 84    omg_pos[1] = R::sin(two_pi * angle_1);
 85    omg_pos[2] = R::cos(two_pi * angle_2);
 86    omg_pos[3] = R::sin(two_pi * angle_2);
 87    pos + 4
 88}
 89
 90#[inline(always)]
 91fn fill_fft8_omegas<R: Float + FloatConst>(j: R, omg: &mut [R], pos: usize) -> usize {
 92    let omg_pos: &mut [R] = &mut omg[pos..];
 93    assert!(omg_pos.len() >= 8);
 94    let _8th: R = R::from(1. / 8.).unwrap();
 95    let angle_1: R = j / R::from(2).unwrap();
 96    let angle_2: R = j / R::from(4).unwrap();
 97    let angle_4: R = j / R::from(8).unwrap();
 98    let two_pi: R = R::from(2).unwrap() * R::PI();
 99    omg_pos[0] = R::cos(two_pi * angle_1);
100    omg_pos[1] = R::sin(two_pi * angle_1);
101    omg_pos[2] = R::cos(two_pi * angle_2);
102    omg_pos[3] = R::sin(two_pi * angle_2);
103    omg_pos[4] = R::cos(two_pi * angle_4);
104    omg_pos[5] = R::cos(two_pi * (angle_4 + _8th));
105    omg_pos[6] = R::sin(two_pi * angle_4);
106    omg_pos[7] = R::sin(two_pi * (angle_4 + _8th));
107    pos + 8
108}
109
110#[inline(always)]
111fn fill_fft16_omegas<R: Float + FloatConst>(j: R, omg: &mut [R], pos: usize) -> usize {
112    let omg_pos: &mut [R] = &mut omg[pos..];
113    assert!(omg_pos.len() >= 16);
114    let _8th: R = R::from(1. / 8.).unwrap();
115    let _16th: R = R::from(1. / 16.).unwrap();
116    let angle_1: R = j / R::from(2).unwrap();
117    let angle_2: R = j / R::from(4).unwrap();
118    let angle_4: R = j / R::from(8).unwrap();
119    let angle_8: R = j / R::from(16).unwrap();
120    let two_pi: R = R::from(2).unwrap() * R::PI();
121    omg_pos[0] = R::cos(two_pi * angle_1);
122    omg_pos[1] = R::sin(two_pi * angle_1);
123    omg_pos[2] = R::cos(two_pi * angle_2);
124    omg_pos[3] = R::sin(two_pi * angle_2);
125    omg_pos[4] = R::cos(two_pi * angle_4);
126    omg_pos[5] = R::sin(two_pi * angle_4);
127    omg_pos[6] = R::cos(two_pi * (angle_4 + _8th));
128    omg_pos[7] = R::sin(two_pi * (angle_4 + _8th));
129    omg_pos[8] = R::cos(two_pi * angle_8);
130    omg_pos[9] = R::cos(two_pi * (angle_8 + _8th));
131    omg_pos[10] = R::cos(two_pi * (angle_8 + _16th));
132    omg_pos[11] = R::cos(two_pi * (angle_8 + _8th + _16th));
133    omg_pos[12] = R::sin(two_pi * angle_8);
134    omg_pos[13] = R::sin(two_pi * (angle_8 + _8th));
135    omg_pos[14] = R::sin(two_pi * (angle_8 + _16th));
136    omg_pos[15] = R::sin(two_pi * (angle_8 + _8th + _16th));
137    pos + 16
138}
139
140#[inline(always)]
141fn fill_fft_bfs_16_omegas<R: Float + FloatConst>(m: usize, j: R, omg: &mut [R], mut pos: usize) -> usize {
142    let log_m: usize = (usize::BITS - (m - 1).leading_zeros()) as usize;
143    let mut mm: usize = m;
144    let mut jj: R = j;
145
146    let two_pi: R = R::from(2).unwrap() * R::PI();
147
148    if !log_m.is_multiple_of(2) {
149        let h = mm >> 1;
150        let j: R = jj * R::from(0.5).unwrap();
151        omg[pos] = R::cos(two_pi * j);
152        omg[pos + 1] = R::sin(two_pi * j);
153        pos += 2;
154        mm = h;
155        jj = j
156    }
157
158    while mm > 16 {
159        let h: usize = mm >> 2;
160        let j: R = jj * R::from(1. / 4.).unwrap();
161        for i in (0..m).step_by(mm) {
162            let rs_0 = j + frac_rev_bits::<R>(i / mm) * R::from(1. / 4.).unwrap();
163            let rs_1 = R::from(2).unwrap() * rs_0;
164            omg[pos] = R::cos(two_pi * rs_1);
165            omg[pos + 1] = R::sin(two_pi * rs_1);
166            omg[pos + 2] = R::cos(two_pi * rs_0);
167            omg[pos + 3] = R::sin(two_pi * rs_0);
168            pos += 4;
169        }
170        mm = h;
171        jj = j;
172    }
173
174    for i in (0..m).step_by(16) {
175        let j = jj + frac_rev_bits(i >> 4);
176        fill_fft16_omegas(j, omg, pos);
177        pos += 16
178    }
179
180    pos
181}
182
183#[inline(always)]
184fn fill_fft_rec_16_omegas<R: Float + FloatConst>(m: usize, j: R, omg: &mut [R], mut pos: usize) -> usize {
185    if m <= 2048 {
186        return fill_fft_bfs_16_omegas(m, j, omg, pos);
187    }
188    let h: usize = m >> 1;
189    let s: R = j * R::from(0.5).unwrap();
190    let _2pi = R::from(2).unwrap() * R::PI();
191    omg[pos] = R::cos(_2pi * s);
192    omg[pos + 1] = R::sin(_2pi * s);
193    pos += 2;
194    pos = fill_fft_rec_16_omegas(h, s, omg, pos);
195    pos = fill_fft_rec_16_omegas(h, s + R::from(0.5).unwrap(), omg, pos);
196    pos
197}
198
199#[inline(always)]
200fn ctwiddle_ref(ra: &mut f64, ia: &mut f64, rb: &mut f64, ib: &mut f64, omg_re: f64, omg_im: f64) {
201    let dr: f64 = *rb * omg_re - *ib * omg_im;
202    let di: f64 = *rb * omg_im + *ib * omg_re;
203    *rb = *ra - dr;
204    *ib = *ia - di;
205    *ra += dr;
206    *ia += di;
207}