module
Slicing and IndexingContents
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.
Overview
All the aforementioned operations are handled through the generic DenseBase::
- 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:
<integral type> operator[](<integral type>) const; <integral type> size() const;
where <integral type>
stands for any integer type compatible with Eigen::std::ptrdiff_t
).
Basic slicing
Taking a set of rows, columns, or elements, uniformly spaced within a matrix or vector is achieved through the Eigen::
function | description | example |
---|---|---|
seq(firstIdx,lastIdx) | 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) | 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::A
and a 1D array/vector v
.
Intent | Code | Block-API equivalence |
---|---|---|
Bottom-left corner starting at row i with n columns | A(seq(i,last), seqN(0,n)) | A.bottomLeftCorner(A.rows()-i,n) |
Block starting at i ,j having m rows, and n columns | A(seqN(i,m), seqN(i,n) | A.block(i,j,m,n) |
Block starting at i0 ,j0 and ending at i1 ,j1 | A(seq(i0,i1), seq(j0,j1) | A.block(i0,j0,i1-i0+1,j1-j0+1) |
Even columns of A | A(all, seq(0,last,2)) | |
First n odd rows A | A(seqN(1,n,2), all) | |
The last past one column | A(all, last-1) | A.col(A.cols()-2) |
The middle row | A(last/2,all) | A.row((A.rows()-1)/2) |
Last elements of v starting at i | v(seq(i,last)) | v.tail(v.size()-i) |
Last n elements of v | v(seq(last+1-n,last)) | v.tail(n) |
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 Eigen::
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 | v(lastN(m), lastN(n)) | A.bottomRightCorner(m,n) |
Bottom-right corner of A of size m times n | v(lastN(m), lastN(n)) | A.bottomRightCorner(m,n) |
Last n columns taking 1 column over 3 | A(all, lastN(n,3)) |
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::v(seq(last-fix<7>, last-fix<2>))
In this example Eigen knowns at compile-time that the returned expression has 6 elements. It is equivalent to: v(seqN(last-7, fix<6>))
We can revisit the even columns of A example as follows: A(all, seq(0,last,fix<2>))
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: A(all, seq(20, 10, fix<-2>))
The last n
rows starting from the last one: A(seqN(last, n, fix<-1>), all)
You can also use the ArithmeticSequence::reverse() method to reverse its order. The previous example can thus also be written as: A(lastN(n).reverse(), all)
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<int>
, std::array<int,N>
, etc.
Example: | Output: |
---|---|
std::vector<int> 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"; | Initial matrix A: 7 9 -5 -3 3 -10 -2 -6 1 0 5 -5 6 -3 0 9 -8 -8 6 6 3 9 2 6 A(all,ind): 3 -5 -10 -10 -3 5 1 -5 -5 0 -8 0 -8 -8 9 2 3 6 6 9 |
You can also directly pass a static array:
Example: | Output: |
---|---|
#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 | Initial matrix A: 7 9 -5 -3 3 -10 -2 -6 1 0 5 -5 6 -3 0 9 -8 -8 6 6 3 9 2 6 A(all,{4,2,5,5,3}): 3 -5 -10 -10 -3 5 1 -5 -5 0 -8 0 -8 -8 9 2 3 6 6 9 |
or expressions:
Example: | Output: |
---|---|
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"; | Initial matrix A: 7 9 -5 -3 3 -10 -2 -6 1 0 5 -5 6 -3 0 9 -8 -8 6 6 3 9 2 6 A(all,ind-1): -3 9 3 3 -5 0 -6 5 5 1 9 -3 -8 -8 0 9 6 2 2 3 |
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.
Custom index list
More generally, operator()
can accept as inputs any object ind
of type T
compatible with:
Index s = ind.size(); or Index s = size(ind); Index i; i = ind[i];
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 additional first rows and columns through repetition:
Example: | Output: |
---|---|
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"; | 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 |