将数组广播到不同的形状(添加“虚假”维度)

7
在Python中(使用NumPy),我可以将一个数组广播到不同的形状:
>>> import numpy as np
>>> a = np.array([2,3,4])
>>> b = np.zeros((3,2))
>>> b[:,:] = np.zeros((3,2))
>>> b[:,:] = a[:,np.newaxis]  #<-- np.newaxis allows `a` to be "broadcasted" to the same shape as b.
>>> b
array([[ 2.,  2.],
       [ 3.,  3.],
       [ 4.,  4.]])
>>> c = np.zeros((2,3))
>>> c[:,:] = a[np.newaxis,:]
>>> c
array([[ 2.,  3.,  4.],
       [ 2.,  3.,  4.]])

有没有办法在fortran中实现相同的效果? 我有一个子程序,期望传入一个2D数组 - 我想像上面演示的那样将我的1-D数组“广播”到2-D。 由于似乎很重要,我的2D数组确实具有显式接口。

顺便说一句,我认为这个功能可能reshape内置函数提供, - 如下所示:

real,dimension(3) :: arr1d
reshape(arr1d, (/3,3/), order=(/1,/1))

但是在阅读文档后,我不认为这是可能的,因为order似乎需要包含所有数字1到"N"。

编辑:为了更清楚一些,我正在寻找一种简单的方法来创建一些转换输入a,使得:

情况1

b(i,j) .eq. a(i)  !for all j, or even just j=1,2

情况 2

b(j,i) .eq. a(i)  !for all j, or even just j=1,2

任意维度的加分1:

b(i,j,k) .eq. a(i,j)
b(i,k,j) .eq. a(i,j)

etc.

1免责声明--我实际上没有SO超能力来赋予回答者额外加分;-)


@HighPerformanceMark -- 这是一个好观点。也许我会尝试一下。(因为我以前从未尝试过,所以没有想到) - mgilson
2个回答

6
我不确定您想要实现什么,但以下几个片段可能会有所帮助。 reshape 可以使用可选参数 pad,在将数组重新塑形为比原来元素更多的数组时,可以用它来提供所需的“额外”元素。例如,从 3x4 调整到 2x4x2。
您可能还对 spread 函数感兴趣,它是为了“提升”数组而设计的,即将一个秩为 N 的数组输入,输出一个秩为 N+1 的数组。您第二次复制中的片段可以重写为:
array2d = spread(array1d,2,2)

在这个例子中,第二个参数是沿着哪个维度将第一个参数展开以生成输出的维度。第三个参数是要生成的输入数组的副本数。
PS:调用 spread 的应该是 spread(array1d,1,2),我没有检查它。
编辑:针对 OP 编辑问题的回应
两种情况,1 和 2,分别通过在维度 2 和 1 上进行展开来满足。在 Fortran 中。
b = spread(a,2,j)

并且

b = spread(a,1,j)

由于spread返回的数组比其第一个参数的秩高1,因此它提供了所需的任意维度。但是,由于显示秩为3或更高的数组占用空间太大,因此我不会展示。


我现在正在检查你的答案(很抱歉我上周末没有机会检查它)。看起来 spread(array1d,1,2) 满足了我更新问题中的第二种情况,但我无法弄清楚如何使其满足第一种情况(或任何其他额外的情况;-)。 - mgilson
发布悬赏,我会再次查看 :-) - High Performance Mark
我现在不能做,需要等12个小时。所以下次当这个问题有赏金时,我可能会发一个帖子。 - mgilson
我看到你已经处理了我的编辑请求,虽然我还是为了好玩加了一点赏金 :). 我仍然很好奇是否有更好的方法来完成它,特别是对于排名>2的情况——例如,在用户定义的函数中以某种方式创建排名N切片的排名N+1指针数组指向原始数组。没有指针完成似乎不会太困难... - mgilson

1

使用reshape内置函数可以将一维数组复制到二维数组中。如果使用足够新的Fortran编译器,还有一种指针技术可供选择。指针提供了第二种引用存储的方式,避免了复制。方法是“指针边界重映射”。示例:

program array_tst

  integer, dimension (4), target :: array_1d
  integer, dimension (:,:), pointer :: array_2d

  array_1d = [ 1, 2, 3, 4 ]

  array_2d (1:2, 1:2) => array_1d

  write (*, *) array_2d (1,1), array_2d (1,2), array_2d (2,1), array_2d (2,2)

end program array_tst

请参见Fortran中更改数组维度

P.S. 回复评论...如果您不介意复制数组,可以使用reshape:

program array_reshape

  integer, dimension (4) :: array_1d
  integer, dimension (2, 2) :: array_2d

  array_1d = [ 1, 2, 3, 4 ]

  array_2d = reshape ( array_1d, [2,2] )

  write (*, *) array_2d (1,1), array_2d (1,2), array_2d (2,1), array_2d (2,2)

end program array_reshape

等等——我有点困惑——这怎么能让我使用reshape来实现我提出的功能呢?其实我并不担心这里的复制……如果这有什么区别的话。 - mgilson
另外,顺便提一下,我的 gfortran 版本尚未实现 - 我认为我们的代码(我现在刚刚更新到Fortran90!)还没有准备好使用这种最前沿的东西;-) - mgilson
我觉得你误解了。对于一个长度为4的输入数组,我不是想要得到形状为(2,2)的东西。我想要得到形状为(4,2)、(2,4)或(N,4)的东西。我想要得到这两种情况。例如,可以通过以下方式实现:do i=1,2; array_2d(i,:) = array_1d; enddo - mgilson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接