Fortran相当于matlab find - 应用于切片矩阵而没有内存重复

时间:2012-07-27 16:30:40

标签: arrays matlab fortran

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

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

Matlab示例1:简单地再现发现

  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 个答案:

答案 0 :(得分:10)

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

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

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

的操作,编译器可能会制作临时副本
call my_subroutine(array(1:12:3, 2:12:4))

启用子程序,该子程序在运行时不知道数组部分元素的索引,以它“看到”的连续数组的形式运行。

答案 1 :(得分:2)

您可以使用" pack"隐含I = pack([(j,j=1,size(v))],v==3) 循环:

cnt != 0;

答案 2 :(得分:1)

在FORTRAN CODE中,Bellow是一个子例程的例子,它在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(True或False)位置的子程序。第一个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

答案 3 :(得分: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