#![crate_type="lib"]
#![feature(std_misc, core)]
extern crate libc;
extern crate num;
extern crate "fftw3-sys" as ffi;
use std::{error, fmt, mem};
use num::Complex;
pub mod plan;
pub mod lock;
#[derive(Debug)]
pub enum FftError {
InsufficientSpace(usize, usize),
FailedPlan,
}
impl fmt::Display for FftError {
fn fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result {
match *self {
FftError::InsufficientSpace(in_, out) => {
write!(fmtr, "insufficient output space: given {}, needed {}", out, in_)
}
FftError::FailedPlan => write!(fmtr, "planning failed"),
}
}
}
impl error::Error for FftError {
fn description(&self) -> &str {
match *self {
FftError::InsufficientSpace(_, _) => "insufficient output space",
FftError::FailedPlan => "planning failed"
}
}
}
pub fn c2c_1d(in_: &[Complex<f64>], out: &mut [Complex<f64>],
forward: bool) -> Result<(), FftError> {
assert!(in_.len() < (1 << (8*mem::size_of::<libc::c_int>() - 1)) - 1);
if out.len() < in_.len() {
return Err(FftError::InsufficientSpace(in_.len(), out.len()))
}
let sign = if forward { ffi::FFTW_FORWARD } else { ffi::FFTW_BACKWARD };
unsafe {
let plan = plan::RawPlan::new(|| {
ffi::fftw_plan_dft_1d(in_.len() as libc::c_int,
in_.as_ptr() as *mut ffi::fftw_complex,
out.as_mut_ptr() as *mut ffi::fftw_complex,
sign,
ffi::FFTW_ESTIMATE)
});
match plan {
None => Err(FftError::FailedPlan),
Some(mut p) => {
p.execute();
Ok(())
}
}
}
}
#[cfg(test)]
mod tests {
use num::Complex;
extern crate rand;
#[test]
fn c2c_1d_roundtrip() {
let input = (0..1000)
.map(|_| Complex::new(rand::random(),
rand::random()))
.collect::<Vec<_>>();
let mut output = (0..1000).map(|_| Complex::new(0.0,0.0)).collect::<Vec<_>>();
let mut output2 = output.clone();
super::c2c_1d(&*input, &mut *output, true).unwrap();
super::c2c_1d(&*output, &mut *output2, false).unwrap();
for (x, raw_y) in input.iter().zip(output2.iter()) {
let y = raw_y.unscale(1000.0);
if (*x - y).norm() >= 1e-10 {
panic!("roundtrip elements too far apart: {}, {}", *x, y)
}
}
}
}