Eigen快速入门-程序员宅基地

技术标签: 算法  c++  矩阵  线性代数  开发语言  

Eigen的下载安装不说了,这个很简单,不懂的查一下就好了。

1. 矩阵类

1.1 矩阵的前三个模板参数

在Eigen中,所有矩阵和向量都是矩阵模板类的对象。向量只是矩阵的一种特殊情况,有1行或1列。

Matrix类共有六个模板参数,这里只介绍前三个参数,剩下的三个参数有其默认值,我们不需要更改。矩阵的三个强制性模板参数是:

Matrix<typename Scalar, int RowsAtCompileTime, int ColsAtCompileTime>
  • Scalar是scalar类型,如想要构造一个单精度的浮点类型矩阵,可以选择float。所有支持的scalar类型参见Scalar types。
  • RowsAtCompileTimeColsAtCompleTime是在编译时已知的矩阵的行数和列数

Eigen提供了许多方便的typedef来涵盖常见的情况。例如,Matrix4f是浮点的4x4矩阵。以下是Eigen对它的定义:

typedef Matrix<float, 4, 4> Matrix4f;
1.2 向量

在Eigen中,向量只是矩阵的一种特殊情况,具有1行或1列。它们有1列的情况是最常见的;这样的矢量称为列矢量,通常简称为矢量。在它们有1行的另一种情况下,它们被称为行向量。

// 包含3个浮点的(列)向量
typedef Matrix<float, 3, 1> Vector3f;
// 包含2个的整数(行)向量
typedef Matrix<int, 1, 2> RowVector2i;
1.3 特殊值Dynamic

Eigen并不局限于在编译时维数已知的矩阵。RowsAtCompileTimeColsAtCompleTime模板参数可以采用特殊值Dynamic,该值表示在编译时大小未知,因此必须作为运行时变量处理。在特征术语中,这种大小被称为动态大小(dynamic size);而在编译时已知的大小被称为固定大小(fixed size)。

// 创建一个双精度的动态矩阵
typedef Matrix<double, Dynamic, Dynamic> MatrixXd;
// 创建一个整型列向量
typedef Matrix<int, Dynamic, 1> VectorXi;
// 创建拥有固定数量的行和动态数量的列的矩阵
Matrix<float, 3, Dynamic>
1.4 矩阵初始化与访问

Eigen提供了默认的构造函数,他不会提供动态内存的分配,也不会初始化任何矩阵的值。Eigen类型可以这样使用:

// 一个3 * 3 的矩阵,矩阵的元素都没有被初始化
Matrix3f a;
// 一个动态矩阵,大小是0 * 0,也就是说还没有为该矩阵分配内存
MatrixXf b;

构造函数提供指定矩阵大小的重载。对于矩阵,总是先传递行数。对于向量,只需传递向量大小。它会分配矩阵或向量所需内存的大小,但是不会初始化他们的值。

// 初始化一个10 * 15的矩阵,内存进行分配,但是没有初始化
MatrixXf a(10,15);
// 初始化一个大小为30的向量,但是没有初始化
VectorXf b(30);

Eigen使用圆括号()访问矩阵或者向量的元素,序号从0开始。

Eigen不支持使用方括号[]访问矩阵的元素(向量除外)。

// 矩阵不可以使用方括号进行初始化
// 例如m[0, 0] = 3;
// 这是不合法的
MatrixXd m(2, 2);
m(0, 0) = 3;

// 使用圆括号或方括号进行初始化向量都是合法的
VectorXd b(3);
b(0) = 1;
b[1] = 2;

矩阵和向量也可以从系数列表中初始化。

在 C++11 之前,此功能仅限于小型固定大小的列或大小不超过 4 的向量:

Vector2d a(5.0, 6.0);
Vector3d b(5.0, 6.0, 7.0);
Vector4d c(5.0, 6.0, 7.0, 8.0);

如果启用C++11,则可以通过传递任意数量的系数来初始化任意大小的固定大小的列或行向量:

Vector2i a(1, 2);
Matrix<int, 5, 1> b {1, 2, 3, 4, 5};
Matrix<int, 1, 5> c = {1, 2, 3, 4, 5};

在具有固定或运行时大小的矩阵和向量的一般情况下,系数必须按行分组,并作为初始化器列表的初始化器列表传递

MatrixXi a {      // 构造一个 2x2 矩阵
      {1, 2},     // 第一行
      {3, 4}      // 第二行
};
Matrix<double, 2, 3> b {
      {2, 3, 4},
      {5, 6, 7},
};

对于列或行向量,允许隐式换位。这意味着可以从一行初始化列向量:

VectorXd a {
   {1.5, 2.5, 3.5}};             // 具有 3 个系数的列向量
RowVectorXd b {
   {1.0, 2.0, 3.0, 4.0}};     // 具有 4 个系数的行向量

逗号表达式初始化:

Matrix3f m;
m << 1, 2, 3,
     4, 5, 6,
     7, 8, 9;
std::cout << m;
1.5 调整大小

矩阵的当前大小可以通过rows()cols()size()来检索。这些方法分别返回行数、列数和矩阵元素数。

通过resize()方法重置矩阵的大小,如果矩阵大小没有变化,那么resize()操作没有任何影响。如果矩阵的大小改变了,那么resize()操作没有任何影响。如果矩阵的大小改变了,那么矩阵的值可能会改变。如果你想在重设大小过程中不改变矩阵的值使用conservativeResize()

使用赋值符号“=”,Eigen自动调整左侧矩阵的大小,使其与右侧矩阵的大小相匹配。

当然,如果左侧是固定大小的,则不允许调整其大小。

1.6 矩阵和向量运算

**加减法:**重载C++中“+”“-”“+=”“-=”操作符,要求左右操作数的相同。不允许一个向量加上或者减去一个数。只要维度一样,向量和矩阵是可I加的,这也说明了向量是特殊的矩阵。

如果需要实现矩阵中的每一个元素都加/减同一个元素的操作,在Eigen中是不可以用矩阵直接加/减一个数的。我们需要用array()将矩阵转换为数组然后在加/减数字。【详见第二部分,数组类章节】

MatrixXd m(3, 5);
m.setZero();
m = m.array() + 5;

**数乘与数除:**重载C++中“\*”“/”“*=”“/=”操作符,支持矩阵和向量乘以或者除以一个数。

如果我们并不希望两矩阵按照矩阵乘法的形式相乘,而是希望对应位置的元素相乘,则我们需要用array()将矩阵转换为数组然后再进行乘法操作。【详见第二部分,数组类章节】

Vector3i m;
Vector3i n;
m << 1, 2, 3;
n = m;
m = m.array() * n.array();
cout << m << endl;

**转置、共轭、共轭转置、逆矩阵:**转置、共轭、共轭转置和求逆分别通过transpose() conjugate()adjoint()inverse()实现。对于实数而言,共轭没有任何影响,共轭转置等价于转置。

MatrixXcf a = MatrixXcf::Random(2, 2);
cout << "矩阵 a\n     " << a << endl;
cout << "转置 a^T\n   " << a.transpose() << endl;
cout << "共轭 a\n     " << a.conjugate() << endl;
cout << "共轭转置 a^*\n" << a.adjoint() << endl;
cout << "逆矩阵 a^-1\n " << a.inverse() << endl;
// 如果矩阵不可逆,会返回无穷值,已经不能再进行计算了

使用a=a.transpose()可能会出现错误,这是因为Eigen在进行转置或者共轭操作时,会同时写左操作数,从而得到意想不到的结果。要实现这种功能可以使用a.transposeInPlace()。类似的,也支持adjointInPlace()

Matrix2i a; a << 1, 2, 3, 4;
cout << "矩阵 a:\n" << a << endl;
 
a = a.transpose(); // !!! 不可以这么做 !!!
cout << "混叠效应的结果:\n" << a << endl;
MatrixXf a(2,3); a << 1, 2, 3, 4, 5, 6;
cout << "矩阵 a:\n" << a << endl;
a.transposeInPlace();
cout << "转置后:\n" << a << endl;

**点乘和叉乘:**点乘又可称为内积,Eigen分别使用dot()cross()来实现内积和向量积。叉乘只适用于三维向量。

Vector3d v(1, 2, 3);
Vector3d w(0, 1, 2);

std::cout << "点乘: " << v.dot(w) << std::endl;
std::cout << "叉乘:\n" << v.cross(w) << std::endl;

基础的代数运算:

  • **sum():**计算所有矩阵元素的和
  • **pro():**计算所有矩阵元素的连乘积
  • **mean():**计算所有矩阵元素的平均值
  • **minCoeff():**计算所有矩阵元素的最小值
  • **maxCoeff():**计算所有矩阵元素的最大值
  • **trace():**计算所有矩阵的迹
#include <iostream>
#include <Eigen/Dense>
 
using namespace std;
int main()
{
  Eigen::Matrix2d mat;
  mat << 1, 2,
         3, 4;
  cout << "求和:   " << mat.sum()       << endl;
  cout << "连乘积: " << mat.prod()      << endl;
  cout << "平均值: " << mat.mean()      << endl;
  cout << "最小值: " << mat.minCoeff()  << endl;
  cout << "最大值: " << mat.maxCoeff()  << endl;
  cout << "迹:    "  << mat.trace()     << endl;
}

计算最大值和最小值的函数支持返回最大值和最小值的位置。

Matrix3f m = Matrix3f::Random();
std::ptrdiff_t i, j;
float minOfM = m.minCoeff(&i, &j);
cout << "矩阵 m:\n" << m << endl;
cout << "最小元素 (" << minOfM
	<< ") 在下标处 (" << i << "," << j << ")\n\n";

RowVector4i v = RowVector4i::Random();
int maxOfV = v.maxCoeff(&i);
cout << "向量 v: " << v << endl;
cout << "最大元素 (" << maxOfV
	<< ") 在下标处 " << i << endl;

2. 数组类

Array类提供通用数组,而Matrix类用于线性代数。此外,Array类提供了一种执行按系数运算的简单方法,这种运算不具有线性代数意义,例如向Array中的每个系数添加一个常数或按系数乘以两个数组。

Array是一个类模板,采用与Matrix相同的模板参数。与Matrix一样,前三个模板参数是强制性的:

Array<typename Scalar, int RowsAtCompileTime, int ColsAtCompileTime>

参数的含义和上面Matrix相同,所以不多解释。

Eigen 还为一些常见情况提供了 typedef,其方式类似于矩阵typedef,但有一些细微差别,因为“数组”一词用于一维和二维数组。 我们采用 ArrayNt 形式的typedef代表一维数组的约定,其中 N 和 t 是大小和标量类型, 对于二维数组,使用 ArrayNNt 形式的类型定义。 下表显示了一些示例:

Type Typedef
Array<float,Dynamic,1> ArrayXf
Array<float,3,1> Array3f
Array<double,Dynamic,Dynamic> ArrayXXd
Array<double,3,3> Array33d

访问 Array 中的值的方式和 Matrix 是一样的。下面介绍和 Matrix 不一样的操作:

**加减乘除:**将对应位置元素相加(减、乘、除)。

**平方根、绝对值:**调用 sqrt()abs()

求两个矩阵的最小值:a.min(b),要求 a 和 b 的维度相同,求对应位置的两个 数的最小值。

那么,如何选择 Matrix 和 Array 呢? 不能对数组应用矩阵运算,也不能对矩阵应用数组运算。因此,如果你需要做线性代数运算,比如矩阵乘法,那么你应该使用矩阵;如果需要进行系数运算,那么应该使用数组。如果又要支持线性代数操作,又要支持数运算操作,那么就可以使用.array().matrix()实现类型的转换,这种转换是没有计算代价的。这些操作也不会改变调用该函数的矩阵或者数组本身,而是返回一个副本。

#include <Eigen/Dense>
#include <iostream>
using Eigen::MatrixXf;
int main()
{
  MatrixXf m(2,2);
  MatrixXf n(2,2);
  MatrixXf result(2,2);
 
  m << 1,2,
       3,4;
  n << 5,6,
       7,8;
 
  result = m * n;
  std::cout << "-- Matrix m*n: --\n" << result << "\n\n";
  result = m.array() * n.array();
  std::cout << "-- Array m*n: --\n" << result << "\n\n";
  result = m.cwiseProduct(n);
  std::cout << "-- With cwiseProduct: --\n" << result << "\n\n";
  result = m.array() + 4;
  std::cout << "-- Array m + 4: --\n" << result << "\n\n";
}

/* 
	
-- Matrix m*n: --
19 22
43 50

-- Array m*n: --
 5 12
21 32

-- With cwiseProduct: --
 5 12
21 32

-- Array m + 4: --
5 6
7 8

*/

Eigen 支持的数组元操作见下图所示。

数组元支持的操作

3. 块操作

块是矩阵或数组的矩形部分。块表达式既可以用作右值,也可以用作左值。与Eigen表达式一样,只要让编译器进行优化,这种抽象的运行时成本为零。

最常用的是 block()操作,它有两个版本:

// 动态大小的块
matrix.block(i,j,p,q);  
// 固定大小的块
matrix.block<p,q>(i,j);  

i、j 表示块的起始位置(块的左上角元素在矩阵中的角标),p、q 表示块的大小。 固定大小的块在运行时效率要高。

Eigen::MatrixXf m(4, 4);
m << 1, 2, 3, 4,
    5, 6, 7, 8,
    9, 10, 11, 12,
    13, 14, 15, 16;
cout << "中间的块:" << endl;
cout << m.block<2, 2>(1, 1) << endl << endl;
for (int i = 1; i <= 3; ++i)
{
    cout << "块的大小: " << i << "x" << i << endl;
    cout << m.block(0, 0, i, i) << endl << endl;
}

/*
中间的块:
 6  7
10 11

块的大小: 1x1
1

块的大小: 2x2
1 2
5 6

块的大小: 3x3
 1  2  3
 5  6  7
 9 10 11
 */

block()操作支持任意的块操作,对于一些特殊的访问 Eigen 也提供了 API。

ith row * matrix.row(i);
jth column * matrix.col(j);

col()row()的参数是要访问的列或行的索引,col()row()操作既可以是左值又可以是右值。

矩阵支持的块操作:

image-20230612013248560

向量支持的块操作:

image-20230612013348616

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_44494578/article/details/131160761

智能推荐

稀疏编码的数学基础与理论分析-程序员宅基地

文章浏览阅读290次,点赞8次,收藏10次。1.背景介绍稀疏编码是一种用于处理稀疏数据的编码技术,其主要应用于信息传输、存储和处理等领域。稀疏数据是指数据中大部分元素为零或近似于零的数据,例如文本、图像、音频、视频等。稀疏编码的核心思想是将稀疏数据表示为非零元素和它们对应的位置信息,从而减少存储空间和计算复杂度。稀疏编码的研究起源于1990年代,随着大数据时代的到来,稀疏编码技术的应用范围和影响力不断扩大。目前,稀疏编码已经成为计算...

EasyGBS国标流媒体服务器GB28181国标方案安装使用文档-程序员宅基地

文章浏览阅读217次。EasyGBS - GB28181 国标方案安装使用文档下载安装包下载,正式使用需商业授权, 功能一致在线演示在线API架构图EasySIPCMSSIP 中心信令服务, 单节点, 自带一个 Redis Server, 随 EasySIPCMS 自启动, 不需要手动运行EasySIPSMSSIP 流媒体服务, 根..._easygbs-windows-2.6.0-23042316使用文档

【Web】记录巅峰极客2023 BabyURL题目复现——Jackson原生链_原生jackson 反序列化链子-程序员宅基地

文章浏览阅读1.2k次,点赞27次,收藏7次。2023巅峰极客 BabyURL之前AliyunCTF Bypassit I这题考查了这样一条链子:其实就是Jackson的原生反序列化利用今天复现的这题也是大同小异,一起来整一下。_原生jackson 反序列化链子

一文搞懂SpringCloud,详解干货,做好笔记_spring cloud-程序员宅基地

文章浏览阅读734次,点赞9次,收藏7次。微服务架构简单的说就是将单体应用进一步拆分,拆分成更小的服务,每个服务都是一个可以独立运行的项目。这么多小服务,如何管理他们?(服务治理 注册中心[服务注册 发现 剔除])这么多小服务,他们之间如何通讯?这么多小服务,客户端怎么访问他们?(网关)这么多小服务,一旦出现问题了,应该如何自处理?(容错)这么多小服务,一旦出现问题了,应该如何排错?(链路追踪)对于上面的问题,是任何一个微服务设计者都不能绕过去的,因此大部分的微服务产品都针对每一个问题提供了相应的组件来解决它们。_spring cloud

Js实现图片点击切换与轮播-程序员宅基地

文章浏览阅读5.9k次,点赞6次,收藏20次。Js实现图片点击切换与轮播图片点击切换<!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title></title> <script type="text/ja..._点击图片进行轮播图切换

tensorflow-gpu版本安装教程(过程详细)_tensorflow gpu版本安装-程序员宅基地

文章浏览阅读10w+次,点赞245次,收藏1.5k次。在开始安装前,如果你的电脑装过tensorflow,请先把他们卸载干净,包括依赖的包(tensorflow-estimator、tensorboard、tensorflow、keras-applications、keras-preprocessing),不然后续安装了tensorflow-gpu可能会出现找不到cuda的问题。cuda、cudnn。..._tensorflow gpu版本安装

随便推点

物联网时代 权限滥用漏洞的攻击及防御-程序员宅基地

文章浏览阅读243次。0x00 简介权限滥用漏洞一般归类于逻辑问题,是指服务端功能开放过多或权限限制不严格,导致攻击者可以通过直接或间接调用的方式达到攻击效果。随着物联网时代的到来,这种漏洞已经屡见不鲜,各种漏洞组合利用也是千奇百怪、五花八门,这里总结漏洞是为了更好地应对和预防,如有不妥之处还请业内人士多多指教。0x01 背景2014年4月,在比特币飞涨的时代某网站曾经..._使用物联网漏洞的使用者

Visual Odometry and Depth Calculation--Epipolar Geometry--Direct Method--PnP_normalized plane coordinates-程序员宅基地

文章浏览阅读786次。A. Epipolar geometry and triangulationThe epipolar geometry mainly adopts the feature point method, such as SIFT, SURF and ORB, etc. to obtain the feature points corresponding to two frames of images. As shown in Figure 1, let the first image be ​ and th_normalized plane coordinates

开放信息抽取(OIE)系统(三)-- 第二代开放信息抽取系统(人工规则, rule-based, 先抽取关系)_语义角色增强的关系抽取-程序员宅基地

文章浏览阅读708次,点赞2次,收藏3次。开放信息抽取(OIE)系统(三)-- 第二代开放信息抽取系统(人工规则, rule-based, 先关系再实体)一.第二代开放信息抽取系统背景​ 第一代开放信息抽取系统(Open Information Extraction, OIE, learning-based, 自学习, 先抽取实体)通常抽取大量冗余信息,为了消除这些冗余信息,诞生了第二代开放信息抽取系统。二.第二代开放信息抽取系统历史第二代开放信息抽取系统着眼于解决第一代系统的三大问题: 大量非信息性提取(即省略关键信息的提取)、_语义角色增强的关系抽取

10个顶尖响应式HTML5网页_html欢迎页面-程序员宅基地

文章浏览阅读1.1w次,点赞6次,收藏51次。快速完成网页设计,10个顶尖响应式HTML5网页模板助你一臂之力为了寻找一个优质的网页模板,网页设计师和开发者往往可能会花上大半天的时间。不过幸运的是,现在的网页设计师和开发人员已经开始共享HTML5,Bootstrap和CSS3中的免费网页模板资源。鉴于网站模板的灵活性和强大的功能,现在广大设计师和开发者对html5网站的实际需求日益增长。为了造福大众,Mockplus的小伙伴整理了2018年最..._html欢迎页面

计算机二级 考试科目,2018全国计算机等级考试调整,一、二级都增加了考试科目...-程序员宅基地

文章浏览阅读282次。原标题:2018全国计算机等级考试调整,一、二级都增加了考试科目全国计算机等级考试将于9月15-17日举行。在备考的最后冲刺阶段,小编为大家整理了今年新公布的全国计算机等级考试调整方案,希望对备考的小伙伴有所帮助,快随小编往下看吧!从2018年3月开始,全国计算机等级考试实施2018版考试大纲,并按新体系开考各个考试级别。具体调整内容如下:一、考试级别及科目1.一级新增“网络安全素质教育”科目(代..._计算机二级增报科目什么意思

conan简单使用_apt install conan-程序员宅基地

文章浏览阅读240次。conan简单使用。_apt install conan