Расширить / Матрица Pad в Eigen - PullRequest
0 голосов
/ 07 ноября 2018

Скажите, у меня есть

A = [1 2 3]
    [4 5 6]
    [7 8 9]

Я хочу дополнить его первой строкой и первым столбцом или последней строкой и последним столбцом столько раз, сколько необходимо для создания A nxn. Например, 4x4 будет

 A = [1 1 2 3]
     [1 1 2 3]
     [4 4 5 6]
     [7 7 8 9]

и A 5x5 будет

 A = [1 1 2 3 3]
     [1 1 2 3 3]
     [4 4 5 6 6]
     [7 7 8 9 9]
     [7 7 8 9 9]

Я знаю, что я мог бы сделать A.conservativeResize(4,4), что заставляет меня

 A = [1 2 3 0]
     [4 5 6 0]
     [7 8 9 0]
     [0 0 0 0]

тогда я мог бы копировать вещи по одному, но есть ли более эффективный способ сделать это с помощью Eigen?

Ответы [ 2 ]

0 голосов
/ 07 ноября 2018

Вы можете обойти, используя нулевое выражение:

#include <iostream>
#include <Eigen/Dense>
using namespace Eigen;
using namespace std;

int main()
{
  Matrix3i A;
  A.reshaped() = VectorXi::LinSpaced(9,1,9);
  cout << A << "\n\n";
  int N = 5;
  MatrixXi B(N,N);
  B = MatrixXi::NullaryExpr(N, N, [&A,N] (Index i,Index j) {
        return A( std::max<Index>(0,i-(N-A.rows())),
                  std::max<Index>(0,j-(N-A.cols())) ); } );
  cout << B << "\n\n";
}

Другой подход заключается в создании фиксированной последовательности индексов, таких как [0 0 0 1 2]:

struct pad {
  Index size() const { return m_out_size; }
  Index operator[] (Index i) const { return std::max<Index>(0,i-(m_out_size-m_in_size)); }
  Index m_in_size, m_out_size;
};

B = A(pad{3,N}, pad{3,N});

Для этой версии требуется голова Эйгена.

Вы можете легко использовать эти примеры, чтобы сделать их еще более общими и / или заключить их в функции.

0 голосов
/ 07 ноября 2018

Как примечание, неверно, что A.conservativeResize(4,4) даст вам матрицу с добавленными строками, заполненными нулями. Документация Eigen гласит:

Если к матрице необходимо добавить значения, они будут неинициализированы.

Новые строки и столбцы будут заполнены мусором, и видеть нули - лишь совпадение (если вы не компилируете специальную директиву препроцессора для Eigen). Но это означает, что не тратится лишнее время на запись нулей, которые вы все равно перезапишете.

Примечание. Этот код демонстрирует, как получить матрицу с исходной матрицей в верхнем левом углу :

Лучший способ заполнить несколько значений одновременно - использовать операции блока Eigen и setConstant. Например, если A - это матрица размером old_size x old_size:

A.conservativeResize(n, n);
for (int i = 0; i < n; ++i) {
    // Fill the end of each row and column
    A.row(i).tail(n - old_size).setConstant(A(i, old_size - 1));
    A.col(i).tail(n - old_size).setConstant(A(old_size - 1, i));
}
// Fill the bottom right block
A.bottomRightCorner(n - old_size, n - old_size).setConstant(A(old_size - 1, old_size - 1));

Более важно, чем быть "эффективным", эти функции выражают ваши намерения как программиста.

Редактировать: чтобы получить дополненную матрицу с исходной матрицей в середине :

Я только что заметил ваши примерные площадки вокруг исходной матрицы посередине, а не вверху слева. В этом случае нет смысла использовать conservativeResize(), потому что исходные значения будут скопированы только в верхний левый угол. Схема решения:

  • Создайте новую матрицу nxn B нужного размера
  • Скопируйте исходную матрицу в середину, используя

    int start = (n - old_size + 1)/2; B.block(start, start, old_size, old_size) = A;

  • Заполните внешние значения, используя операции блока, аналогичные моему примеру выше.

...