Eigen使用总结


Eigen 使用总结

  • 1.模块和头文件
  • 2.语法基础
    • 2.1.Matrix类
    • 2.2 Storage orders
    • 2.2.矩阵与向量的运算
    • 2.3.Array类
    • 2.4.矩阵初始化
    • 2.5. 归约,迭代器,广播
      • 范数计算
      • 布尔归约
      • 迭代器,获取某元素位置
    • 2.6 Eigen 矩阵单个元素操作
      • 2.6.1 vector operator
      • 2.6.2 matrix operator
    • 2.7 Eigen 矩阵化简
    • 2.8 Eigen 求解线性方程组 Ax = b
    • 2.9 矩阵的特殊生成
  • 3.Eigen线性方程与矩阵分解

1.模块和头文件
模块 头文件 说明
Core #include 包含Matrix和Array类,基础的线性代数运算和数组操作
Gemetry #include 包含旋转,平移,缩放,2维和3维的各种变换
LU #include 包含求逆,行列式,LU分解
Cholesky #include 包含LLT和LDLT Cholesky分解
SVD #include 包含SVD分解
QR #include 包含QR分解
Eigenvalues #include 包含特征值,特征向量的分解
Sparse #include 包含稀疏矩阵的存储与运算
Dense #include 包含了Core/Geometry/LU/Cholesky/SVD/QR/Eigenvalues模块
Eigen #include 包含Dense和Sparse
2.语法基础 2.1.Matrix类 所有矩阵和向量都是Matrix模板类的对象,Matrix类有6个模板参数,主要使用前三个,剩下的使用默认值。
  • 默认构造时,指定大小的矩阵,只分配相应大小的空间,不进行初始化。动态大小的矩阵,则未分配空间。
  • []操作符可以用于向量元素的获取,但不能用于matrix。
  • matrix的大小可以通过rows(), cols(), size()获取,resize()可以重新调整矩阵大小。
2.2 Storage orders
  • 矩阵的条目形成一个二维网格。但是,当矩阵存储在存储器中时,必须以某种方式线性排列条目。有两种主要方法可以做到这一点,按行和按列。
  • 我们说矩阵是按行优先存储的。首先存储整个第一行,然后存储整个第二行,依此类推。
Matrix Acolmajor; Acolmajor << 8, 2, 2, 9, 9, 1, 4, 4, 3, 5, 4, 5; cout << "The matrix A:" << endl; cout << Acolmajor << endl << endl; cout << "In memory (column-major):" << endl; for (int i = 0; i < Acolmajor.size(); i++) cout << *(Acolmajor.data() + i) << ""; cout << endl << endl; Matrix Arowmajor = Acolmajor; cout << "In memory (row-major):" << endl; for (int i = 0; i < Arowmajor.size(); i++) cout << *(Arowmajor.data() + i) << ""; cout << endl;

output:
The matrix A: 8 2 2 9 9 1 4 4 3 5 4 5In memory (column-major): 893215244945In memory (row-major): 822991443545

那么,您应该在程序中使用哪个存储顺序?这个问题没有简单的答案。这取决于您的应用程序。请记住以下几点:
  • 您的用户可能希望您使用特定的存储顺序。或者,您可以使用Eigen以外的其他库,并且这些其他库可能需要一定的存储顺序。在这些情况下,在整个程序中使用此存储顺序可能是最简单,最快的。
  • 当矩阵以行优先顺序存储时,逐行遍历矩阵的算法会更快,因为数据位置更好。同样,对于主要列矩阵,逐列遍历更快。可能需要尝试一下以找出对您的特定应用程序更快的方法。
  • Eigen中的默认值是column-major。自然,对Eigen库的大多数开发和测试都是使用列主矩阵完成的。这意味着,即使我们旨在透明地支持列主存储和行主存储顺序,Eigen库也可能很好地与列主存储矩阵配合使用。
2.2.矩阵与向量的运算
MatrixXcf a = MatrixXcf::Random(3,3); a.transpose(); # 转置 a.conjugate(); # 共轭 a.adjoint(); # 共轭转置(伴随矩阵) # 对于实数矩阵,conjugate不执行任何操作,adjoint等价于transpose a.transposeInPlace() #原地转置Vector3d v(1,2,3); Vector3d w(4,5,6); v.dot(w); # 点积 v.cross(w); # 叉积Matrix2d a; a << 1, 2, 3, 4; a.sum(); # 所有元素求和 a.prod(); # 所有元素乘积 a.mean(); # 所有元素求平均 a.minCoeff(); # 所有元素中最小元素 a.maxCoeff(); # 所有元素中最大元素 a.trace(); # 迹,对角元素的和 #minCoeff和maxCoeff还可以返回结果元素的位置信息 int i, j; a.minCoeff(&i, &j);

行列相取:row 取整行
Eigen::Matrix &Pose0 Pose0.row(2)//取第三行 Pose0.row(1)//取第2行 Pose0.row(0)//取第1行

2.3.Array类 Array是个类模板,前三个参数必须指定,后三个参数可选。
  • 当执行array*array时,执行的是相应元素的乘积,所以两个array必须具有相同的尺寸。
  • Matrix对象——>Array对象:.array()函数
  • Array对象——>Matrix对象:.matrix()函数
2.4.矩阵初始化
  • 逗号初始化:为矩阵元素赋值,顺序是从左到右,从上到下,数目必须匹配。
  • 特殊矩阵
    • 零阵:类静态成员函数Zero()
    • 常量矩阵:Constant(rows, cols, value)
    • 随机矩阵:Random()
    • 单位矩阵:Identity()
  • LinSpaced(size, low, high):构建从low到high等间距的size长度的序列,适用于vector和一维数组。
2.5. 归约,迭代器,广播 范数计算
  • squareNorm():L2范数,等价于计算vector自身点积
  • norm():返回`squareNorm的开方根
  • .lpNorm():p范数,p可以取Infinity,表无穷范数
布尔归约
  • all()=true: matrix或array中所有元素为true
  • any()=true: 到少有一个为true
  • count(): 返回true元素个数
迭代器,获取某元素位置
// sample Eigen::MatrixXf m(2,2); m << 1,2,3,4; MatrixXf::Index maxRow, maxCol; float max = m.maxCoeff(&minRow, &minCol);

2.6 Eigen 矩阵单个元素操作 2.6.1 vector operator
// Vectorized operations on each element independently // Eigen// Matlab R = P.cwiseProduct(Q); // R = P .* Q 对应点相乘 R = P.array() * s.array(); // R = P .* s 对应点相乘 R = P.cwiseQuotient(Q); // R = P ./ Q 对应点相除 R = P.array() / Q.array(); // R = P ./ Q对应点相除 R = P.array() + s.array(); // R = P + s对应点相加 R = P.array() - s.array(); // R = P - s对应点相减 R.array() += s; // R = R + s全加s R.array() -= s; // R = R - s全减s R.array() < Q.array(); // R < Q 以下的都是针对矩阵的单个元素的操作 R.array() <= Q.array(); // R <= Q矩阵元素比较,会在相应位置置0或1 R.cwiseInverse(); // 1 ./ P R.array().inverse(); // 1 ./ P R.array().sin()// sin(P) R.array().cos()// cos(P) R.array().pow(s)// P .^ s R.array().square()// P .^ 2 R.array().cube()// P .^ 3 R.cwiseSqrt()// sqrt(P) R.array().sqrt()// sqrt(P) R.array().exp()// exp(P) R.array().log()// log(P) R.cwiseMax(P)// max(R, P) 对应取大 R.array().max(P.array())// max(R, P) 对应取大 R.cwiseMin(P)// min(R, P) 对应取小 R.array().min(P.array())// min(R, P) 对应取小 R.cwiseAbs()// abs(P) 绝对值 R.array().abs()// abs(P) 绝对值 R.cwiseAbs2()// abs(P.^2) 绝对值平方 R.array().abs2()// abs(P.^2) 绝对值平方 (R.array() < s).select(P,Q); // (R < s ? P : Q)这个也是单个元素的操作

2.6.2 matrix operator
#include using namespace std; #include // Eigen 部分 #include // 稠密矩阵的代数运算(逆,特征值等) #include #define MATRIX_SIZE 50 **************************** * 本程序演示了 Eigen 基本类型的使用 ****************************/int main( int argc, char** argv ) { // Eigen 中所有向量和矩阵都是Eigen::Matrix,它是一个模板类。它的前三个参数为:数据类型,行,列 // 声明一个2*3的float矩阵 Eigen::Matrix matrix_23; // 同时,Eigen 通过 typedef 提供了许多内置类型,不过底层仍是Eigen::Matrix // 例如 Vector3d 实质上是 Eigen::Matrix,即三维向量 Eigen::Vector3d v_3d; // 这是一样的 Eigen::Matrix vd_3d; // Matrix3d 实质上是 Eigen::Matrix Eigen::Matrix3d matrix_33 = Eigen::Matrix3d::Zero(); //初始化为零 // 如果不确定矩阵大小,可以使用动态大小的矩阵 Eigen::Matrix< double, Eigen::Dynamic, Eigen::Dynamic > matrix_dynamic; // 更简单的 Eigen::MatrixXd matrix_x; // 这种类型还有很多,我们不一一列举// 下面是对Eigen阵的操作 // 输入数据(初始化) matrix_23 << 1, 2, 3, 4, 5, 6; // 输出 cout << matrix_23 << endl; // 用()访问矩阵中的元素 for (int i=0; i<2; i++) { for (int j=0; j<3; j++) cout< result_wrong_type = matrix_23 * v_3d; // 应该显式转换 Eigen::Matrix result = matrix_23.cast() * v_3d; cout << result << endl; Eigen::Matrix result2 = matrix_23 * vd_3d; cout << result2 << endl; // 同样你不能搞错矩阵的维度 // 试着取消下面的注释,看看Eigen会报什么错 // Eigen::Matrix result_wrong_dimension = matrix_23.cast() * v_3d; // 一些矩阵运算 // 四则运算就不演示了,直接用+-*/即可。 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; // 行列式// 特征值 // 实对称矩阵可以保证对角化成功 Eigen::SelfAdjointEigenSolver 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的大小在前边的宏里定义,它由随机数生成 // 直接求逆自然是最直接的,但是求逆运算量大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 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; return 0; }

2.7 Eigen 矩阵化简
// Reductions. int r, c; // Eigen// Matlab R.minCoeff()// min(R(:))最小值 R.maxCoeff()// max(R(:))最大值 s = R.minCoeff(&r, &c)// [s, i] = min(R(:)); [r, c] = ind2sub(size(R), i); s = R.maxCoeff(&r, &c)// [s, i] = max(R(:)); [r, c] = ind2sub(size(R), i); R.sum()// sum(R(:))求和 R.colwise().sum()// sum(R)列求和1×N R.rowwise().sum()// sum(R, 2) or sum(R')'行求和N×1 R.prod()// prod(R(:))所有乘积 R.colwise().prod()// prod(R)列乘积 R.rowwise().prod()// prod(R, 2) or prod(R')'行乘积 R.trace()// trace(R)迹 R.all()// all(R(:))且运算 R.colwise().all()// all(R) 且运算 R.rowwise().all()// all(R, 2) 且运算 R.any()// any(R(:)) 或运算 R.colwise().any()// any(R) 或运算 R.rowwise().any()// any(R, 2) 或运算

2.8 Eigen 求解线性方程组 Ax = b
// Solve Ax = b. Result stored in x. Matlab: x = A \ b. x = A.ldlt().solve(b)); // #include LDLT分解法实际上是Cholesky分解法的改进 x = A.llt() .solve(b)); // A sym. p.d.#include x = A.lu().solve(b)); // Stable and fast. #include x = A.qr().solve(b)); // No pivoting.#include x = A.svd() .solve(b)); // Stable, slowest. #include // .ldlt() -> .matrixL() and .matrixD() // .llt()-> .matrixL() // .lu()-> .matrixL() and .matrixU() // .qr()-> .matrixQ() and .matrixR() // .svd()-> .matrixU(), .singularValues(), and .matrixV()

2.9 矩阵的特殊生成
// Eigen// Matlab MatrixXd::Identity(rows,cols)// eye(rows,cols) 单位矩阵 C.setIdentity(rows,cols)// C = eye(rows,cols) 单位矩阵 MatrixXd::Zero(rows,cols)// zeros(rows,cols) 零矩阵 C.setZero(rows,cols)// C = ones(rows,cols) 零矩阵 MatrixXd::Ones(rows,cols)// ones(rows,cols)全一矩阵 C.setOnes(rows,cols)// C = ones(rows,cols)全一矩阵 MatrixXd::Random(rows,cols)// rand(rows,cols)*2-1// 元素随机在-1->1 C.setRandom(rows,cols)// C = rand(rows,cols)*2-1 同上 VectorXd::LinSpaced(size,low,high)// linspace(low,high,size)'线性分布的数组 v.setLinSpaced(size,low,high)// v = linspace(low,high,size)'线性分布的数组

3.Eigen线性方程与矩阵分解
  • Eigen提供了解线性方程的计算方法,包括LU分解法,QR分解法,SVD(奇异值分解)、特征值分解等。其中第一部分介绍了各头文件所包含的内容。
  • 对于一般形式如下的线性系统:
    A x = b {Ax=b} Ax=b
  • 解决上述方程的方式一般是将矩阵A进行分解,当然最基本的方法是高斯消元法。
Eigen 官方给的一个案例:
#include #include using namespace std; using namespace Eigen; int main() { Matrix3f A; Vector3f b; A << 1,2,3, 4,5,6, 7,8,10; b << 3,3,4; cout<<"Here is the Matrix A:\n"<< A <

【Eigen使用总结】使用这些接口也可以解决矩阵相乘的问题:
#include #include using namespace std; using namespace Eigen; int main() { Matrix2f A,b; A << 2,-1,-1,3; b << 1,2,3,1; cout<<"Here is the matrix A:\n"<

Eigen也提供了计算特征值和特征向量的算法:
#include #include using namespace std; using namespace Eigen; int main() { Matrix2f A; A << 1,2,2,3; cout<<"Here is the matrix A:\n"< eigensolver(A); if( eigensolver.info() != Success ) abort(); cout<<" The eigenvalues of A are:\n"<

Eigen 也提供了求逆矩阵和求矩阵行列式的算法,但是这两种算法对于大型矩阵来说都是非常不经济的算法,当需要对大型矩阵做这种的操作时,需要自己判断到底需不需这样做。但是对于小型矩阵 则可以没有顾虑地使用。
#include #include using namespace std; using namespace Eigen; int main() { Matrix3f A; A << 1,2,1, 2,1,0, -1,1,2; cout<<"Here is the matrix A:\n"<

Eigen也提供了解最小二乘问题的解法,并给出两种实现,分别是BDCSVD和JacobiSVD,其中推荐使用的一种是BDCSVD。
#include #include using namespace std; using namespace Eigen; int main() { MatrixXf A = MatrixXf::Random(3,2); cout<<"Here is the matrix A:\n"<

    推荐阅读