diff --git a/qiskit/algorithms/eigen_solvers/eigen_solver.py b/qiskit/algorithms/eigen_solvers/eigen_solver.py index 28ca3e9d1f8b..a02cbf876234 100644 --- a/qiskit/algorithms/eigen_solvers/eigen_solver.py +++ b/qiskit/algorithms/eigen_solvers/eigen_solver.py @@ -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 @@ -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]: @@ -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( + """ +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 diff --git a/qiskit/algorithms/eigen_solvers/numpy_eigen_solver.py b/qiskit/algorithms/eigen_solvers/numpy_eigen_solver.py index 4abbe7ed4a26..a612fcd4c1f0 100755 --- a/qiskit/algorithms/eigen_solvers/numpy_eigen_solver.py +++ b/qiskit/algorithms/eigen_solvers/numpy_eigen_solver.py @@ -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( @@ -240,15 +240,15 @@ 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 @@ -256,7 +256,7 @@ def compute_eigenvalues( 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 diff --git a/qiskit/algorithms/minimum_eigen_solvers/minimum_eigen_solver.py b/qiskit/algorithms/minimum_eigen_solvers/minimum_eigen_solver.py index 7cdd245b7076..4474fc9f90aa 100644 --- a/qiskit/algorithms/minimum_eigen_solvers/minimum_eigen_solver.py +++ b/qiskit/algorithms/minimum_eigen_solvers/minimum_eigen_solver.py @@ -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 @@ -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]: @@ -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 diff --git a/qiskit/algorithms/minimum_eigen_solvers/numpy_minimum_eigen_solver.py b/qiskit/algorithms/minimum_eigen_solvers/numpy_minimum_eigen_solver.py index 5515ba92d745..bc7aff1f5ad1 100644 --- a/qiskit/algorithms/minimum_eigen_solvers/numpy_minimum_eigen_solver.py +++ b/qiskit/algorithms/minimum_eigen_solvers/numpy_minimum_eigen_solver.py @@ -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) diff --git a/qiskit/algorithms/minimum_eigen_solvers/vqe.py b/qiskit/algorithms/minimum_eigen_solvers/vqe.py index 36b1ce4878b4..71b8cf14a6ea 100755 --- a/qiskit/algorithms/minimum_eigen_solvers/vqe.py +++ b/qiskit/algorithms/minimum_eigen_solvers/vqe.py @@ -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 diff --git a/qiskit/utils/deprecation.py b/qiskit/utils/deprecation.py index 1a73803ab4f3..1688f1d101e8 100644 --- a/qiskit/utils/deprecation.py +++ b/qiskit/utils/deprecation.py @@ -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 diff --git a/releasenotes/notes/rename-eigensolvers-auxops-values-d91051b00f46acc8.yaml b/releasenotes/notes/rename-eigensolvers-auxops-values-d91051b00f46acc8.yaml new file mode 100644 index 000000000000..401404f0835f --- /dev/null +++ b/releasenotes/notes/rename-eigensolvers-auxops-values-d91051b00f46acc8.yaml @@ -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. diff --git a/test/python/algorithms/test_numpy_eigen_solver.py b/test/python/algorithms/test_numpy_eigen_solver.py index d2a918a8acff..7d7c72ca9241 100644 --- a/test/python/algorithms/test_numpy_eigen_solver.py +++ b/test/python/algorithms/test_numpy_eigen_solver.py @@ -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 @@ -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] @@ -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.""" @@ -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} @@ -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__": diff --git a/test/python/algorithms/test_numpy_minimum_eigen_solver.py b/test/python/algorithms/test_numpy_minimum_eigen_solver.py index 6523e3d10e75..27854a4553db 100644 --- a/test/python/algorithms/test_numpy_minimum_eigen_solver.py +++ b/test/python/algorithms/test_numpy_minimum_eigen_solver.py @@ -13,6 +13,7 @@ """ Test NumPy Minimum Eigensolver """ import unittest +import warnings from test.python.algorithms import QiskitAlgorithmsTestCase import numpy as np @@ -50,9 +51,17 @@ def test_cme(self): operator=self.qubit_op, aux_operators=self.aux_ops_list ) self.assertAlmostEqual(result.eigenvalue, -1.85727503 + 0j) - self.assertEqual(len(result.aux_operator_eigenvalues), 2) - np.testing.assert_array_almost_equal(result.aux_operator_eigenvalues[0], [2, 0]) - np.testing.assert_array_almost_equal(result.aux_operator_eigenvalues[1], [0, 0]) + self.assertEqual(len(result.aux_operator_values), 2) + + with self.subTest(msg="Test aux_operator_values"): + np.testing.assert_array_almost_equal(result.aux_operator_values[0], [2, 0]) + np.testing.assert_array_almost_equal(result.aux_operator_values[1], [0, 0]) + + with self.subTest(msg="Test deprecated aux_operator_eigenvalues"): + with warnings.catch_warnings(): + warnings.filterwarnings("ignore", category=PendingDeprecationWarning) + np.testing.assert_array_almost_equal(result.aux_operator_eigenvalues[0], [2, 0]) + np.testing.assert_array_almost_equal(result.aux_operator_eigenvalues[1], [0, 0]) def test_cme_reuse(self): """Test reuse""" @@ -61,36 +70,36 @@ def test_cme_reuse(self): result = algo.compute_minimum_eigenvalue(operator=self.qubit_op) self.assertEqual(result.eigenvalue.dtype, np.float64) self.assertAlmostEqual(result.eigenvalue, -1.85727503) - self.assertIsNone(result.aux_operator_eigenvalues) + self.assertIsNone(result.aux_operator_values) # Add aux_operators and go again result = algo.compute_minimum_eigenvalue( operator=self.qubit_op, aux_operators=self.aux_ops_list ) self.assertAlmostEqual(result.eigenvalue, -1.85727503 + 0j) - self.assertEqual(len(result.aux_operator_eigenvalues), 2) - np.testing.assert_array_almost_equal(result.aux_operator_eigenvalues[0], [2, 0]) - np.testing.assert_array_almost_equal(result.aux_operator_eigenvalues[1], [0, 0]) + self.assertEqual(len(result.aux_operator_values), 2) + np.testing.assert_array_almost_equal(result.aux_operator_values[0], [2, 0]) + np.testing.assert_array_almost_equal(result.aux_operator_values[1], [0, 0]) # "Remove" aux_operators and go again result = algo.compute_minimum_eigenvalue(operator=self.qubit_op, aux_operators=[]) self.assertEqual(result.eigenvalue.dtype, np.float64) self.assertAlmostEqual(result.eigenvalue, -1.85727503) - self.assertIsNone(result.aux_operator_eigenvalues) + self.assertIsNone(result.aux_operator_values) # Set aux_operators and go again result = algo.compute_minimum_eigenvalue( operator=self.qubit_op, aux_operators=self.aux_ops_list ) self.assertAlmostEqual(result.eigenvalue, -1.85727503 + 0j) - self.assertEqual(len(result.aux_operator_eigenvalues), 2) - np.testing.assert_array_almost_equal(result.aux_operator_eigenvalues[0], [2, 0]) - np.testing.assert_array_almost_equal(result.aux_operator_eigenvalues[1], [0, 0]) + self.assertEqual(len(result.aux_operator_values), 2) + np.testing.assert_array_almost_equal(result.aux_operator_values[0], [2, 0]) + np.testing.assert_array_almost_equal(result.aux_operator_values[1], [0, 0]) # Finally just set one of aux_operators and main operator, remove aux_operators result = algo.compute_minimum_eigenvalue(operator=self.aux_ops_list[0], aux_operators=[]) self.assertAlmostEqual(result.eigenvalue, 2 + 0j) - self.assertIsNone(result.aux_operator_eigenvalues) + self.assertIsNone(result.aux_operator_values) def test_cme_filter(self): """Basic test""" @@ -105,9 +114,9 @@ def criterion(x, v, a_v): operator=self.qubit_op, aux_operators=self.aux_ops_list ) self.assertAlmostEqual(result.eigenvalue, -0.22491125 + 0j) - self.assertEqual(len(result.aux_operator_eigenvalues), 2) - np.testing.assert_array_almost_equal(result.aux_operator_eigenvalues[0], [2, 0]) - np.testing.assert_array_almost_equal(result.aux_operator_eigenvalues[1], [0, 0]) + self.assertEqual(len(result.aux_operator_values), 2) + np.testing.assert_array_almost_equal(result.aux_operator_values[0], [2, 0]) + np.testing.assert_array_almost_equal(result.aux_operator_values[1], [0, 0]) def test_cme_filter_empty(self): """Test with filter always returning False""" @@ -123,7 +132,7 @@ def criterion(x, v, a_v): ) self.assertEqual(result.eigenvalue, None) self.assertEqual(result.eigenstate, None) - self.assertEqual(result.aux_operator_eigenvalues, None) + self.assertEqual(result.aux_operator_values, None) @data(X, Y, Z) def test_cme_1q(self, op): @@ -138,25 +147,25 @@ def test_cme_aux_ops_dict(self): algo = NumPyMinimumEigensolver() result = algo.compute_minimum_eigenvalue(operator=self.qubit_op, aux_operators={}) self.assertAlmostEqual(result.eigenvalue, -1.85727503 + 0j) - self.assertIsNone(result.aux_operator_eigenvalues) + self.assertIsNone(result.aux_operator_values) # Add aux_operators dictionary and go again result = algo.compute_minimum_eigenvalue( operator=self.qubit_op, aux_operators=self.aux_ops_dict ) self.assertAlmostEqual(result.eigenvalue, -1.85727503 + 0j) - self.assertEqual(len(result.aux_operator_eigenvalues), 2) - np.testing.assert_array_almost_equal(result.aux_operator_eigenvalues["aux_op1"], [2, 0]) - np.testing.assert_array_almost_equal(result.aux_operator_eigenvalues["aux_op2"], [0, 0]) + self.assertEqual(len(result.aux_operator_values), 2) + np.testing.assert_array_almost_equal(result.aux_operator_values["aux_op1"], [2, 0]) + np.testing.assert_array_almost_equal(result.aux_operator_values["aux_op2"], [0, 0]) # Add None and zero operators and go again extra_ops = {"None_op": None, "zero_op": 0, **self.aux_ops_dict} result = algo.compute_minimum_eigenvalue(operator=self.qubit_op, aux_operators=extra_ops) self.assertAlmostEqual(result.eigenvalue, -1.85727503 + 0j) - self.assertEqual(len(result.aux_operator_eigenvalues), 3) - np.testing.assert_array_almost_equal(result.aux_operator_eigenvalues["aux_op1"], [2, 0]) - np.testing.assert_array_almost_equal(result.aux_operator_eigenvalues["aux_op2"], [0, 0]) - self.assertEqual(result.aux_operator_eigenvalues["zero_op"], (0.0, 0)) + self.assertEqual(len(result.aux_operator_values), 3) + np.testing.assert_array_almost_equal(result.aux_operator_values["aux_op1"], [2, 0]) + np.testing.assert_array_almost_equal(result.aux_operator_values["aux_op2"], [0, 0]) + self.assertEqual(result.aux_operator_values["zero_op"], (0.0, 0)) def test_aux_operators_list(self): """Test list-based aux_operators.""" @@ -166,28 +175,28 @@ def test_aux_operators_list(self): algo = NumPyMinimumEigensolver() result = algo.compute_minimum_eigenvalue(operator=self.qubit_op, aux_operators=aux_ops) self.assertAlmostEqual(result.eigenvalue, -1.85727503 + 0j) - self.assertEqual(len(result.aux_operator_eigenvalues), 2) + self.assertEqual(len(result.aux_operator_values), 2) # expectation values - self.assertAlmostEqual(result.aux_operator_eigenvalues[0][0], 2, places=6) - self.assertAlmostEqual(result.aux_operator_eigenvalues[1][0], 0, places=6) + self.assertAlmostEqual(result.aux_operator_values[0][0], 2, places=6) + self.assertAlmostEqual(result.aux_operator_values[1][0], 0, places=6) # standard deviations - self.assertAlmostEqual(result.aux_operator_eigenvalues[0][1], 0.0) - self.assertAlmostEqual(result.aux_operator_eigenvalues[1][1], 0.0) + self.assertAlmostEqual(result.aux_operator_values[0][1], 0.0) + self.assertAlmostEqual(result.aux_operator_values[1][1], 0.0) # Go again with additional None and zero operators extra_ops = [*aux_ops, None, 0] result = algo.compute_minimum_eigenvalue(operator=self.qubit_op, aux_operators=extra_ops) self.assertAlmostEqual(result.eigenvalue, -1.85727503 + 0j) - self.assertEqual(len(result.aux_operator_eigenvalues), 4) + self.assertEqual(len(result.aux_operator_values), 4) # expectation values - self.assertAlmostEqual(result.aux_operator_eigenvalues[0][0], 2, places=6) - self.assertAlmostEqual(result.aux_operator_eigenvalues[1][0], 0, places=6) - self.assertIsNone(result.aux_operator_eigenvalues[2], None) - self.assertEqual(result.aux_operator_eigenvalues[3][0], 0.0) + self.assertAlmostEqual(result.aux_operator_values[0][0], 2, places=6) + self.assertAlmostEqual(result.aux_operator_values[1][0], 0, places=6) + self.assertIsNone(result.aux_operator_values[2], None) + self.assertEqual(result.aux_operator_values[3][0], 0.0) # standard deviations - self.assertAlmostEqual(result.aux_operator_eigenvalues[0][1], 0.0) - self.assertAlmostEqual(result.aux_operator_eigenvalues[1][1], 0.0) - self.assertEqual(result.aux_operator_eigenvalues[3][1], 0.0) + self.assertAlmostEqual(result.aux_operator_values[0][1], 0.0) + self.assertAlmostEqual(result.aux_operator_values[1][1], 0.0) + self.assertEqual(result.aux_operator_values[3][1], 0.0) def test_aux_operators_dict(self): """Test dict-based aux_operators.""" @@ -197,28 +206,28 @@ def test_aux_operators_dict(self): algo = NumPyMinimumEigensolver() result = algo.compute_minimum_eigenvalue(operator=self.qubit_op, aux_operators=aux_ops) self.assertAlmostEqual(result.eigenvalue, -1.85727503 + 0j) - self.assertEqual(len(result.aux_operator_eigenvalues), 2) + self.assertEqual(len(result.aux_operator_values), 2) # expectation values - self.assertAlmostEqual(result.aux_operator_eigenvalues["aux_op1"][0], 2, places=6) - self.assertAlmostEqual(result.aux_operator_eigenvalues["aux_op2"][0], 0, places=6) + self.assertAlmostEqual(result.aux_operator_values["aux_op1"][0], 2, places=6) + self.assertAlmostEqual(result.aux_operator_values["aux_op2"][0], 0, places=6) # standard deviations - self.assertAlmostEqual(result.aux_operator_eigenvalues["aux_op1"][1], 0.0) - self.assertAlmostEqual(result.aux_operator_eigenvalues["aux_op2"][1], 0.0) + self.assertAlmostEqual(result.aux_operator_values["aux_op1"][1], 0.0) + self.assertAlmostEqual(result.aux_operator_values["aux_op2"][1], 0.0) # Go again with additional None and zero operators extra_ops = {**aux_ops, "None_operator": None, "zero_operator": 0} result = algo.compute_minimum_eigenvalue(operator=self.qubit_op, aux_operators=extra_ops) self.assertAlmostEqual(result.eigenvalue, -1.85727503 + 0j) - self.assertEqual(len(result.aux_operator_eigenvalues), 3) + self.assertEqual(len(result.aux_operator_values), 3) # expectation values - self.assertAlmostEqual(result.aux_operator_eigenvalues["aux_op1"][0], 2, places=6) - self.assertAlmostEqual(result.aux_operator_eigenvalues["aux_op2"][0], 0, places=6) - self.assertEqual(result.aux_operator_eigenvalues["zero_operator"][0], 0.0) - self.assertTrue("None_operator" not in result.aux_operator_eigenvalues.keys()) + self.assertAlmostEqual(result.aux_operator_values["aux_op1"][0], 2, places=6) + self.assertAlmostEqual(result.aux_operator_values["aux_op2"][0], 0, places=6) + self.assertEqual(result.aux_operator_values["zero_operator"][0], 0.0) + self.assertTrue("None_operator" not in result.aux_operator_values.keys()) # standard deviations - self.assertAlmostEqual(result.aux_operator_eigenvalues["aux_op1"][1], 0.0) - self.assertAlmostEqual(result.aux_operator_eigenvalues["aux_op2"][1], 0.0) - self.assertAlmostEqual(result.aux_operator_eigenvalues["zero_operator"][1], 0.0) + self.assertAlmostEqual(result.aux_operator_values["aux_op1"][1], 0.0) + self.assertAlmostEqual(result.aux_operator_values["aux_op2"][1], 0.0) + self.assertAlmostEqual(result.aux_operator_values["zero_operator"][1], 0.0) if __name__ == "__main__": diff --git a/test/python/algorithms/test_vqe.py b/test/python/algorithms/test_vqe.py index ae1d57824712..ea2ca81dca56 100644 --- a/test/python/algorithms/test_vqe.py +++ b/test/python/algorithms/test_vqe.py @@ -14,6 +14,7 @@ import logging import unittest +import warnings from test.python.algorithms import QiskitAlgorithmsTestCase from test.python.transpiler._dummy_passes import DummyAP @@ -23,7 +24,7 @@ from ddt import data, ddt, unpack from qiskit import BasicAer, QuantumCircuit -from qiskit.algorithms import VQE, AlgorithmError +from qiskit.algorithms import VQE, VQEResult, AlgorithmError from qiskit.algorithms.optimizers import ( CG, COBYLA, @@ -527,7 +528,7 @@ def test_aux_operators_list(self): # Start with an empty list result = vqe.compute_minimum_eigenvalue(self.h2_op, aux_operators=[]) self.assertAlmostEqual(result.eigenvalue.real, self.h2_energy, places=6) - self.assertIsNone(result.aux_operator_eigenvalues) + self.assertIsNone(result.aux_operator_values) # Go again with two auxiliary operators aux_op1 = PauliSumOp.from_list([("II", 2.0)]) @@ -535,29 +536,29 @@ def test_aux_operators_list(self): aux_ops = [aux_op1, aux_op2] result = vqe.compute_minimum_eigenvalue(self.h2_op, aux_operators=aux_ops) self.assertAlmostEqual(result.eigenvalue.real, self.h2_energy, places=6) - self.assertEqual(len(result.aux_operator_eigenvalues), 2) + self.assertEqual(len(result.aux_operator_values), 2) # expectation values - self.assertAlmostEqual(result.aux_operator_eigenvalues[0][0], 2, places=6) - self.assertAlmostEqual(result.aux_operator_eigenvalues[1][0], 0, places=6) + self.assertAlmostEqual(result.aux_operator_values[0][0], 2, places=6) + self.assertAlmostEqual(result.aux_operator_values[1][0], 0, places=6) # standard deviations - self.assertAlmostEqual(result.aux_operator_eigenvalues[0][1], 0.0) - self.assertAlmostEqual(result.aux_operator_eigenvalues[1][1], 0.0) + self.assertAlmostEqual(result.aux_operator_values[0][1], 0.0) + self.assertAlmostEqual(result.aux_operator_values[1][1], 0.0) # Go again with additional None and zero operators extra_ops = [*aux_ops, None, 0] result = vqe.compute_minimum_eigenvalue(self.h2_op, aux_operators=extra_ops) self.assertAlmostEqual(result.eigenvalue.real, self.h2_energy, places=6) - self.assertEqual(len(result.aux_operator_eigenvalues), 4) + self.assertEqual(len(result.aux_operator_values), 4) # expectation values - self.assertAlmostEqual(result.aux_operator_eigenvalues[0][0], 2, places=6) - self.assertAlmostEqual(result.aux_operator_eigenvalues[1][0], 0, places=6) - self.assertEqual(result.aux_operator_eigenvalues[2][0], 0.0) - self.assertEqual(result.aux_operator_eigenvalues[3][0], 0.0) + self.assertAlmostEqual(result.aux_operator_values[0][0], 2, places=6) + self.assertAlmostEqual(result.aux_operator_values[1][0], 0, places=6) + self.assertEqual(result.aux_operator_values[2][0], 0.0) + self.assertEqual(result.aux_operator_values[3][0], 0.0) # standard deviations - self.assertAlmostEqual(result.aux_operator_eigenvalues[0][1], 0.0) - self.assertAlmostEqual(result.aux_operator_eigenvalues[1][1], 0.0) - self.assertAlmostEqual(result.aux_operator_eigenvalues[2][1], 0.0) - self.assertAlmostEqual(result.aux_operator_eigenvalues[3][1], 0.0) + self.assertAlmostEqual(result.aux_operator_values[0][1], 0.0) + self.assertAlmostEqual(result.aux_operator_values[1][1], 0.0) + self.assertAlmostEqual(result.aux_operator_values[2][1], 0.0) + self.assertAlmostEqual(result.aux_operator_values[3][1], 0.0) def test_aux_operators_dict(self): """Test dictionary compatibility of aux_operators""" @@ -567,7 +568,7 @@ def test_aux_operators_dict(self): # Start with an empty dictionary result = vqe.compute_minimum_eigenvalue(self.h2_op, aux_operators={}) self.assertAlmostEqual(result.eigenvalue.real, self.h2_energy, places=6) - self.assertIsNone(result.aux_operator_eigenvalues) + self.assertIsNone(result.aux_operator_values) # Go again with two auxiliary operators aux_op1 = PauliSumOp.from_list([("II", 2.0)]) @@ -575,28 +576,28 @@ def test_aux_operators_dict(self): aux_ops = {"aux_op1": aux_op1, "aux_op2": aux_op2} result = vqe.compute_minimum_eigenvalue(self.h2_op, aux_operators=aux_ops) self.assertAlmostEqual(result.eigenvalue.real, self.h2_energy, places=6) - self.assertEqual(len(result.aux_operator_eigenvalues), 2) + self.assertEqual(len(result.aux_operator_values), 2) # expectation values - self.assertAlmostEqual(result.aux_operator_eigenvalues["aux_op1"][0], 2, places=6) - self.assertAlmostEqual(result.aux_operator_eigenvalues["aux_op2"][0], 0, places=6) + self.assertAlmostEqual(result.aux_operator_values["aux_op1"][0], 2, places=6) + self.assertAlmostEqual(result.aux_operator_values["aux_op2"][0], 0, places=6) # standard deviations - self.assertAlmostEqual(result.aux_operator_eigenvalues["aux_op1"][1], 0.0) - self.assertAlmostEqual(result.aux_operator_eigenvalues["aux_op2"][1], 0.0) + self.assertAlmostEqual(result.aux_operator_values["aux_op1"][1], 0.0) + self.assertAlmostEqual(result.aux_operator_values["aux_op2"][1], 0.0) # Go again with additional None and zero operators extra_ops = {**aux_ops, "None_operator": None, "zero_operator": 0} result = vqe.compute_minimum_eigenvalue(self.h2_op, aux_operators=extra_ops) self.assertAlmostEqual(result.eigenvalue.real, self.h2_energy, places=6) - self.assertEqual(len(result.aux_operator_eigenvalues), 3) + self.assertEqual(len(result.aux_operator_values), 3) # expectation values - self.assertAlmostEqual(result.aux_operator_eigenvalues["aux_op1"][0], 2, places=6) - self.assertAlmostEqual(result.aux_operator_eigenvalues["aux_op2"][0], 0, places=6) - self.assertEqual(result.aux_operator_eigenvalues["zero_operator"][0], 0.0) - self.assertTrue("None_operator" not in result.aux_operator_eigenvalues.keys()) + self.assertAlmostEqual(result.aux_operator_values["aux_op1"][0], 2, places=6) + self.assertAlmostEqual(result.aux_operator_values["aux_op2"][0], 0, places=6) + self.assertEqual(result.aux_operator_values["zero_operator"][0], 0.0) + self.assertTrue("None_operator" not in result.aux_operator_values.keys()) # standard deviations - self.assertAlmostEqual(result.aux_operator_eigenvalues["aux_op1"][1], 0.0) - self.assertAlmostEqual(result.aux_operator_eigenvalues["aux_op2"][1], 0.0) - self.assertAlmostEqual(result.aux_operator_eigenvalues["zero_operator"][1], 0.0) + self.assertAlmostEqual(result.aux_operator_values["aux_op1"][1], 0.0) + self.assertAlmostEqual(result.aux_operator_values["aux_op2"][1], 0.0) + self.assertAlmostEqual(result.aux_operator_values["zero_operator"][1], 0.0) def test_aux_operator_std_dev_pauli(self): """Test non-zero standard deviations of aux operators with PauliExpectation.""" @@ -613,30 +614,28 @@ def test_aux_operator_std_dev_pauli(self): aux_op2 = PauliSumOp.from_list([("II", 0.5), ("ZZ", 0.5), ("YY", 0.5), ("XX", -0.5)]) aux_ops = [aux_op1, aux_op2] result = vqe.compute_minimum_eigenvalue(self.h2_op, aux_operators=aux_ops) - self.assertEqual(len(result.aux_operator_eigenvalues), 2) + self.assertEqual(len(result.aux_operator_values), 2) # expectation values - self.assertAlmostEqual(result.aux_operator_eigenvalues[0][0], 2.0, places=6) - self.assertAlmostEqual(result.aux_operator_eigenvalues[1][0], 0.6796875, places=6) + self.assertAlmostEqual(result.aux_operator_values[0][0], 2.0, places=6) + self.assertAlmostEqual(result.aux_operator_values[1][0], 0.6796875, places=6) # standard deviations - self.assertAlmostEqual(result.aux_operator_eigenvalues[0][1], 0.0) - self.assertAlmostEqual(result.aux_operator_eigenvalues[1][1], 0.02534712219145965, places=6) + self.assertAlmostEqual(result.aux_operator_values[0][1], 0.0) + self.assertAlmostEqual(result.aux_operator_values[1][1], 0.02534712219145965, places=6) # Go again with additional None and zero operators aux_ops = [*aux_ops, None, 0] result = vqe.compute_minimum_eigenvalue(self.h2_op, aux_operators=aux_ops) - self.assertEqual(len(result.aux_operator_eigenvalues), 4) + self.assertEqual(len(result.aux_operator_values), 4) # expectation values - self.assertAlmostEqual(result.aux_operator_eigenvalues[0][0], 2.0, places=6) - self.assertAlmostEqual(result.aux_operator_eigenvalues[1][0], 0.57421875, places=6) - self.assertEqual(result.aux_operator_eigenvalues[2][0], 0.0) - self.assertEqual(result.aux_operator_eigenvalues[3][0], 0.0) + self.assertAlmostEqual(result.aux_operator_values[0][0], 2.0, places=6) + self.assertAlmostEqual(result.aux_operator_values[1][0], 0.57421875, places=6) + self.assertEqual(result.aux_operator_values[2][0], 0.0) + self.assertEqual(result.aux_operator_values[3][0], 0.0) # # standard deviations - self.assertAlmostEqual(result.aux_operator_eigenvalues[0][1], 0.0) - self.assertAlmostEqual( - result.aux_operator_eigenvalues[1][1], 0.026562146577166837, places=6 - ) - self.assertAlmostEqual(result.aux_operator_eigenvalues[2][1], 0.0) - self.assertAlmostEqual(result.aux_operator_eigenvalues[3][1], 0.0) + self.assertAlmostEqual(result.aux_operator_values[0][1], 0.0) + self.assertAlmostEqual(result.aux_operator_values[1][1], 0.026562146577166837, places=6) + self.assertAlmostEqual(result.aux_operator_values[2][1], 0.0) + self.assertAlmostEqual(result.aux_operator_values[3][1], 0.0) @unittest.skipUnless(has_aer(), "qiskit-aer doesn't appear to be installed.") def test_aux_operator_std_dev_aer_pauli(self): @@ -659,28 +658,28 @@ def test_aux_operator_std_dev_aer_pauli(self): aux_op2 = PauliSumOp.from_list([("II", 0.5), ("ZZ", 0.5), ("YY", 0.5), ("XX", -0.5)]) aux_ops = [aux_op1, aux_op2] result = vqe.compute_minimum_eigenvalue(self.h2_op, aux_operators=aux_ops) - self.assertEqual(len(result.aux_operator_eigenvalues), 2) + self.assertEqual(len(result.aux_operator_values), 2) # expectation values - self.assertAlmostEqual(result.aux_operator_eigenvalues[0][0], 2.0, places=6) - self.assertAlmostEqual(result.aux_operator_eigenvalues[1][0], 0.6698863565455391, places=6) + self.assertAlmostEqual(result.aux_operator_values[0][0], 2.0, places=6) + self.assertAlmostEqual(result.aux_operator_values[1][0], 0.6698863565455391, places=6) # standard deviations - self.assertAlmostEqual(result.aux_operator_eigenvalues[0][1], 0.0) - self.assertAlmostEqual(result.aux_operator_eigenvalues[1][1], 0.0, places=6) + self.assertAlmostEqual(result.aux_operator_values[0][1], 0.0) + self.assertAlmostEqual(result.aux_operator_values[1][1], 0.0, places=6) # Go again with additional None and zero operators aux_ops = [*aux_ops, None, 0] result = vqe.compute_minimum_eigenvalue(self.h2_op, aux_operators=aux_ops) - self.assertEqual(len(result.aux_operator_eigenvalues), 4) + self.assertEqual(len(result.aux_operator_values), 4) # expectation values - self.assertAlmostEqual(result.aux_operator_eigenvalues[0][0], 2.0, places=6) - self.assertAlmostEqual(result.aux_operator_eigenvalues[1][0], 0.6036400943063891, places=6) - self.assertEqual(result.aux_operator_eigenvalues[2][0], 0.0) - self.assertEqual(result.aux_operator_eigenvalues[3][0], 0.0) + self.assertAlmostEqual(result.aux_operator_values[0][0], 2.0, places=6) + self.assertAlmostEqual(result.aux_operator_values[1][0], 0.6036400943063891, places=6) + self.assertEqual(result.aux_operator_values[2][0], 0.0) + self.assertEqual(result.aux_operator_values[3][0], 0.0) # standard deviations - self.assertAlmostEqual(result.aux_operator_eigenvalues[0][1], 0.0) - self.assertAlmostEqual(result.aux_operator_eigenvalues[1][1], 0.0, places=6) - self.assertAlmostEqual(result.aux_operator_eigenvalues[2][1], 0.0) - self.assertAlmostEqual(result.aux_operator_eigenvalues[3][1], 0.0) + self.assertAlmostEqual(result.aux_operator_values[0][1], 0.0) + self.assertAlmostEqual(result.aux_operator_values[1][1], 0.0, places=6) + self.assertAlmostEqual(result.aux_operator_values[2][1], 0.0) + self.assertAlmostEqual(result.aux_operator_values[3][1], 0.0) def test_2step_transpile(self): """Test the two-step transpiler pass.""" @@ -742,6 +741,32 @@ def test_construct_eigenstate_from_optpoint(self): optimal_circuit = vqe.ansatz.bind_parameters(result.optimal_point) self.assertTrue(Statevector(result.eigenstate).equiv(optimal_circuit)) + def test_deprecated_aux_operator_eigenvalues(self): + """Test the deprecated aux_operator_eigenvalues getter and setter.""" + result = VQEResult() + result.aux_operator_values = [0, 1, 2] + + 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]) + + 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__": unittest.main()