Skip to content
This repository has been archived by the owner on Dec 7, 2021. It is now read-only.

Create Eigensolver interface #1277

Merged
merged 1 commit into from
Sep 28, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion qiskit/aqua/algorithms/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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,
Expand All @@ -223,6 +230,7 @@
'LinearsolverResult',
'NumPyLSsolver',
'NumPyLSsolverResult',
'Eigensolver',
'EigensolverResult',
'ExactLSsolver',
'NumPyMinimumEigensolver',
Expand Down
3 changes: 2 additions & 1 deletion qiskit/aqua/algorithms/eigen_solvers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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']
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down
18 changes: 11 additions & 7 deletions qiskit/aqua/algorithms/eigen_solvers/numpy_eigen_solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,15 @@
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__)


# pylint: disable=invalid-name


class NumPyEigensolver(ClassicalAlgorithm):
class NumPyEigensolver(ClassicalAlgorithm, Eigensolver):
r"""
The NumPy Eigensolver algorithm.

Expand Down Expand Up @@ -74,20 +74,17 @@ def __init__(self,

@property
def operator(self) -> Optional[OperatorBase]:
""" returns operator """
return self._operator

@operator.setter
def operator(self, operator: Union[OperatorBase, LegacyBaseOperator]) -> None:
""" set operator """
if isinstance(operator, LegacyBaseOperator):
operator = operator.to_opflow()
self._operator = operator
self._check_set_k()

@property
def aux_operators(self) -> Optional[List[Optional[OperatorBase]]]:
""" returns aux operators """
return self._aux_operators

@aux_operators.setter
Expand All @@ -97,7 +94,6 @@ def aux_operators(self,
LegacyBaseOperator,
List[Optional[Union[OperatorBase,
LegacyBaseOperator]]]]]) -> None:
""" Set aux operators """
if aux_operators is None:
aux_operators = []
elif not isinstance(aux_operators, list):
Expand Down Expand Up @@ -126,7 +122,6 @@ def k(self, k: int) -> None:
self._check_set_k()

def supports_aux_operators(self) -> bool:
""" If will process auxiliary operators or not """
return True

def _check_set_k(self) -> None:
Expand Down Expand Up @@ -201,6 +196,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.
Expand Down
25 changes: 15 additions & 10 deletions qiskit/aqua/aqua_globals.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

""" Aqua Globals """

from typing import Optional
import logging

import numpy as np
Expand All @@ -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
Expand All @@ -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)
Expand Down
4 changes: 4 additions & 0 deletions releasenotes/notes/eingensolver-7adb5d4632706259.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
features:
- |
New interface ``Eigensolver`` for Eigensolver algorithms.