今、話題の人工知能(AI)などで人気のPython。初心者に優しいとか言われていますが、全然優しくない! という事を、つらつら、愚痴っていきます

136.オロチ算

»

初回:2021/3/17

1.スピンオフからの昇格

P子「先週の続き?」(※1

 先週『文系と理系』というコラムをアップした所、スピンオフの『妖精の杜』で取り上げたオロチ算に、色々とコメントを頂きました。お礼も込めて、掘り下げてみたいと思います。

P子「本文のコラムに関するコメントはなかったもんね」

 まずは、問題から。

 ヤマタノオロチとキングギドラが居ました。頭の合計が45個でシッポが38本ありました。さて、酒樽は何個用意しないといけないでしょうか?

 ヤマタノオロチは、頭が8つ、尾が8本の大蛇です。8匹の蛇が一つの腹巻を付けている姿を想像すれば判りやすいかもしれません。

P子「迫力が半減ね」

 一方、キングギドラは、頭が3つ、尾が2本の架空の怪獣です。

P子「ヤマタノオロチは架空じゃないの?」

 実在した証拠がないからといって、架空と決めつけることはできません。

 さて、これを小学校で習った方法で解こうとすると結構邪魔くさいので、中学校で習った連立一次方程式で解きます。理系は結構邪魔くさがりなんです。

 ヤマタノオロチを『x』に、キングギドラを『y』とします。

 8x + 3y = 45   ① 頭の合計の計算式
 8x + 2y = 38   ② 尾の合計の計算式

 実は、鶴亀算より簡単な式になってしまいました。これは、私がヤマタノオロチの尾の数が8本だという事を知らなかったのが原因です。

 ①式から②式を引き算します。

 y = 7   ③

 そうです。いきなりキングギドラの数が求まってしまいました。後は、①式のyに値を割り当てるだけです。

 8x + 3*7 = 45   ①に代入(頭の合計)
 8x = 45-21 = 24  ④ヤマタノオロチのみの頭の合計
 x = 3        ⑤ヤマタノオロチ数

 感の良い人は、⑤式でヤマタノオロチの数を求めるまでもなく、酒樽の数は、④式ですでに求まっているじゃないかと思うでしょう。簡単すぎましたね。

2.出題ミス

 実は、@IT自分戦略研究所のFacebookで(編)さんより頂いたコメントがありました。

> 頭の数だけ樽を用意するじゃダメなん?(編:文系)

 『頭の合計が45個で...』という出題のまま、45樽用意すればいいじゃんという事で、最初は単なる酒飲みのたわいのない寝言かと思っていましたが、問題文を読み返したところ、ヤマタノオロチにだけ酒樽を用意するとは書かれていませんでした。クイズ番組なら、正解になる所です。

早坂「噂によると、キングギドラは酒乱で酒を飲ますと暴れるから、24樽で正解です」

P子「素直に出題ミスを認めれば?」

 さて、『勝ち逃げ先生』さんからは、

  問題:雪が溶けるとどうなる?
  理系:水になる
  文系:春が来る

  これも見分けるクイズになりますかね?

 なかなか、きれいな回答です。座布団1枚用意してください。

3.高校数学なら行列式

 さて、先の連立一次方程式ですが、高校で習う行列で解く方法があります。

 8x + 3y = 45 ① 頭の合計の計算式
 8x + 2y = 38 ② 尾の合計の計算式

 | 8  3 | |x|   |45|
 |      | | | = |  |   ⑥
 | 8  2 | |y|   |38|

 左辺の行列を単位行列にするため、2行目から1行目を引きます。

 | 8  3 | |x|   |45|
 |      | | | = |  |   ⑦
 | 0 -1 | |y|   |-7|

 2行目に3を掛けた行を、1行目に足し算します。

 | 8  0 | |x|   |24|
 |      | | | = |  |   ⑧
 | 0 -1 | |y|   |-7|

 1行目は、8で割り、2行目は、-1を掛け算します。

 | 1  0 | |x|   | 3|
 |      | | | = |  |   ⑨
 | 0  1 | |y|   | 7|

 答えが求まりました。

 もう一つは、逆行列を作成して、両辺にかけ合わせます。左辺は単位行列になるので、先ほどと同じ操作をすることになります。まずは、2行2列の逆行列を求める公式です。


 | a  b |         1     |  d -b |
 |      |  ⇒  -------- |       |
 | c  d |      ad - bc  | -c  a |

 ご覧のように、ad = bc の場合、逆行列を求めることが出来ません。

 この式を適用してみます。


    1     |  2 -3 | | 8  3 | |x|       1     |  2 -3 ||45|
 -------- |       | |      | | | =  -------- |       ||  |    ⑩
 8*2-3*8  | -8  8 | | 8  2 | |y|    8*2-3*8  | -8  8 ||38|

 | 1  0 | |x|    1  |(2*45)+(-3*38)|    1  |-24|   | 3|
 |      | | | = --- |              | = --- |   | = |  |   ⑪
 | 0  1 | |y|   -8  |(-8*45)+(8*38)|   -8  |-56|   | 7|

4.3行3列になったら

 「コーン、おいらも仲間に入れてちょ」

P子「そんな軽いノリでいいの?」

 シッポの数でいうと『九尾の狐』の存在は欠かせません。

 問題文を書き直したいと思います。

 ヤマタノオロチとキングギドラと九尾の狐が居ました。全員で9匹、頭の合計が29個でシッポが58本ありました。それぞれの個体数を求めなさい。
  x +  y + z  = 9    ① 合計数
 8x + 3y + z  = 29   ② 頭の合計の計算式
 8x + 2y + 9z = 58   ③ 尾の合計の計算式

 すでに、飽きてきたあなた、解くのが邪魔くさくなってきたと思います。ここでは、Pythonを使って、計算してみたいと思います。


import numpy as np

# 行列の定義
keisu = [[1, 1, 1],
         [8, 3, 1],
         [8, 2, 9]]

xyz = [9,29,58]

# 逆行列は、numpyのlinalg.inv関数を使います。
keisu_inv = np.linalg.inv(keisu)

# 逆行列と右辺の行列との積を計算します。
# 行列の積を取るのは、numpyのdot() 関数を使います。
print(np.dot(keisu_inv, xyz))

[2. 3. 4.]


 numpyの逆行列の計算精度は余り良くないそうです。また、逆行列を求めてから行列の積を取るのではなく、numpy.linalg には、線形行列方程式、または線形スカラー方程式のシステムを解く、solve という関数があります。こちらの方が計算速度も速いそうです。

print(np.linalg.solve(keisu, xyz))

[2. 3. 4.]

 数値計算の精度が問題になるなら、数式処理ライブラリ sympy を使ってみましょう。


import sympy as sp

sp.var('x, y, z')

eq1=sp.Eq(   x +   y +   z,  9)
eq2=sp.Eq( 8*x + 3*y +   z, 29)
eq3=sp.Eq( 8*x + 2*y + 9*z, 58)

sp.solve ([eq1, eq2, eq3], [x, y, z]) 

{x: 2, z: 4, y: 3}

 ただ、私のRaspberryPiのpython3 では、sympy の実行が出来ませんでした。
 sudo pip3 install sympy とか、sudo apt-get install python3-sympy とか、エラーなしで実行できましたが、import sympy as sp で、エラーが出ます。
 RaspberryPiのOSを、aarch64(64bit版)にしたのがいけなかったのでしょうか?

 仕方がないので、上記の実行は、python2 で行いました。

 ちなみに、Windowsの場合は、python3 をインストール後、

 py -3 -m pip install sympy

 で、インストール、実行までできました。


C:\Users\test>py -3   -m pip install sympy

C:\Users\test>py
Python 3.9.1 (tags/v3.9.1:1e5d33e, Dec  7 2020, 17:08:21) [MSC v.1927 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import sympy as sp
>>> sp.var('x, y, z')
(x, y, z)
>>> eq1=sp.Eq(   x +   y +   z,  9)
>>> eq2=sp.Eq( 8*x + 3*y +   z, 29)
>>> eq3=sp.Eq( 8*x + 2*y + 9*z, 58)
>>> sp.solve ([eq1, eq2, eq3], [x, y, z])
{x: 2, y: 3, z: 4}
>>>

 ほな、さいなら。

======= <<注釈>>=======

※1 P子「先週の続き?」
 P子とは、私があこがれているツンデレPythonの仮想女性の心の声です。


スピンオフ:CIA京都支店『妖精の杜』

 ここはCIA京都支店のデバイス開発室。安らぎを求めて傷ついた戦士が立ち寄る憩いの場所、通称『妖精の杜』と呼ばれていた。
 P子:CIA京都支店の優秀なスパイ。早坂さんにはなぜか毒を吐く。
 早坂:デバイス開発室室長代理。みんなから『妖精さん』と呼ばれている。

 P子:「オロチ算で引っ張ってるの?」
 早坂:「別にネタが無いわけじゃありません」
 P子:「もしかして、スピンオフを本文に格上げしようとしてる?」
 早坂:「そんなことは無いようなことは無い感じもしないでも無いかもしれないことも無い気がしないでも...」
 P子:「もう、面倒くさいんだから」
 早坂:「そんなことは無いようなことは無い感じもしないでも...」
 P子:「あああ、そこが面倒くさいって言ってるの」
 早坂:「そんなことは...」
 P子:「うるさい!」

Comment(0)

コメント

コメントを投稿する