5

Esto es un poco complicado; Me gustaría recibir cualquier comentario sobre cómo mejorar la claridad de la pregunta.Asignar matriz dinámica con dimensiones interdependientes

Ok, decir que tengo una matriz:

real, allocatable :: A(:,:,:) 

y quiero asignarlo antes de usarlo. ¿Es posible que el tamaño de la tercera dimensión dependa del tamaño de la segunda dimensión?

E.g.

do i=1,n 
allocate(A(3,i,i**2)) 
end do 

Obviamente, lo anterior no funciona. Me gustaría terminar con una matriz (o un conjunto de matrices) con la forma (s)

(3,1,1), (3,2,4), (3,3,9), ... (3, n, n^2) 

donde el tamaño de la tercera dimensión es el cuadrado del tamaño de la segunda dimensión.

Mi regla para el tamaño de la dimensión dependiente es un poco más complicada, pero si la cuadratura es posible, puedo hacer el resto.

¿Esto es posible? Si es así, ¿cómo podría implementarlo en Fortran?

¿Qué devolvería shape(A)? Eso puede ser interesante.

Mi otra alternativa es asignar al tamaño máximo requerido, y tenga cuidado de usar sólo ciertos elementos en los cálculos, es decir

allocate(A(3,n,n**2)) 

pesar de que no soy difícil para arriba en la memoria en el momento, Me gustaría tener buenas prácticas de programación. Este es un problema interesante de todos modos.

Gracias.

EDIT:

¿Qué hay de tener el tamaño de una dimensión depende del valor de un elemento en otra dimensión?

En la respuesta por debajo del tamaño de la matriz en ambas dimensiones dependía del índice de B. Me gustaría algo en la línea de

type myarray 
    real :: coord(3) 
    integer,allocatable :: lev(:) 
    integer, allocatable :: cell(:) 
endtype myarray 

type(myarray), allocatable :: data 

allocate(data(m)) 
allocate(data%lev(n)) 

forall (j=1:n) !simple now, for argument's sake 
    lev(j)=j 
endforall 

! I was thinking of using a FORALL loop here, but the errors returned 
! suggested that the compiler (gfortran) didn't expect IF blocks and ALLOCATE 
! statements in a FORALL block 
do i=1,m 
    do j=1,n 
     allocate(data(i)%cell(lev(j)**2)) 
    enddo 
enddo 

Se obtiene lo que quiero decir? Pero el programa falla cuando trata de asignar las variables ya asignadas, p. cuando i=1 asigna data(1)%cell(1), y luego intenta asignar data(1)%cell(2) ... uh oh. Lo que quiero es algo así como:

Cada data(i) tiene una gran variedad lev(j) de los valores, con j que va desde 1 hasta n, y para cada valor lev(j) tenemos un tamaño de celllev^2. Tenga en cuenta que estos cell son únicos para cada data(i) y cada lev, y que el tamaño de ese particular cell depende del valor lev correspondiente, y posiblemente el correspondiente data(i) también.

¿Debo usar un tipo derivado en un tipo derivado?

+1

Para que lo sepas, el tipo de matriz que estás buscando se llama matriz "dentada", como matriz "rectangular". IRO-bot a continuación tiene la respuesta correcta; en Fortran los arreglos solos son siempre rectangulares, pero puedes usar tipos definidos para crear tu propia estructura. –

+0

"Jagged" ... hey, eso tiene sentido, pictóricamente. "... puedes usar tipos definidos para crear tu propia estructura". De Verdad? Entonces, si quiero una matriz cuya forma aumenta hasta la mitad, luego disminuye, o sigue la secuencia de Fibonacci, o es completamente aleatoria, eso es posible sin demasiado esfuerzo ... ¡genial! –

+0

@SamuelTan Además edité mi respuesta con código actualizado para resolver su nuevo problema. Compara los dos códigos para ver lo que estabas haciendo mal. – milancurcic

Respuesta

9

sí, se puede utilizar un tipo derivado de lograr esto:

TYPE array 
    REAL,DIMENSION(:,:,:),ALLOCATABLE :: A 
ENDTYPE array 

INTEGER :: i 
INTEGER,PARAMETER :: n=10 

TYPE(array),DIMENSION(:),ALLOCATABLE :: B 

ALLOCATE(B(n)) 

DO i=1,n 
    ALLOCATE(B(i)%A(3,i,i*i)) 
    WRITE(*,*)SHAPE(B(i)%A) 
ENDDO 

END 

Este enfoque permite que cada elemento de la matriz B sea una matriz multi-dimensional de una forma diferente.

La salida del programa es el esperado:

 3   1   1 
     3   2   4 
     3   3   9 
     3   4   16 
     3   5   25 
     3   6   36 
     3   7   49 
     3   8   64 
     3   9   81 
     3   10   100 

EDIT: Para responder a otra pregunta editada de OP. Sí, parece que lo que tendría que hacer algo como esto, utilizar el tipo derivada anidada (compárese con su ejemplo de código de averiguar lo que hizo mal):

integer,parameter :: m=3,n=5 

type cellarray 
    integer,dimension(:),allocatable :: c 
endtype cellarray 

type myarray 
    integer,allocatable :: lev(:) 
    type(cellarray),dimension(:),allocatable :: cell 
endtype myarray 

type(myarray),dimension(:),allocatable :: B 

allocate(B(m)) 

! Allocate and assign lev and cell: 
do i=1,m 
    allocate(B(i)%lev(n)) 
    allocate(B(i)%cell(n)) 
    do j=1,n 
    B(i)%lev(j)=j 
    enddo 
enddo 

! Based on value of lev, allocate B%cell%c:  
do i=1,m 
    do j=1,n 
    allocate(B(i)%cell(j)%c(B(i)%lev(j)**2)) 
    enddo 
enddo 

! Print out to check that it works: 
do j=1,n 
    write(*,*)j,B(1)%lev(j),SIZE(B(1)%cell(j)%c) 
enddo 

end 

intentado esto con gfortran 4.6.2. Se produce una salida esperada:

 1   1   1 
     2   2   4 
     3   3   9 
     4   4   16 
     5   5   25 
+5

Funciona con cualquier gfortran reciente que he encontrado (4.1.2 es totalmente obsoleto). –

+0

@VladimirF Gracias por el comentario. Edité mi respuesta. No estaba al tanto de esto ya que casi nunca uso gfortran, y esto es lo que tenemos en nuestro clúster de cómputo. Supongo que nuestro administrador del sistema no se molestó en actualizarlo. :) – milancurcic

+0

Eso es un consuelo. Uso gfortran, y tenía miedo de tener que obtener otro compilador. –

1

Creo que se puede hacer esto simplemente mediante la asignación/desasignación de la matriz

Program test 
    Implicit none 
    Real, dimension(:,:,:), allocatable :: A 
    Integer :: i,N 
    Write(*,*)"Enter N"; Read(*,*)N 
    Do i = 1, N 
    if(Allocated(A)) then 
    deallocate(A);Allocate(A(i,i,i*i)) 
    else 
    allocate(A(i,i,i*i)) 
    end if 
    Write(*,*)Shape(A) 
    End do 
end program test 

Compilación del programa usando gfortran da:

Enter N 
5 
      1   1   1 
      2   2   4 
      3   3   9 
      4   4   16 
      5   5   25 
+0

No estoy seguro, pero creo que se ha perdido el sentido de la pregunta.La pregunta parece estar preguntando sobre matrices no rectangulares/dentadas, y el investigador ya menciona la idea de tener el superrectangulo más grande y usar (con cuidado) solo esos elementos deseados. – francescalus

+0

Creo que esta es la respuesta a esta pregunta {¿Es posible que el tamaño de la tercera dimensión dependa del tamaño de la segunda dimensión? } – Navaro

+0

* ¿Es posible que el tamaño de la tercera dimensión dependa del tamaño de la segunda dimensión? * Entonces, ¿sí o no? No puedo ver la respuesta a esto en tu respuesta. –

Cuestiones relacionadas