Automatic Differentiation
 
Loading...
Searching...
No Matches
categorical_logit_lpmf.hpp
Go to the documentation of this file.
1#ifndef STAN_MATH_PRIM_PROB_CATEGORICAL_LOGIT_LPMF_HPP
2#define STAN_MATH_PRIM_PROB_CATEGORICAL_LOGIT_LPMF_HPP
3
11#include <cmath>
12#include <vector>
13
14namespace stan {
15namespace math {
16
35template <bool propto, typename T_prob, require_col_vector_t<T_prob>* = nullptr>
37 static constexpr const char* function = "categorical_logit_lpmf";
38 check_bounded(function, "categorical outcome out of support", n, 1,
39 beta.size());
40 ref_type_t<T_prob> beta_ref = beta;
41
42 // Autodiff args must be finite data may be +/-inf
43 if constexpr (is_constant_v<T_prob>) {
44 // Data Case: Throws in nan and all -inf case
45 check_not_nan(function, "log odds parameter", beta_ref);
46 check_greater(function, "log odds parameter", beta_ref.maxCoeff(),
48 } else {
49 // Autodiff Case: Throws in non-finite case
50 check_finite(function, "log odds parameter", beta_ref);
51 }
52
54 return 0.0;
55 }
56
57 // softmax is NaN with +inf, so split probability evenly over the
58 // +inf entries and give every other entry zero probability
59 if constexpr (is_constant_v<T_prob>) {
60 int num_infty = (beta_ref.array() == INFTY).count();
61 if (num_infty > 0) {
62 return beta_ref.coeff(n - 1) == INFTY ? -std::log(num_infty)
64 }
65 }
66
67 // FIXME: wasteful vs. creating term (n-1) if not vectorized
68 return beta_ref.coeff(n - 1)
69 - log_sum_exp(beta_ref); // == log_softmax(beta)(n-1);
70}
71
95template <bool propto, typename T_prob, require_col_vector_t<T_prob>* = nullptr>
96inline return_type_t<T_prob> categorical_logit_lpmf(const std::vector<int>& ns,
97 const T_prob& beta) {
98 static constexpr const char* function = "categorical_logit_lpmf";
99
100 check_bounded(function, "categorical outcome out of support", ns, 1,
101 beta.size());
102 ref_type_t<T_prob> beta_ref = beta;
103
104 // An empty beta forces ns to be empty (checked above)
105 if (beta_ref.size() == 0) {
106 return 0.0;
107 }
108
109 // Autodiff args must be finite data may be +/-inf
110 if constexpr (is_constant_v<T_prob>) {
111 // Data Case: Throws in nan and all -inf case
112 check_not_nan(function, "log odds parameter", beta_ref);
113 check_greater(function, "log odds parameter", beta_ref.maxCoeff(),
115 } else {
116 // Autodiff Case: Throws in non-finite case
117 check_finite(function, "log odds parameter", beta_ref);
118 }
119
121 return 0.0;
122 }
123
124 if (ns.empty()) {
125 return 0.0;
126 }
127
128 // softmax is NaN with +inf, so split probability evenly over the
129 // +inf entries and give every other entry zero probability
130 if constexpr (is_constant_v<T_prob>) {
131 int num_infty = (beta_ref.array() == INFTY).count();
132 if (num_infty > 0) {
133 double lp = 0.0;
134 for (int n : ns) {
135 if (beta_ref.coeff(n - 1) != INFTY) {
136 return NEGATIVE_INFTY;
137 }
138 lp -= std::log(num_infty);
139 }
140 return lp;
141 }
142 }
143
144 auto log_softmax_beta = to_ref(log_softmax(beta_ref));
145
146 // FIXME: replace with more efficient sum()
147 Eigen::Matrix<return_type_t<T_prob>, Eigen::Dynamic, 1> results(ns.size());
148 for (size_t i = 0; i < ns.size(); ++i) {
149 results[i] = log_softmax_beta(ns[i] - 1);
150 }
151 return sum(results);
152}
153
154template <typename T_n, typename T_prob, require_st_integral<T_n>* = nullptr,
155 require_col_vector_t<T_prob>* = nullptr>
157 const T_prob& beta) {
158 return categorical_logit_lpmf<false>(ns, beta);
159}
160
161} // namespace math
162} // namespace stan
163#endif
return_type_t< T_prob > categorical_logit_lpmf(int n, const T_prob &beta)
Categorical log PMF in log-odds parametrization.
results_cl< T_results... > results(T_results &&... results)
Deduces types for constructing results_cl object.
typename return_type< Ts... >::type return_type_t
Convenience type for the return type of the specified template parameters.
void check_bounded(const char *function, const char *name, const T_y &y, const T_low &low, const T_high &high)
Check if the value is between the low and high values, inclusively.
static constexpr double NEGATIVE_INFTY
Negative infinity.
Definition constants.hpp:49
void check_finite(const char *function, const char *name, const T_y &y)
Return true if all values in y are finite.
void check_not_nan(const char *function, const char *name, const T_y &y)
Check if y is not NaN.
auto log_softmax(T &&x)
Return the log softmax of each vector in a container of fvar values.
auto sum(const std::vector< T > &m)
Return the sum of the entries of the specified standard vector.
Definition sum.hpp:23
ref_type_t< T && > to_ref(T &&a)
This evaluates expensive Eigen expressions.
Definition to_ref.hpp:18
fvar< T > beta(const fvar< T > &x1, const fvar< T > &x2)
Return fvar with the beta function applied to the specified arguments and its gradient.
Definition beta.hpp:51
void check_greater(const char *function, const char *name, const T_y &y, const T_low &low, Idxs... idxs)
Throw an exception if y is not strictly greater than low.
static constexpr double INFTY
Positive infinity.
Definition constants.hpp:44
fvar< T > log_sum_exp(const fvar< T > &x1, const fvar< T > &x2)
typename ref_type_if< true, T >::type ref_type_t
Definition ref_type.hpp:56
The lgamma implementation in stan-math is based on either the reentrant safe lgamma_r implementation ...
Template metaprogram to calculate whether a summand needs to be included in a proportional (log) prob...