量子コンピュータ業界は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ゲートを適用します。
最終的に、Hゲートを適用した後の出力量子ビットの状態ベクトルは、
となりますので、位相は0もしくは1の出現確率をサンプルから求めることで三角関数の逆関数から位相を求めることができます。
早速実機を利用してみます。
まずはランダムな位相を決めて、シミュレータで解きます。
from blueqat import Circuit
import numpy as np
theta = np.random.rand()*np.pi
shots = 1000
res = Circuit(2).x[1].h[0].cphase(theta)[0,1].h[0].m[0].run(shots = shots)
p0 = res['00'] / shots
theta_est = np.arccos(2 * p0 - 1)
print("θ推定値 :", theta_est)
print("実際の値 :", theta)
θ推定値 : 1.2387270042036784
実際の値 : 1.3008068934502068
res
Counter({'10': 337, '00': 663})
シミュレータですとサンプリングでも結構いい精度で出せましたね。次に実機を準備します。今回はbraketをつかってblueqat cloud経由でAPIをたたいてみます。
from braket.circuits import Circuit
from braket.device_schema import GateModelParameters
from braket.device_schema.rigetti import RigettiDeviceParameters
from braket.device_schema.ionq import IonqDeviceParameters
import json
import urllib.request
f = open('../.pass', 'r', encoding='UTF-8')
API_KEY = f.read()[:-1]
f.close()
API_ENDPOINT = "https://cloudapi.blueqat.com/v2/"
def post_request(path, body):
headers = {
"Content-Type": "application/json",
"X-Api-Key": API_KEY,
}
req = urllib.request.Request(
API_ENDPOINT + path, json.dumps(body).encode(), headers
)
with urllib.request.urlopen(req) as res:
body = res.read()
return json.loads(body)
def get_quantum_tasks(body):
path = "quantum-tasks/list"
return post_request(path, params)
def get_quantum_task_status(id):
path = "quantum-tasks/get/status"
body = {
"id": id,
}
return post_request(path, body)
def get_quantum_task(id):
path = "quantum-tasks/get"
body = {
"id": id,
}
return post_request(path, body)
def create_quantum_task(body):
path = "quantum-tasks/create"
return post_request(path, body)
#circuit
circuit = Circuit().x(1).h(0).cphaseshift(0, 1, theta).h(0)
paradigm_parameters = GateModelParameters(
qubitCount=circuit.qubit_count, disableQubitRewiring=False
)
# rigetti
dprig = RigettiDeviceParameters(paradigmParameters=paradigm_parameters)
dprig.json()
params = {
"action": circuit.to_ir().json(),
"device": "aws/rigetti/Aspen-9",
"deviceParameters": dprig.json(),
"shots": 1000,
"taskGroup": "",
"sendEmail": False,
}
result = create_quantum_task(params)
tid = get_quantum_tasks({"index":0})['tasks'][0]['id']
res = get_quantum_task(tid)
a = res['result']['measurements']
b = []
for i in a:
b.append("".join(map(str, i)))
import collections
c = collections.Counter(b)
c
Counter({'00': 18, '11': 539, '01': 377, '10': 66})
p0_2 = c['01'] / 1000
theta_est2 = np.arccos(2 * p0_2 - 1)
print("θ推定値 :", theta_est2)
print("実際の値 :", theta)
θ推定値 : 1.8193475889282924
実際の値 : 1.3008068934502068
ある程度は計算できている気がしますが、全然違う答えが出ることも結構あります。。。実機での位相推定はIonQを今度はやってみたいと思います。以上です。