1#ifndef STAN_MATH_PRIM_PROB_MULTI_NORMAL_CHOLESKY_LPDF_HPP
2#define STAN_MATH_PRIM_PROB_MULTI_NORMAL_CHOLESKY_LPDF_HPP
44template <
bool propto,
typename T_y,
typename T_loc,
typename T_covar,
45 require_any_not_vector_vt<is_stan_scalar, T_y, T_loc>* =
nullptr,
47 T_y, T_loc, T_covar>* =
nullptr>
49 const T_y& y,
const T_loc& mu,
const T_covar& L) {
50 static constexpr const char* function =
"multi_normal_cholesky_lpdf";
54 using matrix_partials_t
55 = Eigen::Matrix<T_partials_return, Eigen::Dynamic, Eigen::Dynamic>;
63 if (number_of_y == 0 || number_of_mu == 0) {
74 const int size_y = y_vec[0].size();
75 const int size_mu = mu_vec[0].size();
78 for (
size_t i = 1, size_mvt_y =
size_mvt(y); i < size_mvt_y; i++) {
80 "Size of one of the vectors of "
81 "the random variable",
83 "Size of the first vector of the "
88 for (
size_t i = 1, size_mvt_mu =
size_mvt(mu); i < size_mvt_mu; i++) {
90 "Size of one of the vectors of "
91 "the location variable",
93 "Size of the first vector of the "
99 "size of location parameter", size_mu);
101 "rows of covariance parameter", L.rows());
103 "columns of covariance parameter", L.cols());
105 for (
size_t i = 0; i < size_vec; i++) {
106 check_finite(function,
"Location parameter", mu_vec[i]);
118 T_partials_return logp(0);
124 Eigen::Matrix<T_partials_return, Eigen::Dynamic, Eigen::Dynamic>
125 y_val_minus_mu_val(size_y, size_vec);
127 for (
size_t i = 0; i < size_vec; i++) {
130 y_val_minus_mu_val.col(i) = y_val - mu_val;
133 matrix_partials_t half;
134 matrix_partials_t scaled_diff;
139 matrix_partials_t L_val =
value_of(L_ref);
141 half = mdivide_left_tri<Eigen::Lower>(L_val, y_val_minus_mu_val)
144 scaled_diff = mdivide_right_tri<Eigen::Lower>(half, L_val).transpose();
147 logp -=
sum(
log(L_val.diagonal())) * size_vec;
150 matrix_partials_t inv_L_val
151 = mdivide_left_tri<Eigen::Lower>(
value_of(L_ref));
153 half = (inv_L_val.template triangularView<Eigen::Lower>()
154 * y_val_minus_mu_val)
157 scaled_diff = (half * inv_L_val.template triangularView<Eigen::Lower>())
160 logp +=
sum(
log(inv_L_val.diagonal())) * size_vec;
161 partials<2>(ops_partials) -= size_vec * inv_L_val.transpose();
163 for (
size_t i = 0; i < size_vec; i++) {
164 partials_vec<2>(ops_partials)[i] += scaled_diff.col(i) * half.row(i);
170 for (
size_t i = 0; i < size_vec; i++) {
172 partials_vec<0>(ops_partials)[i] -= scaled_diff.col(i);
175 partials_vec<1>(ops_partials)[i] += scaled_diff.col(i);
180 return ops_partials.build(logp);
203template <
bool propto,
typename T_y,
typename T_loc,
typename T_covar,
206 T_y, T_loc, T_covar>* =
nullptr>
208 const T_y& y,
const T_loc& mu,
const T_covar& L) {
209 static constexpr const char* function =
"multi_normal_cholesky_lpdf";
213 using matrix_partials_t
214 = Eigen::Matrix<T_partials_return, Eigen::Dynamic, Eigen::Dynamic>;
215 using vector_partials_t = Eigen::Matrix<T_partials_return, Eigen::Dynamic, 1>;
216 using row_vector_partials_t
217 = Eigen::Matrix<T_partials_return, 1, Eigen::Dynamic>;
223 T_mu_ref mu_ref = mu;
228 const int size_y = y_ref.size();
229 const int size_mu = mu_ref.size();
232 "size of location parameter", size_mu);
234 "rows of covariance parameter", L.rows());
236 "columns of covariance parameter", L.cols());
247 T_partials_return logp(0);
248 if (include_summand<propto>::value) {
252 if (include_summand<propto, T_y, T_loc, T_covar_elem>::value) {
253 row_vector_partials_t half;
254 vector_partials_t scaled_diff;
255 vector_partials_t y_val_minus_mu_val = y_val - mu_val;
259 if (is_constant<T_covar_elem>::value) {
260 matrix_partials_t L_val =
value_of(L_ref);
262 half = mdivide_left_tri<Eigen::Lower>(L_val, y_val_minus_mu_val)
265 scaled_diff = mdivide_right_tri<Eigen::Lower>(half, L_val).transpose();
267 if (include_summand<propto>::value) {
268 logp -=
sum(
log(L_val.diagonal()));
271 matrix_partials_t inv_L_val
272 = mdivide_left_tri<Eigen::Lower>(
value_of(L_ref));
274 half = (inv_L_val.template triangularView<Eigen::Lower>()
275 * y_val_minus_mu_val.template cast<T_partials_return>())
278 scaled_diff = (half * inv_L_val.template triangularView<Eigen::Lower>())
281 logp +=
sum(
log(inv_L_val.diagonal()));
282 edge<2>(ops_partials).partials_
283 += scaled_diff * half - inv_L_val.transpose();
288 if (!is_constant_all<T_y>::value) {
289 partials<0>(ops_partials) -= scaled_diff;
291 if (!is_constant_all<T_loc>::value) {
292 partials<1>(ops_partials) += scaled_diff;
296 return ops_partials.build(logp);
299template <
typename T_y,
typename T_loc,
typename T_covar>
301 const T_y& y,
const T_loc& mu,
const T_covar& L) {
302 return multi_normal_cholesky_lpdf<false>(y, mu, L);
This class provides a low-cost wrapper for situations where you either need an Eigen Vector or RowVec...
require_all_not_t< is_nonscalar_prim_or_rev_kernel_expression< std::decay_t< Types > >... > require_all_not_nonscalar_prim_or_rev_kernel_expression_t
Require none of the types satisfy is_nonscalar_prim_or_rev_kernel_expression.
auto transpose(Arg &&a)
Transposes a kernel generator expression.
return_type_t< T_y_cl, T_loc_cl, T_covar_cl > multi_normal_cholesky_lpdf(const T_y_cl &y, const T_loc_cl &mu, const T_covar_cl &L)
The log of the multivariate normal density for the given y, mu, and a Cholesky factor L of the varian...
int64_t size_mvt(const ScalarT &)
Provides the size of a multivariate argument.
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>>.
require_all_t< container_type_check_base< is_vector, value_type_t, TypeCheck, Check >... > require_all_vector_vt
Require all of the types satisfy is_vector.
void check_consistent_sizes_mvt(const char *)
Trivial no input case, this function is a no-op.
T value_of(const fvar< T > &v)
Return the value of the specified variable.
fvar< T > log(const fvar< T > &x)
const double NEG_LOG_SQRT_TWO_PI
The value of minus the natural logarithm of the square root of , .
auto columns_dot_self(const T &a)
Returns the dot product of each column of a matrix with itself.
int64_t max_size_mvt(const T1 &x1, const Ts &... xs)
Calculate the size of the largest multivariate input.
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 sum(const std::vector< T > &m)
Return the sum of the entries of the specified standard vector.
void check_cholesky_factor(const char *function, const char *name, const Mat &y)
Throw an exception if the specified matrix is not a valid Cholesky factor.
auto dot_self(const T &a)
Returns squared norm of a vector or matrix.
void check_size_match(const char *function, const char *name_i, T_size1 i, const char *name_j, T_size2 j)
Check if the provided sizes match.
auto as_value_column_vector_or_scalar(T &&a)
Extract values from input argument and transform to a column vector.
auto make_partials_propagator(Ops &&... ops)
Construct an partials_propagator.
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 ...
Metaprogramming struct to detect whether a given type is constant in the mathematical sense (not the ...
Extends std::true_type when instantiated with zero or more template parameters, all of which extend t...
Template metaprogram to calculate whether a summand needs to be included in a proportional (log) prob...