Spec-Zone.ru › Eigen3

Выделение и индексирование

Эта страница демонстрирует многочисленные возможности, предоставляемые operator() для индексирования подмножества строк и столбцов. Этот API был представлен в Eigen 3.4. Он поддерживает все функции, предлагаемые блочным API block API, и многое другое. В частности, он поддерживает выделение, которое состоит в взятии набора строк, столбцов или элементов, равномерно распределенных в матрице или индексированных из массива индексов.

Обзор

Все перечисленные выше операции обрабатываются с помощью универсального метода DenseBase::operator()(const RowIndices&, const ColIndices&). Каждый аргумент может быть:

  • Целое число, индексирующее одну строку или столбец, включая символические индексы.
  • Символ Eigen::all, представляющий весь набор соответствующих строк или столбцов в порядке возрастания.
  • ArithmeticSequence, как построена функциями Eigen::seq, Eigen::seqN или Eigen::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) 
представляет последовательность целых чисел от firstIdx до lastIdx
seq(2,5) <=> {2,3,4,5} 
seq(firstIdx,lastIdx,incr) 
то же самое, но используя приращение incr для перехода от одного индекса к следующему
seq(2,8,2) <=> {2,4,6,8} 
seqN(firstIdx,size) 
представляет последовательность из size целых чисел, начиная с firstIdx
seqN(2,5) <=> {2,3,4,5,6} 
seqN(firstIdx,size,incr) 
то же самое, но используя приращение incr для перехода от одного индекса к следующему
seqN(2,3,3) <=> {2,5,8} 

Параметры firstIdx и lastIdx также могут быть определены с помощью символа Eigen::last, представляющего индекс последней строки, столбца или элемента базовой матрицы/вектора после передачи арифметической последовательности в нее через оператор(). Вот несколько примеров для двумерного массива/матрицы A и одномерного массива/вектора v.

Намерение Код Эквивалент блочного 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) 
Последние n элементов v
v(seq(last+1-n,last)) 
v.tail(n) 

Как видно из последнего примера, ссылка на последние n элементов (или строк/столбцов) немного громоздка для записи. Это становится еще более сложным и подверженным ошибкам при использовании отличного от стандартного приращения. Здесь появляются Eigen::lastN(size) и Eigen::lastN(size,incr):

Намерение Код Эквивалент блочного API
Последние n элементов v
v(lastN(n)) 
v.tail(n) 
Правый нижний угол A размером m на n
v(lastN(m), lastN(n)) 
A.bottomRightCorner(m,n) 
Правый нижний угол A размером m на n
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>))

Обратный порядок

Индексы строк/столбцов также могут быть перечислены в порядке убывания с использованием отрицательного приращения. Например, каждый второй столбец A от столбца 20 до 10:

A(all, seq(20, 10, fix<-2>))

Последние n строк, начиная с последней:

A(seqN(last, n, fix<-1>), all)

Вы также можете использовать метод ArithmeticSequence::reverse() для изменения порядка. Предыдущий пример также можно записать следующим образом:

A(lastN(n).reverse(), all)

Массив индексов

Универсальный operator() также может принимать в качестве входных данных произвольный список индексов строк или столбцов, хранящихся как ArrayXi, std::vector<int>, std::array<int,N>, и т.д.

Пример: Результат:
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

Вы также можете напрямую передать статический массив:

Пример: Результат:
#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

или выражения:

Пример: Результат:
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

При передаче объекта со значением размера на этапе компиляции, таким как Array4i, std::array<int,N>, или статический массив, возвращаемое выражение также имеет размеры на этапе компиляции.

Пользовательский список индексов

Более того, operator() может принимать в качестве входных данных любой объект ind типа T совместимый с:

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


© Eigen.
Licensed under the MPL2 License.
https://eigen.tuxfamily.org/dox/group__TutorialSlicingIndexing.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API