1use crate::recipe::Ops;
3use crate::{Exponent, Float};
4
5#[inline(always)]
7pub(crate) fn polygamma_slopes<F: Float, O: Ops<F> + ?Sized>(o: &O, [n, x]: [O::V; 2], _: O::V, [_, nx]: [bool; 2]) -> [Option<O::V>; 2] {
8 [None, nx.then(|| o.polygamma(o.add(n, o.number(F::one())), x))]
9}
10
11#[inline(always)]
13pub(crate) fn gammainc_slopes<F: Float, O: Ops<F> + ?Sized>(o: &O, [a, x]: [O::V; 2], _: O::V, [_, nx]: [bool; 2]) -> [Option<O::V>; 2] {
14 let one = o.number(F::one());
15 let power = || match o.constant(a) {
16 Some(c) if c == F::one() => o.number(F::zero()), _ => o.multiply(o.subtract(a, one), o.ln(o.add(x, o.one_where(o.equal(a, one)))))
17 };
18 [None, nx.then(|| o.exp(o.subtract(o.subtract(power(), x), o.lgamma(a))))]
19}
20
21#[inline(always)]
23pub(crate) fn logb<F: Float, O: Ops<F> + ?Sized>(o: &O, [x, y]: [O::V; 2], r: O::V, [nx, ny]: [bool; 2]) -> [Option<O::V>; 2] {
24 let base = o.ln(x);
25 [nx.then(|| o.negate(o.divide(r, o.multiply(x, base)))), ny.then(|| o.reciprocal(o.multiply(y, base)))]
26}
27
28#[inline(always)]
30fn binom_points<F: Float, O: Ops<F> + ?Sized>(o: &O, n: O::V, k: O::V) -> (O::V, [O::V; 3]) {
31 let one = o.number(F::one());
32 (o.binom(n, k), [o.add(n, one), o.add(k, one), o.add(o.subtract(n, k), one)])
33}
34
35#[inline(always)]
37fn trigamma<F: Float, O: Ops<F> + ?Sized>(o: &O, x: O::V) -> O::V { o.polygamma(o.number(F::one()), x) }
38
39#[inline(always)]
41pub(crate) fn binom_dn_slopes<F: Float, O: Ops<F> + ?Sized>(o: &O, [n, k]: [O::V; 2], r: O::V, [nn, nk]: [bool; 2]) -> [Option<O::V>; 2] {
42 let (c, [n1, _, m]) = binom_points(o, n, k);
43 let (a, tm) = (o.subtract(o.digamma(n1), o.digamma(m)), trigamma(o, m));
44 [nn.then(|| o.add(o.multiply(r, a), o.multiply(c, o.subtract(trigamma(o, n1), tm)))), nk.then(|| o.add(o.multiply(o.binom_dk(n, k), a), o.multiply(c, tm)))]
45}
46
47#[inline(always)]
49pub(crate) fn binom_dk_slopes<F: Float, O: Ops<F> + ?Sized>(o: &O, [n, k]: [O::V; 2], r: O::V, [nn, nk]: [bool; 2]) -> [Option<O::V>; 2] {
50 let (c, [_, k1, m]) = binom_points(o, n, k);
51 let (b, tm) = (o.subtract(o.digamma(m), o.digamma(k1)), trigamma(o, m));
52 [nn.then(|| o.add(o.multiply(o.binom_dn(n, k), b), o.multiply(c, tm))), nk.then(|| o.subtract(o.multiply(r, b), o.multiply(c, o.add(tm, trigamma(o, k1)))))]
53}
54
55#[inline(always)]
62pub fn power_slope<F: Float, O: Ops<F> + ?Sized>(o: &O, x: O::V, y: O::V, r: O::V, halves: bool) -> O::V {
63 let (zero, one) = (o.number(F::zero()), o.number(F::one()));
64 match o.constant(y).map(|c| (c, c - F::one())) {
65 Some((c, _)) if c == F::one() => one,
66 Some((c, _)) if c == F::zero() => zero,
67 Some((_, k))
68 if match Exponent::of(k.wide(), o.fused()) { Exponent::General => false, Exponent::Halves { .. } => halves, Exponent::Whole { .. } => true } =>
69 { o.multiply(y, o.power(k, x)) }
70 route => {
71 let at_zero = o.equal(x, zero);
72 let stand_in = |v, m| o.add(v, o.one_where(m));
73 let (r, x) = match route {
75 Some((c, _)) if F::zero() < c && c < F::one() => (stand_in(r, at_zero), x),
76 Some(_) => (r, stand_in(x, at_zero)),
77 None => {
78 let between = o.and(o.less(zero, y), o.less(y, one));
79 (stand_in(r, o.and(at_zero, o.or(between, o.equal(y, one)))), stand_in(x, o.and(at_zero, o.not(between))))
80 }
81 };
82 o.multiply(y, o.divide(r, x))
83 }
84 }
85}
86
87#[inline(always)]
89pub(crate) fn power<F: Float, O: Ops<F> + ?Sized>(o: &O, [x, y]: [O::V; 2], r: O::V, [nx, ny]: [bool; 2]) -> [Option<O::V>; 2] {
90 let zero = o.number(F::zero());
91 [nx.then(|| o.power_slope(x, y, r, true)), ny.then(|| o.multiply(r, o.ln(o.larger(x, o.one_where(o.less_equal(x, zero))))))]
92}
93
94#[inline(always)]
96pub(crate) fn real_power<F: Float, O: Ops<F> + ?Sized>(o: &O, [x, y]: [O::V; 2], r: O::V, [nx, ny]: [bool; 2]) -> [Option<O::V>; 2] {
97 let zero = o.number(F::zero());
98 [
99 nx.then(|| o.power_slope(x, y, r, false)), ny.then(|| {
100 let ln = o.ln(o.select(o.equal(x, zero), o.number(F::one()), o.magnitude(x)));
101 let below = o.select(o.less(x, zero), o.number(F::narrow(core::f64::consts::PI)), zero);
103 o.subtract(o.multiply(r, ln), o.multiply(below, o.multiply(o.exp(o.multiply(y, ln)), crate::recipe::sincospi(o, y).0)))
104 }),
105 ]
106}
107
108#[derive(Clone, Copy, Debug)]
110pub struct Slope<K, const SIDE: usize = 0>(pub K);