4日目「行列・ベクトル」:準備

能書き

コンピュータは連続な変数を扱うことができないので、 物理の問題はしばしば離散化してから扱うことになります。
このとき、行列やベクトル(線形代数)は強力なツールとなるため、 コンピュータ上で自在に操れなければなりません。
今のうちに練習して、感覚をつかんでおきましょう。

ファイルを作る

program day4
 !------------------------
 ! Fortran template
 !------------------------
 implicit none
 integer, parameter :: double=selected_real_kind(15)
 !--- begin header ---

 !--- end header ---
 !--- begin main ---
  
 !--- end main ---
end program
Lesson 11. 配列

定義:ベクトル・行列の宣言

n成分のベクトルは『変数名(n)』、m x nの行列は『変数名(m,n)』として宣言する。
 型 :: ベクトル変数名(indexの上限)
 型 :: 行列変数名(index1の上限,index2の上限)
例)3成分の倍精度実数型ベクトル『avec』、2 x 2の倍精度実数型行列『Amat』を宣言
 real(kind=double) :: avec(3), Amat(2,2)
変数名の大文字小文字は区別しません。なので、行列『A』とスカラー変数『a』を同時に宣言することはできません。

定義:ベクトル・行列を使う

ベクトル・行列は「配列」という変数の集合であって、普通の変数とは扱いが異なる。
 ベクトル・行列は、『配列名(i,j)』のように要素のindexを指定することで、
 普通の変数と同じように使うことが出来る。
例)行列『Amat』の (1行, 2列) 成分に『0』を代入
 Amat(1,2) = 0
たとえ中身が1成分しか無くても、「値」を持てるのは「配列『a』」ではなく、「配列の1つめの成分『a(1)』」です。

学習

普通の変数との違いに注意しながら下のプログラムをよく読んで、 実行してみましょう。
 integer :: i, j
 real(kind=double) :: rvec(3), Amat(2,2)
 
 !--- vector r ---
 do i=1,3
    rvec(i) = i
 end do
 print *, "x = ", rvec(1)
 print *, "y = ", rvec(2)
 print *, "z = ", rvec(3)

 !--- matrix A ---
 do i=1,2
    do j=1,2
       Amat(i,j) = i+2.0d0*j
    end do
 end do
 do i=1,2
    do j=1,2
       print *, "A(",i,",",j,") =", Amat(i,j)
    end do
 end do
 x =    1.00000000000000     
 y =    2.00000000000000     
 z =    3.00000000000000     
 A(           1 ,           1 ) =   3.00000000000000     
 A(           1 ,           2 ) =   5.00000000000000     
 A(           2 ,           1 ) =   4.00000000000000     
 A(           2 ,           2 ) =   6.00000000000000
『do』文が2つ、続けて出てくる部分がありますね。 これも確実に理解してほしいポイントなので、次で詳しく説明します。
Lesson 12. 多重ループ

学習: 多重ループ

 ループは多重構造にすることができる。
 このとき、内側のループが、外側のループにより繰り返し実行される。
ループの内側にループを作ることを「多重ループ」と言います。
このあたりからプログラムの構造が複雑になってきますが、
行列を扱うには必要不可欠なので頑張ってマスターしましょう。
例えば
 do i=1,n
    do j=1,m
       {処理}
    end do
 end do
だと、『n』x『m』回、{処理}を繰り返します。
内側のループ変数、この例の場合だと『j』が先に変化することに注意して下さい。
すなわち、(i,j)=(1,1),(1,2),...,(1,m),(2,1),(2,2),...,(n,m)という順番になります。
「iとjの両方が変わるんだな」と、なんとなく理解するだけではプログラミングは上達しません。 内側と外側の実行の順番を意識して、変数の値の変化を正しく追えるようにしましょう。

実践

単位行列を定義するプログラムを作ってみましょう。
 integer :: i, j
 real(kind=double) :: Imat(3,3)
 
 do i=1,3
    do j=1,3
       Imat(i,j) = 0.0d0
    end do
 end do
 do i=1,3
    Imat(i,i) = 1.0d0
 end do
 print *, "Imat"
 do i=1,3
    print *, Imat(i,1), Imat(i,2), Imat(i,3)
 end do
1つめと2つめの(2重)ループで全成分を『0』にしてから、3つめのループで対角成分のみ『1』にしています。
 Imat
   1.00000000000000       0.000000000000000E+000  0.000000000000000E+000
  0.000000000000000E+000   1.00000000000000       0.000000000000000E+000
  0.000000000000000E+000  0.000000000000000E+000   1.00000000000000     
行列の「成分」を扱う感覚はつかめましたか?
ちなみに、『Imat=1.0d0』は単位行列とは全く別の意味になります。

問題3:行列積を求めるプログラムを作りなさい。

ループを駆使して、行列積を求めてみましょう。
 integer :: i, j, k
 real(kind=double) :: Amat(3,3), Bmat(3,3), Cmat(3,3)

 do i=1,3
    do j=1,3
       Amat(i,j) = 1.0d0*i
       Bmat(i,j) = 3.0d0*i-1.0d0*j
    end do
 end do
 !{ここで C = A B を求める}
 print *, "Cmat is"
 do i=1,3
    print *, Cmat(i,1), Cmat(i,2), Cmat(i,3)
 end do
初めての人には結構難問なので、まずは紙の上で手計算してみるといいかもしれません。問題を解く「手順」をしっかり理解しておくことが重要です。
ヒント:Cmatの(1,1)成分は、Amatの(1,1)成分とBmatの(1,1)成分を掛けたもの足す・・・、これをひたすら続ける。
『Cmat=Amat*Bmat』ではダメですよ。念のため。
結果が下のようになれば成功です。
 Cmat is
   15.0000000000000        12.0000000000000        9.00000000000000     
   30.0000000000000        24.0000000000000        18.0000000000000     
   45.0000000000000        36.0000000000000        27.0000000000000     
10分悩んで出来なかったら、一度答えを見てから再挑戦してください。 自分で手順を整理できるよう、理解して練習することが大事です。
>>解答