EigenRand  0.5.0
 
Loading...
Searching...
No Matches
MvNormal.h
Go to the documentation of this file.
1
12#ifndef EIGENRAND_MVDISTS_MVNORMAL_H
13#define EIGENRAND_MVDISTS_MVNORMAL_H
14
15namespace 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;
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
118 namespace detail {
119 template<typename MeanTy, typename CovTy>
120 constexpr bool either_is_dynamic() {
121 return (MatrixBase<MeanTy>::RowsAtCompileTime == Eigen::Dynamic) ||
122 (MatrixBase<CovTy>::RowsAtCompileTime == Eigen::Dynamic);
123 }
124
125 template<typename MeanTy, typename CovTy>
126 constexpr bool normal_check_dims() {
127 return (either_is_dynamic<MeanTy, CovTy>() || MatrixBase<MeanTy>::RowsAtCompileTime == MatrixBase<CovTy>::RowsAtCompileTime) &&
128 MatrixBase<CovTy>::RowsAtCompileTime == MatrixBase<CovTy>::ColsAtCompileTime;
129 }
130 }
131
140 template<typename MeanTy, typename CovTy>
141 inline auto makeMvNormalGen(const MatrixBase<MeanTy>& mean, const MatrixBase<CovTy>& cov)
142 -> MvNormalGen<typename MatrixBase<MeanTy>::Scalar, MatrixBase<MeanTy>::RowsAtCompileTime>
143 {
144 static_assert(
145 std::is_same<typename MatrixBase<MeanTy>::Scalar, typename MatrixBase<CovTy>::Scalar>::value,
146 "Derived::Scalar must be the same with `mean` and `cov`'s Scalar."
147 );
148 static_assert(
149 detail::normal_check_dims<MeanTy, CovTy>(),
150 "assert: mean.RowsAtCompileTime == cov.RowsAtCompileTime && cov.RowsAtCompileTime == cov.ColsAtCompileTime"
151 );
152 return { mean, cov };
153 }
154
163 template<typename MeanTy, typename LTTy>
164 inline auto makeMvNormalGenFromLt(const MatrixBase<MeanTy>& mean, const MatrixBase<LTTy>& lt)
165 -> MvNormalGen<typename MatrixBase<MeanTy>::Scalar, MatrixBase<MeanTy>::RowsAtCompileTime>
166 {
167 static_assert(
168 std::is_same<typename MatrixBase<MeanTy>::Scalar, typename MatrixBase<LTTy>::Scalar>::value,
169 "Derived::Scalar must be the same with `mean` and `lt`'s Scalar."
170 );
171 static_assert(
172 detail::normal_check_dims<MeanTy, LTTy>(),
173 "assert: mean.RowsAtCompileTime == lt.RowsAtCompileTime && lt.RowsAtCompileTime == lt.ColsAtCompileTime"
174 );
175 return { mean, lt, lower_triangular };
176 }
177
184 template<typename _Scalar, Index Dim>
185 class WishartGen : public MvMatGenBase<WishartGen<_Scalar, Dim>, _Scalar, Dim>
186 {
187 static_assert(std::is_floating_point<_Scalar>::value, "`WishartGen` needs floating point types.");
188
189 Index df;
190 Matrix<_Scalar, Dim, Dim> chol;
191 StdNormalGen<_Scalar> stdnorm;
192 std::vector<ChiSquaredGen<_Scalar>> chisqs;
193 public:
201 template<typename ScaleTy>
202 WishartGen(Index _df, const MatrixBase<ScaleTy>& _lt, detail::LowerTriangular)
203 : df{ _df }, chol{ _lt }
204 {
205 eigen_assert(df > chol.rows() - 1);
206 eigen_assert(chol.rows() == chol.cols());
207
208 for (Index i = 0; i < chol.rows(); ++i)
209 {
210 chisqs.emplace_back(df - i);
211 }
212 }
213
221 template<typename ScaleTy>
222 WishartGen(Index _df, const MatrixBase<ScaleTy>& _scale, detail::FullMatrix = {})
223 : WishartGen{ _df, detail::template get_lt<_Scalar, Dim>(_scale), lower_triangular }
224 {
225 eigen_assert(_scale.rows() == _scale.cols());
226 }
227
228 WishartGen(const WishartGen&) = default;
229 WishartGen(WishartGen&&) = default;
230
231 WishartGen& operator=(const WishartGen&) = default;
232 WishartGen& operator=(WishartGen&&) = default;
233
234 Index dims() const { return chol.rows(); }
235
236 template<typename Urng>
237 inline Matrix<_Scalar, Dim, -1> generate(Urng&& urng, Index samples)
238 {
239 const Index dim = chol.rows();
240 const Index normSamples = samples * dim * (dim - 1) / 2;
241 using ArrayXs = Array<_Scalar, -1, 1>;
242 Matrix<_Scalar, Dim, -1> rand_mat(dim, dim * samples), tmp(dim, dim * samples);
243
244 _Scalar* ptr = tmp.data();
245 Map<ArrayXs>{ ptr, normSamples } = stdnorm.template generate<ArrayXs>(normSamples, 1, urng);
246 for (Index j = 0; j < samples; ++j)
247 {
248 for (Index i = 0; i < dim - 1; ++i)
249 {
250 rand_mat.col(i + j * dim).tail(dim - 1 - i) = Map<ArrayXs>{ ptr, dim - 1 - i };
251 ptr += dim - 1 - i;
252 }
253 }
254
255 for (Index i = 0; i < dim; ++i)
256 {
257 _Scalar* ptr = tmp.data();
258 Map<ArrayXs>{ ptr, samples } = chisqs[i].template generate<ArrayXs>(samples, 1, urng).sqrt();
259 for (Index j = 0; j < samples; ++j)
260 {
261 rand_mat(i, i + j * dim) = *ptr++;
262 }
263 }
264
265 for (Index j = 0; j < samples; ++j)
266 {
267 rand_mat.middleCols(j * dim, dim).template triangularView<StrictlyUpper>().setZero();
268 }
269 tmp.noalias() = chol * rand_mat;
270
271 for (Index j = 0; j < samples; ++j)
272 {
273 auto t = tmp.middleCols(j * dim, dim);
274 rand_mat.middleCols(j * dim, dim).noalias() = t * t.transpose();
275 }
276 return rand_mat;
277 }
278
279 template<typename Urng>
280 inline Matrix<_Scalar, Dim, -1> generate(Urng&& urng)
281 {
282 const Index dim = chol.rows();
283 const Index normSamples = dim * (dim - 1) / 2;
284 using ArrayXs = Array<_Scalar, -1, 1>;
285 Matrix<_Scalar, Dim, Dim> rand_mat(dim, dim);
286 Map<ArrayXs>{ rand_mat.data(), normSamples } = stdnorm.template generate<ArrayXs>(normSamples, 1, urng);
287
288 for (Index i = 0; i < dim / 2; ++i)
289 {
290 rand_mat.col(dim - 2 - i).tail(i + 1) = rand_mat.col(i).head(i + 1);
291 }
292
293 for (Index i = 0; i < dim; ++i)
294 {
295 rand_mat(i, i) = chisqs[i].template generate<Array<_Scalar, 1, 1>>(1, 1, urng).sqrt()(0);
296 }
297 rand_mat.template triangularView<StrictlyUpper>().setZero();
298
299 auto t = (chol * rand_mat).eval();
300 return (t * t.transpose()).eval();
301 }
302 };
303
311 template<typename ScaleTy>
312 inline auto makeWishartGen(Index df, const MatrixBase<ScaleTy>& scale)
313 -> WishartGen<typename MatrixBase<ScaleTy>::Scalar, MatrixBase<ScaleTy>::RowsAtCompileTime>
314 {
315 static_assert(
316 MatrixBase<ScaleTy>::RowsAtCompileTime == MatrixBase<ScaleTy>::ColsAtCompileTime,
317 "assert: scale.RowsAtCompileTime == scale.ColsAtCompileTime"
318 );
319 return { df, scale };
320 }
321
329 template<typename LTTy>
330 inline auto makeWishartGenFromLt(Index df, const MatrixBase<LTTy>& lt)
331 -> WishartGen<typename MatrixBase<LTTy>::Scalar, MatrixBase<LTTy>::RowsAtCompileTime>
332 {
333 static_assert(
334 MatrixBase<LTTy>::RowsAtCompileTime == MatrixBase<LTTy>::ColsAtCompileTime,
335 "assert: lt.RowsAtCompileTime == lt.ColsAtCompileTime"
336 );
337 return { df, lt, lower_triangular };
338 }
339
346 template<typename _Scalar, Index Dim>
347 class InvWishartGen : public MvMatGenBase<InvWishartGen<_Scalar, Dim>, _Scalar, Dim>
348 {
349 static_assert(std::is_floating_point<_Scalar>::value, "`InvWishartGen` needs floating point types.");
350
351 Index df;
352 Matrix<_Scalar, Dim, Dim> chol;
353 StdNormalGen<_Scalar> stdnorm;
354 std::vector<ChiSquaredGen<_Scalar>> chisqs;
355 public:
363 template<typename ScaleTy>
364 InvWishartGen(Index _df, const MatrixBase<ScaleTy>& _ilt, detail::InvLowerTriangular)
365 : df{ _df }, chol{ _ilt }
366 {
367 eigen_assert(df > chol.rows() - 1);
368 eigen_assert(chol.rows() == chol.cols());
369
370 for (Index i = 0; i < chol.rows(); ++i)
371 {
372 chisqs.emplace_back(df - i);
373 }
374 }
375
383 template<typename ScaleTy>
384 InvWishartGen(Index _df, const MatrixBase<ScaleTy>& _scale, detail::FullMatrix = {})
385 : InvWishartGen{ _df, detail::template get_lt<_Scalar, Dim>(_scale.inverse()), inv_lower_triangular }
386 {
387 eigen_assert(_scale.rows() == _scale.cols());
388 }
389
390 InvWishartGen(const InvWishartGen&) = default;
391 InvWishartGen(InvWishartGen&&) = default;
392
393 InvWishartGen& operator=(const InvWishartGen&) = default;
394 InvWishartGen& operator=(InvWishartGen&&) = default;
395
396 Index dims() const { return chol.rows(); }
397
398 template<typename Urng>
399 inline Matrix<_Scalar, Dim, -1> generate(Urng&& urng, Index samples)
400 {
401 const Index dim = chol.rows();
402 const Index normSamples = samples * dim * (dim - 1) / 2;
403 using ArrayXs = Array<_Scalar, -1, 1>;
404 Matrix<_Scalar, Dim, -1> rand_mat(dim, dim * samples), tmp(dim, dim * samples);
405
406 _Scalar* ptr = tmp.data();
407 Map<ArrayXs>{ ptr, normSamples } = stdnorm.template generate<ArrayXs>(normSamples, 1, urng);
408 for (Index j = 0; j < samples; ++j)
409 {
410 for (Index i = 0; i < dim - 1; ++i)
411 {
412 rand_mat.col(i + j * dim).tail(dim - 1 - i) = Map<ArrayXs>{ ptr, dim - 1 - i };
413 ptr += dim - 1 - i;
414 }
415 }
416
417 for (Index i = 0; i < dim; ++i)
418 {
419 _Scalar* ptr = tmp.data();
420 Map<ArrayXs>{ ptr, samples } = chisqs[i].template generate<ArrayXs>(samples, 1, urng).sqrt();
421 for (Index j = 0; j < samples; ++j)
422 {
423 rand_mat(i, i + j * dim) = *ptr++;
424 }
425 }
426
427 for (Index j = 0; j < samples; ++j)
428 {
429 rand_mat.middleCols(j * dim, dim).template triangularView<StrictlyUpper>().setZero();
430 }
431 tmp.noalias() = chol * rand_mat;
432
433 auto id = Eigen::Matrix<_Scalar, Dim, Dim>::Identity(dim, dim);
434 for (Index j = 0; j < samples; ++j)
435 {
436 auto t = tmp.middleCols(j * dim, dim);
437 auto u = rand_mat.middleCols(j * dim, dim);
438 u.noalias() = t.template triangularView<Lower>().solve(id);
439 t.noalias() = u.transpose() * u;
440 }
441 return tmp;
442 }
443
444 template<typename Urng>
445 inline Matrix<_Scalar, Dim, -1> generate(Urng&& urng)
446 {
447 const Index dim = chol.rows();
448 const Index normSamples = dim * (dim - 1) / 2;
449 using ArrayXs = Array<_Scalar, -1, 1>;
450 Matrix<_Scalar, Dim, Dim> rand_mat(dim, dim);
451 Map<ArrayXs>{ rand_mat.data(), normSamples } = stdnorm.template generate<ArrayXs>(normSamples, 1, urng);
452
453 for (Index i = 0; i < dim / 2; ++i)
454 {
455 rand_mat.col(dim - 2 - i).tail(i + 1) = rand_mat.col(i).head(i + 1);
456 }
457
458 for (Index i = 0; i < dim; ++i)
459 {
460 rand_mat(i, i) = chisqs[i].template generate<Array<_Scalar, 1, 1>>(1, 1, urng).sqrt()(0);
461 }
462 rand_mat.template triangularView<StrictlyUpper>().setZero();
463
464 auto t = (chol * rand_mat).eval();
465 auto id = Eigen::Matrix<_Scalar, Dim, Dim>::Identity(dim, dim);
466 rand_mat.noalias() = t.template triangularView<Lower>().solve(id);
467
468 return (rand_mat.transpose() * rand_mat).eval();
469 }
470 };
471
479 template<typename ScaleTy>
480 inline auto makeInvWishartGen(Index df, const MatrixBase<ScaleTy>& scale)
481 -> InvWishartGen<typename MatrixBase<ScaleTy>::Scalar, MatrixBase<ScaleTy>::RowsAtCompileTime>
482 {
483 static_assert(
484 MatrixBase<ScaleTy>::RowsAtCompileTime == MatrixBase<ScaleTy>::ColsAtCompileTime,
485 "assert: scale.RowsAtCompileTime == scale.ColsAtCompileTime"
486 );
487 return { df, scale };
488 }
489
497 template<typename ILTTy>
498 inline auto makeInvWishartGenFromIlt(Index df, const MatrixBase<ILTTy>& ilt)
499 -> InvWishartGen<typename MatrixBase<ILTTy>::Scalar, MatrixBase<ILTTy>::RowsAtCompileTime>
500 {
501 static_assert(
502 MatrixBase<ILTTy>::RowsAtCompileTime == MatrixBase<ILTTy>::ColsAtCompileTime,
503 "assert: ilt.RowsAtCompileTime == ilt.ColsAtCompileTime"
504 );
505 return { df, ilt, inv_lower_triangular };
506 }
507 }
508}
509
510#endif
Generator of real matrices on a inverse Wishart distribution.
Definition MvNormal.h:348
InvWishartGen(Index _df, const MatrixBase< ScaleTy > &_scale, detail::FullMatrix={})
Construct a new inverse Wishart generator.
Definition MvNormal.h:384
InvWishartGen(Index _df, const MatrixBase< ScaleTy > &_ilt, detail::InvLowerTriangular)
Construct a new inverse Wishart generator.
Definition MvNormal.h:364
Base class of all multivariate random matrix generators.
Definition Basic.h:225
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:175
Generator of reals on the standard normal distribution.
Definition NormalExp.h:27
Generator of real matrices on a Wishart distribution.
Definition MvNormal.h:186
WishartGen(Index _df, const MatrixBase< ScaleTy > &_scale, detail::FullMatrix={})
Construct a new Wishart generator from scale matrix.
Definition MvNormal.h:222
WishartGen(Index _df, const MatrixBase< ScaleTy > &_lt, detail::LowerTriangular)
Construct a new Wishart generator from lower triangular matrix of decomposed scale.
Definition MvNormal.h:202
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:330
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:141
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:312
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:164
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:480
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:498