n元連立1次方程式

ls_cg.eq1.gif

の係数行列Aが正値対称行列であるならば, その解ls_cg.eq2.gifを求めることは, 以下の方程式の最小値探索と同等である.

ls_cg.eq3.gif

ここで,(*,*)はベクトルの内積を表す. ls_cg.eq4.gifを直接解く代わりに, 方程式ls_cg.eq5.gifの最小値探索により解を求める方法を 共役勾配法(conjugate gradient method:CG法)と呼ぶ.

ls_cg.eq5.gifの最小値探索が元のn元連立1次方程式を解くことと同等になることの証明を以下に示す.

まず,ls_cg.eq5.gifを成分で表すと,

ls_cg.eq6.gif

となる.最小値を持つ点では関数の偏微分値(傾き)が0となる. ls_cg.eq7.gifで偏微分すると,右辺第1項はi=kとj=kの要素のみが残るので,

ls_cg.eq8.gif

Aは対称行列であるので,ls_cg.eq9.gifである.よって,

ls_cg.eq10.gif

この式はls_cg.eq4.gifを成分で表示したものである. よって,ls_cg.eq4.gifの解はls_cg.eq5.gifを最小にするls_cg.eq2.gifと同じになる.

共役勾配法の計算手順

共役勾配法の計算手順を以下に示す.

  1. 初期近似解ls_cg.eq11.gifを適当に設定
  2. 初期近似解に対する残差を計算,修正方向ベクトルを70%&ref(ls_cg.eq13.gif,nolink);ls_cg.eq12.gifで初期化
    ls_cg.eq14.gif
  3. 以下の計算を収束するまで繰り返す(k=0,1,2,...)
    1. ls_cg.eq15.gifを計算
    2. 修正係数ls_cg.eq16.gifを計算
      ls_cg.eq17.gif
    3. k+1ステップの近似値を算出
      ls_cg.eq18.gif
    4. k+1の近似値に対する残差を計算
      ls_cg.eq19.gif
    5. ls_cg.eq20.gifならば収束したとして計算を終了
    6. 方向ベクトルls_cg.eq21.gifの修正係数ls_cg.eq22.gifを計算
      ls_cg.eq23.gif
    7. k+1ステップの方向ベクトルls_cg.eq24.gifを計算
      ls_cg.eq25.gif

共役勾配法の実装

共役勾配法の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
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
/*!
 * 共役勾配法によりA・x=bを解く
 * @param[in] A n×n正値対称行列
 * @param[in] b 右辺ベクトル
 * @param[out] x 結果ベクトル
 * @param[in] n 行列の大きさ
 * @param[inout] max_iter 最大反復数(反復終了後,実際の反復数を返す)
 * @param[inout] eps 許容誤差(反復終了後,実際の誤差を返す) 
 * @return 1:成功,0:失敗
 */
int CGSolver(const vector< vector<double> > &A, const vector<double> &b, vector<double> &x, int n, int &max_iter, double &eps)
{
    if(n <= 0) return 0;
 
    vector<double> r(n), p(n), y(n);
    x.assign(n, 0.0);
 
    // 第0近似解に対する残差の計算
    for(int i = 0; i < n; ++i){
        double ax = 0.0;
        for(int j = 0; j < n; ++j){
            ax += A[i][j]*x[j];
        }
        r[i] = b[i]-ax;
        p[i] = r[i];
    }
 
    double rr0 = dot(r, r, n), rr1;
    double alpha, beta;
 
    double e = 0.0;
    int k;
    for(k = 0; k < max_iter; ++k){
        // y = AP の計算
        for(int i = 0; i < n; ++i){
            y[i] = dot(A[i], p, n);
        }
 
        // alpha = r*r/(P*AP)の計算
        alpha = rr0/dot(p, y, n);
 
        // 解x、残差rの更新
        for(int i = 0; i < n; ++i){
            x[i] += alpha*p[i];
            r[i] -= alpha*y[i];
        }
 
        // (r*r)_(k+1)の計算
        rr1 = dot(r, r, n);
 
        // 収束判定 (||r||<=eps)
        e = sqrt(rr1);
        if(e < eps){
            k++;
            break;
        }
 
        // βの計算とPの更新
        beta = rr1/rr0;
        for(int i = 0; i < n; ++i){
            p[i] = r[i]+beta*p[i];
        }
 
        // (r*r)_(k+1)を次のステップのために確保しておく
        rr0 = rr1;
    }
 
    max_iter = k+1;
    eps = e;
 
    return 1;
}

ここで,std::vectorの内積を求めるdot関数を定義して用いている.


添付ファイル: filels_cg.eq30.gif 708件 [詳細] filels_cg.eq14.gif 695件 [詳細] filels_cg.eq9.gif 672件 [詳細] filels_cg.eq26.gif 636件 [詳細] filels_cg.eq13.gif 632件 [詳細] filels_cg.eq18.gif 652件 [詳細] filels_cg.eq20.gif 641件 [詳細] filels_cg.eq15.gif 570件 [詳細] filels_cg.eq40.gif 625件 [詳細] filels_cg.eq11.gif 624件 [詳細] filels_cg.eq27.gif 596件 [詳細] filels_cg.eq16.gif 650件 [詳細] filels_cg.eq6.gif 1165件 [詳細] filels_cg.eq24.gif 578件 [詳細] filels_cg.eq38.gif 535件 [詳細] filels_cg.eq5.gif 584件 [詳細] filels_cg.eq17.gif 648件 [詳細] filels_cg.eq8.gif 591件 [詳細] filels_cg.eq32.gif 663件 [詳細] filels_cg.eq7.gif 608件 [詳細] filels_cg.eq25.gif 655件 [詳細] filels_cg.eq3.gif 623件 [詳細] filels_cg.eq10.gif 593件 [詳細] filels_cg.eq12.gif 593件 [詳細] filels_cg.eq37.gif 628件 [詳細] filels_cg.eq41.gif 607件 [詳細] filels_cg.eq35.gif 515件 [詳細] filels_cg.eq22.gif 501件 [詳細] filels_cg.eq4.gif 575件 [詳細] filels_cg.eq2.gif 582件 [詳細] filels_cg.eq31.gif 584件 [詳細] filels_cg.eq19.gif 591件 [詳細] filels_cg.eq36.gif 548件 [詳細] filels_cg.eq23.gif 558件 [詳細] filels_cg.eq21.gif 552件 [詳細] filels_cg.eq39.gif 517件 [詳細] filels_cg.eq29.gif 601件 [詳細] filels_cg.eq33.gif 571件 [詳細] filels_cg.eq28.gif 598件 [詳細] filels_cg.eq1.gif 606件 [詳細] filels_cg.eq34.gif 602件 [詳細]

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2012-07-10 (火) 15:33:25 (3310d)