Eigen学习笔记2:C++矩阵运算库Eigen介绍
Eigen常规矩阵定义
1.使⽤
Eigen的使⽤在官⽹上有详细的介绍,这⾥对我学习过程中⽤到的基本操作进⾏介绍。⾸先是矩阵的定义。
在矩阵类的模板参数共有6个。⼀般情况下我们只需要关注前三个参数即可。前三个模板参数如下所⽰:
Matrix<typename Scalar,int RowsAtCompileTime,int ColsAtCompileTime>
1. Scalar参数为矩阵元素的类型,该参数可以是int,float,double等。
2. RowsAtCompileTime和ColsAtCompileTime是矩阵的⾏数和列数。
如Matrix<float,4,4> M44是定义⼀个4×4的矩阵,矩阵元素以float类型存储。直接使⽤矩阵模板定义⼀个矩阵往往会觉得⿇烦,Eigen提供了⼀些基本矩阵的别名定义,如typedef Matrix<float,4,4> Matrix4f.下⾯是⼀些内置的别名定义.来源于:
typedef Matrix< std::complex<double> , 2 , 2 > Matrix2cd
typedef Matrix< std::complex<float> , 2 , 2 > Matrix2cf
typedef Matrix< double , 2 , 2 > Matrix2d
typedef Matrix< float , 2 , 2 > Matrix2f
typedef Matrix< int , 2 , 2 > Matrix2i
typedef Matrix< std::complex<double> , 3 , 3 > Matrix3cd
typedef Matrix< std::complex<float> , 3 , 3 > Matrix3cf
typedef Matrix< double , 3 , 3 > Matrix3d
typedef Matrix< float , 3 , 3 > Matrix3f
typedef Matrix< int , 3 , 3 > Matrix3i
typedef Matrix< std::complex<double> , 4 , 4 > Matrix4cd
typedef Matrix< std::complex<float> , 4 , 4 > Matrix4cf
typedef Matrix< double , 4 , 4 > Matrix4d
typedef Matrix< float , 4 , 4 > Matrix4f
typedef Matrix< int , 4 , 4 > Matrix4i
typedef Matrix< std::complex<double> , Dynamic , Dynamic > MatrixXcd
typedef Matrix< std::complex<float> , Dynamic , Dynamic > MatrixXcf
typedef Matrix< double , Dynamic , Dynamic > MatrixXd
typedef Matrix< float , Dynamic , Dynamic > MatrixXf
typedef Matrix< int , Dynamic , Dynamic > MatrixXi
typedef Matrix< std::complex<double> , 1, 2 > RowVector2cd
typedef Matrix< std::complex<float> , 1, 2 > RowVector2cf
typedef Matrix< double , 1, 2 > RowVector2d
typedef Matrix< float , 1, 2 > RowVector2f
typedef Matrix< int , 1, 2 > RowVector2i
typedef Matrix< std::complex<double> , 1, 3 > RowVector3cd
typedef Matrix< std::complex<float> , 1, 3 > RowVector3cf
typedef Matrix< double , 1, 3 > RowVector3d
typedef Matrix< float , 1, 3 > RowVector3f
typedef Matrix< int , 1, 3 > RowVector3i
typedef Matrix< std::complex<double> , 1, 4 > RowVector4cd
typedef Matrix< std::complex<float> , 1, 4 > RowVector4cf
typedef Matrix< double , 1, 4 > RowVector4d
typedef Matrix< float , 1, 4 > RowVector4f
typedef Matrix< int , 1, 4 > RowVector4i
typedef Matrix< std::complex<double> , 1, Dynamic > RowVectorXcd
typedef Matrix< std::complex<float> , 1, Dynamic > RowVectorXcf
typedef Matrix< double , 1, Dynamic > RowVectorXd
typedef Matrix< float , 1, Dynamic > RowVectorXf
typedef Matrix< int , 1, Dynamic > RowVectorXi
typedef Matrix< std::complex<double> , 2 , 1> Vector2cd
typedef Matrix< std::complex<float> , 2 , 1> Vector2cf
typedef Matrix< double , 2 , 1> Vector2d
typedef Matrix< float , 2 , 1> Vector2f
typedef Matrix< int , 2 , 1> Vector2i
typedef Matrix< std::complex<double> , 3 , 1> Vector3cd
typedef Matrix< std::complex<float> , 3 , 1> Vector3cf
typedef Matrix< double , 3 , 1> Vector3d
typedef Matrix< float , 3 , 1> Vector3f
typedef Matrix< int , 3 , 1> Vector3i
typedef Matrix< std::complex<double> , 4 , 1> Vector4cd
typedef Matrix< std::complex<float> , 4 , 1> Vector4cf
typedef Matrix< double , 4 , 1> Vector4d
typedef Matrix< float , 4 , 1> Vector4f
typedef Matrix< int , 4 , 1> Vector4i
typedef Matrix< std::complex<double> , Dynamic , 1> VectorXcd
typedef Matrix< std::complex<float> , Dynamic , 1> VectorXcf
typedef Matrix< double , Dynamic , 1> VectorXd
typedef Matrix< float , Dynamic , 1> VectorXf
typedef Matrix< int , Dynamic , 1> VectorXi
2 向量
向量被作为⼀种特殊的矩阵进⾏处理,即要么⾏为⼀要么列为⼀。除⾮显式的说明为⾏向量,否则这⾥将向量默认为列向量。请看下⾯两个别名定义:
typedef Matrix<float,3,1> Vector3f;
typedef Matrix<int,1,2> RowVector2i;
3 矩阵的动态空间分配
很多时候在程序的编译阶段也许我们并不知道矩阵具体的⾏列数,这时候使⽤动态控件分配就显得很必要了。当我们给矩阵模板中参数RowsAtCompileTime或者ColsAtCompileTime参数指定为Dynamic时,表⽰该矩阵对应⾏或列为⼀个动态分配的值。下⾯是两个动态矩阵的别名定义:
typedef Matrix<double,Dynamic,Dynamic> MatrixXd;
typedef Matrix<int,Dynamic,1> VectorXi;
4 矩阵的构建
经过上⾯的介绍以后,我们应该能定义⼀些基本的矩阵了。如:
Matrix3f a; //定义⼀个float类型3×3固定矩阵a
MatrixXf b; //定义⼀个float类型动态矩阵b(0×0)
Matrix<int,Dynamic,3> b; //定义⼀个int类型动态矩阵(0×3)
对应动态矩阵,我们也可以在构造的时候给出矩阵所占⽤的空间,⽐如:
MatrixXf a(10,15); //定义float类型10×15动态矩阵
VectorXf b(30); //定义float类型30×1动态矩阵(列向量)
为了保持⼀致性,我们也可以使⽤上⾯构造函数的形式定义⼀个固定的矩阵,即Matrix3f a(3,3)也是允许的。
上⾯矩阵在构造的过程中并没有初始化,Eigen还为⼀些⼩的(列)向量提供了可以初始化的构造函数。如:
Vector2d a(5.0,6.0);
Vector3d b(5.0,6.0,7.0);
Vector4d c(5.0,6.0,7.0,8.0);
5 矩阵元素的访问
Eigen提供了矩阵元素的访问形式和matlab中矩阵的访问形式⾮常相似,最⼤的不同是matlab中元素从1开始,⽽Eigen的矩阵中元素是从0开始访问。对于矩阵,第⼀个参数为⾏索引,第⼆个参数为列索引。⽽对于向量只需要给出⼀个索引即可。
#include <iostream>
#include "Eigen\Core"
//import most common Eigen types
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<<"Hear 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;
}
输出结果如下:
Hear is the matrix m:
3 -1
2.5 1.5
Here is the vector v:
4
3
像m(index)这种访问形式并不仅限于向量之中,对于矩阵也可以这样访问。这⼀点和matlab相同,我们知道在matlab中定义⼀个矩阵
a(3,4),如果我访问a(5)相当于访问a(2,2),这是因为在matlab中矩阵是按列存储的。这⾥⽐较灵活,默认矩阵元素也是按列存储的,但是我们也可以通过矩阵模板构造参数Options=RowMajor改变存储⽅式(这个参数是我们还没有提到的矩阵构造参数的第4个参数)。
6 ⼀般初始化⽅法
对于矩阵的初始化,我们可以采⽤下⾯的⽅法⽅便且直观的进⾏:
Matrix3f m;
m<<1,2,3,
4,5,6,
7,8,9;
std:cout<<m;
7 矩阵的⼤⼩
Eigen提供了rows(),cols(),size()⽅法来获取矩阵的⼤⼩,同时也同了resize()⽅法从新改变动态数组的⼤⼩。
#include <iostream>
#include "Eigen\Core"
using namespace Eigen;
int main()
{
MatrixXd m(2,5);
m<<1,2,3,4,5,
6,7,8,9,10;
std::cout<<"The matrix m is:\n"<<m<<std::endl;
std::cout<<"The matrix m is of size "
<&ws()<<"x"<&ls()<<std::endl;
std::cout<<"It has "<<m.size()<<" coefficients"<<std::endl;
VectorXd v(2);
resize函数c++v<<1,2;
std::cout<<"The vector v is:\n"<<v<<std::endl;
std::cout<<"The vector v is of size "<<v.size()<<std::endl;
std::cout<<"As a matrix,v is of size "<&ws()
<<"x"<&ls()<<std::endl;
}
输出结果如下:
The matrix m is:
1 3 5
6 8 10
2 4 9.58787e-315
7 9 1.17493e-309
The matrix m is of size 4x3
It has 12 coefficients
The vector v is:
1
2
1.17477e-309
7.0868e-304
The vector v is of size 5
As a matrix,v is of size 5x1
可以看到我们可以把矩阵任意的resize,但是resize后矩阵的元素会改变,如果resize后的矩阵⽐之前的⼤会出现⼀些未初始化的元素。如果被resize的矩阵按列存储(默认),那么resize命令和matlab中的reshape执⾏结果相同,只是matlab要求reshape的矩阵前后元素必须相同,也就是不允许resize后不能出现未初始化的元素。
对于固定⼤⼩的矩阵虽然也⽀持resize命令,但是resize后的⼤⼩只能是它本⾝的⼤⼩,否则就会报错。因为resize前后如果矩阵⼤⼩⼀样,就不会执⾏resize。如果我们不想在resize后改变矩阵的对应元素,那么可以使⽤conservativeResize()⽅法。对应上⾯程序中的m矩阵我们调⽤m.conservativeResize(4,3)后得到结果如下。其中因为⾏数增加了,增加的⾏会以未初始化的形式出现。
The matrix m is:
1 2 3
6 7 8
9.58787e-315 2.122e-314 1.52909e+249
0 0 2.47039e+249
8 赋值和⼤⼩变换
在Eigen中使⽤=可以直接将⼀个矩阵复制给另外⼀个矩阵,如果被复制的和赋值矩阵⼤⼩不⼀致,会⾃动对被复制矩阵执⾏resize函数。当然如果被复制的矩阵为固定矩阵当然就不会执⾏resize函数。当然也可以通过⼀些设置取消这个⾃动resize的过程。
using namespace Eigen;
int main()
{
MatrixXf a(2,2);
MatrixXf b(3,3);
b<<1,2,3,
4,5,6,
7,8,9;
a = b;
std::cout<<a<<std::endl;
}
输出结果:
1 2 3
4 5 6
7 8 9
9 固定矩阵和动态矩阵
什么时候使⽤固定矩阵什么时候使⽤动态矩阵呢?简单的说:当矩阵尺⼨⽐较⼩时使⽤固定矩阵(⼀般⼩于16),当矩阵尺⼨较⼤时使⽤动态矩阵(⼀般⼤于32)。使⽤固定矩阵有更好的表现,它可以避免重复的动态内存分配,固定矩阵实际上是⼀个array。即Matrix4f mymatrix;事实上是float mymatrix[16];。所以这个是真的不花费任何运⾏时间。相反动态矩阵的建⽴需要在
heap中分配空间。即MatrixXf mymatrix(rows,colums);实际上是float *mymatrix = new float[rows*colums];.此外动态矩阵还要保存⾏和列的值。
当然固定矩阵也存在着显⽽易见的弊端。当数组的⼤⼩过⼤时,固定数组的速度优势就不那么明显了,相反过⼤的固定数组有可能造成stack的溢出。这时候动态矩阵的灵活性就显得⼗分重要了。
10 其他模板参数
最开始我们已经提到了建⽴⼀个矩阵⼀共有6个模板参数,其中有3个我们还没有提到(其实第三个参数已经提到过了)。
Matrix<typename Scalar,
int RowsAtCompileTime,
int ColsAtCompileTime,
int Options=0,
int MaxRowsAtCompileTime = RowsAtCompileTime,
int MaxColsAtCompileTime = ColsAtCompileTime>
1. Options:这个参数决定了矩阵在存储过程中实际是按⾏还是按列存储。这个存储⽅式在前⾯我们提到的矩阵变换时必须要注意。默认是
按列存储,我们可以显⽰的使⽤Options=RowMajor让矩阵实际按⾏存储。如Matrix<float,2,3,RowMajor> a;.
2. MaxRowsAtCompileTime和MaxColsAtCompileTime:这两个值是设定动态矩阵在分配空间时最⼤的⾏数和列数。
如Matrix<float,Dynamic,Dynamic,0,3,4>;.
11 常规的矩阵typedef
我们前⾯给出了⼀些常⽤的矩阵typedef.其实可以总结如下:
1. MatrixNt对应的是Matrix
2. VectorNt对应的是Matrix
3. RowVectorNt对应的是Matrix
其中:
1. N可以是2,3,4或者X(表⽰Dynamic).
2. t可以是i(int),f(float),d(double),cf(complex
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论