Eigen_icon

1 Matrix类

1.1 介绍

Eigen中所有的矩阵或者向量都用 Matrix 表示,向量就是行为1或者列为1的矩阵

C
// Matrix 是个模板类 模板有六个参数 后三个都有默认值 一般只需要前三个就可以使用
template<typename _Scalar, int _Rows, int _Cols, int _Options, int _MaxRows, int _MaxCols>
class Matrix public ... {
    ...
};
  • _Scalar 矩阵类型(dtype) 可选 double, float, int …
  • _Rows and _Cols 行和列 可以指定为已知值, 可以指定动态类型 Dynamic(const int Dynamic = -1), 表示编译时候大小未知,动态指定
  • _Options 指定主存储顺序, 默认为0, 表示列优先(row-major)存储, 可选RowMajor | ColMajor
  • _MaxRows 指定行上限 默认为 RowsAtCompileTime
  • _MaxCols 指定列上限 默认为 ColsAtCompileTime

当然,在Eigen 定义了许多便利类使用,类似于: typedef Matrix<double, Dynamic, Dynamic> MatrixXd; 行列为动态类型 类型为double的矩阵 typedef Matrix<double, 3, 3> Matrix3d; 3*3 double 类型矩阵 typedef Matrix<float, 4, 4> Matrix4f; 4*4 float 类型矩阵 typedef Matrix<float, 3, 1> Vector3f; 3个元素的列向量 typedef Matrix<int, 1, 2> RowVector2i; 行向量

1.2 构造函数(Constructors)

C
// 默认构造
Matrix3f a; // 3*3 float 大小为3*3 已分配内存  未初始化系数
MatrixXf b; // Dynamic * Dynamic double 大小为0*0 内存未分配  未初始化系数

// 指定行列 会分配内存 但不会初始化系数
MatrixXf a(10, 15)  // 10*15 float
VectorXf b(30);  // 10 * 1
Matrix3f a(3,3); // 合法  但是参数没啥用 已经指定好大小了

1.3 初始化

C
// ★★★ 向量的初始化 最多不超过四个
Vector2d a(5.0, 6.0);
Vector3d b(5.0, 6.0, 7.0);
Vector4d c(5.0, 6.0, 7.0, 8.0);

// c++11初始化列表初始化
Vector2i a(1, 2);                     
Matrix<int, 5, 1> b {1, 2, 3, 4, 5};
Matrix<int, 1, 5> c = {1, 2, 3, 4, 5};

// 2*2 int
MatrixXi a {
      {1, 2},     
      {3, 4}
};
2*3 double
Matrix<double, 2, 3> b {
      {2, 3, 4},
      {5, 6, 7},
};

// 通过隐式内存转化得到列向量
VectorXd a {{1.5, 2.5, 3.5}};   // 列向量
RowVectorXd b {{1.0, 2.0, 3.0, 4.0}}; // 行向量

也可以通过逗号初始化矩阵

C
Matrix3f m;
m << 1, 2, 3,
     4, 5, 6,
     7, 8, 9;
std::cout << m;

1.4 访问矩阵元素

一般通过 重载的 operator() 访问, 先传递行索引, 然后传递列索引, 获得对应位置的值的引用

C
Eigen::MatrixXd m(2,2);  // 2*2 double
m(0,0) = 3;
m(1,0) = 2.5;
m(0,1) = -1;
m(1,1) = m(1,0) + m(0,1);

向量不可以通过重载 operator[] 访问, 直接传递下标访问 矩阵默认存储为列顺序存储, 如果要通过 operator 访问矩阵, 则关注一下存储顺序

1.5 调整大小(Resizing)

  • rows() 获取行数
  • cols() 获取列数
  • size() 获取元素总数 size() = rows() * cols()
  • resize() 调整大小 会给便行列 保证resize()前后 size()不变
C
#include <iostream>
#include <Eigen/Dense>
 
int main()
{
  Eigen::MatrixXd m(2,5);
  m.resize(4,3);
  std::cout << "The matrix m is of size "
            << m.rows() << "x" << m.cols() << std::endl;
  std::cout << "It has " << m.size() << " coefficients" << std::endl;
  Eigen::VectorXd v(2);
  v.resize(5);
  std::cout << "The vector v is of size " << v.size() << std::endl;
  std::cout << "As a matrix, v is of size "
            << v.rows() << "x" << v.cols() << std::endl;
}

output

Bash
The matrix m is of size 4x3
It has 12 coefficients
The vector v is of size 5
As a matrix, v is of size 5x1

1.6 矩阵赋值(Assignment)

使用操作符 = 将一个矩阵复制到另一个矩阵的操作, Eigen会自动调整左边矩阵的大小去适应右边矩阵大小

C
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;

outout

Bash
a is of size 2x2
a is now of size 3x3

1.7 固定大小和动态大小

对于较小的大小,特别是小于(大约)16,使用固定大小对性能非常有益 大于(大约)32的大小,使用固定大小的性能优势变得可以忽略不计 固定大小矩阵的数组直接指定大小 动态大小矩阵的数组总是在堆上分配

2 Tensor arithmetic

Eigen 通过重载c++算数运算符或特殊方法提供了矩阵/向量算数运算, ==操作符只被用作支持线性代数操作==

2.1 加法和减法运算(Addition and subtraction)

计算左边和右边必须有相同的行和列 必须有相同的Scalar类型, Eigen无法自动提升类型

  • 加法 a + b 或者 a += b ==对应位置元素相加==
  • 减法 a - b 或者 a -= b ==对应位置元素相减==
C
#include <iostream>
#include <Eigen/Dense>
 
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;

output

Bash
a * 2.5 =
2.5   5
7.5  10
0.1 * v =
0.1
0.2
0.3
Doing v *= 2;
Now v =
2
4
6

2.2 标量和矩阵的乘法和除法运算(Scalar multiplication and division)

  • 乘法 matrix*scalar 或者 scalar*matrix 或者 matrix*=scalar ==标量和矩阵每个元素相乘==
  • 除法 matrix/scalar 或者 matrix/=scalar ==标量和矩阵每个元素相除== 注意: 标量不能除矩阵
C
#include <iostream>
#include <Eigen/Dense>
 
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;
}

output

Bash
a * 2.5 =
2.5   5
7.5  10
0.1 * v =
0.1
0.2
0.3
Doing v *= 2;
Now v =
2
4
6

2.3 转置和共轭(Transposition and conjugation)

  • transpose() 转置($a^T$)** 调用该方法需要赋值时才计算 ==如果要原地转置则用其他方法==**
  • conjugate() 共轭($\bar{a}$) (虚数才有)
  • adjoint() 共轭转置($a^*$) (实数的共轭转置相当于转置)
  • transposeInPlace() 原地转置 直接在
C
MatrixXcf a = MatrixXcf::Random(2,2);
cout << "Here is the matrix a\n" << a << endl;

cout << "Here is the matrix a^T\n" << a.transpose() << endl;
 
cout << "Here is the conjugate of a\n" << a.conjugate() << endl;

cout << "Here is the matrix a^*\n" << a.adjoint() << endl;

output

Bash
Here is the matrix a
 (-0.211,0.68) (-0.605,0.823)
 (0.597,0.566)  (0.536,-0.33)
Here is the matrix a^T
 (-0.211,0.68)  (0.597,0.566)
(-0.605,0.823)  (0.536,-0.33)
Here is the conjugate of a
 (-0.211,-0.68) (-0.605,-0.823)
 (0.597,-0.566)    (0.536,0.33)
Here is the matrix a^*
 (-0.211,-0.68)  (0.597,-0.566)
(-0.605,-0.823)    (0.536,0.33)

2.4 矩阵-矩阵和矩阵-向量乘法(Matrix-matrix and matrix-vector multiplication)

矩阵和矩阵的乘法也是运算符*完成, 矩阵-向量乘法是矩阵-矩阵的特殊情况 向量-向量的外积(区别于实际中向量的外积(叉积,矢量积))也是特殊情况 都按照矩阵乘法来计算 矩阵相乘的条件是==左矩阵的列和右矩阵的行相同==

  • a * b
  • a *= b
C
#include <iostream>
#include <Eigen/Dense>
 
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;  // temp = m * m; m = temp;
  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;
}

output

Bash
Here is mat*mat:
 7 10
15 22
Here is mat*u:
1
1
Here is u^T*mat:
2 2
Here is u^T*v:
-2
Here is u*v^T:
-2 -0
 2  0
Let's multiply mat by itself
Now mat is mat:
 7 10
15 22

如果知道矩阵计算可以安全计算而没有叠加问题 可以使用 noalias() c.noalias() += a * b;

2.5 点乘(点积)和叉乘(叉积)(Dot product and cross product)

  • dot() 点乘
  • cross() 叉乘
C
#include <iostream>
#include <Eigen/Dense>
 
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;
}

output

Bash
Dot product: 8
Dot product via a matrix product: 8
Cross product:
 1
-2
 1

外积(cross product)适用大小小于3的向量, 而内积(dot product)适用于任意大小的向量

2.6 基本的算术约简操作(Basic arithmetic reduction operations)

约简操作值得是用于汇总或者聚合数据的操作,以便得到某种总结或同级的结果

  • sum() 求和(Summation)
  • prod() 求积(Product)
  • mean() 平均值(Mean)
  • maxCoeff() 最大值(Maximum)
  • minCoeff() 最小值(Minimum)
  • trace() 迹(对角系数的和) == a.diagonal().sum()

maxCoeff()minCoeff() 也可以传入参数, 可以获取最大值或最小值的下标

C
#include <iostream>
#include <Eigen/Dense>
 
using namespace std;
int main()
{
  Eigen::Matrix2d mat;
  mat << 1, 2,
         3, 4;
  cout << "Here is mat.sum():       " << mat.sum()       << endl;
  cout << "Here is mat.prod():      " << mat.prod()      << endl;
  cout << "Here is mat.mean():      " << mat.mean()      << endl;
  cout << "Here is mat.minCoeff():  " << mat.minCoeff()  << endl;
  cout << "Here is mat.maxCoeff():  " << mat.maxCoeff()  << endl;
  cout << "Here is mat.trace():     " << mat.trace()     << endl;
}

output

Bash
Here is mat.sum():       10
Here is mat.prod():      24
Here is mat.mean():      2.5
Here is mat.minCoeff():  1
Here is mat.maxCoeff():  4
Here is mat.trace():     5