工程代码中经常遇到Eigen的使用,故做下学习小结。
ubuntu:
在终端输入:
sudo apt-get install libeigen3-dev
windows:
CLion:
eigen-3.4.0下载地址
解压文件到工程目录,在CMakeList.txt文件上添加:
include_directories(./eigen-3.4.0)
在Eigen中,所有矩阵和向量都是矩阵模板类的对象,Vector也是一种特殊的矩阵,要么指定行为1,要么指定列为1。
Xi: int
Xf: float
Xd: double
Xcf: std::complex
Xcd: std::complex
Vector3d
、Vector3f
、Vector3i
3x1RowVector2i
1x2#include
#include
using namespace Eigen;
using namespace std;
int main()
{
Matrix3d m = Matrix3d::Random(); //3x3
cout << m << endl;
Vector3d v(1,2,3); //3x1
cout << m*v << endl; //3x1
return 0;
}
VectorXi;
、VectorXd
、VectorXf
Vector3i v1;
v1 << 1, 2, 3;
VectorXi v2(5);
v2 << 3, 6, 3, 5, 12;
RowVector2d v3;
v3 << 31, 9;
#include
#include
using namespace Eigen;
using namespace std;
int main()
{
MatrixXd m = Matrix::Random(3,3);
m = m + MatrixXd::Constant(3,3,1.2)*50;
VectorXd v(3);
v << 1, 2, 3;//逗号初始化
cout << m*v << endl;
return 0;
}
cout << m(0,0) << endl;
cout << m(2) << endl;
cout << v(0) << endl;
cout << v[2] << endl;
行数:rows()
列数:cols()
矩阵大小:size()
重新调整动态矩阵的大小resize()
cout << m.rows() << endl;
cout << m.cols() << endl;
cout << m.size() << endl;
m.resize(4,4);
使用Eigen基本上包含#include
就够了。
该头文件内容如下:
#include “Core”
#include “LU”
#include “Cholesky”
#include “QR”
#include “SVD”
#include “Geometry”
#include “Eigenvalues”
MatrixXd c = Matrix::Random(2,2);
MatrixXd d = Matrix::Constant(2,2,3);
Matrix2d e = Matrix2d::Zero();
Matrix3d h = Matrix3d::Ones();
Matrix4d a = Matrix4d::Identity();
Matrix3d b;
b << 1, 2, 3, 4, 5, 6, 7, 8, 9;
Eigen提供了一个Array类,有大量的矩阵未定义的操作,比如矩阵和标量的加法运算,且Array和Matrix很容易相互转换,为使用者的需求提供了更多选择。
ArrayXXf a(3,3);
a << 1, 2, 3,
4, 5, 6,
7, 8, 9;
MatrixXf m = c.matrix();
ArrayXXf d = m.array();
#include
#include
using namespace std;
using namespace Eigen;
int main()
{
ArrayXXf a(3,3);
ArrayXXf b(3,3);
a << 1, 2, 3,
4, 5, 6,
7, 8, 9;
b << 1, 2, 3,
1, 2, 3,
1, 2, 3;
cout << a+b << endl;
cout << a-2 << endl;
cout << a*b << endl;
cout << a/b << endl;
ArrayXXf c = ArrayXXf::Random(2,2);
c*=2;
cout << c << endl;
cout << c.abs() << endl;
cout << c.abs().sqrt() << endl;
cout << c.min(a.abs().sqrt()) << endl;
MatrixXf m = c.matrix();
ArrayXXf d = m.array();
return 0;
表示从第a行b列开始,截取i行j列
m.block(a,b)
详细教程参考该网址,本文列举了一些常用的操作
在 Eigen 中,向量只是矩阵的一个特例,有 1 行或 1 列。他们有 1 列的情况是最常见的;这种向量称为列向量,通常缩写为向量。在它们有 1 行的另一种情况下,它们称为行向量。
typedef Matrix<float, 3, 1> Vector3f;
typedef Matrix<int, 1, 2> RowVector2i;
typedef Matrix<double, Dynamic, Dynamic> MatrixXd;
typedef Matrix<int, Dynamic, 1> VectorXi;
Matrix3d a;
MatrixXd b;
a:3 x 3矩阵,未初始化系数
b:动态大小矩阵,大小 0 x 0
也可提供采用尺寸的构造函数。对于矩阵,始终首先传递行数。对于向量,只需传递向量大小即可。它们使用给定大小分配系数数组,但不初始化系数本身。
MatrixXd a(10,15);
VectorXd b(30);
填充矩阵
#include
#include
int main()
{
Eigen::MatrixXd m(2, 2);
m(0, 0) = 3;
m(1, 0) = 2.5;
m(0, 1) = -1;
m(1, 1) = m(1, 0) + m(0, 1);
std::cout << "Here is the matrix m:\n" << m << std::endl;
Eigen::VectorXd v(2);
v(0) = 4;
v(1) = v(0) - 1;
std::cout << "Here is the vector v:\n" << v << std::endl;
}
Matrix3d m;
m << 1, 2, 3,
4, 5, 6,
7, 8, 9;
cout << m << endl;
矩阵的当前大小可以通过 rows()、cols() 和 size()检索。这些方法分别返回行数、列数和大小。调整动态矩阵大小通过resize()完成的。
#include
#include
using namespace std;
using namespace Eigen;
int main()
{
MatrixXd m(2, 5);
m.resize(4, 3);
cout << m.rows() << ' ' << m.cols() << endl;
cout << m.size() << endl;
VectorXd v(2);
v.resize(5);
cout << v.size() << endl;
cout << v.rows() << ' ' << v.cols() << endl;
}
赋值是使用 将一个矩阵复制到另一个矩阵中的操作。Eigen 会自动调整左侧矩阵的大小,使其与右侧大小的矩阵大小相匹配。
#include
#include
using namespace std;
using namespace Eigen;
int main()
{
MatrixXf a(2,2);
std::cout << "a is of size " << a.rows() << "x" << a.cols() << std::endl;
MatrixXf b(3,3);
a = b;
std::cout << "a is now of size " << a.rows() << "x" << a.cols() << std::endl;
}
输出:
a is of size 2x2
a is now of size 3x3
什么时候应该使用固定大小(例如),什么时候应该更喜欢动态大小(例如)?简单的答案是:尽可能对非常小的尺寸使用固定尺寸,对较大的尺寸或必须使用动态尺寸。对于小尺寸,尤其是小于(大约)16 的尺寸,使用固定大小对性能非常有益,因为它允许 Eigen 避免动态内存分配并展开循环。在内部,固定大小的特征矩阵只是一个普通的数组
#include
#include
int main()
{
Eigen::Matrix2d a;
a << 1, 2,
3, 4;
Eigen::MatrixXd b(2,2);
b << 2, 3,
1, 4;
std::cout << "a + b =\n" << a + b << std::endl;
std::cout << "a - b =\n" << a - b << std::endl;
std::cout << "Doing a += b;" << std::endl;
a += b;
std::cout << "Now a =\n" << a << std::endl;
Eigen::Vector3d v(1,2,3);
Eigen::Vector3d w(1,0,0);
std::cout << "-v + w - v =\n" << -v + w - v << std::endl;
}
#include
#include
int main()
{
Eigen::Matrix2d a;
a << 1, 2,
3, 4;
Eigen::Vector3d v(1,2,3);
std::cout << "a * 2.5 =\n" << a * 2.5 << std::endl;
std::cout << "0.1 * v =\n" << 0.1 * v << std::endl;
std::cout << "Doing v *= 2;" << std::endl;
v *= 2;
std::cout << "Now v =\n" << v << std::endl;
}
MatrixXcf a = MatrixXcf::Random(2,2);
a.transpose();
a.conjugate();
a.adjoint();
不能写如下的格式:
a = a.transpose(); // !!! do NOT do this !!!
#include
#include
int main()
{
Eigen::Matrix2d mat;
mat << 1, 2,
3, 4;
Eigen::Vector2d u(-1,1), v(2,0);
std::cout << "Here is mat*mat:\n" << mat*mat << std::endl;
std::cout << "Here is mat*u:\n" << mat*u << std::endl;
std::cout << "Here is u^T*mat:\n" << u.transpose()*mat << std::endl;
std::cout << "Here is u^T*v:\n" << u.transpose()*v << std::endl;
std::cout << "Here is u*v^T:\n" << u*v.transpose() << std::endl;
std::cout << "Let's multiply mat by itself" << std::endl;
mat = mat*mat;
std::cout << "Now mat is mat:\n" << mat << std::endl;
}
对于点积和叉积,您需要 dot() 和 cross()方法。当然,点积也可以作为 1x1 矩阵作为 u.adjoint() * v获得。
#include
#include
int main()
{
Eigen::Vector3d v(1,2,3);
Eigen::Vector3d w(0,1,2);
std::cout << "Dot product: " << v.dot(w) << std::endl;
double dp = v.adjoint()*w; // automatic conversion of the inner product to a scalar
std::cout << "Dot product via a matrix product: " << dp << std::endl;
std::cout << "Cross product:\n" << v.cross(w) << std::endl;
}
Eigen 还提供了一些约简操作,将给定的矩阵或向量简化为单个值,例如其所有系数的总和(由 sum() 计算)、乘积 (prod()) 或最大值 (maxCoeff()) 和最小值 (minCoeff())。
#include
#include
using namespace std;
int main()
{
Eigen::Matrix2d mat;
mat << 1, 2,
3, 4;
cout << "Here is mat.sum(): " << mat.sum() << endl; // 10
cout << "Here is mat.prod(): " << mat.prod() << endl; // 24
cout << "Here is mat.mean(): " << mat.mean() << endl; // 2.5
cout << "Here is mat.minCoeff(): " << mat.minCoeff() << endl; // 1
cout << "Here is mat.maxCoeff(): " << mat.maxCoeff() << endl; // 4
cout << "Here is mat.trace(): " << mat.trace() << endl; // 5
}
针对一个矩阵方程:
A x = b Ax=b Ax=b
A:矩阵,B:向量,找到一个解决方案x
#include
#include
int main()
{
Eigen::Matrix3f A;
Eigen::Vector3f b;
A << 1,2,3,
4,5,6,
7,8,10;
b << 3, 3, 4;
std::cout << "Here is the matrix A:\n" << A << std::endl;
std::cout << "Here is the vector b:\n" << b << std::endl;
Eigen::Vector3f x = A.colPivHouseholderQr().solve(b); // Ax = b
std::cout << "The solution is:\n" << x << std::endl;
}
您希望允许多大的误差范围,才能使解决方案被视为有效。
#include
#include
using Eigen::MatrixXd;
int main()
{
MatrixXd A = MatrixXd::Random(100,100);
MatrixXd b = MatrixXd::Random(100,50);
MatrixXd x = A.fullPivLu().solve(b);
double relative_error = (A*x - b).norm() / b.norm(); // norm() is L2 norm
std::cout << "The relative error is:\n" << relative_error << std::endl;
}
#include
#include
int main()
{
Eigen::Matrix2f A;
A << 1, 2, 2, 3;
std::cout << "Here is the matrix A:\n" << A << std::endl;
Eigen::SelfAdjointEigenSolver<Eigen::Matrix2f> eigensolver(A);
if (eigensolver.info() != Eigen::Success) abort();
std::cout << "The eigenvalues of A are:\n" << eigensolver.eigenvalues() << std::endl;
std::cout << "Here's a matrix whose columns are eigenvectors of A \n"
<< "corresponding to these eigenvalues:\n"
<< eigensolver.eigenvectors() << std::endl;
}
#include
#include
int main()
{
Eigen::Matrix3f A;
A << 1, 2, 1,
2, 1, 0,
-1, 1, 2;
std::cout << "Here is the matrix A:\n" << A << std::endl;
std::cout << "The determinant of A is " << A.determinant() << std::endl;
std::cout << "The inverse of A is:\n" << A.inverse() << std::endl;
}
参考:
LU:
MatrixBase::inverse()
MatrixBase::determinant()
QR:
MatrixBase::householderQr()
MatrixBase::colPivHouseholderQr()
MatrixBase::fullPivHouseholderQr()
SVD:
MatrixBase::jacobiSvd()
MatrixBase::bdcSvd()
处理非常大的矩阵,其中只有几个系数与零不同。在这种情况下,通过使用仅存储非零系数的专用表示形式,可以减少内存消耗并提高性能。这种矩阵称为稀疏矩阵。
#include
#include
#include
typedef Eigen::SparseMatrix<double> SpMat; // declares a column-major sparse matrix type of double
typedef Eigen::Triplet<double> T;
void buildProblem(std::vector<T>& coefficients, Eigen::VectorXd& b, int n);
void saveAsBitmap(const Eigen::VectorXd& x, int n, const char* filename);
int main(int argc, char** argv)
{
if(argc!=2) {
std::cerr << "Error: expected one and only one argument.\n";
return -1;
}
int n = 300; // size of the image
int m = n*n; // number of unknowns (=number of pixels)
// Assembly:
std::vector<T> coefficients; // list of non-zeros coefficients
Eigen::VectorXd b(m); // the right hand side-vector resulting from the constraints
buildProblem(coefficients, b, n);
SpMat A(m,m);
A.setFromTriplets(coefficients.begin(), coefficients.end());
// Solving:
Eigen::SimplicialCholesky<SpMat> chol(A); // performs a Cholesky factorization of A
Eigen::VectorXd x = chol.solve(b); // use the factorization to solve for the given right hand side
// Export the result to a file:
saveAsBitmap(x, n, argv[1]);
return 0;
}