当前位置:   article > 正文

Eigen的简单用法——C++开源矩阵计算工具_c++ eigen

c++ eigen

第一部分:

 

1.1前言

Eigen是一个高层次的C ++库,有效支持 得到的线性代数,矩阵和矢量运算,数值分析及其相关的算法。

1.2配置

关于Eigen库的配置只需要在属性表包含目录中添加Eigen路径即可。 
这里写图片描述

1.3例子

Example 1:

  1. #include <iostream>

  2. #include <Eigen/Dense>

  3.  
  4. void main()

  5. {

  6. Eigen::MatrixXd m(2, 2); //声明一个MatrixXd类型的变量,它是2*2的矩阵,未初始化

  7. m(0, 0) = 3; //将矩阵第1个元素初始化3

  8. m(1, 0) = 2.5; //将矩阵第3个元素初始化3

  9. m(0, 1) = -1;

  10. m(1, 1) = m(1, 0) + m(0, 1);

  11. std::cout << m << std::endl;

  12. }

  •  

Eigen头文件定义了很多类型,但对于简单的应用程序,可能只使用MatrixXd类型。 这表示任意大小的矩阵(MatrixXd中的X),其中每个条目是双精度(MatrixXd中的d)。 Eigen / Dense头文件定义了MatrixXd类型和相关类型的所有成员函数。 在这个头文件中定义的所有类和函数都在特征名称空间中。

这里写图片描述

Example 2:

  1. #include <iostream>

  2. #include <Eigen/Dense>

  3. using namespace Eigen;

  4. using namespace std;

  5. int main()

  6. {

  7. MatrixXd m = MatrixXd::Random(3,3); //使用Random随机初始化3*3的矩阵

  8. m = (m + MatrixXd::Constant(3,3,1.2)) * 50;

  9. cout << "m =" << endl << m << endl;

  10. VectorXd v(3); //这表示任意大小的(列)向量。

  11. v << 1, 2, 3;

  12. cout << "m * v =" << endl << m * v << endl;

  13. }

  •  
  1. #include <iostream>

  2. #include <Eigen/Dense>

  3. using namespace Eigen;

  4. using namespace std;

  5. int main()

  6. {

  7. Matrix3d m = Matrix3d::Random(); //使用Random随机初始化固定大小的3*3的矩阵

  8. m = (m + Matrix3d::Constant(1.2)) * 50;

  9. cout << "m =" << endl << m << endl; Vector3d v(1,2,3);

  10. cout << "m * v =" << endl << m * v << endl;

  11. }

  •  

Matrix&Vector

Example 3:

  1. #include <iostream>

  2. #include <Eigen/Dense>

  3. using namespace Eigen;

  4. int main()

  5. {

  6. MatrixXd m(2,2);

  7. m(0,0) = 3;

  8. m(1,0) = 2.5;

  9. m(0,1) = -1;

  10. m(1,1) = m(1,0) + m(0,1);

  11. std::cout << "Here is the matrix m:\n" << m << std::endl;

  12. VectorXd v(2);

  13. v(0) = 4;

  14. v(1) = v(0) - 1;

  15. std::cout << "Here is the vector v:\n" << v << std::endl;

  16. }

  •  

逗号初始化

Example 4:

  1. Matrix3f m;

  2. m << 1, 2, 3, 4, 5, 6, 7, 8, 9;

  3. std::cout << m;

  •  

通过Resize调整矩阵大小

矩阵的当前大小可以通过rows(),cols()和size()检索。 这些方法分别返回行数,列数和系数数。 通过resize()方法调整动态大小矩阵的大小。 
Example 5:

  1. #include <iostream>

  2. #include <Eigen/Dense>

  3. using namespace Eigen;

  4. int main()

  5. {

  6. MatrixXd m(2,5); //初始化大小2*5

  7. m.resize(4,3); //重新调整为4*3

  8. std::cout << "The matrix m is of size " << m.rows() << "x" << m.cols() << std::endl;

  9. std::cout << "It has " << m.size() << " coefficients" << std::endl;

  10. VectorXd v(2); v.resize(5);

  11. std::cout << "The vector v is of size " << v.size() << std::endl;

  12. std::cout << "As a matrix, v is of size " << v.rows() << "x" << v.cols() << std::endl;

  13. }

  •  

通过赋值调整矩阵大小

Example 6:

  1. MatrixXf a(2, 2);

  2. std::cout << "a is of size " << a.rows() << "x" << a.cols() << std::endl;

  3. MatrixXf b(3, 3);

  4. a = b;

  5. std::cout << "a is now of size " << a.rows() << "x" << a.cols() << std::endl;

  •  

Eigen + - * 等运算

Eigen通过通用的C ++算术运算符(例如+, - ,)或通过特殊方法(如dot(),cross()等)的重载提供矩阵/向量算术运算。对于Matrix类(矩阵和向量) 只被重载以支持线性代数运算。 例如,matrix1 matrix2表示矩阵矩阵乘积。 
Example 7:

  1. #include <iostream>

  2. #include <Eigen/Dense>

  3. using namespace Eigen;

  4. int main()

  5. {

  6. Matrix2d a; a << 1, 2, 3, 4;

  7. MatrixXd b(2,2);

  8. b << 2, 3, 1, 4;

  9. std::cout << "a + b =\n" << a + b << std::endl;

  10. std::cout << "a - b =\n" << a - b << std::endl;

  11. std::cout << "Doing a += b;" << std::endl;

  12. a += b;

  13. std::cout << "Now a =\n" << a << std::endl;

  14. Vector3d v(1,2,3);

  15. Vector3d w(1,0,0);

  16. std::cout << "-v + w - v =\n" << -v + w - v << std::endl;

  17. }

  •  

Example 8:

  1. #include <iostream>

  2. #include <Eigen/Dense>

  3. using namespace Eigen;

  4. int main()

  5. {

  6. Matrix2d a;

  7. a << 1, 2, 3, 4;

  8. Vector3d v(1,2,3);

  9. std::cout << "a * 2.5 =\n" << a * 2.5 << std::endl;

  10. std::cout << "0.1 * v =\n" << 0.1 * v << std::endl;

  11. std::cout << "Doing v *= 2;" << std::endl; v *= 2;

  12. std::cout << "Now v =\n" << v << std::endl;

  13. }

  •  

矩阵转置、共轭和伴随矩阵

 
  1. MatrixXcf a = MatrixXcf::Random(2,2);

  2. cout << "Here is the matrix a\n" << a << endl;

  3. cout << "Here is the matrix a^T\n" << a.transpose() << endl;

  4. cout << "Here is the conjugate of a\n" << a.conjugate() << endl;

  5. cout << "Here is the matrix a^*\n" << a.adjoint() << endl;

  •  

禁止如下操作:

a = a.transpose(); // !!! do NOT do this !!!
  •  

但是可以使用如下函数:

a.transposeInPlace();
  •  

此时a被其转置替换。

  1. #include <iostream>

  2. #include <Eigen/Dense>

  3. using namespace Eigen;

  4. int main()

  5. {

  6. Matrix2i a;

  7. a << 1, 2, 3, 4;

  8. std::cout << "Here is the matrix a:\n" << a << std::endl;

  9. a = a.transpose(); // !!! do NOT do this !!!

  10. std::cout << "and the result of the aliasing effect:\n" << a << std::endl;

  11. }

  •  

矩阵* 矩阵和矩阵* 向量操作

  1. #include <iostream>

  2. #include <Eigen/Dense>

  3. using namespace Eigen;

  4. int main()

  5. {

  6. Matrix2d mat; mat << 1, 2, 3, 4;

  7. Vector2d u(-1,1), v(2,0);

  8. std::cout << "Here is mat*mat:\n" << mat*mat << std::endl;

  9. std::cout << "Here is mat*u:\n" << mat*u << std::endl;

  10. std::cout << "Here is u^T*mat:\n" << u.transpose()*mat << std::endl;

  11. std::cout << "Here is u^T*v:\n" << u.transpose()*v << std::endl;

  12. std::cout << "Here is u*v^T:\n" << u*v.transpose() << std::endl;

  13. std::cout << "Let's multiply mat by itself" << std::endl;

  14. mat = mat*mat; std::cout << "Now mat is mat:\n" << mat << std::endl;

  15. }

  •  

点乘和叉乘

对于点积和叉乘积,需要使用dot()和cross()方法。

  1. #include <iostream>

  2. #include <Eigen/Dense>

  3. using namespace Eigen;

  4. using namespace std;

  5. int main()

  6. {

  7. Vector3d v(1,2,3);

  8. Vector3d w(0,1,2);

  9. cout << "Dot product: " << v.dot(w) << endl;

  10. double dp = v.adjoint()*w; // automatic conversion of the inner product to a scalar

  11. cout << "Dot product via a matrix product: " << dp << endl;

  12. cout << "Cross product:\n" << v.cross(w) << endl;

  13. }

  •  
  1. #include <iostream>

  2. #include <Eigen/Dense>

  3. using namespace std;

  4. int main()

  5. {

  6. Eigen::Matrix2d mat;

  7. mat << 1, 2, 3, 4;

  8. cout << "Here is mat.sum(): " << mat.sum() << endl;

  9. cout << "Here is mat.prod(): " << mat.prod() << endl;

  10. cout << "Here is mat.mean(): " << mat.mean() << endl;

  11. cout << "Here is mat.minCoeff(): " << mat.minCoeff() << endl;

  12. cout << "Here is mat.maxCoeff(): " << mat.maxCoeff() << endl;

  13. cout << "Here is mat.trace(): " << mat.trace() << endl;

  14. }

  •  

数组的运算(未完待续)
Eigen最小二乘估计

最小平方求解的最好方法是使用SVD分解。 Eigen提供一个作为JacobiSVD类,它的solve()是做最小二乘解。式子为Ax=b 
经过和Matlab对比。

  1. #include <iostream>

  2. #include <Eigen/Dense>

  3. using namespace std;

  4. using namespace Eigen;

  5. int main()

  6. {

  7. MatrixXf A = MatrixXf::Random(3, 2);

  8. cout << "Here is the matrix A:\n" << A << endl;

  9. VectorXf b = VectorXf::Random(3);

  10. cout << "Here is the right hand side b:\n" << b << endl;

  11. cout << "The least-squares solution is:\n" << A.jacobiSvd(ComputeThinU | ComputeThinV).solve(b) << endl;

  12. }

  •  

这里写图片描述

第二部分:

 

矩阵、向量初始化

  1. #include <iostream>

  2. #include "Eigen/Dense"

  3. using namespace Eigen;

  4. int main()

  5. {

  6. MatrixXf m1(3,4); //动态矩阵,建立3行4列。

  7. MatrixXf m2(4,3); //4行3列,依此类推。

  8. MatrixXf m3(3,3);

  9.  
  10. Vector3f v1; //若是静态数组,则不用指定行或者列

  11. /* 初始化 */

  12. Matrix3d m = Matrix3d::Random();

  13. m1 = MatrixXf::Zero(3,4); //用0矩阵初始化,要指定行列数

  14. m2 = MatrixXf::Zero(4,3);

  15. m3 = MatrixXf::Identity(3,3); //用单位矩阵初始化

  16. v1 = Vector3f::Zero(); //同理,若是静态的,不用指定行列数

  17.  
  18. m1 << 1,0,0,1, //也可以以这种方式初始化

  19. 1,5,0,1,

  20. 0,0,9,1;

  21. m2 << 1,0,0,

  22. 0,4,0,

  23. 0,0,7,

  24. 1,1,1;

  25. //向量初始化,与矩阵类似

  26. Vector3d v3(1,2,3);

  27. VectorXf vx(30);

  28. }

  •  

C++数组和矩阵转换

使用Map函数,可以实现Eigen的矩阵和c++中的数组直接转换,语法如下:

  1. //@param MatrixType 矩阵类型

  2. //@param MapOptions 可选参数,指的是指针是否对齐,Aligned, or Unaligned. The default is Unaligned.

  3. //@param StrideType 可选参数,步长

  4. /*

  5. Map<typename MatrixType,

  6. int MapOptions,

  7. typename StrideType>

  8. */

  9. int i;

  10. //数组转矩阵

  11. double *aMat = new double[20];

  12. for(i =0;i<20;i++)

  13. {

  14. aMat[i] = rand()%11;

  15. }

  16. //静态矩阵,编译时确定维数 Matrix<double,4,5>

  17. Eigen:Map<Matrix<double,4,5> > staMat(aMat);

  18.  
  19.  
  20. //输出

  21. for (int i = 0; i < staMat.size(); i++)

  22. std::cout << *(staMat.data() + i) << " ";

  23. std::cout << std::endl << std::endl;

  24.  
  25.  
  26. //动态矩阵,运行时确定 MatrixXd

  27. Map<MatrixXd> dymMat(aMat,4,5);

  28.  
  29.  
  30. //输出,应该和上面一致

  31. for (int i = 0; i < dymMat.size(); i++)

  32. std::cout << *(dymMat.data() + i) << " ";

  33. std::cout << std::endl << std::endl;

  34.  
  35. //Matrix中的数据存在一维数组中,默认是行优先的格式,即一行行的存

  36. //data()返回Matrix中的指针

  37. dymMat.data();

  •  

矩阵基础操作

eigen重载了基础的+ - * / += -= = /= 可以表示标量和矩阵或者矩阵和矩阵

  1. #include <iostream>

  2. #include <Eigen/Dense>

  3. using namespace Eigen;

  4. int main()

  5. {

  6. //单个取值,单个赋值

  7. double value00 = staMat(0,0);

  8. double value10 = staMat(1,0);

  9. staMat(0,0) = 100;

  10. std::cout << value00 <<value10<<std::endl;

  11. std::cout <<staMat<<std::endl<<std::endl;

  12. //加减乘除示例 Matrix2d 等同于 Matrix<double,2,2>

  13. Matrix2d a;

  14. a << 1, 2,

  15. 3, 4;

  16. MatrixXd b(2,2);

  17. b << 2, 3,

  18. 1, 4;

  19.  
  20. Matrix2d c = a + b;

  21. std::cout<< c<<std::endl<<std::endl;

  22.  
  23. c = a - b;

  24. std::cout<<c<<std::endl<<std::endl;

  25.  
  26. c = a * 2;

  27. std::cout<<c<<std::endl<<std::endl;

  28.  
  29. c = 2.5 * a;

  30. std::cout<<c<<std::endl<<std::endl;

  31.  
  32. c = a / 2;

  33. std::cout<<c<<std::endl<<std::endl;

  34.  
  35. c = a * b;

  36. std::cout<<c<<std::endl<<std::endl;

  •  

点积和叉积

  1. #include <iostream>

  2. #include <Eigen/Dense>

  3. using namespace Eigen;

  4. using namespace std;

  5. int main()

  6. {

  7. //点积、叉积(针对向量的)

  8. Vector3d v(1,2,3);

  9. Vector3d w(0,1,2);

  10. std::cout<<v.dot(w)<<std::endl<<std::endl;

  11. std::cout<<w.cross(v)<<std::endl<<std::endl;

  12. }

  13. */

  •  

转置、伴随、行列式、逆矩阵

小矩阵(4 * 4及以下)eigen会自动优化,默认采用LU分解,效率不高

  1. #include <iostream>

  2. #include <Eigen/Dense>

  3. using namespace std;

  4. using namespace Eigen;

  5. int main()

  6. {

  7. Matrix2d c;

  8. c << 1, 2,

  9. 3, 4;

  10. //转置、伴随

  11. std::cout<<c<<std::endl<<std::endl;

  12. std::cout<<"转置\n"<<c.transpose()<<std::endl<<std::endl;

  13. std::cout<<"伴随\n"<<c.adjoint()<<std::endl<<std::endl;

  14. //逆矩阵、行列式

  15. std::cout << "行列式: " << c.determinant() << std::endl;

  16. std::cout << "逆矩阵\n" << c.inverse() << std::endl;

  17. }

  •  

计算特征值和特征向量

  1. #include <iostream>

  2. #include <Eigen/Dense>

  3. using namespace std;

  4. using namespace Eigen;

  5. int main()

  6. {

  7. //特征向量、特征值

  8. std::cout << "Here is the matrix A:\n" << a << std::endl;

  9. SelfAdjointEigenSolver<Matrix2d> eigensolver(a);

  10. if (eigensolver.info() != Success) abort();

  11. std::cout << "特征值:\n" << eigensolver.eigenvalues() << std::endl;

  12. std::cout << "Here's a matrix whose columns are eigenvectors of A \n"

  13. << "corresponding to these eigenvalues:\n"

  14. << eigensolver.eigenvectors() << std::endl;

  15. }

  •  

解线性方程

  1. #include <iostream>

  2. #include <Eigen/Dense>

  3. using namespace std;

  4. using namespace Eigen;

  5. int main()

  6. {

  7. //线性方程求解 Ax =B;

  8. Matrix4d A;

  9. A << 2,-1,-1,1,

  10. 1,1,-2,1,

  11. 4,-6,2,-2,

  12. 3,6,-9,7;

  13.  
  14. Vector4d B(2,4,4,9);

  15.  
  16. Vector4d x = A.colPivHouseholderQr().solve(B);

  17. Vector4d x2 = A.llt().solve(B);

  18. Vector4d x3 = A.ldlt().solve(B);

  19.  
  20.  
  21. std::cout << "The solution is:\n" << x <<"\n\n"<<x2<<"\n\n"<<x3 <<std::endl;

  22. }

  •  

除了colPivHouseholderQr、LLT、LDLT,还有以下的函数可以求解线性方程组,请注意精度和速度: 解小矩阵(4*4)基本没有速度差别

最小二乘求解

最小二乘求解有两种方式,jacobiSvd或者colPivHouseholderQr,4*4以下的小矩阵速度没有区别,jacobiSvd可能更快,大矩阵最好用colPivHouseholderQr

 
  1. #include <iostream>

  2. #include <Eigen/Dense>

  3. using namespace std;

  4. using namespace Eigen;

  5. int main()

  6. {

  7. MatrixXf A1 = MatrixXf::Random(3, 2);

  8. std::cout << "Here is the matrix A:\n" << A1 << std::endl;

  9. VectorXf b1 = VectorXf::Random(3);

  10. std::cout << "Here is the right hand side b:\n" << b1 << std::endl;

  11. //jacobiSvd 方式:Slow (but fast for small matrices)

  12. std::cout << "The least-squares solution is:\n"

  13. << A1.jacobiSvd(ComputeThinU | ComputeThinV).solve(b1) << std::endl;

  14. //colPivHouseholderQr方法:fast

  15. std::cout << "The least-squares solution is:\n"

  16. << A1.colPivHouseholderQr().solve(b1) << std::endl;

  17. }

  •  

稀疏矩阵

稀疏矩阵的头文件包括:

#include

 
  1. typedef Eigen::Triplet<double> T;

  2. std::vector<T> tripletList;

  3. triplets.reserve(estimation_of_entries); //estimation_of_entries是预估的条目

  4. for(...)

  5. {

  6. tripletList.push_back(T(i,j,v_ij));//第 i,j个有值的位置的值

  7. }

  8. SparseMatrixType mat(rows,cols);

  9. mat.setFromTriplets(tripletList.begin(), tripletList.end());

  10. // mat is ready to go!

  •  

2.直接将已知的非0值插入

  1. SparseMatrix<double> mat(rows,cols);

  2. mat.reserve(VectorXi::Constant(cols,6));

  3. for(...)

  4. {

  5. // i,j 个非零值 v_ij != 0

  6. mat.insert(i,j) = v_ij;

  7. }

  8. mat.makeCompressed(); // optional

  •  

稀疏矩阵支持大部分一元和二元运算:

sm1.real() sm1.imag() -sm1 0.5*sm1 
sm1+sm2 sm1-sm2 sm1.cwiseProduct(sm2) 
二元运算中,稀疏矩阵和普通矩阵可以混合使用

//dm表示普通矩阵 
dm2 = sm1 + dm1; 
也支持计算转置矩阵和伴随矩阵

参考以下链接

点击这里跳转查看更多

第三部分:

其他相关博客:

1、单独下载与安装:https://blog.csdn.net/augusdi/article/details/12907341

2、一篇较详细的教程:https://blog.csdn.net/wzaltzap/article/details/79501856

3、计算特征值特征向量:https://blog.csdn.net/wokaowokaowokao12345/article/details/47375427

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/79250
推荐阅读
相关标签
  

闽ICP备14008679号