优化稀疏矩阵的加权和

时间:2011-03-01 12:22:36

标签: matlab performance matrix optimization sparse-matrix

我欢迎任何有关以下代码优化问题的帮助:

我有一组存储在单元格数组[s1 s2]中的相同大小的N个稀疏矩阵(A)以及存储在向量w中的相应数量的标量权重。我想计算A中所有矩阵的总和,加权w中存储的值。通过我的程序的迭代,只有w中的值发生了变化。因此,我可以先计算结果中非零元素的数量,并使用spalloc为其预分配一些内存。
目前我有类似的东西:

result = spalloc(s1,s1,number_of_non_zero);
for i=1:N
    result = result + w(i)*A{i};
end

我真的需要优化这个部分,暂时占用我程序中的大部分计算时间(使用剖析工具检查)。
一些额外的信息:
- 以上代码运行数百万次,因此即使是微小的改进也是值得欢迎的 - A中的矩阵来自有限元素代码(1D或2D)
- 如果我可以节省一些时间(例如使用cell2mat(A)

,我可以顺利离开单元结构

感谢您提供有关如何加速这部分代码的任何提示。

一个。

2 个答案:

答案 0 :(得分:1)

我不能确定这个解决方案是否会在计算上更有效率,但它还有其他的尝试......

如果你真的必须将你的矩阵表示为稀疏(即完整矩阵占用太多内存)并且MATLAB中的built-in sparse representation没有给你你想要的性能,那么你可以尝试表示稀疏矩阵以不同的方式。具体来说,您可以将它们表示为N×3矩阵,其中前两列包含所有非零值的矩阵中的行和列索引,第三列包含非零值。您可以使用函数FIND将数据转换为此表单,如下所示:

for iMatrix = 1:numel(A)
  [r,c,v] = find(A{iMatrix});
  A{iMatrix} = [r c v];
end

每次需要计算这些矩阵的加权和时,首先需要将这些值乘以权重:

B = A;  %# Store a temporary copy of A
for iMatrix = 1:numel(B)
  B{iMatrix}(:,3) = w(iMatrix).*B{iMatrix}(:,3);
end

然后,您可以使用函数ACCUMARRAY计算最终总和:

B = vertcat(B{:});  %# Convert B from a cell array to an N-by-3 matrix
result = accumarray(B(:,1:2),B(:,3));

在这种情况下,变量result将是一个完整的矩阵。如果您需要result作为稀疏矩阵,则可以在ACCUMARRAY的调用中添加额外的参数,如下所示:

result = accumarray(B(:,1:2),B(:,3),[],[],[],true);

答案 1 :(得分:0)

如果将A转换为矩阵而不是单元格数组,则可以使用某些RESHAPEREPMAT杂技来对循环进行矢量化。假装我们有以下数据:

>> A(:,:,1) = [1 0 0; 0 0 2; 0 0 0];
>> A(:,:,2) = [3 0 1; 0 3 0; 0 1 0]

A(:,:,1) =

     1     0     0
     0     0     2
     0     0     0


A(:,:,2) =

     3     0     1
     0     3     0
     0     1     0

>> w = [2; 3]

w =

     2
     3

重新塑造w,以便您可以逐个元素进行乘法,然后求和:

>> w = reshape(w, [1 1 length(w)])

w(:,:,1) =

     2


w(:,:,2) =

     3

>> w = repmat(w, [size(A,1) size(A,2) 1])

w(:,:,1) =

     2     2     2
     2     2     2
     2     2     2


w(:,:,2) =

     3     3     3
     3     3     3
     3     3     3

>> w .* A

ans(:,:,1) =

     2     0     0
     0     0     4
     0     0     0


ans(:,:,2) =

     9     0     3
     0     9     0
     0     3     0

>> sum(w .* A, 3)

ans =

    11     0     3
     0     9     4
     0     3     0