ONLY DO WHAT ONLY YOU CAN DO

こけたら立ちなはれ 立ったら歩きなはれ

Go 言語で固有値・固有ベクトルを求める (逆反復法)

f:id:fornext1119:20150711180736p:plain
正方行列 f:id:fornext1119:20150805175030p:plain逆行列を求め
f:id:fornext1119:20150806125510p:plain
として反復法で最大固有値を求めれば, その逆数が最小固有値になる.
逆行列を計算するより,
f:id:fornext1119:20150806125806p:plain を解いた方が簡単.
逆べき乗法ともいう.

package main

import "fmt"
import "math"

const N = 4

func main() {
    var a [N][N]float64 = [N][N]float64{{5.0, 4.0, 1.0, 1.0},
                                        {4.0, 5.0, 1.0, 1.0},
                                        {1.0, 1.0, 4.0, 2.0},
                                        {1.0, 1.0, 2.0, 4.0}}
    var x               = []float64     {1.0 ,0.0 ,0.0 ,0.0}

    // LU分解
    forward_elimination(&a)
    
    // 逆ベキ乗法
    var lambda float64 = inverse(a, x)

    fmt.Println("\neigenvalue")
    fmt.Printf("%14.10f\n", lambda)

    fmt.Println("eigenvector")
    disp_vector(x)
}

// 逆ベキ乗法
func inverse(a[N][N]float64, x0[]float64) float64 {
    var lambda float64 = 0.0

    // 正規化 (ベクトル x0 の長さを1にする)
    normarize(x0)
    var e0 float64 = 0.0
    for i := 0; i < N; i++ {
        e0 += x0[i]
    }

    for k := 1; k < 200; k++ {
        // 1次元配列を表示
        fmt.Printf("%3d\t", k)
        disp_vector(x0)

        // Ly = b から y を求める (前進代入)
        var b = []float64 {0.0 ,0.0 ,0.0 ,0.0}
        var y = []float64 {0.0 ,0.0 ,0.0 ,0.0}
        for i := 0; i < N; i++ {
            b[i] = x0[i]
        }
        forward_substitution(a,y,b)
        // Ux = y から x を求める (後退代入)
        var x1 = []float64 {0.0 ,0.0 ,0.0 ,0.0}
        backward_substitution(a,x1,y)

        // 内積
        var p0 float64 = 0.0
        var p1 float64 = 0.0
        for i := 0; i < N; i++ {
            p0 += x1[i] * x1[i]
            p1 += x1[i] * x0[i]
        }
        // 固有値
        lambda = p1 / p0

        // 正規化 (ベクトル x1 の長さを1にする)
        normarize(x1)
        // 収束判定
        var e1 float64 = 0.0
        for i := 0; i < N; i++ {
            e1 += x1[i]
        }
        if (math.Fabs(e0 - e1) < 0.00000000001) {
            break
        }

        for i := 0; i < N; i++ {
            x0[i] = x1[i]
        }
        e0 = e1
    }
    return lambda
}
// LU分解
func forward_elimination(a *[N][N]float64) {
    for pivot := 0; pivot < N - 1; pivot++ {
        for row := pivot + 1; row < N; row++ {
            var s = a[row][pivot] / a[pivot][pivot]
            for col := pivot; col < N; col++ {
                a[row][col] -= a[pivot][col] * s  // これが 上三角行列
            }
            a[row][pivot] = s                     // これが 下三角行列
        }
    }
}
// 前進代入
func forward_substitution(a [N][N]float64, y []float64, b []float64) {
    for row := 0; row < N; row++ { 
        for col := 0; col < row; col++ {
            b[row] -= a[row][col] * y[col]
        }
        y[row] = b[row]
    }
}
// 後退代入
func backward_substitution(a [N][N]float64, x []float64, y []float64) {
    for row := N - 1; row >= 0; row-- {
        for col := N - 1; col > row; col-- {
            y[row] -= a[row][col] * x[col]
        }
        x[row] = y[row] / a[row][row]
    }
}
// 1次元配列を表示
func disp_vector(row[]float64) {
    for _, col := range row {
        fmt.Printf("%14.10f\t", col)
    }
    fmt.Println("")
}
// 正規化 (ベクトルの長さを1にする)
func normarize(x[]float64) {
    var s float64 = 0.0

    for i := 0; i < N; i++ {
        s += x[i] * x[i]
    }
    s = math.Sqrt(s)
    
    for i := 0; i < N; i++ {
        x[i] /= s
    }
}
z:\go>8g GO1102.go

z:\go>8l -o GO1102.exe GO1102.8

z:\go>GO1102
  1       1.0000000000    0.0000000000    0.0000000000    0.0000000000
  2       0.7856989466   -0.6173348866   -0.0280606767   -0.0280606767
  3       0.7182768487   -0.6956539558   -0.0084835848   -0.0084835848
  4       0.7087990176   -0.7054049282   -0.0019798855   -0.0019798855
  5       0.7073894400   -0.7068237547   -0.0004242640   -0.0004242640
  6       0.7071576856   -0.7070558622   -0.0000876812   -0.0000876812
  7       0.7071163975   -0.7070971642   -0.0000178191   -0.0000178191
  8       0.7071086479   -0.7071049144   -0.0000035921   -0.0000035921
  9       0.7071071489   -0.7071064135   -0.0000007212   -0.0000007212
 10       0.7071068542   -0.7071067082   -0.0000001445   -0.0000001445
 11       0.7071067957   -0.7071067666   -0.0000000289   -0.0000000289
 12       0.7071067841   -0.7071067783   -0.0000000058   -0.0000000058
 13       0.7071067818   -0.7071067806   -0.0000000012   -0.0000000012
 14       0.7071067813   -0.7071067811   -0.0000000002   -0.0000000002
 15       0.7071067812   -0.7071067812   -0.0000000000   -0.0000000000
 16       0.7071067812   -0.7071067812   -0.0000000000   -0.0000000000

eigenvalue
  1.0000000000
eigenvector
  0.7071067812   -0.7071067812   -0.0000000000   -0.0000000000
参考文献