私は初めての大規模な MATLAB プログラムを構築しています。平射図法でベクトル密度を表す画像を作成しようとするまで、すべての元のベクトル化されたコードを書くことができました。数回失敗した後、私は Mathworks ファイル交換サイトにアクセスし、Malcolm Mcleanの厚意により、私のニーズに合ったオープン ソース プログラムを見つけました。テストマトリックスを使用すると、彼の関数は次のようなものを生成します。
これは私が望んでいたこととほとんど同じですが、彼のコードは 3 重にネストされた for ループに依存しています。私のワークステーションでは、サイズ 25000x2 のテスト データ マトリックスは、コードのこのセクションで 65 秒かかりました。プロジェクトでサイズ 500000x2 のデータ マトリックスにスケールアップするため、これは受け入れられません。
これまでのところ、最も内側のループ (最長/最悪のループ) をベクトル化できましたが、続行して、可能であればループを完全に取り除きたいと考えています。ベクトル化する必要がある Malcolm の元のコードは次のとおりです。
dmap = zeros(height, width); % height, width: scalar with default value = 32
for ii = 0: height - 1 % 32 iterations of this loop
yi = limits(3) + ii * deltay + deltay/2; % limits(3) & deltay: scalars
for jj = 0 : width - 1 % 32 iterations of this loop
xi = limits(1) + jj * deltax + deltax/2; % limits(1) & deltax: scalars
dd = 0;
for kk = 1: length(x) % up to 500,000 iterations in this loop
dist2 = (x(kk) - xi)^2 + (y(kk) - yi)^2;
dd = dd + 1 / ( dist2 + fudge); % fudge is a scalar
end
dmap(ii+1,jj+1) = dd;
end
end
ここでは、最も内側のループに加えた変更を示します (これが効率の最大の浪費でした)。これにより、私のマシンでは同じテスト マトリックスの時間が 65 秒から 12 秒に短縮されました。
dmap = zeros(height, width);
for ii = 0: height - 1
yi = limits(3) + ii * deltay + deltay/2;
for jj = 0 : width - 1
xi = limits(1) + jj * deltax + deltax/2;
dist2 = (x - xi) .^ 2 + (y - yi) .^ 2;
dmap(ii + 1, jj + 1) = sum(1 ./ (dist2 + fudge));
end
end
私の主な質問は、このコードを最適化するためにできる変更はありますか? または、問題にアプローチする別の方法でさえありますか? プログラムのこのセクションでは、MATLAB の代わりに C++ または F# を使用することを検討しました。MATLAB コードで妥当な効率レベルに達しない場合は、そうするかもしれません。
また、この時点で追加のツールボックスを持っていないことにも注意してください。もしそうなら、これは些細なことであることがわかります(たとえば、統計ツールボックスの hist3 を使用します)。