最近由于工作原因,所以需要学习使用 Eigen E i g e n ,顺便写一下学习笔记,方便你我他。
简介
简单的说, Eigen E i g e n 就是一个线性代数的 C++ C + + 库,它对矩阵( Matrix M a t r i x )和向量( Vector V e c t o r )等相关线性代数的运算操作进行了比较系统的实现。
注意:后文的示例代码中使用的变量名之间并无上下文关系,只是为了做一下简单的区分。
矩阵( Matrix M a t r i x )
定义
矩阵模板函数中一共包含六个模板参数,前三个是比较常用的,分别表示矩阵元素的类型、行数、列数。在矩阵定义的时候可以使用
Dynamic
D
y
n
a
m
i
c
来表示行或者列数未知。
ex:
e
x
:
template<typename _Scalar, int _Rows, int _Cols, int _Options, int _MaxRows, int _MaxCols>
class Eigen::Matrix< _Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols >
Eigen::Matrix<int, 3, 4> mat1; // 3x4 的 int 类型的矩阵 mat1
Eigen::Matrix<double, 3, Dynamic> mat2; // 3x? 的 double 类型的矩阵 mat2
Eigen::Matrix<float, Dynamic, 4> mat3; // ?x4 的 float 类型的矩阵 mat3
Eigen::Matrix<long, Dynamic, Dynamic> mat4; // ?x? 的 long 类型的矩阵 mat4
类型
在
Eigen
E
i
g
e
n
中
typedef
t
y
p
e
d
e
f
了很多矩阵的类型,通常命名为
Matrix
M
a
t
r
i
x
前缀加一个长度为
1∼4
1
∼
4
的字符串
S
S
的命名——。其中
S
S
可以用来判断该矩阵类型,数字 表示
n ∗ n
n
∗
n
,
n
n
的范围是 ,字母
d、f、i、c
d
、
f
、
i
、
c
表示
double、float、int、complex
d
o
u
b
l
e
、
f
l
o
a
t
、
i
n
t
、
c
o
m
p
l
e
x
,另外
X
X
表示行或者列数未知的矩阵。
typedef Matrix<std::complex<double>, 2, 2> Eigen::Matrix2cd; // 2x2 的 cd 类型的矩阵
typedef Matrix<double, 2, 2> Eigen::Matrix2d; // 2x2 的 d 类型的矩阵
typedef Matrix<std::complex<double>, 2, Dynamic> Eigen::Matrix2Xcd; // 2x? 的 cd 类型的矩阵
typedef Matrix<std::complex<float>, Dynamic, 2> Eigen::MatrixX2cf; // ?x2 的 cf 类型的矩阵
typedef Matrix<std::complex<double>, Dynamic, Dynamic> Eigen::MatrixXcd;// ?x? 的 cd 类型的矩阵
typedef Matrix<int, Dynamic, Dynamic> Eigen::MatrixXi; // ?x? 的 i 类型的矩阵
存储
在
Eigen
E
i
g
e
n
中矩阵默认均是列主序(
Column Major
C
o
l
u
m
n
M
a
j
o
r
),如果想要改变
Eigen
E
i
g
e
n
中矩阵的主序,就需要动用上述六个模板参数中的第四个参数(默认是
ColMajor
C
o
l
M
a
j
o
r
)。
ex:
e
x
:
Matrix<int, 5, 6, RowMajor> matRow; // 行主序的 5x6 的 int 类型矩阵
默认列主序是因为对于 Eigen E i g e n 来说这样运算会更快一些,但是对我们使用中并不需要特别在意存储的方式。
Ps. C++ C + + 中的二维数组默认的则是行主序( Row Major R o w M a j o r )。
动态矩阵与静态矩阵
在 Eigen E i g e n 中可以用 Dynamic D y n a m i c 表示行或者列数未知,所以在定义一个矩阵时并不能确定矩阵的大小,只有在运行时才可以确定大小,然后进行动态分配,而静态矩阵则是在定义时便明确给定了行数以及列数,在编译时就可以分配好内存。
访问与赋值
与
C++
C
+
+
数组的操作不同的是,
Eigen::Matrix
E
i
g
e
n
::
M
a
t
r
i
x
是不能通过
[]
[
]
来访问赋值数据的,而是需要通过
()
(
)
。矩阵之间也可以通过
=
=
来进行赋值(拷贝)。
x = mat(a, b); // 获取到矩阵 mat 的 a 行 b 列的元素并赋值给 x
mat(b, a) = x; // 将 x 赋值给矩阵 mat 的 b 行 a 列
mat1 = mat2; // 将矩阵 mat2 赋值(拷贝)给矩阵 mat1
Ps. 通过 = = 进行矩阵之间的拷贝时,如果左右两侧矩阵尺寸不一样并且左侧矩阵为动态矩阵,那么会将左侧矩阵的尺寸修改为与右侧一致。
在 中还重载了
<<
<<
<script type="math/tex" id="MathJax-Element-42"><<</script> 可以用来赋值矩阵,也可以用来
cout
c
o
u
t
输出矩阵。
ex:
e
x
:
MatrixXf m(4, 4); // 定义一个 4x4 的 float 类型的动态矩阵
m << 1, 2, 3, 4,
5, 6, 7, 8,
9, 10, 11, 12,
13, 14, 15, 16;// 赋值
std::cout << m; // 输出 m
Eigen
E
i
g
e
n
矩阵还可以进行分块操作,通过成员函数
block()
b
l
o
c
k
(
)
获取某一部分矩阵。
ex:
e
x
:
mat = mat1.block(i, j, p, q); // 从矩阵 mat1 的 i 行 j 列开始获取一个 p 行 q 列的子矩阵
mat = mat1.block<p, q>(i, j); // 从矩阵 mat1 的 i 行 j 列开始获取一个 p 行 q 列的子矩阵(动态矩阵)
Eigen
E
i
g
e
n
矩阵可以使用成员函数
row()、col()
r
o
w
(
)
、
c
o
l
(
)
来获取某一行或者某一列。
ex:
e
x
:
mat = mat1.row(i); // 获取 mat1 的第 i 行
mat = mat1.col(j); // 获取 mat1 的第 j 列
Eigen
E
i
g
e
n
还提供了从边角开始提取子矩阵的方法。
ex:
e
x
:
描述 | 动态矩阵 | 静态矩阵 |
---|---|---|
左上角 pxq p x q | mat.topLeftCorner(p,q) m a t . t o p L e f t C o r n e r ( p , q ) | mat.topLeftCorner<p,q>() m a t . t o p L e f t C o r n e r < p , q > ( ) |
左下角 pxq p x q | mat.bottomLeftCorner(p,q) m a t . b o t t o m L e f t C o r n e r ( p , q ) | mat.bottomLeftCorner<p,q>() m a t . b o t t o m L e f t C o r n e r < p , q > ( ) |
右上角 pxq p x q | mat.topRightCorner(p,q) m a t . t o p R i g h t C o r n e r ( p , q ) | mat.topRightCorner<p,q>() m a t . t o p R i g h t C o r n e r < p , q > ( ) |
右下角 pxq p x q | mat.bottomRightCorner(p,q) m a t . b o t t o m R i g h t C o r n e r ( p , q ) | mat.bottomRightCorner<p,q>() m a t . b o t t o m R i g h t C o r n e r < p , q > ( ) |
前 p p 行 | mat.topRows<p>() m a t . t o p R o w s < p > ( ) | |
后 p p 行 | mat.bottomRows<p>() m a t . b o t t o m R o w s < p > ( ) | |
前 q q 列 | mat.leftCols<q>() m a t . l e f t C o l s < q > ( ) | |
后 q q 列 | mat.rightCols<q>() m a t . r i g h t C o l s < q > ( ) |
Eigen E i g e n 矩阵其他分块操作还有 middleCols()、middleRows() m i d d l e C o l s ( ) 、 m i d d l e R o w s ( ) 等可以了解一下。
Eigen
E
i
g
e
n
矩阵还可以使用成员函数
fill()
f
i
l
l
(
)
进行统一赋值。
ex:
e
x
:
mat.fill(n); // 将 mat 的所有元素均赋值为 n
运算
Eigen
E
i
g
e
n
重载了
+、−(减)、∗、/、−(负)、+=、−=、∗=、/=
+
、
−
(
减
)
、
∗
、
/
、
−
(
负
)
、
+
=
、
−
=
、
∗
=
、
/
=
。
ex:
e
x
:
mat = mat1 + mat2; // +
mat = mat1 - mat2; // -(减)
mat = mat1 * mat2; // *
mat = mat1 * n; // *
mat = mat1 / n; // /
mat = -mat1; // -(负)
mat += mat1; // +=
mat -= mat1; // -=
mat *= mat1; // *=
mat *= n; // *=
mat /= n; // /=
对于
Matrix
M
a
t
r
i
x
的转置矩阵、共轭矩阵、伴随矩阵、对角矩阵可以通过成员函数
transpose()、conjugate()、adjoint()、diagonal()
t
r
a
n
s
p
o
s
e
(
)
、
c
o
n
j
u
g
a
t
e
(
)
、
a
d
j
o
i
n
t
(
)
、
d
i
a
g
o
n
a
l
(
)
来获得,如果想要在原矩阵上进行转换,则需要通过成员函数
transposeInPlace()、conjugateInPlace()、adjointInPlace()
t
r
a
n
s
p
o
s
e
I
n
P
l
a
c
e
(
)
、
c
o
n
j
u
g
a
t
e
I
n
P
l
a
c
e
(
)
、
a
d
j
o
i
n
t
I
n
P
l
a
c
e
(
)
。
ex:
e
x
:
mat = mat1.transpose(); // 获取 mat1 的转置矩阵
mat = mat1.conjugate(); // 获取 mat1 的共轭矩阵
mat = mat1.adjoint(); // 获取 mat1 的伴随矩阵
mat = mat1.diagonal(); // 获取 mat1 的对角矩阵
mat1.transposeInPlace();// mat1 转换为对应的转置矩阵
mat1.conjugateInPlace();// mat1 转换为对应的共轭矩阵
mat1.adjointInPlace(); // mat1 转换为对应的伴随矩阵
mat1.diagonalInPlace(); // mat1 转换为对应的对角矩阵
mat1.transpose().colwise().reverse(); // mat1 Rot90
特殊矩阵
Eigen
E
i
g
e
n
提供了许多特殊矩阵的生成方法。
ex:
e
x
:
mat = MatrixXd::Identity(rows, cols); // 生成 rows x cols 的单位阵
mat.setIdentity(rows, cols); // 将 mat 设置为 rows x cols 的单位阵
mat = MatrixXd::Zero(rows, cols); // 生成 rows x cols 的零矩阵
mat.setZero(rows, cols); // 将 mat 设置为 rows x cols 的零矩阵
mat = MatrixXd::Ones(rows, cols); // 生成 rows x cols 的壹矩阵
mat.setOnes(rows, cols); // 将 mat 设置为 rows x cols 的壹矩阵
mat = MatrixXd::Random(rows, cols); // 生成 rows x cols 的随机矩阵
mat.setRandom(rows, cols); // 将 mat 设置为 rows x cols 的随机矩阵
其他
当前矩阵的行数、列数、大小可以通过成员函数
rows()、cols()、size()
r
o
w
s
(
)
、
c
o
l
s
(
)
、
s
i
z
e
(
)
来获取。
ex:
e
x
:
rows = mat.rows(); // 获取行数
cols = mat.cols(); // 获取列数
size = mat.size(); // 获取大小
动态矩阵可以通过成员函数
resize()
r
e
s
i
z
e
(
)
来进行修改大小,静态矩阵是不可以
resize()
r
e
s
i
z
e
(
)
的,并且动态矩阵
resize()
r
e
s
i
z
e
(
)
后元素不能保证不变。
ex:
e
x
:
mat.resize(rows, cols); // 将动态矩阵 mat 大小尺寸修改为 rows x cols
向量( Vector V e c t o r )
向量( Vector V e c t o r )本身就是一种特殊的矩阵,如果学会了 Matrix M a t r i x ,那么 Vector V e c t o r 的使用将会变得十分简单。
类型与存储
类似于矩阵的类型,不过前缀从
Matrix
M
a
t
r
i
x
改成
Vector
V
e
c
t
o
r
。
ex:
e
x
:
typedef Matrix<std::complex<float>, 2, 1> Eigen::Vector2cf; // cf 类型的 2 向量
typedef Matrix<int, 2, 1> Eigen::Vector2i; // i 类型的 2 向量
typedef Matrix<double, 4, 1> Eigen::Vector4d; // d 类型的 4 向量
typedef Matrix<float, Dynamic, 1> Eigen::VectorXf; // f 类型的 ? 向量
上述的
Vector
V
e
c
t
o
r
默认的都是列向量,如果是行向量,在命名上则需要加上
Row
R
o
w
前缀。
ex:
e
x
:
typedef Matrix<float, 1, 2> Eigen::RowVector2f; // f 类型的 2 向量(行向量)
typedef Matrix<std::complex<double>, 1, 4> Eigen::RowVector4cd; // cd 类型的 4 向量(行向量)
动态向量与静态向量
这里类似于矩阵,动态的没有指定向量的尺寸,只有在运行时才会分配对应的内存,而静态的则一开始便定义好了大小,在编译时分配好内存。
访问与赋值
类似于
Matrix
M
a
t
r
i
x
的操作,不过向量也可以使用
[]
[
]
,另外向量对前四个元素的访问与赋值还可以通过成员函数
x()、y()、z()、w()
x
(
)
、
y
(
)
、
z
(
)
、
w
(
)
来操作。
ex:
e
x
:
x = vec(n); // 获取向量 vec 的第 n 个元素并赋值给 x
x = vec[n];
x = vec.x(); // 获取向量 vec 的第一个元素并赋值给 x
y = vec.y(); // 获取向量 vec 的第二个元素并赋值给 y
z = vec.z(); // 获取向量 vec 的第三个元素并赋值给 z
w = vec.w(); // 获取向量 vec 的第四个元素并赋值给 w
vec(n) = x; // 将 x 赋值给 vec 的第 n 个元素
Eigen
E
i
g
e
n
向量也提供了一些分块操作来获取子向量。
ex:
e
x
:
描述 | 静态向量 | 动态向量 |
---|---|---|
前 n n 个元素 | vec.head<n>() v e c . h e a d < n > ( ) | |
后 n n 个元素 | vec.tail<n>() v e c . t a i l < n > ( ) | |
从 i i 开始取 个元素 | vec.segment(i,n) v e c . s e g m e n t ( i , n ) | vec.segment<n>(i) v e c . s e g m e n t < n > ( i ) |
运算
Eigen
E
i
g
e
n
向量提供了
norm()、squareNorm()、dot()、cross()
n
o
r
m
(
)
、
s
q
u
a
r
e
N
o
r
m
(
)
、
d
o
t
(
)
、
c
r
o
s
s
(
)
等成员函数。
ex:
e
x
:
x.norm() // norm(x) Note that norm(R) doesn't work in Eigen.
x.squaredNorm()
x.dot(y) // dot(x, y)
x.cross(y) // cross(x, y) Requires #include <Eigen/Geometry>
其他
类似于
Matrix
M
a
t
r
i
x
的操作。
ex:
e
x
:
size = vec.size(); // 获取 vec 的尺寸