Skip to main content
IBM Quantum Platform

Establecer el nivel de optimización del transpilador

  • El código de esta página se ha desarrollado teniendo en cuenta los siguientes requisitos. Recomendamos utilizar estas versiones o versiones más recientes.

    qiskit[all]~=2.5.0
    qiskit-ibm-runtime~=0.47.0
    

Los dispositivos cuánticos reales están sujetos a ruido y errores de puerta, por lo que optimizar los circuitos para reducir su profundidad y el número de puertas puede mejorar significativamente los resultados obtenidos al ejecutar esos circuitos. La función generate_preset_pass_manager tiene un argumento posicional obligatorio, optimization_level, que controla cuánto esfuerzo dedica el transpilador a optimizar los circuitos. Este argumento puede ser un número entero con uno de los valores 0, 1, 2 ó 3. Los niveles de optimización más altos generan circuitos más optimizados a costa de tiempos de compilación más largos. En la tabla siguiente se explican las optimizaciones realizadas con cada ajuste.

Nivel de optimización
Descripción
0

Sin optimización: se utiliza normalmente para la caracterización del hardware

  • Traducción básica
  • Layout/Routing: TrivialLayout, donde selecciona los mismos números de qubit físicos que virtuales e inserta SWAPs para que funcione (usando SabreSwap)
1

Optimización de la luz:

  • Trazado: El trazado se intenta primero con TrivialLayout. Si se necesitan SWAPs adicionales, se encuentra una disposición con un número mínimo de SWAPs utilizando SabreSwap, y luego utiliza VF2LayoutPostLayout para intentar seleccionar los mejores qubits del grafo.
  • InverseCancellation
  • 1Q optimización de puertas
2

Optimización media:

  • Trazado/Routing: Optimización nivel 1 (sin trivial) + heurística optimizada con mayor profundidad de búsqueda y ensayos de la función de optimización. Como no se utiliza TrivialLayout , no se intenta utilizar los mismos números de qubit físicos y virtuales.
  • CommutativeCancellation
3

Alta optimización:

  • Optimización nivel 2 + heurística optimizada sobre trazado/ruta más con mayor esfuerzo/pruebas
  • Resíntesis de bloques de dos qubits utilizando la descomposición KAK de Cartan.
  • Pases que rompen la unidad:
    • OptimizeSwapBeforeMeasure: Desplaza las mediciones para evitar SWAPs
    • RemoveDiagonalGatesBeforeMeasure: Elimina las puertas antes de las mediciones que no afectarían a las mediciones

Nivel de optimización en acción

Dado que las puertas de dos qubits suelen ser la fuente más importante de errores, podemos cuantificar aproximadamente la "eficiencia de hardware" de la transpilación contando el número de puertas de dos qubits en el circuito resultante. Aquí probaremos los distintos niveles de optimización en un circuito de entrada formado por un unitario aleatorio seguido de una puerta SWAP.

from qiskit import QuantumCircuit
from qiskit.circuit.library import UnitaryGate
from qiskit.quantum_info import Operator, random_unitary

UU = random_unitary(4, seed=12345)
rand_U = UnitaryGate(UU)

qc = QuantumCircuit(2)
qc.append(rand_U, range(2))
qc.swap(0, 1)
qc.draw("mpl", style="iqp")

Output:

Output of the previous code cell
Note

En estos ejemplos se utiliza el backend FakeSherbrooke``qiskit_ibm_runtime simulado de, pero puedes probarlo con cualquier backend real o simulado compatible con Qiskit. Tus resultados pueden ser diferentes.

En primer lugar, vamos a transpilar utilizando el nivel de optimización 0.

from qiskit.transpiler import generate_preset_pass_manager
from qiskit_ibm_runtime.fake_provider import FakeSherbrooke

backend = FakeSherbrooke()

pass_manager = generate_preset_pass_manager(
    optimization_level=0, backend=backend, seed_transpiler=12345
)
qc_t1_exact = pass_manager.run(qc)
qc_t1_exact.draw("mpl", idle_wires=False)

Output:

Output of the previous code cell

El circuito transpilado tiene seis de las puertas ECR de dos qubits.

Repita la operación para el nivel de optimización 1:

from qiskit.transpiler import generate_preset_pass_manager
from qiskit_ibm_runtime.fake_provider import FakeSherbrooke

backend = FakeSherbrooke()

pass_manager = generate_preset_pass_manager(
    optimization_level=1, backend=backend, seed_transpiler=12345
)
qc_t1_exact = pass_manager.run(qc)
qc_t1_exact.draw("mpl", idle_wires=False)

Output:

Output of the previous code cell

El circuito transpilado sigue teniendo seis puertas ECR, pero el número de puertas single-qubit se ha reducido.

Repita la operación para el nivel de optimización 2:

pass_manager = generate_preset_pass_manager(
    optimization_level=2, backend=backend, seed_transpiler=12345
)
qc_t2_exact = pass_manager.run(qc)
qc_t2_exact.draw("mpl", idle_wires=False)

Output:

Output of the previous code cell

Se obtienen los mismos resultados que en el nivel de optimización 1. Tenga en cuenta que aumentar el nivel de optimización no siempre marca la diferencia.

Repita de nuevo, con el nivel de optimización 3:

pass_manager = generate_preset_pass_manager(
    optimization_level=3, backend=backend, seed_transpiler=12345
)
qc_t3_exact = pass_manager.run(qc)
qc_t3_exact.draw("mpl", idle_wires=False)

Output:

Output of the previous code cell

Ahora, sólo hay tres puertas ECR. Obtenemos este resultado porque en el nivel de optimización 3, Qiskit intenta resintetizar bloques de puertas de dos qubits, y cualquier puerta de dos qubits puede implementarse utilizando como máximo tres puertas ECR. Podemos obtener incluso menos compuertas ECR si establecemos approximation_degree en un valor inferior a 1, permitiendo al transpilador realizar aproximaciones que pueden introducir algún error en la descomposición de la compuerta (véase Parámetros de uso común para la transpilación ):

pass_manager = generate_preset_pass_manager(
    optimization_level=3,
    approximation_degree=0.99,
    backend=backend,
    seed_transpiler=12345,
)
qc_t3_approx = pass_manager.run(qc)
qc_t3_approx.draw("mpl", idle_wires=False)

Output:

Output of the previous code cell

Este circuito sólo tiene dos puertas ECR, pero es un circuito aproximado. Para entender en qué difiere su efecto del circuito exacto, podemos calcular la fidelidad entre el operador unitario que implementa este circuito y el unitario exacto. Antes de realizar el cálculo, primero reducimos el circuito transpilado, que contiene 127 qubits, a un circuito que sólo contiene los qubits activos, que son dos.

import numpy as np


def trace_to_fidelity_2q(trace: float) -> float:
    return (4.0 + trace * trace.conjugate()) / 20.0


# Reduce circuits down to 2 qubits so they are easy to simulate
qc_t3_exact_small = QuantumCircuit.from_instructions(qc_t3_exact)
qc_t3_approx_small = QuantumCircuit.from_instructions(qc_t3_approx)

# Compute the fidelity
exact_fid = trace_to_fidelity_2q(
    np.trace(np.dot(Operator(qc_t3_exact_small).adjoint().data, UU))
)
approx_fid = trace_to_fidelity_2q(
    np.trace(np.dot(Operator(qc_t3_approx_small).adjoint().data, UU))
)
print(
    f"Synthesis fidelity\nExact: {exact_fid:.3f}\nApproximate: {approx_fid:.3f}"
)

Output:

Synthesis fidelity
Exact: 1.000+0.000j
Approximate: 0.992+0.000j

Ajustar el nivel de optimización puede modificar también otros aspectos del circuito, no solo el número de puertas ECR. Para ver ejemplos de cómo la configuración del nivel de optimización modifica la disposición, consulta «Representación de ordenadores cuánticos ».


Próximos pasos

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