整理下Eigen庫的教程,參考:http://eigen.tuxfamily.org/dox/index.html
Matrix類
在Eigen,所有的矩陣和向量都是Matrix模板類的對象,Vector只是一種特殊的矩陣(一行或者一列)。
Matrix有6個模板參數,主要使用前三個參數,剩下的有默認值。
Matrix<typename Scalar, int RowsAtCompileTime, int ColsAtCompileTime>
Scalar是表示元素的類型,RowsAtCompileTime為矩陣的行,ColsAtCompileTime為矩陣的列。
庫中提供了一些類型便於使用,比如:
typedef Matrix<float, 4, 4> Matrix4f;
Vectors向量
列向量
typedef Matrix<float, 3, 1> Vector3f;
行向量
typedef Matrix<int, 1, 2> RowVector2i;
Dynamic
Eigen不只限於已知大小(編譯階段)的矩陣,有些矩陣的尺寸是運行時確定的,於是引入了一個特殊的標識符:Dynamic
typedef Matrix<double, Dynamic, Dynamic> MatrixXd;
typedef Matrix<int, Dynamic, 1> VectorXi;
Matrix<float, 3, Dynamic>
構造函數
默認的構造函數不執行任何空間分配,也不初始化矩陣的元素。
Matrix3f a;
MatrixXf b;
這里,a是一個3*3的矩陣,分配了float[9]的空間,但未初始化內部元素;b是一個動態大小的矩陣,定義是未分配空間(0*0)。
指定大小的矩陣,只是分配相應大小的空間,未初始化元素。
MatrixXf a(10,15);
VectorXf b(30);
這里,a是一個10*15的動態大小的矩陣,分配了空間但未初始化元素;b是一個30大小的向量,同樣分配空間未初始化元素。
為了對固定大小和動態大小的矩陣提供統一的API,對指定大小的Matrix傳遞sizes也是合法的(傳遞也被忽略)。
Matrix3f a(3,3);
可以用構造函數提供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);
獲取元素
通過中括號獲取元素,對於矩陣是:(行,列);對於向量,只是傳遞它的索引,以0為起始。
#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;
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
m(index)也可以用於獲取矩陣元素,但取決於matrix的存儲順序,默認是按列存儲的,當然也可以改為按行。
[]操作符可以用於向量元素的獲取,但是不能用於matrix,因為C++中[]不能傳遞超過一個參數。
逗號初始化
Matrix3f m;
m << 1, 2, 3,
4, 5, 6,
7, 8, 9;
std::cout << m;
resizing
matrix的大小可以通過rows()、cols()、size()獲取,resize()可以重新調整動態matrix的大小。
#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 和 resizing
assignment(分配)是復制一個矩陣到另外一個,操作符=。Eigen會自動resize左變量大小等於右變量大小,比如:
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
當然,如果左邊量是固定大小的,上面的resizing是不允許的。
固定尺寸 vs 動態尺寸
實際中,應該使用固定尺寸還是動態尺寸,簡單的答案是:小的尺寸用固定的,大的尺寸用動態的。使用固定尺寸可以避免動態內存的開辟,固定尺寸只是一個普通數組。
Matrix4f mymatrix;
等價於 float mymatrix[16];
MatrixXf mymatrix(rows,columns);
等價於 float *mymatrix = new float[rows*columns];
使用固定尺寸(<=4*4)需要編譯前知道矩陣大小,而且對於足夠大的尺寸,如大於32,固定尺寸的收益可以忽略不計,而且可能導致棧崩潰。而且基於環境,Eigen會對動態尺寸做優化(類似於std::vector)
其他模板參數
上面只討論了前三個參數,完整的模板參數如下:
Matrix<typename Scalar,
int RowsAtCompileTime,
int ColsAtCompileTime,
int Options = 0,
int MaxRowsAtCompileTime = RowsAtCompileTime,
int MaxColsAtCompileTime = ColsAtCompileTime>
Options是一個比特標志位,這里,我們只介紹一種RowMajor,它表明matrix使用按行存儲,默認是按列存儲。Matrix<float, 3, 3, RowMajor>
MaxRowsAtCompileTime和MaxColsAtCompileTime表示在編譯階段矩陣的上限。主要是避免動態內存分配,使用數組。
Matrix<float, Dynamic, Dynamic, 0, 3, 4>
等價於 float [12]
一些方便的定義
Eigen定義了一些類型
- MatrixNt = Matrix<type, N, N> 特殊地有 MatrxXi = Matrix<int, Dynamic, Dynamic>
- VectorNt = Matrix<type, N, 1> 比如 Vector2f = Matrix<float, 2, 1>
- RowVectorNt = Matrix<type, 1, N> 比如 RowVector3d = Matrix<double, 1, 3>
N可以是2,3,4或X(Dynamic)
t可以是i(int)、f(float)、d(double)、cf(complex)、cd(complex)等。