10
10
# copyright notice, and modified files need to carry a notice indicating
11
11
# that they have been altered from the originals.
12
12
13
- """Converters for migration from IBM Quantum BackendV1 to BackendV2."""
13
+ """
14
+ Converters from BackendConfiguration and BackendProperties
15
+ model (BackendV1) to Target model (BackendV2).
16
+ """
14
17
15
18
from __future__ import annotations
16
19
17
20
import logging
18
21
import warnings
19
- from typing import Any , Dict , List
22
+ from typing import Any
20
23
21
24
from qiskit .circuit .controlflow import (
22
25
CONTROL_FLOW_OP_NAMES ,
26
29
WhileLoopOp ,
27
30
)
28
31
from qiskit .circuit .gate import Gate
32
+ from qiskit .circuit import Instruction
29
33
from qiskit .circuit .library .standard_gates import get_standard_gate_name_mapping
30
34
from qiskit .circuit .parameter import Parameter
31
35
from qiskit .providers .backend import QubitProperties
32
36
from qiskit .transpiler .target import InstructionProperties , Target
33
37
34
- from ..models import BackendConfiguration , BackendProperties
35
- from ..models .exceptions import BackendPropertyError
36
-
37
- # is_fractional_gate used to be defined in this module and might be referenced
38
- # from here externally
39
- from .utils import is_fractional_gate # See comment above before removing
38
+ from qiskit_ibm_runtime .models import BackendConfiguration , BackendProperties
39
+ from qiskit_ibm_runtime .models .exceptions import BackendPropertyError
40
+ from qiskit_ibm_runtime .utils .utils import is_fractional_gate
40
41
41
42
42
43
logger = logging .getLogger (__name__ )
@@ -48,34 +49,42 @@ def convert_to_target( # type: ignore[no-untyped-def]
48
49
* ,
49
50
include_control_flow : bool = True ,
50
51
include_fractional_gates : bool = True ,
52
+ custom_name_mapping : dict [str , Any ] | None = None ,
53
+ add_delay : bool = True ,
54
+ filter_faulty : bool = True ,
51
55
** kwargs ,
52
56
) -> Target :
53
57
"""Decode transpiler target from backend data set.
54
58
55
59
This function generates :class:`.Target`` instance from intermediate
56
60
legacy objects such as :class:`.BackendProperties` and :class:`.BackendConfiguration`.
61
+ These objects were components of the legacy :class:`.BackendV1` model.
57
62
58
63
Args:
59
64
configuration: Backend configuration as ``BackendConfiguration``
60
65
properties: Backend property dictionary or ``BackendProperties``
61
66
include_control_flow: Set True to include control flow instructions.
62
67
include_fractional_gates: Set True to include fractioanl gates.
68
+ custom_name_mapping: A name mapping must be supplied for the operation
69
+ not included in Qiskit Standard Gate name mapping, otherwise the operation
70
+ will be dropped in the resulting ``Target`` object.
71
+ add_delay: If True, adds delay to the instruction set.
72
+ filter_faulty: If True, this filters the non-operational qubits.
63
73
64
74
Returns:
65
75
A ``Target`` instance.
66
76
"""
67
- add_delay = True
68
- filter_faulty = True
69
-
70
77
if "defaults" in kwargs :
71
78
warnings .warn (
72
79
"Backend defaults have been completely from removed IBM Backends. They will be ignored."
73
80
)
74
81
75
82
required = ["measure" , "delay" , "reset" ]
76
83
77
- # Load Qiskit object representation
84
+ # Load qiskit object representation
78
85
qiskit_inst_mapping = get_standard_gate_name_mapping ()
86
+ if custom_name_mapping :
87
+ qiskit_inst_mapping .update (custom_name_mapping )
79
88
80
89
qiskit_control_flow_mapping = {
81
90
"if_else" : IfElseOp ,
@@ -95,9 +104,12 @@ def convert_to_target( # type: ignore[no-untyped-def]
95
104
# Create instruction property placeholder from backend configuration
96
105
basis_gates = set (getattr (configuration , "basis_gates" , []))
97
106
supported_instructions = set (getattr (configuration , "supported_instructions" , []))
107
+ instruction_signatures = getattr (configuration , "instruction_signatures" , [])
98
108
gate_configs = {gate .name : gate for gate in configuration .gates }
99
109
all_instructions = set .union (
100
- basis_gates , set (required ), supported_instructions .intersection (CONTROL_FLOW_OP_NAMES )
110
+ basis_gates ,
111
+ set (required ),
112
+ supported_instructions .intersection (CONTROL_FLOW_OP_NAMES ),
101
113
)
102
114
103
115
inst_name_map = {}
@@ -106,7 +118,7 @@ def convert_to_target( # type: ignore[no-untyped-def]
106
118
faulty_qubits = set ()
107
119
unsupported_instructions = []
108
120
109
- # Create name to Qiskit instruction object repr mapping
121
+ # Create name to qiskit instruction object repr mapping
110
122
for name in all_instructions :
111
123
if name in qiskit_control_flow_mapping :
112
124
if not include_control_flow :
@@ -132,9 +144,9 @@ def convert_to_target( # type: ignore[no-untyped-def]
132
144
inst_name_map [name ] = qiskit_gate
133
145
elif name in gate_configs :
134
146
# GateConfig model is a translator of QASM opcode.
135
- # This doesn't have quantum definition, so Qiskit transpiler doesn't perform
147
+ # This doesn't have quantum definition, so qiskit transpiler doesn't perform
136
148
# any optimization in quantum domain.
137
- # Usually GateConfig counterpart should exist in Qiskit namespace so this is rarely called.
149
+ # Usually GateConfig counterpart should exist in qiskit namespace so this is rarely called.
138
150
this_config = gate_configs [name ]
139
151
params = list (map (Parameter , getattr (this_config , "parameters" , [])))
140
152
coupling_map = getattr (this_config , "coupling_map" , [])
@@ -155,12 +167,29 @@ def convert_to_target( # type: ignore[no-untyped-def]
155
167
for name in unsupported_instructions :
156
168
all_instructions .remove (name )
157
169
170
+ # Create name to qiskit-ibm-runtime instruction object repr mapping
171
+
172
+ for signature in instruction_signatures :
173
+ name = signature .get ("name" )
174
+ num_qubits = signature .get ("num_qubits" )
175
+ num_clbits = signature .get ("num_clbits" )
176
+ param_names = signature .get ("parameters" )
177
+ # Add generic parameter name
178
+ params = [Parameter (name ) for name in param_names ]
179
+
180
+ instruction = Instruction (
181
+ name = name , num_qubits = num_qubits , num_clbits = num_clbits , params = params
182
+ )
183
+ inst_name_map [name ] = instruction
184
+ all_instructions .add (name )
185
+
158
186
# Create inst properties placeholder
159
187
# Without any assignment, properties value is None,
160
188
# which defines a global instruction that can be applied to any qubit(s).
161
189
# The None value behaves differently from an empty dictionary.
162
190
# See API doc of Target.add_instruction for details.
163
191
prop_name_map = dict .fromkeys (all_instructions )
192
+
164
193
for name in all_instructions :
165
194
if name in gate_configs :
166
195
if coupling_map := getattr (gate_configs [name ], "coupling_map" , None ):
@@ -173,7 +202,7 @@ def convert_to_target( # type: ignore[no-untyped-def]
173
202
# Populate instruction properties
174
203
if properties :
175
204
176
- def _get_value (prop_dict : Dict , prop_name : str ) -> Any :
205
+ def _get_value (prop_dict : dict , prop_name : str ) -> Any :
177
206
if ndval := prop_dict .get (prop_name , None ):
178
207
return ndval [0 ]
179
208
return None
@@ -285,11 +314,9 @@ def _get_value(prop_dict: Dict, prop_name: str) -> Any:
285
314
286
315
def qubit_props_list_from_props (
287
316
properties : BackendProperties ,
288
- ) -> List [QubitProperties ]:
289
- """Uses BackendProperties to construct
290
- and return a list of QubitProperties.
291
- """
292
- qubit_props : List [QubitProperties ] = []
317
+ ) -> list [QubitProperties ]:
318
+ """Uses BackendProperties to construct and return a list of QubitProperties."""
319
+ qubit_props : list [QubitProperties ] = []
293
320
for qubit , _ in enumerate (properties .qubits ):
294
321
try :
295
322
t_1 = properties .t1 (qubit )
0 commit comments