わさっきhb

大学(教育研究)とか ,親馬鹿とか,和歌山とか,とか,とか.

大学の数学とプログラミングで,行列を学ぼう

「うーん」と終始,心の中でうなりながら,読み進めていきました.kadamasaruさんによる一連のツイートに共感しました.まとめ主さんによるhttps://twitter.com/Kelangdbn/status/212950295125295106は,表現はやや乱暴ながら,指導内容を組み立てる際に忘れてはならないことだと思っています.
高校数学の中で,論理や確率統計により多くの時間をとって学習するのなら,行列の概念は大学に入ってからとするほうが,学習者のメリットになるとも考えます.


ところで私が担当している,1年後期にC言語を学んでもらう授業では,サンプルプログラムとして何度か,行列の積を取り入れています.
初回授業は2行2列です.変数は全部で12個用意します.
配列を学習したところで,n行m列とm行p列の積(積はn行p列になります),ただしn, m, pは定数,について,3重ループを用いたプログラムを示します.変数は,2次元配列2個に減ります.と言いたいのですが,別に3つのループ用変数を使用します.*1
さらに進み,構造体を解説する中で,行数・列数の変更が可能な,行列構造体の定義を2種類示します.いずれも行数・列数・成分からなるのですが,一つは成分を固定サイズの2次元配列とします.もう一つは成分についてはポインタだけを持っておき,外部で確保した2次元配列を指し示すものとします.*2
ファイル入出力(fopenなど),記憶域管理関数(mallocなど)と連携させ,ファイルから読み出して行列を構成し,積などの演算を施して,結果を別のファイルに格納する方法を確認すれば,1年後期のC言語の内容としては,ゴールにたどり着いたと言っていいでしょう.
上記togetterの中で何度か,積の非可換性のことが書かれていますが,プログラマにとってはそれはさほど重要でないように感じます.一次変換を行ったり,固有値を求めたりするのも,基盤となる行列のデータ構造を記述した上で,線形代数ほかの教科書・解説書をもとにコーディングし,動作確認していけばいいのです.バグなく効率の良いプログラムを作りたければ,Excaliburなどの行列計算用ライブラリを選定・導入することになります.「Cで書くべきか?」というところから,疑問を持つべきかもしれません.
それでもなお,プログラミングを学習する人が,数学の行列を理解する理由,というよりは「これだけは理解してほしい」という点を挙げるなら,行と列の非対称性だと思っています.
数学的には,ある与えられた行列から,特定の行や列を抜き出したり,特定の行や列に関する演算をする際に,行と列とで,コスト面での違いは見られません.しかしプログラムを書くと,違ってきます.素直なコーディングでは,行のコピーはmemcpyでできても,列のコピーはそうはいかず,forループを用いた鈍くさい方法をとらざるを得ません.
ちなみに数学の話であっても,行と列には異なる役割が課されてきたように感じています.行列Aを用いてy=Axといった形のものを見るときに,そう思います.xとyは列ベクトルで表されます.高校までで学習した形(行ベクトル)にしないのは…結局のところ慣習なのでしょう.


かつて授業で示した,行列を使うことの実用的な例を一つ,挙げておきましょう.フィボナッチ数を計算するときに,a1=a2=1から始めて,a3は,a4は,a5は…とするよりも,行列の積形式を用いた漸化式を作って,べき乗で求める(A^2は,A^4は,A^8は…)ことで,演算回数を減らすことができます.ただし,元を取るためには,十分大きな数に対するフィボナッチ数が必要となり,Cの範囲ではすぐにオーバーフローを引き起こします.*3
もちろんフィボナッチ数は本質ではなく,10年以上前ですが,ぷよぷよの連結性判定で行列を用いたアルゴリズムを記したことがあります.そのときの行列の各成分は0/1で,成分ごとの乗算と加算は,論理積論理和に置き換えられます.
(最終更新日時:Tue Jun 19 20:09:14 2012ごろ.タイトルを「情報分野の学生が行列を学ぶ理由」から変更しました)

*1:Σを用いた式に基づき素直に3重ループで表すものよりも,ループの順序変更をすることで,メモリの連続した領域をアクセスするようになり,実行速度が劇的に向上するという事例が,『Cプログラム高速化研究班 コードを高速化する20の実験と達人の技』pp.97-101に示されています.

*2:2次元配列を構造体の中に入れるほうが,コードは簡単ですが,使用しない場所が多くなり,メモリの使用に無駄が生じます.ポインタにすると,その非効率を解消できる反面,指し示すのに処理が増え,バグも生じやすくなります.こういったことを通じて,一つの課題に複数の実現手段があること,そしてその得失を認識することへと持っていきます.

*3:情報科学入門―Rubyを使って学ぶ』に「5.3 行列を用いたFibonacci数のアルゴリズム」の解説があります(pp.90-93).Rubyなので,オーバーフローを考慮する必要はありません.鈍くさいフィボナッチ数計算プログラムのみ,http://lecture.ecc.u-tokyo.ac.jp/johzu/joho-kagaku/text/からダウンロードでき,行列を使ったプログラムは練習問題となっています.