【入門編】WHERE構文とFORALL構文の並列実行特性 – モダンFortran言語仕様と実践実践マスター

「配列演算の魔法」を解き明かす:WHEREとFORALLの現場的流儀

こんにちは。かつて巨大なロケットの軌道計算や、流体解析のコードと格闘し続けてきた元アーキテクトです。

CやPythonからFortranの世界に飛び込んできた皆さん、ようこそ。Fortranは「古い」と言われがちですが、実は「メモリの物理配置とハードウェアの性能を直結させる」という点において、未だに右に出るものがない最強の物理演算ツールです。

今日は、Fortranにおける配列操作の強力な武器である`WHERE`と`FORALL`について、教科書には載っていない「現場の裏側」を語りましょう。

1. WHERE構文:条件分岐という名の「マスク」

PythonのNumPyを使っている方なら、`arr[arr > 0] = 1`のような書き方はお馴染みですよね。Fortranでこれを行うのが`WHERE`構文です。

! 負の値をゼロにクリッピングする処理
WHERE (A < 0.0) A = 0.0 ELSEWHERE A = A 0.5 END WHERE

なぜこれが「速い」のか?

C言語でこれを書くと`if`文による分岐がループ内に発生します。しかし、`WHERE`はコンパイラに対して「条件に一致する要素だけを対象にしたSIMD(ベクトル)演算を生成せよ」という強力なヒントを与えます。

現場での注意点は一つ。`WHERE`はあくまで「マスク処理」です。条件に合致しない要素を無視して演算を進めるため、複雑な条件分岐を入れ子にすると、CPUのパイプラインが乱れ、かえって効率が落ちることがあります。「単純な条件で、広大な配列を叩く」時こそが、`WHERE`の本領発揮です。

2. FORALL構文:コンパイラへの「並列化のサイン」

次に、`FORALL`です。これは「複数の要素を独立して計算できる」ことをコンパイラに宣言するための構文です。

! 2次元配列の全要素にインデックスを使った演算を行う
FORALL (i = 1:N, j = 1:M)
A(i, j) = B(i, j) + C(j, i) ! 転置のようなアクセスも記述可能
END FORALL

ここが極限のポイント:DOループとの違い

初心者がよく陥る罠が「`FORALL`は単なる`DO`ループの省略形だ」という勘違いです。全く違います。

  • DOループ:基本的には順次実行。前の計算結果を次のステップで使う(依存関係がある)処理に適している。
  • FORALL全要素が同時に計算されることを想定している。

コンパイラはこの「同時に計算しても安全」という保証を利用して、マルチコアCPUやGPUへ演算をオフロード(自動並列化)します。もし皆さんが`FORALL`の中で`A(i) = A(i-1) + 1`のような「前の値が必要な処理」を書くと、並列化が破壊されるか、あるいは予測不能な挙動を引き起こします。

「FORALLは独立した計算の集まりである」。このルールを死守してください。

3. 現場で生き残るための「メモリ配置」の鉄則

どれほど`WHERE`や`FORALL`を駆使しても、メモリのアクセス順序を間違えると全てが台無しになります。Fortranは「列優先(Column-major)」です。

! 高速:メモリ上で連続する領域を順に叩く
FORALL (j = 1:M, i = 1:N)
A(i, j) = …
END FORALL

逆に、内側のループを`j`にしてしまうと、メモリ上で飛び石状にアクセスが発生し、キャッシュミスが多発します。最新のCPUであっても、キャッシュラインの効率的な利用は演算速度を10倍以上変えます。「配列の左側の添字を高速に回す」。この泥臭い鉄則は、どんなに高度な構文を使っても変わりません。

4. コンパイラに「本気」を出させるビルド設定

最後に、実際にコードをビルドする際の魔法の言葉を授けます。Intel Fortran (`ifort`/`ifx`) を使う場合、以下のようなフラグを試してみてください。

現場での最適化例
ifx -O3 -xHost -qopenmp -parallel -qopt-report=5 source.f90

  • `-O3`: 言語仕様の限界まで最適化を行う。
  • `-xHost`: 実行環境のCPUアーキテクチャに特化した命令(AVX-512など)をフル活用する。
  • `-parallel`: 自動並列化を有効にする。
  • `-qopt-report=5`: コンパイラがどこをベクトル化し、どこで挫折したかを詳細なレポートで出力してくれる。(これを見ないと一人前とは言えません!)

最後に:皆さんへ

`WHERE`や`FORALL`を使うことは、単にコードを短くするためではありません。コンパイラという「超優秀な相棒」に対して、「ここは並列化しても安全だぞ」「ここはベクトル演算に最適だぞ」という明確な意図を伝えるコミュニケーションなのです。

最初は戸惑うこともあるでしょう。でも、その違和感こそが、皆さんが「ただ動くコード」から「物理現象を高速に再現するコード」へと成長している証です。

まずは小さな配列で、レポート出力を見ながら遊んでみてください。Fortranの世界へようこそ。一緒に計算の限界を突き詰めましょう!

コメント

タイトルとURLをコピーしました