Eigen学习笔记(2)-Matrix类

原文:Eigen官网-The Matrix class

在Eigen中,所有的矩阵Matrix和向量Vector都是由Matrix类构造的。向量只不过是矩阵的特殊形式,只有一列(列向量)或者一行(行向量)。

Matrix类的参数

Matrix有6个模板参数,主要使用前三个参数,剩下的三个参数有默认值。

Matrix<typename Scalar, int RowsAtCompileTime, int ColsAtCompileTime>
  • Scalar是表示元素的类型,取值可以是 float ,int, double 等;
  • RowsAtCompileTime为矩阵的行,在程序编译的时候就已经知道的;
  • ColsAtCompileTime为矩阵的列,在程序编译的时候就已经知道的。

Eigen 提供了一些常用的 定义好的类型。比如,Matrix4f表示一个类型为float的4*4矩阵,在Eigen中定义如下:

typedef Matrix<float, 4, 4> Matrix4f;

Vectors向量

列向量是默认向量。
Eigen中定义的包含3个float元素的列向量如下:

typedef Matrix<float, 3, 1> Vector3f;

行向量定义如下:

typedef Matrix<int, 1, 2> RowVector2i;

Dynamic

Eigen并没有限制矩阵的尺寸必须在编译的时候就要确定下来。如果矩阵的尺寸在编译的时候是不确定的,而在运行的时候才能确定,Eigen提供了定义动态大小的方法,称为dynamic size ;将在编译时候就能确定的尺寸称为fixed size.
MatrixXd表示一个具有动态大小的矩阵,定义如下:

typedef Matrix<double, Dynamic, Dynamic> MatrixXd;

VectorXi表示一个具有动态大小的向量,定义如下:

typedef Matrix<int, Dynamic, 1> VectorXi;

还可以定义行数固定而列数是动态大小的矩阵:

Matrix<float, 3, Dynamic>

构造函数

(1)默认的构造函数不执行任何空间分配,也不初始化矩阵的元素。

Matrix3f a;
MatrixXf b;
  • a是一个3*3的矩阵,分配了float[9]的空间,但未初始化内部元素;
  • b是一个动态大小的矩阵,现在它的尺寸是0*0,还未分配空间。

(2)带参数的构造函数。
对于矩阵,行数在列数前面,对于向量,只有向量的大小。当对矩阵或向量指定大小时,只是分配相应大小的空间,未初始化元素。

MatrixXf a(10,15);
VectorXf b(30);
  • a是一个10*15的动态大小的矩阵,分配了空间但未初始化元素;
  • b是一个30大小的向量,同样分配空间未初始化元素。

(3)为了对固定大小和动态大小的矩阵提供统一的API,对指定大小的Matrix传递sizes也是合法的(传递也被忽略)。

Matrix3f a(3,3);

(4)可以用构造函数提供4以内尺寸的vector的初始化。

Vector2d a(5.0, 6.0);
Vector3d b(5.0, 6.0, 7.0);
Vector4d c(5.0, 6.0, 7.0, 8.0);

元素获取器

Eigen中通过对括号进行重载实现元素的获取。对于矩阵是:(行,列);对于向量,只是传递它的索引。索引都是以0为起始的。

m(index)也可以用于获取矩阵元素,但取决于matrix的存储顺序,默认是按列存储的(即一列一列的进行存储),当然也可以改为按行。

[]操作符可以用于向量元素的获取,但是不能用于matrix,因为C++中[]不能传递超过一个参数。

#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;
  std::cout << "m(2):\\n" << m(2) << std::endl;
}

结果:

Here is the matrix m:
  3  -1
2.5 1.5
m(2):
-1

逗号初始化

可以使用逗号初始化方式(comma-initializer)给矩阵和向量赋值。例如:

Matrix3f m;
m << 1, 2, 3,
     4, 5, 6,
     7, 8, 9;
std::cout << m;

结果如下:

1 2 3 
4 5 6 
7 8 9

这样就将上述值赋给了矩阵,在Eigen中矩阵默认的存储方式是行优先,就是先存储行。

Resizing

rows() , cols() , size() 方法分别返回行数,列数和 元素的个数。

Eigen支持对动态大小的矩阵和向量重新指定大小,通过resize() 实现。

#include <iostream>
#include <Eigen/Dense>
using namespace Eigen;
int main()
{
  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;
  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

如果matrix的实际大小不改变,resize函数不做任何操作;否则resize操作是具有破坏性的,矩阵中元素的值会被改变,如果不想改变元素的值可以执行 conservativeResize()。

为了统一API,所有的操作可用于固定大小的matrix,当然,实际中它不会改变大小。尝试去改变一个固定大小的matrix到一个不同的值,会出发警告失败。只有如下是合法的。

#include <iostream>
#include <Eigen/Dense>
using namespace Eigen;
int main()
{
  Matrix4d m;
  m.resize(4,4); // no operation
  std::cout << "The matrix m is of size "
            << m.rows() << "x" << m.cols() << std::endl;
}

Assignment and resizing

assignment(分配)是复制一个矩阵到另外一个,通过操作符“=”实现。Eigen会自动resize左变量的大小以等于右侧变量的大小。
当然,如果左边变量是固定大小的,resizing是不允许的。

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

固定尺寸VS动态尺寸

实际中,应该使用固定尺寸还是动态尺寸,简单的答案是:对于小尺寸的矩阵,使用固定大小的方式,对于大尺寸的矩阵,使用动态大小的方式。

Matrix4f mymatrix; 等价于 float mymatrix[16];
MatrixXf mymatrix(rows,columns);等价于float *mymatrix = new float[rows*columns];

使用固定尺寸可以避免动态内存的开辟,固定尺寸只是一个普通数组。

使用固定尺寸(<=4*4)需要编译前知道矩阵大小,而且对于足够大的尺寸,如大于32,固定尺寸的收益可以忽略不计,相反,很可能会导致栈崩溃,因为Eigen尝试将数组自动分配为局部变量,这通常在堆栈上完成。而且基于环境,Eigen会对动态尺寸做优化(类似于std::vector)。

Matrix类的其他模板参数

如下石Matrix类的完整参数列表:

Matrix<typename Scalar,
       int RowsAtCompileTime,
       int ColsAtCompileTime,
       int Options = 0,
       int MaxRowsAtCompileTime = RowsAtCompileTime,
       int MaxColsAtCompileTime = ColsAtCompileTime>
  • Options是一个比特标志位,这里,我们只介绍一种标志位:RowMajor,它表明matrix使用按行存储(row-major),默认情况下是按列存储(column-major)。Matrix<float, 3, 3, RowMajor>表示一个按行存储的3*3矩阵。
  • MaxRowsAtCompileTime和MaxColsAtCompileTime表示在编译阶段矩阵的上限。主要是避免动态内存分配,使用数组。

一些方便的类型定义

Eigen定义了一些Matrix的类型:

  • MatrixNt for Matrix<type, N, N>.
  • VectorNt for Matrix<type, N, 1>.
  • RowVectorNt for Matrix<type, 1, N>.

其中,N可以是2,3,4或X(Dynamic);
t可以是i(int)、f(float)、d(double)、cf(complex)、cd(complex)等。

参考:

“Eigen教程(2)”
“Eigen学习笔记2-Matrix类”

© 版权声明
THE END
喜欢就支持一下吧
点赞152 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容