在Matlab中使用矢量化循环进行双重求和

时间:2011-05-30 22:14:03

标签: matlab nested-loops vectorization

我想将这个double for循环向量化,因为它是我代码中的瓶颈。由于Matlab是一种基于索引的语言,我必须为M = 0创建一个附加项。

R,r,lambda是常数

Slm(L,M),Clm(L,M)是基质70×70

pm(L,M)是基质70x71

Cl(L),P1(L)是载体70x1

% function dU_r
  s1 = 0;
  for L = 2:70
     s1 = s1 + ((R/r)^L)*(L+1)*Pl(L)*Cl(L);
     for m = 1:L
        s1 = s1 + ((R/r)^L)*(L+1)*Plm(L,M)*(Clm(L,M)*...
cos(M*lambda) + Slm(L,M)*sin(M*lambda));
     end
  end

  dU_r = -(mu_p/(r^2))*s1;


  % function dU_phi

  s2=0;
  for L = 2:70
      s2 = s2 + ((R/r)^L))*Plm(L,1)*Cl(L);
          for m = 1:l
          s2 = s2 + ((R/r)^L)*(Plm(L,M+1)-M*tan(phi)*Plm(L,M))*...
  (Clm(L,M)*cos(M*lambda) + Slm(L,M)*sin(M*lambda));
          end;
  end;
  dU_phi = (mu_p/r)*s2;

  % function dU_lambda

  s3=0;
      for L=2:70
          for m=1:L
          s3 = s3 + ((R/r)^L)*M*Plm(L,M)*(Slm(L,M)*cos(M*lambda)...
              - Clm(L,M)*sin(M*lambda));
          end;
  dU_lambda = (mu_p/r)*s3;

3 个答案:

答案 0 :(得分:1)

我认为以下代码可能是解决方案的一部分(仅部分矢量化),对于完整的矢量化,您可能希望查看meshgridndgridbsxfun和/或者repmat,我想。

s2     = 0;
L      = 2:70;
PlCl   = Pl.*Cl;
PlmClm = Plm.*Clm;
Rrl    = (R/r).^(L).*(L+1);
COS    = cos((1:70)*lambda);
SIN    = sin((1:70)*lambda);

for l=L
    M  = 1:l;
    s1 = sum(Rrl(l-1)*PlmClm(l,M).*(COS(M) + Slm(l,M).*SIN(M)));
    s2 = s2 + s1;
end;
s2 = s2 + sum(Rrl(L).*PlCl(L));

我没有尝试过运行此代码,因此如果它可能会抱怨某些维度。你应该能够弄明白(这里或那里只有一些转置)。

只是旁边的一个注释:尽量远离短变量名称(当然还有像l这样含糊不清的名称(对于1,I或者l可能会被误读)。此外,它可能是如果您有实际(即未编码)表达式,则更容易对代码进行矢量化。

修改:gnovice

建议的应用核心功能

答案 1 :(得分:1)

对于这种特殊情况,完全向量化您的解决方案可能会更有效率。 As Egon illustrates,可以通过矢量化替换内部循环,但是替换外部for循环也可能减慢您的解决方案。

原因?如果您注意循环中的矩阵PlmClmSlm的索引方式,则只能使用lower triangular parts中的值。主对角线上方的所有值都将被忽略。通过完全向您的解决方案进行矢量化,使得它使用矩阵运算而不是循环,您最终将使用矩阵的零上部三角形部分执行不必要的乘法运算。这是for循环可能是更好选择的情况之一。

因此,这里是Egon's answer的精炼和修正版本,在执行的数学运算次数方面应该接近最优:

index = 2:70;
coeff = ((R/r).^index).*(index+1);
lambda = lambda.*(1:70).';  %'
cosVector = cos(lambda);
sinVector = sin(lambda);
s2 = coeff*(Pl(index).*Cl(index));
for L = index
  M = 1:L;
  s2 = s2 + coeff(L-1)*((Plm(L,M).*Clm(L,M))*cosVector(M) + ...
                        (Plm(L,M).*Slm(L,M))*sinVector(M));
end

答案 2 :(得分:0)

参考Jan Simon 1给出的解决方案,我已经为我的问题编写了以下代码

Rr = R/r;
RrL = Rr;  
cosLambda = cos((1:70)* lambda);
sinLambda = sin((1:70)* lambda);
u1 = uint8(1);
s1 = 0;
s2 = 0;
s3 = 0;
for j = uint8(2):uint8(70)
   RrL = RrL * Rr;
   q1 = RrL * (double(j) + 1);
   t1 = Pl(j) * datos.Cl(j);
   q2 = RrL;
   t2 = Plm(j,1) * Cl(j);
   t3 = 0;
   for m = u1:j
      t1 = t1 + Plm(j,m) * ...
         (Clm(j, m) * cosLambda(m) + ...
          Slm(j, m) * sinLambda(m));
        t2 = t2 + (Plm(j,m+1)-double(m)*tan_phi*Plm(j,m))*...
    (Clm(j,m)*cosLambda(m) + Slm(j,m)*sinLambda(m));
        t3 = t3 + double(m)*Plm(j,m)*(Slm(j,m)*cosLambda(m)...
                - Clm(j,m)*sinLambda(m));
     end
     s1 = s1 + q1 * t1;
     s2 = s2 + q2 * t2;
     s3 = s3 + q2 * t3;
  end
dU_r = -(mu_p/(r^2))*s1;
dU_phi = (mu_p/r)*s2;
dU_lambda = (mu_p/r)*s3