Установить вектор собственных матриц на 0 - PullRequest
0 голосов
/ 20 февраля 2020

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

typedef Eigen::Matrix<int,30,150> HoughMatrix
std::vector<HoughMatrix> hough_spaces(num_spaces)

Мой вопрос сейчас таков: как быстрее всего сделать все элементы всех этих Матриц равными 0? Я попытался зациклить каждый элемент Vector и сделать:

hough_spaces[i].setZero()

Но это было довольно медленно. Есть ли более быстрый способ? Или способ напрямую инициализировать их как 0? Спасибо за вашу помощь

Ответы [ 2 ]

2 голосов
/ 20 февраля 2020

Прежде всего, Eigen::Matrix<int,30,150> по умолчанию будет выровнен до 16 байтов, что в 64-битных системах или с C ++ 17, скорее всего, будет работать правильно, но в противном случае вы можете столкнуться с некоторыми предостережениями . Простой способ обойти любые проблемы, связанные с выравниванием, - написать

typedef Eigen::Matrix<int,30,150, Eigen::DontAlign> HoughMatrix;

Теперь идиоматический c способ написать то, что вы хотите, будет написать

std::vector<HoughMatrix> hough_spaces(num_spaces, HoughMatrix::Zero());

Однако это будет результат в oop из memcpy вызовов (по крайней мере для g cc и clang: https://godbolt.org/z/ULixBm).

В качестве альтернативы, вы можете создать вектор неинициализированных HoughMatrix es и примените к ним std::memset:

std::vector<HoughMatrix> hough_spaces(num_spaces);
std::memset(hough_spaces.data(), 0, num_spaces*sizeof(HoughMatrix));

Обратите внимание, что для того, чтобы для запуска Eigen без l oop через все элементы, необходимо, чтобы HoughMatrix не выровнялся (как показано в начале ) или отключить утверждения выравнивания: https://godbolt.org/z/nDJqV5

Если вам на самом деле не нужна функциональность std::vector (в основном это возможность копирования и изменения размера), вы можете просто выделить несколько использование памяти calloc и free после использования. Для обеспечения утечки это может быть заключено в std::unique_ptr:

// unique_ptr with custom deallocator (use a typedef, if you need this more often):
std::unique_ptr<HoughMatrix[], void(&)(void*)> hough_spaces(static_cast<HoughMatrix*>(std::calloc(num_spaces, sizeof(HoughMatrix))), std::free);
if(!hough_spaces) throw std::bad_alloc(); // Useful, if you actually handle bad-allocs. If you ignore failed callocs, you'll likely segfault when accessing the data.

Clang и g cc оптимизирует это в одну пару calloc / free: https://godbolt.org/z/m4rzRq


Совершенно другой подход - попытаться использовать трехмерный тензор вместо вектора матриц:

typedef Eigen::Tensor<int, 3> HoughSpace;
HoughSpace hough_spaces(num_spaces,30,150);
hough_spaces.setZero();

Просмотр сгенерированной сборки это выглядит полуоптимально, хотя даже с -O3 -DNDEBUG.


В целом, обратите внимание, что сравнение всего, что связано с памятью, может вводить в заблуждение. Например, вызов calloc может вернуться почти мгновенно, но на более низком уровне к нераспределенным страницам, что в действительности делает доступ к ним в первый раз более дорогим.

0 голосов
/ 20 февраля 2020

Интересно то, что Eigen::Matrix не имеет конструктора для инициализации элементов. От Eigen: класс Matrix :

Matrix3f a;

-> без выделения, без инициализации элементов

MatrixXf a(10,15);

-> выделенные, но неинициализированные элементы

Наконец (!) Некоторые конструкторы, которые позволяют инициализировать элементы для векторов малого размера:

Vector2d a(5.0, 6.0);
Vector3d b(5.0, 6.0, 7.0);
Vector4d c(5.0, 6.0, 7.0, 8.0);

Если вы читаете Eigen: расширенная инициализация вы можете найти

Специальные матрицы и массивы

Классы Matrix и Array имеют методы stati c, такие как Ноль (), который можно использовать для инициализации всех коэффициентов до нуля. [...]

Пример

std::cout << "A fixed-size array:\n";
Array33f a1 = Array33f::Zero();
std::cout << a1 << "\n\n";

PS

Но это было довольно медленный. Есть ли более быстрый способ?

Не зная больше деталей о том, что вы имеете в виду под «медленным», трудно обсуждать детали. Все, что я могу сказать, - это то, что я ожидал бы, что инициализация будет происходить быстрее, чем выделение унифицированных элементов, а затем setZero().

...