use numeric::function::{Domain, Eval};
use numeric::piecewise::Piecewise;
use numeric::polynomial::Polynomial;
use std::ops::{Sub, Mul, Add};
use std::fmt::Debug;
extern crate nalgebra;
use self::nalgebra::{DMat, DVec, Inv};
extern crate num;
use self::num::traits::{Zero, CheckedAdd};
use self::num::iter::range;
pub trait Interpolate{
fn cubic_spline(&self) -> Piecewise<Polynomial>;
fn linear(&self) -> Piecewise<Polynomial>;
}
impl Interpolate for Vec<f32> {
fn cubic_spline(&self) -> Piecewise<Polynomial> {
let (mut h, mut coeffs_mat) = gen_coeffs_matrix(range(0f32, self.len() as f32).collect()); let mut B: DVec<f32> = DVec::new_zeros(self.len());
for i in 1..self.len() -1 {
B[i] = ((self[i+1] - self[i]) / h[i] - (self[i] - self[i-1]) / h[i-1]);
}
coeffs_mat[(0,0)] = 1.0;
coeffs_mat[(self.len() -1, self.len() -1)] = 1.0;
let inv = coeffs_mat.inv().unwrap();
println!("{:?}", inv);
let ydd = B * inv;
let mut result: Piecewise<Polynomial> = Piecewise::new(vec![]);
for x in 0..h.len() {
let a = (ydd[x+1] - ydd[x]) / ( 6.0 * h[x] );
let b = ydd[x] / 2.0;
let c = (self[x+1] - self[x]) / h[x] - (ydd[x+1] * h[x]/ 6.0) - (ydd[x] * h[x] / 3.0);
let d = self[x];
let temp = Polynomial{ coeffs: vec![d,c,b,a], domain: (x as f32, (x+1) as f32)};
result.add_sub(temp);
}
result
}
fn linear(&self) -> Piecewise<Polynomial> {
let mut piece = Piecewise::default();
for (idx, win) in self.windows(2).enumerate() {
let idx = idx as f32;
let grad = win[1] - win[0];
let c = win[0] - (grad * idx);
let poly = Polynomial::new(vec![c, grad], (idx, idx + 1.0));
piece.add_sub(poly);
}
piece
}
}
pub enum BoundaryCondition {
Natural,
Parabolic,
Zero,
FirstDev(f32),
SecondDev(f32),
}
pub fn gen_coeffs_matrix<T: Sub<T, Output = T> + Copy + Zero + Add<T, Output = T> + Mul<T, Output = T> + Debug> (v: Vec<T>) -> (Vec<T>, DMat<T>) {
let mut mat: DMat<T> = DMat::new_zeros(v.len(), v.len());
let mut x_diff = vec![];
for win in v.windows(2) {
x_diff.push(win[1] - win[0])
}
let mut offset = 0;
for j in 1..(v.len() - 1) {
mat[(j, offset + 0)] = x_diff[j];
mat[(j, offset + 1)] = (x_diff[j -1 ] + x_diff[j]) + (x_diff[j -1] + x_diff[j]);
mat[(j, offset + 2)] = x_diff[j];
offset += 1;
}
(x_diff, mat)
}