diff --git a/qiskit/aqua/algorithms/__init__.py b/qiskit/aqua/algorithms/__init__.py index dceb88fe00..d03f910ac9 100644 --- a/qiskit/aqua/algorithms/__init__.py +++ b/qiskit/aqua/algorithms/__init__.py @@ -120,6 +120,13 @@ states of a molecule and qiskit.chemistry has some algorithms that leverage chemistry specific knowledge to do this in that application domain. +.. autosummary:: + :toctree: ../stubs/ + :nosignatures: + + Eigensolver + EigensolverResult + .. autosummary:: :toctree: ../stubs/ :nosignatures: @@ -197,7 +204,7 @@ MaximumLikelihoodAmplitudeEstimationResult) from .classifiers import VQC, QSVM, SklearnSVM, SVM_Classical from .distribution_learners import QGAN -from .eigen_solvers import NumPyEigensolver, ExactEigensolver, EigensolverResult +from .eigen_solvers import NumPyEigensolver, ExactEigensolver, Eigensolver, EigensolverResult from .factorizers import Shor from .linear_solvers import (LinearsolverResult, HHL, HHLResult, NumPyLSsolver, @@ -223,6 +230,7 @@ 'LinearsolverResult', 'NumPyLSsolver', 'NumPyLSsolverResult', + 'Eigensolver', 'EigensolverResult', 'ExactLSsolver', 'NumPyMinimumEigensolver', diff --git a/qiskit/aqua/algorithms/eigen_solvers/__init__.py b/qiskit/aqua/algorithms/eigen_solvers/__init__.py index 7695184a33..4665d6fccf 100644 --- a/qiskit/aqua/algorithms/eigen_solvers/__init__.py +++ b/qiskit/aqua/algorithms/eigen_solvers/__init__.py @@ -13,8 +13,9 @@ """ Eigen Solvers Package """ from .numpy_eigen_solver import NumPyEigensolver, ExactEigensolver -from .eigen_solver_result import EigensolverResult +from .eigen_solver import Eigensolver, EigensolverResult __all__ = ['NumPyEigensolver', 'ExactEigensolver', + 'Eigensolver', 'EigensolverResult'] diff --git a/qiskit/aqua/algorithms/eigen_solvers/eigen_solver_result.py b/qiskit/aqua/algorithms/eigen_solvers/eigen_solver.py similarity index 51% rename from qiskit/aqua/algorithms/eigen_solvers/eigen_solver_result.py rename to qiskit/aqua/algorithms/eigen_solvers/eigen_solver.py index 68dae23e1c..c12128c411 100644 --- a/qiskit/aqua/algorithms/eigen_solvers/eigen_solver_result.py +++ b/qiskit/aqua/algorithms/eigen_solvers/eigen_solver.py @@ -10,13 +10,84 @@ # copyright notice, and modified files need to carry a notice indicating # that they have been altered from the originals. -"""The Eigensolver result.""" +"""The Eigensolver interface""" import warnings -from typing import Dict, Optional -import numpy as np +from abc import ABC, abstractmethod +from typing import List, Optional, Union, Dict +import numpy as np from qiskit.aqua.algorithms import AlgorithmResult +from qiskit.aqua.operators import OperatorBase, LegacyBaseOperator + + +class Eigensolver(ABC): + """The Eigensolver Interface. + + Algorithms that can compute eigenvalues for an operator + may implement this interface to allow different algorithms to be + used interchangeably. + """ + + @abstractmethod + def compute_eigenvalues( + self, + operator: Optional[Union[OperatorBase, LegacyBaseOperator]] = None, + aux_operators: Optional[List[Optional[Union[OperatorBase, + LegacyBaseOperator]]]] = None + ) -> 'EigensolverResult': + """ + Computes eigenvalues. Operator and aux_operators can be supplied here and + if not None will override any already set into algorithm so it can be reused with + different operators. While an operator is required by algorithms, aux_operators + are optional. To 'remove' a previous aux_operators array use an empty list here. + + Args: + operator: If not None replaces operator in algorithm + aux_operators: If not None replaces aux_operators in algorithm + + Returns: + EigensolverResult + """ + if operator is not None: + self.operator = operator # type: ignore + if aux_operators is not None: + self.aux_operators = aux_operators if aux_operators else None # type: ignore + return EigensolverResult() + + def supports_aux_operators(self) -> bool: + """Whether computing the expectation value of auxiliary operators is supported. + + Returns: + True if aux_operator expectations can be evaluated, False otherwise + """ + return False + + @property # type: ignore + @abstractmethod + def operator(self) -> Optional[Union[OperatorBase, LegacyBaseOperator]]: + """Return the operator.""" + raise NotImplementedError + + @operator.setter # type: ignore + @abstractmethod + def operator(self, operator: Union[OperatorBase, LegacyBaseOperator]) -> None: + """Set the operator.""" + raise NotImplementedError + + @property # type: ignore + @abstractmethod + def aux_operators(self) -> Optional[List[Optional[OperatorBase]]]: + """Returns the auxiliary operators.""" + raise NotImplementedError + + @aux_operators.setter # type: ignore + @abstractmethod + def aux_operators(self, + aux_operators: Optional[List[Optional[Union[OperatorBase, + LegacyBaseOperator]]]]) -> None: + """Set the auxiliary operators.""" + raise NotImplementedError class EigensolverResult(AlgorithmResult): diff --git a/qiskit/aqua/algorithms/eigen_solvers/numpy_eigen_solver.py b/qiskit/aqua/algorithms/eigen_solvers/numpy_eigen_solver.py index 8db4e7fe5d..bd4cc6c7a7 100755 --- a/qiskit/aqua/algorithms/eigen_solvers/numpy_eigen_solver.py +++ b/qiskit/aqua/algorithms/eigen_solvers/numpy_eigen_solver.py @@ -23,7 +23,7 @@ from qiskit.aqua.algorithms import ClassicalAlgorithm from qiskit.aqua.operators import OperatorBase, LegacyBaseOperator, I, StateFn, ListOp from qiskit.aqua.utils.validation import validate_min -from .eigen_solver_result import EigensolverResult +from .eigen_solver import Eigensolver, EigensolverResult logger = logging.getLogger(__name__) @@ -31,7 +31,7 @@ # pylint: disable=invalid-name -class NumPyEigensolver(ClassicalAlgorithm): +class NumPyEigensolver(ClassicalAlgorithm, Eigensolver): r""" The NumPy Eigensolver algorithm. @@ -201,6 +201,15 @@ def _eval_aux_operators(self, wavefn, threshold: float = 1e-12) -> np.ndarray: values.append((value, 0)) return np.array(values, dtype=object) + def compute_eigenvalues( + self, + operator: Optional[Union[OperatorBase, LegacyBaseOperator]] = None, + aux_operators: Optional[List[Optional[Union[OperatorBase, + LegacyBaseOperator]]]] = None + ) -> EigensolverResult: + super().compute_eigenvalues(operator, aux_operators) + return self._run() + def _run(self): """ Run the algorithm to compute up to the requested k number of eigenvalues. diff --git a/qiskit/aqua/aqua_globals.py b/qiskit/aqua/aqua_globals.py index f9102b21e5..4cb2fa5fe0 100644 --- a/qiskit/aqua/aqua_globals.py +++ b/qiskit/aqua/aqua_globals.py @@ -12,6 +12,7 @@ """ Aqua Globals """ +from typing import Optional import logging import numpy as np @@ -29,33 +30,37 @@ class QiskitAquaGlobals: CPU_COUNT = local_hardware_info()['cpus'] - def __init__(self): - self._random_seed = None + def __init__(self) -> None: + self._random_seed = None # type: Optional[int] self._num_processes = QiskitAquaGlobals.CPU_COUNT self._random = None @property - def random_seed(self): + def random_seed(self) -> Optional[int]: """Return random seed.""" return self._random_seed @random_seed.setter - def random_seed(self, seed): + def random_seed(self, seed: Optional[int]) -> None: """Set random seed.""" self._random_seed = seed self._random = None @property - def num_processes(self): + def num_processes(self) -> int: """Return num processes.""" return self._num_processes @num_processes.setter - def num_processes(self, num_processes): - """Set num processes.""" - if num_processes < 1: + def num_processes(self, num_processes: Optional[int]) -> None: + """Set num processes. + If 'None' is passed, it resets to QiskitAquaGlobals.CPU_COUNT + """ + if num_processes is None: + num_processes = QiskitAquaGlobals.CPU_COUNT + elif num_processes < 1: raise AquaError('Invalid Number of Processes {}.'.format(num_processes)) - if num_processes > QiskitAquaGlobals.CPU_COUNT: + elif num_processes > QiskitAquaGlobals.CPU_COUNT: raise AquaError('Number of Processes {} cannot be greater than cpu count {}.' .format(num_processes, QiskitAquaGlobals.CPU_COUNT)) self._num_processes = num_processes @@ -68,7 +73,7 @@ def num_processes(self, num_processes): "to value: '%s': Error: '%s'", self.num_processes, str(ex)) @property - def random(self): + def random(self) -> np.random.Generator: """Return a numpy np.random.Generator (default_rng).""" if self._random is None: self._random = np.random.default_rng(self._random_seed) diff --git a/releasenotes/notes/eingensolver-7adb5d4632706259.yaml b/releasenotes/notes/eingensolver-7adb5d4632706259.yaml new file mode 100644 index 0000000000..2683023613 --- /dev/null +++ b/releasenotes/notes/eingensolver-7adb5d4632706259.yaml @@ -0,0 +1,4 @@ +--- +features: + - | + New interface ``Eigensolver`` for Eigensolver algorithms.