【问题标题】:Something strange when generating random matrices ( Eigen Library )生成随机矩阵时有些奇怪(特征库)
【发布时间】:2023-04-06 21:54:01
【问题描述】:

我的意图是在 tmp 中堆叠生成为 orth(randn(lenghtDim, dimsSubsp(iK)))' 的矩阵(在 Matlab 表示法中) 我模拟 nresample 次这个过程,每次我计算 tmp 的平方范数并将其保存在 normVal 中。我尝试了不同的方法来生成这些随机矩阵,但它们的范数总是相同的(使用 Matlab 我没有这种行为)!

您能帮我理解这种奇怪的行为并解决它吗?谢谢

Eigen::VectorXd EmpDistrLargSV(const std::size_t lenghtDim, const std::vector<std::size_t>& dimsSubsp, int nresample ){

 Eigen::VectorXd normVal;
 Eigen::MatrixXd tmp(std::accumulate(dimsSubsp.cbegin(),dimsSubsp.cend(),0),lenghtDim);
 normVal.resize(nresample);
 std::normal_distribution<double> distribution(0,1);
 std::default_random_engine engine (nresample );
    for (int i = 0; i <nresample ; ++i) {
        for (int iK = 0; iK < dimsSubsp.size(); ++iK) {
            std::size_t row_start=std::accumulate(dimsSubsp.begin(),dimsSubsp.begin()+iK,0);
            Eigen::MatrixXd myRandMat = Eigen::MatrixXd::NullaryExpr(lenghtDim,dimsSubsp[iK],[&](){return distribution(engine);});
            Eigen::JacobiSVD<Eigen::MatrixXd> svd(myRandMat, Eigen::ComputeThinU );
            tmp.block(row_start,0,dimsSubsp[iK],lenghtDim)=svd.matrixU().transpose();

        }
        normVal(i)=tmp.squaredNorm();
    }
    return normVal;
}

--- 编辑 ---

我想用 C++ 编写的是下面的 Matlab 代码

nb = length(dimsSubsp);
tmp = zeros(sum(dimsSubsp), lengthDim);

normVal = zeros(1, nresample);

    for i = 1:nresample
        for ib = 1:nb
            irow_start = sum(dimsSubsp(1 : (ib - 1))) + 1;
            irow_end = sum(dimsSubsp(1 : ib));
            tmp(irow_start : irow_end, :) =  orth(randn(lengthDim,dimsSubsp(ib)))';
        end
        normVal(i) = norm(M, 2)^2;
    end

为了得到 orth() ,我在 C++ 中计算 svd,然后获取 matrixU。

【问题讨论】:

  • 两件事: 1. 你正在构建一个新的随机引擎,每个函数调用意味着它将像以前一样被播种并产生相同的伪随机数序列。始终在外面构建您的随机引擎并为其播种。 2. 以上是不是您的代码始终产生相同值的唯一原因。事实上,修复随机数生成不会改变任何事情。你没有编程,但有一个数学错误。
  • 我是故意这样做的,将随机引擎放入函数中。我不明白为什么在外部循环的每次迭代中,normVal 总是相同的数字。我试图打印 tmp 并且在每次迭代时看起来都是一个不同的矩阵,但它的规范总是相同的。我添加到 matlab 代码中我试图在 C++ 中“翻译”

标签: c++ matrix random eigen random-seed


【解决方案1】:

编辑:

哈哈,我知道现在是什么了。您正在执行 SVD 并查看 U,它始终(无论输入如何)是一个酉矩阵。酉矩阵具有U^T * U == I 的性质,这意味着它的每一列的范数(和平方范数)正好是 1。因此,矩阵的平方范数将等于列数(在您的“瘦”U) 的情况下,最少行或列,无论您使用什么随机数生成器。

以下无关信息:

试试std::mt19937,而不是std::default_random_engine。我不确定使用nresample 作为种子对你是否重要,但你可能想尝试使用std::chrono::high_resolution_clock::now().time_since_epoch().count() 之类的东西。否则,我认为您的方法与我的方法相似。

#include <chrono>
#include <random> 
#include <Eigen/eigen>

MatrixX<double> random_matrix(int rows, int cols, double min, double max, unsigned seed)
{
   std::mt19937 generator(seed);
   std::uniform_real_distribution<double> distribution(min,max);
   MatrixX<double> result(rows,cols);
   for(double& val : result.reshaped())
      val = distribution(generator);
   return result;
}

MatrixX<double> rando = random_matrix(20, 34, -30.1, 122.3, std::chrono::high_resolution_clock::now().time_since_epoch().count());

【讨论】:

  • 我尝试了你的建议,但我在 normVal 中仍然得到相同的结果
【解决方案2】:

根据default_random_engine documentation,它的默认构造函数创建linear congruential engine,它从某个种子开始进行简单的递增和取模。

因此,您使用的随机引擎是确定性的。

这就是为什么你得到相同的矩阵和相同的范数。 Matlab 可能是不确定的。

【讨论】:

  • 我该如何解决这个问题?你有什么建议吗?
  • std::random_device 在文档中说是不确定的。尝试使用它而不是std::default_random_engine
猜你喜欢
  • 2018-08-11
  • 1970-01-01
  • 1970-01-01
  • 2015-08-24
  • 1970-01-01
  • 2018-10-26
  • 2012-11-21
  • 2016-06-30
  • 1970-01-01
相关资源
最近更新 更多