Source code for qiskit_nature.second_q.problems.harmonic_basis

# 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.

"""The Harmonic basis."""

from __future__ import annotations

from functools import lru_cache

import numpy as np

from .vibrational_basis import VibrationalBasis


[docs]class HarmonicBasis(VibrationalBasis): """The Harmonic basis. This class uses the Hermite polynomials (eigenstates of the harmonic oscillator) as a modal basis for the expression of the Watson Hamiltonian or any bosonic operator. References: [1] Pauline J. Ollitrault et al. "Hardware efficient quantum algorithms for vibrational structure calculations" Chem. Sci., 2020, 11, 6842-6855. https://doi.org/10.1039/D0SC01908A """
[docs] @lru_cache(maxsize=128) def eval_integral( self, mode: int, modal_1: int, modal_2: int, power: int, kinetic_term: bool = False, ) -> complex | None: """The integral evaluation method of this basis. Args: mode: the index of the mode. modal_1: the index of the first modal. modal_2: the index of the second modal. power: the exponent of the coordinate. kinetic_term: if this is True, the method should compute the integral of the kinetic term of the vibrational Hamiltonian, :math:``d^2/dQ^2``. Returns: The evaluated integral for the specified coordinate or ``None`` if this integral value falls below the threshold. Raises: ValueError: if the ``power`` exceeds 4. References: [1] J. Chem. Phys. 135, 134108 (2011) https://doi.org/10.1063/1.3644895 (Table 1) """ coeff = 0.0 if power == 1: if modal_1 - modal_2 == 1: coeff = np.sqrt(modal_1 / 2) elif power == 2: if modal_1 - modal_2 == 0: coeff = (modal_1 + 1 / 2) * (-1.0 if kinetic_term else 1.0) elif modal_1 - modal_2 == 2: coeff = np.sqrt(modal_1 * (modal_1 - 1)) / 2 elif power == 3: if modal_1 - modal_2 == 1: coeff = 3 * np.power(modal_1 / 2, 3 / 2) elif modal_1 - modal_2 == 3: coeff = np.sqrt(modal_1 * (modal_1 - 1) * (modal_1 - 2)) / np.power(2, 3 / 2) elif power == 4: if modal_1 - modal_2 == 0: coeff = (6 * modal_1 * (modal_1 + 1) + 3) / 4 elif modal_1 - modal_2 == 2: coeff = (modal_1 - 1 / 2) * np.sqrt(modal_1 * (modal_1 - 1)) elif modal_1 - modal_2 == 4: coeff = np.sqrt(modal_1 * (modal_1 - 1) * (modal_1 - 2) * (modal_1 - 3)) / 4 else: raise ValueError("The Q power is to high, only up to 4 is currently supported.") coeff *= np.sqrt(2) ** power return None if abs(coeff) < self.threshold else coeff