Eigen (C++ 线性代数库)笔记

                     

贡献者: addis

1. 安装

   Eigen 的主页

  1. 首先下载 Eigen, 只有头文件,不需要任何安装。(如果要做一些跑分等则需要编译自带的测试程序)
  2. 把解压后的文件夹加入 include 路径。
  3. 在使用 Eigen 的代码中加入 #include <Eigen/Dense> 等头文件即可。
  4. 当然也可以直接 apt install libeigen3-dev

2. 基础

// 矩阵
// 第一个维度固定在 3, 第二个维度可以动态变化
Matrix<double, 3, Dynamic> A;
// 两个动态维度, Aligned 可以把起始地址 padding 到一个 2^n 的整数倍的地址
// 以满足 SIMD 优化需求, 默认开启。 RowMajor 是行主序矩阵,默认是 ColMajor
Matrix<double, Dynamic, Dynamic, Aligned | RowMajor> A 
typedef Matrix<int, 4, 4> Matrix4i;
typedef Matrix<double, 4, 4> Matrix4d;
typedef Matrix<double, Dynamic, Dynamic> MatrixXd;
typedef Matrix<double, Dynamic, 1> VectorXd; // 矢量区分行和列
typedef Matrix<double, 1, Dynamic> RowVectorXd;

// declaration & initialization
MatrixXd a(10, 15); // No initialization
a.setRandom(m,n); // 随机赋值
a.setZero(); 把矩阵赋值为 0;
a.setZero(m,n); 把矩阵赋值为 m*n 的 0 矩阵;

   以下函数用法类似 setOnes(); setConstant(); setIdentity();(单位矩阵) setRandom(); setLinSpaced();(等间距赋值) 注意其中 setConstant() 输入 1 个变量时与 fill() 功能相同,输入 3 个变量时最后一个为常数。setLinSpaced(size, val1, val2) 只能对 Vector 或者 RowVector 使用。如果想赋值给 MatrixXd, 可以用 MatrixXd a = VectorXd::LinSpaced(3, 3, 4); 对于整型,setLinSpaced 不保证最后一个值等于 val2, 而是保证间隔相等。这时候只能先生成 Xd, 然后 .cast<int>. * 逗号赋值都是 RowMaor 的,无论 a 是什么 major. a << 1,2,3,4;

3. operations

   获取信息

逐个矩阵元的运算

Aliasing

   如果矩阵同时出现在等号两边,就有可能出现 Aliasing. 例如 MatrixXi mat(3,3); mat.bottomRightCorner(2,2) = mat.topLeftCorner(2,2); 这时,要在等号右边的加上 .eval(). 特殊地,对于转置等,可以直接用 mat = mat.transposeInPlace(). 类似地有 adjointInPlace().

SVD (支持 complex)

   要用 SVD, 要 #include<Eigen/SVD>, 例程:

MatrixXd  A(3,3), U, V, X;
A << 1, 2, 3, 4, 5, 6, 7, 8, 9;
BDCSVD<MatrixXd> svd(A, ComputeThinU | ComputeThinV);
U = svd.matrixU(); V = svd.matrixV(); X = svd.singularValues();

4. 外部接口

   这里介绍如何直接操作 Matrix<> 底层的数据,以及如何将内存中已有的数据直接给 Eigen 使用而无需复制。

访问底层数据

使用内存数据

5. 其他标量类型

   Eigen 使用模板变成的巨大优势就是可以使用自定义标量类型。代码已经默认支持 float,double,long double 以及对应的复数。要让矩阵元支持其他类型(如 g++ 的 __float128,甚至 GMP 的任意精度类型),只需要告诉 Eigen 新增标量的特性即可:

namespace Eigen {
template<> struct NumTraits<Qdoub> : GenericNumTraits<Qdoub>
{
    typedef Qdoub Real;
    typedef Qdoub NonInteger;
    typedef Qdoub Nested;
    static inline Real epsilon() { return FLT128_EPSILON; }
    static inline Real dummy_precision() { return 0; }
    static inline int digits10() { return FLT128_DIG; }
    enum {
        IsInteger = 0,
        IsSigned = 1,
        IsComplex = 0,
        RequireInitialization = 0,
        ReadCost = 2,
        AddCost = 2,
        MulCost = 6
    };
};

template<> struct NumTraits<Qcomp> : GenericNumTraits<Qcomp>
{
    typedef Qdoub Real;
    typedef Qdoub NonInteger;
    typedef Qdoub Nested;
    static inline Real epsilon() { return FLT128_EPSILON; }
    static inline Real dummy_precision() { return 0; }
    static inline int digits10() { return FLT128_DIG; }
    enum {
        IsInteger = 0,
        IsSigned = 0,
        IsComplex = 1,
        RequireInitialization = 0,
        ReadCost = 4,
        AddCost = 4,
        MulCost = 12
    };
};
typedef Matrix<Qdoub, Dynamic, Dynamic> MatrixXq;
typedef Matrix<Qcomp, Dynamic, Dynamic> MatrixXqc;
typedef Matrix<Qdoub, Dynamic, 1> VectorXq;
typedef Matrix<Qcomp, Dynamic, 1> VectorXqc;
} // namespace Eigen

6. 稀疏矩阵(Sparse Matrix)

   参考:稀疏矩阵文档主页SparseMatrix 类文档解稀疏线性方程文档

   Eigen::SparseMatrix<Scalar_, Options_, StorageIndex_> 模板中,Scalar_ 是矩阵元的类型,Options_ 只能是 Eigen::ColMajorEigen::RowMajor,默认是 ColMajorStorageIndex_ 是内部数组的 index 的类型,必须是有符号整数,默认 int。注意这不是成员函数中行标和列表的 index 类型(Eigen::Index)。

   除非特殊说明,我们下面都以 RowMajor 为例。

内部结构

常用成员函数

解线性方程组

  

未完成:见 SLISC/tests/eigen.cpp

                     

© 小时科技 保留一切权利