MCKL
Monte Carlo Kernel Library
normal_mv_distribution.hpp
Go to the documentation of this file.
1 //============================================================================
2 // MCKL/include/mckl/random/normal_mv_distribution.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_RANDOM_NORMAL_MV_DISTRIBUTION_HPP
33 #define MCKL_RANDOM_NORMAL_MV_DISTRIBUTION_HPP
34 
37 
38 namespace mckl {
39 
40 namespace internal {
41 
43  std::size_t n, float *r, std::size_t dim, const float *chol)
44 {
45  cblas_strmm(CblasRowMajor, CblasRight, CblasLower, CblasTrans,
46  CblasNonUnit, static_cast<MCKL_BLAS_INT>(n),
47  static_cast<MCKL_BLAS_INT>(dim), 1, chol,
48  static_cast<MCKL_BLAS_INT>(dim), r, static_cast<MCKL_BLAS_INT>(dim));
49 }
50 
52  std::size_t n, double *r, std::size_t dim, const double *chol)
53 {
54  cblas_dtrmm(CblasRowMajor, CblasRight, CblasLower, CblasTrans,
55  CblasNonUnit, static_cast<MCKL_BLAS_INT>(n),
56  static_cast<MCKL_BLAS_INT>(dim), 1, chol,
57  static_cast<MCKL_BLAS_INT>(dim), r, static_cast<MCKL_BLAS_INT>(dim));
58 }
59 
60 } // namespace internal
61 
62 template <typename RealType, typename RNGType>
63 inline void normal_mv_distribution(RNGType &rng, std::size_t n, RealType *r,
64  std::size_t dim, RealType mean, RealType chol)
65 {
66  internal::size_check<MCKL_BLAS_INT>(n, "normal_mv_distribution");
67  internal::size_check<MCKL_BLAS_INT>(dim, "normal_mv_distribution");
68 
69  normal_distribution(rng, n * dim, r, mean, chol);
70 }
71 
72 template <typename RealType, typename RNGType>
73 inline void normal_mv_distribution(RNGType &rng, std::size_t n, RealType *r,
74  std::size_t dim, RealType mean, const RealType *chol)
75 {
76  internal::size_check<MCKL_BLAS_INT>(n, "normal_mv_distribution");
77  internal::size_check<MCKL_BLAS_INT>(dim, "normal_mv_distribution");
78 
80  rng, n * dim, r, const_zero<RealType>(), const_one<RealType>());
81  Vector<RealType> cholf(dim * dim);
82  for (std::size_t i = 0; i != dim; ++i) {
83  for (std::size_t j = 0; j <= i; ++j) {
84  cholf[i * dim + j] = *chol++;
85  }
86  }
87  internal::normal_mv_distribution_mulchol(n, r, dim, cholf.data());
88  MCKL_PUSH_CLANG_WARNING("-Wfloat-equal")
89  MCKL_PUSH_INTEL_WARNING(1572) // floating-point comparison
90  if (mean != 0) {
91  add(n * dim, mean, r, r);
92  }
95 }
96 
97 template <typename RealType, typename RNGType>
98 inline void normal_mv_distribution(RNGType &rng, std::size_t n, RealType *r,
99  std::size_t dim, const RealType *mean, RealType chol)
100 {
101  internal::size_check<MCKL_BLAS_INT>(n, "normal_mv_distribution");
102  internal::size_check<MCKL_BLAS_INT>(dim, "normal_mv_distribution");
103 
104  normal_distribution(rng, n * dim, r, const_zero<RealType>(), chol);
105  for (std::size_t i = 0; i != n; ++i, r += dim) {
106  add<RealType>(dim, mean, r, r);
107  }
108 }
109 
110 template <typename RealType, typename RNGType>
111 inline void normal_mv_distribution(RNGType &rng, std::size_t n, RealType *r,
112  std::size_t dim, const RealType *mean, const RealType *chol)
113 {
114  internal::size_check<MCKL_BLAS_INT>(n, "normal_mv_distribution");
115  internal::size_check<MCKL_BLAS_INT>(dim, "normal_mv_distribution");
116 
118  rng, n * dim, r, const_zero<RealType>(), const_one<RealType>());
119  Vector<RealType> cholf(dim * dim);
120  for (std::size_t i = 0; i != dim; ++i) {
121  for (std::size_t j = 0; j <= i; ++j) {
122  cholf[i * dim + j] = *chol++;
123  }
124  }
125  internal::normal_mv_distribution_mulchol(n, r, dim, cholf.data());
126  for (std::size_t i = 0; i != n; ++i, r += dim) {
127  add<RealType>(dim, mean, r, r);
128  }
129 }
130 
138 template <typename RealType>
140 {
142 
143  public:
144  using result_type = RealType;
146 
147  MCKL_PUSH_CLANG_WARNING("-Wpadded")
149  {
150  public:
151  using result_type = RealType;
153 
154  explicit param_type(std::size_t dim = 1)
155  : mean_(dim, 0)
156  , chol_(dim * (dim + 1) / 2, 0)
157  , is_scalar_mean_(true)
158  , is_scalar_chol_(true)
159  {
160  scalar_chol(1);
161  }
162 
163  param_type(std::size_t dim, result_type mean, result_type chol)
164  : mean_(dim, mean)
165  , chol_(dim * (dim + 1) / 2, 0)
166  , is_scalar_mean_(true)
167  , is_scalar_chol_(true)
168  {
169  scalar_chol(chol);
170  }
171 
172  param_type(std::size_t dim, result_type mean, const result_type *chol)
173  : mean_(dim, mean)
174  , chol_(chol, chol + dim * (dim + 1) / 2)
175  , is_scalar_mean_(true)
176  , is_scalar_chol_(false)
177  {
178  }
179 
180  param_type(std::size_t dim, const result_type *mean, result_type chol)
181  : mean_(mean, mean + dim)
182  , chol_(dim * (dim + 1) / 2, 0)
183  , is_scalar_mean_(false)
184  , is_scalar_chol_(true)
185  {
186  scalar_chol(chol);
187  }
188 
190  std::size_t dim, const result_type *mean, const result_type *chol)
191  : mean_(mean, mean + dim)
192  , chol_(chol, chol + dim * (dim + 1) / 2)
193  , is_scalar_mean_(false)
194  , is_scalar_chol_(false)
195  {
196  }
197 
198  std::size_t dim() const { return mean_.size(); }
199 
200  const result_type *mean() const { return mean_.data(); }
201 
202  const result_type *chol() const { return chol_.data(); }
203 
204  friend bool operator==(
205  const param_type &param1, const param_type &param2)
206  {
207  if (param1.mean_ != param2.mean_) {
208  return false;
209  }
210  if (param1.chol_ != param2.chol_) {
211  return false;
212  }
213  if (param1.is_scalar_mean_ != param2.is_scalar_mean_) {
214  return false;
215  }
216  if (param1.is_scalar_chol_ != param2.is_scalar_chol_) {
217  return false;
218  }
219  return true;
220  }
221 
222  friend bool operator!=(
223  const param_type &param1, const param_type &param2)
224  {
225  return !(param1 == param2);
226  }
227 
228  template <typename CharT, typename Traits>
229  friend std::basic_ostream<CharT, Traits> &operator<<(
230  std::basic_ostream<CharT, Traits> &os, const param_type &param)
231  {
232  if (!os) {
233  return os;
234  }
235 
236  os << param.mean_ << ' ';
237  os << param.chol_ << ' ';
238  os << param.is_scalar_mean_ << ' ';
239  os << param.is_scalar_chol_;
240 
241  return os;
242  }
243 
244  template <typename CharT, typename Traits>
245  friend std::basic_istream<CharT, Traits> &operator>>(
246  std::basic_istream<CharT, Traits> &is, param_type &param)
247  {
248  if (!is) {
249  return is;
250  }
251 
252  param_type tmp;
253 
254  is >> std::ws >> tmp.mean_;
255  is >> std::ws >> tmp.chol_;
256  is >> std::ws >> tmp.is_scalar_mean_;
257  is >> std::ws >> tmp.is_scalar_chol_;
258 
259  if (is) {
260  param = std::move(tmp);
261  } else {
262  is.setstate(std::ios_base::failbit);
263  }
264 
265  return is;
266  }
267 
268  private:
269  Vector<result_type> mean_;
270  Vector<result_type> chol_;
271  bool is_scalar_mean_;
272  bool is_scalar_chol_;
273 
274  friend distribution_type;
275 
276  void scalar_chol(result_type chol)
277  {
278  for (std::size_t i = 0; i != dim(); ++i) {
279  chol_[(i + 1) * (i + 2) / 2 - 1] = chol;
280  }
281  }
282  }; // class param_type
284 
286  explicit NormalMVDistribution(std::size_t dim = 1) : param_(dim)
287  {
288  reset();
289  }
290 
292  NormalMVDistribution(std::size_t dim, result_type mean, result_type chol)
293  : param_(dim, mean, chol)
294  {
295  reset();
296  }
297 
300  std::size_t dim, result_type mean, const result_type *chol)
301  : param_(dim, mean, chol)
302  {
303  reset();
304  }
305 
308  std::size_t dim, const result_type *mean, result_type chol)
309  : param_(dim, mean, chol)
310  {
311  reset();
312  }
313 
316  std::size_t dim, const result_type *mean, const result_type *chol)
317  : param_(dim, mean, chol)
318  {
319  reset();
320  }
321 
322  explicit NormalMVDistribution(const param_type &param) : param_(param)
323  {
324  reset();
325  }
326 
328  : param_(std::move(param))
329  {
330  reset();
331  }
332 
333  template <typename OutputIter>
334  OutputIter min(OutputIter first) const
335  {
336  return std::fill_n(
337  first, dim(), std::numeric_limits<result_type>::lowest());
338  }
339 
340  template <typename OutputIter>
341  OutputIter max(OutputIter first) const
342  {
343  return std::fill_n(
344  first, dim(), std::numeric_limits<result_type>::max());
345  }
346 
347  void reset() {}
348 
349  std::size_t dim() const { return param_.dim(); }
350 
351  const result_type *mean() const { return param_.mean(); }
352 
353  const result_type *chol() const { return param_.chol(); }
354 
355  const param_type &param() const { return param_; }
356 
357  void param(const param_type &param)
358  {
359  param_ = param;
360  reset();
361  }
362 
363  void param(param_type &&param)
364  {
365  param_ = std::move(param);
366  reset();
367  }
368 
369  template <typename RNGType>
370  void operator()(RNGType &rng, result_type *r)
371  {
372  operator()(rng, r, param_);
373  }
374 
375  template <typename RNGType>
376  void operator()(RNGType &rng, result_type *r, const param_type &param)
377  {
378  generate(rng, r, param);
379  }
380 
381  template <typename RNGType>
382  void operator()(RNGType &rng, std::size_t n, result_type *r)
383  {
384  operator()(rng, n, r, param_);
385  }
386 
387  template <typename RNGType>
389  RNGType &rng, std::size_t n, result_type *r, const param_type &param)
390  {
391  if (param.is_scalar_mean_ && param.is_scalar_chol_) {
393  rng, n, r, param.dim(), param.mean()[0], param.chol()[0]);
394  } else if (param.is_scalar_mean_ && !param.is_scalar_chol_) {
396  rng, n, r, param.dim(), param.mean()[0], param.chol());
397  } else if (!param.is_scalar_mean_ && param.is_scalar_chol_) {
399  rng, n, r, param.dim(), param.mean(), param.chol()[0]);
400  } else if (!param.is_scalar_mean_ && !param.is_scalar_chol_) {
402  rng, n, r, param.dim(), param.mean(), param.chol());
403  }
404  }
405 
406  friend bool operator==(
407  const distribution_type &dist1, const distribution_type &dist2)
408  {
409  if (dist1.param_ != dist2.param_) {
410  return false;
411  }
412  return true;
413  }
414 
415  friend bool operator!=(
416  const distribution_type &dist1, const distribution_type &dist2)
417  {
418  return !(dist1 == dist2);
419  }
420 
421  template <typename CharT, typename Traits>
422  friend std::basic_ostream<CharT, Traits> &operator<<(
423  std::basic_ostream<CharT, Traits> &os, const distribution_type &dist)
424  {
425  if (!os) {
426  return os;
427  }
428 
429  os << dist.param_;
430 
431  return os;
432  }
433 
434  template <typename CharT, typename Traits>
435  friend std::basic_istream<CharT, Traits> &operator>>(
436  std::basic_istream<CharT, Traits> &is, distribution_type &dist)
437  {
438  if (!is) {
439  return is;
440  }
441 
442  param_type param;
443  is >> std::ws >> param;
444  if (is) {
445  dist.param_ = std::move(param);
446  }
447 
448  return is;
449  }
450 
451  private:
452  param_type param_;
453 
454  template <typename RNGType>
455  void generate(RNGType &rng, result_type *r, const param_type &param)
456  {
457  MCKL_PUSH_CLANG_WARNING("-Wfloat-equal")
458  MCKL_PUSH_INTEL_WARNING(1572) // floating-point comparison
459  if (param.is_scalar_mean_ && param.is_scalar_chol_) {
461  param.mean()[0], param.chol()[0]);
462  for (std::size_t i = 0; i != param.dim(); ++i) {
463  r[i] = normal(rng);
464  }
465  } else if (param.is_scalar_mean_ && !param.is_scalar_chol_) {
466  NormalDistribution<RealType> normal(0, 1);
467  for (std::size_t i = 0; i != param.dim(); ++i) {
468  r[i] = normal(rng);
469  }
470  mulchol(r, param);
471  if (param.mean()[0] != 0) {
472  add<result_type>(param.dim(), param.mean(), r, r);
473  }
474  } else if (!param.is_scalar_mean_ && param.is_scalar_chol_) {
475  NormalDistribution<RealType> normal(0, param.chol()[0]);
476  for (std::size_t i = 0; i != param.dim(); ++i) {
477  r[i] = normal(rng);
478  }
479  add<result_type>(param.dim(), param.mean(), r, r);
480  } else if (!param.is_scalar_mean_ && !param.is_scalar_chol_) {
481  NormalDistribution<RealType> normal(0, 1);
482  normal(rng, param.dim(), r);
483  mulchol(r, param);
484  add<result_type>(param.dim(), param.mean(), r, r);
485  }
488  }
489 
490  void mulchol(float *r, const param_type &param)
491  {
492  internal::cblas_stpmv(internal::CblasRowMajor, internal::CblasLower,
493  internal::CblasNoTrans, internal::CblasNonUnit,
494  static_cast<MCKL_BLAS_INT>(dim()), param.chol(), r, 1);
495  }
496 
497  void mulchol(double *r, const param_type &param)
498  {
499  internal::cblas_dtpmv(internal::CblasRowMajor, internal::CblasLower,
500  internal::CblasNoTrans, internal::CblasNonUnit,
501  static_cast<MCKL_BLAS_INT>(dim()), param.chol(), r, 1);
502  }
503 }; // class NormalMVDistribution
504 
505 template <typename RealType, typename RNGType>
506 inline void rand(
507  RNGType &rng, NormalMVDistribution<RealType> &distribution, RealType *r)
508 {
509  distribution(rng, r);
510 }
511 
512 template <typename RealType, typename RNGType>
513 inline void rand(RNGType &rng, NormalMVDistribution<RealType> &distribution,
514  std::size_t n, RealType *r)
515 {
516  distribution(rng, n, r);
517 }
518 
519 } // namespace mckl
520 
521 #endif // MCKL_RANDOM_NORMAL_MV_DISTRIBUTION_HPP
Multivariate Normal distribution.
friend std::basic_istream< CharT, Traits > & operator>>(std::basic_istream< CharT, Traits > &is, distribution_type &dist)
friend bool operator!=(const param_type &param1, const param_type &param2)
NormalMVDistribution(std::size_t dim, result_type mean, result_type chol)
Construct a distribution with scalar mean and scalar covariance.
friend std::basic_ostream< CharT, Traits > & operator<<(std::basic_ostream< CharT, Traits > &os, const param_type &param)
void normal_distribution(MKLEngine< BRNG, Bits > &rng, std::size_t n, float *r, float mean, float stddev)
Definition: mkl.hpp:1386
void normal_mv_distribution_mulchol(std::size_t n, float *r, std::size_t dim, const float *chol)
NormalMVDistribution(const param_type &param)
friend std::basic_istream< CharT, Traits > & operator>>(std::basic_istream< CharT, Traits > &is, param_type &param)
const result_type * mean() const
void normal_mv_distribution(MKLEngine< BRNG, Bits > &rng, std::size_t n, float *r, std::size_t m, const float *mean, const float *chol)
Definition: mkl.hpp:1402
void operator()(RNGType &rng, result_type *r, const param_type &param)
#define MCKL_PUSH_CLANG_WARNING(warning)
Definition: compiler.h:63
void param(const param_type &param)
friend bool operator==(const param_type &param1, const param_type &param2)
void param(param_type &&param)
friend bool operator!=(const distribution_type &dist1, const distribution_type &dist2)
std::vector< T, Alloc > Vector
std::vector with Allocator as the default allocator
Definition: memory.hpp:435
STL namespace.
NormalMVDistribution(std::size_t dim, const result_type *mean, const result_type *chol)
Construct a distribution with vector mean and vector covariance.
void operator()(RNGType &rng, std::size_t n, result_type *r, const param_type &param)
NormalMVDistribution(std::size_t dim, const result_type *mean, result_type chol)
Construct a distribution with vector mean and scalar covariance.
const result_type * chol() const
NormalMVDistribution(std::size_t dim=1)
Construct a distribution with scalar mean and scalar covariance.
param_type(std::size_t dim, const result_type *mean, const result_type *chol)
friend std::basic_ostream< CharT, Traits > & operator<<(std::basic_ostream< CharT, Traits > &os, const distribution_type &dist)
#define MCKL_DEFINE_RANDOM_DISTRIBUTION_ASSERT_BLAS_TYPE(Name)
const param_type & param() const
param_type(std::size_t dim, const result_type *mean, result_type chol)
param_type(std::size_t dim, result_type mean, const result_type *chol)
param_type(std::size_t dim, result_type mean, result_type chol)
#define MCKL_PUSH_INTEL_WARNING(wid)
Definition: compiler.h:88
Definition: mcmc.hpp:40
void rand(RNGType &rng, ArcsineDistribution< RealType > &distribution, std::size_t N, RealType *r)
#define MCKL_POP_CLANG_WARNING
Definition: compiler.h:66
friend bool operator==(const distribution_type &dist1, const distribution_type &dist2)
OutputIter min(OutputIter first) const
NormalMVDistribution(param_type &&param)
NormalMVDistribution(std::size_t dim, result_type mean, const result_type *chol)
Construct a distribution with scalar mean and vector covariance.
OutputIter max(OutputIter first) const
void operator()(RNGType &rng, result_type *r)
#define MCKL_POP_INTEL_WARNING
Definition: compiler.h:89
void operator()(RNGType &rng, std::size_t n, result_type *r)
void add(std::size_t n, const float *a, const float *b, float *y)
Definition: vmf.hpp:119