C++ における行列コンテナ sstd::mat_c<T>/sstd::mat_r<T> の提案
Abstract
C++ において,画像処理や線形代数演算を行う場合,動的確保された固定長 2 次元配列クラスが用いられる.一般に,画像では,行方向にデータが格納されているため,row-major (行優先) の配列が用いられる.また,数値行列では,固有値計算における固有ベクトルなど,必要な計算結果が列方向に現れるため,column-major (列優先) の配列が用いられる.例えば,画像処理ライブラリである OpenCV の cv::Mat クラスは row-major として,線形代数演算ライブラリである Eigen の Matrix クラスは column-major として※1,それぞれ設計されている.また,可変長 2 次元配列を動的確保する場合,std::vector<std::vector<T>> が用いられる.これは,要素の追加や削除が発生する場合に有効である.
このように,C++ において 2 次元配列を利用する場合は,用途に応じて型を使い分けることが望ましい.しかし,実態として,OpenCV や Eigen を用いない場合は,殆ど std::vector<std::vector<T>> が用いられている.これは,現状の STL が標準的な行列コンテナとして std::matrix<T> を提供しておらず,また,代替クラスの設計にはコストが掛かることに起因する.基本的に,std::vector<std::vector<T>> は row-major であるため,column-major のデータを扱うには不向きである.加えて,各行ベクトルは独立してメモリ確保されるため※2,メモリアドレスは不連続となる.これらは,キャッシュミスを誘発する.更に,例え固定長であっても,std::vector<T> は,現在確保しているメモリ長と挿入されている要素数を保持するため,余分にメモリを消費する.これらの問題を解消するため,本投稿では,標準的な行列コンテナとして,sstd::mat_r<T> (row-major: r) と sstd::mat_c<T> (column-major: c) を提案する.
※1. Eigen は,行列サイズが小さい場合,静的確保を用いる [1].
※2. 行ベクトルのコンストラクタは,それぞれの行ごとに別に呼び出される.