chainrules/unary/
hyperbolic.rs

1use crate::unary::one;
2use crate::ScalarAd;
3
4/// Primal `tanh`.
5pub fn tanh<S: ScalarAd>(x: S) -> S {
6    x.tanh()
7}
8
9/// Forward rule for `tanh`.
10pub fn tanh_frule<S: ScalarAd>(x: S, dx: S) -> (S, S) {
11    let y = x.tanh();
12    let scale = one::<S>() - y * y;
13    (y, dx * scale)
14}
15
16/// Reverse rule for `tanh`.
17///
18/// Takes the forward **result** `tanh(x)`, not the input `x`.
19pub fn tanh_rrule<S: ScalarAd>(result: S, cotangent: S) -> S {
20    cotangent * (one::<S>() - result * result).conj()
21}
22
23/// Primal `sinh`.
24pub fn sinh<S: ScalarAd>(x: S) -> S {
25    x.sinh()
26}
27
28/// Forward rule for `sinh`.
29pub fn sinh_frule<S: ScalarAd>(x: S, dx: S) -> (S, S) {
30    let y = x.sinh();
31    (y, dx * x.cosh())
32}
33
34/// Reverse rule for `sinh`.
35///
36/// Takes the original **input** `x`, not the result.
37pub fn sinh_rrule<S: ScalarAd>(x: S, cotangent: S) -> S {
38    cotangent * x.cosh().conj()
39}
40
41/// Primal `cosh`.
42pub fn cosh<S: ScalarAd>(x: S) -> S {
43    x.cosh()
44}
45
46/// Forward rule for `cosh`.
47pub fn cosh_frule<S: ScalarAd>(x: S, dx: S) -> (S, S) {
48    let y = x.cosh();
49    (y, dx * x.sinh())
50}
51
52/// Reverse rule for `cosh`.
53///
54/// Takes the original **input** `x`, not the result.
55pub fn cosh_rrule<S: ScalarAd>(x: S, cotangent: S) -> S {
56    cotangent * x.sinh().conj()
57}
58
59fn inverse_sqrt_one_plus_square<S: ScalarAd>(x: S) -> S {
60    one::<S>() / (one::<S>() + x * x).sqrt()
61}
62
63/// Primal `asinh`.
64pub fn asinh<S: ScalarAd>(x: S) -> S {
65    x.asinh()
66}
67
68/// Forward rule for `asinh`.
69pub fn asinh_frule<S: ScalarAd>(x: S, dx: S) -> (S, S) {
70    let y = x.asinh();
71    let scale = inverse_sqrt_one_plus_square(x);
72    (y, dx * scale)
73}
74
75/// Reverse rule for `asinh`.
76pub fn asinh_rrule<S: ScalarAd>(x: S, cotangent: S) -> S {
77    cotangent * inverse_sqrt_one_plus_square(x).conj()
78}
79
80fn inverse_acosh_scale<S: ScalarAd>(x: S) -> S {
81    one::<S>() / ((x - one::<S>()).sqrt() * (x + one::<S>()).sqrt())
82}
83
84/// Primal `acosh`.
85pub fn acosh<S: ScalarAd>(x: S) -> S {
86    x.acosh()
87}
88
89/// Forward rule for `acosh`.
90pub fn acosh_frule<S: ScalarAd>(x: S, dx: S) -> (S, S) {
91    let y = x.acosh();
92    let scale = inverse_acosh_scale(x);
93    (y, dx * scale)
94}
95
96/// Reverse rule for `acosh`.
97pub fn acosh_rrule<S: ScalarAd>(x: S, cotangent: S) -> S {
98    cotangent * inverse_acosh_scale(x).conj()
99}
100
101/// Primal `atanh`.
102pub fn atanh<S: ScalarAd>(x: S) -> S {
103    x.atanh()
104}
105
106/// Forward rule for `atanh`.
107pub fn atanh_frule<S: ScalarAd>(x: S, dx: S) -> (S, S) {
108    let y = x.atanh();
109    let scale = one::<S>() / (one::<S>() - x * x);
110    (y, dx * scale)
111}
112
113/// Reverse rule for `atanh`.
114pub fn atanh_rrule<S: ScalarAd>(x: S, cotangent: S) -> S {
115    cotangent * (one::<S>() / (one::<S>() - x * x)).conj()
116}