はじめに
こんにちは清水です。
秋葉原ロボット部の理論グループでは、つぎの輪読会をネット上で行っています。
「一般相対性理論を一歩一歩数式で理解する」 2017 石井俊全
このなかで、アインシュタインの縮約記法がでてきます。
アインシュタインの縮約記法(アインシュタインの縮約規則)は、テンソル計算などの添字の取り扱いを簡潔にするための記法です。
本記事は、この記法についての表記例などをまとめたものです。
添字の範囲は1から2とします。
縮約記法の説明
- 同じ添字は数字を代入して総和をとる。つまり縮約する。
- 1つしか現れない添字には手をつけない。
- 式の中で2つ現れて総和をとるとき変化させる添字を「走る添字」、式の中に1つしか現れない添字を「止まっている添字」と呼ぶ。
- 縮約の表記はベクトルや配列の各成分について記述している。
総和
$a_i b^i = \sum_{i=1}^2 a_i b^i$
上下の添字の$i$は走る添字で消えて、全体が1つのスカラー値になる。
[備考] 添字位置が両方とも同じでも良い? 例:$ a^i b^i $
一般的に、縮約を行うためには一つのインデックスが上添字(共変添字)で、もう一つが下添字(反変添字)である必要があります。したがって、上記のように両方とも上添字である場合、アインシュタインの縮約記法による自動的な縮約は適用されません。しかし、文脈や定義によっては縮約が意図されることもあるため、常に文脈やその分野の慣習を確認することが重要です。
横ベクトル (行ベクトル)
$e_i = (e_1,e_2)$ 基底など
$y_i = (y_1,y_2)$ 成分など
[備考] 下添字は列番号を示す。基底の例
e_1 =
\begin{pmatrix}
1 \\ 0
\end{pmatrix}
,
e_2 =
\begin{pmatrix}
0 \\ 1
\end{pmatrix}
縦ベクトル (列ベクトル)
f^i =
\begin{pmatrix}
f^1 \\ f^2
\end{pmatrix}
x^i =
\begin{pmatrix}
x^1 \\ x^2
\end{pmatrix}
[備考] 上添字は行番号を示す。
位置ベクトル
$x^i e_i$ 成分 $x^i$ と基底ベクトル $e_i$ の積
$y_i f^i$ 成分 $y_i$ と基底ベクトル $f^i$ の積
内積
$e_i f^i$
行列
a^i_{\ \ j}=
\begin{pmatrix}
a^1_{\ 1} & a^1_{\ 2} \\
a^2_{\ 1} & a^2_{\ 2} \\
\end{pmatrix}
[備考] 上添字は行番号を示し、下添字は列番号を示す。
つぎのように添字を同じ $i$ に変更すると、走る添字になり行列でなくスカラーになる。
$a^i_{\ \ i}= a^1_{\ \ 1} + a^2_{\ \ 2} = \sum_{i=1}^2 a^i_{\ \ i}$
行列と縦ベクトルの積
$a^i_{\ \ j} \ \ b^{\ \ j} = a^i_1 b^1 + a^i_2 b^2$
\begin{pmatrix}
a^1_{\ 1} & a^1_{\ 2} \\
a^2_{\ 1} & a^2_{\ 2} \\
\end{pmatrix}
\begin{pmatrix}
b^1 \\ b^2
\end{pmatrix}
=
\begin{pmatrix}
a^1_{\ 1}b^1 + a^1_{\ 2}b^2 \\ a^2_{\ 1} b^1 +a^2_{\ 2}b^2
\end{pmatrix}
[備考] 成分の演算のため 積の交換法則が成り立つ。 $a^i_{\ \ j} \ \ b^{\ \ j} = b^{\ \ j} \ \ a^i_{\ \ j} $
行列とベクトルの演算では交換法則は成立しない。
クロネッカーのデルタ
$\delta^i_j$ をクロネッカーのデルタとすると
\begin{equation}
\delta^i_{j} = \left \{ \begin{array}{cc}
1 & (i=j) \\
0 & (i \ne j)
\end{array} \right.
\end{equation}
\delta^i_j=
\begin{pmatrix}
1 & 0 \\
0 & 1 \\
\end{pmatrix}
$\delta^i_j \ \ e_i= e_j = (e_1,\ e_2)$
走る添字 $i$ が止まっている添字 $j$ に一致しないと、デルタがゼロになる。
行列の積
$a^i_{\ \ k} \ \ b^k_{\ \ j}=a^i_{\ \ 1} \ \ b^1_{\ \ j} + a^i_{\ \ 2} \ \ b^2_{\ \ j}$
\begin{pmatrix}
a^1_{\ 1} & a^1_{\ 2} \\
a^2_{\ 1} & a^2_{\ 2} \\
\end{pmatrix}
\begin{pmatrix}
b^1_{\ 1} & b^1_{\ 2} \\
b^2_{\ 1} & b^2_{\ 2} \\
\end{pmatrix}
=
\begin{pmatrix}
a^1_{\ 1}b^1_{\ 1} + a^1_{\ 2}b^2_{\ 1} & a^1_{\ 1}b^1_{\ 2} + a^1_{\ 2}b^2_{\ 2} \\ a^2_{\ 1} b^1_{\ 1} +a^2_{\ 2}b^2_{\ 1} & a^2_{\ 1} b^1_{\ 2} +a^2_{\ 2}b^2_{\ 2}
\end{pmatrix}
$a$と$b$が逆行列ならば、$E$を単位行列とすると$ab=E$である。$\delta^i_j$ をクロネッカーのデルタとすると
$a^i_{\ \ k} \ \ b^k_{\ \ j} = \delta^i_{\ \ j}$
\begin{pmatrix}
a^1_{\ 1} & a^1_{\ 2} \\
a^2_{\ 1} & a^2_{\ 2} \\
\end{pmatrix}
\begin{pmatrix}
b^1_{\ 1} & b^1_{\ 2} \\
b^2_{\ 1} & b^2_{\ 2} \\
\end{pmatrix}
=
\begin{pmatrix}
1 & 0 \\ 0 & 1
\end{pmatrix}
基底の取り換えと成分の書き換え
書き換え関連については、
$e_i$:基底(双対基底は$f^i$)
$x^i$:成分(双対基底の成分は$y_i$)
$a^i_{\ j}$:基底の取り換え行列 $e^{\prime}_ i=a^j_{\ i}e_j$(双対基底の取り替えは、$f^{\prime i}=b^i_{\ j}f^j$)
(e^{\prime}_1, e^{\prime}_2)= (e_1, e_2)
\begin{pmatrix}
a^1_{\ 1} & a^1_{\ 2} \\
a^2_{\ 1} & a^2_{\ 2} \\
\end{pmatrix}
\begin{pmatrix}
f^{\prime 1} \\ f^{\prime 2}
\end{pmatrix} =
\begin{pmatrix}
b^1_{\ 1} & b^1_{\ 2} \\
b^2_{\ 1} & b^2_{\ 2} \\
\end{pmatrix}
\begin{pmatrix}
f^1 \\ f^2
\end{pmatrix}
$b^j_{\ k}$:成分の書き換え行列 $x^{\prime i}=b^i_{\ j}x^j$(双対基底での成分の書き換えは、$y^{\prime}_ i=a^j_{\ i}y_j$)
\begin{pmatrix}
x^{\prime 1} \\ x^{\prime 2}
\end{pmatrix} =
\begin{pmatrix}
b^1_{\ 1} & b^1_{\ 2} \\
b^2_{\ 1} & b^2_{\ 2} \\
\end{pmatrix}
\begin{pmatrix}
x^1 \\ x^2
\end{pmatrix}
(y^{\prime}_1, y^{\prime}_2)= (y_1, y_2)
\begin{pmatrix}
a^1_{\ 1} & a^1_{\ 2} \\
a^2_{\ 1} & a^2_{\ 2} \\
\end{pmatrix}
ただし $a$ と $b$ は逆行列 ($a^i_{\ j} b^j_{\ k}= \delta^ j_{\ k} $)
参考資料
一般相対性理論を一歩一歩数式で理解する 2017 石井俊全
第1章§18 アインシュタインの縮約記法
numpy.einsum
https://numpy.org/doc/stable/reference/generated/numpy.einsum.html
numpy.einsumの仕様
https://zenn.dev/termoshtt/articles/numpy-einsum
参考Wikipedia
https://ja.wikipedia.org/wiki/アインシュタインの縮約記法
付録 アインシュタインの縮約記法のPythonライブラリnumpy.einsum
行列と縦ベクトルの積
$a^i_{\ \ j} \ \ b^{\ j} = a^i_1 b^1 + a^i_2 b^2$
import numpy as np
a = np.arange(4).reshape(2,2)
b = np.array([0, 1])
b1 = np.arange(2).reshape(1,-1) # Error
b2 = np.arange(2).reshape(-1,1) # Error
display("(a,b,b1,b2)",a,b,b1,b2)
display("a@b",a@b)
display('np.einsum("ij,j->i",m,v)',np.einsum("ij,j->i",a,b))
(a,b,b1,b2)
array([[0, 1],
[2, 3]])
array([0, 1])
array([[0, 1]])
array([[0],
[1]])
a@b
array([1, 3])
np.einsum("ij,j->i",m,v)
array([1, 3])
横ベクトルと行列と積
$b_i \ \ a^i_{\ \ j}= b_1 \ \ a^1_{\ \ j} + b_2 \ \ a^2_{\ \ j} $
import numpy as np
a = np.arange(4).reshape(2,2)
b = np.array([0, 1])
b1 = np.arange(2).reshape(1,-1) # Error
b2 = np.arange(2).reshape(-1,1) # Error
display("(a,b,b1,b2)",a,b,b1,b2)
display("b@a",b@a)
display('np.einsum("i,ij->j",b,a)',np.einsum("i,ij->j",b,a))
(a,b,b1,b2)
array([[0, 1],
[2, 3]])
array([0, 1])
array([[0, 1]])
array([[0],
[1]])
b@a
array([2, 3])
np.einsum("i,ij->j",b,a)
array([2, 3])
行列と縦ベクトル列の積
$a^i_{\ \ j} \ \ b^{\ j} = a^i_1 b^1 + a^i_2 b^2$
$a^i_{\ \ j} \ \ b^{\ j}_{\ \ k} = a^i_1 b^1 _{\ \ k} + a^i_2 b^2 _{\ \ k}$
import numpy as np
a = np.arange(4).reshape(2,2)
b = np.array([0, 1])
bb = np.array([[0, 0],[1, 1]])
display("(a,b,bb)",a,b,bb)
display("a@bb",a@bb)
display('np.einsum("ij,jk->ik",a,bb)',np.einsum("ij,jk->ik",a,bb))
(a,b,bb)
array([[0, 1],
[2, 3]])
array([0, 1])
array([[0, 0],
[1, 1]])
a@bb
array([[1, 1],
[3, 3]])
np.einsum("ij,jk->ik",a,bb)
array([[1, 1],
[3, 3]])
縦ベクトルの列 → 横ベクトルの行にして計算する場合は、
import numpy as np
a = np.arange(4).reshape(2,2)
b = np.array([0, 1])
bb = np.array([[0, 1],[0, 1]])
display("(a,b,bb)",a,b,bb)
display("a@bb",a@(bb.T))
display('np.einsum("ij,jk->ik",a,bb)',np.einsum("ij,kj->ki",a,bb))
(a,b,bb)
array([[0, 1],
[2, 3]])
array([0, 1])
array([[0, 1],
[0, 1]])
a@bb
array([[1, 1],
[3, 3]])
np.einsum("ij,jk->ik",a,bb)
array([[1, 3],
[1, 3]])