ベスパリブ

プログラミングを主とした日記・備忘録です。ベスパ持ってないです。

Qiskit Global Summer School 2023 Lab4 参加記録

各Labの記録

まえがき

Qiskit Global Summer School 2023 Lab4の記録です。

Lab 4 : Iterative phase estimation

背景(翻訳)

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

反復位相推定(IPE)は、補助量子ビットを1つだけ必要とするQPEの変種である。IPEでは、補助量子ビットが繰り返し測定され、その測定結果が将来の量子演算の指針となる。このような古典的なフィードフォワードは、以前はIBMの量子プロセッサーで実行することは不可能だったが、最近導入された動的回路機能を使えば可能になる。

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

問題文: ユニタリー行列Uと、未知の固有値 e^{i2πφ}を持つUの固有状態|Ψ⟩が与えられたとき、φの値を推定せよ。

この問題では、いくつかの重要な点を明確にする必要がある。つまりUと|Ψ⟩がどのように指定されるかである。

UはUを実装する量子回路として与えられ、実際、我々は正の整数tに対してcontrolled- U^{2^{t}} の演算を効率的に実装する能力を持っていると仮定する。固有状態も量子回路として与えられる。

簡単のために、まずφが厳密な二項展開ができると仮定してみよう。

φの二項展開

ここで、最後の等式では基数2の「小数点」表記を用いている。簡単のために、Uが1量子ビットに作用するユニタリー演算子であるとする(ここで述べることは、Uが複数の量子ビットに作用する場合にも当てはまる)。IPEは補助量子ビットを必要とするので、q0とq1の2つの量子ビットの系が必要になる。q0は補助量子ビットで、q1はUが作用する物理系を表す。

ここで、q0を状態|+⟩に、q1を状態|Ψ⟩に初期化したとする。q0をコントロール、q1をターゲットとしてcontrolled- U^{2^{t}}ゲートを適用するとどうなるか?|Ψ⟩は固有値 e^{i2πφ}を持つUの固有状態なので、次のようになる。

こうなる。

つまり、システム量子ビットの状態は変化せず、 e^{i2π2^{𝑡}φ}の位相が補助量子ビットの状態に「キックバック」されたことになる。

さて、次のことに注意してほしい。

小数点表記に書ける

最後の等式では、任意の整数nに対して e^{i2πn}=1であるため、位相の「10進数」表現の整数部分は消えている。たとえば、

  • t=0の場合、位相は e^{i2\pi2^{0}\varphi} = e^{i2\pi\varphi} = e^{i2\pi0.\varphi_1 \varphi_2 ... \varphi_m}

  • t=1の場合、位相は e^{i2\pi2^{1}\varphi} = e^{i2\pi\varphi_1} e^{i2\pi0.\varphi_2 \varphi_3 ... \varphi_m} = e^{i2\pi0.\varphi_2 \varphi_3 ... \varphi_m}

  • t=2の場合、位相は e^{i2\pi2^{2}\varphi} = e^{i2\pi0.\varphi_3 \varphi_4 ... \varphi_m}

  • t=m-1の場合、位相は  e^{i2\pi2^{m-1}\varphi} = e^{i2\pi0.\varphi_m}

最後のt=m-1の場合、位相は e^{i2\pi0.\varphi_m}となり、 \varphi_m = 0の場合は1、 \varphi_m = 1の場合は-1となる。最初のケースでは、補助量子ビットq0は|+⟩状態にあり、2番目のケースでは|-⟩状態にある。したがって、Pauli X基底で量子ビットを測定すれば、最初のケースでは0を測定し、2番目のケースでは1を測定するようになり、100%の成功率でこれらのケースを区別できる。測定されたビットは \varphi_mに等しくなる。

Pauli X基底での測定は、量子ビットを測定する前にアダマールゲートを実行することで行われる。

実装

固有値 e^{i\pi/2}=e^{i2\pi・1/4}を持つ固有状態|Ψ⟩=|1⟩を使う。つまり𝜑=1/4=0.01=0.𝜑1𝜑2となる。

𝜑は2ビットで正確に表現できるので、量子回路の実装では2ビットの古典レジスタを使う。

q0が補助量子ビット、q1が|Ψ⟩。

ex1

UゲートとしてSゲートを使って反復位相推定を行う。

Sゲート

controlled-SゲートはCPhaseGateを使えば良い。

CPhaseGateの行列

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 #######
    qc.h(0)
    qc.x(1)
    qc.cp(np.pi, 0, 1)
    qc.h(0)
    qc.measure(0,0)

    return qc


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

qc回路

ex2

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 #######
    qc.reset(qr[0])
    qc.h(qr[0])
    with qc.if_test((cr[0], 0)) as else_:
        # 0を測定したら、正しいので何もしない
        pass
    with else_:
        # 1を測定したら、-pi/2で位相補正する
        qc.rz(-np.pi/2, qr[0])

    return qc


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

ex2の回路

さて、この回路をAerSimulatorで実行してみる。

from qiskit_aer import AerSimulator

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

結果は 01 となり、𝜑=1/4=0.01=0.𝜑1𝜑2 を正しく推定できる回路を作ることができた。

ex3

Tゲートの位相を推定するIPEを作れという問題。

これ以降は以前の問題と同じと気づいたので詳細は省略。この回路は何ビット必要か?固有状態は?など、詳しくはIBM Quantum Challenge: Spring 2023 参加記録のLab3のExercise 3を参照。

TゲートのIPE回路は以下になる。

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 #######
    """𝜑1のステップ"""
    # 初期化
    qc.h(qr[0])
    qc.x(qr[1])
    
    # 𝜑1の推定
    qc.cp(np.pi, qr[0], qr[1])
    qc.h(qr[0])
    qc.measure(qr[0], cr[0])
    
    """𝜑2のステップ"""
    # 初期化
    qc.reset(qr[0])
    qc.h(qr[0])
    
    # Z軸周りの角度wの回転で位相補正
    with qc.if_test((cr[0], 1)):
        qc.p(-2*np.pi/(2**2), qr[0])
    
    # 𝜑2の推定
    qc.cp(np.pi/(2**1), qr[0], qr[1])
    qc.h(qr[0])
    qc.measure(qr[0], cr[1])
    
    """𝜑3のステップ"""
    # 初期化
    qc.reset(qr[0])
    qc.h(qr[0])     

    # Z軸周りの角度wの回転で位相補正
    with qc.if_test((cr[0], 1)):
        qc.p(-2*np.pi/(2**3), qr[0])
    with qc.if_test((cr[1], 1)):
        qc.p(-2*np.pi/(2**2), qr[0])

    # 𝜑3の推定
    qc.cp(np.pi/(2**2), qr[0], qr[1])
    qc.h(qr[0])
    qc.measure(qr[0], cr[2])   
    
    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ゲートのIPE回路

from qiskit_aer import AerSimulator

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

ex4

詳しくはIBM Quantum Challenge: Spring 2023 参加記録のLab3のExercise 4を参照。

ex5

詳しくはIBM Quantum Challenge: Spring 2023 参加記録のLab3のExercise 5を参照。

ex6(ungraded)

ここまでに構築したIPE回路は、特定のゲートと特定の精度ビット数用に設計されたものであった。ここで一般化して、異なるゲートと精度レベルを扱える一般的なIPEルーチンを実装してみよう。

次の関数を完成させて、一般化された IPE ルーチンを実装しよう。以下の入力を受け取る:

from qiskit.circuit import Gate


def iterative_phase_estimation(
    qr: QuantumRegister,
    cr: ClassicalRegister,
    controlled_unitaries: list[Gate],
    state_prep: Gate,
) -> QuantumCircuit:
    qc = QuantumCircuit(qr, cr)

    ####### your code goes here #######
    for i, u_gate in enumerate(controlled_unitaries[::-1]):
        # リセット処理
        if i != 0:
            qc.reset(qr[0])
            
        qc.h(qr[0])
        if i == 0:
            qc.x(qr[1])
        else:
            # Z軸周りの角度wの回転で位相補正
            for j in range(0, i):
                with qc.if_test((cr[j], 1)):
                    qc.p(-np.pi /(2**(i-j)), qr[0])

        qc.append(u_gate, [qr[0], qr[1]])

        # X基底でq0を測定
        qc.h(qr[0])
        qc.measure(qr[0], cr[i])

    return qc

この関数を使用してS ゲートのIPE回路を生成する。

from qiskit.circuit.library import CPhaseGate, XGate

qr = QuantumRegister(2, "q")
cr = ClassicalRegister(2, "c")

s_angle = np.pi / 2
controlled_unitaries = [CPhaseGate(s_angle * 2**k) for k in range(2)]
qc = iterative_phase_estimation(qr, cr, controlled_unitaries, XGate())
qc.draw()

iterative_phase_estimationにSゲートを与えたときの回路

回路を実行する。結果は01になるはずである。

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

合ってる。

Tゲートでも検証してみる。

qr = QuantumRegister(2, "q")
cr = ClassicalRegister(3, "c")

t_angle = np.pi / 4
controlled_unitaries = [CPhaseGate(t_angle * 2**k) for k in range(3)]
qc = iterative_phase_estimation(qr, cr, controlled_unitaries, XGate())
qc.draw()

iterative_phase_estimationにTゲートを与えたときの回路

回路を実行する。結果は001になるはずである。

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

合ってる。