在 Fortran 中优化数组乘法

Optimizing array multiplication in fortran

我正在尝试在 fortran 中优化以下类型的数组乘法:

    do i = 1, n
    do j = 1, n
    do k = 1, n
            do i1 = 1, n
            do j1 = 1, n
            do k1 = 1, n
                    B(k1,j1,i1) = B(k1,j1,i1) + &
                    A(k,j,i)*v1(k,k1)*v2(j,j1)*v3(i,i1)
            enddo
            enddo
            enddo
    enddo
    enddo
    enddo

这里 A 和 B 的大小为 (n,n,n),而 v1、v2 和 v3 的大小为 (n,n)。似乎应该有某种矢量化可以让我加快这个评估。我尝试了不同的指数排序。有没有更快的计算 B 的方法?

编辑:

好的,可以使用 matmul 获得大约 10 倍的加速:

    do i = 1, n
    do i1 = 1, n
    do j = 1, n
    do j1 = 1, n
            B(:,j1,i1) = B(:,j1,i1) + &   
            matmul(A(:,j,i),v1)*v2(j,j1)*v3(i,i1)                                             
    enddo
    enddo
    enddo
    enddo

我们可以做得更好吗?

您至少可以使用 matmul 或 BLAS/LAPACK 将两个循环对减少为矩阵乘法,例如

do i1=1,n
  do i=1,n
    B(:,:,i1) = B(:,:,i1) &
            & + matmul(matmul(transpose(v1), A(:,:,i)), v2) * v3(i,i1)
  enddo
enddo

您几乎肯定可以通过缓存双 matmul 的结果来进一步加快速度,例如

real :: intermediate(n,n,n)

do i=1,n
  intermediate(:,:,i) = matmul(matmul(transpose(v1), A(:,:,i)), v2)
enddo

do i1=1,n
  do i=1,n
    B(:,:,i1) = B(:,:,i1) + intermediate(:,:,i) * v3(i,i1)
  enddo
enddo

这可能反过来会被更多 matmul 加速,例如

real :: intermediate(n,n,n)

do i=1,n
  intermediate(:,:,i) = matmul(matmul(transpose(v1), A(:,:,i)), v2)
enddo

do j1=1,n
  B(:,j1,:) = matmul(intermediate(:,j1,:), v3))
enddo