简化for循环(Matlab)

3
我正在工作中编写一个程序,用于计算飞机在飞越目标区域时可以看到什么。当它飞过该区域时,它可以沿着多条航迹之一飞行,对于普通区域大小约有100条轨迹。我创建了一个大循环来查看飞机是否能够看到区域的某些部分,但其运行效率非常低。我将该区域定义为一个1001x1001的网格。
xgrid是一个变量,1001x1,定义x值。
thelines是一个变量,2 x 1001 x tracks,其中第一行是相应x值顶线处的y值,第二行是底线处的y值。
这两条线之间是可见区域。如果可以看到,则将seenarea(1001x1001)上的点标记为1。否则为0。
for M=1:tracks
    for f=1:1001
        for i=1:1001
            if xgrid(f,1)>thelines(i,1,M) && xgrid(f,1)<thelines(i,2,M);
                seenarea(f,i,M)=1; % This indicated the area has been seen
            else
                seenarea(f,i,M)=0; % This is not seen
            end
        end
    end
    fullbestinfo(1,M)={seenarea(:,:,M)}; % This stores the seen area in another cell
    if max(seenarea(:,:,M)) < 1 % No area seen, stop
        seenarea(:,:,M)=[];
        break
    end
end

我使用Matlab分析器,确定了程序的瓶颈位置。非常感谢您能提供帮助。 谢谢,Rich
1个回答

7

我无法确定您的具体操作,但我建议您首先将内部循环替换为逻辑索引。

seenarea = false(1001, 1001, tracks); #% preallocate matrix to 'false'
xgrid = repmat(1:1001, 1001, 1); #%same size as the first 2D of seenarea

for M=1:tracks
    border1 = thelines(:,ones(1,1001),M); #% same size as xgrid
    border2 = thelines(:,ones(1,1001)*2,M); #% same size as xgrid
    idx = xgrid > border1 & xgrid < border2; #% idx is a "logical index" 
             #%           ^--- single ampersand
    seenarea(idx,M)=true; 
end

使用逻辑索引,您可以用单个操作替换掉数百万次嵌套循环。

另一个提示是:使用逻辑矩阵而不是双精度矩阵来存储真/假值。

>>m1 = zeros(1001,1001,100);
>> m2 = false(1001,1001,100);
>> whos m1
  Name         Size                      Bytes  Class     Attributes

  m1        1001x1001x100            801600800  double              

>> whos m2
  Name         Size                      Bytes  Class      Attributes

  m2        1001x1001x100            100200100  logical 

如您所见,逻辑矩阵的内存使用率是原来的八分之一。

速度测试:我很好奇这会产生多大的差异。下面是一个快速测试(至少其中一种实现是快速的)。将内部循环向量化可使我的计算机速度增加约75倍,将10个轨迹的时间从7+秒降至大约0.1秒。

tic;
for rep=1:100
    for M=1:tracks
        for f=1:1001
            for i=1:1001
                if xgrid(f,1)>thelines(i,1,M) && xgrid(f,1)<thelines(i,2,M);
                    seenarea(f,i,M)=1; 
                else
                    seenarea(f,i,M)=0; 
                end
            end
        end
    end
end
disp(toc/100)
    7.3459

tic;
for rep=1:100
    for M=1:tracks
        border1 = thelines(:,ones(1,1001),M); 
        border2 = thelines(:,ones(1,1001)*2,M); 
        idx = xgrid > border1 & xgrid < border2;                     
        seenarea(idx,M)=true; 
    end
end
disp(toc/100)
    0.0964

>> 7.3459/.0964    
ans =    
   76.2023

1
有一个小bug:您定义了变量idx用于逻辑寻址,但在此之后您使用不存在的变量index来寻址seenarea - nrz
另外加一分耐心 :) - Eitan T

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接