Skip to content
Merged
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
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