简体   繁体   中英

Something strange when generating random matrices ( Eigen Library )

My intention is to stack, in tmp , matrices generated as orth(randn(lenghtDim, dimsSubsp(iK)))' (in Matlab notation) I simulate nresample times this procedure and every time I compute the squared norm of tmp and save it in normVal. I tried different ways to generate these random matrices but their norm value is always the same (with Matlab I don't have this behaviour)!

Could you help me to understand this strange behaviour and to solve it? Thank you

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;
}

--- EDIT ---

What I'm trying to write in C++ is the following Matlab code

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

To get the orth() , in C++ I compute the svd and then take the matrixU.

EDIT:

Haha, I know what it is now. You are performing an SVD and looking at U , which is always (regardless of the input) a unitary matrix. A unitary matrix has the property that U^T * U == I , which implies that the norm (and squared norm) of each of its columns are exactly 1. Therefore, the squared norm of the matrix is going to be equal to the number of columns (the minimum of rows or columns in the case of your "thin" U ), regardless of what random number generator you use.

Irrelevant information below:

Instead of std::default_random_engine , try std::mt19937 . I'm not sure if it is important for you to use nresample as your seed, but you may want to try using something like std::chrono::high_resolution_clock::now().time_since_epoch().count() . Otherwise, I think your approach is similar to mine.

#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());

According to default_random_engine documentation its de fault constructor creates linear congruential engine which does simple increment and modulo starting from some seed.

Therefore random engine you use is deterministic.

This is why you get the same matrices and the same norm. Matlab is probably undeterministic.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM