スワップテスト
アダマールゲートに続いてスワップテストです。 これはアダマールテストのユニタリーゲートについて、SWAPゲートを用いる場合です。 大雑把には制御量子ビット・入力量子ビット1(標的量子ビット1)・入力量子ビット2(標的量子ビット2)の3種類の役割を持つ量子ビットが存在します。 (入力量子ビットは1量子ビットとは限らず、複数量子ビットからなる場合もあります。) 入力量子ビット1, 2を2つのベクトルとした場合の2ベクトル間の内積を評価する量子回路です。
内積を評価する場面はさまざまあり、実装も簡単なため量子機械学習ほか様々な場面で使われるようです。
前提とする知識
- 線形代数がわかること
- 簡単な論理演算(AND, OR, NOT)が分かること
- 基本的な量子ゲート(X, CX, CCX)が分かること
バージョン情報
- Python 3.9.13
- Qiskit 0.36.2
目次
SWAPテスト回路
アダマールテストおさらい
アダマールテストの詳細については前回の解説を参照してください。
量子回路の形は下図の通りで、この回路を使うことで、ユニタリーによって第一量子ビットを測定した時の状態の確率分布を変化させられることがSWAPテストでは重要な意味があります。
この時の第一量子ビットの及び状態の確率分布は以下です。
SWAPテスト回路の理論
SWAPテストによって二つのベクトルの内積を計算できます。 内積の値がアダマールテストの第一量子ビットの確率分布に反映されるのでその確率から内積を逆算できる、ということです。
入力する2つの量子状態を以下のように定義します。
この2つのベクトルを以下の量子回路に入力することで、その内積
を評価できます。
第一量子ビットの状態を測定した時に、となる確率が以下となることから内積を評価できます。
SWAPテストの仕組み導出
まずアダマールゲートを実行すると
そして前回解説した制御SWAPゲートにより入力ビットの状態を反転させると以下になります。
そして最後に第一量子ビットにアダマールゲートをかけると全体の量子状態の最終状態は以下になります。
補助量子ビットの状態がとなる確率はベクトルの成分の長さを求めれば良いので以下となります。
などは内積取ってしまったらただの数なので自由に交換できますので式を整理し
以上では愚直に計算しましたが、制御ユニタリで実行しているゲートに対応するものとしてSWAPゲートを示すにして実行したアダマールテストです。
SWAPゲートを示すユニタリーは以下です。
この行列の固有ベクトルは
のため、一般の入力状態
は固有状態とは限りません。
従って第一量子ビットの状態がである確率は以下となります。
ということで、やはり愚直にやった計算と一致しました。
そのためユニタリーがわかっていれば、今後アダマールテストの計算する時は愚直に計算しなくとも、確率の式に当てはめれば良いです。
この確率の式から、入力ベクトルが直交している場合は確率0.5で平行であれば確率1であることがわかる。(ベクトルの正負の向きまではわからない。)
SWAPテスト回路の実装
実際に内積を計算してみます。
単純なベクトルの計算
今はの二次元平面上のベクトルを考えています。
普段量子ビットを考えるときは[tex | 0 \rangle]とはBlock球面上の上下正反対を向いたベクトル(下図左)ですが、この二つのベクトルは正規直交基底(直交して、その平面・空間の軸に平行な単位ベクトル)なので直交座標上では直交しています(下図右)。
わかりやすい例だとならで ならです。
はに固定して、をからまで直交座標上で (Bloch球面上で)だけ連続的に変化させた時は
のため下図のようになります。(はBloch球面上のとなす角度)
からだけ角度が違うものがに一致して、確かに直交してになってますね。
スワップテスト回路で内積を計算
単純にベクトル計算した時と同じように、以下のようには固定してをY軸に周りにからを経由して一周してに戻るまで角度を変えていった場合に内積が計算できていることを確認します。
これでの角度を0からに変えた時に第一量子ビットでが観測される確率が下図です。
からを算出すると下図です。
ノイズの関係でマイナスになる関係で残念ながら自乗を外せません。
ベクトル計算から求めた場合と測定から求めた場合とでの誤差をRMSEで求めると0.02程度でした。
目盛の間隔が0.2ずつなのでその1/10です。
この誤差が大きいのか小さいのかは実際に解きたい問題に依存すると思うのでここでは評価しませんが、ほぼほぼベクトル計算だけから求めた場合と同等の値を測定から求められると思って良いと思います。
この時のソースです。
effs = np.linspace(0, 2, 51) print(effs) probs = [] for idx, eff in enumerate(effs): rad = np.pi * eff qr_control = QuantumRegister(1, 'control') qr_1 = QuantumRegister(1, 'a') qr_2 = QuantumRegister(1, 'b') cr = ClassicalRegister(1) qc = QuantumCircuit(qr_control, qr_1, qr_2, cr) qc.rx(rad, qr_2) qc.barrier() qc.h(qr_control) qc.cx(qr_1, qr_2) qc.ccx(qr_control, qr_2, qr_1) qc.cx(qr_1, qr_2) qc.h(qr_control) qc.barrier() qc.measure(qr_control, cr) backend = Aer.get_backend('qasm_simulator') job = execute(qc, backend, shot=1024) result = job.result() probs.append({ 'theta': rad, 'prob': calc_p0(result) }) df_result = pd.DataFrame(probs) display(df_result) thetas = np.linspace(0, 2, 51) thetas = np.asarray([theta * np.pi for theta in thetas]) cos = np.cos(thetas / 2) fig = plt.figure() plt.scatter(df_result['theta'] / np.pi, (df_result['prob']*2-1), marker='o', label='測定結果から求めた結果', color='blue') plt.plot(thetas / np.pi, cos**2, label='代数的に求めた結果', color='red', linewidth=2) rmse = sqrt(mean_squared_error(df_result['prob']*2-1, cos**2)) xlim = plt.xlim() ylim = plt.ylim() dy = ylim[1] - ylim[0] plt.text(x=xlim[0], y=ylim[0]+0.1*dy, s=f'RMSE: {rmse:.3f}', fontsize=12) plt.xlabel('θ / π', fontsize=15) plt.ylabel('|<a|b>|^2', fontsize=15) plt.legend(fontsize=12) plt.show() plt.close()
光の系でスワップテストを実装(ちゃんと読んでないですけど実験の提案だけかも)の論文がありました。