Skip to content

Commit 2fa6dd6

Browse files
authored
deprecate BackendV1 in PassManagerConfig.from_backend (#12931)
* 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
1 parent 03575e6 commit 2fa6dd6

4 files changed

Lines changed: 119 additions & 19 deletions

File tree

qiskit/transpiler/passmanager_config.py

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
"""Pass Manager Configuration class."""
1414

1515
import pprint
16+
import warnings
1617

1718
from qiskit.transpiler.coupling import CouplingMap
1819
from qiskit.transpiler.instruction_durations import InstructionDurations
@@ -113,11 +114,17 @@ def __init__(
113114
def from_backend(cls, backend, _skip_target=False, **pass_manager_options):
114115
"""Construct a configuration based on a backend and user input.
115116
116-
This method automatically gererates a PassManagerConfig object based on the backend's
117+
This method automatically generates a PassManagerConfig object based on the backend's
117118
features. User options can be used to overwrite the configuration.
118119
120+
.. deprecated:: 1.3
121+
The method ``PassManagerConfig.from_backend`` will stop supporting inputs of type
122+
:class:`.BackendV1` in the `backend` parameter in a future release no
123+
earlier than 2.0. :class:`.BackendV1` is deprecated and implementations should move
124+
to :class:`.BackendV2`.
125+
119126
Args:
120-
backend (BackendV1): The backend that provides the configuration.
127+
backend (BackendV1 or BackendV2): The backend that provides the configuration.
121128
pass_manager_options: User-defined option-value pairs.
122129
123130
Returns:
@@ -126,12 +133,21 @@ def from_backend(cls, backend, _skip_target=False, **pass_manager_options):
126133
Raises:
127134
AttributeError: If the backend does not support a `configuration()` method.
128135
"""
129-
res = cls(**pass_manager_options)
130136
backend_version = getattr(backend, "version", 0)
137+
if backend_version == 1:
138+
warnings.warn(
139+
"The method PassManagerConfig.from_backend will stop supporting inputs of "
140+
f"type `BackendV1` ( {backend} ) in the `backend` parameter in a future "
141+
"release no earlier than 2.0. `BackendV1` is deprecated and implementations "
142+
"should move to `BackendV2`.",
143+
category=DeprecationWarning,
144+
stacklevel=2,
145+
)
131146
if not isinstance(backend_version, int):
132147
backend_version = 0
133148
if backend_version < 2:
134149
config = backend.configuration()
150+
res = cls(**pass_manager_options)
135151
if res.basis_gates is None:
136152
if backend_version < 2:
137153
res.basis_gates = getattr(config, "basis_gates", None)
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
deprecations_transpiler:
3+
- |
4+
The method :meth:`.PassManagerConfig.from_backend` will stop supporting inputs of type
5+
:class:`.BackendV1` in the `backend` parameter in a future release no earlier than 2.0.
6+
:class:`.BackendV1` is deprecated and implementations should move to :class:`.BackendV2`.

test/python/primitives/test_backend_estimator_v2.py

Lines changed: 88 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,10 @@ def test_estimator_run_v1(self, backend, abelian_grouping):
145145
):
146146
pm = generate_preset_pass_manager(optimization_level=0, backend=backend)
147147
psi1, psi2 = pm.run([psi1, psi2])
148-
estimator = BackendEstimatorV2(backend=backend, options=self._options)
148+
with self.assertWarns(DeprecationWarning):
149+
# When BackendEstimatorV2 is called with a backend V1, it raises a
150+
# DeprecationWarning from PassManagerConfig.from_backend
151+
estimator = BackendEstimatorV2(backend=backend, options=self._options)
149152
estimator.options.abelian_grouping = abelian_grouping
150153
# Specify the circuit and observable by indices.
151154
# calculate [ <psi1(theta1)|H1|psi1(theta1)> ]
@@ -235,7 +238,10 @@ def test_estimator_with_pub_v1(self, backend, abelian_grouping):
235238
bind2 = BindingsArray.coerce({tuple(psi2.parameters): theta2})
236239
pub2 = EstimatorPub(psi2, obs2, bind2)
237240

238-
estimator = BackendEstimatorV2(backend=backend, options=self._options)
241+
with self.assertWarns(DeprecationWarning):
242+
# When BackendEstimatorV2 is called with a backend V1, it raises a
243+
# DeprecationWarning from PassManagerConfig.from_backend
244+
estimator = BackendEstimatorV2(backend=backend, options=self._options)
239245
estimator.options.abelian_grouping = abelian_grouping
240246
result4 = estimator.run([pub1, pub2]).result()
241247
np.testing.assert_allclose(result4[0].data.evs, [1.55555728, -1.08766318], rtol=self._rtol)
@@ -264,7 +270,10 @@ def test_estimator_run_no_params_v1(self, backend, abelian_grouping):
264270
):
265271
pm = generate_preset_pass_manager(optimization_level=0, backend=backend)
266272
circuit = pm.run(circuit)
267-
est = BackendEstimatorV2(backend=backend, options=self._options)
273+
with self.assertWarns(DeprecationWarning):
274+
# When BackendEstimatorV2 is called with a backend V1, it raises a
275+
# DeprecationWarning from PassManagerConfig.from_backend
276+
est = BackendEstimatorV2(backend=backend, options=self._options)
268277
est.options.abelian_grouping = abelian_grouping
269278
observable = self.observable.apply_layout(circuit.layout)
270279
result = est.run([(circuit, observable)]).result()
@@ -331,7 +340,13 @@ def test_run_single_circuit_observable(self, backend, abelian_grouping):
331340
@combine(backend=BACKENDS_V1, abelian_grouping=[True, False])
332341
def test_run_single_circuit_observable_v1(self, backend, abelian_grouping):
333342
"""Test for single circuit and single observable case."""
334-
est = BackendEstimatorV2(backend=backend, options=self._options)
343+
with self.assertWarnsRegex(
344+
DeprecationWarning,
345+
expected_regex=r"The method PassManagerConfig\.from_backend will stop supporting inputs of "
346+
"type `BackendV1`",
347+
):
348+
# BackendEstimatorV2 wont allow BackendV1
349+
est = BackendEstimatorV2(backend=backend, options=self._options)
335350
est.options.abelian_grouping = abelian_grouping
336351
with self.assertWarnsRegex(
337352
DeprecationWarning,
@@ -438,7 +453,11 @@ def test_run_1qubit_v1(self, backend, abelian_grouping):
438453
op = SparsePauliOp.from_list([("I", 1)])
439454
op2 = SparsePauliOp.from_list([("Z", 1)])
440455

441-
est = BackendEstimatorV2(backend=backend, options=self._options)
456+
with self.assertWarns(DeprecationWarning):
457+
# When BackendEstimatorV2 is called with a backend V1, it raises a
458+
# DeprecationWarning from PassManagerConfig.from_backend
459+
est = BackendEstimatorV2(backend=backend, options=self._options)
460+
442461
est.options.abelian_grouping = abelian_grouping
443462
op_1 = op.apply_layout(qc.layout)
444463
result = est.run([(qc, op_1)]).result()
@@ -513,7 +532,10 @@ def test_run_2qubits_v1(self, backend, abelian_grouping):
513532
op2 = SparsePauliOp.from_list([("ZI", 1)])
514533
op3 = SparsePauliOp.from_list([("IZ", 1)])
515534

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

542-
@combine(backend=BACKENDS, abelian_grouping=[True, False])
564+
@combine(backend=BACKENDS_V1, abelian_grouping=[True, False])
565+
def test_run_errors_v1(self, backend, abelian_grouping):
566+
"""Test for errors.
567+
To be removed once BackendV1 is removed."""
568+
qc = QuantumCircuit(1)
569+
qc2 = QuantumCircuit(2)
570+
571+
op = SparsePauliOp.from_list([("I", 1)])
572+
op2 = SparsePauliOp.from_list([("II", 1)])
573+
with self.assertWarns(DeprecationWarning):
574+
# When BackendEstimatorV2 is called with a backend V1, it raises a
575+
# DeprecationWarning from PassManagerConfig.from_backend
576+
est = BackendEstimatorV2(backend=backend, options=self._options)
577+
est.options.abelian_grouping = abelian_grouping
578+
with self.assertRaises(ValueError):
579+
est.run([(qc, op2)]).result()
580+
with self.assertRaises(ValueError):
581+
est.run([(qc, op, [[1e4]])]).result()
582+
with self.assertRaises(ValueError):
583+
est.run([(qc2, op2, [[1, 2]])]).result()
584+
with self.assertRaises(ValueError):
585+
est.run([(qc, [op, op2], [[1]])]).result()
586+
with self.assertRaises(ValueError):
587+
est.run([(qc, op)], precision=-1).result()
588+
with self.assertRaises(ValueError):
589+
est.run([(qc, 1j * op)], precision=0.1).result()
590+
# precision == 0
591+
with self.assertRaises(ValueError):
592+
est.run([(qc, op, None, 0)]).result()
593+
with self.assertRaises(ValueError):
594+
est.run([(qc, op)], precision=0).result()
595+
# precision < 0
596+
with self.assertRaises(ValueError):
597+
est.run([(qc, op, None, -1)]).result()
598+
with self.assertRaises(ValueError):
599+
est.run([(qc, op)], precision=-1).result()
600+
with self.subTest("missing []"):
601+
with self.assertRaisesRegex(ValueError, "An invalid Estimator pub-like was given"):
602+
_ = est.run((qc, op)).result()
603+
604+
@combine(backend=BACKENDS_V2, abelian_grouping=[True, False])
543605
def test_run_errors(self, backend, abelian_grouping):
544606
"""Test for errors"""
545607
qc = QuantumCircuit(1)
@@ -624,7 +686,13 @@ def test_run_numpy_params_v1(self, backend, abelian_grouping):
624686
statevector_estimator = StatevectorEstimator(seed=123)
625687
target = statevector_estimator.run([(qc, op, params_list)]).result()
626688

627-
backend_estimator = BackendEstimatorV2(backend=backend, options=self._options)
689+
with self.assertWarnsRegex(
690+
DeprecationWarning,
691+
expected_regex=r"The method PassManagerConfig\.from_backend will stop supporting inputs of "
692+
"type `BackendV1`",
693+
):
694+
# BackendEstimatorV2 wont allow BackendV1
695+
backend_estimator = BackendEstimatorV2(backend=backend, options=self._options)
628696
backend_estimator.options.abelian_grouping = abelian_grouping
629697

630698
with self.subTest("ndarrary"):
@@ -662,7 +730,10 @@ def test_precision(self, backend, abelian_grouping):
662730
@combine(backend=BACKENDS_V1, abelian_grouping=[True, False])
663731
def test_precision_v1(self, backend, abelian_grouping):
664732
"""Test for precision"""
665-
estimator = BackendEstimatorV2(backend=backend, options=self._options)
733+
with self.assertWarns(DeprecationWarning):
734+
# When BackendEstimatorV2 is called with a backend V1, it raises a
735+
# DeprecationWarning from PassManagerConfig.from_backend
736+
estimator = BackendEstimatorV2(backend=backend, options=self._options)
666737
estimator.options.abelian_grouping = abelian_grouping
667738
with self.assertWarnsRegex(
668739
DeprecationWarning,
@@ -705,7 +776,10 @@ def test_diff_precision(self, backend, abelian_grouping):
705776
@combine(backend=BACKENDS_V1, abelian_grouping=[True, False])
706777
def test_diff_precision_v1(self, backend, abelian_grouping):
707778
"""Test for running different precisions at once"""
708-
estimator = BackendEstimatorV2(backend=backend, options=self._options)
779+
with self.assertWarns(DeprecationWarning):
780+
# When BackendEstimatorV2 is called with a backend V1, it raises a
781+
# DeprecationWarning from PassManagerConfig.from_backend
782+
estimator = BackendEstimatorV2(backend=backend, options=self._options)
709783
estimator.options.abelian_grouping = abelian_grouping
710784
with self.assertWarnsRegex(
711785
DeprecationWarning,
@@ -792,7 +866,10 @@ def test_job_size_limit_backend_v1(self):
792866
op = SparsePauliOp.from_list([("IZ", 1), ("XI", 2), ("ZY", -1)])
793867
k = 5
794868
param_list = self._rng.random(qc.num_parameters).tolist()
795-
estimator = BackendEstimatorV2(backend=backend)
869+
with self.assertWarns(DeprecationWarning):
870+
# When BackendEstimatorV2 is called with a backend V1, it raises a
871+
# DeprecationWarning from PassManagerConfig.from_backend
872+
estimator = BackendEstimatorV2(backend=backend)
796873
with patch.object(backend, "run") as run_mock:
797874
estimator.run([(qc, op, param_list)] * k).result()
798875
self.assertEqual(run_mock.call_count, 10)

test/python/transpiler/test_passmanager_config.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ def test_config_from_backend(self):
3333
"""
3434
with self.assertWarns(DeprecationWarning):
3535
backend = Fake27QPulseV1()
36-
config = PassManagerConfig.from_backend(backend)
36+
config = PassManagerConfig.from_backend(backend)
3737
self.assertEqual(config.basis_gates, backend.configuration().basis_gates)
3838
self.assertEqual(config.inst_map, backend.defaults().instruction_schedule_map)
3939
self.assertEqual(
@@ -66,9 +66,9 @@ def test_from_backend_and_user_v1(self):
6666

6767
with self.assertWarns(DeprecationWarning):
6868
backend = Fake20QV1()
69-
config = PassManagerConfig.from_backend(
70-
backend, basis_gates=["user_gate"], initial_layout=initial_layout
71-
)
69+
config = PassManagerConfig.from_backend(
70+
backend, basis_gates=["user_gate"], initial_layout=initial_layout
71+
)
7272
self.assertEqual(config.basis_gates, ["user_gate"])
7373
self.assertNotEqual(config.basis_gates, backend.configuration().basis_gates)
7474
self.assertIsNone(config.inst_map)
@@ -107,7 +107,8 @@ def test_from_backendv1_inst_map_is_none(self):
107107
with self.assertWarns(DeprecationWarning):
108108
backend = Fake27QPulseV1()
109109
backend.defaults = lambda: None
110-
config = PassManagerConfig.from_backend(backend)
110+
with self.assertWarns(DeprecationWarning):
111+
config = PassManagerConfig.from_backend(backend)
111112
self.assertIsInstance(config, PassManagerConfig)
112113
self.assertIsNone(config.inst_map)
113114

0 commit comments

Comments
 (0)