![]() |
Eigen
5.0.1
|
This page 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 block API , and much more. In particular, it supports slicing that consists in taking a set of rows, columns, or elements, uniformly spaced within a matrix or indexed from an array of indices.
All the aforementioned operations are handled through the generic DenseBase::operator()(const RowIndices&, const ColIndices&) method. Each argument can be:
int[N].The symbols last, lastp1, end, all, and lastN live in the Eigen::placeholders namespace, while seq, seqN, and fix live directly in the Eigen namespace. For convenience, they are all re-exported via the Eigen::indexing namespace. To make the code examples on this page compile, add one of the following:
More generally, it can accept any object exposing the following two member functions:
where <integral type> stands for any integer type compatible with Eigen::Index (i.e. std::ptrdiff_t).
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:
| function | description | example |
|---|---|---|
seq(firstIdx,lastIdx)
auto seq(FirstType f, LastType l, IncrType incr) | represents the sequence of integers ranging from firstIdx to lastIdx | seq(2,5) <=> {2,3,4,5}
|
seq(firstIdx,lastIdx,incr)
| same but using the increment incr to advance from one index to the next | seq(2,8,2) <=> {2,4,6,8}
|
seqN(firstIdx,size)
ArithmeticSequence< typename internal::cleanup_index_type< FirstType >::type, typename internal::cleanup_index_type< SizeType >::type, typename internal::cleanup_seq_incr< IncrType >::type > seqN(FirstType first, SizeType size, IncrType incr) Definition ArithmeticSequence.h:104 | represents the sequence of size integers starting from firstIdx | seqN(2,5) <=> {2,3,4,5,6}
|
seqN(firstIdx,size,incr)
| same but using the increment incr to advance from one index to the next | seqN(2,3,3) <=> {2,5,8}
|
The firstIdx and lastIdx parameters can also be defined with the help of the Eigen::placeholders::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 A and a 1D array/vector v.
| Intent | Code | Block-API equivalence |
|---|---|---|
Bottom-left corner starting at row i with n columns | A.bottomLeftCorner(A.rows()-i,n)
| |
Block starting at i,j having m rows, and n columns | A.block(i,j,m,n)
| |
Block starting at i0,j0 and ending at i1,j1 | A.block(i0,j0,i1-i0+1,j1-j0+1)
| |
| Even columns of A | ||
First n odd rows of A | ||
| The second-last column | A.col(A.cols()-2)
| |
| The middle row | A.row((A.rows()-1)/2)
| |
| Last elements of v starting at i | v.tail(v.size()-i)
| |
Last n elements of v | v.tail(n)
|
As seen in the last example, 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 Eigen_placeholders_lastN :
| Intent | Code | Block-API equivalence |
|---|---|---|
Last n elements of v | v(lastN(n))
| v.tail(n)
|
Bottom-right corner of A of size m times n | A.bottomRightCorner(m,n)
| |
Last n columns taking 1 column over 3 |
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<val>. Such compile-time value can be combined with the Eigen::placeholders::last symbol:
In this example Eigen knowns at compile-time that the returned expression has 6 elements. It is equivalent to:
We can revisit the even columns of A example as follows:
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:
The last n rows starting from the last one:
You can also use the ArithmeticSequence::reverse() method to reverse its order. The previous example can thus also be written as:
The generic operator() can also takes as input an arbitrary list of row or column indices stored as either an ArrayXi, a std::vector<int>, std::array<int,N>, etc.
| Example: | Output: |
|---|---|
// SPDX-FileCopyrightText: The Eigen Authors
// SPDX-License-Identifier: MPL-2.0
std::vector<int> ind{4, 2, 5, 5, 3};
MatrixXi A = MatrixXi::Random(4, 6);
cout << "Initial matrix A:\n" << A << "\n\n";
| Initial matrix A: 1804289383 -1550966999 -782303108 336465782 1315634022 -1016307419 -465790871 -1122281286 -1843394476 278722862 -778350579 -1287999227 1957747793 -1364114958 35005211 2145174067 -1087522255 608413784 -1427598262 -102585885 -1852781081 -1045969719 -1519308637 -412908450 A(all,ind): 1315634022 -782303108 -1016307419 -1016307419 336465782 -778350579 -1843394476 -1287999227 -1287999227 278722862 -1087522255 35005211 608413784 608413784 2145174067 -1519308637 -1852781081 -412908450 -412908450 -1045969719 |
You can also directly pass a static array:
| Example: | Output: |
|---|---|
// SPDX-FileCopyrightText: The Eigen Authors
// SPDX-License-Identifier: MPL-2.0
MatrixXi A = MatrixXi::Random(4, 6);
cout << "Initial matrix A:\n" << A << "\n\n";
| Initial matrix A:
1804289383 -1550966999 -782303108 336465782 1315634022 -1016307419
-465790871 -1122281286 -1843394476 278722862 -778350579 -1287999227
1957747793 -1364114958 35005211 2145174067 -1087522255 608413784
-1427598262 -102585885 -1852781081 -1045969719 -1519308637 -412908450
A(all,{4,2,5,5,3}):
1315634022 -782303108 -1016307419 -1016307419 336465782
-778350579 -1843394476 -1287999227 -1287999227 278722862
-1087522255 35005211 608413784 608413784 2145174067
-1519308637 -1852781081 -412908450 -412908450 -1045969719
|
or expressions:
| Example: | Output: |
|---|---|
// SPDX-FileCopyrightText: The Eigen Authors
// SPDX-License-Identifier: MPL-2.0
ArrayXi ind(5);
ind << 4, 2, 5, 5, 3;
MatrixXi A = MatrixXi::Random(4, 6);
cout << "Initial matrix A:\n" << A << "\n\n";
| Initial matrix A: 1804289383 -1550966999 -782303108 336465782 1315634022 -1016307419 -465790871 -1122281286 -1843394476 278722862 -778350579 -1287999227 1957747793 -1364114958 35005211 2145174067 -1087522255 608413784 -1427598262 -102585885 -1852781081 -1045969719 -1519308637 -412908450 A(all,ind-1): 336465782 -1550966999 1315634022 1315634022 -782303108 278722862 -1122281286 -778350579 -778350579 -1843394476 2145174067 -1364114958 -1087522255 -1087522255 35005211 -1045969719 -102585885 -1519308637 -1519308637 -1852781081 |
When passing an object with a compile-time size such as Array4i, std::array<int,N>, or a static array, then the returned expression also exhibit compile-time dimensions.
More generally, operator() can accept as inputs any object ind of type T compatible with:
This means you can easily build your own fancy sequence generator and pass it to operator(). Here is an example enlarging a given matrix while padding the additional first rows and columns through repetition:
| Example: | Output: |
|---|---|
// SPDX-FileCopyrightText: The Eigen Authors
// SPDX-License-Identifier: MPL-2.0
struct pad {
Index size() const { return out_size; }
Index operator[](Index i) const { return std::max<Index>(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";
Matrix< int, Dynamic, Dynamic > MatrixXi Dynamic×Dynamic matrix of type int. Definition Matrix.h:487 | Initial matrix A:
1 4 7
2 5 8
3 6 9
A(pad{3,N}, pad{3,N}):
1 1 1 4 7
1 1 1 4 7
1 1 1 4 7
2 2 2 5 8
3 3 3 6 9
|
Before the introduction of the operator() API in Eigen 3.4, uniformly spaced slices were typically built by mapping the underlying array with a custom Map and a suitable Stride. This remains a valid alternative, for instance when targeting older versions of Eigen. Here is an example viewing every other coefficient of a vector:
| Example: | Output: |
|---|---|
// SPDX-FileCopyrightText: The Eigen Authors
// SPDX-License-Identifier: MPL-2.0
RowVectorXf v = RowVectorXf::LinSpaced(20, 0, 19);
cout << "Input:" << endl << v << endl;
Map<RowVectorXf, 0, InnerStride<2> > v2(v.data(), v.size() / 2);
cout << "Even:" << v2 << endl;
| Input: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 Even: 0 2 4 6 8 10 12 14 16 18 |
and an example taking one column over three of a matrix:
| Example: | Output: |
|---|---|
// SPDX-FileCopyrightText: The Eigen Authors
// SPDX-License-Identifier: MPL-2.0
MatrixXf M1 = MatrixXf::Random(3, 8);
cout << "Column major input:" << endl << M1 << "\n";
Map<MatrixXf, 0, OuterStride<> > M2(M1.data(), M1.rows(), (M1.cols() + 2) / 3, OuterStride<>(M1.outerStride() * 3));
cout << "1 column over 3:" << endl << M2 << "\n";
typedef Matrix<float, Dynamic, Dynamic, RowMajor> RowMajorMatrixXf;
RowMajorMatrixXf M3(M1);
cout << "Row major input:" << endl << M3 << "\n";
Map<RowMajorMatrixXf, 0, Stride<Dynamic, 3> > M4(M3.data(), M3.rows(), (M3.cols() + 2) / 3,
Stride<Dynamic, 3>(M3.outerStride(), 3));
cout << "1 column over 3:" << endl << M4 << "\n";
| Column major input: 0.68 0.597 -0.33 0.108 -0.27 0.832 -0.717 -0.514 -0.211 0.823 0.536 -0.0452 0.0268 0.271 0.214 -0.726 0.566 -0.605 -0.444 0.258 0.904 0.435 -0.967 0.608 1 column over 3: 0.68 0.108 -0.717 -0.211 -0.0452 0.214 0.566 0.258 -0.967 Row major input: 0.68 0.597 -0.33 0.108 -0.27 0.832 -0.717 -0.514 -0.211 0.823 0.536 -0.0452 0.0268 0.271 0.214 -0.726 0.566 -0.605 -0.444 0.258 0.904 0.435 -0.967 0.608 1 column over 3: 0.68 0.108 -0.717 -0.211 -0.0452 0.214 0.566 0.258 -0.967 |
Beware that with Map the stride has to be adjusted to the storage order of the mapped object, as done for M4 above, whereas the equivalent A(all, seq(0, last, 3)) works regardless of the storage order.