2017-11-29 14 views
0

私はテンソルの収縮に依存するC++ライブラリに取り組んでいます。私はここに完全なアプリケーションを掲載するつもりはありませんが、私はそれを次のように蒸留しました。Eigen :: Tensorの収縮でテンソルを交換することによって、異なる結果が生じるのはなぜですか?

我々は(0、1 ...、15)は何もなく、されていないおもちゃのランク4テンソルを定義作り直さ:

Eigen::Tensor<double, 4> T (2, 2, 2, 2); 
for (size_t i = 0; i < 2; i++) { 
    for (size_t j = 0; j < 2; j++) { 
     for (size_t k = 0; k < 2; k++) { 
      for (size_t l = 0; l < 2; l++) { 
       T(i, j, k, l) = l + 2 * k + 4 * j + 8 * i; 
      } 
     } 
    } 
} 

と何物でもありませんとの契約ランク2テンソル、しかし、(1、2、3、4)形状変更:

Eigen::Tensor<double, 2> A (2, 2); 
for (size_t i = 0; i < 2; i++) { 
    for (size_t j = 0; j < 2; j++) { 
     A(i, j) = 1 + j + 2 * i; 
    } 
} 

を固有に2つのテンソルを縮小するためには、我々は収縮ペアを指定する必要があります。我々の目標は、T(ijkl)*A(ib)=M(bjkl)のように、テンソルの最初の2つのインデックスを縮小することです。固有におけるテンソルモジュールの私の現在の理解では、我々は

Eigen::array<Eigen::IndexPair<int>, 1> contraction_pair = {Eigen::IndexPair<int>(0, 0)}; 

として収縮ペアを書きますが、私は収縮A(ib)*T(ijkl)=N(bjkl)を実行するために、まったく同じ収縮ペアを使用することが可能であるべきだと思います。残念ながら、これはそうではありません、と私はnumpyの中に同じおもちゃのテンソルをテストしている

0 0 0 0 24 
0 0 0 1 28 
0 0 1 0 32 
0 0 1 1 36 
0 1 0 0 40 
0 1 0 1 44 
0 1 1 0 48 
0 1 1 1 52 
1 0 0 0 32 
1 0 0 1 38 
1 0 1 0 44 
1 0 1 1 50 
1 1 0 0 56 
1 1 0 1 62 
1 1 1 0 68 
1 1 1 1 74 

Nのこれらがある一方でMの要素を使用して、

0 0 0 0 24 
0 0 0 1 32 
0 0 1 0 28 
0 0 1 1 38 
0 1 0 0 32 
0 1 0 1 44 
0 1 1 0 36 
0 1 1 1 50 
1 0 0 0 40 
1 0 0 1 56 
1 0 1 0 44 
1 0 1 1 62 
1 1 0 0 48 
1 1 0 1 68 
1 1 1 0 52 
1 1 1 1 74 

ですeinsum:

T = np.arange(16).reshape(2, 2, 2, 2) 
A = np.arange(1, 5).reshape(2, 2) 

contraction1 = np.einsum('ijkl,ia->ajkl', integrals, C) 
contraction2 = np.einsum('ia,ijkl->ajkl', C, integrals) 

およびcontraction1およびcontraction2は、

0 0 0 0 24 
0 0 0 1 28 
0 0 1 0 32 
0 0 1 1 36 
0 1 0 0 40 
0 1 0 1 44 
0 1 1 0 48 
0 1 1 1 52 
1 0 0 0 32 
1 0 0 1 38 
1 0 1 0 44 
1 0 1 1 50 
1 1 0 0 56 
1 1 0 1 62 
1 1 1 0 68 
1 1 1 1 74 

であり、EigenのケースA(ib)*T(ijkl)=N(bjkl)と一致する。アイゲンは、どちらの場合も同じ結果をもたらさない原因は何ですか?

+0

私はここに完全に間違っているかもしれないが、あなただけ収縮する軸を指定した場合、それは、注文残りの軸はで表示されますかが明確ではありません。あなたは完全に最初の引数によって、これを指定するnumpyの例では。おそらく、Eigenは最初のテンソルの生き残り軸を最初に、次に2番目のテンソルの生存軸の順番に保つでしょうか? –

+0

@PaulPanzerその洞察的な答えをくれてありがとう。 'M'の軸を' Mshuffle(Eigen :: array {3、0、1、2}) 'としてシャッフルすると、' M_shuffled = = N).all() 'は値1につながります。つまり、要素ごとに等価です。私はそれを受け入れることができるように答えとしてあなたのコメントを(おそらくこのコメントを含む?)与えることができますか? – lelemmen

+0

私は数分します。 –

答えて

0

Eigenインターフェイスは、指定のために縮小軸のみを使用しているようです。したがって、非契約軸をどのように配置するかを決める必要があります。明白な方法は、元の軸を順番に保持することです。最初は最初の引数、次に2番目の引数です。

は異なる出力レイアウトを指定して、この私たちすることができますいずれか

  • 使用np.einsumを確認し、Eigenの出力に比較するには:

を。

import numpy as np 

T = np.arange(16).reshape(2, 2, 2, 2) 
A = np.arange(1, 5).reshape(2, 2) 

print(np.einsum('ijkl,ia->ajkl', T, A)) 
# [[[[24 28] 
# [32 36]] 

# [[40 44] 
# [48 52]]] 


# [[[32 38] 
# [44 50]] 

# [[56 62] 
# [68 74]]]] 

print(np.einsum('ijkl,ia->jkla', T, A)) 
# [[[[24 32] 
# [28 38]] 

# [[32 44] 
# [36 50]]] 


# [[[40 56] 
# [44 62]] 

# [[48 68] 
# [52 74]]]] 
  • またはEigenに直接シャッフル(感謝の@lelemmen):

M.shuffle(Eigen::array<int, 4> {3, 0, 1, 2}) 
(M_shuffled == N).all() 

# 1 
+0

私は質問とこの受け入れられた答え、すなわち、https://gist.github.com/lelemmen/d01a32387363376d00191d10208a5440を組み合わせて、自由の女神を作りました。 – lelemmen

関連する問題