From 4feb02f61442aa212c13380ce4599d5767b9f7b1 Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Wed, 28 Feb 2024 18:21:03 -0500 Subject: [PATCH] Handle control flow instructions in Target generation (#1443) * Handle control flow instructions in Target generation This commit updates the convert_to_target() function that is used to convert the API response objects used to describe a backend and generate a Qiskit Target object from that to properly handle control flow instructions. The supported control flow instructions are listed in the `supported_instructions` field of the configuration payload. [1] This commit updates the logic to look for the presence of known control flow instruction names in that field and add them as appropriate to the target as global variadic instructions to indicate to Qiskit's transpiler and other Target object users that the backend supports the instructions. [1] https://github.com/Qiskit/ibm-quantum-schemas/blob/0231221082ec722cc31db09c0b41a25f441ac338/schemas/backend_configuration_schema.json#L165-L170 * Add release note --------- Co-authored-by: Jessie Yu --- qiskit_ibm_runtime/utils/backend_converter.py | 10 ++++++++ .../fix-control-flow-d5a61dd5647acb42.yaml | 6 +++++ test/unit/test_backend.py | 25 +++++++++++++++++-- 3 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 releasenotes/notes/fix-control-flow-d5a61dd5647acb42.yaml diff --git a/qiskit_ibm_runtime/utils/backend_converter.py b/qiskit_ibm_runtime/utils/backend_converter.py index 3db605d10..4f7051883 100644 --- a/qiskit_ibm_runtime/utils/backend_converter.py +++ b/qiskit_ibm_runtime/utils/backend_converter.py @@ -25,6 +25,8 @@ ECRGate, CZGate, ) +from qiskit.circuit.controlflow import CONTROL_FLOW_OP_NAMES +from qiskit.circuit import IfElseOp, WhileLoopOp, ForLoopOp, SwitchCaseOp from qiskit.circuit.parameter import Parameter from qiskit.circuit.delay import Delay from qiskit.circuit.gate import Gate @@ -56,6 +58,10 @@ def convert_to_target( "reset": Reset(), "ecr": ECRGate(), "cz": CZGate(), + "if_else": IfElseOp, + "while_loop": WhileLoopOp, + "for_loop": ForLoopOp, + "switch_case": SwitchCaseOp, } custom_gates = {} target = None @@ -128,6 +134,10 @@ def convert_to_target( target.min_length = configuration.timing_constraints.get("min_length") target.pulse_alignment = configuration.timing_constraints.get("pulse_alignment") target.acquire_alignment = configuration.timing_constraints.get("acquire_alignment") + supported_instructions = set(getattr(configuration, "supported_instructions", [])) + control_flow_ops = CONTROL_FLOW_OP_NAMES.intersection(supported_instructions) + for op in control_flow_ops: + target.add_instruction(name_mapping[op], name=op) # If pulse defaults exists use that as the source of truth if defaults is not None: faulty_qubits = set() diff --git a/releasenotes/notes/fix-control-flow-d5a61dd5647acb42.yaml b/releasenotes/notes/fix-control-flow-d5a61dd5647acb42.yaml new file mode 100644 index 000000000..0031db5cc --- /dev/null +++ b/releasenotes/notes/fix-control-flow-d5a61dd5647acb42.yaml @@ -0,0 +1,6 @@ +--- +fixes: + - | + Fixed an issue with the :attr:`.IBMBackend.target` where it would + incorrectly exclude supported control flow operations (:class:`.IfElseOp`, + :class:`.WhileLoop`, etc.) if a given backend supported them. diff --git a/test/unit/test_backend.py b/test/unit/test_backend.py index 3eda26ed2..754236e98 100644 --- a/test/unit/test_backend.py +++ b/test/unit/test_backend.py @@ -16,11 +16,18 @@ import warnings from qiskit import transpile, qasm3, QuantumCircuit -from qiskit.providers.models import BackendStatus +from qiskit.circuit import IfElseOp +from qiskit.providers.models import ( + BackendStatus, + BackendConfiguration, + BackendProperties, + PulseDefaults, +) from qiskit_ibm_runtime.exceptions import IBMBackendValueError -from qiskit_ibm_runtime.fake_provider import FakeManila +from qiskit_ibm_runtime.fake_provider import FakeManila, FakeSherbrooke from qiskit_ibm_runtime.ibm_backend import IBMBackend +from qiskit_ibm_runtime.utils.backend_converter import convert_to_target from ..ibm_test_case import IBMTestCase from ..utils import ( @@ -305,3 +312,17 @@ def test_too_many_circuits(self): f"Number of circuits, {max_circs+1} exceeds the maximum for this backend, {max_circs}", str(err.exception), ) + + def test_control_flow_converter(self): + """Test that control flow instructions are properly added to the target.""" + backend = FakeSherbrooke() + backend._get_conf_dict_from_json() + backend._set_props_dict_from_json() + backend._set_defs_dict_from_json() + target = convert_to_target( + BackendConfiguration.from_dict(backend._conf_dict), + BackendProperties.from_dict(backend._props_dict), + PulseDefaults.from_dict(backend._defs_dict), + ) + self.assertTrue(target.instruction_supported("if_else", ())) + self.assertTrue(target.instruction_supported(operation_class=IfElseOp))