将特征矩阵向量设置为0

时间:2020-02-19 21:00:12

标签: c++ eigen

我正在将Hough变换用于特殊应用,为此,我需要在向量中存储很多本征矩阵,并且一开始它们都必须为0。 这就是我初始化的方式:

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

我现在的问题是,使所有这些矩阵的所有元素等于0的最快方法是什么? 我尝试遍历每个Vector元素并执行以下操作:

hough_spaces[i].setZero()

但这太慢了。有没有更快的方法?还是直接将它们初始化为0的方法? 谢谢您的帮助

2 个答案:

答案 0 :(得分:2)

首先,Eigen::Matrix<int,30,150>默认情况下将对齐为16个字节,这在64位系统或C ++ 17上最有可能正常工作,但是您可能会遇到some caveats。 解决对齐问题的一种简单方法是编写

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

现在惯用的方式来写你想要的东西就是写

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

但是,这将导致memcpy调用循环(至少对于gcc和clang:https://godbolt.org/z/ULixBm)。

或者,您可以创建未初始化的HoughMatrix的向量,并将std::memset应用于它们:

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

请注意,要在没有本征循环的情况下必须遍历所有元素,就必须使HoughMatrix不对齐(如开头所示)或禁用对齐声明:https://godbolt.org/z/nDJqV5

如果实际上不需要std::vector功能(主要是复制和调整大小的功能),则可以使用callocfree在使用后分配一些内存。为了安全起见,可以将其封装到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和gcc会将其优化为单个calloc / free对: https://godbolt.org/z/m4rzRq


一种完全不同的方法是尝试使用3D张量代替矩阵向量:

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

即使在-O3 -DNDEBUG的情况下,看着generated assembly看起来也是半最佳的。


总体而言,请注意,对与内存相关的任何事物进行基准测试可能会产生误导。例如,对calloc的调用可能几乎立即返回,但在较低级别上指向未分配的页面,这使得首次访问它们实际上更加昂贵。

答案 1 :(得分:0)

有趣的部分是Eigen::Matrix似乎没有构造函数来初始化元素。来自Eigen: The Matrix class

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: Advanced initialization,则会发现

特殊矩阵和数组

Matrix和Array类具有静态方法,例如Zero(),该方法可以 可用于将所有系数初始化为零。 [...]

示例

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

PS

但这太慢了。有没有更快的方法?

尽管不了解“慢”意味着什么的更多细节,但很难讨论细节。我只能说,我希望初始化只会比分配单元化元素然后分配setZero()更快。