演習用行列計算ライブラリ
Makefile
円滑に演習が進むようにMakefileを提供している.
コードを編集した場合,make
コマンドでコンパイルすること.
また,.o
ファイルを削除したい場合は,make clean
を実行すること.
コンパイルオプションを変更する場合は,CXXFLAG_ST
を編集すること.
CXXFLAG
は必要なコンパイルオプションなので,変更しないように注意すること.
Matクラス
本演習では,行列クラスとしてMat_XXX
クラスを提供している.
XXX
には,8U,16S,32S,32F,64Fが入る.
これらは順に,unsigned char
,short
,int
,float
,double
型の行列であることを表している.
これらのクラスには,データを格納しているdata
変数,行列の行数を格納しているrows
変数,列数を格納しているcols
変数がある.
//8Uの場合
struct Mat_8U{
unsigned char* data;
int rows;
int cols;
}
データにアクセスする場合,列優先で格納されているため,以下のようにコードを書くことで指定の位置にアクセスができる.
const int row = 3;
const int col = 3;
Mat_8U a(row, col);
//j行,i列へのアクセス
a.data[j*a.cols+i];
また,showという関数を用意しているため,行列の中身を確認したい場合は,以下のようにすること. ただし,非常に大きな行列を表示すると画面に収まりきらないため注意すること.
Mat_8U a(row, col);
a.show();
//もしくは
mat_show(a);
行列の初期化
行列の初期化には,mat_zero
,mat_one
,mat_rand
関数を用意している.
Mat_8U a(row, col);
mat_zero(a); //0で初期化
mat_one(a); //1で初期化
mat_rand(a, 0, 100); //0~100の乱数で初期化
なお,mat_rand
等のrand
関数を使用して乱数を生成しているが,再現性があるようにあえてsrand
はしていない.
通常乱数を使う場合は,srand
等を使ってより乱数らしくなるようにするが,今回は演習用のために行っていない.
また,行列の内容が最初から決まっている場合は,行列オブジェクトを作成する際に値を代入することもできる.
const int row = 3;
const int col = 3;
const unsigned char data[row*cols] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
Mat_8U a(data, row, col);
// 0, 1, 2,
// 3, 4, 5,
// 6, 7, 8,
行列演算
行列演算を行う関数として以下がある. 適時使用すること.
- mat_add
- 行列と行列の加算を行う関数
- 行列とスカラの加算を行う関数
- mat_mul
- 行列と行列の行列積を計算する関数
- 行列とスカラの乗算を行う関数
- mat_div
- 行列とスカラの除算を行う関数
チュートリアル課題1
3x3の単精度浮動小数点(float)の行列を確保し,すべて1で初期化したのちにshowメソッドで中身を確認せよ.
答え:
Mat_32F a(3, 3);
mat_one(a);
a.show();
チュートリアル課題2
5x5 倍精度浮動小数点(double)の行列を確保し,自分でループを書いて単位行列として初期化し,showメソッドで中身を確認せよ. 単位行列は対角要素がすべて1,それ以外はすべて0の行列である.
答え:
Mat_64F a(5, 5);
for (int j = 0; j < a.rows; j++)
{
for (int i = 0; i < a.cols; i++)
{
if (i == j) a.data[j * a.cols + i] = 1.0;
else a.data[j * a.cols + i] = 0.0;
}
}
a.show();
チュートリアル課題3
3x3 の1バイトの符号なし整数(unsigned char)の行列を確保し,自分でループを書いてすべてが255となるようにして,showメソッドで中身を確認せよ.
答え:
Mat_8U a(3, 3);
for (int j = 0; j < a.rows; j++)
{
for (int i = 0; i < a.cols; i++)
{
a.data[j * a.cols + i] = 255;
}
}
a.show();
なお,すべての要素に対して,行と列が関係ないような関数は以下のようにループを1重にできる.
Mat_8U a(3, 3);
const int size = a.cols * a.rows;
for (int i = 0; i < size; i++)
{
a.data[i] = 255;
}
a.show();
もし,演習で実行時間に差がないような場合,この形式にすると差が見えるようになる可能性がある.
なぜなら,行列へのアクセスのためにj*cols+i
をしたり,添え字のi++,j++
をしたりするからである.
これをループつぶしとも呼ぶ(演習を参照のこと).