rust_poly/poly/
calculus.rs

1use itertools::chain;
2use num::{Complex, Zero};
3
4use crate::{Poly, RealScalar};
5
6impl<T: RealScalar> Poly<T> {
7    /// Derivative
8    ///
9    /// # Panics
10    /// On very large degree polynomials coefficients may overflow in `T`
11    #[must_use]
12    pub fn diff(self) -> Self {
13        debug_assert!(self.is_normalized());
14
15        // derivative of constant is zero
16        if self.degree_raw() == 0 {
17            return Self::from_real_slice(&[T::zero()]);
18        }
19
20        let coeffs: Vec<_> = (0..self.len())
21            .map(|x| T::from_usize(x).expect("overflow"))
22            .map(|x| Complex::new(x, T::zero()))
23            .zip(self.0.iter())
24            .map(|(n, c)| n * c)
25            .skip(1) // shift degrees down
26            .collect();
27        Self::from_complex_vec(coeffs).normalize()
28    }
29
30    /// Antiderivative (with C=0)
31    ///
32    /// # Panics
33    /// On very large degree polynomials coefficients may overflow in `T`
34    #[must_use]
35    pub fn integral(self) -> Self {
36        debug_assert!(self.is_normalized());
37
38        let coeffs: Vec<_> = chain(
39            [Complex::<T>::zero()],
40            (1..=self.len())
41                .map(|x| T::from_usize(x).expect("overflow"))
42                .map(|x| Complex::new(x, T::zero()))
43                .zip(self.0.iter())
44                .map(|(n, c)| c / n),
45        )
46        .collect();
47        Self::from_complex_vec(coeffs).normalize()
48    }
49}
50
51#[cfg(test)]
52mod test {
53
54    #[test]
55    fn diff() {
56        let p = poly![1.0, 2.0, 3.0];
57        assert_eq!(p.diff(), poly![2.0, 6.0]);
58    }
59
60    /// This was a bug
61    #[test]
62    fn diff1() {
63        let one = poly![1.0];
64        assert_eq!(one.diff().degree(), -1);
65    }
66
67    #[test]
68    fn integral() {
69        let p = poly![1.0, 2.0, 3.0];
70        assert_eq!(p.integral(), poly![0.0, 1.0, 1.0, 1.0]);
71    }
72
73    #[test]
74    fn integral_diff() {
75        let p = poly![1.0, 2.0, 3.0];
76        let q = p.clone().integral().diff();
77        assert_eq!(p, q);
78    }
79}