Fortran equivalent to matlab find - application to slicing matrix without memory duplication

Viewed 12203

I use the command find quite a lot in matlab, and I wonder how to translate this smartly in fortran to extract a slice of an array. In matlab you can slice with either logicals or indexes, but in fortran you need indexes to slice. I'm aware of the intrinsic subroutines pack et al, but have never used them. Also, since I'm dealing with big matrices, I would like to avoid duplicating memory. I want the sliced matrix to be manipulated within a subroutine. I've read somewhere that slices of array were not duplicated. I don't know how this the slicing in done in matlab though. I'm puzzled also because in matlab some allocations are transparent to you.

I'd like to know how to reproduce the examples below, and make sure I'm not duplicating stuff in memory and that it's actually elegant to do so. Otherwise, I would forget about slicing and just send the whole matrix(since it's by reference) and loop through an index array I...

Matlab example 1: simply reproducing find

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

Matlab example 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.

Example 3: just call a subroutine on m(I,:) , but using directly booleans for slicing

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

In advance thank you for your help!

4 Answers

I think a simpler version is possible, see the subroutine below. The example shows how to find the values smaller than 0.1 in array x.

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
Related