From 78ef8e87809d9899dc6d2651aae34fb3a4193f72 Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Fri, 3 Mar 2023 11:50:03 -0500 Subject: [PATCH] Fix handling of BackendV1 simulators in PassManagerConfig.from_backend This commit fixes two small oversights that would appear when calling PassManagerConfig.from_backend() with a simulator BackendV1 backend. The handling of optional fields in the BackendProperties and PulseDefaults objects for BackendV1 backends was missing that a BackendProperties object's gates field could be None and that the defaults() method could return None in the absense of any pulse calibrations (both of which typically only are True for simulators). In these cases this would cause an error constructing the InstructionDurations object and the InstructionScheduleMap object respectively. This fixes the handling of these edge cases so that PassManagerConfig.from_backend() will work with any BackendV1 based backend. Fixes #8546 Fixes #9265 --- qiskit/transpiler/instruction_durations.py | 20 ++++++++++--------- qiskit/transpiler/passmanager_config.py | 4 +++- ...-config-from-backend-914869dd6e1c06be.yaml | 9 +++++++++ .../transpiler/test_passmanager_config.py | 16 +++++++++++++++ 4 files changed, 39 insertions(+), 10 deletions(-) create mode 100644 releasenotes/notes/fix-backendv1-pm-config-from-backend-914869dd6e1c06be.yaml diff --git a/qiskit/transpiler/instruction_durations.py b/qiskit/transpiler/instruction_durations.py index a13d6e6e5629..efc462f091b2 100644 --- a/qiskit/transpiler/instruction_durations.py +++ b/qiskit/transpiler/instruction_durations.py @@ -74,15 +74,17 @@ def from_backend(cls, backend: Backend): """ # All durations in seconds in gate_length instruction_durations = [] - for gate, insts in backend.properties()._gates.items(): - for qubits, props in insts.items(): - if "gate_length" in props: - gate_length = props["gate_length"][0] # Throw away datetime at index 1 - instruction_durations.append((gate, qubits, gate_length, "s")) - for q, props in backend.properties()._qubits.items(): - if "readout_length" in props: - readout_length = props["readout_length"][0] # Throw away datetime at index 1 - instruction_durations.append(("measure", [q], readout_length, "s")) + backend_properties = backend.properties() + if hasattr(backend_properties, "_gates"): + for gate, insts in backend_properties._gates.items(): + for qubits, props in insts.items(): + if "gate_length" in props: + gate_length = props["gate_length"][0] # Throw away datetime at index 1 + instruction_durations.append((gate, qubits, gate_length, "s")) + for q, props in backend.properties()._qubits.items(): + if "readout_length" in props: + readout_length = props["readout_length"][0] # Throw away datetime at index 1 + instruction_durations.append(("measure", [q], readout_length, "s")) try: dt = backend.configuration().dt diff --git a/qiskit/transpiler/passmanager_config.py b/qiskit/transpiler/passmanager_config.py index 6534212c83da..a50db70d3616 100644 --- a/qiskit/transpiler/passmanager_config.py +++ b/qiskit/transpiler/passmanager_config.py @@ -136,7 +136,9 @@ def from_backend(cls, backend, **pass_manager_options): if res.inst_map is None: if backend_version < 2: if hasattr(backend, "defaults"): - res.inst_map = backend.defaults().instruction_schedule_map + defaults = backend.defaults() + if defaults is not None: + res.inst_map = defaults.instruction_schedule_map else: res.inst_map = backend.instruction_schedule_map if res.coupling_map is None: diff --git a/releasenotes/notes/fix-backendv1-pm-config-from-backend-914869dd6e1c06be.yaml b/releasenotes/notes/fix-backendv1-pm-config-from-backend-914869dd6e1c06be.yaml new file mode 100644 index 000000000000..fd6688bc2e77 --- /dev/null +++ b/releasenotes/notes/fix-backendv1-pm-config-from-backend-914869dd6e1c06be.yaml @@ -0,0 +1,9 @@ +--- +fixes: + - | + Fixed an issue with the :meth:`.PassManagerConfig.from_backend` + constructor method when it was used with a :class:`~.BackendV1` based + simulator backend. For some simulator backends which did not populate + some optional fields the constructor would error. + Fixed `#9265 `__ and + `#8546 `__ diff --git a/test/python/transpiler/test_passmanager_config.py b/test/python/transpiler/test_passmanager_config.py index 94b421097f15..d78b52e86542 100644 --- a/test/python/transpiler/test_passmanager_config.py +++ b/test/python/transpiler/test_passmanager_config.py @@ -16,6 +16,7 @@ from qiskit.providers.backend import Backend from qiskit.test import QiskitTestCase from qiskit.providers.fake_provider import FakeMelbourne, FakeArmonk, FakeHanoi, FakeHanoiV2 +from qiskit.providers.basicaer import QasmSimulatorPy from qiskit.transpiler.coupling import CouplingMap from qiskit.transpiler.passmanager_config import PassManagerConfig @@ -71,6 +72,21 @@ def test_from_backend_and_user(self): ) self.assertEqual(config.initial_layout, initial_layout) + def test_from_backendv1_inst_map_is_none(self): + """Test that from_backend() works with backend that has defaults defined as None.""" + backend = FakeHanoi() + backend.defaults = lambda: None + config = PassManagerConfig.from_backend(backend) + self.assertIsInstance(config, PassManagerConfig) + self.assertIsNone(config.inst_map) + + def test_simulator_backend_v1(self): + """Test that from_backend() works with backendv1 simulator.""" + backend = QasmSimulatorPy() + config = PassManagerConfig.from_backend(backend) + self.assertIsInstance(config, PassManagerConfig) + self.assertIsNone(config.inst_map) + def test_invalid_user_option(self): """Test from_backend() with an invalid user option.""" with self.assertRaises(TypeError):