05 切片和索引

切片和索引

​ 切片和索引用于选择矩阵或向量的多行或多列元素。

[TOC]

OverView

​ 所有的应用都是基于下面的函数。

DenseBase::operator()(const RowIndices&, const ColIndices&)

​ 一般而言,它接受public下面两个函数的任意class对象,即可以与Eigen::Index兼容的任意整数:

<integral type> operator[](<integral type>) const;
<integral type> size() const;

​ 特殊的有:

  • 一个表示行或列数的下标整数。

  • 符号 Eigen::all 按递增顺序表示相应行或列的整套集合。

  • 通过函数Eigen::seq, Eigen::seqN, or Eigen::placeholders::lastN 构造的 ArithmeticSequence

  • 任意一维向量/数组,例如:std::vectorstd::arrayEigen::ArrayEigen::Vector/RowVector、纯C数组。

Basic Slicing

​ 通过seqseqN函数创建在矩阵或向量中均匀分布的一组元素。

function description example
seq(firstIdx,lastIdx) represents the sequence of integers ranging from to firstIdx``lastIdx seq(2,5) <=> {2,3,4,5}
seq(firstIdx,lastIdx,incr) same but using the increment to advance from one index to the next incr seq(2,8,2) <=> {2,4,6,8}
seqN(firstIdx,size) represents the sequence of integers starting from size``firstIdx seqN(2,5) <=> {2,3,4,5,6}
seqN(firstIdx,size,incr) same but using the increment to advance from one index to the next incr seqN(2,3,3) <=> {2,5,8}

​ 通过切片可以来与block函数等价。第一个参数表示选择的行数,第二个参数表示选择的列数。

Intent Code Block-API
Bottom-left corner starting at row with columns i``n A(seq(i,last), seqN(0,n)) A.bottomLeftCorner(A.rows()-i,n)
Block starting at ,j having rows, and columns i``m``n A(seqN(i,m), seqN(i,n)) A.block(i,j,m,n)
Block starting at ,j0 and ending at ,j1 i0``i1 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 odd rows A n 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 elements of v n v(seq(last+1-n,last)) v.tail(n)

​ 最后数个元素从上述API使用会比较复杂,因此可以使用lastNAPI来完成它们。

Intent Code Block-API equivalence
Last elements of v n v(lastN(n)) v.tail(n)
Bottom-right corner of A of size times m``n v(lastN(m), lastN(n)) A.bottomRightCorner(m,n)
Bottom-right corner of A of size times m``n v(lastN(m), lastN(n)) A.bottomRightCorner(m,n)
Last columns taking 1 column over 3 n A(all, lastN(n,3))

编译期size和incr

​ 为了提升性能,如果有需要,可以使用Eigen::fix<val>来指定编译期参数。它可以与Eigen::last联用。

// 获取向量倒数第7至倒数第2
v(seq(last-fix<7>, last-fix<2>));
// same, using seqN
v(seqN(last-7, fix<6>));
// 奇数列
A(all, seq(0,last,fix<2>));

逆序seq

A(all, seq(20, 10, fix<-2>));
A(seqN(last, n, fix<-1>), all);
A(lastN(n).reverse(), all);

通过下标数组指定行列

​ 可以通过std::vector或者std::array来指定需要的行列。

​ 下面演示了如何通过vector指定列数,提取出需要的列形成一个新矩阵。

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(Eigen::placeholders::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
*/

​ 使用大括号表示的临时数组也可:

MatrixXi A = MatrixXi::Random(4,6);
cout << "Initial matrix A:\n" << A << "\n\n";
cout << "A(all,{4,2,5,5,3}):\n" << A(Eigen::placeholders::all,{4,2,5,5,3}) << "\n\n";

​ 或者表达式数组的方式:

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(Eigen::placeholders::all,ind-1) << "\n\n";

自定义index list

​ 更一般而言,只要对象含有size()方法和operator[],都可以用来作为输入规则。

​ 下面演示了一个自定义的结构体,当行数或列数下标i小于out_size - in_size时,选择第0个,否则选择下标i - 差值个元素。

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
*/