矩阵类(The Matrix class)
在Eigen 中,所有矩阵和向量都是Matrix模板类的对象。向量只是矩阵的一种特殊情况,具有 1 行或 1 列。
Matrix的前三个模板参数
该矩阵类需要六个模板参数,但是现在了解前三个参数已经足够了。
剩下的三个参数有默认值,现在我们将保持不变,我们将在下面讨论。
Matrix的三个强制性模板参数是:
Matrix<typename Scalar, int RowsAtCompileTime, int ColsAtCompileTime>
Scalar
是标量类型,即系数的类型。也就是说,如果您想要一个浮点矩阵,请在此处选择float
。有关所有支持的标量类型的列表以及如何扩展对新类型的支持,请参阅标量类型。RowsAtCompileTime
和ColsAtCompileTime
是编译时已知的矩阵的行数和列数(如果在编译时不知道该数字,请参见下文了解该怎么做)。
我们提供了很多方便的 typedef 来涵盖通常的情况。例如,Matrix4f
是一个 4x4 的浮点矩阵。这是Eigen定义的方式:
typedef Matrix<float, 4, 4> Matrix4f;
Eigen里面用到了很多的typedef简化名称长度,例如:
typedef Matrix<float, 3, 1> Vector3f;
typedef Matrix<int, 1, 2> RowVector2i;
typedef Matrix<double, Dynamic, Dynamic> MatrixXd;
typedef Matrix<int, Dynamic, 1> VectorXi;
typedef Array<float,Dynamic,Dynamic> ArrayXXf
typedef Array<double,Dynamic,1> ArrayXd
typedef Array<int,1,Dynamic> RowArrayXi
typedef Array<float,3,3> Array33f
typedef Array<float,4,1> Array4f
······
Tips: 虽然Eigen官方已经提供了许多命名模板,但是这是对于X <= 4
的情况比较试用,一般处理大数据时,为了尽可能的多实用固定矩阵,应该熟练掌握利用原始模板创建对象
Vector
如上所述,在Eigen 中,向量只是矩阵的一种特殊情况,具有 1 行或 1 列。他们有 1 列的情况是最常见的;这样的向量称为列向量,通常简称为向量。在它们有 1 行的另一种情况下,它们被称为行向量。
例如,方便的 typedef Vector3f
是 3 个浮点数的(列)向量。它由Eigen定义如下:
typedef Matrix<float, 3, 1> Vector3f;
我们还为行向量提供方便的 typedef,例如:
typedef Matrix<int, 1, 2> RowVector2i;
The special value Dynamic
当然,Eigen不限于其维度在编译时已知的矩阵。在RowsAtCompileTime和ColsAtCompileTime模板参数可以采取特殊值Dynamic这表明大小在编译时是未知的,所以必须作为运行时变量来处理。在Eigen术语中,这样的大小被称为动态 大小;而在编译时已知的大小称为固定 大小。
例如,方便的 typedef MatrixXd
表示具有动态大小的双精度矩阵,定义如下:
typedef Matrix<double, Dynamic, Dynamic> MatrixXd;
同样,我们定义了一个动态大小的 typedef VectorXi
如下:
typedef Matrix<int, Dynamic, 1> VectorXi;
还可以固定某行或某列的大小:
Matrix<float, 3, Dynamic>;
构造函数
- 默认构造函数始终可用,从不执行任何动态内存分配,也从不初始化矩阵系数。你可以做:
Matrix3f a; //a 是一个 3×3 矩阵,带有未初始化系数的普通 float[9] 数组,
MatrixXf b; //b 是一个动态大小的矩阵,其大小当前为 0×0,并且其系数数组尚未分配。
-
也可以使用获取尺寸的构造函数。
对于矩阵,总是首先传递行数。对于向量,只需传递向量大小。他们分配给定大小的系数数组,但不初始化系数本身:
MatrixXf a(10,15); //a 是一个 10x15 动态大小的矩阵,具有已分配但当前未初始化的系数。
VectorXf b(30); //b 是大小为 30 的动态大小向量,具有已分配但当前未初始化的系数。
- 为了提供跨固定大小和动态大小矩阵的统一 API,在固定大小矩阵上使用这些构造函数是合法的,即使在这种情况下传递大小是无用的。所以这是合法的:
Matrix3f a(3,3); //虽然没有意义,但是是合法的
- 矩阵和向量也可以从系数列表中初始化。在 C++11 之前,此功能仅限于固定大小的小列或最大大小为 4 的向量:
Vector4d c(5.0, 6.0, 7.0, 8.0); //C++11之前只能用于固定尺寸的矩阵和向量,且尺寸不大于4
- 如果启用 C++11,则可以通过传递任意数量的系数来初始化任意大小的固定大小的列或行向量:
Vector2i a(1, 2); // A column vector containing the elements {1, 2}
Matrix<int, 5, 1> b {
1, 2, 3, 4, 5}; // A row-vector containing the elements {1, 2, 3, 4, 5}
Matrix<int, 1, 5> c = {
1, 2, 3, 4, 5}; // A column vector containing the elements {1, 2, 3, 4, 5}
- 无论是固定还是动态矩阵,系数必须按行分组:
MatrixXi a {
// construct a 2x2 matrix
{
1, 2}, // first row
{
3, 4} // second row
};
Matrix<double, 2, 3> b {
{
2, 3, 4},
{
5, 6, 7},
};
-
但是对于列或行向量,允许隐式转置。这意味着可以用行向量初始化列向量:
切记,只有向量才可以这样
VectorXd a {
{
1.5, 2.5, 3.5}}; // A column-vector with 3 coefficients
RowVectorXd b {
{
1.0, 2.0, 3.0, 4.0}}; // A row-vector with 4 coefficients
系数存取器
Eigen重载了圆括号()
操作符,因此采用 (i,j)
取索引访问系数,对于向量只需要传递一个索引(i)
即可,需要注意的是下标索引均是先行后列。
#include <iostream>
#include <Eigen/Dense>
using namespace Eigen;
int main()
{
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;
VectorXd v(2);
v(0) = 4;
v(1) = v(0) - 1