1 #ifndef STAN_MATH_PRIM_FUN_GP_PERIODIC_COV_HPP
2 #define STAN_MATH_PRIM_FUN_GP_PERIODIC_COV_HPP
3
4 #include <stan/math/prim/meta.hpp>
5 #include <stan/math/prim/err.hpp>
6 #include <stan/math/prim/fun/constants.hpp>
7 #include <stan/math/prim/fun/distance.hpp>
8 #include <stan/math/prim/fun/Eigen.hpp>
9 #include <stan/math/prim/fun/exp.hpp>
10 #include <stan/math/prim/fun/inv_square.hpp>
11 #include <stan/math/prim/fun/sin.hpp>
12 #include <stan/math/prim/fun/square.hpp>
13 #include <cmath>
14 #include <vector>
15
16 namespace stan {
17 namespace math {
18
19 /**
20 * Returns a periodic covariance matrix \f$ \mathbf{K} \f$ using the input \f$
21 * \mathbf{X} \f$. The elements of \f$ \mathbf{K} \f$ are defined as \f$
22 * \mathbf{K}_{ij} = k(\mathbf{X}_i,\mathbf{X}_j), \f$ where \f$ \mathbf{X}_i
23 * \f$ is the \f$i\f$-th row of \f$ \mathbf{X} \f$ and \n \f$
24 * k(\mathbf{x},\mathbf{x}^\prime) = \sigma^2 \exp\left(-\frac{2\sin^2(\pi
25 * |\mathbf{x}-\mathbf{x}^\prime|/p)}{\ell^2}\right), \f$ \n where \f$ \sigma^2
26 * \f$, \f$ \ell \f$ and \f$ p \f$ are the signal variance, length-scale and
27 * period.
28 *
29 * @tparam T_x type of std::vector elements of x.
30 * T_x can be a scalar, an Eigen::Vector, or an Eigen::RowVector.
31 * @tparam T_sigma type of sigma
32 * @tparam T_l type of length-scale
33 * @tparam T_p type of period
34 *
35 * @param x std::vector of input elements.
36 * This function assumes that all elements of x have the same size.
37 * @param sigma standard deviation of the signal
38 * @param l length-scale
39 * @param p period
40 * @return periodic covariance matrix
41 * @throw std::domain_error if sigma <= 0, l <= 0, p <= 0 or
42 * x is nan or infinite
43 */
44 template <typename T_x, typename T_sigma, typename T_l, typename T_p>
45 inline typename Eigen::Matrix<return_type_t<T_x, T_sigma, T_l, T_p>,
46 Eigen::Dynamic, Eigen::Dynamic>
gp_periodic_cov(const std::vector<T_x> & x,const T_sigma & sigma,const T_l & l,const T_p & p)47 gp_periodic_cov(const std::vector<T_x> &x, const T_sigma &sigma, const T_l &l,
48 const T_p &p) {
49 using std::exp;
50 using std::sin;
51 const char *fun = "gp_periodic_cov";
52 check_positive(fun, "signal standard deviation", sigma);
53 check_positive(fun, "length-scale", l);
54 check_positive(fun, "period", p);
55 for (size_t n = 0; n < x.size(); ++n) {
56 check_not_nan(fun, "element of x", x[n]);
57 }
58
59 Eigen::Matrix<return_type_t<T_x, T_sigma, T_l, T_p>, Eigen::Dynamic,
60 Eigen::Dynamic>
61 cov(x.size(), x.size());
62
63 size_t x_size = x.size();
64 if (x_size == 0) {
65 return cov;
66 }
67
68 T_sigma sigma_sq = square(sigma);
69 T_l neg_two_inv_l_sq = -2.0 * inv_square(l);
70 T_p pi_div_p = pi() / p;
71 size_t block_size = 10;
72
73 for (size_t jb = 0; jb < x_size; jb += block_size) {
74 for (size_t ib = jb; ib < x_size; ib += block_size) {
75 size_t j_end = std::min(x_size, jb + block_size);
76 for (size_t j = jb; j < j_end; ++j) {
77 cov.coeffRef(j, j) = sigma_sq;
78 size_t i_end = std::min(x_size, ib + block_size);
79 for (size_t i = std::max(ib, j + 1); i < i_end; ++i) {
80 cov.coeffRef(j, i) = cov.coeffRef(i, j)
81 = sigma_sq
82 * exp(square(sin(pi_div_p * distance(x[i], x[j])))
83 * neg_two_inv_l_sq);
84 }
85 }
86 }
87 }
88 return cov;
89 }
90
91 /**
92 * Returns a periodic covariance matrix \f$ \mathbf{K} \f$ using inputs
93 * \f$ \mathbf{X}_1 \f$ and \f$ \mathbf{X}_2 \f$.
94 * The elements of \f$ \mathbf{K} \f$ are defined as
95 * \f$ \mathbf{K}_{ij} = k(\mathbf{X}_{1_i},\mathbf{X}_{2_j}), \f$ where
96 * \f$ \mathbf{X}_{1_i} \f$ and \f$ \mathbf{X}_{2_j} \f$ are the \f$i\f$-th
97 * and \f$j\f$-th rows of \f$ \mathbf{X}_1 \f$ and \f$ \mathbf{X}_2 \f$ and
98 * \n \f$ k(\mathbf{x},\mathbf{x}^\prime) = \sigma^2
99 * \exp\left(-\frac{2\sin^2(\pi
100 * |\mathbf{x}-\mathbf{x}^\prime|/p)}{\ell^2}\right), \f$ \n where \f$
101 * \sigma^2 \f$, \f$ \ell \f$ and \f$ p \f$ are the signal variance,
102 * length-scale and period.
103 *
104 * @tparam T_x1 type of std::vector elements of x1
105 * T_x1 can be a scalar, an Eigen::Vector, or an Eigen::RowVector.
106 * @tparam T_x2 type of std::vector elements of x2
107 * T_x2 can be a scalar, an Eigen::Vector, or an Eigen::RowVector.
108 * @tparam T_sigma type of sigma
109 * @tparam T_l type of length-scale
110 * @tparam T_p type of period
111 *
112 * @param x1 std::vector of first input elements
113 * @param x2 std::vector of second input elements.
114 * This function assumes that all the elements of x1 and x2 have the same
115 * sizes.
116 * @param sigma standard deviation of the signal
117 * @param l length-scale
118 * @param p period
119 * @return periodic covariance matrix
120 * @throw std::domain_error if sigma <= 0, l <= 0, p <= 0 ,
121 * x1 or x2 is nan or infinite
122 */
123 template <typename T_x1, typename T_x2, typename T_sigma, typename T_l,
124 typename T_p>
125 inline typename Eigen::Matrix<return_type_t<T_x1, T_x2, T_sigma, T_l, T_p>,
126 Eigen::Dynamic, Eigen::Dynamic>
gp_periodic_cov(const std::vector<T_x1> & x1,const std::vector<T_x2> & x2,const T_sigma & sigma,const T_l & l,const T_p & p)127 gp_periodic_cov(const std::vector<T_x1> &x1, const std::vector<T_x2> &x2,
128 const T_sigma &sigma, const T_l &l, const T_p &p) {
129 using std::exp;
130 using std::sin;
131 const char *fun = "gp_periodic_cov";
132 check_positive(fun, "signal standard deviation", sigma);
133 check_positive(fun, "length-scale", l);
134 check_positive(fun, "period", p);
135 for (size_t n = 0; n < x1.size(); ++n) {
136 check_not_nan(fun, "element of x1", x1[n]);
137 }
138 for (size_t n = 0; n < x2.size(); ++n) {
139 check_not_nan(fun, "element of x2", x2[n]);
140 }
141
142 Eigen::Matrix<return_type_t<T_x1, T_x2, T_sigma, T_l, T_p>, Eigen::Dynamic,
143 Eigen::Dynamic>
144 cov(x1.size(), x2.size());
145 if (x1.size() == 0 || x2.size() == 0) {
146 return cov;
147 }
148
149 T_sigma sigma_sq = square(sigma);
150 T_l neg_two_inv_l_sq = -2.0 * inv_square(l);
151 T_p pi_div_p = pi() / p;
152 size_t block_size = 10;
153
154 for (size_t ib = 0; ib < x1.size(); ib += block_size) {
155 for (size_t jb = 0; jb < x2.size(); jb += block_size) {
156 size_t j_end = std::min(x2.size(), jb + block_size);
157 for (size_t j = jb; j < j_end; ++j) {
158 size_t i_end = std::min(x1.size(), ib + block_size);
159 for (size_t i = ib; i < i_end; ++i) {
160 cov.coeffRef(i, j)
161 = sigma_sq
162 * exp(square(sin(pi_div_p * distance(x1[i], x2[j])))
163 * neg_two_inv_l_sq);
164 }
165 }
166 }
167 }
168 return cov;
169 }
170 } // namespace math
171 } // namespace stan
172
173 #endif
174