8

我在 matlab 中使用 find 很多命令,我想知道如何在 fortran 中巧妙地翻译它以提取数组的一部分。在 matlab 中,您可以使用逻辑或索引进行切片,但在 fortran 中,您需要索引来切片。我知道内部子程序包等,但从未使用过它们。另外,由于我正在处理大矩阵,我想避免重复内存。我希望在子程序中操作切片矩阵。我在某处读到数组切片没有重复。我不知道这是如何在 matlab 中进行切片的。我也很困惑,因为在 matlab 中,一些分配对你来说是透明的。

我想知道如何重现下面的示例,并确保我没有在内存中复制内容,并且这样做实际上很优雅。否则,我会忘记切片,只发送整个矩阵(因为它是通过引用)并循环遍历索引数组我......

Matlab示例1:简单复现find

  v=[1 2 3 4];
  I=find(v==3);

Matlab示例2:

m=rand(4,4);
bools=logical([ 1 0 0 1]);
I=find(bools==1); 
% which I could also do like: 
I=1:size(m,1); 
I=I(bools);

  for i=1:length(I)
      % here dealing with m(I(i)),:)  and do some computation
      % etc.

示例 3:只调用 m(I,:) 上的子程序,但直接使用布尔值进行切片

   foo( m(bools, :) , arg2, arg3 )

预先感谢您的帮助!

4

4 回答 4

12

Fortran 与 Matlab 没有完全匹配,find但您通常可以使用whereforall,有时同时使用两者来替换它的功能。

例如,给定一个数组v,如您在第一个示例中使用的,Fortran 语句

where (v==3) do_stuff

将仅对v等于 3 的元素进行操作。这不会像那样为您提供这些元素的索引find,但大部分用途find是用于选择元素以对其进行处理,并且在大多数情况下该where构造适用。

如前所述v,以及一个索引数组ix,在 Fortran 中,它是一个逻辑数组,如下所示:

[.true., .false., .false., .true.]

您可以在掩码数组赋值中使用ix,只要它的形状与 相同v,例如

where (ix) v = some_value

ix不一定是逻辑数组,它可以是任何类型的数组,如果它是实数数组,您可能有一个表达式,例如

where (ix>=0.0) v = some_value

我认为当前的任何 Fortran 编译器都不会复制数组来实现where构造。我会让您阅读有关forall构造的信息。

也不要忘记,您可以使用数组作为 Fortran 数组的索引,因此表达式

v([1,3]) = 0

将元素 1 和 3 设置v为 0。当然,如果数组的秩大于 1,则可以使用多个数组索引。

当您开始使用这种索引将数组的非连续部分传递给子程序时,您必须开始担心复制到临时数组中(如果这是您想要担心的事情)。我相信如果您执行类似的操作,编译器可能会制作临时副本

call my_subroutine(array(1:12:3, 2:12:4))

使在运行时不知道数组部分元素索引的子例程能够对它“看到”为连续数组的内容进行操作。

于 2012-07-28T01:55:07.757 回答
5

您可以使用带有隐含do循环的“pack”:

I = pack([(j,j=1,size(v))],v==3)
于 2016-01-13T22:30:40.703 回答
1

Bellow,在 FORTRAN CODE 中,是一个子例程的例子,它相当于 matlab 或 scilab 中的 find。在下面的例子中,我们想要 (a) 找到向量等于 22 的向量的位置 (b) 找到向量中偶数的位置

     PROGRAM Principal
     REAL*8 A(8)
     INTEGER n, npos, pos(8)
     n=8
     A = (/ 19, 20, 21, 22, 23, 24, 25, 26 /)
     ! Find the positions of vector A that is equal to 22 
     CALL FindInVector(n,A==22,npos,pos)
     WRITE(*,*) pos(1:npos)

     ! Find the positions of vector A that contains even numbers 
     CALL FindInVector(n,ABS(A/2.d0-INT(A/2.d0))<1.d-2,npos,pos)
     WRITE(*,*) pos(1:npos)

     END PROGRAM Principal

!________________________________________________________________

!查找逻辑向量 TF(真或假)的位置的子程序。第一个 npos 元素包含响应。

     SUBROUTINE FindInVector(n,TF,npos,pos)
    ! Inlet variables
    INTEGER,INTENT(IN):: n      ! Dimension of logical vector
    LOGICAL,INTENT(IN):: TF(n)  ! Logical vector (True or False)
    ! Outlet variables
    INTEGER npos                ! number of "true" conditions
    INTEGER pos(n)              ! position of "true" conditions
    ! Internal variables
    INTEGER i                   ! counter
    INTEGER v(n)                ! vector of all positions

    pos = 0                     ! Initialize pos
    FORALL(i=1:n)   v(i) = i    ! Enumerate all positions
    npos  = COUNT(TF)           ! Count the elements of TF that are .True.
    pos(1:npos)= pack(v, TF)    ! With Pack function, verify position of true conditions

    ENDSUBROUTINE FindInVector
于 2015-10-25T15:34:39.260 回答
0

我认为更简单的版本是可能的,请参见下面的子例程。该示例说明如何在数组 x 中查找小于 0.1 的值。

program test
   real,    dimension(:), allocatable :: x  
   integer, dimension(:), allocatable :: zeros

   x=[1.,2.,3.,4.,0.,5.,6.,7.,0.,8.]
   call find_in_array(x<0.01,zeros)
   write(*,*)zeros

   contains

   subroutine find_in_array(TF,res)

      ! Dummy arguments
      logical, dimension(:),              intent(in)   :: TF    ! logical array
      integer, dimension(:), allocatable, intent(out)  :: res   ! positions of true 
                                                                ! elements
      ! Local arrays
      integer, dimension(:), allocatable  :: pos
   
      pos=[(i,i=1,size(TF))]
     !pos=[1:size(TF)]  ! valid on Intel compiler
      res=pack(pos,TF)

   end subroutine find_in_array

end program test
于 2021-06-18T11:23:26.397 回答