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 Matrix<_Scalar, Dim, 1> mean;
60 Matrix<_Scalar, Dim, Dim> lt;
72 template<
typename MeanTy,
typename LTTy>
73 MvNormalGen(
const MatrixBase<MeanTy>& _mean,
const MatrixBase<LTTy>& _lt, detail::LowerTriangular)
74 : mean{ _mean }, lt{ _lt }
76 eigen_assert(_mean.cols() == 1 && _mean.rows() == _lt.rows() && _lt.rows() == _lt.cols());
87 template<
typename MeanTy,
typename CovTy>
88 MvNormalGen(
const MatrixBase<MeanTy>& _mean,
const MatrixBase<CovTy>& _cov, detail::FullMatrix = {})
89 :
MvNormalGen{ _mean, detail::template get_lt<_Scalar, Dim>(_cov), lower_triangular }
99 Index dims()
const {
return mean.rows(); }
101 template<
typename Urng>
102 inline auto generate(Urng&& urng, Index samples)
103 -> decltype((lt * stdnorm.template generate<Matrix<_Scalar, Dim, -1>>(mean.rows(), samples, std::forward<Urng>(urng))).colwise() + mean)
105 return (lt * stdnorm.template generate<Matrix<_Scalar, Dim, -1>>(mean.rows(), samples, std::forward<Urng>(urng))).colwise() + mean;
108 template<
typename Urng>
109 inline auto generate(Urng&& urng)
110 -> decltype((lt * stdnorm.template generate<Matrix<_Scalar, Dim, 1>>(mean.rows(), 1, std::forward<Urng>(urng))).colwise() + mean)
112 return (lt * stdnorm.template generate<Matrix<_Scalar, Dim, 1>>(mean.rows(), 1, std::forward<Urng>(urng))).colwise() + mean;
124 template<
typename MeanTy,
typename CovTy>
125 inline auto makeMvNormalGen(
const MatrixBase<MeanTy>& mean,
const MatrixBase<CovTy>& cov)
129 std::is_same<
typename MatrixBase<MeanTy>::Scalar,
typename MatrixBase<CovTy>::Scalar>::value,
130 "Derived::Scalar must be the same with `mean` and `cov`'s Scalar."
133 MatrixBase<MeanTy>::RowsAtCompileTime == MatrixBase<CovTy>::RowsAtCompileTime &&
134 MatrixBase<CovTy>::RowsAtCompileTime == MatrixBase<CovTy>::ColsAtCompileTime,
135 "assert: mean.RowsAtCompileTime == cov.RowsAtCompileTime && cov.RowsAtCompileTime == cov.ColsAtCompileTime"
137 return { mean, cov };
148 template<
typename MeanTy,
typename LTTy>
153 std::is_same<
typename MatrixBase<MeanTy>::Scalar,
typename MatrixBase<LTTy>::Scalar>::value,
154 "Derived::Scalar must be the same with `mean` and `lt`'s Scalar."
157 MatrixBase<MeanTy>::RowsAtCompileTime == MatrixBase<LTTy>::RowsAtCompileTime &&
158 MatrixBase<LTTy>::RowsAtCompileTime == MatrixBase<LTTy>::ColsAtCompileTime,
159 "assert: mean.RowsAtCompileTime == lt.RowsAtCompileTime && lt.RowsAtCompileTime == lt.ColsAtCompileTime"
161 return { mean, lt, lower_triangular };
170 template<
typename _Scalar, Index Dim>
174 Matrix<_Scalar, Dim, Dim> chol;
176 std::vector<ChiSquaredGen<_Scalar>> chisqs;
185 template<
typename ScaleTy>
186 WishartGen(Index _df,
const MatrixBase<ScaleTy>& _lt, detail::LowerTriangular)
187 : df{ _df }, chol{ _lt }
189 eigen_assert(df > chol.rows() - 1);
190 eigen_assert(chol.rows() == chol.cols());
192 for (Index i = 0; i < chol.rows(); ++i)
194 chisqs.emplace_back(df - i);
205 template<
typename ScaleTy>
206 WishartGen(Index _df,
const MatrixBase<ScaleTy>& _scale, detail::FullMatrix = {})
207 :
WishartGen{ _df, detail::template get_lt<_Scalar, Dim>(_scale), lower_triangular }
209 eigen_assert(_scale.rows() == _scale.cols());
218 Index dims()
const {
return chol.rows(); }
220 template<
typename Urng>
221 inline Matrix<_Scalar, Dim, -1> generate(Urng&& urng, Index samples)
223 const Index dim = chol.rows();
224 const Index normSamples = samples * dim * (dim - 1) / 2;
225 using ArrayXs = Array<_Scalar, -1, 1>;
226 Matrix<_Scalar, Dim, -1> rand_mat(dim, dim * samples), tmp(dim, dim * samples);
228 _Scalar* ptr = tmp.data();
229 Map<ArrayXs>{ ptr, normSamples } = stdnorm.template generate<ArrayXs>(normSamples, 1, urng);
230 for (Index j = 0; j < samples; ++j)
232 for (Index i = 0; i < dim - 1; ++i)
234 rand_mat.col(i + j * dim).tail(dim - 1 - i) = Map<ArrayXs>{ ptr, dim - 1 - i };
239 for (Index i = 0; i < dim; ++i)
241 _Scalar* ptr = tmp.data();
242 Map<ArrayXs>{ ptr, samples } = chisqs[i].template generate<ArrayXs>(samples, 1, urng).sqrt();
243 for (Index j = 0; j < samples; ++j)
245 rand_mat(i, i + j * dim) = *ptr++;
249 for (Index j = 0; j < samples; ++j)
251 rand_mat.middleCols(j * dim, dim).template triangularView<StrictlyUpper>().setZero();
253 tmp.noalias() = chol * rand_mat;
255 for (Index j = 0; j < samples; ++j)
257 auto t = tmp.middleCols(j * dim, dim);
258 rand_mat.middleCols(j * dim, dim).noalias() = t * t.transpose();
263 template<
typename Urng>
264 inline Matrix<_Scalar, Dim, -1> generate(Urng&& urng)
266 const Index dim = chol.rows();
267 const Index normSamples = dim * (dim - 1) / 2;
268 using ArrayXs = Array<_Scalar, -1, 1>;
269 Matrix<_Scalar, Dim, Dim> rand_mat(dim, dim);
270 Map<ArrayXs>{ rand_mat.data(), normSamples } = stdnorm.template generate<ArrayXs>(normSamples, 1, urng);
272 for (Index i = 0; i < dim / 2; ++i)
274 rand_mat.col(dim - 2 - i).tail(i + 1) = rand_mat.col(i).head(i + 1);
277 for (Index i = 0; i < dim; ++i)
279 rand_mat(i, i) = chisqs[i].template generate<Array<_Scalar, 1, 1>>(1, 1, urng).sqrt()(0);
281 rand_mat.template triangularView<StrictlyUpper>().setZero();
283 auto t = (chol * rand_mat).eval();
284 return (t * t.transpose()).eval();
295 template<
typename ScaleTy>
300 MatrixBase<ScaleTy>::RowsAtCompileTime == MatrixBase<ScaleTy>::ColsAtCompileTime,
301 "assert: scale.RowsAtCompileTime == scale.ColsAtCompileTime"
303 return { df, scale };
313 template<
typename LTTy>
318 MatrixBase<LTTy>::RowsAtCompileTime == MatrixBase<LTTy>::ColsAtCompileTime,
319 "assert: lt.RowsAtCompileTime == lt.ColsAtCompileTime"
321 return { df, lt, lower_triangular };
330 template<
typename _Scalar, Index Dim>
334 Matrix<_Scalar, Dim, Dim> chol;
336 std::vector<ChiSquaredGen<_Scalar>> chisqs;
345 template<
typename ScaleTy>
346 InvWishartGen(Index _df,
const MatrixBase<ScaleTy>& _ilt, detail::InvLowerTriangular)
347 : df{ _df }, chol{ _ilt }
349 eigen_assert(df > chol.rows() - 1);
350 eigen_assert(chol.rows() == chol.cols());
352 for (Index i = 0; i < chol.rows(); ++i)
354 chisqs.emplace_back(df - i);
365 template<
typename ScaleTy>
366 InvWishartGen(Index _df,
const MatrixBase<ScaleTy>& _scale, detail::FullMatrix = {})
367 :
InvWishartGen{ _df, detail::template get_lt<_Scalar, Dim>(_scale.inverse()), inv_lower_triangular }
369 eigen_assert(_scale.rows() == _scale.cols());
378 Index dims()
const {
return chol.rows(); }
380 template<
typename Urng>
381 inline Matrix<_Scalar, Dim, -1> generate(Urng&& urng, Index samples)
383 const Index dim = chol.rows();
384 const Index normSamples = samples * dim * (dim - 1) / 2;
385 using ArrayXs = Array<_Scalar, -1, 1>;
386 Matrix<_Scalar, Dim, -1> rand_mat(dim, dim * samples), tmp(dim, dim * samples);
388 _Scalar* ptr = tmp.data();
389 Map<ArrayXs>{ ptr, normSamples } = stdnorm.template generate<ArrayXs>(normSamples, 1, urng);
390 for (Index j = 0; j < samples; ++j)
392 for (Index i = 0; i < dim - 1; ++i)
394 rand_mat.col(i + j * dim).tail(dim - 1 - i) = Map<ArrayXs>{ ptr, dim - 1 - i };
399 for (Index i = 0; i < dim; ++i)
401 _Scalar* ptr = tmp.data();
402 Map<ArrayXs>{ ptr, samples } = chisqs[i].template generate<ArrayXs>(samples, 1, urng).sqrt();
403 for (Index j = 0; j < samples; ++j)
405 rand_mat(i, i + j * dim) = *ptr++;
409 for (Index j = 0; j < samples; ++j)
411 rand_mat.middleCols(j * dim, dim).template triangularView<StrictlyUpper>().setZero();
413 tmp.noalias() = chol * rand_mat;
415 auto id = Eigen::Matrix<_Scalar, Dim, Dim>::Identity(dim, dim);
416 for (Index j = 0; j < samples; ++j)
418 auto t = tmp.middleCols(j * dim, dim);
419 auto u = rand_mat.middleCols(j * dim, dim);
420 u.noalias() = t.template triangularView<Lower>().solve(
id);
421 t.noalias() = u.transpose() * u;
426 template<
typename Urng>
427 inline Matrix<_Scalar, Dim, -1> generate(Urng&& urng)
429 const Index dim = chol.rows();
430 const Index normSamples = dim * (dim - 1) / 2;
431 using ArrayXs = Array<_Scalar, -1, 1>;
432 Matrix<_Scalar, Dim, Dim> rand_mat(dim, dim);
433 Map<ArrayXs>{ rand_mat.data(), normSamples } = stdnorm.template generate<ArrayXs>(normSamples, 1, urng);
435 for (Index i = 0; i < dim / 2; ++i)
437 rand_mat.col(dim - 2 - i).tail(i + 1) = rand_mat.col(i).head(i + 1);
440 for (Index i = 0; i < dim; ++i)
442 rand_mat(i, i) = chisqs[i].template generate<Array<_Scalar, 1, 1>>(1, 1, urng).sqrt()(0);
444 rand_mat.template triangularView<StrictlyUpper>().setZero();
446 auto t = (chol * rand_mat).eval();
447 auto id = Eigen::Matrix<_Scalar, Dim, Dim>::Identity(dim, dim);
448 rand_mat.noalias() = t.template triangularView<Lower>().solve(
id);
450 return (rand_mat.transpose() * rand_mat).eval();
461 template<
typename ScaleTy>
466 MatrixBase<ScaleTy>::RowsAtCompileTime == MatrixBase<ScaleTy>::ColsAtCompileTime,
467 "assert: scale.RowsAtCompileTime == scale.ColsAtCompileTime"
469 return { df, scale };
479 template<
typename ILTTy>
484 MatrixBase<ILTTy>::RowsAtCompileTime == MatrixBase<ILTTy>::ColsAtCompileTime,
485 "assert: ilt.RowsAtCompileTime == ilt.ColsAtCompileTime"
487 return { df, ilt, inv_lower_triangular };
Generator of real matrices on a inverse Wishart distribution.
Definition: MvNormal.h:332
InvWishartGen(Index _df, const MatrixBase< ScaleTy > &_scale, detail::FullMatrix={})
Construct a new inverse Wishart generator.
Definition: MvNormal.h:366
InvWishartGen(Index _df, const MatrixBase< ScaleTy > &_ilt, detail::InvLowerTriangular)
Construct a new inverse Wishart generator.
Definition: MvNormal.h:346
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:73
MvNormalGen(const MatrixBase< MeanTy > &_mean, const MatrixBase< CovTy > &_cov, detail::FullMatrix={})
Construct a new multivariate normal generator from covariance matrix.
Definition: MvNormal.h:88
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:172
WishartGen(Index _df, const MatrixBase< ScaleTy > &_scale, detail::FullMatrix={})
Construct a new Wishart generator from scale matrix.
Definition: MvNormal.h:206
WishartGen(Index _df, const MatrixBase< ScaleTy > &_lt, detail::LowerTriangular)
Construct a new Wishart generator from lower triangular matrix of decomposed scale.
Definition: MvNormal.h:186
auto makeWishartGenFromLt(Index df, const MatrixBase< LTTy > <) -> WishartGen< typename MatrixBase< LTTy >::Scalar, MatrixBase< LTTy >::RowsAtCompileTime >
helper function constructing Eigen::Rand::WishartGen
Definition: MvNormal.h:314
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:125
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:296
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:149
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:462
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:480