我有3个阵列,我必须做这个总结 实现的代码是 do i=1,320 do j=1,320 do k=1,10 do l=1,10 do m=1,10 do r=1,10 do s=1,10 sum=sum+B(k,l,r,s,m)*P(i,j,r,s,m) end do end do A(i,j,k,l,m)=sum end do end do end do end doend do 执行代码
实现的代码是
do i=1,320 do j=1,320 do k=1,10 do l=1,10 do m=1,10 do r=1,10 do s=1,10 sum=sum+B(k,l,r,s,m)*P(i,j,r,s,m) end do end do A(i,j,k,l,m)=sum end do end do end do end do end do
执行代码需要1天.
有没有办法优化它?
谢谢.
这些事情的诀窍是寻找常见的模式,并使用现有的有效例程来加速它们.像往常一样,M.S.B是完全正确的,只是翻转你的指数会给你大幅加速,虽然具有高优化的英特尔fortran编译器已经给你带来了一些好处.
但是让我们将m指数剥离一秒钟(这很容易做到,正如MSB所指出的那样,这是最慢的指数)并且只看一下乘法:
Ai,j,k,l = ∑ Bk,l,r,s × Pi,j,r,s
Ai,j,k,l = ∑ Pi,j,r,s × Bk,l,r,s
重塑数组:
Aij,kl = ∑ Pij,rs × Bkl,rs
Aij,kl = ∑ Pij,rs × BTrs,kl
A = P × BT
我们现在有矩阵乘法,其中存在非常有效的例程.因此,如果我们重塑P和B矩阵并转置B,我们可以进行简单的矩阵乘法并重塑结果;在这种情况下,这种重塑甚至不一定需要任何副本.所以改变这样的事情:
program testpsum implicit none integer, dimension(10,10,10,10,10) :: B integer, dimension(32,32,10,10,10) :: P integer, dimension(32,32,10,10,10) :: A integer :: psum integer :: i, j, k, l, m, r, s B = 1 P = 2 do i=1,32 do j=1,32 do k=1,10 do l=1,10 do m=1,10 do r=1,10 do s=1,10 psum=psum+B(k,l,r,s,m)*P(i,j,r,s,m) end do end do A(i,j,k,l,m)=psum psum = 0 end do end do end do end do end do print *,minval(A), maxval(A) end program testpsum
对此:
program testmatmult implicit none integer, dimension(10,10,10,10,10) :: B integer, dimension(32,32,10,10,10) :: P integer, dimension(10*10,10*10) :: Bmt integer, dimension(32*32,10*10) :: Pm integer, dimension(32,32,10,10,10) :: A integer :: m B = 1 P = 2 do m=1,10 Pm = reshape(P(:,:,:,:,m),[32*32,10*10]) Bmt = transpose(reshape(B(:,:,:,:,m),[10*10,10*10])) A(:,:,:,:,m) = reshape(matmul(Pm,Bmt),[32,32,10,10]) end do print *,minval(A), maxval(A) end program testmatmult
给出时间:
$time ./psum 200 200 real 0m2.239s user 0m1.197s sys 0m0.008s $time ./matmult 200 200 real 0m0.064s user 0m0.027s sys 0m0.008s
当使用ifort -O3 -xhost -mkl编译时,我们可以使用fast intel MKL库.如果你没有创建临时的Pm并且只是在matmult调用中进行重新整形,那么它会变得更快,如果对线程例程使用-mkl = parallel,则更快(对于大型矩阵).如果您还没有MKL,您可以链接到其他一些快速LAPACK _GEMM例程.