2017-11-29 7 views
0

나는 텐서 수축에 의존하는 C++ 라이브러리를 만들고 있습니다. 여기에 전체 응용 프로그램을 게시하지는 않겠지 만 다음과 같이 설명했습니다.Eigen :: Tensor 수축에서 텐서를 서로 바꾸면 다른 결과가 발생합니다.

우리는 장난감 순위 4 텐서, 아무것도 없지만 (0, 1, ..., 15) 재편 정의

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; 
    } 
} 

은 아이겐 두 텐서를 계약하기 위해, 우리는 수축 쌍을 지정해야합니다. 우리의 목표는 T(ijkl)*A(ib)=M(bjkl) 에서처럼 tensors의 처음 두 지수를 수축시키는 것입니다. 아이겐에서 텐서 모듈의 내 현재의 이해, 우리는 그러나

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) 

contraction1contraction2은 모두

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)과 일치한다. Eigen이 두 경우 모두 동일한 결과를주지 않게하는 원인은 무엇입니까?

+0

내가 여기에 완전히 틀릴 수 있지만, 당신은 단지 계약을 축을 지정하면 다음 주문 나머지 축에 표시해야하는 분명하지 않다. 완전히 첫 번째 인수하여이를 지정 NumPy와 예에서. 아마 Eigen은 첫 번째 텐서의 생존 축을 먼저 지키고, 두 번째 텐서의 생존 축을 유지할 것입니까? –

+0

@PaulPanzer 그 통찰력있는 답변을 주셔서 감사합니다. 'M' 축을'Mshuffle (Eigen :: array {3, 0, 1, 2})'로 섞으면'(M_shuffled = = N) .all()'은 값 1로 연결되며 요소 의미가 동일 함을 의미합니다. 대답을 수락 할 수 있도록 귀하의 의견 (아마도이 ​​주석을 포함하여?)을 답으로 제공해 주시겠습니까? – lelemmen

+0

몇 분만 기다려주세요. –

답변

0

Eigen 인터페이스는 사양 수축 축 만 사용하는 것처럼 보입니다. 그러므로 비 계약 축을 배치하는 방법을 결정해야합니다. 명백한 방법은 원래 축을 순서대로 유지하는 것입니다. 먼저 첫 번째 인수는 두 번째 인수입니다.

는 서로 다른 출력 레이아웃을 지정이 우리가 할 수있는 하나

  • 사용 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