mirror of
https://gitlab.com/libeigen/eigen.git
synced 2025-08-11 19:29:02 +08:00
Reductions/Broadcasting/Visitor Tutorial added
This commit is contained in:
parent
2066ed91de
commit
9852e7b9cb
199
doc/C07_TutorialReductionsVisitorsBroadcasting.dox
Normal file
199
doc/C07_TutorialReductionsVisitorsBroadcasting.dox
Normal file
@ -0,0 +1,199 @@
|
||||
namespace Eigen {
|
||||
|
||||
/** \page TutorialReductionsVisitorsBroadcasting Tutorial page 7 - Reductions, visitors and broadcasting
|
||||
\ingroup Tutorial
|
||||
|
||||
\li \b Previous: \ref TutorialAdvancedInitialization
|
||||
\li \b Next: \ref TutorialLinearAlgebra
|
||||
|
||||
This tutorial explains Eigen's reductions, visitors and broadcasting and how they are used with
|
||||
\link MatrixBase matrices \endlink and \link ArrayBase arrays \endlink.
|
||||
|
||||
\b Table \b of \b contents
|
||||
- \ref TutorialReductionsVisitorsBroadcastingReductions
|
||||
- FIXME: .redux()
|
||||
- \ref TutorialReductionsVisitorsBroadcastingVisitors
|
||||
- \ref TutorialReductionsVisitorsBroadcastingPartialReductions
|
||||
- \ref TutorialReductionsVisitorsBroadcastingPartialReductionsCombined
|
||||
- \ref TutorialReductionsVisitorsBroadcastingBroadcasting
|
||||
- \ref TutorialReductionsVisitorsBroadcastingBroadcastingCombined
|
||||
|
||||
|
||||
\section TutorialReductionsVisitorsBroadcastingReductions Reductions
|
||||
In Eigen, a reduction is a function that is applied to a certain matrix or array, returning a single
|
||||
value of type scalar. One of the most used reductions is \link MatrixBase::sum() .sum() \endlink,
|
||||
which returns the addition of all the coefficients inside a given matrix or array.
|
||||
|
||||
<table class="tutorial_code"><tr><td>
|
||||
Example: \include tut_arithmetic_redux_basic.cpp
|
||||
</td>
|
||||
<td>
|
||||
Output: \include tut_arithmetic_redux_basic.out
|
||||
</td></tr></table>
|
||||
|
||||
The \em trace of a matrix, as returned by the function \c trace(), is the sum of the diagonal coefficients and can also be computed as efficiently using <tt>a.diagonal().sum()</tt>, as we will see later on.
|
||||
|
||||
\section TutorialReductionsVisitorsBroadcastingVisitors Visitors
|
||||
Visitors are useful when the location of a coefficient inside a Matrix or
|
||||
\link ArrayBase Array \endlink wants to be obtained. The simplest example are the
|
||||
\link MatrixBase::maxCoeff() maxCoeff(&x,&y) \endlink and
|
||||
\link MatrixBase::minCoeff() minCoeff(&x,&y) \endlink, that can be used to find
|
||||
the location of the greatest or smallest coefficient in a Matrix or
|
||||
\link ArrayBase Array \endlink:
|
||||
|
||||
The arguments passed to a visitor are pointers to the variables where the
|
||||
row and column position are to be stored. These variables are of type
|
||||
\link DenseBase::Index Index \endlink FIXME: link? ok?, as shown below:
|
||||
|
||||
<table class="tutorial_code"><tr><td>
|
||||
\include Tutorial_ReductionsVisitorsBroadcasting_visitors.cpp
|
||||
</td>
|
||||
<td>
|
||||
Output:
|
||||
\verbinclude Tutorial_ReductionsVisitorsBroadcasting_visitors.out
|
||||
</td></tr></table>
|
||||
|
||||
Note that both functions also return the value of the minimum or maximum coefficient if needed,
|
||||
as if it was a typical reduction operation.
|
||||
|
||||
\section TutorialReductionsVisitorsBroadcastingPartialReductions Partial reductions
|
||||
Partial reductions are reductions that can operate column- or row-wise on a Matrix or
|
||||
\link ArrayBase Array \endlink, applying the reduction operation on each column or row and
|
||||
returning a column or row-vector with the corresponding values. Partial reductions are applied
|
||||
with \link DenseBase::colwise() colwise() \endlink or \link DenseBase::rowwise() rowwise() \endlink.
|
||||
|
||||
A simple example is obtaining the sum of the elements
|
||||
in each column in a given matrix, storing the result in a row-vector:
|
||||
|
||||
<table class="tutorial_code"><tr><td>
|
||||
\include Tutorial_ReductionsVisitorsBroadcasting_colwise.cpp
|
||||
</td>
|
||||
<td>
|
||||
Output:
|
||||
\verbinclude Tutorial_ReductionsVisitorsBroadcasting_colwise.out
|
||||
</td></tr></table>
|
||||
|
||||
The same operation can be performed row-wise:
|
||||
|
||||
<table class="tutorial_code"><tr><td>
|
||||
\include Tutorial_ReductionsVisitorsBroadcasting_rowwise.cpp
|
||||
</td>
|
||||
<td>
|
||||
Output:
|
||||
\verbinclude Tutorial_ReductionsVisitorsBroadcasting_rowwise.out
|
||||
</td></tr></table>
|
||||
|
||||
<b>Note that column-wise operations return a 'row-vector' while row-wise operations
|
||||
return a 'column-vector'</b>
|
||||
|
||||
\subsection TutorialReductionsVisitorsBroadcastingPartialReductionsCombined Combining partial reductions with other operations
|
||||
It is also possible to use the result of a partial reduction to do further processing.
|
||||
Here there is another example that aims to find the the column whose sum of elements is the maximum
|
||||
within a matrix. With column-wise partial reductions this can be coded as:
|
||||
|
||||
<table class="tutorial_code"><tr><td>
|
||||
\include Tutorial_ReductionsVisitorsBroadcasting_maxnorm.cpp
|
||||
</td>
|
||||
<td>
|
||||
Output:
|
||||
\verbinclude Tutorial_ReductionsVisitorsBroadcasting_maxnorm.out
|
||||
</td></tr></table>
|
||||
|
||||
The previous example applies the \link DenseBase::sum() sum() \endlink reduction on each column
|
||||
though the \link DenseBase::colwise() colwise() \endlink visitor, obtaining a new matrix whose
|
||||
size is 1x4.
|
||||
|
||||
Therefore, if
|
||||
\f[
|
||||
\mbox{m} = \begin{bmatrix} 1 & 2 & 6 & 9 \\
|
||||
3 & 1 & 7 & 2 \end{bmatrix}
|
||||
\f]
|
||||
|
||||
then
|
||||
|
||||
\f[
|
||||
\mbox{m.colwise().sum()} = \begin{bmatrix} 4 & 3 & 13 & 11 \end{bmatrix}
|
||||
\f]
|
||||
|
||||
The \link DenseBase::maxCoeff() maxCoeff() \endlink reduction is finally applied
|
||||
to obtain the column index where the maximum sum is found,
|
||||
which is the column index 2 (third column) in this case.
|
||||
|
||||
|
||||
\section TutorialReductionsVisitorsBroadcastingBroadcasting Broadcasting
|
||||
The concept behind broadcasting is similar to 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.
|
||||
|
||||
A simple example is to add a certain column-vector to each column in a matrix.
|
||||
This can be accomplished with:
|
||||
|
||||
<table class="tutorial_code"><tr><td>
|
||||
\include Tutorial_ReductionsVisitorsBroadcasting_broadcast_simple.cpp
|
||||
</td>
|
||||
<td>
|
||||
Output:
|
||||
\verbinclude Tutorial_ReductionsVisitorsBroadcasting_broadcast_simple.out
|
||||
</td></tr></table>
|
||||
|
||||
It is important to point out that the vector to be added column-wise or row-wise must be of type Vector,
|
||||
and cannot be a Matrix. If this is not met then you will get compile-time error. This also means that
|
||||
broadcasting operations can only be applied with an object of type Vector, when operating with Matrix.
|
||||
The same applies for the \link ArrayBase Array \endlink class, where the equivalent for VectorXf is ArrayXf.
|
||||
|
||||
Therefore, to perform the same operation row-wise we can do:
|
||||
|
||||
<table class="tutorial_code"><tr><td>
|
||||
\include Tutorial_ReductionsVisitorsBroadcasting_broadcast_simple_rowwise.cpp
|
||||
</td>
|
||||
<td>
|
||||
Output:
|
||||
\verbinclude Tutorial_ReductionsVisitorsBroadcasting_broadcast_simple_rowwise.out
|
||||
</td></tr></table>
|
||||
|
||||
\subsection TutorialReductionsVisitorsBroadcastingBroadcastingCombined Combining broadcasting with other operations
|
||||
Broadcasting can also be combined with other operations, such as Matrix or \link ArrayBase Array \endlink operations,
|
||||
reductions and partial reductions.
|
||||
|
||||
Now that broadcasting, reductions and partial reductions have been introduced, we can dive into a more advanced example that finds
|
||||
the nearest neighbour of a vector <tt>v</tt> within the columns of matrix <tt>m</tt>. The Euclidean distance will be used in this example,
|
||||
computing the squared Euclidean distance with the partial reduction named \link DenseBase::squaredNorm() squaredNorm() \endlink:
|
||||
|
||||
<table class="tutorial_code"><tr><td>
|
||||
\include Tutorial_ReductionsVisitorsBroadcasting_broadcast_1nn.cpp
|
||||
</td>
|
||||
<td>
|
||||
Output:
|
||||
\verbinclude Tutorial_ReductionsVisitorsBroadcasting_broadcast_1nn.out
|
||||
</td></tr></table>
|
||||
|
||||
The line that does the job is
|
||||
\code
|
||||
(m.colwise() - v).colwise().squaredNorm().minCoeff(&index);
|
||||
\endcode
|
||||
|
||||
We will go step by step to understand what is happening:
|
||||
|
||||
- <tt>m.colwise() - v</tt> is a broadcasting operation, substracting <tt>v</tt> from each column in <tt>m</tt>. The result of this operation
|
||||
would be a new matrix whose size is the same as matrix <tt>m</tt>: \f[
|
||||
\mbox{m.colwise() - v} =
|
||||
\begin{bmatrix}
|
||||
-1 & 21 & 4 & 7 \\
|
||||
0 & 8 & 4 & -1
|
||||
\end{bmatrix}
|
||||
\f]
|
||||
|
||||
- <tt>(m.colwise() - v).colwise().squaredNorm()</tt> is a partial reduction, computing the squared norm column-wise. The result of
|
||||
this operation would be a row-vector where each coefficient is the squared Euclidean distance between each column in <tt>m</tt> and <tt>v</tt>: \f[
|
||||
\mbox{(m.colwise() - v).colwise().squaredNorm()} =
|
||||
\begin{bmatrix}
|
||||
1 & 505 & 32 & 50
|
||||
\end{bmatrix}
|
||||
\f]
|
||||
|
||||
- Finally, <tt>minCoeff(&index)</tt> is used to obtain the index of the column in <tt>m</tt> that is closer to <tt>v</tt> in terms of Euclidean
|
||||
distance.
|
||||
|
||||
*/
|
||||
|
||||
}
|
@ -0,0 +1,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;
|
||||
}
|
@ -0,0 +1,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, 2, 6, 9,
|
||||
3, 1, 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;
|
||||
}
|
@ -0,0 +1,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;
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
#include <iostream>
|
||||
#include <Eigen/Dense>
|
||||
|
||||
using namespace std;
|
||||
int main()
|
||||
{
|
||||
Eigen::MatrixXf mat(2,4);
|
||||
Eigen::MatrixXf 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;
|
||||
}
|
@ -0,0 +1,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;
|
||||
|
||||
std::cout << "Broadcasting result: " << std::endl;
|
||||
std::cout << mat << std::endl;
|
||||
}
|
@ -0,0 +1,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;
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
#include <iostream>
|
||||
#include <Eigen/Dense>
|
||||
|
||||
using namespace std;
|
||||
int main()
|
||||
{
|
||||
Eigen::MatrixXf mat(2,4);
|
||||
mat << 1, 2, 6, 9,
|
||||
3, 1, 7, 2;
|
||||
|
||||
int 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;
|
||||
}
|
@ -0,0 +1,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;
|
||||
}
|
@ -0,0 +1,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;
|
||||
}
|
@ -0,0 +1,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;
|
||||
m.maxCoeff(&maxRow, &maxCol);
|
||||
|
||||
//get location of minimum
|
||||
MatrixXf::Index minRow, minCol;
|
||||
m.minCoeff(&minRow, &minCol);
|
||||
|
||||
cout << "Max at: " <<
|
||||
maxRow << "," << maxCol << endl;
|
||||
cout << "Min at: " <<
|
||||
minRow << "," << minCol << endl;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user