From 2dc2c977066729c467c2b681422c9231e49fe8d0 Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Mon, 26 Feb 2024 04:47:14 -0500 Subject: [PATCH] Fix handling of control flow instructions in convert_to_target() (#11877) This commit fixes an issue in the convert_to_target() function where it wasn't looking for control flow instructions in the proper location. Typically the control flow instructions are put in the supported_instructions field of the BackendConfiguration, but the convert_to_target() function was ignoring this field. This commit updates the function to check supported_instructions for the control flow instructions. It doesn't more broadly look at the supported_instructions field, because on other backends this field is used to list the supported pulse instructions which might have name conflicts with other instructions and cause issues building a target. Fixes #11872 (cherry picked from commit 65ab96508fe518c7281d0b6f3d805f84bbe146a0) --- qiskit/providers/backend_compat.py | 8 ++- ...ow-convert-to-target-ae838418a7ad2a20.yaml | 9 +++ test/python/providers/test_fake_backends.py | 58 ++++++++++++++++++- 3 files changed, 72 insertions(+), 3 deletions(-) create mode 100644 releasenotes/notes/fix-control-flow-convert-to-target-ae838418a7ad2a20.yaml diff --git a/qiskit/providers/backend_compat.py b/qiskit/providers/backend_compat.py index 3d54656545b4..fcd82765eeb6 100644 --- a/qiskit/providers/backend_compat.py +++ b/qiskit/providers/backend_compat.py @@ -21,7 +21,7 @@ from qiskit.providers.backend import QubitProperties from qiskit.providers.models.backendconfiguration import BackendConfiguration from qiskit.providers.models.backendproperties import BackendProperties - +from qiskit.circuit.controlflow import CONTROL_FLOW_OP_NAMES from qiskit.providers.models.pulsedefaults import PulseDefaults from qiskit.providers.options import Options from qiskit.providers.exceptions import BackendPropertyError @@ -92,8 +92,12 @@ def convert_to_target( # Create instruction property placeholder from backend configuration basis_gates = set(getattr(configuration, "basis_gates", [])) + supported_instructions = set(getattr(configuration, "supported_instructions", [])) gate_configs = {gate.name: gate for gate in configuration.gates} - all_instructions = set.union(basis_gates, set(required)) + all_instructions = set.union( + basis_gates, set(required), supported_instructions.intersection(CONTROL_FLOW_OP_NAMES) + ) + inst_name_map = {} # type: Dict[str, Instruction] faulty_ops = set() diff --git a/releasenotes/notes/fix-control-flow-convert-to-target-ae838418a7ad2a20.yaml b/releasenotes/notes/fix-control-flow-convert-to-target-ae838418a7ad2a20.yaml new file mode 100644 index 000000000000..be29520fad89 --- /dev/null +++ b/releasenotes/notes/fix-control-flow-convert-to-target-ae838418a7ad2a20.yaml @@ -0,0 +1,9 @@ +--- +fixes: + - | + Fixed an issue with the :func:`.convert_to_target` where the converter + would incorrectly ignore control flow instructions if they were specified + in the :attr:`.BackendConfiguration.supported_instructions` attribute which + is the typical location that control flow instructions are specified in a + :class:`.BackendConfiguration` object. + Fixed `#11872 `__. diff --git a/test/python/providers/test_fake_backends.py b/test/python/providers/test_fake_backends.py index f4f42e839f4d..101e35acc8e1 100644 --- a/test/python/providers/test_fake_backends.py +++ b/test/python/providers/test_fake_backends.py @@ -34,7 +34,7 @@ FakeOpenPulse2Q, GenericBackendV2, ) -from qiskit.providers.backend_compat import BackendV2Converter +from qiskit.providers.backend_compat import BackendV2Converter, convert_to_target from qiskit.providers.models.backendproperties import BackendProperties from qiskit.providers.backend import BackendV2 from qiskit.providers.models import GateConfig @@ -709,3 +709,59 @@ def test_faulty_full_path_transpile_connected_cmap(self, opt_level): tqc = transpile(qc, v2_backend, seed_transpiler=433, optimization_level=opt_level) connections = [tuple(sorted(tqc.find_bit(q).index for q in x.qubits)) for x in tqc.data] self.assertNotIn((0, 1), connections) + + def test_convert_to_target_control_flow(self): + backend = Fake27QPulseV1() + properties = backend.properties() + configuration = backend.configuration() + configuration.supported_instructions = [ + "cx", + "id", + "delay", + "measure", + "reset", + "rz", + "sx", + "x", + "if_else", + "for_loop", + "switch_case", + ] + defaults = backend.defaults() + target = convert_to_target(configuration, properties, defaults) + self.assertTrue(target.instruction_supported("if_else", ())) + self.assertFalse(target.instruction_supported("while_loop", ())) + self.assertTrue(target.instruction_supported("for_loop", ())) + self.assertTrue(target.instruction_supported("switch_case", ())) + + def test_convert_unrelated_supported_instructions(self): + backend = Fake27QPulseV1() + properties = backend.properties() + configuration = backend.configuration() + configuration.supported_instructions = [ + "cx", + "id", + "delay", + "measure", + "reset", + "rz", + "sx", + "x", + "play", + "u2", + "u3", + "u1", + "shiftf", + "acquire", + "setf", + "if_else", + "for_loop", + "switch_case", + ] + defaults = backend.defaults() + target = convert_to_target(configuration, properties, defaults) + self.assertTrue(target.instruction_supported("if_else", ())) + self.assertFalse(target.instruction_supported("while_loop", ())) + self.assertTrue(target.instruction_supported("for_loop", ())) + self.assertTrue(target.instruction_supported("switch_case", ())) + self.assertFalse(target.instruction_supported("u3", (0,)))