Nota
Esta página fue generada a partir de tutorials/algorithms/04_vqd.ipynb.
Algoritmo de Deflación Cuántica Variacional (VQD, Variational Quantum Deflation)¶
Este cuaderno demuestra cómo usar la implementación de Qiskit del algoritmo Deflación Cuántica Variacional (VQD, Variational Quantum Deflation) para calcular estados de energía más altos de un Hamiltoniano, tal como se presenta en este artículo de referencia.
Introducción¶
VQD es un algoritmo cuántico que utiliza una técnica variacional para encontrar los valores propios k del Hamiltoniano H de un sistema dado.
El algoritmo calcula las energías del estado excitado de los Hamiltonianos generalizados optimizando una función de costo modificada. Cada valor propio sucesivo se calcula iterativamente introduciendo un término superpuesto con todos los estados propios calculados previamente que deben minimizarse. Esto asegura que se encuentren estados propios de mayor energía.
Ejemplo práctico completo para VQD¶
El primer paso del flujo de trabajo de VQD es crear un operador de qubit, un ansatz y un optimizador. Para este ejemplo, puedes usar la molécula H2, que ya te resultará familiar si completaste los tutoriales anteriores de VQE:
[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),
]
)
Puedes configurar, por ejemplo, un ansatz TwoLocal
con tres qubits y elegir SLSQP
como método de optimización.
[2]:
from qiskit.circuit.library import TwoLocal
from qiskit.algorithms.optimizers import SLSQP
ansatz = TwoLocal(3, rotation_blocks=["ry", "rz"], entanglement_blocks="cz", reps=1)
optimizer = SLSQP()
ansatz.decompose().draw('mpl')
[2]:

El siguiente paso del flujo de trabajo es definir las primitivas requeridas para ejecutar VQD
. Este algoritmo requiere dos instancias primitivas diferentes: un Estimator
para calcular los valores esperados para la «parte VQE» del algoritmo y un Sampler
. El sampler se pasará a la subrutina StateFidelity
que se usará para calcular el costo de los estados de mayor energía. Hay varios métodos que puedes usar para calcular las fidelidades de estado, pero para simplificar las cosas, puedes usar el método ComputeUncompute
ya disponible en qiskit.algorithm.state_fidelities
.
[3]:
from qiskit.primitives import Sampler, Estimator
from qiskit.algorithms.state_fidelities import ComputeUncompute
estimator = Estimator()
sampler = Sampler()
fidelity = ComputeUncompute(sampler)
Para configurar el algoritmo VQD, es importante definir dos entradas adicionales: el número de estados de energía a calcular (k
) y las betas
definidas en el artículo original de VQD. En este ejemplo, el número de estados (k
) se establecerá en tres, lo que indica que se calcularán dos estados excitados además del estado fundamental.
Las betas
equilibran la contribución de cada término superpuesto a la función de costo, y son un argumento opcional en la construcción de VQD
. Si el usuario no los configura, pueden autoevaluarse para operadores de entrada de tipo SparsePauliOp
. Ten en cuenta que si deseas configurar tus propias betas
, debes proporcionar una lista de valores de longitud k
.
[4]:
k = 3
betas = [33, 33, 33]
Estás casi listo para ejecutar el algoritmo VQD, pero primero definamos una devolución de llamada para almacenar valores intermedios:
[5]:
counts = []
values = []
steps = []
def callback(eval_count, params, value, meta, step):
counts.append(eval_count)
values.append(value)
steps.append(step)
Finalmente puedes instanciar VQD
y calcular los valores propios para el operador elegido.
[6]:
from qiskit.algorithms.eigensolvers import VQD
vqd = VQD(estimator, fidelity, ansatz, optimizer, k=k, betas=betas, callback=callback)
result = vqd.compute_eigenvalues(operator = H2_op)
vqd_values = result.optimal_values
Puedes ver las tres energías del estado como parte del resultado de VQD
:
[7]:
print(vqd_values)
[-1.85727464 -1.2445845 -0.88272229]
Y podemos usar los valores almacenados por la devolución de llamada para graficar la convergencia de energía para cada estado:
[8]:
import numpy as np
import pylab
pylab.rcParams["figure.figsize"] = (12, 8)
steps = np.asarray(steps)
counts = np.asarray(counts)
values = np.asarray(values)
for i in range(1,4):
_counts = counts[np.where(steps == i)]
_values = values[np.where(steps == i)]
pylab.plot(_counts, _values, label=f"State {i-1}")
pylab.xlabel("Eval count")
pylab.ylabel("Energy")
pylab.title("Energy convergence for each computed state")
pylab.legend(loc="upper right");

Esta molécula puede ser resuelta exactamente usando la clase NumPyEigensolver
, que dará un valor de referencia que puedes comparar con el resultado de VQD
:
[9]:
from qiskit.algorithms.eigensolvers import NumPyEigensolver
from qiskit.opflow import PauliSumOp
exact_solver = NumPyEigensolver(k=3)
exact_result = exact_solver.compute_eigenvalues(PauliSumOp(H2_op))
ref_values = exact_result.eigenvalues
Veamos una comparación del resultado exacto con los valores propios de VQD
previamente calculados:
[10]:
print(f"Reference values: {ref_values}")
print(f"VQD values: {vqd_values}")
Reference values: [-1.85727503 -1.24458455 -0.88272215]
VQD values: [-1.85727464 -1.2445845 -0.88272229]
Como puedes ver, el resultado de VQD coincide con los valores de la solución exacta y extiende VQE para calcular también los estados excitados.
[11]:
import qiskit.tools.jupyter
%qiskit_version_table
%qiskit_copyright
Version Information
Qiskit Software | Version |
---|---|
qiskit-terra | 0.22.2 |
qiskit-aer | 0.11.1 |
qiskit-ignis | 0.7.1 |
qiskit-ibmq-provider | 0.19.2 |
qiskit | 0.39.2 |
System information | |
Python version | 3.10.2 |
Python compiler | Clang 13.0.0 (clang-1300.0.29.30) |
Python build | v3.10.2:a58ebcc701, Jan 13 2022 14:50:16 |
OS | Darwin |
CPUs | 8 |
Memory (Gb) | 64.0 |
Fri Dec 09 14:27:13 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.