描述

使用C++语言的Eigen库进行一些常见操作

使用库时,请一定注意两点

  1. 定义清楚矩阵类型
  2. 矩阵乘法注意尺寸对应

代码

头文件声明

#include <Eigen/Dense>

1. 矩阵声明

  • n*n方阵(已知n)

  • Eigen::Matrix2d m_matrix;
    m_matrix<< 2,3,2.2,1;
    std::cout << "m_matrix = \n"<< m_matrix<std::endl;
    
  • 注意矩阵里的值有2.2这个浮点型,因此定义Eigen::Matrix2i会出现问题(Matrix2i代表整数)

  • m*n方阵(已知m和n)

Eigen::MatrixXd xx(5,2);
xx << 2,3,2.2,1,2,3,2,1,2,3;

零矩阵

Eigen::MatrixXf m_matrix = Eigen::MatrixXf::Zero(5,5);
Eigen::MatrixXf m_matrix = Eigen::MatrixXf::Zero(5,2);

对角矩阵

Eigen::MatrixXf m_matrix = Eigen::MatrixXf::Identity(5,5);
Eigen::MatrixXf m_matrix = Eigen::MatrixXf::Identity(2,5);

2. 矩阵的大小

int cols = m_matrix.cols();
int rows = m_matrix.rows();
std::cout<<cols<<std::endl;
std::cout<<rows<<std::endl;

3. 矩阵常见操作

  • 操作矩阵元素
m_matrix(1,1) = 2;

乘法

m_matrix = A * B;
  • 矩阵A和矩阵B,应该满足 mn尺寸与nk尺寸,矩阵m_matrix的尺寸应为m*k
  • 矩阵赋值
A = B; 

    矩阵A和矩阵B需要尺寸一致

4. 矩阵绝对值和最大元素

矩阵里的每个元素求绝对值
eigen中矩阵是无法直接对矩阵操作,让每个元素都求绝对值的。
但是可以通过转化为Array类型来操作。

    matrix转为array: .array()
    array转为matrix:.matrix()
    求绝对值

Eigen::MatrixXf x;
Eigen::ArrayXXf x_abs = x.array().abs();

求矩阵绝对值后的最大元素

Eigen::MatrixXf x;
Eigen::ArrayXXf x_abs = x.array().abs();
float max_value = x_abs.maxCoeff();

5. 矩阵转置和矩阵求逆

  • 转置
Eigen::MatrixXf m_matrix;
Eigen::MatrixXf m_matrix_T;
m_matrix_T = m_matrix.transpose();

逆矩阵

Eigen::MatrixXf m_matrix;
Eigen::MatrixXf m_matrix_inv;
m_matrix_inv = m_matrix.inverse();

6. 矩阵的特征值和特征向量

  • 特征值

Eigen::Matrix2d m_matrix;
m_matrix << 2,3,2.2,1;
Eigen::EigenSolver<Eigen::Matrix2d> eigen_solver ( m_matrix );
Eigen::MatrixXd eig_value = eigen_solver.pseudoEigenvalueMatrix();
std::cout << "matrix values = \n" <<eig_value<<std::endl;

输出为2*2的对角矩阵,对角线上的值就是特征值,也就是4.11725和-1.11725

matrix values = 
4.11725        0
   	  0 -1.11725

特征向量

Eigen::Matrix2d m_matrix;
m_matrix << 2,3,2.2,1;
Eigen::EigenSolver<Eigen::Matrix2d> eigen_solver ( m_matrix );
Eigen::MatrixXd eig_vector = eigen_solver.pseudoEigenvectors();
std::cout << "matrix vectors = \n" <<eig_vector<<std::endl;
std::cout << "matrix vectors(1,0) = \n" <<eig_vector(1,0)<<std::endl;

输出是

matrix vectors = 
0.817019 -0.701478
0.576611  0.728894
matrix vectors(1,0) = 
0.576611

特征值与特征向量的使用

我们都知道特征值和特征向量是成对出现的。他们能形成关系:

我们有一个矩阵A,其特征值λ 和 特征向量 v 的关系是
A * V = λ * v

可以用代码验证,还是用之前的矩阵

// 取出全部的特征值
Eigen::MatrixXd new_value = Eigen::MatrixXd::Zero(rows,1);
for (int i = 0 ; i < rows; i++)
{
    new_value(i,0) = eig_value(i,i);
}
std::cout<<new_value<<std::endl;
// 取出对应第一个特征值的特征向量
Eigen::MatrixXd new_vector = Eigen::MatrixXd::Zero(rows,1);
for (int i = 0 ; i < rows; i++)
{
    new_vector(i,0) = eig_vector(i,0);
}
std::cout<<new_vector<<std::endl;

// 观察第一个特征值和其对应特征向量的乘积
std::cout<<"A * V = \n"<<m_matrix*new_vector<<std::endl;
std::cout<<"lambda * V= \n"<<new_value(0,0)*new_vector<<std::endl;

结果是

// 特征值,就是特征值矩阵的对角元素
4.11725
-1.11725
// 第一个特征值的特征向量,就是特征向量矩阵的第一列
0.817019
0.576611
// 我们发现结果是相同的
A * V = 
3.36387
2.37405
lambda * V= 
3.36387
2.37405

只是能输出(代码里怎么可能只是想打印一下呢,所以请你只看第一条)

Eigen::Matrix2d m_matrix;
m_matrix << 2,3,2.2,1;
Eigen::EigenSolver<Eigen::Matrix2d> eigen_solver ( m_matrix );
std::cout << "matrix values = \n" << eigen_solver.eigenvalues() << std::endl;
std::cout << "matrix vectors = \n" << eigen_solver.eigenvectors() << std::endl;

输出为

matrix values = 
 (4.11725,0)
(-1.11725,0)
matrix vectors = 
 (0.817019,0) (-0.693426,0)
 (0.576611,0)  (0.720528,0)

调试经验

在使用Eigen库的时候,总是会出现一些错误,主要长成下面这样,或者一些没有提示错误位置的bug

static_assert failed due to requirement
      'Eigen::internal::has_ReturnType<ScalarBinaryOpTraits<typename
      ActualDstTypeCleaned::Scalar, typename
      CwiseNullaryOp<scalar_constant_op<float>, Matrix<float, -1, -1, 0, -1, -1>
      >::Scalar, assign_op<double, float> > >::value'
      "YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY"
  EIGEN_CHECK_BINARY_COMPATIBILIY(Func,typename ActualDstTypeCleaned::Scalar,typename Src::Scalar);
  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/Users/admin/Desktop/CodeBase/c++_try/Eigen/src/Core/util/XprHelper.h:859:3: note: 
      expanded from macro 'EIGEN_CHECK_BINARY_COMPATIBILIY'
  EIGEN_STATIC_ASSERT((Eigen::internal::has_ReturnType<ScalarBinaryOpTraits<LHS, RHS,BINOP> >::value), \
  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/Users/admin/Desktop/CodeBase/c++_try/Eigen/src/Core/util/StaticAssert.h:33:40: note: 
      expanded from macro 'EIGEN_STATIC_ASSERT'
    #define EIGEN_STATIC_ASSERT(X,MSG) static_assert(X,#MSG);
                                       ^             ~
/Users/admin/Desktop/CodeBase/c++_try/Eigen/src/Core/PlainObjectBase.h:797:17: note: 
      in instantiation of function template specialization
      'Eigen::internal::call_assignment_no_alias<Eigen::Matrix<double, -1, -1,
      0, -1, -1>,
      Eigen::CwiseNullaryOp<Eigen::internal::scalar_constant_op<float>,
      Eigen::Matrix<float, -1, -1, 0, -1, -1> >,
      Eigen::internal::assign_op<double, float> >' requested here
      internal::call_assignment_no_alias(this->derived(), other.derived(...
                ^
/Users/admin/Desktop/CodeBase/c++_try/Eigen/src/Core/PlainObjectBase.h:602:7: note: 
      in instantiation of function template specialization
      'Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1>
      >::_set_noalias<Eigen::CwiseNullaryOp<Eigen::internal::scalar_constant_op<float>,
      Eigen::Matrix<float, -1, -1, 0, -1, -1> > >' requested here
      _set_noalias(other);
      ^
/Users/admin/Desktop/CodeBase/c++_try/Eigen/src/Core/Matrix.h:423:9: note: in
      instantiation of function template specialization
      'Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1>
      >::PlainObjectBase<Eigen::CwiseNullaryOp<Eigen::internal::scalar_constant_op<float>,
      Eigen::Matrix<float, -1, -1, 0, -1, -1> > >' requested here
      : Base(other.derived())
        ^
/Users/admin/Desktop/CodeBase/c++_try/1.cpp:100:33: note: in instantiation of
      function template specialization 'Eigen::Matrix<double, -1, -1, 0, -1,
      -1>::Matrix<Eigen::CwiseNullaryOp<Eigen::internal::scalar_constant_op<float>,
      Eigen::Matrix<float, -1, -1, 0, -1, -1> > >' requested here
    Eigen::MatrixXd new_value = Eigen::MatrixXf::Zero(rows,1);
                                ^
1 error generated.
make[2]: *** [CMakeFiles/s.dir/1.o] Error 1
make[1]: *** [CMakeFiles/s.dir/all] Error 2
make: *** [all] Error 2

出现过很多次,每次的解决办法都是
要么我写错了矩阵的类型,类型A赋值给了类型B;要么就是矩阵乘法的尺寸不对应。
这都是低级的错误。
附录

    几种声明类型
    Matrix:
    Matrix2cd:
    Matrix2cf:
    Matrix2d:
    Matrix2f:
    Matrix2i:
    Matrix2Xcd:
    Matrix2Xcf:
    Matrix2Xd:
    Matrix2Xf:
    Matrix2Xi:

    将2替换成3、4、X,会有相同的声明类型

没有深研究,简单来说,数字代表nn方阵的大小,‘X’代表这个矩阵不是方阵,是一个mn的矩阵,‘d’代表double,‘f’代表float, ‘i’代表整数,‘c’代表complex,即复数;’d’表示dynamic,即表示矩阵中有些维数是不确定的,动态的……

举例子比如说:Matrix2cd,表示的是2*2维的,其每个元素都是复数,复数的实部和虚部都为double类型。