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


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

```j
*/~>:i.9
```

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

```text:実行結果
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 言語の九九表といえばこれをよく目にすると思いますが、なんかこればっかりで面白くないので違う方法でやってみます。

```math
\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](https://code.jsoftware.com/wiki/Vocabulary/dollar#dyadic)

```j: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](https://code.jsoftware.com/wiki/Vocabulary/idot#monadic) を使えば 0 からの整数列を生成できるので、 1 を足すと 1 からの整数列になります。
[`>: y` Increment](https://code.jsoftware.com/wiki/Vocabulary/gtco#monadic) を使って 1 加えることもできます。

しかし、ここで出来上がるのは 1 次元配列です。行列として計算するには **2 次元配列**にする必要があります。
そこで使うのが 2 項の `$` です。
単項の [`$ y` Shape Of](https://code.jsoftware.com/wiki/Vocabulary/dollar#monadic) は [shape](https://code.jsoftware.com/wiki/Vocabulary/Nouns#Shape) （配列の形）を調べるために使いますが、 2 項の [`x $ y` Shape](https://code.jsoftware.com/wiki/Vocabulary/dollar#dyadic) は**配列を指定した shape に整形する**ことができます。

```j: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](https://code.jsoftware.com/wiki/Vocabulary/commaco#monadic)

横に長いほうの行列は、 [`i. y` Integers](https://code.jsoftware.com/wiki/Vocabulary/idot#monadic) で生成した 1 次元配列を要素として持つ 2 次元配列です。
このような配列は、 [`,: y` Itemize](https://code.jsoftware.com/wiki/Vocabulary/commaco#monadic) を使うと [`x $ y` Shape](https://code.jsoftware.com/wiki/Vocabulary/dollar#dyadic) を使うより簡単に作れます。

```j: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](https://code.jsoftware.com/wiki/Vocabulary/barco#monadic)

縦に長いほうの行列は、横に長いほうの行列の転置行列です。
転置行列は [`|: y` Transpose](https://code.jsoftware.com/wiki/Vocabulary/barco#monadic) を使って作ることができます。

```j: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](https://code.jsoftware.com/wiki/Vocabulary/commadot#monadic)

縦に長いほうの行列は [`,. y` Ravel Items](https://code.jsoftware.com/wiki/Vocabulary/commadot#monadic) を使うことでさらに簡単に作れます。
この動詞は要素が縦に並んだ 2 次元配列を作ります。

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

## [`i. y` Integers](https://code.jsoftware.com/wiki/Vocabulary/idot#monadic)

実は [`i. y` Integers](https://code.jsoftware.com/wiki/Vocabulary/idot#monadic) に [shape](https://code.jsoftware.com/wiki/Vocabulary/Nouns#Shape) を示す配列を渡すと、その shape に整形した配列を生成します。

```j: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](https://code.jsoftware.com/wiki/Vocabulary/dot#dyadic) ([Conjunction](https://code.jsoftware.com/wiki/Vocabulary/Glossary#Conjunction))

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

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

```j: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
```


# 九九表

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

```j
(>:i.9 1) +/ . * >:i.1 9
```

```text:実行結果
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 言語らしく短く書くことができます。

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