//! 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());
}
}