Skip to content

Commit

Permalink
deprecate BackendV1 in PassManagerConfig.from_backend (Qiskit#12931)
Browse files Browse the repository at this point in the history
* deprecate BackendV1 in  PassManagerConfig.from_backend

* test.python.transpiler.test_passmanager_config

* primitives/test_backend_estimator_v2

* test.python.primitives.test_backend_estimator_v2.TestBackendEstimatorV2

* res
  • Loading branch information
1ucian0 authored Sep 12, 2024
1 parent 03575e6 commit 2fa6dd6
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 19 deletions.
22 changes: 19 additions & 3 deletions qiskit/transpiler/passmanager_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"""Pass Manager Configuration class."""

import pprint
import warnings

from qiskit.transpiler.coupling import CouplingMap
from qiskit.transpiler.instruction_durations import InstructionDurations
Expand Down Expand Up @@ -113,11 +114,17 @@ def __init__(
def from_backend(cls, backend, _skip_target=False, **pass_manager_options):
"""Construct a configuration based on a backend and user input.
This method automatically gererates a PassManagerConfig object based on the backend's
This method automatically generates a PassManagerConfig object based on the backend's
features. User options can be used to overwrite the configuration.
.. deprecated:: 1.3
The method ``PassManagerConfig.from_backend`` will stop supporting inputs of type
:class:`.BackendV1` in the `backend` parameter in a future release no
earlier than 2.0. :class:`.BackendV1` is deprecated and implementations should move
to :class:`.BackendV2`.
Args:
backend (BackendV1): The backend that provides the configuration.
backend (BackendV1 or BackendV2): The backend that provides the configuration.
pass_manager_options: User-defined option-value pairs.
Returns:
Expand All @@ -126,12 +133,21 @@ def from_backend(cls, backend, _skip_target=False, **pass_manager_options):
Raises:
AttributeError: If the backend does not support a `configuration()` method.
"""
res = cls(**pass_manager_options)
backend_version = getattr(backend, "version", 0)
if backend_version == 1:
warnings.warn(
"The method PassManagerConfig.from_backend will stop supporting inputs of "
f"type `BackendV1` ( {backend} ) in the `backend` parameter in a future "
"release no earlier than 2.0. `BackendV1` is deprecated and implementations "
"should move to `BackendV2`.",
category=DeprecationWarning,
stacklevel=2,
)
if not isinstance(backend_version, int):
backend_version = 0
if backend_version < 2:
config = backend.configuration()
res = cls(**pass_manager_options)
if res.basis_gates is None:
if backend_version < 2:
res.basis_gates = getattr(config, "basis_gates", None)
Expand Down
6 changes: 6 additions & 0 deletions releasenotes/notes/followup_12629-8bfcf1a3d4e6cabf.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
deprecations_transpiler:
- |
The method :meth:`.PassManagerConfig.from_backend` will stop supporting inputs of type
:class:`.BackendV1` in the `backend` parameter in a future release no earlier than 2.0.
:class:`.BackendV1` is deprecated and implementations should move to :class:`.BackendV2`.
99 changes: 88 additions & 11 deletions test/python/primitives/test_backend_estimator_v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,10 @@ def test_estimator_run_v1(self, backend, abelian_grouping):
):
pm = generate_preset_pass_manager(optimization_level=0, backend=backend)
psi1, psi2 = pm.run([psi1, psi2])
estimator = BackendEstimatorV2(backend=backend, options=self._options)
with self.assertWarns(DeprecationWarning):
# When BackendEstimatorV2 is called with a backend V1, it raises a
# DeprecationWarning from PassManagerConfig.from_backend
estimator = BackendEstimatorV2(backend=backend, options=self._options)
estimator.options.abelian_grouping = abelian_grouping
# Specify the circuit and observable by indices.
# calculate [ <psi1(theta1)|H1|psi1(theta1)> ]
Expand Down Expand Up @@ -235,7 +238,10 @@ def test_estimator_with_pub_v1(self, backend, abelian_grouping):
bind2 = BindingsArray.coerce({tuple(psi2.parameters): theta2})
pub2 = EstimatorPub(psi2, obs2, bind2)

estimator = BackendEstimatorV2(backend=backend, options=self._options)
with self.assertWarns(DeprecationWarning):
# When BackendEstimatorV2 is called with a backend V1, it raises a
# DeprecationWarning from PassManagerConfig.from_backend
estimator = BackendEstimatorV2(backend=backend, options=self._options)
estimator.options.abelian_grouping = abelian_grouping
result4 = estimator.run([pub1, pub2]).result()
np.testing.assert_allclose(result4[0].data.evs, [1.55555728, -1.08766318], rtol=self._rtol)
Expand Down Expand Up @@ -264,7 +270,10 @@ def test_estimator_run_no_params_v1(self, backend, abelian_grouping):
):
pm = generate_preset_pass_manager(optimization_level=0, backend=backend)
circuit = pm.run(circuit)
est = BackendEstimatorV2(backend=backend, options=self._options)
with self.assertWarns(DeprecationWarning):
# When BackendEstimatorV2 is called with a backend V1, it raises a
# DeprecationWarning from PassManagerConfig.from_backend
est = BackendEstimatorV2(backend=backend, options=self._options)
est.options.abelian_grouping = abelian_grouping
observable = self.observable.apply_layout(circuit.layout)
result = est.run([(circuit, observable)]).result()
Expand Down Expand Up @@ -331,7 +340,13 @@ def test_run_single_circuit_observable(self, backend, abelian_grouping):
@combine(backend=BACKENDS_V1, abelian_grouping=[True, False])
def test_run_single_circuit_observable_v1(self, backend, abelian_grouping):
"""Test for single circuit and single observable case."""
est = BackendEstimatorV2(backend=backend, options=self._options)
with self.assertWarnsRegex(
DeprecationWarning,
expected_regex=r"The method PassManagerConfig\.from_backend will stop supporting inputs of "
"type `BackendV1`",
):
# BackendEstimatorV2 wont allow BackendV1
est = BackendEstimatorV2(backend=backend, options=self._options)
est.options.abelian_grouping = abelian_grouping
with self.assertWarnsRegex(
DeprecationWarning,
Expand Down Expand Up @@ -438,7 +453,11 @@ def test_run_1qubit_v1(self, backend, abelian_grouping):
op = SparsePauliOp.from_list([("I", 1)])
op2 = SparsePauliOp.from_list([("Z", 1)])

est = BackendEstimatorV2(backend=backend, options=self._options)
with self.assertWarns(DeprecationWarning):
# When BackendEstimatorV2 is called with a backend V1, it raises a
# DeprecationWarning from PassManagerConfig.from_backend
est = BackendEstimatorV2(backend=backend, options=self._options)

est.options.abelian_grouping = abelian_grouping
op_1 = op.apply_layout(qc.layout)
result = est.run([(qc, op_1)]).result()
Expand Down Expand Up @@ -513,7 +532,10 @@ def test_run_2qubits_v1(self, backend, abelian_grouping):
op2 = SparsePauliOp.from_list([("ZI", 1)])
op3 = SparsePauliOp.from_list([("IZ", 1)])

est = BackendEstimatorV2(backend=backend, options=self._options)
with self.assertWarns(DeprecationWarning):
# When BackendEstimatorV2 is called with a backend V1, it raises a
# DeprecationWarning from PassManagerConfig.from_backend
est = BackendEstimatorV2(backend=backend, options=self._options)
est.options.abelian_grouping = abelian_grouping
op_1 = op.apply_layout(qc.layout)
result = est.run([(qc, op_1)]).result()
Expand All @@ -539,7 +561,47 @@ def test_run_2qubits_v1(self, backend, abelian_grouping):
result = est.run([(qc2, op_6)]).result()
np.testing.assert_allclose(result[0].data.evs, [-1], rtol=self._rtol)

@combine(backend=BACKENDS, abelian_grouping=[True, False])
@combine(backend=BACKENDS_V1, abelian_grouping=[True, False])
def test_run_errors_v1(self, backend, abelian_grouping):
"""Test for errors.
To be removed once BackendV1 is removed."""
qc = QuantumCircuit(1)
qc2 = QuantumCircuit(2)

op = SparsePauliOp.from_list([("I", 1)])
op2 = SparsePauliOp.from_list([("II", 1)])
with self.assertWarns(DeprecationWarning):
# When BackendEstimatorV2 is called with a backend V1, it raises a
# DeprecationWarning from PassManagerConfig.from_backend
est = BackendEstimatorV2(backend=backend, options=self._options)
est.options.abelian_grouping = abelian_grouping
with self.assertRaises(ValueError):
est.run([(qc, op2)]).result()
with self.assertRaises(ValueError):
est.run([(qc, op, [[1e4]])]).result()
with self.assertRaises(ValueError):
est.run([(qc2, op2, [[1, 2]])]).result()
with self.assertRaises(ValueError):
est.run([(qc, [op, op2], [[1]])]).result()
with self.assertRaises(ValueError):
est.run([(qc, op)], precision=-1).result()
with self.assertRaises(ValueError):
est.run([(qc, 1j * op)], precision=0.1).result()
# precision == 0
with self.assertRaises(ValueError):
est.run([(qc, op, None, 0)]).result()
with self.assertRaises(ValueError):
est.run([(qc, op)], precision=0).result()
# precision < 0
with self.assertRaises(ValueError):
est.run([(qc, op, None, -1)]).result()
with self.assertRaises(ValueError):
est.run([(qc, op)], precision=-1).result()
with self.subTest("missing []"):
with self.assertRaisesRegex(ValueError, "An invalid Estimator pub-like was given"):
_ = est.run((qc, op)).result()

@combine(backend=BACKENDS_V2, abelian_grouping=[True, False])
def test_run_errors(self, backend, abelian_grouping):
"""Test for errors"""
qc = QuantumCircuit(1)
Expand Down Expand Up @@ -624,7 +686,13 @@ def test_run_numpy_params_v1(self, backend, abelian_grouping):
statevector_estimator = StatevectorEstimator(seed=123)
target = statevector_estimator.run([(qc, op, params_list)]).result()

backend_estimator = BackendEstimatorV2(backend=backend, options=self._options)
with self.assertWarnsRegex(
DeprecationWarning,
expected_regex=r"The method PassManagerConfig\.from_backend will stop supporting inputs of "
"type `BackendV1`",
):
# BackendEstimatorV2 wont allow BackendV1
backend_estimator = BackendEstimatorV2(backend=backend, options=self._options)
backend_estimator.options.abelian_grouping = abelian_grouping

with self.subTest("ndarrary"):
Expand Down Expand Up @@ -662,7 +730,10 @@ def test_precision(self, backend, abelian_grouping):
@combine(backend=BACKENDS_V1, abelian_grouping=[True, False])
def test_precision_v1(self, backend, abelian_grouping):
"""Test for precision"""
estimator = BackendEstimatorV2(backend=backend, options=self._options)
with self.assertWarns(DeprecationWarning):
# When BackendEstimatorV2 is called with a backend V1, it raises a
# DeprecationWarning from PassManagerConfig.from_backend
estimator = BackendEstimatorV2(backend=backend, options=self._options)
estimator.options.abelian_grouping = abelian_grouping
with self.assertWarnsRegex(
DeprecationWarning,
Expand Down Expand Up @@ -705,7 +776,10 @@ def test_diff_precision(self, backend, abelian_grouping):
@combine(backend=BACKENDS_V1, abelian_grouping=[True, False])
def test_diff_precision_v1(self, backend, abelian_grouping):
"""Test for running different precisions at once"""
estimator = BackendEstimatorV2(backend=backend, options=self._options)
with self.assertWarns(DeprecationWarning):
# When BackendEstimatorV2 is called with a backend V1, it raises a
# DeprecationWarning from PassManagerConfig.from_backend
estimator = BackendEstimatorV2(backend=backend, options=self._options)
estimator.options.abelian_grouping = abelian_grouping
with self.assertWarnsRegex(
DeprecationWarning,
Expand Down Expand Up @@ -792,7 +866,10 @@ def test_job_size_limit_backend_v1(self):
op = SparsePauliOp.from_list([("IZ", 1), ("XI", 2), ("ZY", -1)])
k = 5
param_list = self._rng.random(qc.num_parameters).tolist()
estimator = BackendEstimatorV2(backend=backend)
with self.assertWarns(DeprecationWarning):
# When BackendEstimatorV2 is called with a backend V1, it raises a
# DeprecationWarning from PassManagerConfig.from_backend
estimator = BackendEstimatorV2(backend=backend)
with patch.object(backend, "run") as run_mock:
estimator.run([(qc, op, param_list)] * k).result()
self.assertEqual(run_mock.call_count, 10)
Expand Down
11 changes: 6 additions & 5 deletions test/python/transpiler/test_passmanager_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def test_config_from_backend(self):
"""
with self.assertWarns(DeprecationWarning):
backend = Fake27QPulseV1()
config = PassManagerConfig.from_backend(backend)
config = PassManagerConfig.from_backend(backend)
self.assertEqual(config.basis_gates, backend.configuration().basis_gates)
self.assertEqual(config.inst_map, backend.defaults().instruction_schedule_map)
self.assertEqual(
Expand Down Expand Up @@ -66,9 +66,9 @@ def test_from_backend_and_user_v1(self):

with self.assertWarns(DeprecationWarning):
backend = Fake20QV1()
config = PassManagerConfig.from_backend(
backend, basis_gates=["user_gate"], initial_layout=initial_layout
)
config = PassManagerConfig.from_backend(
backend, basis_gates=["user_gate"], initial_layout=initial_layout
)
self.assertEqual(config.basis_gates, ["user_gate"])
self.assertNotEqual(config.basis_gates, backend.configuration().basis_gates)
self.assertIsNone(config.inst_map)
Expand Down Expand Up @@ -107,7 +107,8 @@ def test_from_backendv1_inst_map_is_none(self):
with self.assertWarns(DeprecationWarning):
backend = Fake27QPulseV1()
backend.defaults = lambda: None
config = PassManagerConfig.from_backend(backend)
with self.assertWarns(DeprecationWarning):
config = PassManagerConfig.from_backend(backend)
self.assertIsInstance(config, PassManagerConfig)
self.assertIsNone(config.inst_map)

Expand Down

0 comments on commit 2fa6dd6

Please sign in to comment.