#author("2019-10-07T18:14:56+09:00","default:pbcglab_user","pbcglab_user")
&ref(ls_jacobi.eq1.gif,nolink,70%);が大きいと,ガウスの消去法では時間がかかりすぎる(&ref(ls_jacobi.eq2.gif,nolink,70%);).これに対して,ガウスの消去法のように直接解くのではなく,適当な初期値から出発して計算を反復することで解に近づけていく方法を反復法と呼ぶ.ここでは最も基本的な反復法であるヤコビ(Jacobi)反復法について述べる.

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

#ref(ls_jacobi.eq3.gif,nolink,70%)


係数行列の対角成分&ref(ls_jacobi.eq4.gif,nolink,70%);ならば,

#ref(ls_jacobi.eq5.gif,nolink,70%)


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

#ref(ls_jacobi.eq10.gif,nolink,70%)


ここで,&ref(ls_jacobi.eq11.gif,nolink,70%);である.

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

#ref(ls_jacobi.eq13.gif,nolink,70%)


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

#ref(ls_jacobi.eq14.gif,nolink,70%)


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

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

#ref(ls_jacobi.eq17.gif,nolink,70%)

反復回数が十分大きい数&ref(ls_jacobi.eq18.gif,nolink,70%);であるとき,以下の式が成り立つ.

#ref(ls_jacobi.eq19.gif,nolink,70%)

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

#ref(ls_jacobi.eq20.gif,nolink,70%)


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

#ref(ls_jacobi.eq25.gif,nolink,70%)

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

#ref(ls_jacobi.eq26.gif,nolink,70%)


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


***ヤコビ反復法の実装 [#bf5910ff]

ヤコビ反復法をC++で実装した例を以下に示す.
#code(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;
}
}}

トップ   編集 差分 履歴 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS