1#ifndef STAN_MATH_PRIM_PROB_ORDERED_LOGISTIC_GLM_LPMF_HPP
2#define STAN_MATH_PRIM_PROB_ORDERED_LOGISTIC_GLM_LPMF_HPP
48template <
bool propto,
typename T_y,
typename T_x,
typename T_beta,
49 typename T_cuts, require_matrix_t<T_x>* =
nullptr,
50 require_all_col_vector_t<T_beta, T_cuts>* =
nullptr>
52 const T_y& y,
const T_x& x,
const T_beta&
beta,
const T_cuts& cuts) {
56 using Eigen::VectorXd;
59 constexpr int T_x_rows = T_x::RowsAtCompileTime;
63 typedef typename std::conditional_t<
64 T_x_rows == 1, T_xbeta_partials,
65 Eigen::Matrix<T_xbeta_partials, Eigen::Dynamic, 1>>
73 const size_t N_attributes = x.cols();
76 static constexpr const char* function =
"ordered_logistic_glm_lpmf";
81 T_cuts_ref cuts_ref = cuts;
82 const auto& cuts_val =
value_of(cuts_ref);
84 check_bounded(function,
"Vector of dependent variables", y_ref, 1, N_classes);
88 check_finite(function,
"Final cut-point", cuts_val_vec[N_classes - 2]);
90 check_finite(function,
"First cut-point", cuts_val_vec[0]);
101 T_beta_ref beta_ref =
beta;
103 const auto& x_val = to_ref_if<is_autodiff_v<T_beta>>(
value_of(x_ref));
104 const auto& beta_val =
value_of(beta_ref);
106 const auto& beta_val_vec
110 Array<T_cuts_partials, Dynamic, 1> cuts_y1(N_instances), cuts_y2(N_instances);
111 for (
int i = 0; i < N_instances; i++) {
113 if (c != N_classes) {
114 cuts_y1.coeffRef(i) = cuts_val_vec.coeff(c - 1);
116 cuts_y1.coeffRef(i) = INFINITY;
119 cuts_y2.coeffRef(i) = cuts_val_vec.coeff(c - 2);
121 cuts_y2.coeffRef(i) = -INFINITY;
125 T_location location =
multiply(x_val, beta_val_vec);
128 check_finite(function,
"Matrix of independent variables", x);
131 Array<T_partials_return, Dynamic, 1> cut2
133 Array<T_partials_return, Dynamic, 1> cut1
137 auto m_log_1p_exp_cut1
138 = (cut1 > 0.0).
select(-cut1, 0) - (-cut1.abs()).
exp().log1p();
139 auto m_log_1p_exp_m_cut2
140 = (cut2 <= 0.0).
select(cut2, 0) - (-cut2.abs()).
exp().log1p();
142 T_partials_return logp(0);
144 Eigen::Map<const Eigen::Matrix<int, Eigen::Dynamic, 1>> y_vec(y_seq.data(),
146 logp = y_vec.cwiseEqual(1)
147 .select(m_log_1p_exp_cut1,
148 y_vec.cwiseEqual(N_classes).select(
150 m_log_1p_exp_m_cut2 +
log1m_exp(cut1 - cut2).array()
151 + m_log_1p_exp_cut1))
155 logp = m_log_1p_exp_cut1.sum();
156 }
else if (y_seq[0] == N_classes) {
157 logp = m_log_1p_exp_m_cut2.sum();
159 logp = (m_log_1p_exp_m_cut2 +
log1m_exp(cut1 - cut2).array()
166 if constexpr (is_any_autodiff_v<T_x, T_beta, T_cuts>) {
167 Array<T_partials_return, Dynamic, 1> exp_m_abs_cut1 = (-cut1.abs()).
exp();
168 Array<T_partials_return, Dynamic, 1> exp_m_abs_cut2 = (-cut2.abs()).
exp();
169 Array<T_partials_return, Dynamic, 1> exp_cuts_diff =
exp(cuts_y2 - cuts_y1);
170 Array<T_partials_return, Dynamic, 1> inv_logit_neg_cut2 = (cut2 > 0).
select(
171 exp_m_abs_cut2 / (1 + exp_m_abs_cut2), 1 / (1 + exp_m_abs_cut2));
172 Array<T_partials_return, Dynamic, 1> inv_logit_neg_cut1 = (cut1 > 0).
select(
173 exp_m_abs_cut1 / (1 + exp_m_abs_cut1), 1 / (1 + exp_m_abs_cut1));
174 Array<T_partials_return, Dynamic, 1> d1
175 = inv_logit_neg_cut2 - exp_cuts_diff / (exp_cuts_diff - 1);
176 Array<T_partials_return, Dynamic, 1> d2
177 = 1 / (1 - exp_cuts_diff) - inv_logit_neg_cut1;
178 if constexpr (is_any_autodiff_v<T_x, T_beta>) {
179 Matrix<T_partials_return, 1, Dynamic> location_derivative = d1 - d2;
180 if constexpr (is_autodiff_v<T_x>) {
181 if constexpr (T_x_rows == 1) {
182 edge<0>(ops_partials).partials_
183 = beta_val_vec * location_derivative.sum();
185 edge<0>(ops_partials).partials_
186 = (beta_val_vec * location_derivative).
transpose();
189 if constexpr (is_autodiff_v<T_beta>) {
190 if constexpr (T_x_rows == 1) {
191 edge<1>(ops_partials).partials_
192 = (location_derivative * x_val.replicate(N_instances, 1))
194 }
else if constexpr (T_x::ColsAtCompileTime == 1) {
195 edge<1>(ops_partials).partials_[0]
198 edge<1>(ops_partials).partials_
199 =
multiply(location_derivative, x_val).transpose();
203 if constexpr (is_autodiff_v<T_cuts>) {
204 for (
int i = 0; i < N_instances; i++) {
206 if (c != N_classes) {
207 partials<2>(ops_partials)[c - 1] += d2.coeff(i);
210 partials<2>(ops_partials)[c - 2] -= d1.coeff(i);
215 return ops_partials.build(logp);
218template <
typename T_y,
typename T_x,
typename T_beta,
typename T_cuts>
220 const T_y& y,
const T_x& x,
const T_beta&
beta,
const T_cuts& cuts) {
221 return ordered_logistic_glm_lpmf<false>(y, x,
beta, cuts);
scalar_seq_view provides a uniform sequence-like wrapper around either a scalar or a sequence of scal...
isfinite_< as_operation_cl_t< T > > isfinite(T &&a)
select_< as_operation_cl_t< T_condition >, as_operation_cl_t< T_then >, as_operation_cl_t< T_else > > select(T_condition &&condition, T_then &&then, T_else &&els)
Selection operation on kernel generator expressions.
auto as_column_vector_or_scalar(T &&a)
as_column_vector_or_scalar of a kernel generator expression.
auto transpose(Arg &&a)
Transposes a kernel generator expression.
return_type_t< T_x, T_beta, T_cuts > ordered_logistic_glm_lpmf(const T_y &y, const T_x &x, const T_beta &beta, const T_cuts &cuts)
Returns the log PMF of the ordinal regression Generalized Linear Model (GLM).
typename return_type< Ts... >::type return_type_t
Convenience type for the return type of the specified template parameters.
int64_t size(const T &m)
Returns the size (number of the elements) of a matrix_cl or var_value<matrix_cl<T>>.
T as_array_or_scalar(T &&v)
Returns specified input value.
auto multiply(Mat1 &&m1, Mat2 &&m2)
Return the product of the specified matrices.
bool size_zero(const T &x)
Returns 1 if input is of length 0, returns 0 otherwise.
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.
fvar< T > log1m_exp(const fvar< T > &x)
Return the natural logarithm of one minus the exponentiation of the specified argument.
void check_consistent_size(const char *function, const char *name, const T &x, size_t expected_size)
Check if x is consistent with size expected_size.
T value_of(const fvar< T > &v)
Return the value of the specified variable.
void check_finite(const char *function, const char *name, const T_y &y)
Return true if all values in y are finite.
auto sum(const std::vector< T > &m)
Return the sum of the entries of the specified standard vector.
ref_type_t< T && > to_ref(T &&a)
This evaluates expensive Eigen expressions.
void check_ordered(const char *function, const char *name, const T_y &y)
Throw an exception if the specified vector is not sorted into strictly increasing order.
auto dot_product(const T_a &a, const T_b &b)
Returns the dot product of the specified vectors.
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.
auto make_partials_propagator(Ops &&... ops)
Construct an partials_propagator.
fvar< T > exp(const fvar< T > &x)
typename ref_type_if< is_autodiff_v< T >, T >::type ref_type_if_not_constant_t
typename ref_type_if< true, T >::type ref_type_t
typename partials_return_type< Args... >::type partials_return_t
The lgamma implementation in stan-math is based on either the reentrant safe lgamma_r implementation ...
If the input type T is either an eigen matrix with 1 column or 1 row at compile time or a standard ve...
Template metaprogram to calculate whether a summand needs to be included in a proportional (log) prob...