FORALL

文と構文FORALL 文と FORALL 構文は,Fortran 95/90 の配列選別代入 (WHERE 文および構文) を一般化したものです。これにより,より一般的な配列形状を,特に構文形式で代入することが可能になります。

FORALL は Fortran 95 の機能です。

形式

FORALL (triplet-spec [,triplet-spec]...[,mask-expr]) assignment-stmt

構文

[name:] FORALL (triplet-spec [,triplet-spec]...[,mask-expr])

forall-body-stmt
[forall-body-stmt]...
END FORALL [name]

triplet-spec
次の形式を持つ三つ組宣言。

subscript-name = subscript-1 : subscript-2 [:stride]

subscript-name は整数型のスカラでなくてはなりません。これは FORALL の有効範囲中でのみ有効で,その値は FORALL の完了時に不定となります。

subscriptstride は,triplet-spec 中の subscript-name 引用を含むことはできません。

stride はゼロであってはなりません。これが省略された場合,基本値は 1 です。

三つ組宣言中の式の評価は,他の三つ組宣言中の他の式の評価結果に影響を与えてはなりません。

mask-expr
論理配列式 (選別式と呼ばれます)。これが省略されたときには,値 .TRUE. が使用されます。選別式は triplet-spec 中の添字名を引用することができます。

assignment-stmt
代入文またはポインタ代入文。代入先の変数は,配列要素または部分配列でなくてはならず,すべての triplet-spec に含まれているすべての添字名を引用しなくてはなりません。代入される式は文字式であってはなりません。

name
FORALL 構文の名前。

forall-body-stmt
以下のいずれか。

規則と振る舞い

FORALL 文で構文名が宣言されている場合,同じ名前が対応する END FORALL 文に含まれていなくてはなりません。

FORALL 文の実行にあたっては,まず個々の添字名の値の組が与えられ,三つ組宣言中のすべての境界および刻み幅式が評価されます。FORALL 代入文は,選別式が真である添字名の値のすべての組み合わせについて実行されます。

FORALL 代入文が実行されるとき,左辺のどこかの部分が変更される前に,(代入の両辺の) すべての式が完全に評価されます。有効な値は,代入先の配列の対応する要素に代入されます。配列中の 1 つの要素に値が複数回代入されることはありません。

FORALL 構文は,同じ三つ組宣言と選別式を持つ FORALL 文が複数存在するかのように実行されます。FORALL 本体の個々の文は,次の FORALL 本体の文の実行が開始される前に,完全に実行されます。

選別式または FORALL 代入文で引用されている手続はすべて純粋でなくてはなりません。純粋関数は,選別式の中で使用したり,FORALL 文の中で直接に呼び出すことができます。純粋サブルーチンは FORALL 文の中で直接に呼び出すことはできませんが,他の純粋手続から呼び出すことはできます。

以下の例は,配列構文を使っては表現できない配列の対角線要素を 1 に設定しています。

	REAL, DIMENSION(N, N) :: A
	FORALL (I=1:N)  A(I, I) = 1

次の例を考えます。

	FORALL(I = 1:N, J = 1:N, A(I, J) .NE. 0.0) B(I, J) = 1.0 / A(I, J)

この文は,配列 A(1:N, 1:N) の中の非ゼロ要素の逆数を,配列 B の対応する要素に代入します。A の要素のうち,ゼロであるものについては,逆数は計算されず,B の対応する要素への代入も行われません。

すべての配列代入文と WHERE 文は FORALL 文として書くことができますが,一部の FORALL 文は配列構文だけでは書くことができません。たとえば,上の FORALL 文は次のものと等価です。

	WHERE(A /= 0.0) B = 1.0 / A

これはまた次のものとも等価です。

	FORALL (I = 1:N, J = 1:N)
	  WHERE(A(I, J) .NE. 0.0) B(I, J) = 1.0/A(I, J)
	END FORALL

しかしながら,次の FORALL の例は,配列構文だけでは書くことはできません。

	FORALL(I = 1:N, J = 1:N) H(I, J) = 1.0/REAL(I + J - 1)

この文は,1 から N までの IJ の値について,配列要素 H(I,J) を値「1.0/REAL(I + J - 1)」に設定します。

次の例を考えます。

	TYPE MONARCH
	  INTEGER, POINTER :: P
	END TYPE MONARCH

	TYPE(MONARCH), DIMENSION(8)   :: PATTERN
	INTEGER, DIMENSION(8), TARGET :: OBJECT
	FORALL(J=1:8)  PATTERN(J)%P => OBJECT(1+IEOR(J-1,2))

この FORALL 文により,配列 PATTERN の要素 1 ~ 8 は,それぞれ OBJECT の要素 3,4,1,2,7,8,5,および 6 を指すように設定されます。ここで IEOR を引用することができるのは,これが純粋関数だからです。

次の例は FORALL 構文を示しています。

	FORALL(I = 3:N + 1, J = 3:N + 1)
	  C(I, J) = C(I, J + 2) + C(I, J - 2) + C(I + 2, J) + C(I - 2, J)
	  D(I, J) = C(I, J)
	END FORALL

配列 D への代入には,構文が実行を開始される前の C の値ではなく,構文中の最初の文で計算された C の値が使われます。