bitterharvest’s diary

A Bitter Harvestは小説の題名。作者は豪州のPeter Yeldham。苦闘の末に勝ちえた偏見からの解放は命との引換になったという悲しい物語

量子力学の世界を垣間見る(4):ボーズ粒子とフェルミ粒子

8.ボーズ粒子とフェルミ粒子

粒子には二つの種類がある。一つは、光子に代表されるボーズ粒子であり、他の一つは、電子を代表とするフェルミ粒子である。

ボーズ粒子が来るものは拒まずというような性質を有しているのに対して、フェルミ粒子は共存はできないという性格を持っている。

このような性質はどこから来るのであろうか。

今、二つの粒子\(a\),\(b\)があるとし、その位置を入れ替えることにしよう。入れ替える前の状態を\(|source>\)、後の状態を\(|target>\)で表すことにしよう。入れ替えるときの演算子を\(P\)とすると
\begin{eqnarray}
| target> = P | source>
\end{eqnarray}
となる。また、これを具体的に図で示すと
f:id:bitterharvest:20160912124028p:plain
なお、\(|source>=\hat{a}^\dagger_l \hat{a}^\dagger_k |0>\)で、\(|target>=\hat{a}^\dagger_k \hat{a}^\dagger_l |0>\)とする。即ち、\(a\)が発生演算子\(\hat{a}^\dagger_k\)によって格子点番号\(k\)に先に入り、\(b\)が\(\hat{a}^\dagger_l\)によって\(l\)に後で入って、状態\(|source>\)が作られたとする。さらに、\(a\)が\(\hat{a}^\dagger_l\)によって、\(l\)に先に入り、\(b\)が\(\hat{a}^\dagger_k\)によって\(k\)に後で入って、状態\(|target>\)が作られたとする。


また、\(|source>\)から\(|target>\)へは、次図のように、一つずつ粒子を移動させて得ることができる。
f:id:bitterharvest:20160912124058p:plain

この状態でもう一度入れ替えると、
\begin{eqnarray}
|source> = P |target> = P^2 |source>
\end{eqnarray}
となる。そこで、そこで上の式を満たす\(P\)は\(1\)あるいは\(-1\)となる。

これから、\(P\)の値によって二種類の粒子が存在することが分かるが、結論から言うと、\(P=1\)の場合がボーズ粒子であり、\(P=-1\)がフェルミ粒子である。そこで、この性質は、生成演算子同士、消滅演算子同士、あるいは生成演算子と消滅演算子の順序に由来していると考えてみよう。
そして、それぞれの粒子について、演算子の交換法則を定義してみよう。

8.1 ボーズ粒子

まず、ボーズ粒子から話を始めよう。\(P=1\)から演算子の順序を交換しても変わらないとし、次のことが成り立っていると考える。

二つの生成演算子\(\hat{a}^\dagger_k\)と\(\hat{a}^\dagger_l\)については、交換しても変わらないとする。即ち、
\begin{eqnarray}
\hat{a}^\dagger_k \hat{a}^\dagger_l= \hat{a}^\dagger_l \hat{a}^\dagger_k
\end{eqnarray}

二つの消滅演算子\(\hat{a}^\dagger_k\)と\(\hat{a}^\dagger_l\)についても、交換しても変わらないとする。
\begin{eqnarray}
\hat{a}^\dagger_k \hat{a}^\dagger_l = \hat{a}^\dagger_l \hat{a}^\dagger_k
\end{eqnarray}

消滅演算子\(\hat{a}_k\)と生成演算子\(\hat{a}^\dagger_l\)については、\(k \neq l\)の時は、交換しても変わらないとする。即ち、
\begin{eqnarray}
\hat{a}_k \hat{a}^\dagger_l = \hat{a}^\dagger_l \hat{a}_k
\end{eqnarray}

また、\(k = l\)の時は、生成させた後に消滅させることになる。これは何もしなかったことと同じなので、1ということにする。
\begin{eqnarray}
\hat{a}_k \hat{a}^\dagger_l= 1
\end{eqnarray}

そこで、
\begin{eqnarray}
\hat{a}^\dagger_l \hat{a}_l = 0
\end{eqnarray}
を考慮すると、
\begin{eqnarray}
\hat{a}_k \hat{a}^\dagger_l = \delta_{kl} + \hat{a}^\dagger_l \hat{a}_k
\end{eqnarray}
となる。なお、\(\delta_{kl}\)はδ関数で、\(k = l\)の時は\(1\)、\(k \neq l\)の時は\(0\)である。

交換カッコ\([\hat{A},\hat{B}]=\hat{A},\hat{B}-\hat{B},\hat{A}\)を用いると、上記の式は
\begin{eqnarray}
[\hat{a}^\dagger_k \hat{a}^\dagger_l] &=& \hat{a}^\dagger_l \hat{a}_l = 0 \\
[\hat{a}^\dagger_k \hat{a}^\dagger_l] &=& \hat{a}^\dagger_l \hat{a}^\dagger_k = 0 \\
[\hat{a}_k \hat{a}^\dagger_l] &=& \delta_{kl}
\end{eqnarray}
となる。

8.2 フェルミ粒子

次に、フェルミ粒子に移ろう。\(P=-1\)から順序を変えると変わってしまうと考え、次のことが成り立っていると考える。

二つの生成演算子\(\hat{c}^\dagger_k\)と\(\hat{c}^\dagger_l\)については、符号が変わるとする。即ち、
\begin{eqnarray}
\hat{c}^\dagger_k \hat{c}^\dagger_l= -\hat{c}^\dagger_l \hat{c}^\dagger_k
\end{eqnarray}

但し、\(k = l\)の時は、
\begin{eqnarray}
\hat{c}^\dagger_k \hat{c}^\dagger_k= -\hat{c}^\dagger_k \hat{c}^\dagger_k
\end{eqnarray}
となる。これを満足するのは、\(\hat{c}^\dagger_k \hat{c}^\dagger_k=0\)の時だけである。このことから、フェルミ粒子は、同じ場所では、複数が同時に存在できないということになる。

二つの消滅演算子\(\hat{c}^\dagger_k\)と\(\hat{c}^\dagger_l\)についても、符号が変わるとする。
\begin{eqnarray}
\hat{c}^\dagger_k \hat{c}^\dagger_l= -\hat{c}^\dagger_l \hat{c}^\dagger_k
\end{eqnarray}

消滅演算子\(\hat{c}_k\)と生成演算子\(\hat{c}^\dagger_l\)については、\(k \neq l\)の時は、符号が変わるとする。即ち、
\begin{eqnarray}
\hat{c}_k \hat{c}^\dagger_l= -\hat{c}^\dagger_l \hat{c}_k
\end{eqnarray}

また、\(k = l\)の時は、生成させた後に消滅させることになる。これは、ボーズ粒子の時と同様に、何もしなかったことと同じなので、1ということにする。
\begin{eqnarray}
\hat{c}_k \hat{c}^\dagger_l= 1
\end{eqnarray}

そこで、前と同じように、
\begin{eqnarray}
\hat{c}^\dagger_l \hat{c}_l = 0
\end{eqnarray}
を考慮すると、
\begin{eqnarray}
\hat{c}_k \hat{c}^\dagger_l = \delta_{kl} - \hat{c}^\dagger_l \hat{c}_k
\end{eqnarray}
となる。

反交換カッコ\({\hat{c},\hat{B}}=\hat{A},\hat{B}+\hat{B},\hat{c}\)を用いると、上記の式は
\begin{eqnarray}
{\hat{c}^\dagger_k \hat{c}^\dagger_l} &=& \hat{c}^\dagger_l \hat{c}_l = 0 \\
{\hat{c}^\dagger_k \hat{c}^\dagger_l} &=& \hat{c}^\dagger_l \hat{c}^\dagger_k = 0 \\
{\hat{c}_k \hat{c}^\dagger_l} &=& \delta_{kl}
\end{eqnarray}
となる。



8.3 Haskellで実装する

フェルミ粒子では、状態が符号を持つため、これまで説明してきたケットをそのまま用いてフェルミ粒子の状態を表すことはできない。ケットに符号の情報をつける必要があるので、符号とケットを対にして表すことにしよう。また、演算子は、生成演算子あるいは消滅演算子の並びで表すことにしよう。この二つのことを念頭に置いて、Haskellを用いて実装することにする。

上記の方針に基づいて、真空状態\(|0>\)への演算子、即ち、生成演算子と消滅演算子の並びを、配列で定義することにする。配列の要素は、生成か消滅かの区別と何番目の格子点であるかを示せるように対で表した。対の右側は、文字+,-でそれぞれ生成か消滅を表す。左側は、格子点の番号である。そこで、ボーズ粒子とフェルミ粒子それぞれに次のようなデータ型を用意した。

data Boson = Boson [(Char, Integer)] deriving (Show)

data Fermion = Fermion [(Char, Integer)] deriving (Show)

1)ボーズ粒子に関する実装

ボーズ粒子への演算子の作用は、先にケットを考えた時と同じであるが、記憶を呼び戻すために、図を用いて詳しく説明しよう。
f:id:bitterharvest:20160911165511p:plain

図は、配列で表された演算子を一つずつ順番に読み込んで、状態を作り出しているようすを示したものである。

①は、処理の途中を示したもので、演算子の配列はまだ処理していない演算子の並びを示したものである。符号は、1か-1である。フェルミ粒子はいずれかをとるが、ボーズ粒子の場合は常に1である。真空状態から始めて、いくつかの演算子の並びを作用させた結果、①のようになったと仮定し、ここを説明の出発点とする。

①では、現在の状態は、格子点の番号が1と2に粒子がある状態である。演算子の配列は右端から読み込む。従って、現在の状態は、配列の右側の要素(+ 3)で示される生成演算子\(\hat{a}^\dagger_3\)を作用させて、次の状態を得る。ボーズ粒子の場合は、生成演算子を作用させた場合には、いかなる状態においても、指定されている格子点番号に粒子を加えてよいので、②で示される状態になる。

②では、消滅演算子\(\hat{a}_2\)を作用させる。現在の状態の中に、この演算子で指定されている格子点の番号に粒子があれば、それを消去すればよい(この理由はすぐ後で説明する)。従って、③で示される状態になる。
なお、指定された場所に粒子がない場合には、状態はないものとする。即ち、0にする。

③では、生成演算子\(\hat{a}^\dagger_1\)を作用させる。生成演算子なので、これが指定しているところに粒子を追加し、④で示される状態になる。

④は、最終結果である。

ところで、②での処理は簡単に述べたが、実際には次の図で示すような行程により粒子が消去される。しかし、プログラムでは、効率を優先に、存在しているかいないかを判断して消去の処理を行う。
f:id:bitterharvest:20160911165634p:plain

それでは、プログラムを示そう。実際には、ケットでの生成演算子+^と消滅演算子-^の処理をそのまま用いる。

bose :: Boson -> (Integer, (Ket Integer))
bose (Boson a) = bose' (reverse a) (1, KetZero)

bose' [] b = b
bose' ((a, b):s) (c, k)
  | a == '+' = bose' s (c, b +^ k)
  | a == '-' = bose' s (c, b -^ k)
  | otherwise = error "unexpected error in bose operation."

発生演算子\(\hat{a}^\dagger_2\)と\(\hat{a}^\dagger_3\)を作用させてみる。

これは、配列では次のようになる。

a = [('+', 3), ('+', 2)]

これをボーズ粒子に作用する演算子の配列にすると、

*Test4> a
[('+',3),('+',2)]
*Test4> Boson a
Boson [('+',3),('+',2)]

となる。

この演算子を作用させると

*Test4> bose $ Boson a
(1,,a3+,a2+| ...00(0)00... >)

なお、上の結果は対になっていて、左側のa3+,a2+| ...00(0)00... >が状態を表し、右側の1が符号を表す。ボーズ粒子の場合には常に符号は1である。

プログラムが正しく動いているかどうかを確認してみよう。
\(\hat{a}^\dagger_2\)と\(\hat{a}^\dagger_3\)を作用させた後で、消滅演算子\(\hat{a}_3\)を作用させてみよう。

*Test4> b
[('-',3),('+',3),('+',2)]
*Test4> Boson b
Boson [('-',3),('+',3),('+',2)]
*Test4> bose $ Boson b
(1,,a2+| ...00(0)00... >)

\(\hat{a}^\dagger_2\)と\(\hat{a}^\dagger_3\)を作用させた後で、消滅演算子\(\hat{a}_2\)を作用させてみよう。

*Test4> c
[('-',2),('+',3),('+',2)]
*Test4> Boson c
Boson [('-',2),('+',3),('+',2)]
*Test4> bose $ Boson c
(1,,a3+| ...00(0)00... >)

\(\hat{a}^\dagger_2\)と\(\hat{a}^\dagger_3\)を作用させた後で、生成演算子\(\hat{a}^\dagger_2\)を作用させてみよう。

*Test4> d
[('+',2),('+',3),('+',2)]
*Test4> Boson d
Boson [('+',2),('+',3),('+',2)]
*Test4> bose $ Boson d
(1,,a2+,a3+,a2+| ...00(0)00... >)

上手く動いているようである。それでは、入れ替え操作を説明した図を参考にして、\(|source>=\hat{a}^\dagger_2 \hat{a}^\dagger_1 |0>\)から、粒子を入れ替えて\(|target>=\hat{a}^\dagger_1 \hat{a}^\dagger_2 |0>\)を作り出すことを考えよう。

これには、2番目の粒子を3番目に移し、次に1番目の粒子を2番目に移し、最後に3番目の粒子を1番目に移すとよいので、
\begin{eqnarray}
P= \hat{a}^\dagger_1 \hat{a}_3 \hat{a}^\dagger_2 \hat{a}_1 \hat{a}^\dagger_3 \hat{a}_2
\end{eqnarray}

となる。そこで、
\begin{eqnarray}
|target> = P \hat{a}^\dagger_2 \hat{a}^\dagger_1 |0>
\end{eqnarray}
が求めるものとなる。

そこで、演算子の配列は次のようになる。

*Test4> h
[('+',1),('-',3),('+',2),('-',1),('+',3),('-',2),('+',2),('+',1)]

これをボーズ粒子に作用する演算子の配列にすると、

*Test4> Boson h
Boson [('+',1),('-',3),('+',2),('-',1),('+',3),('-',2),('+',2),('+',1)]

となる。

この演算子を作用させると

*Test4> bose $ Boson h
(1,,a1+,a2+| ...00(0)00... >)

これより
\( |target> \) =(1,,a1+,a2+| ...00(0)00... >)
となる。また、
\( |source> \)=(1,,a2+,a1+| ...00(0)00... >)
であることから、\(|target>=|source>\)であることが分かり、\(P=1\)が確認できた。

2)フェルミ粒子に関する実装

フェルミ粒子への演算子の作用は、ボーズ粒子の場合と比べると少し複雑である。それらは以下の点による。
1) 演算子を交換すると符号が変わる。
2) 同じ格子点の番号には二つの粒子は同時に存在できない。

それでは、フェルミ粒子の処理を図を用いて詳しく説明しよう。
f:id:bitterharvest:20160911165705p:plain

図は、配列で表された演算子を一つずつ順番に読み込んで、状態を作り出しているようすを示したものである。

①は、生成演算子\(\hat{a}^\dagger_1\)を作用させる。ここでは、現在の状態の中に、この演算子で指定された場所に粒子が存在しているかどうか調べる。もし、存在していなければ、粒子を追加する。存在していれば、同じ場所に複数の粒子が入ることができないので、状態はないものとする。即ち、0にする。この場合には、格子点の番号1の場所には粒子が存在しないので、次の状態を得る。その結果、②となる。

②では、消滅演算子\(\hat{a}_2\)を作用させる。現在の状態の中に、この演算子で指定されている格子点の番号に粒子があれば、それを消去する。そうでない場合には、状態はないものとする。即ち、0にする。

ところで、消去する場合には、消去の対象となる粒子がどこにあるかで、状態の符号が変わる。これは次のようにして得る。この粒子の左隣に並ぶまでにいくつの粒子と交換しなければならないかを数える。図の場合には、消去しようとする粒子は格子点番号が2(a2+なので)である。このためには、格子点番号3(a3+なので)の粒子と交換しなければならないので、交換数は1である。交換数が偶数の場合には符号はそのまま、奇数の場合には符号を反転させる。この場合は、符号は反転させることになるので、-1となる。そして、③となる。

③では、生成演算子\(\hat{a}^\dagger_1\)を作用させる。生成演算子なので、この場所に粒子が存在しているかどうかを調べる。存在しているので、状態はないものとする。即ち、0にする。

④は、最終結果である。

ところで、②での処理は簡単に述べたが、実際には次の図で示すような行程により粒子が消去される。粒子が並んだ後、これらの粒子を最も右側に位置するように移動する。
f:id:bitterharvest:20160911165740p:plain

この時、どちらの粒子も同じ交換数となる。従って、並んだ後、右側に移動させたときの交換数は、両者の交換数の合計となるので、必ず、偶数となる。従って、符号がどのように変わるかを調べるためには、隣に並ぶまでの交換数を求めれば十分である。

それでは、プログラムを示そう。singleは、発生演算子が指定した場所に粒子を加えた場合、単独なのか複数になるのかを調べる関数である。deleteは、消滅演算子が指定した場所から粒子を取り去る関数である。signは隣に並ばせるまでの交換数を調べる関数である。

fermi :: Fermion -> (Integer, (Ket Integer))
fermi (Fermion a) = fermi' (reverse a) (1, KetZero)

fermi' [] b = b
fermi' ((a, b):s) (c, k)
      | a == '+' = fermi' s (fg c b k)
      | a == '-' = fermi' s (fd c b k)
      | otherwise = error "unexpected error in fermi operation."
  where
    fg m a b
      | single a b = (m, a +^b)
      | otherwise = (m * (-1) ^ n, Zero)
    fg' _ Zero = Zero
    single a KetZero = True
    single a (x :+: xs) 
      | a == x = False 
      | otherwise = single a xs        
    fd m a b
      | b == p = (m, Zero)
      | otherwise = (m * (-1) ^ n, p) 
    p = delete b k
    delete a KetZero = KetZero
    delete a (x :+: xs) 
      | a == x = xs 
      | otherwise = x :+: delete a xs
    n = sign b k
    sign a KetZero = 0
    sign a (x :+: xs)
      | a == x = 0
      | otherwise = 1 + sign a xs

ボーズ粒子の時と同じように、発生演算子\(\hat{c}^\dagger_2\)と\(\hat{c}^\dagger_3\)を作用させてみる。

これは、前と同じで、配列では次のようになる。

a = [('+', 3), ('+', 2)]

これをフェルミ粒子に作用する演算子の配列にすると、

*Test4> a
[('+',3),('+',2)]
*Test4> Fermion a
Fermion [('+',3),('+',2)]

となる。

この演算子を作用させると

*Test4> fermi $ Fermion a
(1,,a3+,a2+| ...00(0)00... >

なお、上の結果は、ボーズ粒子の時と同じように、対になっていて、左側のa3+,a2+| ...00(0)00... >が状態を表し、右側の1が符号を表す。

プログラムが正しく動いているかどうかを確認してみよう。
\(\hat{c}^\dagger_2\)と\(\hat{c}^\dagger_3\)を作用させた後で、消滅演算子\(\hat{c}_3\)を作用させてみよう。

*Test4> b
[('-',3),('+',3),('+',2)]
*Test4> Fermion b
Fermion [('-',3),('+',3),('+',2)]
*Test4> fermi $ Fermion b
(1,,a2+| ...00(0)00... >)

\(\hat{c}^\dagger_2\)と\(\hat{c}^\dagger_3\)を作用させた後で、消滅演算子\(\hat{c}_2\)を作用させてみよう。

*Test4> c
[('-',2),('+',3),('+',2)]
*Test4> Fermion c
Fermion [('-',2),('+',3),('+',2)]
*Test4> fermi $ Fermion c
(-1,,a3+| ...00(0)00... >)

\(\hat{c}^\dagger_2\)と\(\hat{c}^\dagger_3\)を作用させた後で、生成演算子\(\hat{c}^\dagger_2\)を作用させてみよう。

*Test4> d
[('+',2),('+',3),('+',2)]
*Test4> Fermion d
Fermion [('+',2),('+',3),('+',2)]
*Test4> fermi $ Fermion d
(-1,0)

上手く動いているようである。それではボーズの時と同様に、\(|source>=\hat{c}^\dagger_2 \hat{c}^\dagger_1 |0>\)から、粒子を入れ替えて\(|target>=\hat{c}^\dagger_1 \hat{c}^\dagger_2 |0>\)を作り出すことを考えよう。

それはボーズ粒子の時と同じで、2番目の粒子を3番目に移し、次に1番目の粒子を2番目に移し、最後に3番目の粒子を1番目に移すとよい。従って、
\begin{eqnarray}
P= \hat{c}^\dagger_1 \hat{c}_3 \hat{c}^\dagger_2 \hat{c}_1 \hat{c}^\dagger_3 \hat{c}_2
\end{eqnarray}

となる。そこで、
\begin{eqnarray}
|target> = -P \hat{c}^\dagger_2 \hat{c}^\dagger_1 |0>
\end{eqnarray}
が求めるものとなる。

そこで、演算子の配列は次のようになる。

*Test4> h
[('+',1),('-',3),('+',2),('-',1),('+',3),('-',2),('+',2),('+',1)]

これをフェルミ粒子に作用する演算子の配列にすると、

*Test4> Fermion h
Fermion [('+',1),('-',3),('+',2),('-',1),('+',3),('-',2),('+',2),('+',1)]

となる。

この演算子を作用させると

*Test4> fermi $ Fermion h
(1,,a1+,a2+| ...00(0)00... >)

これより
\( |target> \) =(1,,a1+,a2+| ...00(0)00... >)
となる。また、
\( |source> \) =(1,,a2+,a1+| ...00(0)00... >)
であることから、\(| target>=-|source>\)であることが分かり、\(P=-1\)が確認できた。

注意:なお、\(\hat{c}^\dagger_2,\hat{c}_l\)はプログラムではcl+,cl-ではなくal+,al-となっているので、注意すること。なお、気になるようであれば、プログラムを修正すること。

8.4 プログラムの全体

プログラムの全体を示す。

module Qtm.BoseFermi.BoseFermi (Boson (Boson), Fermion (Fermion), bose, fermi) where
import Qtm.KetBra.Ket

data Boson = Boson [(Char, Integer)] deriving (Show)

data Fermion = Fermion [(Char, Integer)] deriving (Show)

bose :: Boson -> (Integer, (Ket Integer))
bose (Boson a) = bose' (reverse a) (1, KetZero)

bose' [] b = b
bose' ((a, b):s) (c, k)
  | a == '+' = bose' s (c, b +^ k)
  | a == '-' = bose' s (c, b -^ k)
  | otherwise = error "unexpected error in bose operation."

fermi :: Fermion -> (Integer, (Ket Integer))
fermi (Fermion a) = fermi' (reverse a) (1, KetZero)

fermi' [] b = b
fermi' ((a, b):s) (c, k)
      | a == '+' = fermi' s (fg c b k)
      | a == '-' = fermi' s (fd c b k)
      | otherwise = error "unexpected error in fermi operation."
  where
    fg m a b
      | single a b = (m, a +^b)
      | otherwise = (m * (-1) ^ n, Zero)
    fg' _ Zero = Zero
    single a KetZero = True
    single a (x :+: xs) 
      | a == x = False 
      | otherwise = single a xs        
    fd m a b
      | b == p = (m, Zero)
      | otherwise = (m * (-1) ^ n, p) 
    p = delete b k
    delete a KetZero = KetZero
    delete a (x :+: xs) 
      | a == x = xs 
      | otherwise = x :+: delete a xs
    n = sign b k
    sign a KetZero = 0
    sign a (x :+: xs)
      | a == x = 0
      | otherwise = 1 + sign a xs

なおテストに用いたプログラムは以下の通りである。

module Test4 where

import Qtm.KetBra
import Qtm.BoseFermi.BoseFermi

a = [('+', 3), ('+', 2)]

b = [('-', 3), ('+', 3), ('+', 2)]

c = [('-', 2), ('+', 3), ('+', 2)]

d = [('+', 2), ('+', 3), ('+', 2)]

e = [('+',3), ('-',2), ('+',2), ('+',1)]

f = [('-',1), ('+',3), ('-',2), ('+',2), ('+',1)]

g = [('-',3), ('+',2), ('-',1), ('+',3), ('-',2), ('+',2), ('+',1)]

h = [('+',1), ('-',3), ('+',2), ('-',1), ('+',3), ('-',2), ('+',2), ('+',1)]