Saltar al contenido principal

Simulación eficiente de circuitos estabilizadores con las primitivas de Qiskit Aer

Versiones de paquetes

El código de esta página fue desarrollado usando los siguientes requisitos. Se recomienda usar estas versiones o versiones más recientes.

qiskit[all]~=2.3.0
qiskit-aer~=0.17

Esta página muestra cómo usar las primitivas de Qiskit Aer para simular eficientemente circuitos estabilizadores, incluidos aquellos sujetos a ruido de Pauli.

Los circuitos estabilizadores, también conocidos como circuitos de Clifford, son una clase restringida importante de circuitos cuánticos que pueden simularse de manera eficiente de forma clásica. Existen varias formas equivalentes de definir los circuitos estabilizadores. Una definición es que un circuito estabilizador es un circuito cuántico compuesto únicamente por las siguientes compuertas:

Ten en cuenta que usando Hadamard y S podemos construir cualquier compuerta de rotación de Pauli (RxR_x, RyR_y y RzR_z) cuyo ángulo esté contenido en el conjunto {0,π2,π,3π2}\{0, \frac{\pi}{2}, \pi, \frac{3\pi}{2}\} (salvo fase global), por lo que también podemos incluir estas compuertas en la definición.

Los circuitos estabilizadores son importantes para el estudio de la corrección de errores cuánticos. Su simulabilidad clásica también los hace útiles para verificar la salida de computadoras cuánticas. Por ejemplo, supón que quieres ejecutar en una computadora cuántica un circuito cuántico de 100 qubits. ¿Cómo sabes que la computadora cuántica se está comportando correctamente? Un circuito cuántico de 100 qubits está fuera del alcance de la simulación clásica por fuerza bruta. Al modificar tu circuito para que se convierta en un circuito estabilizador, puedes ejecutar circuitos en la computadora cuántica que tengan una estructura similar a tu circuito deseado, pero que puedas simular en una computadora clásica. Al verificar la salida de la computadora cuántica en los circuitos estabilizadores, puedes ganar confianza en que se está comportando correctamente también en los circuitos no estabilizadores. Consulta Evidence for the utility of quantum computing before fault tolerance para ver un ejemplo de esta idea en la práctica.

Simulación exacta y con ruido con las primitivas de Qiskit Aer muestra cómo usar Qiskit Aer para realizar simulaciones exactas y con ruido de circuitos cuánticos genéricos. Considera el circuito de ejemplo usado en ese artículo, un circuito de 8 qubits construido con efficient_su2:

# Added by doQumentation — required packages for this notebook
!pip install -q numpy qiskit qiskit-aer
from qiskit.circuit.library import efficient_su2

n_qubits = 8
circuit = efficient_su2(n_qubits)
circuit.draw("mpl")

Salida de la celda de código anterior

Usando Qiskit Aer, pudimos simular este circuito fácilmente. Sin embargo, supón que establecemos el número de qubits en 500:

n_qubits = 500
circuit = efficient_su2(n_qubits)
# don't try to draw the circuit because it's too large

Dado que el costo de simular circuitos cuánticos escala exponencialmente con el número de qubits, un circuito tan grande generalmente superaría las capacidades incluso de un simulador de alto rendimiento como Qiskit Aer. La simulación clásica de circuitos cuánticos genéricos se vuelve inviable cuando el número de qubits supera aproximadamente los 50 a 100 qubits. Sin embargo, ten en cuenta que el circuito efficient_su2 está parametrizado por ángulos en las compuertas RyR_y y RzR_z. Si todos esos ángulos están contenidos en el conjunto {0,π2,π,3π2}\{0, \frac{\pi}{2}, \pi, \frac{3\pi}{2}\}, entonces el circuito es un circuito estabilizador y puede simularse eficientemente.

En la siguiente celda, ejecutamos el circuito con la primitiva Sampler respaldada por el simulador de circuitos estabilizadores, usando parámetros elegidos aleatoriamente de modo que el circuito sea garantizadamente un circuito estabilizador.

import numpy as np
from qiskit.transpiler import generate_preset_pass_manager
from qiskit_aer import AerSimulator
from qiskit_aer.primitives import SamplerV2 as Sampler

measured_circuit = circuit.copy()
measured_circuit.measure_all()

rng = np.random.default_rng(1234)
params = rng.choice(
[0, np.pi / 2, np.pi, 3 * np.pi / 2],
size=circuit.num_parameters,
)

# Initialize a Sampler backed by the stabilizer circuit simulator
exact_sampler = Sampler(
options=dict(backend_options=dict(method="stabilizer"))
)
# The circuit needs to be transpiled to the AerSimulator target
pass_manager = generate_preset_pass_manager(
1, AerSimulator(method="stabilizer")
)
isa_circuit = pass_manager.run(measured_circuit)
pub = (isa_circuit, params)
job = exact_sampler.run([pub])
result = job.result()
pub_result = result[0]
counts = pub_result.data.meas.get_counts()

El simulador de circuitos estabilizadores también admite simulación con ruido, pero solo para una clase restringida de modelos de ruido. En concreto, cualquier ruido cuántico debe caracterizarse por un canal de error de Pauli. El error de despolarización entra en esta categoría, por lo que también puede simularse. Los canales de ruido clásico como el error de lectura también pueden simularse.

La siguiente celda de código ejecuta la misma simulación que antes, pero esta vez especificando un modelo de ruido que añade un error de despolarización del 2 % a cada compuerta CX, así como un error de lectura que invierte cada bit medido con una probabilidad del 5 %.

from qiskit_aer.noise import NoiseModel, depolarizing_error, ReadoutError

noise_model = NoiseModel()
cx_depolarizing_prob = 0.02
bit_flip_prob = 0.05
noise_model.add_all_qubit_quantum_error(
depolarizing_error(cx_depolarizing_prob, 2), ["cx"]
)
noise_model.add_all_qubit_readout_error(
ReadoutError(
[
[1 - bit_flip_prob, bit_flip_prob],
[bit_flip_prob, 1 - bit_flip_prob],
]
)
)

noisy_sampler = Sampler(
options=dict(
backend_options=dict(method="stabilizer", noise_model=noise_model)
)
)
job = noisy_sampler.run([pub])
result = job.result()
pub_result = result[0]
counts = pub_result.data.meas.get_counts()

Ahora usemos la primitiva Estimator respaldada por el simulador de estabilizadores para calcular el valor esperado del observable ZZZZZ \cdots Z. Debido a la estructura especial de los circuitos estabilizadores, es muy probable que el resultado sea 0.

from qiskit.quantum_info import SparsePauliOp
from qiskit_aer.primitives import EstimatorV2 as Estimator

observable = SparsePauliOp("Z" * n_qubits)

exact_estimator = Estimator(
options=dict(backend_options=dict(method="stabilizer")),
)
isa_circuit = pass_manager.run(circuit)
pub = (isa_circuit, observable, params)
job = exact_estimator.run([pub])
result = job.result()
pub_result = result[0]
exact_value = float(pub_result.data.evs)
exact_value
0.0

Próximos pasos

Recomendaciones