Skip to content
Closed
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
41 changes: 36 additions & 5 deletions qiskit/algorithms/eigen_solvers/eigen_solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import numpy as np

from qiskit.opflow import OperatorBase
from qiskit.utils.deprecation import deprecate_function
from ..algorithm_result import AlgorithmResult
from ..list_or_dict import ListOrDict

Expand Down Expand Up @@ -69,7 +70,7 @@ def __init__(self) -> None:
super().__init__()
self._eigenvalues = None
self._eigenstates = None
self._aux_operator_eigenvalues = None
self._aux_operator_values = None

@property
def eigenvalues(self) -> Optional[np.ndarray]:
Expand All @@ -92,14 +93,44 @@ def eigenstates(self, value: np.ndarray) -> None:
self._eigenstates = value

@property
def aux_operator_eigenvalues(self) -> Optional[List[ListOrDict[Tuple[complex, complex]]]]:
def aux_operator_values(self) -> Optional[List[ListOrDict[Tuple[complex, complex]]]]:
"""Return aux operator expectation values.

These values are in fact tuples formatted as (mean, standard deviation).
"""
return self._aux_operator_eigenvalues
return self._aux_operator_values

@aux_operator_values.setter
def aux_operator_values(self, value: List[ListOrDict[Tuple[complex, complex]]]) -> None:
"""set aux operator values"""
self._aux_operator_values = value

@property
@deprecate_function(
Comment thread
Cryoris marked this conversation as resolved.
"""
The EigensolverResult.aux_operator_eigenvalues property is pending deprecation as of
Qiskit Terra 0.21.0. It will be deprecated in the release 0.22.0 and removed no sooner than 3 months
after that release date. You can use EigensolverResult.aux_operator_values as a direct
replacement instead, which reflects that these values are not eigenvalues of the operators but just
expectation values.
""",
pending_deprecation=True,
)
def aux_operator_eigenvalues(self) -> Optional[List[ListOrDict[Tuple[complex, complex]]]]:
"""Pending deprecation. Use the ``aux_operator_values`` property instead."""
return self.aux_operator_values

@aux_operator_eigenvalues.setter
@deprecate_function(
"""
The EigensolverResult.aux_operator_eigenvalues setter is pending deprecation as of
Qiskit Terra 0.21.0. It will be deprecated in the release 0.22.0 and removed no sooner than 3 months
after that release date. You can use EigensolverResult.aux_operator_values as a direct
replacement instead, which reflects that these values are not eigenvalues of the operators but just
expectation values.
""",
pending_deprecation=True,
)
def aux_operator_eigenvalues(self, value: List[ListOrDict[Tuple[complex, complex]]]) -> None:
"""set aux operator eigen values"""
self._aux_operator_eigenvalues = value
"""Pending deprecation. Use the ``aux_operator_values`` setter instead."""
self.aux_operator_values = value
10 changes: 5 additions & 5 deletions qiskit/algorithms/eigen_solvers/numpy_eigen_solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ def _get_energies(
aux_op_vals.append(
self._eval_aux_operators(aux_operators, self._ret.eigenstates[i])
)
self._ret.aux_operator_eigenvalues = aux_op_vals
self._ret.aux_operator_values = aux_op_vals

@staticmethod
def _eval_aux_operators(
Expand Down Expand Up @@ -240,23 +240,23 @@ def compute_eigenvalues(
for i in range(len(self._ret.eigenvalues)):
eigvec = self._ret.eigenstates[i]
eigval = self._ret.eigenvalues[i]
if self._ret.aux_operator_eigenvalues is not None:
aux_op = self._ret.aux_operator_eigenvalues[i]
if self._ret.aux_operator_values is not None:
aux_op = self._ret.aux_operator_values[i]
else:
aux_op = None
if self._filter_criterion(eigvec, eigval, aux_op):
cnt += 1
eigvecs += [eigvec]
eigvals += [eigval]
if self._ret.aux_operator_eigenvalues is not None:
if self._ret.aux_operator_values is not None:
aux_ops += [aux_op]
if cnt == k_orig:
break

self._ret.eigenstates = np.array(eigvecs)
self._ret.eigenvalues = np.array(eigvals)
# conversion to np.array breaks in case of aux_ops
self._ret.aux_operator_eigenvalues = aux_ops
self._ret.aux_operator_values = aux_ops

self._k = k_orig

Expand Down
41 changes: 36 additions & 5 deletions qiskit/algorithms/minimum_eigen_solvers/minimum_eigen_solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import numpy as np

from qiskit.opflow import OperatorBase
from qiskit.utils.deprecation import deprecate_function
from ..algorithm_result import AlgorithmResult
from ..list_or_dict import ListOrDict

Expand Down Expand Up @@ -73,7 +74,7 @@ def __init__(self) -> None:
super().__init__()
self._eigenvalue = None
self._eigenstate = None
self._aux_operator_eigenvalues = None
self._aux_operator_values = None

@property
def eigenvalue(self) -> Optional[complex]:
Expand All @@ -96,14 +97,44 @@ def eigenstate(self, value: np.ndarray) -> None:
self._eigenstate = value

@property
def aux_operator_eigenvalues(self) -> Optional[ListOrDict[Tuple[complex, complex]]]:
def aux_operator_values(self) -> Optional[ListOrDict[Tuple[complex, complex]]]:
"""Return aux operator expectation values.

These values are in fact tuples formatted as (mean, standard deviation).
"""
return self._aux_operator_eigenvalues
return self._aux_operator_values

@aux_operator_values.setter
def aux_operator_values(self, value: ListOrDict[Tuple[complex, complex]]) -> None:
"""set aux operator values"""
self._aux_operator_values = value

@property
@deprecate_function(
"""
The MinimumEigensolverResult.aux_operator_eigenvalues property is pending deprecation as of
Qiskit Terra 0.21.0. It will be deprecated in the release 0.22.0 and removed no sooner than 3 months
after that release date. You can use MinimumEigensolverResult.aux_operator_values as a direct
replacement instead, which reflects that these values are not eigenvalues of the operators but just
expectation values.
""",
pending_deprecation=True,
)
def aux_operator_eigenvalues(self) -> Optional[ListOrDict[Tuple[complex, complex]]]:
"""Pending deprecation. Use the ``aux_operator_values`` property instead."""
return self.aux_operator_values

@aux_operator_eigenvalues.setter
@deprecate_function(
"""
The MinimumEigensolverResult.aux_operator_eigenvalues setter is pending deprecation as of
Qiskit Terra 0.21.0. It will be deprecated in the release 0.22.0 and removed no sooner than 3 months
after that release date. You can use MinimumEigensolverResult.aux_operator_values as a direct
replacement instead, which reflects that these values are not eigenvalues of the operators but just
expectation values.
""",
pending_deprecation=True,
)
def aux_operator_eigenvalues(self, value: ListOrDict[Tuple[complex, complex]]) -> None:
"""set aux operator eigen values"""
self._aux_operator_eigenvalues = value
"""Pending deprecation. Use the ``aux_operator_values`` setter instead."""
self.aux_operator_values = value
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,8 @@ def compute_minimum_eigenvalue(
if result_ces.eigenvalues is not None and len(result_ces.eigenvalues) > 0:
self._ret.eigenvalue = result_ces.eigenvalues[0]
self._ret.eigenstate = result_ces.eigenstates[0]
if result_ces.aux_operator_eigenvalues:
self._ret.aux_operator_eigenvalues = result_ces.aux_operator_eigenvalues[0]
if result_ces.aux_operator_values:
self._ret.aux_operator_values = result_ces.aux_operator_values[0]

logger.debug("MinimumEigensolver:\n%s", self._ret)

Expand Down
2 changes: 1 addition & 1 deletion qiskit/algorithms/minimum_eigen_solvers/vqe.py
Original file line number Diff line number Diff line change
Expand Up @@ -589,7 +589,7 @@ def compute_minimum_eigenvalue(
aux_values = eval_observables(
self.quantum_instance, bound_ansatz, aux_operators, expectation=expectation
)
result.aux_operator_eigenvalues = aux_values
result.aux_operator_values = aux_values

return result

Expand Down
8 changes: 6 additions & 2 deletions qiskit/utils/deprecation.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,21 +31,25 @@ def wrapper(*args, **kwargs):
return decorator


def deprecate_function(msg, stacklevel=2):
def deprecate_function(msg, stacklevel=2, pending_deprecation=False):
"""Emit a warning prior to calling decorated function.

Args:
msg (str): Warning message to emit.
stacklevel (int): The warning stackevel to use, defaults to 2.
pending_deprecation (bool): If True emit a ``PendingDeprecationWarning``, else a
``DeprecationWarning``.

Returns:
Callable: The decorated, deprecated callable.
"""

deprecation_cls = PendingDeprecationWarning if pending_deprecation else DeprecationWarning

def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
warnings.warn(msg, DeprecationWarning, stacklevel=stacklevel)
warnings.warn(msg, deprecation_cls, stacklevel=stacklevel)
return func(*args, **kwargs)

return wrapper
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
deprecations:
- |
The ``aux_operator_eigenvalues`` attribute of the
:class:`~qiskit.algorithms.MinimumEigensolverResult` and :class:`~qiskit.algorithms.EigensolverResult`
are pending deprecation in favor of ``aux_operator_values``. This naming reflects that the
returned values are the expectation values of the auxiliary operators which are generally _not_
eigenvalues of these operators.
89 changes: 58 additions & 31 deletions test/python/algorithms/test_numpy_eigen_solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@
""" Test NumPy Eigen solver """

import unittest
import warnings
from test.python.algorithms import QiskitAlgorithmsTestCase

import numpy as np
from ddt import data, ddt

from qiskit.algorithms import NumPyEigensolver
from qiskit.algorithms import NumPyEigensolver, EigensolverResult
from qiskit.opflow import PauliSumOp, X, Y, Z


Expand Down Expand Up @@ -111,14 +112,14 @@ def test_aux_operators_list(self):
self.assertEqual(len(result.eigenstates), 1)
self.assertEqual(result.eigenvalues.dtype, np.float64)
self.assertAlmostEqual(result.eigenvalues[0], -1.85727503)
self.assertEqual(len(result.aux_operator_eigenvalues), 1)
self.assertEqual(len(result.aux_operator_eigenvalues[0]), 2)
self.assertEqual(len(result.aux_operator_values), 1)
self.assertEqual(len(result.aux_operator_values[0]), 2)
# expectation values
self.assertAlmostEqual(result.aux_operator_eigenvalues[0][0][0], 2, places=6)
self.assertAlmostEqual(result.aux_operator_eigenvalues[0][1][0], 0, places=6)
self.assertAlmostEqual(result.aux_operator_values[0][0][0], 2, places=6)
self.assertAlmostEqual(result.aux_operator_values[0][1][0], 0, places=6)
# standard deviations
self.assertAlmostEqual(result.aux_operator_eigenvalues[0][0][1], 0.0)
self.assertAlmostEqual(result.aux_operator_eigenvalues[0][1][1], 0.0)
self.assertAlmostEqual(result.aux_operator_values[0][0][1], 0.0)
self.assertAlmostEqual(result.aux_operator_values[0][1][1], 0.0)

# Go again with additional None and zero operators
extra_ops = [*aux_ops, None, 0]
Expand All @@ -127,17 +128,17 @@ def test_aux_operators_list(self):
self.assertEqual(len(result.eigenstates), 1)
self.assertEqual(result.eigenvalues.dtype, np.float64)
self.assertAlmostEqual(result.eigenvalues[0], -1.85727503)
self.assertEqual(len(result.aux_operator_eigenvalues), 1)
self.assertEqual(len(result.aux_operator_eigenvalues[0]), 4)
self.assertEqual(len(result.aux_operator_values), 1)
self.assertEqual(len(result.aux_operator_values[0]), 4)
# expectation values
self.assertAlmostEqual(result.aux_operator_eigenvalues[0][0][0], 2, places=6)
self.assertAlmostEqual(result.aux_operator_eigenvalues[0][1][0], 0, places=6)
self.assertIsNone(result.aux_operator_eigenvalues[0][2], None)
self.assertEqual(result.aux_operator_eigenvalues[0][3][0], 0.0)
self.assertAlmostEqual(result.aux_operator_values[0][0][0], 2, places=6)
self.assertAlmostEqual(result.aux_operator_values[0][1][0], 0, places=6)
self.assertIsNone(result.aux_operator_values[0][2], None)
self.assertEqual(result.aux_operator_values[0][3][0], 0.0)
# standard deviations
self.assertAlmostEqual(result.aux_operator_eigenvalues[0][0][1], 0.0)
self.assertAlmostEqual(result.aux_operator_eigenvalues[0][1][1], 0.0)
self.assertEqual(result.aux_operator_eigenvalues[0][3][1], 0.0)
self.assertAlmostEqual(result.aux_operator_values[0][0][1], 0.0)
self.assertAlmostEqual(result.aux_operator_values[0][1][1], 0.0)
self.assertEqual(result.aux_operator_values[0][3][1], 0.0)

def test_aux_operators_dict(self):
"""Test dict-based aux_operators."""
Expand All @@ -150,14 +151,14 @@ def test_aux_operators_dict(self):
self.assertEqual(len(result.eigenstates), 1)
self.assertEqual(result.eigenvalues.dtype, np.float64)
self.assertAlmostEqual(result.eigenvalues[0], -1.85727503)
self.assertEqual(len(result.aux_operator_eigenvalues), 1)
self.assertEqual(len(result.aux_operator_eigenvalues[0]), 2)
self.assertEqual(len(result.aux_operator_values), 1)
self.assertEqual(len(result.aux_operator_values[0]), 2)
# expectation values
self.assertAlmostEqual(result.aux_operator_eigenvalues[0]["aux_op1"][0], 2, places=6)
self.assertAlmostEqual(result.aux_operator_eigenvalues[0]["aux_op2"][0], 0, places=6)
self.assertAlmostEqual(result.aux_operator_values[0]["aux_op1"][0], 2, places=6)
self.assertAlmostEqual(result.aux_operator_values[0]["aux_op2"][0], 0, places=6)
# standard deviations
self.assertAlmostEqual(result.aux_operator_eigenvalues[0]["aux_op1"][1], 0.0)
self.assertAlmostEqual(result.aux_operator_eigenvalues[0]["aux_op2"][1], 0.0)
self.assertAlmostEqual(result.aux_operator_values[0]["aux_op1"][1], 0.0)
self.assertAlmostEqual(result.aux_operator_values[0]["aux_op2"][1], 0.0)

# Go again with additional None and zero operators
extra_ops = {**aux_ops, "None_operator": None, "zero_operator": 0}
Expand All @@ -166,17 +167,43 @@ def test_aux_operators_dict(self):
self.assertEqual(len(result.eigenstates), 1)
self.assertEqual(result.eigenvalues.dtype, np.float64)
self.assertAlmostEqual(result.eigenvalues[0], -1.85727503)
self.assertEqual(len(result.aux_operator_eigenvalues), 1)
self.assertEqual(len(result.aux_operator_eigenvalues[0]), 3)
self.assertEqual(len(result.aux_operator_values), 1)
self.assertEqual(len(result.aux_operator_values[0]), 3)
# expectation values
self.assertAlmostEqual(result.aux_operator_eigenvalues[0]["aux_op1"][0], 2, places=6)
self.assertAlmostEqual(result.aux_operator_eigenvalues[0]["aux_op2"][0], 0, places=6)
self.assertEqual(result.aux_operator_eigenvalues[0]["zero_operator"][0], 0.0)
self.assertTrue("None_operator" not in result.aux_operator_eigenvalues[0].keys())
self.assertAlmostEqual(result.aux_operator_values[0]["aux_op1"][0], 2, places=6)
self.assertAlmostEqual(result.aux_operator_values[0]["aux_op2"][0], 0, places=6)
self.assertEqual(result.aux_operator_values[0]["zero_operator"][0], 0.0)
self.assertTrue("None_operator" not in result.aux_operator_values[0].keys())
# standard deviations
self.assertAlmostEqual(result.aux_operator_eigenvalues[0]["aux_op1"][1], 0.0)
self.assertAlmostEqual(result.aux_operator_eigenvalues[0]["aux_op2"][1], 0.0)
self.assertAlmostEqual(result.aux_operator_eigenvalues[0]["zero_operator"][1], 0.0)
self.assertAlmostEqual(result.aux_operator_values[0]["aux_op1"][1], 0.0)
self.assertAlmostEqual(result.aux_operator_values[0]["aux_op2"][1], 0.0)
self.assertAlmostEqual(result.aux_operator_values[0]["zero_operator"][1], 0.0)

def test_deprecated_aux_operator_eigenvalues(self):
"""Test the deprecated aux_operator_eigenvalues getter and setter."""
result = EigensolverResult()
result.aux_operator_values = [[0, 1], [2, 3]]

with self.subTest(msg="Getter raises warning"):
with self.assertRaises(PendingDeprecationWarning):
_ = result.aux_operator_eigenvalues

with self.subTest(msg="Eigenvalues getter is correctly set"):
with warnings.catch_warnings():
warnings.filterwarnings("ignore", category=PendingDeprecationWarning)
self.assertListEqual(result.aux_operator_eigenvalues, [[0, 1], [2, 3]])

with self.subTest(msg="Setter raises warning"):
with self.assertRaises(PendingDeprecationWarning):
# note that this does NOT correctly set the values in this context manager
result.aux_operator_eigenvalues = [[2], [4]]

with self.subTest(msg="Deprecated eigenvalues setter works"):
with warnings.catch_warnings():
warnings.filterwarnings("ignore", category=PendingDeprecationWarning)
result.aux_operator_eigenvalues = [[2], [4]]

self.assertListEqual(result.aux_operator_values, [[2], [4]])


if __name__ == "__main__":
Expand Down
Loading