Einfüehrung en Bruchteil-Gates
Verbruchsschätzung: ungefähr 30 Sekunde op enem Heron r2 Prozessor (OPJEPASS: Dat es bloß en Schätzung. Ding Laufzick kann anders sin.)
Hintergrund
Bruchteil-Gates op IBM QPUs
Bruchteil-Gates sinn parametrisierte Quante-Gates die et möglich maache arbiträr-Winkel Rotationen direkt ußzeföhre (en bestemmpte Jränze), un dodurch bruchme se nit en miehr Basis-Gates zerrleeje. Door dat mer de nativ Interakzjohne zwesche de physikalische Qubits nütze, künne Benutzer bestemmpte Unitäre effizienter op Hardware implementiere.
IBM Quantum® Heron QPUs ongerstötze die folgende Bruchteil-Gates:
- för
- för all reell Wäät
Die Gates künne suwohl de Deef wie och de Dauer vun Quanteschaltkreis bedütend reduziere. Se sinn besönders vorteilhaft en Aanwendunge die stark op un baue, wie Hamiltonscher Simulation, dem Quantum Approximate Optimization Algorithm (QAOA), un Quante-Kernel Methode. En däm Tutorial konzentriere mer uns op der Quante-Kernel als praktisch Beispill.
Beschränkunge
Bruchteil-Gates sinn em Momang en experimentell Funkzjon un komme met e paar Beschränkunge:
- es beschränk op Winkel em Bereich .
- De Verweendung vun Bruchteil-Gates weed nit ongerstötz för dynamische Schaltkreis, Pauli twirling, probabilistische Fehlerauslöschung (PEC), un zero-noise extrapolation (ZNE) (met probabilistische Fehlerverstärkung (PEA)).
Bruchteil-Gates bruche en andre Workflow als de Standardaansatz. Dat Tutorial erklärt wie mer met Bruchteil-Gates dörch en praktisch Aanwendung ärbeide.
Luurt ens en die folgend för mieh Details övver Bruchteil-Gates.
Övverbleck
De Workflow för de Verweendung vun Bruchteil-Gates folgk jenerell dem Qiskit patterns Workflow. Dä wesentlich Ongerscheid es dat all RZZ Winkel de Beschränkung erfülle mösse. Et jitt zwei Aansätze öm sescher ze stelle dat die Bedingung erföllt weed. Dat Tutorial konzentreert sich op un empfehlt dä zweete Aansatz.
# Added by doQumentation — installs packages not in the Binder environment
!pip install -q qiskit-basis-constructor
1. Parameterwääte jeneriere die de RZZ Winkelbeschränkung erfülle
Wann de secher bes dat all RZZ Winkel em jöltije Bereich ligge, kanns de dem Standardworkflow vun Qiskit patterns folgke. En däm Fall jifs de einfach de Parameterwääte als Deil vun enem PUB aan. Dä Workflow löppt esu:
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)])
Wann de versöchs en PUB aanzejevve dat enn RZZ Gate met enem Winkel ußerhalv vum jöltije Bereich enthällt, kriss de en Fehlermeldung wie:
'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].'
Öm dä Fehler ze vermeide, solls de dä zweete Aansatz övverleeje dä unge beschrevve weed.
2. Parameterwääte aan Schaltkreis zuweise vör de Transpilazjon
Et qiskit-ibm-runtime Paket stellt enne spezialisierte Transpiler-Pass bereet dä FoldRzzAngle heißt.
Dä Pass transformeert Quanteschaltkreis esu dat all RZZ Winkel met de RZZ Winkelbeschränkung övvereinstemme.
Wann de et Backend aan generate_preset_pass_manager oder transpile jiss, wend Qiskit automatisch FoldRzzAngle op de Quanteschaltkreis aan.
Dat froog dich drüm Parameterwääte aan Quanteschaltkreis vör de Transpilazjon zuzuweise.
Dä Workflow löppt esu:
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)])
Merk dat dä Workflow mieh Berechnungskooste verursaach als dä eeschte Aansatz, weil et Parameterwääte aan Quanteschaltkreis zuwise un de parameterjebondene Schaltkreis lokal speichere beinhällt. Zosätzlich jitt et enn bekannt Problem en Qiskit woh de Transformazjon vun RZZ Gates en bestemmpte Szenarien fählschloh kann. För en Lösung, luurt bes en dä Troubleshooting Abschnett. Dat Tutorial zeigg wie mer Bruchteil-Gates övver dä zweete Aansatz bruche, dörch en Beispill dat vum Quante-Kernel Methode inspireet es. Öm besser ze verstohn wo Quante-Kernels wohrscheinlich nützlich sinn, empfehle mer dat Lese vun Liu, Arunachalam & Temme (2021).
De kanns och et Quantum kernel training Tutorial un de Quantum kernels Lekzjon em Quantum machine learning Kurs op IBM Quantum Learning duurchärbeide.
Aanforderunge
Bevör de met däm Tutorial aanfängst, versichre dat de et Folgend installeert häs:
- Qiskit SDK v2.0 oder späder, met visualization Ongerstötzung
- Qiskit Runtime v0.37 oder späder (
pip install qiskit-ibm-runtime) - Qiskit Basis Constructor (
pip install qiskit_basis_constructor)
Oprüstung
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
Bruchteil-Gates aktiviere un Basis-Gates övverpröfe
Öm Bruchteil-Gates ze bruche, kanns de en Backend krige dat se ongerstötz, endem de de use_fractional_gates=True Opzjon setz.
Wann et Backend Bruchteil-Gates ongerstötz, sees de rzz un rx ongk sine Basis-Gates opjeföhrt.
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']
Workflow met Bruchteil-Gates
Schrett 1: Klassisch Eingabe op Quanteproblem abbeelde
Quante-Kernel Schaltkreis
En däm Abschnett ongersöche mer dä Quante-Kernel Schaltkreis met RZZ Gates öm dä Workflow för Bruchteil-Gates vörzestelle.
Mer fange aan endem mer enne Quanteschaltkreis bouwe öm einzeln Eenträg vun de Kernel-Matrix ze berechne. Dat weed jemaat endem mer ZZ Feature-Map Schaltkreis met enem unitary overlap kombiniere. De Kernel-Funkzjon nimmp Vektore em feature-mapped Raum un jitt ehr inner Produkt als Eentraach vun de Kernel-Matrix zeröck: woh dä feature-mapped Quantezustand darstellt.
Mer bouwe manuell enne ZZ Feature-Map Schaltkreis met RZZ Gates.
Obwohl Qiskit enne injebouwte zz_feature_map bereet stellt, ongerstötz et zurzigg kein RZZ Gates ab Qiskit v2.0.2 (luurt bes öm Issue).
Als nächste berechne mer de Kernel-Funkzjon för identisch Eingabe - för Beispill, . Op verrauschte Quantecomputer kann dä Wäät weniger als 1 sin wejen Rausche. En Resultat nöcher aan 1 bedügg weniger Rausche bei de Ußföhrung. En däm Tutorial nenne mer dä Wäät de Fidelity, defeneert als
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
Quante-Kernel Schaltkreis un ehr entsprechend Parameterwääte weede för Systeme met 4 bes 40 Qubits jenereet, un ehr Fidelities weede anschließend bewertet.
qubits = list(range(4, 44, 4))
circuits = [quantum_kernel(i, reps=reps) for i in qubits]
params = [random_parameters(circ) for circ in circuits]
Dä Vier-Qubit Schaltkreis weed unge visualiseert.
circuits[0].draw("mpl", fold=-1)

Em Standard Qiskit patterns Workflow weede Parameterwääte normalerwies als Deil vun enem PUB aan et Sampler oder Estimator Primitive övverjoffe. Wann mer ävver en Backend bruche dat Bruchteil-Gates ongerstötz, mösse die Parameterwääte explizit vör de Transpilazjon aan dä Quanteschaltkreis zujewise weede.
b_qc = [
circ.assign_parameters(param) for circ, param in zip(circuits, params)
]
b_qc[0].draw("mpl", fold=-1)

Schrett 2: Problem för Quante-Hardware Ußföhrung optimiere
Mer transpiliere dann dä Schaltkreis met dem Pass Manager noh dem Standard Qiskit Pattern.
Endem mer en Backend bereet stelle dat Bruchteil-Gates ongerstötz aan generate_preset_pass_manager, weed enne spezialiseerde Pass jenanndt FoldRzzAngle automatisch enjefögg.
Dä Pass modifizeert dä Schaltkreis öm met de RZZ Winkelbeschränkunge övverein ze stemme.
Als Resultat weede RZZ Gates met negative Wääte em vörijje Beld en positiv Wääte transformeert, un paar zosätzlich X Gates weede enjefögg.
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)])

Öm de Einfloß vun Bruchteil-Gates ze bewätte, evaluere mer de Zahl vun Nit-Lokal Gates (CZ un RZZ för dat Backend), zosamme met Schaltkreisdeefe un Dauerijkeete, un verglieche die Metrike met däne vun enem Standardworkflow späder.
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
]
Schrett 3: Met Qiskit Primitives ußföhre
Mer losse dä transpileete Schaltkreis met dem Backend dat Bruchteil-Gates ongerstötz.
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
Schrett 4: Nohbeärbeide un Resultat em jewönschte klassische Format zeröckjevve
De kanns dä Kernel-Funkzjonswäät krije endem de de Wohrscheinlichkeit vum all-null Bitstring 00...00 em Output miss.
# 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]
Verglich vun Workflow un Schaltkreis ohne Bruchteil-Gates
En däm Abschnett präsentiere mer dä Standard Qiskit patterns Workflow met enem Backend dat kein Bruchteil-Gates ongerstötz. Endem de de transpileete Schaltkreis vergliechs, wees de merke dat de Versjohn met Bruchteil-Gates (vum vörijje Abschnett) kompakter es als die ohne Bruchteil-Gates.
# 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]
Verglich vun Deefe un Fidelities
En däm Abschnett verglieche mer de Zahl vun Nit-Lokal Gates un de Fidelities zwesche Schaltkreis met un ohne Bruchteil-Gates. Dat hält de potenziell Vordeile vun de Verweendung vun Bruchteil-Gates bezöglich Ußföhrungseffizienz un Qualität hörvor.
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>
Mer verglieche de QPU Verbrauchszick met un ohne Bruchteil-Gates. De Resultate en de folgend Zell zeije dat de QPU Verbrauchswicke fast identisch sinn.
print(f"no fractional gates: {usage_c} seconds")
print(f"fractional gates: {usage_f} seconds")
no fractional gates: 7 seconds
fractional gates: 7 seconds
Fortjeschrittent Thema: Bloß fraktionell RX Gates bruche
De Notwendigkeit för dä modifizeete Workflow beim Bruche vun Bruchteil-Gates stemmp hauptsächlich vun de Beschränkung op RZZ Gate Winkel. Wann de ävver bloß de fraktionell RX Gates bruchs un de fraktionell RZZ Gates ußschlüss, kanns de widder dem Standard Qiskit patterns Workflow folgke. Dä Aansatz kann trotzdem bedütend Vordeile brenge, besönders en Schaltkreis die en jruß Zahl vun RX Gates un U Gates enthalde, endem et de Jesamtzahl vun Gates reduzeet un möglicherwiis de Performance verbessert. En däm Abschnett zeije mer wie de ding Schaltkreis optimeers met bloß fraktionelle RX Gates, während de RZZ Gates ußslüss.
Öm dat ze ongerstötze, stelle mer en Hilfsfunkzjon bereet die et dir erlaubt en bestemmpte Basis-Gate en enem Target Objekt ze deaktiviere. Hee bruche mer et öm RZZ Gates ze deaktiviere.
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
Mer bruche enne Schaltkreis dä us U, CZ, un RZZ Gates bestoht als Beispill.
qc = n_local(3, "u", "cz", "linear", reps=1)
qc.rzz(1.1, 0, 1)
qc.draw("mpl")
Mer transpiliere zuerst dä Schaltkreis för en Backend dat kein Bruchteil-Gates ongerstötz.
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)])

Dann transpiliere mer dä selve Schaltkreis met fraktionelle RX Gates, während mer RZZ Gates ußschleeße. Dat führt ze ener leeije Redukzjon en de Jesamtgatezahl, dank de effizienter Implementazjon vun de RX Gates.
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)])

U Gates met fraktionelle RX Gates optimiere
En däm Abschnett zeije mer wie mer U Gates met fraktionelle RX Gates optimeere, ufbouwend op däm selve Schaltkreis dä em vörijje Abschnett vörjestellt wood.
De mööss et qiskit-basis-constructor Paket för dä Abschnett installeere.
Dat es en Beta-Versjohn vun enem neue Transpilazjons-Plugin för Qiskit, dat möglicherwiis en de Zukunft en Qiskit integreet weed.
# %pip install qiskit-basis-constructor
from qiskit.circuit.library import UGate
from qiskit_basis_constructor import DEFAULT_EQUIVALENCE_LIBRARY
Mer transpiliere dä Schaltkreis bloß met fraktionelle RX Gates, un schließe RZZ Gates us. Endem mer en benutzerdefineete Zerleejungsregel enföhre, wie unge jezeicht, künne mer de Zahl vun Single-Qubit Gates reduziere die nödich sinn öm en U Gate ze implementiere.
Die Funkzjon weed em Momang en däm GitHub Issue diskuteert.
# 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)
Als nächste wende mer dä Transpiler aan met constructor-beta Övversetzung bereetjestellt vum qiskit-basis-constructor Paket.
Als Resultat weed de Jesamtzahl vun Gates reduzeet em Verglich zur vörijje Transpilazjon.
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)])
Troubleshooting
Problem: Onjöltije RZZ Winkel künne noh de Transpilazjon blieve
Ab Qiskit v2.0.3 jitt et bekannt Probleme woh RZZ Gates met onjöltije Winkele en de Schaltkreis blieve künne och noh de Transpilazjon. Dat Problem trett normalerwies ongk de folgend Bedingunge op.
Fählschlaach wann de target Opzjon met generate_preset_pass_manager oder transpiler bruchs
Wann de target Opzjon met generate_preset_pass_manager oder transpiler jebruch weed, weed dä spezialiseerde Transpiler-Pass FoldRzzAngle nit opjerufe.
Öm en richtije Behandlung vun RZZ Winkele för Bruchteil-Gates sescher ze stelle, empfehle mer immer de backend Opzjon ze bruche.
Luurt bes öm dat Issue för mieh Details.
Fählschlaach wann Schaltkreis bestemmpte Gates enthalde
Wann ding Schaltkreis bestemmpte Gates wie XXPlusYYGate enthällt, kann dä Qiskit Transpiler RZZ Gates met onjöltije Winkele jeneriere.
Wann de dat Problem antreff, luurt bes öm dat GitHub Issue för en Lösung.
Tutorial-Umfrooch
Bes esu jood un maach an dere korze Umfrooch met öm Feedback övver dat Tutorial ze jevve. Ding Einsichte weede uns hellefe unser Inhaltaanjebot un Benutzerfahrung ze verbessere.