[英]Sparse Random Matrix with Eigen
Is it possible to make a (sparse) matrix with the C++ Eigen library similar to this elegant python code I need to translate?是否可以使用 C++ Eigen 库制作一个(稀疏)矩阵,类似于我需要翻译的这个优雅的 Python 代码?
(np.random.rand(100,100) < 0.1) * np.random.rand(100,100)
eg a matrix filled with a certain proportion of random values.例如,一个矩阵填充了一定比例的随机值。
Directly adapted from the Eigen Documentation , and not quite that concise:直接改编自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
This requires C++11 and is untested.这需要 C++11 并且未经测试。
davidhigh's answer addresses the sparse requirement of your question. davidhigh 的回答解决了您问题的稀疏要求。 However, I don't think that your python code actually produces a sparse matrix, but rather a dense matrix with mostly zeros.
但是,我不认为您的 Python 代码实际上会生成一个稀疏矩阵,而是生成一个大部分为零的密集矩阵。 A similarly elegant version for Eigen can be
Eigen 的类似优雅版本可以是
MatrixXd mat;
mat2 = (MatrixXd::Random(5,5).array() > 0.3).cast<double>() * MatrixXd::Random(5,5).array();
Note that this uses the standard C++ rand()
, so may not be sufficiently "random", depending on your needs.请注意,这使用标准 C++
rand()
,因此可能不够“随机”,具体取决于您的需要。 You can also replace MatrixXd
with MatrixXf
if you prefer float
s over double
s (change the cast<...>()
as well).您也可以替换
MatrixXd
与MatrixXf
如果你喜欢float
结束了double
S(改cast<...>()
为好)。
davidhigh's answer has O(rows*cols)
complexity and can be impractical and take too long for large matrices. davidhigh 的答案具有
O(rows*cols)
复杂度,并且可能不切实际,并且对于大型矩阵来说花费的时间太长。 Here's an adapted version that has only O(nnz)
complexity.这是一个只有
O(nnz)
复杂度的改编版本。 p
is the desired sparsity. p
是所需的稀疏度。 You may adjust the range of valdis
if the value in your matrix needs to be in other ranges.如果矩阵中的值需要在其他范围内,您可以调整
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;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.