量子アルゴリズム:位相推定
Kento Ueda(2024年5月15日)
このノートブックでは、量子フーリエ変換(QFT)と量子位相推定(QPE)の基本概念と実装について説明します。
元の講義のPDFをダウンロードできます。コードスニペットは静止画像のため、一部が非推奨になっている場合があります。
この実験の実行に必要な QPU 時間の目安は約 7 秒です。
1. はじめに
量子フーリエ変換(QFT)
量子フーリエ変換は、古典的な離散フーリエ変換の量子版です。量子状態に適用される線形変換であり、計算基底をフーリエ基底表現にマッピングします。QFT は多くの量子アルゴリズムにおいて重要な役割を担っており、量子状態から周期性の情報を効率的に抽出する手法を提供します。 QFT は、 qubit に対してアダマールゲートや制御位相ゲートなどの量子ゲートを 回の演算で実装でき、古典的なフーリエ変換に対する指数的な高速化を実現します。
- 応用例:大きな整数の素因数分解や離散対数を求める Shor のアルゴリズムなど、量子アルゴリズムの基盤となっています。
量子位相推定(QPE)
量子位相推定は、ユニタリ演算子の固有ベクトルに対応する位相を推定するための量子アルゴリズムです。このアルゴリズムは、量子状態の抽象的な数学的性質と計算上の応用との橋渡しをします。
- 応用例:ユニタリ行列の固有値の探索や量子システムのシミュレーションなどの問題を解くことができます。
QFT と QPE を組み合わせることで、古典コンピュータでは困難な多くの問題を解く量子アルゴリズムの本質的な基盤が形成されます。このノートブックを通じて、これらの技法がどのように実装されるかを理解できるようになります。
2. 量子フーリエ変換(QFT)の基礎
# Added by doQumentation — required packages for this notebook
!pip install -q numpy qiskit qiskit-aer qiskit-ibm-runtime
from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister
from qiskit_aer import AerSimulator
from qiskit.visualization import plot_histogram, plot_bloch_multivector
from qiskit.quantum_info import Statevector
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit_ibm_runtime import Sampler
from numpy import pi
離散フーリエ変換との類比から、QFT は qubit の量子状態 に作用し、量子状態 にマッピングします。
ここで です。
またはユニタリ行列表現として:
2.1. 直感的理解
量子フーリエ変換(QFT)は、計算基底(Z 基底)とフーリエ基底という 2 つの基底間の変換を行います。ではここでのフーリエ基底とはどのような意味でしょうか?フーリエ変換 は関数 を周波数 の正弦波関数に畳み込んだものを表すことを思い出してください。平たく言えば、フーリエ変換は を正弦波(または余弦波)で構成するために各周波数 がどれだけ必要かを示す関数です。QFT がこの文脈でどのような意味を持つかをより直感的に理解するため、4 つの qubit を使って整数を 2 進数で符号化した以下のステップ画像を参照してください:
計算基底では、状態 と を使って数を 2 進数で格納します。
異なる qubit が変化する頻度に注目してください。一番左の qubit は数が 1 増えるごとに反転し、次の qubit は 2 増えるごと、3 番目は 4 増えるごとに反転し、以降も同様です。
これらの状態に量子フーリエ変換を適用すると、次のようにマッピングされます:
(フーリエ基底の状態はチルダ(~)で表すことが多いです。)
フーリエ基底では、Z 軸周りの異なる回転を使って数を格納します:
IFRAME
格納したい数が、各 qubit が Z 軸周りに回転する角度を決定します。状態 では、すべての qubit が の状態にあります。上記の例でわかるように、4 qubit に状態 を符号化するには、一番左の qubit を 回転( ラジアン)させました。次の qubit はその 2 倍( ラジアン、すなわち 回転)となり、さらに次の qubit ではこの角度が 2 倍になり、以降も同様です。
各 qubit が変化する頻度にも注目してください。この場合、一番左の qubit(qubit 0)が最も低い周波数を持ち、一番右が最も高い周波数を持ちます。
2.2 例:1-Qubit QFT
の場合を考えます。
ユニタリ行列は次のように書けます:
この演算はアダマールゲート()を適用した結果です。
2.3 QFT の積表現
の場合の変換を一般化し、状態 に作用する を考えます。
2.4 例:3 qubit QFT の Circuit 構成
上記の説明だけでは、QFT Circuit をどのように構成するかは明確でないかもしれません。ここでは、3 つの qubit が異なる「速度」で位相が変化することを期待するという点のみを押さえておいてください。これが Circuit にどのように変換されるかを正確に理解することは、読者への演習問題とします。講義 PDF には複数の図と例が記載されています。また、「量子アルゴリズムの基礎」コースのこのレッスンも参考になります。
ここではシミュレータのみを使って QFT を示します。量子位相推定に移るまでは Qiskit パターンズフレームワークを使用しません。
# Prepare for 3 qubits circuit
qr = QuantumRegister(3)
cr = ClassicalRegister(3)
qc = QuantumCircuit(qr, cr)
qc.h(2)
qc.cp(pi / 2, 1, 2) # Controlled-phase gate from qubit 1 to qubit 2
qc.cp(pi / 4, 0, 2) # Controlled-phase gate from qubit 0 to qubit 2
qc.draw(output="mpl")
qc.h(1)
qc.cp(pi / 2, 0, 1) # Controlled-phase gate from qubit 0 to qubit 1
qc.draw(output="mpl")
qc.h(0)
qc.draw(output="mpl")
qc.swap(0, 2)
qc.draw(output="mpl")
例として に QFT を適用してみます。
まず、整数 5 の 2 進数表現を確認し、状態 5 を符号化する Circuit を作成します:
bin(5)
'0b101'
qc = QuantumCircuit(3)
qc.x(0)
qc.x(2)
qc.draw(output="mpl")
Aer シミュレータを使って量子状態を確認します:
statevector = Statevector(qc)
plot_bloch_multivector(statevector)

最後に QFT を追加し、qubit の最終状態を確認します:
qc.h(2)
qc.cp(pi / 2, 1, 2)
qc.cp(pi / 4, 0, 2)
qc.h(1)
qc.cp(pi / 2, 0, 1)
qc.h(0)
qc.swap(0, 2)
qc.draw(output="mpl")
statevector = Statevector(qc)
plot_bloch_multivector(statevector)

QFT 関数が正しく動作していることが確認できます。qubit 0 は 回転、qubit 1 は 回転( 回転に相当)、qubit 2 は 回転( 回転に相当)しています。
2.5 演習:QFT
(1)4 qubit の QFT を実装してください。
##your code goes here##
(2) に QFT を適用し、ブロッホ球を使って状態ベクトルをシミュレートして描画してください。
##your code goes here##
演習の解答:QFT
(1)
qr = QuantumRegister(4)
cr = ClassicalRegister(4)
qc = QuantumCircuit(qr, cr)
qc.h(3)
qc.cp(pi / 2, 2, 3)
qc.cp(pi / 4, 1, 3)
qc.cp(pi / 8, 0, 3)
qc.h(2)
qc.cp(pi / 2, 1, 2)
qc.cp(pi / 4, 0, 2)
qc.h(1)
qc.cp(pi / 2, 0, 1)
qc.h(0)
qc.swap(0, 3)
qc.swap(1, 2)
qc.draw(output="mpl")
(2)
bin(14)
'0b1110'
qc = QuantumCircuit(4)
qc.x(1)
qc.x(2)
qc.x(3)
qc.draw("mpl")
qc.h(3)
qc.cp(pi / 2, 2, 3)
qc.cp(pi / 4, 1, 3)
qc.cp(pi / 8, 0, 3)
qc.h(2)
qc.cp(pi / 2, 1, 2)
qc.cp(pi / 4, 0, 2)
qc.h(1)
qc.cp(pi / 2, 0, 1)
qc.h(0)
qc.swap(0, 3)
qc.swap(1, 2)
qc.draw(output="mpl")
statevector = Statevector(qc)
plot_bloch_multivector(statevector)

3. 量子位相推定(QPE)の基礎
ユニタリ演算 が与えられたとき、QPE は における を推定します。 はユニタリであるため、その固有値はすべてノルムが 1 です。
3.1 手順
1. 準備
は一組の量子ビットレジスタに格納されます。追加の 量子ビットからなるカウンティングレジスタに、値 を記録します:
2. 重ね合わせ
カウンティングレジスタに ビットのアダマールゲート演算 を適用します:
3. 制御ユニタリ演算
対応する制御ビットが のときにのみ、ターゲットレジスタにユニタリ演算子 を適用する制御ユニタリ を導入する必要があります。 は固有ベクトル を持つユニタリ演算子であり、 を満たすため、次のようになります:
3.2 例:T ゲートの QPE
QPE の例として ゲートを使い、その位相 を推定してみましょう。
期待される結果は次のとおりです:
ここで
ゲートを適用して、 ゲートの固有ベクトル を初期化します:
qpe = QuantumCircuit(4, 3)
qpe.x(3)
qpe.draw(output="mpl")
次に、カウンティング量子ビットにアダマールゲートを適用します:
for qubit in range(3):
qpe.h(qubit)
qpe.draw(output="mpl")
制御ユニタリ演算を実行します:
repetitions = 1
for counting_qubit in range(3):
for i in range(repetitions):
qpe.cp(pi / 4, counting_qubit, 3) # This is C-U
repetitions *= 2
qpe.draw(output="mpl")
逆量子フーリエ変換を適用してカウンティングレジスタの状態を変換し、その後カウンティングレジスタを測定します:
from qiskit.circuit.library import QFT
# Apply inverse QFT
qpe.append(QFT(3, inverse=True), [0, 1, 2])
qpe.draw(output="mpl")
for n in range(3):
qpe.measure(n, n)
qpe.draw(output="mpl")
Aer シミュレーターを使ってシミュレーションを実行できます:
aer_sim = AerSimulator()
shots = 2048
pm = generate_preset_pass_manager(backend=aer_sim, optimization_level=1)
t_qpe = pm.run(qpe)
sampler = Sampler(mode=aer_sim)
job = sampler.run([t_qpe], shots=shots)
result = job.result()
answer = result[0].data.c.get_counts()
plot_histogram(answer)
結果として 001 が確実に得られており、これは10進数で 1 に相当します。次に、 を求めるために結果(1)を で割ります:
ショアのアルゴリズムでは、 を未知としてその値を回路から取得することで、数の素因数分解が可能になります。
3.3 演習
3 量子ビットのカウンティングと固有ベクトル用の 1 量子ビットを使って、 を推定してください。
。 を実装したいので、 と設定する必要があります。
##your code goes here##
演習の解答:
# Create and set up circuit
qpe = QuantumCircuit(4, 3)
# Apply H-Gates to counting qubits:
for qubit in range(3):
qpe.h(qubit)
# Prepare our eigenstate |psi>:
qpe.x(3)
# Do the controlled-U operations:
angle = 2 * pi / 3
repetitions = 1
for counting_qubit in range(3):
for i in range(repetitions):
qpe.cp(angle, counting_qubit, 3)
repetitions *= 2
# Do the inverse QFT:
qpe.append(QFT(3, inverse=True), [0, 1, 2])
for n in range(3):
qpe.measure(n, n)
qpe.draw(output="mpl")
aer_sim = AerSimulator()
shots = 4096
pm = generate_preset_pass_manager(backend=aer_sim, optimization_level=1)
t_qpe = pm.run(qpe)
sampler = Sampler(mode=aer_sim)
job = sampler.run([t_qpe], shots=shots)
result = job.result()
answer = result[0].data.c.get_counts()
plot_histogram(answer)
4. Qiskit Runtime Sampler プリミティブを使った実行
実際の量子デバイスを使って QPE を実行し、Qiskit パターンの 4 ステップに従います。
- 問題を量子ネイティブな形式にマッピングする
- 回路を最適化する
- ターゲット回路を実行する
- 結果を後処理する
from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit_ibm_runtime import Sampler
# Loading your IBM Quantum® account(s)
service = QiskitRuntimeService()
4.1 ステップ 1:問題を量子回路と演算子にマッピングする
qpe = QuantumCircuit(4, 3)
qpe.x(3)
for qubit in range(3):
qpe.h(qubit)
repetitions = 1
for counting_qubit in range(3):
for i in range(repetitions):
qpe.cp(pi / 4, counting_qubit, 3) # This is C-U
repetitions *= 2
qpe.append(QFT(3, inverse=True), [0, 1, 2])
for n in range(3):
qpe.measure(n, n)
qpe.draw(output="mpl")
backend = service.least_busy(simulator=False, operational=True, min_num_qubits=4)
print(backend)
<IBMBackend('ibm_strasbourg')>
4.2 ステップ 2:ターゲットハードウェア向けに最適化する
# Transpile the circuit into basis gates executable on the hardware
pm = generate_preset_pass_manager(backend=backend, optimization_level=2)
qc_compiled = pm.run(qpe)
qc_compiled.draw("mpl", idle_wires=False)

4.3 ステップ 3:ターゲットハードウェアで実行する
real_sampler = Sampler(mode=backend)
job = real_sampler.run([qc_compiled], shots=1024)
job_id = job.job_id()
print("job id:", job_id)
job id: d13p4zb5z6q00087ag00
job = service.job(job_id) # Input your job-id between the quotations
job.status()
'DONE'
result_real = job.result()
print(result_real)
PrimitiveResult([SamplerPubResult(data=DataBin(c=BitArray(<shape=(), num_shots=1024, num_bits=3>)), metadata={'circuit_metadata': {}})], metadata={'execution': {'execution_spans': ExecutionSpans([DoubleSliceSpan(<start='2025-06-09 22:39:00', stop='2025-06-09 22:39:00', size=1024>)])}, 'version': 2})
4.4 ステップ 4:結果を後処理する
from qiskit.visualization import plot_histogram
plot_histogram(result_real[0].data.c.get_counts())
# See the version of Qiskit
import qiskit
qiskit.__version__
'2.0.2'