在Matlab中Vectorize double for循环

时间:2014-12-05 01:20:31

标签: matlab for-loop parallel-processing vectorization

我提出了简单的Matlab代码,并会提出问题:

tic

nrand1 = 10000;
nrand2 = 20000;  

% Location matrix 1: [longitude, latitude, w1]
lmat1=[rand(nrand1,1)-75 rand(nrand1,1)+39 round(rand(nrand1,1)*1000)+1];

% Location matrix 2: [longitude, latitude, w2]     
lmat2=[rand(nrand2,1)-75 rand(nrand2,1)+39 round(rand(nrand2,1)*100)+1];

% The number of rows for each matrix = In fact it's nrand1 X nrand2, obviously
nobs1 = size(lmat1,1);
nobs2 = size(lmat2,1);

% The number of pair-wise distances 
% between L1 locations X L2 locations
ndist = nobs1*nobs2;

% Initialization: Distance vector and weight vector
hdist = zeros(ndist,1);
weight = zeros(ndist,1);

% Double for loop -- for calculating the pair-wise distances and weights
k=1;
for i=1:nobs1
 for j=1:nobs2
     % distances in kilometers.
     lonH = sin(0.5*(lmat1(i,1)-lmat2(j,1))*pi/180.0)^2;
     latH = sin(0.5*(lmat1(i,2)-lmat2(j,2))*pi/180.0)^2;
     hdist(k) = 0.001*6372797.560856*2 ...
               *asin(sqrt(latH+(cos(lmat1(i,2)*pi/180.0) ...
               *cos(lmat2(j,2)*pi/180.0))*lonH));
     weight(k) = lmat1(i,3)*lmat2(j,3);
 k=k+1;
 end
end

toc

代码计算10000 X 20000距离和权重。

Elapsed time is 67.124844 seconds. 

有没有办法对双循环处理进行矢量化,还是执行并行计算?如果在Matlab中没有提高性能的空间,我可能必须在C中编写双循环并从Matlab调用它。我不知道如何从matlab调用C,所以我会问一个单独的问题。谢谢!

2 个答案:

答案 0 :(得分:2)

解决方案是你的输入(lmat1和lmat2)不需要像你拥有它们那样是矩阵。每一个都是三个向量。一旦你打破了向量,就可以创建将lmat1和lmat2的每个排列组合在一起的数组(这就是你的双循环正在做的事情)。此时,您可以将数学称为单一的,完全向量化的操作......

%make your vectors
lmat1A = rand(nrand1,1)-75;
lmat1B = rand(nrand1,1)+39;
lmat1C = round(rand(nrand1,1)*1000)+1
lmat2A = rand(nrand2,1)-75;
lmat2B = rand(nrand2,1)+39;
lmat2C = round(rand(nrand2,1)*1000)+1

%make every combination
lmat1A = lmat1A(:)*ones(1,nrand2);
lmat1B = lmat1B(:)*ones(1,nrand2);
lmat1C = lmat1C(:)*ones(1,nrand2);
lmat2A = ones(nrand1,1)*(lmat2A(:)');
lmat2B = ones(nrand1,1)*(lmat2B(:)');
lmat2C = ones(nrand1,1)*(lmat2C(:)');

%do your math
lonH = sin(0.5*(lmat1A-lmat2A)*pi/180.0).^2;
latH = sin(0.5*(lmat1B-lmat2B)*pi/180.0).^2;
hdist = 0.001*6372797.560856*2 ...
    .*asin(sqrt(latH+(cos(lmat1B*pi/180.0) ...
    .*cos(lmat2B*pi/180.0)).*lonH));  %use element-wise multiplication
weight = lmat1C.*lmat2C;

%reshape your output into vectors (not arrays), which is what your original code does
lonH = lonH(:)
latH = latH(:)
hdist = hdist(:);
weight = weight(:);

答案 1 :(得分:2)

使用bsxfun,您可以消除for循环以及计算每个组合矩阵的需要(这可以减少内存使用量)。以下是使用R2014b在我的计算机上比原始代码快六倍的速度:

nrand1 = 10000;
nrand2 = 20000;

% Location matrix 1: [longitude, latitude, w1]
lmat1=[rand(nrand1,1)-75 rand(nrand1,1)+39 round(rand(nrand1,1)*1000)+1];

% Location matrix 2: [longitude, latitude, w2]     
lmat2=[rand(nrand2,1)-75 rand(nrand2,1)+39 round(rand(nrand2,1)*100)+1];

p180 = pi/180;
lonH = sin(0.5*bsxfun(@minus,lmat1(:,1).',lmat2(:,1))*p180).^2;
latH = sin(0.5*bsxfun(@minus,lmat1(:,2).',lmat2(:,2))*p180).^2;
hdist = 0.001*6372797.560856*2*asin(sqrt(latH+bsxfun(@times,cos(lmat1(:,2).'*p180),cos(lmat2(:,2)*p180)).*lonH));
hdist1 = hdist(:);
weight1 = bsxfun(@times,lmat1(:,3).',lmat2(:,3));
weight1 = weight1(:);

请注意,通过使用变量p180,数学会稍微改变,因此您将无法获得完全相同的值,但它们将非常接近。