我有兩個我想要並行化的嵌套循環。正確的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