1 #ifndef __STAN__PROB__DISTRIBUTIONS__MULTIVARIATE__CONTINUOUS__MULTI_NORMAL_HPP__
2 #define __STAN__PROB__DISTRIBUTIONS__MULTIVARIATE__CONTINUOUS__MULTI_NORMAL_HPP__
4 #include <boost/random/normal_distribution.hpp>
5 #include <boost/random/variate_generator.hpp>
45 template <
bool propto,
46 typename T_y,
typename T_loc,
typename T_covar,
48 typename boost::math::tools::promote_args<T_y,T_loc,T_covar>::type
50 const Eigen::Matrix<T_loc,Eigen::Dynamic,1>& mu,
51 const Eigen::Matrix<T_covar,Eigen::Dynamic,Eigen::Dynamic>& L,
53 static const char*
function =
"stan::prob::multi_normal_cholesky_log(%1%)";
65 using boost::math::tools::promote_args;
67 typename promote_args<T_y,T_loc,T_covar>::type lp(0.0);
70 y.size(),
"Size of random variable",
71 mu.size(),
"size of location parameter",
75 y.size(),
"Size of random variable",
76 L.rows(),
"rows of covariance parameter",
80 y.size(),
"Size of random variable",
81 L.cols(),
"columns of covariance parameter",
84 if (!
check_finite(
function, mu,
"Location parameter", &lp, Policy()))
86 if (!
check_not_nan(
function, y,
"Random variable", &lp, Policy()))
93 lp += NEG_LOG_SQRT_TWO_PI * y.rows();
96 Eigen::Matrix<T_covar,Eigen::Dynamic,1> L_log_diag = L.diagonal().array().log().matrix();
97 lp -=
sum(L_log_diag);
101 Eigen::Matrix<
typename
102 boost::math::tools::promote_args<T_y,T_loc>::type,
103 Eigen::Dynamic, 1> y_minus_mu(y.size());
104 for (
int i = 0; i < y.size(); i++)
105 y_minus_mu(i) = y(i)-mu(i);
106 Eigen::Matrix<
typename
107 boost::math::tools::promote_args<T_covar,T_loc,T_y>::type,
120 template <
bool propto,
121 typename T_y,
typename T_loc,
typename T_covar>
123 typename boost::math::tools::promote_args<T_y,T_loc,T_covar>::type
125 const Eigen::Matrix<T_loc,Eigen::Dynamic,1>& mu,
126 const Eigen::Matrix<T_covar,Eigen::Dynamic,Eigen::Dynamic>& L) {
127 return multi_normal_cholesky_log<propto>(y,mu,L,
131 template <
typename T_y,
typename T_loc,
typename T_covar,
134 typename boost::math::tools::promote_args<T_y,T_loc,T_covar>::type
136 const Eigen::Matrix<T_loc,Eigen::Dynamic,1>& mu,
137 const Eigen::Matrix<T_covar,Eigen::Dynamic,Eigen::Dynamic>& L,
139 return multi_normal_cholesky_log<false>(y,mu,L,Policy());
142 template <
typename T_y,
typename T_loc,
typename T_covar>
144 typename boost::math::tools::promote_args<T_y,T_loc,T_covar>::type
146 const Eigen::Matrix<T_loc,Eigen::Dynamic,1>& mu,
147 const Eigen::Matrix<T_covar,Eigen::Dynamic,Eigen::Dynamic>& L) {
148 return multi_normal_cholesky_log<false>(y,mu,L,
154 template <
bool propto,
155 typename T_y,
typename T_loc,
typename T_covar,
157 typename boost::math::tools::promote_args<T_y,T_loc,T_covar>::type
159 const Eigen::Matrix<T_loc,Eigen::Dynamic,1>& mu,
160 const Eigen::Matrix<T_covar,Eigen::Dynamic,Eigen::Dynamic>& L,
162 static const char*
function =
"stan::prob::multi_normal_cholesky_log(%1%)";
175 using boost::math::tools::promote_args;
177 typename promote_args<T_y,T_loc,T_covar>::type lp(0.0);
180 y.cols(),
"Columns of random variable",
181 mu.rows(),
"rows of location parameter",
185 y.cols(),
"Columns of random variable",
186 L.rows(),
"rows of covariance parameter",
190 y.cols(),
"Columns of random variable",
191 L.cols(),
"columns of covariance parameter",
194 if (!
check_finite(
function, mu,
"Location parameter", &lp, Policy()))
196 if (!
check_not_nan(
function, y,
"Random variable", &lp, Policy()))
203 lp += NEG_LOG_SQRT_TWO_PI * y.cols() * y.rows();
206 Eigen::Matrix<T_covar,Eigen::Dynamic,1> L_log_diag = L.diagonal().array().log().matrix();
207 lp -=
sum(L_log_diag) * y.rows();
211 Eigen::Matrix<T_loc, Eigen::Dynamic, Eigen::Dynamic> MU(y.rows(),y.cols());
215 Eigen::Matrix<
typename
216 boost::math::tools::promote_args<T_loc,T_y>::type,
217 Eigen::Dynamic,Eigen::Dynamic>
218 y_minus_MU(y.rows(), y.cols());
219 for (
int i = 0; i < y.size(); i++)
220 y_minus_MU(i) = y(i)-MU(i);
222 Eigen::Matrix<
typename
223 boost::math::tools::promote_args<T_loc,T_y>::type,
224 Eigen::Dynamic,Eigen::Dynamic>
225 z(y_minus_MU.transpose());
233 Eigen::Matrix<
typename
234 boost::math::tools::promote_args<T_covar,T_loc,T_y>::type,
235 Eigen::Dynamic,Eigen::Dynamic>
243 template <
bool propto,
244 typename T_y,
typename T_loc,
typename T_covar>
246 typename boost::math::tools::promote_args<T_y,T_loc,T_covar>::type
248 const Eigen::Matrix<T_loc,Eigen::Dynamic,1>& mu,
249 const Eigen::Matrix<T_covar,Eigen::Dynamic,Eigen::Dynamic>& L) {
250 return multi_normal_cholesky_log<propto>(y,mu,L,
254 template <
typename T_y,
typename T_loc,
typename T_covar,
257 typename boost::math::tools::promote_args<T_y,T_loc,T_covar>::type
259 const Eigen::Matrix<T_loc,Eigen::Dynamic,1>& mu,
260 const Eigen::Matrix<T_covar,Eigen::Dynamic,Eigen::Dynamic>& L,
262 return multi_normal_cholesky_log<false>(y,mu,L,Policy());
265 template <
typename T_y,
typename T_loc,
typename T_covar>
267 typename boost::math::tools::promote_args<T_y,T_loc,T_covar>::type
269 const Eigen::Matrix<T_loc,Eigen::Dynamic,1>& mu,
270 const Eigen::Matrix<T_covar,Eigen::Dynamic,Eigen::Dynamic>& L) {
271 return multi_normal_cholesky_log<false>(y,mu,L,
294 template <
bool propto,
295 typename T_y,
typename T_loc,
typename T_covar,
297 typename boost::math::tools::promote_args<T_y,T_loc,T_covar>::type
299 const Eigen::Matrix<T_loc,Eigen::Dynamic,1>& mu,
300 const Eigen::Matrix<T_covar,Eigen::Dynamic,Eigen::Dynamic>& Sigma,
302 static const char*
function =
"stan::prob::multi_normal_log(%1%)";
303 typename boost::math::tools::promote_args<T_y,T_loc,T_covar>::type lp(0.0);
316 Sigma.rows(),
"Rows of covariance parameter",
317 Sigma.cols(),
"columns of covariance parameter",
320 if (!
check_positive(
function, Sigma.rows(),
"Covariance matrix rows", &lp, Policy()))
322 if (!
check_symmetric(
function, Sigma,
"Covariance matrix", &lp, Policy()))
327 y.size(),
"Size of random variable",
328 mu.size(),
"size of location parameter",
332 y.size(),
"Size of random variable",
333 Sigma.rows(),
"rows of covariance parameter",
337 y.size(),
"Size of random variable",
338 Sigma.cols(),
"columns of covariance parameter",
341 if (!
check_finite(
function, mu,
"Location parameter", &lp, Policy()))
343 if (!
check_not_nan(
function, y,
"Random variable", &lp, Policy()))
350 lp += NEG_LOG_SQRT_TWO_PI * y.rows();
357 Eigen::Matrix<
typename
358 boost::math::tools::promote_args<T_y,T_loc>::type,
359 Eigen::Dynamic, 1> y_minus_mu(y.size());
360 for (
int i = 0; i < y.size(); i++)
361 y_minus_mu(i) = y(i)-mu(i);
362 Eigen::Matrix<
typename
363 boost::math::tools::promote_args<T_covar,T_loc,T_y>::type,
365 lp -= 0.5 *
dot_product(y_minus_mu,Sinv_y_minus_mu);
370 template <
bool propto,
371 typename T_y,
typename T_loc,
typename T_covar>
373 typename boost::math::tools::promote_args<T_y,T_loc,T_covar>::type
375 const Eigen::Matrix<T_loc,Eigen::Dynamic,1>& mu,
376 const Eigen::Matrix<T_covar,Eigen::Dynamic,Eigen::Dynamic>& Sigma) {
381 template <
typename T_y,
typename T_loc,
typename T_covar,
384 typename boost::math::tools::promote_args<T_y,T_loc,T_covar>::type
386 const Eigen::Matrix<T_loc,Eigen::Dynamic,1>& mu,
387 const Eigen::Matrix<T_covar,Eigen::Dynamic,Eigen::Dynamic>& Sigma,
389 return multi_normal_log<false>(y,mu,Sigma,Policy());
393 template <
typename T_y,
typename T_loc,
typename T_covar>
395 typename boost::math::tools::promote_args<T_y,T_loc,T_covar>::type
397 const Eigen::Matrix<T_loc,Eigen::Dynamic,1>& mu,
398 const Eigen::Matrix<T_covar,Eigen::Dynamic,Eigen::Dynamic>& Sigma) {
405 template <
bool propto,
406 typename T_y,
typename T_loc,
typename T_covar,
408 typename boost::math::tools::promote_args<T_y,T_loc,T_covar>::type
410 const Eigen::Matrix<T_loc,Eigen::Dynamic,1>& mu,
411 const Eigen::Matrix<T_covar,Eigen::Dynamic,Eigen::Dynamic>& Sigma,
413 static const char*
function =
"stan::prob::multi_normal_log(%1%)";
414 typename boost::math::tools::promote_args<T_y,T_loc,T_covar>::type lp(0.0);
428 Sigma.rows(),
"Rows of covariance matrix",
429 Sigma.cols(),
"columns of covariance matrix",
432 if (!
check_positive(
function, Sigma.rows(),
"Covariance matrix rows", &lp, Policy()))
434 if (!
check_symmetric(
function, Sigma,
"Covariance matrix", &lp, Policy()))
439 y.cols(),
"Columns of random variable",
440 mu.rows(),
"rows of location parameter",
444 y.cols(),
"Columns of random variable",
445 Sigma.rows(),
"rows of covariance parameter",
449 y.cols(),
"Columns of random variable",
450 Sigma.cols(),
"columns of covariance parameter",
453 if (!
check_finite(
function, mu,
"Location parameter", &lp, Policy()))
455 if (!
check_not_nan(
function, y,
"Random variable", &lp, Policy()))
462 lp += NEG_LOG_SQRT_TWO_PI * y.cols() * y.rows();
469 Eigen::Matrix<T_loc, Eigen::Dynamic, Eigen::Dynamic> MU(y.rows(),y.cols());
473 Eigen::Matrix<
typename
474 boost::math::tools::promote_args<T_loc,T_y>::type,
475 Eigen::Dynamic,Eigen::Dynamic> y_minus_MU(y.rows(), y.cols());
477 for (
int i = 0; i < y.size(); i++)
478 y_minus_MU(i) = y(i)-MU(i);
480 Eigen::Matrix<
typename
481 boost::math::tools::promote_args<T_loc,T_y>::type,
482 Eigen::Dynamic,Eigen::Dynamic> z(y_minus_MU.transpose());
490 Eigen::Matrix<
typename
491 boost::math::tools::promote_args<T_covar,T_loc,T_y>::type,
499 template <
bool propto,
500 typename T_y,
typename T_loc,
typename T_covar>
502 typename boost::math::tools::promote_args<T_y,T_loc,T_covar>::type
504 const Eigen::Matrix<T_loc,Eigen::Dynamic,1>& mu,
505 const Eigen::Matrix<T_covar,Eigen::Dynamic,Eigen::Dynamic>& Sigma) {
510 template <
typename T_y,
typename T_loc,
typename T_covar,
513 typename boost::math::tools::promote_args<T_y,T_loc,T_covar>::type
515 const Eigen::Matrix<T_loc,Eigen::Dynamic,1>& mu,
516 const Eigen::Matrix<T_covar,Eigen::Dynamic,Eigen::Dynamic>& Sigma,
518 return multi_normal_log<false>(y,mu,Sigma,Policy());
521 template <
typename T_y,
typename T_loc,
typename T_covar>
523 typename boost::math::tools::promote_args<T_y,T_loc,T_covar>::type
525 const Eigen::Matrix<T_loc,Eigen::Dynamic,1>& mu,
526 const Eigen::Matrix<T_covar,Eigen::Dynamic,Eigen::Dynamic>& Sigma) {
530 template <
bool propto,
531 typename T_y,
typename T_loc,
typename T_covar,
533 typename boost::math::tools::promote_args<T_y,T_loc,T_covar>::type
535 const Eigen::Matrix<T_loc,Eigen::Dynamic,1>& mu,
536 const Eigen::Matrix<T_covar,Eigen::Dynamic,Eigen::Dynamic>& Sigma,
538 static const char*
function =
"stan::prob::multi_normal_prec_log(%1%)";
539 typename boost::math::tools::promote_args<T_y,T_loc,T_covar>::type lp(0.0);
553 Sigma.rows(),
"Rows of covariance parameter",
554 Sigma.cols(),
"columns of covariance parameter",
557 if (!
check_positive(
function, Sigma.rows(),
"Covariance matrix rows", &lp, Policy()))
559 if (!
check_symmetric(
function, Sigma,
"Covariance matrix", &lp, Policy()))
564 y.size(),
"Size of random variable",
565 mu.size(),
"size of location parameter",
569 y.size(),
"Size of random variable",
570 Sigma.rows(),
"rows of covariance parameter",
574 y.size(),
"Size of random variable",
575 Sigma.cols(),
"columns of covariance parameter",
578 if (!
check_finite(
function, mu,
"Location parameter", &lp, Policy()))
580 if (!
check_not_nan(
function, y,
"Random variable", &lp, Policy()))
587 lp += NEG_LOG_SQRT_TWO_PI * y.rows();
593 Eigen::Matrix<
typename
594 boost::math::tools::promote_args<T_y,T_loc>::type,
595 Eigen::Dynamic, 1> y_minus_mu(y.size());
596 for (
int i = 0; i < y.size(); i++)
597 y_minus_mu(i) = y(i)-mu(i);
598 Eigen::Matrix<
typename
599 boost::math::tools::promote_args<T_covar,T_loc,T_y>::type,
600 Eigen::Dynamic, 1> Sinv_y_minus_mu(
multiply(Sigma,y_minus_mu));
601 lp -= 0.5 *
dot_product(y_minus_mu,Sinv_y_minus_mu);
606 template <
bool propto,
607 typename T_y,
typename T_loc,
typename T_covar>
609 typename boost::math::tools::promote_args<T_y,T_loc,T_covar>::type
611 const Eigen::Matrix<T_loc,Eigen::Dynamic,1>& mu,
612 const Eigen::Matrix<T_covar,Eigen::Dynamic,Eigen::Dynamic>& Sigma) {
617 template <
typename T_y,
typename T_loc,
typename T_covar,
620 typename boost::math::tools::promote_args<T_y,T_loc,T_covar>::type
622 const Eigen::Matrix<T_loc,Eigen::Dynamic,1>& mu,
623 const Eigen::Matrix<T_covar,Eigen::Dynamic,Eigen::Dynamic>& Sigma,
625 return multi_normal_prec_log<false>(y,mu,Sigma,Policy());
629 template <
typename T_y,
typename T_loc,
typename T_covar>
631 typename boost::math::tools::promote_args<T_y,T_loc,T_covar>::type
633 const Eigen::Matrix<T_loc,Eigen::Dynamic,1>& mu,
634 const Eigen::Matrix<T_covar,Eigen::Dynamic,Eigen::Dynamic>& Sigma) {
641 template <
bool propto,
642 typename T_y,
typename T_loc,
typename T_covar,
644 typename boost::math::tools::promote_args<T_y,T_loc,T_covar>::type
646 const Eigen::Matrix<T_loc,Eigen::Dynamic,1>& mu,
647 const Eigen::Matrix<T_covar,Eigen::Dynamic,Eigen::Dynamic>& Sigma,
649 static const char*
function =
"stan::prob::multi_normal_prec_log(%1%)";
650 typename boost::math::tools::promote_args<T_y,T_loc,T_covar>::type lp(0.0);
664 Sigma.rows(),
"Rows of covariance matrix",
665 Sigma.cols(),
"columns of covariance matrix",
668 if (!
check_positive(
function, Sigma.rows(),
"Covariance matrix rows", &lp, Policy()))
670 if (!
check_symmetric(
function, Sigma,
"Covariance matrix", &lp, Policy()))
675 y.cols(),
"Columns of random variable",
676 mu.rows(),
"rows of location parameter",
680 y.cols(),
"Columns of random variable",
681 Sigma.rows(),
"rows of covariance parameter",
685 y.cols(),
"Columns of random variable",
686 Sigma.cols(),
"columns of covariance parameter",
689 if (!
check_finite(
function, mu,
"Location parameter", &lp, Policy()))
691 if (!
check_not_nan(
function, y,
"Random variable", &lp, Policy()))
698 lp += NEG_LOG_SQRT_TWO_PI * y.cols() * y.rows();
705 Eigen::Matrix<T_loc, Eigen::Dynamic, Eigen::Dynamic> MU(y.rows(),y.cols());
709 Eigen::Matrix<
typename
710 boost::math::tools::promote_args<T_loc,T_y>::type,
711 Eigen::Dynamic,Eigen::Dynamic> y_minus_MU(y.rows(), y.cols());
713 for (
int i = 0; i < y.size(); i++)
714 y_minus_MU(i) = y(i)-MU(i);
716 Eigen::Matrix<
typename
717 boost::math::tools::promote_args<T_loc,T_y>::type,
718 Eigen::Dynamic,Eigen::Dynamic> z(y_minus_MU.transpose());
726 Eigen::Matrix<
typename
727 boost::math::tools::promote_args<T_covar,T_loc,T_y>::type,
728 Eigen::Dynamic,Eigen::Dynamic> Sinv_y_minus_mu(
multiply(Sigma,z));
735 template <
bool propto,
736 typename T_y,
typename T_loc,
typename T_covar>
738 typename boost::math::tools::promote_args<T_y,T_loc,T_covar>::type
740 const Eigen::Matrix<T_loc,Eigen::Dynamic,1>& mu,
741 const Eigen::Matrix<T_covar,Eigen::Dynamic,Eigen::Dynamic>& Sigma) {
746 template <
typename T_y,
typename T_loc,
typename T_covar,
749 typename boost::math::tools::promote_args<T_y,T_loc,T_covar>::type
751 const Eigen::Matrix<T_loc,Eigen::Dynamic,1>& mu,
752 const Eigen::Matrix<T_covar,Eigen::Dynamic,Eigen::Dynamic>& Sigma,
754 return multi_normal_prec_log<false>(y,mu,Sigma,Policy());
757 template <
typename T_y,
typename T_loc,
typename T_covar>
759 typename boost::math::tools::promote_args<T_y,T_loc,T_covar>::type
761 const Eigen::Matrix<T_loc,Eigen::Dynamic,1>& mu,
762 const Eigen::Matrix<T_covar,Eigen::Dynamic,Eigen::Dynamic>& Sigma) {
767 inline Eigen::VectorXd
769 const Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic>& S,
771 using boost::variate_generator;
772 using boost::normal_distribution;
773 variate_generator<RNG&, normal_distribution<> >
774 std_normal_rng(rng, normal_distribution<>(0,1));
776 Eigen::VectorXd z(S.cols());
777 for(
int i = 0; i < S.cols(); i++)
778 z(i) = std_normal_rng();
780 return mu + S.llt().matrixL() * z;