如何对Scilab中的所有矩阵元素执行操作?

时间:2015-09-05 10:01:34

标签: performance loops matrix scilab heat

随着时间的推移,我试图模拟无限大板上的热量分布。为此,我写了一个Scilab脚本。现在,它的关键点是计算所有板块的温度,并且必须在我想要观察的每个时刻进行:

for j=2:S-1
    for i=2:S-1
        heat(i, j) = tcoeff*10000*(plate(i-1,j) + plate(i+1,j) - 4*plate(i,j) + plate(i, j-1) + plate(i, j+1)) + plate(i,j);          
    end;
end 

问题是,如果我想为100x100点牌做这件事,那就意味着,这里(它只适用于内部,没有边界条件),我必须循环98x98 = 9604次,在每一个回合计算给定i,j点的热量。如果我想观察那个,比如100个secons,1步,我必须重复100次,共计960,400次迭代。这花了很长时间,我想避免它。高达50x50的盘子,这一切都发生在合理的4-5秒时间范围内。

现在我的问题是 - 是否有必要使用for循环完成所有这些操作?在Scilab中是否有任何内置的聚合函数,这将让我对矩阵的所有元素执行此操作?我还没有找到方法的原因是,每个点的结果都取决于其他矩阵点的值,这使得我使用嵌套循环。关于如何让它更快被欣赏的任何想法。

3 个答案:

答案 0 :(得分:2)

在我看来,你想要计算你的热场和某种扩散模式的二维相互关系。这种模式可以被视为"过滤器"内核,这是使用线性滤波器矩阵修改图像的常用方法。你的"过滤器"是:

F=[0,1,0;1,-4,1;0,1,0];

如果您安装了图像处理工具箱(IPD),您将拥有MaskFilter功能来执行此2D相互关系。

S=500;
plate=rand(S,S);
tcoeff=1;

//your solution with nested for loops
t0=getdate();
for j=2:S-1
  for i=2:S-1
    heat(i, j) = tcoeff*10000*(plate(i-1,j)+plate(i+1,j)-..
    4*plate(i,j)+plate(i,j-1)+plate(i, j+1))+plate(i,j);          
  end
end
t1=getdate();
T0=etime(t1,t0);
mprintf("\nNested for loops: %f s (100 %%)",T0);

//optimised nested for loop
F=[0,1,0;1,-4,1;0,1,0];   //"filter" matrix
F=tcoeff*10000*F;
heat2=zeros(plate);
t0=getdate();
for j=2:S-1
  for i=2:S-1
    heat2(i,j)=sum(F.*plate(i-1:i+1,j-1:j+1));
  end
end
heat2=heat2+plate;
t1=getdate();
T2=etime(t1,t0);
mprintf("\nNested for loops optimised: %f s (%.2f %%)",T2,T2/T0*100);

//MaskFilter from IPD toolbox
t0=getdate();
heat3=MaskFilter(plate,F);
heat3=heat3+plate;
t1=getdate();
T3=etime(t1,t0);
mprintf("\nWith MaskFilter: %f s (%.2f %%)",T3,T3/T0*100);

disp(heat3(1:10,1:10)-heat(1:10,1:10),"Difference of the results (heat3-heat):");

请注意,MaskFilter在应用滤镜之前填充图像(原始矩阵),据我所知,它使用的是#34;镜像"越过边界的阵列。您应该检查此行为是否适合您。

速度提升约为* 320(执行时间为原始代码的0.32%)。这够快吗?

理论上可以使用两个2D傅里叶变换(可能内置Scilab mfft),但它可能不会比这更快。见这里:http://mailinglists.scilab.org/Image-processing-filter-td2618144.html#a2618168

答案 1 :(得分:0)

请注意,如我所解释的here,向量化操作与并行计算之间有很大的区别。尽管向量化可能会稍微提高性能,但是这与例如通过GPU计算(例如OpenCL)所能达到的效果无法相比。我将尝试解释代码的矢量化形式,而无需过多介绍细节。如下考虑:

S = ...;
tcoeff = ...;

function Plate = plate(i, j)
    ...;
endfunction

function Heat = heat(i, j)
    ...;
endfunction

现在您可以定义一个meshgrid

x = 2 : S - 1;
y = 2 : S - 1;
[M, N] = meshgrid(x,y);
Result = feval(M, N, heat);

此处的键feval将在fevalM矩阵上广播N函数。

答案 2 :(得分:0)

您的方案是拉普拉斯算子应用于矩形网格的有限差分方案。如果您选择自由度的按行或按列编号(此处为plate(i,j))以将其视为向量,则可以通过乘以稀疏矩阵来应用“离散”拉普拉斯算子在左侧(非常快),在以下文档中对此进行了详细说明:

https://www.math.uci.edu/~chenlong/226/FDMcode.pdf

该实现在Matlab中进行了描述,但在Scilab中很容易翻译。