アインシュタインの縮約記法ってナンだ？

# はじめに <!--コメント-->
こんにちは清水です。
秋葉原ロボット部の理論グループでは、つぎの輪読会をネット上で行っています。
「一般相対性理論を一歩一歩数式で理解する」 2017 石井俊全

このなかで、アインシュタインの縮約記法がでてきます。
**アインシュタインの縮約記法**（アインシュタインの縮約規則）は、テンソル計算などの添字の取り扱いを簡潔にするための記法です。


本記事は、この記法についての表記例などをまとめたものです。
添字の範囲は１から２とします。


# 縮約記法の説明 <!--P118、P119-->
- 同じ添字は数字を代入して総和をとる。つまり縮約する。
- １つしか現れない添字には手をつけない。
- 式の中で２つ現れて総和をとるとき変化させる添字を「走る添字」、式の中に１つしか現れない添字を「止まっている添字」と呼ぶ。
- 縮約の表記はベクトルや配列の**各成分**について記述している。

# 総和
$a_i b^i = \sum_{i=1}^2 a_i b^i$  　

上下の添字の$i$は走る添字で消えて、全体が１つのスカラー値になる。

[備考]　添字位置が両方とも同じでも良い？ 例：$ a^i b^i $
一般的に、縮約を行うためには一つのインデックスが上添字（共変添字）で、もう一つが下添字（反変添字）である必要があります。したがって、上記のように両方とも上添字である場合、アインシュタインの縮約記法による自動的な縮約は適用されません。しかし、文脈や定義によっては縮約が意図されることもあるため、常に文脈やその分野の慣習を確認することが重要です。

# 横ベクトル　（行ベクトル）
　$e_i = (e_1,e_2)$　　基底など
　$y_i = (y_1,y_2)$　　成分など

[備考]　下添字は列番号を示す。基底の例
```math
e_1 =
\begin{pmatrix}
 1 \\ 0 
\end{pmatrix}
　,　
e_2 =
\begin{pmatrix}
 0 \\ 1 
\end{pmatrix}
```



# 縦ベクトル　（列ベクトル）
```math
f^i =
\begin{pmatrix}
 f^1 \\ f^2 
\end{pmatrix}
```

```math
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$



# 行列

```math
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}$






# 行列と縦ベクトルの積 <!--P120--> 
$a^i_{\ \ j} \ \ b^{\ \ j} = a^i_1 b^1 + a^i_2 b^2$ 

```math
\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$ をクロネッカーのデルタとすると
```math
\begin{equation} 
\delta^i_{j} = \left \{ \begin{array}{cc} 
1 & (i=j) \\ 
0 & (i \ne j) 
\end{array} \right. 
\end{equation}
```
```math
\delta^i_j=
\begin{pmatrix}
1 & 0 \\
0 & 1 \\
\end{pmatrix}
```

$\delta^i_j \ \ e_i= e_j = (e_1,\ e_2)$  <!--P219-->
走る添字 $i$ が止まっている添字 $j$ に一致しないと、デルタがゼロになる。

# 行列の積 <!-P121--> 
$a^i_{\ \ k} \ \ b^k_{\ \ j}=a^i_{\ \ 1} \ \ b^1_{\ \ j} + a^i_{\ \ 2} \ \ b^2_{\ \ j}$

```math
\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}$ 


```math
\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}
```
# 基底の取り換えと成分の書き換え  <!- P222 --> 
書き換え関連については、
$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$）

```math
(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}
```

```math
\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$）
```math
\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}
```

```math
(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 石井俊全
 第１章§１８ アインシュタインの縮約記法 <!--P118-->

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$ 
```python　
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}  $ 
```python　
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}$ 
```python　
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]])

縦ベクトルの列  → 横ベクトルの行にして計算する場合は、

```python　
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]])