1use crate::error::FFTResult;
7use crate::fft;
8use scirs2_core::ndarray::{Array2, ArrayD, IxDyn};
9use scirs2_core::numeric::Complex64;
10use scirs2_core::numeric::NumCast;
11use scirs2_core::simd_ops::PlatformCapabilities;
12use std::fmt::Debug;
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16pub enum NormMode {
17 None,
18 Backward,
19 Ortho,
20 Forward,
21}
22
23#[allow(dead_code)]
25pub fn simd_support_available() -> bool {
26 let caps = PlatformCapabilities::detect();
27 caps.simd_available
28}
29
30#[allow(dead_code)]
32pub fn apply_simd_normalization(data: &mut [Complex64], scale: f64) {
33 for c in data.iter_mut() {
34 *c *= scale;
35 }
36}
37
38#[allow(dead_code)]
40pub fn fft_simd<T>(x: &[T], _norm: Option<&str>) -> FFTResult<Vec<Complex64>>
41where
42 T: NumCast + Copy + Debug + 'static,
43{
44 fft::fft(x, None)
45}
46
47#[allow(dead_code)]
49pub fn ifft_simd<T>(x: &[T], _norm: Option<&str>) -> FFTResult<Vec<Complex64>>
50where
51 T: NumCast + Copy + Debug + 'static,
52{
53 fft::ifft(x, None)
54}
55
56#[allow(dead_code)]
58pub fn fft2_simd<T>(
59 x: &[T],
60 shape: Option<(usize, usize)>,
61 norm: Option<&str>,
62) -> FFTResult<Array2<Complex64>>
63where
64 T: NumCast + Copy + Debug + 'static,
65{
66 let (n_rows, n_cols) = if let Some(s) = shape {
68 s
69 } else {
70 let len = x.len();
71 let size = (len as f64).sqrt() as usize;
72 if size * size != len {
73 return Err(crate::error::FFTError::ValueError(
74 "Cannot infer 2D shape from slice length".to_string(),
75 ));
76 }
77 (size, size)
78 };
79
80 if x.len() != n_rows * n_cols {
82 return Err(crate::error::FFTError::ValueError(format!(
83 "Shape ({}, {}) requires {} elements, but slice has {}",
84 n_rows,
85 n_cols,
86 n_rows * n_cols,
87 x.len()
88 )));
89 }
90
91 let mut values = Vec::with_capacity(n_rows * n_cols);
93 for &val in x.iter() {
94 values.push(val);
95 }
96 let arr = Array2::from_shape_vec((n_rows, n_cols), values)
97 .map_err(|e| crate::error::FFTError::DimensionError(e.to_string()))?;
98
99 crate::fft::fft2(&arr, None, None, norm)
101}
102
103#[allow(dead_code)]
105pub fn ifft2_simd<T>(
106 _x: &[T],
107 _shape: Option<(usize, usize)>,
108 _norm: Option<&str>,
109) -> FFTResult<Array2<Complex64>>
110where
111 T: NumCast + Copy + Debug + 'static,
112{
113 Err(crate::error::FFTError::NotImplementedError(
115 "2D inverse FFT from slice not yet implemented".to_string(),
116 ))
117}
118
119#[allow(dead_code)]
121pub fn fftn_simd<T>(
122 x: &[T],
123 shape: Option<&[usize]>,
124 axes: Option<&[usize]>,
125 norm: Option<&str>,
126) -> FFTResult<ArrayD<Complex64>>
127where
128 T: NumCast + Copy + Debug + 'static,
129{
130 let shape = shape.ok_or_else(|| {
132 crate::error::FFTError::ValueError(
133 "Shape is required for N-dimensional FFT from slice".to_string(),
134 )
135 })?;
136
137 let total_elements: usize = shape.iter().product();
139
140 if x.len() != total_elements {
142 return Err(crate::error::FFTError::ValueError(format!(
143 "Shape {:?} requires {} elements, but slice has {}",
144 shape,
145 total_elements,
146 x.len()
147 )));
148 }
149
150 let mut values = Vec::with_capacity(total_elements);
152 for &val in x.iter() {
153 values.push(val);
154 }
155 let arr = ArrayD::from_shape_vec(IxDyn(shape), values)
156 .map_err(|e| crate::error::FFTError::DimensionError(e.to_string()))?;
157
158 crate::fft::fftn(&arr, None, axes.map(|a| a.to_vec()), norm, None, None)
160}
161
162#[allow(dead_code)]
164pub fn ifftn_simd<T>(
165 _x: &[T],
166 _shape: Option<&[usize]>,
167 _axes: Option<&[usize]>,
168 _norm: Option<&str>,
169) -> FFTResult<ArrayD<Complex64>>
170where
171 T: NumCast + Copy + Debug + 'static,
172{
173 Err(crate::error::FFTError::NotImplementedError(
175 "N-dimensional inverse FFT from slice not yet implemented".to_string(),
176 ))
177}
178
179#[allow(dead_code)]
181pub fn fft_adaptive<T>(x: &[T], norm: Option<&str>) -> FFTResult<Vec<Complex64>>
182where
183 T: NumCast + Copy + Debug + 'static,
184{
185 fft_simd(x, norm)
186}
187
188#[allow(dead_code)]
190pub fn ifft_adaptive<T>(x: &[T], norm: Option<&str>) -> FFTResult<Vec<Complex64>>
191where
192 T: NumCast + Copy + Debug + 'static,
193{
194 ifft_simd(x, norm)
195}
196
197#[allow(dead_code)]
199pub fn fft2_adaptive<T>(
200 _x: &[T],
201 shape: Option<(usize, usize)>,
202 norm: Option<&str>,
203) -> FFTResult<Array2<Complex64>>
204where
205 T: NumCast + Copy + Debug + 'static,
206{
207 fft2_simd(_x, shape, norm)
208}
209
210#[allow(dead_code)]
212pub fn ifft2_adaptive<T>(
213 _x: &[T],
214 shape: Option<(usize, usize)>,
215 norm: Option<&str>,
216) -> FFTResult<Array2<Complex64>>
217where
218 T: NumCast + Copy + Debug + 'static,
219{
220 ifft2_simd(_x, shape, norm)
221}
222
223#[allow(dead_code)]
225pub fn fftn_adaptive<T>(
226 _x: &[T],
227 shape: Option<&[usize]>,
228 axes: Option<&[usize]>,
229 norm: Option<&str>,
230) -> FFTResult<ArrayD<Complex64>>
231where
232 T: NumCast + Copy + Debug + 'static,
233{
234 fftn_simd(_x, shape, axes, norm)
235}
236
237#[allow(dead_code)]
239pub fn ifftn_adaptive<T>(
240 _x: &[T],
241 shape: Option<&[usize]>,
242 axes: Option<&[usize]>,
243 norm: Option<&str>,
244) -> FFTResult<ArrayD<Complex64>>
245where
246 T: NumCast + Copy + Debug + 'static,
247{
248 ifftn_simd(_x, shape, axes, norm)
249}