Skip to content

Interpolation

Rust

mod math {
    use std::ops;

    /// Lagrange interpolation
    pub struct Interpolation<T> {
        /// Degree of polynomial
        n: usize,
        /// Coefficients
        coeff: Vec<T>,
    }

    impl<T> Interpolation<T>
    where
        T: Copy
            + ops::Neg<Output = T>
            + ops::Add<Output = T>
            + ops::Sub<Output = T>
            + ops::Mul<Output = T>
            + ops::Div<Output = T>
            + num::Zero
            + num::One
            + num::FromPrimitive,
    {
        /// Given n+1 points (0, y0), (1, y1), ..., (n, yn), construct the interpolation polynomial
        pub fn new(y: &[T]) -> Self {
            let n = y.len() - 1;
            let mut coeff = Vec::with_capacity(n + 1);
            let mut fact = T::one();
            for i in 1..=n {
                fact = fact * T::from_usize(i).unwrap();
            }
            fact = T::one() / fact;
            let mut inv = vec![fact; n + 1];
            for i in (0..n).rev() {
                inv[i] = inv[i + 1] * T::from_usize(i + 1).unwrap();
            }
            let mut neg = T::one();
            if (n % 2) == 1 {
                neg = -neg;
            }

            for i in 0..=n {
                let left = inv[i];
                let right = inv[n - i] * neg;
                coeff.push(left * right * y[i]);
                neg = -neg;
            }
            Self { n, coeff }
        }

        /// Evaluate the polynomial at x
        pub fn eval(&self, x: T) -> T {
            let mut left = T::one();
            let mut right = vec![T::one(); self.n + 1];
            for i in (0..self.n).rev() {
                right[i] = right[i + 1] * (x - T::from_usize(i + 1).unwrap());
            }
            let mut ans = T::zero();
            for i in 0..=self.n {
                ans = ans + self.coeff[i] * left * right[i];
                left = left * (x - T::from_usize(i).unwrap());
            }
            ans
        }
    }
}