iqm-benchmarks 2.43__py3-none-any.whl → 2.44__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- iqm/benchmarks/entanglement/ghz.py +3 -3
- iqm/benchmarks/entanglement/graph_states.py +21 -21
- iqm/benchmarks/quantum_volume/clops.py +2 -3
- iqm/benchmarks/randomized_benchmarking/eplg/eplg.py +23 -24
- iqm/benchmarks/utils.py +72 -8
- iqm/benchmarks/utils_plots.py +309 -65
- {iqm_benchmarks-2.43.dist-info → iqm_benchmarks-2.44.dist-info}/METADATA +1 -1
- {iqm_benchmarks-2.43.dist-info → iqm_benchmarks-2.44.dist-info}/RECORD +11 -11
- {iqm_benchmarks-2.43.dist-info → iqm_benchmarks-2.44.dist-info}/WHEEL +0 -0
- {iqm_benchmarks-2.43.dist-info → iqm_benchmarks-2.44.dist-info}/licenses/LICENSE +0 -0
- {iqm_benchmarks-2.43.dist-info → iqm_benchmarks-2.44.dist-info}/top_level.txt +0 -0
|
@@ -145,7 +145,6 @@ def fidelity_ghz_coherences(dataset: xr.Dataset, qubit_layout: List[int], circui
|
|
|
145
145
|
phases = [np.pi * i / (num_qubits + 1) for i in range(2 * num_qubits + 2)]
|
|
146
146
|
idx = BenchmarkObservationIdentifier(qubit_layout).string_identifier
|
|
147
147
|
transpiled_circuits = circuits["transpiled_circuits"]
|
|
148
|
-
num_shots = dataset.attrs["shots"]
|
|
149
148
|
num_circuits = len(transpiled_circuits[f"{qubit_layout}_native_ghz"].circuits)
|
|
150
149
|
|
|
151
150
|
# Computing the phase acquired by the |11...1> component for each interval
|
|
@@ -155,8 +154,9 @@ def fidelity_ghz_coherences(dataset: xr.Dataset, qubit_layout: List[int], circui
|
|
|
155
154
|
counts = xrvariable_to_counts(dataset, f"{idx}", num_circuits)
|
|
156
155
|
all_zero_probability_list = [] # An ordered list for storing the probabilities of returning to the |00..0> state
|
|
157
156
|
for count in counts[1:]:
|
|
157
|
+
normalization = np.sum(list(count.values()))
|
|
158
158
|
if "0" * num_qubits in count.keys():
|
|
159
|
-
probability = count["0" * num_qubits] /
|
|
159
|
+
probability = count["0" * num_qubits] / normalization
|
|
160
160
|
else:
|
|
161
161
|
probability = 0
|
|
162
162
|
all_zero_probability_list.append(probability)
|
|
@@ -165,7 +165,7 @@ def fidelity_ghz_coherences(dataset: xr.Dataset, qubit_layout: List[int], circui
|
|
|
165
165
|
i_n = np.abs(np.dot(complex_coefficients, np.array(all_zero_probability_list))) / (len(phases))
|
|
166
166
|
|
|
167
167
|
# Extracting the probabilities of the 00...0 and 11...1 bit strings
|
|
168
|
-
probs_direct = {label: count /
|
|
168
|
+
probs_direct = {label: count / np.sum(list(counts[0].values())) for label, count in counts[0].items()}
|
|
169
169
|
|
|
170
170
|
# Computing GHZ state fidelity from i_n and the probabilities according to the method in [Mooney, 2021]
|
|
171
171
|
p0 = probs_direct["0" * num_qubits] if "0" * num_qubits in probs_direct.keys() else 0
|
|
@@ -439,34 +439,29 @@ def plot_max_negativities_graph(
|
|
|
439
439
|
fig = plt.figure()
|
|
440
440
|
ax = plt.axes()
|
|
441
441
|
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
else:
|
|
446
|
-
graph_backend = backend_coupling_map.graph.to_undirected(multigraph=False)
|
|
447
|
-
qubit_positions = GraphPositions.create_positions(graph_backend)
|
|
448
|
-
else:
|
|
449
|
-
graph_backend = backend_coupling_map.graph.to_undirected(multigraph=False)
|
|
450
|
-
if num_qubits in (20, 7):
|
|
451
|
-
station = "garnet" if num_qubits == 20 else "deneb"
|
|
452
|
-
qubit_positions = GraphPositions.predefined_stations[station]
|
|
453
|
-
else:
|
|
454
|
-
qubit_positions = GraphPositions.create_positions(graph_backend)
|
|
442
|
+
qubit_positions = GraphPositions.get_positions(
|
|
443
|
+
station=station, graph=backend_coupling_map.graph.to_undirected(multigraph=False), num_qubits=num_qubits
|
|
444
|
+
)
|
|
455
445
|
|
|
456
446
|
# Normalize negativity values to the range [0, 1] for color mapping
|
|
457
447
|
norm = plt.Normalize(vmin=cast(float, min(negativity_values)), vmax=cast(float, max(negativity_values)))
|
|
458
|
-
edge_colors = [
|
|
448
|
+
edge_colors = [
|
|
449
|
+
cmap(norm(negativity_edges[edge])) if edge in qubit_pairs else "lightgray" for edge in backend_coupling_map
|
|
450
|
+
] #
|
|
451
|
+
nodes = list(set(v for edge in backend_coupling_map for v in edge))
|
|
452
|
+
active_nodes = list(set(v for edge in qubit_pairs for v in edge))
|
|
453
|
+
node_colors = ["lightgray" if v not in active_nodes else "k" for v in nodes]
|
|
459
454
|
|
|
460
455
|
nx.draw_networkx(
|
|
461
456
|
rx_to_nx_graph(backend_coupling_map),
|
|
462
457
|
pos=qubit_positions,
|
|
463
|
-
nodelist=
|
|
464
|
-
|
|
458
|
+
nodelist=nodes,
|
|
459
|
+
edgelist=list(backend_coupling_map),
|
|
460
|
+
labels={x: qubit_names[x] for x in nodes},
|
|
465
461
|
font_size=6.5,
|
|
466
|
-
edgelist=qubit_pairs,
|
|
467
462
|
width=4.0,
|
|
468
463
|
edge_color=edge_colors,
|
|
469
|
-
node_color=
|
|
464
|
+
node_color=node_colors,
|
|
470
465
|
font_color="w",
|
|
471
466
|
ax=ax,
|
|
472
467
|
)
|
|
@@ -490,6 +485,8 @@ def plot_max_negativities_graph(
|
|
|
490
485
|
f"{shots_string}; Bootstraps: {num_bootstraps}"
|
|
491
486
|
f"\n{timestamp}"
|
|
492
487
|
)
|
|
488
|
+
# Invert y-axis to match the intended qubit positions
|
|
489
|
+
plt.gca().invert_yaxis()
|
|
493
490
|
plt.close()
|
|
494
491
|
|
|
495
492
|
return fig_name, fig
|
|
@@ -955,7 +952,7 @@ def negativity_analysis(run: BenchmarkRunResult) -> BenchmarkAnalysisResult:
|
|
|
955
952
|
dataset = run.dataset.copy(deep=True)
|
|
956
953
|
qcvv_logger.info("Dataset imported OK")
|
|
957
954
|
backend_name = dataset.attrs["backend_name"]
|
|
958
|
-
|
|
955
|
+
coupling_map_full = dataset.attrs["coupling_map_full"]
|
|
959
956
|
qubit_names = dataset.attrs["qubit_names"]
|
|
960
957
|
execution_timestamp = dataset.attrs["execution_timestamp"]
|
|
961
958
|
tomography = dataset.attrs["tomography"]
|
|
@@ -1004,7 +1001,7 @@ def negativity_analysis(run: BenchmarkRunResult) -> BenchmarkAnalysisResult:
|
|
|
1004
1001
|
|
|
1005
1002
|
fig_name, fig = plot_max_negativities_graph(
|
|
1006
1003
|
negativities=max_negativities,
|
|
1007
|
-
backend_coupling_map=
|
|
1004
|
+
backend_coupling_map=coupling_map_full,
|
|
1008
1005
|
qubit_names=qubit_names,
|
|
1009
1006
|
timestamp=execution_timestamp,
|
|
1010
1007
|
tomography=tomography,
|
|
@@ -1066,8 +1063,11 @@ class GraphStateBenchmark(Benchmark):
|
|
|
1066
1063
|
dataset.attrs["execution_timestamp"] = self.execution_timestamp
|
|
1067
1064
|
dataset.attrs["backend_configuration_name"] = self.backend_configuration_name
|
|
1068
1065
|
dataset.attrs["backend_name"] = self.backend.name
|
|
1069
|
-
dataset.attrs["qubit_names"] = {
|
|
1066
|
+
dataset.attrs["qubit_names"] = {
|
|
1067
|
+
qubit: self.backend.index_to_qubit_name(qubit) for qubit in np.arange(self.backend.num_qubits)
|
|
1068
|
+
}
|
|
1070
1069
|
dataset.attrs["coupling_map"] = self.coupling_map
|
|
1070
|
+
dataset.attrs["coupling_map_full"] = self.backend.coupling_map
|
|
1071
1071
|
|
|
1072
1072
|
for key, value in self.configuration:
|
|
1073
1073
|
if key == "benchmark": # Avoid saving the class object
|
|
@@ -21,7 +21,6 @@ from math import floor, pi
|
|
|
21
21
|
from time import perf_counter, strftime
|
|
22
22
|
from typing import Any, Dict, List, Sequence, Tuple, Type
|
|
23
23
|
|
|
24
|
-
import matplotlib as mpl
|
|
25
24
|
from matplotlib.figure import Figure
|
|
26
25
|
import matplotlib.pyplot as plt
|
|
27
26
|
import numpy as np
|
|
@@ -178,8 +177,8 @@ def retrieve_clops_elapsed_times(job_meta: Dict[str, Dict[str, Any]]) -> Dict[st
|
|
|
178
177
|
# submit_i = datetime.strptime(x["submit_start"], job_time_format)
|
|
179
178
|
execution_f = datetime.strptime(x["execution_end"], job_time_format)
|
|
180
179
|
execution_i = datetime.strptime(x["execution_start"], job_time_format)
|
|
181
|
-
job_f = datetime.strptime(x["
|
|
182
|
-
job_i = datetime.strptime(x["
|
|
180
|
+
job_f = datetime.strptime(x["ready"], job_time_format)
|
|
181
|
+
job_i = datetime.strptime(x["received"], job_time_format)
|
|
183
182
|
|
|
184
183
|
all_job_elapsed[update][batch] = {
|
|
185
184
|
"job_total": job_f - job_i,
|
|
@@ -5,6 +5,7 @@ Error Per Layered Gate (EPLG).
|
|
|
5
5
|
from time import strftime
|
|
6
6
|
from typing import Dict, Optional, Sequence, Tuple, Type, cast
|
|
7
7
|
|
|
8
|
+
from matplotlib.colors import to_rgba
|
|
8
9
|
from matplotlib.figure import Figure
|
|
9
10
|
import matplotlib.pyplot as plt
|
|
10
11
|
import networkx as nx
|
|
@@ -76,38 +77,35 @@ def plot_layered_fidelities_graph(
|
|
|
76
77
|
fig = plt.figure()
|
|
77
78
|
ax = plt.axes()
|
|
78
79
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
else:
|
|
83
|
-
if num_qubits in (20, 7):
|
|
84
|
-
station = "garnet" if num_qubits == 20 else "deneb"
|
|
85
|
-
qubit_positions = GraphPositions.predefined_stations[station]
|
|
86
|
-
else:
|
|
87
|
-
graph_backend = backend_coupling_map.graph.to_undirected(multigraph=False)
|
|
88
|
-
qubit_positions = GraphPositions.create_positions(graph_backend)
|
|
89
|
-
else:
|
|
90
|
-
graph_backend = backend_coupling_map.graph.to_undirected(multigraph=False)
|
|
91
|
-
if num_qubits in (20, 7):
|
|
92
|
-
station = "garnet" if num_qubits == 20 else "deneb"
|
|
93
|
-
qubit_positions = GraphPositions.predefined_stations[station]
|
|
94
|
-
else:
|
|
95
|
-
qubit_positions = GraphPositions.create_positions(graph_backend)
|
|
80
|
+
qubit_positions = GraphPositions.get_positions(
|
|
81
|
+
station=station, graph=backend_coupling_map.graph.to_undirected(multigraph=False), num_qubits=num_qubits
|
|
82
|
+
)
|
|
96
83
|
|
|
97
84
|
# Normalize fidelity values to the range [0, 1] for color mapping
|
|
98
85
|
norm = plt.Normalize(vmin=cast(float, min(fidelity_values)), vmax=cast(float, max(fidelity_values)))
|
|
99
|
-
edge_colors = [
|
|
86
|
+
edge_colors = []
|
|
87
|
+
for edge in backend_coupling_map:
|
|
88
|
+
if edge in fidelity_edges:
|
|
89
|
+
edge_colors.append(cmap(norm(fidelity_edges[edge])))
|
|
90
|
+
elif (edge[1], edge[0]) in fidelity_edges:
|
|
91
|
+
edge_colors.append(cmap(norm(fidelity_edges[(edge[1], edge[0])])))
|
|
92
|
+
else:
|
|
93
|
+
edge_colors.append(to_rgba("lightgray"))
|
|
94
|
+
|
|
95
|
+
nodes = list(set(v for edge in backend_coupling_map for v in edge))
|
|
96
|
+
active_nodes = list(set(v for edge in qubit_pairs for v in edge))
|
|
97
|
+
node_colors = ["lightgray" if v not in active_nodes else "k" for v in nodes]
|
|
100
98
|
|
|
101
99
|
nx.draw_networkx(
|
|
102
100
|
rx_to_nx_graph(backend_coupling_map),
|
|
103
101
|
pos=qubit_positions,
|
|
104
|
-
nodelist=
|
|
105
|
-
|
|
102
|
+
nodelist=nodes,
|
|
103
|
+
edgelist=list(backend_coupling_map),
|
|
104
|
+
labels={x: qubit_names[x] for x in nodes},
|
|
106
105
|
font_size=6.5,
|
|
107
|
-
edgelist=qubit_pairs,
|
|
108
106
|
width=4.0,
|
|
109
107
|
edge_color=edge_colors,
|
|
110
|
-
node_color=
|
|
108
|
+
node_color=node_colors,
|
|
111
109
|
font_color="w",
|
|
112
110
|
ax=ax,
|
|
113
111
|
)
|
|
@@ -116,7 +114,7 @@ def plot_layered_fidelities_graph(
|
|
|
116
114
|
sm = plt.cm.ScalarMappable(cmap=cmap, norm=norm)
|
|
117
115
|
sm.set_array([])
|
|
118
116
|
cbar = fig.colorbar(sm, ax=ax, shrink=0.5, label="Layered Fidelity (%)", format="%.2f")
|
|
119
|
-
cbar.set_ticks(np.linspace(min(fidelity_values), max(fidelity_values), 5, endpoint=True))
|
|
117
|
+
cbar.set_ticks(tuple(np.linspace(min(fidelity_values), max(fidelity_values), 5, endpoint=True)))
|
|
120
118
|
|
|
121
119
|
station_string = "IQM Backend" if station is None else station.capitalize()
|
|
122
120
|
|
|
@@ -124,6 +122,7 @@ def plot_layered_fidelities_graph(
|
|
|
124
122
|
f"EPLG estimate: {eplg_estimate['value']:.2e} +/- {eplg_estimate['uncertainty']:.2e}\n" if eplg_estimate else ""
|
|
125
123
|
)
|
|
126
124
|
plt.title(f"Layered fidelities for qubit pairs in {station_string}\n" f"{eplg_string}{timestamp}")
|
|
125
|
+
plt.gca().invert_yaxis()
|
|
127
126
|
plt.close()
|
|
128
127
|
|
|
129
128
|
return fig_name, fig
|
|
@@ -190,8 +189,8 @@ def eplg_analysis(run: BenchmarkRunResult) -> BenchmarkAnalysisResult:
|
|
|
190
189
|
backend_num_qubits=backend_num_qubits,
|
|
191
190
|
edge_list=edges,
|
|
192
191
|
timestamp=timestamp,
|
|
193
|
-
disjoint_layers=disjoint_layers,
|
|
194
192
|
station=backend_configuration_name,
|
|
193
|
+
disjoint_layers=disjoint_layers,
|
|
195
194
|
qubit_names=qubit_names,
|
|
196
195
|
is_eplg=True,
|
|
197
196
|
)
|
iqm/benchmarks/utils.py
CHANGED
|
@@ -48,6 +48,9 @@ from iqm.qiskit_iqm.iqm_job import IQMJob
|
|
|
48
48
|
from iqm.qiskit_iqm.iqm_provider import IQMProvider
|
|
49
49
|
|
|
50
50
|
|
|
51
|
+
# pylint: disable=too-many-lines
|
|
52
|
+
|
|
53
|
+
|
|
51
54
|
def timeit(f):
|
|
52
55
|
"""Calculates the amount of time a function takes to execute.
|
|
53
56
|
|
|
@@ -283,12 +286,18 @@ def get_active_qubits(qc: QuantumCircuit) -> List[int]:
|
|
|
283
286
|
return list(active_qubits)
|
|
284
287
|
|
|
285
288
|
|
|
286
|
-
def extract_fidelities(cal_url: str) ->
|
|
289
|
+
def extract_fidelities(cal_url: str, all_metrics: bool = False) -> Union[
|
|
290
|
+
Tuple[List[List[int]], List[float], str, Dict[int, int]],
|
|
291
|
+
Tuple[List[List[int]], List[float], str, Dict[int, int], Dict[str, Dict[Union[int, Tuple[int, int]], float]]],
|
|
292
|
+
]:
|
|
287
293
|
"""Returns couplings and CZ-fidelities from calibration data URL
|
|
288
294
|
|
|
289
295
|
Args:
|
|
290
296
|
cal_url: str
|
|
291
297
|
The url under which the calibration data for the backend can be found
|
|
298
|
+
all_metrics: bool
|
|
299
|
+
If True, returns a dictionary with all metrics from the calibration data
|
|
300
|
+
Default is False
|
|
292
301
|
Returns:
|
|
293
302
|
list_couplings: List[List[int]]
|
|
294
303
|
A list of pairs, each of which is a qubit coupling for which the calibration
|
|
@@ -297,6 +306,13 @@ def extract_fidelities(cal_url: str) -> tuple[list[list[int]], list[float], str]
|
|
|
297
306
|
A list of CZ fidelities from the calibration url, ordered in the same way as list_couplings
|
|
298
307
|
topology: str
|
|
299
308
|
Name of the chip topology layout, currently either "star" or "crystal"
|
|
309
|
+
qubit_mapping: Dict[int, int]
|
|
310
|
+
Enumerating all calibrated qubits starting from 0. For instance if on a 5 qubit chip the qubits 2, 3 are calibrated,
|
|
311
|
+
the mapping will be {2: 0, 3: 1}.
|
|
312
|
+
metrics_dict: Dict
|
|
313
|
+
Dictionary of all metrics (returned only if all_metrics=True)
|
|
314
|
+
Format: {metric_name: {qubit: value}} for single qubit metrics
|
|
315
|
+
Format: {metric_name: {(qubit_1, qubit_2): value}} for two qubit metrics
|
|
300
316
|
"""
|
|
301
317
|
headers = {"Accept": "application/json", "Authorization": "Bearer " + os.environ["IQM_TOKEN"]}
|
|
302
318
|
r = requests.get(cal_url, headers=headers, timeout=60)
|
|
@@ -304,6 +320,7 @@ def extract_fidelities(cal_url: str) -> tuple[list[list[int]], list[float], str]
|
|
|
304
320
|
cal_keys = {
|
|
305
321
|
el2["key"]: (i, j) for i, el1 in enumerate(calibration["calibrations"]) for j, el2 in enumerate(el1["metrics"])
|
|
306
322
|
}
|
|
323
|
+
resonator_names = ["COMPR", "COMP_R", "MPR1", "MPR_1"]
|
|
307
324
|
list_couplings = []
|
|
308
325
|
list_fids = []
|
|
309
326
|
if "double_move_gate_fidelity" in cal_keys.keys():
|
|
@@ -313,18 +330,65 @@ def extract_fidelities(cal_url: str) -> tuple[list[list[int]], list[float], str]
|
|
|
313
330
|
i, j = cal_keys["cz_gate_fidelity"]
|
|
314
331
|
topology = "crystal"
|
|
315
332
|
for item in calibration["calibrations"][i]["metrics"][j]["metrics"]:
|
|
316
|
-
qb1 =
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
333
|
+
qb1 = (
|
|
334
|
+
int(item["locus"][0][2:])
|
|
335
|
+
if not any(resonator in item["locus"][0] for resonator in resonator_names)
|
|
336
|
+
else 0
|
|
337
|
+
)
|
|
338
|
+
qb2 = (
|
|
339
|
+
int(item["locus"][1][2:])
|
|
340
|
+
if not any(resonator in item["locus"][1] for resonator in resonator_names)
|
|
341
|
+
else 0
|
|
342
|
+
)
|
|
343
|
+
list_couplings.append([qb1, qb2])
|
|
322
344
|
list_fids.append(float(item["value"]))
|
|
323
345
|
calibrated_qubits = set(np.array(list_couplings).reshape(-1))
|
|
346
|
+
|
|
347
|
+
# Process all metrics if all_metrics is True
|
|
348
|
+
metrics_dict: Dict[str, Dict[Union[int, Tuple[int, int]], float]] = {}
|
|
349
|
+
for metric_key, (i, j) in cal_keys.items():
|
|
350
|
+
metric_data = calibration["calibrations"][i]["metrics"][j]["metrics"]
|
|
351
|
+
metrics_dict[metric_key] = {}
|
|
352
|
+
|
|
353
|
+
for item in metric_data:
|
|
354
|
+
# Determine if it's a single or two-qubit metric
|
|
355
|
+
if "component" in item:
|
|
356
|
+
# Single qubit metric
|
|
357
|
+
component = item["component"]
|
|
358
|
+
if not any(resonator in component for resonator in resonator_names):
|
|
359
|
+
qb = int(component[2:])
|
|
360
|
+
metrics_dict[metric_key][qb] = float(item["value"])
|
|
361
|
+
calibrated_qubits.add(qb) # Add qubits that have a single qubit metric
|
|
362
|
+
if "locus" in item and len(item["locus"]) == 2:
|
|
363
|
+
# Two qubit metric
|
|
364
|
+
locus = item["locus"]
|
|
365
|
+
if not (any(resonator in locus[0] for resonator in resonator_names) or any(resonator in locus[1] for resonator in resonator_names)):
|
|
366
|
+
qb1 = int(locus[0][2:])
|
|
367
|
+
qb2 = int(locus[1][2:])
|
|
368
|
+
metrics_dict[metric_key][(qb1, qb2)] = float(item["value"])
|
|
369
|
+
|
|
370
|
+
# Enumerate all calibrated qubits starting from 0
|
|
324
371
|
qubit_mapping = {qubit: idx for idx, qubit in enumerate(calibrated_qubits)}
|
|
325
372
|
list_couplings = [[qubit_mapping[edge[0]], qubit_mapping[edge[1]]] for edge in list_couplings]
|
|
326
373
|
|
|
327
|
-
|
|
374
|
+
# Apply the qubit mapping to metrics_dict
|
|
375
|
+
remapped_metrics_dict = {}
|
|
376
|
+
for metric_key, metric_values in metrics_dict.items():
|
|
377
|
+
remapped_metrics_dict[metric_key] = {}
|
|
378
|
+
for key, value in metric_values.items():
|
|
379
|
+
if isinstance(key, tuple):
|
|
380
|
+
# Two-qubit metric
|
|
381
|
+
remapped_metrics_dict[metric_key][(qubit_mapping[key[0]], qubit_mapping[key[1]])] = value
|
|
382
|
+
else:
|
|
383
|
+
# Single-qubit metric
|
|
384
|
+
remapped_metrics_dict[metric_key][qubit_mapping[key]] = value
|
|
385
|
+
metrics_dict = remapped_metrics_dict
|
|
386
|
+
|
|
387
|
+
# If all_metrics is False, only return everything related to CZ fidelites
|
|
388
|
+
if not all_metrics:
|
|
389
|
+
return list_couplings, list_fids, topology, qubit_mapping
|
|
390
|
+
|
|
391
|
+
return list_couplings, list_fids, topology, qubit_mapping, metrics_dict
|
|
328
392
|
|
|
329
393
|
|
|
330
394
|
# pylint: disable=too-many-branches
|
iqm/benchmarks/utils_plots.py
CHANGED
|
@@ -17,9 +17,10 @@ Plotting and visualization utility functions
|
|
|
17
17
|
"""
|
|
18
18
|
from dataclasses import dataclass
|
|
19
19
|
import os
|
|
20
|
-
from typing import Dict, List, Literal, Optional, Sequence, Tuple
|
|
20
|
+
from typing import Dict, List, Literal, Optional, Sequence, Tuple, cast
|
|
21
21
|
|
|
22
22
|
from matplotlib.figure import Figure
|
|
23
|
+
from matplotlib.patches import Circle, FancyBboxPatch
|
|
23
24
|
import matplotlib.pyplot as plt
|
|
24
25
|
import networkx as nx
|
|
25
26
|
import numpy as np
|
|
@@ -40,9 +41,9 @@ class GraphPositions:
|
|
|
40
41
|
provides methods to generate positions for different layout types.
|
|
41
42
|
|
|
42
43
|
Attributes:
|
|
43
|
-
garnet_positions (Dict[int, Tuple[
|
|
44
|
-
deneb_positions (Dict[int, Tuple[
|
|
45
|
-
predefined_stations (Dict[str, Dict[int, Tuple[
|
|
44
|
+
garnet_positions (Dict[int, Tuple[float, float]]): Mapping of node indices to (x,y) positions for Garnet chip.
|
|
45
|
+
deneb_positions (Dict[int, Tuple[float, float]]): Mapping of node indices to (x,y) positions for Deneb chip.
|
|
46
|
+
predefined_stations (Dict[str, Dict[int, Tuple[float, float]]]): Mapping of chip names to their position dictionaries.
|
|
46
47
|
"""
|
|
47
48
|
|
|
48
49
|
garnet_positions = {
|
|
@@ -68,15 +69,116 @@ class GraphPositions:
|
|
|
68
69
|
19: (3.0, 1.0),
|
|
69
70
|
}
|
|
70
71
|
|
|
72
|
+
emerald_positions = {
|
|
73
|
+
0: (10, 10),
|
|
74
|
+
1: (11, 9),
|
|
75
|
+
2: (7, 11),
|
|
76
|
+
3: (8, 10),
|
|
77
|
+
4: (9, 9),
|
|
78
|
+
5: (10, 8),
|
|
79
|
+
6: (11, 7),
|
|
80
|
+
7: (5, 11),
|
|
81
|
+
8: (6, 10),
|
|
82
|
+
9: (7, 9),
|
|
83
|
+
10: (8, 8),
|
|
84
|
+
11: (9, 7),
|
|
85
|
+
12: (10, 6),
|
|
86
|
+
13: (11, 5),
|
|
87
|
+
14: (3, 11),
|
|
88
|
+
15: (4, 10),
|
|
89
|
+
16: (5, 9),
|
|
90
|
+
17: (6, 8),
|
|
91
|
+
18: (7, 7),
|
|
92
|
+
19: (8, 6),
|
|
93
|
+
20: (9, 5),
|
|
94
|
+
21: (10, 4),
|
|
95
|
+
22: (2, 10),
|
|
96
|
+
23: (3, 9),
|
|
97
|
+
24: (4, 8),
|
|
98
|
+
25: (5, 7),
|
|
99
|
+
26: (6, 6),
|
|
100
|
+
27: (7, 5),
|
|
101
|
+
28: (8, 4),
|
|
102
|
+
29: (9, 3),
|
|
103
|
+
30: (10, 2),
|
|
104
|
+
31: (2, 8),
|
|
105
|
+
32: (3, 7),
|
|
106
|
+
33: (4, 6),
|
|
107
|
+
34: (5, 5),
|
|
108
|
+
35: (6, 4),
|
|
109
|
+
36: (7, 3),
|
|
110
|
+
37: (8, 2),
|
|
111
|
+
38: (9, 1),
|
|
112
|
+
39: (1, 7),
|
|
113
|
+
40: (2, 6),
|
|
114
|
+
41: (3, 5),
|
|
115
|
+
42: (4, 4),
|
|
116
|
+
43: (5, 3),
|
|
117
|
+
44: (6, 2),
|
|
118
|
+
45: (7, 1),
|
|
119
|
+
46: (1, 5),
|
|
120
|
+
47: (2, 4),
|
|
121
|
+
48: (3, 3),
|
|
122
|
+
49: (4, 2),
|
|
123
|
+
50: (5, 1),
|
|
124
|
+
51: (1, 3),
|
|
125
|
+
52: (2, 2),
|
|
126
|
+
53: (3, 1),
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
sirius_positions = {
|
|
130
|
+
# Even nodes on the bottom
|
|
131
|
+
2: (1, 5),
|
|
132
|
+
4: (3, 5),
|
|
133
|
+
6: (5, 5),
|
|
134
|
+
8: (7, 5),
|
|
135
|
+
10: (9, 5),
|
|
136
|
+
12: (11, 5),
|
|
137
|
+
14: (13, 5),
|
|
138
|
+
16: (15, 5),
|
|
139
|
+
18: (17, 5),
|
|
140
|
+
20: (19, 5),
|
|
141
|
+
22: (21, 5),
|
|
142
|
+
24: (23, 5),
|
|
143
|
+
# Odd nodes on the top
|
|
144
|
+
1: (1, 1),
|
|
145
|
+
3: (3, 1),
|
|
146
|
+
5: (5, 1),
|
|
147
|
+
7: (7, 1),
|
|
148
|
+
9: (9, 1),
|
|
149
|
+
11: (11, 1),
|
|
150
|
+
13: (13, 1),
|
|
151
|
+
15: (15, 1),
|
|
152
|
+
17: (17, 1),
|
|
153
|
+
19: (19, 1),
|
|
154
|
+
21: (21, 1),
|
|
155
|
+
23: (23, 1),
|
|
156
|
+
}
|
|
157
|
+
# Add dummy indices for the resonator
|
|
158
|
+
max_qubit_number = np.max(list(sirius_positions.keys()))
|
|
159
|
+
previous_nodes = list(sirius_positions.keys())
|
|
160
|
+
for node in previous_nodes:
|
|
161
|
+
sirius_positions.update({node + max_qubit_number: (sirius_positions[node][0], 3)})
|
|
162
|
+
# Node 0 in the middle
|
|
163
|
+
sirius_positions.update({0: (16.5, 3)})
|
|
164
|
+
|
|
71
165
|
deneb_positions = {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
166
|
+
# Even nodes on the bottom
|
|
167
|
+
2: (1, 5),
|
|
168
|
+
4: (3, 5),
|
|
169
|
+
6: (5, 5),
|
|
170
|
+
# Odd nodes on the top
|
|
171
|
+
1: (1, 1),
|
|
172
|
+
3: (3, 1),
|
|
173
|
+
5: (5, 1),
|
|
79
174
|
}
|
|
175
|
+
# Add dummy indices for the resonator
|
|
176
|
+
max_qubit_number = np.max(list(deneb_positions.keys()))
|
|
177
|
+
previous_nodes = list(deneb_positions.keys())
|
|
178
|
+
for node in previous_nodes:
|
|
179
|
+
deneb_positions.update({node + max_qubit_number: (deneb_positions[node][0], 3)})
|
|
180
|
+
# Node 0 in the middle
|
|
181
|
+
deneb_positions.update({0: (2.5, 3)})
|
|
80
182
|
|
|
81
183
|
predefined_stations = {
|
|
82
184
|
"garnet": garnet_positions,
|
|
@@ -85,6 +187,8 @@ class GraphPositions:
|
|
|
85
187
|
"deneb": deneb_positions,
|
|
86
188
|
"fakedeneb": deneb_positions,
|
|
87
189
|
"iqmfakedeneb": deneb_positions,
|
|
190
|
+
"emerald": emerald_positions,
|
|
191
|
+
"sirius": sirius_positions,
|
|
88
192
|
}
|
|
89
193
|
|
|
90
194
|
@staticmethod
|
|
@@ -128,6 +232,40 @@ class GraphPositions:
|
|
|
128
232
|
}
|
|
129
233
|
return pos
|
|
130
234
|
|
|
235
|
+
@staticmethod
|
|
236
|
+
def get_positions(
|
|
237
|
+
station: Optional[str] = None, graph: Optional[PyGraph] = None, num_qubits: Optional[int] = None
|
|
238
|
+
) -> Dict[int, Tuple[float, float]]:
|
|
239
|
+
"""Get predefined positions for a specific station or generate positions for a custom graph.
|
|
240
|
+
|
|
241
|
+
Args:
|
|
242
|
+
station (Optional[str]): The name of the station to get predefined positions for.
|
|
243
|
+
If None, positions will be generated algorithmically.
|
|
244
|
+
graph (Optional[PyGraph]): The graph to generate positions for if no predefined positions exist.
|
|
245
|
+
Used only when station is None and num_qubits doesn't match any predefined layout.
|
|
246
|
+
num_qubits (Optional[int]): The number of qubits to get a layout for.
|
|
247
|
+
If matches a known system, predefined positions will be used.
|
|
248
|
+
|
|
249
|
+
Returns:
|
|
250
|
+
Dict[int, Tuple[float, float]]: A dictionary mapping node indices to (x,y) coordinates.
|
|
251
|
+
|
|
252
|
+
Raises:
|
|
253
|
+
ValueError: If none of station, graph, or num_qubits are provided, or if num_qubits doesn't
|
|
254
|
+
match any predefined layout and graph is None.
|
|
255
|
+
"""
|
|
256
|
+
if station is not None and station.lower() in GraphPositions.predefined_stations:
|
|
257
|
+
qubit_positions = cast(Dict[int, Tuple[float, float]], GraphPositions.predefined_stations[station.lower()])
|
|
258
|
+
else:
|
|
259
|
+
qubit_station_dict = {6: "deneb", 7: "deneb", 20: "garnet", 24: "sirius", 17: "sirius", 54: "emerald"}
|
|
260
|
+
if num_qubits is not None and num_qubits in qubit_station_dict:
|
|
261
|
+
station = qubit_station_dict[num_qubits]
|
|
262
|
+
qubit_positions = cast(Dict[int, Tuple[float, float]], GraphPositions.predefined_stations[station])
|
|
263
|
+
elif graph is not None:
|
|
264
|
+
qubit_positions = GraphPositions.create_positions(graph)
|
|
265
|
+
else:
|
|
266
|
+
raise ValueError("Either a station name, a graph, or a qubit count must be provided to get positions.")
|
|
267
|
+
return qubit_positions
|
|
268
|
+
|
|
131
269
|
|
|
132
270
|
def draw_graph_edges(
|
|
133
271
|
backend_coupling_map: CouplingMap,
|
|
@@ -165,23 +303,7 @@ def draw_graph_edges(
|
|
|
165
303
|
fig = plt.figure()
|
|
166
304
|
ax = plt.axes()
|
|
167
305
|
|
|
168
|
-
|
|
169
|
-
if station.lower() in GraphPositions.predefined_stations:
|
|
170
|
-
qubit_positions = GraphPositions.predefined_stations[station.lower()]
|
|
171
|
-
else:
|
|
172
|
-
if backend_num_qubits in (6, 20):
|
|
173
|
-
station = "garnet" if backend_num_qubits == 20 else "deneb"
|
|
174
|
-
qubit_positions = GraphPositions.predefined_stations[station]
|
|
175
|
-
else:
|
|
176
|
-
graph_backend = backend_coupling_map.graph.to_undirected(multigraph=False)
|
|
177
|
-
qubit_positions = GraphPositions.create_positions(graph_backend)
|
|
178
|
-
else:
|
|
179
|
-
graph_backend = backend_coupling_map.graph.to_undirected(multigraph=False)
|
|
180
|
-
if backend_num_qubits in (6, 20):
|
|
181
|
-
station = "garnet" if backend_num_qubits == 20 else "deneb"
|
|
182
|
-
qubit_positions = GraphPositions.predefined_stations[station]
|
|
183
|
-
else:
|
|
184
|
-
qubit_positions = GraphPositions.create_positions(graph_backend)
|
|
306
|
+
qubit_positions = GraphPositions.get_positions(station=station, graph=None, num_qubits=backend_num_qubits)
|
|
185
307
|
|
|
186
308
|
label_station = station if station is not None else f"{backend_num_qubits}-qubit IQM Backend"
|
|
187
309
|
if disjoint_layers is None:
|
|
@@ -226,6 +348,7 @@ def draw_graph_edges(
|
|
|
226
348
|
f"\n{timestamp}"
|
|
227
349
|
)
|
|
228
350
|
ax.set_aspect(0.925)
|
|
351
|
+
plt.gca().invert_yaxis()
|
|
229
352
|
plt.close()
|
|
230
353
|
|
|
231
354
|
return fig_name, fig
|
|
@@ -302,8 +425,55 @@ def evaluate_hamiltonian_paths(
|
|
|
302
425
|
return path_costs
|
|
303
426
|
|
|
304
427
|
|
|
428
|
+
def calculate_node_radii(metric_dict: Dict[str, Dict[int, float]], qubit_nodes: List[int], sq_metric: str) -> np.ndarray:
|
|
429
|
+
"""Calculate node radii based on the specified single qubit metric. For the coherence metric, the fidelity is calculated as the idling fidelity of a single qubit gate duration.
|
|
430
|
+
|
|
431
|
+
Args:
|
|
432
|
+
metric_dict (Dict[str, Dict[int, float]]): Dictionary containing various qubit metrics.
|
|
433
|
+
qubit_nodes (List[int]): List of qubits to calculate the radius for.
|
|
434
|
+
sq_metric (str): Metric to use for radius calculation.
|
|
435
|
+
Options: "fidelity", "coherence", or "readout".
|
|
436
|
+
|
|
437
|
+
Returns:
|
|
438
|
+
numpy.ndarray: Array of radii values for each qubit node.
|
|
439
|
+
|
|
440
|
+
Raises:
|
|
441
|
+
ValueError: If an unsupported metric type is provided.
|
|
442
|
+
"""
|
|
443
|
+
if sq_metric == "fidelity":
|
|
444
|
+
radii = -np.log(np.array([metric_dict["fidelity_1qb_gates_averaged"][node] for node in qubit_nodes]))
|
|
445
|
+
if "fidelity_1qb_gates_averaged" not in metric_dict:
|
|
446
|
+
raise ValueError(
|
|
447
|
+
"The metric 'fidelity_1qb_gates_averaged' is not available in the backend metrics."
|
|
448
|
+
)
|
|
449
|
+
elif sq_metric == "coherence":
|
|
450
|
+
if "t1_time" not in metric_dict or "t2_time" not in metric_dict:
|
|
451
|
+
raise ValueError(
|
|
452
|
+
"At least one of the metrics 't1_time' and 't2_time' is not available in the backend metrics."
|
|
453
|
+
)
|
|
454
|
+
sqg_time = 32e-9
|
|
455
|
+
t1_times = [metric_dict["t1_time"][node] for node in qubit_nodes]
|
|
456
|
+
t2_times = [metric_dict["t2_time"][node] for node in qubit_nodes]
|
|
457
|
+
idle_fidelities = (3 + np.exp(-sqg_time / np.array(t1_times)) + 2 * np.exp(-sqg_time / np.array(t2_times))) / 6
|
|
458
|
+
radii = -np.log(idle_fidelities)
|
|
459
|
+
elif sq_metric == "readout":
|
|
460
|
+
if "single_shot_readout_fidelity" not in metric_dict:
|
|
461
|
+
raise ValueError(
|
|
462
|
+
"The metric 'single_shot_readout_fidelity' is both available in the backend metrics."
|
|
463
|
+
)
|
|
464
|
+
readout_fidelities = [metric_dict["single_shot_readout_fidelity"][node] for node in qubit_nodes]
|
|
465
|
+
radii = -np.log(readout_fidelities)
|
|
466
|
+
else:
|
|
467
|
+
raise ValueError(
|
|
468
|
+
f"Unsupported single qubit metric: {sq_metric}, supported metrics are: fidelity, coherence, readout"
|
|
469
|
+
)
|
|
470
|
+
return radii
|
|
471
|
+
|
|
305
472
|
def plot_layout_fidelity_graph(
|
|
306
|
-
cal_url: str,
|
|
473
|
+
cal_url: str,
|
|
474
|
+
qubit_layouts: Optional[list[list[int]]] = None,
|
|
475
|
+
station: Optional[str] = None,
|
|
476
|
+
sq_metric: Optional[str] = "coherence",
|
|
307
477
|
):
|
|
308
478
|
"""Plot a graph showing the quantum chip layout with fidelity information.
|
|
309
479
|
|
|
@@ -316,57 +486,75 @@ def plot_layout_fidelity_graph(
|
|
|
316
486
|
qubit_layouts: List of qubit layouts where each layout is a list of qubit indices
|
|
317
487
|
station: Name of the quantum computing station to use predefined positions for.
|
|
318
488
|
If None, positions will be generated algorithmically.
|
|
489
|
+
sq_metric: Optional single qubit metric to use for the visualization, can be either "fidelity", "coherence",
|
|
490
|
+
or "readout".
|
|
319
491
|
|
|
320
492
|
Returns:
|
|
321
493
|
matplotlib.figure.Figure: The generated figure object containing the graph visualization
|
|
322
494
|
"""
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
495
|
+
# pylint: disable=unbalanced-tuple-unpacking, disable=too-many-statements
|
|
496
|
+
edges_cal, fidelities_cal, topology, qubit_mapping, metric_dict = extract_fidelities(cal_url, all_metrics=True)
|
|
497
|
+
if topology == "star":
|
|
498
|
+
idx_to_qubit = {idx: qubit for qubit, idx in qubit_mapping.items()}
|
|
499
|
+
qubit_nodes = list(idx_to_qubit.keys())[1:]
|
|
500
|
+
fig, ax = plt.subplots(figsize=(len(qubit_nodes), 3))
|
|
501
|
+
else:
|
|
502
|
+
# For other topologies, qubits are indexed starting from 0 as per the Qiskit convention
|
|
503
|
+
idx_to_qubit = {idx: qubit - 1 for qubit, idx in qubit_mapping.items()}
|
|
504
|
+
qubit_nodes = list(idx_to_qubit.keys())
|
|
505
|
+
fig, ax = plt.subplots(figsize=(1.5 * np.sqrt(len(qubit_nodes)), 1.5 * np.sqrt(len(qubit_nodes))))
|
|
334
506
|
|
|
335
|
-
|
|
336
|
-
|
|
507
|
+
weights = -np.log(np.array(fidelities_cal))
|
|
508
|
+
calibrated_nodes = list(idx_to_qubit.keys())
|
|
337
509
|
|
|
338
510
|
# Define qubit positions in plot
|
|
339
|
-
|
|
340
|
-
pos = GraphPositions.predefined_stations[station.lower()]
|
|
341
|
-
else:
|
|
342
|
-
pos = GraphPositions.create_positions(graph, topology)
|
|
511
|
+
qubit_positions = GraphPositions.get_positions(station=station, graph=None, num_qubits=len(calibrated_nodes))
|
|
343
512
|
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
513
|
+
graph = PyGraph()
|
|
514
|
+
nodes = list(set(qubit_positions.keys()))
|
|
515
|
+
graph.add_nodes_from(nodes)
|
|
516
|
+
for edge, weight in zip(edges_cal, weights):
|
|
517
|
+
if topology == "star":
|
|
518
|
+
max_qubit_number = (np.max(list(qubit_positions.keys())) + 1) // 2
|
|
519
|
+
graph.add_edge(idx_to_qubit[edge[0]], idx_to_qubit[edge[0]] + max_qubit_number, weight)
|
|
520
|
+
else:
|
|
521
|
+
graph.add_edge(idx_to_qubit[edge[0]], idx_to_qubit[edge[1]], weight)
|
|
351
522
|
|
|
352
|
-
# Draw the graph
|
|
523
|
+
# Draw the main graph
|
|
353
524
|
visualization.mpl_draw(
|
|
354
525
|
graph,
|
|
526
|
+
ax=ax,
|
|
355
527
|
with_labels=True,
|
|
356
|
-
node_color=
|
|
357
|
-
pos=
|
|
528
|
+
node_color="none", # No node color since we're using circles
|
|
529
|
+
pos=qubit_positions,
|
|
358
530
|
labels=lambda node: node,
|
|
359
|
-
|
|
531
|
+
font_color="white",
|
|
532
|
+
width=graph.edges() / np.max(graph.edges()) * 10,
|
|
360
533
|
) # type: ignore[call-arg]
|
|
361
534
|
|
|
535
|
+
# Draw nodes as circles with varying radii given by the single qubit metric
|
|
536
|
+
radii = calculate_node_radii(metric_dict, qubit_nodes, sq_metric)
|
|
537
|
+
node_colors = ["darkgray" for _ in range(len(nodes))]
|
|
538
|
+
if qubit_layouts is not None:
|
|
539
|
+
for qb in {qb for layout in qubit_layouts for qb in layout}:
|
|
540
|
+
node_colors[qb] = "orange"
|
|
541
|
+
max_radius = 0.12 + np.max(radii) / np.max(radii) / 2.5
|
|
542
|
+
|
|
543
|
+
for idx, node in enumerate(qubit_nodes):
|
|
544
|
+
position = qubit_positions[idx_to_qubit[node]]
|
|
545
|
+
radius = 0.12 + radii[idx] / np.max(radii) / 2.5
|
|
546
|
+
circle = Circle(position, radius=radius, color=node_colors[idx_to_qubit[node]], fill=True, alpha=1)
|
|
547
|
+
ax.add_patch(circle)
|
|
548
|
+
|
|
362
549
|
# Add edge labels using matplotlib's annotate
|
|
363
|
-
for edge in
|
|
364
|
-
|
|
365
|
-
|
|
550
|
+
# for idx, edge in enumerate(edges_cal):
|
|
551
|
+
for edge, weight in zip(list(graph.edge_list()), graph.edges()):
|
|
552
|
+
x1, y1 = qubit_positions[edge[0]]
|
|
553
|
+
x2, y2 = qubit_positions[edge[1]]
|
|
366
554
|
x = (x1 + x2) / 2
|
|
367
555
|
y = (y1 + y2) / 2
|
|
368
556
|
plt.annotate(
|
|
369
|
-
f"{
|
|
557
|
+
f"{weight:.1e}",
|
|
370
558
|
xy=(x, y),
|
|
371
559
|
xytext=(0, 0),
|
|
372
560
|
textcoords="offset points",
|
|
@@ -375,12 +563,68 @@ def plot_layout_fidelity_graph(
|
|
|
375
563
|
bbox={"boxstyle": "round,pad=0.2", "fc": "white", "ec": "none", "alpha": 0.6},
|
|
376
564
|
)
|
|
377
565
|
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
566
|
+
# Add horizontal bar representing resonator
|
|
567
|
+
if topology == "star":
|
|
568
|
+
resonator_height = 3
|
|
569
|
+
resonator_thickness = 0.8
|
|
570
|
+
x_min = 0.5
|
|
571
|
+
x_max = qubit_positions[idx_to_qubit[qubit_nodes[-1]]][0] + 0.5
|
|
572
|
+
resonator_width = x_max - x_min
|
|
573
|
+
|
|
574
|
+
# Create rectangle with rounded corners
|
|
575
|
+
resonator = FancyBboxPatch(
|
|
576
|
+
(x_min, resonator_height - resonator_thickness / 2),
|
|
577
|
+
resonator_width,
|
|
578
|
+
resonator_thickness,
|
|
579
|
+
boxstyle="round,pad=0.01,rounding_size=0.3",
|
|
580
|
+
color="lightsteelblue",
|
|
581
|
+
zorder=10,
|
|
582
|
+
)
|
|
583
|
+
ax.add_patch(resonator)
|
|
584
|
+
|
|
585
|
+
# Add "Resonator" label in the center
|
|
586
|
+
plt.annotate(
|
|
587
|
+
"Resonator",
|
|
588
|
+
xy=((x_min + x_max) / 2, resonator_height),
|
|
589
|
+
xytext=(0, 0),
|
|
590
|
+
textcoords="offset points",
|
|
591
|
+
ha="center",
|
|
592
|
+
va="center",
|
|
593
|
+
color="black",
|
|
594
|
+
fontsize=10,
|
|
595
|
+
zorder=11,
|
|
596
|
+
bbox={"boxstyle": "round,pad=0.2", "fc": "white", "ec": "none", "alpha": 0.8},
|
|
597
|
+
)
|
|
598
|
+
|
|
599
|
+
# Calculate axis limits to ensure all circles are visible
|
|
600
|
+
all_x = [pos[0] for pos in qubit_positions.values()]
|
|
601
|
+
all_y = [pos[1] for pos in qubit_positions.values()]
|
|
602
|
+
x_min, x_max = min(all_x), max(all_x)
|
|
603
|
+
y_min, y_max = min(all_y), max(all_y)
|
|
604
|
+
|
|
605
|
+
# Add padding for circles
|
|
606
|
+
padding = max_radius * 1.5
|
|
607
|
+
ax.set_xlim(x_min - padding, x_max + padding)
|
|
608
|
+
ax.set_ylim(y_min - padding, y_max + padding)
|
|
609
|
+
|
|
610
|
+
# Adjust layout first
|
|
611
|
+
plt.tight_layout(pad=2.0)
|
|
612
|
+
ax.set_aspect("equal")
|
|
613
|
+
ax.invert_yaxis()
|
|
614
|
+
|
|
615
|
+
plt.figtext(
|
|
616
|
+
0.5,
|
|
617
|
+
0.99, # x=0.5 (center), y=0.01 (bottom)
|
|
618
|
+
f"Qubit connectivity with selected qubits in orange\n"
|
|
619
|
+
f"CZ errors -log(F) indicated by edge thickness (thinner is better)\n"
|
|
620
|
+
f"Single qubit errors -log(F) shown as node size with F computed from {sq_metric} metrics",
|
|
621
|
+
fontsize=10,
|
|
622
|
+
ha="center",
|
|
623
|
+
wrap=True,
|
|
382
624
|
)
|
|
625
|
+
|
|
383
626
|
plt.show()
|
|
627
|
+
return fig
|
|
384
628
|
|
|
385
629
|
|
|
386
630
|
def rx_to_nx_graph(backend_coupling_map: CouplingMap) -> nx.Graph:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: iqm-benchmarks
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.44
|
|
4
4
|
Summary: A package for implementation of Quantum Characterization, Verification and Validation (QCVV) techniques on IQM's hardware at gate level abstraction
|
|
5
5
|
Author-email: IQM Finland Oy <developers@meetiqm.com>, Adrian Auer <adrian.auer@meetiqm.com>, Raphael Brieger <raphael.brieger@meetiqm.com>, Alessio Calzona <alessio.calzona@meetiqm.com>, Pedro Figueroa Romero <pedro.romero@meetiqm.com>, Amin Hosseinkhani <amin.hosseinkhani@meetiqm.com>, Miikka Koistinen <miikka@meetiqm.com>, Nadia Milazzo <nadia.milazzo@meetiqm.com>, Vicente Pina Canelles <vicente.pina@meetiqm.com>, Aniket Rath <aniket.rath@meetiqm.com>, Jami Rönkkö <jami@meetiqm.com>, Stefan Seegerer <stefan.seegerer@meetiqm.com>
|
|
6
6
|
Project-URL: Homepage, https://github.com/iqm-finland/iqm-benchmarks
|
|
@@ -4,8 +4,8 @@ iqm/benchmarks/benchmark_definition.py,sha256=e4xe0wlWKZqj48_6-zTglMaMeoiA9aGkHr
|
|
|
4
4
|
iqm/benchmarks/circuit_containers.py,sha256=anEtZEsodYqOX-34oZRmuKGeEpp_VfgG5045Mz4-4hI,7562
|
|
5
5
|
iqm/benchmarks/logging_config.py,sha256=U7olP5Kr75AcLJqNODf9VBhJLVqIvA4AYR6J39D5rww,1052
|
|
6
6
|
iqm/benchmarks/readout_mitigation.py,sha256=Q2SOGWTNgmklOYkNxepAaSaXlxSj0QQyymYY1bOkT8A,11756
|
|
7
|
-
iqm/benchmarks/utils.py,sha256=
|
|
8
|
-
iqm/benchmarks/utils_plots.py,sha256=
|
|
7
|
+
iqm/benchmarks/utils.py,sha256=kJz9T9nJXpLl_iFYYUDtSq83N-Y3JFQBuvW1o7-AVSM,44137
|
|
8
|
+
iqm/benchmarks/utils_plots.py,sha256=CaqA9fJNgRnrbYqwBdpzFUlhwvKw5lhZX3KfRlroQV4,24420
|
|
9
9
|
iqm/benchmarks/utils_shadows.py,sha256=e77PV_uaAO5m_woox9lAzompKAvFeDJ-0AKJrNJ7NFg,9728
|
|
10
10
|
iqm/benchmarks/coherence/__init__.py,sha256=yeyhk-_Lp8IbJ-f5lQj0HP5Q1HSKK_FzuXHazotUrVY,704
|
|
11
11
|
iqm/benchmarks/coherence/coherence.py,sha256=zX_6A8vCS2zeWesMDXPFZBfrJ8wUG90JI9_tFsonwXk,21191
|
|
@@ -13,12 +13,12 @@ iqm/benchmarks/compressive_gst/__init__.py,sha256=LneifgYXtcwo2jcXo7GdUEHL6_peip
|
|
|
13
13
|
iqm/benchmarks/compressive_gst/compressive_gst.py,sha256=2kiRttog4jR-vtMHu847GTFe5qL_i_uYr_4WMGqt9Ww,25653
|
|
14
14
|
iqm/benchmarks/compressive_gst/gst_analysis.py,sha256=g0kEovWbetoDRvX7JFrS9oOoNrqBxaFmprujJi7qQbU,36297
|
|
15
15
|
iqm/benchmarks/entanglement/__init__.py,sha256=sHVVToRWRCz0LSntk1rQaoSNNeyZLPoiTjUKWZWrk1E,778
|
|
16
|
-
iqm/benchmarks/entanglement/ghz.py,sha256=
|
|
17
|
-
iqm/benchmarks/entanglement/graph_states.py,sha256=
|
|
16
|
+
iqm/benchmarks/entanglement/ghz.py,sha256=nJ0gsLRfl50mcGrBVWjx22gXY9fwn9-sO3St2SbM4MA,41254
|
|
17
|
+
iqm/benchmarks/entanglement/graph_states.py,sha256=saoAw2QF8j7W4nZMOElnjuNylqDAbY9cBwBypWZKUz8,62521
|
|
18
18
|
iqm/benchmarks/optimization/__init__.py,sha256=_ajW_OibYLCtzU5AUv5c2zuuVYn8ZNeZUcUUSIGt51M,747
|
|
19
19
|
iqm/benchmarks/optimization/qscore.py,sha256=D2BVVNAqO32uGu5_kLVl2XJUOBlRl1C-c6zYenaCBMg,37259
|
|
20
20
|
iqm/benchmarks/quantum_volume/__init__.py,sha256=i-Q4SpDWELBw7frXnxm1j4wJRcxbIyrS5uEK_v06YHo,951
|
|
21
|
-
iqm/benchmarks/quantum_volume/clops.py,sha256=
|
|
21
|
+
iqm/benchmarks/quantum_volume/clops.py,sha256=QS9iK-gtop0zix6IBeUumQeG01-0dXsv0jsYSDhgEu0,31071
|
|
22
22
|
iqm/benchmarks/quantum_volume/quantum_volume.py,sha256=pro7Lz-A5pPpT9UZ8wtXKTyhdWmTjQjRHt4BylDR-3U,36553
|
|
23
23
|
iqm/benchmarks/randomized_benchmarking/__init__.py,sha256=IkKo-7zUChxZZd3my_csQCJfJfZNsV3-JTvdG8uqys4,734
|
|
24
24
|
iqm/benchmarks/randomized_benchmarking/clifford_1q.pkl,sha256=yrmSJqhv7Lb1yqiqU9-2baqTljJPNmTUPQR-AH6GGfc,7800
|
|
@@ -30,12 +30,12 @@ iqm/benchmarks/randomized_benchmarking/clifford_rb/clifford_rb.py,sha256=IGBrq_a
|
|
|
30
30
|
iqm/benchmarks/randomized_benchmarking/direct_rb/__init__.py,sha256=lCIIeWMFZHnMUUEUTjUBvrhhUur6uBTHIVkxFBSfHC4,681
|
|
31
31
|
iqm/benchmarks/randomized_benchmarking/direct_rb/direct_rb.py,sha256=Cbx6B9q8Sqc_uPalX6fUEWJX6UEHCfWRof9u4brtx5A,48977
|
|
32
32
|
iqm/benchmarks/randomized_benchmarking/eplg/__init__.py,sha256=1MeGZTErElXJypQV2rQf7hwqLLvIp_JNVbwNhaP5vyI,696
|
|
33
|
-
iqm/benchmarks/randomized_benchmarking/eplg/eplg.py,sha256=
|
|
33
|
+
iqm/benchmarks/randomized_benchmarking/eplg/eplg.py,sha256=3A_gxzAs6mi3APKvqCwYDcNwRogIZNy5SDL33Cro89E,17036
|
|
34
34
|
iqm/benchmarks/randomized_benchmarking/interleaved_rb/__init__.py,sha256=sq6MgN_hwlpkOj10vyCU4e6eKSX-oLcF2L9na6W2Gt4,681
|
|
35
35
|
iqm/benchmarks/randomized_benchmarking/interleaved_rb/interleaved_rb.py,sha256=TaR1YFWBhOgm1hmEQzuwLYpp0yl0Xpuo3jAT6YhiXpc,28471
|
|
36
36
|
iqm/benchmarks/randomized_benchmarking/mirror_rb/__init__.py,sha256=jRKbivWCZ3xdO1k0sx-ygC3s5DUkGSModd975PoAtcg,692
|
|
37
37
|
iqm/benchmarks/randomized_benchmarking/mirror_rb/mirror_rb.py,sha256=n_5gt9636ZDMsM9hC3Zm5qP2bQr2sy41zxGhOh0XMjI,32932
|
|
38
|
-
iqm_benchmarks-2.
|
|
38
|
+
iqm_benchmarks-2.44.dist-info/licenses/LICENSE,sha256=2Ncb40-hqkTil78RPv3-YiJfKaJ8te9USJgliKqIdSY,11558
|
|
39
39
|
mGST/LICENSE,sha256=TtHNq55cUcbglb7uhVudeBLUh_qPdUoAEvU0BBwFz-k,1098
|
|
40
40
|
mGST/README.md,sha256=v_5kw253csHF4-RfE-44KqFmBXIsSMRmOtN0AUPrRxE,5050
|
|
41
41
|
mGST/additional_fns.py,sha256=_SEJ10FRNM7_CroysT8hCLZTfpm6ZhEIDCY5zPTnhjo,31390
|
|
@@ -46,7 +46,7 @@ mGST/optimization.py,sha256=YHwkzIkYvsZOPjclR-BCQWh24jeqjuXp0BB0WX5Lwow,10559
|
|
|
46
46
|
mGST/qiskit_interface.py,sha256=ajx6Zn5FnrX_T7tMP8xnBLyG4c2ddFRm0Fu2_3r1t30,10118
|
|
47
47
|
mGST/reporting/figure_gen.py,sha256=6Xd8vwfy09hLY1YbJY6TRevuMsQSU4MsWqemly3ZO0I,12970
|
|
48
48
|
mGST/reporting/reporting.py,sha256=B8NWfpZrrSmyH7lwZxd0EbZMYLsAGK1YsHRB4D5qXH4,26002
|
|
49
|
-
iqm_benchmarks-2.
|
|
50
|
-
iqm_benchmarks-2.
|
|
51
|
-
iqm_benchmarks-2.
|
|
52
|
-
iqm_benchmarks-2.
|
|
49
|
+
iqm_benchmarks-2.44.dist-info/METADATA,sha256=g7tbfF4edqqPEnS50lTJ_0pdp9KzCKMs4RNUQeCxUcU,10872
|
|
50
|
+
iqm_benchmarks-2.44.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
51
|
+
iqm_benchmarks-2.44.dist-info/top_level.txt,sha256=3G23Z-1LGf-IOzTCUl6QwWqiQ3USz25Zt90Ihq192to,9
|
|
52
|
+
iqm_benchmarks-2.44.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|