polynomen 1.0.0

Polynomial library
Documentation
//! Polynomial calculus methods
//!
//! Polynomial derivative and integral

use std::ops::{Div, Mul};

use crate::{NumCast, One, Poly, Zero};

impl<T: Clone + Mul<Output = T> + NumCast + One + PartialEq + Zero> Poly<T> {
    /// Calculate the derivative of the polynomial.
    ///
    /// # Example
    /// ```
    /// use polynomen::Poly;
    /// let p = Poly::new_from_coeffs(&[1., 0., 1.]);
    /// let d = p.derive();
    /// assert_eq!(Poly::new_from_coeffs(&[0., 2.]), d);
    /// ```
    ///
    /// # Panics
    ///
    /// Panics when the exponent of the term (`usize`) cannot be converted
    /// to `T`.
    #[must_use]
    pub fn derive(&self) -> Self {
        if self.len() == 1 {
            return Poly::zero(); // Never empty polynomial.
        }

        let derive_coeffs: Vec<_> = self
            .coeffs
            .iter()
            .enumerate()
            .skip(1)
            .map(|(i, c)| c.clone() * T::from(i).unwrap())
            .collect();

        let result = Self {
            coeffs: derive_coeffs,
        };
        debug_assert!(!result.coeffs.is_empty());
        result
    }
}

impl<T: Clone + Div<Output = T> + NumCast + PartialEq + Zero> Poly<T> {
    /// Calculate the integral of the polynomial. When used with integral types
    /// it does not convert the coefficients to floats, division is between
    /// integers.
    ///
    /// # Arguments
    ///
    /// * `constant` - Integration constant
    ///
    /// # Example
    /// ```
    /// use polynomen::Poly;
    /// let p = Poly::new_from_coeffs(&[1., 0., 3.]);
    /// let d = p.integrate(5.3);
    /// assert_eq!(Poly::new_from_coeffs(&[5.3, 1., 0., 1.]), d);
    /// ```
    ///
    /// # Panics
    ///
    /// Panics when the exponent of the term (`usize`) cannot be converted
    /// to `T`.
    pub fn integrate(&self, constant: T) -> Self {
        if self.is_zero() {
            // Never empty polynomial.
            return Self {
                coeffs: vec![constant],
            };
        }
        let int_coeffs: Vec<_> = std::iter::once(constant)
            .chain(
                self.coeffs
                    .iter()
                    .enumerate()
                    .map(|(i, c)| c.clone() / T::from(i + 1).unwrap()),
            )
            .collect();
        let result = Self { coeffs: int_coeffs };
        debug_assert!(!result.coeffs.is_empty());
        result
    }
}

#[cfg(test)]
mod tests {
    use crate::poly;

    #[test]
    fn derive() {
        let p = poly!(1_u8, 2, 4, 8, 16);
        let p_prime = poly!(2_u8, 8, 24, 64);
        assert_eq!(p_prime, p.derive());
    }

    #[test]
    fn integrate() {
        let p = poly!(1_u8, 2, 4, 8, 16);
        let p2 = poly!(9_u8, 1, 1, 1, 2, 3);
        // Integer division.
        assert_eq!(p2, p.integrate(9));
    }

    #[test]
    fn derive_integrate() {
        let d = poly!(1.3, 3.5, -2.3, -1.6);
        let i = d.integrate(3.2);
        assert_eq!(d, i.derive());
    }
}