言語要素の概要2(cont'd)

配列(多次元)

ベクトル(1次元)に対して行列やテンソル(2次元以上)があるように,配列にも1次元配列に対して多次元配列というものがある.

多次元配列の宣言

1次元配列と基本的には変わらない.いろいろな方法がある.

real, dimension(1:100, 1:100):: data1
real, dimension(100,   100  ):: data1_b

  !pattern2 : fortran90 only
real :: data2  (1:100, 1:100, 1:100)
real :: data2_b(100,   100,   100  )

  !pattern 3
real data3  (1:100, 1:100, 1:100, 1:5)
real data3_b(100,   100,   100,   5))

  !pattern 4
real data4
dimension(100, 4, 4) data4

配列は,たとえばdata1(2, 5)のようにコンマで添え字を区切って表す.

配列と代入:1

配列の各要素(a(4, 3, 2)など)への代入は,ただ単純に「a(4,3,2)=4.」のように行えばよい.この点では一次元配列と同じ.

配列と代入:2

多次元配列でも当然部分配列が使用可能である.

部分配列の表現方法は,一次元配列と同様に「配列名(添字最初:添字最後:ステップ, 最初:最後:ステップ,...)」である.ただし最初も最後も省略することもでき,その場合は元の配列の添字下限・同上限となる.ステップも省略可能.

部分配列は普通の配列と同じように,演算・代入が可能.

integer:: x(5, 5), a(5), b(5), c(3, 3)

! 4th column of x --> a

a(1:5) = x(:, 4:4)   ! ":" means "1:5"

! 3rd row of x --> b

b      = x(3, :)

!
! partial array substitution
!

c = a(1:3, 2:4)

このように高次元の配列から低次元の配列を抜き取ったり逆に代入したりする操作は基本中の基本である(行列からベクトルを抜き出すなど).

配列の演算

配列要素間の演算は,一次元配列と同様に行えるが,現実には行列計算・内積外積計算など,「要素間計算」にとどまらない機能が必要になる場合が多いだろう.そういうときには[1]組み込み配列関数を用いる[2]自前で関数やサブルーチンを書く といった手法が必要になる.

配列の入出力

多次元配列の入出力のとき,例えばprint *, aと配列全体を書き出したときの要素の順序はどうなるのだろうか.2次元配列で試してみよう.


実行例:
& ./a.out
 d(1, 1) = 11
 d(1, 2) = 12
 d(1, 3) = 13
 d(2, 1) = 21
 d(2, 2) = 22
 d(2, 3) = 23
 d(3, 1) = 31
 d(3, 2) = 32
 d(3, 3) = 33
 print all...
 11,  21,  31,  12,  22,  32,  13,  23,  33
つまり,要素の順番は

     第二添字
    1   2   3
  +---+---+---
第 1| 1 | 4 | 7
一 +---+---+---
添 2| 2 | 5 | 8
字 +---+---+---
  3| 3 | 6 | 9

と並んでいる.なんとなく,d(1,1)の次にd(1,2)がかかれそうな気がするが違うのである.より前にある添え字のほうがより「小さく回転」するのである(ここはCとは根本的に異なるところである.).

print *, aで全体を書き出した配列を,別の機会にDO文で一つ一つの要素を読み直すという場合には注意が必要である.

明示的に,どこにどの値が入るか確定したい場合にはこういう書き方がお薦め.要するにすべて一次元に落とし込んで書く.

b(1,1:3) = (/ 11, 12, 13 /)
b(2,1:3) = (/ 21, 22, 23 /)
b(3,1:3) = (/ 31, 32, 33 /)

配列関数

さすがFORTRAN,配列関数には強烈なものが揃っている.

名前 意味 戻り値
ALL(m[,DIM]) LOGICAL型配列mの(DIM番目の添え字方向の)要素が全て.TRUE.のとき真,そうでなければ.FALSE.となる要素で出来た配列(ないしスカラ)を返す LOGICAL配列またはLOGICAL値
ALLOCATED(a) ALLOCATABLE配列(後述)aがすでにALLOCATEされているかどうか LOGICAL値
ANY(m[,DIM]) 配列mの(多次元配列の場合DIM番目の次元の)要素のうち一つでも.TRUE.なら.TRUE., そうでなければ.FALSE.を返す LOGICAL型
CSHIFT(a,s[,DIM]), EOSHIFT(a,s[,DIM]) 添え字をsだけシフトする.CSHIFTの場合はcircular,EOSHIFTの場合ははみ出た分を切り捨て.多次元配列の場合は,DIM番目の添え字方向. mと同じサイズの配列
COUNT(m[,DIM]) LOGICAL型配列mの(DIM番目次元方向の)要素のうち.TRUE.であるものの個数. integer
DOT_PRODUCT(u,v), MATMUL(a,b) 一次元配列u,vの内積,行列a,bの積 実数,配列
LBOUND(a[,DIM]), UBOUND(a[,DIM]) 配列aの(DIM番目次元の)添え字の下限と上限 integer
MAXLOC(a[,MASK]), MINLOC(a[,MASK]) 配列aの(LOGICAL型配列MASKが真である位置の)要素のうち最大値/最小値をとるものの位置を表す配列を返す.例:a(1,2,5)が最大値なら(/ 1, 2, 5 /)を返す. aのRANKと同じサイズの1次元配列
MAXVAL(a[,DIM,MASK]), MINVAL(a[,DIM,MASK]) 行列aのDIM番目次元方向要素の最大値or最小値を配列とする行列(aが1次元ならスカラ)を返す (aのランク-1)次元の行列
MERGE(t,f,m) mはLOGICAL型の配列.mの要素が.TRUE.のときは行列tから,.FALSE.の時には行列fからそれぞれ要素をもってきた新しい配列を作る t,fと同じサイズ・型の配列
PACK(a,m), UNPACK(v, m, f) PACK:LOGICAL型配列mに従って,配列aの要素から1次元配列を作る.UNPACK:LOGICAL型配列mに従って,1次元配列vを移動してfと同じサイズの配列をつくり,mが.FALSE.である位置にはfの要素をそのまま入れる. 位置次元配列/fと同じSHAPEの配列
PRODUCT(a[,DIM,MASK]), SUM(a[,DIM,MASK]) 配列aの(LOGICAL型配列MASKの要素が.TRUE.である位置の)要素の積や和 スカラ
RESHAPE(a,s) 配列aの要素を,配列sで表される形状(SHAPE関数参照)に従って並べ替え,新しい配列を作る sでSHAPEが表される配列
SHAPE(a), SIZE(a[,DIM]) SHAPE:配列aの寸法(多次元の場合,各次元の寸法を要素とする配列), SIZE:配列Aの(DIM番目次元の)サイズ.DIMが指定されないときは全要素数.
SPREAD(a,DIM,n) 配列aを,DIM番目の次元方向にn回繰り返した,aより1次元高い配列を作る (aのRANK+1)次元の配列
TRANSPOSE(a) 2次元配列の転置行列を返す 2次元配列

AGATASHI