MCKL
Monte Carlo Kernel Library
covariance.hpp
Go to the documentation of this file.
1 //============================================================================
2 // MCKL/include/mckl/utility/covariance.hpp
3 //----------------------------------------------------------------------------
4 // MCKL: Monte Carlo Kernel Library
5 //----------------------------------------------------------------------------
6 // Copyright (c) 2013-2018, Yan Zhou
7 // All rights reserved.
8 //
9 // Redistribution and use in source and binary forms, with or without
10 // modification, are permitted provided that the following conditions are met:
11 //
12 // Redistributions of source code must retain the above copyright notice,
13 // this list of conditions and the following disclaimer.
14 //
15 // Redistributions in binary form must reproduce the above copyright notice,
16 // this list of conditions and the following disclaimer in the documentation
17 // and/or other materials provided with the distribution.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS
20 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 // POSSIBILITY OF SUCH DAMAGE.
30 //============================================================================
31 
32 #ifndef MCKL_UTILITY_COVARIANCE_HPP
33 #define MCKL_UTILITY_COVARIANCE_HPP
34 
35 #include <mckl/internal/common.hpp>
36 #include <mckl/internal/cblas.hpp>
37 
38 namespace mckl {
39 
42 template <typename RealType = double>
44 {
46  "**Covariance** used with RealType other than float or double");
47 
48  public:
49  using result_type = RealType;
50 
71  void operator()(MatrixLayout layout, std::size_t n, std::size_t p,
72  const result_type *x, const result_type *w, result_type *mean,
73  result_type *cov, MatrixLayout cov_layout = RowMajor,
74  bool cov_upper = false, bool cov_packed = false)
75  {
76  if (n * p == 0) {
77  return;
78  }
79 
80  if (x == nullptr) {
81  return;
82  }
83 
84  if (mean == nullptr && cov == nullptr) {
85  return;
86  }
87 
88  internal::size_check<MCKL_BLAS_INT>(p, "Covariance::operator()");
89  internal::size_check<MCKL_BLAS_INT>(n, "Covariance::operator()");
90 
91  result_type sw = w == nullptr ?
92  static_cast<result_type>(n) :
93  std::accumulate(w, w + n, const_zero<result_type>());
94  mean_.resize(p);
95  if (w == nullptr) {
96  if (layout == RowMajor) {
97  std::fill(mean_.begin(), mean_.end(), 0);
98  for (std::size_t i = 0; i != n; ++i) {
99  add(p, x + i * p, mean_.data(), mean_.data());
100  }
101  } else {
102  for (std::size_t i = 0; i != p; ++i) {
103  mean_[i] = std::accumulate(
104  x + i * n, x + (i + 1) * n, const_zero<result_type>());
105  }
106  }
107  } else {
108  mean_init(layout, n, p, x, w);
109  }
110  div(p, mean_.data(), sw, mean_.data());
111  if (mean != nullptr) {
112  std::memcpy(
113  mean, mean_.data(), sizeof(result_type) * mean_.size());
114  }
115  if (cov == nullptr) {
116  return;
117  }
118 
119  result_type sw2 =
120  w == nullptr ? static_cast<result_type>(n) : swsqr(n, w);
121  result_type B = sw / (sw * sw - sw2);
122  result_type BW = B * sw;
123  cov_.resize(p * p);
124  std::fill(cov_.begin(), cov_.end(), 0);
125  cov_init(layout, p, static_cast<result_type *>(nullptr));
126  if (w == nullptr) {
127  cov_update(layout, n, p, x, B, BW);
128  } else {
129  wsqrt_.resize(n);
130  x_.resize(n * p);
131  sqrt(n, w, wsqrt_.data());
132  if (layout == RowMajor) {
133  for (std::size_t i = 0; i != n; ++i) {
134  mul(p, x + i * p, wsqrt_[i], x_.data() + i * p);
135  }
136  } else {
137  for (std::size_t i = 0; i != p; ++i) {
138  mul(n, x + i * n, wsqrt_.data(), x_.data() + i * n);
139  }
140  }
141  cov_update(layout, n, p, x_.data(), B, BW);
142  }
143  cov_pack(p, cov, layout, cov_layout, cov_upper, cov_packed);
144  }
145 
146  private:
147  Vector<result_type> mean_;
148  Vector<result_type> cov_;
149  Vector<result_type> wsqrt_;
151 
152  void mean_init(MatrixLayout layout, std::size_t n, std::size_t p,
153  const float *x, const float *w)
154  {
155  internal::cblas_sgemv(layout == RowMajor ? internal::CblasRowMajor :
156  internal::CblasColMajor,
157  internal::CblasTrans, static_cast<MCKL_BLAS_INT>(n),
158  static_cast<MCKL_BLAS_INT>(p), 1.0, x,
159  static_cast<MCKL_BLAS_INT>(layout == RowMajor ? p : n), w, 1, 0.0,
160  mean_.data(), 1);
161  }
162 
163  void mean_init(MatrixLayout layout, std::size_t n, std::size_t p,
164  const double *x, const double *w)
165  {
166  internal::cblas_dgemv(layout == RowMajor ? internal::CblasRowMajor :
167  internal::CblasColMajor,
168  internal::CblasTrans, static_cast<MCKL_BLAS_INT>(n),
169  static_cast<MCKL_BLAS_INT>(p), 1.0, x,
170  static_cast<MCKL_BLAS_INT>(layout == RowMajor ? p : n), w, 1, 0.0,
171  mean_.data(), 1);
172  }
173 
174  static float swsqr(std::size_t n, const float *w)
175  {
176  return internal::cblas_sdot(static_cast<MCKL_BLAS_INT>(n), w, 1, w, 1);
177  }
178 
179  static double swsqr(std::size_t n, const double *w)
180  {
181  return internal::cblas_ddot(static_cast<MCKL_BLAS_INT>(n), w, 1, w, 1);
182  }
183 
184  void cov_init(MatrixLayout layout, std::size_t p, float *)
185  {
186  internal::cblas_ssyr(layout == RowMajor ? internal::CblasRowMajor :
187  internal::CblasColMajor,
188  internal::CblasLower, static_cast<MCKL_BLAS_INT>(p), 1,
189  mean_.data(), 1, cov_.data(), static_cast<MCKL_BLAS_INT>(p));
190  }
191 
192  void cov_init(MatrixLayout layout, std::size_t p, double *)
193  {
194  internal::cblas_dsyr(layout == RowMajor ? internal::CblasRowMajor :
195  internal::CblasColMajor,
196  internal::CblasLower, static_cast<MCKL_BLAS_INT>(p), 1,
197  mean_.data(), 1, cov_.data(), static_cast<MCKL_BLAS_INT>(p));
198  }
199 
200  void cov_update(MatrixLayout layout, std::size_t n, std::size_t p,
201  const float *x, float B, float BW)
202  {
203  internal::cblas_ssyrk(layout == RowMajor ? internal::CblasRowMajor :
204  internal::CblasColMajor,
205  internal::CblasLower, internal::CblasTrans,
206  static_cast<MCKL_BLAS_INT>(p), static_cast<MCKL_BLAS_INT>(n), B, x,
207  static_cast<MCKL_BLAS_INT>(layout == RowMajor ? p : n), -BW,
208  cov_.data(), static_cast<MCKL_BLAS_INT>(p));
209  }
210 
211  void cov_update(MatrixLayout layout, std::size_t n, std::size_t p,
212  const double *x, double B, double BW)
213  {
214  internal::cblas_dsyrk(layout == RowMajor ? internal::CblasRowMajor :
215  internal::CblasColMajor,
216  internal::CblasLower, internal::CblasTrans,
217  static_cast<MCKL_BLAS_INT>(p), static_cast<MCKL_BLAS_INT>(n), B, x,
218  static_cast<MCKL_BLAS_INT>(layout == RowMajor ? p : n), -BW,
219  cov_.data(), static_cast<MCKL_BLAS_INT>(p));
220  }
221 
222  void cov_pack(std::size_t p, result_type *cov, MatrixLayout layout,
223  MatrixLayout cov_layout, bool cov_upper, bool cov_packed)
224  {
225  if (layout == RowMajor) {
226  for (std::size_t i = 0; i != p; ++i) {
227  for (std::size_t j = 0; j != i; ++j) {
228  cov_[j * p + i] = cov_[i * p + j];
229  }
230  }
231  }
232 
233  if (layout == ColMajor) {
234  for (std::size_t i = 0; i != p; ++i) {
235  for (std::size_t j = 0; j != i; ++j) {
236  cov_[i * p + j] = cov_[j * p + i];
237  }
238  }
239  }
240 
241  if (!cov_packed) {
242  std::memcpy(cov, cov_.data(), sizeof(result_type) * cov_.size());
243  return;
244  }
245 
246  unsigned l = cov_layout == RowMajor ? 0 : 1;
247  unsigned u = cov_upper ? 1 : 0;
248  unsigned c = (l << 1) + u;
249  switch (c) {
250  case 0: // Row, Lower, Pack
251  for (size_t i = 0; i != p; ++i) {
252  for (std::size_t j = 0; j <= i; ++j) {
253  *cov++ = cov_[i * p + j];
254  }
255  }
256  break;
257  case 1: // Row, Upper, Pack
258  for (std::size_t i = 0; i != p; ++i) {
259  for (std::size_t j = i; j != p; ++j) {
260  *cov++ = cov_[i * p + j];
261  }
262  }
263  break;
264  case 2: // Col, Lower, Pack
265  for (std::size_t j = 0; j != p; ++j) {
266  for (std::size_t i = j; i != p; ++i) {
267  *cov++ = cov_[j * p + i];
268  }
269  }
270  break;
271  case 3: // Col, Upper, Pack
272  for (std::size_t j = 0; j != p; ++j) {
273  for (std::size_t i = 0; i <= j; ++i) {
274  *cov++ = cov_[j * p + i];
275  }
276  }
277  break;
278  default:
279  break;
280  }
281  }
282 }; // class Covariance
283 
284 } // namespace mckl
285 
286 #endif // MCKL_UTILITY_COVARIANCE_HPP
void mul(std::size_t n, const float *a, const float *b, float *y)
Definition: vmf.hpp:124
std::integral_constant< bool, std::is_same< typename std::remove_cv< T >::type, float >::value||std::is_same< typename std::remove_cv< T >::type, double >::value > is_blas_floating_point
Definition: traits.hpp:180
#define MCKL_BLAS_INT
Definition: cblas.hpp:42
std::vector< T, Alloc > Vector
std::vector with Allocator as the default allocator
Definition: memory.hpp:435
RealType result_type
Definition: covariance.hpp:49
Covariance.
Definition: covariance.hpp:43
void sqrt(std::size_t n, const float *a, float *y)
Definition: vmf.hpp:177
Definition: mcmc.hpp:40
void operator()(MatrixLayout layout, std::size_t n, std::size_t p, const result_type *x, const result_type *w, result_type *mean, result_type *cov, MatrixLayout cov_layout=RowMajor, bool cov_upper=false, bool cov_packed=false)
Compute the sample covariance matrix.
Definition: covariance.hpp:71
void div(std::size_t n, const float *a, const float *b, float *y)
Definition: vmf.hpp:175
MatrixLayout
Matrix layout.
Definition: defines.hpp:46
void add(std::size_t n, const float *a, const float *b, float *y)
Definition: vmf.hpp:119