本章介绍Eigen中的归约( Reductions
),迭代器( Visitors
) 和广播( Broadcasting
)机制,以及它们是如何应用与矩阵和数组的。
归约 归约指的是一类以矩阵或数组作为输入,返回一个标量值的函数。
常用归约函数 .sum()
.prod()
.mean()
.minCoeff()
.maxCoeff()
.trace()
范数计算
.norm()
: L-2 范数(所有系数平方和开根号)
.squaredNorm()
: L-2 范数的平方(所有系数平方和)
.lpNorm<p>()
: P范数(所有系数绝对值的p次幂之和的p次根),当 p=Infinity
时表示所有系数绝对值的最大值
逻辑归约函数
.all()
: Matrix 或 Array 的所有系数均为 true 时返回 true
.any()
: Matrix 或 Array 存在某个系数为 true 时返回 true
.count()
: 返回 Matrix 或 Array 中为 true 的系数总个数
1 2 3 4 5 6 7 8 9 10 11 12 13 int main () { ArrayXXf a (2 ,2 ) ; a << 1 ,2 , 3 ,4 ; cout << "(a > 0).all() = " << (a > 0 ).all () << endl; cout << "(a > 0).any() = " << (a > 0 ).any () << endl; cout << "(a > 0).count() = " << (a > 0 ).count () << endl; cout << endl; cout << "(a > 2).all() = " << (a > 2 ).all () << endl; cout << "(a > 2).any() = " << (a > 2 ).any () << endl; cout << "(a > 2).count() = " << (a > 2 ).count () << endl; }
输出:
1 2 3 4 5 6 7 (a > 0).all() = 1 (a > 0).any() = 1 (a > 0).count() = 4 (a > 2).all() = 0 (a > 2).any() = 1 (a > 2).count() = 2
部分归约 部分归约是可以对矩阵或数组按列或行进行操作的归约,对每个列或行应用归约运算,然后返回具有相应值的列或行向量。部分归约由函数 .colwise()
和 rowwise()
实现:
1 2 3 4 5 6 7 8 9 10 int main () { Eigen::MatrixXf mat (2 ,4 ) ; mat << 1 , 2 , 6 , 9 , 3 , 1 , 7 , 2 ; cout << "Column's maximum: " << endl << mat.colwise ().maxCoeff () << endl; cout << "Row's maximum: " << endl << mat.rowwise ().maxCoeff () << endl; }
输出:
1 2 3 4 5 Column's maximum: 3 2 7 9 Row' s maximum: 9 7
显然:列操作返回行向量,行操作返回列向量
将部分归约与其他操作结合 例:寻找系数和最大的列
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 int main () { MatrixXf mat (2 ,4 ) ; mat << 1 , 2 , 6 , 9 , 3 , 1 , 7 , 2 ; MatrixXf::Index maxIndex; float maxNorm = mat.colwise ().sum ().maxCoeff (&maxIndex); cout << "Maximum sum at position " << maxIndex << endl; cout << "The corresponding vector is: " << endl; cout << mat.col ( maxIndex ) << endl; cout << "And its sum is is: " << maxNorm << endl; }
输出:
1 2 3 4 5 Maximum sum at position 2 The corresponding vector is: 6 7 And its sum is is: 13
迭代器 最常用的就是利用visitor机制获取矩阵/数组中最大值/最小值的位置,交给一个visitor的参数是指向存储行列位置变量的指针,变量类型为 Index
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 int main () { Eigen::MatrixXf m (2 ,2 ) ; m << 1 , 2 , 3 , 4 ; MatrixXf::Index maxRow, maxCol; float max = m.maxCoeff (&maxRow, &maxCol); MatrixXf::Index minRow, minCol; float min = m.minCoeff (&minRow, &minCol); cout << "Max: " << max << ", at: " << maxRow << "," << maxCol << endl; cout << "Min: " << min << ", at: " << minRow << "," << minCol << endl; }
输出:
1 2 Max: 4, at: 1,1 Min: 1, at: 0,0
广播 广播机制类似于部分规约,区别在于广播构造了一个表达式,其中向量被解释成了一个矩阵,这个矩阵由向量在行/列方向上复制自身形成。
加减(+、-、+=、-=) 只能用于Vector类型的对象!!!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 int main () { Eigen::MatrixXf mat (2 ,4 ) ; Eigen::VectorXf v (2 ) ; mat << 1 , 2 , 6 , 9 , 3 , 1 , 7 , 2 ; v << 0 , 1 ; mat.colwise () += v; cout << "Broadcasting result: " << endl; cout << mat << endl; Eigen::VectorXf w (4 ) ; w << 0 ,1 ,2 ,3 ; mat.rowwise () += v.transpose (); cout << "Broadcasting result: " << endl; cout << mat << endl; }
输出:
1 2 3 4 5 6 Broadcasting result: 1 2 6 9 4 2 8 3 Broadcasting result: 1 3 8 12 4 3 10 6
在执行 mat.colwise() += v
时,相当于进行了两步操作,首先将向量 v
在行方向上复制了4次形成了一个新的4x2的矩阵,再将这个矩阵和矩阵 mat
进行加法操作:
只有向量才能进行按行列加减,不能是矩阵,否则会报编译错误;
Array类同理,只能对 ArrayXf
执行这种操作
乘除(、/、\ =、/=) 按行/按列执行系数级乘法除法运算。
只能用于 Array 类型的对象!!!
如果想让矩阵第 i
列乘上向量的第 i
个系数,应该写成 mat = mat * v.asDiagonal()
将广播与其他操作结合 例:在矩阵 m
中找到与向量 v
距离最近的列向量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 #include <iostream> #include <Eigen/Dense> using namespace std;using namespace Eigen; int main () { Eigen::MatrixXf m (2 ,4 ) ; Eigen::VectorXf v (2 ) ; m << 1 , 23 , 6 , 9 , 3 , 11 , 7 , 2 ; v << 2 , 3 ; MatrixXf::Index index; (m.colwise () - v).colwise ().squaredNorm ().minCoeff (&index); cout << "Nearest neighbour is column " << index << ":" << endl; cout << m.col (index) << endl; }
输出:
1 2 3 Nearest neighbour is column 0: 1 3