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) 

其中第三維度的大小是所述第二尺寸的大小的平方來結束。

我的規則對於依賴維度的大小稍微複雜一點,但是如果可以進行平方,我可以完成剩下的工作。

這可能嗎?如果是這樣,我如何在Fortran中實現它?

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到n,併爲每個lev(j)價值,我們有大小lev^2的cell。請注意,這些cell對於每個data(i)和每個lev都是唯一的,並且該特定cell的大小取決於對應的lev值,並且可能也取決於對應的data(i)

我必須在派生類型中使用派生類型嗎?

+1

只要你知道,你正在尋找的數組類型稱爲「鋸齒狀」數組,就像「矩形」數組一樣。下面的IRO-bot有正確答案;在Fortran中,數組本身總是矩形的,但您可以使用定義的類型來創建自己的結構。 – 2011-12-19 13:54:56

+0

「鐵血」......嘿,這很有道理,畫像。 「...您可以使用定義的類型來創建自己的結構。」真?所以如果我想要一個數組的形狀一直增加到一半然後減少,或者遵循斐波那契數列,或者完全是隨機的,那麼所有這些都可能不需要太多的努力......很酷! – 2011-12-20 00:17:32

+0

@SamuelTan我用更新後的代碼進一步編輯了我的答案,以解決您的新問題。比較兩個代碼,看看你做錯了什麼。 – milancurcic 2011-12-20 04:53:57

回答

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 

這種方法允許陣列B的每個元素是一個不同的形狀的多維數組。

程序的輸出爲預期:

 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 

編輯:爲了進一步回答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完全過時)。 – 2011-12-19 10:12:02

+0

@VladimirF感謝您的評論 - 我編輯了我的答案。由於我幾乎沒有使用過gfortran,所以我沒有意識到這一點,而這正是我們在計算集羣上所擁有的。我假設我們的系統管理員沒有打擾更新它。 :) – milancurcic 2011-12-19 16:35:57

+0

這是一個安慰。我使用gfortran,而且我擔心我可能需要另外一個編譯器。 – 2011-12-20 00:22:45

1

我想你可以簡單地通過分配/取消分配陣列

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 2016-04-09 10:36:49

+0

我認爲這是這個問題的答案{是否有可能第三維的大小取決於第二維的大小? } – Navaro 2016-04-09 14:00:31

+0

*第三維的大小可能取決於第二維的大小嗎?*是的,或者不是?在你的回答中,我看不到這個答案。 – 2016-04-09 14:07:02