Avvio rapido
Questa guida illustra un esempio minimale funzionante del pacchetto qiskit-addon-obp . Utilizziamo la retropropagazione degli operatori (OBP) per ridurre la profondità di un circuito quantistico, incorporando i gate finali nell'osservabile.
Il valore atteso rimane invariato se si rimuove dal circuito un blocco finale di porte logiche e si coniuga l'osservabile in modo classico in base a tale blocco. OBP applica questo approccio ripetutamente, valutando una parte del circuito in modo classico, in modo che sull'hardware venga eseguito solo un circuito più semplice. Il prezzo da pagare è che ogni gate assorbito può espandere l'osservabile in un numero maggiore di termini di Pauli, quindi la profondità risparmiata deve essere valutata alla luce dell'aumento dell'osservabile.
Per vedere alcuni esempi su come creare flussi di lavoro realistici con questo strumento ed eseguirli su hardware quantistico, consulta i tutorial disponibili sull’ IBM Quantum Platform ( Tutorial OBP ).
Preparare i dati di input per l'OBP
OBP accetta come input un elenco di sezioni di circuito e un osservabile. Esegue la retropropagazione delle sezioni una alla volta, partendo dalla fine del circuito verso l'osservabile, riducendo la profondità del circuito a costo di termini di Pauli aggiuntivi nell'osservabile. In questa sede generiamo un circuito di evoluzione temporale per un modello di Heisenberg a 10 qubit e lo suddividiamo per tipo di gate.
Di seguito riportiamo il circuito originale, seguito dallo stesso circuito riorganizzato con delle barriere che segnano i confini delle sezioni: ciascuna sezione è un’unità che può essere assorbita nell’osservabile in un unico passo di retropropagazione.
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)}")Output:
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)Output:
Original circuit:
Sliced circuit (recombined with barriers for visualization)
Ridurre la profondità del circuito con OBP
Chiamiamo backpropagate per incorporare le sezioni nell'osservabile. La funzione restituisce l'osservabile espanso, le sezioni del circuito che non sono state propagate e i metadati relativi alla procedura.
Se non controllata, la grandezza osservabile può crescere verso termini di Pauli di ordine . Questo limite operator_budget pone un tetto massimo a tale crescita: in questo caso ammettiamo al massimo 8 gruppi commutanti a livello di qubit, il che determina approssimativamente il numero di tentativi necessari per valutare l’osservabile sulla QPU. La retropropagazione si interrompe non appena l'assorbimento della fetta successiva supererebbe il budget, ed è esattamente ciò che accade nell'esempio riportato di seguito: solo 7 delle 18 fette vengono assorbite prima che l'osservabile riempia tutti e 8 i gruppi di commutazione e la procedura si interrompa.
Per approfondire l'analisi del circuito, backpropagate è possibile utilizzare l'argomento " truncation_error_budget keyword" di per eliminare i termini di Pauli con coefficienti piccoli dall'osservabile man mano che questo cresce. Ciò attenua la crescita dell'osservabile in cambio di un errore proporzionale all'ampiezza dei termini di Pauli che vengono troncati. I due budget sono complementari e possono essere utilizzati insieme: operator_budget regola l' entità della grandezza osservabile, mentre truncation_error_budget regola l' errore derivante dall'esclusione di alcuni termini.
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."
)Output:
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: