具有特征的稀疏随机矩阵

Sparse Random Matrix with Eigen

本文关键字:随机 特征      更新时间:2023-10-16

是否可以使用c++特征库制作(稀疏)矩阵,类似于我需要翻译的这个优雅的python代码?

(np.random.rand(100,100)  < 0.1) * np.random.rand(100,100)

。由一定比例的随机值填充的矩阵。

直接改编自特征文档,并没有那么简洁:

std::default_random_engine gen;
std::uniform_real_distribution<double> dist(0.0,1.0);
int rows=100;
int cols=100;
std::vector<Eigen::Triplet<double> > tripletList;
for(int i=0;i<rows;++i)
    for(int j=0;j<cols;++j)
    {
       auto v_ij=dist(gen);                         //generate random number
       if(v_ij < 0.1)
       {
           tripletList.push_back(T(i,j,v_ij));      //if larger than treshold, insert it
       }
    }
SparseMatrixType mat(rows,cols);
mat.setFromTriplets(tripletList.begin(), tripletList.end());   //create the matrix

davidhigh的回答解决了您问题的稀疏要求。然而,我不认为你的python代码实际上产生了一个稀疏矩阵,而是一个几乎为零的密集矩阵。一个同样优雅的Eigen版本可以是

MatrixXd mat;
mat2 = (MatrixXd::Random(5,5).array() > 0.3).cast<double>() * MatrixXd::Random(5,5).array();

注意,这使用了标准的c++ rand(),因此可能不够"随机",这取决于您的需要。如果您更喜欢float s而不是double s,您也可以将MatrixXd替换为MatrixXf(也可以更改cast<...>())。

davidhigh的答案具有O(rows*cols)复杂性,并且对于大型矩阵可能不切实际且耗时太长。这是一个只有O(nnz)复杂度的改编版本。p是期望的稀疏性。如果您的矩阵中的值需要在其他范围内,您可以调整valdis的范围。

typedef Eigen::SparseMatrix<double, Eigen::RowMajor> SpMat;
SpMat getRandomSpMat(size_t rows, size_t cols, double p) {
    typedef Eigen::Triplet<double> T;
    std::random_device rd;  //Will be used to obtain a seed for the random number engine
    std::mt19937 gen(rd()); //Standard mersenne_twister_engine seeded with rd()
    std::uniform_real_distribution<> valdis(0, 1.0);
    std::uniform_int_distribution<> rowdis(0, rows-1);
    std::uniform_int_distribution<> coldis(0, cols-1);
    std::vector<Eigen::Triplet<double> > tripletList;
    size_t nnz = (size_t) (rows * (cols * p));
    std::set<size_t> nnz_pos;
    for (size_t i = 0; i < nnz; ++i) {
        auto r = rowdis(gen);
        auto c = coldis(gen);
        size_t pos = r * cols + c;
        while (nnz_pos.find(pos) != nnz_pos.end()) {
            r = rowdis(gen);
            c = coldis(gen);
            pos = r * cols + c;
        }
        nnz_pos.insert(pos);
        tripletList.push_back(T(r, c, valdis(gen)));
    }
    SpMat mat(rows,cols);
    mat.setFromTriplets(tripletList.begin(), tripletList.end());   //create the matrix
    return mat;
}