Eigen 快速入门指南

Eigen Quick reference guide

模块和头文件

Eigen库分为一个核心模块和几个附加模块。每个模块都有一个相应的头文件,为了使用模块必须包含该头文件。提供了Dense和Eigen头文件,方便地同时访问多个模块。

模块

头文件

内容

Core

#include<Eigen/Core>

核心模块,Matrix 矩阵和 Array 数组类,基本线性代数(包括三角形和自伴随乘积),数组操作。

Geometry

#include<Eigen/Geometry>

几何模块,提供 Transform 变换、Translation 平移变换、缩放、Rotation2D 2D 旋转和3D rotations3D 旋转功能(使用Quaternion四元数和AngleAxis三轴旋转的方式)

LU

#include<Eigen/LU>

Inverse逆、行列式和 LU 分解的求解方法(FullPivLU, PartialPivLU)

Cholesky

#include<Eigen/Cholesky>

提供 LLTLDLT Cholesky 因式分解

Householder

#include<Eigen/Householder>

Householder 变换,这个模块被一些线性代数模块所使用

SVD

#include<Eigen/SVD>

SVD分解与最小二乘求解方法(JacobiSVD, BDCSVD)

QR

#include<Eigen/QR>

QR 分解求解方法(HouseholderQR, ColPivHouseHolderQR, FullPivHouseholderQR)

Eigenvalues

#include<Eigen/Eigenvalues>

特征值、特征向量分解(EigenSolver, SelfAdjointEigenSolver, ComplexEigenSolver)

Sparse

#include<Eigen/Sparse>

稀疏矩阵存储及相关的基本线性代数 (SparseMatrix, SparseVector

#include<Eigen/Dense>

包含CoreGeometryLUSVDQREigenvalues头文件

#include<Eigen/Eigen>

包含DenseSparse头文件,即整个Eigen库

数组(Array)、矩阵(Matrix)和向量(vector)类型

Eigen提供了两种密集对象:用模板类Matrix表示的数学矩阵和向量,以及用模板类Array表示的通用1D和2D数组:

typedef Matrix<Scalar, RowsAtCompileTime, ColsAtCompileTime, Options> MyMatrixType;
typedef Array<Scalar, RowsAtCompileTime, ColsAtCompileTime, Options> MyArrayType;
  • Scalar 是标量的系数类型如:floatdoubleintbool等。
  • RowsAtComileTImeColsAtCompileTime 表示矩阵的行列在编译时是否已知,或者是Dynamic 动态的
  • Options 可以是 ColMajorRowMajor 即列主序或行主序(存储时),默认是ColMajor

所有的组合都是允许的:您可以拥有一个具有固定行数和动态列数的矩阵等。以下都是有效的:

Matrix<double, 6, Dynamic>                  // 固定行数,动态列数(堆分配)
Matrix<double, Dynamic, 2>                  // 动态行数,固定列数
Matrix<double, Dynamic, Dynamic, RowMajor>  // 都是动态分配,行主序
Matrix<double, 13, 3>                       // 固定大小(一般在栈上分配)

在大多数情况下,您可以简单地为矩阵和数组使用一个方便的类型定义。如:

// Matrix
Matrix<float,Dynamic,Dynamic>   <=>   MatrixXf
Matrix<double,Dynamic,1>        <=>   VectorXd
Matrix<int,1,Dynamic>           <=>   RowVectorXi
Matrix<float,3,3>               <=>   Matrix3f
Matrix<float,4,1>               <=>   Vector4f

// Arrays
Array<float,Dynamic,Dynamic>    <=>   ArrayXXf
Array<double,Dynamic,1>         <=>   ArrayXd
Array<int,1,Dynamic>            <=>   RowArrayXi
Array<float,3,3>                <=>   Array33f
Array<float,4,1>                <=>   Array4f

在 Matrix 和 Array 之间转换:

Array44f a1, a2;
Matrix4f m1, m2;
m1 = a1 * a2;                     // 系数乘法,从数组到矩阵的隐式转换。
a1 = m1 * m2;                     // 矩阵乘法,从矩阵到数组的隐式转换。
a2 = a1 + m1.array();             // 混合使用 array 和 matrix 是禁止的
m2 = a1.matrix() + m1;            // 必须使用显式转换.
ArrayWrapper<Matrix4f> m1a(m1);   // m1a是m1.array()的别名,它们共享相同的系数
MatrixWrapper<Array44f> a1m(a1);

在本文档的其余部分中,我们将使用以下符号来强调特定对象的特征:

  • 线性代数矩阵和向量
  • 数组对象

矩阵基础操作

构造(默认情况下系数未初始化)

// 1D 对象
Vector4d v4;
Vector2f v1(x,y);
Array3i v2(x,y,z);
Vector4d v3(x,y,z,w);
VectorXf v5;

ArrayXf v6(size);

// 2D 对象
Matrix4f m1;
MatrixXf m5;
MatrixXf m6(nb_rows, nb_columns);

初始化操作(使用逗号运算符)

// simaple
Vector3f v1; 
v1 << x, y, z;

ArrayXf v2(4);
v2 << 1, 2, 3, 4;

Matrix3f m1;
m1 << 1,2,3,4,5,6,7,8,9;

// complex
int rows = 5, cols = 5;
MatrixXf m(rows, cols);
m << (Matrix3f() << 1,2,3,4,5,6,7,8,9>>).finished(),
  MatrixXf::Zero(3, cols-3),
  MatrixXf::Zero(rows-3, 3),
  MatrixXf::Identity(rows-3, cols-3);
// output
/*
1 2 3 0 0
4 5 6 0 0
7 8 9 0 0
0 0 0 1 0
0 0 0 0 1
*/

运行时信息

vector.size(); // 向量大小
matrix.size(); // 矩阵大小 cols x rows
matrix.rows(); // 矩阵行大小
matrix.cols(); // 矩阵列大小

编译时信息

ObjectType::Scalar // 系数类型
ObjectType::RealScalar 
ObjectType::Index

ObjectType::RowsAtCompileTime
ObjectType::ColsAtCompileTime
ObjectType::SizeAtCompileTime

改变矩阵、向量大小

// vector
vector.resize(size); // 改变大小后将丢失原始的数据
vector.resizeLike(other_vector);
vector.conservativeResize(size); // 改变大小后保留矩阵中的数据

// matrix
matrix.resize(nb_rows, nb_cols);
matrix.resize(Eigen::NoChange, nb_cols);
matrix.resize(nb_rows, Eigen::NoChange);
matrix.resizeLike(other_matrix);
matrix.conservativeResize(nb_rows, nb_cols);

访问运算符

// 包含范围检测,可在NDEBUG 和 EIGEN_NO_DEBUG 情况下disable
vector(i);
vector[i];
vector.x() <=> vector(0)
vector.y() <=> vector(1)
vector.z() <=> vector(2)
vector.w() <=> vector(3)

matrix(i, j);

// 取消范围检测
vector.coeff(i);
vector.coeffRef(i);
matrix.coeff(i, j);
matrix.coeffRef(i, j);

赋值或拷贝,会自动改变大小

VectorXd object(4);
object << 1, 2, 3, 4;
cout << "object: \n"
        << object << endl;
Vector3d expression = {5, 4, 3};

object = expression;
cout << "object: \n"
        << object << endl;

VectorXf object_of_float(4);
object_of_float << 1.2, 2.4, 4.5, 5.7;
cout << "object_of_float: \n"
        << object_of_float << endl;

Vector3d expression_of_double = {11.7, 7.8, 9.4};
object_of_float               = expression_of_double.cast<float>();
cout << "object_of_float: \n"
        << object_of_float << endl;

预定义矩阵

cout << "zero: \n"
         << Matrix3d::Zero() << endl;   // 0矩阵
    cout << "constant(1.2): \n"
         << Matrix3d::Constant(1.2) << endl;   // 全为1.2的矩阵
    cout << "random: \n"
         << Matrix3d::Random() << endl;   // 随机矩阵
    cout << "ones: \n"
         << Matrix3d::Ones() << endl;   // 全为1的矩阵
    cout << "linSpaced: \n"
         << Vector3d::LinSpaced(1.2, 5.6) << endl;   // 生成线性序列, Vector only

    cout << "zero: \n"
         << MatrixXd::Zero(3, 4) << endl;
    cout << "constant(1.2): \n"
         << MatrixXd::Constant(3, 4, 1.2) << endl;
    cout << "random: \n"
         << MatrixXd::Random(3, 4) << endl;
    cout << "ones: \n"
         << MatrixXd::Ones(4, 4) << endl;
    cout << "linSpaced: \n"
         << VectorXd::LinSpaced(3, 1.2, 5.6) << endl;   // 生成线性序列, Vector only

    cout << "identity: \n"
         << Matrix3d::Identity() << endl;   // 单位阵
    cout << "identity: \n"
         << MatrixXd::Identity(4, 3) << endl;
    cout << "unitx: \n"
         << Vector3f::UnitX() << endl; // 单位基向量
    cout << "unity: \n"
         << Vector3f::UnitY() << endl;
    cout << "unitZ: \n"
         << Vector3f::UnitZ() << endl;
    cout << "unit(4,1): \n"
         << VectorXd::Unit(4, 1) << endl;
    cout << "unit(4,2): \n"
         << VectorXd::Unit(4, 2) << endl;

映射到数组

// 连续内存的使用

    {
        float data[] = {1, 2, 3, 4};

        Map<Vector3f> v1(data);
        cout << "v1: \n"
             << v1 << endl;
        Map<ArrayXf> v2(data, 3);
        cout << "v2: \n"
             << v2 << endl;
        Map<Array22f> m1(data);
        cout << "m1: \n"
             << m1 << endl;
        Map<Matrix<float, Dynamic, Dynamic, RowMajor>> m2(data, 2, 2);   // 按行生成 m2
        cout << "m2: \n"
             << m2 << endl;
        cout << "m2(0,1): " << m2(0, 1) << endl;
    }

    // 步进式生成数据
    {
        float data[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};

        Map<VectorXf, 0, InnerStride<2>> v1(data, 3);                        // = [1,3,5]
        Map<VectorXf, 0, InnerStride<>>  v2(data, 3, InnerStride<>(3));      // = [1,4,7]
        Map<MatrixXf, 0, OuterStride<3>> m2(data, 2, 3);                     // both lines     |1,4,7|
        Map<MatrixXf, 0, OuterStride<>>  m1(data, 2, 3, OuterStride<>(3));   // are equal to:  |2,5,8|

        cout << "v1: \n"
             << v1 << endl;
        cout << "v2: \n"
             << v2 << endl;
        cout << "m2: \n"
             << m2 << endl;
        cout << "m1: \n"
             << m1 << endl;
    }

算术运算

Matrix3i m1;
    m1 << 1, 2, 3, 4, 5, 6, 7, 8, 9;
    cout << m1 << endl;
    Matrix3i m2;
    m2 << 2, 3, 4, 5, 6, 7, 8, 9, 10;
    cout << m2 << endl;

    Vector3i v1;
    v1 << 1, 2, 3;

    auto v2 = v1.transpose();

    cout << "m1 + m2: \n"
         << m1 + m2 << endl;
    cout << "m1 - m2: \n"
         << m1 - m2 << endl;

    cout << "m1 * 3: \n"
         << m1 * 3 << endl;
    cout << "m1 / 2: \n"
         << m1 / 2 << endl;

    cout << "m1 * m2: \n"
         << m1 * m2 << endl;

    cout << "m1 * v1: \n"
         << m1 * v1 << endl;
    cout << "v2 * m1: \n"
         << v2 * m1 << endl;

    Matrix2cd m3 = Matrix2cd::Random();
    cout << "m3(2x2): \n"
         << m3 << endl;
    cout << "m3^T(2x2): \n"
         << m3.transpose() << endl;
    cout << "m3(2x2) 复共轭转置: \n"
         << m3.adjoint() << endl;

    Vector3i v3 = Vector3i::LinSpaced(3, 5);
    cout << "v3: \n"
         << v3 << endl;
    cout << "v1.dot(v3): " << v1.dot(v3);   // 点乘
    cout << "v3.dot(v1): " << v3.dot(v1);   // 点乘
    cout << "v1 * v3^T: \n"
         << v1 * v3.transpose() << endl;
    cout << "v3 2-范: \n"
         << v3.norm() << endl;
    cout << "v3 1-范: \n"
         << v3.lpNorm<1>() << endl;
    cout << "v3 2-范: \n"
         << v3.lpNorm<2>() << endl;
    cout << "v3 无穷范: \n"
         << v3.lpNorm<Eigen::Infinity>() << endl;
    cout << "v3 2-范的平方: \n"
         << v3.squaredNorm() << endl;
    cout << "v3 normalized: \n"
         << v3.normalized() << endl;
    cout << "v1 和 v3 的叉乘: \n"
         << v1.cross(v3) << endl;

    Vector3cf c1 = Vector3cf::Random();
    cout << "c1: \n"
         << c1 << endl;
    Vector3cf c2 = Vector3cf::Random();
    cout << "c2: \n"
         << c2 << endl;

    cout << "c1^H * c2: " << c1.adjoint() * c2 << endl;
    cout << "c1^H * c2(value): " << (c1.adjoint() * c2).value() << endl;

按系数的数组运算

// 按系数进行运算的函数只能使用在Array上
    Array2d a1(2, 5);
    cout << "a1: \n"
         << a1 << endl;
    Array2d a2(3, 4);
    cout << "a2: \n"
         << a2 << endl;
    // 数组元素之间进行标量运算, 需要维度一致
    cout << "a1 + a2: \n"
         << a1 + a2 << endl;
    cout << "a1 - a2: \n"
         << a1 - a2 << endl;
    cout << "a1 * a2: \n"
         << a1 * a2 << endl;
    cout << "a1 / a2: \n"
         << a1 / a2 << endl;
    cout << "a1 < a2: \n"
         << (a1 < a2) << endl;

    // 获取 a1 和 a2 中相同位置下的最小值或最大值
    cout << "a1.min(a2): \n"
         << a1.min(a2) << endl;
    cout << "a1.max(a2): \n"
         << a1.max(a2) << endl;
    // 小于 2 的都保留,大于2的都设为2
    cout << "a1.min(2): \n"
         << a1.min(2) << endl;
    // 大于 2 的都保留,小于2的都设为2
    cout << "a1.max(2): \n"
         << a1.max(2) << endl;

    Matrix2d m1;
    m1 << 1, 2, 3, 4;
    cout << "m1: \n"
         << m1 << endl;
    Matrix2d m2;
    m2 << 4, 6, 8, 4;
    cout << "m2: \n"
         << m2 << endl;

    cout << "将矩阵转换为向量后元素对应相乘 m1 * m2:\n"
         << m1.array() * m2.array() << endl;
    cout << "a1.sqrt(): \n"
         << a1.sqrt() << endl;
    cout << "sqrt(a1): \n"
         << sqrt(a1) << endl;
    cout << "a1 各系数的平方: \n"
         << a1.square() << endl;
    cout << "a1 各系数的立方: \n"
         << a1.cube() << endl;
    cout << "a1 各系数的倒数: \n"
         << a1.inverse() << endl;

    cout << "sin(a1): \n"
         << sin(a1) << endl;
    Array2cd a3;
    a3 << std::complex<double> {1, 2}, std::complex<double>(3, 4);
    cout << "arg(a3): \n"   // 复数
         << arg(a3) << endl;

    cout << "a1.isFinite: \n"
         << a1.isFinite() << endl;
    cout << "a1.isInf: \n"
         << a1.isInf() << endl;
    cout << "a1.isNaN: \n"
         << a1.isNaN() << endl;

    Matrix2cd m3 = Matrix2cd::Random();

    cout << "m3 :\n"
         << m3 << endl;
    cout << "m3 的实部:\n"
         << m3.real() << endl;
    cout << "m3 的虚部:\n"
         << m3.imag() << endl;
    cout << "m3 的共轭复数: \n"
         << m3.conjugate() << endl;

    // 使用 cwise 开头的函数可以在 Matrix 和 Vector 上使用按系数运算的函数