Zom Hauptinhalt springe

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:

  • RZZ(θ)R_{ZZ}(\theta) för 0<θ<π/20 < \theta < \pi / 2
  • RX(θ)R_X(\theta) för all reell Wäät θ\theta

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 RZZR_{ZZ} un RXR_X 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:

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 0<θπ/20 < \theta \leq \pi/2 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: K(x,y)=Φ(x)Φ(y),K(x, y) = \langle \Phi(x) | \Phi(y) \rangle, woh Φ(x)|\Phi(x)\rangle 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, K(x,x)=1K(x, x) = 1. 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 fidelity=K(x,x).\text{fidelity} = K(x, x).

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)

Output of the previous code cell

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)

Output of the previous code cell

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)])

Output of the previous code cell

Ö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 K(x,x)K(x, x) 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)])

Output of the previous code cell

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>

Output of the previous code cell

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>

Output of the previous code cell

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>

Output of the previous code cell

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>

Output of the previous code cell

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")

Output of the previous code cell

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)])

Output of the previous code cell

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)])

Output of the previous code cell

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)])

Output of the previous code cell

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.

Link zur Umfrooch