Eigen3 教程基础篇(三)

news2024/9/20 15:07:57

 参考

Eigen3 主页,Eigen3 官网教程

矩阵的本质,通过多种矩阵的应用去感受矩阵本质

3Blue1Brown 的线性代数,用可视化方法来表现线性代数的特性,强推

如何理解复数和虚数,有动画方便理解复数的意义

相关文章

Eigen3 教程基础篇(一)

 Eigen3 教程基础篇(二)

块操作

分块矩阵

一个分块矩阵是将矩阵分割出较小的矩形矩阵,这些较小的矩阵就称为区块。分块矩阵的分割原则是以水平线和垂直线进行划分。分块矩阵中,位在同一行(列)分区的每个子矩阵,都拥有相同的行数(列数)。

  • 分块矩阵加法:如果两个分块矩阵的每个子矩阵行列相同,那么矩阵相加等于各个子矩阵相加。

  • 分块矩阵乘法:分块矩阵 A 有 m*r 个子矩阵, 分块矩阵 B 有 r*n 个子矩阵,相乘后的矩阵 C 有 m*n 个子矩阵。

这里的 A_{i,k}*B_{k,j} 同样要满足矩阵乘法规则。

矩阵取块操作

对矩阵 matrix 的 [ i, j ] 位置,取大小 ( p, q ) 的块操作:

动态大小的块操作:

matrix.block(i,j,p,q);

固定大小的块操作:

matrix.block<p,q>(i,j);

行和列是特殊的块,可以通过 row()col()

取出来的矩阵块可以视作独立的矩阵类进行操作。

void TestBlock()
{
  Eigen::Matrix4f m;
  m << 1.2, -2.3, 3.4, -4.5,
       5.6, -6.7, 7.8, -8.9,
       9.0, -0.1, 1.2, -2.3,
       3.4, -4.5, 5.6, -6.7;
  Eigen::Matrix2f md1122 = m.block(1,1,2,2);
  Eigen::Matrix2f mf1122 = m.block<2,2>(1,1);
  ROS_INFO_STREAM("动态取块,矩阵 m 的 (1,1) 取 2*2 块:" << std::endl << md1122);
  ROS_INFO_STREAM("固定取块,矩阵 m 的 (1,1) 取 2*2 块:" << std::endl << mf1122);

  Eigen::Matrix3f n;
  n << 1.2, -2.3, 3.4,
       -4.5, 5.6, -6.7,
       7.8, -8.9, 9.0;
  Eigen::Matrix2f nd0022 = m.block(0,0,2,2);
  Eigen::Matrix2f mn22 = md1122 + nd0022;
  ROS_INFO_STREAM("动态取块,矩阵 n 的 (0,0) 取 2*2 块:" << std::endl << nd0022);
  ROS_INFO_STREAM("矩阵 m(1,1){2*2} + n(0,0){2*2}" << std::endl << mn22);

  Eigen::Matrix2f md2022 = m.block(2,0,2,2);
  Eigen::Matrix2f nf1122 = n.block<2,2>(1,1);
  ROS_INFO_STREAM("矩阵 m(2,0){2*2} * n(1,1){2*2}" << std::endl << md2022*nf1122);
}

向量取块操作

取 n 个向量头部元素的块,动态块操作:vector.head(n),固定区块:vector.head<n>()

取 n 个向量尾部元素的块,动态块操作:vector.tail(n),固定区块:vector.tail<n>()

在 i 位置取 n 个元素的块,动态块操作:vector.segment(i,n),固定区块:vector.segment<n>(i)

void TestVectorBlock()
{
  Eigen::Vector3f v3f(1.2, -2.3, 3.4);
  Eigen::Vector2f v3fh2 = v3f.head(2);
  Eigen::Vector2f v3ft2 = v3f.tail(2);
  ROS_INFO_STREAM("向量 v3f:" << std::endl << v3f);
  ROS_INFO_STREAM("向量 v3f 取头部 2 个元素:" << std::endl << v3fh2);
  ROS_INFO_STREAM("向量 v3f 取尾部 2 个元素:" << std::endl << v3ft2);

  Eigen::VectorXf v6f(6);
  v6f << 0.1, -1.2, 2.3, -3.4, 4.5, -5.6;
  Eigen::Vector3f v6f33 = v6f.segment(3,3);
  Eigen::Vector3f v6f23 = v6f.segment<3>(2);
  ROS_INFO_STREAM("向量 v6f:" << std::endl << v6f);
  ROS_INFO_STREAM("向量 v6f 动态取块在 3 位置取 3 个元素:" << std::endl << v6f33);
  ROS_INFO_STREAM("向量 v6f 在 2 位置固定取块 3 个元素:" << std::endl << v6f23);
}

Reductions 归约

在 Eigen 中,Reductions(归约)是返回单个标量值的函数方法。

  • 常见的归约方法:

sum() 矩阵系数和,prod() 矩阵系数乘积,mean() 矩阵系数均值,minCoeff() 矩阵中最小系数,maxCoeff() 矩阵中最大系数,trace() 矩阵中对角线(左上角到右下角)元素之和。

squaredNorm() 向量系数绝对值的平方之和,norm() 向量系数绝对值平方和的平方根。

这两个方法对矩阵同样适用,此时矩阵 M(n,p) 被看做 n*p 大小的向量。

  • 布尔归约:

all(),如果矩阵,数组的所有系数均计算为 true,返回 true;

any(),如果矩阵,数组的存在任一系数计算为 true,返回 true;

count(),返回矩阵或数组中系数计算为 true 的数量;

  • 部分归约:

colwise() 和 rowwise() 可以取得列向,或行向的归约。

void TestReductions()
{
  Eigen::Matrix4f m;
  m << 1.2, -2.3, 3.4, -4.5,
       5.6, -6.7, 7.8, -8.9,
       9.0, -0.1, 1.2, -2.3,
       3.4, -4.5, 5.6, -6.7;
  ROS_INFO_STREAM("矩阵 m:" << std::endl << m);

  ROS_INFO_STREAM("m.sum():" << m.sum() << std::endl <<
                  "m.prod():" << m.prod() << std::endl <<
                  "m.mean():" << m.mean() << std::endl <<
                  "m.minCoeff():" << m.minCoeff() << std::endl <<
                  "m.maxCoeff():" << m.maxCoeff() << std::endl <<
                  "m.trace():" << m.trace() << std::endl <<
                  "m.squaredNorm():" << m.squaredNorm() << std::endl <<
                  "m.norm():" << m.norm() << std::endl);

  ROS_INFO_STREAM("m.colwise().maxCoeff():" << m.colwise().maxCoeff() << std::endl <<
                  "m.rowwise().sum().minCoeff():" << m.rowwise().sum().minCoeff() << std::endl);
}

broadcasting 传播

对所有的方向进行操作。

void TestBroadcasting()
{
  Eigen::MatrixXf m(2,4);
  m << 1.0, -11.23, 6.9, -0.83,
       -5.6, 2.56, -2.97, 6.56;
  ROS_INFO_STREAM("矩阵 m:" << std::endl << m);

  Eigen::VectorXf n(2);
  n << 2,
       3;
  ROS_INFO_STREAM("向量 n:" << std::endl << n);

  Eigen::Index index;
  (m.colwise() - n).colwise().squaredNorm().minCoeff(&index);
  std::cout << "Nearest neighbour is column " << index << ":" << std::endl;
  std::cout << m.col(index) << std::endl;
}

Map 类:原始缓存数据接口

当在 Eigen 之外定义了一组数据,这组数据就是一个矩阵或者向量。这里可以通过 Eigen 的 Map 模板来使用 Eigen 的算法处理这组数据。

Map 模板类:

Map<Matrix<typename Scalar, int RowsAtCompileTime, int ColsAtCompileTime> >

例如Map<MatrixXf> mf(pf,rows,cols),pf 是 Eigen 之外定义的 rows*cols 大小的矩阵的数据内存地址,这里通过 Map 模板构造的对象 mf 得到了和 MatrixXf 等效的数据处理接口,可以像使用 MatrixXf 一样处理 pf 地址的数据。

修改 Map 模板类对象的数据地址,挺奇怪的写法:

new (&map) Map<Matrix<typename Scalar, int Rows, int Cols> >(new_data);
void TestMap()
{
  int array[8];
  for(int i = 0; i < 8; ++i)
    array[i] = i;
  auto m = Eigen::Map<Eigen::Matrix<int,2,4>>(array);
  ROS_INFO_STREAM("矩阵 array -> m:" << std::endl << m);
  ROS_INFO_STREAM("矩阵 array -> m.colwise().sum()" << std::endl << m.colwise().sum());

  int data[] = {1,2,3,4,5,6,7,8,9};
  new (&m) Eigen::Map<Eigen::Matrix<int,2,4>>(data);
  ROS_INFO_STREAM("矩阵 data -> m:" << std::endl << m);
  ROS_INFO_STREAM("矩阵 data -> m.rowwise().squaredNorm():" << std::endl << m.rowwise().squaredNorm());
}

Aliasing 混叠

在 Eigen 中,Aliasing 混叠指赋值语句左右两侧出现相同的矩阵/数组/向量,这里指左右操作数内存上有重叠。有时候 Aliasing 混叠会导致异常。

  • 混叠异常情况

void TestAliasing()
{
  Eigen::MatrixXi m(3,3); 
  m << 1, 2, 3,
       4, 5, 6,
       7, 8, 9;
  ROS_INFO_STREAM("矩阵 m:" << std::endl << m);
  
  m.bottomRightCorner(2,2) = m.topLeftCorner(2,2);
  ROS_INFO_STREAM("after the assignment, m:" << std::endl << m);
}

上面的例子中,系数 5 同时存在于左上 2*2 矩阵块和右下 2*2 矩阵块中,Eigen 一般情况下为了性能直接修改数据内存,而没有拷贝右值的临时变量处理。这就导致了混叠操作有可能出现计算错误。

其他像 a = a.transpose()的操作也有导致出错!

  • 避免混叠异常

通过 eval() 函数给右值创建临时对象。

void TestAliasing()
{
  ROS_INFO_STREAM("---------- 混叠异常 ----------");
  Eigen::MatrixXi m(3,3); 
  m << 1, 2, 3,
       4, 5, 6,
       7, 8, 9;
  auto x = m;
  ROS_INFO_STREAM("矩阵 m:" << std::endl << m);
  
  m.bottomRightCorner(2,2) = m.topLeftCorner(2,2);
  ROS_INFO_STREAM("after the assignment, m:" << std::endl << m);

  ROS_INFO_STREAM("---------- 避免混叠 ----------");
  x.bottomRightCorner(2,2) = x.topLeftCorner(2,2).eval();
  ROS_INFO_STREAM("after the assignment, x:" << std::endl << x);
}

另外还有 ***InPlace() 接口避免混叠异常:

矩阵乘法是唯一被默认假定混叠的运算,所以矩阵乘法是默认通过临时对象计算,此时混叠不会出现异常。

也是由于矩阵乘法的特殊处理,其中的临时对象赋值和销毁消耗了时间,此时可以通过 noalias() 函数指定矩阵乘法不使用临时对象。

下面用 noalias() 告诉 eigen 库,左值的矩阵数据内存不与右值操作数有重叠,不需要拷贝右值的临时变量。

void TestAliasingMultiplication()
{
  Eigen::MatrixXi m(3,3); 
  m << 1, 2, 3,
       4, 5, 6,
       7, 8, 9;
  auto x = m;
  ROS_INFO_STREAM("矩阵 m:" << std::endl << m);

  auto mx = m * x;
  ROS_INFO_STREAM("矩阵 m * 矩阵 x:" << std::endl << mx);

  m *= m;
  ROS_INFO_STREAM("矩阵 m 乘法混叠无异常, m:" << std::endl << m);

  x.noalias() = x * x;
  ROS_INFO_STREAM("矩阵 x 混叠,不使用临时变量, x:" << std::endl << x);
}

一般来说,可以用 noalias() 指定不创建临时对象,加速计算;用 eval() 来创建临时对象,避免计算错误。

Explanation of the assertion on unaligned arrays 未对齐内存问题

使用 eigen 库时候,可能出现下面的断言错误:

这个错误的根本原因是固定矩阵/向量大小的 Eigen 对象没有在正确对齐的位置创建,导致 SIMD 指令寻址错误。

!!!使用 C++17 可以避免这个问题!!!

!!!动态大小的矩阵不会有这个问题,Eigen 会管理动态内存的对象!!!

常见的出错场景(C++11编译测试)

  • 构建具有固定大小的 Eigen 成员变量的对象

class xclass
{
 public:
  Eigen::Matrix2d v;
};

void TestUnalignedArray()
{
  auto x = new xclass();
  x->v << 1.0, 2.0, 3.0, 4.0;
  ROS_INFO_STREAM("x.v:" << std::endl << x->v);
}

未出现上面的错误:

  • 使用容器存储 Eigen 对象

void TestUnalignedArray()
{
  std::vector<Eigen::Vector2d> ve2d;
  Eigen::Vector2d m2d0;
  m2d0 << 1.0, 2.0;
  Eigen::Vector2d m2d1;
  m2d1 << 5.0, 6.0;

  ve2d.push_back(m2d0);
  ve2d.push_back(m2d1);
  ROS_INFO_STREAM("ve2d.front()" << std::endl << ve2d.front());
  ROS_INFO_STREAM("ve2d.at(1)" << std::endl << ve2d.at(1));
}

未出现上面的错误:

  • 按值传递 Eigen 对象

void PrintInputMatrix(const Eigen::Matrix2d m)
{
  ROS_INFO_STREAM("input m:" << std::endl << m);
}

void TestUnalignedArray()
{
  Eigen::Matrix2d m;
  m << 1.2, 2.3, 3.4, 4.5;
  PrintInputMatrix(m);
}

未出现上面的错误:

  • 在堆栈创建 Eigen 对象(Win 中的 gcc)

void foo()
{
  Eigen::Quaternionf q;
  //...
}

这个就不测试了...

不知道为啥就是没出现异常 :) 具体的解决办法参考原文资料吧。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2149214.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于SpringBoot+Vue+MySQL的在线宠物用品商城销售系统

系统展示 用户前台界面 管理员后台界面 系统背景 随着人们生活质量的提升和宠物经济的蓬勃发展&#xff0c;宠物已成为众多家庭不可或缺的一员。宠物市场的需求日益增长&#xff0c;涵盖了食品、用品、医疗、美容等多个领域。基于SpringBootVueMySQL的在线宠物用品商城销售系统…

新产品,推出 MLX90372GVS 第三代 Triaxis® 位置传感器 IC,适用于汽车和工业系统(MLX90372GVS-ACE-308)

Triaxis 旋转和线性位置传感器IC&#xff1a; MLX90372GVS-ACE-103 MLX90372GVS-ACE-108 MLX90372GVS-ACE-301 MLX90372GVS-ACE-200 MLX90372GVS-ACE-208 MLX90372GVS-ACE-303 MLX90372GVS-ACE-300 MLX90372GVS-ACE-350 MLX90372GVS-ACE-100 MLX90372GVS-ACE-101 MLX90372GVS-…

【Java算法】二叉树的深搜

&#x1f525;个人主页&#xff1a; 中草药 &#x1f525;专栏&#xff1a;【算法工作坊】算法实战揭秘 一.2331.计算布尔二叉树的值 题目链接&#xff1a;2331.计算布尔二叉树的值 代码 public boolean evaluateTree(TreeNode root) {if(root.leftnull){return root.val0?f…

VSCode值得推荐的插件(持续更新中)

VSCode值得推荐的插件&#xff08;持续更新中&#xff09; 说明1.Peacock 说明 主要记录VSCode开发过程中插件 1.Peacock 允许开发者为 Visual Studio Code 的工作区界面&#xff08;如侧边栏、底栏和标题栏&#xff09;自定义颜色&#xff0c;以区分不同的项目或编码环境。…

【machine learning-七-线性回归之成本函数】

监督学习之cost function 成本函数权重、偏置如何实现拟合数据成本函数是如何寻找出来w和b&#xff0c;使成本函数值最小化&#xff1f; 在线性回归中&#xff0c;我们说到评估模型训练中好坏的一个方法&#xff0c;是用成本函数来衡量&#xff0c;下面来详细介绍一下 成本函数…

需求3:照猫画虎

说起写需求&#xff0c;其实对于我这种小白而言&#xff0c;接到一个需求&#xff0c;最好的方式就是照猫画虎。 因为我从0到1写&#xff0c;以我现在这种水平&#xff0c;根本就不可能完成。所以照猫画虎&#xff0c;模仿着来写是最好的提升方法。 之前在聊天的时候&#xf…

记录|如何对批量型的pictureBox组件进行批量Image设置

目录 前言一、问题表述二、批量化处理更新时间 前言 参考文章&#xff1a; 一、问题表述 问题就是上图所示&#xff0c;这些的命名风格统一&#xff0c;只是最后的数字是不同的。所以存在可以批量化进行处理的可能性。 二、批量化处理 private void SetPictureBoxImages(){for…

Flat File端口更新:如何实现嵌套结构

Flat File端口可以实现平面文件和XML文件的互相转换&#xff0c;本文主要介绍在知行之桥EDI系统8971及更高版本中&#xff0c;Flat File端口如何支持类似EDI嵌套结构的转换。 Flatfile端口如何自定义嵌套结构 下载示例工作流以及示例文件 打开知行之桥EDI系统&#xff0c;创建…

OpenCV特征检测(1)检测图像中的线段的类LineSegmentDe()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 检测图像中线段的类.。 遵循在 285中描述的算法。 函数原型1 绘制两组线&#xff0c;一组用蓝色&#xff0c;一组用红色&#xff0c;并计算非重…

[云服务器12] 搭建eaglercraft网页MC

众所周知&#xff0c;MC是一个炒鸡好玩的游戏&#xff01; 但是&#xff0c;Mojang开发出来是经过Java JAR打包过的的.jar文件&#xff0c;这就不得不依赖HMCL PCL BakaXL等启动器来启动了…… 所以今天&#xff0c;我们将使用开源的eaglercraft来搭建一个在线版MC&#xff0…

鸟类识别系统Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+ResNet50算法模型+图像识别

一、介绍 鸟类识别系统。本系统采用Python作为主要开发语言&#xff0c;通过使用加利福利亚大学开源的200种鸟类图像作为数据集。使用TensorFlow搭建ResNet50卷积神经网络算法模型&#xff0c;然后进行模型的迭代训练&#xff0c;得到一个识别精度较高的模型&#xff0c;然后在…

【VUE3.0】动手做一套像素风的前端UI组件库---Button

目录 引言做之前先仔细看看UI设计稿解读一下都有哪些元素&#xff1a;素材补充 代码编写1. 按钮四周边框2. 默认状态下按钮颜色立体效果3. 鼠标移入聚焦4. 模拟鼠标点击效果 组件封装1. 按类型设置颜色2. 设置按钮禁用状态3. 处理一个bug4. 看下整体组件效果5. 组件完整代码6. …

数字自然资源领域的实现路径

在数字化浪潮的推动下&#xff0c;自然资源的管理与利用正经历着前所未有的变革。本文将从测绘地理信息与遥感专业的角度&#xff0c;深度分析数字自然资源领域的实现路径。 1. 基础数据的数字化 数字自然资源的构建&#xff0c;首先需要实现基础数据的数字化。这包括地形地貌…

db2恢复数据库

db2licm -l检查下license IBM Support: Fix Central - Please wait, Select fixes db2 force application all db2ckbkp -H JYC.0.DB2.NODE0000.CATN0000.20240603223001.001 db2 "restore db jyc logtarget x:\db2\log" db2 "rollforward db jyc to end of log…

音频北斗定位系统有什么用?

在当今科技飞速发展的时代&#xff0c;定位技术已经成为我们日常生活和各行各业不可或缺的一部分。其中&#xff0c;音频北斗定位系统作为一种新兴的定位技术&#xff0c;正逐渐展现出其独特的优势和应用价值。那么&#xff0c;到底音频北斗定位系统有什么用呢?我们一起来了解…

住宅代理IP如何提高 IP声誉?

你有没有遇到过类似的问题&#xff1f;发送的邮件被标记为垃圾邮件并被屏蔽、访问某些网站被拒绝、广告效果不理想&#xff0c;甚至网上交易无缘无故被拒绝&#xff1f;这到底是什么原因造成的&#xff1f;其实&#xff0c;这些问题可能都和 IP 信誉息息相关。 如果你的 IP 地址…

一文读懂HPA弹性扩展以及实践攻略

一文读懂HPA弹性扩展以及实践攻略 目录 1 概念&#xff1a; 1.1 什么是弹性扩展1.2 HPA 的工作原理1.3 通过监控指标来调整副本数 1.3.1 计算公式说明1.3.2 平均值计算1.3.3 未就绪 Pod 和丢失的指标处理1.3.4 多指标支持1.3.5 缩减副本的平滑策略 1.4 HPA的优缺点 2 实践攻略…

微服务保护学习笔记(五)Sentinel授权规则、获取origin、自定义异常结果、规则持久化

文章目录 前言4 授权规则4.1 基本原理4.2 获取origin4.3 配置授权规则 5 自定义异常结果6 规则持久化 前言 微服务保护学习笔记(一)雪崩问题及解决方案、Sentinel介绍与安装 微服务保护学习笔记(二)簇点链路、流控操作、流控模式(关联、链路) 微服务保护学习笔记(三)流控效果(…

C语言 14 结构体 联合体 枚举

之前认识过很多种数据类型&#xff0c;包括整数、小数、字符、数组等&#xff0c;通过使用对应的数据类型&#xff0c;就可以很轻松地将数据进行保存了&#xff0c;但是有些时候&#xff0c;这种简单类型很难去表示一些复杂结构。 结构体 比如现在要保存 100 个学生的信息&am…

本地部署一个轻量化智能聊天服务Vocechat并实现异地远程交互

文章目录 前言1. 拉取Vocechat2. 运行Vocechat3. 本地局域网访问4. 群晖安装Cpolar5. 配置公网地址6. 公网访问小结 7. 固定公网地址 前言 本文主要介绍如何在本地群晖NAS搭建一个自己的聊天服务Vocechat&#xff0c;并结合内网穿透工具实现使用任意浏览器远程访问进行智能聊天…