这章介绍Eigen中矩阵、向量和标量之间的运算。对Matrix类,运算符重载仅支持线性代数运算,例如矩阵x矩阵,而像向量+标量的操作是不允许的。Array类则允许执行所有的数组操作,见 The Array Class and Coefficient-wise Operations 。
加减法 Eigen不会自动执行类型转换,所以左右维度和数值类型必须保证相同。可用的操作符包括:
一元操作符 -
: -a
二元操作符 +
-
: a+b, a-b
复合操作符 +=
-=
: a+=b, a-=b
标量乘除 矩阵所有系数乘/除以该标量。可用操作符包括:
二元操作符 *
: matrix scalar, scalar matrix
二元操作符 /
: matrix / scalar
复合操作符 *=
/=
: matrix *= scalar, matrix /= scalar
转置与共轭
transpose()
: $\boldsymbol{a}^T$ (转置)
conjugate()
: $\overline{\boldsymbol{a}}$ (共轭)
adjoint()
: $\boldsymbol{a}^*$ (共轭转置)
显然,对实矩阵而言,conjugate()
并不执行什么操作,所以 adjoint()
完全等同于 transpose()
。
需要非常注意 的一点是,基本运算符 transpose()
和 adjoint()
仅仅返回一个代理对象,而并未进行实质的运算。例如,执行 b = a.transpose()
时,Eigen在将结果写入b的同时执行转置;从而引出另一个问题,如果执行 a = a.transpose()
,Eigen同样会在转置完成前开始将结果写入矩阵a,因此这句话不会像预期一样将a变为它的转置,反而会在执行过程中得到 aliasing issue
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 #include <iostream> #include <eigen3/Eigen/Eigen> using namespace std;int main () { Eigen::Matrix3i a; Eigen::Matrix3i b; a << 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ; cout << "origin matrix a:\n" << a << endl; b = a.transpose (); cout << "b as the transpose of matrix a:\n" << b << endl; a = a.transpose (); cout << "Here is the result of the aliasing effect:\n" << a << endl; return 0 ; }
输出:
1 2 3 4 5 6 7 8 9 10 origin matrix a: 1 2 3 4 5 6 7 8 9 b as the transpose of matrix a: 1 4 7 2 5 8 3 6 9 main: /usr/include/eigen3/Eigen/src/Core/Transpose.h:378: static void Eigen::internal::checkTransposeAliasing_impl<Derived, OtherDerived, MightHaveTransposeAliasing>::run(const Derived&, const OtherDerived&) [with Derived = Eigen::Matrix<int, 3, 3>; OtherDerived = Eigen::Transpose<Eigen::Matrix<int, 3, 3> >; bool MightHaveTransposeAliasing = true ]: Assertion `(!check_transpose_aliasing_run_time_selector <typename Derived::Scalar,blas_traits<Derived>::IsTransposed,OtherDerived> ::run(extract_data(dst), other)) && "aliasing detected during transposition, use transposeInPlace() " "or evaluate the rhs into a temporary using .eval()" ' failed. Aborted (core dumped)
所谓混叠问题 ,即 aliasing issue
,指的是在赋值表达式的左右两边存在矩阵的重叠区域,这种情况下,有可能得到非预期的结果,具体见 Aliasing 。
如果想执行就地转置(in-place transposition),调用 transposeInPlace()
方法:
1 2 3 a.transposeInPlace (); cout << "After being transposed:\n" << a << endl;
输出:
1 2 3 4 After being transposed: 1 4 7 2 5 8 3 6 9
同理,也有为复矩阵准备的就地共轭转置 adjointInPlace()
方法
矩阵-矩阵乘法乘法 向量是一种特殊的矩阵,因此矩阵-向量、向量-向量乘法也包括其中。可用操作符有:
二元操作符 *
: a*b
复合操作符 *=
: a*=b
执行操作 m = m * m
是安全的,因为Eigen将矩阵乘法当作一种特殊形式进行处理,会在编译时引入一个临时变量,所以不必担心会出现 aliasing issue
:
当然,如果你很清楚自己的矩阵乘法不会有引起 aliasing issue
的可能,也可以调用 noalias()
方法来避免引入临时变量:
向量点乘和叉乘 dot()
和 corss()
方法分别实现向量点乘和叉乘,当然,点乘也可以通过 u.adjoint()*v
实现,只不过返回的结果是个1x1的矩阵:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #include <iostream> #include <eigen3/Eigen/Eigen> using namespace std;using namespace Eigen;int main () { Vector3d v (1 , 2 , 3 ) ; Vector3d w (0 , 1 , 2 ) ; cout << "Dot product: " << v.dot (w) << endl; double dp = v.adjoint () * w; cout << "Dot product via a matrix product: " << dp << endl; cout << "Cross product:\n" << v.cross (w) << endl; return 0 ; }
输出:
1 2 3 4 5 6 Dot product: 8 Dot product via a matrix product: 8 Cross product: 1 -2 1
需要非常注意 的是,叉乘只能用于大小为3的向量 ;点乘则可用于任意大小的向量
基本算数归约运算 Eigen提供了一些归约运算(reduction operation),将给定的矩阵或向量归约为单个值,例如 sum()
, prod()
, maxCoeff()
, minCoeff()
, trace()
分别表示所有矩阵系数的和、积、最大值、最小值,以及矩阵的迹,矩阵的迹也可以通过 m.diagonal().sum()
求得。
通过向 maxCoeff()
或 minCoeff()
中传入 std::ptrdiff_t
类型的参数指针,可以得到对应最大值/最小值的坐标:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 #include <iostream> #include <eigen3/Eigen/Eigen> using namespace std;using namespace Eigen;int main () { Matrix3f m = Matrix3f::Random (); std::ptrdiff_t i, j; float minOfM = m.minCoeff (&i, &j); cout << "Here is the matrix m:\n" << m << endl; cout << "Its minimum coefficient (" << minOfM << ") is at position (" << i << "," << j << ")\n\n" ; RowVector4i v = RowVector4i::Random (); int maxOfV = v.maxCoeff (&i); cout << "Here is the vector v: " << v << endl; cout << "Its maximum coefficient (" << maxOfV << ") is at position " << i << endl; return 0 ; }
输出:
1 2 3 4 5 6 7 8 Here is the matrix m: 0.680375 0.59688 -0.329554 -0.211234 0.823295 0.536459 0.566198 -0.604897 -0.444451 Its minimum coefficient (-0.604897) is at position (2,1) Here is the vector v: 115899597 -48539462 276748203 -290373134 Its maximum coefficient (276748203) is at position 2
操作有效性 Eigen会在执行操作的时候检查有效性。
重要的编译错误信息会用大写突出出来。
但更多时候(例如检查动态大小的矩阵的操作),编译过程不会检查出错误。Eigen将在 debug mode
下使用 runtime assertions
让程序在运行过程中碰到非法操作的时候退出,同时报出错误信息。如果关掉assertions,程序很有可能会崩溃。