Nota
Esta página fue generada a partir de tutorials/algorithms/01_algorithms_introduction.ipynb.
Una Introducción a los Algoritmos en Qiskit¶
Esta es una introducción a algoritmos en Qiskit la cual proporciona una visión general para ayudarte a entender los diversos aspectos de su funcionalidad para poder comenzar. Otros tutoriales proporcionan un material más a profundidad para algunos algoritmos y maneras de usarlos, etc.
¿Cómo está estructurada la librería de algoritmos?¶
Qiskit proporciona una serie de Algoritmos y están agrupados por categoría según la tarea que pueden realizar. Por ejemplo, Minimum Eigensolvers
para encontrar el valor propio más pequeño de un operador, por ejemplo, la energía del estado fundamental de un Hamiltoniano químico o una solución a un problema de optimización cuando se expresa como un Hamiltoniano de Ising. Existen los Time Evolvers
para la evolución temporal de los sistemas cuánticos y Amplitude Estimators
para la estimación de valores que se pueden utilizar, por ejemplo, en aplicaciones financieras. El conjunto completo de categorías se puede ver en el enlace de la documentación de algoritmos mencionado anteriormente.
Los algoritmos son configurables y, a menudo, parte de la configuración será en forma de bloques de construcción más pequeños, de los cuales se pueden dar diferentes instancias del tipo de bloque de construcción. Por ejemplo, con VQE
, el Variacional Quantum Eigensolver, se necesita una función de onda de prueba, en forma de un QuantumCircuit
y un optimizador clásico, entre otras cosas.
Veamos un ejemplo para construir una instancia de VQE. Aquí TwoLocal
es la forma variacional (función de onda de prueba), un circuito parametrizado que se puede variar y SLSQP
es un optimizador clásico. Estos se crean como instancias separadas y se pasan a VQE cuando este es construido. Probar, por ejemplo, un optimizador clásico diferente o una forma variacional implica simplemente generar una nueva instancia de la que deseas y pasársela al VQE.
[1]:
from qiskit.algorithms.optimizers import SLSQP
from qiskit.circuit.library import TwoLocal
num_qubits = 2
ansatz = TwoLocal(num_qubits, "ry", "cz")
optimizer = SLSQP(maxiter=1000)
Dibujemos el ansatz para que podamos ver que es un QuantumCircuit
donde θ[0] a θ[7] van a ser parámetros que serán variados, mientras que el optimizador VQE encuentra el valor propio mínimo. Volveremos a revisar los parámetros más adelante en un ejemplo.
[2]:
ansatz.decompose().draw("mpl", style="iqx")
[2]:

Pero se necesita más para poder ejecutar un algoritmo, así que, vamos a ello a continuación.
¿Cómo ejecutar un algoritmo?¶
Los algoritmos se basan en las primitivas para evaluar valores esperados o circuitos de muestra. Las primitivas pueden estar basadas en un simulador o dispositivo real y pueden usarse indistintamente en los algoritmos, ya que todas implementan la misma interfaz.
En el VQE, tenemos que evaluar los valores esperados, por ejemplo, podemos usar qiskit.primitives.Estimator
que se obtiene con la instalación predeterminada de Qiskit Terra.
[3]:
from qiskit.primitives import Estimator
estimator = Estimator()
Este estimador utiliza una simulación de vector de estado exacta para evaluar los valores esperados. También podemos usar simuladores ruidosos y basados en iteraciones o backends reales. Para obtener más información sobre los simuladores, puedes consultar Qiskit Aer y para el hardware real Qiskit IBM Runtime.
Con todos los ingredientes listos, ahora podemos instanciar el VQE:
[4]:
from qiskit.algorithms.minimum_eigensolvers import VQE
vqe = VQE(estimator, ansatz, optimizer)
Ahora podemos llamar al método compute_mininum_eigenvalue(). Esta última es la interfaz de elección para los módulos de la aplicación, como Nature y Optimization, para que puedan funcionar indistintamente con cualquier algoritmo dentro de la categoría específica.
Un ejemplo funcional completo¶
Juntemos lo que hemos aprendido anteriormente y creemos un ejemplo de trabajo completo. VQE encontrará el valor propio mínimo, es decir, el valor mínimo de energía de un operador Hamiltoniano y, por lo tanto, necesitamos dicho operador para que VQE funcione. Dicho operador se da a continuación. Esto fue creado originalmente por el módulo de aplicación Nature como el Hamiltoniano para una molécula de H2 a una distancia interatómica de 0.735A. Es una suma de términos de Pauli como se muestra a continuación, pero por ahora no voy a decir nada más al respecto, ya que el objetivo es ejecutar el algoritmo, pero se puede encontrar más información sobre los operadores en otros tutoriales.
[5]:
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)
])
Ahora corramos el VQE e imprimamos el objeto que devuelve como resultado.
[6]:
result = vqe.compute_minimum_eigenvalue(H2_op)
print(result)
{ 'aux_operators_evaluated': None,
'cost_function_evals': 102,
'eigenvalue': -1.857275020719397,
'optimal_circuit': <qiskit.circuit.library.n_local.two_local.TwoLocal object at 0x7f96da26a470>,
'optimal_parameters': { ParameterVectorElement(θ[0]): -2.403507257619715,
ParameterVectorElement(θ[5]): 1.7060524493254914,
ParameterVectorElement(θ[1]): 3.085467047665086,
ParameterVectorElement(θ[2]): -2.1949965223522487,
ParameterVectorElement(θ[3]): 4.276089268519914,
ParameterVectorElement(θ[4]): -3.098644972035885,
ParameterVectorElement(θ[6]): 0.032773583818940334,
ParameterVectorElement(θ[7]): 2.8861019033185396},
'optimal_point': array([-2.40350726, 3.08546705, -2.19499652, 4.27608927, -3.09864497,
1.70605245, 0.03277358, 2.8861019 ]),
'optimal_value': -1.857275020719397,
'optimizer_evals': None,
'optimizer_result': <qiskit.algorithms.optimizers.optimizer.OptimizerResult object at 0x7f96da2a4d60>,
'optimizer_time': 0.29071593284606934}
A partir del resultado anterior, podemos ver el número de evaluaciones de la función de costo (=energía) que tomó el optimizador hasta que encontró el valor propio mínimo de \(\approx -1.85727\), que es la energía del estado fundamental electrónico de la molécula de H2 dada. También se pueden ver los parámetros óptimos del ansatz que son los valores que estaban en el ansatz en el valor mínimo.
Actualizando la primitiva dentro de VQE¶
Para cerrar, también cambiemos la primitiva del estimador dentro de un VQE. ¡Tal vez estés satisfecho con los resultados de la simulación y ahora quieras usar un simulador basado en iteraciones o ejecutarlo en hardware!
En este ejemplo, estamos cambiando a un estimador basado en iteraciones, aun usando la primitiva de referencia de Qiskit Terra. Sin embargo, podrías reemplazar la primitiva por, por ejemplo, el estimador de Qiskit Aer (qiskit_aer.primitives.Estimator
) o incluso un backend real (qiskit_ibm_runtime.Estimator
).
Para las funciones de pérdida ruidosas, el optimizador SPSA generalmente funciona bien, por lo que también actualizamos el optimizador. Consulta también el tutorial de VQE ruidoso para obtener más detalles sobre simulaciones ruidosas y basadas en iteraciones.
[7]:
from qiskit.algorithms.optimizers import SPSA
estimator = Estimator(options={"shots": 1000})
vqe.estimator = estimator
vqe.optimizer = SPSA(maxiter=100)
result = vqe.compute_minimum_eigenvalue(operator=H2_op)
print(result)
{ 'aux_operators_evaluated': None,
'cost_function_evals': 200,
'eigenvalue': -1.8574503552440247,
'optimal_circuit': <qiskit.circuit.library.n_local.two_local.TwoLocal object at 0x7f96da2f4250>,
'optimal_parameters': { ParameterVectorElement(θ[0]): -7.7940259581467375,
ParameterVectorElement(θ[5]): 0.28827257835035214,
ParameterVectorElement(θ[1]): -1.8091021117029589,
ParameterVectorElement(θ[2]): -2.460381278734678,
ParameterVectorElement(θ[3]): -7.725013961075425,
ParameterVectorElement(θ[4]): -1.3793338621798832,
ParameterVectorElement(θ[6]): -2.4148423942537587,
ParameterVectorElement(θ[7]): -1.8555574263247812},
'optimal_point': array([-7.79402596, -1.80910211, -2.46038128, -7.72501396, -1.37933386,
0.28827258, -2.41484239, -1.85555743]),
'optimal_value': -1.8574503552440247,
'optimizer_evals': None,
'optimizer_result': <qiskit.algorithms.optimizers.optimizer.OptimizerResult object at 0x7f96da26a5f0>,
'optimizer_time': 0.8142139911651611}
Nota: Aquí no fijamos la semilla aleatoria en los simuladores, por lo que volver a ejecutarlos arroja resultados ligeramente diferentes.
Con esto concluye esta introducción a los algoritmos en Qiskit. Por favor consulta los otros tutoriales de algoritmos de esta serie, para obtener una cobertura más amplia y más profunda sobre los algoritmos.
[8]:
import qiskit.tools.jupyter
%qiskit_version_table
%qiskit_copyright
Version Information
Qiskit Software | Version |
---|---|
qiskit-terra | 0.23.0.dev0+f52bb33 |
qiskit-aer | 0.11.1 |
qiskit-ignis | 0.7.1 |
qiskit-ibmq-provider | 0.19.2 |
qiskit-nature | 0.5.0 |
qiskit-optimization | 0.5.0 |
qiskit-machine-learning | 0.6.0 |
System information | |
Python version | 3.10.4 |
Python compiler | Clang 12.0.0 |
Python build | main, Mar 31 2022 03:38:35 |
OS | Darwin |
CPUs | 4 |
Memory (Gb) | 32.0 |
Wed Dec 07 11:02:26 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.
[ ]: