位相推定#

量子位相推定(Quantum phase estimation, QPE)アルゴリズムは、最も重要で有名な量子アルゴリズムの1つです。Shorの因数分解アルゴリズムの重要なサブルーチンであり、量子シミュレーションのアルゴリズムでもあります。
教科書で解説されるバージョンでは精度に応じて数がスケールする補助量子ビットを使用しているため、今日のノイズのあるデバイスでは量子ビットの数や接続性が限られていることから実行が困難です。

そこで反復位相推定(Iterative phase estimation, IPE)という、1つの補助量子ビットしか必要としないQPEの派生バージョンを考えます。IPEでは補助量子ビットを繰り返し測定し、測定結果をその後の量子演算の補助として利用する古典的なフィードフォワード制御が必要となります。 このLabではQiskitのDynamic Circuitの機能を使ってIPEを実装してみましょう。

背景#

他の位相推定アルゴリズムと同じように、IPEは以下の問題を解くために設計されています:

問題文: ユニタリー行列 \(U\) と 未知の固有値 \(e^{i 2\pi \varphi}\) を持つ \(U\) の固有状態 \(|\Psi\rangle\) が与えられたとき、 \(\varphi\) の値を推定せよ。

この問題文では、いくつか重要な前提を明確にする必要があります。すなわち、 \(U\)\(|\Psi\rangle\) がどのように指定されるかです。 \(U\)\(U\) を実装した量子回路として与えられ、正の整数 \(t\) に対して制御 \(U^{2^t}\) という演算を効率よく実装できる能力があると仮定します。これは、オリジナルのQPEアルゴリズムで用いられたものと同じ仮定です。固有状態も量子回路として与えられます:つまり、 \(|\Psi\rangle\) を効率的に準備できると仮定します。

まず、簡単にするために \(\varphi\) が正確にバイナリ展開できる、つまり、次のように書くことができると仮定します。

\[ \varphi = \varphi_1/2 + \varphi_2/4 + \cdots + \varphi_m/2^m = 0.\varphi_1 \varphi_2 \cdots \varphi_m \]

ここで、最後の等式では、二進数の「小数」表記を使用しています。簡略化のため \(U\) が単一量子ビットに作用するユニタリー演算子であるとします(ここで述べていることはすべて \(U\) が複数の量子ビットに作用する場合にも適用されます)。IPEは補助量子ビットを必要とするので、 \(q_0\)\(q_1\) という2つの量子ビットの系が必要であり、 \(q_0\) は補助量子ビット、 \(q_1\)\(U\) が作用する物理系を表します。

ここで、 \(q_0\)\(|+\rangle = \frac{|0\rangle + |1\rangle}{\sqrt{2}}\) の状態に、 \(q_1\)\(|\Psi \rangle\) の状態に初期化するとします。
\(q_0\) をコントロール、 \(q_1\) をターゲットとして、 \(controlled-U^{2^t}\) ゲートを適用するとどうなるでしょうか? \(|\Psi \rangle\) は固有値 \(e^{i 2\pi \varphi}\) を持つ \(U\) の固有状態であるため、次のようになります。

\[\begin{split} \begin{align} |+\rangle |\Psi \rangle &= \left(\frac{|0\rangle + |1\rangle}{\sqrt{2}}\right) |\Psi \rangle \\ &= \frac{|0\rangle |\Psi \rangle + |1\rangle |\Psi \rangle}{\sqrt{2}} \\ &\xrightarrow{\text{controlled-}U^{2^t}} \frac{|0\rangle |\Psi \rangle + e^{i 2 \pi 2^{t} \varphi} |1\rangle |\Psi \rangle}{\sqrt{2}} \\ &= \left(\frac{|0\rangle + e^{i 2 \pi 2^{t} \varphi} |1\rangle}{\sqrt{2}}\right) |\Psi \rangle. \end{align} \end{split}\]

つまり、系の量子ビットの状態は変化せず、補助量子ビットの状態に位相 \(e^{i 2 \pi 2^{t} \varphi}\) が「キックバック」されました。

さて、位相は以下のように変形することが可能です。

\[ e^{i 2 \pi 2^{t} \varphi} = e^{i 2 \pi 2^{t} (0.\varphi_1 \varphi_2 \cdots \varphi_m)} = e^{i 2 \pi (\varphi_1 \cdots \varphi_t . \varphi_{t + 1} \cdots \varphi_m)} = e^{i 2 \pi (0. \varphi_{t + 1} \cdots \varphi_m)}, \]

最後の等式では、任意の整数 \(n\) に対して \(e^{i 2\pi n} = 1\) であるため、位相の「小数」表現の整数部分が消えています。 例えば:

  • \(t=0\) の場合、位相は \(e^{i 2 \pi 2^{0} \varphi} = e^{i 2 \pi \varphi} = e^{i 2 \pi 0.\varphi_1 \varphi_2 ... \varphi_m}\)

  • \(t=1\) の場合、位相は \(e^{i 2 \pi 2^{1} \varphi}= e^{i 2 \pi \varphi_1} e^{i 2 \pi 0.\varphi_2 \varphi_3 ... \varphi_m} = e^{i 2 \pi 0.\varphi_2 \varphi_3 ... \varphi_m}\)

  • \(t=2\) の場合、位相は \(e^{i 2 \pi 2^{2} \varphi} = e^{i 2 \pi 0.\varphi_3 \varphi_4 ... \varphi_m}\)

  • \(t=m-1\) の場合、位相は \(e^{i 2 \pi 2^{m-1} \varphi} = e^{i 2 \pi 0.\varphi_m}\)

\(t = m - 1\) の最後のケースでは、位相は \(e^{i 2 \pi 0.\varphi_m}\) で、 \(\varphi_m = 0\) の場合は \(1\)\(\varphi_m = 1\) の場合は \(-1\) に等しくなります。
前者は、補助量子ビット \(q_0\)\(|+\rangle = \frac{|0\rangle + |1\rangle}{\sqrt{2}}\) の状態になり、後者は \(|-\rangle = \frac{|0\rangle - |1\rangle}{\sqrt{2}}\) の状態になります。
したがって、量子ビットに対してアダマール ゲートを実行すると前者は \(|0\rangle\) 、後者は \(|1\rangle\) の状態になり、これは \(\varphi_m\) と一致します。つまりパウリの \(X\) 基底で量子ビットを測定することで \(\varphi_m\) の情報を得ることが出来ます。

アルゴリズムの概要#

上記を前提にIPEアルゴリズムを考えていきます。
最初のステップでは、上記で説明したように 2 量子ビットレジスターを初期化 ( \(q_0 \rightarrow |+\rangle\)\(q_1 \rightarrow |\Psi \rangle\) )し、 \(controlled-U^{2^{m-1}}\) を実行してパウリの \(X\) 基底で \(q_0\) を測定することで、位相 \(\varphi\) の最下位ビット \(\varphi_m\) を直接測定します。

次のステップでは、同じ方法で系を初期化し、 \(controlled-U^{2^{m-2}}\) 演算を適用します。 この操作後の \(q_0\) の相対位相は \(e^{i 2 \pi 0.\varphi_{m-1}\varphi_{m}}= e^{i 2 \pi 0.\varphi_{m-1}} e^{i 2 \pi \varphi_m/4}\) になります。 位相ビット \(\varphi_{m-1}\) を抽出するには、まず \(Z\) 軸の周りを角度 \(-2 \pi \varphi_m/4=-\pi \varphi_m/2\) だけ回転させて位相補正を実行します。その結果、\(q_0\) の状態は \(|0\rangle + e^{i 2 \pi 0.\varphi_{m-1}} | 1 \rangle\) になります。 パウリの \(X\) 基底で \(q_0\) の測定を実行し、位相ビット \(\varphi_{m-1}\) を取得します。

したがって、 \(\varphi_{m-k+1}\) を取得する IPE の \(k\) 番目のステップは、

  1. レジスターの初期化 (\(q_0\)\(|+\rangle\) に、 \(q_1\)\(|\Psi\rangle\) に)

  2. \(controlled-U^{2^{m-k}}\) の適用

  3. \(Z\) 軸周りの角度 \(\omega_k = -2 \pi 0.0\varphi_{m-k+2} ... \varphi_m\) の回転

  4. パウリの \(X\) 基底での \(q_0\) の測定(つまり、 \(q_0\) をアダマール変換後、計算基底で \(q_0\) を測定)

から構成されます。
\(q_1\) はアルゴリズム全体を通じて状態 \(|\Psi\rangle\) のままであることに注意してください。

Qiskitによる実装#

このLabでは、単一量子ビットの \(S\) ゲートのIPEを行います。 \(S\) ゲートは次の行列で与えられます。

import qiskit
qiskit.__version__
'1.4.2'
from qiskit.quantum_info import Operator
display(Operator.from_label('S').draw('latex'))
\[\begin{split}\begin{bmatrix} 1 & 0 \\ 0 & i \\ \end{bmatrix} \end{split}\]

固有値 \(i = e^{i\pi / 2}= e^{i2\pi \cdot 1/4}\) を持つ固有ベクトル \(|\Psi\rangle = |1\rangle\) を使います。
よって、 \(\varphi = 1/4 = 0.01 = 0.\varphi_1 \varphi_2\) となります。 \(\varphi\) は2ビットで完全に表現できるため、結果を格納するための2ビットの古典ビットを持つ量子回路を用意します。

制御 \(S\) ゲートは、制御位相ゲート(Qiskitでは CPhaseGate )を使って実装でき、 QuantumCircuitcp メソッドを呼び出すことでも適用できます。
制御位相ゲートは角度 \(\theta\) でパラメーター化され、次の行列を持ちます。

\[\begin{split} \text{CPhase}(\theta) = \begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & e^{i\theta} \end{pmatrix} \end{split}\]

ステップ1: \(\varphi\)の最下位ビットの測定#

アルゴリズムの最初のステップで、 \(\varphi\)の最下位ビットを測定します。

  1. 量子ビットを初期化:

    • 補助量子ビットにアダマールゲートを適用

    • Xゲートをシステムの量子ビットに適用 (\(|1\rangle\) )

  2. 適当な角度の CPhaseGate を適用することで、制御 \(S^{2}\) ゲートを適用

  3. \(X\) 基底で補助量子ビットを測定:

    • 補助量子ビットにアダマールゲートを適用

    • 計算基底で上記を測定

回路は以下のようになるはずです:

step1-circuit

Exercise: ステップ1の実装#

Exercise

ステップ1の実行をQiskitで実装してみましょう。

from qiskit import ClassicalRegister, QuantumCircuit, QuantumRegister
import numpy as np


def step_1_circuit(qr: QuantumRegister, cr: ClassicalRegister) -> QuantumCircuit:
    # qr is a quantum register with 2 qubits
    # cr is a classical register with 2 bits

    qc = QuantumCircuit(qr, cr)

    ####### your code goes here #######

    return qc


qr = QuantumRegister(2, "q")
cr = ClassicalRegister(2, "c")
qc = QuantumCircuit(qr, cr)
qc = step_1_circuit(qr, cr)
qc.draw("mpl")
Hide code cell content
from qiskit import ClassicalRegister, QuantumCircuit, QuantumRegister
import numpy as np


def step_1_circuit(qr: QuantumRegister, cr: ClassicalRegister) -> QuantumCircuit:
    # qrは2量子ビットレジスタ
    # crは2古典ビットレジスタ

    qc = QuantumCircuit(qr, cr)

    ##1. 量子ビットを初期化
    q0, q1 = qr
    # 補助量子ビット(q0)にアダマールゲートを適用
    qc.h(q0)
    # Xゲートをシステムの量子ビットに適用し、|1>の状態にする。
    qc.x(q1)

    ##2. 制御位相ゲートを適用する。
    # 制御Sゲートは位相πのCPhaseと等しい
    s_angle = np.pi / 2
    # 制御Sゲートを2^k回適用する。
    # 今回は2量子ビットであり、ステップ1なので、k=2-1=1
    k = 1
    cphase_angle = s_angle * 2**k
    # 制御位相ゲートを適用
    qc.cp(cphase_angle, q0, q1)

    ##3. X基底で補助量子ビットを測定する。
    # 補助量子ビット(q0)にアダマールゲートを適用
    qc.h(q0)
    # 測定し、結果をc0に格納
    c0, _ = cr
    qc.measure(q0, c0)

    return qc


qr = QuantumRegister(2, "q")
cr = ClassicalRegister(2, "c")
qc = QuantumCircuit(qr, cr)
qc = step_1_circuit(qr, cr)
qc.draw("mpl")
_images/16e9257e36b16692f744969257c4be913b756f01309769febab236497548e80a.png

ステップ 2: \(\varphi\) の次のビットの測定#

ステップ 1では、最下位ビット \(\varphi_2\) を測定しました。ステップ 2では、次のビット \(\varphi_1\) を抽出します。
このとき、 \(\varphi_2\) からの位相寄与を打ち消すために位相補正を適用することになります。この位相補正は、 \(\varphi_2\) の測定結果を保持する古典レジスターの値を用います。この古典的なフィードバックを行うには、Dynamic circuitが必要です。
位相補正は、 PhaseGate を使うか、QuantumCircuitの p メソッドを呼び出すことで適用することができます。

ステップ1に続き以下のステップを実行することで、 \(\varphi\) の次のビットを得ることができます:

  1. 補助量子ビットをリセットして再初期化

  2. 制御ユニタリーゲートを適用

  3. 補助量子ビットを \(X\) 基底で測定

回路は、以下のようになるはずです:

step1-circuit

Exercise: ステップ2の実装#

Exercise

ステップ2の実行をQiskitで実装してみましょう。 このExerciseでは、Exercise1で作成したステップ1の回路から始めます。

def step_2_circuit(qr: QuantumRegister, cr: ClassicalRegister) -> QuantumCircuit:
    # qr is a quantum register with 2 qubits
    # cr is a classical register with 2 bits

    # begin with the circuit from Step 1
    qc = step_1_circuit(qr, cr)

    ####### your code goes here #######

    return qc


qr = QuantumRegister(2, "q")
cr = ClassicalRegister(2, "c")
qc = QuantumCircuit(qr, cr)
qc = step_2_circuit(qr, cr)
qc.draw("mpl")
Hide code cell content
def step_2_circuit(qr: QuantumRegister, cr: ClassicalRegister) -> QuantumCircuit:
    # qrは2量子ビットレジスタ
    # crは2古典ビットレジスタ

    # Exercise1で作成したステップ1の回路から始める。
    qc = step_1_circuit(qr, cr)

    ####### your code goes here #######

    ##1. 補助量子ビットをリセットして再初期化する。
    q0, q1 = qr
    # 補助量子ビットのリセット(|0>)
    qc.reset(q0)
    # アダマールゲートを適用し初期化
    qc.h(q0)

    ##2. φ_2の位相寄与を打ち消すために位相補正を適用
    c0, c1 = cr
    # 位相寄与は|1>のみに出るので、|0>のみについて位相補正を適用
    with qc.if_test((c0, 1)) as else_:
        qc.p(-np.pi/2, q0)

    
    ##3. 制御位相ゲートを適用する。
    # 制御Sゲートは位相πのCPhaseと等しい
    s_angle = np.pi / 2
    # 制御Sゲートを2^k回適用する。
    # 今回は2量子ビットであり、ステップ2なので、k=2-2=0
    k = 0
    cphase_angle = s_angle * 2**k
    # 制御位相ゲートを適用
    qc.cp(cphase_angle, q0, q1)

    ##4. X基底で補助量子ビットを測定する。
    # 補助量子ビット(q0)にアダマールゲートを適用
    qc.h(q0)
    # 測定し、結果をc1に格納
    qc.measure(q0, c1)

    return qc


qr = QuantumRegister(2, "q")
cr = ClassicalRegister(2, "c")
qc = QuantumCircuit(qr, cr)
qc = step_2_circuit(qr, cr)
qc.draw("mpl")
_images/40e82976a7b5a055537c343a164219f37b633b697b82b01e45d9c908eed3b504.png

シミュレーター上での実行#

回路が完成したので、まずローカルシミュレーターで動かしてみましょう。

from qiskit_aer import AerSimulator

sim = AerSimulator()
job = sim.run(qc, shots=1000)
result = job.result()
counts = result.get_counts()
counts
{'01': 1000}

回路が正しければ、100%の確率でビット列 01 が得られるはずです。
この値は、2進数で \(\varphi = 0.01 = 1/4\) と書かれた位相に対応します。これは正しい位相です!

Exercise: Tゲートの位相推定回路#

Exercise

以下で与えられる行列を持つ、Tゲートの位相を推定するIPE回路を構築してください。

\[\begin{split} T = \begin{bmatrix} 1 & 0\\\\ 0 & e^{i\pi / 4}\\\\ \end{bmatrix}\end{split}\]

この場合、位相を表すのに必要なビットは何ビットですか?

from qiskit import ClassicalRegister, QuantumCircuit, QuantumRegister
import numpy as np


def t_gate_ipe_circuit(qr: QuantumRegister, cr: ClassicalRegister) -> QuantumCircuit:
    # qr is a quantum register with 2 qubits
    # cr is a classical register with 3 bits

    qc = QuantumCircuit(qr, cr)

    ####### your code goes here #######

    return qc


qr = QuantumRegister(2, "q")
cr = ClassicalRegister(3, "c")
qc = QuantumCircuit(qr, cr)
qc = t_gate_ipe_circuit(qr, cr)
qc.draw("mpl")

\(T\) は固有値 \(e^{i\pi / 4}= e^{i2\pi \times \frac{1}{8}}\) を持ちます。

よって \(\varphi = \frac{1}{8} = 0.001_{(2)}\) であり、 \(\varphi \) は3ビットで完全に表現されます。

Hide code cell content
from qiskit import ClassicalRegister, QuantumCircuit, QuantumRegister
import numpy as np


def t_gate_ipe_circuit(qr: QuantumRegister, cr: ClassicalRegister) -> QuantumCircuit:
    # qrは2量子ビットレジスタ
    # crは3古典ビットレジスタ

    qc = QuantumCircuit(qr, cr)

    # 初期化する
    q0, q1 = qr
    qc.h(q0)
    qc.x(q1)

    # 最下位の位相ビットを取得するために必要なだけ制御ユニタリ演算子を適用する
    t_angle = np.pi / 4
    k = 2
    cphase_angle = t_angle * 2**k
    qc.cp(cphase_angle, q0, q1)

    # X基底で補助量子ビットを測定する
    qc.h(q0)
    c0, c1, c2 = cr
    qc.measure(q0, c0)

    # 補助量子ビットをリセットし、アダマールゲートで再初期化する
    qc.reset(q0)
    qc.h(q0)

    # 最初の古典ビットを条件として位相補正を適用する
    with qc.if_test((c0, 1)):
        qc.p(-np.pi / 2, q0)

    # 次の位相ビットを取得するために必要なだけ制御ユニタリ演算子を適用する
    k = 1
    cphase_angle = t_angle * 2**k
    qc.cp(cphase_angle, q0, q1)

    #  X基底で補助量子ビットを測定し、2番目の古典ビットに格納する
    qc.h(q0)
    qc.measure(q0, c1)

    # 補助量子ビットをリセットし、アダマールゲートで再初期化する
    qc.reset(q0)
    qc.h(q0)

    # 一番目と二番目の古典ビットを条件として位相補正を適用する
    with qc.if_test((c0, 1)):
        qc.p(-np.pi / 4, q0)
    with qc.if_test((c1, 1)):
        qc.p(-np.pi / 2, q0)

    # さらに次の位相ビットを取得するために必要なだけ制御ユニタリ演算子を適用する
    k = 0
    cphase_angle = t_angle * 2**k
    qc.cp(cphase_angle, q0, q1)

    #  X基底で補助量子ビットを測定し、3番目の古典ビットに格納する
    qc.h(q0)
    qc.measure(q0, c2)

    return qc


qr = QuantumRegister(2, "q")
cr = ClassicalRegister(3, "c")
qc = QuantumCircuit(qr, cr)
qc = t_gate_ipe_circuit(qr, cr)
qc.draw("mpl")
_images/a95be9cce2204346003bd6e432f624e226a9e07fe75c5aebe8512dedbed0efa8.png
from qiskit_aer import AerSimulator

sim = AerSimulator()
job = sim.run(qc, shots=1000)
result = job.result()
counts = result.get_counts()
counts
{'001': 1000}

位相が正確なバイナリ展開を持たない場合#

位相が正確にバイナリー展開をしない場合、例えば \(\varphi = 1/3\) の場合を考えてみましょう。 この場合、1量子ビットゲートは、次のユニタリー行列になります。

\[\begin{split} U = \begin{bmatrix} 1 & 0\\\\ 0 & e^{i2\pi / 3}\\\\ \end{bmatrix} \end{split}\]

角度 \(\varphi = 1/3\) は有限なバイナリー展開で正確に表現することはできず、無限のバイナリー展開となります。

\[ 1/3 = 0.010101\ldots \]

実際は有限のビット数の精度で作業するので、そのビット数で表現できる精度での近似値を得ることが目標になります。
次の例では2ビットの精度を使用することにします。この場合、最も近い値は \(0.01 = 1/4\)です。この値は正確な位相を表していないため、より精度の低い別の結果が得られる可能性があります。

このゲートの位相を測定するIPE回路を構築し、シミュレーションを行いましょう。

from qiskit import ClassicalRegister, QuantumCircuit, QuantumRegister
import numpy as np


def u_circuit(qr: QuantumRegister, cr: ClassicalRegister) -> QuantumCircuit:
    # qrは2量子ビットレジスタ
    # crは2古典ビットレジスタ

    qc = QuantumCircuit(qr, cr)

    # 初期化する
    q0, q1 = qr
    qc.h(q0)
    qc.x(q1)

    # 最下位の位相ビットを取得するために必要なだけ制御ユニタリ演算子を適用する
    u_angle = 2 * np.pi / 3
    k = 1
    cphase_angle = u_angle * 2**k
    qc.cp(cphase_angle, q0, q1)

    # X基底で補助量子ビットを測定する
    qc.h(q0)
    c0, c1 = cr
    qc.measure(q0, c0)

    # 補助量子ビットをリセットし、アダマールゲートで再初期化する
    qc.reset(q0)
    qc.h(q0)

    # 最初の古典ビットを条件として位相補正を適用する
    with qc.if_test((c0, 1)):
        qc.p(-np.pi / 2, q0)

    # 次の位相ビットを取得するために必要なだけ制御ユニタリ演算子を適用する
    k = 0
    cphase_angle = u_angle * 2**k
    qc.cp(cphase_angle, q0, q1)

    # X基底で補助量子ビットを測定し、2番目の古典ビットに格納する
    qc.h(q0)
    qc.measure(q0, c1)

    return qc


qr = QuantumRegister(2, "q")
cr = ClassicalRegister(2, "c")
qc = QuantumCircuit(qr, cr)
qc = u_circuit(qr, cr)
qc.draw("mpl")
_images/e3499df41f1bbb10894cc2cb27c29c9fa4eeacbaa6d605b33613cecb3be38976.png
from qiskit_aer import AerSimulator

sim = AerSimulator()
job = sim.run(qc, shots=1000)
result = job.result()
counts = result.get_counts()
print(counts)
success_probability = counts["01"] / counts.shots()
print(f"Success probability: {success_probability}")
{'01': 699, '11': 50, '10': 191, '00': 60}
Success probability: 0.699

ご覧のように、今回は期待通りの結果を得ることが保証されているわけではありません。

ではどうすれば成功確率を上げられるでしょうか?

アルゴリズムが失敗する原因の1つは、最初に測定したビットが正しくないことです。この場合、2番目のビットを測定する時の位相補正も不正確となるため、後続のビットも不正確となる可能性が高くなります。この問題を軽減する簡単な方法は、最初の数ビットの測定を何度か繰り返し、多数決でビットを正しく測定する可能性を高めることです。この手順を1つの回路内に実装するには、測定した結果に対して演算を行う必要があります。
Qiskitでは一時的な制限により、現在、測定したビットに対して演算を行い、その結果に基づいて将来の回路動作を条件付けることはできません。そこで、ここでは各ビットを別々の回路で測定することにします。

以下のコードセルで、位相の1ビット目だけを測定するためのIPE回路を構成し、シミュレーションを行います。

from qiskit import ClassicalRegister, QuantumCircuit, QuantumRegister
import numpy as np


def u_circuit(qr: QuantumRegister, cr: ClassicalRegister) -> QuantumCircuit:
    # qrは2量子ビットレジスタ
    # crは1古典ビットレジスタ

    qc = QuantumCircuit(qr, cr)

    # 初期化する
    q0, q1 = qr
    qc.h(q0)
    qc.x(q1)

    # 最下位の位相ビットを取得するために必要なだけ制御ユニタリ演算子を適用する
    u_angle = 2 * np.pi / 3
    k = 1
    cphase_angle = u_angle * 2**k
    qc.cp(cphase_angle, q0, q1)

    # X基底で補助量子ビットを測定する
    qc.h(q0)
    (c0,) = cr
    qc.measure(q0, c0)

    return qc


qr = QuantumRegister(2, "q")
cr = ClassicalRegister(1, "c")
qc = QuantumCircuit(qr, cr)
qc = u_circuit(qr, cr)
qc.draw("mpl")
_images/148ed41d74cf0b1a1d85ff012b19efe8dbe7a5302fc70be3b3a236bafd0877aa.png
job = sim.run(qc, shots=15)
result = job.result()
counts = result.get_counts()
print(counts)
{'0': 4, '1': 11}

正しいビットが測定されることが多くなってくれたことを期待します。

練習問題: 最下位ビットの値の決定#

Exercise 4: 最下位ビットの値の決定

最後のコードセルの出力の counts ディクショナリーを調べます。最初のビットの正しい値は何ですか?測定される頻度は高くなりましたか?もしそうでないなら、そうなるまで最後のコードセルを再実行してください。

そして、以下のコードセルに、変数 step1_bit を、最も多く測定されたビットの値に等しくするコードを書いてください。

step1_bit: int

####### your code goes here #######

print(step1_bit)
Hide code cell content
step1_bit: int

step1_bit = 1 if counts["1"] > counts["0"] else 0

print(step1_bit)
1

練習問題: 2ビット目の位相測定#

Exercise 5: 2ビット目の位相測定

次に、位相の2ビット目を測定するための回路を構築してください。この回路の最初のステージを、補助ビットを上記で測定した値に設定するだけのものに置き換えることで、位相の最初のビットについて常に正しい値を測定するようにします。

from qiskit import ClassicalRegister, QuantumCircuit, QuantumRegister
import numpy as np


def u_circuit(qr: QuantumRegister, cr: ClassicalRegister) -> QuantumCircuit:
    # qr is a quantum register with 2 qubits
    # cr is a classical register with 2 bits

    qc = QuantumCircuit(qr, cr)

    ####### your code goes here #######

    return qc


qr = QuantumRegister(2, "q")
cr = ClassicalRegister(2, "c")
qc = QuantumCircuit(qr, cr)
qc = u_circuit(qr, cr)
qc.draw("mpl")
Hide code cell content
from qiskit import ClassicalRegister, QuantumCircuit, QuantumRegister
import numpy as np


def u_circuit(qr: QuantumRegister, cr: ClassicalRegister) -> QuantumCircuit:
    # qrは2量子ビットレジスタ
    # crは2古典ビットレジスタ

    qc = QuantumCircuit(qr, cr)

    # 初期化
    q0, q1 = qr
    if step1_bit:
        qc.x(q0)
    qc.x(q1)

    # 補助量子ビットを測定する
    c0, c1 = cr
    qc.measure(q0, c0)

    # 補助量子ビットをリセットし、アダマールゲートで再初期化する
    qc.reset(q0)
    qc.h(q0)

    # 最初の古典ビットを条件として位相補正を適用する
    with qc.if_test((c0, 1)):
        qc.p(-np.pi / 2, q0)

    # 次の位相ビットを取得するために必要なだけ制御ユニタリ演算子を適用する
    u_angle = 2 * np.pi / 3
    k = 0
    cphase_angle = u_angle * 2**k
    qc.cp(cphase_angle, q0, q1)

    # X基底で補助量子ビットを測定し、2番目の古典ビットに格納する
    qc.h(q0)
    qc.measure(q0, c1)

    return qc


qr = QuantumRegister(2, "q")
cr = ClassicalRegister(2, "c")
qc = QuantumCircuit(qr, cr)
qc = u_circuit(qr, cr)
qc.draw("mpl")
_images/e97702f80693386548a213b9c4551ff5cf2debfc58322ed60bab0e28e21b9fe0.png
from qiskit_aer import AerSimulator

sim = AerSimulator()
job = sim.run(qc, shots=1000)
result = job.result()
counts = result.get_counts()
print(counts)
success_probability = counts["01"] / counts.shots()
print(f"Success probability: {success_probability}")
{'11': 62, '01': 938}
Success probability: 0.938

今度は、成功確率が以前よりずっと高くなりました!