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++で実装した例を以下に示す.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
/*!
 * ヤコビ反復法(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.eq5.gif 598件 [詳細] filels_jacobi.eq10.gif 605件 [詳細] filels_jacobi.eq27.gif 575件 [詳細] filels_jacobi.eq1.gif 581件 [詳細] filels_jacobi.eq11.gif 608件 [詳細] filels_jacobi.eq26.gif 550件 [詳細] filels_jacobi.eq19.gif 549件 [詳細] filels_jacobi.eq24.gif 582件 [詳細] filels_jacobi.eq12.gif 527件 [詳細] filels_jacobi.eq18.gif 968件 [詳細] filels_jacobi.eq7.gif 521件 [詳細] filels_jacobi.eq6.gif 480件 [詳細] filels_jacobi.eq23.gif 567件 [詳細] filels_jacobi.eq13.gif 526件 [詳細] filels_jacobi.eq14.gif 534件 [詳細] filels_jacobi.eq21.gif 532件 [詳細] filels_jacobi.eq16.gif 547件 [詳細] filels_jacobi.eq22.gif 542件 [詳細] filels_jacobi.eq17.gif 525件 [詳細] filels_jacobi.eq25.gif 572件 [詳細] filels_jacobi.eq20.gif 531件 [詳細] filels_jacobi.eq9.gif 453件 [詳細] filels_jacobi.eq2.gif 495件 [詳細] filels_jacobi.eq8.gif 458件 [詳細] filels_jacobi.eq15.gif 559件 [詳細] filels_jacobi.eq3.gif 536件 [詳細] filels_jacobi.eq4.gif 499件 [詳細]

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2019-10-07 (月) 18:14:56 (357d)