$$
\def\bra#1{\mathinner{\left\langle{#1}\right|}}
\def\ket#1{\mathinner{\left|{#1}\right\rangle}}
\def\braket#1#2{\mathinner{\left\langle{#1}\middle|#2\right\rangle}}
$$
自作の量子計算シミュレータを使って、任意方向からスピンの上下を測定してみるよ。
はじめに
「量子力学の基本:スピンと測定の不思議」で、X軸、Z軸方向からスピンの上下を測定してみて、量子力学の不思議さを実感してみましたが、特定軸方向ではない、任意の方向からスピンを測定してみるとどうなるかが気になります。
ちょうど、ここ(↑)に良い解説があります。それによると、ある軸方向(例えばX軸)上向きに100%向いているスピンがあったとき、これをZ軸周りに角度$\phi$だけ傾けた方向から測定すると、上向きが観測される確率は理論的には、$$cos^{2}\frac{\phi}{2}$$に等しくなるとのことです(EMANでは、$\phi$ではなく$\theta$という記号が使われていますが)。このことをこれからシミュレータで確認してみたいと思います。
シミュレータで測定
Linuxコマンドではなく、Pythonでやってみます。コードは以下の通りです。簡単なコードなので、見てすぐわかると思いますが、measure関数の引数phaseに、上の$\phi$に相当する値を次々に入れていって、確率を計測して、合わせて理論値も出力するようにしています。
import math
from qlazypy import QState
def measure(phase):
qs = QState(1)
qs.h(0)
freq_list = qs.m(id=[0],angle=0.5,phase=phase).frq
prob = freq_list[0] / 100
print("===")
print("phase = {0:.4f} PI".format(phase))
print("[measured] prob. of up-spin = {0:.4f}".format(prob))
print("[theoretical] cos(phase/2)^2 = {0:.4f}".format((math.cos(phase*math.pi/2))**2))
del qs
def main():
measure(0.0)
measure(0.25)
measure(0.5)
measure(0.75)
measure(1.0)
if __name__ == '__main__':
main()
measure関数で何をやっているか一応簡単に説明します。
qs = QState(1)
qs.h(0)
まず、QStateで量子ビットを1個初期化します。量子状態は$\ket{0}$になります。つまり、Z軸方向上向きのスピンが1個生成されたと思ってください。次に、この量子ビットに対してアダマールゲートを適用します。そうすると、スピンはX軸方向上向きになります(上向きと言っていますが、ブロッホ球上では横に寝るイメージですが)。
freq_list = qs.m(id=[0],angle=0.5,phase=phase).frq
prob = freq_list[0] / 100
量子状態qsに適用されているm()メソッドでスピンの上下を測定するのですが、ここで、引数idには測定する量子ビット番号のリスト、引数angleにはZ軸上向きとのなす角$\theta$、引数phaseにはZ軸周りの回転角$\phi$(X軸プラス方向が基準)を指定し、測定の方向を表します。ブロッホ球をイメージしていただければ良いです。ここで、phase,angleの単位は$\pi$ラジアンです。なので、0.5は$0.5\pi$を表します。上のコードでは指定していませんが、引数shotsに試行回数も指定できます(デフォルトは100回です)。測定結果のヒストグラムは、frqプロパティで取得することができ、今の場合、frq_listとして格納されます。また、上のコードでは使っていませんが、lstプロパティで最後の測定結果(int)も取得できます。いま、計測したいのは上向きスピンの確率なので、frq_list[0]を試行回数100で割っています。
後は適当に表示して、最後に、
del qs
で、qsのメモリを解放しています。qlazyでは内部の計算はC言語で実装していて、CtypesでPythonから呼び出すようにしています。Cで動的確保したメモリは、明示的に解放してあげないといけないようなので、そうしています。
というわけで、実行してみます。
$ python measure_spin_any_direction.py
以下のような結果が得られました。
===
phase = 0.0000 PI
[measured] prob. of up-spin = 1.0000
[theoretical] cos(phase/2)^2 = 1.0000
===
phase = 0.2500 PI
[measured] prob. of up-spin = 0.8800
[theoretical] cos(phase/2)^2 = 0.8536
===
phase = 0.5000 PI
[measured] prob. of up-spin = 0.4900
[theoretical] cos(phase/2)^2 = 0.5000
===
phase = 0.7500 PI
[measured] prob. of up-spin = 0.1500
[theoretical] cos(phase/2)^2 = 0.1464
===
phase = 1.0000 PI
[measured] prob. of up-spin = 0.0000
[theoretical] cos(phase/2)^2 = 0.0000
どうでしょうか。だいたい理論値とあってますよね。ということで、一応ちゃんと実装されてますなー、という確認でした。
以上