相互依存ディメンションを持つ動的配列を割り当てる

これはちょっと複雑です。私は質問の明快さを改善する方法についてのコメントを歓迎する。

私は配列を持っていると言う:

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

私はそれを使用する前にそれを割り当てる必要があります。 3次元の大きさが2次元の大きさに依存するのは可能ですか?

例えば。

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)

ここで、第3の次元のサイズは、第2の次元のサイズの2乗である。

依存ディメンションのサイズに対する私のルールはもう少し複雑ですが、二乗が可能な場合は残りを実行できます。

これは可能ですか?もしそうなら、どうすればFortranで実装できますか?

シェイプ(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

You get what I mean? But the program falls over as it tries to allocate already allocated variables, 例えば。 when i=1 it allocates data(1)%cell(1), and then tries to allocate data(1)%cell(2)...uh oh. What I want is something like:

それぞれの data(i)は、 j が1からnまでの値を持つ配列 lev(j) size lev ^ 2の cell を持つlev(j)の値です。これらの cell は、各 data(i)とそれぞれの lev で一意であり、 は対応する lev の値と対応する data(i)の値によって決まります。

派生型内で派生型を使用する必要がありますか?

5
@SamuelTan私はあなたの新しい問題を解決するために、更新されたコードで私の答えをさらに編集しました。 2つのコードを比較して、間違っていたことを確認してください。
追加された 著者 milancurcic,
探している配列のタイプは、「長方形」配列と同じように「ギザギザ」配列と呼ばれます。以下のIRO-botには正しい答えがあります。 Fortran配列自体は常に長方形ですが、定義された型を使用して独自の構造を作ることができます。
追加された 著者 Jonathan Dursi,
"ギザギザ" ...ねえ、それは絵のように意味がある。 "...あなたは独自の構造を作るために定義された型を使うことができます。"本当に?したがって、形状が途中まで増加し、次に減少する配列、またはフィボナッチ配列に従う配列、または完全にランダムな配列が必要な場合は、それほど多くの労力を要しません。
追加された 著者 Samuel Tan,

2 答え

はい、派生型を使用してこれを行うことができます:

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
9
追加された
それは私が遭遇した最近のgfortranで動作します(4.1.2はまったく時代遅れです)。
追加された 著者 Vladimir F,
@ VladimirFコメントをいただきありがとうございます - 私は私の答えをeditted。私はgfortranをほとんど使用していないので、これを認識していませんでした。これが私たちの計算クラスタ上にあります。私は、システム管理者がそれを更新することを嫌うと仮定します。 :)
追加された 著者 milancurcic,
@ SamuelTanいいえ、他の配列と同じように、Bを1つのステートメントに割り当てることになります。それぞれが異なる形をしているので、ループ内にBの要素を割り当てることに注意してください。私はBが割り振れるように私の答えを編集しました。
追加された 著者 milancurcic,
@SamuelTan私はHPCの派生型に関する経験はありません。あなた自身で把握しなければなりません。私はそれが大幅に遅くなるべきではないと仮定し、派生型は単にデータの抽象化であり、すべてがメモリ内の1次元配列に格納されていることに留意してください。練習として、両方の方法で問題を実装し、パフォーマンスに違いがあるかどうかを確認することができます。しかし、私が心配しているのは、最初にあなたのために働く最も簡単で最も明白な方法でプログラムを実装し、後で最適化することを心配することです。
追加された 著者 milancurcic,
はい!!!驚くばかり!どうもありがとうございます!できます!派生型の派生型! Erm ...これは物事を遅くするのですか?タイプ内でタイプし、いくつかのネストされたループを知っていますか?私は後でこの配列をループします。私は、xyz座標( coord )、レベル( lev )、およびそれらが属するセル(コード>)。彼らは、充電や元素記号のような他の属性を持っています。単一の派生型にすべての属性を含めることをお勧めしますか、可能であればこれらのプロパティを別々にするのが最適ですか?
追加された 著者 Samuel Tan,
B も同様に割り当て可能な場合はどうなりますか?割り振りはまだ1つのループを取りますか?
追加された 著者 Samuel Tan,
それは慰めです。私はgfortranを使っています。私は別のコンパイラを手に入れなければならないかもしれません。
追加された 著者 Samuel Tan,

私はあなたが配列を割り当て/割り当て解除するだけでこれを行うことができると思います

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
1
追加された
まあ、私はフランセスカラスに同意します、私たちはあなたとは違って質問を解釈しました(私はOPの意図に近いと強く信じています)。彼は(上記の答えを受け入れたので)実際に<第3次元のサイズが第2次元の異なるインデックスで異なるのかどうかを聞いていましたか?
追加された 著者 Vladimir F,
第3次元のサイズは第2次元のサイズに依存する可能性はありますか?そうですか、いいえ?私はあなたの答えでこれに対する答えを見ることができません。
追加された 著者 Vladimir F,
私はこれが本当に文字通りの質問に対する答えであることに同意します。しかし、質問と受け入れられた答えについてのコメント(そして少し違った解釈)があると、私はもっと欲しいものを読んでいました: " A(:、1、:) (3,4)、...、 A(:、n、:)としてを形状(3,1)として A(:、2、:) (3、n ^ 2)。
追加された 著者 francescalus,
私は確信していませんが、私はあなたが質問のポイントを逃したかもしれないと思います。疑問は、非長方形/ギザギザの配列について質問しているようであり、質問者はすでに最大の超長方形を持ち、必要な要素だけを(注意して)使用するという考えを述べています。
追加された 著者 francescalus,
私はこれがこの質問の答えだと思います。{第3次元のサイズは第2次元のサイズに依存できますか? }
追加された 著者 Navaro,
@ウラジミール:もちろん、はい、私は結果を印刷
追加された 著者 Navaro,
私のコードに何が問題なのか教えてください。
追加された 著者 Navaro,