views:

158

answers:

3

Hi,

I have a p*p*n array in Fortran, and I want to extract k*k subarray from that bigger array. I tried like this, but not sure does it work:

do i=1,p
     vp(i)=i
end do
help=y(1:p,t)*vp
do t = 1, n
  A(1:k,1:k,t) = B(pack(help,help>0), pack(help,help>0), t)
end do

where y contains values 0 and 1, 1 meaning that row/column is wanted to subarray. Does that work, and if not, how that same thing could be archieved? Thanks.

A: 

If I understand what you want to do, here is an example program that extracts selected columns and rows, but not using much array notation.

program test

integer, parameter :: Adim = 2
integer, parameter :: Bdim = 3
integer, dimension (Adim,Adim) :: A
integer, dimension (Bdim,Bdim) :: B
logical, dimension (Bdim) :: good_row = [.true., .false., .true.]
logical, dimension (Bdim) :: good_col = [.false., .true., .true.]
integer :: i, j, ia, ja, ib, jb


if (count (good_row) /= Adim  .or.  count (good_col) /= Adim) then
   write (*, *) 'selection arrays not setup correctly.'
   stop
end if

do i=1, Bdim
   do j=1, Bdim
      B (i,j) = i + i*j**2  ! test values
   end do
end do

do i=1, Bdim
   write (*, *) (B (i, j), j=1, Bdim)
end do

ia = 0
do ib=1, Bdim
  if (good_row (ib)) then
     ia = ia + 1
     ja = 0
     do jb=1, Bdim
        if (good_col (jb)) then
           ja = ja + 1
           !write (*, *) ia, ja, ib, jb
           A(ia,ja) = B(ib,jb)
        end if
     end do
  end if
end do

write (*, *)
do i=1, Adim
   write (*, *) (A (i, j), j=1, Adim)
end do

stop
end program test
M. S. B.
A: 

Solution two, using array operations at the vector (1D array) level -- replace the main loop with:

ia = 0
do ib=1, Bdim
  if (good_row (ib)) then
     ia = ia + 1
     A (ia,:) = pack (B(ib,:), good_col)
  end if
end do

Solution three, fully using array operations:

program test

integer, parameter :: Adim = 2
integer, parameter :: Bdim = 3
integer, dimension (Adim,Adim) :: A
integer, dimension (Bdim,Bdim) :: B
logical, dimension (Bdim,Bdim) :: mask
integer :: i, j

mask (1,:) = [.false., .true., .true.]
mask (2,:) = .false.
mask (3,:) = [.false., .true., .true.]


do i=1, Bdim
   do j=1, Bdim
      B (i,j) = i + i*j**2  ! test values
   end do
end do

do i=1, Bdim
   write (*, *) (B (i, j), j=1, Bdim)
end do

A  = reshape ( pack (B, mask), [Adim, Adim] )

write (*, *)
do i=1, Adim
   write (*, *) (A (i, j), j=1, Adim)
end do

stop
end program test
M. S. B.
A: 

Hi

Not sure if these fragments of non-code are any use to you but;

  • Don't forget the array sectioning features of Fortran.
  • Don't forget that you can use vector subscripts to get array sections, for example, you might select elements of a vector v like this:

    v( (/1, 3, 6, 5, 10 /) )

Vector subscripting can be applied to arrays of rank greater than 1. It would hurt my head to figure out your subscripting requirements this way, but you might want to try it.

Regards

Mark

High Performance Mark