有没有一种聪明的方法来矢量化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。我们非常感谢您对优化代码的建议!
答案 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);