5

Jest to nieco skomplikowane; Z zadowoleniem przyjmuję wszelkie uwagi dotyczące poprawy jasności pytania.Przydzielanie dynamicznej macierzy o współzależnych wymiarach

Ok, powiedzmy Mam tablicę:

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

i chcę przeznaczyć go zanim go używać. Czy rozmiar trzeciego wymiaru może zależeć od rozmiaru drugiego wymiaru?

E.g.

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

Oczywiście powyższe nie działa. Chciałbym koniec z tablicy (albo zestaw matryc) o kształcie (a)

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

gdzie wielkość trzeci wymiar kwadratu o wielkości na drugim wymiarze.

Moja zasada wielkości wymiaru zależnego jest nieco bardziej skomplikowana, ale jeśli kwadratura jest możliwa, mogę zrobić resztę.

Czy to możliwe? Jeśli tak, jak mogę go wdrożyć w Fortranie?

Co powróci shape(A)? To byłoby interesujące.

Moja druga alternatywa jest przyznanie się do maksymalnej wielkości wymaganej, i uważać, aby stosować tylko niektóre elementy w obliczeniach, tj

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

Choć nie jestem ciężko się na pamięć w tej chwili, ja chciałby mieć dobre praktyki programistyczne. To i tak interesujący problem.

Dziękuję.

EDIT:

Co mający rozmiar wymiar zależy od wartości elementu w innym wymiarze ?

W odpowiedzi poniżej rozmiaru tablicy w obu wymiarach zależy od indeksu B. Chciałbym coś wzdłuż linii

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 

Ci co mam na myśli? Ale program przewraca się, ponieważ próbuje przydzielić już przydzielone zmienne, np. gdy i=1 przydziela data(1)%cell(1), a następnie próbuje przydzielić data(1)%cell(2) ... uh oh. Co chcę jest coś takiego:

Każdy data(i) ma tablicę lev(j) wartości, z j biegnący od 1 do n, a dla każdej wartości lev(j) mamy cell wielkości lev^2. Zauważ, że te cell są unikatowe dla każdego data(i) i każdego lev i że rozmiar tego konkretnego cell zależy od odpowiedniej wartości lev i ewentualnie odpowiadającego data(i).

Czy musiałbym używać typu pochodnego w typie pochodnym?

+1

tak wiesz, Typ poszukiwanej macierzy nazywa się tablicą "postrzępioną", a nie tablicą "prostokątną". IRO-bot poniżej ma poprawną odpowiedź; w tablicach Fortranu same są zawsze prostokątne, ale można użyć zdefiniowanych typów do stworzenia własnej struktury. –

+0

"Jagged" ... hej, to ma sens, obrazowo. "... możesz użyć zdefiniowanych typów, aby stworzyć własną strukturę." Naprawdę? Więc jeśli chcę tablicy, której kształt wzrasta do połowy, a następnie maleje, lub podąża za sekwencją Fibonacciego, lub jest całkowicie losowy - to wszystko jest możliwe bez zbytniego wysiłku ... fajnie! –

+0

@SamuelTan Dalej edytowałem swoją odpowiedź z zaktualizowanym kodem, aby rozwiązać twój nowy problem. Porównaj dwa kody, aby zobaczyć, co robiłeś źle. – milancurcic

Odpowiedz

9

Tak, można użyć typu pochodzącą do osiągnięcia tego celu:

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 

Takie podejście pozwala każdy element tablicy B być wielowymiarowa tablica innym kształcie.

Wyjście programu jest zgodnie z oczekiwaniami:

 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: Aby odpowiedzieć dalej OP edytowany pytanie. Tak, wydaje się, że trzeba by zrobić coś takiego, należy użyć typu zagnieżdżonego pochodzącą (porównanie do przykładu kodu, aby dowiedzieć się, co zrobiłeś źle):

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 

próbował tego z gfortran 4.6.2. Produkuje oczekiwany wynik:

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

Działa z każdym nowym programem, z którym się zetknąłem (4.1.2 jest całkowicie przestarzały). –

+0

@VladimirF Dzięki za komentarz - zredagowałem swoją odpowiedź. Nie zdawałem sobie z tego sprawy, ponieważ prawie nigdy nie używam gfortran, i to jest to, co mamy w naszym klastrze obliczeniowym. Zakładam, że nasz sysadmin nie zawracał sobie głowy aktualizowaniem. :) – milancurcic

+0

To jest pocieszenie. Używam gfortran, i bałem się, że mógłbym dostać inny kompilator. –

1

myślę, że można to zrobić jedynie poprzez przydzielenie/dealokując tablicę

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 

Kompilacja programu za pomocą gfortran daje:

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

Nie jestem pewien, ale myślę, że mogłeś przegapić punkt pytania.Pytanie wydaje się pytać o tablice inne niż prostokątne/postrzępione, a osoba pytająca już wspomina o tym, że ma największy super-prostokąt i używa (ostrożnie) tylko tych pożądanych elementów. – francescalus

+0

Myślę, że jest to odpowiedź na to pytanie {Czy rozmiar trzeciego wymiaru może zależeć od rozmiaru drugiego wymiaru? } – Navaro

+0

* Czy rozmiar trzeciego wymiaru może zależeć od rozmiaru drugiego wymiaru? * ​​Tak, czy nie? Nie widzę odpowiedzi na to w twojej odpowiedzi. –

Powiązane problemy