gpt4 book ai didi

c++ - 来自 C++ 中的多元正态/高斯分布的样本

转载 作者:IT老高 更新时间:2023-10-28 12:43:33 31 4
gpt4 key购买 nike

我一直在寻找一种从多元正态分布中采样的便捷方法。有谁知道一个现成的代码片段来做到这一点?对于矩阵/vector ,我更喜欢使用 BoostEigen或其他我不熟悉的非凡库,但我可以使用 GSL在紧要关头。如果该方法接受 非负 定协方差矩阵而不是要求正定协方差矩阵(例如,与 Cholesky 分解一样),我也会喜欢它。这存在于 MATLAB、NumPy 和其他软件中,但我很难找到现成的 C/C++ 解决方案。

如果我必须自己实现它,我会提示,但没关系。如果我这样做,Wikipedia makes it sound就像我应该的那样

  1. 生成 n 0 均值、单位方差、独立正态样本(boost 会这样做)
  2. 求协方差矩阵的特征分解
  3. 按对应特征值的平方根缩放每个 n 个样本
  4. 通过将缩放 vector 与分解找到的正交特征向量矩阵预乘来旋转样本 vector

我希望它能够快速工作。是否有人直觉知道何时值得检查协方差矩阵是否为正,如果是,请改用 Cholesky?

最佳答案

由于这个问题已经获得了很多意见,我想我会发布我找到的最终答案的代码,部分来自 posting to the Eigen forums .该代码将 Boost 用于单变量法线,将 Eigen 用于矩阵处理。这感觉相当不正统,因为它涉及使用“内部”命名空间,但它确实有效。如果有人提出建议,我愿意改进它。

#include <Eigen/Dense>
#include <boost/random/mersenne_twister.hpp>
#include <boost/random/normal_distribution.hpp>

/*
We need a functor that can pretend it's const,
but to be a good random number generator
it needs mutable state.
*/
namespace Eigen {
namespace internal {
template<typename Scalar>
struct scalar_normal_dist_op
{
static boost::mt19937 rng; // The uniform pseudo-random algorithm
mutable boost::normal_distribution<Scalar> norm; // The gaussian combinator

EIGEN_EMPTY_STRUCT_CTOR(scalar_normal_dist_op)

template<typename Index>
inline const Scalar operator() (Index, Index = 0) const { return norm(rng); }
};

template<typename Scalar> boost::mt19937 scalar_normal_dist_op<Scalar>::rng;

template<typename Scalar>
struct functor_traits<scalar_normal_dist_op<Scalar> >
{ enum { Cost = 50 * NumTraits<Scalar>::MulCost, PacketAccess = false, IsRepeatable = false }; };
} // end namespace internal
} // end namespace Eigen

/*
Draw nn samples from a size-dimensional normal distribution
with a specified mean and covariance
*/
void main()
{
int size = 2; // Dimensionality (rows)
int nn=5; // How many samples (columns) to draw
Eigen::internal::scalar_normal_dist_op<double> randN; // Gaussian functor
Eigen::internal::scalar_normal_dist_op<double>::rng.seed(1); // Seed the rng

// Define mean and covariance of the distribution
Eigen::VectorXd mean(size);
Eigen::MatrixXd covar(size,size);

mean << 0, 0;
covar << 1, .5,
.5, 1;

Eigen::MatrixXd normTransform(size,size);

Eigen::LLT<Eigen::MatrixXd> cholSolver(covar);

// We can only use the cholesky decomposition if
// the covariance matrix is symmetric, pos-definite.
// But a covariance matrix might be pos-semi-definite.
// In that case, we'll go to an EigenSolver
if (cholSolver.info()==Eigen::Success) {
// Use cholesky solver
normTransform = cholSolver.matrixL();
} else {
// Use eigen solver
Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> eigenSolver(covar);
normTransform = eigenSolver.eigenvectors()
* eigenSolver.eigenvalues().cwiseSqrt().asDiagonal();
}

Eigen::MatrixXd samples = (normTransform
* Eigen::MatrixXd::NullaryExpr(size,nn,randN)).colwise()
+ mean;

std::cout << "Mean\n" << mean << std::endl;
std::cout << "Covar\n" << covar << std::endl;
std::cout << "Samples\n" << samples << std::endl;
}

关于c++ - 来自 C++ 中的多元正态/高斯分布的样本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6142576/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com