当前位置:   article > 正文

C++——Eigen库的学习(3)_eigen dot

eigen dot

四、矩阵和向量的运算

这一小节主要介绍Eigen库对于矩阵运算的一些支持,基本和matlab里运算操作一致,便于数据运算,常见的包括矩阵的加减、矩阵的乘法、矩阵的转置与共轭等操作,下面将逐一介绍所有的操作符。

1.矩阵的加减

Eigen中进行矩阵的加减操作需要满足两点条件:1.进行加减操作的矩阵变量具有相同的尺寸(行和列);2.矩阵的元素类型相同(Eigen不自动转化类型),具体可以看下面的代码例子:

#include <iostream>
#include <Eigen/Dense>
using namespace Eigen;
int main()
{
    Eigen::Matrix2d a;  //定义一个2维矩阵
    a << 1,2,   //矩阵赋值
         3,4;

    Eigen::Matrix2d b;
    b << 2,3,
         1,4;

    std::cout << "a + b =\n" << a + b << std::endl; //执行矩阵 a+b
    std::cout << "**************************" << std::endl;
    std::cout << "a + b =\n" << a - b << std::endl; //执行矩阵 a-b
    std::cout << "**************************" << std::endl;

    a += b;
    std::cout << "执行a += b\n" << "现在a=\n" << a << std::endl; //执行矩阵 a+=b,会将结果赋值给a
    std::cout << "**************************" << std::endl;

    Eigen::Vector3d v(1, 2, 3); //定义3维列向量
    Eigen::Vector3d w(1, 0, 0);

    std::cout << "-v + w -v =\n" << -v + w -v << std::endl;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

特别注意执行 a+=b 的操作后会将结果赋值给a,下面是程序的输出结果:

a + b =
3 5
4 8
**************************
a + b =
-1 -1
 2  0
**************************
执行a += b
现在a=
3 5
4 8
**************************
-v + w -v =
-1
-4
-6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

2.矩阵-标量的乘除法

Eigen中对于矩阵的运算可以直接对矩阵与标量进行乘除法,相当于对矩阵中每个元素都进行乘除法,具体的内容看下面的代码:

#include <iostream>
#include <Eigen/Dense>
using namespace Eigen;
int main()
{
    Eigen::Matrix2d a;  //定义一个2维矩阵
    a << 1,2,   //矩阵赋值
         3,4;

    Eigen::Vector3d v(1, 2, 3); //定义3维列向量

    std::cout << "a * 2.5 =\n" << a * 2.5 << std::endl; //执行矩阵 a * 2.5
    std::cout << "**************************" << std::endl;
    std::cout << "0.1 * v =\n" << 0.1 * v << std::endl; //执行 0.1 * v
    std::cout << "**************************" << std::endl;

    v *= 2;
    std::cout << "执行v *= 2\n" << "现在v=\n" << v << std::endl; //执行向量 v *= 2,会将结果赋值给v
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

特别注意执行 v *= 2的操作后会将结果赋值给v,下面是程序的输出结果:

a * 2.5 =
2.5   5
7.5  10
**************************
0.1 * v =
0.1
0.2
0.3
**************************
执行v *= 2
现在v=
2
4
6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

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

Eigen库除了支持矩阵与标量的乘法,还支持矩阵与矩阵间的乘法,前提是满足矩阵乘法的维度大小,即满足a(m*n)b(nk)的形式,具体用法看下面的代码:

#include <iostream>
#include <Eigen/Dense>
using namespace Eigen;
int main()
{
    Eigen::Matrix2d a;  //定义一个2维矩阵
    a << 1,2,   //矩阵赋值
         3,4;

    Eigen::Vector2d u(-1, 1), v(2, 0); //定义2维列向量

    std::cout << "a * a =\n" << a * a << std::endl; //执行矩阵 a * a
    std::cout << "**************************" << std::endl;
    std::cout << "a * u =\n" << a * u << std::endl; //执行 a * u
    std::cout << "**************************" << std::endl;
    std::cout << "u^T * a =\n" << u.transpose() * a <<std::endl; //执行 u^T * a
    std::cout << "**************************" << std::endl;
    std::cout << "u^T * v =\n" << u.transpose() * v <<std::endl; //执行 u^T * v
    std::cout << "**************************" << std::endl;
    std::cout << "u * v^T =\n" << u * v.transpose() <<std::endl; //执行 u * v^T
    std::cout << "**************************" << std::endl;
    a = a * a;
    std::cout << "执行 a = a * a\n" << "现在a=\n" << a << std::endl;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

这个程序的输出结果如下:

a * a =
 7 10
15 22
**************************
a * u =
1
1
**************************
u^T * a =
2 2
**************************
u^T * v =
-2
**************************
u * v^T =
-2 -0
 2  0
**************************
执行 a = a * a
现在a=
 7 10
15 22
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

4.矩阵的点运算与叉运算

在Eigen库中,dot()执行点积,cross()执行叉积,点运算得到1*1的矩阵。

#include <iostream>
#include <Eigen/Dense>
using namespace Eigen;
int main()
{
    Eigen::Vector3d u(1, 2, 3), v(0, 1, 2); //定义2维列向量

    std::cout << "点乘:" << u.dot(v) << std::endl; //执行点乘
    std::cout << "**************************" << std::endl;
    std::cout << "叉乘:\n" << u.cross(v) << std::endl; //执行叉乘
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

输出的结果如下:

点乘:8
**************************
叉乘:
 1
-2
 1
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

5.矩阵的转置和共轭

具体用法看下面的示例代码:

#include <iostream>
#include <Eigen/Dense>
using namespace Eigen;
int main()
{
    Eigen::MatrixXcf a = MatrixXcf::Random(2,2);    //定义一个复数矩阵:MatrixXcf

    std::cout << "***************************" << std::endl;
    std::cout << "矩阵 a\n" << a << std::endl;
    std::cout << "***************************" << std::endl;
    std::cout << "矩阵 a 的转置 a^T\n" << a.transpose() << std::endl;
    std::cout << "***************************" << std::endl;
    std::cout << "矩阵 a 的共轭\n" << a.conjugate() << std::endl;
    std::cout << "***************************" << std::endl;
    std::cout << "矩阵 a 的共轭转置 a^*\n" << a.adjoint() << std::endl;
    std::cout << "***************************" << std::endl;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

输出结果如下:

***************************
矩阵 a
(-0.211234,0.680375) (-0.604897,0.823295)
  (0.59688,0.566198) (0.536459,-0.329554)
***************************
矩阵 a 的转置 a^T
(-0.211234,0.680375)   (0.59688,0.566198)
(-0.604897,0.823295) (0.536459,-0.329554)
***************************
矩阵 a 的共轭
(-0.211234,-0.680375) (-0.604897,-0.823295)
  (0.59688,-0.566198)   (0.536459,0.329554)
***************************
矩阵 a 的共轭转置 a^*
(-0.211234,-0.680375)   (0.59688,-0.566198)
(-0.604897,-0.823295)   (0.536459,0.329554)
***************************
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

注意共轭操作仅对复数矩阵有用,对于实数矩阵,共轭不执行任何操作,转置共轭操作等价于转置操作。

转置和共轭转置会返回一个代理对象并不对本身做转置。如果执行 b=a.transpose() ,a不变,转置结果被赋值给b。如果执行 a=a.transpose() ,Eigen在转置结束之前结果会开始写入a,所以a的最终结果不一定等于a的转置。切记千万不要这样做!!!!!!!!!

6.矩阵的基础归约操作

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

具体的使用案例看下面的代码例子:

#include <iostream>
#include <Eigen/Dense>
using namespace Eigen;
int main()
{
    Eigen::Matrix2d mat;    //定义一个2维矩阵
    mat << 1, 2,    //给2位矩阵赋值
           3, 4;

    std::cout << "***************************" << std::endl;
    std::cout << "mat.sum():       " << mat.sum()        << std::endl;
    std::cout << "***************************" << std::endl;
    std::cout << "mat.prod():      " << mat.prod()       << std::endl;
    std::cout << "***************************" << std::endl;
    std::cout << "mat.mean():      " << mat.mean()       << std::endl;
    std::cout << "***************************" << std::endl;
    std::cout << "mat.minCoeff():  " << mat.minCoeff()   << std::endl;
    std::cout << "***************************" << std::endl;
    std::cout << "mat.maxCoeff():  " << mat.maxCoeff()  << std::endl;
    std::cout << "***************************" << std::endl;
    std::cout << "mat.trace():     " << mat.trace()     << std::endl;
    std::cout << "***************************" << std::endl;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

输出结果为:

***************************
mat.sum():       10
***************************
mat.prod():      24
***************************
mat.mean():      2.5
***************************
mat.minCoeff():  1
***************************
mat.maxCoeff():  4
***************************
mat.trace():     5
***************************
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

7.表达式模板

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

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

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

Eigen会编译这段代码最终遍历一次即可运算完成,因此,我们不必要担心大的线性表达式的运算效率。

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

8.矩阵操作的有效性

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

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

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

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

更多技术欢迎加入交流:320297153

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/79257
推荐阅读
相关标签
  

闽ICP备14008679号