diff --git a/doc/Manual.dox b/doc/Manual.dox index 342b145fd..cb0e7d156 100644 --- a/doc/Manual.dox +++ b/doc/Manual.dox @@ -64,13 +64,15 @@ namespace Eigen { \ingroup DenseMatrixManipulation_chapter */ /** \addtogroup TutorialBlockOperations \ingroup DenseMatrixManipulation_chapter */ +/** \addtogroup TutorialSlicingIndexing + \ingroup DenseMatrixManipulation_chapter */ /** \addtogroup TutorialAdvancedInitialization \ingroup DenseMatrixManipulation_chapter */ /** \addtogroup TutorialReductionsVisitorsBroadcasting \ingroup DenseMatrixManipulation_chapter */ /** \addtogroup TutorialMapClass \ingroup DenseMatrixManipulation_chapter */ -/** \addtogroup TutorialReshapeSlicing +/** \addtogroup TutorialReshape \ingroup DenseMatrixManipulation_chapter */ /** \addtogroup TopicAliasing \ingroup DenseMatrixManipulation_chapter */ diff --git a/doc/TutorialReshape.dox b/doc/TutorialReshape.dox new file mode 100644 index 000000000..5b4022a3b --- /dev/null +++ b/doc/TutorialReshape.dox @@ -0,0 +1,82 @@ +namespace Eigen { + +/** \eigenManualPage TutorialReshape Reshape + +Since the version 3.4, %Eigen exposes convenient methods to reshape a matrix to another matrix of different sizes or vector. +All cases are handled via the DenseBase::reshaped(NRowsType,NColsType) and DenseBase::reshaped() functions. +Those functions do not perform in-place reshaping, but instead return a view on the input expression. + +\eigenAutoToc + +\section TutorialReshapeMat2Mat Reshaped 2D views + +The more general reshaping transformation is handled via: `reshaped(nrows,ncols)`. +Here is an example reshaping a 4x4 matrix to a 2x8 one: + + + + +
Example:Output:
+\include MatrixBase_reshaped_int_int.cpp + +\verbinclude MatrixBase_reshaped_int_int.out +
+ +By default, the input coefficients are always interpreted in column-major order regardless of the storage order of the input expression. +For more control on ordering, compile-time sizes, and automatic size deduction, please see de documentation of DenseBase::reshaped(NRowsType,NColsType) that contains all the details with many examples. + + +\section TutorialReshapeMat2Vec 1D linear views + +A very common usage of reshaping is to create a 1D linear view over a given 2D matrix or expression. +In this case, sizes can be deduced and thus omitted as in the following example: + + + + + +
Example:
+\include MatrixBase_reshaped_to_vector.cpp +
Output:
+\verbinclude MatrixBase_reshaped_to_vector.out +
+ +This shortcut always returns a column vector and by default input coefficients are always interpreted in column-major order. +Again, see the documentation of DenseBase::reshaped() for more control on the ordering. + +\section TutorialReshapeInPlace + +The above examples create reshaped views, but what about reshaping inplace a given matrix? +Of course this task in only conceivable for matrix and arrays having runtime dimensions. +In many cases, this can be accomplished via PlainObjectBase::resize(Index,Index): + + + + + +
Example:
+\include Tutorial_reshaped_vs_resize_1.cpp +
Output:
+\verbinclude Tutorial_reshaped_vs_resize_1.out +
+ +However beware that unlike \c reshaped, the result of \c resize depends on the input storage order. +It thus behaves similarly to `reshaped`: + + + + + +
Example:
+\include Tutorial_reshaped_vs_resize_2.cpp +
Output:
+\verbinclude Tutorial_reshaped_vs_resize_2.out +
+ +Finally, assigning a reshaped matrix to itself is currently not supported and will result to undefined-behavior because of \link TopicAliasing aliasing \endlink. +The following is forbidden: \code A = A.reshaped(2,8); \endcode +This is OK: \code A = A.reshaped(2,8).eval(); \endcode + +*/ + +} diff --git a/doc/TutorialReshapeSlicing.dox b/doc/TutorialReshapeSlicing.dox deleted file mode 100644 index 44de786ea..000000000 --- a/doc/TutorialReshapeSlicing.dox +++ /dev/null @@ -1,65 +0,0 @@ -namespace Eigen { - -/** \eigenManualPage TutorialReshapeSlicing Reshape and Slicing - -%Eigen does not expose convenient methods to take slices or to reshape a matrix yet. -Nonetheless, such features can easily be emulated using the Map class. - -\eigenAutoToc - -\section TutorialReshape Reshape - -A reshape operation consists in modifying the sizes of a matrix while keeping the same coefficients. -Instead of modifying the input matrix itself, which is not possible for compile-time sizes, the approach consist in creating a different \em view on the storage using class Map. -Here is a typical example creating a 1D linear view of a matrix: - - - - -
Example:Output:
-\include Tutorial_ReshapeMat2Vec.cpp - -\verbinclude Tutorial_ReshapeMat2Vec.out -
- -Remark how the storage order of the input matrix modifies the order of the coefficients in the linear view. -Here is another example reshaping a 2x6 matrix to a 6x2 one: - - - -
Example:Output:
-\include Tutorial_ReshapeMat2Mat.cpp - -\verbinclude Tutorial_ReshapeMat2Mat.out -
- - - -\section TutorialSlicing Slicing - -Slicing consists in taking a set of rows, columns, or elements, uniformly spaced within a matrix. -Again, the class Map allows to easily mimic this feature. - -For instance, one can skip every P elements in a vector: - - - -
Example:Output:
-\include Tutorial_SlicingVec.cpp - -\verbinclude Tutorial_SlicingVec.out -
- -One can also take one column over three using an adequate outer-stride or inner-stride depending on the actual storage order: - - - -
Example:Output:
-\include Tutorial_SlicingCol.cpp - -\verbinclude Tutorial_SlicingCol.out -
- -*/ - -} diff --git a/doc/TutorialSlicingIndexing.dox b/doc/TutorialSlicingIndexing.dox new file mode 100644 index 000000000..2e5543539 --- /dev/null +++ b/doc/TutorialSlicingIndexing.dox @@ -0,0 +1,244 @@ +namespace Eigen { + +/** \eigenManualPage TutorialSlicingIndexing Slicing and Indexing + +This pape presents the numerous possibilities offered by `operator()` to index sub-set of rows and columns. +This API has been introduced in %Eigen 3.4. +It supports all the feature proposed by the \link TutorialBlockOperations block API \endlink, and much more. +In particular, it supports \b slicing that consists in taking a set of rows, columns, or elements, uniformly spaced within a matrix or indexed from an array of indices. + +\eigenAutoToc + +\section TutorialSlicingOverview Overview + +All the aforementioned operations are handled through the generic DenseBase::operator()(const RowIndices&, const ColIndices&) method. +Each argument can be: + - An integer indexing a single row or column, including symbolic indices. + - The symbol Eigen::all representing the whole set of respective rows or columns in increasing order. + - An ArithmeticSequence as constructed by the Eigen::seq, Eigen::seqN, or Eigen::lastN functions. + - Any 1D vector/array of integers including %Eigen's vector/array, expressions, std::vector, std::array, as well as plain C arrays: `int[N]`. + +More generally, it can accepts any object exposing the following two member functions: + \code + operator[]() const; + size() const; + \endcode +where `` stands for any integer type compatible with Eigen::Index (i.e. `std::ptrdiff_t`). + +\section TutorialSlicingBasic Basic slicing + +Taking a set of rows, columns, or elements, uniformly spaced within a matrix or vector is achieved through the Eigen::seq or Eigen::seqN functions where "seq" stands for arithmetic sequence. Their signatures are summarized below: + + + + + + + + + + + + + + + + + + + + + + + + + + + +
functiondescriptionexample
\code seq(firstIdx,lastIdx) \endcoderepresents the sequence of integers ranging from \c firstIdx to \c lastIdx\code seq(2,5) <=> {2,3,4,5} \endcode
\code seq(firstIdx,lastIdx,incr) \endcodesame but using the increment \c incr to advance from one index to the next\code seq(2,8,2) <=> {2,4,6,8} \endcode
\code seqN(firstIdx,size) \endcoderepresents the sequence of \c size integers starting from \c firstIdx\code seqN(2,5) <=> {2,3,4,5,6} \endcode
\code seqN(firstIdx,size,incr) \endcodesame but using the increment \c incr to advance from one index to the next\code seqN(2,3,3) <=> {2,5,8} \endcode
+ +The \c firstIdx and \c lastIdx parameters can also be defined with the help of the Eigen::last symbol representing the index of the last row, column or element of the underlying matrix/vector once the arithmetic sequence is passed to it through operator(). +Here are some examples for a 2D array/matrix \c A and a 1D array/vector \c v. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IntentCodeBlock-API equivalence
Bottom-left corner starting at row \c i with \c n columns\code A(seq(i,last), seqN(0,n)) \endcode\code A.bottomLeftCorner(A.rows()-i,n) \endcode
%Block starting at \c i,j having \c m rows, and \c n columns\code A(seqN(i,m), seqN(i,n) \endcode\code A.block(i,j,m,n) \endcode
%Block starting at \c i0,j0 and ending at \c i1,j1\code A(seq(i0,i1), seq(j0,j1) \endcode\code A.block(i0,j0,i1-i0+1,j1-j0+1) \endcode
Even columns of A\code A(all, seq(0,last,2)) \endcode
First \c n odd rows A\code A(seqN(1,n,2), all) \endcode
The last past one column\code A(all, last-1) \endcode\code A.col(A.cols()-2) \endcode
The middle row\code A(last/2,all) \endcode\code A.row((A.rows()-1)/2) \endcode
Last elements of v starting at i\code v(seq(i,last)) \endcode\code v.tail(v.size()-i) \endcode
Last \c n elements of v\code v(seq(last+1-n,last)) \endcode\code v.tail(n) \endcode
+ +As seen in the last exemple, referencing the last n elements (or rows/columns) is a bit cumbersome to write. +This becomes even more tricky and error prone with a non-default increment. +Here comes \link Eigen::lastN(SizeType) Eigen::lastN(size) \endlink, and \link Eigen::lastN(SizeType,IncrType) Eigen::lastN(size,incr) \endlink: + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IntentCodeBlock-API equivalence
Last \c n elements of v\code v(lastN(n)) \endcode\code v.tail(n) \endcode
Bottom-right corner of A of size \c m times \c n\code v(lastN(m), lastN(n)) \endcode\code A.bottomRightCorner(m,n) \endcode
Bottom-right corner of A of size \c m times \c n\code v(lastN(m), lastN(n)) \endcode\code A.bottomRightCorner(m,n) \endcode
Last \c n columns taking 1 column over 3\code A(all, lastN(n,3)) \endcode
+ +\section TutorialSlicingFixed Compile time size and increment + +In terms of performance, %Eigen and the compiler can take advantage of compile-time size and increment. +To this end, you can enforce compile-time parameters using Eigen::fix. +Such compile-time value can be combined with the Eigen::last symbol: +\code v(seq(last-fix<7>, last-fix<2>)) +\endcode +In this example %Eigen knowns at compile-time that the returned expression has 6 elements. +It is equivalent to: +\code v(seqN(last-7, fix<6>)) +\endcode + +We can revisit the even columns of A example as follows: +\code A(all, seq(0,last,fix<2>)) +\endcode + + +\section TutorialSlicingReverse Reverse order + +Row/column indices can also be enumerated in decreasing order using a negative increment. +For instance, one over two columns of A from the column 20 to 10: +\code A(all, seq(20, 10, fix<-2>)) +\endcode +The last \c n rows starting from the last one: +\code A(seqN(last, n, fix<-1>), all) +\endcode +You can also use the ArithmeticSequence::reverse() method to reverse its order. +The previous example can thus also be written as: +\code A(lastN(n).reverse(), all) +\endcode + + +\section TutorialSlicingArray Array of indices + +The generic `operator()` can also takes as input an arbitrary list of row or column indices stored as either an `ArrayXi`, a `std::vector`, `std::array`, etc. + + + + +
Example:Output:
+\include Slicing_stdvector_cxx11.cpp + +\verbinclude Slicing_stdvector_cxx11.out +
+ +You can also directly pass a static array: + + + +
Example:Output:
+\include Slicing_rawarray_cxx11.cpp + +\verbinclude Slicing_rawarray_cxx11.out +
+ +or expressions: + + + +
Example:Output:
+\include Slicing_arrayexpr.cpp + +\verbinclude Slicing_arrayexpr.out +
+ +When passing an object with a compile-time size such as `Array4i`, `std::array`, or a static array, then the returned expression also exhibit compile-time dimensions. + +\section TutorialSlicingCustomArray Custom index list + +More generally, `operator()` can accept as inputs any object \c ind of type \c T compatible with: +\code +Index s = ind.size(); or Index s = size(ind); +Index i; +i = ind[i]; +\endcode + +This means you can easily build your own fancy sequence generator and pass it to `operator()`. +Here is an exemple enlarging a given matrix while padding the first rows and columns through repetition: + + + + +
Example:Output:
+\include Slicing_custom_padding_cxx11.cpp + +\verbinclude Slicing_custom_padding_cxx11.out +
+ +
+ +*/ + +/* +TODO add: +so_repeat_inner.cpp +so_repeleme.cpp +*/ +} diff --git a/doc/snippets/Slicing_arrayexpr.cpp b/doc/snippets/Slicing_arrayexpr.cpp new file mode 100644 index 000000000..00b689b90 --- /dev/null +++ b/doc/snippets/Slicing_arrayexpr.cpp @@ -0,0 +1,4 @@ +ArrayXi ind(5); ind<<4,2,5,5,3; +MatrixXi A = MatrixXi::Random(4,6); +cout << "Initial matrix A:\n" << A << "\n\n"; +cout << "A(all,ind-1):\n" << A(all,ind-1) << "\n\n"; \ No newline at end of file diff --git a/doc/snippets/Slicing_custom_padding_cxx11.cpp b/doc/snippets/Slicing_custom_padding_cxx11.cpp new file mode 100644 index 000000000..5dac3d7c9 --- /dev/null +++ b/doc/snippets/Slicing_custom_padding_cxx11.cpp @@ -0,0 +1,12 @@ +struct pad { + Index size() const { return out_size; } + Index operator[] (Index i) const { return std::max(0,i-(out_size-in_size)); } + Index in_size, out_size; +}; + +Matrix3i A; +A.reshaped() = VectorXi::LinSpaced(9,1,9); +cout << "Initial matrix A:\n" << A << "\n\n"; +MatrixXi B(5,5); +B = A(pad{3,5}, pad{3,5}); +cout << "A(pad{3,N}, pad{3,N}):\n" << B << "\n\n"; \ No newline at end of file diff --git a/doc/snippets/Slicing_rawarray_cxx11.cpp b/doc/snippets/Slicing_rawarray_cxx11.cpp new file mode 100644 index 000000000..0d3287a42 --- /dev/null +++ b/doc/snippets/Slicing_rawarray_cxx11.cpp @@ -0,0 +1,5 @@ +#if EIGEN_HAS_STATIC_ARRAY_TEMPLATE +MatrixXi A = MatrixXi::Random(4,6); +cout << "Initial matrix A:\n" << A << "\n\n"; +cout << "A(all,{4,2,5,5,3}):\n" << A(all,{4,2,5,5,3}) << "\n\n"; +#endif \ No newline at end of file diff --git a/doc/snippets/Slicing_stdvector_cxx11.cpp b/doc/snippets/Slicing_stdvector_cxx11.cpp new file mode 100644 index 000000000..469651e38 --- /dev/null +++ b/doc/snippets/Slicing_stdvector_cxx11.cpp @@ -0,0 +1,4 @@ +std::vector ind{4,2,5,5,3}; +MatrixXi A = MatrixXi::Random(4,6); +cout << "Initial matrix A:\n" << A << "\n\n"; +cout << "A(all,ind):\n" << A(all,ind) << "\n\n"; \ No newline at end of file diff --git a/doc/snippets/Tutorial_reshaped_vs_resize_1.cpp b/doc/snippets/Tutorial_reshaped_vs_resize_1.cpp new file mode 100644 index 000000000..686b96c38 --- /dev/null +++ b/doc/snippets/Tutorial_reshaped_vs_resize_1.cpp @@ -0,0 +1,5 @@ +MatrixXi m = Matrix4i::Random(); +cout << "Here is the matrix m:" << endl << m << endl; +cout << "Here is m.reshaped(2, 8):" << endl << m.reshaped(2, 8) << endl; +m.resize(2,8); +cout << "Here is the matrix m after m.resize(2,8):" << endl << m << endl; \ No newline at end of file diff --git a/doc/snippets/Tutorial_reshaped_vs_resize_2.cpp b/doc/snippets/Tutorial_reshaped_vs_resize_2.cpp new file mode 100644 index 000000000..50dc45488 --- /dev/null +++ b/doc/snippets/Tutorial_reshaped_vs_resize_2.cpp @@ -0,0 +1,6 @@ +Matrix m = Matrix4i::Random(); +cout << "Here is the matrix m:" << endl << m << endl; +cout << "Here is m.reshaped(2, 8):" << endl << m.reshaped(2, 8) << endl; +cout << "Here is m.reshaped(2, 8):" << endl << m.reshaped(2, 8) << endl; +m.resize(2,8); +cout << "Here is the matrix m after m.resize(2,8):" << endl << m << endl;