Gauss-Jordan 法

ガウス-ジョルダン法 ( Gauss-Jordan Method )は、連立1次方程式の解くためのアルゴリズムである.解くべき連立1次方程式を

Ax = b

と表す.右辺行列で表現した係数と左辺ベクトル(もしくは行列)をまとめた表式を拡大係数行列と呼ぶ.ここでの Gauss-Jordan 法は、拡大係数行列に対する一連の変形操作により、解を得る手法を意味する.一連の変形操作として、 行基本変形 を用いる場合と 列基本変形 を用いる場合がある.例えば、行基本変形を用いる場合、もし行列 A が正則であれば、 A の逆行列 A^{-1} を用いて、連立一次方程式は

x = A^{-1}b

へ変形することができる.この際に、使用する行基本変形は以下の3つである.

  1. 行列Aの i 行目と j 行目を入れ替える.

  2. 行列Aの i 行目を定数倍する.

  3. 行列Aの i 行目を j 行目に加える.

行に対する操作を列に対する操作へ置き換えると、列基本変形である.

Gauss-Jordan 法は、行基本変形によって方程式 Ax=bx=A^{-1}b へと変形する手法であり、連立一次方程式の解法にあたる. これは、掃き出し法 などとも呼ばれ、本質的には、中学校で習う連立方程式の解法と同じ手法である.右辺をベクトルとした拡大係数行列の場合、連立一次方程式を解くことができ、右辺を単位行列とした拡大係数行列の場合、逆行列を求めることができる.以下に、逆行列解法の数値的アルゴリズムについて解説する.

Gauss-Jordan法の数値的アルゴリズム

Gauss-Jordan法のアルゴリズムの種類として、 pivoting ( ピボット選択 ) の 種類によって、以下の 2つがある.

  • 部分 pivoting ( full pivoting 行・列、いづれかの方向で pivot 探索する )

  • 完全 pivoting ( full pivoting 行列両方向同時に pivot 探索する )

簡単のため、部分 pivoting のアルゴリズムに対して、以下に流れを示す.

  1. 行列 A を 行列 U へコピーし、連立一次方程式の解を求める場合は右辺ベクトル、逆行列を求める場合は、右辺単位行列を用意する.

  2. i=1,2,3,...,n 行目に対して、以下の操作を繰り返す.

    1. i行目の対角要素 A_{ii}A_{ij} ( j=i,i+1,...,n ) のうち、最大の値をとるものとして探索する.探索後、初期の行と異なっていれば、2つの行を交換する.

    2. i 行目を 1/A_{ii} 倍して、対角要素を 1 とする.

    3. i行目以外の全ての j=1~n 行目に対して、 i 列目要素を 0 とする.つまり、i 行目を -A_{ji} 倍して、j 行目へ加算する.

  3. n 行目までに、全ての対角要素 がゼロとならずに計算できた場合、行列 A は正則行列であり、右辺行列が A の逆行列となる.

Gauss-Jordan法のサンプルコード

Gauss-Jordan 法のサンプルコードについて、以下に示す.

main.f90
 1! ====================================================== !
 2! === Gauss Jordan Inverting Example                 === !
 3! ====================================================== !
 4program main
 5  use gausJordaMod, only : gaussJordan
 6  implicit none
 7  character(100)  , parameter   :: AmatFile = 'dat/Amat.dat'
 8  character(100)  , parameter   :: BmatFile = 'dat/Bmat.dat'
 9  double precision, allocatable :: Amat(:,:), Bmat(:,:), Cmat(:,:)
10  integer                       :: i, j, nSize
11  integer         , parameter   :: lun = 50
12
13  ! ------------------------------------- !
14  ! --- [1] Data Load                 --- !
15  ! ------------------------------------- !
16  open(lun,file=trim(AmatFile),status='old',form='formatted')
17  read(lun,*) nSize, nSize
18  allocate( Amat(nSize,nSize), Bmat(nSize,nSize), Cmat(nSize,nSize) )
19  Amat(:,:) = 0.d0
20  Bmat(:,:) = 0.d0
21  Cmat(:,:) = 0.d0
22  do i=1, nSize
23     read(lun,*) Amat(i,:)
24  enddo
25  close(lun)
26
27  ! ------------------------------------- !
28  ! --- [2] Gauss Elimination         --- !
29  ! ------------------------------------- !
30  call gaussJordan( Amat, Bmat, nSize )
31  
32  ! ------------------------------------- !
33  ! --- [3] save Results              --- !
34  ! ------------------------------------- !
35  open(lun,file=trim(BmatFile),status='replace',form='formatted')
36  write(lun,*) nSize
37  do i=1, nSize
38     write(lun,*) Bmat(i,:)
39  enddo
40  close(lun)
41  ! ------------------------------------- !
42  ! --- [4] confirm results           --- !
43  ! ------------------------------------- !
44  do i=1, nSize
45     write(6,*) Amat(i,:), ' | ', Bmat(i,:)
46  enddo
47  Cmat = matmul( Amat, Bmat )
48  do i=1, nSize
49     write(6,*) Cmat(i,:)
50  enddo
51  
52  return
53end program main
gausJordaMod.f90
 1! ====================================================== !
 2! === Gauss Jordan Method :: partial pivoting ver.   === !
 3! ====================================================== !
 4module gausJordaMod
 5contains
 6
 7  ! ========================================================== !
 8  ! === Gauss Jordan Matrix Inversion                      === !
 9  ! ========================================================== !
10  subroutine gaussJordan( Amat, Bmat, nSize )
11    implicit none
12    integer         , intent(in)  :: nSize
13    double precision, intent(in)  :: Amat(nSize,nSize)
14    double precision, intent(out) :: Bmat(nSize,nSize)
15    integer                       :: i, j, k, ipivot
16    double precision              :: Dinv, Dval, vpivot, buff
17    double precision, parameter   :: eps = 1.d-10
18    double precision, allocatable :: Umat(:,:)
19
20    ! ----------------------------------------- !
21    ! --- [1] Preparation                   --- !
22    ! ----------------------------------------- !
23    !  -- [1-1] allocate Umat               --  !
24    allocate( Umat(nSize,nSize) )
25    !  -- [1-2] Copy AMat & bvec            --  !
26    do j=1, nSize
27       do i=1, nSize
28          Umat(i,j) = Amat(i,j)
29       enddo
30    enddo
31    do j=1, nSize
32       do i=1, nSize
33          if ( i.eq.j ) then
34             Bmat(i,j) = 1.d0
35          else
36             Bmat(i,j) = 0.d0
37          endif
38       enddo
39    enddo
40    
41    ! ----------------------------------------- !
42    ! --- [2] Upper Triangular Matrization  --- !
43    ! ----------------------------------------- !
44    do k=1, nSize
45       !  -- [2-1] Partial pivot selection   -- !
46       vpivot = abs( Umat(k,k) )
47       ipivot = k
48       do j=k+1, nSize
49          if ( abs( Umat(j,k) ).gt.vpivot ) then
50             vpivot = abs( Umat(j,k) )
51             ipivot = j
52          endif
53       end do
54       if ( ipivot.ne.k ) then
55          do j=k, nSize
56             buff           = Umat(ipivot,j)
57             Umat(ipivot,j) = Umat(k     ,j)
58             Umat(k     ,j) = buff
59          enddo
60          do j=1, nSize
61             buff           = Bmat(ipivot,j)
62             Bmat(ipivot,j) = Bmat(k     ,j)
63             Bmat(k     ,j) = buff
64          enddo
65       end if
66       !  -- [2-2] Singular Matrix Detection -- !
67       if ( abs( Umat(k,k) ).lt.eps ) then
68          write(6,*) '[gaussElimin] Amat :: Singular Matrix :: No Solution End :: @ k= ', k
69          stop
70       endif
71       !  -- [2-3] For pivot row            --  !
72       !  --      a'(k,:) = a(k,:) / a(k,k) --  !
73       Dinv                = 1.d0 / Umat(k,k)
74       Umat(k,k)           = 1.d0
75       Umat(k,(k+1):nSize) = Dinv * Umat(k,(k+1):nSize)
76       Bmat(k,    1:nSize) = Dinv * Bmat(k,    1:nSize)
77       !  -- [2-4] For Non-pivot row        --  !
78       !  --      a'(j,:) = a(j,:) - a(j,k) * a(k,:) --  !
79       do j=1, nSize
80          if ( j.ne.k ) then
81             Dval            = Umat(j,k)
82             Umat(j,k:nSize) = Umat(j,k:nSize) - Dval * Umat(k,k:nSize)
83             Bmat(j,1:nSize) = Bmat(j,1:nSize) - Dval * Bmat(k,1:nSize)             
84          endif
85       enddo
86    end do
87
88    return
89  end subroutine gaussJordan
90
91end module gausJordaMod

Gauss-Jordan法のサンプル実行結果

実行結果を以下に示す.1段目に与えた行列Aとルーチンによって得られた逆行列を示している.2段目には、得た逆行列がAの逆行列であることを示すために、 AA^{-1}=E を計算している.

../../../_images/gaussJordanSampleResult.png