Eigen c++库

Eigen

前言

工程代码中经常遇到Eigen的使用,故做下学习小结。
ubuntu:
在终端输入:
sudo apt-get install libeigen3-dev

windows:
CLion:
eigen-3.4.0下载地址
Eigen c++库_第1张图片
解压文件到工程目录,在CMakeList.txt文件上添加:

include_directories(./eigen-3.4.0)

Eigen简单入门

1 Eigen矩阵和向量

在Eigen中,所有矩阵和向量都是矩阵模板类的对象,Vector也是一种特殊的矩阵,要么指定行为1,要么指定列为1。

1.1 Matrix、Vector

Xi: int
Xf: float
Xd: double
Xcf: std::complex
Xcd: std::complex

  1. 编译确定大小的Matrix3d
    向量元素个数已知,列向量定义:Vector3dVector3fVector3i 3x1
    定义行向量:RowVector2i 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;
}
  1. 编译不确定大小的MatrixXd、VectorXd
    Vector 向量是行或者列为1的矩阵
    向量元素个数未知,定义向量:VectorXi;VectorXdVectorXf
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;
}
1.2 基本操作
  1. 获取元素
cout << m(0,0) << endl;
cout << m(2) << endl;
cout << v(0) << endl;
cout << v[2] << endl;
  1. 矩阵的大小,调整大小
    行数:rows()
    列数:cols()
    矩阵大小:size()
    重新调整动态矩阵的大小resize()
cout << m.rows() << endl;
cout << m.cols() << endl;
cout << m.size() << endl;
m.resize(4,4);

2. Eigen使用

使用Eigen基本上包含#include 就够了。
该头文件内容如下:

#include “Core”
#include “LU”
#include “Cholesky”
#include “QR”
#include “SVD”
#include “Geometry”
#include “Eigenvalues”

2.1 矩阵初始化
  1. 随机初始化,初始值在[-1,1]内,矩阵大小2x2
MatrixXd c = Matrix::Random(2,2);
  1. 常量值初始化,三个参数:行数、列数、常量值
MatrixXd d = Matrix::Constant(2,2,3);
  1. 零初始化
Matrix2d e = Matrix2d::Zero();
  1. 矩阵里面的值全部初始化为1
Matrix3d h = Matrix3d::Ones();
  1. 初始化为单位矩阵
Matrix4d a = Matrix4d::Identity();
  1. 逗号初始化
Matrix3d b;
b << 1, 2, 3, 4, 5, 6, 7, 8, 9;
2.2 Array类

Eigen提供了一个Array类,有大量的矩阵未定义的操作,比如矩阵和标量的加法运算,且Array和Matrix很容易相互转换,为使用者的需求提供了更多选择。

  1. 对象创建

ArrayXXf a(3,3);

  1. 初始化

a << 1, 2, 3,
4, 5, 6,
7, 8, 9;

  1. 数学运算
  2. Array和Matrix互相转换

MatrixXf m = c.matrix();
ArrayXXf d = m.array();

  1. 实例
#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;
2.3 块操作

表示从第a行b列开始,截取i行j列

m.block(a,b)

Eigen教程

详细教程参考该网址,本文列举了一些常用的操作

1 密集矩阵和数组操作

1.1 向量

在 Eigen 中,向量只是矩阵的一个特例,有 1 行或 1 列。他们有 1 列的情况是最常见的;这种向量称为列向量,通常缩写为向量。在它们有 1 行的另一种情况下,它们称为行向量

typedef Matrix<float, 3, 1> Vector3f;
typedef Matrix<int, 1, 2> RowVector2i;
1.2 动态大小矩阵
typedef Matrix<double, Dynamic, Dynamic> MatrixXd;
typedef Matrix<int, Dynamic, 1> VectorXi;
1.3 构造函数
Matrix3d a;
MatrixXd b;

a:3 x 3矩阵,未初始化系数
b:动态大小矩阵,大小 0 x 0

也可提供采用尺寸的构造函数。对于矩阵,始终首先传递行数。对于向量,只需传递向量大小即可。它们使用给定大小分配系数数组,但不初始化系数本身。

MatrixXd a(10,15);
VectorXd b(30);
1.4 Coefficient accessors

填充矩阵

#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;
}
1.5 逗号初始化
Matrix3d m;
m << 1, 2, 3,
	 4, 5, 6,
	 7, 8, 9;
cout << m << endl;
1.6 resize

矩阵的当前大小可以通过 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;
}
1.7 分配和调整大小

赋值是使用 将一个矩阵复制到另一个矩阵中的操作。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
1.8 固定大小与动态大小

什么时候应该使用固定大小(例如),什么时候应该更喜欢动态大小(例如)?简单的答案是:尽可能对非常小的尺寸使用固定尺寸,对较大的尺寸或必须使用动态尺寸。对于小尺寸,尤其是小于(大约)16 的尺寸,使用固定大小对性能非常有益,因为它允许 Eigen 避免动态内存分配并展开循环。在内部,固定大小的特征矩阵只是一个普通的数组

2 矩阵和向量算术

2.1 加法和减法
#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;
}
2.2 标量乘法和除法
#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;
}
2.3 转置、共轭、伴随
MatrixXcf a = MatrixXcf::Random(2,2);
a.transpose();
a.conjugate();
a.adjoint();

不能写如下的格式:

a = a.transpose(); // !!! do NOT do this !!!
2.4 矩阵-矩阵和矩阵-向量乘法
#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;
}
2.5 点积和叉积

对于点积和叉积,您需要 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;
}
2.6 基本算术约简运算

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
}

3 密集线性问题和分解

3.1 基本线性求解

针对一个矩阵方程:
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;
}

Eigen c++库_第2张图片

3.2 检查矩阵是否奇异

您希望允许多大的误差范围,才能使解决方案被视为有效。

#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;
}
3.3 计算特征值和特征向量
#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;
}
3.4 计算逆式和行列式
#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()

4 稀疏矩阵操作

Eigen c++库_第3张图片
处理非常大的矩阵,其中只有几个系数与零不同。在这种情况下,通过使用仅存储非零系数的专用表示形式,可以减少内存消耗并提高性能。这种矩阵称为稀疏矩阵。

#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;
}

你可能感兴趣的:(决策规划控制,C++,c++,Eigen)