2016-05-11 12 views
1

行列A(m x n)であり、ベクトルB(m x 1)であるとします。このベクトルBは0と1のベクトルです。Fortran - 論理インデックス

Bの要素の合計をsとします。

Iは1に等しくBの行に対応s x nある行列Cを作成したい、とAにおけるそれらの要素の位置と、S×1ベクトルであるD。類似でC = A(論理(B)、:)、およびD:

Take as an example: 

     A = [1, 2, 3; 
      4, 5, 6; 
      7, 8, 9; 
      10, 11, 12; 
      13, 14, 15 ] 

     B = [0; 1; 0; 1; 1] 

    Then: 
C = [ 4, 5, 6; 
    10, 11, 12; 
    13, 14, 15 ] 
and 
D = [2; 
    4 
    5] 

私のFortranコードがどのように見える今のように:MATLABで

PROGRAM test1 
IMPLICIT NONE 

REAL, DIMENSION(5,3) :: A 
INTEGER, DIMENSION(5,1) :: B = 0 
INTEGER :: i, j, k 

k = 1 

!Create A matrix 
do i=1,5 
    do j=1,3 
     A(i,j) = k 
     k = k+1 
    end do 
end do 

!Create B matrix 
B(2,1) = 1 
B(4,1) = 1 
B(5,1) = 1 


end program 

Iは、単に行うことで、Cを作成することができ方法。

ループを回避するにはどうすればよいでしょうか?私はwhereforallのステートメントを調べましたが、正確には私が探しているものではありません。

+0

'PACK()'は検索の際にあなたの友人かもしれません。 – francescalus

+1

[この例](http://stackoverflow.com/q/21208593)のように。より良いものが利用できるかもしれません、私は重複を示唆していません。 – francescalus

答えて

3

@francescalusが示唆しているように、PACKの組み込み関数はFortranのMatlab論理スライスと同等ですが、部分的にのみです。

  • アレイ全体の論理インデックス付け:配列と戻り値は、ランク1(MATLABでベクトル)であるように、マスクは、同じ形状を有していなければならないMatlabの論理インデックス付けの2つのタイプがあります。これは本当の位置が恣意的なので、基本的に穴を行列に突き刺すのが矩形になるという保証はできません。 これは、PACKがFortranで行う処理です。

    c = a(a < 1); % Matlab: a(m,n) -> c(s) 
    C = PACK(A, A < 1) ! Fortran: A(m,n) -> C(s) 
    
  • 単一次元の論理インデックス付け:マスクは1-Dでなければならず、アレイの単一次元内部選択するために使用されます。他のディメンションは、全体を選択することも、独自に索引付けすることもできます。 これはあなたが欲しいものです

    b = a(:,1) > 0; % a(m,n) gives logical b(m) 
    c = a(b,:); % a(m,n) selected with b(m) -> c(s,n) 
    

しかし、PACKは、直接この使用を認めていません。 @高性能マークのソリューションは、この偉業を実行する方法を示しています、

a(bMat)は行列ではないので、最終的な再形成が必要とされて
b = a(:,1) > 0; % a(m,n) gives logical b(m) 
bMat = repmat(b, 1, size(a,2)); % n copies of b(m) -> bMat(m,n) 
c = reshape(a(bMat), [sum(b), size(a,2)]); % a(m,n) -> c(s,n) 

SPREADは基本的にrepmatなので、彼のソリューションは、Matlabの中で次のようになります行列全体の選択フォームの使用に起因するサイズs * nのベクトルです。

c = RESHAPE(& 
     PACK(a, & ! The matrix we are selecting from 
      SPREAD(b==1, ! The == 1 is because you were using an INTEGER array, not LOGICAL 
        dim=2, ncopies=SIZE(a,2)) & ! This is the repmat-like code 
     ), & ! The result of this PACK is cVec(s*n) 
     [COUNT(b==1),SIZE(a,2)]) ! Reshape into (s,n) 

Dに割り当てるコードが非常に似ていますが、代わりにAを使用しての私たちはから番号が含まれているためにオンザフライ生成される配列から選択されています。他の回答者のFortranコードはまさにそれをやっています1の長さをAの第1の次元の長さ(これはBのサイズと同じである)にする。今回は、ソース配列が1次元であるため、マスクのSPREADまたはRESHAPEを結果として得る必要はありません。

最初の(Bの真の要素のインデックスを有する)Dベクトルを生成するためにコードを使用できるようなお、Fortranのは、直接支持整数ベクトルの索引付けを行い、次いで行う:

C = A(D,:) ! Works the same in Fortran! 

自分自身を広げ、形を整えることなく保存します。