多次元配列#

多次元配列は列優先順序で格納されます。これは、最左(最内側)インデックスが要素を連続的にアドレスすることを意味します。実際的には、配列スライス V(:, 1) は連続しているが、スライス V(1, :) 内の要素間のストライドは列の次元になることを意味します。これは、連続データを処理することを期待している手続きに配列スライスを渡す場合に重要です。

メモリの局所性は、アプリケーションに応じて考慮することが重要です。通常、多次元に対して演算を実行する場合、逐次アクセスは常に 1 ステップのストライドで進む必要があります。

以下の例では、 2 組の点間の逆距離が評価されます。点は配列 xyz1/xyz2 に連続的に格納されていますが、内側のループは行列 a の最左インデックスを進めています。

subroutine coulomb_matrix(xyz1, xyz2, a)
  real(dp), intent(in) :: xyz1(:, :)
  real(dp), intent(in) :: xyz2(:, :)
  real(dp), intent(out) :: a(:, :)
  integer :: i, j
  do i = 1, size(a, 2)
    do j = 1, size(a, 1)
      a(j, i) = 1.0_dp/norm2(xyz1(:, j) - xyz2(:, i))
    end do
  end do
end subroutine coulomb_matrix

もう 1 つの例として、ランク 3 配列の 3 番目の次元の収縮があります。

do i = 1, size(amat, 3)
  do j = 1, size(amat, 2)
    do k = 1, size(amat, 1)
      cmat(k, j) = cmat(k, j) + amat(k, j, i) * bvec(i)
    end do
  end do
end do

連続的な配列スライスは、配列バウンド remapping で使用でき、より高いランクの配列をより低いランクの配列として使用できるようにし、配列の形状変更や一時コピーの作成が不要になります。

たとえば、これを使用して、行列ベクトル演算を使用してランク 3 配列の 3 番目の次元を収縮できます。

subroutine matmul312(amat, bvec, cmat)
  real(dp), contiguous, intent(in), target :: amat(:, :, :)
  real(dp), intent(in) :: bvec(:)
  real(dp), contiguous, intent(out), target :: cmat(:, :)
  real(dp), pointer :: aptr(:, :)
  real(dp), pointer :: cptr(:)

  aptr(1:size(amat, 1)*size(amat, 2), 1:size(amat, 3)) => amat
  cptr(1:size(cmat)) => cmat

  cptr = matmul(aptr, bvec)
end subroutine matmul312