はじめに
本記事は僕自身の研究で必要な4階完全反対称テンソルの実装を行いたいと思います。numpyやscipyなどで完全反対称テンソルが元から用意されていてほしかったのですが、多分ないっぽいのでDIYしました。
まず始めに4階完全反対称テンソルとはなんでしょうか。本当に数学的な定義(表現論に基づいた定義など)はここでは必要ありません。
単純に添字が4つあり、その中の2つを入れ替えた時に符号が逆になるようなものを言います。数式で書くと次のようなものです:
J_{abcd} = - J_{bacd}\hspace{50pt}(1)\\
J_{abcd} = - J_{dbca}\hspace{50pt}(2)\\
J_{abcd} = - J_{cadb}\hspace{50pt}(3)
ここで(1)式では添字 $abcd$ のうち $a$ と $b$ を、(2)式では $a$ と $d$ を入れ替えました。一方、(3)式では $abcd\ \to\ acbd\ \to\ cabd\ \to\ cadb$ という風に3回添字の入れ替えを行っています。
ここで重要な事は、$abcd$ から奇数回だけ入れ替えを行ったものは $-J_{abcd}$と言うようにマイナス倍になる事です。一方で偶数回だけ入れ替えを行ったものは、マイナス倍を偶数回行う事になるので $J_{abcd}$に等しくなります。
今回はこの事実を駆使して4階完全反対称テンソル $J_{abcd}$ を実装したいと思います。特に僕自身の研究の都合上、ガウス分布に従う乱数を成分に持つものを考えます。
テンソルの初期化
pythonは非常に便利です。4階のテンソルだって作るだけなら簡単にできちゃいます。
まず始めに4階テンソルを用意します。今回は全ての成分を0として初期化しました。
import numpy as np
N = 8
J = np.zeros((N, N, N, N))
ここでN
は4つの添字が動く上限です: $a = 0, \cdots, N-1$ などなど。成分の指定は一般的な多次元配列のような方法ではなく、J[a, b, c, d]
という様にします。
次に$J_{abcd}$の各成分に対して乱数を入れます。これはひたすらfor
文を回しましょう。
import random
random.seed()
for a in range(N):
for b in range(N):
for c in range(N):
for d in range(N):
J[a, b, c, d] = random.gauss(0, 6 / (N ** 3))
ここで乱数は、中央値が0、分散が $6N^{-3}$ となるようなガウス分布に従うものとしました。
反対称化
さて、このままでは $J_{abcd}$ は乱数を成分に持つただのテンソルであり、添字の入れ替えに対して符号が反対になるようにはなっていません。つまり残ったタスクは $J_{abcd}$ の反対称化です。
このタスクを処理するために最初にやるべき事は、添字の順番の分類です。ある添字 $abcd$ に対して、別の添字 $ijkl$ が与えられた時、この添字は $abcd$ から出発して何回目の入れ替えで到達できるのかを知る必要があります。もし奇数回で到達できるなら $J_{ijkl} = -J_{abcd}$ ですし、偶数回ならば $J_{ijkl} = J_{abcd}$ となる訳です。また、中には ${ijkl}$ の中に数字が同じもの混じっている可能性もあるでしょう。例えば $3356$ や $1111$ などです。これらは完全反対称の性質から $0$ とする事ができます。なぜなら、例えば $i = j$ だった場合、
J_{iikl} = - J_{iikl} = 0
となるからです。ここで一つ目の等号では「 $i$ と $i$ を入れ替えました」。入れ替えるとマイナス倍になるので、状況としては自分と自分自身のマイナス倍が等しい実数となりますが、そのような実数は$0$しかありません。
次に考えるべきは、添字の入れ替えを行うにしても一体どのような添字を出発点とするのかです。これはどれでも良いのですが、やりやすいのは $J_{abcd}$ とあった時に添字が $a < b < c < d$ という大小関係にある場合だと思います。そのような成分を基準にして、そこからの入れ替えの回数を考える事にしましょう。
以上を踏まえて $J_{abcd}$ を反対称化します:
for a in range(N):
for b in range(N):
for c in range(N):
for d in range(N):
if a == b or a == c or a == d or b == c or b == d or c == d:
J[a, b, c, d] = 0
if a < b < c < d:
J[a, b, d, c] = -J[a, b, c, d]
J[a, c, b, d] = -J[a, b, c, d]
J[a, d, c, b] = -J[a, b, c, d]
J[b, a, c, d] = -J[a, b, c, d]
J[b, c, d, a] = -J[a, b, c, d]
J[b, d, a, c] = -J[a, b, c, d]
J[c, a, d, b] = -J[a, b, c, d]
J[c, b, a, d] = -J[a, b, c, d]
J[c, d, b, a] = -J[a, b, c, d]
J[d, a, b, c] = -J[a, b, c, d]
J[d, b, c, a] = -J[a, b, c, d]
J[d, c, a, b] = -J[a, b, c, d]
J[a, c, d, b] = J[a, b, c, d]
J[a, d, b, c] = J[a, b, c, d]
J[b, a, d, c] = J[a, b, c, d]
J[b, c, a, d] = J[a, b, c, d]
J[b, d, c, a] = J[a, b, c, d]
J[c, a, b, d] = J[a, b, c, d]
J[c, b, d, a] = J[a, b, c, d]
J[c, d, a, b] = J[a, b, c, d]
J[d, a, c, b] = J[a, b, c, d]
J[d, b, a, c] = J[a, b, c, d]
J[d, c, b, a] = J[a, b, c, d]
$abcd$ を $a < b < c < d$ となるように固定した後で、考えるべき入れ替えのパターンは $4! - 1= 24 - 1 = 23$通りで全てです。$1$を引いたのは入れ替えをしないというパターンを除いたからです。
これにて欲しかったものが得られました。
お願い
完全反対称テンソルをつくるアルゴリズムって他にもありそうなものですが、僕にはいまいち思いつきません。ひとつ言えるのは、任意のテンソルは対称部分と反対称部分に分ける事ができるので、それを使えばもっと楽にできそうな気がしてます。多分。「こうすればもっと楽につくれるよ」というものがあったら、是非ご教授お願いいたします。
ありがとうございました。