12#ifndef EIGENRAND_MVDISTS_MVNORMAL_H
13#define EIGENRAND_MVDISTS_MVNORMAL_H
21 template<
typename _Scalar, Index Dim,
typename _Mat>
22 Matrix<_Scalar, Dim, Dim> get_lt(
const MatrixBase<_Mat>& mat)
24 LLT<Matrix<_Scalar, Dim, Dim>> llt(mat);
25 if (llt.info() == Eigen::Success)
31 SelfAdjointEigenSolver<Matrix<_Scalar, Dim, Dim>> solver(mat);
32 if (solver.info() != Eigen::Success)
34 throw std::runtime_error{
"The matrix cannot be solved!" };
36 return solver.eigenvectors() * solver.eigenvalues().cwiseMax(0).cwiseSqrt().asDiagonal();
41 class LowerTriangular {};
42 class InvLowerTriangular {};
45 constexpr detail::FullMatrix full_matrix;
46 constexpr detail::LowerTriangular lower_triangular;
47 constexpr detail::InvLowerTriangular inv_lower_triangular;
56 template<
typename _Scalar, Index Dim = -1>
59 static_assert(std::is_floating_point<_Scalar>::value,
"`MvNormalGen` needs floating point types.");
61 Matrix<_Scalar, Dim, 1> mean;
62 Matrix<_Scalar, Dim, Dim> lt;
74 template<
typename MeanTy,
typename LTTy>
75 MvNormalGen(
const MatrixBase<MeanTy>& _mean,
const MatrixBase<LTTy>& _lt, detail::LowerTriangular)
76 : mean{ _mean }, lt{ _lt }
78 eigen_assert(_mean.cols() == 1 && _mean.rows() == _lt.rows() && _lt.rows() == _lt.cols());
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 }
95 MvNormalGen(
const MvNormalGen&) =
default;
96 MvNormalGen(MvNormalGen&&) =
default;
98 MvNormalGen& operator=(
const MvNormalGen&) =
default;
99 MvNormalGen& operator=(MvNormalGen&&) =
default;
101 Index dims()
const {
return mean.rows(); }
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)
107 return (lt * stdnorm.template generate<Matrix<_Scalar, Dim, -1>>(mean.rows(), samples, std::forward<Urng>(urng))).colwise() + mean;
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)
114 return (lt * stdnorm.template generate<Matrix<_Scalar, Dim, 1>>(mean.rows(), 1, std::forward<Urng>(urng))).colwise() + mean;
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);
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;
140 template<
typename MeanTy,
typename CovTy>
141 inline auto makeMvNormalGen(
const MatrixBase<MeanTy>& mean,
const MatrixBase<CovTy>& cov)
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."
149 detail::normal_check_dims<MeanTy, CovTy>(),
150 "assert: mean.RowsAtCompileTime == cov.RowsAtCompileTime && cov.RowsAtCompileTime == cov.ColsAtCompileTime"
152 return { mean, cov };
163 template<
typename MeanTy,
typename LTTy>
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."
172 detail::normal_check_dims<MeanTy, LTTy>(),
173 "assert: mean.RowsAtCompileTime == lt.RowsAtCompileTime && lt.RowsAtCompileTime == lt.ColsAtCompileTime"
175 return { mean, lt, lower_triangular };
184 template<
typename _Scalar, Index Dim>
187 static_assert(std::is_floating_point<_Scalar>::value,
"`WishartGen` needs floating point types.");
190 Matrix<_Scalar, Dim, Dim> chol;
192 std::vector<ChiSquaredGen<_Scalar>> chisqs;
201 template<
typename ScaleTy>
202 WishartGen(Index _df,
const MatrixBase<ScaleTy>& _lt, detail::LowerTriangular)
203 : df{ _df }, chol{ _lt }
205 eigen_assert(df > chol.rows() - 1);
206 eigen_assert(chol.rows() == chol.cols());
208 for (Index i = 0; i < chol.rows(); ++i)
210 chisqs.emplace_back(df - i);
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 }
225 eigen_assert(_scale.rows() == _scale.cols());
228 WishartGen(
const WishartGen&) =
default;
229 WishartGen(WishartGen&&) =
default;
231 WishartGen& operator=(
const WishartGen&) =
default;
232 WishartGen& operator=(WishartGen&&) =
default;
234 Index dims()
const {
return chol.rows(); }
236 template<
typename Urng>
237 inline Matrix<_Scalar, Dim, -1> generate(Urng&& urng, Index samples)
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);
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)
248 for (Index i = 0; i < dim - 1; ++i)
250 rand_mat.col(i + j * dim).tail(dim - 1 - i) = Map<ArrayXs>{ ptr, dim - 1 - i };
255 for (Index i = 0; i < dim; ++i)
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)
261 rand_mat(i, i + j * dim) = *ptr++;
265 for (Index j = 0; j < samples; ++j)
267 rand_mat.middleCols(j * dim, dim).template triangularView<StrictlyUpper>().setZero();
269 tmp.noalias() = chol * rand_mat;
271 for (Index j = 0; j < samples; ++j)
273 auto t = tmp.middleCols(j * dim, dim);
274 rand_mat.middleCols(j * dim, dim).noalias() = t * t.transpose();
279 template<
typename Urng>
280 inline Matrix<_Scalar, Dim, -1> generate(Urng&& urng)
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);
288 for (Index i = 0; i < dim / 2; ++i)
290 rand_mat.col(dim - 2 - i).tail(i + 1) = rand_mat.col(i).head(i + 1);
293 for (Index i = 0; i < dim; ++i)
295 rand_mat(i, i) = chisqs[i].template generate<Array<_Scalar, 1, 1>>(1, 1, urng).sqrt()(0);
297 rand_mat.template triangularView<StrictlyUpper>().setZero();
299 auto t = (chol * rand_mat).eval();
300 return (t * t.transpose()).eval();
311 template<
typename ScaleTy>
316 MatrixBase<ScaleTy>::RowsAtCompileTime == MatrixBase<ScaleTy>::ColsAtCompileTime,
317 "assert: scale.RowsAtCompileTime == scale.ColsAtCompileTime"
319 return { df, scale };
329 template<
typename LTTy>
334 MatrixBase<LTTy>::RowsAtCompileTime == MatrixBase<LTTy>::ColsAtCompileTime,
335 "assert: lt.RowsAtCompileTime == lt.ColsAtCompileTime"
337 return { df, lt, lower_triangular };
346 template<
typename _Scalar, Index Dim>
349 static_assert(std::is_floating_point<_Scalar>::value,
"`InvWishartGen` needs floating point types.");
352 Matrix<_Scalar, Dim, Dim> chol;
354 std::vector<ChiSquaredGen<_Scalar>> chisqs;
363 template<
typename ScaleTy>
364 InvWishartGen(Index _df,
const MatrixBase<ScaleTy>& _ilt, detail::InvLowerTriangular)
365 : df{ _df }, chol{ _ilt }
367 eigen_assert(df > chol.rows() - 1);
368 eigen_assert(chol.rows() == chol.cols());
370 for (Index i = 0; i < chol.rows(); ++i)
372 chisqs.emplace_back(df - i);
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 }
387 eigen_assert(_scale.rows() == _scale.cols());
390 InvWishartGen(
const InvWishartGen&) =
default;
391 InvWishartGen(InvWishartGen&&) =
default;
393 InvWishartGen& operator=(
const InvWishartGen&) =
default;
394 InvWishartGen& operator=(InvWishartGen&&) =
default;
396 Index dims()
const {
return chol.rows(); }
398 template<
typename Urng>
399 inline Matrix<_Scalar, Dim, -1> generate(Urng&& urng, Index samples)
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);
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)
410 for (Index i = 0; i < dim - 1; ++i)
412 rand_mat.col(i + j * dim).tail(dim - 1 - i) = Map<ArrayXs>{ ptr, dim - 1 - i };
417 for (Index i = 0; i < dim; ++i)
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)
423 rand_mat(i, i + j * dim) = *ptr++;
427 for (Index j = 0; j < samples; ++j)
429 rand_mat.middleCols(j * dim, dim).template triangularView<StrictlyUpper>().setZero();
431 tmp.noalias() = chol * rand_mat;
433 auto id = Eigen::Matrix<_Scalar, Dim, Dim>::Identity(dim, dim);
434 for (Index j = 0; j < samples; ++j)
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;
444 template<
typename Urng>
445 inline Matrix<_Scalar, Dim, -1> generate(Urng&& urng)
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);
453 for (Index i = 0; i < dim / 2; ++i)
455 rand_mat.col(dim - 2 - i).tail(i + 1) = rand_mat.col(i).head(i + 1);
458 for (Index i = 0; i < dim; ++i)
460 rand_mat(i, i) = chisqs[i].template generate<Array<_Scalar, 1, 1>>(1, 1, urng).sqrt()(0);
462 rand_mat.template triangularView<StrictlyUpper>().setZero();
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);
468 return (rand_mat.transpose() * rand_mat).eval();
479 template<
typename ScaleTy>
484 MatrixBase<ScaleTy>::RowsAtCompileTime == MatrixBase<ScaleTy>::ColsAtCompileTime,
485 "assert: scale.RowsAtCompileTime == scale.ColsAtCompileTime"
487 return { df, scale };
497 template<
typename ILTTy>
502 MatrixBase<ILTTy>::RowsAtCompileTime == MatrixBase<ILTTy>::ColsAtCompileTime,
503 "assert: ilt.RowsAtCompileTime == ilt.ColsAtCompileTime"
505 return { df, ilt, inv_lower_triangular };
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 > <) -> 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 > <) -> 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