Přeskočit na hlavní obsah

Kvantový odhad fáze s Qiskit Functions od Q-CTRL

Odhadovaná spotřeba: 40 sekund na procesoru Heron r2. (POZNÁMKA: Jedná se pouze o odhad. Skutečná doba běhu se může lišit.)

Pozadí

Kvantový odhad fáze (QPE) je základní algoritmus kvantového výpočtu, který tvoří základ mnoha důležitých aplikací, jako jsou Shorův algoritmus, odhad energie základního stavu v kvantové chemii a úlohy s vlastními hodnotami. QPE odhaduje fázi φ\varphi spojenou s vlastním stavem unitárního operátoru, zakódovanou ve vztahu

Uφ=e2πiφφ,U \lvert \varphi \rangle = e^{2\pi i \varphi} \lvert \varphi \rangle,

a určuje ji s přesností ϵ=O(1/2m)\epsilon = O(1/2^m) pomocí mm počítacích qubitů [1]. QPE připraví tyto qubity v superpozici, aplikuje řízené mocniny UU a poté pomocí inverzní Kvantové Fourierovy transformace (QFT) extrahuje fázi do binárně zakódovaných výsledků měření. QPE tak produkuje pravděpodobnostní distribuci soustředěnou okolo bitových řetězců, jejichž binární zlomky aproximují φ\varphi. V ideálním případě nejpravděpodobnější výsledek měření přímo odpovídá binárnímu rozvoji fáze, zatímco pravděpodobnost ostatních výsledků rychle klesá s počtem počítacích qubitů. Spouštění hlubokých QPE okruhů na hardwaru však přináší výzvy: velký počet qubitů a propletovacích operací činí algoritmus vysoce citlivým na dekoherenci a chyby hradel. To vede k rozšířeným a posunutým distribucím bitových řetězců, které zakrývají skutečnou vlastní fázi. Výsledkem je, že bitový řetězec s nejvyšší pravděpodobností už nemusí odpovídat správnému binárnímu rozvoji φ\varphi.

V tomto tutoriálu představujeme implementaci algoritmu QPE pomocí nástrojů pro potlačení chyb a správu výkonu Fire Opal od Q-CTRL, nabízených jako Qiskit Function (viz dokumentaci Fire Opal). Fire Opal automaticky aplikuje pokročilé optimalizace, včetně dynamického oddělování, vylepšení rozmístění qubitů a technik potlačení chyb, což vede k výsledkům s vyšší věrností. Tato vylepšení přibližují distribuce bitových řetězců z hardwaru těm získaným v simulacích bez šumu, takže dokážeš spolehlivě identifikovat správnou vlastní fázi i při vlivu šumu.

Požadavky

Než začneš s tímto tutoriálem, ujisti se, že máš nainstalované následující:

  • Qiskit SDK v1.4 nebo novější s podporou vizualizace
  • Qiskit Runtime v0.40 nebo novější (pip install qiskit-ibm-runtime)
  • Qiskit Functions Catalog v0.9.0 (pip install qiskit-ibm-catalog)
  • Fire Opal SDK v9.0.2 nebo novější (pip install fire-opal)
  • Q-CTRL Visualizer v8.0.2 nebo novější (pip install qctrl-visualizer)

Nastavení

Nejprve se autentizuj pomocí svého IBM Quantum API klíče. Poté vyber Qiskit Function takto. (Tento kód předpokládá, že sis již uložil/a svůj účet do místního prostředí.)

# Added by doQumentation — required packages for this notebook
!pip install -q matplotlib numpy qctrlvisualizer qiskit qiskit-aer qiskit-ibm-catalog qiskit-ibm-runtime
from qiskit import QuantumCircuit

import numpy as np
import matplotlib.pyplot as plt
import qiskit
from qiskit import qasm2
from qiskit_aer import AerSimulator
from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit_ibm_runtime import SamplerV2 as Sampler
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
import qctrlvisualizer as qv
from qiskit_ibm_catalog import QiskitFunctionsCatalog

plt.style.use(qv.get_qctrl_style())
catalog = QiskitFunctionsCatalog(channel="ibm_quantum_platform")

# Access Function
perf_mgmt = catalog.load("q-ctrl/performance-management")

Krok 1: Mapování klasických vstupů na kvantový problém

V tomto tutoriálu ilustrujeme QPE na příkladu obnovy vlastní fáze známé jednoQubitové unitární matice. Unitární matice, jejíž fázi chceme odhadnout, je hradlo fáze jednoho qubitu aplikované na cílový Qubit:

U(θ)=(100eiθ)=eiθ1 ⁣1.U(\theta)= \begin{pmatrix} 1 & 0\\[2pt] 0 & e^{i\theta} \end{pmatrix} = e^{i\theta\,|1\rangle\!\langle 1|}.

Připravíme jeho vlastní stav ψ=1|\psi\rangle=|1\rangle. Protože 1|1\rangle je vlastní vektor U(θ)U(\theta) s vlastní hodnotou eiθe^{i\theta}, odhadovaná vlastní fáze je:

φ=θ2π(mod1)\varphi = \frac{\theta}{2\pi} \pmod{1}

Nastavíme θ=162π\theta=\tfrac{1}{6}\cdot 2\pi, takže skutečná fáze je φ=1/6\varphi=1/6. QPE Circuit implementuje řízené mocniny U2kU^{2^k} aplikací řízených fázových rotací s úhly θ2k\theta\cdot2^k, poté aplikuje inverzní QFT na počítací registr a změří ho. Výsledné bitové řetězce se soustřeďují okolo binárního vyjádření 1/61/6.

Circuit používá mm počítacích qubitů (pro nastavení přesnosti odhadu) plus jeden cílový Qubit. Začneme definováním stavebních bloků potřebných k implementaci QPE: Kvantová Fourierova transformace (QFT) a její inverzní verze, pomocné funkce pro převod mezi desítkovými a binárními zlomky vlastní fáze a pomocníci pro normalizaci surových počtů na pravděpodobnosti pro srovnání výsledků simulace a hardwaru.

def inverse_quantum_fourier_transform(quantum_circuit, number_of_qubits):
"""
Apply an inverse Quantum Fourier Transform the first `number_of_qubits` qubits in the
`quantum_circuit`.
"""
for qubit in range(number_of_qubits // 2):
quantum_circuit.swap(qubit, number_of_qubits - qubit - 1)
for j in range(number_of_qubits):
for m in range(j):
quantum_circuit.cp(-np.pi / float(2 ** (j - m)), m, j)
quantum_circuit.h(j)
return quantum_circuit
def bitstring_count_to_probabilities(data, shot_count):
"""
This function turns an unsorted dictionary of bitstring counts into a sorted dictionary
of probabilities.
"""
# Turn the bitstring counts into probabilities.
probabilities = {
bitstring: bitstring_count / shot_count
for bitstring, bitstring_count in data.items()
}

sorted_probabilities = dict(
sorted(probabilities.items(), key=lambda x: x[1], reverse=True)
)

return sorted_probabilities

Krok 2: Optimalizace problému pro spuštění na kvantovém hardwaru

Sestavíme QPE Circuit tak, že připravíme počítací qubity v superpozici, aplikujeme řízené fázové rotace pro zakódování cílové vlastní fáze a zakončíme inverzní QFT před měřením.

def quantum_phase_estimation_benchmark_circuit(
number_of_counting_qubits, phase
):
"""
Create the circuit for quantum phase estimation.

Parameters
----------
number_of_counting_qubits : The number of qubits in the circuit.
phase : The desired phase.

Returns
-------
QuantumCircuit
The quantum phase estimation circuit for `number_of_counting_qubits` qubits.
"""
qc = QuantumCircuit(
number_of_counting_qubits + 1, number_of_counting_qubits
)
target = number_of_counting_qubits

# |1> eigenstate for the single-qubit phase gate
qc.x(target)

# Hadamards on counting register
for q in range(number_of_counting_qubits):
qc.h(q)

# ONE controlled phase per counting qubit: cp(phase * 2**k)
for k in range(number_of_counting_qubits):
qc.cp(phase * (1 << k), k, target)

qc.barrier()

# Inverse QFT on counting register
inverse_quantum_fourier_transform(qc, number_of_counting_qubits)

qc.barrier()
for q in range(number_of_counting_qubits):
qc.measure(q, q)
return qc

Krok 3: Spuštění pomocí primitiv Qiskit

Nastavíme počet snímků a qubitů pro experiment a zakódujeme cílovou fázi φ=1/6\varphi = 1/6 pomocí mm binárních číslic. S těmito parametry sestavíme QPE Circuit, který bude spuštěn na simulaci, výchozím hardwaru a Backend vylepšeném pomocí Fire Opal.

shot_count = 10000
num_qubits = 35
phase = (1 / 6) * 2 * np.pi
circuits_quantum_phase_estimation = (
quantum_phase_estimation_benchmark_circuit(
number_of_counting_qubits=num_qubits, phase=phase
)
)

Spuštění MPS simulace

Nejprve vygenerujeme referenční distribuci pomocí simulátoru matrix_product_state a převedeme počty na normalizované pravděpodobnosti pro pozdější srovnání s výsledky z hardwaru.

# Run the algorithm on the IBM Aer simulator.
aer_simulator = AerSimulator(method="matrix_product_state")

# Transpile the circuits for the simulator.
transpiled_circuits = qiskit.transpile(
circuits_quantum_phase_estimation, aer_simulator
)
simulated_result = (
aer_simulator.run(transpiled_circuits, shots=shot_count)
.result()
.get_counts()
)
simulated_result_probabilities = []

simulated_result_probabilities.append(
bitstring_count_to_probabilities(
simulated_result,
shot_count=shot_count,
)
)

Spuštění na hardwaru

service = QiskitRuntimeService()
backend = service.least_busy(operational=True, simulator=False)

pm = generate_preset_pass_manager(backend=backend, optimization_level=3)
isa_circuits = pm.run(circuits_quantum_phase_estimation)
# Run the algorithm with IBM default.
sampler = Sampler(backend)

# Run all circuits using Qiskit Runtime.
ibm_default_job = sampler.run([isa_circuits], shots=shot_count)

Spuštění na hardwaru s Fire Opal

# Run the circuit using the sampler
fire_opal_job = perf_mgmt.run(
primitive="sampler",
pubs=[qasm2.dumps(circuits_quantum_phase_estimation)],
backend_name=backend.name,
options={"default_shots": shot_count},
)

Krok 4: Následné zpracování a vrácení výsledku v požadovaném klasickém formátu

# Retrieve results.
ibm_default_result = ibm_default_job.result()
ibm_default_probabilities = []

for idx, pub_result in enumerate(ibm_default_result):
ibm_default_probabilities.append(
bitstring_count_to_probabilities(
pub_result.data.c0.get_counts(),
shot_count=shot_count,
)
)
fire_opal_result = fire_opal_job.result()

fire_opal_probabilities = []
for idx, pub_result in enumerate(fire_opal_result):
fire_opal_probabilities.append(
bitstring_count_to_probabilities(
pub_result.data.c0.get_counts(),
shot_count=shot_count,
)
)
data = {
"simulation": simulated_result_probabilities,
"default": ibm_default_probabilities,
"fire_opal": fire_opal_probabilities,
}
def plot_distributions(
data,
number_of_counting_qubits,
top_k=None,
by="prob",
shot_count=None,
):
def nrm(d):
s = sum(d.values())
return {k: (v / s if s else 0.0) for k, v in d.items()}

def as_float(d):
return {k: float(v) for k, v in d.items()}

def to_space(d):
if by == "prob":
return nrm(as_float(d))
else:
if shot_count and 0.99 <= sum(d.values()) <= 1.01:
return {
k: v * float(shot_count) for k, v in as_float(d).items()
}
else:
return as_float(d)

def topk(d, k):
items = sorted(d.items(), key=lambda kv: kv[1], reverse=True)
return items[: (k or len(d))]

phase = "1/6"

sim = to_space(data["simulation"])
dft = to_space(data["default"])
qct = to_space(data["fire_opal"])

correct = max(sim, key=sim.get) if sim else None
print("Correct result:", correct)

sim_items = topk(sim, top_k)
dft_items = topk(dft, top_k)
qct_items = topk(qct, top_k)

sim_keys, y_sim = zip(*sim_items) if sim_items else ([], [])
dft_keys, y_dft = zip(*dft_items) if dft_items else ([], [])
qct_keys, y_qct = zip(*qct_items) if qct_items else ([], [])

fig, axes = plt.subplots(3, 1, layout="constrained")
ylab = "Probabilities"

def panel(ax, keys, ys, title, color):
x = np.arange(len(keys))
bars = ax.bar(x, ys, color=color)
ax.set_title(title)
ax.set_ylabel(ylab)
ax.set_xticks(x)
ax.set_xticklabels(keys, rotation=90)
ax.set_xlabel("Bitstrings")
if correct in keys:
i = keys.index(correct)
bars[i].set_edgecolor("black")
bars[i].set_linewidth(2)
return max(ys, default=0.0)

c_sim, c_dft, c_qct = (
qv.QCTRL_STYLE_COLORS[5],
qv.QCTRL_STYLE_COLORS[1],
qv.QCTRL_STYLE_COLORS[0],
)
m1 = panel(axes[0], list(sim_keys), list(y_sim), "Simulation", c_sim)
m2 = panel(axes[1], list(dft_keys), list(y_dft), "Default", c_dft)
m3 = panel(axes[2], list(qct_keys), list(y_qct), "Q-CTRL", c_qct)

for ax, m in zip(axes, (m1, m2, m3)):
ax.set_ylim(0, 1.05 * (m or 1.0))

for ax in axes:
ax.label_outer()
fig.suptitle(
rf"{number_of_counting_qubits} counting qubits, $2\pi\varphi$={phase}"
)
fig.set_size_inches(20, 10)
plt.show()
experiment_index = 0
phase_index = 0

distributions = {
"simulation": data["simulation"][phase_index],
"default": data["default"][phase_index],
"fire_opal": data["fire_opal"][phase_index],
}

plot_distributions(
distributions, num_qubits, top_k=100, by="prob", shot_count=shot_count
)
Correct result: 00101010101010101010101010101010101

Output of the previous code cell

Simulace nastavuje základní linii pro správnou vlastní fázi. Výchozí hardwarové běhy vykazují šum, který tento výsledek zakrývá, protože šum rozptyluje pravděpodobnost do mnoha nesprávných bitových řetězců. S Q-CTRL Performance Management se distribuce zostřuje a správný výsledek je obnoven, což umožňuje spolehlivé QPE v tomto měřítku.

Reference

[1] Přednáška 7: Odhad fáze a faktorizace. IBM Quantum Learning - Základy kvantových algoritmů. Přístup 3. října 2025.

Průzkum k tutoriálu

Věnuj prosím chvíli zpětné vazbě k tomuto tutoriálu. Tvé postřehy nám pomohou zlepšit naše výukové materiály a uživatelský zážitek.

Odkaz na průzkum

Note: This survey is provided by IBM Quantum and relates to the original English content. To give feedback on doQumentation's website, translations, or code execution, please open a GitHub issue.