Nota

Esta página fue generada a partir de docs/tutorials/04_excited_states_solvers.ipynb.

Solucionadores de estados excitados#

Introducción#

324620d1cda6409c90f88660d77f1684

En este tutorial vamos a discutir la interfaz de cálculo de estados excitados de Qiskit Nature. El objetivo es calcular los estados excitados de un Hamiltoniano molecular. Este Hamiltoniano puede ser electrónico o vibracional. Para saber más sobre la preparación del Hamiltoniano, consulta los tutoriales de Estructura electrónica y Estructura vibracional.

El primer paso es definir el sistema molecular. A continuación, pedimos la parte electrónica de una molécula de hidrógeno.

[1]:
from qiskit_nature.units import DistanceUnit
from qiskit_nature.second_q.drivers import PySCFDriver

driver = PySCFDriver(
    atom="H 0 0 0; H 0 0 0.735",
    basis="sto3g",
    charge=0,
    spin=0,
    unit=DistanceUnit.ANGSTROM,
)

es_problem = driver.run()

También nos apegaremos al mapeo de Jordan-Wigner. Para obtener más información sobre los diversos mapeadores disponibles en Qiskit Nature, consulta el Tutorial de Mapeadores de Qubit.

[2]:
from qiskit_nature.second_q.mappers import JordanWignerMapper

mapper = JordanWignerMapper()

El Solucionador#

Después de estos pasos necesitamos definir un solucionador. El solucionador es el algoritmo a través del cual se calculan los estados excitados.

Comencemos primero con un ejemplo puramente clásico: el NumPyEigensolver. Este algoritmo diagonaliza exactamente al Hamiltoniano. Aunque escala mal, se puede usar en sistemas pequeños para verificar los resultados de los algoritmos cuánticos. Aquí, solo estamos interesados en mirar estados propios con un número dado de partículas. Para calcular únicamente esos estados, se puede pasar una función de filtro al NumPyEigensolver. Está implementada una función de filtro predeterminada en Qiskit Nature que puedes usar para este propósito.

También necesitamos especificar el número de valores propios que serán calculados por el NumPyEigensolver. Para este sistema en particular, estamos interesados en el estado fundamental y los primeros tres estados excitados, por lo que estableceremos k=4 (que por defecto es 1, así que asegúrate de configurar esto, de lo contrario, ¡solo obtendrás el estado fundamental!).

[3]:
from qiskit_algorithms import NumPyEigensolver

numpy_solver = NumPyEigensolver(k=4, filter_criterion=es_problem.get_default_filter_criterion())

También se puede acceder a las energías de excitación con el algoritmo qEOM. El método EOM encuentra las energías de excitación (diferencias de energía entre el estado fundamental y todos los \(n\)-ésimos estados excitados) resolviendo el siguiente problema de pseudovalores propios.

\[\begin{split}\begin{pmatrix} \text{M} & \text{Q}\\ \text{Q*} & \text{M*} \end{pmatrix} \begin{pmatrix} \text{X}_n\\ \text{Y}_n \end{pmatrix} = E_{0n} \begin{pmatrix} \text{V} & \text{W}\\ -\text{W*} & -\text{V*} \end{pmatrix} \begin{pmatrix} \text{X}_n\\ \text{Y}_n \end{pmatrix}\end{split}\]

con

\[M_{\mu_{\alpha}\nu_{\beta}} = \langle0| [(\hat{\text{E}}_{\mu_{\alpha}}^{(\alpha)})^{\dagger},\hat{\text{H}}, \hat{\text{E}}_{\nu_{\beta}}^{(\beta)}]|0\rangle\]
\[Q_{\mu_{\alpha}\nu_{\beta}} = -\langle0| [(\hat{\text{E}}_{\mu_{\alpha}}^{(\alpha)})^{\dagger}, \hat{\text{H}}, (\hat{\text{E}}_{\nu_{\beta}}^{(\beta)})^{\dagger}]|0\rangle\]
\[V_{\mu_{\alpha}\nu_{\beta}} = \langle0| [(\hat{\text{E}}_{\mu_{\alpha}}^{(\alpha)})^{\dagger}, \hat{\text{E}}_{\nu_{\beta}}^{(\beta)}]|0\rangle\]
\[W_{\mu_{\alpha}\nu_{\beta}} = -\langle0| [(\hat{\text{E}}_{\mu_\alpha}^{(\alpha)})^{\dagger}, (\hat{\text{E}}_{\nu_{\beta}}^{(\beta)})^{\dagger}]|0\rangle\]

Aunque la ecuación anterior se puede resolver clásicamente, cada elemento de matriz se debe medir en la computadora cuántica con el estado fundamental correspondiente. Para usar qEOM como un solucionador en Qiskit, primero tenemos que definir un cálculo del estado fundamental, que proporcionará la información de estado fundamental necesaria para el algoritmo. Con esto, el solucionador qEOM se puede inicializar así:

[4]:
from qiskit_algorithms import VQE
from qiskit_algorithms.optimizers import SLSQP
from qiskit.primitives import Estimator
from qiskit_nature.second_q.algorithms import GroundStateEigensolver, QEOM, EvaluationRule
from qiskit_nature.second_q.circuit.library import HartreeFock, UCCSD

ansatz = UCCSD(
    es_problem.num_spatial_orbitals,
    es_problem.num_particles,
    mapper,
    initial_state=HartreeFock(
        es_problem.num_spatial_orbitals,
        es_problem.num_particles,
        mapper,
    ),
)

estimator = Estimator()
# This first part sets the ground state solver
# see more about this part in the ground state calculation tutorial
solver = VQE(estimator, ansatz, SLSQP())
solver.initial_point = [0.0] * ansatz.num_parameters
gse = GroundStateEigensolver(mapper, solver)

# The qEOM algorithm is simply instantiated with the chosen ground state solver and Estimator primitive
qeom_excited_states_solver = QEOM(gse, estimator, "sd", EvaluationRule.ALL)

El cálculo y los resultados#

Ahora estamos listos para calcular los resultados. A continuación, comparamos los resultados obtenidos por el NumPyEigensolver exacto con el criterio de filtro predeterminado habilitado con los resultados obtenidos por el algoritmo qEOM.

[5]:
from qiskit_nature.second_q.algorithms import ExcitedStatesEigensolver

numpy_excited_states_solver = ExcitedStatesEigensolver(mapper, numpy_solver)
numpy_results = numpy_excited_states_solver.solve(es_problem)

qeom_results = qeom_excited_states_solver.solve(es_problem)

print(numpy_results)
print("\n\n")
print(qeom_results)
=== GROUND STATE ENERGY ===

* Electronic ground state energy (Hartree): -1.857275030202
  - computed part:      -1.857275030202
~ Nuclear repulsion energy (Hartree): 0.719968994449
> Total ground state energy (Hartree): -1.137306035753

=== EXCITED STATE ENERGIES ===

  1:
* Electronic excited state energy (Hartree): -0.882722150245
> Total excited state energy (Hartree): -0.162753155796
  2:
* Electronic excited state energy (Hartree): -0.224911252831
> Total excited state energy (Hartree): 0.495057741618

=== MEASURED OBSERVABLES ===

  0:  # Particles: 2.000 S: 0.000 S^2: 0.000 M: 0.000
  1:  # Particles: 2.000 S: 0.000 S^2: 0.000 M: 0.000
  2:  # Particles: 2.000 S: 0.000 S^2: 0.000 M: 0.000

=== DIPOLE MOMENTS ===

~ Nuclear dipole moment (a.u.): [0.0  0.0  1.3889487]

  0:
  * Electronic dipole moment (a.u.): [0.0  0.0  1.388948701555]
    - computed part:      [0.0  0.0  1.388948701555]
  > Dipole moment (a.u.): [0.0  0.0  -0.000000001555]  Total: 0.000000001555
                 (debye): [0.0  0.0  -0.000000003953]  Total: 0.000000003953

  1:
  * Electronic dipole moment (a.u.): [0.0  0.0  1.388948701555]
    - computed part:      [0.0  0.0  1.388948701555]
  > Dipole moment (a.u.): [0.0  0.0  -0.000000001555]  Total: 0.000000001555
                 (debye): [0.0  0.0  -0.000000003953]  Total: 0.000000003953

  2:
  * Electronic dipole moment (a.u.): [0.0  0.0  1.388948701555]
    - computed part:      [0.0  0.0  1.388948701555]
  > Dipole moment (a.u.): [0.0  0.0  -0.000000001555]  Total: 0.000000001555
                 (debye): [0.0  0.0  -0.000000003953]  Total: 0.000000003953




=== GROUND STATE ENERGY ===

* Electronic ground state energy (Hartree): -1.857275030145
  - computed part:      -1.857275030145
~ Nuclear repulsion energy (Hartree): 0.719968994449
> Total ground state energy (Hartree): -1.137306035696

=== EXCITED STATE ENERGIES ===

  1:
* Electronic excited state energy (Hartree): -1.244586756145
> Total excited state energy (Hartree): -0.524617761696
  2:
* Electronic excited state energy (Hartree): -0.882724356546
> Total excited state energy (Hartree): -0.162755362097
  3:
* Electronic excited state energy (Hartree): -0.224913459141
> Total excited state energy (Hartree): 0.495055535308

=== MEASURED OBSERVABLES ===

  0:  # Particles: 2.000 S: 0.000 S^2: 0.000 M: 0.000
  1:  # Particles: 2.000 S: 1.000 S^2: 2.000 M: 0.000
  2:  # Particles: 2.000 S: 0.000 S^2: -0.000 M: 0.000
  3:  # Particles: 2.000 S: 0.000 S^2: 0.000 M: -0.000

=== DIPOLE MOMENTS ===

~ Nuclear dipole moment (a.u.): [0.0  0.0  1.3889487]

  0:
  * Electronic dipole moment (a.u.): [0.0  0.0  1.388948961657]
    - computed part:      [0.0  0.0  1.388948961657]
  > Dipole moment (a.u.): [0.0  0.0  -0.000000261657]  Total: 0.000000261657
                 (debye): [0.0  0.0  -0.000000665065]  Total: 0.000000665065

  1:
  * Electronic dipole moment (a.u.): [0.0  0.0  1.388948701647]
    - computed part:      [0.0  0.0  1.388948701647]
  > Dipole moment (a.u.): [0.0  0.0  -0.000000001647]  Total: 0.000000001647
                 (debye): [0.0  0.0  -0.000000004186]  Total: 0.000000004186

  2:
  * Electronic dipole moment (a.u.): [0.0  0.0  1.388949035771]
    - computed part:      [0.0  0.0  1.388949035771]
  > Dipole moment (a.u.): [0.0  0.0  -0.000000335771]  Total: 0.000000335771
                 (debye): [0.0  0.0  -0.000000853445]  Total: 0.000000853445

  3:
  * Electronic dipole moment (a.u.): [0.0  0.0  1.388948738594]
    - computed part:      [0.0  0.0  1.388948738594]
  > Dipole moment (a.u.): [0.0  0.0  -0.000000038594]  Total: 0.000000038594
                 (debye): [0.0  0.0  -0.000000098097]  Total: 0.000000098097

Uno puede ver a partir de estos resultados que falta un estado en los resultados de NumPy. La razón de esto es que el espín también se usa como filtro y solo se muestran los estados singletes. A continuación, usamos una función de filtro personalizada para verificar nuestros resultados de manera consistente y solo filtramos los estados con el número incorrecto de partículas (en este caso, el número de partículas es 2) así como la magnetización incorrecta (que forzamos a que sea 0).

[6]:
import numpy as np


def filter_criterion(eigenstate, eigenvalue, aux_values):
    return np.isclose(aux_values["ParticleNumber"][0], 2.0) and np.isclose(
        aux_values["Magnetization"][0], 0.0
    )


new_numpy_solver = NumPyEigensolver(k=4, filter_criterion=filter_criterion)
new_numpy_excited_states_solver = ExcitedStatesEigensolver(mapper, new_numpy_solver)
new_numpy_results = new_numpy_excited_states_solver.solve(es_problem)

print(new_numpy_results)
=== GROUND STATE ENERGY ===

* Electronic ground state energy (Hartree): -1.857275030202
  - computed part:      -1.857275030202
~ Nuclear repulsion energy (Hartree): 0.719968994449
> Total ground state energy (Hartree): -1.137306035753

=== EXCITED STATE ENERGIES ===

  1:
* Electronic excited state energy (Hartree): -1.244584549813
> Total excited state energy (Hartree): -0.524615555364
  2:
* Electronic excited state energy (Hartree): -0.882722150245
> Total excited state energy (Hartree): -0.162753155796
  3:
* Electronic excited state energy (Hartree): -0.224911252831
> Total excited state energy (Hartree): 0.495057741618

=== MEASURED OBSERVABLES ===

  0:  # Particles: 2.000 S: 0.000 S^2: 0.000 M: 0.000
  1:  # Particles: 2.000 S: 1.000 S^2: 2.000 M: 0.000
  2:  # Particles: 2.000 S: 0.000 S^2: 0.000 M: 0.000
  3:  # Particles: 2.000 S: 0.000 S^2: 0.000 M: 0.000

=== DIPOLE MOMENTS ===

~ Nuclear dipole moment (a.u.): [0.0  0.0  1.3889487]

  0:
  * Electronic dipole moment (a.u.): [0.0  0.0  1.388948701555]
    - computed part:      [0.0  0.0  1.388948701555]
  > Dipole moment (a.u.): [0.0  0.0  -0.000000001555]  Total: 0.000000001555
                 (debye): [0.0  0.0  -0.000000003953]  Total: 0.000000003953

  1:
  * Electronic dipole moment (a.u.): [0.0  0.0  1.388948701555]
    - computed part:      [0.0  0.0  1.388948701555]
  > Dipole moment (a.u.): [0.0  0.0  -0.000000001555]  Total: 0.000000001555
                 (debye): [0.0  0.0  -0.000000003953]  Total: 0.000000003953

  2:
  * Electronic dipole moment (a.u.): [0.0  0.0  1.388948701555]
    - computed part:      [0.0  0.0  1.388948701555]
  > Dipole moment (a.u.): [0.0  0.0  -0.000000001555]  Total: 0.000000001555
                 (debye): [0.0  0.0  -0.000000003953]  Total: 0.000000003953

  3:
  * Electronic dipole moment (a.u.): [0.0  0.0  1.388948701555]
    - computed part:      [0.0  0.0  1.388948701555]
  > Dipole moment (a.u.): [0.0  0.0  -0.000000001555]  Total: 0.000000001555
                 (debye): [0.0  0.0  -0.000000003953]  Total: 0.000000003953

[7]:
import qiskit.tools.jupyter

%qiskit_version_table
%qiskit_copyright

Version Information

Qiskit SoftwareVersion
qiskit-terra0.24.1
qiskit-nature0.7.0
System information
Python version3.10.11
Python compilerGCC 12.2.1 20221121 (Red Hat 12.2.1-4)
Python buildmain, Apr 5 2023 00:00:00
OSLinux
CPUs8
Memory (Gb)62.48404312133789
Wed Jun 07 10:45:42 2023 CEST

This code is a part of Qiskit

© Copyright IBM 2017, 2023.

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.