同时分配矩阵的多个子矩阵。矢量化指数可能的优化

时间:2011-03-27 10:40:14

标签: optimization matlab matrix vectorization pde

有没有一种聪明的方法来矢量化for循环,它将元素分配给矩阵的子矩阵?
最初,我有两个for循环:

U=zeros(6*(M-2),M-2);
for k=2:M-3  
    i=(k-1)*6+1; 
    for j=2:M-3
        U(i:i+5,j)=A*temp(i:i+5,j)+B*temp(i:i+5,j-1)+C*temp(i:i+5,j+1)+D*temp(i-6:i-1,j)+E*temp(i+6:i+11,j);
    end
end

然后我对内部循环进行了矢量化,以便代码现在读取

U=zeros(6*(M-2),M-2);
j=2:M-2;
for k=2:M-3
    i=(k-1)*6+1;
    U(i:i+5,j)=A*temp(i:i+5,j)+B*temp(i:i+5,j-1)+C*temp(i:i+5,j+1)+D*temp(i-6:i-1,j)+E*temp(i+6:i+11,j);
end

这使我的CPU时间减少了90%以上,所以我想知道我是否可以对外循环做同样的事情,但是看起来有点棘手,因为我在U矩阵中分配了(6x1) - 矩阵。我试过了

U=zeros(6*(M-2),M-2);
k=2:M-3;
i=(k-1)*6+1;
j=2:M-2;
U(i:i+5,j)=A*temp(i:i+5,j)+B*temp(i:i+5,j-1)+C*temp(i:i+5,j+1)+D*temp(i-6:i-1,j)+E*temp(i+6:i+11,j);

但这失败了,因为i:i + 5只取出了我想要的前6个指数。

我还尝试使用reshape()函数将矩阵转换为向量,但似乎仍然难以一次分配给多个元素块。总共有三个这样的for循环 代码,所以我想另一种优化是以某种方式并行化它们。但是,如果没有访问并行工具箱的话,在我看来,矢量化似乎是一个很好的解决方案。

该代码是数值有限差分方法中子程序的一部分,用于求解网格上6个方程的系统,因此这个问题可能适用于任何使用矩阵计算的人。 方程组,特别是PDEs。我们非常感谢您对优化代码的建议!

2 个答案:

答案 0 :(得分:0)

为了选择矩阵的非矩形部分,您需要使用线性索引:在3x3矩阵A中,A(3,3)==A(9)A([1 3 5 7 9])是无法实现的向量通过行/列索引方法。

sub2ind函数将行/列索引转换为线性索引,因此您可以使用sub2ind(size(U),i:i+5,j)形式使用它来获取U块的一个块的线性索引。将循环更改为仅执行收集线性指数的工作,然后你可以说在循环之外:

U(ind_U) = A*temp(ind_A) + B*temp(ind_B) ...

此外,无论何时处理FDM或FEM,都要考虑是否应该使用稀疏矩阵。

答案 1 :(得分:0)

要了解如何在没有循环的情况下在一行中编写赋值,可能有助于将数组temp绘制为矩形。然后,将合并到U的不同加数只是temp的子矩形(或子网格,如果您想跟踪temp中将导致的单个元素在U)的特定元素中,分别向左,向右,向上,向下移动。

%# define row, column shifts
rowShift = 6;
colShift = 1;

%# That's how we'd like to shift 
%# U(i:i+5,j)=A*temp(i:i+5,j)+B*temp(i:i+5,j-1)+C*temp(i:i+5,j+1)+
%# D*temp(i-6:i-1,j)+E*temp(i+6:i+11,j);

%# assign U
U = A * temp(rowShift+1 : end-rowShift, colShift+1 : end-colShift) +... 
    B * temp(rowShift+1 : end-rowShift, 1 : end-2*colShift) + ...
    C * temp(rowShift+1 : end-rowShift, 2*colShift+1 : end) + ...
    D * temp(1 : end-2*rowShift, colShift+1 : end-colShift) + ...
    E * temp(2*rowShift+1 : end, colShift+1 : end-colShift);