1use thermite::{
13 math::{PrimalProjection, specialized::SpecializedPrimalMath},
14 register::FloatElement,
15};
16
17#[inline(always)]
27pub(crate) const fn bessel_reflect_negates(n: i32) -> bool {
28 n < 0 && n % 2 != 0
29}
30
31#[inline(always)]
41pub(crate) fn bessel_reflect_v<V: thermite::vector::FloatVector>(nu: V) -> (V, V::Mask) {
42 let na = nu.abs();
43 let half = na * V::HALF;
44
45 (na, nu.cmp_lt(V::ZERO) & half.cmp_ne(half.floor()))
46}
47
48macro_rules! impl_sph_bessel_entries {
54 ($e:ty, $bi0:expr) => {
55 #[inline(always)]
56 fn sph_bessel_j_n<P: Policy, const N: usize>(self) -> Self {
57 generic::bessel::spherical::sph_jy_impl_n::<P, $e, _, N>(self).1
58 }
59
60 #[inline(always)]
61 fn sph_bessel_y_n<P: Policy, const N: usize>(self) -> Self {
62 generic::bessel::spherical::sph_jy_impl_n::<P, $e, _, N>(self).3
63 }
64
65 #[inline(always)]
66 fn sph_bessel_i_n<P: Policy, const N: usize>(self) -> Self {
67 generic::bessel::spherical::sph_ik_impl_n::<P, $e, _, N,false>(self, $bi0.far_threshold).1
68 }
69
70 #[inline(always)]
71 fn sph_bessel_i_scaled_n<P: Policy, const N: usize>(self) -> Self {
72 generic::bessel::spherical::sph_ik_impl_n::<P, $e, _, N,true>(self, $bi0.far_threshold).1
73 }
74
75 #[inline(always)]
76 fn sph_bessel_k_n<P: Policy, const N: usize>(self) -> Self {
77 generic::bessel::spherical::sph_ik_impl_n::<P, $e, _, N,false>(self, $bi0.far_threshold).3
78 }
79
80 #[inline(always)]
81 fn sph_bessel_k_scaled_n<P: Policy, const N: usize>(self) -> Self {
82 generic::bessel::spherical::sph_ik_impl_n::<P, $e, _, N,true>(self, $bi0.far_threshold).3
83 }
84
85 #[inline(always)]
86 fn sph_bessel_j_with_deriv_n<P: Policy, const N: usize>(self) -> (Self, Self) {
87 let (prev, v, _, _) = generic::bessel::spherical::sph_jy_impl_n::<P, $e, _, N>(self);
88 (v, generic::bessel::spherical::sph_deriv_n::<$e, _, N,false>(self, prev, v))
89 }
90
91 #[inline(always)]
92 fn sph_bessel_y_with_deriv_n<P: Policy, const N: usize>(self) -> (Self, Self) {
93 let (_, _, prev, v) = generic::bessel::spherical::sph_jy_impl_n::<P, $e, _, N>(self);
94 (v, generic::bessel::spherical::sph_deriv_n::<$e, _, N,false>(self, prev, v))
95 }
96
97 #[inline(always)]
98 fn sph_bessel_i_with_deriv_n<P: Policy, const N: usize, const SCALED: bool>(self) -> (Self, Self) {
99 let (prev, v, _, _) = generic::bessel::spherical::sph_ik_impl_n::<P, $e, _, N,SCALED>(self, $bi0.far_threshold);
100 let d = generic::bessel::spherical::sph_deriv_n::<$e, _, N,false>(self, prev, v);
101 (v, if const { SCALED } { d - v } else { d })
104 }
105
106 #[inline(always)]
107 fn sph_bessel_k_with_deriv_n<P: Policy, const N: usize, const SCALED: bool>(self) -> (Self, Self) {
108 let (_, _, prev, v) = generic::bessel::spherical::sph_ik_impl_n::<P, $e, _, N,SCALED>(self, $bi0.far_threshold);
109 let d = generic::bessel::spherical::sph_deriv_n::<$e, _, N,true>(self, prev, v);
111 (v, if const { SCALED } { self.is_zero().select(d, d + v) } else { d })
114 }
115
116 #[inline(always)]
119 fn sph_bessel_j<P: Policy>(self, n: u32) -> Self {
120 generic::bessel::spherical::sph_jy_impl::<P, $e, _>(self, n).1
121 }
122
123 #[inline(always)]
124 fn sph_bessel_y<P: Policy>(self, n: u32) -> Self {
125 generic::bessel::spherical::sph_jy_impl::<P, $e, _>(self, n).3
126 }
127
128 #[inline(always)]
129 fn sph_bessel_i<P: Policy>(self, n: u32) -> Self {
130 generic::bessel::spherical::sph_ik_impl::<P, $e, _, false>(self, n, $bi0.far_threshold).1
131 }
132
133 #[inline(always)]
134 fn sph_bessel_i_scaled<P: Policy>(self, n: u32) -> Self {
135 generic::bessel::spherical::sph_ik_impl::<P, $e, _, true>(self, n, $bi0.far_threshold).1
136 }
137
138 #[inline(always)]
139 fn sph_bessel_k<P: Policy>(self, n: u32) -> Self {
140 generic::bessel::spherical::sph_ik_impl::<P, $e, _, false>(self, n, $bi0.far_threshold).3
141 }
142
143 #[inline(always)]
144 fn sph_bessel_k_scaled<P: Policy>(self, n: u32) -> Self {
145 generic::bessel::spherical::sph_ik_impl::<P, $e, _, true>(self, n, $bi0.far_threshold).3
146 }
147
148 #[inline(always)]
149 fn sph_bessel_j_with_deriv<P: Policy>(self, n: u32) -> (Self, Self) {
150 let (prev, v, _, _) = generic::bessel::spherical::sph_jy_impl::<P, $e, _>(self, n);
151 (v, generic::bessel::spherical::sph_deriv::<$e, _, false>(self, n, prev, v))
152 }
153
154 #[inline(always)]
155 fn sph_bessel_y_with_deriv<P: Policy>(self, n: u32) -> (Self, Self) {
156 let (_, _, prev, v) = generic::bessel::spherical::sph_jy_impl::<P, $e, _>(self, n);
157 (v, generic::bessel::spherical::sph_deriv::<$e, _, false>(self, n, prev, v))
158 }
159
160 #[inline(always)]
161 fn sph_bessel_i_with_deriv<P: Policy, const SCALED: bool>(self, n: u32) -> (Self, Self) {
162 let (prev, v, _, _) = generic::bessel::spherical::sph_ik_impl::<P, $e, _, SCALED>(self, n, $bi0.far_threshold);
163 let d = generic::bessel::spherical::sph_deriv::<$e, _, false>(self, n, prev, v);
164 (v, if const { SCALED } { d - v } else { d })
165 }
166
167 #[inline(always)]
168 fn sph_bessel_k_with_deriv<P: Policy, const SCALED: bool>(self, n: u32) -> (Self, Self) {
169 let (_, _, prev, v) = generic::bessel::spherical::sph_ik_impl::<P, $e, _, SCALED>(self, n, $bi0.far_threshold);
170 let d = generic::bessel::spherical::sph_deriv::<$e, _, true>(self, n, prev, v);
171 (v, if const { SCALED } { self.is_zero().select(d, d + v) } else { d })
172 }
173 };
174}
175
176macro_rules! impl_airy_entries {
185 ($e:ty, $nh:literal, $ne:literal, $no:literal, $fnum:literal, $fden:literal, $lgamma:expr, $zero:expr, $bi0:expr) => {
186 #[inline(always)]
188 fn airy_tuple<P: Policy>(self) -> (Self, Self, Self, Self) {
189 generic::bessel::airy::airy_impl::<P, $e, _, $nh, $ne, $no, $fnum, $fden, false, true, true, true, true>(
190 self, $lgamma, $zero, $bi0.far_threshold,
191 )
192 }
193
194 #[inline(always)]
196 fn airy_tuple_scaled<P: Policy>(self) -> (Self, Self, Self, Self) {
197 generic::bessel::airy::airy_impl::<P, $e, _, $nh, $ne, $no, $fnum, $fden, true, true, true, true, true>(
198 self, $lgamma, $zero, $bi0.far_threshold,
199 )
200 }
201
202 #[inline(always)]
204 fn airy_ai<P: Policy>(self) -> Self {
205 generic::bessel::airy::airy_impl::<P, $e, _, $nh, $ne, $no, $fnum, $fden, false, true, false, false, false>(
206 self, $lgamma, $zero, $bi0.far_threshold,
207 )
208 .0
209 }
210
211 #[inline(always)]
213 fn airy_ai_scaled<P: Policy>(self) -> Self {
214 generic::bessel::airy::airy_impl::<P, $e, _, $nh, $ne, $no, $fnum, $fden, true, true, false, false, false>(
215 self, $lgamma, $zero, $bi0.far_threshold,
216 )
217 .0
218 }
219
220 #[inline(always)]
222 fn airy_bi<P: Policy>(self) -> Self {
223 generic::bessel::airy::airy_impl::<P, $e, _, $nh, $ne, $no, $fnum, $fden, false, false, false, true, false>(
224 self, $lgamma, $zero, $bi0.far_threshold,
225 )
226 .2
227 }
228
229 #[inline(always)]
231 fn airy_bi_scaled<P: Policy>(self) -> Self {
232 generic::bessel::airy::airy_impl::<P, $e, _, $nh, $ne, $no, $fnum, $fden, true, false, false, true, false>(
233 self, $lgamma, $zero, $bi0.far_threshold,
234 )
235 .2
236 }
237
238 #[inline(always)]
240 fn airy_ai_prime<P: Policy>(self) -> Self {
241 generic::bessel::airy::airy_impl::<P, $e, _, $nh, $ne, $no, $fnum, $fden, false, false, true, false, false>(
242 self, $lgamma, $zero, $bi0.far_threshold,
243 )
244 .1
245 }
246
247 #[inline(always)]
249 fn airy_ai_prime_scaled<P: Policy>(self) -> Self {
250 generic::bessel::airy::airy_impl::<P, $e, _, $nh, $ne, $no, $fnum, $fden, true, false, true, false, false>(
251 self, $lgamma, $zero, $bi0.far_threshold,
252 )
253 .1
254 }
255
256 #[inline(always)]
258 fn airy_bi_prime<P: Policy>(self) -> Self {
259 generic::bessel::airy::airy_impl::<P, $e, _, $nh, $ne, $no, $fnum, $fden, false, false, false, false, true>(
260 self, $lgamma, $zero, $bi0.far_threshold,
261 )
262 .3
263 }
264
265 #[inline(always)]
267 fn airy_bi_prime_scaled<P: Policy>(self) -> Self {
268 generic::bessel::airy::airy_impl::<P, $e, _, $nh, $ne, $no, $fnum, $fden, true, false, false, false, true>(
269 self, $lgamma, $zero, $bi0.far_threshold,
270 )
271 .3
272 }
273 };
274}
275
276pub trait BesselDetails<V: thermite::vector::FloatVector + PrimalProjection> {
292 #[inline(always)]
294 fn near(z: V) -> V::Mask {
295 z.cmp_le(V::TWO)
296 }
297
298 #[inline(always)]
300 fn beyond(z: V, threshold: V::Primal) -> V::Mask {
301 z.cmp_ge(V::from_primal(threshold))
302 }
303
304 #[inline(always)]
308 fn valid(z: V) -> V::Mask {
309 z.cmp_gt(V::ZERO)
310 }
311
312 #[inline(always)]
315 fn exp_far(z: V, threshold: V::Primal) -> V::Mask {
316 z.cmp_ge(V::from_primal(threshold))
317 }
318
319 const ASYM_TWO_TERMS: bool = false;
327
328 #[inline(always)]
331 fn asym_second_exponent(z: V, _nu: V::Primal) -> V {
332 z
333 }
334}
335
336impl<E: FloatElement, V: thermite::vector::FloatVector<Element = E> + SpecializedPrimalMath<E>> BesselDetails<V> for V {}
337
338#[doc(hidden)]
343pub mod kernels {
344 pub use crate::specialized::generic::bessel::ik::{asymptotic_series_g, unscale_i_pair_masked};
345 pub use crate::specialized::generic::bessel::ik_real::bessel_ik_real;
346}