phd*_*ent 3 indexing fortran logical-operators
假设我有一个矩阵A,其是(m x n)和向量B是(m x 1)。这个向量B是一个由零和一组成的向量。
也让标量s是 中元素的总和B。
我想创建一个矩阵C,它s x n对应于B等于 1的行,以及一个Dsx 1的向量,这些元素的位置在A.
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]
Run Code Online (Sandbox Code Playgroud)
截至目前,我的 Fortran 代码如下所示:
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
Run Code Online (Sandbox Code Playgroud)
在 matlab 中,我可以简单地通过以类似的方式使:C = A(logical(B),:) 和 D 来创建 C。
我怎样才能在 fortran 中做到这一点,避免循环?我已经查看了where和forall语句,但它们并不是我正在寻找的。
正如@francescalus 所建议的那样,PACK内在函数是 Matlab 逻辑切片的 Fortran 等效项,但只是部分功能。Matlab 的逻辑索引有两种类型:
整个数组逻辑索引:掩码必须与数组具有相同的形状,并且返回值的等级为 1(Matlab 中的向量)。这是因为 true 的位置是任意的,因此您不能保证基本上在矩阵中戳孔的结果是矩形的。这就是 PACK 在 Fortran 中所做的。
c = a(a < 1); % Matlab: a(m,n) -> c(s)
C = PACK(A, A < 1) ! Fortran: A(m,n) -> C(s)
Run Code Online (Sandbox Code Playgroud)单维逻辑索引:掩码必须是一维的,用于在数组的单维内部进行选择。可以整体选择其他维度或使用它们自己的索引选择其他维度。这就是你想要的。
b = a(:,1) > 0; % a(m,n) gives logical b(m)
c = a(b,:); % a(m,n) selected with b(m) -> c(s,n)
Run Code Online (Sandbox Code Playgroud)但是,PACK 并不直接承认这种用法。@high-performance-mark 的解决方案向您展示了如何执行此壮举:SPREADis basic repmat,因此他的解决方案在 Matlab 中将如下所示:
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)
Run Code Online (Sandbox Code Playgroud)
由于a(bMat)不是矩阵,而是由于使用了全矩阵选择形式,因此需要最终的重塑,而是大小为 s*n 的向量。另一个答案的 Fortran 代码正是这样做的:
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)
Run Code Online (Sandbox Code Playgroud)
分配给 D 的代码非常相似,但我们不是使用 A,而是从动态生成的数组中进行选择,该数组包含从 1 到 A 第一维长度的数字(与B)的大小。这次不需要对结果进行任何掩码的 SPREAD 或 RESHAPE,因为源数组是一维的。
顺便说一句,Fortran确实直接支持整数向量索引,因此您可以使用代码首先生成 D 向量(具有 B 的真实元素的索引),然后执行以下操作:
C = A(D,:) ! Works the same in Fortran!
Run Code Online (Sandbox Code Playgroud)
保存自己的传播和重塑。