我试图为这个等式生成矢量化代码(以及同一形式的多个其他代码):
这将在ode45
中进行评估,唯一更改的部分是Rmn(t)
,因此我预先计算了贝塞尔和sin
函数。目前我的代码看起来像这样:
for iR = 1:nR
p(:, iR) = sum(Rmn.*J0m(:, :, iR),1)*sinanz;
end
M
,N
是总和中的字词数,R
,Z
是r
和z
坐标的数量我正在使用。 Rmn
是M*N
矩阵。 J0m
是一个M*N*R
数组。它是M*R
矩阵,重复N
次。 sinanz
是N*Z
矩阵。 J0m
和sinanz
是预先计算出来的,不会发生变化。
这可行,但速度很慢,所以我试图优化它。我认为第一步是减少J0m
,因此只有m*R
,但我无法弄清楚如何。我正在寻找有关如何执行此操作的任何建议以及有关如何优化此操作的任何建议。
答案 0 :(得分:5)
正如您可能已经知道的那样,您应该在循环之前预先分配p
:
p = zeros(Z, nR);
这可以防止数组p
在每次迭代时增长,从而极大地加速循环。
你可以凭bsxfun
:
% C ≣ M×N×R array of all products Rmn·J0m
C = bsxfun(@times, Rmn, J0m);
% D ≣ M×N×R×Z array of all products C·sinanz
D = bsxfun(@times, C, permute(sinanz, [3 1 4 2]));
% Sum in M and N directions, and re-order
p = permute(sum(sum(D,1),2), [4 3 1 2]);
但我怀疑它会更快; MATLAB(读取:BLAS)与2D矩阵相当快,但对于更多D阵列通常不是很好。
我建议你阅读bsxfun
;它也是以您描述的方式将J0m
数组缩减为M
×R
的方法。
当然,您可以通过正确定义变量来摆脱permute
,所以让我们在循环代码和矢量化代码的“理想”版本中进行一个小测试:
%% Initialize some variables
% Number of tests
TESTS = 1e4;
% Your dimensions
M = 5; nR = 4;
N = 2; Z = 3;
% Some dummy data
Rmn = rand(M,N);
sinanz = rand(N,Z);
J0m = rand(M,nR); % NOTE: J0m doesn't have to be 3D anymore by using bsxfun
%% Test 1: your own version, optimized
% Start test
start = tic;
% Repeat the test a couple of times to get a good average
for ii = 1:TESTS
p1 = zeros(Z,nR);
for iR = 1:nR
p1(:, iR) = sum( bsxfun(@times,Rmn,J0m(:, iR)), 1 )*sinanz;
end
end
stop = toc(start);
% Average execution time
fprintf(1, 'Average time of looped version: %f seconds.\n', stop/TESTS);
%% Vectorized version, using 4D arrays:
% Don't make the permutes part of the test
J0m = permute(J0m, [1 3 2]);
sinanz = permute(sinanz, [3 1 4 2]);
% Start test
start = tic;
% Repeat the test a couple of times to get a good average
for ii = 1:TESTS
C = bsxfun(@times, Rmn, J0m);
D = bsxfun(@times, C, sinanz);
p2 = sum(sum(D,1),2);
end
stop = toc(start);
% Average execution time
fprintf(1, 'Average time of vectorized version: %f seconds.\n', stop/TESTS);
%% Check for equality
maxDifference = max(max(p1 - squeeze(p2)'))
结果:
Average time of looped version : 0.000054 seconds.
Average time of vectorized version: 0.000023 seconds.
maxDifference =
4.440892098500626e-016
看起来还不错!但是,使用
M = 50; nR = 40;
N = 20; Z = 30;
你得到了
Average time of looped version : 0.000708 seconds.
Average time of vectorized version: 0.009835 seconds.
maxDifference =
8.526512829121202e-014
所以矢量化版本的比循环变体慢了一个数量级。
当然,your mileage may vary,但带回家的信息是,你应该期望这种差异会因为增加维度而变得越来越糟。
所以,最后:
p
变量bsxfun
来减少内存占用(但不会提高速度)