Eigen3 教程基础篇(三)

 参考

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.rhkb.cn/news/427465.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

《ElementUI/Plus 踩坑》el-table + sortablejs 拖拽顺序错乱(Vue2/3适用)

如图所示&#xff1a; 把第一行拖到最后一行&#xff0c;鼠标up&#xff1b;该行莫名其妙的跳到倒数第二行&#xff1b; 最后发现没有设置 el-table 属性 row-key &#xff0c;即行数据的 Key&#xff0c;用来优化 table 的渲染&#xff1b; 属性 row-key 描述如下&#xf…

YOLOv10轻量化快速涨点之改进AKConv

目录 1,什么是AKConv? 2,如何使用AKConv使YOLOv10快速长点? 2.1,在ultralytics-main/ultralytics/nn/modules/conv.py里面添加AKConv类 2.2,ultralytics-main/ultralytics/nn/modules/conv.py添加如下 2.3 在E:\czc\YOLOv10\ultralytics-main\ultralytics\nn\tasks.p…

算法.图论-并查集上

文章目录 1. 并查集介绍2. 并查集的实现2.1 实现逻辑2.2 isSameSet方法2.3 union方法(小挂大优化)2.4 find方法(路径压缩优化) 3. 并查集模板 1. 并查集介绍 定义&#xff1a; 并查集是一种树型的数据结构&#xff0c;用于处理一些不相交集合的合并及查询问题&#xff08;即所…

1 elasticsearch安装

【0】官网参考 https://www.elastic.co/guide/en/elasticsearch/reference/7.11/targz.html 【1】Centos7 下载安装 【1.1】下载 官网&#xff1a;Download Elasticsearch | Elastic 选择好自己想要的相关版本即可&#xff1b; 【2】Centos7.X 前置环境配置&#xff08;uli…

秦时明月6.2魔改版+GM工具+虚拟机一键端

今天给大家带来一款单机游戏的架设&#xff1a;秦时明月。 另外&#xff1a;本人承接各种游戏架设&#xff08;单机联网&#xff09; 本人为了学习和研究软件内含的设计思想和原理&#xff0c;带了架设教程仅供娱乐。 教程是本人亲自搭建成功的&#xff0c;绝对是完整可运行…

【Vmware16安装教程】

&#x1f4d6;Vmware16安装教程 ✅1.下载✅2.安装 ✅1.下载 官网地址&#xff1a;https://www.vmware.com/ 百度云盘&#xff1a;Vmware16下载 123云盘&#xff1a;Vmware16下载 ✅2.安装 1.双击安装包VMware-workstation-full-16.1.0-LinuxProbe.Com.exe&#xff0c;点击…

最新动态一致的文生视频大模型FancyVideo部署

FancyVideo是一个由360AI团队和中山大学联合开发并开源的视频生成模型。 FancyVideo的创新之处在于它能够实现帧特定的文本指导&#xff0c;使得生成的视频既动态又具有一致性。 FancyVideo模型通过精心设计的跨帧文本引导模块&#xff08;Cross-frame Textual Guidance Modu…

C#和数据库高级:抽象类和抽象方法

文章目录 一、为什么使用抽象类和抽象方法&#xff1f;1.1、父类与子类的相互转换 二、抽象类和抽象方法2.1、抽象类的定义和方法声明规范2.2、使用继承多态的机制解决问题 三、抽象类的概念和使用特点总结 一、为什么使用抽象类和抽象方法&#xff1f; 1.1、父类与子类的相互…

考研数据结构——C语言实现有向图邻接矩阵

首先&#xff0c;定义了一些基本的数据结构和常量&#xff1a; VertexType&#xff1a;顶点的数据类型&#xff0c;这里定义为char。EdgeType&#xff1a;边的数据类型&#xff0c;这里定义为int&#xff0c;用于存储权重。MAXVEX&#xff1a;定义了图中最大顶点数为100。INFIN…

C语言——自定义类型

目录 结构体 概念 结构体变量的创建和初始化 结构体的自引用 结构体的内存对齐 内存对齐存在的原因 合理设计结构体 方法一 方法二 结构体传参 结构体实现位段 什么是位段 位段的内存分配 位段的跨平台问题 注意 联合体 概念 验证 优点 小应用 什么是大小…

【Unity】对象池 - 未更新完

自定义泛型对象池 文章目录 自定义泛型对象池封装泛型类例子 使用Unity自带对象池 封装泛型类 public abstract class MyPool<T> : MonoBehaviour where T :Component {[SerializeField] protected T prefab; // 生成的预制体[SerializeField] protected int defaultNum…

鸿蒙环境服务端签名直传文件到OSS

本文介绍如何在鸿蒙环境下将文件上传到OSS。 背景信息 鸿蒙环境是当下比较流行的操作环境&#xff0c;与服务端签名直传的原理类似&#xff0c;鸿蒙环境上传文件到OSS是利用OSS提供的PutObject接口来实现文件上传到OSS。关于PutObject的详细介绍&#xff0c;请参见PutObject。…

VMware安装飞牛私有云fnOS并挂载小雅Alist实现异地远程访问

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

记一次键盘f2和f5键被自动触发情况

背景&#xff1a; 联想小新笔记本电脑内置键盘&#xff0c;其中f2键和f5键一直被自动触发&#xff0c;已尝试过更换输入法&#xff0c;重装系统&#xff0c;拆开键帽清灰依旧无效。考虑维修费或者更换键盘&#xff08;内置&#xff09;费都挺贵的&#xff0c;而且f2和f5作用也…

Unity教程(十六)敌人攻击状态的实现

Unity开发2D类银河恶魔城游戏学习笔记 Unity教程&#xff08;零&#xff09;Unity和VS的使用相关内容 Unity教程&#xff08;一&#xff09;开始学习状态机 Unity教程&#xff08;二&#xff09;角色移动的实现 Unity教程&#xff08;三&#xff09;角色跳跃的实现 Unity教程&…

2024java面试-软实力篇

为什么说简历很重要&#xff1f; 一份好的简历可以在整个申请面试以及面试过程中起到非常好的作用。 在不夸大自己能力的情 况 下&#xff0c;写出一份好的简历也是一项很棒的能力。为什么说简历很重要呢&#xff1f; 、 先从面试来说 假如你是网申&#xff0c;你的简历必然…

论文阅读-《Attention is All You Need》

注意力就是一切 【要点】&#xff1a;论文提出了一种全新的网络架构——Transformer&#xff0c;完全基于注意力机制&#xff0c;无需使用循环和卷积&#xff0c;实现了在机器翻译任务上的性能提升和训练效率的显著提高。 【方法】&#xff1a;通过构建一个仅使用注意力机制的…

【计算机网络 - 基础问题】每日 3 题(十三)

✍个人博客&#xff1a;Pandaconda-CSDN博客 &#x1f4e3;专栏地址&#xff1a;http://t.csdnimg.cn/fYaBd &#x1f4da;专栏简介&#xff1a;在这个专栏中&#xff0c;我将会分享 C 面试中常见的面试题给大家~ ❤️如果有收获的话&#xff0c;欢迎点赞&#x1f44d;收藏&…

cadence SPB17.4 - allegro - 用板子外形创建整板铺铜

文章目录 cadence SPB17.4 - allegro - 用板子外形创建整板铺铜概述笔记先确定自己板子的 board Geometry/Design_Outline 是否有外形shape为了将软件提示看得更清楚&#xff0c;在每个操作之前&#xff0c;先将命令提示区内容先删了用Z-copy从外形层生成整板的铺铜备注END cad…

【JS】postMessage与MessageChannel

前言 postMessage 和 MessageChannel 都是用来实现跨文档、跨窗口或跨线程&#xff08;Web Worker&#xff09;的消息传递机制。 postMessage 可以在 iframe、同源或跨源窗口之间传递数据&#xff0c;也可以用于主线程与 Web Worker 之间的通信。 postMessage 是一种单向的…