鶴亀算とは割り算である~疑似逆行列について~

# 何故この記事を書くのか
割り算？何を今更…と呆れられそうですが、
この記事は数学わからない人向けです。

かつての自分は初心者向けの本を色々読んでも分かりませんでした。
でも、とっても大事なものであって、
今でも後輩が苦戦しているかもしれないので、書いてみます。

# 割り算？それ何に使うの？
逆行列を解くという事はとても大事なことです。
例えば、サポートベクターマシンなんかにも逆行列入っています。
他にも脳波から脳内の電流を推定するとか、色んなのに使ってたりします。
そして、鶴亀算は割り算なのであります👶

# 鶴亀算とは連立一次方程式である
鶴亀算とはこの様な問題です🐦🐢
> 鶴と亀の脚の本数の合計はa、個体数をbとします。
> 鶴と亀はそれぞれ何匹ずつ居るでしょうか？

これは簡単な連立方程式で表わせます。
鶴をx匹、亀をy匹とすると以下のとおりです。

$2x + 4y = a$
$x + y = b$

## 連立一次方程式とは行列の割り算である➗
上記の2つの式ですが、この様に変形できます。
(ここで、仮に足の数を本、体の数を体の単位で表してみます)
$$ \left(\begin{array}{rr} 2本 & 4本 \\\
 1体 & 1体  \end{array}\right) 
\left(\begin{array}{r} x匹 \\\
 y匹 \end{array}\right) = 
\left(\begin{array}{r} a本 \\\
 b体 \end{array}\right)$$

横から縦に掛けるからそうなるのは実際に計算すれば分かると思います。

## 鶴亀算の解き方
鶴亀算の式が上記のように行列で表現できるならば、
逆行列を使うことで解を得られます。
numpyを使ってみましょう。
ここで、上記の式を以下のように表してみます。
$$A= \left(\begin{array}{rr} 2本 & 4本 \\\
 1体 & 1体  \end{array}\right) $$

$$X= \left(\begin{array}{r} x匹 \\\
 y匹 \end{array}\right) $$

$$Y=\left(\begin{array}{r} a本 \\\
 b体 \end{array}\right)$$

$$AX=Y$$
逆行列を用いて
$$X = A^{-1}Y$$

これでXを計算できます。なんと、鶴亀算とは行列の割り算のことでした🐢
ちなみに、これは鶴てんとう虫算とか亀てんとう虫算とかも成立するのですが、
蛇鶴算とか亀猫算は成立しません😺
０本足や足の数が同じお友達が入ると難しいのですね🐍

## 実装(python🐍)

では逆行列を作りましょう!今回はnumpyを使います。
まずは、pythonで割り算のモジュールをimportして、上の行列を入れ込みます。
(足と体の数は適当に入れました)

```python
from numpy import linalg, array
A = [[2, 4], [1, 1]]  # それぞれ足と首の数
At = linalg.inv(A) # 逆行列
Y = array([10, 3]) # 足が10本、首が3本
```

逆行列が出来たので、あとはなんなりと。

```python
At @ Y  # 逆行列の掛け算
>array([1., 2.])
```
答えは鶴1匹と亀2匹ですね。

## 方程式をもっとサクッと解く
さっきのは実はコード上無駄が多いので、こっちのほうが速いです！

```python
linalg.solve(A, Y)
```
しかし、本記事では割り算を強調するために愚直に書いていこうと思います。

# 鶴亀てんとう虫算
鶴亀算が出来たので、次は鶴亀てんとう虫算をやってみましょう。
項目を増やしていけば「鶴亀てんとう虫蜘蛛ムカデ」算が出来るようになり、
非常に応用の幅が広がります。

さて、鶴亀てんとう虫算は下記のような形をしているはずです。
(もういいかなと思うので単位は省略します)

$$ \left(\begin{array}{rrr} 2 & 4 & 6\\\
 1 & 1 & 1 \end{array}\right) 
\left(\begin{array}{r} x \\\
 y  \\\
 z \end{array}\right)= 
\left(\begin{array}{r} a \\\
 b \end{array}\right)$$

## 無限個の解とその解決策
実は、鶴亀てんとう虫算は小学校中学校の正攻法では解くことが出来ません。
yが増えても減ってもxとzで調整できてしまうから、
答えが一意に決まらないのです(´・ω・｀)

では、どういう条件なら解があるのでしょうか？
鶴、亀、てんとう虫と、三種類の動物の数を調べるなら、
足と首の数だけじゃ決まらないということです。
他の何かを与えてやれば解が定まります。

…とは言っても、足、首、胴体だったら何の解決にもなっていないことは
分かると思います。(この状態のことをランク落ちといいます)

そうです。
鶴亀てんとう虫算にはもう一つの値、羽の数が必要だったのですね🐞
では、それでやってみましょう！

## 逆行列は作れないこともある🐍
```python
from numpy import linalg, array
A = array([[2, 4, 6], [1, 1, 1], [0, 2, 4]])
At = linalg.inv(A)
> LinAlgError: Singular matrix
```
ぶべら！💀
この条件じゃ逆行列は作れないのでした！
こういうこともあるんですね。

## じゃあなんだったら良かったの？
じゃあ、これでどうでしょう？
ナナホシテントウの羽には~~ケンシロウ兄さんと同じく~~7つの星がありますね。
では3つ目の数字は星の数にしてみましょう！

```python
from numpy import linalg, array
A = array([[2, 4, 6], [1, 1, 1], [0, 0, 7]])
At = linalg.inv(A)
Y = array([10, 3, 7])
At @ Y

>array([ 2., -0.,  1.])
```

これでうまくいきました。
うまくいくかどうかの条件は正則行列でググってください。
本記事では数学はしません👶


## 足と首だけでもっともらしい解
でも、足の数と首の数しか無いよ！というときは困りますね？
そこで、どうするかというと、色々な解法があってよいかと思います。
例えば、鶴と亀とてんとう虫の数は必ず正の整数であるというのもいいでしょう。
(これも、実際は複数の解が出現します)
よく使われる方法は$X$のノルム(大きさ)が最も小さくなる解です。

## 疑似逆行列
擬似逆行列とは、上記の一番もっともらしい解を出してくるものです。
便利ですね！では実装してみます。

```python
from numpy import linalg, array
A = [[2, 4, 6], [1, 1, 1]]  # 足と首の数
At = linalg.pinv(A)  # 擬似逆行列
Y = array([10, 3])  # 足10本と首3本
At @ Y  # 擬似逆行列の掛け算

>array([1.5, 1. , 0.5])
```

うわお！適当に数を決めたら少数が出てきました👻
まぁ、それはそれとして、擬似逆行列が割り算みたいなもんということは
わかっていただけるのではないでしょうか？

## 逆行列/擬似逆行列の導出👻
この記事では導出はしません👶
何故なら、面倒くさいからです！
擬似逆行列を導出するためには特異値分解、行列の微分、
ラグランジュの未定乗数法を使わないといけないからです＞＜
いや、まぁ、出来るっちゃできるんですが、ググったほうが早いです。

# 応用~ソースベース脳波解析
僕は脳波を専門にしている学生なので、脳波を使って応用例を示してみます。
脳の中にいっぱい点を打ちます。そして、脳波のセンサーをくっつけます。
そして、脳とセンサーの位置関係から「どの程度電気がセンサーに伝わるか」を計算します。
センサーで拾った情報が「足の数、体の数」
どのように伝わるかが「一匹の持つ足の数、胴体の数」
そして、脳の中に沢山ある点たちが動物の種類、脳内の一点一点の電気活動の大きさが「動物の数」です。
すなわち、脳内電気活動の推定は鶴亀算であり割り算です。

# まとめ
- 鶴亀算とは割り算であった
- 割り算を応用することで様々なことが分かる
- numpyで割り算を解くことが出来る