Kerneluri cuantice cu porți fracționale
Estimare de utilizare: sub 30 de secunde pe un procesor Heron r2 (NOTĂ: Aceasta este doar o estimare. Timpul de execuție poate varia.)
Rezultate ale învățării
-
Ce sunt porțile fracționale și cum reduc adâncimea și durata circuitelor pe QPU-urile IBM®
-
Constrângerile asociate cu utilizarea porților fracționale (în particular, intervalul unghiului RZZ)
-
Cum să construiești un flux de lucru pentru kernelul cuantic care folosește porți fracționale cu IBM Quantum Compute Service
-
Cum să compari metricile de execuție pe hardware (adâncime, durată, numărul de porți non-locale, fidelitate) cu și fără porți fracționale
-
Cum să folosești doar porți RX fracționale, păstrând în același timp fluxul de lucru standard cu modele Qiskit
Cerințe preliminare
-
Fluxul de lucru Qiskit patterns
-
Ghidul Porți fracționale
-
Tutorialul Antrenarea kernelului cuantic și lecția Kerneluri cuantice din cursul de învățare automată cuantică
Fundal
Porți fracționale pe QPU-urile IBM
Porțile fracționale sunt porți cuantice parametrizate ce permit executarea directă a rotațiilor cu unghi arbitrar (în anumite limite), eliminând nevoia de a le descompune în mai multe porți de bază. Prin valorificarea interacțiunilor native dintre qubiții fizici, poți implementa anumite unitare mai eficient pe hardware.
QPU-urile IBM Quantum® Heron suportă următoarele porți fracționale:
- pentru
- pentru orice valoare reală
Aceste porți pot reduce semnificativ atât adâncimea, cât și durata circuitelor cuantice. Sunt deosebit de avantajoase în aplicațiile care se bazează mult pe și , cum ar fi simularea Hamiltonianului, Algoritmul de Optimizare Aproximativă Cuantică (QAOA) și metodele de kernel cuantic. În acest tutorial, ne concentrăm pe kernelul cuantic ca exemplu practic.
Limitări
Porțile fracționale sunt în prezent o funcționalitate experimentală și vin cu câteva restricții:
- este limitat la unghiuri în intervalul .
- Utilizarea porților fracționale nu este suportată pentru circuite dinamice, răsucire Pauli, anularea probabilistică a erorilor (PEC) și extrapolarea la zgomot zero (ZNE) (folosind amplificarea probabilistică a erorilor (PEA)).
Porțile fracționale necesită un flux de lucru diferit față de abordarea standard. Acest tutorial explică cum să lucrezi cu porți fracționale printr-o aplicație practică.
Consultă următoarele resurse pentru mai multe detalii despre porțile fracționale.
Abordări ale fluxului de lucru pentru constrângerea unghiului RZZ
Fluxul de lucru pentru utilizarea porților fracționale urmează în general fluxul Qiskit patterns. Diferența esențială este că toate unghiurile RZZ trebuie să satisfacă constrângerea . Există două abordări pentru a asigura respectarea acestei condiții, după cum discutăm mai jos. Recomandăm a doua abordare, iar în acest tutorial o demonstrăm printr-un exemplu inspirat de metoda kernelului cuantic. Pentru a înțelege mai bine unde kernelurile cuantice sunt susceptibile de a fi utile, recomandăm citirea lucrării Liu, Arunachalam & Temme (2021).
Poți parcurge și tutorialul Antrenarea kernelului cuantic și lecția Kerneluri cuantice din cursul de învățare automată cuantică de pe IBM Quantum® Learning.
# Added by doQumentation — required packages for this notebook
!pip install -q matplotlib numpy qiskit qiskit-aer qiskit-basis-constructor qiskit-ibm-runtime
1. Generează valori de parametri care respectă constrângerea unghiului RZZ
Dacă ești sigur că toate unghiurile RZZ se încadrează în intervalul valid, poți urma fluxul standard Qiskit patterns. În acest caz, transmiți pur și simplu valorile parametrilor ca parte a unui PUB. Fluxul de lucru se desfășoară astfel.
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)])
Dacă încerci să trimiți un PUB care conține o poartă RZZ cu un unghi în afara intervalului valid, vei întâlni un mesaj de eroare de tipul:
'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].'
Pentru a evita această eroare, folosește a doua abordare descrisă mai jos.
2. Asignează valorile parametrilor circuitelor înainte de transpilare
Pachetul qiskit-ibm-runtime oferă un pas de transpilare specializat numit FoldRzzAngle.
Acest pas transformă circuitele cuantice astfel încât toate unghiurile RZZ să respecte constrângerea unghiului RZZ.
Dacă furnizezi backend-ul la generate_preset_pass_manager sau transpile, Qiskit aplică automat FoldRzzAngle circuitelor cuantice.
Această abordare necesită să asignezi valorile parametrilor circuitelor cuantice înainte de transpilare.
Fluxul de lucru se desfășoară astfel.
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)])
Reține că acest flux de lucru presupune un cost computațional mai mare decât prima abordare, deoarece implică atribuirea valorilor parametrilor circuitelor cuantice și stocarea locală a circuitelor cu parametri asignați.
Reține o problemă cunoscută în qiskit-ibm-runtime v0.47.0 în care porțile RZZ cu unghiuri invalide ar putea rămâne în circuite chiar și după transpilare, în anumite scenarii.
Consultă qiskit-ibm-runtime#2441 pentru a urmări progresul acestei probleme. Recomandăm următoarea soluție temporară până la rezolvarea ei.
pm = generate_preset_pass_manager(backend=backend, ...)
pm.post_optimization = PassManager(
[
FoldRzzAngle(),
Optimize1qGatesDecomposition(target=backend.target),
RemoveIdentityEquivalent(target=backend.target),
]
)
... = pm.run(...)
Cerințe
Înainte de a începe acest tutorial, asigură-te că ai instalate următoarele:
- Qiskit SDK v2.0 sau o versiune ulterioară, cu suport pentru vizualizare
- Qiskit Runtime v0.41 sau o versiune ulterioară (
pip install qiskit-ibm-runtime) - Qiskit Aer v0.17 sau o versiune ulterioară (
pip install qiskit-aer) - Qiskit Basis Constructor (
pip install qiskit_basis_constructor)
Configurare
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 UGate, n_local, unitary_overlap
from qiskit.transpiler import Target, PassManager
from qiskit.transpiler.passes import (
Optimize1qGatesDecomposition,
RemoveIdentityEquivalent,
)
from qiskit_aer.primitives import SamplerV2 as AerSampler
from qiskit_basis_constructor import DEFAULT_EQUIVALENCE_LIBRARY
from qiskit_ibm_runtime import QiskitRuntimeService, SamplerV2
from qiskit_ibm_runtime.transpiler.passes import FoldRzzAngle
Activează porțile fracționale și verifică porțile de bază
Pentru a utiliza porțile fracționale, poți obține un backend care le suportă setând opțiunea use_fractional_gates=True.
Dacă backend-ul suportă porțile fracționale, vei vedea rzz și rx listate printre porțile sale de bază.
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_marrakesh
No fractional gates: ['cz', 'id', 'rz', 'sx', 'x']
With fractional gates: ['cz', 'id', 'rx', 'rz', 'rzz', 'sx', 'x']
Exemplu pe simulator la scară mică
În această secțiune, parcurgem cei patru pași ai fluxului de lucru Qiskit patterns pe un simulator, folosind circuitul kernelului cuantic ca exemplu practic.
Pasul 1: Mapează intrările clasice la o problemă cuantică
Circuit kernel cuantic
În această secțiune, explorăm circuitul kernelului cuantic folosind porți RZZ pentru a introduce fluxul de lucru pentru porțile fracționale.
Începem prin construirea unui circuit cuantic pentru a calcula intrările individuale ale matricei kernel. Aceasta se face combinând circuite ZZ feature map cu o suprapunere unitară. Funcția kernel preia vectori din spațiul mapat prin caracteristici și returnează produsul lor intern ca intrare a matricei kernel: unde reprezintă starea cuantică mapată prin caracteristici.
Construim manual un circuit ZZ feature map folosind porți RZZ.
Deși Qiskit oferă un zz_feature_map integrat, acesta nu suportă în prezent porțile RZZ începând cu Qiskit v2.4.1 (vezi problema).
Apoi, calculăm funcția kernel pentru intrări identice — de exemplu, . Pe calculatoarele cuantice cu zgomot, această valoare poate fi mai mică de 1 din cauza zgomotului. Un rezultat mai aproape de 1 indică un zgomot mai scăzut în execuție. În acest tutorial, ne referim la această valoare ca fidelitate, definită ca
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
Circuitele kernelului cuantic și valorile corespunzătoare ale parametrilor sunt generate pentru sisteme cu 4 până la 40 de qubiți, iar fidelitățile acestora sunt evaluate ulterior.
qubits = list(range(4, 12, 2))
circuits = [quantum_kernel(i, reps=reps) for i in qubits]
params = [random_parameters(circ) for circ in circuits]
Circuitul cu patru qubiți este vizualizat mai jos.
circuits[0].draw("mpl", fold=-1)

În fluxul standard Qiskit patterns, valorile parametrilor sunt transmise de obicei primitivei Sampler sau Estimator ca parte a unui PUB. Totuși, când folosești un backend care suportă porțile fracționale, aceste valori ale parametrilor trebuie asignate explicit circuitului cuantic înainte de transpilare.
b_qc = [
circ.assign_parameters(param) for circ, param in zip(circuits, params)
]
b_qc[0].draw("mpl", fold=-1)

Pasul 2: Optimizează problema pentru execuția pe hardware quantum
Transpilăm apoi circuitul folosind managerul de treceri, urmând pattern-ul standard Qiskit.
Furnizând un backend care suportă gate-uri fracționare la generate_preset_pass_manager, o trecere specializată numită FoldRzzAngle este inclusă automat.
Această trecere modifică circuitul pentru a respecta constrângerile de unghi RZZ.
Prin urmare, gate-urile RZZ cu valori negative din figura anterioară sunt transformate în valori pozitive, iar câteva gate-uri X suplimentare sunt adăugate.
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
)
pm_f.post_optimization = PassManager(
[
FoldRzzAngle(),
Optimize1qGatesDecomposition(target=backend_f.target),
RemoveIdentityEquivalent(target=backend_f.target),
]
)
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})

Pentru a evalua impactul gate-urilor fracționare, calculăm numărul de gate-uri nelocale (CZ și RZZ pentru acest backend), împreună cu adâncimile și duratele circuitelor, și comparăm aceste metrici cu cele din fluxul de lucru standard mai târziu.
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
]
Pasul 3: Execută folosind primitivele Qiskit
Rulăm circuitul transpilat cu backend-ul care suportă gate-uri fracționare.
sampler_f = AerSampler.from_backend(backend_f)
job = sampler_f.run(t_qc_f, shots=shots)
print(job.job_id())
085ce928-767e-4200-93bf-3905e5411cfe
Pasul 4: Post-procesează și returnează rezultatul în formatul clasic dorit
Poți obține valoarea funcției kernel măsurând probabilitatea șirului de biți toți-zero 00...00 în ieșire.
result = job.result()
fidelity_f = [fidelity(result=res) for res in result]
print(fidelity_f)
[0.929, 0.882, 0.8645, 0.817]
Comparație între fluxul de lucru și circuitul fără gate-uri fracționare
În această secțiune, prezentăm fluxul de lucru standard Qiskit patterns folosind un backend care nu suportă gate-uri fracționare. Comparând circuitele transpilate, vei observa că versiunea cu gate-uri fracționare (din secțiunea anterioară) este mai compactă decât cea fără gate-uri fracționare.
# 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 = AerSampler.from_backend(backend_c)
job = sampler_c.run(pubs=zip(t_qc_c, params), shots=shots)
print(job.job_id())
f2cca29d-7263-4976-9e51-13a91b75c3ae
# step 4: post-processing
result = job.result()
fidelity_c = [fidelity(res) for res in result]
print(fidelity_c)
[0.8625, 0.7605, 0.702, 0.671]
Comparație între adâncimi, durate și fidelități
În această secțiune, comparăm numărul de gate-uri nelocale și fidelitățile între circuitele cu și fără gate-uri fracționare. Aceasta evidențiază beneficiile potențiale ale utilizării gate-urilor fracționare în ceea ce privește eficiența și calitatea execuției.
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 0x116af3cb0>
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 0x11ea4f4d0>
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 0x1247fc440>
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 0x120b792b0>
Exemplu pe hardware la scară mare
În această secțiune, evaluăm fluxul de lucru al kernelului cuantic cu și fără porți fracționale pe hardware cuantic cu până la 40 de qubiți.
Pașii 1-4 combinați
Fluxul de lucru urmează aceeași structură ca exemplul la scară mică. Transpilăm toate circuitele cu și fără porți fracționale, colectăm metrici, apoi trimitem circuitele către hardware cuantic real.
# -------------------------Step 1-------------------------
qubits = list(range(4, 44, 4))
circuits = [quantum_kernel(i, reps=reps) for i in qubits]
params = [random_parameters(circ) for circ in circuits]
b_qc = [
circ.assign_parameters(param) for circ, param in zip(circuits, params)
]
def benchmark(b_qc, backend):
# -------------------------Step 2-------------------------
pm = generate_preset_pass_manager(optimization_level, backend=backend)
if "rzz" in backend.target.operation_names:
# workaround until https://github.com/Qiskit/qiskit-ibm-runtime/issues/2441 is resolved
pm.post_optimization = PassManager(
[
FoldRzzAngle(),
Optimize1qGatesDecomposition(target=backend.target),
RemoveIdentityEquivalent(target=backend.target),
]
)
t_qc = pm.run(b_qc)
nnl = [qc.num_nonlocal_gates() for qc in t_qc]
depth = [qc.depth() for qc in t_qc]
duration = [
qc.estimate_duration(backend_f.target, unit="u") for qc in t_qc
]
# -------------------------Step 3-------------------------
sampler = SamplerV2(mode=backend)
sampler.options.dynamical_decoupling.enable = True
sampler.options.dynamical_decoupling.sequence_type = "XY4"
sampler.options.dynamical_decoupling.skip_reset_qubits = True
sampler.options.environment.job_tags = ["TUT_FG"]
job = sampler.run(t_qc, shots=shots)
job_id = job.job_id()
return nnl, depth, duration, job_id
def postprocessing(job_id: str):
# -------------------------Step 4-------------------------
job = service.job(job_id)
result = job.result()
fidelities = [fidelity(result=res) for res in result]
usage = job.usage()
return fidelities, usage
backend_f = service.backend(backend_name, use_fractional_gates=True)
nnl_f, depth_f, duration_f, job_id_f = benchmark(
b_qc, backend_f
) # step 2 & 3
print("job id (w/ fractional gates):", job_id_f)
fidelity_f, usage_f = postprocessing(job_id_f) # step 4
job id (w/ fractional gates): d8uasitbh0os73eqnpig
backend_c = service.backend(backend_name, use_fractional_gates=False)
nnl_c, depth_c, duration_c, job_id_c = benchmark(b_qc, backend_c)
print("job id (w/o fractional gates):", job_id_c)
fidelity_c, usage_c = postprocessing(job_id_c)
job id (w/o fractional gates): d8uav3lposuc738pruug
Apoi comparăm metricile.
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 0x12461e660>
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 0x11f2ac980>
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 0x125c91be0>
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 0x11fcf6e40>
Comparăm timpul de utilizare al QPU-ului cu și fără gate-uri fracționare. Rezultatele din celula următoare arată că timpii de utilizare ai QPU-ului sunt aproape identici.
print(f"no fractional gates: {usage_c} seconds")
print(f"fractional gates: {usage_f} seconds")
no fractional gates: 8 seconds
fractional gates: 8 seconds
Subiect avansat: Folosind doar porți RX fracționale
Necesitatea unui flux de lucru modificat atunci când se folosesc porți fracționale provine în principal din restricția asupra unghiurilor porții RZZ. Cu toate acestea, dacă folosești doar porțile RX fracționale și excluzi porțile RZZ fracționale, poți continua să urmezi fluxul de lucru standard al tiparelor Qiskit. Această abordare poate oferi în continuare beneficii semnificative, în special în Circuit-uri care implică un număr mare de porți RX și U, reducând numărul total de porți și îmbunătățind potențial performanța. În această secțiune, demonstrăm cum să îți optimizezi Circuit-urile folosind doar porți RX fracționale, omițând porțile RZZ.
Pentru a susține acest lucru, furnizăm o funcție utilitară care îți permite să dezactivezi un anumit basis gate dintr-un obiect Target. Aici, o folosim pentru a dezactiva porțile RZZ.
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
Folosim un circuit format din porți U, CZ și RZZ ca exemplu.
qc = n_local(3, "u", "cz", "linear", reps=1)
qc.rzz(1.1, 0, 1)
qc.draw("mpl")
Mai întâi transpilăm Circuit-ul pentru un Backend care nu suportă porți fracționale.
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})

Apoi, transpilăm același Circuit folosind porți RX fracționale, excluzând porțile RZZ. Aceasta conduce la o ușoară reducere a numărului total de porți, datorită implementării mai eficiente a porților RX.
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})

Optimizarea porților U cu porți RX fracționale
În această secțiune, demonstrăm cum să optimizăm porțile U folosind porți RX fracționale, construind pe același circuit introdus în secțiunea anterioară. Transpilăm circuitul folosind doar porți RX fracționale, excluzând porțile RZZ. Introducând o regulă de descompunere personalizată, după cum se arată mai jos, putem reduce numărul de porți pe un singur qubit necesare pentru a implementa o poartă U.
Această funcționalitate este în prezent în discuție în această problemă GitHub.
# 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)
În continuare, aplicăm Transpiler-ul folosind traducerea constructor-beta furnizată de pachetul qiskit-basis-constructor.
Ca rezultat, numărul total de porți este redus comparativ cu transpilarea anterioară.
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})
Pași următori
Dacă ai găsit acest material interesant, ai putea fi interesat de următoarele materiale:
- Ghidul Porți fracționale
- Când nu să folosești porți fracționale
- Referința API a treceri transpilatorului
FoldRzzAngle - Tutorialul Antrenarea kernelului cuantic
- Lecția Kerneluri cuantice din cursul de învățare automată cuantică