整理下Eigen库的教程,参考:http://eigen.tuxfamily.org/dox/index.html

矩阵和向量的运算

提供一些概述和细节:关于矩阵、向量以及标量的运算。

介绍

Eigen提供了matrix/vector的运算操作,既包括重载了c++的算术运算符+/-/*,也引入了一些特殊的运算比如点乘dot、叉乘cross等。

对于Matrix类(matrix和vectors)这些操作只支持线性代数运算,比如:matrix1*matrix2表示矩阵的乘机,vetor+scalar是不允许的。如果你想执行非线性代数操作,请看下一篇(暂时放下)。

加减

左右两侧变量具有相同的尺寸(行和列),并且元素类型相同(Eigen不自动转化类型)操作包括:

  • 二元运算 + 如a+b
  • 二元运算 - 如a-b
  • 一元运算 - 如-a
  • 复合运算 += 如a+=b
  • 复合运算 -= 如a-=b
  1. #include <iostream>
  2. #include <Eigen/Dense>
  3. using namespace Eigen;
  4. int main()
  5. {
  6. Matrix2d a;
  7. a << 1, 2,
  8. 3, 4;
  9. MatrixXd b(2,2);
  10. b << 2, 3,
  11. 1, 4;
  12. std::cout << "a + b =\n" << a + b << std::endl;
  13. std::cout << "a - b =\n" << a - b << std::endl;
  14. std::cout << "Doing a += b;" << std::endl;
  15. a += b;
  16. std::cout << "Now a =\n" << a << std::endl;
  17. Vector3d v(1,2,3);
  18. Vector3d w(1,0,0);
  19. std::cout << "-v + w - v =\n" << -v + w - v << std::endl;
  20. }

输出:

  1. a + b =
  2. 3 5
  3. 4 8
  4. a - b =
  5. -1 -1
  6. 2 0
  7. Doing a += b;
  8. Now a =
  9. 3 5
  10. 4 8
  11. -v + w - v =
  12. -1
  13. -4
  14. -6

标量乘法和除法

乘/除标量是非常简单的,如下:

  • 二元运算 * 如matrix*scalar
  • 二元运算 * 如scalar*matrix
  • 二元运算 / 如matrix/scalar
  • 复合运算 *= 如matrix*=scalar
  • 复合运算 /= 如matrix/=scalar
  1. #include <iostream>
  2. #include <Eigen/Dense>
  3. using namespace Eigen;
  4. int main()
  5. {
  6. Matrix2d a;
  7. a << 1, 2,
  8. 3, 4;
  9. Vector3d v(1,2,3);
  10. std::cout << "a * 2.5 =\n" << a * 2.5 << std::endl;
  11. std::cout << "0.1 * v =\n" << 0.1 * v << std::endl;
  12. std::cout << "Doing v *= 2;" << std::endl;
  13. v *= 2;
  14. std::cout << "Now v =\n" << v << std::endl;
  15. }

结果

  1. a * 2.5 =
  2. 2.5 5
  3. 7.5 10
  4. 0.1 * v =
  5. 0.1
  6. 0.2
  7. 0.3
  8. Doing v *= 2;
  9. Now v =
  10. 2
  11. 4
  12. 6

表达式模板

这里简单介绍,在高级主题中会详细解释。在Eigen中,线性运算比如+不会对变量自身做任何操作,会返回一个“表达式对象”来描述被执行的计算。当整个表达式被评估完(一般是遇到=号),实际的操作才执行。

这样做主要是为了优化,比如

  1. VectorXf a(50), b(50), c(50), d(50);
  2. ...
  3. a = 3*b + 4*c + 5*d;

Eigen会编译这段代码最终遍历一次即可运算完成。

  1. for(int i = 0; i < 50; ++i)
  2. a[i] = 3*b[i] + 4*c[i] + 5*d[i];

因此,我们不必要担心大的线性表达式的运算效率。

转置和共轭

表示transpose转置

表示conjugate共轭

表示adjoint(共轭转置) 伴随矩阵

  1. MatrixXcf a = MatrixXcf::Random(2,2);
  2. cout << "Here is the matrix a\n" << a << endl;
  3. cout << "Here is the matrix a^T\n" << a.transpose() << endl;
  4. cout << "Here is the conjugate of a\n" << a.conjugate() << endl;
  5. cout << "Here is the matrix a^*\n" << a.adjoint() << endl;

输出

  1. Here is the matrix a
  2. (-0.211,0.68) (-0.605,0.823)
  3. (0.597,0.566) (0.536,-0.33)
  4. Here is the matrix a^T
  5. (-0.211,0.68) (0.597,0.566)
  6. (-0.605,0.823) (0.536,-0.33)
  7. Here is the conjugate of a
  8. (-0.211,-0.68) (-0.605,-0.823)
  9. (0.597,-0.566) (0.536,0.33)
  10. Here is the matrix a^*
  11. (-0.211,-0.68) (0.597,-0.566)
  12. (-0.605,-0.823) (0.536,0.33)

对于实数矩阵,conjugate不执行任何操作,adjoint等价于transpose。

transpose和adjoint会简单的返回一个代理对象并不对本省做转置。如果执行 b=a.transpose() ,a不变,转置结果被赋值给b。如果执行 a=a.transpose() Eigen在转置结束之前结果会开始写入a,所以a的最终结果不一定等于a的转置。

  1. Matrix2i a; a << 1, 2, 3, 4;
  2. cout << "Here is the matrix a:\n" << a << endl;
  3. a = a.transpose(); // !!! do NOT do this !!!
  4. cout << "and the result of the aliasing effect:\n" << a << endl;
  5. Here is the matrix a:
  6. 1 2
  7. 3 4
  8. and the result of the aliasing effect:
  9. 1 2
  10. 2 4

这被称为“别名问题”。在debug模式,当assertions打开的情况加,这种常见陷阱可以被自动检测到。

a=a.transpose() 这种操作,可以执行in-palce转置。类似还有adjointInPlace。

  1. MatrixXf a(2,3); a << 1, 2, 3, 4, 5, 6;
  2. cout << "Here is the initial matrix a:\n" << a << endl;
  3. a.transposeInPlace();
  4. cout << "and after being transposed:\n" << a << endl;
  5. Here is the initial matrix a:
  6. 1 2 3
  7. 4 5 6
  8. and after being transposed:
  9. 1 4
  10. 2 5
  11. 3 6

矩阵-矩阵的乘法和矩阵-向量的乘法

向量也是一种矩阵,实质都是矩阵-矩阵的乘法。

  • 二元运算 *如a*b
  • 复合运算 *=如a*=b
  1. #include <iostream>
  2. #include <Eigen/Dense>
  3. using namespace Eigen;
  4. int main()
  5. {
  6. Matrix2d mat;
  7. mat << 1, 2,
  8. 3, 4;
  9. Vector2d u(-1,1), v(2,0);
  10. std::cout << "Here is mat*mat:\n" << mat*mat << std::endl;
  11. std::cout << "Here is mat*u:\n" << mat*u << std::endl;
  12. std::cout << "Here is u^T*mat:\n" << u.transpose()*mat << std::endl;
  13. std::cout << "Here is u^T*v:\n" << u.transpose()*v << std::endl;
  14. std::cout << "Here is u*v^T:\n" << u*v.transpose() << std::endl;
  15. std::cout << "Let's multiply mat by itself" << std::endl;
  16. mat = mat*mat;
  17. std::cout << "Now mat is mat:\n" << mat << std::endl;
  18. }

输出

  1. Here is mat*mat:
  2. 7 10
  3. 15 22
  4. Here is mat*u:
  5. 1
  6. 1
  7. Here is u^T*mat:
  8. 2 2
  9. Here is u^T*v:
  10. -2
  11. Here is u*v^T:
  12. -2 -0
  13. 2 0
  14. Let's multiply mat by itself
  15. Now mat is mat:
  16. 7 10
  17. 15 22

m=m*m并不会导致别名问题,Eigen在这里做了特殊处理,引入了临时变量。实质将编译为:

  1. tmp = m*m
  2. m = tmp

如果你确定矩阵乘法是安全的(并没有别名问题),你可以使用noalias()函数来避免临时变量 c.noalias() += a*b

点运算和叉运算

dot()执行点积,cross()执行叉积,点运算得到1*1的矩阵。当然,点运算也可以用u.adjoint()*v来代替。

  1. #include <iostream>
  2. #include <Eigen/Dense>
  3. using namespace Eigen;
  4. using namespace std;
  5. int main()
  6. {
  7. Vector3d v(1,2,3);
  8. Vector3d w(0,1,2);
  9. cout << "Dot product: " << v.dot(w) << endl;
  10. double dp = v.adjoint()*w; // automatic conversion of the inner product to a scalar
  11. cout << "Dot product via a matrix product: " << dp << endl;
  12. cout << "Cross product:\n" << v.cross(w) << endl;
  13. }

输出

  1. Dot product: 8
  2. Dot product via a matrix product: 8
  3. Cross product:
  4. 1
  5. -2
  6. 1

注意:点积只对三维vector有效。对于复数,Eigen的点积是第一个变量共轭和第二个变量的线性积。

基础的归约操作

Eigen提供了而一些归约函数:sum()、prod()、maxCoeff()和minCoeff(),他们对所有元素进行操作。

  1. #include <iostream>
  2. #include <Eigen/Dense>
  3. using namespace std;
  4. int main()
  5. {
  6. Eigen::Matrix2d mat;
  7. mat << 1, 2,
  8. 3, 4;
  9. cout << "Here is mat.sum(): " << mat.sum() << endl;
  10. cout << "Here is mat.prod(): " << mat.prod() << endl;
  11. cout << "Here is mat.mean(): " << mat.mean() << endl;
  12. cout << "Here is mat.minCoeff(): " << mat.minCoeff() << endl;
  13. cout << "Here is mat.maxCoeff(): " << mat.maxCoeff() << endl;
  14. cout << "Here is mat.trace(): " << mat.trace() << endl;
  15. }

输出

  1. Here is mat.sum(): 10
  2. Here is mat.prod(): 24
  3. Here is mat.mean(): 2.5
  4. Here is mat.minCoeff(): 1
  5. Here is mat.maxCoeff(): 4
  6. Here is mat.trace(): 5

trace表示矩阵的迹,对角元素的和等价于 a.diagonal().sum()

minCoeff和maxCoeff函数也可以返回结果元素的位置信息。

  1. Matrix3f m = Matrix3f::Random();
  2. std::ptrdiff_t i, j;
  3. float minOfM = m.minCoeff(&i,&j);
  4. cout << "Here is the matrix m:\n" << m << endl;
  5. cout << "Its minimum coefficient (" << minOfM
  6. << ") is at position (" << i << "," << j << ")\n\n";
  7. RowVector4i v = RowVector4i::Random();
  8. int maxOfV = v.maxCoeff(&i);
  9. cout << "Here is the vector v: " << v << endl;
  10. cout << "Its maximum coefficient (" << maxOfV
  11. << ") is at position " << i << endl;

输出

  1. Here is the matrix m:
  2. 0.68 0.597 -0.33
  3. -0.211 0.823 0.536
  4. 0.566 -0.605 -0.444
  5. Its minimum coefficient (-0.605) is at position (2,1)
  6. Here is the vector v: 1 0 3 -3
  7. Its maximum coefficient (3) is at position 2

操作的有效性

Eigen会检测执行操作的有效性,在编译阶段Eigen会检测它们,错误信息是繁冗的,但错误信息会大写字母突出,比如:

  1. Matrix3f m;
  2. Vector4f v;
  3. v = m*v; // Compile-time error: YOU_MIXED_MATRICES_OF_DIFFERENT_SIZES

当然动态尺寸的错误要在运行时发现,如果在debug模式,assertions会触发后,程序将崩溃。

  1. MatrixXf m(3,3);
  2. VectorXf v(4);
  3. v = m * v; // Run-time assertion failure here: "invalid matrix product"

Eigen教程(3)的更多相关文章

  1. Eigen教程(7)

    整理下Eigen库的教程,参考:http://eigen.tuxfamily.org/dox/index.html 归约.迭代器和广播 归约 在Eigen中,有些函数可以统计matrix/array的 ...

  2. Eigen教程(6)

    整理下Eigen库的教程,参考:http://eigen.tuxfamily.org/dox/index.html 高级初始化方法 本篇介绍几种高级的矩阵初始化方法,重点介绍逗号初始化和特殊矩阵(单位 ...

  3. Eigen教程(11)

    整理下Eigen库的教程,参考:http://eigen.tuxfamily.org/dox/index.html 存储顺序 对于矩阵和二维数组有两种存储方式,列优先和行优先. 假设矩阵: 按行优先存 ...

  4. Eigen教程(9)

    整理下Eigen库的教程,参考:http://eigen.tuxfamily.org/dox/index.html Eigen并没有为matrix提供直接的Reshape和Slicing的API,但是 ...

  5. Eigen教程(10)

    整理下Eigen库的教程,参考:http://eigen.tuxfamily.org/dox/index.html 混淆 在Eigen中,当变量同时出现在左值和右值,赋值操作可能会带来混淆问题.这一篇 ...

  6. Eigen教程(8)

    整理下Eigen库的教程,参考:http://eigen.tuxfamily.org/dox/index.html 原生缓存的接口:Map类 这篇将解释Eigen如何与原生raw C/C++ 数组混合 ...

  7. Eigen教程(5)

    整理下Eigen库的教程,参考:http://eigen.tuxfamily.org/dox/index.html 块操作 块是matrix或array中的矩形子部分. 使用块 函数.block(), ...

  8. Eigen教程(4)

    整理下Eigen库的教程,参考:http://eigen.tuxfamily.org/dox/index.html Array类和元素级操作 为什么使用Array 相对于Matrix提供的线性代数运算 ...

  9. Eigen教程(2)

    整理下Eigen库的教程,参考:http://eigen.tuxfamily.org/dox/index.html Matrix类 在Eigen,所有的矩阵和向量都是Matrix模板类的对象,Vect ...

随机推荐

  1. shiro过滤器过滤属性含义

    securityManager:这个属性是必须的. loginUrl :没有登录的用户请求需要登录的页面时自动跳转到登录页面,不是必须的属性,不输入地址的话会自动寻找项目web项目的根目录下的”/lo ...

  2. 中小研发团队架构实践之生产环境诊断工具WinDbg 三分钟学会.NET微服务之Polly 使用.Net Core+IView+Vue集成上传图片功能 Fiddler原理~知多少? ABP框架(asp.net core 2.X+Vue)模板项目学习之路(一) C#程序中设置全局代理(Global Proxy) WCF 4.0 使用说明 如何在IIS上发布,并能正常访问

    中小研发团队架构实践之生产环境诊断工具WinDbg 生产环境偶尔会出现一些异常问题,WinDbg或GDB是解决此类问题的利器.调试工具WinDbg如同医生的听诊器,是系统生病时做问题诊断的逆向分析工具 ...

  3. 还没被玩坏的robobrowser(3)——简单的spider

    背景 做一个简单的spider用来获取python selenium实战教程的一些基本信息.因为python selenium每年滚动开课,所以做这样一个爬虫随时更新最新的开课信息是很有必要的. 预备 ...

  4. 整合大量开源库项目(八)能够载入Gif动画的GifImageView

    转载请注明出处王亟亟的大牛之路 上周大多数时间都是依据兴起,想到什么做什么写了几个自己定义控件,把Soyi丢在那没怎么动,今天就把写的东西整合进来,顺便把SOyi"个人研发的结构理一下&qu ...

  5. root用户Linux 环境变量的配置解决(-bash: jps: command not found)有关问题

    可以写成:$JAVA_HOME/bin 3. source /root/.bash_profile 发现 jps 等命令运行正常了

  6. Java 垃圾回收思维导图

    文 by / 林本托 Tips 做一个终身学习的人. Java 的垃圾回收,不像 C和 C++语言,内存的分配和释放都是靠程序员来控制的.而 Java 的内存回收,程序员是不能也是无法干预,具体什么时 ...

  7. flowable 中task的相关操作

    1 获取任务列表 1)获取候选人的任务列表 TaskService taskService = processEngine.getTaskService(); List<Task> tas ...

  8. springboot 整合 Redis 方法二

    方法一请参考之前博文 spring boot 整合 redis 自己的版本  java8 + redis3.0 + springboot 2.0.0 1 spring boot已经支持集成 redis ...

  9. iphone5刷机教程

    如果不想麻烦可以在越狱之后添加源,cydia.china3gpp.com打ios7的补丁就可以了 机器为iphone5 美国sprint有锁版 1. 首先备份需要的程序和数据(把各种缓存的影片删掉再备 ...

  10. constexpr与常量表达式(c++11标准)

    关键字 constexpr 是C++11中引入的关键字,是指值不会改变并且在编译过程中就得到计算结果的表达式.(运行中得到结果的不能成为常量表达式,比如变量). 声明为constexpr的变量一定是一 ...