use crate::error::{FFTError, FFTResult};
use scirs2_core::ndarray::{Array, ArrayD, IxDyn};
use scirs2_core::numeric::Complex64;
use std::fmt::Debug;
pub(crate) fn try_as_complex<T: Copy + Debug + 'static>(val: T) -> Option<Complex64> {
if std::any::TypeId::of::<T>() == std::any::TypeId::of::<Complex64>() {
unsafe {
let ptr = &val as *const T as *const Complex64;
return Some(*ptr);
}
}
None
}
#[inline]
#[allow(dead_code)]
pub fn is_power_of_two(n: usize) -> bool {
n != 0 && (n & (n - 1)) == 0
}
#[inline]
#[allow(dead_code)]
pub fn next_power_of_two(n: usize) -> usize {
if n == 0 {
return 1;
}
if is_power_of_two(n) {
return n;
}
let msb_pos = usize::BITS - n.leading_zeros();
1 << msb_pos
}
#[allow(dead_code)]
pub fn validate_fft_size(inputsize: usize, n: Option<usize>) -> FFTResult<usize> {
if inputsize == 0 {
return Err(FFTError::ValueError("Input cannot be empty".to_string()));
}
match n {
Some(0) => Err(FFTError::ValueError("FFT _size cannot be zero".to_string())),
Some(_size) => Ok(_size),
None => Ok(next_power_of_two(inputsize)),
}
}
#[allow(dead_code)]
pub fn validate_fftshapes(inputshape: &[usize], shape: Option<&[usize]>) -> FFTResult<Vec<usize>> {
match shape {
Some(outputshape) => {
if outputshape.len() != inputshape.len() {
return Err(FFTError::ValueError(
"Output shape must have the same number of dimensions as input".to_string(),
));
}
Ok(outputshape.to_vec())
}
None => Ok(inputshape.to_vec()),
}
}
#[allow(dead_code)]
pub fn validate_fft_axes(ndim: usize, axes: Option<&[usize]>) -> FFTResult<Vec<usize>> {
match axes {
Some(axes) => {
for &axis in axes {
if axis >= ndim {
return Err(FFTError::ValueError(format!(
"Axis {axis} out of bounds for array of dimension {ndim}"
)));
}
}
Ok(axes.to_vec())
}
None => Ok((0..ndim).collect()),
}
}
#[allow(dead_code)]
pub fn zeros_like_complex(shape: &[usize]) -> ArrayD<Complex64> {
ArrayD::<Complex64>::zeros(IxDyn(shape))
}
#[allow(dead_code)]
pub fn real_to_complex<D>(_realarray: &Array<f64, D>) -> Array<Complex64, D>
where
D: scirs2_core::ndarray::Dimension,
{
_realarray.mapv(|x| Complex64::new(x, 0.0))
}
#[allow(dead_code)]
pub fn complex_to_real<D>(_complexarray: &Array<Complex64, D>) -> Array<f64, D>
where
D: scirs2_core::ndarray::Dimension,
{
_complexarray.mapv(|x| x.re)
}
#[allow(dead_code)]
pub fn complex_magnitude<D>(_complexarray: &Array<Complex64, D>) -> Array<f64, D>
where
D: scirs2_core::ndarray::Dimension,
{
_complexarray.mapv(|x| x.norm())
}
#[allow(dead_code)]
pub fn complex_angle<D>(_complexarray: &Array<Complex64, D>) -> Array<f64, D>
where
D: scirs2_core::ndarray::Dimension,
{
_complexarray.mapv(|x| x.arg())
}
#[allow(dead_code)]
pub fn power_spectrum<D>(_complexarray: &Array<Complex64, D>) -> Array<f64, D>
where
D: scirs2_core::ndarray::Dimension,
{
_complexarray.mapv(|x| x.norm_sqr())
}
#[allow(dead_code)]
pub fn slice_to_indices(slice: &[usize]) -> Vec<usize> {
slice.to_vec()
}