diff --git a/qiskit_ibm_runtime/utils/backend_converter.py b/qiskit_ibm_runtime/utils/backend_converter.py index 3db605d100..4f7051883a 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 0000000000..0031db5cc7 --- /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 3eda26ed2b..754236e988 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))