“行列型”をあらわし,変数や関数(の型)などを宣言・定義するために使用します。 実体はライブラリ matrix0.c 内で宣言された構造体typedef struct { int rows; int cols; double *elem; /* 行列要素を記憶している領域へのポインタ */} mat_t;ですが,ライブラリを利用するに際し構造自体を気にする必要はありません。 次々項 mat_size の使用例参照。 2. mat_t *mat_init(mat_t *mat)
行列型(mat_t 型)の引数 mat を初期化します。 行列型の変数を使用する際,必ず実行しなければなりません(使用例参照)。 何らかの原因で mat 用の記憶領域の確保に失敗したとき,*** MEM ALLOC ERR *** と表示して停止します。 次項 mat_size の使用例参照。 3. mat_t *mat_size(mat_t *mat, int rows, int cols)
行列型(mat_t 型)の引数 mat に,行数 rows と列数 cols を設定します。 mat を初期化(mat_init)したあとでなければ使用できません。 行列の各要素を設定したり変更するには後述の mat_write,参照するには後述の mat_read を用います。 mat_set,mat_rand,mat_attrac,mat_copy,mat_trans,mat_sprod,mat_add,mat_sub,mat_mul,mat_minor,mat_adj,mat_inv,mat_eq を実行する前に,演算結果を格納するための行列型(mat_t 型)仮引数 mat の大きさを予め mat_size により設定する必要はありません。 何らかの原因で mat 用の記憶領域の確保に失敗したとき,*** MEM REALLOC ERR *** と表示して停止します。 次のプログラムは 2×3 行列 A を初期化し表示します。#include "matrix0.c"int main(void) { mat_t A; mat_init(&A); /* 前項 mat_init の機能参照 */ mat_size(&A, 2, 3); mat_print(&A); mat_free(&A); return 0;}実行すると,例えば (1, 1): 0.000000 (1, 2): 0.000000 (1, 3): 0.000000(2, 1): 0.000000 (2, 2): 0.000000 (2, 3): 0.000000が表示されます。 ただし,各要素は不定であり零とは限りません(補足1 参照)。 行列演算用ライブラリを利用するときの一般的な形は,次のとおりです。#include "matrix….c"戻り値の型 関数名(仮引数のリスト) { mat_t A, B, …, X; mat_init(&A); mat_init(&B); …; mat_init(&X); … 諸演算 … mat_free(&A); mat_free(&B); …; mat_free(&X); return 戻り値;}4. void mat_free(mat_t *mat)
mat_init や mat_size によって行列型(mat_t 型)の引数 mat に割り当てられた記憶領域を,解放します。 記憶領域の浪費を抑制するには,一時的にしか使用しない行列用に確保した記憶領域は mat_free により小まめに解放しなければなりません。 直前の mat_size の使用例参照。5. mat_t *mat_set(mat_t *mat, char *csv)
行列の要素を記述する文字列 csv を解釈し,行列 mat に設定します。 mat を初期化(mat_init)したあとでなければ使用できません。 次のプログラムは 3×4 行列を設定し表示します。#include "matrix0.c"int main(void) { mat_t A; mat_init(&A); mat_set(&A, "2,3,3,17;1,2,2,11;6,3,6,30"); mat_print(&A); mat_free(&A); return 0;}実行すると(1, 1): 2.000000 (1, 2): 3.000000 (1, 3): 3.000000 (1, 4): 17.000000(2, 1): 1.000000 (2, 2): 2.000000 (2, 3): 2.000000 (2, 4): 11.000000(3, 1): 6.000000 (3, 2): 3.000000 (3, 3): 6.000000 (3, 4): 30.000000が表示されます。 6. int mat_rows(mat_t *mat)
行列 mat の行数を出力します。 次項 mat_cols の使用例参照。 7. int mat_cols(mat_t *mat)
行列 mat の列数を出力します。 次のプログラムは 3×4 行列の行数と列数を答えます。#include "matrix0.c"int main(void) { mat_t A; mat_init(&A); mat_set(&A, "2,3,3,17;1,2,2,11;6,3,6,30"); mat_print(&A); printf("Number of rows : %d\n", mat_rows(&A)); printf("Number of columns: %d\n", mat_cols(&A)); return 0;}実行すると(1, 1): 2.000000 (1, 2): 3.000000 (1, 3): 3.000000 (1, 4): 17.000000(2, 1): 1.000000 (2, 2): 2.000000 (2, 3): 2.000000 (2, 4): 11.000000(3, 1): 6.000000 (3, 2): 3.000000 (3, 3): 6.000000 (3, 4): 30.000000Number of rows : 3Number of columns: 4が表示されます。 8. mat_t *mat_rand(mat_t *mat, int rows, int cols)
-10 以上 10 以下の整数から負の数 0.3 および正の数 0.7 の確率で選ばれた乱数を要素とする,rows 行 cols 列の行列 mat を生成します。 mat を初期化(mat_init)したあとでなければ使用できません。 mat_rand はその内部で,疑似乱数を生成するライブラリ関数 rand を利用していますので,void srand(unsigned seed) により疑似乱数の種を設定すれば毎回同じ行列が生成でき,シミュレーションの再現などに便利です。 次項 mat_print の使用例参照。 9. mat_t *mat_print(mat_t *mat)
行列 mat を表示します。 次のプログラムは 2×3 行列をランダムに生成し表示します。#include "matrix0.c"int main(void) { mat_t A; srand(16000); /* 疑似乱数の種を設定(mat_rand の補足参照)*/ mat_init(&A); mat_rand(&A, 2, 3); mat_print(&A); mat_free(&A); return 0;}実行すると,例えば(1, 1): 8.000000 (1, 2): 1.000000 (1, 3): -4.000000(2, 1): 1.000000 (2, 2): 3.000000 (2, 3): 5.000000が表示されます。 10. double nearint(double real)
実数 real が至近の整数に対し NEAR_ZERO 以内の距離(差の絶対値)にあるときその整数を出力し,それ以外のときは real をそのまま出力します。 NEAR_ZERO は別途 0.000005 と定義されています。 次項の mat_attrac はその内部で nearint を利用していますので,mat_attrac の使用例を参考にして下さい。 11. mat_t *mat_attrac(mat_t *org, mat_t *mat)
行列 org の各要素が至近の整数に対し NEAR_ZERO 以内の距離(差の絶対値)にあるとき,その要素を整数に整形して行列 mat に設定します。 NEAR_ZERO は別途 0.000005 と定義されています。 mat を初期化(mat_init)したあとでなければ使用できません。 次のプログラムは,行列の各要素が整数に近いとき整数化します。#include "matrix0.c"int main(void) { mat_t A, B; mat_print(mat_set(mat_init(&A), "1.000001,-0.000001;0.999999,0.499999")); printf("\n"); mat_print(mat_attrac(&A, mat_init(&B))); mat_free(&A); mat_free(&B); return 0;}実行すると(1, 1): 1.000001 (1, 2): -0.000001(2, 1): 0.999999 (2, 2): 0.499999(1, 1): 1.000000 (1, 2): 0.000000(2, 1): 1.000000 (2, 2): 0.499999が表示されます。 最初の行列における (1, 2) 要素 -0.000001 は零に整数化されています。 12. mat_t *mat_write(mat_t *mat, int row, int col, double elem)
行列 mat における (row, col) 要素を elem の値に設定します。 エラー row や col が行列の大きさを超えているとき,*** OUT OF DIM *** と表示して停止します。 次のプログラムは (2, 1) 要素を変更します。#include "matrix0.c"int main(void) { mat_t A; mat_init(&A); mat_set(&A, "1,2;3,4"); mat_print(&A); printf("\n"); mat_write(&A, 2, 1, 5.5); mat_print(&A); mat_free(&A); return 0;}実行すると(1, 1): 1.000000 (1, 2): 2.000000(2, 1): 3.000000 (2, 2): 4.000000(1, 1): 1.000000 (1, 2): 2.000000(2, 1): 5.500000 (2, 2): 4.000000が表示されます。 最初の行列における (2, 1) 要素は 3 ですが,二番目の行列では 5.5 に変更されています。 13. double mat_read(mat_t *mat, int row, int col)
行列 mat の (row, col) 要素を参照します。 エラー row や col が行列の大きさを超えているとき,*** OUT OF DIM *** と表示して停止します。 次のプログラムは (2, 1) 要素を参照して表示します。#include "matrix0.c"int main(void) { mat_t A; int row = 2, col = 1; double elem; mat_init(&A); mat_set(&A, "1,2;3,4"); mat_print(&A); elem = mat_read(&A, row, col); printf("\n(%d, %d): %f\n", row, col, elem); mat_free(&A); return 0;}実行すると(1, 1): 1.000000 (1, 2): 2.000000(2, 1): 3.000000 (2, 2): 4.000000(2, 1): 3.000000が表示されます。 行列 A の (2, 1) 要素 3.000000 が参照されました。 次のプログラムは 2×3 行列 A を設定して表示したのち,(1, 2) 要素だけを表示し,次に (1, 2) 要素を 7 に入れかえた行列を表示後,再び (1, 2) 要素だけを表示します。#include "matrix0.c"int main(void) { double elem; mat_t A; mat_init(&A); mat_set(&A, "1,2,3;4,5,6"); mat_print(&A); elem = mat_read(&A, 1, 2); printf("\n(1, 2): %f\n\n", elem); mat_write(&A, 1, 2, 7); mat_print(&A); elem = mat_read(&A, 1, 2); printf("\n(1, 2): %f\n", elem); mat_free(&A); return 0;}実行すると(1, 1): 1.000000 (1, 2): 2.000000 (1, 3): 3.000000(2, 1): 4.000000 (2, 2): 5.000000 (2, 3): 6.000000(1, 2): 2.000000(1, 1): 1.000000 (1, 2): 7.000000 (1, 3): 3.000000(2, 1): 4.000000 (2, 2): 5.000000 (2, 3): 6.000000(1, 2): 7.000000が表示されます。 次のプログラムは 2×3 行列 A を設定したのち,A を 1.5 倍して表示します。#include "matrix0.c"mat_t *my_sprod(mat_t *mat, double scalar) { int rows, cols, i, j; double elem; mat_t newmat; rows = mat_rows(mat); cols = mat_cols(mat); mat_init(&newmat); mat_size(&newmat, rows, cols); for(i = 1; i <= rows; i++) { for(j = 1; j <= cols; j++) { elem = mat_read(mat, i, j); elem *= scalar; mat_write(&newmat, i, j, elem); } } for(i = 1; i <= rows; i++) { for(j = 1; j <= cols; j++) { elem = mat_read(&newmat, i, j); mat_write(mat, i, j, elem); } } mat_free(&newmat); return mat;}int main(void) { mat_t A; mat_init(&A); mat_set(&A, "1,2,3;4,5,6"); mat_print(&A); putchar('\n'); my_sprod(&A, 1.5); mat_print(&A); mat_free(&A); return 0;}実行すると(1, 1): 1.000000 (1, 2): 2.000000 (1, 3): 3.000000(2, 1): 4.000000 (2, 2): 5.000000 (2, 3): 6.000000(1, 1): 1.500000 (1, 2): 3.000000 (1, 3): 4.500000(2, 1): 6.000000 (2, 2): 7.500000 (2, 3): 9.000000が表示されます。 なお,拡張ライブラリ matrix1.c 内の関数 mat_sprod は上述の関数 my_sprod と同様な機能をもちます。基本ライブラリ matrix0.c 内の関数 mat_init,mat_size,mat_free,mat_set,mat_rows,mat_cols,mat_rand,mat_print,nearint,mat_attrac,mat_write,mat_read を利用して,行列の複製 転置行列 スカラー積 和 差 積 連立方程式の解を求めるプログラムを作って下さい(拡張ライブラリ matrix1.c 内の関数 mat_copy,mat_trans,mat_sprod,mat_add,mat_sub,mat_mul,mat_eq 参照)。 連立方程式の解法には,直接的に逆行列を適用する方法のほか,ガウスの消去法(Gaussian elimination)や,LU 分解を利用する方法などがあります。