導入:なぜ「共次元」が必要なのか
並列プログラミングにおいて、計算領域を分割して複数のCPU(像)で処理を分担する手法は非常に一般的です。しかし、単純な1次元の配列で像を管理しようとすると、「自分の隣はどの像か?」という計算が複雑になりがちです。ここで登場するのが共次元(Codimension)です。これを使うことで、物理的な3次元格子などを論理的な座標として扱うことができ、通信アルゴリズムを劇的にシンプルに記述できるようになります。
基礎知識:共次元とは何か
Fortranの共配列(Coarray)における「像(Image)」は、デフォルトでは1次元的に番号が振られています。しかし、`[px, py]` のように複数の次元を指定して像を配置することを「共次元」と呼びます。
例えば、行列を分割する際に、1次元で並べるよりも2次元(行方向と列方向)で配置したほうが、上下左右の隣接する像を `a[i, j]` というインデックスで指定できるため、直感的でミスが少なくなります。
実装:共次元の設定方法
共次元の設定は、変数宣言の最後に角括弧 `[]` を使って行います。
例:`real :: grid(n, n)[2, ]`
この指定により、像を2列の格子状に並べた状態として扱えます。“ は「アスタリスク」と呼ばれ、次元数を自動的に補完する役割があります。これにより、像の総数に合わせて柔軟にレイアウトを決定できます。
サンプルプログラム
以下は、2次元的に配置された像の間で、隣接する像のデータを取得するイメージのコードです。
! 2行2列の像(合計4像)で実行することを想定
program codimension_example
use iso_fortran_env
implicit none
! 2x2の像配置を指定(各像が1つの値を持つ)
real :: my_val[2, 2]
real :: neighbor_val
integer :: row, col
! 自分の像番号を2次元座標に変換
row = this_image(my_val, 1)
col = this_image(my_val, 2)
! 自分の値を初期化
my_val = real(row + col)
! 右側の像(列番号+1)の値を取得
if (col < 2) then
! [row, col+1] という論理座標で通信が可能
neighbor_val = my_val[row, col + 1]
print , "像(", row, ",", col, ")の右隣の値は:", neighbor_val
else
print , "像(", row, ",", col, ")には右隣がいません"
end if
end program codimension_example
応用・注意点:現場での運用テクニック
共次元を利用する際は、以下の点に注意してください。
1. 像の総数と共次元の整合性
指定した共次元の積が、実行時の像の総数と一致しない場合、実行時エラーが発生します。`` を使って調整するか、実行時に `num_images()` を取得して動的に計算レイアウトを決定するのが安全です。
2. 通信の同期
`my_val[row, col + 1]` のようにデータを取得する際、相手側の像がその値を書き込み済みであることを保証する必要があります。必ず `sync images(target_image)` や `sync all` を適切に使用して、競合を防ぐようにしてください。
3. 境界条件の処理
今回紹介したようなグリッド状の配置は、境界(端っこ)の処理が重要です。ループ構造を工夫し、端の像では通信を行わない等の条件分岐を正確に記述することで、堅牢な並列プログラムが構築できます。

コメント