Eigen学习笔记7:Reductions, visitors and broadcasting

Reductions

In Eigen, a reduction is a function taking a matrix or array, and returning a single scalar value.最常用的归约方法之一是.sum(),它返回给定矩阵或数组内所有元素的总和。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#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;
}

输出:

1
2
3
4
5
6
ere 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

The trace of a matrix, as returned by the function trace(), is the sum of the diagonal coefficients and can equivalently be computed a.diagonal().sum().

范数计算

向量的平方范数可以通过squaredNorm()获得。它其系数的平方的绝对值之和。

Eigen还提供了norm()方法,该方法返回squaredNorm()的平方根。

这些运算也可以在矩阵上运算。在这种情况下,n×p矩阵被视为大小为(n * p)的向量,因此例如norm()方法返回“ Frobenius”或“ Hilbert-Schmidt”范数。

如果你想使用其他Lp范数,可以使用lpNorm< p >()方法。

p可以取Infinity,which is the maximum of the absolute values of the coefficients.

下面的示例演示了这些方法。

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
28
#include <Eigen/Dense>
#include <iostream>

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<Infinity>() = " << v.lpNorm<Infinity>() << 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<Infinity>() = " << m.lpNorm<Infinity>() << 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
28
#include <Eigen/Dense>
#include <iostream>

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<Infinity>() = " << v.lpNorm<Infinity>() << 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<Infinity>() = " << m.lpNorm<Infinity>() << endl;
}

Operator norm: 1-norm和∞-norm可以通过其他方式得到。

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
28
#include <Eigen/Dense>
#include <iostream>

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<Infinity>() = " << v.lpNorm<Infinity>() << 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<Infinity>() = " << m.lpNorm<Infinity>() << endl;
}

输出:

1
2
1-norm(m)     = 6 == 6
infty-norm(m) = 7 == 7

有关这些表达式的语法的更多说明,请参见下文。

Boolean reductions

以下归约运算适用于布尔值:

  • all() returns true if all of the coefficients in a given Matrix or Array evaluate to true .
  • any() returns true if at least one of the coefficients in a given Matrix or Array evaluates to true .
  • count() returns the number of coefficients in a given Matrix or Array that evaluate to true.

这些通常与Array提供的按元素比较和相等运算符结合使用。

For instance, array > 0 is an Array of the same size as array , with true at those positions where the corresponding coefficient of array is positive. 因此,(array > 0).all()测试的所有系数是否array均为正。

在以下示例中可以看到:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <Eigen/Dense>
#include <iostream>

using namespace std;
using namespace Eigen;

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

用户定义的Reductions

查看DenseBase :: redux()函数。

Visitors

Visitors are useful when one wants to obtain the location of a coefficient inside a Matrix or Array.

最简单的示例是maxCoeff(&x,&y)和minCoeff(&x,&y),用于查找Matrix或Array中最大或最小元素的位置。

传递给Visitors的参数是指向要存储行和列位置变量的指针。这些变量应为Index类型,如下所示:

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
#include <iostream>
#include <Eigen/Dense>

using namespace std;
using namespace Eigen;

int main()
{
    Eigen::MatrixXf m(2,2);

    m << 1, 2,
         3, 4;

    //get location of maximum
    MatrixXf::Index maxRow, maxCol;
    float max = m.maxCoeff(&maxRow, &maxCol);

    //get location of minimum
    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

Partial reductions

Partial reductions是可以在Matrix或Array上按列或按行操作的reductions,对每个列或行应用reductions运算,并返回具有相应值的列或行向量。Partial reductions适用于colwise()或rowwise()。

一个简单的示例是获取给定矩阵中每一列中元素的最大值,并将结果存储在行向量中:

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>
#include <Eigen/Dense>

using namespace std;
int main()
{
    Eigen::MatrixXf mat(2,4);
    mat << 1, 2, 6, 9,
           3, 1, 7, 2;

    std::cout << "Column's maximum: " << std::endl
              << mat.colwise().maxCoeff() << std::endl;
}

输出:

1
2
Column's maximum:
3 2 7 9

可以逐行执行相同的操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>
#include <Eigen/Dense>

using namespace std;
int main()
{
    Eigen::MatrixXf mat(2,4);
    mat << 1, 2, 6, 9,
           3, 1, 7, 2;

    std::cout << "Row's maximum: " << std::endl
              << mat.rowwise().maxCoeff() << std::endl;
}

输出:

1
2
3
Row's maximum:
9
7

Note that column-wise operations return a row vector, while row-wise operations return a column vector.

将Partial reductions与其他操作结合起来

将Partial reductions的结果进行进一步处理。

Here is another example that finds the column whose sum of elements is the maximum within a matrix. With column-wise partial reductions this can be coded as:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
#include <Eigen/Dense>

using namespace std;
using namespace Eigen;
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);

    std::cout << "Maximum sum at position " << maxIndex << std::endl;

    std::cout << "The corresponding vector is: " << std::endl;
    std::cout << mat.col( maxIndex ) << std::endl;
    std::cout << "And its sum is is: " << maxNorm << std::endl;
}

输出:

1
2
3
4
5
Maximum sum at position 2
The corresponding vector is:
6
7
And its sum is is: 13

广播

广播背后的概念类似于 partial reductions,with the difference that broadcasting constructs an expression where a vector (column or row) is interpreted as a matrix by replicating it in one direction.

一个简单的示例是将某个列向量添加到矩阵中的每一列。这可以通过以下方式完成:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
#include <Eigen/Dense>

using namespace std;
int main()
{
    Eigen::MatrixXf mat(2,4);
    Eigen::VectorXf v(2);

    mat << 1, 2, 6, 9,
           3, 1, 7, 2;

    v << 0,
         1;

    //add v to each column of m
    mat.colwise() += v;

    std::cout << "Broadcasting result: " << std::endl;
    std::cout << mat << std::endl;
}

输出:

1
2
3
Broadcasting result:
1 2 6 9
4 2 8 3

要指出的是,要逐列或逐行添加的向量必须为Vector类型,并且不能为Matrix。如果不满足,则会出现编译时错误。这也意味着,在使用Matrix进行操作时,只能对Vector类型的对象应用广播操作。这同样适用于Array类,其中等效VectorXf是ArrayXf。与往常一样,您不应在同一表达式中混合使用数组和矩阵。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
#include <Eigen/Dense>

using namespace std;
int main()
{
    Eigen::MatrixXf mat(2,4);
    Eigen::VectorXf v(4);

    mat << 1, 2, 6, 9,
           3, 1, 7, 2;

    v << 0,1,2,3;

    //add v to each row of m
    mat.rowwise() += v.transpose();

    std::cout << "Broadcasting result: " << std::endl;
    std::cout << mat << std::endl;
}

输出:

1
2
3
Broadcasting result:
 1  3  8 12
 3  2  9  5

将广播与其他操作结合

Broadcasting can also be combined with other operations, such as Matrix or Array operations, reductions and partial reductions.我们可以深入研究一个更高级的示例:

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;
    // find nearest neighbour
    (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