ls_jacobi.eq1.gifが大きいと,ガウスの消去法では時間がかかりすぎる(ls_jacobi.eq2.gif).これに対して,ガウスの消去法のように直接解くのではなく,適当な初期値から出発して計算を反復することで解に近づけていく方法を反復法と呼ぶ.ここでは最も基本的な反復法であるヤコビ(Jacobi)反復法について述べる.

以下に示す3元連立方程式を考える.

ls_jacobi.eq3.gif

係数行列の対角成分ls_jacobi.eq4.gifならば,

ls_jacobi.eq5.gif

が導かれる. ls_jacobi.eq6.gifを初期値として与え,上式に基づきls_jacobi.eq7.gifと計算していく. 反復回数をls_jacobi.eq8.gifとし,ls_jacobi.eq8.gifを十分大きくするとls_jacobi.eq9.gifは解に収束する. n元連立1次方程式の場合は以下となる.

ls_jacobi.eq10.gif

ここで,ls_jacobi.eq11.gifである.

このようにして解を求める方法がヤコビ反復法である. 解が収束したかどうかはls_jacobi.eq9.gifls_jacobi.eq12.gifの値を比べて,その差が許容誤差内に収まったかどうかで判断する. 絶対誤差を用いる場合の収束条件は以下となる.

ls_jacobi.eq13.gif

また,相対誤差を用いた場合は,

ls_jacobi.eq14.gif

ここでls_jacobi.eq15.gifは許容誤差であり,ユーザが任意の値を設定する. 計算量は反復回数をls_jacobi.eq8.gifとするとls_jacobi.eq16.gifとなり, ls_jacobi.eq8.gifをなるべく小さくすることが計算量を減らすために重要となる.

また,反復法で問題となるのは収束するための条件である. そもそも収束しないのであれば反復を繰り返しても解が発散するだけである. 収束条件を上記の反復式から導出する. まず,反復式を以下のような形で表す.

ls_jacobi.eq17.gif

反復回数が十分大きい数ls_jacobi.eq18.gifであるとき,以下の式が成り立つ.

ls_jacobi.eq19.gif

この2つの式から以下が導かれる.

ls_jacobi.eq20.gif

ls_jacobi.eq21.gifls_jacobi.eq22.gifステップでの誤差, ls_jacobi.eq23.gifls_jacobi.eq8.gifステップでの誤差である. つまり,反復を繰り返すと1ステップごとに誤差がls_jacobi.eq24.gif倍になるということである. そのため,解が収束するためには以下の条件を満たす必要がある.

ls_jacobi.eq25.gif

反復式から係数行列の要素を使って表すと,

ls_jacobi.eq26.gif

この式より,係数行列ls_jacobi.eq27.gifの各行において対角要素の絶対値が非対角要素の絶対値の和より大きい場合に収束する.このような条件を対角優位(diagonal dominant)と呼ぶ.

ヤコビ反復法の実装

ヤコビ反復法をC++で実装した例を以下に示す.

/*!
 * ヤコビ反復法(Jacobi iterative method)
 *  - 解が収束するのは
 *      ・対角有利(diagonal dominant, 対角要素の絶対値>その行の他の要素の絶対値の和)
 *      ・係数行列が対称(symmetric)かつ正定(positive definite)
 *    のどちらかの場合
 * @param[inout] A n×nの係数行列とn×1の定数項(b)を併せたn×(n+1)の拡大行列.n+1列目に解が入る.
 * @param[in] n n元連立一次方程式
 * @param[inout] max_iter 最大反復数(反復終了後,実際の反復数を返す)
 * @param[inout] eps 許容誤差(反復終了後,実際の誤差を返す) 
 * @return 1:成功,0:失敗
 */
int JacobiIteration(vector< vector<double> > &A, int n, int &max_iter, double &eps)
{
	vector<double> x(n, 0.0);	// 初期値はすべて0とする
	vector<double> y(n, 0.0);

	double e = 0.0;
	int k;
	for(k = 0; k < max_iter; ++k){
		// 現在の値を代入して,次の解候補を計算
		for(int i = 0; i < n; ++i){
			y[i] = A[i][n];
			for(int j = 0; j < n; ++j){
				y[i] -= (j != i ? A[i][j]*x[j] : 0.0);
			}
			y[i] /= A[i][i];
		}

		// 収束判定
		e = 0.0;
		for(int i = 0; i < n; ++i){
			e += fabs(y[i]-x[i]);	// 絶対誤差の場合
			//e += fabs((y[i]-x[i])/y[i]);	// 相対誤差の場合
		}
		if(e <= eps){
			break;
		}

		swap(x, y);
	}

	max_iter = k;
	eps = e;

	for(int i = 0; i < n; ++i){
		A[i][n] = y[i];
	}

	return 1;
}

添付ファイル: filels_jacobi.eq3.gif 875件 [詳細] filels_jacobi.eq4.gif 855件 [詳細] filels_jacobi.eq25.gif 907件 [詳細] filels_jacobi.eq26.gif 921件 [詳細] filels_jacobi.eq27.gif 966件 [詳細] filels_jacobi.eq5.gif 1018件 [詳細] filels_jacobi.eq6.gif 809件 [詳細] filels_jacobi.eq7.gif 826件 [詳細] filels_jacobi.eq8.gif 753件 [詳細] filels_jacobi.eq9.gif 792件 [詳細] filels_jacobi.eq11.gif 1001件 [詳細] filels_jacobi.eq12.gif 831件 [詳細] filels_jacobi.eq13.gif 836件 [詳細] filels_jacobi.eq14.gif 856件 [詳細] filels_jacobi.eq15.gif 859件 [詳細] filels_jacobi.eq2.gif 847件 [詳細] filels_jacobi.eq16.gif 864件 [詳細] filels_jacobi.eq17.gif 835件 [詳細] filels_jacobi.eq18.gif 1285件 [詳細] filels_jacobi.eq19.gif 859件 [詳細] filels_jacobi.eq20.gif 846件 [詳細] filels_jacobi.eq21.gif 835件 [詳細] filels_jacobi.eq22.gif 854件 [詳細] filels_jacobi.eq23.gif 913件 [詳細] filels_jacobi.eq24.gif 889件 [詳細] filels_jacobi.eq1.gif 951件 [詳細] filels_jacobi.eq10.gif 993件 [詳細]

トップ   編集 凍結 差分 履歴 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2024-03-08 (金) 18:06:10