矩陣切片和索引
- 一、概述
- 二、基本的切片
- 三、編譯時間大小和增量
- 四、相反的順序
- 五、索引數組
- 六、自定義索引列表
一、概述
本頁介紹了操作符 () 為索引子集行和列提供的多種可能性。這個API已經在特性3.4中引入。它支持塊API提出的所有特性,以及更多。特別是,它支持切片,包括在矩陣中均勻間隔的一組行、列或元素,或者從索引數組中索引。
上述所有操作都通過通用的下面的API方法處理。
DenseBase::operator()(const RowIndices&, const ColIndices&)
每個參數可以是:
- 索引單行或列的整數,包括符號索引。
- 符號 Eigen::all 表示按遞增順序排列的全部行或列。
- 一個由 Eigen::seq、Eigen::seqN或Eigen::placeholders::lastN 函數構造的算術序列。
- 任何一維矢量/整數數組,包括Eigen的矢量/數組、表達式、std::vector、std::array以及普通C數組:int[N]。
更一般地說,它可以接受暴露以下兩個成員函數的任何對象:
<integral type> operator[](<integral type>) const;
<integral type> size() const;
其中<integral type>表示與Eigen::Index(即std::ptrdiff_t)兼容的任何整數類型。
二、基本的切片
通過 Eigen::seq 或 Eigen::seqN 函數(其中“seq”表示等差數列),可以在矩陣或向量中獲得一組均勻間隔的行、列或元素。他們的簽名摘要如下:
功能 | 描述 | 示例 |
---|---|---|
seq (firstIdx, lastIdx) | 表示從firstdx到lastdx的整數序列 | seq (2,5) <=> {2,3,4,5} |
seq (firstIdx, lastIdx, incr) | 相同的,但使用增量incr從一個索引推進到下一個索引 | Seq (2,8,2) <=> {2,4,6,8} |
seqN (firstIdx, size) | 表示從firstIdx開始的大小整數序列 | seqN(2,5) <=> {2,3,4,5,6} |
seqN (firstIdx, size, incr) | 相同的,但使用增量incr從一個索引推進到下一個索引 | seqN(2,3,3) <=> {2,5,8} |
還可以在 Eigen::last 符號的幫助下定義 firstdx 和 lastdx 參數,該符號表示通過 operator() 將等差數列傳遞給底層矩陣/向量后的最后一行、最后一列或最后一個元素的索引。下面是二維數組/矩陣 A 和一維數組/向量 v 的一些示例。
意圖 | 代碼塊 | Block- api等價 |
---|---|---|
左下角從第i行開始,有n列 | A(seq(i, last), seqN (0, n)) | A.bottomLeftCorner (A.rows () - i, n) |
塊從i開始,j有m行n列 | A(seqN(i, m), seqN(i, n)) | A.block (i, j, m, n) |
塊從i0,j0開始,到i1,j1結束 | A(seq(i0,i1), seq(j0,j1) | A.block(i0,j0,i1-i0+1,j1-j0+1) |
A的偶列 | A(all, seq(0,last,2)) | |
前n行奇數A | A(seqN(1, n, 2), all) | |
最后一列 | A(all, last-1) | A.col(A.cols() - 2) |
中間一排 | A(last / 2, all) | A.row((A.rows() - 1)/2) |
v的最后一個元素從i開始 | v(seq(i, last)) | v.tail(v.size() - i) |
v的最后n個元素 | v(seq(last + 1 - n, last)) | v.tail (n) |
正如在最后一個示例中所看到的,引用最后n個元素(或行/列)編寫起來有點麻煩。對于非默認的增量,這變得更加棘手和容易出錯。下面是 Eigen::placeholders::lastN(size) 和 Eigen::placeholders::lastN(size,incr):
意圖 | 代碼塊 | Block - api等價 |
---|---|---|
v的最后n個元素 | v(lastN(n)) | v.tail (n) |
大小為m乘以n的A的右下角 | v(lastN(m), lastN(n)) | A.bottomRightCorner(m,n) |
大小為m乘以n的A的右下角 | v(lastN(m), lastN(n)) | A.bottomRightCorner(m,n) |
最后n列取1列除以3 | A(all, lastN(n,3)) |
三、編譯時間大小和增量
在性能方面,Eigen和編譯器可以利用編譯時大小和增量。為此,可以使用 Eigen::fix<val> 強制執行編譯時參數。這樣的編譯時值可以與 Eigen::last 符號組合使用:
v(seq(last - fix<7>, last - fix<2>))
在這個例子中,Eigen在編譯時知道返回的表達式有6個元素。它相當于:
v(seqN(last-7, fix<6>))
我們可以重新審視A的偶數列,如下所示:
A(all, seq(0,last,fix<2>))
四、相反的順序
還可以使用負增量按降序枚舉行/列索引。例如,從第 20 列到第 10 列A的1 / 2
A(all, seq(20, 10, fix<-2>))
從最后一行開始的最后n行:
A(seqN(last, n, fix<-1>), all)
您還可以使用 ArithmeticSequence::reverse() 方法來反轉其順序。因此,前面的例子也可以寫成:
A(lastN(n).reverse(), all)
五、索引數組
泛型操作符()也可以接受任意的行或列索引列表作為輸入,存儲形式可以是 ArrayXi、std::vector、std::array<int,N> 等。
下面的例子就是用用 ind 里的數作為索引,去取A中的指定列構成的新矩陣。
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 -56 -3 0 9 -8 -86 6 3 9 2 6A(all,ind):3 -5 -10 -10 -35 1 -5 -5 0-8 0 -8 -8 92 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";//輸出
Initial matrix A:7 9 -5 -3 3 -10-2 -6 1 0 5 -56 -3 0 9 -8 -86 6 3 9 2 6A(all,{4,2,5,5,3}):3 -5 -10 -10 -35 1 -5 -5 0-8 0 -8 -8 92 3 6 6 9
或表達式:
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";//輸出
Initial matrix A:7 9 -5 -3 3 -10-2 -6 1 0 5 -56 -3 0 9 -8 -86 6 3 9 2 6A(all,ind-1):
-3 9 3 3 -50 -6 5 5 19 -3 -8 -8 09 6 2 2 3
當傳遞具有編譯時大小的對象(如Array4i、std::array<int,N>或靜態數組)時,返回的表達式也顯示編譯時尺寸。
六、自定義索引列表
更一般地說,operator()可以接受任何類型為T的對象ind作為輸入,并且兼容:
Index s = ind.size(); or Index s = size(ind);
Index i;
i = ind[i];
這意味著您可以輕松地構建自己的序列生成器并將其傳遞給operator()。下面是一個例子,擴大一個給定的矩陣,同時填充額外的第一行和列通過重復:
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 9A(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