Skip to main content
IBM Quantum Platform

Inicio rápido

Esta guía muestra un ejemplo mínimo y funcional del paquete qiskit-addon-obp . Utilizamos la retropropagación de operadores (OBP) para reducir la profundidad de un circuito cuántico mediante la absorción de las puertas finales en el observable.

El valor esperado O=ψUOUψ\langle O \rangle = \langle \psi | U^\dagger O U | \psi \rangle no varía si eliminamos un bloque de puertas situado al final del circuito UU y conjugamos el observable con él de forma clásica. OBP aplica este proceso repetidamente, evaluando parte del circuito de forma clásica para que solo se ejecute en el hardware una parte más superficial del mismo. El precio a pagar es que cada puerta absorbida puede ampliar el observable a más términos de Pauli, por lo que la profundidad que se ahorra debe sopesarse con el aumento del observable.

Para ver ejemplos de cómo crear flujos de trabajo realistas con esta herramienta y ejecutarlos en hardware cuántico, consulta los tutoriales de la Plataforma de Búsqueda de Órdenes ( IBM Quantum Platform, OBP Tutorial ).


Preparar los datos para el OBP

OBP toma como entrada una lista de segmentos de circuito y una variable observable. Realiza una retropropagación de las secciones una a una, desde el final del circuito hasta el observable, lo que reduce la profundidad del circuito a costa de la aparición de términos de Pauli adicionales en el observable. Aquí generamos un circuito de evolución temporal para un modelo de Heisenberg de 10 qubits y lo dividimos por tipo de puerta.

A continuación dibujamos el circuito original y, a continuación, el mismo circuito recombinado con barreras que marcan los límites de los segmentos; cada segmento es una unidad que puede integrarse en el observable en un único paso de retropropagación.

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:
Output of the previous code cell
Sliced circuit (recombined with barriers for visualization)
Output of the previous code cell

Reducir la profundidad del circuito con OBP

Llamamos a esta función backpropagate para incorporar segmentos al observable. La función devuelve el observable expandido, los segmentos del circuito por los que no se ha propagado la señal y los metadatos sobre el procedimiento.

Si no se controla, la magnitud observable puede crecer hasta alcanzar términos de Pauli de tipo « 2n2^n ». Esto limita operator_budget dicho crecimiento: en este caso permitimos como máximo 8 grupos conmutativos en términos de qubits, lo que establece, a grandes rasgos, el número de intentos necesarios para evaluar el observable en la QPU. La retropropagación se detiene en cuanto la absorción del siguiente segmento superaría el presupuesto, que es precisamente lo que ocurre a continuación: solo se absorben 7 de los 18 segmentos antes de que el observable llene los 8 grupos de conmutación y el procedimiento se detenga.

Para profundizar aún más en el circuito, se backpropagate puede utilizar el argumento de truncation_error_budget palabra clave de para eliminar los términos de Pauli con coeficientes pequeños del observable a medida que este crece. Esto atenúa el crecimiento de la magnitud observable a cambio de un error proporcional a la magnitud de los términos de Pauli que se truncan. Los dos presupuestos son complementarios y pueden utilizarse conjuntamente: operator_budget controla el tamaño de la variable observable, mientras que truncation_error_budget controla el error que se produce al descartar términos.

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:

Output of the previous code cell
¿Le ha resultado útil esta página?
Informe de un error, de una errata o solicite contenido en GitHub.