ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Eigen 矩阵基本运算

2022-07-06 15:32:10  阅读:194  来源: 互联网

标签:运算 matrix Eigen 矩阵 Here mat


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

1. 介绍

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

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

2. 加减

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

二元运算 + 如a+b
二元运算 - 如a-b
一元运算 - 如-a
复合运算 += 如a+=b
复合运算 -= 如a-=b

 1 #include <iostream>
 2  
 3 #include <Eigen/Dense>
 4  
 5 using namespace Eigen;
 6  
 7 int main()
 8  
 9 {
10  
11   Matrix2d a;
12  
13   a << 1, 2,
14  
15        3, 4;
16  
17   MatrixXd b(2,2);
18  
19   b << 2, 3,
20  
21        1, 4;
22  
23   std::cout << "a + b =\n" << a + b << std::endl;
24  
25   std::cout << "a - b =\n" << a - b << std::endl;
26  
27   std::cout << "Doing a += b;" << std::endl;
28  
29   a += b;
30  
31   std::cout << "Now a =\n" << a << std::endl;
32  
33   Vector3d v(1,2,3);
34  
35   Vector3d w(1,0,0);
36  
37   std::cout << "-v + w - v =\n" << -v + w - v << std::endl;
38  
39 }

输出:

a + b =

3 5

4 8

a - b =

-1 -1

2 0

Doing a += b;

Now a =

3 5

4 8

-v + w - v =

-1

-4

-6

3. 标量乘法和除法

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

二元运算 * 如matrix*scalar
二元运算 * 如scalar*matrix
二元运算 / 如matrix/scalar
复合运算 *= 如matrix*=scalar
复合运算 /= 如matrix/=scalar

 1 #include <iostream>
 2  
 3 #include <Eigen/Dense>
 4  
 5 using namespace Eigen;
 6  
 7 int main()
 8  
 9 {
10  
11   Matrix2d a;
12  
13   a << 1, 2,
14  
15        3, 4;
16  
17   Vector3d v(1,2,3);
18  
19   std::cout << "a * 2.5 =\n" << a * 2.5 << std::endl;
20  
21   std::cout << "0.1 * v =\n" << 0.1 * v << std::endl;
22  
23   std::cout << "Doing v *= 2;" << std::endl;
24  
25   v *= 2;
26  
27   std::cout << "Now v =\n" << v << std::endl;
28  
29 }

结果

a * 2.5 =

2.5 5

7.5 10

0.1 * v =

0.1

0.2

0.3

Doing v *= 2;

Now v =

2

4

6

4. 表达式模板

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

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

VectorXf a(50), b(50), c(50), d(50);

...

a = 3*b + 4*c + 5*d;

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

for(int i = 0; i < 50; ++i)

a[i] = 3*b[i] + 4*c[i] + 5*d[i];

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

5. 转置和共轭

表示transpose转置

表示conjugate共轭

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

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

输出

Here is the matrix a

(-0.211,0.68) (-0.605,0.823)

(0.597,0.566) (0.536,-0.33)

Here is the matrix a^T

(-0.211,0.68) (0.597,0.566)

(-0.605,0.823) (0.536,-0.33)

Here is the conjugate of a

(-0.211,-0.68) (-0.605,-0.823)

(0.597,-0.566) (0.536,0.33)

Here is the matrix a^*

(-0.211,-0.68) (0.597,-0.566)

(-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  
3 cout << "Here is the matrix a:\n" << a << endl;
4  
5 a = a.transpose(); // !!! do NOT do this !!!
6  
7 cout << "and the result of the aliasing effect:\n" << a << endl;

Here is the initial matrix a:

1 2 3

4 5 6

and after being transposed:

1 4

2 5

3 6

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

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

二元运算 *如a*b
复合运算 *=如a*=b

 1 #include <iostream>
 2  
 3 #include <Eigen/Dense>
 4  
 5 using namespace Eigen;
 6  
 7 int main()
 8  
 9 {
10  
11   Matrix2d mat;
12  
13   mat << 1, 2,
14  
15          3, 4;
16  
17   Vector2d u(-1,1), v(2,0);
18  
19   std::cout << "Here is mat*mat:\n" << mat*mat << std::endl;
20  
21   std::cout << "Here is mat*u:\n" << mat*u << std::endl;
22  
23   std::cout << "Here is u^T*mat:\n" << u.transpose()*mat << std::endl;
24  
25   std::cout << "Here is u^T*v:\n" << u.transpose()*v << std::endl;
26  
27   std::cout << "Here is u*v^T:\n" << u*v.transpose() << std::endl;
28  
29   std::cout << "Let's multiply mat by itself" << std::endl;
30  
31   mat = mat*mat;
32  
33   std::cout << "Now mat is mat:\n" << mat << std::endl;
34  
35 }

输出

Here is mat*mat:

7 10

15 22

Here is mat*u:

1

1

Here is u^T*mat:

2 2

Here is u^T*v:

-2

Here is u*v^T:

-2 -0

2 0

Let's multiply mat by itself

Now mat is mat:

7 10

15 22

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

tmp = m*m

m = tmp

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

7. 点运算和叉运算

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

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

输出

Dot product: 8

Dot product via a matrix product: 8

Cross product:

1

-2

1

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

8. 基础的归约操作

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

 1 #include <iostream>
 2  
 3 #include <Eigen/Dense>
 4  
 5 using namespace std;
 6  
 7 int main()
 8  
 9 {
10  
11   Eigen::Matrix2d mat;
12  
13   mat << 1, 2,
14  
15          3, 4;
16  
17   cout << "Here is mat.sum():       " << mat.sum()       << endl;
18  
19   cout << "Here is mat.prod():      " << mat.prod()      << endl;
20  
21   cout << "Here is mat.mean():      " << mat.mean()      << endl;
22  
23   cout << "Here is mat.minCoeff():  " << mat.minCoeff()  << endl;
24  
25   cout << "Here is mat.maxCoeff():  " << mat.maxCoeff()  << endl;
26  
27   cout << "Here is mat.trace():     " << mat.trace()     << endl;
28  
29 }

输出

Here is mat.sum(): 10

Here is mat.prod(): 24

Here is mat.mean(): 2.5

Here is mat.minCoeff(): 1

Here is mat.maxCoeff(): 4

Here is mat.trace(): 5

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

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

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

输出

Here is the matrix m:

0.68 0.597 -0.33

-0.211 0.823 0.536

0.566 -0.605 -0.444

Its minimum coefficient (-0.605) is at position (2,1)

 

Here is the vector v: 1 0 3 -3

Its maximum coefficient (3) is at position 2

9. 操作的有效性

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

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

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

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

 

标签:运算,matrix,Eigen,矩阵,Here,mat
来源: https://www.cnblogs.com/ybqjymy/p/16450957.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有