※現在、ブログ記事を移行中のため一部表示が崩れる場合がございます。
順次修正対応にあたっておりますので何卒ご了承いただけますよう、お願い致します。

中身が2行だけ書かれたプログラムを全力解説(後編)


2022年 05月 17日

※こちら記事は後編です.前編中編があります.

中身が2行だけ書かれた,以下のMATLABプログラムについて解説していきます. 

function W = SLD(H,M)
  W = nchoosek(1:H+M-1,M-1) - repmat(0:M-2,nchoosek(H+M-1,M-1),1) - 1;
  W = ([W,zeros(size(W,1),1)+H]-[zeros(size(W,1),1),W])/H;
end

前編,中編で準備が整いました.後編では,いよいよプログラムの解説に入ります.

プログラムを解説

\(H=4\),\(M=3\)を例にプログラムを解説します.処理を1個ずつ進めながら,プログラムの変化を見ていきます.1行目,2行目で分けて考えます.

1行目の処理

処理開始前.初期状態.

W = nchoosek(1:H+M-1,M-1) - repmat(0:M-2,nchoosek(H+M-1,M-1),1) - 1;

最初に,プログラムを以下のように変形します.

A = nchoosek(1:H+M-1,M-1);
B = repmat(0:M-2,nchoosek(H+M-1,M-1),1);
W = A - B - 1;

次に,括弧の中でカンマで区切られた要素の四則演算をします.

A = nchoosek(1:6,2);
B = repmat(0:1,nchoosek(6,2),1);
W = A - B - 1;

次に,括弧の中でカンマで区切られた要素について,コロン演算子(:)を適用し行ベクトルを作成します.

A = nchoosek([1 2 3 4 5 6],2);
B = repmat([0 1],nchoosek(6,2),1);
W = A - B - 1;

次に,nchoosekを利用して,行ベクトル[1 2 3 4 5 6]から2要素取り出す組み合わせを計算します.

A = [[1 2];[1 3];[1 4];[1 5];[1 6];[2 3];[2 4];[2 5];[2 6];[3 4];[3 5];[3 6];[4 5];[4 6];[5 6]];
B = repmat([0 1],nchoosek(6,2),1);
W = A - B - 1;

結果,\(A\)は15行2列の行列になります.散布図としてプロットすると以下が得られます.

次に,nchoosekを利用して,6個の対象から2個選ぶ選び方の総数,二項係数を計算します.

A = [[1 2];[1 3];[1 4];[1 5];[1 6];[2 3];[2 4];[2 5];[2 6];[3 4];[3 5];[3 6];[4 5];[4 6];[5 6]];
B = repmat([0 1],15,1);
W = A - B - 1;

次に,repmatを利用して,行ベクトル[0 1]のコピーを作成します.\(B\)も15行2列の行列になります.

A = [[1 2];[1 3];[1 4];[1 5];[1 6];[2 3];[2 4];[2 5];[2 6];[3 4];[3 5];[3 6];[4 5];[4 6];[5 6]];
B = [[0 1];[0 1];[0 1];[0 1];[0 1];[0 1];[0 1];[0 1];[0 1];[0 1];[0 1];[0 1];[0 1];[0 1];[0 1]];
W = A - B - 1;

次に,同じ要素数の行列\(A\),\(B\)の各要素について,引き算をします.

W = [[1 1];[1 2];[1 3];[1 4];[1 5];[2 2];[2 3];[2 4];[2 5];[3 3];[3 4];[3 5];[4 4];[4 5];[5 5]] - 1;

そして,行列の各要素を-1します.

W = [[0 0];[0 1];[0 2];[0 3];[0 4];[1 1];[1 2];[1 3];[1 4];[2 2];[2 3];[2 4];[3 3];[3 4];[4 4]];

以上で,1行目の処理が全て終了し,15行2列の行列\(W\)が作成されます.散布図としてプロットすると以下が得られます.

2行目の処理

処理開始前.初期状態.

W = [[0 0];[0 1];[0 2];[0 3];[0 4];[1 1];[1 2];[1 3];[1 4];[2 2];[2 3];[2 4];[3 3];[3 4];[4 4]];
W = ([W,zeros(size(W,1),1)+H]-[zeros(size(W,1),1),W])/H;

最初に,プログラムを以下のように変形します.

W = [[0 0];[0 1];[0 2];[0 3];[0 4];[1 1];[1 2];[1 3];[1 4];[2 2];[2 3];[2 4];[3 3];[3 4];[4 4]];
C = zeros(size(W,1),1);
D = C+H;
E = [W,D];
F = [C,W];
W = (E-F)/H;

次に,sizeを利用して,行列\(W\)の行数を計算します.

W = [[0 0];[0 1];[0 2];[0 3];[0 4];[1 1];[1 2];[1 3];[1 4];[2 2];[2 3];[2 4];[3 3];[3 4];[4 4]];
C = zeros(15,1);
D = C+H;
E = [W,D];
F = [C,W];
W = (E-F)/H;

次に,\(C\)を計算します.(zerosを利用して,すべての要素が0の列ベクトルを作成します.)

W = [[0 0];[0 1];[0 2];[0 3];[0 4];[1 1];[1 2];[1 3];[1 4];[2 2];[2 3];[2 4];[3 3];[3 4];[4 4]];
C = [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]';
D = C+H;
E = [W,D];
F = [C,W];
W = (E-F)/H;

次に,\(D\)を計算します.(列ベクトル\(C\)の各要素を+\(H\)(=4)します.)

W = [[0 0];[0 1];[0 2];[0 3];[0 4];[1 1];[1 2];[1 3];[1 4];[2 2];[2 3];[2 4];[3 3];[3 4];[4 4]];
C = [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]';
D = [4 4 4 4 4 4 4 4 4 4 4 4 4 4 4]';
E = [W,D];
F = [C,W];
W = (E-F)/H;

次に,\(E\)と\(F\)を計算します.(同じ行数である\(W\)と\(D\),\(C\)と\(W\)を水平連結します.)

E = [[0 0 4];[0 1 4];[0 2 4];[0 3 4];[0 4 4];[1 1 4];[1 2 4];[1 3 4];[1 4 4];[2 2 4];[2 3 4];[2 4 4];[3 3 4];[3 4 4];[4 4 4]];
F = [[0 0 0];[0 0 1];[0 0 2];[0 0 3];[0 0 4];[0 1 1];[0 1 2];[0 1 3];[0 1 4];[0 2 2];[0 2 3];[0 2 4];[0 3 3];[0 3 4];[0 4 4]];
W = (F-G)/H;

最後に,行列を引き算し,各要素を\(H\)で割って正規化します.
これで,単位超平面に均一分布する点群SLDが得られます.

$$
W\quad=\quad\left(
\begin{matrix}
[0\ 0\ 4]\cr
[0\ 1\ 4]\cr
[0\ 2\ 4]\cr
[0\ 3\ 4]\cr
[0\ 4\ 4]\cr
[1\ 1\ 4]\cr
[1\ 2\ 4]\cr
[1\ 3\ 4]\cr
[1\ 4\ 4]\cr
[2\ 2\ 4]\cr
[2\ 3\ 4]\cr
[2\ 4\ 4]\cr
[3\ 3\ 4]\cr
[3\ 4\ 4]\cr
[4\ 4\ 4]\cr
\end{matrix}\;-\;\;
\begin{matrix}
[0\ 0\ 0]\cr
[0\ 0\ 1]\cr
[0\ 0\ 2]\cr
[0\ 0\ 3]\cr
[0\ 0\ 4]\cr
[0\ 1\ 1]\cr
[0\ 1\ 2]\cr
[0\ 1\ 3]\cr
[0\ 1\ 4]\cr
[0\ 2\ 2]\cr
[0\ 2\ 3]\cr
[0\ 2\ 4]\cr
[0\ 3\ 3]\cr
[0\ 3\ 4]\cr
[0\ 4\ 4]\cr
\end{matrix}
\right)\;/\;4\quad=\quad
\left(
\begin{matrix}
[0\ 0\ 4]\cr
[0\ 1\ 3]\cr
[0\ 2\ 2]\cr
[0\ 3\ 1]\cr
[0\ 4\ 0]\cr
[1\ 0\ 3]\cr
[1\ 1\ 2]\cr
[1\ 2\ 1]\cr
[1\ 3\ 0]\cr
[2\ 0\ 2]\cr
[2\ 1\ 1]\cr
[2\ 2\ 0]\cr
[3\ 0\ 1]\cr
[3\ 1\ 0]\cr
[4\ 0\ 0]\cr
\end{matrix}
\right)\;/\;4\quad=\quad
\begin{matrix}
[\quad\ 0\quad\ \ \ 0\quad\ \ \ 1]\cr
[\quad\ 0\ \ 0.25\ \ 0.75]\cr
[\quad\ 0\quad0.5\quad0.5]\cr
[\quad\ 0\ \ 0.75\ \ 0.25]\cr
[\quad\ 0\quad\ \ \ 1\quad\ \ \ 0]\cr
[0.25\quad\ \ \ 0\ \ 0.75]\cr
[0.25\ \ 0.25\quad0.5]\cr
[0.25\quad0.5\ \ 0.25]\cr
[0.25\ \ 0.75\quad\ \ \ 0]\cr
[\ \ 0.5\quad\ \ \ 0\quad0.5]\cr
[\ \ 0.5\ \ 0.25\ \ 0.25]\cr
[\ \ 0.5\quad0.5\quad\ \ \ 0]\cr
[0.75\quad\ \ \ 0\ \ 0.25]\cr
[0.75\ \ 0.25\quad\ \ \ 0]\cr
[\quad\ 1\quad\ \ \ 0\quad\ \ \ 0]\cr
\end{matrix}
$$

以上で,プログラムは終了です.

終わりに

解説するのはたった2行なのに,3つに分割する必要があるほど内容が膨らんで自分でも驚きました.基礎の基礎から解説したため,MATLABに全く触れたことがない人でも理解できる記事が書けたと思います.普段なら関数の入出力を説明して,前編の内容で解説を終えることが多いです.しかし,技術者ブログということで,関数の中の処理も頑張って解説しました.

MATLABは,非常に短く簡潔にプログラムが書ける利点があります.それが,今回解説した2行のプログラムに良く表れていると思います.また,MATLABは,日本語で書かれた公式のドキュメント教材が充実しており,学習も非常にしやすいです.更に,公式が提供するファイル共有サイトGitHubに多数のコードが公開されています.ぜひ一度,MATLABを触ってみてください.

最後に,この内容を更に詳しく知りたいという方は,元のプログラムを眺めてみることをお勧めします.論文も2本,Referenceとして紹介されています.

  • Y. Tian, X. Xiang, X. Zhang, R. Cheng, and Y. Jin, “Sampling reference points on the Pareto fronts of benchmark multi-objective optimization problems,” Proceedings of the IEEE Congress on Evolutionary Computation (CEC2018), 2018.
  • T. Takagi, K. Takadama, and H. Sato, “Incremental lattice design of weight vector set,” Proceedings of the Genetic and Evolutionary Computation Conference Companion (GECCO2020), pp. 1486–1494, 2020.

以上です.