我在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 )
提前感谢您的帮助!
答案 0 :(得分:10)
Fortran与Matlab的find
没有完全匹配,但您通常可以使用where
或forall
,有时两者都可以替换其功能。
例如,给定一个数组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