iqm-benchmarks 2.31__py3-none-any.whl → 2.33__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.

Potentially problematic release.


This version of iqm-benchmarks might be problematic. Click here for more details.

iqm/benchmarks/utils.py CHANGED
@@ -20,12 +20,14 @@ from functools import wraps
20
20
  import itertools
21
21
  from math import floor
22
22
  import os
23
+ import random
23
24
  from time import time
24
25
  from typing import Any, Dict, Iterable, List, Literal, Optional, Sequence, Set, Tuple, Union, cast
25
26
  import warnings
26
27
 
27
28
  from more_itertools import chunked
28
29
  from mthree.utils import final_measurement_mapping
30
+ import networkx as nx
29
31
  import numpy as np
30
32
  from numpy.random import Generator
31
33
  from qiskit import ClassicalRegister, transpile
@@ -47,12 +49,12 @@ from iqm.qiskit_iqm.iqm_provider import IQMProvider
47
49
 
48
50
 
49
51
  def timeit(f):
50
- """Calculates the amount of time a function takes to execute
52
+ """Calculates the amount of time a function takes to execute.
51
53
 
52
54
  Args:
53
- f: The function to add the timing attribute to
55
+ f: The function to add the timing attribute to.
54
56
  Returns:
55
- The decorated function execution with logger statement of elapsed time in execution
57
+ The decorated function execution with logger statement of elapsed time in execution.
56
58
  """
57
59
 
58
60
  @wraps(f)
@@ -168,7 +170,7 @@ def count_native_gates(
168
170
 
169
171
  native_operations = backend.operation_names
170
172
 
171
- if "move" in backend.architecture.gates:
173
+ if backend.has_resonators():
172
174
  native_operations.append("move")
173
175
  # Some backends may not include "barrier" in the operation_names attribute
174
176
  if "barrier" not in native_operations:
@@ -281,6 +283,50 @@ def get_active_qubits(qc: QuantumCircuit) -> List[int]:
281
283
  return list(active_qubits)
282
284
 
283
285
 
286
+ def extract_fidelities(cal_url: str) -> tuple[list[list[int]], list[float], str]:
287
+ """Returns couplings and CZ-fidelities from calibration data URL
288
+
289
+ Args:
290
+ cal_url: str
291
+ The url under which the calibration data for the backend can be found
292
+ Returns:
293
+ list_couplings: List[List[int]]
294
+ A list of pairs, each of which is a qubit coupling for which the calibration
295
+ data contains a fidelity.
296
+ list_fids: List[float]
297
+ A list of CZ fidelities from the calibration url, ordered in the same way as list_couplings
298
+ topology: str
299
+ Name of the chip topology layout, currently either "star" or "crystal"
300
+ """
301
+ headers = {"Accept": "application/json", "Authorization": "Bearer " + os.environ["IQM_TOKEN"]}
302
+ r = requests.get(cal_url, headers=headers, timeout=60)
303
+ calibration = r.json()
304
+ cal_keys = {
305
+ el2["key"]: (i, j) for i, el1 in enumerate(calibration["calibrations"]) for j, el2 in enumerate(el1["metrics"])
306
+ }
307
+ list_couplings = []
308
+ list_fids = []
309
+ if "double_move_gate_fidelity" in cal_keys.keys():
310
+ i, j = cal_keys["double_move_gate_fidelity"]
311
+ topology = "star"
312
+ else:
313
+ i, j = cal_keys["cz_gate_fidelity"]
314
+ topology = "crystal"
315
+ 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])
322
+ list_fids.append(float(item["value"]))
323
+ calibrated_qubits = set(np.array(list_couplings).reshape(-1))
324
+ qubit_mapping = {qubit: idx for idx, qubit in enumerate(calibrated_qubits)}
325
+ list_couplings = [[qubit_mapping[edge[0]], qubit_mapping[edge[1]]] for edge in list_couplings]
326
+
327
+ return list_couplings, list_fids, topology
328
+
329
+
284
330
  # pylint: disable=too-many-branches
285
331
  def get_iqm_backend(backend_label: str) -> IQMBackendBase:
286
332
  """Get the IQM backend object from a backend name (str).
@@ -320,8 +366,20 @@ def get_iqm_backend(backend_label: str) -> IQMBackendBase:
320
366
  elif backend_label.lower() in ("iqmfakedeneb", "fakedeneb"):
321
367
  backend_object = IQMFakeDeneb()
322
368
 
369
+ # ****** 16Q Resonator Star ******
370
+ # Sirius
371
+ elif backend_label.lower() == "sirius":
372
+ iqm_server_url = "https://cocos.resonance.meetiqm.com/sirius"
373
+ provider = IQMProvider(iqm_server_url)
374
+ backend_object = provider.get_backend()
375
+ # FakeSirius
376
+ # elif backend_label.lower() in ("iqmfakesirius", "fakesirius"):
377
+ # backend_object = IQMFakeSirius()
378
+
323
379
  else:
324
- raise ValueError(f"Backend {backend_label} not supported. Try 'garnet', 'deneb', 'fakeadonis' or 'fakeapollo'.")
380
+ raise ValueError(
381
+ f"Backend {backend_label} not supported. Try 'garnet', 'deneb', 'sirius', 'fakeadonis' or 'fakeapollo'."
382
+ )
325
383
 
326
384
  return backend_object
327
385
 
@@ -517,12 +575,12 @@ def perform_backend_transpilation(
517
575
  initial_layout=qubits if aux_qc is None else None,
518
576
  routing_method=routing_method,
519
577
  )
520
- if "move" in backend.architecture.gates:
578
+ if backend.has_resonators():
521
579
  transpiled = transpile_to_IQM(
522
580
  qc, backend=backend, optimize_single_qubits=optimize_sqg, remove_final_rzs=drop_final_rz
523
581
  )
524
582
  if aux_qc is not None:
525
- if "move" in backend.architecture.gates:
583
+ if backend.has_resonators():
526
584
  if backend.num_qubits in qubits:
527
585
  raise ValueError(
528
586
  f"Label {backend.num_qubits} is reserved for Resonator - "
@@ -546,7 +604,7 @@ def perform_backend_transpilation(
546
604
  if coupling_map == backend.coupling_map:
547
605
  transpiled_qc_list = [transpile_and_optimize(qc) for qc in qc_list]
548
606
  else: # The coupling map will be reduced if the physical layout is to be fixed
549
- if "move" in backend.architecture.gates:
607
+ if backend.has_resonators():
550
608
  aux_qc_list = [QuantumCircuit(backend.num_qubits + 1, q.num_clbits) for q in qc_list]
551
609
  else:
552
610
  aux_qc_list = [QuantumCircuit(backend.num_qubits, q.num_clbits) for q in qc_list]
@@ -555,6 +613,47 @@ def perform_backend_transpilation(
555
613
  return transpiled_qc_list
556
614
 
557
615
 
616
+ def random_hamiltonian_path(G: nx.Graph, N: int) -> List[Tuple[int, int]]:
617
+ """
618
+ Generates a random Hamiltonian path with N vertices from a given NetworkX graph.
619
+
620
+ Args:
621
+ G (networkx.Graph): The input graph.
622
+ N (int): The desired number of vertices in the Hamiltonian path.
623
+
624
+ Returns:
625
+ list: A list of edges (tuples of nodes) representing the Hamiltonian path, or an empty list if not possible.
626
+ """
627
+ if N > len(G):
628
+ raise ValueError(
629
+ f"The number of vertices in the Hamiltonian path ({N}) cannot be greater than the number of nodes in the graph ({len(G)})"
630
+ )
631
+
632
+ nodes = list(G.nodes)
633
+ random.shuffle(nodes) # Shuffle nodes to introduce randomness
634
+
635
+ for start in nodes:
636
+ path = [start]
637
+ visited = set(path)
638
+ edges = []
639
+
640
+ while len(path) < N:
641
+ neighbors = [n for n in G.neighbors(path[-1]) if n not in visited]
642
+
643
+ if not neighbors:
644
+ break # Dead end, stop trying this path
645
+
646
+ next_node = random.choice(neighbors)
647
+ edges.append((int(path[-1]), int(next_node)))
648
+ path.append(next_node)
649
+ visited.add(next_node)
650
+
651
+ if len(path) == N:
652
+ return edges # Successfully found a Hamiltonian path of length N
653
+
654
+ return [] # No valid path found
655
+
656
+
558
657
  def reduce_to_active_qubits(
559
658
  circuit: QuantumCircuit, backend_topology: Optional[str] = None, backend_num_qubits=None
560
659
  ) -> QuantumCircuit:
@@ -725,6 +824,34 @@ def split_sequence_in_chunks(sequence_in: Sequence[Any], split_size: int) -> Lis
725
824
  return [sequence_in[i : i + split_size] for i in range(0, len(sequence_in), split_size)]
726
825
 
727
826
 
827
+ def split_into_disjoint_pairs(pairs: Sequence[Tuple[int, int]]) -> List[List[Tuple[int, int]]]:
828
+ """
829
+ Split a Sequence of pairs of integers into a List of a minimal number of Lists of disjoint pairs.
830
+ Example: input [(0,3), (2,3), (3,8), (8,13), (13,17), (17,18)] gives
831
+ output [[(0, 3), (8, 13), (17, 18)], [(2, 3), (13, 17)], [(3, 8)]].
832
+
833
+ # TODO: enable specifying a max split size of Lists of disjoint pairs. # pylint: disable=fixme
834
+
835
+ Args:
836
+ pairs (Sequence[Tuple[int, int]]): The input list of pairs of integers.
837
+ Returns:
838
+ List[List[Tuple[int, int]]]: A List of Lists of disjoint pairs.
839
+ """
840
+ result: List[List[Tuple[int, int]]] = []
841
+
842
+ for pair in pairs:
843
+ added = False
844
+ for group in result:
845
+ if not any(elem in pair for p in group for elem in p):
846
+ group.append(pair)
847
+ added = True
848
+ break
849
+ if not added:
850
+ result.append([pair])
851
+
852
+ return result
853
+
854
+
728
855
  @timeit
729
856
  def sort_batches_by_final_layout(
730
857
  transpiled_circuit_list: List[QuantumCircuit],
@@ -824,7 +951,9 @@ def submit_execute(
824
951
  qcvv_logger.warning(
825
952
  "Both max_gates_per_batch and max_circuits_per_batch are not None. Selecting the one giving the smallest batches."
826
953
  )
827
- batching_size = min(max_circuits_per_batch, max(1, floor(max_gates_per_batch / avg_gates_per_qc))) # type: ignore
954
+ batching_size = min(
955
+ cast(int, max_circuits_per_batch), max(1, floor(cast(int, max_gates_per_batch) / avg_gates_per_qc))
956
+ )
828
957
  if batching_size == max_circuits_per_batch:
829
958
  restriction = "max_circuits_per_batch"
830
959
  else:
@@ -861,47 +990,3 @@ def xrvariable_to_counts(dataset: xr.Dataset, identifier: str, counts_range: int
861
990
  dict(zip(list(dataset[f"{identifier}_state_{u}"].data), dataset[f"{identifier}_counts_{u}"].data))
862
991
  for u in range(counts_range)
863
992
  ]
864
-
865
-
866
- def extract_fidelities(cal_url: str) -> tuple[list[list[int]], list[float], str]:
867
- """Returns couplings and CZ-fidelities from calibration data URL
868
-
869
- Args:
870
- cal_url: str
871
- The url under which the calibration data for the backend can be found
872
- Returns:
873
- list_couplings: List[List[int]]
874
- A list of pairs, each of which is a qubit coupling for which the calibration
875
- data contains a fidelity.
876
- list_fids: List[float]
877
- A list of CZ fidelities from the calibration url, ordered in the same way as list_couplings
878
- topology: str
879
- Name of the chip topology layout, currently either "star" or "crystal"
880
- """
881
- headers = {"Accept": "application/json", "Authorization": "Bearer " + os.environ["IQM_TOKEN"]}
882
- r = requests.get(cal_url, headers=headers, timeout=60)
883
- calibration = r.json()
884
- cal_keys = {
885
- el2["key"]: (i, j) for i, el1 in enumerate(calibration["calibrations"]) for j, el2 in enumerate(el1["metrics"])
886
- }
887
- list_couplings = []
888
- list_fids = []
889
- if "double_move_gate_fidelity" in cal_keys.keys():
890
- i, j = cal_keys["double_move_gate_fidelity"]
891
- topology = "star"
892
- else:
893
- i, j = cal_keys["cz_gate_fidelity"]
894
- topology = "crystal"
895
- for item in calibration["calibrations"][i]["metrics"][j]["metrics"]:
896
- qb1 = int(item["locus"][0][2:]) if "COMP" not in item["locus"][0] else 0
897
- qb2 = int(item["locus"][1][2:]) if "COMP" not in item["locus"][1] else 0
898
- list_couplings.append([qb1 - 1, qb2 - 1])
899
- list_fids.append(float(item["value"]))
900
- calibrated_qubits = set(np.array(list_couplings).reshape(-1))
901
- qubit_mapping = {}
902
- if topology == "star":
903
- qubit_mapping.update({-1: len(calibrated_qubits)}) # Place resonator qubit as last qubit
904
- qubit_mapping.update({qubit: idx for idx, qubit in enumerate(calibrated_qubits)})
905
- list_couplings = [[qubit_mapping[edge[0]], qubit_mapping[edge[1]]] for edge in list_couplings]
906
-
907
- return list_couplings, list_fids, topology
@@ -16,15 +16,20 @@
16
16
  Plotting and visualization utility functions
17
17
  """
18
18
  from dataclasses import dataclass
19
- from typing import Dict, Literal, Optional, Tuple
19
+ import os
20
+ from typing import Dict, List, Literal, Optional, Sequence, Tuple
20
21
 
22
+ from matplotlib.figure import Figure
21
23
  import matplotlib.pyplot as plt
22
24
  import networkx as nx
23
25
  import numpy as np
24
26
  from qiskit.transpiler import CouplingMap
27
+ import requests
25
28
  from rustworkx import PyGraph, spring_layout, visualization # pylint: disable=no-name-in-module
26
29
 
27
- from iqm.benchmarks.utils import extract_fidelities
30
+ from iqm.benchmarks.logging_config import qcvv_logger
31
+ from iqm.benchmarks.utils import extract_fidelities, get_iqm_backend, random_hamiltonian_path
32
+ from iqm.qiskit_iqm.iqm_backend import IQMBackendBase
28
33
 
29
34
 
30
35
  @dataclass
@@ -73,7 +78,14 @@ class GraphPositions:
73
78
  6: (3.0, 3.0),
74
79
  }
75
80
 
76
- predefined_stations = {"garnet": garnet_positions, "deneb": deneb_positions}
81
+ predefined_stations = {
82
+ "garnet": garnet_positions,
83
+ "fakeapollo": garnet_positions,
84
+ "iqmfakeapollo": garnet_positions,
85
+ "deneb": deneb_positions,
86
+ "fakedeneb": deneb_positions,
87
+ "iqmfakedeneb": deneb_positions,
88
+ }
77
89
 
78
90
  @staticmethod
79
91
  def create_positions(
@@ -117,6 +129,179 @@ class GraphPositions:
117
129
  return pos
118
130
 
119
131
 
132
+ def draw_graph_edges(
133
+ backend_coupling_map: CouplingMap,
134
+ backend_num_qubits: int,
135
+ edge_list: Sequence[Tuple[int, int]],
136
+ timestamp: str,
137
+ disjoint_layers: Optional[Sequence[Sequence[Tuple[int, int]]]] = None,
138
+ station: Optional[str] = None,
139
+ qubit_names: Optional[Dict[int, str]] = None,
140
+ is_eplg: Optional[bool] = False,
141
+ ) -> Tuple[str, Figure]:
142
+ """Draw given edges on a graph within the given backend.
143
+
144
+ Args:
145
+ backend_coupling_map (CouplingMap): The coupling map to draw the graph from.
146
+ backend_num_qubits (int): The number of qubits of the respectve backend.
147
+ edge_list (Sequence[Tuple[int, int]]): The edge list of the linear chain.
148
+ timestamp (str): The timestamp to include in the figure name.
149
+ disjoint_layers (Optional[Sequence[Sequence[Tuple[int, int]]]): Sequences of edges defining disjoint layers to draw.
150
+ * Default is None.
151
+ station (Optional[str]): The name of the station.
152
+ * Default is None.
153
+ qubit_names (Optional[Dict[int, str]]): A dictionary mapping qubit indices to their names.
154
+ * Default is None.
155
+ is_eplg (Optional[bool]): A flag indicating if the graph refers to an EPLG experiment.
156
+ * Default is False.
157
+
158
+ Returns:
159
+ Tuple[str, Figure]: The figure name and the figure object.
160
+ """
161
+ disjoint = "_disjoint" if disjoint_layers is not None else ""
162
+ fig_name_station = f"_{station.lower()}" if station is not None else ""
163
+ fig_name = f"edges_graph{disjoint}{fig_name_station}_{timestamp}"
164
+
165
+ fig = plt.figure()
166
+ ax = plt.axes()
167
+
168
+ if station is not None:
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)
185
+
186
+ label_station = station if station is not None else f"{backend_num_qubits}-qubit IQM Backend"
187
+ if disjoint_layers is None:
188
+ nx.draw_networkx(
189
+ rx_to_nx_graph(backend_coupling_map),
190
+ pos=qubit_positions,
191
+ edgelist=edge_list,
192
+ width=4.0,
193
+ edge_color="k",
194
+ node_color="k",
195
+ font_color="w",
196
+ ax=ax,
197
+ )
198
+
199
+ plt.title(f"Selected edges in {label_station}\n" f"\n{timestamp}")
200
+
201
+ else:
202
+ num_disjoint_layers = len(disjoint_layers)
203
+ colors = plt.colormaps["rainbow"](np.linspace(0, 1, num_disjoint_layers))
204
+ all_edge_colors = [[colors[i]] * len(l) for i, l in enumerate(disjoint_layers)] # Flatten below
205
+ nx.draw_networkx(
206
+ rx_to_nx_graph(backend_coupling_map),
207
+ pos=qubit_positions,
208
+ labels=(
209
+ {x: qubit_names[x] for x in range(backend_num_qubits)}
210
+ if qubit_names
211
+ else list(range(backend_num_qubits))
212
+ ),
213
+ font_size=6.5 if qubit_names else 10,
214
+ edgelist=[x for y in disjoint_layers for x in y],
215
+ width=4.0,
216
+ edge_color=[x for y in all_edge_colors for x in y],
217
+ node_color="k",
218
+ font_color="w",
219
+ ax=ax,
220
+ )
221
+
222
+ is_eplg_string = " for EPLG experiment" if is_eplg else ""
223
+ plt.title(
224
+ f"Selected edges in {label_station.capitalize()}{is_eplg_string}\n"
225
+ f"{len(disjoint_layers)} groups of disjoint layers"
226
+ f"\n{timestamp}"
227
+ )
228
+ ax.set_aspect(0.925)
229
+ plt.close()
230
+
231
+ return fig_name, fig
232
+
233
+
234
+ def evaluate_hamiltonian_paths(
235
+ N: int,
236
+ path_samples: int,
237
+ backend_arg: str | IQMBackendBase,
238
+ url: str,
239
+ max_tries: int = 10,
240
+ ) -> Dict[int, List[Tuple[int, int]]]:
241
+ """Evaluates Hamiltonian paths according to the product of 2Q gate fidelities on the corresponding edges of the backend graph.
242
+
243
+ Args:
244
+ N (int): the number of vertices in the Hamiltonian paths to evaluate.
245
+ path_samples (int): the number of Hamiltonian paths to evaluate.
246
+ backend_arg (str | IQMBackendBase): the backend to evaluate the Hamiltonian paths on with respect to fidelity.
247
+ url (str): the URL address for the backend to retrieve calibration data from.
248
+ max_tries (int): the maximum number of tries to generate a Hamiltonian path.
249
+
250
+ Returns:
251
+ Dict[int, List[Tuple[int, int]]]: A dictionary with keys being fidelity products and values being the respective Hamiltonian paths.
252
+ """
253
+ if isinstance(backend_arg, str):
254
+ backend = get_iqm_backend(backend_arg)
255
+ else:
256
+ backend = backend_arg
257
+
258
+ backend_nx_graph = rx_to_nx_graph(backend.coupling_map)
259
+
260
+ all_paths = []
261
+ sample_counter = 0
262
+ tries = 0
263
+ while sample_counter < path_samples and tries <= max_tries:
264
+ h_path = random_hamiltonian_path(backend_nx_graph, N)
265
+ if not h_path:
266
+ qcvv_logger.debug(f"Failed to generate a Hamiltonian path with {N} vertices - retrying...")
267
+ tries += 1
268
+ if tries == max_tries:
269
+ raise RecursionError(
270
+ f"Max tries to generate a Hamiltonian path with {N} vertices reached - Try with less vertices!\n"
271
+ f"For EPLG, you may also manually specify qubit pairs."
272
+ )
273
+ continue
274
+ all_paths.append(h_path)
275
+ tries = 0
276
+ sample_counter += 1
277
+
278
+ # Get scores for all paths
279
+ # Retrieve fidelity data
280
+ two_qubit_fidelity = {}
281
+
282
+ headers = {"Accept": "application/json", "Authorization": "Bearer " + os.environ["IQM_TOKEN"]}
283
+ r = requests.get(url, headers=headers, timeout=60)
284
+ calibration = r.json()
285
+
286
+ for iq in calibration["calibrations"][0]["metrics"][0]["metrics"]:
287
+ temp = list(iq.values())
288
+ two_qubit_fidelity[str(temp[0])] = temp[1]
289
+ two_qubit_fidelity[str([temp[0][1], temp[0][0]])] = temp[1]
290
+
291
+ # Rate all the paths
292
+ path_costs = {} # keys are costs, values are edge paths
293
+ for h_path in all_paths:
294
+ total_cost = 1
295
+ for edge in h_path:
296
+ if len(edge) == 2:
297
+ total_cost *= two_qubit_fidelity[
298
+ str([backend.index_to_qubit_name(edge[0]), backend.index_to_qubit_name(edge[1])])
299
+ ]
300
+ path_costs[total_cost] = h_path
301
+
302
+ return path_costs
303
+
304
+
120
305
  def plot_layout_fidelity_graph(
121
306
  cal_url: str, qubit_layouts: Optional[list[list[int]]] = None, station: Optional[str] = None
122
307
  ):
@@ -162,21 +347,7 @@ def plot_layout_fidelity_graph(
162
347
  for qb in {qb for layout in qubit_layouts for qb in layout}:
163
348
  node_colors[qb] = "orange"
164
349
 
165
- # Ensuring weights are in correct order for the plot
166
- edge_list = graph.edge_list()
167
- weights_dict = {}
168
- edge_pos = set()
169
-
170
- # Create a mapping between edge positions as defined in rustworkx and their weights
171
- for e, w in zip(edge_list, weights):
172
- pos_tuple = (tuple(pos[e[0]]), tuple(pos[e[1]]))
173
- weights_dict[pos_tuple] = w
174
- edge_pos.add(pos_tuple)
175
-
176
- # Get corresponding weights in the same order
177
- weights_ordered = np.array([weights_dict[edge] for edge in list(edge_pos)])
178
-
179
- plt.subplots(figsize=(6, 6))
350
+ plt.subplots(figsize=(1.5 * np.sqrt(len(nodes)), 1.5 * np.sqrt(len(nodes))))
180
351
 
181
352
  # Draw the graph
182
353
  visualization.mpl_draw(
@@ -185,7 +356,7 @@ def plot_layout_fidelity_graph(
185
356
  node_color=node_colors,
186
357
  pos=pos,
187
358
  labels=lambda node: node,
188
- width=7 * weights_ordered / np.max(weights_ordered),
359
+ width=7 * weights / np.max(weights),
189
360
  ) # type: ignore[call-arg]
190
361
 
191
362
  # Add edge labels using matplotlib's annotate
@@ -222,6 +393,7 @@ def rx_to_nx_graph(backend_coupling_map: CouplingMap) -> nx.Graph:
222
393
  networkx.Graph: The Networkx Graph corresponding to the backend graph.
223
394
 
224
395
  """
396
+
225
397
  # Generate a Networkx graph
226
398
  graph_backend = backend_coupling_map.graph.to_undirected(multigraph=False)
227
399
  backend_egdes, backend_nodes = (list(graph_backend.edge_list()), list(graph_backend.node_indices()))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: iqm-benchmarks
3
- Version: 2.31
3
+ Version: 2.33
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
@@ -21,6 +21,7 @@ Requires-Dist: numpy<2.0,>=1.25.2
21
21
  Requires-Dist: qiskit<2.0,>=1.2.4
22
22
  Requires-Dist: qiskit-iqm<18.0,>=17.8
23
23
  Requires-Dist: iqm-client>=22.7
24
+ Requires-Dist: requests<3.0,>=2.32.3
24
25
  Requires-Dist: scikit-optimize<0.11.0,>=0.10.2
25
26
  Requires-Dist: tabulate<1.0.0,>=0.9.0
26
27
  Requires-Dist: uncertainties<3.3.0,>=3.2.2
@@ -64,6 +65,7 @@ Below is a list of the benchmarks currently available in the suite:
64
65
  - Interleaved Randomized Benchmarking [[Phys. Rev. Lett. 109, 080505](https://doi.org/10.1103/PhysRevLett.109.080505) (2012)]
65
66
  - Compressive Gate Set Tomography [[PRX Quantum 4, 010325](https://journals.aps.org/prxquantum/abstract/10.1103/PRXQuantum.4.010325) (2023)]
66
67
  - Mirror Randomized Benchmarking [[Phys. Rev. Lett. 129, 150502](https://journals.aps.org/prl/abstract/10.1103/PhysRevLett.129.150502) (2022)]
68
+ - Error Per Layered Gate [[arXiv:2311.05933 [quant-ph]](https://arxiv.org/abs/2311.05933) (2023)]
67
69
  * Holistic:
68
70
  - Quantum Volume [[Phys. Rev. A 100, 032328](https://doi.org/10.1103/PhysRevA.100.032328) (2019)]
69
71
  - CLOPS [[arXiv:2110.14108 [quant-ph]](https://arxiv.org/abs/2110.14108) (2021)]
@@ -1,18 +1,18 @@
1
- iqm/benchmarks/__init__.py,sha256=74NuBycITM-CV7nx0l1T2wbnQDdVmF8jTZVE0KpG7pc,2773
1
+ iqm/benchmarks/__init__.py,sha256=-drZ_whue067Tu4I9RxBCqrrzu38Tm5Kqf9jHTftUPk,3070
2
2
  iqm/benchmarks/benchmark.py,sha256=3E7g7RQjCIGIpSI1gOSrI3V9SAVs-XEOMrPgToK_7vw,4972
3
3
  iqm/benchmarks/benchmark_definition.py,sha256=e4xe0wlWKZqj48_6-zTglMaMeoiA9aGkHrrSgoCfPkM,11271
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=2aEwFhZAHBmqLjSMtnqjuWcXCyMX3vpUfF-vqoeBIHw,38517
8
- iqm/benchmarks/utils_plots.py,sha256=gNeGf5bnZjvKGGSglCFLonbG3oOd_z30mCx66__cbEY,8035
7
+ iqm/benchmarks/utils.py,sha256=HywFLNDq713HYebtQfKpzP_cXXD9DbyPGdxArsukQbw,41233
8
+ iqm/benchmarks/utils_plots.py,sha256=Q4h7gcKXf8Eizm13P0yL2I_P-QobHVFr9JCV83wrUi8,14942
9
9
  iqm/benchmarks/utils_shadows.py,sha256=e77PV_uaAO5m_woox9lAzompKAvFeDJ-0AKJrNJ7NFg,9728
10
10
  iqm/benchmarks/compressive_gst/__init__.py,sha256=LneifgYXtcwo2jcXo7GdUEHL6_peipukShhkrdaTRCA,929
11
11
  iqm/benchmarks/compressive_gst/compressive_gst.py,sha256=2kiRttog4jR-vtMHu847GTFe5qL_i_uYr_4WMGqt9Ww,25653
12
- iqm/benchmarks/compressive_gst/gst_analysis.py,sha256=y4Yk9v1N9DP91MieXTMIASzjoFlg2pCzkm4LhvEYi0k,36335
12
+ iqm/benchmarks/compressive_gst/gst_analysis.py,sha256=g0kEovWbetoDRvX7JFrS9oOoNrqBxaFmprujJi7qQbU,36297
13
13
  iqm/benchmarks/entanglement/__init__.py,sha256=sHVVToRWRCz0LSntk1rQaoSNNeyZLPoiTjUKWZWrk1E,778
14
14
  iqm/benchmarks/entanglement/ghz.py,sha256=RGA6ynJFsfaCJv0nKccsiIzPk2G-iHHvIeW8LVu30HY,41249
15
- iqm/benchmarks/entanglement/graph_states.py,sha256=7IlPocwHbi_K_KQqTSVEaDfB7wLH9loTawqDnnaDYek,62528
15
+ iqm/benchmarks/entanglement/graph_states.py,sha256=qv6nAgbvm1toSgNGLjBA8DpF9fN7UUlMpPeR_gixMcI,62561
16
16
  iqm/benchmarks/optimization/__init__.py,sha256=_ajW_OibYLCtzU5AUv5c2zuuVYn8ZNeZUcUUSIGt51M,747
17
17
  iqm/benchmarks/optimization/qscore.py,sha256=KOw8fjXeMwCjYvKukpX7IiAqRQrVTkrnIgKjNCPVWdw,38130
18
18
  iqm/benchmarks/quantum_volume/__init__.py,sha256=i-Q4SpDWELBw7frXnxm1j4wJRcxbIyrS5uEK_v06YHo,951
@@ -22,14 +22,18 @@ iqm/benchmarks/randomized_benchmarking/__init__.py,sha256=IkKo-7zUChxZZd3my_csQC
22
22
  iqm/benchmarks/randomized_benchmarking/clifford_1q.pkl,sha256=yrmSJqhv7Lb1yqiqU9-2baqTljJPNmTUPQR-AH6GGfc,7800
23
23
  iqm/benchmarks/randomized_benchmarking/clifford_2q.pkl,sha256=mJQLubWPOb-DbmFi4oKYJqAMW_Yyo3eJjRjLGl9Sqmo,10282247
24
24
  iqm/benchmarks/randomized_benchmarking/multi_lmfit.py,sha256=Se1ygR4mXn_2_P82Ch31KBnCmY-g_A9NKzE9Ir8nEvw,3247
25
- iqm/benchmarks/randomized_benchmarking/randomized_benchmarking_common.py,sha256=MryufwrOCBcZZHDeX9WGHVtYhFz2XtS3xLm6YQYEAM4,43160
25
+ iqm/benchmarks/randomized_benchmarking/randomized_benchmarking_common.py,sha256=kX4ODF7MEB5olYKjpnUVon0hJ0irTOxz-z1exCa7mqc,54286
26
26
  iqm/benchmarks/randomized_benchmarking/clifford_rb/__init__.py,sha256=bTDA156LAl7OLGcMec--1nzDrV1XpPRVq3CquTmucgE,677
27
27
  iqm/benchmarks/randomized_benchmarking/clifford_rb/clifford_rb.py,sha256=IGBrq_a9eaVPknkBLKHKS4BOcumHn6TZdasUNKTZjGI,18685
28
+ iqm/benchmarks/randomized_benchmarking/direct_rb/__init__.py,sha256=lCIIeWMFZHnMUUEUTjUBvrhhUur6uBTHIVkxFBSfHC4,681
29
+ iqm/benchmarks/randomized_benchmarking/direct_rb/direct_rb.py,sha256=Cbx6B9q8Sqc_uPalX6fUEWJX6UEHCfWRof9u4brtx5A,48977
30
+ iqm/benchmarks/randomized_benchmarking/eplg/__init__.py,sha256=1MeGZTErElXJypQV2rQf7hwqLLvIp_JNVbwNhaP5vyI,696
31
+ iqm/benchmarks/randomized_benchmarking/eplg/eplg.py,sha256=VifpRgw8AHHu1NG9N86lcF0lFhFtauQUaclk5mc__EY,17217
28
32
  iqm/benchmarks/randomized_benchmarking/interleaved_rb/__init__.py,sha256=sq6MgN_hwlpkOj10vyCU4e6eKSX-oLcF2L9na6W2Gt4,681
29
33
  iqm/benchmarks/randomized_benchmarking/interleaved_rb/interleaved_rb.py,sha256=TaR1YFWBhOgm1hmEQzuwLYpp0yl0Xpuo3jAT6YhiXpc,28471
30
- iqm/benchmarks/randomized_benchmarking/mirror_rb/__init__.py,sha256=ZekEqI_89nXzGO1vjM-b5Uwwicy59M4fYHXfA-f0MIg,674
31
- iqm/benchmarks/randomized_benchmarking/mirror_rb/mirror_rb.py,sha256=_xdp8XLPcZyuqy7Xz8-K8H7zjgRo9ZxFiDgCXE72gaE,34997
32
- iqm_benchmarks-2.31.dist-info/licenses/LICENSE,sha256=2Ncb40-hqkTil78RPv3-YiJfKaJ8te9USJgliKqIdSY,11558
34
+ iqm/benchmarks/randomized_benchmarking/mirror_rb/__init__.py,sha256=jRKbivWCZ3xdO1k0sx-ygC3s5DUkGSModd975PoAtcg,692
35
+ iqm/benchmarks/randomized_benchmarking/mirror_rb/mirror_rb.py,sha256=n_5gt9636ZDMsM9hC3Zm5qP2bQr2sy41zxGhOh0XMjI,32932
36
+ iqm_benchmarks-2.33.dist-info/licenses/LICENSE,sha256=2Ncb40-hqkTil78RPv3-YiJfKaJ8te9USJgliKqIdSY,11558
33
37
  mGST/LICENSE,sha256=TtHNq55cUcbglb7uhVudeBLUh_qPdUoAEvU0BBwFz-k,1098
34
38
  mGST/README.md,sha256=v_5kw253csHF4-RfE-44KqFmBXIsSMRmOtN0AUPrRxE,5050
35
39
  mGST/additional_fns.py,sha256=_SEJ10FRNM7_CroysT8hCLZTfpm6ZhEIDCY5zPTnhjo,31390
@@ -40,7 +44,7 @@ mGST/optimization.py,sha256=YHwkzIkYvsZOPjclR-BCQWh24jeqjuXp0BB0WX5Lwow,10559
40
44
  mGST/qiskit_interface.py,sha256=ajx6Zn5FnrX_T7tMP8xnBLyG4c2ddFRm0Fu2_3r1t30,10118
41
45
  mGST/reporting/figure_gen.py,sha256=6Xd8vwfy09hLY1YbJY6TRevuMsQSU4MsWqemly3ZO0I,12970
42
46
  mGST/reporting/reporting.py,sha256=B8NWfpZrrSmyH7lwZxd0EbZMYLsAGK1YsHRB4D5qXH4,26002
43
- iqm_benchmarks-2.31.dist-info/METADATA,sha256=q-6NOPnr9dvN0ZQ1clPFZ4nFhgd38se5bR8tC_MxsdA,10710
44
- iqm_benchmarks-2.31.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
45
- iqm_benchmarks-2.31.dist-info/top_level.txt,sha256=3G23Z-1LGf-IOzTCUl6QwWqiQ3USz25Zt90Ihq192to,9
46
- iqm_benchmarks-2.31.dist-info/RECORD,,
47
+ iqm_benchmarks-2.33.dist-info/METADATA,sha256=XMUhEH8xorvgfxDPTRpjgp7hVd9bfZnsFgzTcxOhLI4,10847
48
+ iqm_benchmarks-2.33.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
49
+ iqm_benchmarks-2.33.dist-info/top_level.txt,sha256=3G23Z-1LGf-IOzTCUl6QwWqiQ3USz25Zt90Ihq192to,9
50
+ iqm_benchmarks-2.33.dist-info/RECORD,,