C++是我这个行业的主要语言,所以还是需要认真的学习一下,Eigen3是C++生态中非常重要的第三方库,主要完成矩阵的计算,我找了一下没找到成熟的学习教程,和后面发现官网上有纯英文教程。所以现在决定跟着网上官方教程走一遍,即学习了c++还顺带学习了英语,岂不是double win?
所以本系列算是Eigen3教程也算是网页汉化。大部分为网页翻译,也会有部分个人批注。
本期:
第一章 稠密矩阵及数组操作
第一节 矩阵类
首先我们需要知道什么是稠密矩阵(Dense matrix)和稀疏矩阵
稠密矩阵:非0元素占比比较大的矩阵
稀疏矩阵:0元素占比比较大的矩阵
在Eigen中,所有的矩阵和向量都属矩阵类的对象,向量仅仅只是特殊情况下的矩阵,只有一行或是只有一列
矩阵类的前三个形参
矩阵类有6个形参,但学习前三个形参对现在来说已经足够,剩下的参数有默认值,现在我们不去改变他们,我们会在后面对其进行讨论。
前三个矩阵类强制的形参是:
Matrix<typename Scalar,int RowsAtCompileTime,int ColsAtCompileTime>
其中:
Scalar是精度类型,即数的类型,比如,如果你想创建一个浮点数矩阵,那么这里应该填float。
后面两个数是指在定义时已经知道的矩阵的行数和列数(如果定义时不知道矩阵的行数和列数见后文)。
我们提供很多便捷的类名来代替常用的矩阵,比如,Matrix4f,它代表4乘4的浮点型矩阵,它在Eigen中的定义如下:
typedef Matrix<float,4,4> Matrix4f
我们会在下文介绍这中快捷方法。
向量
如上所述,在Eigen中,向量只是一种特殊的情况下的矩阵(1行或1列),其中一列的情况最为普遍,这种向量我们称为列向量。其他情况,只有一行的向量我们成为行向量。
比如,3维浮点列向量的快捷类名是Vector3f,2维整型行向量的快捷类名是RowVector2i,其在Eigen种的定义如下:
typename Matrix<float,3,1> Vector3f
typename Martix<int,1,2> RowVector2i
特殊的动态值
当然,Eigen并不会限制定义矩阵时必须知道确切的维度。矩阵的行和列所对应的形参可以采用动态值,该值在定义的时候大小未知,因此必须当作变量来处理。在Eigen的术语中,这种维度被称为动态维度;而在定义时已知的维度被称为固定维度。例如:MatrixXd,意思是动态维度的矩阵。其定义为:
typename Matrix<double,Dynamic,Dynamic> MatrixXd;
类似的还有动态维度的向量定义方法:
typename Matrix<double,Dynamic,1> VectorXi
(注意:不能使用变量来对矩阵进行定义,有值的变量也不行,有值初始化的const int可以)
//不允许的错误初始化
int a;
Eigen::Matrix<float,a,a> Mat_a;
//不允许的错误初始化
int c,b;
const int a = b + c;
Eigen::Matrix<float,a,a> Mat_a;
//允许的正确初始化
const int a = 5;
Eigen::Matrix<float,a,a> Mat_a;
构造函数
默认构造函数总是可用的,不会执行任何的动态内存分配,并且从不初始化矩阵中的元素。你可以如下使用默认构造函数:
Matrix3f a;
MatrixXf b;
上述,a是一个未初始化的3乘3的浮点数矩阵。b是一个动态维度未初始化的矩阵(当前维度维0维)。
也可使用设置维度的构造函数。对于矩阵,总是先传递行数。对于向量,只需传递向量的大小。它们以给定的大小分配系数数组,但不初始化系数本身
MatrixXf a(10,15); //10行15列的float矩阵
VectorXf b(30); //长度为30的float的列向量
为了提供一致的API,对固定矩阵进行内存分配是合法的,如下语句是合法的
Matrix3f a(3,3)
矩阵和向量还可以使用列表进行初始化,在c++11以前,使用列表进行初始化有所限制,在c++11之后,可以使用列表初始化任意维度的矩阵和向量。如下:
Vector2i a(1, 2); // 元素为{1, 2}的列向量
Matrix<int, 5, 1> b {1, 2, 3, 4, 5}; // 包含元素{1, 2, 3, 4, 5}的列向量
Matrix<int, 1, 5> c = {1, 2, 3, 4, 5}; // 包含元素{1, 2, 3, 4, 5}的行向量
对于固定维度大小的矩阵,使用列表进行初始化必须按行进行分组。如下:
MatrixXi a { // 构造2x2矩阵
{1, 2}, // 第一行
{3, 4} // 第二行
Matrix<double, 2, 3> b {
{2, 3, 4},
{5, 6, 7},
};
矩阵元素访问
对于矩阵及向量元素的访问见下例:
#include <iostream>
#include <Eigen/Dense>
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;
}
// 输出
Here is the matrix m:
3 -1
2.5 1.5
Here is the vector v:
4
3
应注意,最好不要使用 [] 操作进行索引
逗号初始器
可以使用逗号来对矩阵数值进行初始化。如下例:
Matrix3f m;
m << 1, 2, 3,
4, 5, 6,
7, 8, 9;
std::cout << m;
// 输出
1 2 3
4 5 6
7 8 9
维度变化
矩阵可以通过 .rows() .cols() 来获取矩阵行和列,用 .resize() 来对动态维度进行改变,但是如果矩阵有确切的数值,可能会导致矩阵元素会进行破坏,如果想要使用稳妥一点的变换可以使用conservativeResize(),如下示例代码:
#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;
}
//输出
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
// ------------------------------ //
#include <iostream>
#include <Eigen/Dense>
int main()
{
Eigen::Matrix4d m;
m.resize(4,4); // no operation
std::cout << "The matrix m is of size "
<< m.rows() << "x" << m.cols() << std::endl;
}
// 输出
The matrix m is of size 4x4
赋值和调整维度
赋值是将一个矩阵复制到另一个矩阵的操作,使用运算符 = ,Eigen会自动调整左侧矩阵的大小使其与右边大小相匹配,如下,当然,若左边是一个固定维度的矩阵,那么改变维度则是不被允许的。
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
固定维度 / 动态维度
固定维度矩阵是一个普通数组,而动态维度矩阵是一个动态数组,所以理论上固定维度数组更快。
可选形参
全部参数表如下:
Matrix<typename Scalar,
int RowsAtCompileTime,
int ColsAtCompileTime,
int Options = 0,
int MaxRowsAtCompileTime = RowsAtCompileTime,
int MaxColsAtCompileTime = ColsAtCompileTime>
剩下三个介绍略。
方便的快捷类型
MatrixNt 表示 Matrix<type, N, N>.
例:MatrixXi 表示 Matrix<int, Dynamic, Dynamic>.
MatrixXNt 表示 Matrix<type, Dynamic, N>.
例:MatrixX3i 表示 Matrix<int, Dynamic, 3>.
MatrixNXt 表示 Matrix<type, N, Dynamic>.
例:Matrix4Xd 表示 Matrix<double, 4, Dynamic>.
VectorNt 表示 Matrix<type, N, 1>.
例:Vector2f 表示 Matrix<float, 2, 1>.
RowVectorNt 表示 Matrix<type, 1, N>.
例:RowVector3d 表示 Matrix<double, 1, 3>.