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


致读者: 小时百科一直以来坚持所有内容免费无广告,这导致我们处于严重的亏损状态。 长此以往很可能会最终导致我们不得不选择大量广告以及内容付费等。 因此,我们请求广大读者热心打赏 ,使网站得以健康发展。 如果看到这条信息的每位读者能慷慨打赏 20 元,我们一周就能脱离亏损, 并在接下来的一年里向所有读者继续免费提供优质内容。 但遗憾的是只有不到 1% 的读者愿意捐款, 他们的付出帮助了 99% 的读者免费获取知识, 我们在此表示感谢。

                     

友情链接: 超理论坛 | ©小时科技 保留一切权利