{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Excited states solvers" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Introduction\n", "\n", "\n", "\n", "In this tutorial we are going to discuss the excited states calculation interface of Qiskit Chemistry. The goal is to compute the excited states of a molecular Hamiltonian. This Hamiltonian can be electronic or vibrational. To know more about the preparation of the Hamiltonian, check out the Electronic structure and Vibrational structure tutorials. \n", "\n", "The first step is to define the molecular system. In the following we ask for the electronic part of a hydrogen molecule." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "from qiskit_nature.drivers import PySCFDriver, UnitsType, Molecule\n", "from qiskit_nature.problems.second_quantization import ElectronicStructureProblem\n", "from qiskit_nature.converters.second_quantization import QubitConverter\n", "from qiskit_nature.mappers.second_quantization import JordanWignerMapper\n", "\n", "molecule = Molecule(geometry=[['H', [0., 0., 0.]],\n", " ['H', [0., 0., 0.735]]],\n", " charge=0, multiplicity=1)\n", "driver = PySCFDriver(molecule = molecule, unit=UnitsType.ANGSTROM, basis='sto3g')\n", "\n", "es_problem = ElectronicStructureProblem(driver)\n", "qubit_converter = QubitConverter(JordanWignerMapper())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## The Solver\n", "\n", "Then we need to define a solver. The solver is the algorithm through which the ground state is computed. \n", "\n", "Let's first start with a purely classical example: the NumPy eigensolver. This algorithm exactly diagonalizes the Hamiltonian. Although it scales badly, it can be used on small systems to check the results of the quantum algorithms. \n", "Here, we are only interested to look at eigenstates with a given number of particle. To compute only those states a filter function can be passed to the NumPy eigensolver. A default filter function is already implemented in Qiskit and can be used in this way:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "from qiskit_nature.algorithms import NumPyEigensolverFactory\n", "\n", "numpy_solver = NumPyEigensolverFactory(use_default_filter_criterion=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The excitation energies can also be accessed with the qEOM algorithm [arXiv preprint arXiv:1910.12890 (2019)]. The EOM method finds the excitation energies (differences in energy between the ground state and all $n$th excited states) by solving the following pseudo-eigenvalue problem.\n", "\n", "$$\n", "\\begin{pmatrix}\n", " \\text{M} & \\text{Q}\\\\ \n", " \\text{Q*} & \\text{M*}\n", "\\end{pmatrix}\n", "\\begin{pmatrix}\n", " \\text{X}_n\\\\ \n", " \\text{Y}_n\n", "\\end{pmatrix}\n", "= E_{0n}\n", "\\begin{pmatrix}\n", " \\text{V} & \\text{W}\\\\ \n", " -\\text{W*} & -\\text{V*}\n", "\\end{pmatrix}\n", "\\begin{pmatrix}\n", " \\text{X}_n\\\\ \n", " \\text{Y}_n\n", "\\end{pmatrix}\n", "$$\n", "\n", "with \n", "\n", "$$\n", "M_{\\mu_{\\alpha}\\nu_{\\beta}} = \\langle0| [(\\hat{\\text{E}}_{\\mu_{\\alpha}}^{(\\alpha)})^{\\dagger},\\hat{\\text{H}}, \\hat{\\text{E}}_{\\nu_{\\beta}}^{(\\beta)}]|0\\rangle\n", "$$\n", "$$\n", "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\n", "$$\n", "$$\n", "V_{\\mu_{\\alpha}\\nu_{\\beta}} = \\langle0| [(\\hat{\\text{E}}_{\\mu_{\\alpha}}^{(\\alpha)})^{\\dagger}, \\hat{\\text{E}}_{\\nu_{\\beta}}^{(\\beta)}]|0\\rangle\n", "$$\n", "$$\n", "W_{\\mu_{\\alpha}\\nu_{\\beta}} = -\\langle0| [(\\hat{\\text{E}}_{\\mu_\\alpha}^{(\\alpha)})^{\\dagger}, (\\hat{\\text{E}}_{\\nu_{\\beta}}^{(\\beta)})^{\\dagger}]|0\\rangle\n", "$$\n", "\n", "Although the previous equation can be solved classically, each matrix element must be measured on the quantum computer with the corresponding ground state. \n", "To use the qEOM as a solver in Qiskit, we have to define a ground state calculation first, providing to the algorithm information on how to find the ground state. With this the qEOM solver can be initialized:" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "from qiskit import Aer\n", "from qiskit.utils import QuantumInstance\n", "from qiskit_nature.algorithms import GroundStateEigensolver, QEOM, VQEUCCFactory\n", "\n", "# This first part sets the ground state solver\n", "# see more about this part in the ground state calculation tutorial\n", "quantum_instance = QuantumInstance(Aer.get_backend('statevector_simulator'))\n", "solver = VQEUCCFactory(quantum_instance)\n", "gsc = GroundStateEigensolver(qubit_converter, solver)\n", "\n", "# The qEOM algorithm is simply instantiated with the chosen ground state solver\n", "qeom_excited_states_calculation = QEOM(gsc, 'sd') " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## The calculation and results\n", "\n", "The results are computed and printed" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "=== GROUND STATE ENERGY ===\n", " \n", "* Electronic ground state energy (Hartree): -1.857275030202\n", " - computed part: -1.857275030202\n", "~ Nuclear repulsion energy (Hartree): 0.719968994449\n", "> Total ground state energy (Hartree): -1.137306035753\n", " \n", "=== EXCITED STATE ENERGIES ===\n", " \n", " 1: \n", "* Electronic excited state energy (Hartree): -0.882722150245\n", "> Total excited state energy (Hartree): -0.162753155796\n", " 2: \n", "* Electronic excited state energy (Hartree): -0.224911252831\n", "> Total excited state energy (Hartree): 0.495057741618\n", " \n", "=== MEASURED OBSERVABLES ===\n", " \n", " 0: # Particles: 2.000 S: 0.000 S^2: 0.000 M: 0.000\n", " 1: # Particles: 2.000 S: 0.000 S^2: 0.000 M: 0.000\n", " 2: # Particles: 2.000 S: 0.000 S^2: 0.000 M: 0.000\n", " \n", "=== DIPOLE MOMENTS ===\n", " \n", "~ Nuclear dipole moment (a.u.): [0.0 0.0 1.3889487]\n", " \n", " 0: \n", " * Electronic dipole moment (a.u.): [0.0 0.0 1.3889487]\n", " - computed part: [0.0 0.0 1.3889487]\n", " > Dipole moment (a.u.): [0.0 0.0 0.0] Total: 0.\n", " (debye): [0.0 0.0 0.0] Total: 0.\n", " \n", " 1: \n", " * Electronic dipole moment (a.u.): [0.0 0.0 1.3889487]\n", " - computed part: [0.0 0.0 1.3889487]\n", " > Dipole moment (a.u.): [0.0 0.0 0.0] Total: 0.\n", " (debye): [0.0 0.0 0.0] Total: 0.\n", " \n", " 2: \n", " * Electronic dipole moment (a.u.): [0.0 0.0 1.3889487]\n", " - computed part: [0.0 0.0 1.3889487]\n", " > Dipole moment (a.u.): [0.0 0.0 0.0] Total: 0.\n", " (debye): [0.0 0.0 0.0] Total: 0.\n", " \n", "\n", "\n", "\n", "=== GROUND STATE ENERGY ===\n", " \n", "* Electronic ground state energy (Hartree): -1.857275030145\n", " - computed part: -1.857275030145\n", "~ Nuclear repulsion energy (Hartree): 0.719968994449\n", "> Total ground state energy (Hartree): -1.137306035696\n", " \n", "=== EXCITED STATE ENERGIES ===\n", " \n", " 1: \n", "* Electronic excited state energy (Hartree): -1.244586754624\n", "> Total excited state energy (Hartree): -0.524617760175\n", " 2: \n", "* Electronic excited state energy (Hartree): -0.882724355025\n", "> Total excited state energy (Hartree): -0.162755360576\n", " 3: \n", "* Electronic excited state energy (Hartree): -0.22491345762\n", "> Total excited state energy (Hartree): 0.495055536829\n", " \n", "=== MEASURED OBSERVABLES ===\n", " \n", " 0: # Particles: 2.000 S: 0.000 S^2: 0.000 M: -0.000\n", " \n", "=== DIPOLE MOMENTS ===\n", " \n", "~ Nuclear dipole moment (a.u.): [0.0 0.0 1.3889487]\n", " \n", " 0: \n", " * Electronic dipole moment (a.u.): [0.0 0.0 1.38894866]\n", " - computed part: [0.0 0.0 1.38894866]\n", " > Dipole moment (a.u.): [0.0 0.0 0.00000004] Total: 0.00000004\n", " (debye): [0.0 0.0 0.0000001] Total: 0.0000001\n", " \n" ] } ], "source": [ "from qiskit_nature.algorithms import ExcitedStatesEigensolver\n", "\n", "numpy_excited_states_calculation = ExcitedStatesEigensolver(qubit_converter, numpy_solver)\n", "numpy_results = numpy_excited_states_calculation.solve(es_problem)\n", "\n", "qeom_results = qeom_excited_states_calculation.solve(es_problem)\n", "\n", "print(numpy_results)\n", "print('\\n\\n')\n", "print(qeom_results)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "One can see from these results that one state is missing from the NumPy results. The reason for this is because the spin is also used as a filter and only singlet states are shown. \n", "In the following we use a custom filter function to check consistently our results and only filter out states with incorrect number of particle (in this case the number of particle is 2)." ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "=== GROUND STATE ENERGY ===\n", " \n", "* Electronic ground state energy (Hartree): -1.857275030202\n", " - computed part: -1.857275030202\n", "~ Nuclear repulsion energy (Hartree): 0.719968994449\n", "> Total ground state energy (Hartree): -1.137306035753\n", " \n", "=== EXCITED STATE ENERGIES ===\n", " \n", " 1: \n", "* Electronic excited state energy (Hartree): -1.244584549813\n", "> Total excited state energy (Hartree): -0.524615555364\n", " 2: \n", "* Electronic excited state energy (Hartree): -1.244584549813\n", "> Total excited state energy (Hartree): -0.524615555364\n", " 3: \n", "* Electronic excited state energy (Hartree): -1.244584549813\n", "> Total excited state energy (Hartree): -0.524615555364\n", " 4: \n", "* Electronic excited state energy (Hartree): -0.882722150245\n", "> Total excited state energy (Hartree): -0.162753155796\n", " 5: \n", "* Electronic excited state energy (Hartree): -0.224911252831\n", "> Total excited state energy (Hartree): 0.495057741618\n", " \n", "=== MEASURED OBSERVABLES ===\n", " \n", " 0: # Particles: 2.000 S: 0.000 S^2: 0.000 M: 0.000\n", " 1: # Particles: 2.000 S: 1.000 S^2: 2.000 M: 0.000\n", " 2: # Particles: 2.000 S: 1.000 S^2: 2.000 M: 1.000\n", " 3: # Particles: 2.000 S: 1.000 S^2: 2.000 M: -1.000\n", " 4: # Particles: 2.000 S: 0.000 S^2: 0.000 M: 0.000\n", " 5: # Particles: 2.000 S: 0.000 S^2: 0.000 M: 0.000\n", " \n", "=== DIPOLE MOMENTS ===\n", " \n", "~ Nuclear dipole moment (a.u.): [0.0 0.0 1.3889487]\n", " \n", " 0: \n", " * Electronic dipole moment (a.u.): [0.0 0.0 1.3889487]\n", " - computed part: [0.0 0.0 1.3889487]\n", " > Dipole moment (a.u.): [0.0 0.0 0.0] Total: 0.\n", " (debye): [0.0 0.0 0.0] Total: 0.\n", " \n", " 1: \n", " * Electronic dipole moment (a.u.): [0.0 0.0 1.3889487]\n", " - computed part: [0.0 0.0 1.3889487]\n", " > Dipole moment (a.u.): [0.0 0.0 0.0] Total: 0.\n", " (debye): [0.0 0.0 0.0] Total: 0.\n", " \n", " 2: \n", " * Electronic dipole moment (a.u.): [0.0 0.0 1.3889487]\n", " - computed part: [0.0 0.0 1.3889487]\n", " > Dipole moment (a.u.): [0.0 0.0 0.0] Total: 0.\n", " (debye): [0.0 0.0 0.0] Total: 0.\n", " \n", " 3: \n", " * Electronic dipole moment (a.u.): [0.0 0.0 1.3889487]\n", " - computed part: [0.0 0.0 1.3889487]\n", " > Dipole moment (a.u.): [0.0 0.0 0.0] Total: 0.\n", " (debye): [0.0 0.0 0.0] Total: 0.\n", " \n", " 4: \n", " * Electronic dipole moment (a.u.): [0.0 0.0 1.3889487]\n", " - computed part: [0.0 0.0 1.3889487]\n", " > Dipole moment (a.u.): [0.0 0.0 0.0] Total: 0.\n", " (debye): [0.0 0.0 0.0] Total: 0.\n", " \n", " 5: \n", " * Electronic dipole moment (a.u.): [0.0 0.0 1.3889487]\n", " - computed part: [0.0 0.0 1.3889487]\n", " > Dipole moment (a.u.): [0.0 0.0 0.0] Total: 0.\n", " (debye): [0.0 0.0 0.0] Total: 0.\n", " \n" ] } ], "source": [ "import numpy as np\n", "\n", "def filter_criterion(eigenstate, eigenvalue, aux_values):\n", " return np.isclose(aux_values[0][0], 2.)\n", "\n", "new_numpy_solver = NumPyEigensolverFactory(filter_criterion=filter_criterion)\n", "new_numpy_excited_states_calculation = ExcitedStatesEigensolver(qubit_converter, new_numpy_solver)\n", "new_numpy_results = new_numpy_excited_states_calculation.solve(es_problem)\n", "\n", "print(new_numpy_results)" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/html": [ "

### Version Information

Qiskit SoftwareVersion
Qiskit0.24.1
Terra0.17.0.dev0+bcbc13c
Aer0.7.6
Ignis0.5.2
AquaNone
IBM Q Provider0.12.2
System information
Python3.7.10 (default, Feb 26 2021, 10:16:00) \n", "[Clang 10.0.0 ]
OSDarwin
CPUs4
Memory (Gb)16.0
Thu Apr 01 12:26:00 2021 CEST
" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "