15
15
import pickle
16
16
from itertools import combinations
17
17
from pathlib import Path
18
- from typing import TYPE_CHECKING , Dict , NewType , Set , Tuple
18
+ from typing import TYPE_CHECKING , Dict , NewType , Optional , Set , Tuple
19
19
20
20
if TYPE_CHECKING : # pragma: no cover
21
+ from collections .abc import Iterable
22
+
21
23
from matplotlib import figure
22
- from qiskit .providers import Backend
24
+ from qiskit .providers import BackendV1
25
+ from typing_extensions import TypeAlias
23
26
24
27
from mqt .qmap import Architecture
25
28
26
29
30
+ import contextlib
31
+
27
32
import rustworkx as rx
33
+ import rustworkx .visualization as rxviz
34
+
35
+ with contextlib .suppress (TypeError ):
36
+ Graph : TypeAlias = rx .PyGraph [int , Optional [int ]]
37
+
28
38
29
39
PartialOrder = NewType ("PartialOrder" , Dict [Tuple [int , int ], Set [Tuple [int , int ]]])
30
40
@@ -40,7 +50,7 @@ class SubarchitectureOrder:
40
50
41
51
def __init__ (self ) -> None :
42
52
"""Initialize a partial order."""
43
- self .arch : rx . PyGraph = rx .PyGraph ()
53
+ self .arch : Graph = rx .PyGraph ()
44
54
self .subarch_order : PartialOrder = PartialOrder ({})
45
55
self .desirable_subarchitectures : PartialOrder = PartialOrder ({})
46
56
self .isomorphisms : dict [tuple [int , int ], dict [tuple [int , int ], dict [int , int ]]] = {}
@@ -50,7 +60,7 @@ def __init__(self) -> None:
50
60
self .__compute_desirable_subarchitectures ()
51
61
52
62
@classmethod
53
- def from_retworkx_graph (cls , graph : rx . PyGraph ) -> SubarchitectureOrder :
63
+ def from_retworkx_graph (cls , graph : Graph ) -> SubarchitectureOrder :
54
64
"""Construct the partial order from retworkx graph.
55
65
56
66
Args:
@@ -68,24 +78,24 @@ def from_retworkx_graph(cls, graph: rx.PyGraph) -> SubarchitectureOrder:
68
78
return so
69
79
70
80
@classmethod
71
- def from_coupling_map (cls , coupling_map : set [ tuple [ int , int ]] | list [tuple [int , int ]]) -> SubarchitectureOrder :
81
+ def from_coupling_map (cls , coupling_map : Iterable [tuple [int , int ]]) -> SubarchitectureOrder :
72
82
"""Construct partial order from coupling map defined as set of tuples of connected qubits.
73
83
74
84
Args:
75
- coupling_map: Set or list of tuples of connected qubits.
85
+ coupling_map: Iterable of tuples of connected qubits.
76
86
77
87
Returns:
78
88
The resulting partial order.
79
89
"""
80
90
num_nodes = max (max (int (u ), int (v )) for u , v in coupling_map )
81
- graph = rx .PyGraph ()
91
+ graph : Graph = rx .PyGraph ()
82
92
graph .add_nodes_from (list (range (num_nodes + 1 )))
83
- graph .add_edges_from_no_data ([ tuple ( edge ) for edge in coupling_map ] )
93
+ graph .add_edges_from_no_data (list ( coupling_map ) )
84
94
85
95
return cls .from_retworkx_graph (graph )
86
96
87
97
@classmethod
88
- def from_backend (cls , backend : Backend ) -> SubarchitectureOrder :
98
+ def from_backend (cls , backend : BackendV1 ) -> SubarchitectureOrder :
89
99
"""Construct the partial order from a coupling map defined as a Qiskit backend.
90
100
91
101
Args:
@@ -144,7 +154,7 @@ def from_string(cls, name: str) -> SubarchitectureOrder:
144
154
return cls .from_library (lib_path )
145
155
return SubarchitectureOrder ()
146
156
147
- def optimal_candidates (self , nqubits : int ) -> list [rx . PyGraph ]:
157
+ def optimal_candidates (self , nqubits : int ) -> list [Graph ]:
148
158
"""Return optimal subarchitecture candidate.
149
159
150
160
Args:
@@ -176,7 +186,7 @@ def optimal_candidates(self, nqubits: int) -> list[rx.PyGraph]:
176
186
177
187
return [self .sgs [n ][i ] for (n , i ) in opt_cands ]
178
188
179
- def covering (self , nqubits : int , size : int ) -> list [rx . PyGraph ]:
189
+ def covering (self , nqubits : int , size : int ) -> list [Graph ]:
180
190
"""Return covering for nqubit circuits.
181
191
182
192
Args:
@@ -218,7 +228,7 @@ def store_library(self, lib_name: str | Path) -> None:
218
228
with path .open ("wb" ) as f :
219
229
pickle .dump (self , f )
220
230
221
- def draw_subarchitecture (self , subarchitecture : rx . PyGraph | tuple [int , int ]) -> figure .Figure :
231
+ def draw_subarchitecture (self , subarchitecture : Graph | tuple [int , int ]) -> figure .Figure :
222
232
"""Create a matplotlib figure showing subarchitecture within the entire architecture.
223
233
224
234
Nodes that are part of the subarchitecture are drawn yellow.
@@ -235,9 +245,9 @@ def draw_subarchitecture(self, subarchitecture: rx.PyGraph | tuple[int, int]) ->
235
245
colors = [SubarchitectureOrder .inactive_color for _ in range (self .arch .num_nodes ())]
236
246
for node in subarchitecture .nodes ():
237
247
colors [node ] = SubarchitectureOrder .active_color
238
- return rx . visualization . mpl_draw (subarchitecture , node_color = colors )
248
+ return rxviz . mpl_draw (self . arch , node_color = colors ) # type: ignore[no-untyped-call]
239
249
240
- def draw_subarchitectures (self , subarchitectures : list [rx . PyGraph ] | list [tuple [int , int ]]) -> list [figure .Figure ]:
250
+ def draw_subarchitectures (self , subarchitectures : list [Graph ] | list [tuple [int , int ]]) -> list [figure .Figure ]:
241
251
"""Create matplotlib figures showing subarchitectures within the entire architecture.
242
252
243
253
For each subarchitecture one figure is drawn.
@@ -254,15 +264,15 @@ def draw_subarchitectures(self, subarchitectures: list[rx.PyGraph] | list[tuple[
254
264
255
265
def __compute_subarchs (self ) -> None :
256
266
"""Compute all subarchitectures of the architecture."""
257
- self .sgs : list [list [rx . PyGraph ]] = [[] for i in range (self .arch .num_nodes () + 1 )]
267
+ self .sgs : list [list [Graph ]] = [[] for i in range (self .arch .num_nodes () + 1 )]
258
268
259
269
for i in range (1 , self .arch .num_nodes () + 1 ):
260
270
node_combinations = combinations (range (self .arch .num_nodes ()), i )
261
271
for sg in (self .arch .subgraph (selected_nodes ) for selected_nodes in node_combinations ):
262
- if rx .is_connected (sg ):
272
+ if rx .is_connected (sg ): # type: ignore[attr-defined]
263
273
new_class = True
264
274
for g in self .sgs [i ]:
265
- if rx .is_isomorphic (g , sg ):
275
+ if rx .is_isomorphic (g , sg ): # type: ignore[attr-defined]
266
276
new_class = False
267
277
break
268
278
if new_class :
@@ -279,7 +289,7 @@ def __compute_subarch_order(self) -> None:
279
289
for n , sgs_n in enumerate (self .sgs [:- 1 ]):
280
290
for i , sg in enumerate (sgs_n ):
281
291
for j , parent_sg in enumerate (self .sgs [n + 1 ]):
282
- matcher = rx .graph_vf2_mapping (parent_sg , sg , subgraph = True )
292
+ matcher = rx .graph_vf2_mapping (parent_sg , sg , subgraph = True ) # type: ignore[attr-defined]
283
293
for iso in matcher :
284
294
self .subarch_order [(n , i )].add ((n + 1 , j ))
285
295
iso_rev = {}
@@ -354,8 +364,8 @@ def __path_order_less(self, n: int, i: int, n_prime: int, i_prime: int) -> bool:
354
364
if v is w :
355
365
continue
356
366
if (
357
- rx .dijkstra_shortest_path_lengths (lhs , v , lambda _x : 1 , goal = w )[w ]
358
- > rx .dijkstra_shortest_path_lengths (rhs , iso [v ], lambda _x : 1 , goal = iso [w ])[iso [w ]]
367
+ rx .dijkstra_shortest_path_lengths (lhs , v , lambda _x : 1 , goal = w )[w ] # type: ignore[attr-defined]
368
+ > rx .dijkstra_shortest_path_lengths (rhs , iso [v ], lambda _x : 1 , goal = iso [w ])[iso [w ]] # type: ignore[attr-defined]
359
369
):
360
370
return True
361
371
return False
0 commit comments