在c++中处理大矩阵

Handling large matrices in C++

本文关键字:处理 c++      更新时间:2023-10-16

我在c++中使用double s的大矩阵。我需要从这些矩阵中得到行或列并把它们传递给一个函数。我最快的方法是什么?

    一种方法是编写一个函数,返回所需行或列的副本作为std::vector
  1. 另一种方法是将整个东西作为引用传递,并修改函数以能够读取所需值。

还有其他选择吗?你推荐哪一种?

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

编辑

我必须提到矩阵可能有两个以上的维度。因此,在这里使用boost或arma::mat是不可能的。虽然,我在库的其他部分使用armadillo

如果关键需求是2以上的可变维数,请查看boost的多维数组库。它具有高效(无复制)"视图"可以用来引用完整矩阵的低维"切片"。

对于这类事情,什么是"最快"的细节在很大程度上取决于你到底在做什么,以及访问模式/工作集"足迹"如何适合你的HW的各种缓存和内存延迟级别;在实践中,复制到更紧凑的表示来获得更多的缓存一致性访问是值得的,而不是进行稀疏的跨行访问,因为这只会浪费大量的缓存线。替代方案是Morton-order访问方案,它至少可以在所有轴上摊销"坏轴"效应。只有你自己对自己的代码和用例进行基准测试才能真正回答这个问题。

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

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

高效(多)线性代数是一门非常深奥的学科;没有简单的放之四海而皆准的答案。主要的挑战是数据局部性:计算机的内存硬件是为访问连续的内存区域而优化的,并且可能一次只能在缓存线上操作(即使可以,效率也会下降)。

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

正因为如此,将数据放在矩阵中以使其可以在多个方向上有效地访问是一个非平凡的挑战;对于高阶张量更是如此。

此外,最好的选择可能在很大程度上取决于你对矩阵做了什么。

你的问题真的不是一个可以用这样的形式令人满意地回答的问题。

但为了至少让你开始研究,这里有两个关键短语可能值得研究:

    <
  • 块矩阵/gh>
  • 快速转置算法

你最好使用一个库,而不是自己编写;例如闪电战+ +。(免责声明:我没有使用blitz++)

vector<vector<...>>分配的速度很慢,释放的速度很慢,访问的速度也很慢,因为它会有多个解引用(不是缓存友好的)。

只有当你的(行或列)没有相同的大小(锯齿数组)时,我才会推荐它。

对于一个"正常"矩阵,你可以这样写:

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

和重载operator(size_t i, size_t j, etc.)来访问元素

operator()必须进行索引计算(您必须在以行为主的顺序或以列为主的顺序之间进行选择)。对于nDim > 2,它变得有些复杂,并且可以从缓存一些索引计算中获益。

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

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

然后定义一个将返回tensor.vect[iStart + i*stride]operator(size_t i)

stride值将取决于它是行还是列,以及(行为主还是列为主)排序选择。

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

请参阅其他关于为什么先迭代行后迭代列可能会比先迭代列后迭代行有巨大性能差异的问题。

我建议您通过引用传递它,因为根据大小的不同,复制可能是一个缓慢的过程。如果您希望能够扩展和收缩容器,Std::vector是可以的。