Source code for qiskit_nature.second_q.problems.vibrational_structure_problem

# 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 Vibrational Structure Problem class."""

from __future__ import annotations

from functools import partial
from typing import cast, Callable, List, Optional, Union

import numpy as np

from qiskit_algorithms import EigensolverResult, MinimumEigensolverResult

from qiskit_nature.second_q.hamiltonians import VibrationalEnergy
from qiskit_nature.second_q.properties import Interpretable

from .base_problem import BaseProblem
from .vibrational_basis import VibrationalBasis
from .vibrational_structure_result import VibrationalStructureResult
from .vibrational_properties_container import VibrationalPropertiesContainer
from .eigenstate_result import EigenstateResult


[docs]class VibrationalStructureProblem(BaseProblem): """Vibrational Structure Problem The following attributes can be read and updated once the ``VibrationalStructureProblem`` object has been constructed. Attributes: properties (VibrationalPropertiesContainer): a container for additional observable operator factories. basis (VibrationalBasis): the second-quantization basis in which the problem's operators are expressed. """ def __init__(self, hamiltonian: VibrationalEnergy) -> None: """ Args: hamiltonian: the Hamiltonian of this problem. """ super().__init__(hamiltonian) self.properties: VibrationalPropertiesContainer = VibrationalPropertiesContainer() self.basis: VibrationalBasis = None @property def hamiltonian(self) -> VibrationalEnergy: return cast(VibrationalEnergy, self._hamiltonian) @property def num_modals(self) -> list[int]: """The number of modals into which each mode got expanded in second-quantization.""" return self.basis.num_modals
[docs] def interpret( self, raw_result: Union[EigenstateResult, EigensolverResult, MinimumEigensolverResult], ) -> VibrationalStructureResult: """Interprets an EigenstateResult in the context of this problem. Args: raw_result: an eigenstate result object. Returns: A vibrational structure result. """ eigenstate_result = super().interpret(raw_result) result = VibrationalStructureResult() result.combine(eigenstate_result) if isinstance(self.hamiltonian, Interpretable): self.hamiltonian.interpret(result) for prop in self.properties: if isinstance(prop, Interpretable): prop.interpret(result) result.computed_vibrational_energies = eigenstate_result.eigenvalues return result
[docs] def get_default_filter_criterion( self, ) -> Optional[Callable[[Union[List, np.ndarray], float, Optional[List[float]]], bool]]: """Returns a default filter criterion method to filter the eigenvalues computed by the eigen solver. For more information see also :meth:`~qiskit_algorithms.NumPyEigensolver.filter_criterion`. This particular default ensures that the occupation of every mode is (close to) 1. """ # pylint: disable=unused-argument def filter_criterion(self, eigenstate, eigenvalue, aux_values): for mode, _ in enumerate(self.num_modals): if aux_values is None or not np.isclose(aux_values[str(mode)][0], 1): return False return True return partial(filter_criterion, self)