use thermite::{
element::FloatElementWithBits,
mask::GenericMask,
math::{CoreMathWithPolicy as _, TranscendentalMathWithPolicy as _, policy::Policy},
prelude::*,
};
use crate::specialized::SpecializedSpecialMath;
use crate::tables::Trigamma;
#[inline(always)]
pub fn trigamma_impl<P, E, V>(x_in: V, t: &Trigamma<E>) -> V
where
P: Policy,
E: FloatElementWithBits,
V: FloatVectorWithBits<Element = E> + SpecializedSpecialMath<E>,
{
let x0 = x_in.flush_denormals_p::<P>();
let reflect = x0.cmp_le(V::ZERO);
let mut refl = V::ZERO;
let mut x = x0;
if const { P::POLICY.avoid_branching } || reflect.any() {
let s = x0.sin_pi_p::<P>();
refl = (V::PI_SQUARED / (s * s)).zz(reflect);
x = reflect.select(V::ONE - x0, x);
}
let mut acc = V::ZERO;
let below_one = x.cmp_lt(V::ONE);
if const { P::POLICY.avoid_branching } || below_one.any() {
acc = (x * x).reciprocal_p::<P>().zz(below_one);
x = x.add_c(below_one, V::ONE);
}
let small = x.cmp_le(V::TWO);
let mid = x.cmp_le(V::splat(E::from_int(4))) & !small;
let large = !(small | mid);
let y = small.select(x * x, x).reciprocal_p::<P>();
let mut num = V::EMPTY;
let mut den = V::EMPTY;
let mut base = V::ONE;
if const { P::POLICY.avoid_branching } || small.any() {
num = x.poly_p::<P, _>(&t.p_1_2);
den = x.poly_p::<P, _>(&t.q_1_2);
base = small.select(V::splat(t.offset), V::ONE);
}
if const { P::POLICY.avoid_branching } || mid.any() {
num = mid.select(y.poly_p::<P, _>(&t.p_2_4), num);
den = mid.select(y.poly_p::<P, _>(&t.q_2_4), den);
}
if const { P::POLICY.avoid_branching } || large.any() {
num = large.select(y.poly_p::<P, _>(&t.p_4_inf), num);
den = large.select(y.poly_p::<P, _>(&t.q_4_inf), den);
}
let main = (base + num / den) * y;
reflect.select(refl - main, acc + main)
}