柔道の「一本背負い投げ」を学ぶ手順を例にとって見ます。相手と相対して立ち、一歩踏み出して相手に近づきながらくるりと背を向ける動作を稽古します。全てをいっぺんに身につけることは出来ませんから、おおよそこのような形で、ということだけを伝えて繰り返し稽古してもらいます。良い形になってきたところで、手の使い方を学びます。最初から手の使い方を教えると、手にばかりに気を取られて肝心の足裁きがおろそかになります。手の使い方がうまくなってきたら、また足裁きに戻ります。効率よく、有効な技を学ぶには、こうした学習手順のコツがあるのです。
今回、再び逆行列に注目したのは、逆行列を求めるために、前回学習したガウス-ジョルダン法の計算手順が役に立つからです。この連載で行列の数学を学ぶ目的は、連立一次方程式の解を得ることです。この順番の方が学習効率がよいのです。これまでの学習の手順を怪訝に感じられた方もおられるやもしれませんが、こういう意図だったのです。
問題 ガウス-ジョルダン法の計算手順を利用して逆行列を求めましょう
ガウス-ジョルダン法で逆行列が得られる仕組み
ガウス-ジョルダン法の計算手順を利用して、逆行列を求めましょう。ガウス-ジョルダン法を用いて逆行列が得られる理屈は次の式45.1~45.4の通りです。行列Aの逆行列を求めています。
式45.2のように、方程式の定数ベクトルには単位ベクトルが掛かっていると見なせます。
両辺に逆行列を掛けると(式45.3)、左辺は解ベクトルのみに、右辺は逆行列と定数ベクトルの積になります(式45.4)。この逆行列は、単位ベクトルが式変形により変化したものと見なせます。
以上のことから、ガウス-ジョルダン法を用いて行列に施した操作を、単位行列に同じように施せば、逆行列が得られることがわかります。
サンプルコードを完成させましょう
サンプルコード未完成版に処理の大筋と、スモークテストを示しました。サンプルコードには(A)から(D)の4カ所、コードの不足した部分があります。それぞれの内容は次の通りです。
(A)から(C)
3つの箇所は、reguratePivot、doSweepの二つのメソッドに含まれています。前回示したコードと比較して、わずかな変更を加えて、定数ベクトルを指定する変数bのところに戻り値用の正方行列を指定できるようにしましょう。
このとき、変更後も、reguratePivot,doSweepメソッドは、evokeGaussJordanEliminationメソッドから変わらず呼び出せるようにしてください。
(D)
新しく作るinverseMatrixメソッドに含まれています。このメソッドは、evokeGaussJordanEliminationメソッドとほぼ同じ流れです。前回の解説で示したソースコードを参考にしてコードを組み上げてください。
少々長いサンプルのソースコードですが、コードリーディングの精神でじっくり取り組んでください。「こうすればもっといいのに」というところがありましたら、どしどし教えてください。お待ちしております。
解説
以下にコードを加えた部分のメソッドを示します。コードを実行、特別なメッセージを表示せずに終了すれば、与えたデータについては想定した動作をしたと見なすことが出来ます。
ガウス-ジョルダン法の計算手順では、係数行列に対してはピボット列を含めて右の値にしか操作が必要ありませんでしたが、逆行列を求めるためには、ピボット位置よりも左のデータについての操作を忘れないようにしなければなりません。それさえ気をつけていれば、そう難しい課題ではなかったことでしょう。
行列の数学の最後に
長きにわたった行列の数学ですが、今回で一通りの課題をこなしたことにいたします。数学の教科書には行列式が掲載されていますが、最初に設定した目標「連立一次方程式の解をコンピュータで求める」から見ると、必須とは思われませんので省略させていただきました。最低限の道具立てはそろったと思いますので、積極的に活用を検討しましょう。
連載の中で学習したアルゴリズムを頻繁に利用することが考えられる方は、利用環境に合わせてチューニングし、クラス化して用いましょう。行列の計算はメモリを大変多く必要としますので、チューニングのポイントは多岐にわたります。メモリ量か、計算速度か、精度か、それぞれをどのくらいの割合で重要視するかによって、実装方法は様々に変化するでしょう。
科学技術計算におけるJava言語の地位はまだまだ確立されたものとは言えません。目的に合わせた活用のための仕事の余地が多く残されています。参考書やオープンにされているソースコードを研究して、どんどん活用し、できれば結果を公開しましょう。