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 do1つめと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.000000000000010分悩んで出来なかったら、一度答えを見てから再挑戦してください。 自分で手順を整理できるよう、理解して練習することが大事です。
>>解答