1#ifndef STAN_MATH_PRIM_PROB_MULTI_NORMAL_LPDF_HPP
2#define STAN_MATH_PRIM_PROB_MULTI_NORMAL_LPDF_HPP
24template <
bool propto,
typename T_y,
typename T_loc,
typename T_covar,
25 require_any_not_vector_vt<is_stan_scalar, T_y, T_loc>* =
nullptr,
27 T_y, T_loc, T_covar>* =
nullptr>
29 const T_y& y,
const T_loc& mu,
const T_covar& Sigma) {
33 using matrix_partials_t
34 = Eigen::Matrix<T_partials_return, Eigen::Dynamic, Eigen::Dynamic>;
35 using vector_partials_t = Eigen::Matrix<T_partials_return, Eigen::Dynamic, 1>;
40 static const char* function =
"multi_normal_lpdf";
46 if (number_of_y == 0 || number_of_mu == 0) {
52 T_Sigma_ref Sigma_ref = Sigma;
56 const int K = Sigma.rows();
58 int size_y = y_vec[0].size();
59 int size_mu = mu_vec[0].size();
62 for (
size_t i = 1, size_mvt_y =
size_mvt(y); i < size_mvt_y; i++) {
64 "Size of one of the vectors of "
65 "the random variable",
67 "Size of the first vector of the "
72 for (
size_t i = 1, size_mvt_mu =
size_mvt(mu); i < size_mvt_mu; i++) {
74 "Size of one of the vectors of "
75 "the location variable",
77 "Size of the first vector of the "
83 "size of location parameter", size_mu);
85 "rows of covariance parameter", Sigma.rows());
87 "columns of covariance parameter", Sigma.cols());
89 for (
size_t i = 0; i < size_vec; i++) {
106 T_partials_return logp(0);
113 vector_partials_t half(size_vec);
114 vector_partials_t y_val_minus_mu_val(size_vec);
116 T_partials_return sum_lp_vec(0.0);
117 for (
size_t i = 0; i < size_vec; i++) {
120 y_val_minus_mu_val =
eval(y_val - mu_val);
123 sum_lp_vec +=
dot_product(y_val_minus_mu_val, half);
125 if constexpr (is_autodiff_v<T_y>) {
126 partials_vec<0>(ops_partials)[i] += -half;
128 if constexpr (is_autodiff_v<T_loc>) {
129 partials_vec<1>(ops_partials)[i] += half;
131 if constexpr (is_autodiff_v<T_covar_elem>) {
132 partials_vec<2>(ops_partials)[i] += 0.5 * half * half.transpose();
136 logp += -0.5 * sum_lp_vec;
140 if constexpr (is_constant_v<T_covar_elem>) {
145 matrix_partials_t inv_Sigma
150 partials<2>(ops_partials) += -0.5 * size_vec * inv_Sigma;
154 return ops_partials.build(logp);
157template <
bool propto,
typename T_y,
typename T_loc,
typename T_covar,
160 T_y, T_loc, T_covar>* =
nullptr>
162 const T_y& y,
const T_loc& mu,
const T_covar& Sigma) {
166 using matrix_partials_t
167 = Eigen::Matrix<T_partials_return, Eigen::Dynamic, Eigen::Dynamic>;
168 using vector_partials_t = Eigen::Matrix<T_partials_return, Eigen::Dynamic, 1>;
173 static const char* function =
"multi_normal_lpdf";
177 T_mu_ref mu_ref = mu;
178 T_Sigma_ref Sigma_ref = Sigma;
183 const int size_y = y_ref.size();
184 const int size_mu = mu_ref.size();
185 const unsigned int K = Sigma.rows();
191 "size of location parameter", size_mu);
193 "rows of covariance parameter", Sigma.rows());
195 "columns of covariance parameter", Sigma.cols());
209 T_partials_return logp(0);
211 if constexpr (include_summand<propto>::value) {
215 if constexpr (include_summand<propto, T_y, T_loc, T_covar_elem>::value) {
216 vector_partials_t half(size_y);
217 vector_partials_t y_val_minus_mu_val =
eval(y_val - mu_val);
221 if constexpr (is_constant_v<T_covar_elem>) {
224 if constexpr (include_summand<propto>::value) {
228 matrix_partials_t inv_Sigma
231 half.noalias() = inv_Sigma * y_val_minus_mu_val;
235 edge<2>(ops_partials).partials_
236 += 0.5 * (half * half.transpose() - inv_Sigma);
239 logp += -0.5 *
dot_product(y_val_minus_mu_val, half);
241 if constexpr (is_autodiff_v<T_y>) {
242 partials<0>(ops_partials) += -half;
244 if constexpr (is_autodiff_v<T_loc>) {
245 partials<1>(ops_partials) += half;
249 return ops_partials.build(logp);
252template <
typename T_y,
typename T_loc,
typename T_covar>
254 const T_y& y,
const T_loc& mu,
const T_covar& Sigma) {
255 return multi_normal_lpdf<false>(y, mu, Sigma);
This class provides a low-cost wrapper for situations where you either need an Eigen Vector or RowVec...
void check_symmetric(const char *function, const char *name, const matrix_cl< T > &y)
Check if the matrix_cl is symmetric.
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.
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.
value_type_t< T > log_determinant_ldlt(LDLT_factor< T > &A)
Returns log(abs(det(A))) given a LDLT_factor of A.
auto make_ldlt_factor(const T &A)
Make an LDLT_factor with matrix type plain_type_t<T>
return_type_t< T_y, T_loc, T_covar > multi_normal_lpdf(const T_y &y, const T_loc &mu, const T_covar &Sigma)
void check_consistent_sizes_mvt(const char *)
Trivial no input case, this function is a no-op.
T eval(T &&arg)
Inputs which have a plain_type equal to the own time are forwarded unmodified (for Eigen expressions ...
T value_of(const fvar< T > &v)
Return the value of the specified variable.
const double NEG_LOG_SQRT_TWO_PI
The value of minus the natural logarithm of the square root of , .
int64_t max_size_mvt(const T1 &x1, const Ts &... xs)
Calculate the size of the largest multivariate input.
Eigen::Matrix< value_type_t< EigMat >, Eigen::Dynamic, EigMat::ColsAtCompileTime > mdivide_left_ldlt(LDLT_factor< T > &A, const EigMat &b)
Returns the solution of the system Ax=b given an LDLT_factor of A.
void check_finite(const char *function, const char *name, const T_y &y)
Return true if all values in y are finite.
void check_ldlt_factor(const char *function, const char *name, LDLT_factor< T > &A)
Raise domain error if the specified LDLT factor is invalid.
void check_not_nan(const char *function, const char *name, const T_y &y)
Check if y is not NaN.
void check_positive(const char *function, const char *name, const T_y &y)
Check if y is positive.
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 dot_product(const T_a &a, const T_b &b)
Returns the dot product of the specified vectors.
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 ...
Template metaprogram to calculate whether a summand needs to be included in a proportional (log) prob...