diff --git a/qiskit_aer/primitives/estimator.py b/qiskit_aer/primitives/estimator.py index 65d87231c5..63593b2359 100644 --- a/qiskit_aer/primitives/estimator.py +++ b/qiskit_aer/primitives/estimator.py @@ -32,6 +32,7 @@ from qiskit.quantum_info import Pauli, PauliList from qiskit.quantum_info.operators.base_operator import BaseOperator from qiskit.result.models import ExperimentResult +from qiskit.utils import deprecate_arg, deprecate_func from .. import AerError, AerSimulator @@ -68,6 +69,12 @@ class Estimator(BaseEstimator): normal distribution approximation. """ + @deprecate_arg( + "approximation", + since=0.13, + package_name="qiskit-aer", + additional_msg="approximation=True will be default in the future.", + ) def __init__( self, *, @@ -100,7 +107,15 @@ def __init__( self._transpile_options = Options() if transpile_options is not None: self._transpile_options.update_options(**transpile_options) - self.approximation = approximation + if not approximation: + warn( + "Option approximation=False is deprecated as of qiskit-aer 0.13. " + "It will be removed no earlier than 3 months after the release date. " + "Instead, use BackendEstmator from qiskit.primitives.", + DeprecationWarning, + stacklevel=3, + ) + self._approximation = approximation self._skip_transpilation = skip_transpilation self._cache: dict[tuple[tuple[int], tuple[int], bool], tuple[dict, dict]] = {} self._transpiled_circuits: dict[int, QuantumCircuit] = {} @@ -109,6 +124,34 @@ def __init__( self._observable_ids: dict[tuple, int] = {} self._abelian_grouping = abelian_grouping + @property + @deprecate_func( + since=0.13, + package_name="qiskit-aer", + is_property=True, + ) + def approximation(self): + """The approximation property""" + return self._approximation + + @approximation.setter + @deprecate_func( + since=0.13, + package_name="qiskit-aer", + is_property=True, + ) + def approximation(self, approximation): + """Setter for approximation""" + if not approximation: + warn( + "Option approximation=False is deprecated as of qiskit-aer 0.13. " + "It will be removed no earlier than 3 months after the release date. " + "Instead, use BackendEstmator from qiskit.primitives.", + DeprecationWarning, + stacklevel=3, + ) + self._approximation = approximation + def _call( self, circuits: Sequence[int], @@ -120,7 +163,7 @@ def _call( if seed is not None: run_options.setdefault("seed_simulator", seed) - if self.approximation: + if self._approximation: return self._compute_with_approximation( circuits, observables, parameter_values, run_options, seed ) @@ -174,7 +217,7 @@ def _compute(self, circuits, observables, parameter_values, run_options): ) # Key for cache - key = (tuple(circuits), tuple(observables), self.approximation) + key = (tuple(circuits), tuple(observables), self._approximation) # Create expectation value experiments. if key in self._cache: # Use a cache @@ -363,7 +406,7 @@ def _compute_with_approximation( self, circuits, observables, parameter_values, run_options, seed ): # Key for cache - key = (tuple(circuits), tuple(observables), self.approximation) + key = (tuple(circuits), tuple(observables), self._approximation) shots = run_options.pop("shots", None) # Create expectation value experiments. diff --git a/test/terra/primitives/test_estimator.py b/test/terra/primitives/test_estimator.py index 399ab43f5b..8a3e080080 100644 --- a/test/terra/primitives/test_estimator.py +++ b/test/terra/primitives/test_estimator.py @@ -69,9 +69,10 @@ def test_estimator(self, abelian_grouping): with self.subTest("SparsePauliOp"): observable = SparsePauliOp.from_list(lst) ansatz = RealAmplitudes(num_qubits=2, reps=2) - est = Estimator( - backend_options={"method": "statevector"}, abelian_grouping=abelian_grouping - ) + with self.assertWarns(DeprecationWarning): + est = Estimator( + backend_options={"method": "statevector"}, abelian_grouping=abelian_grouping + ) result = est.run( ansatz, observable, parameter_values=[[0, 1, 1, 2, 3, 5]], seed=15 ).result() @@ -88,9 +89,10 @@ def test_estimator(self, abelian_grouping): ] ) ansatz = RealAmplitudes(num_qubits=2, reps=2) - est = Estimator( - backend_options={"method": "statevector"}, abelian_grouping=abelian_grouping - ) + with self.assertWarns(DeprecationWarning): + est = Estimator( + backend_options={"method": "statevector"}, abelian_grouping=abelian_grouping + ) result = est.run(ansatz, observable, parameter_values=[[0] * 6], seed=15).result() self.assertIsInstance(result, EstimatorResult) np.testing.assert_allclose(result.values, [-0.4], rtol=0.02) @@ -107,7 +109,8 @@ def test_init_observable_from_operator(self, abelian_grouping): [0.1809312, 0.0, 0.0, -1.06365335], ] ) - est = Estimator(abelian_grouping=abelian_grouping) + with self.assertWarns(DeprecationWarning): + est = Estimator(abelian_grouping=abelian_grouping) result = est.run([circuit], [matrix], seed=15, shots=8192).result() self.assertIsInstance(result, EstimatorResult) np.testing.assert_allclose(result.values, [self.expval], rtol=0.02) @@ -115,7 +118,8 @@ def test_init_observable_from_operator(self, abelian_grouping): @data(True, False) def test_evaluate(self, abelian_grouping): """test for evaluate""" - est = Estimator(abelian_grouping=abelian_grouping) + with self.assertWarns(DeprecationWarning): + est = Estimator(abelian_grouping=abelian_grouping) result = est.run( self.ansatz, self.observable, parameter_values=[[0, 1, 1, 2, 3, 5]], seed=15, shots=8192 ).result() @@ -125,7 +129,8 @@ def test_evaluate(self, abelian_grouping): @data(True, False) def test_evaluate_multi_params(self, abelian_grouping): """test for evaluate with multiple parameters""" - est = Estimator(abelian_grouping=abelian_grouping) + with self.assertWarns(DeprecationWarning): + est = Estimator(abelian_grouping=abelian_grouping) result = est.run( [self.ansatz] * 2, [self.observable] * 2, @@ -139,7 +144,8 @@ def test_evaluate_multi_params(self, abelian_grouping): def test_evaluate_no_params(self, abelian_grouping): """test for evaluate without parameters""" circuit = self.ansatz.assign_parameters([0, 1, 1, 2, 3, 5]) - est = Estimator(abelian_grouping=abelian_grouping) + with self.assertWarns(DeprecationWarning): + est = Estimator(abelian_grouping=abelian_grouping) result = est.run(circuit, self.observable, seed=15, shots=8192).result() self.assertIsInstance(result, EstimatorResult) np.testing.assert_allclose(result.values, [self.expval], rtol=0.02) @@ -151,7 +157,8 @@ def test_run_with_multiple_observables_and_none_parameters(self, abelian_groupin circuit.h(0) circuit.cx(0, 1) circuit.cx(1, 2) - est = Estimator(abelian_grouping=abelian_grouping) + with self.assertWarns(DeprecationWarning): + est = Estimator(abelian_grouping=abelian_grouping) result = est.run( [circuit] * 2, [SparsePauliOp("ZZZ"), SparsePauliOp("III")], seed=15 ).result() @@ -168,7 +175,8 @@ def test_1qubit(self, abelian_grouping): op0 = SparsePauliOp.from_list([("I", 1)]) op1 = SparsePauliOp.from_list([("Z", 1)]) - est = Estimator(abelian_grouping=abelian_grouping) + with self.assertWarns(DeprecationWarning): + est = Estimator(abelian_grouping=abelian_grouping) with self.subTest("test circuit 0, observable 0"): result = est.run(qc0, op0).result() self.assertIsInstance(result, EstimatorResult) @@ -200,7 +208,8 @@ def test_2qubits(self, abelian_grouping): op1 = SparsePauliOp.from_list([("ZI", 1)]) op2 = SparsePauliOp.from_list([("IZ", 1)]) - est = Estimator(abelian_grouping=abelian_grouping) + with self.assertWarns(DeprecationWarning): + est = Estimator(abelian_grouping=abelian_grouping) with self.subTest("test circuit 0, observable 0"): result = est.run(qc0, op0).result() self.assertIsInstance(result, EstimatorResult) @@ -237,7 +246,8 @@ def test_empty_parameter(self, abelian_grouping): n = 2 qc = QuantumCircuit(n) op = SparsePauliOp.from_list([("I" * n, 1)]) - estimator = Estimator(abelian_grouping=abelian_grouping) + with self.assertWarns(DeprecationWarning): + estimator = Estimator(abelian_grouping=abelian_grouping) with self.subTest("one circuit"): result = estimator.run(qc, op, shots=1000).result() np.testing.assert_allclose(result.values, [1]) @@ -257,7 +267,8 @@ def test_numpy_params(self, abelian_grouping): params_array = np.random.rand(k, qc.num_parameters) params_list = params_array.tolist() params_list_array = list(params_array) - estimator = Estimator(abelian_grouping=abelian_grouping) + with self.assertWarns(DeprecationWarning): + estimator = Estimator(abelian_grouping=abelian_grouping) target = estimator.run([qc] * k, [op] * k, params_list, seed=15).result() with self.subTest("ndarrary"): @@ -275,7 +286,8 @@ def test_with_shots_option_with_approximation(self, abelian_grouping): """test with shots option.""" # Note: abelian_gropuing is ignored when approximation is True as documented. # The purpose of this test is to make sure the results remain the same. - est = Estimator(approximation=True, abelian_grouping=abelian_grouping) + with self.assertWarns(DeprecationWarning): + est = Estimator(approximation=True, abelian_grouping=abelian_grouping) result = est.run( self.ansatz, self.observable, parameter_values=[[0, 1, 1, 2, 3, 5]], shots=1024, seed=15 ).result() @@ -285,7 +297,8 @@ def test_with_shots_option_with_approximation(self, abelian_grouping): def test_with_shots_option_without_approximation(self): """test with shots option.""" - est = Estimator(approximation=False, abelian_grouping=False) + with self.assertWarns(DeprecationWarning): + est = Estimator(approximation=False, abelian_grouping=False) result = est.run( self.ansatz, self.observable, parameter_values=[[0, 1, 1, 2, 3, 5]], shots=1024, seed=15 ).result() @@ -295,15 +308,15 @@ def test_with_shots_option_without_approximation(self): def test_warn_shots_none_without_approximation(self): """Test waning for shots=None without approximation.""" - est = Estimator(approximation=False) - with self.assertWarns(RuntimeWarning): - result = est.run( - self.ansatz, - self.observable, - parameter_values=[[0, 1, 1, 2, 3, 5]], - shots=None, - seed=15, - ).result() + with self.assertWarns(DeprecationWarning): + est = Estimator(approximation=False) + result = est.run( + self.ansatz, + self.observable, + parameter_values=[[0, 1, 1, 2, 3, 5]], + shots=None, + seed=15, + ).result() self.assertIsInstance(result, EstimatorResult) np.testing.assert_allclose(result.values, [-1.313831587508902]) self.assertIsInstance(result.metadata[0]["variance"], float) @@ -318,7 +331,8 @@ def test_result_order(self): qc2.ry(np.pi / 2 * param, 0) qc2.measure_all() - estimator = Estimator(approximation=True) + with self.assertWarns(DeprecationWarning): + estimator = Estimator(approximation=True) job = estimator.run([qc1, qc2, qc1, qc1, qc2], ["Z"] * 5, [[], [1], [], [], [1]]) result = job.result() np.testing.assert_allclose(result.values, [1, 0, 1, 1, 0], atol=1e-10)