見出し画像

No. 2 C++で学ぶ最適化ソフトウェア開発, コンピュータに最適値をどうやって探させるか

※忙しい人はタイトルと太字だけ読めば大体OK

No. 2の記事も書いていきますよ!


数学が広げるプログラミングの可能性

 文系の方がプログラミングで苦戦する理由の一つだと思うのですが,高度なものを作ろうとするのであれば数学ができた方が良いです.例えば今回作ろうとしている最適化ソフトウェアは、次のような最小値を探す問題を自動で解いてくるものでした:

何かしらの最小値を自動で見つける最適化ソフトウェア

こういった問題を解く際,コンピュータがやっていることは坂の下る向きを探すことです.「え?」と思うかもしれませんが,もう一枚図を出しましょう.

最適値はこうやって探す!

例えば上の図で,x=1の場所でyの坂は左右どちらに向かって下るのかな?ということを調べます.当然,yの坂は左に向かって下っています.なので探し物(最適値)が左にあると判断できます.また,x=-1で調べるとyの坂は右に向かって下っていますので,x=-1から見ると探し物は右にあります.左にある事が分かったなら,ちょっと左に進んでまた坂の方向を調べる、行き過ぎたら反対方向にまたちょっと進んで調べる・・・この繰り返しで,最適値の近くまでたどり着くことができるでしょう.ざっくりと,コンピュータに問題を解いてもらうプロセスはこんな感じです.
 この例くらいなら見ただけで坂の下る方向は簡単に分っちゃいますが,実際にプログラムに解かせる問題はもっと複雑になる予定です.でも,この坂が下る方向を調べるプロセスはxの数がx1,x2,x3,…と増えても基本的に同じになります.そして,この坂がどちらに向かって下っているかの情報を与えてくれるのが微分という概念になります.微分ができない人には最適化ソフトウェアのスクラッチ(一から作ること)ができない,ということになります.また,ここでは微分の概念を紹介しましたが,他にも積分や微分積分の両方を使った概念なんかもよく使います.そういう意味で,数学ができた方がプログラミングの幅が広がると言えるでしょう.先ほどから例題で前提知識として平気で使っている2次関数の概念も,中2で習う数学の内容ですしね.

坂道情報をコンピュータに調べてもらうにはどんなコードを書く?

さてさて,最適化ソフトウェアの開発には坂道の情報を探す(つまり微分)操作が必要だということを説明しました.これをどうやって実現するのか,という話をしたいと思います.さっきみたいに関数の形がわかっている場合は,もちろん数式そのものから坂の情報を見つけてやれば良いことになります.でも,普通はそんな数式なんて与えられていません😂
 じゃあどうするのか?現実の坂道で考えてみましょう.自分のいる位置を中心にして近くの位置の高さを調べ,一番低い方向に進めばいいと思いません?実は,コンピュータにもこれをやってもらいます.基準の位置を決め,そこから少し動いた時の情報を集めます.そのようにして集めた情報を元に坂がどちらに下っているかを調べることができ,その方向に少し進んでまた調べ直す...ということをやればいいわけですね.やることの方向性が見えてきました!

繰り返し計算はコンピュータの得意技!

 さて,上で紹介した,たくさんの点の情報から坂道全体の情報を調べる方法は,結構大変に思えます.というのも,ちょっと進んで高さの情報を集め直し,坂道の下る方向を見つけて進み,また高さの情報を集め直す・・・の繰り返しだからです.現実の世界で考えて100 mの距離を1 cmずつ調べながら進んでいくとすると,計算回数は1万回になりますよね.調べる回数が多すぎて人間がやったら日が暮れるどころではないかもしれません.しかし,こういった膨大な繰り返し作業はコンピュータの得意とするところですので,実はあまり心配いりません.だって,最近のCPUのクロック数は5 GHzを超えているものもあります.5GHzって,一秒間に50億回の計算ができるって意味ですよ?(本当はちょっと違うけどまぁざっくりと)安いCPUでも2 GHzくらいは平気で出ていますよね.これでも20億回/秒なので,1万回くらい,瞬きする間にも満たないわけです.ということで,人間にとって膨大な負荷に思える作業も,遠慮なく任せて良いということになります.コードは遠慮なく書いちゃいましょう!

坂が下っている方向を調べる数値微分のコードを作ってみる

 筆者の開発している最適化ソフトウェアでも坂道情報を探す微分操作をバリバリ使います.ということで,位置情報を元に微分を行うコードが必要になるわけですね.今回は次のように書きました

数値微分コードの主要部分

ごちゃついていますが,そんなに難しいことはしていません.まず,stepなる変数に距離の情報を代入しています.これの意味するところは自分を中心にどれくらい近いところの坂の情報を調べるか,です.で,その下でちょっと前に進んだとき(+step)ちょっと後ろに進んだとき(-step)の位置を求めています.Xという変数に自分の位置が入っていて,そこに足したり引いたりしていると思ってもらえれば良いです.このXをKY_FVALというものに放り込むと坂の情報が返ってくるので,自分の前後の位置が今自分のいる場所より高いか低いかを調べているわけですね.イメージするとこんな感じ?

坂の高低を調べるイメージ

で,それらの情報を使って坂がどちらに向かって下っているのかを調べています.この主要部分だけで20行もないので,コードにしてみると案外あっさりしていませんでしたか?このプロセスこそ数値微分ということになります.ここでは自分の前の情報と後ろの情報を調べていますが,単純な坂道なら自分の前と後ろ,どちらかだけの情報でも良さそうに思いません?実はこれ,中心差分法という有名な方法で,こうすることで精度が上がるのです.だって,こうなってるかもしれないですし:

前後の値を調べる理由のイメージ

この場合,自分の前だけの情報で調べちゃうと,えらく急な坂だと勘違いしてしまうのです.実際は,自分の後ろがなだらかで前が急,つまり今いる位置の急さは中くらいというのが正しいのです.前後の情報を使えば,このことが分かってしまうという仕組みですね.

おわりに

 今回は,コンピュータに最適値を求めてもらう上で重要な概念となる数値微分について書いてみました最適化問題の概念を坂道の下る方向の調査に例えてみたのですが,いかがだったでしょうか...ちょっと不安です.
 開発の方は進めていますが,書くべきコードの量が多いのでちょっと大変な思いをしています.無事に完成するまで走り切りたいです...年内には開発を終えたいですね!

K. HISAKAWA

いいなと思ったら応援しよう!