【问题标题】:Sparse Random Matrix with Eigen具有特征的稀疏随机矩阵
【发布时间】:2015-08-24 20:26:56
【问题描述】:

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

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

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

【问题讨论】:

  • 你确定这会在 python 中创建一个稀疏矩阵,而不是一个 90% 零的密集矩阵吗?
  • 确实没有,但它会是一个不错的附加选项。

标签: python c++ sparse-matrix eigen


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    davidhigh 的answer 解决了您问题的稀疏要求。但是,我认为您的 python 代码实际上不会产生稀疏矩阵,而是产生大部分为零的密集矩阵。 Eigen 的一个同样优雅的版本可以是

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

    请注意,这使用标准 C++ rand(),因此可能不够“随机”,具体取决于您的需要。如果您更喜欢floats 而不是doubles,也可以将MatrixXd 替换为MatrixXf(也可以更改cast&lt;...&gt;())。

    【讨论】:

    • 与额外的 .abs() 一起使用:MatrixXd mat = (MatrixXd::Random(100,100).array().abs() () * MatrixXd::Random (100,100).array().abs();
    【解决方案3】:

    直接改编自Eigen Documentation,不太简洁:

    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
    

    这需要 C++11 并且未经测试。

    【讨论】:

    • 不幸卡在 C++98 上。
    • 然后你需要用其他一些生成器(升压或其他)替换随机数的东西
    • 仅供记录。这种方法效果很好,也值得被接受,但如前所述,它不太简洁,这是主要要求。
    猜你喜欢
    • 2013-09-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-29
    • 2019-10-14
    • 1970-01-01
    • 2016-10-09
    • 2020-08-20
    相关资源
    最近更新 更多