Saltar al contenido principal

Simulación exacta y ruidosa con primitivas de Qiskit Aer

Versiones de paquetes

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

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

La simulación exacta con primitivas de Qiskit muestra cómo usar las primitivas de referencia incluidas en Qiskit para realizar simulaciones exactas de circuitos cuánticos. Los procesadores cuánticos actuales sufren de errores, o ruido, por lo que los resultados de una simulación exacta no necesariamente reflejan los resultados que obtendrías al ejecutar circuitos en hardware real. Si bien las primitivas de referencia en Qiskit no admiten el modelado de ruido, Qiskit Aer incluye implementaciones de las primitivas que sí lo admiten. Qiskit Aer es un simulador de circuitos cuánticos de alto rendimiento que puedes usar en lugar de las primitivas de referencia para obtener mejor rendimiento y más funcionalidades. Es parte del Ecosistema de Qiskit. En este artículo, demostramos el uso de las primitivas de Qiskit Aer para simulaciones exactas y ruidosas.

Notas
  • Se requiere qiskit-aer v0.14 o posterior.
  • Si bien las primitivas de Qiskit Aer implementan las interfaces de primitivas, no ofrecen las mismas opciones que las primitivas de Qiskit Runtime. El nivel de resiliencia, por ejemplo, no está disponible con las primitivas de Qiskit Aer.
  • Consulta la documentación de AerSimulator para obtener detalles sobre las opciones del método de simulación que admite Aer.

Para explorar la simulación exacta y ruidosa, crea un circuito de ejemplo con ocho qubits:

# Added by doQumentation — required packages for this notebook
!pip install -q 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

Este circuito contiene parámetros que representan los ángulos de rotación de las compuertas RyR_y y RzR_z. Al simular este circuito, necesitamos especificar valores explícitos para estos parámetros. En la siguiente celda, especificamos algunos valores para estos parámetros y usamos la primitiva Estimator de Qiskit Aer para calcular el valor de expectación exacto del observable ZZZZZ \cdots Z.

from qiskit.quantum_info import SparsePauliOp
from qiskit.transpiler import generate_preset_pass_manager
from qiskit_aer import AerSimulator
from qiskit_aer.primitives import EstimatorV2 as Estimator

observable = SparsePauliOp("Z" * n_qubits)
params = [0.1] * circuit.num_parameters

exact_estimator = Estimator()
# The circuit needs to be transpiled to the AerSimulator target
pass_manager = generate_preset_pass_manager(3, AerSimulator())
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.8870140234256602

Ahora, inicialicemos un modelo de ruido que incluya un error de despolarización del 2% en cada compuerta CX. En la práctica, el error que proviene de las compuertas de dos qubits, que aquí son compuertas CX, es la fuente de error dominante al ejecutar un circuito. Consulta Construir modelos de ruido para una descripción general de cómo construir modelos de ruido en Qiskit Aer.

En la siguiente celda, construimos un Estimator que incorpora este modelo de ruido y lo usamos para calcular el valor de expectación del observable.

from qiskit_aer.noise import NoiseModel, depolarizing_error

noise_model = NoiseModel()
cx_depolarizing_prob = 0.02
noise_model.add_all_qubit_quantum_error(
depolarizing_error(cx_depolarizing_prob, 2), ["cx"]
)

noisy_estimator = Estimator(
options=dict(backend_options=dict(noise_model=noise_model))
)
job = noisy_estimator.run([pub])
result = job.result()
pub_result = result[0]
noisy_value = float(pub_result.data.evs)
noisy_value
0.7247404214143528

Como puedes ver, el valor de expectación en presencia de ruido está bastante lejos del valor correcto. En la práctica, puedes emplear una variedad de técnicas de mitigación de errores para contrarrestar los efectos del ruido, pero una discusión de estas técnicas está fuera del alcance de este artículo.

Para tener una idea muy aproximada de cómo el ruido afecta el resultado final, considera nuestro modelo de ruido, que agrega un error de despolarización del 2% a cada compuerta CX. El error de despolarización con probabilidad pp se define como un canal cuántico EE que tiene la siguiente acción sobre una matriz de densidad ρ\rho:

E(ρ)=(1p)ρ+pI2nE(\rho) = (1 - p) \rho + p\frac{I}{2^n}

donde nn es el número de qubits, en este caso, 2. Es decir, con probabilidad pp, el estado se reemplaza con el estado completamente mezclado, y el estado se preserva con probabilidad 1p1 - p. Después de mm aplicaciones del canal de despolarización, la probabilidad de que el estado se preserve sería (1p)m(1 - p)^m. Por lo tanto, esperamos que la probabilidad de retener el estado correcto al final de la simulación disminuya exponencialmente con el número de compuertas CX en nuestro circuito.

Contemos el número de compuertas CX en nuestro circuito y calculemos (1p)m(1 - p)^m. Llamamos a count_ops para obtener un diccionario que mapea nombres de compuertas a conteos, y recuperamos la entrada para la compuerta CX.

cx_count = circuit.count_ops()["cx"]
(1 - cx_depolarizing_prob) ** cx_count
0.6542558123199923

Este valor, 65%, da una estimación aproximada de la probabilidad de que nuestro estado final sea correcto. Es una estimación conservadora porque no toma en cuenta el estado inicial de la simulación.

La siguiente celda de código muestra cómo usar la primitiva Sampler de Qiskit Aer para muestrear del circuito ruidoso. Necesitamos agregar mediciones al circuito antes de ejecutarlo con la primitiva Sampler.

from qiskit_aer.primitives import SamplerV2 as Sampler

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

noisy_sampler = Sampler(
options=dict(backend_options=dict(noise_model=noise_model))
)
# The circuit needs to be transpiled to the AerSimulator target
pass_manager = generate_preset_pass_manager(3, AerSimulator())
isa_circuit = pass_manager.run(measured_circuit)
pub = (isa_circuit, params, 100)
job = noisy_sampler.run([pub])
result = job.result()
pub_result = result[0]
pub_result.data.meas.get_counts()
{'00100000': 1,
'00000000': 65,
'10101000': 1,
'10000000': 5,
'00001000': 1,
'00000110': 2,
'11110010': 1,
'00000011': 3,
'01010000': 3,
'11000000': 3,
'01111000': 1,
'01000000': 2,
'00000010': 1,
'01100000': 1,
'00011000': 1,
'00111100': 1,
'00010100': 1,
'00001111': 1,
'00110000': 1,
'01100101': 1,
'00000100': 1,
'10100000': 1,
'00000001': 1,
'11010000': 1}

Próximos pasos

Recomendaciones