rust_poly/poly/
special_funcs.rs1use crate::{
2 util::{
3 casting::{usize_to_f64, usize_to_i32, usize_to_u32},
4 luts::factorial_lut,
5 },
6 Poly, RealScalar,
7};
8use num::{BigUint, FromPrimitive};
9
10impl<T: RealScalar + FromPrimitive> Poly<T> {
11 #[deprecated(note = "use cheby1 instead")]
12 #[inline]
13 #[must_use]
14 pub fn cheby(n: usize) -> Self {
15 Self::cheby1(n)
16 }
17
18 #[allow(clippy::missing_panics_doc)]
31 #[must_use]
32 pub fn cheby1(n: usize) -> Self {
33 match n {
35 0 => poly![T::one()],
36 1 => poly![T::zero(), T::one()],
37 2 => poly![
38 T::zero() - T::one(),
39 T::zero(),
40 T::from_u8(2).expect("overflow")
41 ],
42 3 => poly![
43 T::zero(),
44 T::zero() - T::from_u8(3).expect("overflow"),
45 T::zero(),
46 T::from_u8(4).expect("overflow")
47 ],
48 4 => poly![
49 T::one(),
50 T::zero(),
51 T::zero() - T::from_u8(8).expect("overflow"),
52 T::zero(),
53 T::from_u8(8).expect("overflow")
54 ],
55 _ => {
56 poly![T::zero(), T::from_u8(2).expect("overflow")] * Self::cheby1(n - 1)
57 - Self::cheby1(n - 2)
58 }
59 }
60 }
61
62 #[must_use]
64 pub fn bessel(n: usize) -> Option<Self> {
65 let mut poly = poly![];
66 for k in 0..=n {
67 let c = T::from_f64(coeff(n, k))?;
68 let term = Self::term(complex!(c), usize_to_u32(k));
69 poly = poly + term;
70 }
71 Some(poly)
72 }
73
74 #[must_use]
75 pub fn reverse_bessel(n: usize) -> Option<Self> {
76 let p = Self::bessel(n)?;
77 let v: Vec<_> = p.iter().cloned().rev().collect();
78 Some(Self::from_complex_vec(v))
79 }
80}
81
82impl<T: RealScalar> Poly<T> {
83 #[allow(clippy::missing_panics_doc)]
86 #[must_use]
87 pub fn legendre(n: usize) -> Self {
88 match n {
89 0 => return poly![T::one()],
90 1 => return poly![T::zero(), T::one()],
91 _ => {}
92 }
93
94 let mut memo = Vec::with_capacity(n - 1);
96 memo.push(poly![T::one()]);
97 memo.push(poly![T::zero(), T::one()]);
98
99 for i in 2..=n {
100 let p1 = &memo[i - 1];
101 let p2 = &memo[i - 2];
102 let ns = T::from_usize(i).expect("overflow");
103 memo.push(
104 poly![
105 T::zero(),
106 T::from_usize(2 * i - 1).expect("overflow") / ns.clone()
107 ] * p1
108 + poly![(T::one() - ns.clone()) / ns] * p2,
109 );
110 }
111 memo.last().expect("infallible").clone()
112 }
113}
114
115fn factorial(n: usize) -> BigUint {
116 if n <= 128 {
117 return factorial_lut(n);
118 }
119 BigUint::from(n) * factorial(n - 1)
120}
121
122#[allow(clippy::cast_precision_loss)]
123fn biguint_to_f64(x: &BigUint) -> f64 {
124 let mut x_f: f64 = 0.0;
125 for (i, d) in x.to_u64_digits().iter().enumerate() {
126 x_f += (*d as f64) * 2.0f64.powi(usize_to_i32(i) * 64);
127 }
128 x_f
129}
130
131pub fn coeff(n: usize, k: usize) -> f64 {
133 let aux_a = factorial(n + k) / factorial(n - k) / factorial(k);
138 let aux_b = 1.0 / (usize_to_f64(k)).exp2();
139 biguint_to_f64(&aux_a) * aux_b
140}
141
142#[cfg(test)]
143#[allow(clippy::pedantic)]
144mod test {
145 use num::{BigUint, Num};
146
147 use crate::{poly::special_funcs::biguint_to_f64, Poly, Poly64};
148
149 use super::factorial;
150
151 #[test]
152 fn factorial_129() {
153 let x = factorial(129);
154 let x_expected = BigUint::from_str_radix("49745042224772874403902341504126809639656611137138843145968864022652168932196355119328515747917449637889876686464600208839390308261862352651828829226610077151044469167497022952331930501120000000000000000000000000000000", 10).unwrap();
155 assert_eq!(x, x_expected);
156 }
157
158 #[test]
159 fn test_biguint_to_f64() {
160 let i = 1u128 << 90;
161 let x = BigUint::from(i);
162 assert_eq!(i as f64, biguint_to_f64(&x));
163 }
164
165 #[test]
166 #[cfg_attr(miri, ignore)] fn bessel_big() {
168 let _ = Poly64::bessel(134).unwrap();
170 }
171
172 #[test]
173 #[cfg_attr(miri, ignore)] fn reverse_bessel_big() {
175 let _ = Poly64::reverse_bessel(134).unwrap();
177 }
178
179 #[test]
180 fn legendre() {
181 let p = Poly::<f32>::legendre(3);
182 assert_eq!(p, poly![0.0, -1.5, 0.0, 2.5]);
183 }
184}