我有两个我想要并行化的嵌套循环。正确的Matlab parfor切片
n=100;
x=rand(1,n);
m=5;
xx=rand(1,m);
r = zeros(1,m);
for i=1:n
q = ones(1,m);
for j=1:n
q = q .* (xx-x(j))/(x(i)-x(j));
end
r = r + q;
end
为了准备这个功能腭化,我将局部变量更改为全局变量。
n=100;
x=rand(1,n);
m=5;
xx=rand(1,m);
r = ones(n,m);
for i=1:n
for j=1:n
r(i,:) = r(i,:) .* (xx-x(j))/x(i)-x(j))
end
end
r = sum(r,1);
而不是一次转化的整体载体,让我们尝试它只有一个标量。也使用依赖于i和j的x中最简单的元素。最后我还删除了sum
。我们可以稍后添加它。
n=100;
x=rand(1,n);
r = ones(n,1);
for i=1:n
for j=1:n
y = x(i)+x(j);
r(i) = r(i) * y;
end
end
上面的代码是示例函数,我想并行化。
对于外环i
的一次迭代,内循环始终需要访问相同的向量r(i)
。此操作是写入操作(*=
),但命令对此操作无关紧要。
由于嵌套parfor
循环不允许在Matlab中,我试图在一个parfor
循环中打包一切。
n=100;
x=rand(1,n);
r = ones(n,1);
parfor k=1:(n*n)
%i = floor((k-1)/n)+1; % outer loop
%j = mod(k-1,n)+1; % inner loop
[j,i] = ind2sub([n,n],k);
y = x(i)+x(j);
r(i) = r(i) * y; % ERROR here
end
由于独立计算,Matlab仍然不知道热切片它。 因此,我决定将乘法运算移到外面并使用线性索引。
n=100;
x=rand(1,n);
r = ones(n,n);
parfor k=1:(n*n)
[j,i] = ind2sub([n,n],k);
y = x(i)+x(j);
r(k) = y;
end
r = prod(r,1);
r = squeeze(r); % remove singleton dimensions
虽然这对内部循环中的标量值有效,但它不适用于内部循环中的向量,因为必须重新计算索引。
n=100;
x=rand(1,n);
m=5;
r = ones(n,n,m);
parfor k=1:(n*n)
[j,i] = ind2sub([n,n],k);
y = x(i)+x(j);
r((k-1)*m+1:k*m) = y.*(1:m); % ERROR here
end
r = prod(r,1);
r = squeeze(r); % remove singleton dimensions
尽管它确实有效,但当我重新整形数组时。
n=100;
x=rand(1,n);
m=5;
r = ones(n*n,m);
parfor k=1:(n*n)
[j,i] = ind2sub([n,n],k);
y = x(i)+x(j);
r(k,:) = y.*(1:m); % ERROR here
end
r = reshape(r,n,n,m);
r = prod(r,2);
r = squeeze(r); % remove singleton dimensions
这样一来,我可以转换到另一个向量r
矢量xx
。
n=100;
x=rand(1,n);
m=5;
xx=rand(1,m);
r = ones(n*n,m);
parfor k=1:(n*n)
[j,i] = ind2sub([n,n],k);
y = x(i)+x(j);
r(k,:) = y.*xx; % ERROR here
end
r = reshape(r,n,n,m);
r = prod(r,2);
r = sum(r,1);
r = reshape(r,size(xx)); % reshape output vector to input vector
对于我的并行解决方案,我需要一个n*n*m
数组,而不是n*m
阵列,这似乎非常低效的。 有没有更好的方式来做我想做的事? 其他方式的优点是什么(更漂亮的代码,更少的CPU,更少的RAM,...)?
UPDATE
在试图简化任务,并减少对问题的最低工作示例中的顺序,我省略i~=j
检查,使其更容易,虽然导致全面NaN
结果。此外,添加此检查时,代码的性质会导致所有1
结果。为了使代码有意义,这些因素仅仅是另一个向量z
的权重。
结构复杂的问题如下所示:
n=100;
x=rand(1,n);
z=rand(1,n);
m=5;
xx=rand(1,m);
r = zeros(1,m);
for i=1:n
q = ones(1,m);
for j=1:n
if i~=j
q = q .* (xx-x(j))/(x(i)-x(j));
end
end
r = r + z(i) .* q;
end
对于每个元素'm'(或者每个元素'm'只需要一个循环,但不再需要),这可能是完全向量化的。然而,你所拥有的示例代码是错误的,因为它总是会被(x(k) - x(k))除,并生成NaN,所以很难检查。不过,我建议你绕过这个方法,并尝试着重于循环最短的向量。如果你的记忆不足,这个建议是不可能的。 – patrik
关于注释“嵌套for循环在Matlab中不允许”。我不相信这是必要的。如果外循环运行数千次,你仍然会得到很多任务。建立一个工人需要一些时间,所以这可能不是更有效。 – patrik