当我无法矢量化计算时,如何加速循环的Matlab嵌套?

当我无法矢量化计算时,如何加速循环的Matlab嵌套?,matlab,Matlab,我有三个大小相同的大3D阵列[41*141*12403],在下面的Matlab代码中命名为alpha、beta和ni。从中,我需要计算另一个具有相同大小的3D数组,该数组是通过使用每个元素的值,结合无穷和和和定积分计算,从原始矩阵中以元素方式获得的。因此,必须使用多个嵌套循环来进行此计算似乎是不可行的。代码现在已经运行了几个小时(!),它仍然在外循环的第一次迭代中(需要执行41次!!根据我的计算,这样程序将不得不运行两年以上!!!)。我不知道如何优化代码。请帮帮我 我使用的代码是: z_

我有三个大小相同的大3D阵列[41*141*12403],在下面的Matlab代码中命名为alpha、beta和ni。从中,我需要计算另一个具有相同大小的3D数组,该数组是通过使用每个元素的值,结合无穷和和和定积分计算,从原始矩阵中以元素方式获得的。因此,必须使用多个嵌套循环来进行此计算似乎是不可行的。代码现在已经运行了几个小时(!),它仍然在外循环的第一次迭代中(需要执行41次!!根据我的计算,这样程序将不得不运行两年以上!!!)。我不知道如何优化代码。请帮帮我

我使用的代码是:

    z_len=size(KELDYSH_PARAM_r_z_t,1);   % 41 rows
    r_len=size(KELDYSH_PARAM_r_z_t,2);   % 141 columns   
    t_len=size(KELDYSH_PARAM_r_z_t,3);   % 12403 slices

    sumRes=zeros(z_len,r_len,t_len);

    for z_ind=1:z_len
        z_ind     % in order to track the advancement of the calculation
        for r_ind=1:r_len
            for t_ind=1:t_len
                sumCurrent=0;
                sumPrevious=inf;
                s=0;

                while abs(sumPrevious-sumCurrent)>1e-6
                    kapa=kapa_0+s;    %some scalar
                    x_of_w=(beta(z_ind,r_ind,t_ind).*(kapa-ni...
                       (z_ind,r_ind,t_ind))).^0.5;               
                    sumPrevious=sumCurrent;
                    sumCurrent=sumCurrent+exp(-alpha(z_ind,r_ind,t_ind).* ...
                        (kapa-ni(z_ind,r_ind,t_ind))).*(x_of_w.^(2*abs(m)+1)/2).* ...
                            w_m_integral(x_of_w,m);
                    s=s+1;
                end

                sumRes(z_ind,r_ind,t_ind)=sumCurrent;
            end
        end
    end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function  res=w_m_integral(x_of_w,m)

    res=quad(@integrandFun,0,1,1e-6);

    function y=integrandFun(t)
            y=exp(-x_of_w^2*t).*t.^(abs(m))./((1-t).^0.5);
    end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

选项1-更多矢量化

这是一个非常复杂的模型,并没有解释所有的术语,但有些部分仍然可以进一步矢量化。您的
alpha
beta
ni
矩阵可能是静态的,并且是预计算的?你的
s
值是一个标量,
kapa
可以是任何一个,因此你也可以一次性预计算w矩阵的x_。这将给你一个非常轻微的加速,虽然你会花费内存来获得它-7100万点是可行的,但这些天将需要大量的硬件。在你的41行中每行做一次,可以很好地减轻负担

剩下的就是积分本身。
quad
函数不接受矢量输入-这将是一场噩梦,不是吗Mathworks建议您改用的
integral
。但是,如果你的积分极限在每种情况下都是相同的,那么为什么不用老式的方法进行积分呢?为1处的被积函数值计算一个矩阵,为0处的被积函数值计算另一个矩阵,然后取差

然后您可以编写一个循环来计算整个输入空间的积分,然后测试所有矩阵元素的收敛性。制作一个遮罩,记录尚未收敛的部分,并重新计算增加的
s
。重复上述步骤,直到所有步骤都收敛(或者达到迭代的阈值)

选项2-将其并行化

过去的情况是,matlab使用矢量化运算比循环快得多。我现在找不到它的源代码,但我想我已经读到,最近使用
for
循环的速度也快了很多,因此,根据您可用的资源,通过并行化您当前拥有的代码,您可能会得到更好的结果。这也需要一点重构——将数据复制到工作人员时(可以通过将输入切块并输入相关的数据来解决),以及
parfor
循环不允许您使用某些变量,通常是覆盖整个空间的变量,而大问题是开销。再次切碎它们会有帮助

但是如果你有一个2年的运行时间,我猜你需要一个至少100倍的因子,所以这意味着一个集群!如果你在一所大学或某个地方,在那里你可以在一个500核的集群上呆上几天,那么就去吧

如果你可以写一个封闭形式的积分,那么它可能是服从GPU计算。这些东西可以很快地完成某些类别的计算,但你必须能够并行化作业,并将实际计算减少到一些基本的东西,主要包括加法和乘法。CUDA图书馆已经做了大量的腿部工作,所以请阅读这些

选项3-缩小范围

最后,如果以上两种方法都不能带来足够的加速,那么您可能需要缩小计算范围。尽可能地修剪输入空间,也许可以接受较低的收敛阈值。如果您知道在最内层的
while
循环(其中包含
s
计数器)中需要多少次迭代,那么减少收敛条件可能会减少您需要的迭代次数,从而加快迭代速度。探查器可以帮助查看您在哪里花费时间

但底线是7100万个点需要一些时间来计算。到目前为止,您只能优化计算,很可能对于这种规模的问题,您将不得不使用硬件