目录
前情提要
稀疏矩阵操作
头文件 | 内容 |
#include <Eigen/SparseCore> | 稀疏矩阵、稀疏矢量、矩阵组装、基础稀疏线性代数 |
#include <Eigen/SparseCholesky> | 直接稀疏LLT、LDLT分解用于稀疏自伴随正定问题 |
#include<Eigen/SparseLU> | 稀疏LU分解用于一般二乘稀疏系统 |
#include<Eigen/SparseQR> | 稀疏QR分解用于稀疏线性最小二乘问题 |
#include <Eigen/IterativeLinearSolvers> | 迭代法求解大型一般线性二乘问题 |
#include <Eigen/Sparse> | 包含上面全部 |
稀疏矩阵格式
- Values:各非零元素的值(column-major)
- InnerIndices:各非零元素所在的行数
- OuterStarts:每一列第一个出现的非零元素在前两个数组中的索引,末尾再添上前两个数组的长度
- InnerNNZs:每列中非零元素的个数
例子如下
第一个例子(纯是没看懂)
使用有限差分法和Dirichlet边界条件在普通2D网格上求解拉普拉斯方程Δu=0
#include <Eigen/Sparse>
#include <vector>
#include <QImage>
typedef Eigen::SparseMatrix<double> SpMat; // declares a column-major sparse matrix type of double
typedef Eigen::Triplet<double> T;
void insertCoefficient(int id, int i, int j, double w, std::vector<T>& coeffs,
Eigen::VectorXd& b, const Eigen::VectorXd& boundary)
{
int n = int(boundary.size());
int id1 = i+j*n;
if(i==-1 || i==n) b(id) -= w * boundary(j); // constrained coefficient
else if(j==-1 || j==n) b(id) -= w * boundary(i); // constrained coefficient
else coeffs.push_back(T(id,id1,w)); // unknown coefficient
}
void buildProblem(std::vector<T>& coefficients, Eigen::VectorXd& b, int n)
{
b.setZero();
Eigen::ArrayXd boundary = Eigen::ArrayXd::LinSpaced(n, 0,M_PI).sin().pow(2);
for(int j=0; j<n; ++j)
{
for(int i=0; i<n; ++i)
{
int id = i+j*n;
insertCoefficient(id, i-1,j, -1, coefficients, b, boundary);
insertCoefficient(id, i+1,j, -1, coefficients, b, boundary);
insertCoefficient(id, i,j-1, -1, coefficients, b, boundary);
insertCoefficient(id, i,j+1, -1, coefficients, b, boundary);
insertCoefficient(id, i,j, 4, coefficients, b, boundary);
}
}
}
void saveAsBitmap(const Eigen::VectorXd& x, int n, const char* filename)
{
Eigen::Array<unsigned char,Eigen::Dynamic,Eigen::Dynamic> bits = (x*255).cast<unsigned char>();
QImage img(bits.data(), n,n,QImage::Format_Indexed8);
img.setColorCount(256);
for(int i=0;i<256;i++) img.setColor(i,qRgb(i,i,i));
img.save(filename);
}
稀疏矩阵类
SparseMatrix<std::complex<float> > mat(1000,2000);
// declares a 1000x2000 column-major compressed sparse matrix of complex<float>
SparseMatrix<double,RowMajor> mat(1000,2000);
// declares a 1000x2000 row-major compressed sparse matrix of double
SparseVector<std::complex<float> > vec(1000);
// declares a column sparse vector of complex<float> of size 1000
SparseVector<double,RowMajor> vec(1000);
// declares a row sparse vector of double of size 1000
获取矩阵信息
- mat.rows()、mat.cols()、vec.size()
- mat.innerSize()、mat.outerSize()
- mat.nonZeros()、vec.nonZeros()
遍历非零元素:先遍历outer维度(每列),再遍历inter矢量(非零元素所在的列)
SparseMatrix<double> mat(rows,cols);
for (int k=0; k<mat.outerSize(); ++k)
for (SparseMatrix<double>::InnerIterator it(mat,k); it; ++it)
{
it.value();
it.row(); // row index
it.col(); // col index (here it is equal to k)
it.index(); // inner index, here it is equal to it.row()
}
SparseVector<double> vec(size);
for (SparseVector<double>::InnerIterator it(vec); it; ++it)
{
it.value(); // == vec[ it.index() ]
it.index();
}
装填稀疏矩阵
typedef Eigen::Triplet<double> T;
std::vector<T> tripletList;
tripletList.reserve(estimation_of_entries);
for(...)
{
// ...
tripletList.push_back(T(i,j,v_ij)); // 猜测大概是行数、列数、值
}
SparseMatrixType mat(rows,cols);
mat.setFromTriplets(tripletList.begin(), tripletList.end());
// mat is ready to go!
SparseMatrix<double> mat(rows,cols); // default is column major
mat.reserve(VectorXi::Constant(cols,6)); // 每列保留6个位置
for each i,j such that v_ij != 0
mat.insert(i,j) = v_ij; // alternative: mat.coeffRef(i,j) += v_ij;
mat.makeCompressed(); // optional
支持的运算符和函数
基础操作
加、减、取实部、取虚部、点积、转置、伴随
注意!存储方式必须相同,因此
SparseMatrix<double> A, B;
B = SparseMatrix<double>(A.transpose()) + A;
稀疏矩阵和普通矩阵可以混用
sm2 = sm1.cwiseProduct(dm1);
dm2 = sm1 + dm1;
dm2 = dm1 - sm1;
dm2 = dm1;
dm2 += sm1;
// 好于
dm2 = sm1 + dm1
矩阵乘积
稀疏-普通
dv2 = sm1 * dv1;
dm2 = dm1 * sm1.adjoint();
dm2 = 2. * sm1 * dm1;
对称稀疏-普通
dm2 = sm1.selfadjointView<>() * dm1; // if all coefficients of A are stored
dm2 = A.selfadjointView<Upper>() * dm1; // if only the upper part of A is stored
dm2 = A.selfadjointView<Lower>() * dm1; // if only the lower part of A is stored
稀疏-稀疏
sm3 = sm1 * sm2;
sm3 = 4 * sm1.adjoint() * sm2;
sm3 = (sm1 * sm2).pruned(); // removes numerical zeros
sm3 = (sm1 * sm2).pruned(ref); // removes elements much smaller than ref
sm3 = (sm1 * sm2).pruned(ref,epsilon); // removes elements smaller than ref*epsilon
置换矩阵
PermutationMatrix<Dynamic,Dynamic> P = ...;
sm2 = P * sm1;
sm2 = sm1 * P.inverse();
sm2 = sm1.transpose() * P;
分块操作
读的话和普通矩阵一样,写的话仅限于连续的列或行(存储方式为column-major或row-major的情况下)
SparseMatrix<double,ColMajor> sm1;
sm1.col(j) = ...;
sm1.leftCols(ncols) = ...;
sm1.middleCols(j,ncols) = ...;
sm1.rightCols(ncols) = ...;
SparseMatrix<double,RowMajor> sm2;
sm2.row(i) = ...;
sm2.topRows(nrows) = ...;
sm2.middleRows(i,nrows) = ...;
sm2.bottomRows(nrows) = ...;
三角化和自伴随(没懂)
三角化
dm2 = sm1.triangularView<Lower>(dm1);
dv2 = sm1.transpose().triangularView<Upper>(dv1);
自伴随
dm2 = sm1.selfadjointView<>() * dm1; // if all coefficients of A are stored
dm2 = A.selfadjointView<Upper>() * dm1; // if only the upper part of A is stored
dm2 = A.selfadjointView<Lower>() * dm1; // if only the lower part of A is stored
sm2 = sm1.selfadjointView<Upper>();
// makes a full selfadjoint matrix from the upper triangular part
sm2.selfadjointView<Lower>() = sm1.selfadjointView<Upper>();
// copies the upper triangular part to the lower triangular part
PermutationMatrix<Dynamic,Dynamic> P = ...;
sm2 = A.selfadjointView<Upper>().twistedBy(P);
// compute P S P' from the upper triangular part of A, and make it a full matrix
sm2.selfadjointView<Lower>() = A.selfadjointView<Lower>().twistedBy(P);
// compute P S P' from the lower triangular part of A, and then only compute the lower part
求解稀疏线性系统
基本方法
#include <Eigen/RequiredModuleName>
// ...
SparseMatrix<double> A;
// fill A
VectorXd b, x;
// fill b
// solve Ax = b
SolverClassName<SparseMatrix<double> > solver;
solver.compute(A);
if(solver.info()!=Success) {
// decomposition failed
return;
}
x = solver.solve(b);
if(solver.info()!=Success) {
// solving failed
return;
}
// solve for another right hand side:
x1 = solver.solve(b1);
稀疏矩阵快速参考手册(重要)
https://eigen.tuxfamily.org/dox/group__SparseQuickRefPage.html
Pingback: C++库Eigen学习4:几何 - Fivyex's Blog