rust_poly/
lib.rs

1// TODO(version: v1.0.0): license/author header project-wide, see MIT guidelines
2
3// lint groups
4#![warn(clippy::pedantic)]
5#![warn(clippy::cargo)]
6// restriction lints
7#![warn(clippy::dbg_macro)]
8#![warn(clippy::print_stdout)]
9#![warn(clippy::print_stderr)]
10#![warn(clippy::undocumented_unsafe_blocks)]
11#![warn(clippy::unnecessary_safety_doc)]
12#![warn(clippy::unwrap_used)]
13
14pub use num;
15
16/// A more convenient way to write `Complex::new(...)`.
17///
18/// # Examples
19///
20/// ```
21/// use rust_poly::complex;
22/// use num::Complex;
23///
24/// let c1: Complex<f32> = complex!();
25/// let c2 = Complex::new(0.0, 0.0);
26/// let c3 = complex!(1.0f32, 2.0);
27/// let c4 = Complex::new(1.0, 2.0);
28///
29/// assert_eq!(c1, c2);
30/// assert_eq!(c3, c4);
31/// assert_eq!(complex!(4.20), complex!(4.20, 0.0));
32/// ```
33#[macro_export]
34macro_rules! complex {
35    () => {{
36        <$crate::num::Complex<_> as $crate::num::Zero>::zero()
37    }};
38    ($re:expr) => {{
39        $crate::num::Complex::new(
40            $re,
41            <$crate::num::Complex<_> as $crate::num::Zero>::zero().im,
42        )
43    }};
44    ($re:expr, $im: expr) => {{
45        $crate::num::Complex::new($re, $im)
46    }};
47}
48
49/// A more convenient way of writing `Poly::new(&[Complex::new(...)...])`
50///
51/// It takes ownership of its arguments.
52///
53/// It can take a list of `Scalar` or `Complex<Scalar>`. If left empty, it is
54/// equivalent to `Poly::zero()`.
55///
56/// # Examples
57///
58/// Basic syntax
59/// ```
60/// use rust_poly::{poly, Poly};
61/// use num::Zero;
62/// use num::Complex;
63///
64/// let p1: Poly<f32> = poly![];
65/// let p2 = poly![1.0f32, 2.0, 3.0];
66/// let p3 = Poly::from_complex_vec(vec![Complex::new(1.0, 0.0), Complex::new(2.0, 0.0), Complex::new(3.0, 0.0)]);
67///
68/// assert_eq!(p1, Poly::zero());
69/// assert_eq!(p2, p3);
70/// ```
71///
72/// Similarly to `vec!`, you can initialize a large polynomial where all coefficients
73/// are equal like so:
74/// ```
75/// # use rust_poly::{poly, Poly};
76/// use num::Complex;
77///
78/// let p1 = poly![2.0; 4];
79/// let p2 = poly![(2.0, 0.0); 4];
80/// let p3 = poly![2.0, 2.0, 2.0, 2.0];
81/// assert_eq!(p1, p2);
82/// assert_eq!(p2, p3);
83/// ```
84#[macro_export]
85macro_rules! poly {
86    () => {{
87        <$crate::Poly<_> as $crate::num::Zero>::zero()
88    }};
89    (($re:expr, $im:expr); $n:expr) => {{
90        $crate::Poly::from_complex_vec(vec![$crate::complex!($re, $im); $n])
91    }};
92    ($elem:expr; $n:expr) => {{
93        $crate::Poly::from_real_vec(vec![$elem; $n])
94    }};
95    ($(($re:expr, $im:expr)),+ $(,)?) => {{
96        $crate::Poly::from_complex_vec(vec![$($crate::complex!($re, $im)),*])
97    }};
98    ($($elems:expr),+ $(,)?) => {{
99        $crate::Poly::from_real_vec(vec![$($elems),*])
100    }};
101}
102
103mod scalar;
104pub use scalar::RealScalar;
105
106mod poly;
107pub use poly::{roots, Poly};
108
109pub(crate) mod util;
110pub use util::__testing;
111
112pub type Poly32 = Poly<f32>;
113pub type Poly64 = Poly<f64>;
114
115#[cfg(test)]
116mod tests {
117    use super::*;
118    use num::{Complex, One, Zero};
119
120    #[test]
121    fn macro_complex() {
122        assert_eq!(complex!(), Complex::<f64>::zero());
123        assert_eq!(complex!(1.0, 2.0), Complex::<f64>::new(1.0, 2.0));
124    }
125
126    #[test]
127    fn macro_poly() {
128        assert_eq!(poly!(), Poly::<f64>::zero());
129        assert_eq!(poly!(1.0), Poly::<f64>::one());
130        assert_eq!(
131            poly!(1.0, 2.0, 3.0),
132            Poly::<f64>::new(&[
133                Complex::new(1.0, 0.0),
134                Complex::new(2.0, 0.0),
135                Complex::new(3.0, 0.0),
136            ])
137        );
138        assert_eq!(poly!((1.0, 0.0)), Poly::<f64>::one());
139        assert_eq!(
140            poly!((1.0, 1.0), (2.0, 2.0), (3.0, 3.0)),
141            Poly::<f64>::new(&[
142                Complex::new(1.0, 1.0),
143                Complex::new(2.0, 2.0),
144                Complex::new(3.0, 3.0)
145            ])
146        );
147        assert_eq!(
148            poly!(2.0; 3),
149            Poly::<f64>::new(&[
150                Complex::new(2.0, 0.0),
151                Complex::new(2.0, 0.0),
152                Complex::new(2.0, 0.0)
153            ])
154        );
155        assert_eq!(
156            poly!((1.0, -1.0); 3),
157            Poly::<f64>::new(&[
158                Complex::new(1.0, -1.0),
159                Complex::new(1.0, -1.0),
160                Complex::new(1.0, -1.0)
161            ])
162        );
163    }
164
165    #[test]
166    fn poly_new() {
167        // trivial, but here for completeness
168        Poly::new(&[Complex::new(2.0, -2.0)]);
169    }
170
171    #[test]
172    fn poly_from_complex_slice() {
173        let p = Poly::from_complex_slice(&[Complex::new(1.0, 2.0), Complex::new(3.0, 4.0)]);
174        let e = poly!((1.0, 2.0), (3.0, 4.0));
175        assert_eq!(p, e);
176    }
177
178    // TODO: test the rest of the "boring" functions
179
180    #[test]
181    fn poly_line() {
182        let p = Poly::<f64>::line(Complex::<f64>::new(1.0, 0.0), Complex::<f64>::new(2.0, 0.0));
183        let e = poly!(1.0, 2.0);
184        assert_eq!(p, e);
185    }
186
187    #[test]
188    fn poly_term() {
189        let p = Poly64::term(complex!(2.0), 2);
190        let e = poly!(0.0, 0.0, 2.0);
191        assert_eq!(p, e);
192    }
193
194    #[test]
195    fn poly_bessel() {
196        assert_eq!(Poly64::bessel(0).unwrap(), poly![1.0]);
197        assert_eq!(Poly64::bessel(1).unwrap(), poly![1.0, 1.0]);
198        assert_eq!(Poly64::bessel(2).unwrap(), poly![1.0, 3.0, 3.0]);
199        assert_eq!(Poly64::bessel(3).unwrap(), poly![1.0, 6.0, 15.0, 15.0]);
200    }
201
202    #[test]
203    fn poly_reverse_bessel() {
204        assert_eq!(Poly64::reverse_bessel(0).unwrap(), poly![1.0]);
205        assert_eq!(Poly64::reverse_bessel(1).unwrap(), poly![1.0, 1.0]);
206        assert_eq!(Poly64::reverse_bessel(2).unwrap(), poly![3.0, 3.0, 1.0]);
207        assert_eq!(
208            Poly64::reverse_bessel(3).unwrap(),
209            poly![15.0, 15.0, 6.0, 1.0]
210        );
211    }
212}