【 J 言語】超簡単!行列積で九九表


毎度おなじみ J 言語の記事です。

*/~>:i.9

ASCII 文字が 8 つ並んでいますが、これは九九表を出力する J 言語のコードです。

実行結果
1  2  3  4  5  6  7  8  9
2  4  6  8 10 12 14 16 18
3  6  9 12 15 18 21 24 27
4  8 12 16 20 24 28 32 36
5 10 15 20 25 30 35 40 45
6 12 18 24 30 36 42 48 54
7 14 21 28 35 42 49 56 63
8 16 24 32 40 48 56 64 72
9 18 27 36 45 54 63 72 81

J 言語の九九表といえばこれをよく目にすると思いますが、なんかこればっかりで面白くないので違う方法でやってみます。

\begin{pmatrix}
1 \\ 2 \\ \vdots \\ 9
\end{pmatrix}
\begin{pmatrix}
1 & 2 & \cdots & 9
\end{pmatrix}
=
\begin{pmatrix}
1 & 2 & \cdots & 9 \\
2 & 4 & \cdots & 18 \\
\vdots & \vdots & \ddots & \vdots \\
9 & 18 & \cdots & 81
\end{pmatrix}

今回は行列積を使って九九表を出します。

行列を作る

行列積を計算するにあたって、まずは積をとる 2 つの行列、 $\begin{pmatrix} 1 \\ 2 \\ \vdots \\ 9 \end{pmatrix}$ と $\begin{pmatrix} 1 & 2 & \cdots & 9 \end{pmatrix}$ を作ります。
J 言語で行列を作る方法はいろいろあります。

x $ y Shape

REPL
   i.9    NB. [0, 9) の整数列を作成
0 1 2 3 4 5 6 7 8
   1+i.9    NB. すべての要素に 1 を加算
1 2 3 4 5 6 7 8 9
   >:i.9    NB. すべての要素をインクリメント
1 2 3 4 5 6 7 8 9

i. y Integers を使えば 0 からの整数列を生成できるので、 1 を足すと 1 からの整数列になります。
>: y Increment を使って 1 加えることもできます。

しかし、ここで出来上がるのは 1 次元配列です。行列として計算するには 2 次元配列にする必要があります。
そこで使うのが 2 項の $ です。
単項の $ y Shape Ofshape (配列の形)を調べるために使いますが、 2 項の x $ y Shape配列を指定した shape に整形することができます。

REPL
   >:i.9    NB. これは 1 次元配列
1 2 3 4 5 6 7 8 9
   $ >:i.9    NB. shape は 9
9

   9 1 $ >:i.9    NB. 9×1 の 2 次元配列に整形
1
2
3
4
5
6
7
8
9
   $ 9 1$>:i.9    NB. shape は 9 1
9 1

   1 9 $ >:i.9    NB. 1×9 の 2 次元配列に整形
1 2 3 4 5 6 7 8 9
   $ 1 9$>:i.9    NB. 出力の見た目は >:i.9 と変わっていないが shape は 1 9
1 9

,: y Itemize

横に長いほうの行列は、 i. y Integers で生成した 1 次元配列を要素として持つ 2 次元配列です。
このような配列は、 ,: y Itemize を使うと x $ y Shape を使うより簡単に作れます。

REPL
   ,: >:i.9    NB. >:i.9 を要素に持つ配列を作成
1 2 3 4 5 6 7 8 9
   $ ,:>:i.9    NB. shape は 1 9
1 9

|: y Transpose

縦に長いほうの行列は、横に長いほうの行列の転置行列です。
転置行列は |: y Transpose を使って作ることができます。

REPL
   |: ,:>:i.9    NB. ,:>:i.9 を転置
1
2
3
4
5
6
7
8
9
   $ |: ,:>:i.9    NB. shape が反転している( 1 9 → 9 1 )
9 1

,. y Ravel Items

縦に長いほうの行列は ,. y Ravel Items を使うことでさらに簡単に作れます。
この動詞は要素が縦に並んだ 2 次元配列を作ります。

REPL
   ,. >:i.9    NB. 縦に要素を並べた 2 次元配列を作成
1
2
3
4
5
6
7
8
9

i. y Integers

実は i. y Integersshape を示す配列を渡すと、その shape に整形した配列を生成します。

REPL
   >:i.1 9    NB. [0, 9) の整数列を 1×9 の配列に並べてインクリメント
1 2 3 4 5 6 7 8 9
   $ >:i.1 9    NB. shape は 1 9
1 9

   >:i.9 1    NB. [0, 9) の整数列を 9×1 の配列に並べてインクリメント
1
2
3
4
5
6
7
8
9
   $ >:i.9 1    NB. shape は 9 1
9 1

行列積

次は行列積の計算方法です。

x u . v y Matrix Product (Conjunction)

J 言語には行列積演算子なるものがあります。それが . ←これです。
行列積はこの演算子(正確には接続詞 (conjunction) )を使って +/ . * で求められます。

ここで +/.* と詰めて書くと . ではなく /. と認識されるので、 /. の間のスペースが必須なことに注意です。( .* の間のスペースは任意です。)

REPL
   ]a=: 2 3 $ 2 _3 8 _8 _2 _3
 2 _3  8
_8 _2 _3
   ]b=: 3 3 $ _8 2 _4 8 _4 _2 4 6 6
_8  2 _4
 8 _4 _2
 4  6  6

   a +/ . * b    NB. a と b の行列積
_8  64 46
36 _26 18

九九表

最後に上で紹介したものを組み合わせます。

(>:i.9 1) +/ . * >:i.1 9
実行結果
1  2  3  4  5  6  7  8  9
2  4  6  8 10 12 14 16 18
3  6  9 12 15 18 21 24 27
4  8 12 16 20 24 28 32 36
5 10 15 20 25 30 35 40 45
6 12 18 24 30 36 42 48 54
7 14 21 28 35 42 49 56 63
8 16 24 32 40 48 56 64 72
9 18 27 36 45 54 63 72 81

完成です。

J 言語は「配列型プログラミング言語」というだけあって、行列演算は得意分野です。

コードゴルフ

やはり最後は短くしたくなります。
共通部分をくくりだすことで、 J 言語らしく短く書くことができます。

(,.>:i.9) +/ . * ,:>:i.9    NB. 共通部分が増えるように ,. と ,: を使って行列を作る
NB. ↓ '>:i.9' をくくりだす
(,.+/ .*,:)>:i.9