在 Fortran 中从 p*p*n 数组中选择 k*k 子数组

发布于 2024-08-19 12:03:21 字数 296 浏览 3 评论 0原文

我在 Fortran 中有一个 ppn 数组,我想从那个更大的数组中提取 k*k 子数组。我尝试这样做,但不确定它是否有效:

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

其中 y 包含值 0 和 1,1 意味着行/列需要子数组。这可行吗?如果不行,如何实现同样的事情?谢谢。

I have a ppn 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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

墨落成白 2024-08-26 12:03:21

如果我明白你想要做什么,这里有一个示例程序,它提取选定的列和行,但不使用太多数组表示法。

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

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
变身佩奇 2024-08-26 12:03:21

解决方案二,在向量(一维数组)级别使用数组操作 - 将主循环替换为:

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

解决方案三,完全使用数组操作:

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

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
烟若柳尘 2024-08-26 12:03:21

不确定这些非代码片段对您是否有用,但是;

  • 不要忘记 Fortran 的数组分段功能。
  • 不要忘记,您可以使用向量下标来获取数组部分,例如,您可以像这样选择向量 v 的元素:

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

向量下标可以应用于秩大于 1 的数组。以这种方式弄清楚你的下标要求会让我很头疼,但你可能想要尝试一下。

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.

九歌凝 2024-08-26 12:03:21

是的,它应该可以工作,您甚至不需要使用

  program main
  integer,dimension(3,3,2):: a
  integer,dimension(4,4,2):: b
  integer,dimension(4):: y
  integer,dimension(4):: idx
  integer:: i,j,k

  y = (/ 1 , 0 , 1 , 1 /)
  idx = (/ (i,i=1,4) /)
  b(:,:,:)=reshape((/((((i+10*j+100*k),i=1,4),j=1,4),k=1,2)/),(/4,4,2/))
  a(:,:,:) = b( pack(idx,y>0) , pack(idx,y>0) , :)

  print '(A2/,(4I4))','b=',b
  print '(A2/,(3I4))','a=',a

  end

gfortran 4.2.3 正确编译的 do t = ... 循环给我

b=
 111 112 113 114
 121 122 123 124
 131 132 133 134
 141 142 143 144
 211 212 213 214
 221 222 223 224
 231 232 233 234
 241 242 243 244
a=
 111 113 114
 131 133 134
 141 143 144
 211 213 214
 231 233 234
 241 243 244

您也可以使用

  k = count( y> 0)
  a(1:k,1:k,:) = b( pack(idx,y>0) , pack(idx,y>0) , :)

或考虑使用 LOGICAL .true。和.false。而不是 1 和 0...

  program main
  integer,dimension(3,3,2):: a
  integer,dimension(4,4,2):: b
  logical,dimension(4):: y
  integer,dimension(4):: idx
  integer:: i,j,k

  idx = (/ (i,i=1,4) /)
  y = idx /= 2
  b(:,:,:)=reshape((/((((i+10*j+100*k),i=1,4),j=1,4),k=1,2)/),(/4,4,2/))

  k = count( y )
  a(1:k,1:k,:) = b( pack(idx,y) , pack(idx,y) , :)

  print '(A2/,(4I4))','b=',b
  print '(A2/,(3I4))','a=',a

  end

Yes it should work, and you even do not need the do t = ... loop

  program main
  integer,dimension(3,3,2):: a
  integer,dimension(4,4,2):: b
  integer,dimension(4):: y
  integer,dimension(4):: idx
  integer:: i,j,k

  y = (/ 1 , 0 , 1 , 1 /)
  idx = (/ (i,i=1,4) /)
  b(:,:,:)=reshape((/((((i+10*j+100*k),i=1,4),j=1,4),k=1,2)/),(/4,4,2/))
  a(:,:,:) = b( pack(idx,y>0) , pack(idx,y>0) , :)

  print '(A2/,(4I4))','b=',b
  print '(A2/,(3I4))','a=',a

  end

compiled with gfortran 4.2.3 correctly gives me

b=
 111 112 113 114
 121 122 123 124
 131 132 133 134
 141 142 143 144
 211 212 213 214
 221 222 223 224
 231 232 233 234
 241 242 243 244
a=
 111 113 114
 131 133 134
 141 143 144
 211 213 214
 231 233 234
 241 243 244

You could also use

  k = count( y> 0)
  a(1:k,1:k,:) = b( pack(idx,y>0) , pack(idx,y>0) , :)

Or think using LOGICAL .true. and .false. instead of 1 and 0...

  program main
  integer,dimension(3,3,2):: a
  integer,dimension(4,4,2):: b
  logical,dimension(4):: y
  integer,dimension(4):: idx
  integer:: i,j,k

  idx = (/ (i,i=1,4) /)
  y = idx /= 2
  b(:,:,:)=reshape((/((((i+10*j+100*k),i=1,4),j=1,4),k=1,2)/),(/4,4,2/))

  k = count( y )
  a(1:k,1:k,:) = b( pack(idx,y) , pack(idx,y) , :)

  print '(A2/,(4I4))','b=',b
  print '(A2/,(3I4))','a=',a

  end
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文