在恒定时间内“拆分”矩阵

Posted

技术标签:

【中文标题】在恒定时间内“拆分”矩阵【英文标题】:"Splitting" a matrix in constant time 【发布时间】:2016-11-29 16:25:12 【问题描述】:

我正在尝试在 C++ 中实现 Strassen 的矩阵乘法算法,并且我想找到一种方法在恒定时间内将两个矩阵分成四个部分。这是我目前的做法:

for(int i = 0; i < n; i++)
    for(int j = 0; j < n; j++)
        A11[i][j] = a[i][j];
        A12[i][j] = a[i][j+n];
        A21[i][j] = a[i+n][j];
        A22[i][j] = a[i+n][j+n];
        B11[i][j] = b[i][j];
        B12[i][j] = b[i][j+n];
        B21[i][j] = b[i+n][j];
        B22[i][j] = b[i+n][j+n];
    

这种方法显然是 O(n^2),它会将 n^2*log(n) 添加到运行时,因为它在每次递归调用时都会被调用。

似乎在恒定时间内执行此操作的方法是创建指向四个子矩阵的指针,而不是复制值,但我很难弄清楚如何创建这些指针。任何帮助将不胜感激。

【问题讨论】:

您的源矩阵的大小是否为 2*n? 【参考方案1】:

不要考虑矩阵,要考虑矩阵视图。

矩阵视图具有指向T 缓冲区的指针、宽度、高度、偏移量以及列(或行)之间的步幅。

我们可以从数组视图类型开始。

template<class T>
struct array_view 
  T* b = 0; T* e = 0;
  T* begin() const return b; 
  T* end() const return e; 

  array_view( T* s, T* f ):b(s), e(f) 
  array_view( T* s, std::size_t l ):array_view(s, s+l) 

  std::size_t size() const  return end()-begin(); 
  T& operator[]( std::size_t n ) const  return *(begin()+n); 
  array_view slice( std::size_t start, std::size_t length ) const 
    start = (std::min)(start, size());
    length = (std::min)(size()-start, length);
    return b+start, length;
  
;

现在我们的矩阵视图:

temlpate<class T>
struct matrix_view 
  std::size_t height, width;
  std::size_t offset, stride;
  array_view<T> buffer;

  // TODO: Ctors
  // one from a matrix that has offset and stirde set to 0.
  // another that lets you create a sub-matrix
  array_view<T> operator[]( std::size_t n ) const 
    return buffer.slice( offset+stride*n, width ); // or width, depending on if row or column major
  
;

现在您的代码确实适用于 matrix_views,而不是矩阵。

【讨论】:

【参考方案2】:

您可以创建一个子矩阵类来保存您要使用的较小矩阵在父矩阵中的位置。主要是您已经为 Matrix 拥有的东西,除了您需要存储行和列的起始索引,然后通过这些偏移量偏移您的索引。如果处理得当,主/根矩阵将是一个以完整矩阵为边界的子矩阵。

【讨论】:

以上是关于在恒定时间内“拆分”矩阵的主要内容,如果未能解决你的问题,请参考以下文章

将矩阵拆分为 4 个子矩阵,它们的总和之间的差异最小

在生成文档术语矩阵之前或之后拆分为测试和训练集?

相机的外部参数 - 它们是恒定的吗?

使用索引数组拆分矩阵

如何将稀疏矩阵拆分为训练集和测试集?

将长二维矩阵拆分为第三维