use crate::{Anime, AnimeError};
pub enum Tensive {
In,
Ex,
}
impl Anime {
pub fn interpolate(&self, var: &[f64], tensive: Tensive) -> Result<Vec<f64>, AnimeError> {
match tensive {
Tensive::In => self.interpolate_intensive(var),
Tensive::Ex => self.interpolate_extensive(var),
}
}
pub fn interpolate_extensive(&self, source_var: &[f64]) -> Result<Vec<f64>, AnimeError> {
if source_var.len() != self.source_lens.len() {
return Err(AnimeError::IncorrectLength);
}
let matches = self.matches.get().ok_or(AnimeError::MatchesNotFound)?;
let res = matches
.iter()
.map(|(_, matches)| {
matches.iter().fold(0.0, |acc, mi| {
let source_idx = mi.index as usize;
let shared_len = mi.shared_len;
let wt = shared_len / self.source_lens[source_idx];
acc + (source_var[source_idx] * wt)
})
})
.collect::<Vec<f64>>();
Ok(res)
}
pub fn interpolate_intensive(&self, source_var: &[f64]) -> Result<Vec<f64>, AnimeError> {
let nv = source_var.len();
let n_tar = self.source_lens.len();
if nv != n_tar {
return Err(AnimeError::IncorrectLength);
}
let matches = self.matches.get().ok_or(AnimeError::MatchesNotFound)?;
let res = matches
.iter()
.map(|(target_idx, matches)| {
let (numerator, denominator) =
matches.iter().fold((0.0, 0.0), |(acc_num, acc_den), mi| {
let source_idx = mi.index as usize;
let wt =
mi.shared_len / self.target_lens.get(*target_idx as usize).unwrap(); let weighted_value = source_var[source_idx] * wt;
(acc_num + weighted_value, acc_den + wt)
});
if denominator > 0.0 {
numerator / denominator
} else {
0.0 }
})
.collect::<Vec<f64>>();
Ok(res)
}
}