Buscar..


Notación básica

Cualquier tipo se puede declarar como una matriz utilizando el atributo de dimensión o simplemente indicando directamente la dimension o dimension de la matriz:

! One dimensional array with 4 elements
integer, dimension(4) :: foo

! Two dimensional array with 4 rows and 2 columns
real, dimension(4, 2) :: bar

! Three dimensional array
type(mytype), dimension(6, 7, 8) :: myarray

! Same as above without using the dimension keyword
integer :: foo2(4)
real :: bar2(4, 2)
type(mytype) :: myarray2(6, 7, 8)

La última forma de declarar una matriz multidimensional, permite la declaración de matrices de diferente rango / dimensiones del mismo tipo en una línea, como sigue

real :: pencil(5), plate(3,-2:4), cuboid(0:3,-10:5,6)

El rango máximo permitido (número de dimensiones) es 15 en el estándar Fortran 2008 y fue 7 antes.

Fortran almacena matrices en orden de columnas mayores . Es decir, los elementos de la bar se almacenan en la memoria de la siguiente manera:

bar(1, 1), bar(2, 1), bar(3, 1), bar(4, 1), bar(1, 2), bar(2, 2), ...

En Fortran, la numeración de matrices comienza en 1 por defecto, a diferencia de C que comienza en 0 . De hecho, en Fortran, puede especificar explícitamente los límites superior e inferior de cada dimensión:

integer, dimension(7:12, -3:-1) :: geese

Esto declara una matriz de forma (6, 3) , cuyo primer elemento son los geese(7, -3) .

Los límites inferior y superior a lo largo de las 2 (o más) dimensiones pueden accederse mediante las funciones intrínsecas ubound y lbound . De hecho, lbound(geese,2) devolvería -3 , mientras que ubound(geese,1) devolvería 12 .

Se puede acceder al tamaño de una matriz mediante el size función intrínseca. Por ejemplo, size(geese, dim = 1) devuelve el tamaño de la primera dimensión que es 6.

Arreglos asignables

Las matrices pueden tener el atributo asignable :

! One dimensional allocatable array
integer, dimension(:), allocatable :: foo
! Two dimensional allocatable array
real, dimension(:,:), allocatable :: bar

Esto declara la variable pero no le asigna ningún espacio.

! We can specify the bounds as usual
allocate(foo(3:5))

! It is an error to allocate an array twice
! so check it has not been allocated first
if (.not. allocated(foo)) then
  allocate(bar(10, 2))
end if

Una vez que una variable ya no es necesaria, se puede desasignar :

deallocate(foo)

Si por alguna razón falla una instrucción de allocate , el programa se detendrá. Esto se puede evitar si el estado se comprueba mediante la palabra clave stat :

real, dimension(:), allocatable :: geese
integer :: status

allocate(geese(17), stat=status)
if (stat /= 0) then
  print*, "Something went wrong trying to allocate 'geese'"
  stop 1
end if

El deallocate declaración tiene stat de palabras clave también:

deallocate (geese, stat=status)

status es una variable entera cuyo valor es 0 si la asignación o desasignación fue exitosa.

Constructores de matrices

Se puede crear un valor de matriz de rango 1 utilizando un constructor de matriz , con la sintaxis

(/ ... /)
[ ... ]

La forma [...] se introdujo en Fortran 2003 y generalmente es considerado como más fáciles de interpretar, sobre todo en expresiones complejas. Este formulario se utiliza exclusivamente en este ejemplo.

Los valores que aparecen en un constructor de matriz pueden ser valores escalares, valores de matriz o bucles implícitos.

Los parámetros de tipo y tipo de la matriz construida coinciden con los de los valores en el constructor de matriz

[1, 2, 3]      ! A rank-1 length-3 array of default integer type
[1., 2., 3.]   ! A rank-1 length-3 array of default real type
["A", "B"]     ! A rank-1 length-2 array of default character type

integer, parameter :: A = [2, 4]
[1, A, 3]      ! A rank-1 length-4 array of default integer type, with A's elements

integer i
[1, (i, i=2, 5), 6]  ! A rank-1 length-6 array of default integer type with an implied-do

En los formularios anteriores, todos los valores dados deben ser del mismo tipo y tipo de parámetro. Los tipos de mezcla, o parámetros de tipo, no están permitidos. Los siguientes ejemplos no son válidos.

[1, 2.]      ! INVALID: Mixing integer and default real
[1e0, 2d0]   ! INVALID: Mixing default real and double precision
[1., 2._dp]  ! INVALID: Allowed only if kind `dp` corresponds to default real
["Hello", "Frederick"]  ! INVALID: Different length parameters

Para construir una matriz utilizando diferentes tipos, se dará una especificación de tipo para la matriz

[integer :: 1, 2., 3d0]    ! A default integer array
[real(dp) :: 1, 2, 3._sp]  ! A real(dp) array
[character(len=9) :: "Hello", "Frederick"]  ! A length-2 array of length-9 characters

Esta última forma para matrices de caracteres es especialmente conveniente para evitar el espacio de relleno, como la alternativa

["Hello    ", "Frederick"]  ! A length-2 array of length-9 characters

El tamaño de una matriz denominada constante puede estar implícito en el constructor de la matriz que se utiliza para establecer su valor

integer, parameter :: ids(*) = [1, 2, 3, 4]

y para tipos parametrizados por longitud, el parámetro de longitud puede ser asumido

character(len=*), parameter :: names(*) = [character(3) :: "Me", "You", "Her"]

La especificación de tipo también se requiere en la construcción de matrices de longitud cero. Desde

[ ] ! Not a valid array constructor

los parámetros de tipo y tipo no se pueden determinar a partir del conjunto de valores no existentes. Para crear una matriz de enteros por defecto de longitud cero:

[integer :: ]

Los constructores de matrices construyen solo matrices de rango 1. A veces, como al establecer el valor de una constante nombrada, también se requieren arreglos de rango más alto en una expresión. Las matrices de rango más alto se pueden tomar del resultado de la reshape con una matriz de rango 1 construida

integer, parameter :: multi_rank_ids(2,2) = RESHAPE([1,2,3,4], shape=[2,2])

En un constructor de matriz, los valores de la matriz en orden de elementos con cualquier matriz en la lista de valores es como si los elementos individuales se dieran en orden de elementos de matriz. Así, el ejemplo anterior

integer, parameter :: A = [2, 4]
[1, A, 3]      ! A rank-1 length-4 array of default integer type, with A's elements

es equivalente a

[1, 2, 4, 3]   ! With the array written out in array element order

En general, los valores en el constructor pueden ser expresiones arbitrarias, incluidos los constructores de matrices anidadas. Para que un constructor de matriz de este tipo cumpla ciertas condiciones, como ser una expresión constante o de especificación, las restricciones se aplican a los valores constituyentes.


Aunque no es un constructor de matriz, ciertos valores de matriz también pueden crearse convenientemente usando la función intrínseca de spread . Por ejemplo

[(0, i=1,10)]  ! An array with 10 default integers each of value 0

También es el resultado de la referencia de la función.

SPREAD(0, 1, 10)

Especificación de la naturaleza de la matriz: rango y forma

El atributo de dimension en un objeto especifica que ese objeto es una matriz. Hay, en Fortran 2008, cinco naturalezas de matrices: 1

  • forma explícita
  • forma asumida
  • tamaño asumido
  • forma diferida
  • forma implícita

Toma las tres matrices de rango 1 2

integer a, b, c
dimension(5) a    ! Explicit shape (default lower bound 1), extent 5
dimension(:) b    ! Assumed or deferred shape
dimension(*) c    ! Assumed size or implied shape array

Con estos se puede ver que se requiere un contexto adicional para determinar completamente la naturaleza de una matriz.

Forma explícita

Una matriz de forma explícita es siempre la forma de su declaración. A menos que la matriz se declare como local a un subprograma o construcción de block , los límites que definen la forma deben ser expresiones constantes. En otros casos, una matriz de forma explícita puede ser un objeto automático, utilizando extensiones que pueden variar en cada invocación de un subprograma o block .

subroutine sub(n)
  integer, intent(in) :: n
  integer a(5)   ! A local explicit shape array with constant bound
  integer b(n)   ! A local explicit shape array, automatic object
end subroutine

Forma asumida

Una matriz de forma asumida es un argumento ficticio sin el atributo allocatable o pointer . Dicha matriz toma su forma del argumento real con el que está asociada.

integer a(5), b(10)
call sub(a)   ! In this call the dummy argument is like x(5)
call sub(b)   ! In this call the dummy argument is like x(10)

contains

  subroutine sub(x)
    integer x(:)    ! Assumed shape dummy argument
  end subroutine sub

end

Cuando un argumento ficticio ha tomado forma, el alcance que hace referencia al procedimiento debe tener una interfaz explícita disponible para ese procedimiento.

Tamaño asumido

Una matriz de tamaño asumido es un argumento ficticio que tiene su tamaño asumido a partir de su argumento real.

subroutine sub(x)
  integer x(*)   ! Assumed size array
end subroutine

Las matrices de tamaños asumidos se comportan de manera muy diferente a las matrices de formas asumidas y estas diferencias se documentan en otra parte.

Forma diferida

Una matriz de forma diferida es una matriz que tiene el atributo allocatable o pointer . La forma de dicha matriz está determinada por su asignación o asignación de puntero.

integer, allocatable :: a(:)
integer, pointer :: b(:)

Forma implícita

Una matriz de formas implícita es una constante con nombre que toma su forma de la expresión utilizada para establecer su valor

integer, parameter :: a(*) = [1,2,3,4]

Las implicaciones de estas declaraciones matriciales en argumentos ficticios deben documentarse en otra parte.


1 Una Especificación Técnica que extiende Fortran 2008 agrega una sexta naturaleza de matriz: rango asumido. Esto no está cubierto aquí.

2 Se pueden escribir de manera equivalente como

integer, dimension(5) :: a
integer, dimension(:) :: b
integer, dimension(*) :: c

o

integer a(5)
integer b(:)
integer c(*)

Arreglos enteros, elementos de arreglo y secciones de arreglo.

Considere la matriz declarada como

real x(10)

Entonces tenemos tres aspectos de interés:

  1. Toda la matriz x ;
  2. Elementos de matriz, como x(1) ;
  3. Arreglo de secciones, como x(2:6) .

Arreglos enteros

En la mayoría de los casos, toda la matriz x refiere a todos los elementos de la matriz como una sola entidad. Puede aparecer en sentencias ejecutables, como print *, SUM(x) , print *, SIZE(x) o x=1 .

Una matriz completa puede hacer referencia a matrices que no tienen forma explícita (como x arriba):

function f(y)
  real, intent(out) :: y(:)
  real, allocatable :: z(:)

  y = 1.         ! Intrinsic assignment for the whole array
  z = [1., 2.,]  ! Intrinsic assignment for the whole array, invoking allocation
end function

Una matriz de tamaño supuesto también puede aparecer como una matriz completa, pero solo en circunstancias limitadas (para ser documentada en otra parte).

Elementos de matriz

Se hace referencia a un elemento de la matriz para dar índices enteros, uno para cada rango de la matriz, que denota la ubicación en la matriz completa:

real x(5,2)
x(1,1) = 0.2
x(2,4) = 0.3

Un elemento de matriz es un escalar.

Secciones de matriz

Una sección de matriz es una referencia a una serie de elementos (quizás solo uno) de una matriz completa, utilizando una sintaxis que involucra dos puntos:

real x(5,2)
x(:,1) = 0.         ! Referring to x(1,1), x(2,1), x(3,1), x(4,1) and x(5,1)
x(2,:) = 0.         ! Referring to x(2,1), x(2,2)
x(2:4,1) = 0.       ! Referring to x(2,1), x(3,1) and x(4,1)
x(2:3,1:2) = 0.     ! Referring to x(2,1), x(3,1), x(2,2) and x(3,2)
x(1:1,1) = 0.       ! Referring to x(1,1)
x([1,3,5],2) = 0.   ! Referring to x(1,2), x(3,2) and x(5,2)

La forma final anterior utiliza un subíndice vectorial . Esto está sujeto a una serie de restricciones más allá de otras secciones de la matriz.

Cada sección de matriz es en sí misma una matriz, incluso cuando solo se hace referencia a un elemento. Eso es x(1:1,1) es una matriz de rango 1 y x(1:1,1:1) es una matriz de rango 2.

Las secciones de matriz en general no tienen un atributo de toda la matriz. En particular, donde

real, allocatable :: x(:)
x = [1,2,3]     ! x is allocated as part of the assignment
x = [1,2,3,4]   ! x is dealloacted then allocated to a new shape in the assignment

la asignación

x(:) = [1,2,3,4,5]   ! This is bad when x isn't the same shape as the right-hand side

no está permitido: x(:) , aunque una sección de matriz con todos los elementos de x , no es una matriz asignable.

x(:) = [5,6,7,8]

está bien cuando x es de la forma del lado derecho.


Componentes de matrices de matrices

type t
   real y(5)
end type t

type(t) x(2)

También podemos referirnos a matrices completas, elementos de matriz y secciones de matriz en configuraciones más complicadas.

De lo anterior, x es una matriz completa. También tenemos

x(1)%y        ! A whole array
x(1)%y(1)     ! An array element
x%y(1)        ! An array section
x(1)%y(:)     ! An array section
x([1,2]%y(1)  ! An array section
x(1)%y(1:1)   ! An array section

En tales casos, no se nos permite tener más de una parte de la referencia que consiste en una matriz de rango 1. Lo siguiente, por ejemplo, no está permitido

x%y             ! Both the x and y parts are arrays
x(1:1)%y(1:1)   ! Recall that each part is still an array section

Operaciones de matriz

Debido a sus objetivos computacionales, las operaciones matemáticas en matrices son sencillas en Fortran.

Adición y sustracción

Las operaciones en matrices de la misma forma y tamaño son muy similares al álgebra matricial. En lugar de recorrer todos los índices con bucles, se puede escribir suma (y resta):

real, dimension(2,3) :: A, B, C
real, dimension(5,6,3) :: D
A    = 3.    ! Assigning single value to the whole array
B    = 5.    ! Equivalent writing for assignment
C    = A + B ! All elements of C now have value 8.
D    = A + B ! Compiler will raise an error. The shapes and dimensions are not the same

Las matrices de corte son también válidas:

integer :: i, j
real, dimension(3,2) :: Mat = 0.
real, dimension(3)   :: Vec1 = 0., Vec2 = 0., Vec3 = 0.
i = 0
j = 0
do i = 1,3
  do j = 1,2
    Mat(i,j) = i+j
  enddo
enddo
Vec1 = Mat(:,1)
Vec2 = Mat(:,2)
Vec3 = Mat(1:2,1) + Mat(2:3,2)

Función

De la misma manera, la mayoría de las funciones intrínsecas se pueden usar de forma implícita asumiendo una operación de componentes (aunque esto no es sistemático):

real, dimension(2) :: A, B
A(1) = 6
A(2) = 44 ! Random values
B    = sin(A) ! Identical to B(1) = sin(6), B(2) = sin(44).

Multiplicación y división

Se debe tener cuidado con el producto y la división: las operaciones intrínsecas que usan * y / son símbolos en forma elemental:

real, dimension(2) :: A, B, C
A(1) = 2
A(2) = 4
B(1) = 1
B(2) = 3
C = A*B ! Returns C(1) = 2*1 and C(2) = 4*3

Esto no debe confundirse con operaciones matriciales (ver más abajo).

Operaciones matriciales

Las operaciones matriciales son procedimientos intrínsecos. Por ejemplo, el producto matricial de las matrices de la sección anterior se escribe de la siguiente manera:

real, dimension(2,1) :: A, B
real, dimension(1,1) :: C
A(1) = 2
A(2) = 4
B(1) = 1
B(2) = 3
C = matmul(transpose(A),B) ! Returns the scalar product of vectors A and B

Las operaciones complejas permiten encapsular funciones mediante la creación de arreglos temporales. Mientras que algunos compiladores y opciones de compilación lo permiten, esto no se recomienda. Por ejemplo, un producto que incluye una transposición matricial puede escribirse:

real, dimension(3,3) :: A, B, C
A(:) = 4
B(:) = 5
C = matmul(transpose(A),matmul(B,matmul(A,transpose(B)))) ! Equivalent to A^t.B.A.B^T

Secciones de matrices avanzadas: tripletes de subíndices y subíndices vectoriales

Como se mencionó en otro ejemplo , se puede hacer referencia a un subconjunto de los elementos de una matriz, llamada sección de matriz. De ese ejemplo podemos tener

real x(10)
x(:)   = 0.
x(2:6) = 1.
x(3:4) = [3., 5.]

Sin embargo, las secciones de matriz pueden ser más generales que esto. Pueden tomar la forma de tripletes de subíndice o subíndices vectoriales.

Tripletes de subíndices

Un subíndice triple toma la forma [bound1]:[bound2][:stride] . Por ejemplo

real x(10)
x(1:10) = ...   ! Elements x(1), x(2), ..., x(10)
x(1:) = ...     ! The omitted second bound is equivalent to the upper, same as above
x(:10) = ...    ! The omitted first bound is equivalent to the lower, same as above
x(1:6:2) = ...  ! Elements x(1), x(3), x(5)
x(5:1) = ...    ! No elements: the lower bound is greater than the upper
x(5:1:-1) = ... ! Elements x(5), x(4), x(3), x(2), x(1)
x(::3) = ...    ! Elements x(1), x(4), x(7), x(10), assuming omitted bounds
x(::-3) = ...   ! No elements: the bounds are assumed with the first the lower, negative stride

Cuando se especifica un paso (que no debe ser cero), la secuencia de elementos comienza con el primer límite especificado. Si la zancada es positiva (resp. Negativa), los elementos seleccionados siguiendo una secuencia incrementada (resp. Decrementada) por la zancada hasta que el último elemento no sea mayor (resp. Más pequeño) que el segundo límite se toma. Si se omite el paso, se trata como si fuera uno.

Si el primer límite es mayor que el segundo límite, y la zancada es positiva, no se especifican elementos. Si el primer límite es más pequeño que el segundo límite y la zancada es negativa, no se especifican elementos.

Cabe señalar que x(10:1:-1) no es lo mismo que x(1:10:1) aunque cada elemento de x aparezca en ambos casos.

Subíndices vectoriales

Un subíndice vectorial es una matriz de enteros de rango 1. Esto designa una secuencia de elementos correspondientes a los valores de la matriz.

real x(10)
integer i
x([1,6,4]) = ...     ! Elements x(1), x(6), x(4)
x([(i,i=2,4)]) = ... ! Elements x(2), x(3) and x(4)
print*, x([2,5,2])   ! Elements x(2), x(5) and x(2)

Una sección de matriz con un subíndice vectorial está restringida en la forma en que se puede usar:

  • puede que no sea un argumento asociado con un argumento ficticio que se define en el procedimiento;
  • puede que no sea el objetivo en una instrucción de asignación de puntero;
  • puede que no sea un archivo interno en una declaración de transferencia de datos.

Además, tal sección de matriz puede no aparecer en una declaración que implique su definición cuando el mismo elemento se selecciona dos veces. Desde arriba:

print*, x([2,5,2])   ! Elements x(2), x(5) and x(2) are printed
x([2,5,2]) = 1.      ! Not permitted: x(2) appears twice in this definition

Secciones de matriz de rango más alto

real x(5,2)
print*, x(::2,2:1:-1)  ! Elements x(1,2), x(3,2), x(5,2), x(1,1), x(3,1), x(5,1)


Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow