Skip to content

Commit 21da2b5

Browse files
committed
remaining mypy issues solved locally, excluded ipynb from disallow-caps hook
1 parent 3e59e25 commit 21da2b5

File tree

6 files changed

+117
-76
lines changed

6 files changed

+117
-76
lines changed

.pre-commit-config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ repos:
106106
name: Disallow improper capitalization
107107
language: pygrep
108108
entry: PyBind|Numpy|Cmake|CCache|Github|PyTest|Mqt|Tum
109-
exclude: .pre-commit-config.yaml
109+
exclude: '(\.pre-commit-config\.yaml$|\.ipynb$)'
110110

111111
# Check best practices for scientific Python code
112112
- repo: https://github.com/scientific-python/cookie

src/mqt/qecc/co3/plots/evaluation.py

Lines changed: 35 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import logging
77
import pickle # noqa: S403
88
from pathlib import Path
9+
from typing import TYPE_CHECKING, Any
910

1011
import matplotlib.patheffects as path_effects
1112
import matplotlib.pyplot as plt
@@ -14,10 +15,13 @@
1415

1516
import mqt.qecc.co3 as co
1617

18+
if TYPE_CHECKING:
19+
from numpy.typing import NDArray
20+
1721

1822
def collect_data_space_time(
19-
instances: list[dict], hc_params: dict, reps: int, path: str, both_metric: bool = False
20-
) -> list[dict]:
23+
instances: list[dict[str, Any]], hc_params: dict[str, Any], reps: int, path: str, both_metric: bool = False
24+
) -> list[dict[str, Any]]:
2125
"""Collects the data for a run which will compare space and time cost.
2226
2327
Args:
@@ -371,7 +375,7 @@ def collect_data_space_time(
371375

372376

373377
def plot_improvement_circuit_types(
374-
res_lst: list[dict], path: str = "./results", size: tuple[int, int] = (5, 4)
378+
res_lst: list[dict[str, Any]], path: str = "./results", size: tuple[int, int] = (5, 4)
375379
) -> None:
376380
"""Based on a run of collect_data_space time with different circuit types and constant t, and constant factories.
377381
@@ -603,13 +607,13 @@ def plot_improvement_circuit_types(
603607

604608

605609
def plot_f_vs_t(
606-
res_lst: list[dict],
610+
res_lst: list[dict[str, Any]],
607611
q: int,
608612
ratio: float,
609613
layout_name: str,
610614
min_depth: int,
611615
graphtype: str,
612-
hc_params: dict,
616+
hc_params: dict[str, Any],
613617
path: str = "./results",
614618
size: tuple[int, int] = (5, 4),
615619
) -> None:
@@ -682,11 +686,11 @@ def plot_f_vs_t(
682686
available_t_dct = {t: i for i, t in enumerate(available_t)}
683687

684688
# order the entries
685-
available_t = sorted(available_t)
686-
available_f = sorted(available_f)
689+
available_t_sorted = sorted(available_t)
690+
available_f_sorted = sorted(available_f)
687691

688-
available_f_dct = {f: i for i, f in enumerate(available_f)}
689-
available_t_dct = {t: i for i, t in enumerate(available_t)}
692+
available_f_dct = {f: i for i, f in enumerate(available_f_sorted)}
693+
available_t_dct = {t: i for i, t in enumerate(available_t_sorted)}
690694

691695
for el in dct_mat:
692696
f_idx = available_f_dct[len(el["factory_locs"])]
@@ -863,7 +867,7 @@ def plot_f_vs_t(
863867

864868

865869
def plot_ratio_vs_t(
866-
res_lst: list[dict],
870+
res_lst: list[dict[str, Any]],
867871
q: int,
868872
num_factories: int,
869873
layout_name: str,
@@ -938,8 +942,8 @@ def plot_ratio_vs_t(
938942
available_t_dct = {t: i for i, t in enumerate(available_t)}
939943

940944
# order the entries
941-
available_t = sorted(available_t)
942-
available_ratio = sorted(available_ratio)
945+
# available_t = sorted(available_t)
946+
# available_ratio = sorted(available_ratio)
943947

944948
for el in dct_mat:
945949
ratio_idx = available_ratio_dct[el["ratio"]]
@@ -1035,7 +1039,11 @@ def plot_ratio_vs_t(
10351039

10361040

10371041
def plot_space_time(
1038-
instances: list[dict], hc_params: dict, res_lst: list[dict], path: str = "./results", size: tuple[int, int] = (5, 4)
1042+
instances: list[dict[str, Any]],
1043+
hc_params: dict[str, Any],
1044+
res_lst: list[dict[str, Any]],
1045+
path: str = "./results",
1046+
size: tuple[int, int] = (5, 4),
10391047
) -> None:
10401048
"""Plots the results from collect_data_space_time.
10411049
@@ -1138,8 +1146,8 @@ def plot_space_time(
11381146

11391147

11401148
def plot_improvement_f_variation(
1141-
res_lst_crossing: list[dict],
1142-
res_lst_routing: list[dict],
1149+
res_lst_crossing: list[dict[str, Any]],
1150+
res_lst_routing: list[dict[str, Any]],
11431151
t: int,
11441152
ratio: float,
11451153
q: int,
@@ -1268,9 +1276,9 @@ def plot_improvement_f_variation(
12681276
data_abs_r = data_c.copy()
12691277
data_abs_std_r = data_c.copy()
12701278

1271-
available_f_c = sorted(available_f_c)
1279+
# available_f_c = sorted(available_f_c)
12721280

1273-
available_f_dct = {f: i for i, f in enumerate(available_f_c)}
1281+
available_f_dct = {f: i for i, f in enumerate(sorted(available_f_c))}
12741282
available_layout_dct = {f: i for i, f in enumerate(available_layout_c)}
12751283

12761284
for el in dct_mat_c:
@@ -1344,20 +1352,20 @@ def plot_improvement_f_variation(
13441352

13451353

13461354
def plot_f_vs_t_subfigs(
1347-
res_lst1: list[dict],
1348-
res_lst2: list[dict],
1355+
res_lst1: list[dict[str, Any]],
1356+
res_lst2: list[dict[str, Any]],
13491357
q: int,
13501358
ratio: float,
13511359
layout_name: str,
13521360
min_depth: int,
13531361
graphtype: str,
1354-
hc_params: dict,
1362+
hc_params: dict[str, Any],
13551363
path: str = "./results",
13561364
size: tuple[int, int] = (5, 5),
13571365
) -> None:
13581366
"""Plots a Matrix Plot with variation in number of factories and t for two result lists in subplots."""
13591367

1360-
def process_res_list(res_lst: list) -> tuple:
1368+
def process_res_list(res_lst: list[dict[str, Any]]) -> tuple[Any, ...]:
13611369
instances = res_lst[0]["instances"][: len(res_lst)]
13621370
idx_include = [
13631371
i
@@ -1371,8 +1379,8 @@ def process_res_list(res_lst: list) -> tuple:
13711379

13721380
for i in idx_include:
13731381
res = res_lst[i]
1374-
num_init_lst = res["num_init_lst"]
1375-
num_final_lst = res["num_final_lst"]
1382+
num_init_lst: list[int] = res["num_init_lst"]
1383+
num_final_lst: list[int] = res["num_final_lst"]
13761384
improvements = [(ni - nf) / ni for ni, nf in zip(num_init_lst, num_final_lst)]
13771385
dct_mat.append({
13781386
"mean_final_layers": np.mean(num_final_lst),
@@ -1410,7 +1418,7 @@ def process_res_list(res_lst: list) -> tuple:
14101418

14111419
fig, axes = plt.subplots(2, 2, figsize=size, gridspec_kw={"width_ratios": [1, 1], "height_ratios": [1, 1]})
14121420

1413-
def plot_with_text(ax: plt.axes.Axes, data: np.ndarray, data_std: np.ndarray, r: int) -> plt.image.AxesImage:
1421+
def plot_with_text(ax: plt.axes.Axes, data: NDArray[Any], data_std: NDArray[Any], r: int) -> plt.image.AxesImage:
14141422
im = ax.imshow(data, cmap="viridis", aspect="auto")
14151423
for i in range(data.shape[0]):
14161424
for j in range(data.shape[1]):
@@ -1427,7 +1435,7 @@ def plot_with_text(ax: plt.axes.Axes, data: np.ndarray, data_std: np.ndarray, r:
14271435
ax.text(
14281436
j,
14291437
i + 0.25,
1430-
"$\pm$" + str(round(data_std[i, j], r)),
1438+
r"$\pm$" + str(round(data_std[i, j], r)),
14311439
ha="center",
14321440
va="center",
14331441
color="white",
@@ -1440,7 +1448,7 @@ def plot_with_text(ax: plt.axes.Axes, data: np.ndarray, data_std: np.ndarray, r:
14401448
ax.set_yticklabels(list(available_f_dct.keys()))
14411449
return im
14421450

1443-
def plot_with_text_int(ax: plt.axes.Axes, data: np.ndarray, data_std: np.ndarray) -> plt.image.AxesImage:
1451+
def plot_with_text_int(ax: plt.axes.Axes, data: NDArray[Any], data_std: NDArray[Any]) -> plt.image.AxesImage:
14441452
im = ax.imshow(data, cmap="viridis", aspect="auto")
14451453
r = 0
14461454
for i in range(data.shape[0]):
@@ -1458,7 +1466,7 @@ def plot_with_text_int(ax: plt.axes.Axes, data: np.ndarray, data_std: np.ndarray
14581466
ax.text(
14591467
j,
14601468
i + 0.25,
1461-
"$\pm$" + str(int(round(data_std[i, j], r))),
1469+
r"$\pm$" + str(int(round(data_std[i, j], r))),
14621470
ha="center",
14631471
va="center",
14641472
color="white",

src/mqt/qecc/co3/utils/hill_climber.py

Lines changed: 41 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,13 @@
2525

2626
random.seed(45)
2727

28+
2829
class HistoryTemp(TypedDict, total=False):
2930
"""Type for history dictionaries."""
31+
3032
scores: list[int]
31-
layout_init: dict[int | str, tuple[int, int] | list[tuple[int, int]]]
32-
layout_final: dict[int | str, tuple[int, int] | list[tuple[int, int]]]
33+
layout_init: dict[int | str, Any] # tuple[int, int] | list[tuple[int, int]]]
34+
layout_final: dict[int | str, Any] # tuple[int, int] | list[tuple[int, int]]]
3335

3436

3537
def save_to_file(path: str, data: Any) -> None: # noqa: ANN401
@@ -55,7 +57,7 @@ def __init__(
5557
free_rows: list[str] | None = None,
5658
t: int | None = None,
5759
optimize_factories: bool = False,
58-
custom_layout: list[list[tuple[int,int]] | nx.Graph] | None = None,
60+
custom_layout: list[list[tuple[int, int]] | nx.Graph] | None = None,
5961
routing: str = "static",
6062
) -> None:
6163
"""Initializes the Hill Climbing with Random Restarts algorithm.
@@ -133,7 +135,7 @@ def __init__(
133135
elif layout_type == "hex":
134136
data_qubit_locs = lat.gen_layout_hex()
135137
elif layout_type == "custom":
136-
if custom_layout is not None: #only for mypy
138+
if custom_layout is not None: # only for mypy
137139
data_qubit_locs = custom_layout[0]
138140
self.lat.G = custom_layout[1]
139141
else:
@@ -148,7 +150,9 @@ def __init__(
148150
num for tup in self.circuit for num in (tup if isinstance(tup, tuple) else (tup,))
149151
]
150152
else:
151-
flattened_qubit_labels = [num for tup in self.circuit if isinstance(tup, tuple) for num in tup] #isinstance only added for mypy
153+
flattened_qubit_labels = [
154+
num for tup in self.circuit if isinstance(tup, tuple) for num in tup
155+
] # isinstance only added for mypy
152156
self.q = max(flattened_qubit_labels) + 1
153157
if self.q < len(self.data_qubit_locs):
154158
self.data_qubit_locs = self.data_qubit_locs[: self.q] # cut-off unnecessary qubit spots.
@@ -234,16 +238,22 @@ def add_left_g(g: nx.Graph) -> nx.Graph:
234238

235239
return g
236240

237-
def evaluate_solution(self, layout: dict[int | str, tuple[int, int] | list[tuple[int,int]]]) -> int:
241+
def evaluate_solution(self, layout: dict[int | str, tuple[int, int] | list[tuple[int, int]]]) -> int:
238242
"""Evaluates the layout=solution according to self.metric."""
239243
terminal_pairs = translate_layout_circuit(self.circuit, layout)
240-
factory_positions: list[tuple[int,int]]
241-
#if type(layout["factory_positions"]) is list[tuple[int,int]] or list:
242-
factory_positions = layout["factory_positions"]
243-
#else:
244+
# factory_positions: list[tuple[int, int]]
245+
# if type(layout["factory_positions"]) is list[tuple[int,int]] or list:
246+
factory_positions_temp = layout["factory_positions"]
247+
if isinstance(factory_positions_temp, list):
248+
factory_positions: list[tuple[int, int]] = factory_positions_temp
249+
else:
250+
msg = "`layout['factory_positions']` must be of type list[tuple[int,int]] but this is not even a list."
251+
raise TypeError(msg)
252+
253+
# else:
244254
# msg = f"factory positions of layout must be list[tuple[int,int]]. But you got {type(layout['factory_positions'])}"
245255
# raise TypeError(msg)
246-
router : ShortestFirstRouter | ShortestFirstRouterTGatesDyn | ShortestFirstRouterTGates
256+
router: ShortestFirstRouter | ShortestFirstRouterTGatesDyn | ShortestFirstRouterTGates
247257
if any(type(el) is int for el in self.circuit):
248258
if self.t is not None:
249259
if self.routing == "static":
@@ -258,7 +268,7 @@ def evaluate_solution(self, layout: dict[int | str, tuple[int, int] | list[tuple
258268
router.G = self.lat.G.copy()
259269
else: # if not custom, update self.lat.G by the router's G because m,n might differ from initial values.
260270
self.lat.G = router.G # also add to self
261-
if self.free_rows is not None: #for mypy # noqa: SIM102
271+
if self.free_rows is not None: # for mypy # noqa: SIM102
262272
if "left" in self.free_rows:
263273
router.G = self.add_left_g(router.G)
264274
self.lat.G = router.G # also add to self
@@ -281,15 +291,15 @@ def evaluate_solution(self, layout: dict[int | str, tuple[int, int] | list[tuple
281291
cost: int
282292
if self.metric == "crossing":
283293
if self.optimize_factories and any(type(el) is int for el in self.circuit):
284-
router = cast("ShortestFirstRouterTGates | ShortestFirstRouterTGatesDyn", router)
294+
router = cast("ShortestFirstRouterTGates | ShortestFirstRouterTGatesDyn", router)
285295
cost = np.sum(router.count_crossings_per_layer(t_crossings=True))
286296
elif self.optimize_factories is False and any(type(el) is int for el in self.circuit):
287-
router = cast("ShortestFirstRouterTGates | ShortestFirstRouterTGatesDyn", router)
297+
router = cast("ShortestFirstRouterTGates | ShortestFirstRouterTGatesDyn", router)
288298
cost = np.sum(router.count_crossings_per_layer(t_crossings=False))
289299
else:
290300
cost = np.sum(router.count_crossings_per_layer())
291301
elif self.metric == "distance":
292-
router = cast("ShortestFirstRouter", router)
302+
router = cast("ShortestFirstRouter", router)
293303
distances = router.measure_terminal_pair_distances()
294304
cost = np.sum(distances)
295305
if any(type(el) is int for el in self.circuit):
@@ -298,14 +308,14 @@ def evaluate_solution(self, layout: dict[int | str, tuple[int, int] | list[tuple
298308
if self.routing == "static":
299309
vdp_layers = router.find_total_vdp_layers()
300310
elif self.routing == "dynamic":
301-
router = cast("ShortestFirstRouterTGatesDyn", router)
311+
router = cast("ShortestFirstRouterTGatesDyn", router)
302312
vdp_layers = router.find_total_vdp_layers_dyn()
303313
cost = len(vdp_layers)
304314
return cost
305315

306-
def gen_random_qubit_assignment(self) -> dict[int | str, tuple[int, int] | list[tuple[int,int]]]:
316+
def gen_random_qubit_assignment(self) -> dict[int | str, tuple[int, int] | list[tuple[int, int]]]:
307317
"""Yields a random qubit assignment given the `data_qubit_locs`."""
308-
layout: dict[int | str, tuple[int, int] | list[tuple[int,int]]] = {}
318+
layout: dict[int | str, tuple[int, int] | list[tuple[int, int]]] = {}
309319
perm = list(range(self.q))
310320
random.shuffle(perm)
311321
for i, j in zip(
@@ -323,7 +333,9 @@ def gen_random_qubit_assignment(self) -> dict[int | str, tuple[int, int] | list[
323333

324334
return layout
325335

326-
def gen_neighborhood(self, layout: dict[int | str, tuple[int, int] | list[tuple[int,int]]]) -> list[dict[int | str, tuple[int, int] | list[tuple[int,int]]]]:
336+
def gen_neighborhood(
337+
self, layout: dict[int | str, tuple[int, int] | list[tuple[int, int]]]
338+
) -> list[dict[int | str, tuple[int, int] | list[tuple[int, int]]]]:
327339
"""Creates the Neighborhood of a given layout by going through each terminal pair and swapping their positions.
328340
329341
If there are no T gates, there will be l=len(terminal_pairs) elements in the neighborhood.
@@ -364,12 +376,9 @@ def gen_neighborhood(self, layout: dict[int | str, tuple[int, int] | list[tuple[
364376

365377
return neighborhood
366378

367-
def _parallel_hill_climbing(self, restart: int) -> tuple[
368-
int,
369-
dict[int | str, tuple[int, int] | list[tuple[int,int]]],
370-
int,
371-
HistoryTemp
372-
]:
379+
def _parallel_hill_climbing(
380+
self, restart: int
381+
) -> tuple[int, dict[int | str, tuple[int, int] | list[tuple[int, int]]], int, HistoryTemp]:
373382
"""Helper method for parallel execution of hill climbing restarts.
374383
375384
Args:
@@ -408,7 +417,9 @@ def _parallel_hill_climbing(self, restart: int) -> tuple[
408417
history_temp.update({"layout_final": current_solution.copy()})
409418
return restart, current_solution, current_score, history_temp
410419

411-
def run(self, prefix: str, suffix: str, parallel: bool, processes: int = 8) -> tuple[dict[int | str, tuple[int, int] | list[tuple[int, int]]], int, int, dict[int,HistoryTemp]]:
420+
def run(
421+
self, prefix: str, suffix: str, parallel: bool, processes: int = 8
422+
) -> tuple[dict[int | str, tuple[int, int] | list[tuple[int, int]]], int, int, dict[int, HistoryTemp]]:
412423
"""Executes the Hill Climbing algorithm with random restarts.
413424
414425
Args:
@@ -495,7 +506,10 @@ def run(self, prefix: str, suffix: str, parallel: bool, processes: int = 8) -> t
495506
return best_solution, best_score, best_rep, score_history
496507

497508
def plot_history(
498-
self, score_history: HistoryTemp, filename: str = "./hc_history_plot.pdf", size: tuple[float, float] = (5, 5)
509+
self,
510+
score_history: dict[int, HistoryTemp],
511+
filename: str = "./hc_history_plot.pdf",
512+
size: tuple[float, float] = (5, 5),
499513
) -> None:
500514
"""Plots the scores for each restart and iteration.
501515

0 commit comments

Comments
 (0)