如何在Matlab中通过双循环提高此代码的速度?可能吗?

时间:2018-09-19 17:11:48

标签: matlab performance vectorization

亲爱的堆栈溢出社区。是否可以在Matlab中提高此代码的速度?我可以使用向量化吗?请注意,我必须在每个循环中使用“ vpasolve”或“ fsolve”功能。

以下是使用双循环调用该函数的代码:

   for i=1:1000
        for j=1:1000
            SilA(i,j)=SolW(i,j);  
        end
    end 

这是上面的代码调用的函数。我可以向量化w,xi的输入并使代码运行得更快吗?

function [ffw] = SolW(w,xi)

format long e;
z=0;mm=0.46;sop=80;
epit=0.1;voP=80.;
rho=2.1;aposC=0.1;aposD=0.1;
parEh=0.2*10^6;parEv=0.2*10^6;parGv=0.074*10^6;
parpos=0.35;hp=0.2;Ep=30*10^6;
parposV=0.20;ll=0.15;dd=2*ll;

 C11=(parEh*(parEv-parEh*parpos^2)/((1+parpos)*(parEv-parEv*parpos-2*parEh*parpos^2)))*(1+2*1i*aposD);
C13=(parEh*parEv*parpos/((parEv-parEv*parpos-2*parEh*parpos^2)))*(1+2*1i*aposD);
C33=((1-parpos)*parEv^2/(parEv-parEv*parpos-2*parEh*parpos^2))*(1+2*1i*aposD);
C44=parGv*(1+2*1i*aposD);
DD=(Ep*hp^3)/(12*(1-parposV^2));
a1=C44;
a2=C33;
c1=(C13+C44)*1i*xi;
c2=(C13+C44)*1i*xi;
b1=rho*w^2-C11*xi^2;
b2=rho*w^2-C44*xi^2;

 syms xr
rsol=vpasolve((a1*xr+b1).*(a2*xr+b2)-c1*c2*xr==0,xr);
rsol=eval(rsol);
r=[-sqrt(rsol)];
r1=r(1,:);
r2=r(2,:);


 Fdf1=sop*sqrt(2*pi/(1i*epit*xi))*exp(1i*(xi*voP+w)^2/(2*epit*xi));
BC11=C44*(r1-1i*xi*c2*r1/(a2*r1^2+b2));
BC21=(C13*1i*xi)-((C33*c2*r1^2)/(a2*r1^2+b2))+(DD*xi^4-mm*w^2+1i*aposC*w)*c2*r1/(a2*r1^2+b2);
BC12=C44*(r2-1i*xi*c2*r2/(a2*r2^2+b2));
BC22=(C13*1i*xi)-((C33*c2*r2^2)/(a2*r2^2+b2))+(DD*xi^4-mm*w^2+1i*aposC*w)*c2*r2/(a2*r2^2+b2);

 syms As1 As2;
   try
[Ass1,Ass2]=vpasolve(BC11*As1+BC12*As2==0,BC21*As1+BC22*As2+Fdf1==0,As1,As2);
       A1=eval(Ass1);
       A2=eval(Ass2);
   catch
       A1=0.0;
       A2=0.0;
   end


Bn1=-(c2*r1/(a2*r1^2+b2))*A1;
Bn2=-(c2*r2/(a2*r2^2+b2))*A2;
ffw=Bn1*exp(r1*z)+Bn2*exp(r2*z);

end

2 个答案:

答案 0 :(得分:1)

函数中的所有内容,但对vpasolvetry....的调用都可以向量化。

首先,所有这些都不取决于wxi,因此只能计算一次

format long e;
z=0;mm=0.46;sop=80;
epit=0.1;voP=80.;
rho=2.1;aposC=0.1;aposD=0.1;
parEh=0.2*10^6;parEv=0.2*10^6;parGv=0.074*10^6;
parpos=0.35;hp=0.2;Ep=30*10^6;
parposV=0.20;ll=0.15;dd=2*ll;

C11=(parEh*(parEv-parEh*parpos^2)/((1+parpos)*(parEv-parEv*parpos-2*parEh*parpos^2)))*(1+2*1i*aposD);
C13=(parEh*parEv*parpos/((parEv-parEv*parpos-2*parEh*parpos^2)))*(1+2*1i*aposD);
C33=((1-parpos)*parEv^2/(parEv-parEv*parpos-2*parEh*parpos^2))*(1+2*1i*aposD);
C44=parGv*(1+2*1i*aposD);
DD=(Ep*hp^3)/(12*(1-parposV^2));
a1=C44;
a2=C33;

据我所知,eval很慢,我很确定您不需要它:

rsol=eval(rsol);

这里是矢量化的一个示例。您应该首先使用meshgrid生成所有索引组合,然后使用.注意到matlab使用元素明智的操作:

[I, J] = meshgrid(1:1000, 1:1000)
c1=(C13+C44)*1i.*xi;
c2=(C13+C44)*1i.*xi;
b1=rho.*w.^2 - C11.*xi.^2;
b2=rho.*w.^2-C44.*xi.^2;

但是您将无法向量化 vpasolvetry....,而不能将其更改为其他内容。 vpasolve可能是您计算的瓶颈(使用matlab profiler 进行验证),因此如上所述的优化可能不会大大减少您的计算时间。

那么您有几种解决方案:

  • 如果可以使用parfor来并行化计算,这取决于您的体系结构,可以使速度提高4倍左右。
  • 可能可以一次方程式化您的方程式并将其全部求解。无论如何,使用线性求解器可能比使用vpasolve要快得多。 这可能会为您带来最快的加速速度(猜测因子10 -100吗?)
  • 因为您有连续的数据,所以如果您不愿意提高精度,则可以减少步骤数。

希望这会有所帮助

答案 1 :(得分:0)

在上面的程序中,所有内容都可以向量化为上述@beesleep。 例如:

[I, J] = meshgrid(1:1000, 1:1000)
c1=(C13+C44)*1i.*xi;
c2=(C13+C44)*1i.*xi;
b1=rho.*w.^2 - C11.*xi.^2;
b2=rho.*w.^2-C44.*xi.^2;   

vpasolve部分,即

 syms xr
 rsol=vpasolve((a1*xr+b1).*(a2*xr+b2)-c1*c2*xr==0,xr);
 rsol=eval(rsol);
 r=[-sqrt(rsol)];
 r1=r(1,:);
 r2=r(2,:);

也可以使用fsolve进行矢量化处理,如下所示:

fun=@(Xr) (a1.*Xr+b1).*(a2.*Xr+b2)-c1.*c2.*Xr
x01=-ones(2*Nxi);
x02=ones(2*Nxi);
options.Algorithm= 'trust-region-reflective'
options.JacobPattern=speye(4*Nxi^2);
options.PrecondBandWidth=0;
[rsol1]=fsolve(fun,x01,options);
[rsol2]=fsolve(fun,x02,options);

另一部分,即

 syms As1 As2;
 try
 [Ass1,Ass2]=vpasolve(BC11*As1+BC12*As2==0,BC21*As1+BC22*As2+Fdf1==0,As1,As2);
      A1=eval(Ass1);
      A2=eval(Ass2);
  catch
      A1=0.0;
      A2=0.0;
  end

由于包含线性方程,并且在每一行中都有两个从属方程可以被求解,如下所示:

 funAB1=@(As1) BC11.*As1+BC12.*((-Fdf2-BC21.*As1)./BC22);

 x0AB=ones(2*Nxi)+1i*ones(2*Nxi);
 options.Algorithm= 'trust-region-reflective';
 options.JacobPattern=speye(4*Nxi^2);
 options.PrecondBandWidth=0;
 [A1]=fsolve(funAB1,x0AB,options);

 A2=((-Fdf2-BC21.*A1)./BC22); 

但是,两者都可以通过解析来解决,即

AAr=a1.*a2;
BBr=a1.*b2+b1.*a2-c1.*c2;
CCr=b1.*b2;

Xr1=(-BBr+sqrt(BBr^.2-4.*AAr.*CCr))./(2.*AAr);
Xr2=(-BBr-sqrt(BBr^.2-4.*AAr.*CCr))./(2.*AAr);
r1=-sqrt(Xr1(:,:));
r2=-sqrt(Xr2(:,:));