/* trid-lu1.c -- 3項方程式を Gauss の消去法で解く */ #include "trid-lu1.h" /* 3項方程式 (係数行列が三重対角である連立1次方程式のこと) Ax=b を解く * * 入力 * n: 未知数の個数 * al,ad,au: 連立1次方程式の係数行列 * (al: 対角線の下側 i.e. 下三角部分 (lower part) * ad: 対角線 i.e. 対角部分 (diagonal part) * au: 対角線の上側 i.e. 上三角部分 (upper part) * つまり * * ad[1] au[1] 0 .................. 0 * al[2] ad[2] au[2] 0 ............. 0 * 0 al[3] ad[3] au[3] 0 ......... 0 * .................... * al[n-1] ad[n-1] au[n-1] * 0 al[n] ad[n] * al[i] = A_{i,i-1}, ad[i] = A_{i,i}, au[i] = A_{i,i+1}, * al[1], au[n] は意味がない) * * b: 連立1次方程式の右辺の既知ベクトル * (添字は 1 から。i.e. b[1],b[2],...,b[n] にデータが入っている。) * 出力 * al,ad,au: 入力した係数行列を LU 分解したもの * b: 連立1次方程式の解 * 能書き * 一度 call すると係数行列を LU 分解したものが返されるので、 * 以後は同じ係数行列に関する連立1次方程式を解くために、 * 関数 trisol1() が使える。 * 注意 * Gauss の消去法を用いているが、ピボットの選択等はしていな * いので、ピボットの選択をしていないので、係数行列が正定値である * などの適切な条件がない場合は結果が保証できない。 */ void trid1(int n, double *al, double *ad, double *au, double *b) { trilu1(n,al,ad,au); trisol1(n,al,ad,au,b); } /* 三重対角行列の LU 分解 (pivoting なし) */ void trilu1(int n, double *al, double *ad, double *au) { int i; /* 前進消去 (forward elimination) */ for (i = 1; i < n; i++) { al[i + 1] /= ad[i]; ad[i + 1] -= au[i] * al[i + 1]; } } /* LU 分解済みの三重対角行列を係数に持つ3項方程式を解く */ void trisol1(int n, double *al, double *ad, double *au, double *b) { int i; /* 前進消去 (forward elimination) */ for (i = 1; i < n; i++) b[i + 1] -= b[i] * al[i + 1]; /* 後退代入 (backward substitution) */ b[n] /= ad[n]; for (i = n - 1; i >= 1; i--) b[i] = (b[i] - au[i] * b[i + 1]) / ad[i]; }
これを使って、
/* * test-trid-lu1.c * gcc -o test-trid-lu1 test-trid-lu1.c trid-lu1.c */ #include <stdio.h> #include "trid-lu1.h" #define N 3 int main(void) { int n; double al[N+1], ad[N+1], au[N+1], b[N+1]; n = 3; /* 行列 A の設定 */ ad[1] = 2; au[1] = 3; al[2] = 4; ad[2] = 4; au[2] = -3; al[3] = 3; ad[3] = -1; /* A の LU 分解 */ trilu1(n, al, ad, au); /* LU 分解の結果の表示 */ printf("%f %f %f\n", ad[1], au[1], 0.0); printf("%f %f %f\n", al[2], ad[2], au[2]); printf("%f %f %f\n", 0.0, al[3], ad[3]); /* x=(1,2,3) に対応する b=A x */ b[1] = 8; b[2] = 3; b[3] = 3; /* A x = b を解く */ trisol1(n, al, ad, au, b); /* 解を表示する */ printf("%f %f %f\n", b[1], b[2], b[3]); return 0; } |
oyabun% gcc -o test-trid-lu1 test-trid-lu1.c trid-lu1.c oyabun% ./test-trid-lu1 2.000000 3.000000 0.000000 2.000000 -2.000000 -3.000000 0.000000 -1.500000 -5.500000 1.000000 2.000000 3.000000 oyabun% |