1 #ifndef STAN_MATH_PRIM_FUN_INV_LOGIT_HPP
2 #define STAN_MATH_PRIM_FUN_INV_LOGIT_HPP
3 
4 #include <stan/math/prim/meta.hpp>
5 #include <stan/math/prim/fun/constants.hpp>
6 #include <stan/math/prim/fun/exp.hpp>
7 #include <stan/math/prim/fun/inv.hpp>
8 #include <stan/math/prim/functor/apply_scalar_unary.hpp>
9 #include <cmath>
10 
11 namespace stan {
12 namespace math {
13 
14 /**
15  * Returns the inverse logit function applied to the argument.
16  *
17  * The inverse logit function is defined by
18  *
19  * \f$\mbox{logit}^{-1}(x) = \frac{1}{1 + \exp(-x)}\f$.
20  *
21  * This function can be used to implement the inverse link function
22  * for logistic regression.
23  *
24  * The inverse to this function is <code>logit</code>.
25  *
26  \f[
27  \mbox{inv\_logit}(y) =
28  \begin{cases}
29  \mbox{logit}^{-1}(y) & \mbox{if } -\infty\leq y \leq \infty \\[6pt]
30  \textrm{NaN} & \mbox{if } y = \textrm{NaN}
31  \end{cases}
32  \f]
33 
34  \f[
35  \frac{\partial\, \mbox{inv\_logit}(y)}{\partial y} =
36  \begin{cases}
37  \frac{\partial\, \mbox{logit}^{-1}(y)}{\partial y} & \mbox{if } -\infty\leq
38  y\leq \infty \\[6pt] \textrm{NaN} & \mbox{if } y = \textrm{NaN} \end{cases} \f]
39 
40  \f[
41  \mbox{logit}^{-1}(y) = \frac{1}{1 + \exp(-y)}
42  \f]
43 
44  \f[
45  \frac{\partial \, \mbox{logit}^{-1}(y)}{\partial y} =
46  \frac{\exp(y)}{(\exp(y)+1)^2} \f]
47  *
48  * @param a Argument.
49  * @return Inverse logit of argument.
50  */
inv_logit(double a)51 inline double inv_logit(double a) {
52   using std::exp;
53   if (a < 0) {
54     double exp_a = exp(a);
55     if (a < LOG_EPSILON) {
56       return exp_a;
57     }
58     return exp_a / (1 + exp_a);
59   }
60   return inv(1 + exp(-a));
61 }
62 
63 /**
64  * Structure to wrap inv_logit() so that it can be vectorized.
65  *
66  * @tparam T type of variable
67  * @param x variable
68  * @return Inverse logit of x.
69  */
70 struct inv_logit_fun {
71   template <typename T>
funstan::math::inv_logit_fun72   static inline T fun(const T& x) {
73     return inv_logit(x);
74   }
75 };
76 
77 /**
78  * Vectorized version of inv_logit().
79  *
80  * @tparam T type of container
81  * @param x container
82  * @return Inverse logit applied to each value in x.
83  */
84 template <
85     typename T, require_not_var_matrix_t<T>* = nullptr,
86     require_all_not_nonscalar_prim_or_rev_kernel_expression_t<T>* = nullptr>
inv_logit(const T & x)87 inline auto inv_logit(const T& x) {
88   return apply_scalar_unary<inv_logit_fun, T>::apply(x);
89 }
90 
91 // TODO(Tadej): Eigen is introducing their implementation logistic() of this
92 // in 3.4. Use that once we switch to Eigen 3.4
93 
94 }  // namespace math
95 }  // namespace stan
96 
97 #endif
98