Performance 使用嵌套for循环时提高数组填充速度-matlab

Performance 使用嵌套for循环时提高数组填充速度-matlab,performance,matlab,for-loop,vectorization,Performance,Matlab,For Loop,Vectorization,我编写这个函数是为了根据某些标准查找索引。它应该可以工作,问题是在我的电脑上运行需要2-3天。有没有办法让它在一小时内运行(或者更快)?这真的不需要很快。但是2天的时间慢得令人无法接受 我不期望对函数进行深入的分析(尽管这会很好)。只是一些一般性的改进 它本质上是3 for循环,用于使用另一个256x8矩阵逻辑填充8个大型3d阵列。然后进行一些逻辑测试以找到所需的索引 %These are sample values from the g.u.i. and other functions -

我编写这个函数是为了根据某些标准查找索引。它应该可以工作,问题是在我的电脑上运行需要2-3天。有没有办法让它在一小时内运行(或者更快)?这真的不需要很快。但是2天的时间慢得令人无法接受

我不期望对函数进行深入的分析(尽管这会很好)。只是一些一般性的改进

它本质上是3 for循环,用于使用另一个256x8矩阵逻辑填充8个大型3d阵列。然后进行一些逻辑测试以找到所需的索引

%These are sample values from the g.u.i. and other functions - 
%ignore up til the loops unless you need it to understand something in the loops.

PriceMat=[58867 55620 16682 97384 11660 18175 25896 16300];
CapMat=[1400 1200 450 3600 150 1330 2000 250];
RepMat=[58 53 31 127 15 164 242 27];
DesiredRep=293.04;
DesiredCap=2600;

prevmin=99999999;
P=perms(0:7);

D=zeros(256,8,40320);
Cap=zeros(size(D,3),8);
Rep=zeros(size(D,3),8);
Price=zeros(size(D,3),8);
SufRep=zeros(1,size(D,3));
SufCap=zeros(1,size(D,3));
CapTot=zeros(1,size(D,3));
RepTot=zeros(1,size(D,3));
PriceTot=zeros(1,size(D,3));


for i=1:40320
    for x=1:8

        for   j=1:256
            D(j,x,i)=P(i,x)*Logic(j,x);

            Cap(i,x)=D(j,x,i)*CapMat(x);
            Price(i,x)=D(j,x,i)*PriceMat(x);
            Rep(i,x)=D(j,x,i)*RepMat(x);
            CapTot=sum(Cap,2);
            RepTot=sum(Rep,2);
            PriceTot=sum(Price,2);

            if CapTot(i)>=DesiredCap
                SufCap(i)=true;
            else 
                SufCap(i)=false;
            end

            if RepTot(i)>=DesiredRep
                SufRep(i)=true;
            else 
                SufRep(i)=false;
            end

            if SufRep(i)==true && SufCap(i)==true

                if PriceTot(i)<=prevmin
                    prevmin=i;
                end
            end

        end

    end

end

return prevmin
%这些是来自g.u.i.和其他函数的样本值-
%忽略直到循环,除非你需要它来理解循环中的某些东西。
价格=[58867 55620 16682 97384 11660 18175 25896 16300];
CapMat=[1400 1200 450 3600 150 1330 2000 250];
RepMat=[58 53 31 127 15 164 242 27];
DesiredRep=293.04;
期望上限=2600;
prevmin=9999999;
P=perms(0:7);
D=零(256,840320);
上限=零(尺寸(D,3),8);
代表=零(尺寸(D,3),8);
价格=零(尺寸(D,3),8);
SufRep=零(1,大小(D,3));
SufCap=零(1,尺寸(D,3));
CapTot=零(1,尺寸(D,3));
RepTot=零(1,大小(D,3));
PriceTot=0(1,大小(D,3));
对于i=1:40320
对于x=1:8
对于j=1:256
D(j,x,i)=P(i,x)*逻辑(j,x);
Cap(i,x)=D(j,x,i)*CapMat(x);
价格(i,x)=D(j,x,i)*PriceMat(x);
Rep(i,x)=D(j,x,i)*RepMat(x);
CapTot=总和(Cap,2);
RepTot=总和(Rep,2);
PriceTot=总和(价格,2);
如果CapTot(i)>=所需CAP
SufCap(i)=正确;
其他的
SufCap(i)=错误;
结束
如果RepTot(i)>=DesiredRep
SufRep(i)=真;
其他的
SufRep(i)=假;
结束
如果SufRep(i)=真&&SufCap(i)=真

如果PriceTot(i)使用
bsxfun
那太有趣了

以下是如何在一行中计算矩阵
D
(无循环):

我想你可以从这里开始,以这种方式计算其余的矩阵-没有循环。

你说“如果能对函数进行深入分析就好了”。它相当复杂,而且可以大大简化。我有点担心我的解决方案会占用多少内存—您的256x8x40320阵列中有一个大约660 MB,我创建了四个。如果这不是问题的话,很好。否则,您可能必须选择一种更保守的数据类型,以降低内存需求—如果您开始交换到磁盘,您就死定了,时间方面

因此,假设您不受RAM的限制,那么下面的内容将大大加快速度(注意——我正在窃取Shai关于使用bsxfun的建议)。还要注意的是,我在计算了“真正大的”数组的和之后,正在清除这些数组-这可以在一行中完成,但您更难遵循:

D = bsxfun( @times, permute( P, [ 3 2 1] ), Logic );
Cap = bsxfun( @times, D, CapMat );
CapTot = sum( Cap, 2 );
clear Cap

Price = bsxfun( @times, PriceMat );
PriceTot = sum( Price, 2 );
clear Price

Rep = bsxfun( @times, D, RepMat ); % <<<<< STRONGLY recommend not to use RepMat -
                                   % <<<<< to avoid confusion with built in repmat()
RepTot = sum( Rep, 2 );
clear Rep

CapRepOK = ( CapTot >= DesiredCap && RepTot >= DesiredRep ); % logical array - fast, small

[minPrice minPriceInd ] = min(PriceTot(CapRepOK)); % find minimum value and index

% convert index to correct value of `i` in original code:
cs = cumsum(ok(:)); % increases by one for every value that meets criteria
                    % but we need to know which original index that corresponds to:
possibleValues = find( cs == minPriceInd );
[j i] = ind2sub( size(CapRepOK), possibleValues(1) );
prevmin = i;
D=bsxfun(@times,permute(P[3,2,1]),逻辑);
Cap=bsxfun(@times,D,CapMat);
CapTot=总和(Cap,2);
透明盖
Price=bsxfun(@次,PriceMat);
PriceTot=总和(价格,2);
净价

Rep=bsxfun(@times,D,RepMat);%什么是逻辑(j,x)
?逻辑是另一个数组。我在开头提到的256×8矩阵是逻辑矩阵,不是D矩阵。对此我很抱歉。现在将编辑它什么是
D(j,x)
<代码>D
是3D…应该是D(j,x,i)。从之前的一次尝试复制而来,但没有注意到,谢谢。你能更新你的代码,让所有的“已知bug”都消失吗?谢谢。我没想到你能用你所用的技巧把二维矩阵变换成三维矩阵,真是太棒了。我认为你不希望
逻辑
被转置。。。它的尺寸顺序是
(j,x)
D
@Floris的尺寸顺序相同,请查看tag wiki以了解更多的技巧和窍门。不幸的是,内存是一个很大的问题。我用4GB内存运行32位。我的电脑可以处理的最大阵列大小约为700-1200MB。所有阵列的总可用内存约为1500-1700MB,据我所知,所有这些都是用来释放内存的。我想我可以在同事更好的电脑上运行它。非常感谢您的努力,我一定会尝试您的一些建议并尝试使用bsxfun。对于许多应用程序,使用
float
作为数据类型就足够了-这取决于值的范围和所需的精度。如果是这样,那么从一开始就使用
P
Logic
CapMat
PriceMat
RepMat
浮动将使内存需求减半,并很可能提高速度。
D = bsxfun( @times, permute( P, [ 3 2 1] ), Logic );
Cap = bsxfun( @times, D, CapMat );
CapTot = sum( Cap, 2 );
clear Cap

Price = bsxfun( @times, PriceMat );
PriceTot = sum( Price, 2 );
clear Price

Rep = bsxfun( @times, D, RepMat ); % <<<<< STRONGLY recommend not to use RepMat -
                                   % <<<<< to avoid confusion with built in repmat()
RepTot = sum( Rep, 2 );
clear Rep

CapRepOK = ( CapTot >= DesiredCap && RepTot >= DesiredRep ); % logical array - fast, small

[minPrice minPriceInd ] = min(PriceTot(CapRepOK)); % find minimum value and index

% convert index to correct value of `i` in original code:
cs = cumsum(ok(:)); % increases by one for every value that meets criteria
                    % but we need to know which original index that corresponds to:
possibleValues = find( cs == minPriceInd );
[j i] = ind2sub( size(CapRepOK), possibleValues(1) );
prevmin = i;