Eigen
是一个C++
开源线性代数库,它提供了快速的矩阵相关的线性代数运算,还包括求解方程组,求特征值,特征向量等功能,许多上层的软件库也使用Eigen
进行矩阵运算
与其他库相比,Eigen的特殊之处在于,它是一个纯用头文件搭建起来的库,这意味着你只能找到它的头文件,而没有文件后缀名为.so或.a的二进制文件的库,因此在使用的时候,只需引入Eigen的头文件即可,不需要链接库文件,接下来进行一些关于Eigen的简单使用
首先在工作目录下建立源文件eigenMatrix.cpp
#include<iostream>
using namespace std;
#include<ctime>
//Eigen的核心部分
#include<Eigen/Core>
//稠密矩阵的代数运算(逆,特征值等)
#include<Eigen/Dense>
using namespace Eigen;
#define Matrix_size 50
/*接下来演示其基本类型的使用*/
int main(int argc,char **argv)
{
//Eigen中所有向量和矩阵都是Eigen::Matrix,他是一个模板类,前三个参数为数据类型、行、列
//声明一个2*3的float矩阵
Matrix<float,2,3> matrix_23;
//同时,Eigen通过typedef提供了许多内置类型,不过底层仍是Eigen::Matrix
//例如,Vector3d实质上是Eigen::Matrix<double,3,1>,即三维向量
Vector3d v_3d;
//这是一样的
Matrix<float,3,1> vd_3d;
//Matrix3d实质上是Eigen::Matrix<double,3.3>
Matrix3d matrix_33 = Matrix3d::Zero();//初始化为0
//如果不确定矩阵大小,可以使用动态大小的矩阵
Matrix<double,Dynamic,Dynamic> matrix_dynamic;
//更简单
MatrixXd matrix_x;
//.....依次类推
//接下来是对Eigen阵的操作
//输入数据(初始化)
matrix_23<<1,2,3,4,5,6;
cout<<"matrix_23输出为:\n"<<matrix_23<<endl;
//用()访问矩阵中的元素
cout<<"print matrix 2*3"<<endl;
for(int i=0;i<2;i++)
{
for(int j=0;j<3;j++)
{
cout<<matrix_23(i,j)<<"\t";
}
cout<<endl;
}
//矩阵和向量相乘(实际上仍是矩阵和矩阵)
v_3d<< 3,2,1;
vd_3d<<4,5,6;
//在eigen里面。不同数据类型的矩阵不能混合,应该显示转换
//同时也要遵守矩阵的乘法法则
//result.transpose()矩阵转置
Matrix<double,2,1> result = matrix_23.cast<double>()*v_3d;
cout<<"[1,2,3;4,5,6]*[3,2,1]:\n"<<result.transpose()<<endl;
Matrix<float,2,1> result2 = matrix_23*vd_3d;
cout<<"[1,2,3;4,5,6]*[4,5,6]:\n"<<result2.transpose()<<endl;
//其他类型的矩阵运算如下
matrix_33 = Matrix3d::Random();//随机数矩阵
cout<<"random matrix:\n"<<matrix_33<<endl;
cout<<"transpose:\n"<<matrix_33.transpose()<<endl;//转置
cout<<"各元素和sum:\t"<<matrix_33.sum()<<endl;//各元素求和
cout<<"trace:\t"<<matrix_33.trace()<<endl;//迹
cout<<"times 10:\n"<<10*matrix_33<<endl;//数乘
cout<<"inverse:\n"<<matrix_33.inverse()<<endl;//逆
cout<<"det:\t"<<matrix_33.determinant()<<endl;//行列式
//特征值
//实对称矩阵可以进行相似对角化
SelfAdjointEigenSolver<Matrix3d> eigen_solver(matrix_33.transpose()*matrix_33);
cout<<"Eigen values = \n"<<eigen_solver.eigenvalues()<<endl;//特征值
cout<<"Eigen vectors = \n"<<eigen_solver.eigenvectors()<<endl;//特征向量
//解方程
//求解matrix_NN*x = v_Nd方程
//N的大小在前面的宏里定义,它是由随机数生成
//直接求逆较直接,但是运算量较大
Matrix<double,Matrix_size,Matrix_size> matrix_NN = MatrixXd::Random(Matrix_size,Matrix_size);
matrix_NN = matrix_NN * matrix_NN.transpose();//保证半正定
Matrix<double,Matrix_size,1> v_Nd = MatrixXd::Random(Matrix_size,1);
clock_t time_stt = clock();//计时
//直接求逆
Matrix<double,Matrix_size,1> x = matrix_NN.inverse()*v_Nd;
cout<<"time of normal inverse is:"<<1000*(clock() - time_stt)/(double) CLOCKS_PER_SEC<<"ms"<<endl;
cout<<"x = "<<x.transpose()<<endl;
//通常用矩阵分解来求,比如QR分解,速度快很多
time_stt = clock();
x = matrix_NN.colPivHouseholderQr().solve(v_Nd);
cout<< "time of QR is:"<<1000*(clock() - time_stt)/(double) CLOCKS_PER_SEC<<"ms"<<endl;
cout<<"x = "<<x.transpose()<<endl;
//对于正定矩阵,还可以用cholesky分解来解方程
time_stt = clock();
x = matrix_NN.ldlt().solve(v_Nd);
cout<< "time of ldlt decomposition is:"<<1000*(clock() - time_stt)/(double) CLOCKS_PER_SEC<<"ms"<<endl;
cout<<"x = "<<x.transpose()<<endl;
system("pause");
return 0;
}
上述程序历程演示了Eigen的一些基本运算,接下来要进行编译,在CMakeLists.txt中要指定Eigen的头文件目录:
#因为eigen库只有头文件,所以不需要再用target_link_libraries语句将程序链接到库上
include_directories("/usr/include/eigen3")
最后终端输入命令编译运行:
cd build
cmake ..
make
./eigenMatrix.cpp
运行结果为:
matrix_23输出为:
1 2 3
4 5 6
print matrix 2*3
1 2 3
4 5 6
[1,2,3;4,5,6]*[3,2,1]:
10 28
[1,2,3;4,5,6]*[4,5,6]:
32 77
random matrix:
0.680375 0.59688 -0.329554
-0.211234 0.823295 0.536459
0.566198 -0.604897 -0.444451
transpose:
0.680375 -0.211234 0.566198
0.59688 0.823295 -0.604897
-0.329554 0.536459 -0.444451
各元素和sum: 1.61307
trace: 1.05922
times 10:
6.80375 5.9688 -3.29554
-2.11234 8.23295 5.36459
5.66198 -6.04897 -4.44451
inverse:
-0.198521 2.22739 2.8357
1.00605 -0.555135 -1.41603
-1.62213 3.59308 3.28973
det: 0.208598
Eigen values =
0.0242899
0.992154
1.80558
Eigen vectors =
-0.549013 -0.735943 0.396198
0.253452 -0.598296 -0.760134
-0.796459 0.316906 -0.514998