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
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:205
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:160
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