Úvod do frakčních gates
Odhadovaná spotřeba: méně než 30 sekund na procesoru Heron r2 (POZNÁMKA: Jde pouze o odhad. Skutečná doba zpracování se může lišit.)
Pozadí
Frakční Gates na IBM QPU
Frakční gates jsou parametrizované kvantové gates, které umožňují přímé provádění rotací o libovolný úhel (v rámci určitých mezí), čímž odpadá nutnost rozkládat je do několika základních gates. Využitím nativních interakcí mezi fyzickými Qubit mohou uživatelé implementovat určité unitární operace na hardwaru efektivněji.
IBM Quantum® Heron QPU podporují následující frakční gates:
- pro
- pro libovolnou reálnou hodnotu
Tyto gates mohou výrazně snížit jak hloubku, tak dobu trvání kvantových Circuit. Jsou obzvláště výhodné v aplikacích, které silně spoléhají na a , jako je simulace Hamiltoniánů, Quantum Approximate Optimization Algorithm (QAOA) a metody kvantového jádra. V tomto tutoriálu se zaměřujeme na kvantové jádro jako praktický příklad.
Omezení
Frakční gates jsou momentálně experimentální funkcí a mají určitá omezení:
- je omezen na úhly v rozsahu .
- Použití frakčních gates není podporováno pro dynamické Circuit, Pauli twirling, probabilistické rušení chyb (PEC) a extrapolaci nulového šumu (ZNE) (při použití probabilistického zesílení chyb (PEA)).
Frakční gates vyžadují odlišný pracovní postup oproti standardnímu přístupu. Tento tutoriál vysvětluje, jak pracovat s frakčními gates prostřednictvím praktické aplikace.
Více podrobností o frakčních gates najdeš na následujících stránkách.
Přehled
Pracovní postup pro použití frakčních gates obecně sleduje postup Qiskit patterns. Klíčový rozdíl je v tom, že všechny úhly RZZ musí splňovat podmínku . Existují dva přístupy, jak tuto podmínku zajistit. Tento tutoriál se zaměřuje na druhý přístup a doporučuje ho.
# Added by doQumentation — required packages for this notebook
!pip install -q matplotlib numpy qiskit qiskit-basis-constructor qiskit-ibm-runtime
1. Generování hodnot parametrů splňujících podmínku úhlu RZZ
Pokud jsi přesvědčen/a, že všechny úhly RZZ leží v platném rozsahu, můžeš postupovat podle standardního pracovního postupu Qiskit patterns. V takovém případě jednoduše předáš hodnoty parametrů jako součást PUB. Postup je následující.
pm = generate_preset_pass_manager(backend=backend, ...)
t_circuit = pm.run(circuit)
t_observable = observable.apply_layout(t_circuit.layout)
sampler.run([(t_circuit, parameter_values)])
estimator.run([(t_circuit, t_observable, parameter_values)])
Pokud se pokusíš odeslat PUB obsahující Gate RZZ s úhlem mimo platný rozsah, zobrazí se chybová zpráva podobná této:
'The instruction rzz is supported only for angles in the range [0, pi/2], but an angle (20.0) outside of this range has been requested; via parameter value(s) γ[0]=10.0, substituted in parameter expression 2.0*γ[0].'
Abys této chybě předešel/a, zvaž použití druhého přístupu popsaného níže.
2. Přiřazení hodnot parametrů Circuit před transpilací
Balíček qiskit-ibm-runtime poskytuje specializovaný transpilační průchod nazvaný FoldRzzAngle.
Tento průchod transformuje kvantové Circuit tak, aby všechny úhly RZZ splňovaly podmínku úhlu RZZ.
Pokud poskytneš Backend funkci generate_preset_pass_manager nebo transpile, Qiskit automaticky aplikuje FoldRzzAngle na kvantové Circuit.
To vyžaduje přiřazení hodnot parametrů ke kvantovým Circuit před transpilací.
Postup je následující.
pm = generate_preset_pass_manager(backend=backend, ...)
b_circuit = circuit.assign_parameters(parameter_values)
t_circuit = pm.run(b_circuit)
t_observable = observable.apply_layout(t_circuit.layout)
sampler.run([(t_circuit,)])
estimator.run([(t_circuit, t_observable)])
Všimni si, že tento postup je výpočetně náročnější než první přístup, protože zahrnuje přiřazení hodnot parametrů ke kvantovým Circuit a lokální uložení Circuit s vázanými parametry. Navíc existuje v Qiskit známý problém, kdy transformace Gate RZZ může v určitých scénářích selhat. Řešení najdeš v části Řešení problémů. Tento tutoriál ukazuje, jak používat frakční gates prostřednictvím druhého přístupu na příkladu inspirovaném metodou kvantového jádra. Abys lépe pochopil/a, kde jsou kvantová jádra pravděpodobně užitečná, doporučujeme přečíst Liu, Arunachalam & Temme (2021).
Můžeš také projít tutoriál Trénování kvantového jádra a lekci Kvantová jádra v kurzu Quantum machine learning na IBM Quantum Learning.
Požadavky
Před zahájením tohoto tutoriálu se ujisti, že máš nainstalováno:
- Qiskit SDK v2.0 nebo novější, s podporou vizualizace
- Qiskit Runtime v0.37 nebo novější (
pip install qiskit-ibm-runtime) - Qiskit Basis Constructor (
pip install qiskit_basis_constructor)
Nastavení
import matplotlib.pyplot as plt
import numpy as np
from qiskit import QuantumCircuit, generate_preset_pass_manager
from qiskit.circuit import ParameterVector
from qiskit.circuit.library import unitary_overlap
from qiskit_ibm_runtime import QiskitRuntimeService, SamplerV2
Aktivace frakčních gates a kontrola základních gates
Chceš-li použít frakční gates, můžeš získat Backend, který je podporuje, nastavením možnosti use_fractional_gates=True.
Pokud Backend frakční gates podporuje, uvidíš rzz a rx v seznamu jeho základních gates.
service = QiskitRuntimeService()
backend = service.least_busy(
operational=True, simulator=False, min_num_qubits=133
) # backend should be a heron device or later
backend_name = backend.name
backend_c = service.backend(backend_name) # w/o fractional gates
backend_f = service.backend(
backend_name, use_fractional_gates=True
) # w/ fractional gates
print(f"Backend: {backend_name}")
print(f"No fractional gates: {backend_c.basis_gates}")
print(f"With fractional gates: {backend_f.basis_gates}")
if "rzz" not in backend_f.basis_gates:
print(f"Backend {backend_name} does not support fractional gates")
Backend: ibm_fez
No fractional gates: ['cz', 'id', 'rz', 'sx', 'x']
With fractional gates: ['cz', 'id', 'rx', 'rz', 'rzz', 'sx', 'x']
Pracovní postup s frakčními gates
Krok 1: Mapování klasických vstupů na kvantový problém
Circuit kvantového jádra
V této části prozkoumáme Circuit kvantového jádra s použitím Gate RZZ a představíme pracovní postup pro frakční gates.
Začneme sestavením kvantového Circuit pro výpočet jednotlivých prvků matice jádra. To se provádí kombinací Circuit ZZ feature map s unitárním překryvem. Funkce jádra přijímá vektory v prostoru příznaků a vrací jejich skalární součin jako prvek matice jádra: kde představuje kvantový stav mapovaný přes příznaky.
Ručně sestavíme Circuit ZZ feature map s použitím Gate RZZ.
Přestože Qiskit poskytuje vestavěný zz_feature_map, od verze Qiskit v2.0.2 Gate RZZ zatím nepodporuje (viz issue).
Dále vypočítáme funkci jádra pro identické vstupy – například . Na zašumělých kvantových počítačích může být tato hodnota menší než 1 kvůli šumu. Výsledek blíže k 1 indikuje nižší šum při provádění. V tomto tutoriálu označujeme tuto hodnotu jako věrnost (fidelity), definovanou jako
optimization_level = 2
shots = 2000
reps = 3
rng = np.random.default_rng(seed=123)
def my_zz_feature_map(num_qubits: int, reps: int = 1) -> QuantumCircuit:
x = ParameterVector("x", num_qubits * reps)
qc = QuantumCircuit(num_qubits)
qc.h(range(num_qubits))
for k in range(reps):
K = k * num_qubits
for i in range(num_qubits):
qc.rz(x[i + K], i)
pairs = [(i, i + 1) for i in range(num_qubits - 1)]
for i, j in pairs[0::2] + pairs[1::2]:
qc.rzz((np.pi - x[i + K]) * (np.pi - x[j + K]), i, j)
return qc
def quantum_kernel(num_qubits: int, reps: int = 1) -> QuantumCircuit:
qc = my_zz_feature_map(num_qubits, reps=reps)
inner_product = unitary_overlap(qc, qc, "x", "y", insert_barrier=True)
inner_product.measure_all()
return inner_product
def random_parameters(inner_product: QuantumCircuit) -> np.ndarray:
return np.tile(rng.random(inner_product.num_parameters // 2), 2)
def fidelity(result) -> float:
ba = result.data.meas
return ba.get_int_counts().get(0, 0) / ba.num_shots
Circuit kvantového jádra a odpovídající hodnoty parametrů jsou generovány pro systémy se 4 až 40 Qubit a jejich věrnosti jsou následně vyhodnocovány.
qubits = list(range(4, 44, 4))
circuits = [quantum_kernel(i, reps=reps) for i in qubits]
params = [random_parameters(circ) for circ in circuits]
Čtyřqubitový Circuit je vizualizován níže.
circuits[0].draw("mpl", fold=-1)

Ve standardním pracovním postupu Qiskit patterns jsou hodnoty parametrů obvykle předávány primitivě Sampler nebo Estimator jako součást PUB. Při použití Backend podporujícího frakční gates však musí být tyto hodnoty parametrů explicitně přiřazeny ke kvantovému Circuit před transpilací.
b_qc = [
circ.assign_parameters(param) for circ, param in zip(circuits, params)
]
b_qc[0].draw("mpl", fold=-1)

Krok 2: Optimalizace problému pro spuštění na kvantovém hardwaru
Poté transpilujeme Circuit pomocí správce průchodů (pass manager) podle standardního vzoru Qiskit.
Tím, že předáme Backend podporující frakční Gate do generate_preset_pass_manager, je automaticky zahrnut specializovaný průchod FoldRzzAngle.
Tento průchod upravuje Circuit tak, aby splňoval omezení úhlů RZZ.
Výsledkem je, že RZZ Gate se zápornými hodnotami z předchozího obrázku jsou transformovány na kladné hodnoty a jsou přidány některé dodatečné Gate X.
backend_f = service.backend(name=backend_name, use_fractional_gates=True)
# pm_f includes `FoldRzzAngle` pass
pm_f = generate_preset_pass_manager(
optimization_level=optimization_level, backend=backend_f
)
t_qc_f = pm_f.run(b_qc)
print(t_qc_f[0].count_ops())
t_qc_f[0].draw("mpl", fold=-1)
OrderedDict([('rz', 35), ('rzz', 18), ('x', 13), ('rx', 9), ('measure', 4), ('barrier', 2)])

Abychom posoudili dopad frakčních Gate, vyhodnocujeme počet nelokálních Gate (CZ a RZZ pro tento Backend), spolu s hloubkami a dobami trvání Circuit, a porovnáváme tato měřítka s měřítky ze standardního pracovního postupu níže.
nnl_f = [qc.num_nonlocal_gates() for qc in t_qc_f]
depth_f = [qc.depth() for qc in t_qc_f]
duration_f = [
qc.estimate_duration(backend_f.target, unit="u") for qc in t_qc_f
]
Krok 3: Spuštění pomocí primitiv Qiskit
Spustíme transpilovaný Circuit s Backendem, který podporuje frakční Gate.
sampler_f = SamplerV2(mode=backend_f)
sampler_f.options.dynamical_decoupling.enable = True
sampler_f.options.dynamical_decoupling.sequence_type = "XY4"
sampler_f.options.dynamical_decoupling.skip_reset_qubits = True
job = sampler_f.run(t_qc_f, shots=shots)
print(job.job_id())
d4bninsi51bc738j97eg
Krok 4: Následné zpracování a vrácení výsledku v požadovaném klasickém formátu
Hodnotu funkce jádra lze získat měřením pravděpodobnosti bitového řetězce samých nul 00...00 ve výstupu.
# job = service.job("d1obougt0npc73flhiag")
result = job.result()
fidelity_f = [fidelity(result=res) for res in result]
print(fidelity_f)
usage_f = job.usage()
[0.9005, 0.647, 0.3345, 0.355, 0.3315, 0.174, 0.1875, 0.149, 0.1175, 0.085]
Srovnání pracovního postupu a Circuit bez frakčních Gate
V této části představujeme standardní pracovní postup vzorů Qiskit s použitím Backendu, který nepodporuje frakční Gate. Porovnáním transpilovaných Circuit si všimneš, že verze s frakčními Gate (z předchozí části) je kompaktnější než verze bez frakčních Gate.
# step 1: map classical inputs to quantum problem
# `circuits` and `params` from the previous section are reused here
# step 2: optimize circuits
backend_c = service.backend(backend_name) # w/o fractional gates
pm_c = generate_preset_pass_manager(
optimization_level=optimization_level, backend=backend_c
)
t_qc_c = pm_c.run(circuits)
print(t_qc_c[0].count_ops())
t_qc_c[0].draw("mpl", fold=-1)
OrderedDict([('rz', 130), ('sx', 80), ('cz', 36), ('measure', 4), ('barrier', 2)])

nnl_c = [qc.num_nonlocal_gates() for qc in t_qc_c]
depth_c = [qc.depth() for qc in t_qc_c]
duration_c = [
qc.estimate_duration(backend_c.target, unit="u") for qc in t_qc_c
]
# step 3: execute
sampler_c = SamplerV2(backend_c)
sampler_c.options.dynamical_decoupling.enable = True
sampler_c.options.dynamical_decoupling.sequence_type = "XY4"
sampler_c.options.dynamical_decoupling.skip_reset_qubits = True
job = sampler_c.run(pubs=zip(t_qc_c, params), shots=shots)
print(job.job_id())
d4bnirvnmdfs73ae3a2g
# step 4: post-processing
# job = service.job("d1obp8j3rr0s73bg4810")
result = job.result()
fidelity_c = [fidelity(res) for res in result]
print(fidelity_c)
usage_c = job.usage()
[0.6675, 0.5725, 0.098, 0.102, 0.065, 0.0235, 0.006, 0.0015, 0.0015, 0.002]
Srovnání hloubek a věrností
V této části porovnáváme počet nelokálních Gate a věrnosti Circuit s frakčními Gate a bez nich. To zdůrazňuje potenciální přínosy použití frakčních Gate z hlediska efektivity spuštění a kvality.
plt.plot(qubits, depth_c, "-o", label="no fractional gates")
plt.plot(qubits, depth_f, "-o", label="with fractional gates")
plt.xlabel("number of qubits")
plt.ylabel("depth")
plt.title("Comparison of depths")
plt.grid()
plt.legend()
<matplotlib.legend.Legend at 0x12bcaac50>
plt.plot(qubits, duration_c, "-o", label="no fractional gates")
plt.plot(qubits, duration_f, "-o", label="with fractional gates")
plt.xlabel("number of qubits")
plt.ylabel("duration (µs)")
plt.title("Comparison of durations")
plt.grid()
plt.legend()
<matplotlib.legend.Legend at 0x12bdef310>
plt.plot(qubits, nnl_c, "-o", label="no fractional gates")
plt.plot(qubits, nnl_f, "-o", label="with fractional gates")
plt.xlabel("number of qubits")
plt.ylabel("number of non-local gates")
plt.title("Comparison of numbers of non-local gates")
plt.grid()
plt.legend()
<matplotlib.legend.Legend at 0x12be8ac90>
plt.plot(qubits, fidelity_c, "-o", label="no fractional gates")
plt.plot(qubits, fidelity_f, "-o", label="with fractional gates")
plt.xlabel("number of qubits")
plt.ylabel("fidelity")
plt.title("Comparison of fidelities")
plt.grid()
plt.legend()
<matplotlib.legend.Legend at 0x12bea8290>
Porovnáváme dobu využití QPU s frakčními Gate a bez nich. Výsledky v následující buňce ukazují, že doby využití QPU jsou téměř totožné.
print(f"no fractional gates: {usage_c} seconds")
print(f"fractional gates: {usage_f} seconds")
no fractional gates: 7 seconds
fractional gates: 7 seconds
Pokročilé téma: Použití pouze zlomkových RX bran
Potřeba upraveného postupu při použití zlomkových bran pramení především z omezení úhlů brány RZZ. Pokud ale použiješ pouze zlomkové RX brány a zlomkové RZZ brány vynecháš, můžeš dále postupovat podle standardního pracovního postupu vzorů Qiskit. Tento přístup může přinést smysluplné výhody zejména v obvodech s velkým počtem bran RX a U, a to snížením celkového počtu bran a potenciálním zlepšením výkonu. V této části ukážeme, jak optimalizovat své obvody pomocí pouze zlomkových RX bran, přičemž vynecháme RZZ brány.
Aby to bylo možné, poskytujeme pomocnou funkci, která ti umožní zakázat konkrétní základní bránu v objektu Target. Zde ji použijeme k zakázání RZZ bran.
from qiskit.circuit.library import n_local
from qiskit.transpiler import Target
def remove_instruction_from_target(target: Target, gate_name: str) -> Target:
new_target = Target(
description=target.description,
num_qubits=target.num_qubits,
dt=target.dt,
granularity=target.granularity,
min_length=target.min_length,
pulse_alignment=target.pulse_alignment,
acquire_alignment=target.acquire_alignment,
qubit_properties=target.qubit_properties,
concurrent_measurements=target.concurrent_measurements,
)
for name, qarg_map in target.items():
if name == gate_name:
continue
instruction = target.operation_from_name(name)
if qarg_map == {None: None}:
qarg_map = None
new_target.add_instruction(instruction, qarg_map, name=name)
return new_target
Jako příklad použijeme Circuit složený z bran U, CZ a RZZ.
qc = n_local(3, "u", "cz", "linear", reps=1)
qc.rzz(1.1, 0, 1)
qc.draw("mpl")
Nejprve transpilujeme Circuit pro Backend, který nepodporuje zlomkové brány.
pm_c = generate_preset_pass_manager(
optimization_level=optimization_level, backend=backend_c
)
t_qc = pm_c.run(qc)
print(t_qc.count_ops())
t_qc.draw("mpl")
OrderedDict([('rz', 23), ('sx', 16), ('cz', 4)])

Poté transpilujeme stejný Circuit pomocí zlomkových RX bran, přičemž vynecháme RZZ brány. Výsledkem je mírné snížení celkového počtu bran díky efektivnější implementaci RX bran.
backend_f = service.backend(backend_name, use_fractional_gates=True)
target = remove_instruction_from_target(backend_f.target, "rzz")
pm_f = generate_preset_pass_manager(
optimization_level=optimization_level,
target=target,
)
t_qc = pm_f.run(qc)
print(t_qc.count_ops())
t_qc.draw("mpl")
OrderedDict([('rz', 22), ('sx', 14), ('cz', 4), ('rx', 1)])

Optimalizace bran U pomocí zlomkových RX bran
V této části ukážeme, jak optimalizovat brány U pomocí zlomkových RX bran, přičemž navážeme na stejný Circuit představený v předchozí části.
Pro tuto část budeš muset nainstalovat balíček qiskit-basis-constructor package.
Jedná se o beta verzi nového transpilačního pluginu pro Qiskit, který může být v budoucnu integrován přímo do Qiskit.
# %pip install qiskit-basis-constructor
from qiskit.circuit.library import UGate
from qiskit_basis_constructor import DEFAULT_EQUIVALENCE_LIBRARY
Transpilujeme Circuit s použitím pouze zlomkových RX bran, bez RZZ bran. Zavedením vlastního pravidla dekompozice, jak je ukázáno níže, můžeme snížit počet jednoqubitových bran potřebných k implementaci brány U.
Tato funkce je momentálně projednávána v tomto GitHub issue.
# special decomposition rule for UGate
x = ParameterVector("x", 3)
zxz = QuantumCircuit(1)
zxz.rz(x[2] - np.pi / 2, 0)
zxz.rx(x[0], 0)
zxz.rz(x[1] + np.pi / 2, 0)
DEFAULT_EQUIVALENCE_LIBRARY.add_equivalence(UGate(x[0], x[1], x[2]), zxz)
Dále aplikujeme Transpiler s překladem constructor-beta poskytovaným balíčkem qiskit-basis-constructor.
Výsledkem je snížení celkového počtu bran oproti předchozí transpilaci.
pm_f = generate_preset_pass_manager(
optimization_level=optimization_level,
target=target,
translation_method="constructor-beta",
)
t_qc = pm_f.run(qc)
print(t_qc.count_ops())
t_qc.draw("mpl")
OrderedDict([('rz', 16), ('rx', 9), ('cz', 4)])
Řešení problémů
Problém: Neplatné úhly RZZ mohou zůstat po transpilaci
Od verze Qiskit v2.0.3 existují známé problémy, kdy RZZ brány s neplatnými úhly mohou v obvodech zůstat i po transpilaci. Tento problém se typicky vyskytuje za následujících podmínek.
Selhání při použití volby target s generate_preset_pass_manager nebo transpiler
Pokud je volba target použita s generate_preset_pass_manager nebo transpiler, specializovaný transpilační průchod FoldRzzAngle není vyvolán.
Aby bylo zajištěno správné zpracování úhlů RZZ pro zlomkové brány, doporučujeme vždy místo toho používat volbu backend.
Více podrobností najdeš v tomto issue.
Selhání, když obvody obsahují určité brány
Pokud tvůj Circuit obsahuje určité brány jako XXPlusYYGate, může Transpiler Qiskit vygenerovat RZZ brány s neplatnými úhly.
Pokud na tento problém narazíš, podívej se na tento GitHub issue pro obejití problému.
Průzkum k tutoriálu
Vyplň prosím tento krátký průzkum a poskytni zpětnou vazbu k tomuto tutoriálu. Tvoje postřehy nám pomohou zlepšit naši nabídku obsahu a uživatelský zážitek.
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.