【问题标题】:broadcast an array to different shape (adding "fake" dimensions)将数组广播到不同的形状(添加“假”尺寸)
【发布时间】:2013-02-03 02:49:43
【问题描述】:

在 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 数组——我想将我的一维数组“广播”到二维,正如我上面演示的那样。看起来很重要,我的二维数组确实有一个明确的接口。

作为旁注,我认为此功能可能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)

等等

1免责声明——我实际上并没有给回答者加分的超能力;-)

【问题讨论】:

  • @HighPerformanceMark -- 这是一个很好的观点。也许我会。 (我没有想到,因为我以前从来没有这样做过)

标签: python arrays numpy fortran array-broadcasting


【解决方案1】:

我不确定您要完成什么,但这里有几个片段可能会有所帮助。

reshape 可以接受一个可选参数,称为pad,当您将其重新整形为具有比您开始时更多的元素的数组时(例如从 3x4 到 2x4x2),该参数可用于提供所需的“额外”元素。

您可能还对spread 函数感兴趣,该函数专为“提升”数组而设计,该函数将一个 rank-N 数组放入并输出一个 rank-N+1 数组。第二个副本中的片段可以重写为

array2d = spread(array1d,2,2)

在此示例中,第二个参数是沿其展开第一个参数以生成输出的维度。第三个参数是要制作的输入数组的副本数。

PS 对spread 的调用应该是spread(array1d,1,2),我没有检查过。

EDIT回应OP对问题的编辑

通过分别在维度 2 和 1 上扩展来满足 1 和 2 这两种情况。在 Fortran 中

b = spread(a,2,j)

b = spread(a,1,j)

由于spread 返回一个秩 1 大于其第一个参数的秩的数组,它提供了所寻求的任意维度。但是,由于显示 rank-3 及以上的数组非常占用空间,我不打算这样做。

【讨论】:

  • 我现在正在查看您的答案(抱歉,我周末没有机会查看)。在我更新的问题中,spread(array1d,1,2) 似乎满足 case2,但我不知道如何让它满足 case1(或任何奖励案例 ;-)。
  • 发布赏金,我再看看 :-)
  • 我在 12 小时内都做不到 -- 所以下次我在这里,当问题有资格获得赏金时,我可能会发布一个。
  • 我看到您在没有赏金的情况下解决了我的编辑问题——无论如何,我添加了一个小编辑以供娱乐:)。我仍然很好奇是否有更好的方法来做到这一点,特别是对于 rank > 2 的情况——例如以某种方式使秩 N+1 指针数组的秩 N 切片指向用户定义函数中的原始数组。在没有指针的情况下这样做似乎不会太难......
【解决方案2】:

重塑内在函数将允许您将一维数组复制到二维数组。使用足够新的 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

另见changing array dimensions in fortran

附:回复 cmets ...如果你不介意复制数组,这里是如何使用 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 来做我建议的事情?我实际上并不担心这里的副本......如果这有影响的话。
  • 而且,顺便说一句,我的gfortran 版本还没有实现它——我认为我们的代码(我刚刚更新到fortran90!)还没有准备好对于一些最前沿的东西;-)
  • 我认为你误解了。输入数组长度为 4,我不希望得到形状为 (2,2) 的东西。我正在寻找形状(4,2) - 或(2,4) - 或(N,4)的东西。我想得到这两种情况。可以实现:例如do i=1,2; array_2d(i,:) = array_1d; enddo
猜你喜欢
  • 1970-01-01
  • 2019-04-22
  • 2019-12-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-06
  • 2020-11-23
  • 2021-08-13
相关资源
最近更新 更多