diff options
author | Carlos Becker <carlosbecker@gmail.com> | 2010-07-08 17:42:23 +0100 |
---|---|---|
committer | Carlos Becker <carlosbecker@gmail.com> | 2010-07-08 17:42:23 +0100 |
commit | 9852e7b9cbb6cbfbd9769642355bdac52eb4b4d7 (patch) | |
tree | f1dc86420adb6b9c7edbe07c86f3b2bf5120907b | |
parent | 2066ed91de31b118e20c40fdc74badac8d02dd22 (diff) |
Reductions/Broadcasting/Visitor Tutorial added
11 files changed, 406 insertions, 0 deletions
diff --git a/doc/C07_TutorialReductionsVisitorsBroadcasting.dox b/doc/C07_TutorialReductionsVisitorsBroadcasting.dox new file mode 100644 index 000000000..17124cb3b --- /dev/null +++ b/doc/C07_TutorialReductionsVisitorsBroadcasting.dox @@ -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. + +*/ + +} diff --git a/doc/examples/Tutorial_ReductionsVisitorsBroadcasting_broadcast_1nn.cpp b/doc/examples/Tutorial_ReductionsVisitorsBroadcasting_broadcast_1nn.cpp new file mode 100644 index 000000000..334b4d852 --- /dev/null +++ b/doc/examples/Tutorial_ReductionsVisitorsBroadcasting_broadcast_1nn.cpp @@ -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; +} diff --git a/doc/examples/Tutorial_ReductionsVisitorsBroadcasting_broadcast_1nn.cpp~ b/doc/examples/Tutorial_ReductionsVisitorsBroadcasting_broadcast_1nn.cpp~ new file mode 100644 index 000000000..de05ab961 --- /dev/null +++ b/doc/examples/Tutorial_ReductionsVisitorsBroadcasting_broadcast_1nn.cpp~ @@ -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; +} diff --git a/doc/examples/Tutorial_ReductionsVisitorsBroadcasting_broadcast_simple.cpp b/doc/examples/Tutorial_ReductionsVisitorsBroadcasting_broadcast_simple.cpp new file mode 100644 index 000000000..e6c87c6a4 --- /dev/null +++ b/doc/examples/Tutorial_ReductionsVisitorsBroadcasting_broadcast_simple.cpp @@ -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; +} diff --git a/doc/examples/Tutorial_ReductionsVisitorsBroadcasting_broadcast_simple.cpp~ b/doc/examples/Tutorial_ReductionsVisitorsBroadcasting_broadcast_simple.cpp~ new file mode 100644 index 000000000..f4e6a0db0 --- /dev/null +++ b/doc/examples/Tutorial_ReductionsVisitorsBroadcasting_broadcast_simple.cpp~ @@ -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; +} diff --git a/doc/examples/Tutorial_ReductionsVisitorsBroadcasting_broadcast_simple_rowwise.cpp b/doc/examples/Tutorial_ReductionsVisitorsBroadcasting_broadcast_simple_rowwise.cpp new file mode 100644 index 000000000..9959c7909 --- /dev/null +++ b/doc/examples/Tutorial_ReductionsVisitorsBroadcasting_broadcast_simple_rowwise.cpp @@ -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; +} diff --git a/doc/examples/Tutorial_ReductionsVisitorsBroadcasting_colwise.cpp b/doc/examples/Tutorial_ReductionsVisitorsBroadcasting_colwise.cpp new file mode 100644 index 000000000..df6825663 --- /dev/null +++ b/doc/examples/Tutorial_ReductionsVisitorsBroadcasting_colwise.cpp @@ -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; +} diff --git a/doc/examples/Tutorial_ReductionsVisitorsBroadcasting_maxnorm.cpp b/doc/examples/Tutorial_ReductionsVisitorsBroadcasting_maxnorm.cpp new file mode 100644 index 000000000..cb46887b6 --- /dev/null +++ b/doc/examples/Tutorial_ReductionsVisitorsBroadcasting_maxnorm.cpp @@ -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; +} diff --git a/doc/examples/Tutorial_ReductionsVisitorsBroadcasting_rowwise.cpp b/doc/examples/Tutorial_ReductionsVisitorsBroadcasting_rowwise.cpp new file mode 100644 index 000000000..80427c9f7 --- /dev/null +++ b/doc/examples/Tutorial_ReductionsVisitorsBroadcasting_rowwise.cpp @@ -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; +} diff --git a/doc/examples/Tutorial_ReductionsVisitorsBroadcasting_visitors.cpp b/doc/examples/Tutorial_ReductionsVisitorsBroadcasting_visitors.cpp new file mode 100644 index 000000000..b54e9aa31 --- /dev/null +++ b/doc/examples/Tutorial_ReductionsVisitorsBroadcasting_visitors.cpp @@ -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; +} diff --git a/doc/examples/Tutorial_ReductionsVisitorsBroadcasting_visitors.cpp~ b/doc/examples/Tutorial_ReductionsVisitorsBroadcasting_visitors.cpp~ new file mode 100644 index 000000000..ff7ed9ee4 --- /dev/null +++ b/doc/examples/Tutorial_ReductionsVisitorsBroadcasting_visitors.cpp~ @@ -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; +} |