Транспонирование матрицы Fortran не работает с массивами, отличными от 2D

Скажем, у меня есть трехмерный массив A(1:3,1:4,1:5), и я хочу работать только с его частью, например:

real :: A(1:3,1:4,1:5), B(1:5,1:2)
real, allocatable :: C(:,:)

allocate(C(size(A,1),size(B,2)))
C = matmul(A(1:3,1,1:5),B)

Фортран с этим справляется. Однако, если мне нужно было иметь дело с транспонированием, то функция transpose в Фортране запуталась, например:

real :: A(1:3,1:4,1:5), B(1:3,1:2)
real, allocatable :: C(:,:)

allocate(C(size(A,3),size(B,2)))
C = matmul(transpose(A(1:3,1,1:5)),B)

Как я могу поменять местами измерения в массиве с помощью Fortran? Например, у меня есть A(3,4,5); есть ли функция/команда, которая берет это и дает мне A (5,4,3) или A (4,3,5) или любое другое расположение, которое я мог бы пожелать? Без, конечно, чего-то вроде копирования A в фиктивный массив с размерами в требуемом порядке. Я ищу простой элегантный способ с одной строкой.

Спасибо.


person Samuel Tan    schedule 16.12.2011    source источник
comment
Когда ваши индексы массива начинаются с 1, вы можете просто написать верхнюю границу во время объявления, например. A(3,4,5), потому что индексация по умолчанию начинается с 1 в Fortran. Таких ошибок может быть легче обнаружить. Кроме того, когда вы разрезаете все измерение, вы можете просто сделать A(:,1,:) вместо A(1:3,1,1:5).   -  person milancurcic    schedule 16.12.2011


Ответы (2)


У вас нет проблем с TRANSPOSE. Он отлично работает для предоставленного вами примера кода. Проблема в том, что ваши массивы не совместимы для умножения матриц. Из стандартного проекта Fortran 2008:

Случай (i): Если МАТРИЦА A имеет форму [n, m], а МАТРИЦА B имеет форму [m, k], результат имеет форму [n, k].

В твоем случае:

C = matmul(transpose(A(1:3,1,1:5)),B)

Здесь transpose(A(1:3,1,1:5)) — матрица 5x3, а B — 2x5. Таким образом, эти две матрицы несовместимы для MATMUL. Мне интересно, как вы не уловили этого, поскольку компиляторы выдают четкое сообщение об ошибке:

Фортран 4.1.2:

In file matrix.f90:13

C = matmul(transpose(A(:,1,:)),B)
          1
Error: different shape on dimension 2 for argument 'matrix_a' and dimension 1 for argument 'matrix_b' at (1) for intrinsic matmul

ифорт 12.0.2.137:

matrix.f90(13): error #6241: The shapes of the arguments are inconsistent or nonconformable.   [MATMUL]
C = matmul(transpose(A(:,1,:)),B)
----^
compilation aborted for matrix.f90 (code 1)

pgf90 10.6-0 компилируется, но выдает ошибку времени выполнения:

0: MATMUL: nonconforming array shapes

Для изменения формы массивов в Fortran вы можете использовать встроенную функцию RESHAPE. Из стандартного проекта Fortran 2008:

13.7.140 ИЗМЕНИТЬ (ИСТОЧНИК, ФОРМА [, ПЛОЩАДКА, ПОРЯДОК])

1 Описание. Построить массив произвольной формы.

2 класс. Трансформационная функция.

3 аргумента. SOURCE должен быть массивом любого типа. Если PAD отсутствует или имеет нулевой размер, размер SOURCE должен быть больше или равен PRODUCT (SHAPE). Размер результата является произведением значений элементов SHAPE. SHAPE должен быть целочисленным массивом первого ранга. SIZE (x), где x — фактический аргумент, соответствующий SHAPE, должен быть постоянным выражением, значение которого положительно и меньше 16. Оно не должно иметь элемента, значение которого отрицательно. PAD (необязательно) должен быть массивом того же типа и параметров типа, что и SOURCE. ORDER (необязательно) должен иметь целочисленный тип, должен иметь ту же форму, что и SHAPE, и его значение должно быть перестановкой (1, 2,..., n), где n — размер SHAPE. Если он отсутствует, он как бы присутствует со значением (1, 2,..., n).

4 Характеристики результатов. Результатом является массив формы SHAPE (то есть SHAPE (RESHAPE (SOURCE, SHAPE, PAD, ORDER)) равен SHAPE) с тем же типом и параметрами типа, что и SOURCE.

5 Значение результата. Элементы результата, взятые в порядке перестановки индексов ORDER (1), . . . , ORDER (n) — это копии SOURCE в обычном порядке элементов массива, за которыми, если необходимо, следуют PAD в порядке элементов массива, за которыми, если необходимо, следуют дополнительные копии PAD в порядке элементов массива.

person milancurcic    schedule 16.12.2011
comment
Извини за это. Теперь это исправлено. Это не было ошибкой в ​​моем коде. Вы говорите, что после того, как это будет исправлено, код должен работать нормально? Он компилируется, но завершается с кодом 02. - person Samuel Tan; 16.12.2011
comment
@SamuelTan Да. Теперь у вас есть A (3x5) с B (3,2), поэтому MATMUL транспонирования A (5x3) с B дает вам форму C (5x2). Ваша программа мне подходит. - person milancurcic; 16.12.2011

A(1:3,1,1:5) представляет собой массив второго ранга размером 3 x 5. Указав конкретное значение (1) для второго индекса массива третьего ранга «A», а не диапазон, вы уменьшили размерность. транспонирование A(1:3,1,1:5) должно быть массивом второго ранга размером 5 x 3.

Если вы хотите сделать произвольное изменение размеров массива, используйте встроенную функцию «изменить форму». Разместит ли он элементы там, где вы хотите, это другой вопрос. Пример использования: A = reshape (A, [5,4,3]).

person M. S. B.    schedule 16.12.2011
comment
Итак, вы говорите, что для A(i,j,k), A(k,j,i) = reshape(A, [k,j,i]), A(j,k,i) = reshape(A,[j,k,i]) и т. д. просто используйте изменение формы для перемещения индексов измерений? - person Samuel Tan; 17.12.2011
comment
[5,4,3] это форма нового A, как я понимаю. Вы не уверены, как элементы заполняются в новый массив. Я думаю, что это должно работать: reshape(A,[5,4,3], [3,2,1])), где [3,2,1] — это порядок размеров по мере заполнения элементов. Узнал об этом из nsc.liu.se/~boein/f77to90/a5.html. Очень полезная страница, которую я нашел. Пожалуйста, поправьте меня, если я ошибаюсь. - person Samuel Tan; 19.12.2011