iqm-benchmarks 2.42__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.
@@ -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["job_end"], job_time_format)
182
- job_i = datetime.strptime(x["job_start"], job_time_format)
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
- if station is not None:
80
- if station.lower() in GraphPositions.predefined_stations:
81
- qubit_positions = GraphPositions.predefined_stations[station.lower()]
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 = [cmap(norm(fidelity_edges[edge])) for edge in qubit_pairs]
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=list(range(num_qubits)),
105
- labels={x: qubit_names[x] for x in range(num_qubits)},
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="k",
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) -> tuple[list[list[int]], list[float], 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 = int(item["locus"][0][2:]) if item["locus"][0] != "COMP_R" else 0
317
- qb2 = int(item["locus"][1][2:]) if item["locus"][1] != "COMP_R" else 0
318
- if topology == "star":
319
- list_couplings.append([qb1, qb2])
320
- else:
321
- list_couplings.append([qb1 - 1, qb2 - 1])
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
- return list_couplings, list_fids, topology
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