Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 13 additions & 8 deletions qiskit_ibm_runtime/utils/backend_converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,13 @@

logger = logging.getLogger(__name__)

NON_UNITARY_ISA_INSTRUCTIONS = frozenset(("measure", "delay", "reset"))
"""The names of non-unitary Qiskit instructions.

Not every backend supports the full set of non-unitary instructions. To know which instructions
are supported by a given backend, one can inspect ``backend.supported_operations``.
"""


def convert_to_target( # type: ignore[no-untyped-def]
configuration: BackendConfiguration,
Expand Down Expand Up @@ -79,8 +86,6 @@ def convert_to_target( # type: ignore[no-untyped-def]
"Backend defaults have been completely from removed IBM Backends. They will be ignored."
)

required = ["measure", "delay", "reset"]

# Load qiskit object representation
qiskit_inst_mapping = get_standard_gate_name_mapping()
if custom_name_mapping:
Expand All @@ -104,16 +109,16 @@ def convert_to_target( # type: ignore[no-untyped-def]
# Create instruction property placeholder from backend configuration
basis_gates = set(getattr(configuration, "basis_gates", []))
supported_instructions = set(getattr(configuration, "supported_instructions", []))
instruction_signatures = getattr(configuration, "instruction_signatures", [])
gate_configs = {gate.name: gate for gate in configuration.gates}

# Instructions that are not defined in Qiskit, such as `measure_2`, are placed in
# `instruction_signatures` (see below) and handled separately
all_instructions = set.union(
basis_gates,
set(required),
supported_instructions.intersection(NON_UNITARY_ISA_INSTRUCTIONS),
supported_instructions.intersection(CONTROL_FLOW_OP_NAMES),
)

inst_name_map = {}

faulty_ops = set()
faulty_qubits = set()
unsupported_instructions = []
Expand Down Expand Up @@ -168,7 +173,7 @@ def convert_to_target( # type: ignore[no-untyped-def]
all_instructions.remove(name)

# Create name to qiskit-ibm-runtime instruction object repr mapping

instruction_signatures = getattr(configuration, "instruction_signatures", [])
for signature in instruction_signatures:
name = signature.get("name")
num_qubits = signature.get("num_qubits")
Expand Down Expand Up @@ -283,7 +288,7 @@ def _get_value(prop_dict: dict, prop_name: str) -> Any:
duration=_get_value(qubit_prop, "readout_length"), # type: ignore[arg-type]
)

for op in required:
for op in supported_instructions.intersection(NON_UNITARY_ISA_INSTRUCTIONS):
# Map required ops to each operational qubit
if prop_name_map[op] is None:
prop_name_map[op] = {
Expand Down
8 changes: 8 additions & 0 deletions test/unit/test_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,14 @@ def test_reset(self):
self.assertTrue(target.instruction_supported("reset"))
self.assertTrue(target.instruction_supported(operation_class=Reset))

def test_non_unitary_isa_operations(self):
"""Test handling of non-unitary ISA operations."""
target = convert_to_target(FakeSherbrooke().configuration())

assert isinstance(target.get("reset"), dict)
assert isinstance(target.get("measure"), dict)
assert target.get("measure_2") is None

def test_convert_to_target_with_filter(self):
"""Test converting legacy data structure to V2 target model with faulty qubits.

Expand Down