Skip to content

Commit

Permalink
Fix handling of control flow instructions in convert_to_target() (#11877
Browse files Browse the repository at this point in the history
)

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 65ab965)
  • Loading branch information
mtreinish authored and mergify[bot] committed Feb 26, 2024
1 parent 160f68e commit 2dc2c97
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 3 deletions.
8 changes: 6 additions & 2 deletions qiskit/providers/backend_compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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()
Expand Down
Original file line number Diff line number Diff line change
@@ -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 <https://github.com/Qiskit/qiskit/issues/11872>`__.
58 changes: 57 additions & 1 deletion test/python/providers/test_fake_backends.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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,)))

0 comments on commit 2dc2c97

Please sign in to comment.