Sari la conținutul principal
Acest proiect este în versiune beta. Ai găsit o eroare? Deschide un issue pe GitHub. Ai o întrebare sau o idee? Întreabă în Discussions — ne-ar plăcea să aflăm părerea ta!
Cum este calitatea traducerii pe această pagină?

Start rapid

Acest ghid demonstrează un exemplu minimal funcțional al pachetului qiskit-addon-obp. Folosim operator backpropagation (OBP) pentru a reduce adâncimea unui circuit cuantic absorbind porțile finale în observabilă.

O valoare de așteptare ⟨O⟩=⟨ψ∣U†OU∣ψ⟩\langle O \rangle = \langle \psi | U^\dagger O U | \psi \rangle rămâne neschimbată dacă detașăm un bloc final de porți din circuitul UU și conjugăm clasic observabila cu el. OBP aplică acest lucru în mod repetat, evaluând clasic o parte din circuit, astfel încât pe hardware rulează doar un circuit mai puțin adânc. Prețul este că fiecare poartă absorbită poate extinde observabila în mai mulți termeni Pauli, deci adâncimea câștigată trebuie cântărită în raport cu creșterea observabilei.

Pentru exemple despre cum să construiești fluxuri de lucru realiste cu acest instrument și să le execuți pe hardware cuantic, consultă tutorialele de pe IBM Quantum Platform (OBP Tutorial).

Pregătește intrările pentru OBP​

OBP primește ca intrare o listă de felii de circuit și o observabilă. Retropropagă feliile pe rând, de la sfârșitul circuitului în observabilă, reducând adâncimea circuitului în schimbul unor termeni Pauli suplimentari în observabilă. Aici generăm un circuit de evoluție în timp pentru un model Heisenberg cu 10 qubiți și îl tăiem în felii după tipul de poartă.

Mai jos desenăm circuitul original, apoi același circuit recombinat, cu bariere care marchează limitele feliilor — fiecare felie este o unitate care poate fi absorbită în observabilă într-un singur pas de retropropagare.

# Added by doQumentation — installs the packages this notebook needs if they are missing
import importlib.util

_needed = {"numpy": "numpy", "qiskit": "qiskit", "qiskit_addon_obp": "qiskit-addon-obp", "qiskit_addon_utils": "qiskit-addon-utils"}
_missing = [pip for module, pip in _needed.items()
if importlib.util.find_spec(module) is None]
# One at a time, so a package that fails to install does not block the others
for _pip in _missing:
%pip install -q {_pip}
if not _missing:
print("\u2713 All required packages are installed")
import numpy as np
from qiskit.quantum_info import SparsePauliOp
from qiskit.synthesis import LieTrotter
from qiskit.transpiler import CouplingMap
from qiskit_addon_utils.problem_generators import (
generate_time_evolution_circuit,
generate_xyz_hamiltonian,
)
from qiskit_addon_utils.slicing import combine_slices, slice_by_gate_types

# Generate a circuit to reduce
coupling_map = CouplingMap.from_heavy_hex(3, bidirectional=False)
reduced_coupling_map = coupling_map.reduce(
[0, 13, 1, 14, 10, 16, 5, 12, 8, 18]
)

hamiltonian = generate_xyz_hamiltonian(
reduced_coupling_map,
coupling_constants=(np.pi / 8, np.pi / 4, np.pi / 2),
ext_magnetic_field=(np.pi / 3, np.pi / 6, np.pi / 9),
)

circuit = generate_time_evolution_circuit(
hamiltonian,
time=0.2,
synthesis=LieTrotter(reps=2),
)

# Slice the circuit and define an observable
slices = slice_by_gate_types(circuit)
observable = SparsePauliOp("IIIIIIIIIZ")

print(f"Original circuit depth: {circuit.depth()}")
print(f"Number of slices: {len(slices)}")
print(f"Observable terms: {len(observable)}")
Original circuit depth: 18
Number of slices: 18
Observable terms: 1
# Recombine the slices with barriers to make the slice boundaries visible
sliced_circuit = combine_slices(slices, include_barriers=True)

print("Original circuit:")
display(circuit.draw("mpl", scale=0.6, fold=-1))
print("Sliced circuit (recombined with barriers for visualization)")
sliced_circuit.draw("mpl", scale=0.6, fold=-1)
Original circuit:

Output of the previous code cell

Sliced circuit (recombined with barriers for visualization)

Output of the previous code cell

Redu adâncimea circuitului cu OBP​

Apelăm backpropagate pentru a absorbi felii în observabilă. Funcția returnează observabila extinsă, feliile de circuit prin care nu s-a propagat și metadate despre procedură.

Dacă nu este controlată, observabila poate crește spre 2n2^n termeni Pauli. operator_budget limitează această creștere — aici permitem cel mult 8 grupuri comutative la nivel de qubit, ceea ce stabilește aproximativ numărul de shoturi necesare pentru a evalua observabila pe QPU. Retropropagarea se oprește imediat ce absorbirea următoarei felii ar depăși bugetul, exact ceea ce se întâmplă mai jos: doar 7 din cele 18 felii sunt absorbite înainte ca observabila să umple toate cele 8 grupuri comutative și procedura să se oprească.

Pentru a pătrunde mai adânc în circuit, argumentul cuvânt-cheie truncation_error_budget al funcției backpropagate poate fi folosit pentru a elimina din observabilă termenii Pauli cu coeficienți mici pe măsură ce aceasta crește. Aceasta atenuează creșterea observabilei în schimbul unei erori proporționale cu magnitudinea termenilor Pauli trunchiați. Cele două bugete sunt complementare și pot fi folosite împreună: operator_budget controlează dimensiunea observabilei, în timp ce truncation_error_budget controlează eroarea introdusă prin eliminarea termenilor.

from qiskit_addon_obp import backpropagate
from qiskit_addon_obp.utils.simplify import OperatorBudget

max_qwc_groups = 8
bp_obs, remaining_slices, metadata = backpropagate(
observable,
slices,
operator_budget=OperatorBudget(max_qwc_groups=max_qwc_groups),
)

reduced_circuit = combine_slices(remaining_slices)
num_groups = len(bp_obs.group_commuting(qubit_wise=True))

print(
f"Backpropagated {metadata.num_backpropagated_slices} of {len(slices)} slices."
)
print(
f"Reduced circuit depth: {reduced_circuit.depth()} (was {circuit.depth()})"
)
print(f"Observable grew from {len(observable)} to {len(bp_obs)} Pauli terms.")
print(
f"Filled {num_groups} of {max_qwc_groups} commuting groups, exhausting the budget."
)
Backpropagated 7 of 18 slices.
Reduced circuit depth: 11 (was 18)
Observable grew from 1 to 18 Pauli terms.
Filled 8 of 8 commuting groups, exhausting the budget.
reduced_circuit.draw("mpl", scale=0.6, fold=-1)

Output of the previous code cell