Eigen中所有矩阵和向量都是属于Matrix模板类的对象,Vectors
是特殊的矩阵(一行或一列)
Matrix前三个模板参数
虽然Matrix一共有六个模板参数,但目前暂时学前三个就够了,剩下三个参数有默认值,现在还用不到。Matrix的三个必需模板参数如下:
1 | Matrix<typename Scalar, int RowsAtCompileTime, int ColsAtCompileTime> |
Scalar
:矩阵参数的变量类型,如int
,float
,double
等RowsAtCompileTime
和ColsAtCompileTime
:矩阵的行数和列数特殊值 Dynamic :表示矩阵维度未知
例如:
MatrixXd
表示一个double类型的未知行列的矩阵1
typedef Matrix<double, Dynamic, Dynamic> MatrixXd;
类似地,
VectorXi
表示一个int类型的未知维度的向量1
typedef Matrix<int, Dynamic, 1> VectorXi;
Eigen中还提供了一些typedefs覆盖一些常用类型
MatrixNt
:即Matrix<type, N, N>
,例如Matrix4f
表示4x4的float矩阵VectorNt
:即Matrix<type, N, 1>
,例如Vector4f
表示4维的float列向量RowVectorNt
:即Matrix<type, 1, N>
,例如RowVector3d
表示3维的double行向量- 以上
N
可以是2,3,4或X(表示Dynamic),t
可以是i
(int),f
(float),d
(double),cd
(complex\), cd
(complex\)等。
向量类型
列向量(最常用),列参数固定为1,例如 Vector3f
表示3维float列向量
1 | typedef Matrix<float, 3, 1> Vector3f; |
行向量,行参数固定为1,例如 RowVector2i
表示2维int行向量
1 | typedef Matrix<int, 1, 2> RowVector2i; |
构造函数
默认构造函数
不执行动态内存分配,不初始化矩阵所有系数
1 | Matrix3f a; |
- a是一个3x3矩阵,有一个未初始化的float[9]系数数组
- b是一个动态大小的矩阵,当前大小为0x0,系数数组内存空间尚未分配
含维度的构造函数
- 矩阵类构造函数第一个参数为行数,第二个参数为列数:
1 | MatrixXf a(10,15); |
- a是一个10x15的动态大小矩阵,内存空间已分配,矩阵系数未初始化
- 向量类构造函数传入向量维数即可:
1 | VectorXf b(30); |
- b是一个维度为30的动态大小向量,内存空间已分配,向量系数未初始化
- 在固定大小的矩阵上使用该构造函数是合法的,这是为了给固定大小和动态大小的矩阵提供相同的API接口,虽然这种行为并不会执行什么操作:
1 | Matrix3f a(3,3); |
固定维度向量(<4)允许直接初始化系数
1 | Vector2d a(5.0, 6.0); |
访问系数
用括号访问/修改系数,矩阵先行后列,向量仅传下标即可
1 |
|
输出:
1 | Here is the matrix m: |
语法
m(index)
不仅适用于向量,对一般矩阵都适用,表示矩阵m在内存中存储的第index个元素,默认存储顺序为列优先,当然也可以修改为行有限,见 Storage Orders操作符[]对向量重载,因为C++中[]只能容纳一个参数,所以只能向量使用,且
matrix[i,j]
将会被编译成matrix[j]
并报错:1
error: static assertion failed: THE_BRACKET_OPERATOR_IS_ONLY_FOR_VECTORS__USE_THE_PARENTHESIS_OPERATOR_INSTEAD
逗号初始化
1 | m << 1, 2, 3, |
输出:
1 | m: |
更多介绍见 Advanced Initialization
大小调整
调用
rows()
cols()
size()
方法获取矩阵行数、列数和系数个数动态大小矩阵调用
resize()
方法调整大小。如果矩阵大小不发生变化,该方法不进行任何操作;否则它是破坏性的,矩阵系数可能被改变:
1 |
|
输出:
1 | The matrix m is of size 3x3, with 9 cofficients. |
- 如果想保持矩阵原有系数不变,调用
conservativeResize()
方法:
1 |
|
输出:
1 | The matrix m is of size 3x3, with 9 cofficients. |
- 为了保证API的统一性,上述改变矩阵大小的方法也可以用于固定大小的矩阵类。resize到不同大小会触发
assertion
错误;resize到原本大小不会报错,也不会执行任何操作。
整体赋值
操作符 =
左边的矩阵会被自动resize到右边矩阵的大小,如果不希望这种自动resize发生,也可以将其禁用
1 |
|
输出:
1 | The matrix m is of size 3x3, with 9 cofficients. |
如果左侧为固定大小矩阵,编译不会报错。但如果大小与右侧不同,执行时会报错;相同则不会。
固定大小 vs. 动态大小
固定大小:适用于小矩阵(尤其是个数≤16的矩阵)。固定大小避免了动态内存分配并展开循环,有利于提高性能。实际上一个固定大小的Eigen矩阵只是一个简单的数组,即:执行 Matrix4f m
实际上就是在做 float m[16]
这件事,所以几乎不花时间。但需要注意的是,Eigen默认将数组自动分配为局部变量,这个操作在堆栈(stack)上完成,因此矩阵太大可能会导致堆栈溢出,并且矩阵太大(≥32)时,使用固定大小的性能优势就变得可以忽略不计了。
动态大小:适用于大矩阵或不清楚具体维度的情况。与固定大小矩阵不同,它始终分配在堆(heap)上,即 MatrixXf m(rows, cols)
相当与执行 float *m = new float[rows*cols]
;除此之外,MatrixXf
对象还需要将行数、列数存储为成员变量。
Matrix其他模板参数
完整的 Matrix
模板类如下:
1 | Matrix<typename Scalar, |
Options
:0
表示按列优先存储;RowMajor
表示按行优先存储。例如,一个3x3行优先矩阵:1
Matrix<float, 3, 3, RowMajor> m;
MaxRowsAtCompileTime
MaxColsAtCompileTime
:不知道矩阵具体大小,但知道维度上限的时候很有用,这么做的最大原因是为了避免动态内存分配。1
Matrix<float, Dynamic, Dynamic, 0, 3, 4> m
这句话定义的矩阵仅仅使用了一个大小为12的float数组。