English
Languages
English
Bengali
Japanese
Spanish

Note

# Electronic structure¶

## Introduction¶

The molecular Hamiltonian is

$\mathcal{H} = - \sum_I \frac{\nabla_{R_I}^2}{M_I} - \sum_i \frac{\nabla_{r_i}^2}{m_e} - \sum_I\sum_i \frac{Z_I e^2}{|R_I-r_i|} + \sum_i \sum_{j>i} \frac{e^2}{|r_i-r_j|} + \sum_I\sum_{J>I} \frac{Z_I Z_J e^2}{|R_I-R_J|}$

Because the nuclei are much heavier than the electrons they do not move on the same time scale and therefore, the behavior of nuclei and electrons can be decoupled. This is the Born-Oppenheimer approximation.

Therefore, one can first tackle the electronic problem with the nuclear coordinates entering only as parameters. The energy levels of the electrons in the molecule can then be found by solving the non-relativistic time independent Schrödinger equation,

$\mathcal{H}_{\text{el}} |\Psi_{n}\rangle = E_{n} |\Psi_{n}\rangle$

where

$\mathcal{H}_{\text{el}} = - \sum_i \frac{\nabla_{r_i}^2}{m_e} - \sum_I\sum_i \frac{Z_I e^2}{|R_I-r_i|} + \sum_i \sum_{j>i} \frac{e^2}{|r_i-r_j|}.$

In particular the ground state energy is given by:

$E_0 = \frac{\langle \Psi_0 | H_{\text{el}} | \Psi_0 \rangle}{\langle \Psi_0 | \Psi_0 \rangle}$

where $$\Psi_0$$ is the ground state of the system.

However, the dimensionality of this problem grows exponentially with the number of degrees of freedom. To tackle this issue we would like to prepare $$\Psi_0$$ on a quantum computer and measure the Hamiltonian expectation value (or $$E_0$$) directly.

So how do we do that concretely?

## Starting from the Hartree-Fock solution¶

A good starting point for solving this problem is the Hartree-Fock (HF) method. This method approximates the N-body problem by N one-body problems where each electron evolves in the mean-field of the others. Classically solving the HF equations is efficient and leads to the exact exchange energy but does not include any electron correlation. Therefore, it is usually a good starting point to which to add correlation.

The Hamiltonian can then be re-expressed in the basis of the solutions of the HF method, also called Molecular Orbitals (MOs):

$\hat{H}_{elec}=\sum_{pq} h_{pq} \hat{a}^{\dagger}_p \hat{a}_q + \frac{1}{2} \sum_{pqrs} h_{pqrs} \hat{a}^{\dagger}_p \hat{a}^{\dagger}_q \hat{a}_r \hat{a}_s$

with the 1-body integrals

$h_{pq} = \int \phi^*_p(r) \left( -\frac{1}{2} \nabla^2 - \sum_{I} \frac{Z_I}{R_I- r} \right) \phi_q(r)dr$

and 2-body integrals

$h_{pqrs} = \int \frac{\phi^*_p(r_1) \phi^*_q(r_2) \phi_r(r_2) \phi_s(r_1)}{|r_1-r_2|}dr_1dr_2.$

The MOs ($$\phi_u$$) can be occupied or virtual (unoccupied). One MO can contain 2 electrons. However, in what follows we actually work with Spin Orbitals which are associated with a spin up ($$\alpha$$) of spin down ($$\beta$$) electron. Thus Spin Orbitals can contain one electron or be unoccupied.

Note: when referring to the number of orbitals, we will be using the number of spatial orbitals. This refers to any orbital in Cartesian space (whether its a molecular orbital or in another basis does not matter here). Each spatial orbital is then generally split into two spin orbitals.

We now show how to concretely realise these steps with Qiskit.

### Obtaining an initial Hartree-Fock solution¶

Qiskit is interfaced with different classical codes which are able to find the HF solutions. Interfacing between Qiskit and the following codes is already available:

• Gaussian

• Psi4

• PySCF

In the following we set up a PySCF driver, for the hydrogen molecule at equilibrium bond length (0.735 angstrom) in the singlet state and with no charge.

:

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,
)


Running this driver, will yield an ElectronicStructureProblem, Qiskit Nature’s representation of the electronic structure problem which we are interested in solving. For further information about the drivers see https://qiskit.org/documentation/nature/apidocs/qiskit_nature.second_q.drivers.html

:

problem = driver.run()
print(problem)

<qiskit_nature.second_q.problems.electronic_structure_problem.ElectronicStructureProblem object at 0x7f4274250af0>

/opt/hostedtoolcache/Python/3.8.17/x64/lib/python3.8/site-packages/pyscf/dft/libxc.py:772: UserWarning: Since PySCF-2.3, B3LYP (and B3P86) are changed to the VWN-RPA variant, the same to the B3LYP functional in Gaussian and ORCA (issue 1480). To restore the VWN5 definition, you can put the setting "B3LYP_WITH_VWN5 = True" in pyscf_conf.py
warnings.warn('Since PySCF-2.3, B3LYP (and B3P86) are changed to the VWN-RPA variant, '


### The ElectronicStructureProblem and its components¶

Let us spend some time to understand this problem instance and its components.

#### The ElectronicEnergy Hamiltonian¶

The most important aspect is the internal Hamiltonian; in this case an ElectronicEnergy hamiltonian. This class is able to generate the second-quantized operator from the 1- and 2-body integrals which the classical code has computed for us.

IMPORTANT: The container class for the integral coefficients (PolynomialTensor) requires the 2-body terms to be provided in physicist order!

:

hamiltonian = problem.hamiltonian

coefficients = hamiltonian.electronic_integrals
print(coefficients.alpha)

Polynomial Tensor
"+-":
[[-1.25633907e+00 -1.37083854e-17]
[-6.07732712e-17 -4.71896007e-01]]
"++--":
[[[[6.75710155e-01 1.69253442e-16]
[1.56722377e-16 1.80931200e-01]]

[[4.84650299e-17 1.80931200e-01]
[6.64581730e-01 3.79897400e-16]]]

[[[1.01440795e-16 6.64581730e-01]
[1.80931200e-01 4.71502663e-17]]

[[1.80931200e-01 3.78920172e-16]
[6.59828421e-17 6.98573723e-01]]]]

:

second_q_op = hamiltonian.second_q_op()
print(second_q_op)

Fermionic Operator
number spin orbitals=4, number terms=36
-1.25633907300325 * ( +_0 -_0 )
+ -0.47189600728114184 * ( +_1 -_1 )
+ -1.25633907300325 * ( +_2 -_2 )
+ -0.47189600728114184 * ( +_3 -_3 )
+ 0.33785507740175813 * ( +_0 +_0 -_0 -_0 )
+ 0.09046559989211568 * ( +_0 +_0 -_1 -_1 )
+ 0.09046559989211564 * ( +_0 +_1 -_0 -_1 )
+ 0.33229086512764827 * ( +_0 +_1 -_1 -_0 )
+ 0.33785507740175813 * ( +_0 +_2 -_2 -_0 )
+ 0.09046559989211568 * ( +_0 +_2 -_3 -_1 )
+ 0.09046559989211564 * ( +_0 +_3 -_2 -_1 )
+ 0.33229086512764827 * ( +_0 +_3 -_3 -_0 )
+ 0.3322908651276482 * ( +_1 +_0 -_0 -_1 )
+ 0.09046559989211574 * ( +_1 +_0 -_1 -_0 )
+ 0.09046559989211565 * ( +_1 +_1 -_0 -_0 )
+ 0.3492868613660089 * ( +_1 +_1 -_1 -_1 )
+ 0.3322908651276482 * ( +_1 +_2 -_2 -_1 )
+ 0.09046559989211574 * ( +_1 +_2 -_3 -_0 )
+ 0.09046559989211565 * ( +_1 +_3 -_2 -_0 )
+ 0.3492868613660089 * ( +_1 +_3 -_3 -_1 )
+ 0.33785507740175813 * ( +_2 +_0 -_0 -_2 )
+ 0.09046559989211568 * ( +_2 +_0 -_1 -_3 )
+ 0.09046559989211564 * ( +_2 +_1 -_0 -_3 )
+ 0.33229086512764827 * ( +_2 +_1 -_1 -_2 )
+ 0.33785507740175813 * ( +_2 +_2 -_2 -_2 )
+ 0.09046559989211568 * ( +_2 +_2 -_3 -_3 )
+ 0.09046559989211564 * ( +_2 +_3 -_2 -_3 )
+ 0.33229086512764827 * ( +_2 +_3 -_3 -_2 )
+ 0.3322908651276482 * ( +_3 +_0 -_0 -_3 )
+ 0.09046559989211574 * ( +_3 +_0 -_1 -_2 )
+ 0.09046559989211565 * ( +_3 +_1 -_0 -_2 )
+ 0.3492868613660089 * ( +_3 +_1 -_1 -_3 )
+ 0.3322908651276482 * ( +_3 +_2 -_2 -_3 )
+ 0.09046559989211574 * ( +_3 +_2 -_3 -_2 )
+ 0.09046559989211565 * ( +_3 +_3 -_2 -_2 )
+ 0.3492868613660089 * ( +_3 +_3 -_3 -_3 )


Note, that this is purely the electronic Hamiltonian of the system. That means, that the nuclear repulsion energy is not included. Instead, Qiskit Nature will add this constant energy offset in a post-processing step, in order to compute the total energy of your system. To learn how to include the nuclear repulsion energy in this operator, please refer to the documentation of the ElectronicEnergy class here.

:

hamiltonian.nuclear_repulsion_energy  # NOT included in the second_q_op above

:

0.7199689944489797


#### More attributes of the ElectronicStructureProblem¶

Below we list some additional attributes of our problem instance:

:

problem.molecule

:

MoleculeInfo(symbols=['H', 'H'], coords=[(0.0, 0.0, 0.0), (0.0, 0.0, 1.3889487015553204)], multiplicity=1, charge=0, units=<DistanceUnit.BOHR: 'Bohr'>, masses=[1, 1])

:

problem.reference_energy

:

-1.116998996754004

:

problem.num_particles

:

(1, 1)

:

problem.num_spatial_orbitals

:

2

:

problem.basis

:

<ElectronicBasis.MO: 'molecular'>


To learn more about the basis of your problem, please refer to the tutorial on the BasisTransformer <05_problem_transformers.ipynb>__.

The ElectronicStructureProblem also contains additional operator factories, which will generate observables to be evaluated at the ground- and excited-states at the end of your computation.

:

problem.properties

:

<qiskit_nature.second_q.problems.electronic_properties_container.ElectronicPropertiesContainer at 0x7f4274250be0>

:

problem.properties.particle_number

:

<qiskit_nature.second_q.properties.particle_number.ParticleNumber at 0x7f4274250c70>

:

problem.properties.angular_momentum

:

<qiskit_nature.second_q.properties.angular_momentum.AngularMomentum at 0x7f4274250b50>

:

problem.properties.magnetization

:

<qiskit_nature.second_q.properties.magnetization.Magnetization at 0x7f4274250bb0>

:

problem.properties.electronic_dipole_moment

:

<qiskit_nature.second_q.properties.dipole_moment.ElectronicDipoleMoment at 0x7f4274250cd0>


## Solving the ElectronicStructureProblem¶

In the following, we will compute the ground-state of our problem instance. To learn more about the individual components that go into the GroundStateSolver, please refer to the ground state tutorial.

:

from qiskit.algorithms.minimum_eigensolvers import NumPyMinimumEigensolver
from qiskit_nature.second_q.algorithms import GroundStateEigensolver
from qiskit_nature.second_q.mappers import JordanWignerMapper

solver = GroundStateEigensolver(
JordanWignerMapper(),
NumPyMinimumEigensolver(),
)

:

result = solver.solve(problem)
print(result)

=== 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

=== MEASURED OBSERVABLES ===

0:  # 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


/home/runner/work/qiskit-nature/qiskit-nature/qiskit_nature/deprecation.py:297: PauliSumOpDeprecationWarning: PauliSumOp is deprecated as of version 0.6.0 and support for them will be removed no sooner than 3 months after the release. Instead, use SparsePauliOp. You can switch to SparsePauliOp immediately, by setting qiskit_nature.settings.use_pauli_sum_op to False.
return func(*args, **kwargs)

:

import qiskit.tools.jupyter

%qiskit_version_table


### Version Information

SoftwareVersion
qiskitNone
qiskit-terra0.25.1
qiskit_nature0.6.2
System information
Python version3.8.17
Python compilerGCC 11.3.0
Python builddefault, Jun 7 2023 12:29:56
OSLinux
CPUs2
Memory (Gb)6.7694854736328125
Fri Sep 01 17:56:17 2023 UTC