EigenRand  0.4.0-alpha
MvNormal.h
Go to the documentation of this file.
1 
12 #ifndef EIGENRAND_MVDISTS_MVNORMAL_H
13 #define EIGENRAND_MVDISTS_MVNORMAL_H
14 
15 namespace Eigen
16 {
17  namespace Rand
18  {
19  namespace detail
20  {
21  template<typename _Scalar, Index Dim, typename _Mat>
22  Matrix<_Scalar, Dim, Dim> get_lt(const MatrixBase<_Mat>& mat)
23  {
24  LLT<Matrix<_Scalar, Dim, Dim>> llt(mat);
25  if (llt.info() == Eigen::Success)
26  {
27  return llt.matrixL();
28  }
29  else
30  {
31  SelfAdjointEigenSolver<Matrix<_Scalar, Dim, Dim>> solver(mat);
32  if (solver.info() != Eigen::Success)
33  {
34  throw std::runtime_error{ "The matrix cannot be solved!" };
35  }
36  return solver.eigenvectors() * solver.eigenvalues().cwiseMax(0).cwiseSqrt().asDiagonal();
37  }
38  }
39 
40  class FullMatrix {};
41  class LowerTriangular {};
42  class InvLowerTriangular {};
43  }
44 
45  constexpr detail::FullMatrix full_matrix;
46  constexpr detail::LowerTriangular lower_triangular;
47  constexpr detail::InvLowerTriangular inv_lower_triangular;
48 
49 
56  template<typename _Scalar, Index Dim = -1>
57  class MvNormalGen : public MvVecGenBase<MvNormalGen<_Scalar, Dim>, _Scalar, Dim>
58  {
59  static_assert(std::is_floating_point<_Scalar>::value, "`MvNormalGen` needs floating point types.");
60 
61  Matrix<_Scalar, Dim, 1> mean;
62  Matrix<_Scalar, Dim, Dim> lt;
63  StdNormalGen<_Scalar> stdnorm;
64 
65  public:
74  template<typename MeanTy, typename LTTy>
75  MvNormalGen(const MatrixBase<MeanTy>& _mean, const MatrixBase<LTTy>& _lt, detail::LowerTriangular)
76  : mean{ _mean }, lt{ _lt }
77  {
78  eigen_assert(_mean.cols() == 1 && _mean.rows() == _lt.rows() && _lt.rows() == _lt.cols());
79  }
80 
89  template<typename MeanTy, typename CovTy>
90  MvNormalGen(const MatrixBase<MeanTy>& _mean, const MatrixBase<CovTy>& _cov, detail::FullMatrix = {})
91  : MvNormalGen{ _mean, detail::template get_lt<_Scalar, Dim>(_cov), lower_triangular }
92  {
93  }
94 
95  MvNormalGen(const MvNormalGen&) = default;
96  MvNormalGen(MvNormalGen&&) = default;
97 
98  MvNormalGen& operator=(const MvNormalGen&) = default;
99  MvNormalGen& operator=(MvNormalGen&&) = default;
100 
101  Index dims() const { return mean.rows(); }
102 
103  template<typename Urng>
104  inline auto generate(Urng&& urng, Index samples)
105  -> decltype((lt * stdnorm.template generate<Matrix<_Scalar, Dim, -1>>(mean.rows(), samples, std::forward<Urng>(urng))).colwise() + mean)
106  {
107  return (lt * stdnorm.template generate<Matrix<_Scalar, Dim, -1>>(mean.rows(), samples, std::forward<Urng>(urng))).colwise() + mean;
108  }
109 
110  template<typename Urng>
111  inline auto generate(Urng&& urng)
112  -> decltype((lt * stdnorm.template generate<Matrix<_Scalar, Dim, 1>>(mean.rows(), 1, std::forward<Urng>(urng))).colwise() + mean)
113  {
114  return (lt * stdnorm.template generate<Matrix<_Scalar, Dim, 1>>(mean.rows(), 1, std::forward<Urng>(urng))).colwise() + mean;
115  }
116  };
117 
126  template<typename MeanTy, typename CovTy>
127  inline auto makeMvNormalGen(const MatrixBase<MeanTy>& mean, const MatrixBase<CovTy>& cov)
128  -> MvNormalGen<typename MatrixBase<MeanTy>::Scalar, MatrixBase<MeanTy>::RowsAtCompileTime>
129  {
130  static_assert(
131  std::is_same<typename MatrixBase<MeanTy>::Scalar, typename MatrixBase<CovTy>::Scalar>::value,
132  "Derived::Scalar must be the same with `mean` and `cov`'s Scalar."
133  );
134  static_assert(
135  MatrixBase<MeanTy>::RowsAtCompileTime == MatrixBase<CovTy>::RowsAtCompileTime &&
136  MatrixBase<CovTy>::RowsAtCompileTime == MatrixBase<CovTy>::ColsAtCompileTime,
137  "assert: mean.RowsAtCompileTime == cov.RowsAtCompileTime && cov.RowsAtCompileTime == cov.ColsAtCompileTime"
138  );
139  return { mean, cov };
140  }
141 
150  template<typename MeanTy, typename LTTy>
151  inline auto makeMvNormalGenFromLt(const MatrixBase<MeanTy>& mean, const MatrixBase<LTTy>& lt)
152  -> MvNormalGen<typename MatrixBase<MeanTy>::Scalar, MatrixBase<MeanTy>::RowsAtCompileTime>
153  {
154  static_assert(
155  std::is_same<typename MatrixBase<MeanTy>::Scalar, typename MatrixBase<LTTy>::Scalar>::value,
156  "Derived::Scalar must be the same with `mean` and `lt`'s Scalar."
157  );
158  static_assert(
159  MatrixBase<MeanTy>::RowsAtCompileTime == MatrixBase<LTTy>::RowsAtCompileTime &&
160  MatrixBase<LTTy>::RowsAtCompileTime == MatrixBase<LTTy>::ColsAtCompileTime,
161  "assert: mean.RowsAtCompileTime == lt.RowsAtCompileTime && lt.RowsAtCompileTime == lt.ColsAtCompileTime"
162  );
163  return { mean, lt, lower_triangular };
164  }
165 
172  template<typename _Scalar, Index Dim>
173  class WishartGen : public MvMatGenBase<WishartGen<_Scalar, Dim>, _Scalar, Dim>
174  {
175  static_assert(std::is_floating_point<_Scalar>::value, "`WishartGen` needs floating point types.");
176 
177  Index df;
178  Matrix<_Scalar, Dim, Dim> chol;
179  StdNormalGen<_Scalar> stdnorm;
180  std::vector<ChiSquaredGen<_Scalar>> chisqs;
181  public:
189  template<typename ScaleTy>
190  WishartGen(Index _df, const MatrixBase<ScaleTy>& _lt, detail::LowerTriangular)
191  : df{ _df }, chol{ _lt }
192  {
193  eigen_assert(df > chol.rows() - 1);
194  eigen_assert(chol.rows() == chol.cols());
195 
196  for (Index i = 0; i < chol.rows(); ++i)
197  {
198  chisqs.emplace_back(df - i);
199  }
200  }
201 
209  template<typename ScaleTy>
210  WishartGen(Index _df, const MatrixBase<ScaleTy>& _scale, detail::FullMatrix = {})
211  : WishartGen{ _df, detail::template get_lt<_Scalar, Dim>(_scale), lower_triangular }
212  {
213  eigen_assert(_scale.rows() == _scale.cols());
214  }
215 
216  WishartGen(const WishartGen&) = default;
217  WishartGen(WishartGen&&) = default;
218 
219  WishartGen& operator=(const WishartGen&) = default;
220  WishartGen& operator=(WishartGen&&) = default;
221 
222  Index dims() const { return chol.rows(); }
223 
224  template<typename Urng>
225  inline Matrix<_Scalar, Dim, -1> generate(Urng&& urng, Index samples)
226  {
227  const Index dim = chol.rows();
228  const Index normSamples = samples * dim * (dim - 1) / 2;
229  using ArrayXs = Array<_Scalar, -1, 1>;
230  Matrix<_Scalar, Dim, -1> rand_mat(dim, dim * samples), tmp(dim, dim * samples);
231 
232  _Scalar* ptr = tmp.data();
233  Map<ArrayXs>{ ptr, normSamples } = stdnorm.template generate<ArrayXs>(normSamples, 1, urng);
234  for (Index j = 0; j < samples; ++j)
235  {
236  for (Index i = 0; i < dim - 1; ++i)
237  {
238  rand_mat.col(i + j * dim).tail(dim - 1 - i) = Map<ArrayXs>{ ptr, dim - 1 - i };
239  ptr += dim - 1 - i;
240  }
241  }
242 
243  for (Index i = 0; i < dim; ++i)
244  {
245  _Scalar* ptr = tmp.data();
246  Map<ArrayXs>{ ptr, samples } = chisqs[i].template generate<ArrayXs>(samples, 1, urng).sqrt();
247  for (Index j = 0; j < samples; ++j)
248  {
249  rand_mat(i, i + j * dim) = *ptr++;
250  }
251  }
252 
253  for (Index j = 0; j < samples; ++j)
254  {
255  rand_mat.middleCols(j * dim, dim).template triangularView<StrictlyUpper>().setZero();
256  }
257  tmp.noalias() = chol * rand_mat;
258 
259  for (Index j = 0; j < samples; ++j)
260  {
261  auto t = tmp.middleCols(j * dim, dim);
262  rand_mat.middleCols(j * dim, dim).noalias() = t * t.transpose();
263  }
264  return rand_mat;
265  }
266 
267  template<typename Urng>
268  inline Matrix<_Scalar, Dim, -1> generate(Urng&& urng)
269  {
270  const Index dim = chol.rows();
271  const Index normSamples = dim * (dim - 1) / 2;
272  using ArrayXs = Array<_Scalar, -1, 1>;
273  Matrix<_Scalar, Dim, Dim> rand_mat(dim, dim);
274  Map<ArrayXs>{ rand_mat.data(), normSamples } = stdnorm.template generate<ArrayXs>(normSamples, 1, urng);
275 
276  for (Index i = 0; i < dim / 2; ++i)
277  {
278  rand_mat.col(dim - 2 - i).tail(i + 1) = rand_mat.col(i).head(i + 1);
279  }
280 
281  for (Index i = 0; i < dim; ++i)
282  {
283  rand_mat(i, i) = chisqs[i].template generate<Array<_Scalar, 1, 1>>(1, 1, urng).sqrt()(0);
284  }
285  rand_mat.template triangularView<StrictlyUpper>().setZero();
286 
287  auto t = (chol * rand_mat).eval();
288  return (t * t.transpose()).eval();
289  }
290  };
291 
299  template<typename ScaleTy>
300  inline auto makeWishartGen(Index df, const MatrixBase<ScaleTy>& scale)
301  -> WishartGen<typename MatrixBase<ScaleTy>::Scalar, MatrixBase<ScaleTy>::RowsAtCompileTime>
302  {
303  static_assert(
304  MatrixBase<ScaleTy>::RowsAtCompileTime == MatrixBase<ScaleTy>::ColsAtCompileTime,
305  "assert: scale.RowsAtCompileTime == scale.ColsAtCompileTime"
306  );
307  return { df, scale };
308  }
309 
317  template<typename LTTy>
318  inline auto makeWishartGenFromLt(Index df, const MatrixBase<LTTy>& lt)
319  -> WishartGen<typename MatrixBase<LTTy>::Scalar, MatrixBase<LTTy>::RowsAtCompileTime>
320  {
321  static_assert(
322  MatrixBase<LTTy>::RowsAtCompileTime == MatrixBase<LTTy>::ColsAtCompileTime,
323  "assert: lt.RowsAtCompileTime == lt.ColsAtCompileTime"
324  );
325  return { df, lt, lower_triangular };
326  }
327 
334  template<typename _Scalar, Index Dim>
335  class InvWishartGen : public MvMatGenBase<InvWishartGen<_Scalar, Dim>, _Scalar, Dim>
336  {
337  static_assert(std::is_floating_point<_Scalar>::value, "`InvWishartGen` needs floating point types.");
338 
339  Index df;
340  Matrix<_Scalar, Dim, Dim> chol;
341  StdNormalGen<_Scalar> stdnorm;
342  std::vector<ChiSquaredGen<_Scalar>> chisqs;
343  public:
351  template<typename ScaleTy>
352  InvWishartGen(Index _df, const MatrixBase<ScaleTy>& _ilt, detail::InvLowerTriangular)
353  : df{ _df }, chol{ _ilt }
354  {
355  eigen_assert(df > chol.rows() - 1);
356  eigen_assert(chol.rows() == chol.cols());
357 
358  for (Index i = 0; i < chol.rows(); ++i)
359  {
360  chisqs.emplace_back(df - i);
361  }
362  }
363 
371  template<typename ScaleTy>
372  InvWishartGen(Index _df, const MatrixBase<ScaleTy>& _scale, detail::FullMatrix = {})
373  : InvWishartGen{ _df, detail::template get_lt<_Scalar, Dim>(_scale.inverse()), inv_lower_triangular }
374  {
375  eigen_assert(_scale.rows() == _scale.cols());
376  }
377 
378  InvWishartGen(const InvWishartGen&) = default;
379  InvWishartGen(InvWishartGen&&) = default;
380 
381  InvWishartGen& operator=(const InvWishartGen&) = default;
382  InvWishartGen& operator=(InvWishartGen&&) = default;
383 
384  Index dims() const { return chol.rows(); }
385 
386  template<typename Urng>
387  inline Matrix<_Scalar, Dim, -1> generate(Urng&& urng, Index samples)
388  {
389  const Index dim = chol.rows();
390  const Index normSamples = samples * dim * (dim - 1) / 2;
391  using ArrayXs = Array<_Scalar, -1, 1>;
392  Matrix<_Scalar, Dim, -1> rand_mat(dim, dim * samples), tmp(dim, dim * samples);
393 
394  _Scalar* ptr = tmp.data();
395  Map<ArrayXs>{ ptr, normSamples } = stdnorm.template generate<ArrayXs>(normSamples, 1, urng);
396  for (Index j = 0; j < samples; ++j)
397  {
398  for (Index i = 0; i < dim - 1; ++i)
399  {
400  rand_mat.col(i + j * dim).tail(dim - 1 - i) = Map<ArrayXs>{ ptr, dim - 1 - i };
401  ptr += dim - 1 - i;
402  }
403  }
404 
405  for (Index i = 0; i < dim; ++i)
406  {
407  _Scalar* ptr = tmp.data();
408  Map<ArrayXs>{ ptr, samples } = chisqs[i].template generate<ArrayXs>(samples, 1, urng).sqrt();
409  for (Index j = 0; j < samples; ++j)
410  {
411  rand_mat(i, i + j * dim) = *ptr++;
412  }
413  }
414 
415  for (Index j = 0; j < samples; ++j)
416  {
417  rand_mat.middleCols(j * dim, dim).template triangularView<StrictlyUpper>().setZero();
418  }
419  tmp.noalias() = chol * rand_mat;
420 
421  auto id = Eigen::Matrix<_Scalar, Dim, Dim>::Identity(dim, dim);
422  for (Index j = 0; j < samples; ++j)
423  {
424  auto t = tmp.middleCols(j * dim, dim);
425  auto u = rand_mat.middleCols(j * dim, dim);
426  u.noalias() = t.template triangularView<Lower>().solve(id);
427  t.noalias() = u.transpose() * u;
428  }
429  return tmp;
430  }
431 
432  template<typename Urng>
433  inline Matrix<_Scalar, Dim, -1> generate(Urng&& urng)
434  {
435  const Index dim = chol.rows();
436  const Index normSamples = dim * (dim - 1) / 2;
437  using ArrayXs = Array<_Scalar, -1, 1>;
438  Matrix<_Scalar, Dim, Dim> rand_mat(dim, dim);
439  Map<ArrayXs>{ rand_mat.data(), normSamples } = stdnorm.template generate<ArrayXs>(normSamples, 1, urng);
440 
441  for (Index i = 0; i < dim / 2; ++i)
442  {
443  rand_mat.col(dim - 2 - i).tail(i + 1) = rand_mat.col(i).head(i + 1);
444  }
445 
446  for (Index i = 0; i < dim; ++i)
447  {
448  rand_mat(i, i) = chisqs[i].template generate<Array<_Scalar, 1, 1>>(1, 1, urng).sqrt()(0);
449  }
450  rand_mat.template triangularView<StrictlyUpper>().setZero();
451 
452  auto t = (chol * rand_mat).eval();
453  auto id = Eigen::Matrix<_Scalar, Dim, Dim>::Identity(dim, dim);
454  rand_mat.noalias() = t.template triangularView<Lower>().solve(id);
455 
456  return (rand_mat.transpose() * rand_mat).eval();
457  }
458  };
459 
467  template<typename ScaleTy>
468  inline auto makeInvWishartGen(Index df, const MatrixBase<ScaleTy>& scale)
469  -> InvWishartGen<typename MatrixBase<ScaleTy>::Scalar, MatrixBase<ScaleTy>::RowsAtCompileTime>
470  {
471  static_assert(
472  MatrixBase<ScaleTy>::RowsAtCompileTime == MatrixBase<ScaleTy>::ColsAtCompileTime,
473  "assert: scale.RowsAtCompileTime == scale.ColsAtCompileTime"
474  );
475  return { df, scale };
476  }
477 
485  template<typename ILTTy>
486  inline auto makeInvWishartGenFromIlt(Index df, const MatrixBase<ILTTy>& ilt)
487  -> InvWishartGen<typename MatrixBase<ILTTy>::Scalar, MatrixBase<ILTTy>::RowsAtCompileTime>
488  {
489  static_assert(
490  MatrixBase<ILTTy>::RowsAtCompileTime == MatrixBase<ILTTy>::ColsAtCompileTime,
491  "assert: ilt.RowsAtCompileTime == ilt.ColsAtCompileTime"
492  );
493  return { df, ilt, inv_lower_triangular };
494  }
495  }
496 }
497 
498 #endif
Generator of real matrices on a inverse Wishart distribution.
Definition: MvNormal.h:336
InvWishartGen(Index _df, const MatrixBase< ScaleTy > &_scale, detail::FullMatrix={})
Construct a new inverse Wishart generator.
Definition: MvNormal.h:372
InvWishartGen(Index _df, const MatrixBase< ScaleTy > &_ilt, detail::InvLowerTriangular)
Construct a new inverse Wishart generator.
Definition: MvNormal.h:352
Base class of all multivariate random matrix generators.
Definition: Basic.h:129
Generator of real vectors on a multivariate normal distribution.
Definition: MvNormal.h:58
MvNormalGen(const MatrixBase< MeanTy > &_mean, const MatrixBase< LTTy > &_lt, detail::LowerTriangular)
Construct a new multivariate normal generator from lower triangular matrix of decomposed covariance.
Definition: MvNormal.h:75
MvNormalGen(const MatrixBase< MeanTy > &_mean, const MatrixBase< CovTy > &_cov, detail::FullMatrix={})
Construct a new multivariate normal generator from covariance matrix.
Definition: MvNormal.h:90
Base class of all multivariate random vector generators.
Definition: Basic.h:84
Generator of reals on the standard normal distribution.
Definition: NormalExp.h:27
Generator of real matrices on a Wishart distribution.
Definition: MvNormal.h:174
WishartGen(Index _df, const MatrixBase< ScaleTy > &_scale, detail::FullMatrix={})
Construct a new Wishart generator from scale matrix.
Definition: MvNormal.h:210
WishartGen(Index _df, const MatrixBase< ScaleTy > &_lt, detail::LowerTriangular)
Construct a new Wishart generator from lower triangular matrix of decomposed scale.
Definition: MvNormal.h:190
auto makeWishartGenFromLt(Index df, const MatrixBase< LTTy > &lt) -> WishartGen< typename MatrixBase< LTTy >::Scalar, MatrixBase< LTTy >::RowsAtCompileTime >
helper function constructing Eigen::Rand::WishartGen
Definition: MvNormal.h:318
auto makeMvNormalGen(const MatrixBase< MeanTy > &mean, const MatrixBase< CovTy > &cov) -> MvNormalGen< typename MatrixBase< MeanTy >::Scalar, MatrixBase< MeanTy >::RowsAtCompileTime >
helper function constructing Eigen::Rand::MvNormal
Definition: MvNormal.h:127
auto makeWishartGen(Index df, const MatrixBase< ScaleTy > &scale) -> WishartGen< typename MatrixBase< ScaleTy >::Scalar, MatrixBase< ScaleTy >::RowsAtCompileTime >
helper function constructing Eigen::Rand::WishartGen
Definition: MvNormal.h:300
auto makeMvNormalGenFromLt(const MatrixBase< MeanTy > &mean, const MatrixBase< LTTy > &lt) -> MvNormalGen< typename MatrixBase< MeanTy >::Scalar, MatrixBase< MeanTy >::RowsAtCompileTime >
helper function constructing Eigen::Rand::MvNormal
Definition: MvNormal.h:151
auto makeInvWishartGen(Index df, const MatrixBase< ScaleTy > &scale) -> InvWishartGen< typename MatrixBase< ScaleTy >::Scalar, MatrixBase< ScaleTy >::RowsAtCompileTime >
helper function constructing Eigen::Rand::InvWishartGen
Definition: MvNormal.h:468
auto makeInvWishartGenFromIlt(Index df, const MatrixBase< ILTTy > &ilt) -> InvWishartGen< typename MatrixBase< ILTTy >::Scalar, MatrixBase< ILTTy >::RowsAtCompileTime >
helper function constructing Eigen::Rand::InvWishartGen
Definition: MvNormal.h:486