Skip to content

Commit

Permalink
Handle control flow instructions in Target generation (Qiskit#1443)
Browse files Browse the repository at this point in the history
* 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 <[email protected]>
  • Loading branch information
mtreinish and jyu00 authored Feb 28, 2024
1 parent 36b995b commit 4feb02f
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 2 deletions.
10 changes: 10 additions & 0 deletions qiskit_ibm_runtime/utils/backend_converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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()
Expand Down
6 changes: 6 additions & 0 deletions releasenotes/notes/fix-control-flow-d5a61dd5647acb42.yaml
Original file line number Diff line number Diff line change
@@ -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.
25 changes: 23 additions & 2 deletions test/unit/test_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand Down Expand Up @@ -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))

0 comments on commit 4feb02f

Please sign in to comment.