транслировать массив в другую форму (добавляя поддельные размеры)

В 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 -- я хотел бы "транслировать" свои одномерные массивы до двумерных, как я продемонстрировал выше. Похоже, что это имеет значение, но мой 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отказ от ответственности - на самом деле у меня нет НАСТОЛЬКО сверхспособностей, чтобы начислять бонусные баллы отвечающему ;-)


person mgilson    schedule 03.02.2013    source источник
comment
@HighPerformanceMark - это хороший момент. Может быть, я буду. (Я не думал об этом, потому что я никогда не делал этого раньше)   -  person mgilson    schedule 04.02.2013


Ответы (2)


Я не уверен, чего вы пытаетесь достичь, но вот несколько фрагментов, которые могут помочь.

reshape может принимать необязательный аргумент, называемый pad, который можно использовать для предоставления «дополнительных» элементов, необходимых при преобразовании в массив с большим количеством элементов, чем вы начали, скажем, с 3x4 до 2x4x2.

Вас также может заинтересовать функция spread, которая предназначена для «повышения ранга» массивов, то есть принимает массив ранга N и выдает массив ранга N+1. Фрагмент в вашей второй копии может быть переписан как

array2d = spread(array1d,2,2)

В этом примере второй аргумент — это измерение, по которому следует распространить первый аргумент для создания выходных данных. Третий аргумент — это количество копий входного массива, которое необходимо сделать.

PS Вызов spread возможно должен быть spread(array1d,1,2), я не проверял.

EDIT в ответ на редактирование вопроса OP

Два случая, 1 и 2, выполняются путем распространения по измерениям 2 и 1 соответственно. В Фортране

b = spread(a,2,j)

и

b = spread(a,1,j)

Поскольку spread возвращает массив с рангом на 1 больше, чем ранг его первого аргумента, он обеспечивает искомую произвольную размерность. Однако, поскольку это так много места, чтобы показать массивы ранга 3 и выше, я не собираюсь.

person High Performance Mark    schedule 03.02.2013
comment
Я проверяю ваш ответ сейчас (извините, у меня не было возможности проверить его на выходных). Похоже, что spread(array1d,1,2) удовлетворяет case2 в моем обновленном вопросе, но я не могу понять, как заставить его удовлетворять case1 (или любому из бонусных случаев ;-). - person mgilson; 04.02.2013
comment
Опубликуйте эту награду, и я посмотрю еще раз :-) - person High Performance Mark; 04.02.2013
comment
Я не могу в течение 12 часов. Так что в следующий раз, когда я буду здесь, когда вопрос будет иметь право на награду, я могу опубликовать его. - person mgilson; 04.02.2013
comment
Я вижу, вы отреагировали на мое редактирование без вознаграждения - я все равно добавил небольшое для развлечения :). Мне все еще любопытно, есть ли лучший способ сделать это, особенно для случая ранга › 2 - например. каким-то образом срезы ранга N массива указателей ранга N+1 указывают на исходный массив в пользовательской функции. сделать это без указателей кажется, что это было бы не слишком сложно... - person mgilson; 05.02.2013

Встроенная функция reshape позволит вам скопировать 1D-массив в 2D-массив. С достаточно новым компилятором 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. В ответ на комментарии... если вы не против скопировать массив, вот как использовать изменение формы:

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
person M. S. B.    schedule 03.02.2013
comment
подождите -- я в замешательстве -- Как это позволяет мне использовать reshape для выполнения того, что я предложил? Я на самом деле не беспокоюсь о копии здесь ... если это имеет значение. - person mgilson; 03.02.2013
comment
И, в качестве примечания, это еще не реализовано в моей версии gfortran -- я не думаю, что наш код (который я только что обновляю до fortran90!) готов к чему-то столь передовому ;-) - person mgilson; 03.02.2013
comment
Я думаю, вы неправильно понимаете. С длиной входного массива 4 я не собираюсь получать что-то в форме (2,2). Я хочу получить что-то в форме (4,2) -- или (2,4) -- или (N,4). Я хочу получить оба сценария. Это может быть выполнено: do i=1,2; array_2d(i,:) = array_1d; enddo например. - person mgilson; 03.02.2013