use std::io::Error;
use std::io::ErrorKind;
use num_complex::Complex;
pub fn filon_tab_sin(ftab: Vec<Complex<f64>>, a: f64, b: f64, sin_coeff: f64) -> Result<Complex<f64>, Error> {
if a == b {
return Ok(Complex::new(0.0, 0.0))
}
let mesh_size: usize = ftab.len();
if mesh_size <= 1 || mesh_size % 2 == 0 {
return Err(Error::new(ErrorKind::InvalidInput, "mesh size must be an odd integer greater than 1."))
}
let h: f64 = (b - a) / (mesh_size as f64 - 1.0);
let theta: f64 = sin_coeff * h;
let sintab: Vec<f64> = linspace(&a, &b, mesh_size).iter().map(|x| (sin_coeff*x).sin()).collect();
let (alpha, beta, gamma) = calculate_abg(&theta);
let s2n: Complex<f64> = (0..ftab.len()).step_by(2).map(|x| ftab[x] * sintab[x]).sum::<Complex<f64>>()
- 0.5*(ftab[ftab.len()-1]*sintab[ftab.len()-1] + ftab[0]*sintab[0]);
let s2nm1: Complex<f64> = (1..ftab.len()-1).step_by(2).map(|x| ftab[x] * sintab[x]).sum::<Complex<f64>>();
let output: Complex<f64> = h * (
alpha * ((ftab[0] * (sin_coeff*a).cos()) - (ftab[ftab.len()-1] * (sin_coeff*b).cos()))
+ beta * s2n
+ gamma * s2nm1
);
Ok(output)
}
pub fn filon_tab_cos(ftab: Vec<Complex<f64>>, a: f64, b: f64, cos_coeff: f64) -> Result<Complex<f64>, Error> {
if a == b {
return Ok(Complex::new(0.0, 0.0))
}
let mesh_size: usize = ftab.len();
if mesh_size <= 1 || mesh_size % 2 == 0 {
return Err(Error::new(ErrorKind::InvalidInput, "mesh size must be an odd integer greater than 1."))
}
let h: f64 = (b - a) / (mesh_size as f64 - 1.0);
let theta: f64 = cos_coeff * h;
let costab: Vec<f64> = linspace(&a, &b, mesh_size).iter().map(|x| (cos_coeff*x).cos()).collect();
let (alpha, beta, gamma) = calculate_abg(&theta);
let c2n: Complex<f64> = (0..ftab.len()).step_by(2).map(|x| ftab[x] * costab[x]).sum::<Complex<f64>>()
- 0.5*(ftab[ftab.len()-1]*costab[ftab.len()-1] + ftab[0]*costab[0]);
let c2nm1: Complex<f64> = (1..ftab.len()-1).step_by(2).map(|x| ftab[x] * costab[x]).sum::<Complex<f64>>();
let output: Complex<f64> = h * (
alpha * ((ftab[ftab.len()-1] * (cos_coeff*b).sin()) - (ftab[0] * (cos_coeff*a).sin()))
+ beta * c2n
+ gamma * c2nm1
);
Ok(output)
}
pub fn filon_tab_iexp(ftab: Vec<Complex<f64>>, a: f64, b: f64, exp_coeff: f64) -> Result<Complex<f64>, Error> {
let re = filon_tab_cos(ftab.clone(), a, b, exp_coeff)?;
let im = filon_tab_sin(ftab, a, b, exp_coeff)?;
let i = Complex::<f64>::new(0., 1.);
Ok(re + i*im)
}
fn linspace(a: &f64, b: &f64, num_steps: usize) -> Vec<f64>{
let step_size: f64 = (b - a) / (num_steps as f64 - 1.0);
let mut lspace: Vec<f64> = Vec::new();
for n in 0..num_steps {
lspace.push(a + step_size * n as f64)
}
lspace
}
fn calculate_abg(theta: &f64) -> (f64, f64, f64) {
if theta.abs() <= 1.0/6.0 {
(2.0 * (theta.powi(3)) / 45.0
- 2.0 * (theta.powi(5)) / 315.0
+ 2.0 * (theta.powi(7)) / 4725.0,
2.0/3.0
+ 2.0 * theta.powi(2) / 15.0
- 4.0 * theta.powi(4) / 105.0
+ 2.0 * theta.powi(6) / 567.0
- 4.0 * theta.powi(8) / 22275.0,
4.0/3.0
- 2.0 * theta.powi(2) / 15.0
+ theta.powi(4) / 210.0
- theta.powi(6) / 11340.0
)
} else {
let sint: f64 = theta.sin();
let cost: f64 = theta.cos();
((theta.powi(2) + theta * sint * cost
- 2.0 * sint.powi(2)) / theta.powi(3),
(2.0 * theta + 2.0 * theta * cost.powi(2)
- 4.0 * sint * cost) / theta.powi(3),
(4.0 * (sint - theta * cost) / theta.powi(3))
)
}
}