I want to compute the summation more efficient. There are nested loops, which I want to avoid.
! If i j <= I,then A_{j} = \sum_{m,n,i} C_{m, i j} G_{ m, n, i, j} C_{n, i}
! else if i j >= I, then A_{j} = \sum_{m,n,i} C_{m, i j-I} G_{ m, n, i, j} C_{n, i}
program main
implicit none
real, allocatable :: A(:)
real, allocatable :: C(:,:), G(:,:,:,:)
integer :: i, j, m, n
integer, parameter :: N = 1500, I = 2000
allocate(A(J))
allocate(C(N,I))
allocate(G(N,N,I,I))
! If i j <= I,then
! A_{j} = \sum_{m,n,i} C_{m, i j} G_{ m, n, i, j} C_{n, i}
! else if i j >= I, then
! A_{j} = \sum_{m,n,i} C_{m, i j-I} G_{ m, n, i, j} C_{n, i}
do j = 1, I
do i = 1, I
if ( i j <= I ) then
do n = 1, N
do m = 1, N
A(j) = A(j) C(m,i j) * G(m,n,i,j) * C(n,i)
end do
end do
else
do n = 1, N
do m = 1, N
A(j) = A(j) C(m,i j-I) * G(m,n,i,j) * C(n,i)
end do
end do
end if
end do
end do
end program main
CodePudding user response:
Let's start by addressing @francescalus' comment, and rename I
and N
. Let's call them II
and NN
. No, this is not a good naming convention, but I don't know what these variables actually are.
Let's also assume you've initialised your variables, as per @lastchance's comment.
The first thing that leaps out is the lines
do j=1,II
do i=1,II
if (i j <= II) then
...
else
...
this loop-with-an-if-inside can be replaced with a couple of loops with no if, which is usually a good idea. Something like:
do j=1,II
do i=1,II-j
...
end do
do i=II-j 1,II
...
end do
Now let's use matmul to clean up the loops over m
and n
, something like:
do j=1,II
do i=1,II-j
A(j) = A(j) dot_product(matmul(C(:,i j), G(:,:,i,j)), C(:,i))
end do
do i=II-j 1,II
A(j) = A(j) dot_product(matmul(C(:,i j-I), G(:,:,i,j)), C(:,i))
end do
end do
Note that this isn't doing any less work than your code (and indeed, since you're looping over all four indices of G
, doing less work doesn't look possible), but it should at least do the work a little more efficiently.