extern crate num;
use num::complex::Complex;
use std::f64::consts::PI;
const I: Complex<f64> = Complex { re: 0.0, im: 1.0 };
pub fn read(filename: &str) -> std::io::Result<Vec<Complex<f64>>> {
use std::fs::File;
use std::io::prelude::*;
use std::io::BufReader;
let file = File::open(filename)?;
let mut buf_reader = BufReader::new(file);
let mut buf = String::new();
let mut res = vec![];
while let Ok(s) = buf_reader.read_line(&mut buf) {
if s > 0 {
buf.pop();
let n: Vec<&str> = buf.split(' ').collect();
res.push(Complex::new(n[0].parse().unwrap(), n[1].parse().unwrap()));
buf.clear();
} else {
break;
}
}
Ok(res)
}
pub fn fft(filename: &str) -> Vec<Complex<f64>> {
let input = read(filename).unwrap();
let n_orig = input.len();
let n = n_orig.next_power_of_two();
let mut buf_a = input.to_vec();
buf_a.append(&mut vec![Complex { re: 0.0, im: 0.0 }; n - n_orig]);
let mut buf_b = buf_a.clone();
fn ft(a: &[Complex<f64>], c: &mut [Complex<f64>], n: usize, is: usize) {
for k in 0..n {
let mut s = Complex::new(0.0, 0.0);
for x in 0..n {
s += (I * PI * 2.0 * (is as f64) / (n as f64)).exp() * a[x];
}
c[k] = s;
}
}
ft(&buf_a, &mut buf_b, n, 1);
buf_b
}
fn show(label: &str, buf: &[Complex<f64>]) {
println!("{}", label);
let string = buf
.into_iter()
.map(|x| format!("{:.4}{:+.4}i", x.re, x.im))
.collect::<Vec<_>>()
.join(", ");
println!("{}", string);
}
pub fn fft_persistent(filename: &str) -> Vec<Complex<f64>> {
use crndm::default::*;
type P = BuddyAlloc;
struct FFT {
a: PRefCell<PVec<PCell<Complex<f64>>>>,
c: PRefCell<PVec<PCell<Complex<f64>>>>,
n: PCell<usize>,
is: PCell<usize>,
k: PCell<usize>,
x: PCell<usize>,
s: PCell<Complex<f64>>,
filled: PCell<bool>,
}
impl RootObj<P> for FFT {
fn init(j: &Journal) -> Self {
Self {
a: PRefCell::new(PVec::new(j), j),
c: PRefCell::new(PVec::new(j), j),
n: PCell::new(0, j),
is: PCell::new(0, j),
k: PCell::new(0, j),
x: PCell::new(0, j),
s: PCell::new(Complex::new(0.0, 0.0), j),
filled: PCell::new(false, j),
}
}
}
impl FFT {
pub fn fill(&self, input: &[Complex<f64>], n: usize, step: usize) {
P::transaction(|j| {
let mut buf_a = self.a.borrow_mut(j);
let mut buf_b = self.c.borrow_mut(j);
buf_a.reserve(input.len(), j);
buf_b.reserve(input.len(), j);
for c in input {
buf_a.push(PCell::new(*c, j), j);
buf_b.push(PCell::new(*c, j), j);
}
self.n.set(n, j);
self.is.set(step, j);
self.k.set(0, j);
self.x.set(0, j);
self.filled.set(true, j);
})
.unwrap();
}
fn process(&self) -> bool {
P::transaction(|j| {
let n = self.n.get();
let k = self.k.get();
let x = self.x.get();
if x == n {
let c = self.c.borrow();
c[k].set(self.s.get(), j);
self.s.set(Complex::new(0.0, 0.0), j);
self.k.add(1, j);
self.x.set(0, j);
return false;
}
if k == n {
return true;
}
let is = self.is.get();
let a = self.a.borrow();
self.s.set(
self.s.get() + (I * PI * 2.0 * (is as f64) / (n as f64)).exp() * a[x].get(),
j,
);
self.x.add(1, j);
false
})
.unwrap()
}
pub fn fft(&self, filename: &str) -> std::vec::Vec<Complex<f64>> {
if !self.filled.get() {
let input = read(filename).unwrap();
let n_orig = input.len();
let n = n_orig.next_power_of_two();
let mut buf_a = input.to_vec();
buf_a.append(&mut vec![Complex { re: 0.0, im: 0.0 }; n - n_orig]);
self.fill(buf_a.as_slice(), n, 1);
}
while !self.process() {}
let c = self.c.borrow();
c.cast(|v| v.get())
}
}
let root = P::open::<FFT>("fft.pool", O_CFNE).unwrap();
root.fft(filename)
}
fn main() {
use std::env;
let args: Vec<String> = env::args().collect();
if args.len() > 1 {
if args[1] == "p" {
let output = fft_persistent("fft.in");
show("fft output:", &output);
return;
}
}
let output = fft("fft.in");
show("fft output:", &output);
}