矢量化 - Sum和Bessel函数

时间:2014-03-07 19:13:30

标签: matlab sum vectorization nested-loops bessel-functions

任何人都可以帮助矢量化这个Matlab代码吗?具体问题是带向量输入的sum和bessel函数。 谢谢!

N = 3;
rho_g = linspace(1e-3,1,N);
phi_g = linspace(0,2*pi,N);

n = 1:3;
tau = [1 2.*ones(1,length(n)-1)];
for ii = 1:length(rho_g)
    for jj = 1:length(phi_g)
        % Coordinates
        rho_o = rho_g(ii);
        phi_o = phi_g(jj);
        % factors
        fc = cos(n.*(phi_o-phi_s));
        fs = sin(n.*(phi_o-phi_s));

        Ez_t(ii,jj) = sum(tau.*besselj(n,k(3)*rho_s).*besselh(n,2,k(3)*rho_o).*fc);
    end
end

3 个答案:

答案 0 :(得分:1)

您可以尝试对这些代码进行矢量化,这可能会使用某些bsxfun左右,但是很难理解代码,并且问题是它是否会运行得更快,因为您的代码已经在内循环中使用向量数学(即使您的向量只有长度3)。由此产生的代码将变得非常难以阅读,因此当您在2年内查看它时,您或您的同事将不知道它的作用。

在浪费时间进行矢量化之前,了解loop invariant code motion更为重要,这很容易应用于您的代码。一些观察:

  • 您不使用fs,因此请将其删除。
  • 术语tau.*besselj(n,k(3)*rho_s)不依赖于任何循环变量iijj,因此它是常量。在循环之前计算一次。
  • 你应该预先分配矩阵Ez_t
  • 在循环期间更改的唯一字词为fc,取决于jjbesselh(n,2,k(3)*rho_o)取决于ii。我猜后者花费的时间要多得多,所以最好不要在内循环中计算N*N次,而在外循环中只计算N次。如果基于jj的计算花费更多时间,您可以将for循环交换为iijj,但这似乎不是这种情况。

结果代码看起来像这样(未经测试):

N = 3;
rho_g = linspace(1e-3,1,N);
phi_g = linspace(0,2*pi,N);

n = 1:3;
tau = [1 2.*ones(1,length(n)-1)];

% constant part, does not depend on ii and jj, so calculate only once!
temp1 = tau.*besselj(n,k(3)*rho_s); 

Ez_t = nan(length(rho_g), length(phi_g)); % preallocate space
for ii = 1:length(rho_g)
    % calculate stuff that depends on ii only
    rho_o = rho_g(ii);
    temp2 = besselh(n,2,k(3)*rho_o);

    for jj = 1:length(phi_g)
        phi_o = phi_g(jj);
        fc = cos(n.*(phi_o-phi_s));
        Ez_t(ii,jj) = sum(temp1.*temp2.*fc);
    end
end

答案 1 :(得分:0)

为了给出一个独立的答案,我将复制原始初始化

N = 3;
rho_g = linspace(1e-3,1,N);
phi_g = linspace(0,2*pi,N);

n = 1:3;
tau = [1 2.*ones(1,length(n)-1)];

并生成一些缺失数据(k(3)和rho_s和phi_s在n维)

rho_s = rand(size(n));
phi_s = rand(size(n));
k(3) = rand(1);

然后你可以用多维数组计算相同的Ez_t:

[RHO_G, PHI_G, N] = meshgrid(rho_g, phi_g, n);
[~, ~, TAU] = meshgrid(rho_g, phi_g, tau);
[~, ~, RHO_S] = meshgrid(rho_g, phi_g, rho_s);
[~, ~, PHI_S] = meshgrid(rho_g, phi_g, phi_s);

FC = cos(N.*(PHI_G - PHI_S));
FS = sin(N.*(PHI_G - PHI_S)); % not used

EZ_T = sum(TAU.*besselj(N, k(3)*RHO_S).*besselh(N, 2, k(3)*RHO_G).*FC, 3).';

您可以事后检查两个矩阵是否相同

norm(Ez_t - EZ_T)

答案 2 :(得分:0)

初始化 -

N = 3;
rho_g = linspace(1e-3,1,N);
phi_g = linspace(0,2*pi,N);

n = 1:3;
tau = [1 2.*ones(1,length(n)-1)];

嵌套循环表单(从代码中复制并在此处显示仅供比较) -

for ii = 1:length(rho_g)
    for jj = 1:length(phi_g)
        % Coordinates
        rho_o = rho_g(ii);
        phi_o = phi_g(jj);
        % factors
        fc = cos(n.*(phi_o-phi_s));
        fs = sin(n.*(phi_o-phi_s));

        Ez_t(ii,jj) = sum(tau.*besselj(n,k(3)*rho_s).*besselh(n,2,k(3)*rho_o).*fc);
    end
end

矢量化解决方案 -

%%// Term - 1
term1 = repmat(tau.*besselj(n,k(3)*rho_s),[N*N 1]);

%%// Term - 2
[n1,rho_g1] = meshgrid(n,rho_g);
term2_intm = besselh(n1,2,k(3)*rho_g1);
term2 = transpose(reshape(repmat(transpose(term2_intm),[N 1]),N,N*N));

%%// Term -3
angle1 = repmat(bsxfun(@times,bsxfun(@minus,phi_g,phi_s')',n),[N 1]);
fc = cos(angle1);

%%// Output
Ez_t = sum(term1.*term2.*fc,2);
Ez_t = transpose(reshape(Ez_t,N,N));

关于此向量化或代码简化的注意事项 -

  1. 'fs'不会更改脚本的输出Ez_t,因此现在可以将其删除。
  2. 输出似乎是'Ez_t',在代码中需要三个基本术语 - tau。* besselj(n,k(3)* rho_s) besselh(n,2,k(3)* rho_o) fc 。这些分别作为术语1,2和3分别计算。
  3. 所有这三个术语似乎都是1xN大小。因此,我们的目标是无循环地计算这三个术语。现在,两个循环各运行N次,从而为我们提供NxN的总循环计数。因此,与这些术语在嵌套循环中的时间相比,每个这样的术语中的数据必须是NxN倍。
  4. 这基本上是这里完成的矢量化的本质,因为这三个术语由'term1','term2'和'fc'本身表示。