8

私はmatlabでコマンドfindをかなり多く使用していますが、これをFortranでスマートに変換して、配列のスライスを抽出する方法を考えています。matlabでは、論理またはインデックスのいずれかでスライスできますが、Fortranでは、スライスするためにインデックスが必要です。私は組み込みサブルーチンpacketalを知っていますが、それらを使用したことはありません。また、大きな行列を扱っているので、メモリの重複は避けたいと思います。スライスした行列をサブルーチン内で操作したい。配列のスライスが複製されていないことをどこかで読んだことがあります。しかし、これがmatlabでどのようにスライスされたかはわかりません。matlabでは、一部の割り当てが透過的であるため、私も困惑しています。

以下の例を再現する方法を知りたいのですが、メモリ内の内容を複製していないことと、実際に複製するのがエレガントであることを確認してください。そうでなければ、スライスすることを忘れて、マトリックス全体を送信し(参照によるため)、インデックス配列をループします...

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

4 に答える 4

12

Fortranは、Matlabと完全に一致するわけではありませんが、find通常、どちらwhereforall、または場合によっては両方を使用して、その機能を置き換えることができます。

たとえば、v最初の例のような配列が与えられた場合、Fortranステートメント

where (v==3) do_stuff

vは、3に等しい要素でのみ動作します。これは、これらの要素のインデックスを取得しませんfindが、の使用の多くは、findそれらに何かを行うための要素を選択するためのものであり、ほとんどの場合、構成がwhere適用可能です。

前と同じように与えられ、Fortranでは次のような論理の配列でvあるインデックス配列:ix

[.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と3vを0に設定します。もちろん、配列のランクが1より大きい場合は、複数の配列インデックスを使用できます。

この種のインデックスを使用して配列の非連続セクションをサブプログラムに渡す場合は、一時配列へのコピーについて心配する必要があります(それが心配したい場合)。あなたが次のようなことをすると、コンパイラは一時的なコピーを作成するかもしれないと私は信じています

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

実行時に配列セクションの要素のインデックスを知らないサブルーチンが、連続した配列として「見ている」ものを操作できるようにします。

于 2012-07-28T01:55:07.757 に答える
5

do暗黙のループで「パック」を使用できます。

I = pack([(j,j=1,size(v))],v==3)
于 2016-01-13T22:30:40.703 に答える
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
于 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 に答える