use crate::foreign::mkl::dfti::*;
use crate::foreign::mkl::utils::fetch_ptrs;
use std::os::raw::c_long;
use std::ffi::CStr;
use nalgebra::*;
use nalgebra::base::storage::Storage;
use nalgebra::base::storage::ContiguousStorage;
use std::fmt::Debug;
use super::super::*;
use std::marker::PhantomData;
use std::mem::MaybeUninit;
#[derive(Clone)]
pub struct FFTPlan<N>
where
N : Scalar {
n : PhantomData<N>,
dims : (usize, usize),
pub handle : *mut DFTI_DESCRIPTOR,
pub handle_backward : *mut DFTI_DESCRIPTOR,
}
fn check_dfti_status(fail : u32, prefix_if_fail : &str) -> Result<(), String> {
if fail == DFTI_NO_ERROR {
return Ok(());
}
unsafe {
let msg_ptr = DftiErrorMessage(fail as c_long);
match CStr::from_ptr(msg_ptr).to_str() {
Ok(msg) => {
return Err( format!("{} \n MKL Message : {}",
prefix_if_fail, msg) );
}
Err(err) => {
return Err( format!("{} \n Could not decode MKL message: {}",
prefix_if_fail, err) );
}
}
}
}
fn build_descriptor(
dims : (usize, usize),
backward : bool,
double_prec : bool
) -> Result<*mut DFTI_DESCRIPTOR, String> {
if dims.0 < 2 || dims.0 % 2 != 0 || (dims.1 != 0 && dims.1 % 2 != 0) {
return Err(String::from(
"First dimension must have non-zero size. \
All non-zero dimensions should have an even \
number of elements"));
}
let ndims = if dims.1 > 0 {
2
} else {
1
};
let dims_arr = if ndims == 1 {
[dims.0 as c_long, 0 as c_long]
} else {
[dims.0 as c_long, dims.1 as c_long]
};
unsafe {
let mut descriptor : DFTI_DESCRIPTOR = MaybeUninit::uninit().assume_init();
let mut handle : *mut DFTI_DESCRIPTOR = &mut descriptor as *mut DFTI_DESCRIPTOR;
let handle_ptr : *mut *mut DFTI_DESCRIPTOR = &mut handle as *mut *mut DFTI_DESCRIPTOR;
let prec_const = if double_prec {
DFTI_CONFIG_VALUE_DFTI_DOUBLE
} else {
DFTI_CONFIG_VALUE_DFTI_SINGLE
};
let fail = if ndims == 1 {
DftiCreateDescriptor(
handle_ptr,
prec_const,
DFTI_CONFIG_VALUE_DFTI_REAL,
ndims as c_long,
dims_arr
) as u32
} else {
DftiCreateDescriptor(
handle_ptr,
prec_const,
DFTI_CONFIG_VALUE_DFTI_REAL,
ndims as c_long,
&dims_arr
) as u32
};
check_dfti_status(fail as u32, "Could not construct Planner.")?;
let fail = DftiSetValue(handle,
DFTI_CONFIG_PARAM_DFTI_PLACEMENT,
DFTI_CONFIG_VALUE_DFTI_NOT_INPLACE);
check_dfti_status(fail as u32, "Could not set placement.")?;
let fail = DftiSetValue(handle,
DFTI_CONFIG_PARAM_DFTI_CONJUGATE_EVEN_STORAGE,
DFTI_CONFIG_VALUE_DFTI_COMPLEX_COMPLEX);
check_dfti_status(fail as u32, "Could not set conjugate-even storage.")?;
let mut input_strides : [c_long;4] = [0,0,0,0];
let mut output_strides : [c_long;4] = [0,0,0,0];
DftiGetValue(
handle,
DFTI_CONFIG_PARAM_DFTI_INPUT_STRIDES,
&input_strides as *const c_long
);
DftiGetValue(
handle,
DFTI_CONFIG_PARAM_DFTI_OUTPUT_STRIDES,
&output_strides as *const c_long
);
if ndims >= 2 && backward {
input_strides [1] = input_strides[1] / 2 + 1;
DftiSetValue(
handle,
DFTI_CONFIG_PARAM_DFTI_INPUT_STRIDES,
&input_strides as *const c_long
);
}
if ndims >= 2 && !backward {
output_strides [1] = input_strides[1] / 2 + 1;
DftiSetValue(
handle,
DFTI_CONFIG_PARAM_DFTI_OUTPUT_STRIDES,
&output_strides as *const c_long
);
}
let fail = DftiCommitDescriptor(handle) as u32;
if fail == DFTI_NO_ERROR {
Ok(handle)
} else {
Err(String::from("Could not commit descriptor"))
}
}
}
impl<N> FFTPlan<N>
where
N : Scalar {
pub fn shape(&self) -> (usize, usize) {
self.dims
}
pub fn new(dims : (usize, usize)) -> Result<FFTPlan<N> , String> {
let double_prec = N::is::<f64>();
let handle_forward = build_descriptor(dims, false, double_prec)?;
let handle_backward = build_descriptor(dims, true, double_prec)?;
Ok( FFTPlan::<N > {
dims,
handle : handle_forward,
handle_backward,
n : PhantomData,
})
}
pub fn apply_forward(
&self,
src : &[N],
dst : &mut [Complex<N>]
) -> Result<(), String> {
crate::panic_on_invalid_slices(src, dst);
unsafe {
let status = DftiComputeForward(
self.handle,
src.as_ptr() as *mut _,
dst.as_mut_ptr()
);
if status == 0 {
Ok(())
} else {
if status > 0 {
if let Err(e) = check_dfti_status(status as u32, "(MKL message)") {
return Err(format!("{}", e));
}
}
Err(format!("Error computing DFT: {}", status))
}
}
}
pub fn apply_backward(
&self,
src : &[Complex<N>],
dst : &mut [N]
) -> Result<(), String> {
unsafe {
crate::panic_on_invalid_slices(src, dst);
let status = DftiComputeBackward(
self.handle_backward,
src.as_ptr() as *mut _,
dst.as_mut_ptr()
);
if status == 0 {
Ok(())
} else {
if status > 0 {
if let Err(e) = check_dfti_status(status as u32, "(MKL message)") {
return Err(format!("{}", e));
}
}
Err(format!("Error computing DFT: {}", status))
}
}
}
}
fn check_desc_free_err(status : i64) {
if status > 0 {
if let Err(e) = check_dfti_status(status as u32, "(MKL message)") {
println!("{}", e);
} else {
println!("Error freeing forward descriptor: {}", status);
}
}
}
impl<N> Drop for FFTPlan<N>
where
N : Scalar {
fn drop(&mut self) {
unsafe {
}
}
}
#[cfg(test)]
pub mod test {
}