#![cfg_attr(feature = "std", doc = "```")]
#![cfg_attr(not(feature = "std"), doc = "```ignore")]
#![cfg_attr(not(feature = "std"), no_std)]
#![allow(
clippy::erasing_op,
clippy::identity_op,
clippy::zero_prefixed_literal,
clippy::excessive_precision,
clippy::type_complexity,
clippy::too_many_arguments,
non_camel_case_types
)]
#![cfg_attr(docsrs, feature(doc_cfg))]
#![warn(rustdoc::broken_intra_doc_links)]
use core::marker::PhantomData;
use fft_simd::{FftSimd, Pod};
use num_complex::Complex64;
pub type c64 = Complex64;
macro_rules! izip {
(@ __closure @ ($a:expr)) => { |a| (a,) };
(@ __closure @ ($a:expr, $b:expr)) => { |(a, b)| (a, b) };
(@ __closure @ ($a:expr, $b:expr, $c:expr)) => { |((a, b), c)| (a, b, c) };
(@ __closure @ ($a:expr, $b:expr, $c:expr, $d:expr)) => { |(((a, b), c), d)| (a, b, c, d) };
(@ __closure @ ($a:expr, $b:expr, $c:expr, $d:expr, $e: expr)) => { |((((a, b), c), d), e)| (a, b, c, d, e) };
(@ __closure @ ($a:expr, $b:expr, $c:expr, $d:expr, $e: expr, $f:expr)) => { |(((((a, b), c), d), e), f)| (a, b, c, d, e, f) };
(@ __closure @ ($a:expr, $b:expr, $c:expr, $d:expr, $e: expr, $f:expr, $g:expr)) => { |((((((a, b), c), d), e), f), g)| (a, b, c, d, e, f, g) };
(@ __closure @ ($a:expr, $b:expr, $c:expr, $d:expr, $e: expr, $f:expr, $g:expr, $h:expr)) => { |(((((((a, b), c), d), e), f), g), h)| (a, b, c, d, e, f, g, h) };
(@ __closure @ ($a:expr, $b:expr, $c:expr, $d:expr, $e: expr, $f:expr, $g:expr, $h:expr, $i: expr)) => { |((((((((a, b), c), d), e), f), g), h), i)| (a, b, c, d, e, f, g, h, i) };
(@ __closure @ ($a:expr, $b:expr, $c:expr, $d:expr, $e: expr, $f:expr, $g:expr, $h:expr, $i: expr, $j: expr)) => { |(((((((((a, b), c), d), e), f), g), h), i), j)| (a, b, c, d, e, f, g, h, i, j) };
(@ __closure @ ($a:expr, $b:expr, $c:expr, $d:expr, $e: expr, $f:expr, $g:expr, $h:expr, $i: expr, $j: expr, $k: expr)) => { |((((((((((a, b), c), d), e), f), g), h), i), j), k)| (a, b, c, d, e, f, g, h, i, j, k) };
(@ __closure @ ($a:expr, $b:expr, $c:expr, $d:expr, $e: expr, $f:expr, $g:expr, $h:expr, $i: expr, $j: expr, $k: expr, $l: expr)) => { |(((((((((((a, b), c), d), e), f), g), h), i), j), k), l)| (a, b, c, d, e, f, g, h, i, j, k, l) };
(@ __closure @ ($a:expr, $b:expr, $c:expr, $d:expr, $e: expr, $f:expr, $g:expr, $h:expr, $i: expr, $j: expr, $k: expr, $l: expr, $m:expr)) => { |((((((((((((a, b), c), d), e), f), g), h), i), j), k), l), m)| (a, b, c, d, e, f, g, h, i, j, k, l, m) };
(@ __closure @ ($a:expr, $b:expr, $c:expr, $d:expr, $e: expr, $f:expr, $g:expr, $h:expr, $i: expr, $j: expr, $k: expr, $l: expr, $m:expr, $n:expr)) => { |(((((((((((((a, b), c), d), e), f), g), h), i), j), k), l), m), n)| (a, b, c, d, e, f, g, h, i, j, k, l, m, n) };
(@ __closure @ ($a:expr, $b:expr, $c:expr, $d:expr, $e: expr, $f:expr, $g:expr, $h:expr, $i: expr, $j: expr, $k: expr, $l: expr, $m:expr, $n:expr, $o:expr)) => { |((((((((((((((a, b), c), d), e), f), g), h), i), j), k), l), m), n), o)| (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) };
(@ __closure @ ($a:expr, $b:expr, $c:expr, $d:expr, $e: expr, $f:expr, $g:expr, $h:expr, $i: expr, $j: expr, $k: expr, $l: expr, $m:expr, $n:expr, $o:expr, $p: expr)) => { |(((((((((((((((a, b), c), d), e), f), g), h), i), j), k), l), m), n), o), p)| (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) };
( $first:expr $(,)?) => {
{
::core::iter::IntoIterator::into_iter($first)
}
};
( $first:expr, $($rest:expr),+ $(,)?) => {
{
::core::iter::IntoIterator::into_iter($first)
$(.zip($rest))*
.map(izip!(@ __closure @ ($first, $($rest),*)))
}
};
}
mod fft_simd;
mod nat;
#[cfg(feature = "std")]
pub(crate) mod time;
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
mod x86;
type FnArray = [fn(&mut [c64], &mut [c64], &[c64], &[c64]); 10];
#[derive(Copy, Clone)]
struct FftImpl {
fwd: FnArray,
inv: FnArray,
}
impl FftImpl {
#[inline]
pub fn make_fn_ptr(&self, n: usize) -> [fn(&mut [c64], &mut [c64], &[c64], &[c64]); 2] {
let idx = n.trailing_zeros() as usize - 1;
[self.fwd[idx], self.inv[idx]]
}
}
trait RecursiveFft: nat::Nat {
fn fft_recurse_impl<c64xN: Pod>(
simd: impl FftSimd<c64xN>,
fwd: bool,
read_from_x: bool,
s: usize,
x: &mut [c64xN],
y: &mut [c64xN],
w_init: &[c64xN],
w: &[c64],
);
}
#[inline]
fn fn_ptr<const FWD: bool, N: RecursiveFft, c64xN: Pod, Simd: FftSimd<c64xN>>(
simd: Simd,
) -> fn(&mut [c64], &mut [c64], &[c64], &[c64]) {
let _ = simd;
#[inline(never)]
|buf: &mut [c64], scratch: &mut [c64], w_init: &[c64], w: &[c64]| {
struct Impl<'a, const FWD: bool, N, c64xN, Simd> {
simd: Simd,
buf: &'a mut [c64],
scratch: &'a mut [c64],
w_init: &'a [c64],
w: &'a [c64],
__marker: PhantomData<(N, c64xN)>,
}
let simd = Simd::try_new().unwrap();
impl<const FWD: bool, N: RecursiveFft, c64xN: Pod, Simd: FftSimd<c64xN>> pulp::NullaryFnOnce
for Impl<'_, FWD, N, c64xN, Simd>
{
type Output = ();
#[inline(always)]
fn call(self) -> Self::Output {
let Self {
simd,
buf,
scratch,
w_init,
w,
__marker: _,
} = self;
let n = 1 << (N::VALUE + 1);
assert_eq!(buf.len(), n);
assert_eq!(scratch.len(), n);
assert_eq!(w_init.len(), n);
assert_eq!(w.len(), n);
N::fft_recurse_impl(
simd,
FWD,
true,
1,
bytemuck::cast_slice_mut(buf),
bytemuck::cast_slice_mut(scratch),
bytemuck::cast_slice(w_init),
w,
);
}
}
simd.vectorize(Impl::<FWD, N, c64xN, Simd> {
simd,
buf,
scratch,
w_init,
w,
__marker: PhantomData,
})
}
}
mod dif2;
mod dit2;
mod dif4;
mod dit4;
mod dif8;
mod dit8;
mod dif16;
mod dit16;
pub mod ordered;
pub mod unordered;
#[cfg(feature = "fft128")]
#[cfg_attr(docsrs, doc(cfg(feature = "fft128")))]
pub mod fft128;