用C ++处理大型矩阵

时间:2015-06-06 18:47:25

标签: c++ c++11 matrix

我在C ++中使用double s的大型矩阵。我需要从这些矩阵中获取行或列并将它们传递给函数。我能做到这一点的最快方法是什么?

  1. 一种方法是编写一个函数,将所需行或列的副本作为std::vector返回。
  2. 另一种方法是将整个事物作为参考传递并修改函数以便能够读取所需的值。
  3. 还有其他选择吗?你推荐哪一个?

    顺便说一句,你怎么建议我把数据存储在矩阵类中?我现在正在使用std::vector< std::vector< double > >

    修改

    我已经提到过矩阵可能有两个以上的维度。所以在这里使用boost或arma::mat是不可能的。虽然,我在图书馆的其他部分使用犰狳。

5 个答案:

答案 0 :(得分:3)

如果大于2的可变维数是关键要求,请查看boost's multidimensional array library。它有效(免费复制)&#34; views&#34;你可以用来引用低维&#34;切片&#34;全矩阵。

&#34; s&#34;最快&#34;的细节对于这类事情,很大程度上取决于你究竟在做什么,以及访问模式/工作集&#34;足迹&#34;适合您硬件的各种级别的缓存和内存延迟;在实践中,值得复制到更紧凑的表示以获得更多的高速缓存一致性访问,而不是进行稀疏的跨步访问,这只会浪费大量的高速缓存行。替代方案是Morton-order访问方案,这些方案至少可以分摊&#34;坏轴&#34;对所有轴的影响。只有你自己的代码和你硬件上的用例的基准测试才能真正回答这个问题。

(请注意,我不会将Boost.MultiArray用于二维数组 - 对于线性代数/图像处理应用程序有更快,更好的选择 - 但对于3+以上,它值得考虑。)

答案 1 :(得分:2)

我会使用像http://arma.sourceforge.net/这样的库,因为你不仅可以找到存储矩阵的方法。您还可以使用可以对其进行操作的函数。

答案 2 :(得分:2)

高效(多)线性代数是一个令人惊讶的深层主题;没有简单的一刀切的答案。主要挑战是数据位置:您的计算机的内存硬件已经过优化,可以访问连续的内存区域,并且可能无法同时运行缓存行以外的任何内容(即使可能,效率会下降)。

缓存行的大小各不相同,但要考虑64或128字节。

正因为如此,将数据布置在矩阵中以便能够在多个方向上有效地访问是一项非常重要的挑战;更高等级的张量更是如此。

此外,最佳选择可能在很大程度上取决于您对矩阵的确切做法。

您的问题确实不是能够以这样的Q&amp; A格式得到满意答案的问题。

但至少让你开始研究,这里有两个可能值得研究的关键词:

  • 块矩阵
  • 快速转置算法

你最好使用一个图书馆,而不是试图自己动手;例如突击++。 (免责声明:我没有使用过闪电战++)

答案 3 :(得分:1)

vector<vector<...>>分配速度慢,释放缓慢,访问速度慢,因为它会有多个解除引用(不支持缓存)。

只有当您的(行或列)大小不同(jagged arrays)时,我才会推荐它。

对于“普通”矩阵,您可以选择以下内容:

template <class T, size_t nDim> struct tensor {
    size_t dims[nDim];
    vector<T> vect;
};

并重载operator(size_t i, size_t j, etc.)以访问元素。

operator()必须进行索引计算(您必须在row-major或列主要订单之间进行选择)。对于nDim > 2,它变得有些复杂,它可以从缓存一些索引计算中受益。

要返回行或列,您可以定义子类型。

template <class T, size_t nDim> struct row /*or column*/ {
    tensor<T, nDim> & tensor;
    size_t iStart;
    size_t stride;
}

然后定义将返回operator(size_t i)

tensor.vect[iStart + i*stride]

stride值取决于它是行还是列,以及您的(行主要或列主要)排序选择。

对于您的一个子类型,

stride将为1。请注意,对于此子类型,迭代可能会快得多,因为它将是缓存友好的。不幸的是,对于其他子类型,它可能会相当慢,而且你无能为力。

请参阅其他有关为什么在行上进行迭代的SO问题,然后列可能会比在行和行上迭代时具有巨大的性能差异。

答案 4 :(得分:0)

我建议您通过引用传递它,因为复制可能是一个缓慢的过程,具体取决于大小。如果你想扩展和收缩容器的能力,std :: vector很好。