加快MATLAB的集成方法

时间:2015-02-26 12:19:01

标签: matlab

我使用MATLAB使用integral3执行三重积分,它运行速度非常慢。我想知道是否有办法加速它。我猜它是因为我把abstol设置错了。不知道如何处理它。 PS下面的代码工作没有语法错误。有几件事我不知道如何选择,弃用,方法等。

clear all
syms gamma1
syms gamma2
syms z
syms v 

Nt=16; sigmanoise=10^(-7.9); c3=0.129; c1=(1-c3)/2;a2=0;b2=0; 
a1=0.0030; b1= 0.0030; A1=  1.5625e-04,A2=0;  B1= 7.8125e-05;B2=0;
theta= 3.1623;lambda1=  4.9736e-05;lambda2=0;p1=1;p2=0; alpha1=2; alpha2=4;delta1=2/alpha1; delta2=2/alpha2;beta1=0.025; beta2=0.025;


a= gamma1^-1+gamma2^-1+2*gamma1^(-0.5)*gamma2^(-0.5);
laplacesgi=(exp(+2*pi*j.*z*a)-1)./(2*pi*j*z);
laplacesgi=matlabFunction(laplacesgi);


laplacenoi=exp(-2*pi*j.*z*theta*sigmanoise/Nt);
laplacenoi=matlabFunction(laplacenoi);


interfere= @(gamma1,gamma2,v,z)( (1 -2*c1-c3./(1+2*pi*j*z*theta*v.^(-1))).*(A1.*(v).^(delta1-1).*exp(-a1.*(v).^ (delta1./2))+B1.*(v).^(delta2-1) .*(1-exp(-b1.*(v).^ (delta2./2))))); 
gscalar =@(gamma1,gamma2,z)integral(@(v)(interfere(gamma1,gamma2,v,z)),gamma2,inf);
g = @(gamma1,gamma2,z)arrayfun(gscalar,gamma1,gamma2,z);

lp= A1*(gamma1)^(delta1-1)*exp(-a1*(gamma1)^ (delta1/2))+B1*(gamma1)^(delta2-1)*(1-exp(-b1*(gamma1)^ (delta2/2)))+A2*gamma1^(delta1-1)*exp(-a2*gamma1^(delta1/2))+ B2*gamma1^(delta2-1)*(1-exp(-b2*gamma1^ (delta2/2)));%;
dk1=((2*pi*lambda1))/(beta1^2)*(1-exp(-a1*(gamma2)^(delta1/2))*(1+(gamma2)^(delta1/2)*a1))+ pi*lambda1*gamma2^(delta2)*p1^delta2-((2*pi*lambda1)/(beta1^2))*(1-exp(-b1*(gamma2)^(delta2/2))*(1+(gamma2)^(delta2/2)*b1));
dk2=((2*pi*lambda2))/(beta2^2)*(1-exp(-a2*(gamma2)^(delta1/2))*(1+(gamma2)^(delta1/2)*a2))+ pi*lambda2*gamma2^(delta2)*p2^delta2-((2*pi*lambda2)/(beta2^2))*(1-exp(-b2*(gamma2)^(delta2/2))*(1+(gamma2)^(delta2/2)*b2));
dk=dk1+dk2;
lcp= A1*(gamma2)^(delta1-1)*exp(-a1*(gamma2)^ (delta1/2))+B1*(gamma2)^(delta2-1)*(1-exp(-b1*(gamma2)^ (delta2/2)))+A2*gamma2^(delta1-1)*exp(-a2*gamma2^ (delta1/2))+ B2*gamma2^(delta2-1)*(1-exp(-b2*gamma2^(delta2/2)));%;

pdflast=lp*lcp*exp(-dk);
pdflast=matlabFunction(pdflast);
pdflast= @(gamma1,gamma2)arrayfun(pdflast,gamma1,gamma2);
gamma2min=@(gamma1)gamma1;
warning('off','MATLAB:integral:MinStepSize');
T = integral3(@(gamma1,gamma2,z)(laplacenoi(z).*laplacesgi(gamma1,gamma2,z).*pdflast(gamma1,gamma2).*exp(-g(gamma1,gamma2,z))),0,inf,@(gamma2)gamma2,inf,0.05,1000,'abstol',1e-3)

我感谢任何想法或建议。

1 个答案:

答案 0 :(得分:0)

对于评论来说这已经太长了,虽然它也没有给出答案,但我认为它可能会有所帮助,所以我会略微滥用答案表格。

代码可读性

我认为你的代码不能满足代码的基本目的:与人类沟通,可能是你自己的未来。

我不知道变量名称是否足够明确,在六个月内,他们仍然会告诉你到底是什么。如果他们是伟大的。如果没有,您可能希望改进它们。 (是的,命名内容是编程中最难的部分之一,但这并不会使它变得不那么重要。)

同样适用于评论:如果您不需要对公式发表评论,请为您提供更多权力。我不知道你在计算什么,所以我不理解你的公式并不是很重要。但是再一次,在几个月内想想自己,找一个问题:你是否希望发表评论,以便你知道这个因素是真的是正确的还是由一个人解决?

这里有一些我知道的事情:你的公式太宽大,无法立即被理解。简单的重新格式化有助于更好地查看结构。这是我如何重新格式化你的代码以开始从它做出正面或反面:

clear all
syms gamma1
syms gamma2
syms z
syms v 

Nt=16;
sigmanoise=10^(-7.9);
c3=0.129;
c1=(1-c3)/2;
a2=0;
b2=0; 
a1=0.0030;
b1=0.0030;
A1=1.5625e-04;
A2=0;
B1=7.8125e-05;
B2=0;
theta=3.1623;
lambda1=4.9736e-05;
lambda2=0;
p1=1;
p2=0;
alpha1=2;
alpha2=4;
delta1=2/alpha1;
delta2=2/alpha2;
beta1=0.025;
beta2=0.025;


a=gamma1^(-1)+gamma2^(-1)+2*gamma1^(-0.5)*gamma2^(-0.5);
laplacesgi=matlabFunction((exp(2*pi*1j*z*a)-1)./(2*pi*1j*z));
laplacenoi=matlabFunction(exp(-2*pi*1j*z*theta*sigmanoise/Nt));


interfere= @(gamma1,gamma2,v,z)( ...
  (1 -2*c1-c3./(1+2*pi*j*z*theta*v.^(-1))).*(A1.*v.^(delta1-1).* ...
    exp(-a1.*v.^(delta1./2))+B1.*v.^(delta2-1).*(1-exp(-b1.*v.^(delta2./2))))); 
gscalar=@(gamma1,gamma2,z)integral(@(v)(interfere(gamma1,gamma2,v,z)),gamma2,inf);
g=@(gamma1,gamma2,z)arrayfun(gscalar,gamma1,gamma2,z);

lp=A1*gamma1^(delta1-1)*exp(-a1*gamma1^(delta1/2))+ ...
    B1*gamma1^(delta2-1)*(1-exp(-b1*gamma1^(delta2/2)))+ ...
   A2*gamma1^(delta1-1)*exp(-a2*gamma1^(delta1/2))+ ...
    B2*gamma1^(delta2-1)*(1-exp(-b2*gamma1^(delta2/2)));
dk1=((2*pi*lambda1))/(beta1^2)*(1-exp(-a1*gamma2^(delta1/2))*(1+gamma2^(delta1/2)*a1))+ ...
  pi*lambda1*gamma2^(delta2)*p1^delta2- ...
  ((2*pi*lambda1)/(beta1^2))*(1-exp(-b1*gamma2^(delta2/2))*(1+gamma2^(delta2/2)*b1));
dk2=((2*pi*lambda2))/(beta2^2)*(1-exp(-a2*gamma2^(delta1/2))*(1+gamma2^(delta1/2)*a2))+ ...
  pi*lambda2*gamma2^(delta2)*p2^delta2- ...
  ((2*pi*lambda2)/(beta2^2))*(1-exp(-b2*gamma2^(delta2/2))*(1+gamma2^(delta2/2)*b2));
dk=dk1+dk2;
lcp=A1*gamma2^(delta1-1)*exp(-a1*gamma2^(delta1/2))+ ...
      B1*gamma2^(delta2-1)*(1-exp(-b1*gamma2^(delta2/2)))+ ...
    A2*gamma2^(delta1-1)*exp(-a2*gamma2^(delta1/2))+ ...
      B2*gamma2^(delta2-1)*(1-exp(-b2*gamma2^(delta2/2)));

pdflast=matlabFunction(lp*lcp*exp(-dk));
pdflast=@(gamma1,gamma2)arrayfun(pdflast,gamma1,gamma2);
gamma2min=@(gamma1)gamma1;
T = integral3(@(gamma1,gamma2,z)( ...
  laplacenoi(z).*laplacesgi(gamma1,gamma2,z).*pdflast(gamma1,gamma2).*exp(-g(gamma1,gamma2,z))), ...
  0,inf,...
  @(gamma2)gamma2,inf,...
  0.05,1000,...
  'abstol',1e-3)

一些注意事项:

  • MATLAB是需要指示逻辑行应在物理换行后继续运行的语言之一。 MATLAB中的指示是三个点。
  • 摆脱MATLAB编辑器向您显示的任何和所有警告。在极少数情况下,通过禁用此行的警告;通常,通过更正您的代码。其中一些警告可能看起来过于保护,但很快就达到了这样的程度:在我的经验中,我们没有人能够在我们的脑海中看到更多细微的问题,并且linting有助于避免相当多的问题。 / LI>
  • 一致的间距有助于以同样的方式“正确”(即标准化)拼写使阅读英语更容易:模式更加明显。
  • 换行符一般不应随意进行,而是强调命令和公式的结构。在你的几个公式中,我已经看到了输入参数之间的对称性,并试图通过相应地放置换行符来使它们变得明显。在寻找拼写错误时,这有很大帮助。
  • 您的代码包含以下行:

    pdflast=lp*lcp*exp(-dk);

    pdflast=matlabFunction(pdflast);

    我过去常常回收变量。随着时间的推移,我学到了很难,它有助于调试和可读性,特别是如果你的值有不同的类型,就像在这里一样。

此时我还有几点要清理。例如,pdflast在数组上运行正常,应删除行pdflast= @(gamma1,gamma2)arrayfun(pdflast,gamma1,gamma2);gamma2调用中integral3的下限是{{1}的函数并且应该更改为gamma1

计算机/ MATLAB是否关心这些?也许有些东西在它的位置滑落,但基本上是:不。所有这些变化都适合你,如果你在SO帖子中发送你的代码,对我们来说,读者。

(可能)Bug:矢量化

我认为您对@(gamma1)gamma1的定义是错误的:

g

cubature(即g=@(gamma1,gamma2,z)arrayfun(gscalar,gamma1,gamma2,z); )将尝试使用一个或多个参数的非标量值调用此函数。最有可能的是,这些并不都是相同的大小,即使它们是,它也会期望获得3D结果,而不是矢量。尝试以这种方式致电integral3

g

检查这样的中间构建块确实是一个好主意。您真正需要的是>> g(1:2,1,1) Error using arrayfun All of the input arguments must be of the same size and shape. Previous inputs had size 2 in dimension 2. Input #3 has size 1 Error in @(gamma1,gamma2,z)arrayfun(gscalar,gamma1,gamma2,z) 超过arrayfun,如下所示:

gamma2

(可能)错误:gscalar=@(gamma1,gamma2,z) ... integral(@(v)(interfere(gamma1,gamma2,v,z)),gamma2,inf, ... 'ArrayValued',true); g = @(gamma1,gamma2,z)arrayfun(@(gamma2)gscalar(gamma1,gamma2,z),gamma2);

的定义

我不知道您是否尝试检查interfere是否存在任何已知或可疑的值。 (我只是打字的公式检查对我来说似乎是个好主意。)我怀疑公式是否正确地捕捉了你的意图:

interfere

此公式的潜在问题(除了interfere=@(gamma1,gamma2,v,z)( ... (1-2*c1-c3./(1+2*pi*1j*z*theta*v.^(-1))).*(A1.*v.^(delta1-1).* ... exp(-a1.*v.^(delta1./2))+B1.*v.^(delta2-1).*(1-exp(-b1.*v.^(delta2./2))))); *等的使用有些不一致)是值不依赖于.*和{完全{1}}。

当然,这种情况可能会发生,但如果您实际上是这样的话,那么首先在公式中包含gamma1的理由是什么?

如果它应该是这样,你可能仍然需要使结果具有合适的大小:现在,gamma2只是忽略它的前两个输入,这可能会使积分器绊倒:gamma1应该返回一个3元素的向量。

结论性思考

您可能已经注意到,您的问题尚未得到令人满意的答案。我认为它目前的形式也不会。为了让志愿者看到你的问题,你需要让你很容易理解你在做什么:

  • 首先简化您的公式。他们可能对您不感兴趣,但现在,它们只是混乱。
  • 修剪您的参数。这在某种程度上是上述的一部分。
  • 扔出可能无关紧要的东西。除了您不需要(并且可能不想要)在interfere结果附近interfere(1:3,1,1,1)之外,符号数学可能与您的实际问题无关。 arrayfun。如果你可以在没有它的情况下提出问题,可能会引起更多关注。
  • 对于任何你无法减少的事情,请考虑解释发生的事情。

当然,在这个过程中,对于每次迭代,测试你的代码(在说出matlabFunction之后或在一个新的MATLAB会话中!)来检查问题是否仍然存在。如果不是,您可能已经找到了隐藏基本问题的提示。

有关该主题的更长时间的讨论,请参阅https://meta.stackexchange.com/questions/18584/how-to-ask-a-smart-question以及与该讨论相关的指南。