Skip to content

Commit

Permalink
Add Slater determinant and fermionic Gaussian state initial states (#483
Browse files Browse the repository at this point in the history
)

* add QuadraticHamiltonian class

* preparation of Slater determinants and fermionic Gaussian states

* validate input

* expose _fermionic_op as to_fermionic_op

* use tuple labels and merge loops

* update docs

* add num_modes argument

* document new errors

* add num_modes property

* update doc

* spelling

* mypy

* from __future__ import annotations

* add release note

* trigger CI

* fix spelling

* update terra

* split so each class has own file

* fix comments and error messages, don't name registers

* revert library init description

* run copyright check

* add release note

* spelling

* spelling and docs

* make private functions hidden again

* mypy

* improve docs and error messages

* split test file

* add input validation

* mypy

* lint

* add slater determinants test file

* create utils module

* test unsupported mappers fail gracefully

* fix imports

* raise NotImplementedError for unsupported mapper

* improve docs

* rewrite documentation

* improve docs and error messages

* factor out validation function

* improve slater determinant docs

* add tutorial notebook

* typo

* fix warning in notebook

* edit notebook

* comma

* spelling and format

* add note to QuadraticHamiltonian class

* Update docs/tutorials/11_quadratic_hamiltonian_and_slater_determinants.ipynb

Co-authored-by: Max Rossmannek <[email protected]>

* add hyperlinks

* update print output in notebook

* Update releasenotes/notes/slater-53415163fff84313.yaml

Co-authored-by: Steve Wood <[email protected]>

* format

* edit notebook kernel to satisfy CI

* edit notebook

* edit notebook to say creation instead of annihilation

Co-authored-by: Panagiotis Barkoutsos <[email protected]>
Co-authored-by: Manoel Marques <[email protected]>
Co-authored-by: Max Rossmannek <[email protected]>
Co-authored-by: Steve Wood <[email protected]>
Co-authored-by: Max Rossmannek <[email protected]>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
  • Loading branch information
7 people authored May 20, 2022
1 parent a3bf369 commit 762fc0c
Show file tree
Hide file tree
Showing 12 changed files with 1,187 additions and 5 deletions.
9 changes: 9 additions & 0 deletions .pylintdict
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ cargs
cartesian
cbit
ccx
cdots
cfg
chc
chiral
Expand Down Expand Up @@ -101,6 +102,7 @@ debye
deepcopy
dft
diag
diagonalization
diagonalize
diagonalizes
diagonalizing
Expand All @@ -110,6 +112,7 @@ dimensionality
discoverable
distinguishability
dll
docstring
dof
doi
dt
Expand All @@ -123,6 +126,7 @@ eigensolvers
eigenstate
eigenstateresult
eigenstates
eigenvector
einact
einsum
endian
Expand Down Expand Up @@ -233,6 +237,7 @@ kwargs
kwds
labelled
lda
ldots
len
leucine
levinthal
Expand All @@ -247,6 +252,7 @@ ljik
lk
logfile
lookback
lvert
lysine
macos
majorana
Expand Down Expand Up @@ -324,6 +330,7 @@ ortho
orthonormal
otimes
outpath
overline
pac
param
parameterized
Expand Down Expand Up @@ -376,6 +383,7 @@ qubit
qubits
qutrit
radians
rangle
rcccx
rccx
readme
Expand Down Expand Up @@ -419,6 +427,7 @@ setia
setted
shende
sklearn
slater
spinop
springer
spsa
Expand Down
440 changes: 440 additions & 0 deletions docs/tutorials/11_quadratic_hamiltonian_and_slater_determinants.ipynb

Large diffs are not rendered by default.

8 changes: 6 additions & 2 deletions qiskit_nature/circuit/library/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# This code is part of Qiskit.
#
# (C) Copyright IBM 2020, 2021.
# (C) Copyright IBM 2020, 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
Expand All @@ -25,7 +25,9 @@
:toctree: ../stubs/
:nosignatures:
FermionicGaussianState
HartreeFock
SlaterDeterminant
VSCF
Ansatzes
Expand Down Expand Up @@ -64,7 +66,7 @@
UVCCSD,
)

from .initial_states import HartreeFock, VSCF
from .initial_states import FermionicGaussianState, HartreeFock, SlaterDeterminant, VSCF

__all__ = [
"UCC",
Expand All @@ -76,4 +78,6 @@
"UVCC",
"UVCCSD",
"VSCF",
"FermionicGaussianState",
"SlaterDeterminant",
]
11 changes: 9 additions & 2 deletions qiskit_nature/circuit/library/initial_states/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# This code is part of Qiskit.
#
# (C) Copyright IBM 2020, 2021.
# (C) Copyright IBM 2020, 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
Expand All @@ -11,7 +11,14 @@
# that they have been altered from the originals.
"""Qiskit Nature Circuit Library Initial States."""

from .fermionic_gaussian_state import FermionicGaussianState
from .hartree_fock import HartreeFock
from .slater_determinants import SlaterDeterminant
from .vscf import VSCF

__all__ = ["HartreeFock", "VSCF"]
__all__ = [
"FermionicGaussianState",
"HartreeFock",
"SlaterDeterminant",
"VSCF",
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
# This code is part of Qiskit.
#
# (C) Copyright IBM 2021, 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.

"""Fermionic Gaussian states."""

from typing import Optional, Sequence

import numpy as np
from qiskit import QuantumCircuit, QuantumRegister
from qiskit_nature.converters.second_quantization import QubitConverter
from qiskit_nature.mappers.second_quantization import JordanWignerMapper

from .utils.givens_rotations import _prepare_fermionic_gaussian_state_jordan_wigner


def _validate_transformation_matrix(
mat: np.ndarray, rtol: float = 1e-5, atol: float = 1e-8
) -> None:
if not len(mat.shape) == 2:
raise ValueError(
"transformation_matrix must be a 2-dimensional array. "
f"Instead, got shape {mat.shape}."
)

n, p = mat.shape # pylint: disable=invalid-name
if p != n * 2:
raise ValueError(
"transformation_matrix must have shape (n_orbitals, 2 * n_orbitals). "
f"Instead, got shape {mat.shape}."
)

left = mat[:, :n]
right = mat[:, n:]
comm1 = left @ left.T.conj() + right @ right.T.conj()
comm2 = left @ right.T + right @ left.T
one = np.eye(n)
zero = np.zeros((n, n))
if not np.allclose(comm1, one, rtol=rtol, atol=atol) or not np.allclose(comm2, zero):
raise ValueError(
"transformation_matrix does not describe a valid transformation "
"of fermionic ladder operators. A valid matrix should have the block form "
"[W1 W2] where W1 @ W1.T.conj() + W2 @ W2.T.conj() = I and "
"W1 @ W2.T + W2 @ W1.T = 0."
)


class FermionicGaussianState(QuantumCircuit):
r"""A circuit that prepares a fermionic Gaussian state.
A fermionic Gaussian state is a state of the form
.. math::
b^\dagger_1 \cdots b^\dagger_{N_p} \lvert \overline{\text{vac}} \rangle
where
.. math::
\begin{pmatrix}
b^\dagger_1 \\
\vdots \\
b^\dagger_N \\
\end{pmatrix}
= W
\begin{pmatrix}
a^\dagger_1 \\
\vdots \\
a^\dagger_N \\
a_1 \\
\vdots \\
a_N
\end{pmatrix},
- :math:`a^\dagger_1, \ldots, a^\dagger_{N}` are the fermionic creation operators
- :math:`W` is an :math:`N \times 2N` matrix such that
:math:`b^\dagger_1, \ldots, b^\dagger_{N}` also satisfy the
fermionic anticommutation relations
- :math:`\lvert \overline{\text{vac}} \rangle` is the mutual 0-eigenvector of
the operators :math:`\{b_j^\dagger b_j\}`
The matrix :math:`W` has the block form
.. math::
\begin{pmatrix}
W_1 & W_2
\end{pmatrix}
where :math:`W_1` and :math:`W_2` must satisfy
.. math::
W_1 W_1^\dagger + W_2 W_2^\dagger = I \\
W_1 W_2^T + W_2 W_1^T = 0
The matrix :math:`W` is commonly obtained by calling the
:meth:`~.QuadraticHamiltonian.diagonalizing_bogoliubov_transform`
method of the :class:`~.QuadraticHamiltonian` class.
This matrix is used to create circuits that prepare eigenstates of the
quadratic Hamiltonian.
Currently, only the Jordan-Wigner Transformation is supported.
Reference: `arXiv:1711.05395`_
.. _arXiv:1711.05395: https://arxiv.org/abs/1711.05395
"""

def __init__(
self,
transformation_matrix: np.ndarray,
occupied_orbitals: Optional[Sequence[int]] = None,
qubit_converter: QubitConverter = None,
validate: bool = True,
rtol: float = 1e-5,
atol: float = 1e-8,
**circuit_kwargs,
) -> None:
r"""
Args:
transformation_matrix: The matrix :math:`W` that specifies the coefficients of the
new creation operators in terms of the original creation and annihilation operators.
This matrix must satisfy special constraints; see the main body of the docstring
of this class.
occupied_orbitals: The pseudo-particle orbitals to fill. These refer to the indices
of the operators :math:`\{b^\dagger_j\}` from the main body of the docstring
of this function. The default behavior is to use the empty set of orbitals,
which corresponds to a state with zero pseudo-particles.
qubit_converter: a QubitConverter instance.
validate: Whether to validate the inputs.
rtol: Relative numerical tolerance for input validation.
atol: Absolute numerical tolerance for input validation.
circuit_kwargs: Keyword arguments to pass to the QuantumCircuit initializer.
Raises:
ValueError: transformation_matrix must be a 2-dimensional array.
ValueError: transformation_matrix must have shape (n_orbitals, 2 * n_orbitals).
NotImplementedError: Currently, only the Jordan-Wigner Transform is supported.
Please use
:class:`qiskit_nature.mappers.second_quantization.JordanWignerMapper`
to construct the qubit mapper used to construct `qubit_converter`.
"""
if validate:
_validate_transformation_matrix(transformation_matrix, rtol=rtol, atol=atol)

if occupied_orbitals is None:
occupied_orbitals = []
if qubit_converter is None:
qubit_converter = QubitConverter(JordanWignerMapper())

n, _ = transformation_matrix.shape
register = QuantumRegister(n)
super().__init__(register, **circuit_kwargs)

if isinstance(qubit_converter.mapper, JordanWignerMapper):
operations = _prepare_fermionic_gaussian_state_jordan_wigner(
register, transformation_matrix, occupied_orbitals
)
for gate, qubits in operations:
self.append(gate, qubits)
else:
raise NotImplementedError(
"Currently, only the Jordan-Wigner Transform is supported. "
"Please use "
"qiskit_nature.mappers.second_quantization.JordanWignerMapper "
"to construct the qubit mapper used to construct qubit_converter."
)
Loading

0 comments on commit 762fc0c

Please sign in to comment.