44#
55import pickle
66from pathlib import Path
7- from typing import Union , Optional , Set
7+ from typing import Union , Optional , Set , List , Tuple
8+
9+ from qiskit import QuantumCircuit , QuantumRegister
10+ from qiskit .providers import Backend
11+ from qiskit .providers .models import BackendProperties
12+ from qiskit .transpiler .target import Target
13+ from qiskit .transpiler import Layout
14+
815from mqt .qmap .pyqmap import map , Method , InitialLayout , Layering , Arch , Encoding , CommanderGrouping , SwapReduction , Configuration , MappingResults , Architecture
916
10- try :
11- from qiskit .providers import Backend
12- from qiskit .providers .models import BackendProperties
13- from qiskit .transpiler .target import Target
1417
15- PossibleArchitectureTypes = Union [str , Arch , Architecture , Backend ]
16- PossibleCalibrationTypes = Union [str , BackendProperties , Target ]
17- except ModuleNotFoundError :
18- PossibleArchitectureTypes = Union [str , Arch , Architecture ]
19- PossibleCalibrationTypes = Union [str ]
18+ def extract_initial_layout_from_qasm (qasm : str , qregs : List [QuantumRegister ]) -> Layout :
19+ """
20+ Extracts the initial layout resulting from compiling a circuit from a QASM file.
21+ :param qasm: QASM file
22+ :type qasm: str
23+ :param qregs: The quantum registers to apply the layout to.
24+ :type qregs: List[QuantumRegister]
25+ :return: layout to be used in Qiskit
26+ """
27+ for line in qasm .split ("\n " ):
28+ if line .startswith ("// i " ):
29+ # strip away initial part of line
30+ line = line [5 :]
31+ # split line into tokens
32+ tokens = line .split (" " )
33+ # convert tokens to integers
34+ tokens = [int (token ) for token in tokens ]
35+ # create an empty layout
36+ layout = Layout ().from_intlist (tokens , * qregs )
37+ return layout
2038
2139
22- def compile (circ , arch : Optional [PossibleArchitectureTypes ],
23- calibration : Optional [PossibleCalibrationTypes ] = None ,
40+ def compile (circ : Union [QuantumCircuit , str ],
41+ arch : Optional [Union [str , Arch , Architecture , Backend ]],
42+ calibration : Optional [Union [str , BackendProperties , Target ]] = None ,
2443 method : Union [str , Method ] = "heuristic" ,
2544 initial_layout : Union [str , InitialLayout ] = "dynamic" ,
2645 layering : Union [str , Layering ] = "individual_gates" ,
@@ -38,14 +57,15 @@ def compile(circ, arch: Optional[PossibleArchitectureTypes],
3857 pre_mapping_optimizations : bool = True ,
3958 post_mapping_optimizations : bool = True ,
4059 verbose : bool = False
41- ) -> MappingResults :
60+ ) -> Tuple [ QuantumCircuit , MappingResults ] :
4261 """Interface to the MQT QMAP tool for mapping quantum circuits
4362
44- :param circ: Path to circuit file, path to Qiskit QuantumCircuit pickle, or Qiskit QuantumCircuit object
63+ :param circ: Qiskit QuantumCircuit object, path to circuit file, or path to Qiskit QuantumCircuit pickle
64+ :type circ: Union[QuantumCircuit, str]
4565 :param arch: Architecture to map to. Either a path to a file with architecture information, one of the available architectures (Arch), qmap.Architecture, or `qiskit.providers.backend` (if Qiskit is installed)
46- :type arch: Optional[PossibleArchitectureTypes ]
66+ :type arch: Optional[Union[str, Arch, Architecture, Backend] ]
4767 :param calibration: Path to file containing calibration information, `qiskit.providers.models.BackendProperties` object (if Qiskit is installed), or `qiskit.transpiler.target.Target` object (if Qiskit is installed)
48- :type calibration: Optional[PossibleCalibrationTypes ]
68+ :type calibration: Optional[Union[str, BackendProperties, Target] ]
4969 :param method: Mapping technique to use (*heuristic* | exact)
5070 :type method: Union[str, Method]
5171 :param initial_layout: Strategy to use for determining initial layout in heuristic mapper (identity | static | *dynamic*)
@@ -77,12 +97,13 @@ def compile(circ, arch: Optional[PossibleArchitectureTypes],
7797 :type post_mapping_optimizations: bool
7898 :param verbose: Print more detailed information during the mapping process
7999 :type verbose: bool
80- :return: Object containing all the results
81- :rtype: MappingResults
100+ :return: Mapped circuit (as Qiskit `QuantumCircuit`) and results
101+ :rtype: Tuple[QuantumCircuit, MappingResults]
82102 """
83103
84104 if subgraph is None :
85105 subgraph = set ()
106+
86107 if type (circ ) == str and Path (circ ).suffix == '.pickle' :
87108 circ = pickle .load (open (circ , "rb" ))
88109
@@ -100,34 +121,26 @@ def compile(circ, arch: Optional[PossibleArchitectureTypes],
100121 architecture .load_coupling_map (arch )
101122 elif isinstance (arch , Architecture ):
102123 architecture = arch
124+ elif isinstance (arch , Backend ):
125+ from mqt .qmap .qiskit .backend import import_backend
126+
127+ architecture = import_backend (arch )
103128 else :
104- try :
105- from qiskit .providers .backend import Backend
106- from mqt .qmap .qiskit .backend import import_backend
107- if isinstance (arch , Backend ):
108- architecture = import_backend (arch )
109- else :
110- raise ValueError ("No compatible type for architecture:" , type (arch ))
111- except ModuleNotFoundError :
112- raise ValueError ("No compatible type for architecture:" , type (arch ))
129+ raise ValueError ("No compatible type for architecture:" , type (arch ))
113130
114131 if calibration is not None :
115132 if type (calibration ) == str :
116133 architecture .load_properties (calibration )
134+ elif isinstance (calibration , BackendProperties ):
135+ from mqt .qmap .qiskit .backend import import_backend_properties
136+
137+ architecture .load_properties (import_backend_properties (calibration ))
138+ elif isinstance (calibration , Target ):
139+ from mqt .qmap .qiskit .backend import import_target
140+
141+ architecture .load_properties (import_target (calibration ))
117142 else :
118- try :
119- from qiskit .providers .models import BackendProperties
120- from qiskit .transpiler .target import Target
121- from mqt .qmap .qiskit .backend import import_backend_properties , import_target
122-
123- if isinstance (calibration , BackendProperties ):
124- architecture .load_properties (import_backend_properties (calibration ))
125- elif isinstance (calibration , Target ):
126- architecture .load_properties (import_target (calibration ))
127- else :
128- raise ValueError ("No compatible type for calibration:" , type (calibration ))
129- except ModuleNotFoundError :
130- raise ValueError ("No compatible type for calibration:" , type (calibration ))
143+ raise ValueError ("No compatible type for calibration:" , type (calibration ))
131144
132145 config = Configuration ()
133146 config .method = Method (method )
@@ -148,4 +161,10 @@ def compile(circ, arch: Optional[PossibleArchitectureTypes],
148161 config .post_mapping_optimizations = post_mapping_optimizations
149162 config .verbose = verbose
150163
151- return map (circ , architecture , config )
164+ results = map (circ , architecture , config )
165+
166+ circ = QuantumCircuit .from_qasm_str (results .mapped_circuit )
167+ layout = extract_initial_layout_from_qasm (results .mapped_circuit , circ .qregs )
168+ circ ._layout = layout
169+
170+ return circ , results
0 commit comments