子矩阵分配

时间:2018-04-27 11:27:10

标签: matlab

我有一个关于子矩阵分配的计算时间的问题。 我曾经有过这样的代码:

B_tot(1:6,pos:pos+2) = [ddx 0 0;0 ddy 0;0 0 ddz;ddy ddx 0;0 ddz ddy;ddz 0 ddx];

根据Matlab分析器,这条线需要3.91秒(执行超过800,000次)。我觉得它需要很长时间,所以我用它取而代之:

B_tot(1,pos) = ddx;
B_tot(2,pos+1) = ddy;
B_tot(3,pos+2) = ddz;
B_tot(4,pos) = ddy;
B_tot(4,pos+1) = ddx;
B_tot(5,pos+1) = ddz;
B_tot(5,pos+2) = ddy;
B_tot(6,pos) = ddz;
B_tot(6,pos+2) = ddx;

计算时间仅为0.22秒,因此速度更快。

我现在的问题是:为什么子矩阵的分配速度要慢得多,我是否可以用漂亮的方式编写这样的分配,这仍然不是很耗时?

编辑: 我制作了一个可重复的代码用于比较:

tic
for i = 1:10000
    B_tot = zeros(6,24);
    for j = 1:8
        ddx = 1;
        ddy = 2;
        ddz = 3;
        pos = j*3-2;
        B_tot(1:6,pos:pos+2) = [ddx 0 0;0 ddy 0;0 0 ddz;ddy ddx 0;0 ddz ddy;ddz 0 ddx];
    end
end
toc
tic
for i = 1:10000
    B_tot = zeros(6,24);
    for j = 1:8
        ddx = 1;
        ddy = 2;
        ddz = 3;
        pos = j*3-2;
        B_tot(1,pos) = ddx;
        B_tot(2,pos+1) = ddy;
        B_tot(3,pos+2) = ddz;
        B_tot(4,pos) = ddy;
        B_tot(4,pos+1) = ddx;
        B_tot(5,pos+1) = ddz;
        B_tot(5,pos+2) = ddy;
        B_tot(6,pos) = ddz;
        B_tot(6,pos+2) = ddx;
    end
end
toc
tic
for i = 1:10000
    B_tot = zeros(6,24);
    for j = 1:8
        ddx = 1;
        ddy = 2;
        ddz = 3;
        pos = j*3-2;
        B_tot(sub2ind(size(B_tot),[1 2 3 4 4 5 5 6 6],pos+[0,1,2,0,1,1,2,0,2]))=[ddx,ddy,ddz,ddy,ddx,ddz,ddy,ddz,ddx];
    end
end
toc

输出:

Elapsed time is 0.287602 seconds.
Elapsed time is 0.012062 seconds.
Elapsed time is 0.510040 seconds.

2 个答案:

答案 0 :(得分:0)

使用Octave 4.0,我看到了运行脚本的时间:

Elapsed time is 2.30614 seconds.
Elapsed time is 3.02992 seconds.
Elapsed time is 1.84936 seconds.

Wolfie的版本是最快的,单元素索引是最慢的!

Octave的JIT(如果有的话)不如MATLAB好,因此时间相对较慢。

我认为你在这里看到的是MATLAB的JIT在某种程度上更好地针对单元素索引进行了优化。还要注意

B_tot(1:6,pos:pos+2) = [ddx 0 0;0 ddy 0;0 0 ddz;ddy ddx 0;0 ddz ddy;ddz 0 ddx];

创建一个矩阵,将值复制到其中,然后索引到B_tot并复制那里的值。当然,这可以优化执行,但他们可能没有这样做。

另请注意,您将在不同版本的MATLAB中看到非常不同的时序。我确信旧版本的MATLAB将显示类似于我现在使用Octave的时序。但是,未来版本的MATLAB很可能会为这些时序显示不同的顺序,因为它们会进一步改进JIT并优化更多语法案例。

答案 1 :(得分:-1)

子矩阵分配的底层实现由循环组成。循环总是慢于线性编程流程。如果你要进入assambler层,循环看起来有点像这样。

Pos  Operation
  1  load variable1, variable2
  2  cmp = compare variable1, variable2
  3  if cmp : goto pos 4, else : goto pos 17
  4  load something
  5  operate on something
...
 16  goto pos 1
 17  load something_else

虽然线性程序至少可以减少四次操作。

......我知道这不是真正的汇编程序,但我不知道语法。