Skip to main content
IBM Quantum Platform

Corte de circuitos para reducir la profundidad

Estimación de uso: Ocho minutos en un procesador Eagle (NOTA: Esto es sólo una estimación. Su tiempo de ejecución puede variar)


En segundo plano

Este tutorial muestra cómo construir un Qiskit pattern para cortar puertas en un circuito cuántico para reducir la profundidad del circuito. Para obtener una discusión más detallada sobre el corte de circuitos, visita la documentación del complemento Qiskit de corte de circuitos.


Requisitos

Antes de empezar este tutorial, asegúrate de tener instalado lo siguiente:

  • Qiskit SDK v2.0 o posterior, con soporte de visualización
  • Qiskit Runtime v0.22 o posterior (pip install qiskit-ibm-runtime)
  • Complemento Qiskit para corte de circuitos v0.9.0 o posterior (pip install qiskit-addon-cutting)

Configuración

import numpy as np

from qiskit.circuit.library import EfficientSU2
from qiskit.quantum_info import PauliList, Statevector, SparsePauliOp
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager

from qiskit_addon_cutting import (
    cut_gates,
    generate_cutting_experiments,
    reconstruct_expectation_values,
)

from qiskit_ibm_runtime import QiskitRuntimeService, SamplerV2

Paso 1: Asignar entradas clásicas a un problema cuántico

Implementaremos nuestro patrón Qiskit siguiendo los cuatro pasos descritos en la documentación. En este caso, simularemos valores de expectativa en un circuito de cierta profundidad cortando puertas que den lugar a puertas de intercambio y ejecutando subexperimentos en circuitos menos profundos. El corte de puertas es relevante para los pasos 2 (optimizar el circuito para la ejecución cuántica descomponiendo las puertas distantes) y 4 (post-procesamiento para reconstruir los valores de expectativa en el circuito original). En el primer paso, generaremos un circuito a partir de la librería de circuitos Qiskit y definiremos algunos observables.

  • Entrada: Parámetros clásicos para definir un circuito
  • Salida: Circuito abstracto y observables
circuit = EfficientSU2(num_qubits=4, entanglement="circular").decompose()
circuit.assign_parameters([0.4] * len(circuit.parameters), inplace=True)
observables = PauliList(["ZZII", "IZZI", "IIZZ", "XIXI", "ZIZZ", "IXIX"])
circuit.draw("mpl", scale=0.8, style="iqp")

Output:

Output of the previous code cell

Paso 2: Optimizar el problema para la ejecución en hardware cuántico

  • Entrada: Circuito abstracto y observables
  • Resultado: Circuito objetivo y observables producidos cortando puertas distantes para reducir la profundidad del circuito transpilado

Elegimos una disposición inicial que requiere dos intercambios para ejecutar las puertas entre los qubits 3 y 0 y otros dos intercambios para devolver los qubits a sus posiciones iniciales. Elegimos optimization_level=3, que es el nivel más alto de optimización disponible con un gestor de pases preestablecido.

service = QiskitRuntimeService()
backend = service.least_busy(
    operational=True, min_num_qubits=circuit.num_qubits, simulator=False
)

pm = generate_preset_pass_manager(
    optimization_level=3, initial_layout=[0, 1, 2, 3], backend=backend
)
transpiled_qc = pm.run(circuit)
Mapa de acoplamiento que muestra los qubits que habrá que intercambiar
print(f"Transpiled circuit depth: {transpiled_qc.depth()}")
transpiled_qc.draw("mpl", scale=0.4, idle_wires=False, style="iqp", fold=-1)

Output:

Transpiled circuit depth: 103
Output of the previous code cell

Buscar y cortar las puertas distantes: Reemplazaremos las puertas distantes (puertas que conectan qubits no locales, 0 y 3) con TwoQubitQPDGate objetos especificando sus índices. cut_gates Reemplazará las puertas en los índices especificados con TwoQubitQPDGate objetos y también devolverá una lista de QPDBasis instancias, una por cada descomposición de puerta. El QPDBasis objeto contiene información sobre cómo descomponer las puertas cortadas en operaciones de un solo qubit.

# Find the indices of the distant gates
cut_indices = [
    i
    for i, instruction in enumerate(circuit.data)
    if {circuit.find_bit(q)[0] for q in instruction.qubits} == {0, 3}
]

# Decompose distant CNOTs into TwoQubitQPDGate instances
qpd_circuit, bases = cut_gates(circuit, cut_indices)

qpd_circuit.draw("mpl", scale=0.8)

Output:

Output of the previous code cell

Generar los subexperimentos que se ejecutarán en el backend : generate_cutting_experiments acepta un circuito que contiene instancias y observables de TwoQubitQPDGate como PauliList.

Para simular el valor esperado del circuito de tamaño completo, se generan muchos subexperimentos a partir de la distribución de cuasiprobabilidad conjunta de las puertas descompuestas y, a continuación, se ejecutan en uno o más backends. El número de muestras tomadas de la distribución se controla mediante num_samples, y se da un coeficiente combinado para cada muestra única. Para más información sobre cómo se calculan los coeficientes, consulte el material explicativo.

# Generate the subexperiments and sampling coefficients
subexperiments, coefficients = generate_cutting_experiments(
    circuits=qpd_circuit, observables=observables, num_samples=np.inf
)

Para comparar, vemos que los subexperimentos QPD serán menos profundos después de cortar puertas distantes : He aquí un ejemplo de subexperimento elegido arbitrariamente y generado a partir del circuito QPD. Su profundidad se ha reducido a más de la mitad. Hay que generar y evaluar muchos de estos subexperimentos probabilísticos para reconstruir un valor de expectativa del circuito más profundo.

# Transpile the decomposed circuit to the same layout
transpiled_qpd_circuit = pm.run(subexperiments[100])

print(f"Original circuit depth after transpile: {transpiled_qc.depth()}")
print(
    f"QPD subexperiment depth after transpile: {transpiled_qpd_circuit.depth()}"
)
transpiled_qpd_circuit.draw(
    "mpl", scale=0.6, style="iqp", idle_wires=False, fold=-1
)

Output:

Original circuit depth after transpile: 103
QPD subexperiment depth after transpile: 46
Output of the previous code cell

Por otro lado, el corte hace necesario un muestreo adicional. Aquí cortamos tres puertas CNOT, lo que resulta en una sobrecarga de muestreo de 939^3. Para más información sobre la sobrecarga de muestreo incurrida por el corte de circuitos, consulte la documentación de Circuit Knitting Toolbox.

print(f"Sampling overhead: {np.prod([basis.overhead for basis in bases])}")

Output:

Sampling overhead: 729.0

Paso 3: Ejecutar utilizando Qiskit primitives

Ejecuta los circuitos de destino («subexperimentos») con la primitiva Sampler.

  • Entrada: Circuitos objetivo
  • Resultados: Distribuciones de cuasiprobabilidad
# Transpile the subexperiments to the backend's instruction set architecture (ISA)
isa_subexperiments = pm.run(subexperiments)

# Set up the Qiskit Runtime Sampler primitive.  For a fake backend, this will use a local simulator.
sampler = SamplerV2(backend)

# Submit the subexperiments
job = sampler.run(isa_subexperiments)
# Retrieve the results
results = job.result()
print(job.job_id())

Output:

czypg1r6rr3g008mgp6g

Paso 4: Procesamiento posterior y devolución del resultado en el formato clásico deseado

Utiliza los resultados del subexperimento, las subobservables y los coeficientes de muestreo para reconstruir el valor esperado del circuito original.

Entrada: Distribuciones de cuasiprobabilidad Salida: Valores de expectativa reconstruidos

reconstructed_expvals = reconstruct_expectation_values(
    results,
    coefficients,
    observables,
)
# Reconstruct final expectation value
final_expval = np.dot(reconstructed_expvals, [1] * len(observables))
print("Final reconstructed expectation value")
print(final_expval)

Output:

Final reconstructed expectation value
1.0751342773437473
ideal_expvals = [
    Statevector(circuit).expectation_value(SparsePauliOp(observable))
    for observable in observables
]
print("Ideal expectation value")
print(np.dot(ideal_expvals, [1] * len(observables)).real)

Output:

Ideal expectation value
1.2283177520039992

Encuesta tutorial

Responda a esta breve encuesta para darnos su opinión sobre este tutorial. Su opinión nos ayudará a mejorar nuestra oferta de contenidos y la experiencia de los usuarios.

Enlace a la encuesta

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