6. Reductions, visitors和broadcasting
本章介绍Eigen的Reductions, visitors和broadcasting(不知道该怎么翻译了:),以及Matrix和Array如何使用这些功能。
6.1 Reductions
在Eigen中reduction是一种Matrix或者是Array的函数,他们把一个Matrix或者Array映射为一个数。
其中最常用的reduction的操作是.sum(),它将返回Matrix或者Array中所有元素的和。下面的例程中列举了一些常用的reduction操作。
#include <iostream>
#include <Eigen/Dense>
using namespace std;
int main()
{
Eigen::Matrix2d mat;
mat << 1, 2,
3, 4;
cout << "Here is mat.sum(): " << mat.sum() << endl;
cout << "Here is mat.prod(): " << mat.prod() << endl;
cout << "Here is mat.mean(): " << mat.mean() << endl;
cout << "Here is mat.minCoeff(): " << mat.minCoeff() << endl;
cout << "Here is mat.maxCoeff(): " << mat.maxCoeff() << endl;
cout << "Here is mat.trace(): " << mat.trace() << endl;
}
|
输出结果如下:
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
|
6.1.1 范数运算
函数squaredNorm()可以用来求取一个向量的二范数(\(\ell^2\),Euclidean,欧氏距离),数学上为向量自己对自己的点积,
即向量各个元素的平方和。Eigen还提供.norm(),返回向量二范数的平方根。这一操作,也可以用于矩阵,
对于一个\(m\)行\(n\)列的矩阵可以看做一个具有\(m \times n\)的向量,所以.norm()返回的是"Frobenius"范数。
Eigen还提供了函数lpNorm<p>()来求\(\ell^p\)范数。如果模板参数p是Infinity的话,求取的则是\(\ell^\infty\)范数,
它返回的是所有元素中最大的绝对值。
#include <iostream>
#include <Eigen/Dense>
using namespace std;
using namespace Eigen;
int main()
{
VectorXf v(2);
MatrixXf m(2,2), n(2,2);
v << -1,
2;
m << 1,-2,
-3,4;
cout << "v.squaredNorm() = " << v.squaredNorm() << endl;
cout << "v.norm() = " << v.norm() << endl;
cout << "v.lpNorm<1>() = " << v.lpNorm<1>() << endl;
cout << "v.lpNorm() = " << v.lpNorm() << endl;
cout << endl;
cout << "m.squaredNorm() = " << m.squaredNorm() << endl;
cout << "m.norm() = " << m.norm() << endl;
cout << "m.lpNorm<1>() = " << m.lpNorm<1>() << endl;
cout << "m.lpNorm() = " << m.lpNorm() << endl;
}
|
输出结果如下:
v.squaredNorm() = 5
v.norm() = 2.23607
v.lpNorm<1>() = 3
v.lpNorm<Infinity>() = 2
m.squaredNorm() = 30
m.norm() = 5.47723
m.lpNorm<1>() = 10
m.lpNorm<Infinity>() = 4
|
6.1.3 关于逻辑的reduction操作
Eigen提供如下的一些用于逻辑判断的reduction操作:
- all(). 如果给定的Matrix或者Array都为true则返回true
- any(). 如果给定的Matrix或者Array中至少有一个元素为true则返回true
- count(). 返回满足条件的元素个数
由于Array的coefficient-wise运算返回的是一个与原Array相同大小的Array,例如array > 0的运算结果就是一个Array,
其中对应于array中正数的元素的值为true。因此我们可以用形如(array > 0).all()的形式判断Array中的所有元素是否全为正数。
#include <iostream>
#include <Eigen/Dense>
using namespace std;
using namespace Eigen;
int main()
{
Array22f a;
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;
Matrix2f b;
b << 0,2,
3,4;
cout << "b.all() = " << b.all() << endl;
cout << "b.any() = " << b.any() << endl;
cout << "b.count() = " << b.count() << endl;
}
|
输出结果如下:
(a > 0).all() = 1
(a > 0).any() = 1
(a > 0).count() = 4
(a > 2).all() = 0
(a > 2).any() = 1
(a > 2).count() = 2
b.all() = 0
b.any() = 1
b.count() = 3
|
6.1.4 局部reduction
局部reduction是指对Matrix或者Array按行或者按列进行约减,借助colwise()或者rowwise()实现。
参考如下的代码,需要注意的是按行约减得到的是一个列向量,按列约减得到的是一个行向量。
#include <iostream>
#include <Eigen/Dense>
using namespace std;
using namespace Eigen;
int main()
{
MatrixXf m(2,4);
m << 1, 2, 6, 9,
3, 1, 7, 0;
cout << "Column's maximum: " << endl
<< m.colwise().maxCoeff() << endl;
cout << "Row's maximum: " << endl
<< m.rowwise().maxCoeff() << endl;
cout << "Column's all: " << endl
<< m.colwise().all() << endl;
}
|
输出结果如下:
Column's maximum:
3 2 7 9
Row's maximum:
9
7
Column's all:
1 1 1 0
|
我们也可以把局部约减的结果拿来做进一步的处理。
下面这个例子可以用来求取元素和最大的列:
#include <iostream>
#include <Eigen/Dense>
using namespace std;
using namespace Eigen;
int main()
{
MatrixXf m(2,4);
m << 1, 2, 6, 9,
3, 1, 7, 0;
MatrixXf::Index maxIndex;
float maxNorm = m.colwise().sum().maxCoeff(&maxIndex);
cout << "Maximum sum at column " << maxIndex << endl;
cout << "The corresponding vector is: " << endl;
cout << m.col(maxIndex) << endl;
cout << "and its sum is: " << maxNorm << endl;
}
|
输出结果如下:
Maximum sum at column 2
The corresponding vector is:
6
7
and its sum is: 13
|
在这个例子中,先通过colwise()访问器按行求取每一列的元素的和得到一个\(1\times4\)的行向量[4, 3, 13, 9]。
然后利用maxCoeff求取其中的最大值及其位置索引。
6.2 visitors
Visitor一般被用来获取Matrix或者Array中元素的位置索引。
一个最简单的例子就是maxCoeff(&x, &y)和minCoeff(&x, &y),
它们在求得Matrix或者Array中的最大和最小元素的同时还将通过x,y返回元素的位置索引。
Visitor的参数是Index类型的指针。
#include <iostream>
#include <Eigen/Dense>
using namespace std;
using namespace Eigen;
int main()
{
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;
}
|
输出结果如下:
Max: 4, at: 1,1
Min: 1, at: 0,0
|
6.3 Broadcasting
Broadcasting与局部约简的概念类似,按行或者列对Matrix或者Array进行操作。
所不同的是Broadcasting是按行或者列的形式与一个向量进行运算,
局部约简则是对Matrix或者Array自身的运算。
下面是一个简单的例程。把一个矩阵的每一列都与一个向量相加,
把一个Array的每一列的元素都与一个向量中对应位置上的元素相乘。
#include <iostream>
#include <Eigen/Dense>
using namespace std;
using namespace Eigen;
int main()
{
MatrixXf m(2,4);
VectorXf v(2);
ArrayXXf a(2,4);
m << 1, 2, 6, 9,
3, 1, 7, 2;
a << 1, 2, 6, 9,
3, 1, 7, 2;
v << 0,
1;
m.colwise() += v;
a.colwise() *= v.array();
cout << "m: " << endl;
cout << m << endl;
cout << "a: " << endl;
cout << a << endl;
}
|
输出结果如下:
m:
1 2 6 9
4 2 8 3
a:
0 0 0 0
3 1 7 2
|
对于Array,可以应用运算符[*]和[/],对每一列或者行中的元素分别与向量的对应元素相乘或相除。
但对于Matrix则不可以应用这两个运算符作Broadcasting,
因为Matrix或者Vector本身对于乘除运算有数学上的定义,这样做会产生歧义。
有一点需要注意的是,用于Broadcasting的向量一定是Vector类型的数据,不可以是Matrix。
Broadcasting运算之后也可以直接进行其他形式的运算。
下面这个例子包含了前面介绍的约简以及部分约简的运算,
最终求出一个矩阵中与一向量欧式距离最近的一列。
#include <iostream>
#include <Eigen/Dense>
using namespace std;
using namespace Eigen;
int main()
{
MatrixXf m(2,4);
VectorXf v(2);
m << 1, 23, 6, 9,
3, 11, 7, 2;
v << 2,
3;
MatrixXf::Index i;
(m.colwise() - v).colwise().squaredNorm().minCoeff(&i);
cout << "The nearest neighbour is column " << i << ":" << endl;
cout << m.col(i) << endl;
}
|
输出结果如下:
The nearest neighbour is column 0:
1
3
|