有没有办法减少这两个相关矩阵之间的操作?

时间:2017-04-22 17:44:31

标签: c matrix matrix-multiplication

我有两个矩阵,第一个矩阵是从第二个数据创建的,用于转换第二个矩阵。我重复这个操作很多次。由于这两个矩阵的依赖性,我还没有找到一种方法来加速这里的操作。我会尝试用小矩阵大小向您展示我所说的内容。

Type mismatch: cannot convert from List<String> to ArrayList<String>

假设我执行此操作数百万次,并且计算值在A中的位置取决于我希望在B中发生旋转的位置。因此,在每次迭代中,矩阵A和B不同,并且使用的值计算放在A中的新值是不同的。

有没有人知道加速此类代码的方法?考虑到矩阵乘法本质上是向量矩阵乘法,我希望创建一个组合A(展开到A是一个完整矩阵的点,或者足以充分利用MMM算法),但新值的数据依赖性使得好像我可能会陷入困境。我得到这样的东西:

[ 1 0 0     0     ]     [ .11 .22 .33 .44 ]
[ 0 1 0     0     ]     [ .65 .42 .01 .92 ]
[ 0 0 .51^2 .85^2 ]  *  [ .31 .15 .51 .85 ]
[ 0 0 .44^2 .23^2 ]     [ .25 .78 .44 .23 ]
        A                        B

其中A&#39;源于B&#39;,A&#39;&#39;来自B&#39;&#39;等等。

编辑:

澄清一下,第二轮可能是:

A * B = B'
A' * B' = B''
A'' * B'' = B'''

2 个答案:

答案 0 :(得分:0)

这更像是一个数学问题,而不是一个编程问题,但是有一种方法可以加速你的计算。这个答案假设您正在乘以大型矩阵,但A是对单位矩阵的略微修改,仅在位置(i,i),(i,i+1),({{ 1}})和(i+1,i)正如您在评论中提到的那样。

请注意,左侧的i+1,i+1乘以矩阵B,其中A除了对角线上的1之外都有一行全零,相当于说{{1} } A的行等于B的i行。这意味着您可以立即在迭代中保存大量计算。

鉴于更新AB i具有这些不错的属性,我们有以下算法:

  1. B' = A*B初始化为A
  2. 执行矩阵乘法B',此左侧是B矩阵。
  3. 将此更新的输出存储在正确的两行update = [A(i,:),A(i+1,:)]*B中:(2xn)
  4. 翻转每次更新= B'

    如果您的大小[B'(i,:),B'(i+1,:)]真的很大,您可能希望通过利用两行O(2n^2)的行稀疏性来在这些小矩阵乘法中保存更多计算。您可以执行nA矩阵乘法,而不是执行(2xn)(nxn)矩阵乘法。

    这个新算法将再次更新正确的两行(2x2)。但是,现在您的更新矩阵乘法必须是:

    (2xn)

    翻转每次更新= B'

    请注意,两种算法都没有明确存储所有update = [A(i ,i), A(i ,i+1)] * [B(i ,:)] [A(i+1,i), A(i+1,i+1)] [B(i+1,:)] ,因此您将节省内存和计算。此外,如果以行主格式存储矩阵,前面的两种算法都将非常有效。

答案 1 :(得分:0)

将矩阵A[rows][num]乘以矩阵B[num][cols]时,结果矩阵C[rows][cols]中的每个元素都是

C[r][c] = A[r][0]*B[0][c] + ... + A[r][num-1]*B[num-1][c]
        = sum( A[r][k] * B[k][c], k = 0 .. num-1 )

此处,A是除两行(r0r1)之外的单位矩阵,每行包含两列(c0和{{1} }})。由于行c1r0否则为零,因此这些行上结果矩阵r1中的每个元素都是两个产品的总和:

C

由于C[r0][i] = A[r0][c0] * B[c0][i] + A[r0][c1] * B[c1][i] C[r1][i] = A[r1][c0] * B[c0][i] + A[r1][c1] * B[c1][i] 是一个单位矩阵,因此结果中的所有其他行与A矩阵中的相应行相同。

如果我们使用

B

然后我们可以将更新循环描述为

a00 = A[r0][c0]        a01 = A[r0][c1]
a10 = A[r1][c0]        a11 = A[r1][c1]

如果我们在更新循环中使用两个临时变量(例如For i = 0 .. cols-1 C[r0][i] = a00 * B[c0][i] + a01 * B[c1][i] C[r1][i] = a10 * B[c0][i] + a11 * B[c1][i] End for c0 == r0,那么在我们计算c1 == r0处的元素之前,我们不会覆盖[r0][i]处的元素1}}),只使用[r1][i]矩阵就可以完成整个操作。

如果左矩阵B中的非同一性元素是矩阵A中的对应元素,并且我们进行了更新,则变得非常简单。在C99:

B

上述操作的计算成本为#include <stdlib.h> void update(const size_t n, double B[n][n], const size_t r, const size_t c) { const double a00 = B[r ][c ] * B[r ][c ]; const double a01 = B[r ][c+1] * B[r ][c+1]; const double a10 = B[r+1][c ] * B[r+1][c ]; const double a11 = B[r+1][c+1] * B[r+1][c+1]; size_t i; for (i = 0; i < n; i++) { const double b0i = B[c ][i]; const double b1i = B[c+1][i]; B[r ][i] = a00 * b0i + a01 * b1i; B[r+1][i] = a10 * b0i + a11 * b1i; } } 乘法和4*n+4个(矩阵元素的加法),即 O(N)

这种方法也适用于GivensJacobi旋转,除了不是使用给定矩阵计算四个元素,而是根据传递给函数的参数计算它们;而不是连续的行和列,需要传递两个单独的行和两个列参数。