获取密集 Eigen::Matrix 对象的所有非零值
Get all non-zero values of a dense Eigen::Matrix object
假设您有一个动态大小的 Eigen::Matrix 对象并且只想对非零值进行一些计算,您如何获得所有非零值的向量或列表表示形式?
Matrix3f m;
m << 1, 0, 0,
0, 5, 6,
0, 0, 9;
VectorXf v = get_non_zero_values(m);
cout << v;
应该给你
1 5 6 9
如何使用 Eigen 完成此操作(最有效)?
在网络上进行了大量研究并受此启发后 Whosebug post 我想出了自己的解决方案
template <typename T>
Eigen::Matrix<T, Eigen::Dynamic, 1> get_non_zeros(Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>& _input)
{
Eigen::Matrix<T, Eigen::Dynamic, 1> reduced(Eigen::Map<Eigen::Matrix<T, Eigen::Dynamic, 1>>(_input.data(), _input.size()));
Eigen::Matrix<bool, Eigen::Dynamic, 1> empty = (reduced.array() == 0).rowwise().all();
size_t last = reduced.rows() - 1;
for ( size_t i = 0; i < last + 1;) {
if ( empty(i) ) {
reduced.row(i).swap(reduced.row(last));
empty.segment<1>(i).swap(empty.segment<1>(last));
--last;
}
else {
++i;
}
}
reduced.conservativeResize(last + 1, reduced.cols());
return reduced;
}
使用临时 std::vector
可以应用 push_back
方法来存储非零值。 std::vector
的内容然后可以 Map
ped 到 Eigen::Vector
。
VectorXf get_non_zero_values(const MatrixXf& m) {
std::vector<float> nzv;
for (int i = 0; i < m.size(); ++i) {
if (m(i)) nzv.push_back(m(i));
}
Map<VectorXf> nzm(nzv.data(), nzv.size());
return nzm;
}
这是一个使用 Eigen ver 3.4.0 的解决方案。
如果需要额外的并行性,您可以 #include <execution>
用于 STL 算法。
#include <Eigen/Dense>
#include <algorithm>
#include <functional>
#include <iostream>
int main()
{
Eigen::MatrixXf const m{{1, 0, 0},
{0, 5, 6},
{0, 0, 9}};
auto const size = m.size();
// create 1D view
auto const view = m.reshaped().transpose();
// create boolean markers for nonzeros
auto const mask = view.array() != 0;
// create index list and set useless elements to sentinel value
auto constexpr sentinel = std::numeric_limits<int>::lowest();
auto idxs = mask.select(Eigen::RowVectorXi::LinSpaced(size, 0, size), sentinel).eval();
// sort to remove sentinel values
std::partial_sort(idxs.begin(), idxs.begin() + size, idxs.end(), std::greater{});
idxs.conservativeResize(mask.count());
auto const nonzeros = view(idxs.reverse()).eval();
std::cout << nonzeros << std::endl;
}
输出:
1 5 6 9
解决此问题的另一种可能性是 Eigen's Sparse Module:
Eigen::Matrix3f m;
m << 1, 0, 0,
0, 5, 6,
0, 0, 9;
// Construct a sparse matrix
Eigen::SparseMatrix<float> sparseM(m.sparseView());
你现在可以用sparseM
做任何你想做的事了:
// Print non-zeros
for (int i = 0; i < sparseM.nonZeros(); ++i)
std::cout << *(sparseM.valuePtr() + i) << "\n";
// Construct a dense map
Eigen::Map<Eigen::VectorXf> denseMap(sparseM.valuePtr(), sparseM.nonZeros());
// Construct a dense vector
Eigen::VectorXf denseVector(denseMap);
假设您有一个动态大小的 Eigen::Matrix 对象并且只想对非零值进行一些计算,您如何获得所有非零值的向量或列表表示形式?
Matrix3f m;
m << 1, 0, 0,
0, 5, 6,
0, 0, 9;
VectorXf v = get_non_zero_values(m);
cout << v;
应该给你
1 5 6 9
如何使用 Eigen 完成此操作(最有效)?
在网络上进行了大量研究并受此启发后 Whosebug post 我想出了自己的解决方案
template <typename T>
Eigen::Matrix<T, Eigen::Dynamic, 1> get_non_zeros(Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>& _input)
{
Eigen::Matrix<T, Eigen::Dynamic, 1> reduced(Eigen::Map<Eigen::Matrix<T, Eigen::Dynamic, 1>>(_input.data(), _input.size()));
Eigen::Matrix<bool, Eigen::Dynamic, 1> empty = (reduced.array() == 0).rowwise().all();
size_t last = reduced.rows() - 1;
for ( size_t i = 0; i < last + 1;) {
if ( empty(i) ) {
reduced.row(i).swap(reduced.row(last));
empty.segment<1>(i).swap(empty.segment<1>(last));
--last;
}
else {
++i;
}
}
reduced.conservativeResize(last + 1, reduced.cols());
return reduced;
}
使用临时 std::vector
可以应用 push_back
方法来存储非零值。 std::vector
的内容然后可以 Map
ped 到 Eigen::Vector
。
VectorXf get_non_zero_values(const MatrixXf& m) {
std::vector<float> nzv;
for (int i = 0; i < m.size(); ++i) {
if (m(i)) nzv.push_back(m(i));
}
Map<VectorXf> nzm(nzv.data(), nzv.size());
return nzm;
}
这是一个使用 Eigen ver 3.4.0 的解决方案。
如果需要额外的并行性,您可以 #include <execution>
用于 STL 算法。
#include <Eigen/Dense>
#include <algorithm>
#include <functional>
#include <iostream>
int main()
{
Eigen::MatrixXf const m{{1, 0, 0},
{0, 5, 6},
{0, 0, 9}};
auto const size = m.size();
// create 1D view
auto const view = m.reshaped().transpose();
// create boolean markers for nonzeros
auto const mask = view.array() != 0;
// create index list and set useless elements to sentinel value
auto constexpr sentinel = std::numeric_limits<int>::lowest();
auto idxs = mask.select(Eigen::RowVectorXi::LinSpaced(size, 0, size), sentinel).eval();
// sort to remove sentinel values
std::partial_sort(idxs.begin(), idxs.begin() + size, idxs.end(), std::greater{});
idxs.conservativeResize(mask.count());
auto const nonzeros = view(idxs.reverse()).eval();
std::cout << nonzeros << std::endl;
}
输出:
1 5 6 9
解决此问题的另一种可能性是 Eigen's Sparse Module:
Eigen::Matrix3f m;
m << 1, 0, 0,
0, 5, 6,
0, 0, 9;
// Construct a sparse matrix
Eigen::SparseMatrix<float> sparseM(m.sparseView());
你现在可以用sparseM
做任何你想做的事了:
// Print non-zeros
for (int i = 0; i < sparseM.nonZeros(); ++i)
std::cout << *(sparseM.valuePtr() + i) << "\n";
// Construct a dense map
Eigen::Map<Eigen::VectorXf> denseMap(sparseM.valuePtr(), sparseM.nonZeros());
// Construct a dense vector
Eigen::VectorXf denseVector(denseMap);