最近学习C++对矩阵进行操作,需要调用Eigen库,做个学习笔记。
1 介绍:
Eigen是可以用来进行线性代数、矩阵、向量操作等运算的C++库,它里面包含了很多算法。它的License是MPL2。它支持多平台。
Eigen采用源码的方式提供给用户使用,在使用时只需要包含Eigen的头文件即可进行使用。之所以采用这种方式,是因为Eigen采用模板方式实现,由于模板函数不支持分离编译,所以只能提供源码而不是动态库的方式供用户使用。
1.1 矩阵定义
Eigen中关于矩阵类的模板函数中,共有六个模板参数,常用的只有前三个。其前三个参数分别表示矩阵元素的类型、行数和列数。矩阵定义时可以使用Dynamic来表示矩阵的行列数为未知。
Eigen中无论是矩阵还是数组、向量,无论是静态矩阵还是动态矩阵都提供默认构造函数,也就是定义这些数据结构时都可以不用提供任何参数,其大小均由运行时来确定。矩阵的构造函数中只提供行列数、元素类型的构造参数,而不提供元素值的构造,对于比较小的、固定长度的向量提供初始化元素的定义。
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
1.2 类型
在 EigenEigen 中 typedef了很多矩阵的类型,通常命名为Matrix 后缀加一个长度为 1∼4 的字符串 S即:MatrixS。其中 S 可以用来判断该矩阵类型,比如”d”表示double类型,”f”表示float类型,”i”表示整数,”c”表示复数;Matrix2f,表示的是一个2*2维的,其每个元素都是float类。
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 类型的矩阵
1.3 数据存储
Matrix创建的矩阵默认是按列存储(ColMajor),Eigen在处理按列存储的矩阵时会更加高效。如果想修改可以在创建矩阵的时候加入参数,如:
Matrix<int,3, 4, ColMajor> Acolmajor;//列主序
Matrix<int,3, 4, RowMajor> Arowmajor;//行主序
Ps. C++中的二维数组默认的则是行主序(Row Major)。Matlab中的二维矩阵默认则是列主序(ColMajor)。
其中:动态矩阵和静态矩阵
动态矩阵在定义一个矩阵时并不能确定矩阵的大小,只有在运行时才可以确定大小,然后进行动态分配其大小;
静态矩阵是在定义时便明确给定了行数以及列数,在编译时确定。
MatrixXd:表示任意大小的元素类型为double的矩阵变量,其大小只有在运行时被赋值之后才能知道。
Matrix3d:表示元素类型为double大小为3*3的矩阵变量,其大小在编译时就知道。
在Eigen中优先的矩阵会在其名字中包含有row,否则就是列优先。
Eigen中的向量只是一个特殊的矩阵,其维度为1而已。
1.4矩阵元素的赋值与访问
在 Eigen 中还重载了 <<可以用来赋值矩阵,通过该操作符即可以一个一个元素的进行赋值,也可以一块一块的赋值。另外也可以使用下标进行赋值。
也可以用来 cout输出矩阵。
Matrix3d m(3,3); // 定义一个 3x3的 double类型的矩阵
m << 1, 2, 3,
5, 6, 7,
9, 10, 11,;// 赋值
cout << m; // 输出 m
在矩阵的访问中,行索引总是作为第一个参数,Eigen中矩阵、数组、向量的下标都是从0开始。矩阵元素的访问可以通过”()”操作符完成。矩阵之间也可以通过 = 来进行赋值(拷贝)。例如m(2, 3)既是获取矩阵m的第2行第3列元素。
注意:针对向量还提供”[]”操作符,注意矩阵则不可如此使用。
x = mat(a, b); // 获取到矩阵 mat 的 a 行 b 列的元素并赋值给 x
mat(b, a) = x; // 将 x 赋值给矩阵 mat 的 b 行 a 列
mat1 = mat2; // 将矩阵 mat2 赋值(拷贝)给矩阵 mat1
Ps. 通过 =进行矩阵之间的拷贝时,如果左右两侧矩阵尺寸不一样并且左侧矩阵为动态矩阵,那么会将左侧矩阵的尺寸修改为与右侧一致。
当前矩阵的行数、列数、大小可以通过成员函数 rows()、cols()、size()来获取。
mat = mat1.row(i); // 获取 mat1 的第 i 行
mat = mat1.col(j); // 获取 mat1 的第 j 列
size = mat1.size(); // 获取大小
1.5 重置矩阵的大小
当前矩阵的行数、列数、大小可以通过rows()、cols()和size()来获取,对于动态矩阵可以通过resize()函数来动态修改矩阵的大小。
注意:
(1)、固定大小的矩阵是不能使用resize()来修改矩阵的大小;
(2)、resize()函数会析构掉原来的数据,因此调用resize()函数之后将不能保证元素的值不改变;
(3)、使用”=”操作符操作动态矩阵时,如果左右两边的矩阵大小不等,则左边的动态矩阵的大小会被修改为右边的大小。
1.6 动态矩阵和静态矩阵的选择
对于小矩阵(一般大小小于16)使用固定大小的静态矩阵,它可以带来比较高的效率;对于大矩阵(一般大小大于32)建议使用动态矩阵。注意:如果特别大的矩阵使用了固定大小的静态矩阵则可能会造成栈溢出的问题。
1.7 矩阵、向量的运算
在Eigen中算术运算重载了 +、−(减)、∗、/、−(负)、+=、−=、∗=、/=+、−(减)、∗、/、−(负)、+=、−=、∗=、/=。
二元操作符+/-,表示两矩阵相加(矩阵中对应元素相加/减,返回一个临时矩阵);
一元操作符-表示对矩阵取负(矩阵中对应元素取负,返回一个临时矩阵);
组合操作法+=或者-=表示(对应每个元素都做相应操作);
矩阵还提供与标量(单一数字)的乘除操作,表示每个元素都与该标量进行乘除操作;
mat = mat1 + mat2; // +
mat = mat1 - mat2; // -&#x