use crate::traits::FloatScalar;
use super::{InterpError, find_interval, validate_sorted};
#[derive(Debug, Clone)]
pub struct LinearInterp<T, const N: usize> {
xs: [T; N],
ys: [T; N],
}
impl<T: FloatScalar, const N: usize> LinearInterp<T, N> {
pub fn new(xs: [T; N], ys: [T; N]) -> Result<Self, InterpError> {
if N < 2 {
return Err(InterpError::TooFewPoints);
}
validate_sorted(&xs)?;
Ok(Self { xs, ys })
}
pub fn eval(&self, x: T) -> T {
let i = find_interval(&self.xs, x);
let h = self.xs[i + 1] - self.xs[i];
let t = (x - self.xs[i]) / h;
self.ys[i] + t * (self.ys[i + 1] - self.ys[i])
}
pub fn eval_derivative(&self, x: T) -> (T, T) {
let i = find_interval(&self.xs, x);
let h = self.xs[i + 1] - self.xs[i];
let t = (x - self.xs[i]) / h;
let dy = self.ys[i + 1] - self.ys[i];
(self.ys[i] + t * dy, dy / h)
}
pub fn xs(&self) -> &[T; N] {
&self.xs
}
pub fn ys(&self) -> &[T; N] {
&self.ys
}
}
#[cfg(feature = "alloc")]
extern crate alloc;
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
#[cfg(feature = "alloc")]
#[derive(Debug, Clone)]
pub struct DynLinearInterp<T> {
xs: Vec<T>,
ys: Vec<T>,
}
#[cfg(feature = "alloc")]
impl<T: FloatScalar> DynLinearInterp<T> {
pub fn new(xs: Vec<T>, ys: Vec<T>) -> Result<Self, InterpError> {
if xs.len() != ys.len() {
return Err(InterpError::LengthMismatch);
}
if xs.len() < 2 {
return Err(InterpError::TooFewPoints);
}
validate_sorted(&xs)?;
Ok(Self { xs, ys })
}
pub fn eval(&self, x: T) -> T {
let i = find_interval(&self.xs, x);
let h = self.xs[i + 1] - self.xs[i];
let t = (x - self.xs[i]) / h;
self.ys[i] + t * (self.ys[i + 1] - self.ys[i])
}
pub fn eval_derivative(&self, x: T) -> (T, T) {
let i = find_interval(&self.xs, x);
let h = self.xs[i + 1] - self.xs[i];
let t = (x - self.xs[i]) / h;
let dy = self.ys[i + 1] - self.ys[i];
(self.ys[i] + t * dy, dy / h)
}
pub fn xs(&self) -> &[T] {
&self.xs
}
pub fn ys(&self) -> &[T] {
&self.ys
}
}