第三讲,实践编程 Eigen
目录
- 1.实践 Eigen
- 1.1 Eigen的简介
- 1.2 Eigen 向量和矩阵的 声明
- 1.3 Eigen的输出操作
- 1.4 矩阵和向量相乘 要注意数据类型 矩阵纬度
- 1.5 矩阵的四则运算
- 1.6 矩阵求解特征向量和特征值
- 1.7 解方程 求逆
1.实践 Eigen
1.1 Eigen的简介
Eigen是一个 C++ 开源线性代数库。它提供了快速的有关矩阵的线性代数运算,还包括解方程等功能。许多上层的软件库也使用 Eigen 进行矩阵运算,包括 g2o、Sophus 等。
相比于其他库,Eigen 特殊之处在于,它是一个纯用头文件搭建起来的库。这意味着你只能找到它的头文件,而没有.so 或.a 那样的二进制文件。 我们在使用时,只需引入 Eigen 的头文件即可,不需要链接它的库文件(因为它没有库文件)。
1.2 Eigen 向量和矩阵的 声明
// 声明一个2*3的float矩阵Eigen::Matrix<float, 2, 3> matrix_23;// 同时,Eigen 通过 typedef 提供了许多内置类型,不过底层仍是Eigen::Matrix// 例如 Vector3d 实质上是 Eigen::Matrix<double, 3, 1>,即三维向量Eigen::Vector3d v_3d;// 效果这是一样的Eigen::Matrix<float,3,1> vd_3d;// Matrix3d 实质上是 Eigen::Matrix<double, 3, 3>Eigen::Matrix3d matrix_33 = Eigen::Matrix3d::Zero(); //初始化为零// 如果不确定矩阵大小,可以使用动态大小的矩阵Eigen::Matrix< double, Eigen::Dynamic, Eigen::Dynamic > matrix_dynamic;// 还有更简单的Eigen::MatrixXd matrix_x;
1.3 Eigen的输出操作
// 声明一个2*3的float矩阵Eigen::Matrix<float, 2, 3> matrix_23; // 下面是对Eigen阵的操作// 输入数据(初始化)matrix_23 << 1, 2, 3, 4, 5, 6;// 输出cout << matrix_23 << endl;//输出结果 1 2 3// 4 5 6// 用()访问矩阵中的元素for (int i=0; i<2; i++) {for (int j=0; j<3; j++)cout<<matrix_23(i,j)<<"\t";cout<<endl;}//输出结果 1 2 3// 4 5 6//也可以跟数组访问一样matrix_23[0];//结果 1
1.4 矩阵和向量相乘 要注意数据类型 矩阵纬度
Eigen::Vector3d v_3d;//内置的是double类型Eigen::Matrix<float,3,1> vd_3d; Eigen::MatrixXd matrix_x;// 矩阵和向量相乘(实际上仍是矩阵和矩阵)matrix_23 << 1, 2, 3, 4, 5, 6;v_3d << 3, 2, 1;vd_3d << 4,5,6;// 但是在Eigen里你不能混合两种不同类型的矩阵,double类型的不能和float类型的相乘,像这样是错的// Eigen::Matrix<double, 2, 1> result_wrong_type = matrix_23 * v_3d;// 应该显式转换//matrix_23.cast<double>() matrix_23矩阵转变为double类型Eigen::Matrix<double, 2, 1> result = matrix_23.cast<double>() * v_3d;cout << result << endl;Eigen::Matrix<float, 2, 1> result2 = matrix_23 * vd_3d;cout << result2 << endl;// 同样你不能搞错矩阵的维度// 试着取消下面的注释,看看Eigen会报什么错// Eigen::Matrix<double, 2, 3> result_wrong_dimension = matrix_23.cast<double>() * v_3d;
1.5 矩阵的四则运算
matrix_33 = Eigen::Matrix3d::Random(); // 随机数矩阵cout << matrix_33 << endl << endl;cout << matrix_33.transpose() << endl; // 转置cout << matrix_33.sum() << endl; // 各元素和cout << matrix_33.trace() << endl; // 迹cout << 10*matrix_33 << endl; // 数乘cout << matrix_33.inverse() << endl; // 逆cout << matrix_33.determinant() << endl; // 行列式
1.6 矩阵求解特征向量和特征值
// 特征值// 实对称矩阵可以保证对角化成功Eigen::SelfAdjointEigenSolver<Eigen::Matrix3d> eigen_solver ( matrix_33.transpose()*matrix_33 );cout << "Eigen values = \n" << eigen_solver.eigenvalues() << endl;//特征值cout << "Eigen vectors = \n" << eigen_solver.eigenvectors() << endl;//特征向量
1.7 解方程 求逆
// 解方程// 我们求解 matrix_NN * x = v_Nd 这个方程// N的大小在前边的宏里定义,它由随机数生成// 直接求逆自然是最直接的,但是求逆运算量大Eigen::Matrix< double, MATRIX_SIZE, MATRIX_SIZE > matrix_NN;matrix_NN = Eigen::MatrixXd::Random( MATRIX_SIZE, MATRIX_SIZE );Eigen::Matrix< double, MATRIX_SIZE, 1> v_Nd;v_Nd = Eigen::MatrixXd::Random( MATRIX_SIZE,1 );clock_t time_stt = clock(); // 计时// 直接求逆Eigen::Matrix<double,MATRIX_SIZE,1> x = matrix_NN.inverse()*v_Nd;cout <<"time use in normal inverse is " << 1000* (clock() - time_stt)/(double)CLOCKS_PER_SEC << "ms"<< endl;// 通常用矩阵分解来求,例如QR分解,速度会快很多time_stt = clock();x = matrix_NN.colPivHouseholderQr().solve(v_Nd);cout <<"time use in Qr decomposition is " <<1000* (clock() - time_stt)/(double)CLOCKS_PER_SEC <<"ms" << endl;