Cómo inicializar arreglos bidimensionales en Fortran


En C puede inicializar fácilmente un array usando la sintaxis de llaves, si no recuerdo mal:

int* a = new int[] { 1, 2, 3, 4 };

¿Cómo puede hacer lo mismo en Fortran para matrices bidimensionales cuando desea inicializar una matriz con valores de prueba específicos para fines matemáticos? (Sin tener que indexar doblemente cada elemento en sentencias separadas)

El array está definido por

real, dimension(3, 3) :: a

O

real, dimension(:), allocatable :: a
Author: Fludlu McBorry, 2010-09-14

3 answers

Puedes hacerlo usando reshape y shape intrínsecos. Algo como:

INTEGER, DIMENSION(3, 3) :: array
array = reshape((/ 1, 2, 3, 4, 5, 6, 7, 8, 9 /), shape(array))

Pero recuerde el orden mayor de la columna. La matriz será

1   4   7
2   5   8
3   6   9

Después de remodelar.

Así que para obtener:

1   2   3
4   5   6
7   8   9

También necesitas transponer intrínseco:

array = transpose(reshape((/ 1, 2, 3, 4, 5, 6, 7, 8, 9 /), shape(array)))

Para un ejemplo más general (matriz 2D asignable con diferentes dimensiones), se necesita tamaño intrínseco:

PROGRAM main

  IMPLICIT NONE

  INTEGER, DIMENSION(:, :), ALLOCATABLE :: array

  ALLOCATE (array(2, 3))

  array = transpose(reshape((/ 1, 2, 3, 4, 5, 6 /),                            &
    (/ size(array, 2), size(array, 1) /)))

  DEALLOCATE (array)

END PROGRAM main
 44
Author: Wildcat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-10-21 19:56:40

Para los arrays multidimensionales (rank>1), la forma Fortran para la inicialización difiere de la solución C porque en C los arrays multidimensionales son solo arrays de arrays de etc.

En Fortran, cada rango corresponde a un atributo diferente del tipo de datos modificado. Pero solo hay un constructor de matriz, para matrices de rango-1. Por estas dos razones, la inicialización a través de array constructor requiere la función intrisic RESHAPE.

Además de lo que ya se ha contestado, hay una forma más directa de ingresar el valor de una matriz por fila en lugar de por columna: reshape tiene un argumento opcional ORDER que se puede usar para modificar el orden de llenado del elemento de la matriz multidimensional con las entradas del constructor de la matriz.

Por ejemplo, en el caso del ejemplo en la primera respuesta, uno podría escribir:

INTEGER, DIMENSION(3, 3) :: array=reshape( (/ 1, 2, 3, &
                                              4, 5, 6, &
                                              7, 8, 9 /), &
                                           shape(array), order=(/2,1/) )

Obteniendo el relleno de la matriz exactamente en el orden mostrado por las líneas de código.

El array (/2, 1/) fuerza la columna index (2) tendrá precedencia sobre la fila index (1), dando el efecto deseado.

 14
Author: GiorgioP,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-09-10 16:22:06

La inicialización del array se puede hacer en la propia declaración del array, como se muestra a continuación:

program test
 real:: x(3) = (/1,2,3/)
 real:: y(3,3) = reshape((/1,2,3,4,5,6,7,8,9/), (/3,3/))
 integer:: i(3,2,2) = reshape((/1,2,3,4,5,6,7,8,9,10,11,12/), (/3,2,2/))

end program test

Me sorprende que

 real:: y(3,3) = (/(/1,2,3/),(/4,5,6/),(/7,8,9/)/)

Es no aceptado por el compilador (probado g95, gfortran). Resulta que el shape de (/(/1,2,3/),(/4,5,6/),(/7,8,9/)/) es 9 y no 3 3!

 5
Author: Sourav Mukherjee,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-06-23 07:07:49