Eigen稀疏矩阵格式及使用方法
finish time:2025-05-20 15:45
参考链接:
-
https://zhuanlan.zhihu.com/p/188700729
-
https://eigen.tuxfamily.org/dox/group__SparseQuickRefPage.html
-
https://eigen.tuxfamily.org/dox/group__TutorialSparse.html
详细介绍Eigen中的稀疏矩阵格式、定义方法以及索引方法。
稀疏矩阵格式
压缩存储:只存储非零值
存储矩阵的一般方法是采用二维数组,其优点是可以随机地访问每一个元素,因而能够容易实现矩阵的各种运算。
对于稀疏矩阵,它通常具有很大的维度,有时甚大到整个矩阵(零元素)占用了绝大部分内存
采用二维数组的存储方法既浪费大量的存储单元来存放零元素,又要在运算中浪费大量的时间来进行零元素的无效运算。因此必须考虑==对稀疏矩阵进行压缩存储(只存储非零元素)==
一、Eigen中的稀疏矩阵格式
Eigen主要支持以下几种稀疏矩阵存储格式:
- Compressed Sparse Column (CSC) - 压缩稀疏列格式
- 默认格式,也是最高效的格式
-
适合列优先操作
-
Compressed Sparse Row (CSR) - 压缩稀疏行格式
- 适合行优先操作
- 按行对矩阵进行压缩的
- 需要通过
SparseMatrix<double, RowMajor>
指定 - 适用:常用于读入数据后进行稀疏矩阵计算,运算高效
-
优点:
- 高效的稀疏矩阵算术运算
- 高效的行切片
- 快速地矩阵矢量积运算
-
Triplet格式 (COO) - 坐标列表格式
- 用于构建稀疏矩阵的中间格式
- 每个非0值用(row, column, value)三元组列表表示
- 应用场景:
- 主要用来创建矩阵,因为coo_matrix无法对矩阵的元素进行增删改等操作
- 一旦创建之后,除了将之转换成其它格式的矩阵,几乎无法对其做任何操作和矩阵运算
- 优点:
- 转换成其它存储格式很快捷简便,能与CSR / CSC格式的快速转换
- 允许重复的索引(例如在1行1列处存了值2.0,又在1行1列处存了值3.0,则转换成其它矩阵时就是2.0+3.0=5.0)
- 缺点:
- 不支持切片和算术运算操作;
稀疏矩阵的顺序:COO用于读取和构造稀疏矩阵变量->Coo转换为csr/csc进行矩阵操作和运算;
二、稀疏矩阵的定义方法
1. 直接定义稀疏矩阵
#include <Eigen/Sparse>
// 定义一个10x10的双精度稀疏矩阵(默认CSC格式)
Eigen::SparseMatrix<double> mat(10, 10);
// 定义一个行优先的稀疏矩阵
Eigen::SparseMatrix<double, Eigen::RowMajor> row_major_mat(10, 10);
2. 使用Triplet列表构建稀疏矩阵
#include <Eigen/Sparse>
// 定义Triplet列表
std::vector<Eigen::Triplet<double>> triplets;
// 添加非零元素 (行索引, 列索引, 值),索引是0-based
triplets.push_back(Eigen::Triplet<double>(0, 0, 1.0));
triplets.push_back(Eigen::Triplet<double>(1, 1, 2.0));
triplets.push_back(Eigen::Triplet<double>(2, 2, 3.0));
// 创建稀疏矩阵并填充
Eigen::SparseMatrix<double> mat(3, 3);
mat.setFromTriplets(triplets.begin(), triplets.end());
3. 从密集矩阵转换
Eigen::MatrixXd dense_mat = Eigen::MatrixXd::Random(5, 5);
Eigen::SparseMatrix<double> sparse_mat = dense_mat.sparseView();
三、稀疏矩阵的索引方法
1. 使用coeffRef()访问元素
Eigen::SparseMatrix<double> mat(3, 3);
mat.coeffRef(0, 0) = 1.0; // 设置(0,0)元素
double val = mat.coeff(1, 1); // 获取(1,1)元素
注意:coeffRef()
会自动插入不存在的元素,而coeff()
只是读取。
2. 使用insert()和prune()方法
3. 迭代非零元素
// 外部迭代器
for (int k = 0; k < mat.outerSize(); ++k) {
for (Eigen::SparseMatrix<double>::InnerIterator it(mat, k); it; ++it) {
std::cout << "(" << it.row() << "," << it.col() << ") = "
<< it.value() << std::endl;
}
}
4. 块操作
四、稀疏矩阵的特殊操作
2. 获取稀疏矩阵信息
3. 稀疏矩阵运算
Eigen::SparseMatrix<double> mat1, mat2, result;
// 矩阵加法
result = mat1 + mat2;
// 矩阵乘法
result = mat1 * mat2;
// 标量乘法
result = mat1 * 2.0;
五、性能考虑
- 对于一次性构建稀疏矩阵,使用Triplet格式最方便
- 对于逐步插入元素,使用insert()方法
- 频繁操作后调用prune()移除零元素