Eigen中Map封装SparseMatrix调用prune报错及pruned()无效问题求助
解决Eigen稀疏矩阵映射后修剪非零元的问题
问题描述
需要删除nnz_arr中的0值,同时同步更新col_arr和row_arr两个数组。原代码通过Map<SparseMatrix>映射现有数组构建稀疏矩阵,调用prune()时出现错误:
class "Eigen::Map<Eigen::SparseMatrix<double, 1, int>, 0, Eigen::Stride<0, 0>>" has no member "prune"
改用pruned()方法时,原数组无任何变化;尝试将pruned()结果赋值给映射矩阵时,又出现新错误。
错误原因
Map<SparseMatrix>无prune成员:Map只是对现有内存的视图,不支持原地修改稀疏矩阵结构的操作,而prune()(原地修剪)是SparseMatrix的专属成员,Map未实现该方法。pruned()不修改原数组:pruned()返回一个新的、已修剪的SparseMatrix实例,不会改变原nnz_arr、col_arr、row_arr的内容。- 无法直接赋值给
Map:pruned()返回的矩阵内存布局与原映射的数组结构不匹配,不能直接赋值。
解决方案
方法1:转换为真实SparseMatrix后修剪,再同步回原数组
先将映射的矩阵转换为真正的SparseMatrix,修剪后把数据拷贝回原向量:
#include <iostream> #include <Eigen/Sparse> #include <vector> using namespace std; using namespace Eigen; int main(){ int nnz_size = 4; int num_rows = 3; vector<double> nnz_arr(nnz_size); vector<int> col_arr(nnz_size); vector<int> row_arr(num_rows+1); row_arr[0] = 0; row_arr[1] = 1; row_arr[2] = 2; row_arr[3] = 4; nnz_arr[0] = 1; nnz_arr[1] = 1; nnz_arr[2] = 0; nnz_arr[3] = 1; col_arr[0] = 0; col_arr[1] = 1; col_arr[2] = 1; col_arr[3] = 2; // 转换为真实的SparseMatrix SparseMatrix<double, RowMajor, int> mat(num_rows, num_rows, nnz_size, row_arr.data(), col_arr.data(), nnz_arr.data()); // 修剪0元素 mat.prune(0.0); // 清空原数组,拷贝修剪后的数据 nnz_arr.assign(mat.valuePtr(), mat.valuePtr() + mat.nonZeros()); col_arr.assign(mat.innerIndexPtr(), mat.innerIndexPtr() + mat.nonZeros()); row_arr.assign(mat.outerIndexPtr(), mat.outerIndexPtr() + mat.outerSize()); // 输出结果 cout << "修剪后的nnz_arr: "; for(double val : nnz_arr) cout << val << " "; cout << "\n修剪后的col_arr: "; for(int val : col_arr) cout << val << " "; cout << "\n修剪后的row_arr: "; for(int val : row_arr) cout << val << " "; return 0; }
方法2:手动过滤原数组(无需依赖Eigen的修剪方法)
直接遍历原数组,过滤掉值为0的元素,同时同步更新列索引数组,最后重新计算行索引数组:
#include <iostream> #include <vector> using namespace std; int main(){ int nnz_size = 4; int num_rows = 3; vector<double> nnz_arr = {1, 1, 0, 1}; vector<int> col_arr = {0, 1, 1, 2}; vector<int> row_arr = {0, 1, 2, 4}; vector<double> new_nnz; vector<int> new_col; vector<int> new_row(num_rows + 1, 0); // 遍历每一行,收集非零元素 for(int row = 0; row < num_rows; ++row){ int start = row_arr[row]; int end = row_arr[row + 1]; new_row[row + 1] = new_row[row]; for(int idx = start; idx < end; ++idx){ if(nnz_arr[idx] != 0){ new_nnz.push_back(nnz_arr[idx]); new_col.push_back(col_arr[idx]); new_row[row + 1]++; } } } // 替换原数组 nnz_arr.swap(new_nnz); col_arr.swap(new_col); row_arr.swap(new_row); // 输出结果 cout << "修剪后的nnz_arr: "; for(double val : nnz_arr) cout << val << " "; cout << "\n修剪后的col_arr: "; for(int val : col_arr) cout << val << " "; cout << "\n修剪后的row_arr: "; for(int val : row_arr) cout << val << " "; return 0; }
说明
- 方法1利用Eigen内置的修剪逻辑,适合复杂场景;
- 方法2手动处理数组,更轻量,无需依赖Eigen的稀疏矩阵操作。
内容的提问来源于stack exchange,提问作者manne
相关产品推荐
相关产品推荐

