5

Это немного сложно; Я бы приветствовал любые замечания о том, как улучшить ясность вопроса.Выделить динамический массив с взаимозависимыми размерами

Хорошо, что у меня есть массив:

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

, и я хочу, чтобы выделить его, прежде чем использовать его. Возможно ли, чтобы размер третьего измерения зависел от размера второго измерения?

E.g.

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

Очевидно, что вышеуказанное не работает. Я хотел бы в конечном итоге с массивом (или набор массивов) с формой (ами)

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

где размер третьего измерения является квадрат размера второго измерения.

Мое правило для размера зависимого измерения немного сложнее, но если возведение в квадрат возможно, я могу сделать все остальное.

Возможно ли это? Если да, то как я могу реализовать его в Фортране?

Что будет shape(A) возвращение? Это было бы интересно.

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

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

Даже если я не трудно на память в данный момент, я «Мне нравится иметь хорошие методы программирования. В любом случае, это интересная проблема.

спасибо.

РЕДАКТИРОВАТЬ:

Что о том, размер измерения зависит от величины элемента в другом измерении?

В ответ ниже размера массива в обоих измерениях зависит от индекса B. Я хотел бы что-то вдоль линий

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 

Вы получаете то, что я имею в виду? Но программа падает, поскольку она пытается выделить уже выделенные переменные, например. когда i=1 выделяет data(1)%cell(1), а затем пытается выделить data(1)%cell(2) ... о, о. То, что я хочу что-то вроде:

Каждого data(i) имеет массив lev(j) значений, с j работает от 1 до п, и для каждого lev(j) значения мы имеем cell размера lev^2. Обратите внимание, что эти cell уникальны для каждого data(i) и каждого lev, а размер этого конкретного cell зависит от соответствующего значения lev и, возможно, соответствующего data(i).

Должен ли я использовать производный тип в производном типе?

+1

Точно так же вы знаете, тип массива, который вы ищете, называется «зубчатым» массивом, как и «прямоугольный» массив. Ниже приведен правильный ответ IRO-bot; в массивах Fortran сами по себе всегда прямоугольны, но вы можете использовать определенные типы, чтобы создать свою собственную структуру. –

+0

«Jagged» ... эй, это имеет смысл, наглядно. «... вы можете использовать определенные типы, чтобы создать свою собственную структуру». В самом деле? Поэтому, если мне нужен массив, чья форма увеличивается до половины, то уменьшается или следует за последовательностью Фибоначчи или полностью случайна - все это возможно для не слишком больших усилий ... круто! –

+0

@SamuelTan Я отредактировал свой ответ с обновленным кодом, чтобы решить вашу новую проблему. Сравните два кода, чтобы узнать, что вы делаете неправильно. – milancurcic

ответ

9

Да, вы можете использовать производный тип для достижения этой цели:

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 

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

Выход программы, как ожидается:

 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: Для дальнейшего ответа отредактированного вопроса OP еще. Да, похоже, что вам нужно будет сделать что-то вроде этого, используйте вложенный производный тип (сравните ваш пример кода, чтобы выяснить, что вы сделали не так):

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 

Пробовал это с gfortran 4.6.2. Он производит ожидаемый результат:

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

Он работает с любым последним gfortran, с которым я столкнулся (4.1.2 полностью устарел). –

+0

@ VladimirF Спасибо за комментарий - я отредактировал свой ответ. Я не знал об этом, так как я почти никогда не использовал gfortran, и это то, что мы имеем в нашем вычислительном кластере. Я предполагаю, что наш системный администратор не стал обновлять его. :) – milancurcic

+0

Это утешение. Я использую gfortran, и я боялся, что мне придется получить другой компилятор. –

1

Я думаю, что вы можете сделать это просто путем выделения/deallocating массива

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 

Составление программы с использованием gfortran дает:

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

Я не уверен, но я думаю, что вы, возможно, пропустили суть вопроса.Вопрос, кажется, задает вопрос о непрямоугольных/зубчатых массивах, и спрашивающий уже упоминает идею о том, что имеет самый большой супер-прямоугольник и использует (с осторожностью) только те из них, которые нужны. – francescalus

+0

Я думаю, что это ответ на этот вопрос {Возможно ли, чтобы размер третьего измерения зависел от размера второго измерения? } – Navaro

+0

* Возможно ли, чтобы размер третьего измерения зависел от размера второго измерения? * Так что да или нет? Я не вижу ответа на это в вашем ответе. –

Смежные вопросы