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;
126 template<
typename MeanTy,
typename CovTy>
127 inline auto makeMvNormalGen(
const MatrixBase<MeanTy>& mean,
const MatrixBase<CovTy>& cov)
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."
135 MatrixBase<MeanTy>::RowsAtCompileTime == MatrixBase<CovTy>::RowsAtCompileTime &&
136 MatrixBase<CovTy>::RowsAtCompileTime == MatrixBase<CovTy>::ColsAtCompileTime,
137 "assert: mean.RowsAtCompileTime == cov.RowsAtCompileTime && cov.RowsAtCompileTime == cov.ColsAtCompileTime"
139 return { mean, cov };
150 template<
typename MeanTy,
typename LTTy>
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."
159 MatrixBase<MeanTy>::RowsAtCompileTime == MatrixBase<LTTy>::RowsAtCompileTime &&
160 MatrixBase<LTTy>::RowsAtCompileTime == MatrixBase<LTTy>::ColsAtCompileTime,
161 "assert: mean.RowsAtCompileTime == lt.RowsAtCompileTime && lt.RowsAtCompileTime == lt.ColsAtCompileTime"
163 return { mean, lt, lower_triangular };
172 template<
typename _Scalar, Index Dim>
175 static_assert(std::is_floating_point<_Scalar>::value,
"`WishartGen` needs floating point types.");
178 Matrix<_Scalar, Dim, Dim> chol;
180 std::vector<ChiSquaredGen<_Scalar>> chisqs;
189 template<
typename ScaleTy>
190 WishartGen(Index _df,
const MatrixBase<ScaleTy>& _lt, detail::LowerTriangular)
191 : df{ _df }, chol{ _lt }
193 eigen_assert(df > chol.rows() - 1);
194 eigen_assert(chol.rows() == chol.cols());
196 for (Index i = 0; i < chol.rows(); ++i)
198 chisqs.emplace_back(df - i);
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 }
213 eigen_assert(_scale.rows() == _scale.cols());
216 WishartGen(
const WishartGen&) =
default;
217 WishartGen(WishartGen&&) =
default;
219 WishartGen& operator=(
const WishartGen&) =
default;
220 WishartGen& operator=(WishartGen&&) =
default;
222 Index dims()
const {
return chol.rows(); }
224 template<
typename Urng>
225 inline Matrix<_Scalar, Dim, -1> generate(Urng&& urng, Index samples)
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);
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)
236 for (Index i = 0; i < dim - 1; ++i)
238 rand_mat.col(i + j * dim).tail(dim - 1 - i) = Map<ArrayXs>{ ptr, dim - 1 - i };
243 for (Index i = 0; i < dim; ++i)
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)
249 rand_mat(i, i + j * dim) = *ptr++;
253 for (Index j = 0; j < samples; ++j)
255 rand_mat.middleCols(j * dim, dim).template triangularView<StrictlyUpper>().setZero();
257 tmp.noalias() = chol * rand_mat;
259 for (Index j = 0; j < samples; ++j)
261 auto t = tmp.middleCols(j * dim, dim);
262 rand_mat.middleCols(j * dim, dim).noalias() = t * t.transpose();
267 template<
typename Urng>
268 inline Matrix<_Scalar, Dim, -1> generate(Urng&& urng)
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);
276 for (Index i = 0; i < dim / 2; ++i)
278 rand_mat.col(dim - 2 - i).tail(i + 1) = rand_mat.col(i).head(i + 1);
281 for (Index i = 0; i < dim; ++i)
283 rand_mat(i, i) = chisqs[i].template generate<Array<_Scalar, 1, 1>>(1, 1, urng).sqrt()(0);
285 rand_mat.template triangularView<StrictlyUpper>().setZero();
287 auto t = (chol * rand_mat).eval();
288 return (t * t.transpose()).eval();
299 template<
typename ScaleTy>
304 MatrixBase<ScaleTy>::RowsAtCompileTime == MatrixBase<ScaleTy>::ColsAtCompileTime,
305 "assert: scale.RowsAtCompileTime == scale.ColsAtCompileTime"
307 return { df, scale };
317 template<
typename LTTy>
322 MatrixBase<LTTy>::RowsAtCompileTime == MatrixBase<LTTy>::ColsAtCompileTime,
323 "assert: lt.RowsAtCompileTime == lt.ColsAtCompileTime"
325 return { df, lt, lower_triangular };
334 template<
typename _Scalar, Index Dim>
337 static_assert(std::is_floating_point<_Scalar>::value,
"`InvWishartGen` needs floating point types.");
340 Matrix<_Scalar, Dim, Dim> chol;
342 std::vector<ChiSquaredGen<_Scalar>> chisqs;
351 template<
typename ScaleTy>
352 InvWishartGen(Index _df,
const MatrixBase<ScaleTy>& _ilt, detail::InvLowerTriangular)
353 : df{ _df }, chol{ _ilt }
355 eigen_assert(df > chol.rows() - 1);
356 eigen_assert(chol.rows() == chol.cols());
358 for (Index i = 0; i < chol.rows(); ++i)
360 chisqs.emplace_back(df - i);
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 }
375 eigen_assert(_scale.rows() == _scale.cols());
378 InvWishartGen(
const InvWishartGen&) =
default;
379 InvWishartGen(InvWishartGen&&) =
default;
381 InvWishartGen& operator=(
const InvWishartGen&) =
default;
382 InvWishartGen& operator=(InvWishartGen&&) =
default;
384 Index dims()
const {
return chol.rows(); }
386 template<
typename Urng>
387 inline Matrix<_Scalar, Dim, -1> generate(Urng&& urng, Index samples)
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);
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)
398 for (Index i = 0; i < dim - 1; ++i)
400 rand_mat.col(i + j * dim).tail(dim - 1 - i) = Map<ArrayXs>{ ptr, dim - 1 - i };
405 for (Index i = 0; i < dim; ++i)
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)
411 rand_mat(i, i + j * dim) = *ptr++;
415 for (Index j = 0; j < samples; ++j)
417 rand_mat.middleCols(j * dim, dim).template triangularView<StrictlyUpper>().setZero();
419 tmp.noalias() = chol * rand_mat;
421 auto id = Eigen::Matrix<_Scalar, Dim, Dim>::Identity(dim, dim);
422 for (Index j = 0; j < samples; ++j)
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;
432 template<
typename Urng>
433 inline Matrix<_Scalar, Dim, -1> generate(Urng&& urng)
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);
441 for (Index i = 0; i < dim / 2; ++i)
443 rand_mat.col(dim - 2 - i).tail(i + 1) = rand_mat.col(i).head(i + 1);
446 for (Index i = 0; i < dim; ++i)
448 rand_mat(i, i) = chisqs[i].template generate<Array<_Scalar, 1, 1>>(1, 1, urng).sqrt()(0);
450 rand_mat.template triangularView<StrictlyUpper>().setZero();
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);
456 return (rand_mat.transpose() * rand_mat).eval();
467 template<
typename ScaleTy>
472 MatrixBase<ScaleTy>::RowsAtCompileTime == MatrixBase<ScaleTy>::ColsAtCompileTime,
473 "assert: scale.RowsAtCompileTime == scale.ColsAtCompileTime"
475 return { df, scale };
485 template<
typename ILTTy>
490 MatrixBase<ILTTy>::RowsAtCompileTime == MatrixBase<ILTTy>::ColsAtCompileTime,
491 "assert: ilt.RowsAtCompileTime == ilt.ColsAtCompileTime"
493 return { df, ilt, inv_lower_triangular };
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 > <) -> 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 > <) -> 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