Spanish
Idiomas
English
Bengali
French
German
Japanese
Korean
Portuguese
Spanish
Tamil

Nota

Esta página fue generada a partir de tutorials/algorithms/03_vqe_simulation_with_noise.ipynb.

VQE con Primitivas de Qiskit Aer

Este cuaderno demuestra cómo aprovechar las Primitivas de Qiskit Aer para ejecutar localmente simulaciones ruidosas y no ruidosas. Qiskit Aer no solo te permite definir tu propio modelo de ruido personalizado, sino también crear fácilmente un modelo de ruido basado en las propiedades de un dispositivo cuántico real. Este cuaderno mostrará un ejemplo de esto último, para ilustrar el flujo de trabajo general de ejecutar algoritmos con simuladores ruidosos locales.

Para más información sobre el modelo de ruido de Qiskit Aer, puedes consultar la documentación de Qiskit Aer, así como el tutorial para la Construcción de Modelos de Ruido.

El algoritmo de elección es una vez más VQE, donde la tarea consiste en encontrar la energía mínima (estado fundamental) de un Hamiltoniano. Como se muestra en tutoriales anteriores, VQE toma un operador de qubit como entrada. Aquí, tomará un conjunto de operadores de Pauli que Qiskit Nature calculó originalmente para la molécula H2, usando la clase SparsePauliOp.

[1]:
from qiskit.quantum_info import SparsePauliOp

H2_op = SparsePauliOp.from_list(
    [
        ("II", -1.052373245772859),
        ("IZ", 0.39793742484318045),
        ("ZI", -0.39793742484318045),
        ("ZZ", -0.01128010425623538),
        ("XX", 0.18093119978423156),
    ]
)

print(f"Number of qubits: {H2_op.num_qubits}")
Number of qubits: 2

Como el problema anterior todavía es fácilmente manejable de forma clásica, puedes usar NumPyMinimumEigensolver para calcular un valor de referencia para comparar los resultados más adelante.

[2]:
from qiskit.algorithms import NumPyMinimumEigensolver
from qiskit.opflow import PauliSumOp

numpy_solver = NumPyMinimumEigensolver()
result = numpy_solver.compute_minimum_eigenvalue(operator=PauliSumOp(H2_op))
ref_value = result.eigenvalue.real
print(f"Reference value: {ref_value:.5f}")
Reference value: -1.85728

Todos los siguientes ejemplos usarán el mismo ansatz y optimizador, definidos de la siguiente manera:

[3]:
# define ansatz and optimizer
from qiskit.circuit.library import TwoLocal
from qiskit.algorithms.optimizers import SPSA

iterations = 125
ansatz = TwoLocal(rotation_blocks="ry", entanglement_blocks="cz")
spsa = SPSA(maxiter=iterations)

Rendimiento sin ruido

Primero ejecutemos el VQE en el simulador Aer predeterminado sin agregar ruido, con una semilla fija para la ejecución y la transpilación para obtener resultados reproducibles. Este resultado debe estar relativamente cerca del valor de referencia del cálculo exacto.

[4]:
# define callback
# note: Re-run this cell to restart lists before training
counts = []
values = []


def store_intermediate_result(eval_count, parameters, mean, std):
    counts.append(eval_count)
    values.append(mean)
[5]:
# define Aer Estimator for noiseless statevector simulation
from qiskit.utils import algorithm_globals
from qiskit_aer.primitives import Estimator as AerEstimator

seed = 170
algorithm_globals.random_seed = seed

noiseless_estimator = AerEstimator(
    run_options={"seed": seed, "shots": 1024},
    transpile_options={"seed_transpiler": seed},
)
[6]:
# instantiate and run VQE
from qiskit.algorithms.minimum_eigensolvers import VQE

vqe = VQE(
    noiseless_estimator, ansatz, optimizer=spsa, callback=store_intermediate_result
)
result = vqe.compute_minimum_eigenvalue(operator=H2_op)

print(f"VQE on Aer qasm simulator (no noise): {result.eigenvalue.real:.5f}")
print(
    f"Delta from reference energy value is {(result.eigenvalue.real - ref_value):.5f}"
)
VQE on Aer qasm simulator (no noise): -1.84322
Delta from reference energy value is 0.01406

Capturaste los valores de energía anteriores durante la convergencia, por lo que puedes seguir el proceso en la gráfica a continuación.

[7]:
import pylab

pylab.rcParams["figure.figsize"] = (12, 4)
pylab.plot(counts, values)
pylab.xlabel("Eval count")
pylab.ylabel("Energy")
pylab.title("Convergence with no noise")
[7]:
Text(0.5, 1.0, 'Convergence with no noise')
../../_images/tutorials_algorithms_03_vqe_simulation_with_noise_12_1.png

Rendimiento con ruido

Ahora, agreguemos ruido a nuestra simulación. En particular, extraerás un modelo de ruido de un dispositivo (falso). Como se indicó en la introducción, también es posible crear modelos de ruido personalizados desde cero, pero esta tarea está más allá del alcance de este cuaderno.

En primer lugar, debes obtener un backend real del dispositivo y, a partir de su configuration y properties, puedes configurar un mapa de acoplamiento y un modelo de ruido para que coincida con el dispositivo. Nota: También puedes usar este mapa de acoplamiento como el mapa de entrelazamiento para la forma variacional si lo deseas.

[8]:
from qiskit_aer.noise import NoiseModel
from qiskit.providers.fake_provider import FakeVigo

# fake providers contain data from real IBM Quantum devices stored in Qiskit Terra,
# and are useful for extracting realistic noise models.
device = FakeVigo()

coupling_map = device.configuration().coupling_map
noise_model = NoiseModel.from_backend(device)

print(noise_model)
NoiseModel:
  Basis gates: ['cx', 'id', 'rz', 'sx', 'x']
  Instructions with noise: ['id', 'measure', 'sx', 'x', 'cx']
  Qubits with noise: [0, 1, 2, 3, 4]
  Specific qubit errors: [('id', (0,)), ('id', (1,)), ('id', (2,)), ('id', (3,)), ('id', (4,)), ('sx', (0,)), ('sx', (1,)), ('sx', (2,)), ('sx', (3,)), ('sx', (4,)), ('x', (0,)), ('x', (1,)), ('x', (2,)), ('x', (3,)), ('x', (4,)), ('cx', (3, 4)), ('cx', (4, 3)), ('cx', (3, 1)), ('cx', (1, 3)), ('cx', (1, 2)), ('cx', (2, 1)), ('cx', (0, 1)), ('cx', (1, 0)), ('measure', (0,)), ('measure', (1,)), ('measure', (2,)), ('measure', (3,)), ('measure', (4,))]

Una vez que se define el modelo de ruido, puedes ejecutar VQE usando un Estimator de Aer, donde puedes pasar el modelo de ruido al simulador subyacente usando el diccionario backend_options. Ten en cuenta que esta simulación llevará más tiempo que la no ruidosa.

[9]:
noisy_estimator = AerEstimator(
    backend_options={
        "method": "density_matrix",
        "coupling_map": coupling_map,
        "noise_model": noise_model,
    },
    run_options={"seed": seed, "shots": 1024},
    transpile_options={"seed_transpiler": seed},
)

En lugar de definir una nueva instancia de la clase VQE, ahora puedes simplemente asignar un nuevo estimator a nuestra instancia VQE anterior. Como se reutilizará el método de devolución de llamada, también deberás reiniciar las variables counts y values para poder trazar la gráfica de convergencia más adelante.

[10]:
# re-start callback variables
counts = []
values = []
[11]:
vqe.estimator = noisy_estimator

result1 = vqe.compute_minimum_eigenvalue(operator=H2_op)

print(f"VQE on Aer qasm simulator (with noise): {result1.eigenvalue.real:.5f}")
print(
    f"Delta from reference energy value is {(result1.eigenvalue.real - ref_value):.5f}"
)
VQE on Aer qasm simulator (with noise): -1.74645
Delta from reference energy value is 0.11083
[12]:
if counts or values:
    pylab.rcParams["figure.figsize"] = (12, 4)
    pylab.plot(counts, values)
    pylab.xlabel("Eval count")
    pylab.ylabel("Energy")
    pylab.title("Convergence with noise")
../../_images/tutorials_algorithms_03_vqe_simulation_with_noise_20_0.png

Resumen

En este tutorial, comparaste tres cálculos para el estado fundamental de la molécula H2. En primer lugar, generaste un valor de referencia utilizando un solucionador propio mínimo clásico. Luego, procediste a ejecutar VQE usando el Estimator de Qiskit Aer con 1024 iteraciones. Finalmente, extrajiste un modelo de ruido de un backend y lo usaste para definir un nuevo Estimator para simulaciones ruidosas. Los resultados son:

[13]:
print(f"Reference value: {ref_value:.5f}")
print(f"VQE on Aer qasm simulator (no noise): {result.eigenvalue.real:.5f}")
print(f"VQE on Aer qasm simulator (with noise): {result1.eigenvalue.real:.5f}")
Reference value: -1.85728
VQE on Aer qasm simulator (no noise): -1.84322
VQE on Aer qasm simulator (with noise): -1.74645

Puedes notar que, aunque el resultado de la simulación sin ruido está más cerca del valor de referencia exacto, todavía hay alguna diferencia. Esto se debe al ruido de muestreo, introducido al limitar el número de iteraciones a 1024. Un mayor número de iteraciones disminuiría este error de muestreo y cerraría la brecha entre estos dos valores.

En cuanto al ruido introducido por dispositivos reales (o modelos de ruido simulado), se podría abordar mediante una amplia variedad de técnicas de mitigación de errores. Las Primitivas de Qiskit Runtime han habilitado la mitigación de errores a través de la opción resilience_level. Esta opción está actualmente disponible para simuladores remotos y backends reales a los que se accede a través de las Primitivas de Runtime. Puedes consultar este tutorial para obtener más información.

[14]:
import qiskit.tools.jupyter

%qiskit_version_table
%qiskit_copyright

Version Information

Qiskit SoftwareVersion
qiskit-terra0.22.2
qiskit-aer0.11.1
qiskit-ignis0.7.1
qiskit-ibmq-provider0.19.2
qiskit0.39.2
System information
Python version3.10.2
Python compilerClang 13.0.0 (clang-1300.0.29.30)
Python buildv3.10.2:a58ebcc701, Jan 13 2022 14:50:16
OSDarwin
CPUs8
Memory (Gb)64.0
Fri Nov 18 01:03:00 2022 CET

This code is a part of Qiskit

© Copyright IBM 2017, 2022.

This code is licensed under the Apache License, Version 2.0. You may
obtain a copy of this license in the LICENSE.txt file in the root directory
of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.

Any modifications or derivative works of this code must retain this
copyright notice, and modified files need to carry a notice indicating
that they have been altered from the originals.