Source code for qiskit_nature.second_q.circuit.library.initial_states.slater_determinant

# This code is part of a Qiskit project.
#
# (C) Copyright IBM 2021, 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.

"""Slater determinants."""

from __future__ import annotations

import numpy as np
from qiskit import QuantumCircuit, QuantumRegister
from qiskit_nature.second_q.mappers import QubitMapper
from qiskit_nature.second_q.mappers import JordanWignerMapper

from .utils.givens_rotations import _prepare_slater_determinant_jw


def _rows_are_orthonormal(mat: np.ndarray, rtol: float = 1e-5, atol: float = 1e-8) -> bool:
    m, _ = mat.shape
    return np.allclose(mat @ mat.T.conj(), np.eye(m), rtol=rtol, atol=atol)


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}."
        )
    if not _rows_are_orthonormal(mat, rtol=rtol, atol=atol):
        raise ValueError("transformation_matrix must have orthonormal rows.")


[docs]class SlaterDeterminant(QuantumCircuit): r"""A circuit that prepares a Slater determinant. A Slater determinant is a state of the form .. math:: b^\dagger_1 \cdots b^\dagger_{N_f} \lvert \text{vac} \rangle, where .. math:: b^\dagger_j = \sum_{k = 1}^N Q_{jk} a^\dagger_k. - :math:`Q` is an :math:`N_f \times N` matrix with orthonormal rows. - :math:`a^\dagger_1, \ldots, a^\dagger_{N}` are the fermionic creation operators. - :math:`\lvert \text{vac} \rangle` is the vacuum state. (mutual 0-eigenvector of the fermionic number operators :math:`\{a^\dagger_j a_j\}`) The matrix :math:`Q` can be obtained by calling the :meth:`~.QuadraticHamiltonian.diagonalizing_bogoliubov_transform` method of the :class:`~.QuadraticHamiltonian` class when the quadratic Hamiltonian conserves particle number. 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, qubit_mapper: QubitMapper | None = None, *, validate: bool = True, rtol: float = 1e-5, atol: float = 1e-8, **circuit_kwargs, ) -> None: # pylint: disable=unused-argument r""" Args: transformation_matrix: The matrix :math:`Q` that specifies the coefficients of the new creation operators in terms of the original creation operators. The rows of the matrix must be orthonormal. qubit_mapper: The ``QubitMapper``. The default behavior is to create one using the call ``JordanWignerMapper()``. 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 orthonormal rows. NotImplementedError: Currently, only the Jordan-Wigner Transform is supported. Please use the :class:`qiskit_nature.second_q.mappers.JordanWignerMapper`. """ if validate: _validate_transformation_matrix(transformation_matrix, rtol=rtol, atol=atol) if qubit_mapper is None: qubit_mapper = JordanWignerMapper() _, n = transformation_matrix.shape register = QuantumRegister(n) super().__init__(register, **circuit_kwargs) if isinstance(qubit_mapper, JordanWignerMapper): operations = _prepare_slater_determinant_jw(register, transformation_matrix) for gate, qubits in operations: self.append(gate, qubits) else: raise NotImplementedError( "Currently, only the Jordan-Wigner Transform is supported. " "Please use the qiskit_nature.second_q.mappers.JordanWignerMapper." )