gaussian_dlm_obs_lpdf.hpp
Go to the documentation of this file.
#ifndef STAN_MATH_PRIM_MAT_PROB_GAUSSIAN_DLM_OBS_LPDF_HPP
#define STAN_MATH_PRIM_MAT_PROB_GAUSSIAN_DLM_OBS_LPDF_HPP
#include <boost/random/normal_distribution.hpp>
#include <boost/random/variate_generator.hpp>
#include <stan/math/prim/mat/err/check_cov_matrix.hpp>
#include <stan/math/prim/scal/err/check_size_match.hpp>
#include <stan/math/prim/mat/err/check_spsd_matrix.hpp>
#include <stan/math/prim/scal/err/check_finite.hpp>
#include <stan/math/prim/scal/err/check_nonnegative.hpp>
#include <stan/math/prim/scal/err/check_not_nan.hpp>
#include <stan/math/prim/mat/fun/add.hpp>
#include <stan/math/prim/mat/fun/dot_product.hpp>
#include <stan/math/prim/mat/fun/inverse_spd.hpp>
#include <stan/math/prim/mat/fun/log.hpp>
#include <stan/math/prim/mat/fun/log_determinant_spd.hpp>
#include <stan/math/prim/mat/fun/multiply.hpp>
#include <stan/math/prim/mat/fun/quad_form.hpp>
#include <stan/math/prim/mat/fun/quad_form_sym.hpp>
#include <stan/math/prim/mat/fun/subtract.hpp>
#include <stan/math/prim/mat/fun/tcrossprod.hpp>
#include <stan/math/prim/mat/fun/trace_quad_form.hpp>
#include <stan/math/prim/mat/fun/transpose.hpp>
#include <stan/math/prim/scal/fun/constants.hpp>
#include <stan/math/prim/scal/meta/include_summand.hpp>
#include <stan/math/prim/scal/meta/return_type.hpp>
/*
TODO: time-varying system matrices
TODO: use sequential processing even for non-diagonal obs
covariance.
TODO: add constant terms in observation.
*/
namespace stan {
namespace math {
template <bool propto,
typename T_y,
typename T_F, typename T_G,
typename T_V, typename T_W,
typename T_m0, typename T_C0
>
typename return_type<
T_y,
typename return_type<T_F, T_G, T_V, T_W, T_m0, T_C0>::type >::type
gaussian_dlm_obs_lpdf(const Eigen::Matrix
<T_y, Eigen::Dynamic, Eigen::Dynamic>& y,
const Eigen::Matrix
<T_F, Eigen::Dynamic, Eigen::Dynamic>& F,
const Eigen::Matrix
<T_G, Eigen::Dynamic, Eigen::Dynamic>& G,
const Eigen::Matrix
<T_V, Eigen::Dynamic, Eigen::Dynamic>& V,
const Eigen::Matrix
<T_W, Eigen::Dynamic, Eigen::Dynamic>& W,
const Eigen::Matrix<T_m0, Eigen::Dynamic, 1>& m0,
const Eigen::Matrix
<T_C0, Eigen::Dynamic, Eigen::Dynamic>& C0) {
static const char* function("gaussian_dlm_obs_lpdf");
typedef typename return_type<
T_y,
typename return_type<T_F, T_G, T_V, T_W, T_m0, T_C0>::type>::type T_lp;
T_lp lp(0.0);
int r = y.rows(); // number of variables
int T = y.cols(); // number of observations
int n = G.rows(); // number of states
check_finite(function, "y", y);
check_not_nan(function, "y", y);
check_size_match(function,
"columns of F", F.cols(),
"rows of y", y.rows());
check_size_match(function,
"rows of F", F.rows(),
"rows of G", G.rows());
check_finite(function, "F", F);
check_square(function, "G", G);
check_finite(function, "G", G);
check_size_match(function,
"rows of V", V.rows(),
"rows of y", y.rows());
// TODO(anyone): incorporate support for infinite V
check_finite(function, "V", V);
check_spsd_matrix(function, "V", V);
check_size_match(function,
"rows of W", W.rows(),
"rows of G", G.rows());
// TODO(anyone): incorporate support for infinite W
check_finite(function, "W", W);
check_spsd_matrix(function, "W", W);
check_size_match(function,
"size of m0", m0.size(),
"rows of G", G.rows());
check_finite(function, "m0", m0);
check_size_match(function,
"rows of C0", C0.rows(),
"rows of G", G.rows());
check_cov_matrix(function, "C0", C0);
check_finite(function, "C0", C0);
if (y.cols() == 0 || y.rows() == 0)
return lp;
if (include_summand<propto>::value) {
lp -= 0.5 * LOG_TWO_PI * r * T;
}
if (include_summand<propto, T_y, T_F, T_G, T_V, T_W, T_m0, T_C0>::value) {
Eigen::Matrix<T_lp, Eigen::Dynamic, 1> m(n);
Eigen::Matrix<T_lp, Eigen::Dynamic, Eigen::Dynamic> C(n, n);
// TODO(anyone): how to recast matrices
for (int i = 0; i < m0.size(); i++) {
m(i) = m0(i);
}
for (int i = 0; i < C0.rows(); i++) {
for (int j = 0; j < C0.cols(); j++) {
C(i, j) = C0(i, j);
}
}
Eigen::Matrix<typename return_type<T_y>::type,
Eigen::Dynamic, 1> yi(r);
Eigen::Matrix<T_lp, Eigen::Dynamic, 1> a(n);
Eigen::Matrix<T_lp, Eigen::Dynamic, Eigen::Dynamic> R(n, n);
Eigen::Matrix<T_lp, Eigen::Dynamic, 1> f(r);
Eigen::Matrix<T_lp, Eigen::Dynamic, Eigen::Dynamic> Q(r, r);
Eigen::Matrix<T_lp, Eigen::Dynamic, Eigen::Dynamic> Q_inv(r, r);
Eigen::Matrix<T_lp, Eigen::Dynamic, 1> e(r);
Eigen::Matrix<T_lp, Eigen::Dynamic, Eigen::Dynamic> A(n, r);
for (int i = 0; i < y.cols(); i++) {
yi = y.col(i);
// // Predict state
// a_t = G_t m_{t-1}
a = multiply(G, m);
// R_t = G_t C_{t-1} G_t' + W_t
R = add(quad_form_sym(C, transpose(G)), W);
// // predict observation
// f_t = F_t' a_t
f = multiply(transpose(F), a);
// Q_t = F'_t R_t F_t + V_t
Q = add(quad_form_sym(R, F), V);
Q_inv = inverse_spd(Q);
// // filtered state
// e_t = y_t - f_t
e = subtract(yi, f);
// A_t = R_t F_t Q^{-1}_t
A = multiply(multiply(R, F), Q_inv);
// m_t = a_t + A_t e_t
m = add(a, multiply(A, e));
// C = R_t - A_t Q_t A_t'
C = subtract(R, quad_form_sym(Q, transpose(A)));
lp -= 0.5 * (log_determinant_spd(Q) + trace_quad_form(Q_inv, e));
}
}
return lp;
}
template <typename T_y,
typename T_F, typename T_G,
typename T_V, typename T_W,
typename T_m0, typename T_C0
>
inline
typename return_type<
T_y,
typename return_type<T_F, T_G, T_V, T_W, T_m0, T_C0>::type >::type
gaussian_dlm_obs_lpdf(const Eigen::Matrix
<T_y, Eigen::Dynamic, Eigen::Dynamic>& y,
const Eigen::Matrix
<T_F, Eigen::Dynamic, Eigen::Dynamic>& F,
const Eigen::Matrix
<T_G, Eigen::Dynamic, Eigen::Dynamic>& G,
const Eigen::Matrix
<T_V, Eigen::Dynamic, Eigen::Dynamic>& V,
const Eigen::Matrix
<T_W, Eigen::Dynamic, Eigen::Dynamic>& W,
const Eigen::Matrix<T_m0, Eigen::Dynamic, 1>& m0,
const Eigen::Matrix
<T_C0, Eigen::Dynamic, Eigen::Dynamic>& C0) {
return gaussian_dlm_obs_lpdf<false>(y, F, G, V, W, m0, C0);
}
template <bool propto,
typename T_y,
typename T_F, typename T_G,
typename T_V, typename T_W,
typename T_m0, typename T_C0
>
typename return_type<
T_y,
typename return_type<T_F, T_G, T_V, T_W, T_m0, T_C0>::type >::type
gaussian_dlm_obs_lpdf(const Eigen::Matrix
<T_y, Eigen::Dynamic, Eigen::Dynamic>& y,
const Eigen::Matrix
<T_F, Eigen::Dynamic, Eigen::Dynamic>& F,
const Eigen::Matrix
<T_G, Eigen::Dynamic, Eigen::Dynamic>& G,
const Eigen::Matrix<T_V, Eigen::Dynamic, 1>& V,
const Eigen::Matrix
<T_W, Eigen::Dynamic, Eigen::Dynamic>& W,
const Eigen::Matrix<T_m0, Eigen::Dynamic, 1>& m0,
const Eigen::Matrix
<T_C0, Eigen::Dynamic, Eigen::Dynamic>& C0) {
static const char* function("gaussian_dlm_obs_lpdf");
typedef
typename return_type
<T_y, typename return_type<T_F, T_G, T_V, T_W, T_m0, T_C0>::type>::type
T_lp;
T_lp lp(0.0);
using std::log;
int r = y.rows(); // number of variables
int T = y.cols(); // number of observations
int n = G.rows(); // number of states
check_finite(function, "y", y);
check_not_nan(function, "y", y);
check_size_match(function,
"columns of F", F.cols(),
"rows of y", y.rows());
check_size_match(function,
"rows of F", F.rows(),
"rows of G", G.rows());
check_finite(function, "F", F);
check_not_nan(function, "F", F);
check_size_match(function,
"rows of G", G.rows(),
"columns of G", G.cols());
check_finite(function, "G", G);
check_not_nan(function, "G", G);
check_nonnegative(function, "V", V);
check_size_match(function,
"size of V", V.size(),
"rows of y", y.rows());
// TODO(anyone): support infinite V
check_finite(function, "V", V);
check_not_nan(function, "V", V);
check_spsd_matrix(function, "W", W);
check_size_match(function,
"rows of W", W.rows(),
"rows of G", G.rows());
// TODO(anyone): support infinite W
check_finite(function, "W", W);
check_not_nan(function, "W", W);
check_size_match(function,
"size of m0", m0.size(),
"rows of G", G.rows());
check_finite(function, "m0", m0);
check_not_nan(function, "m0", m0);
check_cov_matrix(function, "C0", C0);
check_size_match(function,
"rows of C0", C0.rows(),
"rows of G", G.rows());
check_finite(function, "C0", C0);
check_not_nan(function, "C0", C0);
if (y.cols() == 0 || y.rows() == 0)
return lp;
if (include_summand<propto>::value) {
lp += 0.5 * NEG_LOG_TWO_PI * r * T;
}
if (include_summand<propto, T_y, T_F, T_G, T_V, T_W, T_m0, T_C0>::value) {
T_lp f;
T_lp Q;
T_lp Q_inv;
T_lp e;
Eigen::Matrix<T_lp, Eigen::Dynamic, 1> A(n);
Eigen::Matrix<T_lp, Eigen::Dynamic, 1> Fj(n);
Eigen::Matrix<T_lp, Eigen::Dynamic, 1> m(n);
Eigen::Matrix<T_lp, Eigen::Dynamic, Eigen::Dynamic> C(n, n);
// TODO(anyone): how to recast matrices
for (int i = 0; i < m0.size(); i++) {
m(i) = m0(i);
}
for (int i = 0; i < C0.rows(); i++) {
for (int j = 0; j < C0.cols(); j++) {
C(i, j) = C0(i, j);
}
}
for (int i = 0; i < y.cols(); i++) {
// Predict state
// reuse m and C instead of using a and R
m = multiply(G, m);
C = add(quad_form_sym(C, transpose(G)), W);
for (int j = 0; j < y.rows(); ++j) {
// predict observation
T_lp yij(y(j, i));
// dim Fj = (n, 1)
for (int k = 0; k < F.rows(); ++k) {
Fj(k) = F(k, j);
}
// f_{t, i} = F_{t, i}' m_{t, i-1}
f = dot_product(Fj, m);
Q = trace_quad_form(C, Fj) + V(j);
Q_inv = 1.0 / Q;
// filtered observation
// e_{t, i} = y_{t, i} - f_{t, i}
e = yij - f;
// A_{t, i} = C_{t, i-1} F_{t, i} Q_{t, i}^{-1}
A = multiply(multiply(C, Fj), Q_inv);
// m_{t, i} = m_{t, i-1} + A_{t, i} e_{t, i}
m += multiply(A, e);
// c_{t, i} = C_{t, i-1} - Q_{t, i} A_{t, i} A_{t, i}'
// tcrossprod throws an error (ambiguous)
// C = subtract(C, multiply(Q, tcrossprod(A)));
C -= multiply(Q, multiply(A, transpose(A)));
C = 0.5 * add(C, transpose(C));
lp -= 0.5 * (log(Q) + pow(e, 2) * Q_inv);
}
}
}
return lp;
}
template <typename T_y,
typename T_F, typename T_G,
typename T_V, typename T_W,
typename T_m0, typename T_C0>
inline
typename return_type
<T_y, typename return_type<T_F, T_G, T_V, T_W, T_m0, T_C0>::type>::type
gaussian_dlm_obs_lpdf
(const Eigen::Matrix<T_y, Eigen::Dynamic, Eigen::Dynamic>& y,
const Eigen::Matrix<T_F, Eigen::Dynamic, Eigen::Dynamic>& F,
const Eigen::Matrix<T_G, Eigen::Dynamic, Eigen::Dynamic>& G,
const Eigen::Matrix<T_V, Eigen::Dynamic, 1>& V,
const Eigen::Matrix<T_W, Eigen::Dynamic, Eigen::Dynamic>& W,
const Eigen::Matrix<T_m0, Eigen::Dynamic, 1>& m0,
const Eigen::Matrix<T_C0, Eigen::Dynamic, Eigen::Dynamic>& C0) {
return gaussian_dlm_obs_lpdf<false>(y, F, G, V, W, m0, C0);
}
}
}
#endif
check_not_nan.hpp
multiply.hpp
tcrossprod.hpp
log_determinant_spd.hpp
stan::math::check_finite
void check_finite(const char *function, const char *name, const T_y &y)
Check if y is finite.
Definition: check_finite.hpp:57
stan::math::trace_quad_form
fvar< T > trace_quad_form(const Eigen::Matrix< fvar< T >, RA, CA > &A, const Eigen::Matrix< fvar< T >, RB, CB > &B)
Definition: trace_quad_form.hpp:18
check_size_match.hpp
stan
Definition: log_sum_exp.hpp:8
stan::math::subtract
Eigen::Matrix< typename boost::math::tools::promote_args< T1, T2 >::type, R, C > subtract(const Eigen::Matrix< T1, R, C > &m1, const Eigen::Matrix< T2, R, C > &m2)
Return the result of subtracting the second specified matrix from the first specified matrix...
Definition: subtract.hpp:27
stan::math::log
fvar< T > log(const fvar< T > &x)
Definition: log.hpp:14
stan::math::multiply
Eigen::Matrix< fvar< T >, R1, C1 > multiply(const Eigen::Matrix< fvar< T >, R1, C1 > &m, const fvar< T > &c)
Definition: multiply.hpp:20
add.hpp
stan::return_type
Metaprogram to calculate the base scalar return type resulting from promoting all the scalar types of...
Definition: return_type.hpp:19
stan::math::check_size_match
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.
Definition: check_size_match.hpp:29
return_type.hpp
stan::math::include_summand
Template metaprogram to calculate whether a summand needs to be included in a proportional (log) prob...
Definition: include_summand.hpp:35
log.hpp
check_cov_matrix.hpp
stan::math::check_nonnegative
void check_nonnegative(const char *function, const char *name, const T_y &y)
Check if y is non-negative.
Definition: check_nonnegative.hpp:61
transpose.hpp
stan::return_type::type
boost::math::tools::promote_args< typename scalar_type< T1 >::type, typename scalar_type< T2 >::type, typename scalar_type< T3 >::type, typename scalar_type< T4 >::type, typename scalar_type< T5 >::type, typename scalar_type< T6 >::type >::type type
Definition: return_type.hpp:27
include_summand.hpp
stan::math::LOG_TWO_PI
const double LOG_TWO_PI
Definition: constants.hpp:190
check_nonnegative.hpp
quad_form_sym.hpp
stan::math::check_not_nan
void check_not_nan(const char *function, const char *name, const T_y &y)
Check if y is not NaN.
Definition: check_not_nan.hpp:57
trace_quad_form.hpp
stan::math::check_spsd_matrix
void check_spsd_matrix(const char *function, const char *name, const Eigen::Matrix< T_y, Eigen::Dynamic, Eigen::Dynamic > &y)
Check if the specified matrix is a square, symmetric, and positive semi-definite. ...
Definition: check_spsd_matrix.hpp:29
stan::math::gaussian_dlm_obs_lpdf
return_type< T_y, typename return_type< T_F, T_G, T_V, T_W, T_m0, T_C0 >::type >::type gaussian_dlm_obs_lpdf(const Eigen::Matrix< T_y, Eigen::Dynamic, Eigen::Dynamic > &y, const Eigen::Matrix< T_F, Eigen::Dynamic, Eigen::Dynamic > &F, const Eigen::Matrix< T_G, Eigen::Dynamic, Eigen::Dynamic > &G, const Eigen::Matrix< T_V, Eigen::Dynamic, Eigen::Dynamic > &V, const Eigen::Matrix< T_W, Eigen::Dynamic, Eigen::Dynamic > &W, const Eigen::Matrix< T_m0, Eigen::Dynamic, 1 > &m0, const Eigen::Matrix< T_C0, Eigen::Dynamic, Eigen::Dynamic > &C0)
The log of a Gaussian dynamic linear model (GDLM).
Definition: gaussian_dlm_obs_lpdf.hpp:78
stan::math::dot_product
fvar< T > dot_product(const Eigen::Matrix< fvar< T >, R1, C1 > &v1, const Eigen::Matrix< fvar< T >, R2, C2 > &v2)
Definition: dot_product.hpp:18
dot_product.hpp
stan::math::check_cov_matrix
void check_cov_matrix(const char *function, const char *name, const Eigen::Matrix< T_y, Eigen::Dynamic, Eigen::Dynamic > &y)
Check if the specified matrix is a valid covariance matrix.
Definition: check_cov_matrix.hpp:30
stan::math::check_square
void check_square(const char *function, const char *name, const Eigen::Matrix< T_y, Eigen::Dynamic, Eigen::Dynamic > &y)
Check if the specified matrix is square.
Definition: check_square.hpp:27
stan::math::e
double e()
Return the base of the natural logarithm.
Definition: constants.hpp:94
stan::math::quad_form_sym
Eigen::Matrix< fvar< T >, CB, CB > quad_form_sym(const Eigen::Matrix< fvar< T >, RA, CA > &A, const Eigen::Matrix< double, RB, CB > &B)
Definition: quad_form_sym.hpp:14
constants.hpp
check_finite.hpp
stan::math::inverse_spd
Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic > inverse_spd(const Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic > &m)
Returns the inverse of the specified symmetric, pos/neg-definite matrix.
Definition: inverse_spd.hpp:20
stan::math::NEG_LOG_TWO_PI
const double NEG_LOG_TWO_PI
Definition: constants.hpp:192
stan::math::add
Eigen::Matrix< typename boost::math::tools::promote_args< T1, T2 >::type, R, C > add(const Eigen::Matrix< T1, R, C > &m1, const Eigen::Matrix< T2, R, C > &m2)
Return the sum of the specified matrices.
Definition: add.hpp:27
stan::math::pow
fvar< T > pow(const fvar< T > &x1, const fvar< T > &x2)
Definition: pow.hpp:17
stan::math::transpose
Eigen::Matrix< T, C, R > transpose(const Eigen::Matrix< T, R, C > &m)
Definition: transpose.hpp:12
quad_form.hpp
subtract.hpp
check_spsd_matrix.hpp
inverse_spd.hpp
stan::math::log_determinant_spd
T log_determinant_spd(const Eigen::Matrix< T, R, C > &m)
Returns the log absolute determinant of the specified square matrix.
Definition: log_determinant_spd.hpp:19

[ Stan Home Page ] © 2011–2016, Stan Development Team.