Fortran 中数组赋值的不同形状

Different shape for array assignment in Fortran

这是我的代码:

Program Arrays

Implicit none

Integer::i,j
Integer,dimension(2)::V_Max
Complex,dimension(0:7,3)::V_cvo
Complex,dimension(7,3)::V_cvo_temp


Do concurrent(i=0:7,j=1:3)

   V_cvo(i,j)=cmplx(i+j,2*i-j)

End Do

V_cvo_temp=V_cvo(1:,:)
V_Min=minloc(abs((/((V_cvo_temp(i,j),j=1,3),i=2,5)/)))

Stop
End Program Arrays

编译后我收到一条消息:

Error: Different shape for array assignment  on dimension 1 (2 and 1)|

这里有什么问题?如果我想在该数组的特定扇区中的某个数组中找到最小元素的位置,这怎么可能?

这可能是问题的可能解决方案之一:

Program Arrays

Implicit none

Integer::i,j
Integer,dimension(2)::V_Max
Complex,dimension(0:7,2)::V_cvo
Logical,dimension(0:7,2) :: lmask = .FALSE.

forall(i=2:5,j=1:2)lmask(i,j) = .TRUE.

Do concurrent(i=0:7,j=1:2)

   V_cvo(i,j)=cmplx(i+j,2*i-j)

End Do

V_Max = Maxloc(abs(V_cvo),mask=lmask)-(/1,0/)

Open(1,File='Output.txt',Status='Unknown')

Write(1,'(2x,i0,2x,i0)') V_max
Write(1,*)

Do concurrent(i=2:5,j=1:2)

   Write(1,'(1x,i0,1x,i0,2x,f7.4)')i,j,abs(V_cvo(i,j))

End Do

Close(1)

Stop
End Program Arrays

输出文件为:

 5  1

 2 1   4.2426
 3 1   6.4031
 4 1   8.6023
 5 1  10.8167
 2 2   4.4721
 3 2   6.4031
 4 2   8.4853
 5 2  10.6301

对此有何看法?

右边好像是

V_Min=minloc(abs((/((V_cvo_temp(i,j),j=1,3),i=2,5)/)))

returns 一个标量而不是 2 个分量的向量。你需要的是 array slicing: V_cvo_temp(1:3,2:5)

V_Min=minloc(abs(V_cvo_temp(2:5,1:3)))

或更简单

V_Min=minloc(abs(V_cvo(2:5,1:3))) ! without temp array 

另外你不需要最后的stop

编辑 1:

minloc returns 相对于 (1,1) 的索引。要了解此行为,请尝试以下示例:

Program Hello
Implicit none
Integer,dimension(2)::V_Min
Complex,dimension(0:7,3)::V_cvo
V_cvo = cmplx(10,10)
V_cvo(3,2) = cmplx(0,0) ! the minimum index = [3,2]
V_Min=minloc(abs(V_cvo))
print *, 'minloc for whole array: ', V_Min
V_Min=minloc(abs(V_cvo(3:,2:)))
print *, 'minloc for sub-array:   ', V_Min
End Program Hello

它输出:

minloc for whole array:            4           2 ! base index=[-1,0]
minloc for sub-array:              1           1 ! base index=[2,2]

因此,如果将子数组传递给 minloc,您需要添加基本索引以获得 'correct' 答案。

这个表达式

minloc(abs((/((V_cvo_temp(i,j),j=1,3),i=2,5)/)))

returns 具有 1 个元素的 rank-1 数组。作业的 lhs 是一个包含 2 个元素的 rank-1 数组。 Fortran 不会分配不兼容的数组——因此会出现编译器错误消息。

(@gdlmx 的回答在其诊断中有细微的错误,如果表达式 returned 标量 Fortran 会愉快地将其值广播到数组的每个元素。)

如果表达式 return 一个标量,它仍然不会 return V_cvo 的那个部分中的最小元素的位置。子表达式

(/((V_cvo_temp(i,j),j=1,3),i=2,5)/)

生成包含 V_cvo_temp 的指定元素的 rank-1 数组,它实质上将数组展平为向量并在此过程中丢失它们的位置。这就是为什么第一个表达式 return 是具有 1 个元素的 rank-1 数组 - 它是 rank-1 数组中元素的位置。

这个解决方案的问题

V_Min=minloc(abs(V_cvo(2:5,1:3)))

是表达式 abs(V_cvo(2:5,1:3)) 将 return 索引的(临时)数组,因为默认情况下 Fortran 数组从每个等级的 1 开始。当我尝试代码时,它 return 的位置 (1,1) 似乎在所考虑的部分之外。那就是临时数组的最小元素所在的位置。

我尝试过的 'clever' 解决方案的问题是 abs(V_cvo(2:5,1:3)) 总是 returns,即使从视图中隐藏,每个等级从 1 开始索引的临时数组. minloc 或类似函数的任何应用程序都使用这些索引,而不是 v_cvo 使用的索引。最好的解决方案可能是像这样制作一个显式临时数组(适当声明):

allocate(abstemp(LBOUND(v_cvo,1):UBOUND(v_cvo,1),LBOUND(v_cvo,2):UBOUND(v_cvo,2)))

然后

v_min = minloc(abstemp(2:5,1:3))

deallocate(abstemp)

这个解决方案也可以正常工作(也许最好):

forall(i=1:7,j=1:3) V_cvo_temp(i,j)=abs(V_cvo(i,j))
V_Min = MINLOC(V_cvo_temp(m:n,:))+(/m-1,0/)

代码对于每个 m 和 n 都是正确的,如果它们在这种情况下的间隔 1:7 或其他间隔中。