注釈
このページは tutorials/algorithms/09_IQPE.ipynb. から生成されました。
反復量子相推定アルゴリズム¶
このチュートリアルの目的は、反復位相推定 (IPE) アルゴリズムがどのように機能するか、なぜQPE (Quantum Phase Estimation) アルゴリズムではなくIPEアルゴリズムを使うのか、そしてどうやって Qiskit で構築するか、を理解することです。リセットゲートと c_i f
メソッドは、古典レジスタに格納した前回の測定結果の値で、条件付きゲートを適用することができます。
参考文献
条件付きゲート: c_if
メソッド¶
IPEアルゴリズムを始める前に、Qiskitの条件付きメソッドである c_if
について、IPE回路を構築するための簡単なチュートリアルをおこないます。
c_if
は、古典レジスタに以前格納された値に基づいて条件付きの演算を行う関数(実際にはゲートクラスのメソッド)です。この機能を使えば測定後に測定結果を条件にしたゲートを、同じ回路に適用することができます。
例えば次のコードでは、古典レジスターの値が \(0\) の場合 \(X\) ゲートが実行されます。
[1]:
from qiskit import QuantumCircuit
qc = QuantumCircuit(1, 1)
qc.h(0)
qc.measure(0,0)
qc.x(0).c_if(0, 0)
qc.draw(output='mpl')
[1]:

強調しておきたいことは、メソッド c_if
がとる第1引数は、古典レジスタ全体であり、単一の古典ビット (または古典ビットのリスト) ではないことです。また第2引数は、十進数の値 (非負の整数) であり、単一ビットの 0、1の値 (または2進数のリスト/文字列) ではありません。
別の例を見てみましょう。次の回路の測定後、 \(q_0\) と \(q_1\) の測定結果が両方とも \(1\) のとき3番目の量子ビットにビットフリップを実行したいとします。
[2]:
from qiskit import QuantumRegister, ClassicalRegister
q = QuantumRegister(3, 'q')
c = ClassicalRegister(3, 'c')
qc = QuantumCircuit(q, c)
qc.h([0, 1, 2])
qc.barrier()
qc.measure(q, c)
qc.draw('mpl')
[2]:

\(q_0\) と \(q_1\) の測定結果が両方とも \(1\) である場合にのみ、 \(X\) ゲートを適用します。 これは、 c_if
メソッドを使用して、 c_if
に引数として渡された値に応じて \(X\) のアプリケーションを条件付けて行うことができます。
\(q_2\) が何として測定されるかは問題ではないため、値 011 と 111(バイナリー表現)をチェックするように、 c_if
メソッドに渡す値をエンコードする必要があります。
2つの整数の10 進数表記は以下:
Python の bin()
メソッドを使って結果を確認することができます (prefix 0b
はバイナリフォーマットを示します)。
[3]:
print(bin(3))
print(bin(7))
0b11
0b111
そのため、011と111 に対して \(X\) を \(q_2\) に c_if
で 2 回適用しなければなりません。
[4]:
qc.x(2).c_if(c, 3) # for the 011 case
qc.x(2).c_if(c, 7) # for the 111 case
qc.draw(output='mpl')
[4]:

IPE¶
IPE アルゴリズムを使用する動機は QPE アルゴリズムが、短い回路ではうまく動作するが、大きくなるとゲートノイズやデコヒーレンス時間のためにちゃんと動作しなくなることです。
アルゴリズムがどのように動作するかについての詳細な説明は、「 反復位相推定 (IPE) アルゴリズム 」にあります。より深く QPE を理解するには、「 Ch.3.6 量子位相推定」も参照してください。
\(U\) の1量子ビットゲートでの IPE の例¶
1量子ビット演算子 \(U\) の位相を推定するために、IPEアルゴリズムを適用したいとします。例えば、 \(S\)-ゲートを使用します。
\(S\) ゲートの位相を推定するために、IPE アルゴリズムを適用しましょう。その行列は
つまり、 \(S\)-ゲートは \(|0\rangle\) 状態の位相はそのままにし、 \(|1\rangle\) 状態に位相 \(\pi/2\) を加えます。
以下では、 Section 2 of lab 4 と同じ表記と用語を使用します。
固有状態 \(|1\rangle\) の位相 \(\phi=\frac{\pi}{2}\) の位相推定を考えましょう。 \(\varphi=\frac{1}{4}\) を得るはずです ( \(\phi = 2 \pi \varphi\) のため) 。\(1/2^2=1/4\) なので位相推定のためにちょうど 2 つの位相ビット、すなわち \(m=2\) が必要になります。 そして \(\varphi=0.\varphi_1\varphi_2\) です。
IPEアルゴリズムの理論を思い出してください。 \(m\) は繰り返し数でもありますので、 :math:`2`の繰り返し数またはステップだけが必要です。
最初に回路を初期化します。 IPE は、 QPE アルゴリズムでの量子ビット数 \(m\) ではなく、たった1 つの補助量子ビットを使用します。 そのため補助量子ビットに1、 \(U\) -ゲート の固有状態に1、合計2量子ビットを必要とします。そして位相ビット \(\varphi_1\), \(\varphi_2\) のために、古典レジスタが2ビット必要です。
[5]:
nq = 2
m = 2
q = QuantumRegister(nq, 'q')
c = ClassicalRegister(m, 'c')
qc_S = QuantumCircuit(q,c)
第1ステップ¶
さて、最初のステップの量子回路を構築します。つまりアルゴリズムの最初の反復として、位相ビットの最下位ビット \(\varphi_m\) 、今の場合 \(\varphi_2\) を推定します。最初のステップには3つのサブステップがあります: - 初期化 - 制御-\(U\) ゲート適用 -X基底での補助量子ビットの測定。
初期化¶
初期化は、補助量子ビットへのアダマールゲートの適用と、固有状態 \(|1\rangle\) の準備から構成されます。
[6]:
qc_S.h(0)
qc_S.x(1)
qc_S.draw('mpl')
[6]:

制御-\(U\) ゲートの適用¶
次に制御- \(U\) 演算子を \(2^t\) 回適用しなければなりません( 2量子ビットゲート も参照)。 今回の例では制御- \(S\) ゲート (略して \(CS\))です。
回路に \(CS\) を実装するため、 \(S\) は位相ゲートなので制御位相ゲート \(\text{CP}(\theta)\) が使えます。ここで \(\theta=\pi/2\) です。
[7]:
from math import pi
cu_circ = QuantumCircuit(2)
cu_circ.cp(pi/2, 0, 1)
cu_circ.draw('mpl')
[7]:

それでは \(\text{CP}(\pi/2)\) を \(2^t\) 回適用しましょう。最初のステップは \(t=m-1\)、そして \(m=2\) なので、 \(2^t=2\) です。
[8]:
for _ in range(2 ** (m - 1)):
qc_S.cp(pi/2, 0, 1)
qc_S.draw('mpl')
[8]:

X 基底の測定¶
最後に、補助量子ビットをX基底で測定します。 そのため、 x_measurement
を実行する関数を定義し、それを適用します。
[9]:
def x_measurement(qc, qubit, cbit):
"""Measure 'qubit' in the X-basis, and store the result in 'cbit'"""
qc.h(qubit)
qc.measure(qubit, cbit)
この方法で位相ビット \(\varphi_2\) を取得し、古典ビット \(c_0\) に保存します。
[10]:
x_measurement(qc_S, q[0], c[0])
qc_S.draw('mpl')
[10]:

次のステップ (第2ステップ)¶
次に、残りのステップの量子回路を構築します。この例では 第2ステップのみです。 このステップには、4つのサブステップがあります。3サブステップは最初のステップと同じですが、その途中に位相補正の追加ステップがあります。 - リセットと初期化 - 位相補正 - 制御-:math:U ゲート適用 - X-基底での補助量子ビット測定。
リセットによる初期化¶
反復アルゴリズムを同じ回路で実行したいので、補助量子ビット \(q_0\) をリサイクルする前に、測定の後でにリセットして初期化する必要があります。
[11]:
qc_S.reset(0)
qc_S.h(0)
qc_S.draw('mpl')
[11]:

位相補正 (ステップ 2 の場合)¶
理論で見てきたように、位相ビット \(\varphi_{1}\) を展開するために \(-\pi\varphi_2/2\) の位相補正をします。もちろん位相ビットが \(\varphi_2=1\) の場合だけ、位相補正が必要です。すなわち、古典ビット \(c_0\) が 1 の場合のみ、位相補正 \(-\pi/2\) を実行します。
そのため、リセット後に位相ゲート \(P(\theta)\) を位相 \(\theta=-\pi/2\) で条件付きで適用します。古典ビット \(c_0\) (\(=\varphi_2\)) を c_if
メソッドを使って条件付けます。このチュートリアルの最初の部分で見たように、\(1_{10} = 001_{2}\) なので値が 1 の c_if
メソッドを使用します(下付き \(_{10}\) と \(_2\) は10進数表現と2進数表現を示します)。
[12]:
qc_S.p(-pi/2, 0).c_if(c, 1)
qc_S.draw('mpl')
[12]:

制御-\(U\) ゲートとx-基底測定の適用 (ステップ 2 の場合)¶
\(CU\) 演算子を最初のステップでやったように適用します。第2ステップでは \(t=m-2\) のため \(2^t=1\) です。そのため、 \(\text{CP}(\pi/2)\) を一回適用します。そして量子ビット \(q_0\) の X基底測定をして、位相ビット \(\varphi_1\) を古典レジスター \(c_1\) に格納します。
[13]:
## 2^t c-U operations (with t=m-2)
for _ in range(2 ** (m - 2)):
qc_S.cp(pi/2, 0, 1)
x_measurement(qc_S, q[0], c[1])
ついに、最終的な回路が得られました。
[14]:
qc_S.draw('mpl')
[14]:

Qiskit Aerの Sampler
primitiveで回路をサンプリングしてみましょう。これは、ローカルで動作するノイズのないシミュレーターです。
[15]:
import matplotlib.pyplot as plt
from qiskit.tools.visualization import plot_histogram
from qiskit_aer.primitives import Sampler
sampler = Sampler()
job = sampler.run(qc_S)
result = job.result()
dist0 = result.quasi_dists[0]
key_new = [str(key/2**m) for key in list(dist0.keys())]
dist1 = dict(zip(key_new, dist0.values()))
fig, ax = plt.subplots(1,2)
plot_histogram(dist0, ax=ax[0])
plot_histogram(dist1, ax=ax[1])
plt.tight_layout()

図のヒストグラムは同じものですが、左側は x軸に位相ビットが \(\varphi_1\)、 \(\varphi_2\) の文字列で、右側は実際の位相 \(\varphi\) が10 進数表記になっています。
予想通り \(\varphi=\frac{1}{4}=0.25\) が確率 \(100\%\) になっています。
2量子ビットゲートの IPE の例¶
ここで、IPEアルゴリズムを適用して、2量子ビットゲート \(U\) の位相を推定します。この例では、 \(T\) ゲートの制御バージョン、つまりゲート \(U=\textrm{Controlled-}T\) (これからは \(CT\) でもっとコンパクトに表現していきます)について考えてみましょう。その行列は、
これは、\(CT\) ゲートが状態 \(|11\rangle\) に位相 \(\pi/4\) を加え、その他の計算基底状態 \(|00\rangle\), \(|01\rangle\), \(|10\rangle\) はそのままにする、ということです。
固有状態 \(|11\rangle\) の位相 \(\phi=\pi/4\) の位相推定を考えましょう。 \(\phi = 2 \pi \varphi\) なので \(\varphi=1/8\) を得るはずです。そのため位相推定に、ちょうど3つの古典ビットが必要です。つまり \(1/2^3=1/8\) なので \(m=3\)。従って \(\varphi=0.\varphi_1\varphi_2\varphi_3\) となります。
1量子ビット \(U\) 演算子の例でみたように、同じステップを実行します。しかし今回は \(m=3\) なので \(3\) ステップありますが、同じ説明は繰り返しません。そのため詳細は上記1量子ビット \(U\) ゲートの例を参照してください。
最初に、3つの量子ビットの回路を初期化します。1つは補助量子ビット、2つは2量子ビットゲートのものです。そして位相ビット \(\varphi_1\), \(\varphi_2\), \(\varphi_3\) を格納する3つの古典ビットを初期化します。
[16]:
nq = 3 # number of qubits
m = 3 # number of classical bits
q = QuantumRegister(nq,'q')
c = ClassicalRegister(m,'c')
qc = QuantumCircuit(q,c)
第1ステップ¶
ここでは最初のステップの量子回路を構築し、位相ビットの最下位ビット \(\varphi_m=\varphi_3\) を推定します。
初期化¶
補助量子ビットを初期化し、その他の量子ビットを固有状態 \(|11\rangle\) で初期化します。
[17]:
qc.h(0)
qc.x([1, 2])
qc.draw('mpl')
[17]:

制御-\(U\) ゲートの適用¶
この場合、 \(CU\) 演算子を複数回適用する必要があります。この例では、制御 -\(CT\) ゲート (短縮して \(CCT\)) です。
\(CCT\) を回路に実装するには、 \(T\) は位相ゲートなので、マルチ制御位相ゲート \(\text{MCP}(\theta)\) を \(\theta=\pi/4\) で使用できます。
[18]:
cu_circ = QuantumCircuit(nq)
cu_circ.mcp(pi/4, [0, 1], 2)
cu_circ.draw('mpl')
[18]:

それでは \(\text{MCP}(\pi/4)\) を \(2^t\) 回適用しましょう。最初のステップは \(t=m-1\)、そして \(m=3\) なので、 \(2^t=4\) です。
[19]:
for _ in range(2 ** (m - 1)):
qc.mcp(pi/4, [0, 1], 2)
qc.draw('mpl')
[19]:

X 基底の測定¶
最後に、補助量子ビットをX基底で測定します。上の1量子ビットの例で定義した x_measurement
関数が使えます。この方法で位相ビット \(\varphi_3\) を古典ビット \(c_0\) に取得することができます。
[20]:
x_measurement(qc, q[0], c[0])
qc.draw('mpl')
[20]:

次のステップ (第2、第3)¶
さて、残りの第2と第3のステップのために量子回路を作ります。最初の例で述べたように、ここでは位相補正のサブステップの追加があります。
位相補正 (ステップ 2 の場合)¶
位相ビット \(\varphi_{2}\) を抽出するために、 \(-\pi\varphi_3/2\) の位相補正を行います。
したがって、リセット後に古典ビット \(c_0\) (\(=\varphi_3\))を条件として、ゲート \(P(\theta)\) を位相 \(\theta=-\pi/2\) で適用します。
[22]:
qc.p(-pi/2, 0).c_if(c, 1)
qc.draw('mpl')
[22]:

制御-\(U\) ゲートとx-基底測定の適用 (ステップ 2 の場合)¶
\(CU\) 演算子を最初のステップでやったように適用します。第2ステップでは \(t=m-2\) のため \(2^t=2\) です。そのため、 \(\text{MCP}(\pi/2)\) を \(2\) 回適用します。そして量子ビット \(q_0\) の X基底測定をして、位相ビット \(\varphi_2\) を古典レジスター \(c_1\) に格納します。
[23]:
for _ in range(2 ** (m - 2)):
qc.mcp(pi/4, [0, 1], 2)
x_measurement(qc, q[0], c[1])
qc.draw('mpl')
[23]:

第3ステップの全てのサブステップ¶
第3と最後のステップでは、補助量子ビットのリセットと初期化を、第2ステップと同じようにします。
次に、3番目のステップで、 \(-2\pi 0.0\varphi_{2}\varphi_{3}= -2\pi \left(\frac{\varphi_2}{4}+\frac{\varphi_3}{8}\right)=-\frac{\varphi_2\pi}{2}-\frac{ \varphi_3\pi}{4}\) の位相補正を実行する必要があります。したがって、1つは \(\varphi_3\) ( \(=c_0\) )で、もう1つは \(\varphi_2\) ( \(=c_1\) )で条件付けされた2つの条件付き位相補正を適用する必要があります。これを行うには、以下を適用する必要があります。 - ゲート \(P(-\pi/4)\) は \(c_0=1\) 、つまり \(c=001\) によって条件付けられます(値 \(1\) の``c_if``) ゲート \(P(-\pi/2)\) は \(c_1=1\) によって条件付けられます。つまり、ゲートは \(c=010\) (値 \(2\) の``c_if``)のときに適用されます。 ゲート \(P(-3\pi/4)\) は \(c_1=1\) と \(c_0=1\) によって調整されます。つまり、ゲートは \(c=011\) (値 \(3\) の``c_if``)のときに適用されます。
次に、 \(CU\) 演算: \(\text{MCP}(\pi/4)\) ゲートを \(2^t\) 回適用します。第3のステップでは \(t=m-3=0\) のため、ゲートを適用するのは一度だけです。
[24]:
# initialization of qubit q0
qc.reset(0)
qc.h(0)
# phase correction
qc.p(-pi/4, 0).c_if(c, 1)
qc.p(-pi/2, 0).c_if(c, 2)
qc.p(-3*pi/2, 0).c_if(c, 3)
# c-U operations
for _ in range(2 ** (m - 3)):
qc.mcp(pi/4, [0, 1], 2)
# X measurement
qc.h(0)
qc.measure(0, 2)
qc.draw('mpl')
[24]:

では、ノイズのないシミュレータで回路を実行します。
[25]:
result = sampler.run(qc).result()
dist0 = result.quasi_dists[0]
key_new = [str(key/2**m) for key in list(dist0.keys())]
dist1 = dict(zip(key_new, dist0.values()))
fig, ax = plt.subplots(1,2)
plot_histogram(dist0, ax=ax[0])
plot_histogram(dist1, ax=ax[1])
plt.tight_layout()

\(100\%\) の確率で \(\varphi=0.125\) 、つまり期待通り \(1/8\) を取得することができました。
[26]:
import qiskit.tools.jupyter
%qiskit_version_table
%qiskit_copyright
Version Information
Qiskit Software | Version |
---|---|
qiskit-terra | 0.23.0.dev0+1b4fed3 |
qiskit-aer | 0.11.1 |
qiskit-nature | 0.5.0 |
System information | |
Python version | 3.9.13 |
Python compiler | Clang 12.0.0 |
Python build | main, Oct 13 2022 16:12:30 |
OS | Darwin |
CPUs | 4 |
Memory (Gb) | 32.0 |
Fri Dec 09 16:18:07 2022 CET |
This code is a part of Qiskit
© Copyright IBM 2017, 2022.
This code is licensed under the Apache License, Version 2.0. You may
obtain a copy of this license in the LICENSE.txt file in the root directory
of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
Any modifications or derivative works of this code must retain this
copyright notice, and modified files need to carry a notice indicating
that they have been altered from the originals.