量子コンピュータ業界はFTQCと呼ばれる誤り訂正ありの量子コンピュータへと向かい始めました。ここでは、FTQCのうち、暗号解読や量子化学計算などに利用される量子位相推定アルゴリズムを取り上げますが、その前段階として位相キックバックと呼ばれるテクニックを実機で確認します。
こちらのチュートリアルを参考とします。
量子コンピュータの文脈でたびたび出現する固有値問題ですが、ユニタリゲート
$$
U|\psi\rangle = e^{i\theta}|\psi\rangle
$$
今回はチュートリアルの例題に合わせて、ユニタリーゲートが下記のゲートの場合の固有値の位相を求めてみます。
$$
U = \begin{bmatrix}1 & 0\ 0 & e^{i\theta}\end{bmatrix}
$$
細かい内容は上記のチュートリアルを見てもらうと助かりますが、固有状態は
位相キックバックでは制御Uゲートを準備します。
|0> --H--*--H--測定
|
|1> -----U-----
出力の回路を重ね合わせで準備し、入力の回路に固有状態を入力します。そして、制御ユニタリを利用して位相キックバックを行います。位相キックバックされた後の量子状態は|1>の出現確率は位相でしか見れないので、位相情報を取り出す必要があります。今回は1量子ビットの量子フーリエ変換に対応するHゲートを適用します。
まずはランダムな位相を決めて、シミュレータで解きます。今回はIonQにジョブを投入する際に角度が大きいもしくはマイナスだと投入できなかったので、ちょっとrzのマイナス角度のところをZとSとRZに分解して実行しています。
from blueqat import Circuit
from bqcloud import load_api, Device
import numpy as np
theta = np.random.rand() * np.pi
shots=1000
#c = Circuit(2).h[0].x[1].rz(theta)[1].cnot[0,1].rz(-theta/2)[1].cnot[0,1].rz(-theta/2)[1].rz(theta/2)[0].h[0].m[:].run(shots=shots)
c = Circuit().h[0].x[1].rz(theta)[1].cnot[0,1].z[1].s[1].rz(np.pi/2-theta/2)[1].cnot[0,1].z[1].s[1].rz(np.pi/2-theta/2)[1].rz(theta/2)[0].h[0].m[:].run(shots=shots)
print(c)
p0 = c['01'] / shots
theta_est = np.arccos(2 * p0 - 1)
print("θ推定値 :", theta_est)
print("実際の値 :", theta)
Counter({'01': 774, '11': 226})
θ推定値 : 0.9908249432160733
実際の値 : 1.007552805352795
次にさっそく実機で実行します。シミュレータではうまくいっていました。IonQでも1000ショットでチャレンジをします。
#キーの読み込み
api = load_api()
task = api.execute(Circuit().h[0].x[1].rz(theta)[1].cnot[0,1].z[1].s[1].rz(np.pi/2-theta/2)[1].cnot[0,1].z[1].s[1].rz(np.pi/2-theta/2)[1].rz(theta/2)[0].h[0], Device.IonQDevice, shots)
result = task.wait(timeout=300)
c2 = result.shots()
print(c2)
p0_2 = c2['01'] / shots
theta_est_2 = np.arccos(2 * p0_2 - 1)
print("θ推定値シミュレータ :", theta_est)
print("θ推定値IonQ実機 :", theta_est_2)
print("実際の値 :", theta)
Counter({'01': 895, '11': 69, '00': 25, '10': 11})
θ推定値シミュレータ : 0.9908249432160733
θ推定値IonQ実機 : 0.6599873293874984
実際の値 : 1.007552805352795
このようになりました。ショットの数がやはりずれてしまいますので、精度の高い計算はまだまだ工夫が必要そうです。位相キックバックを行いました。以上です。