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

@@ -28,7 +28,7 @@ import networkx
28
28
  from networkx import Graph, all_pairs_shortest_path, is_connected, minimum_spanning_tree
29
29
  import numpy as np
30
30
  import pycurl
31
- from qiskit import QuantumCircuit, transpile
31
+ from qiskit import QuantumRegister, transpile
32
32
  from qiskit.quantum_info import random_clifford
33
33
  from qiskit.transpiler import CouplingMap
34
34
  from qiskit_aer import Aer
@@ -44,6 +44,7 @@ from iqm.benchmarks.benchmark_definition import (
44
44
  BenchmarkRunResult,
45
45
  add_counts_to_dataset,
46
46
  )
47
+ from iqm.benchmarks.circuit_containers import BenchmarkCircuit, CircuitGroup, Circuits
47
48
  from iqm.benchmarks.logging_config import qcvv_logger
48
49
  from iqm.benchmarks.readout_mitigation import apply_readout_error_mitigation
49
50
  from iqm.benchmarks.utils import (
@@ -55,6 +56,7 @@ from iqm.benchmarks.utils import (
55
56
  timeit,
56
57
  xrvariable_to_counts,
57
58
  )
59
+ from iqm.qiskit_iqm import IQMCircuit as QuantumCircuit
58
60
  from iqm.qiskit_iqm.iqm_backend import IQMBackendBase
59
61
 
60
62
 
@@ -94,16 +96,13 @@ def append_rms(
94
96
  rm_circ.compose(rand_clifford, qubits=[q], inplace=True)
95
97
 
96
98
  rm_circ.measure_active()
97
- # if backend is not None and backend.name != "IQMNdonisBackend" and optimize_sqg:
98
- # rm_circuits.append(optimize_single_qubit_gates(rm_circ))
99
- # else:
100
99
  rm_circuits.append(transpile(rm_circ, basis_gates=backend.operation_names))
101
100
 
102
101
  return rm_circuits
103
102
 
104
103
 
105
104
  def fidelity_ghz_randomized_measurements(
106
- dataset: xr.Dataset, qubit_layout, ideal_probabilities: List[Dict[str, int]], num_qubits: int
105
+ dataset: xr.Dataset, qubit_layout, ideal_probabilities: List[Dict[str, int]], num_qubits: int, circuits: Circuits
107
106
  ) -> tuple[dict[str, Any], dict[str, Any]]:
108
107
  """
109
108
  Estimates GHZ state fidelity through cross-correlations of RMs.
@@ -113,7 +112,8 @@ def fidelity_ghz_randomized_measurements(
113
112
  dataset (xr.Dataset):
114
113
  qubit_layout: List[int]: The subset of system-qubits used in the protocol
115
114
  ideal_probabilities (List[Dict[str, int]]):
116
- num_qubits (int):
115
+ num_qubits (int): Number of qubits
116
+ circuits (Circuits): Instance of `Circuits` containing transpiled circuits
117
117
  Returns:
118
118
  values: dict[str, Any]
119
119
  The fidelities
@@ -125,7 +125,7 @@ def fidelity_ghz_randomized_measurements(
125
125
  fid_rm = []
126
126
 
127
127
  # Loop through RMs and add each contribution
128
- num_rms = len(dataset.attrs["transpiled_circuits"][f"{idx}"])
128
+ num_rms = len(circuits["transpiled_circuits"][f"{idx}_native_ghz"].circuits)
129
129
  for u in range(num_rms):
130
130
  # Probability estimates for noisy measurements
131
131
  probabilities_sample = {}
@@ -168,7 +168,7 @@ def fidelity_ghz_randomized_measurements(
168
168
  return values, uncertainties
169
169
 
170
170
 
171
- def fidelity_ghz_coherences(dataset: xr.Dataset, qubit_layout: List[int]) -> list[Any]:
171
+ def fidelity_ghz_coherences(dataset: xr.Dataset, qubit_layout: List[int], circuits: Circuits) -> list[Any]:
172
172
  """
173
173
  Estimates the GHZ state fidelity based on the multiple quantum coherences method based on [Mooney, 2021]
174
174
 
@@ -177,6 +177,8 @@ def fidelity_ghz_coherences(dataset: xr.Dataset, qubit_layout: List[int]) -> lis
177
177
  An xarray dataset containing the measurement data
178
178
  qubit_layout: List[int]
179
179
  The subset of system-qubits used in the protocol
180
+ circuits: Circuits
181
+ Instance of `Circuits` containing transpiled circuits
180
182
 
181
183
  Returns:
182
184
  dict[str, dict[str, Any]]: The ghz fidelity or, if rem=True, fidelity and readout error mitigated fidelity
@@ -185,9 +187,9 @@ def fidelity_ghz_coherences(dataset: xr.Dataset, qubit_layout: List[int]) -> lis
185
187
  num_qubits = len(qubit_layout)
186
188
  phases = [np.pi * i / (num_qubits + 1) for i in range(2 * num_qubits + 2)]
187
189
  idx = BenchmarkObservationIdentifier(qubit_layout).string_identifier
188
- transpiled_circuits = dataset.attrs["transpiled_circuits"][idx]
190
+ transpiled_circuits = circuits["transpiled_circuits"]
189
191
  num_shots = dataset.attrs["shots"]
190
- num_circuits = len(transpiled_circuits)
192
+ num_circuits = len(transpiled_circuits[f"{qubit_layout}_native_ghz"].circuits)
191
193
 
192
194
  # Computing the phase acquired by the |11...1> component for each interval
193
195
  complex_coefficients = np.exp(1j * num_qubits * np.array(phases))
@@ -250,45 +252,50 @@ def fidelity_analysis(run: BenchmarkRunResult) -> BenchmarkAnalysisResult:
250
252
 
251
253
  observation_list: list[BenchmarkObservation] = []
252
254
  for qubit_layout in qubit_layouts:
253
- if routine == "randomized_measurements":
254
- ideal_simulator = Aer.get_backend("statevector_simulator")
255
- ideal_probabilities = []
256
- idx = BenchmarkObservationIdentifier(qubit_layout).string_identifier
257
- all_circuits = run.dataset.attrs["transpiled_circuits"][idx]
258
- for qc in all_circuits:
259
- qc_copy = qc.copy()
260
- qc_copy.remove_final_measurements()
261
- deflated_qc = reduce_to_active_qubits(qc_copy, backend_name)
262
- ideal_probabilities.append(dict(sorted(ideal_simulator.run(deflated_qc).result().get_counts().items())))
263
- values, uncertainties = fidelity_ghz_randomized_measurements(
264
- dataset, qubit_layout, ideal_probabilities, len(qubit_layout)
265
- )
266
- observation_list.extend(
267
- [
268
- BenchmarkObservation(
269
- name=key,
270
- identifier=BenchmarkObservationIdentifier(qubit_layout),
271
- value=value,
272
- uncertainty=uncertainties[key],
273
- )
274
- for key, value in values.items()
275
- ]
276
- )
277
- else: # default routine == "coherences":
278
- fidelity = fidelity_ghz_coherences(dataset, qubit_layout)
279
- observation_list.extend(
280
- [
281
- BenchmarkObservation(
282
- name="fidelity", identifier=BenchmarkObservationIdentifier(qubit_layout), value=fidelity[0]
283
- )
284
- ]
285
- )
286
- if len(fidelity) > 1:
287
- observation_list.append(
288
- BenchmarkObservation(
289
- name="fidelity_rem", identifier=BenchmarkObservationIdentifier(qubit_layout), value=fidelity[1]
255
+ match routine:
256
+ case "randomized_measurements":
257
+ ideal_simulator = Aer.get_backend("statevector_simulator")
258
+ ideal_probabilities = []
259
+ idx = BenchmarkObservationIdentifier(qubit_layout).string_identifier
260
+ all_circuits = run.circuits["transpiled_circuits"][f"{idx}_native_ghz"].circuits
261
+ for qc in all_circuits:
262
+ qc_copy = qc.copy()
263
+ qc_copy.remove_final_measurements()
264
+ deflated_qc = reduce_to_active_qubits(qc_copy, backend_name)
265
+ ideal_probabilities.append(
266
+ dict(sorted(ideal_simulator.run(deflated_qc).result().get_counts().items()))
290
267
  )
268
+ values, uncertainties = fidelity_ghz_randomized_measurements(
269
+ dataset, qubit_layout, ideal_probabilities, len(qubit_layout), run.circuits
291
270
  )
271
+ observation_list.extend(
272
+ [
273
+ BenchmarkObservation(
274
+ name=key,
275
+ identifier=BenchmarkObservationIdentifier(qubit_layout),
276
+ value=value,
277
+ uncertainty=uncertainties[key],
278
+ )
279
+ for key, value in values.items()
280
+ ]
281
+ )
282
+ case "coherences":
283
+ fidelity = fidelity_ghz_coherences(dataset, qubit_layout, run.circuits)
284
+ observation_list.extend(
285
+ [
286
+ BenchmarkObservation(
287
+ name="fidelity", identifier=BenchmarkObservationIdentifier(qubit_layout), value=fidelity[0]
288
+ )
289
+ ]
290
+ )
291
+ if len(fidelity) > 1:
292
+ observation_list.append(
293
+ BenchmarkObservation(
294
+ name="fidelity_rem",
295
+ identifier=BenchmarkObservationIdentifier(qubit_layout),
296
+ value=fidelity[1],
297
+ )
298
+ )
292
299
  plots = {"All layout fidelities": plot_fidelities(observation_list, qubit_layouts)}
293
300
  return BenchmarkAnalysisResult(dataset=dataset, observations=observation_list, plots=plots)
294
301
 
@@ -304,7 +311,8 @@ def generate_ghz_linear(num_qubits: int) -> QuantumCircuit:
304
311
  A quantum circuit generating a GHZ state of n qubits
305
312
  """
306
313
  s = int(num_qubits / 2)
307
- qc = QuantumCircuit(num_qubits)
314
+ quantum_register = QuantumRegister(num_qubits)
315
+ qc = QuantumCircuit(quantum_register, name="GHZ_linear")
308
316
  qc.h(s)
309
317
 
310
318
  for m in range(s, 0, -1):
@@ -325,7 +333,8 @@ def generate_ghz_log_cruz(num_qubits: int) -> QuantumCircuit:
325
333
  Returns:
326
334
  A quantum circuit generating a GHZ state of n qubits
327
335
  """
328
- qc = QuantumCircuit(num_qubits)
336
+ quantum_register = QuantumRegister(num_qubits)
337
+ qc = QuantumCircuit(quantum_register, name="GHZ_log_Cruz")
329
338
  qc.h(0)
330
339
 
331
340
  for m in range(num_qubits):
@@ -346,7 +355,8 @@ def generate_ghz_log_mooney(num_qubits: int) -> QuantumCircuit:
346
355
  Returns:
347
356
  A quantum circuit generating a GHZ state of n qubits
348
357
  """
349
- qc = QuantumCircuit(num_qubits)
358
+ quantum_register = QuantumRegister(num_qubits)
359
+ qc = QuantumCircuit(quantum_register, name="GHZ_log_Mooney")
350
360
  qc.h(0)
351
361
 
352
362
  aux_n = int(np.ceil(np.log2(num_qubits)))
@@ -389,7 +399,8 @@ def generate_ghz_spanning_tree(
389
399
  participating_qubits = set(qubit for pair in cx_map[: n_state - 1] for qubit in pair)
390
400
 
391
401
  relabeling = {idx_old: idx_new for idx_new, idx_old in enumerate(participating_qubits)}
392
- qc = QuantumCircuit(n_state, name="ghz")
402
+ n_state_register = QuantumRegister(n_state)
403
+ qc = QuantumCircuit(n_state_register, name="ghz")
393
404
  qc.h([relabeling[cx_map[0][0]]])
394
405
  for _, pair in zip(np.arange(n_state - 1), cx_map):
395
406
  relabeled_pair = [relabeling[pair[0]], relabeling[pair[1]]]
@@ -594,7 +605,6 @@ class GHZBenchmark(Benchmark):
594
605
  super().__init__(backend, configuration)
595
606
 
596
607
  self.state_generation_routine = configuration.state_generation_routine
597
- # self.choose_qubits_routine = configuration.choose_qubits_routine
598
608
  if configuration.custom_qubits_array:
599
609
  self.custom_qubits_array = configuration.custom_qubits_array
600
610
  else:
@@ -606,7 +616,6 @@ class GHZBenchmark(Benchmark):
606
616
  if any(np.max(configuration.qubit_counts) > [len(layout) for layout in self.custom_qubits_array]):
607
617
  raise ValueError("The maximum given qubit count is larger than the size of the smallest qubit layout.")
608
618
  self.qubit_counts = configuration.qubit_counts
609
- # self.layout_idx_mapping = {str(qubit_layout): idx for idx, qubit_layout in enumerate(self.custom_qubits_array)}
610
619
 
611
620
  self.qiskit_optim_level = configuration.qiskit_optim_level
612
621
  self.optimize_sqg = configuration.optimize_sqg
@@ -617,11 +626,7 @@ class GHZBenchmark(Benchmark):
617
626
  self.cal_url = configuration.cal_url
618
627
  self.timestamp = strftime("%Y%m%d-%H%M%S")
619
628
 
620
- # @staticmethod
621
- # def name() -> str:
622
- # return "ghz"
623
-
624
- def generate_native_ghz(self, qubit_layout: List[int], qubit_count: int, routine: str) -> QuantumCircuit:
629
+ def generate_native_ghz(self, qubit_layout: List[int], qubit_count: int, routine: str) -> CircuitGroup:
625
630
  """
626
631
  Generate a circuit preparing a GHZ state,
627
632
  according to a given routine and transpiled to the native gate set and topology.
@@ -638,13 +643,13 @@ class GHZBenchmark(Benchmark):
638
643
  Returns:
639
644
  QuantumCircuit implementing GHZ native state
640
645
  """
641
- # num_qubits = len(qubit_layout)
646
+ circuit_group = CircuitGroup(name=f"{qubit_layout}_native_ghz")
642
647
  fixed_coupling_map = set_coupling_map(qubit_layout, self.backend, "fixed")
643
- idx = BenchmarkObservationIdentifier(qubit_layout).string_identifier
644
648
  ghz_native_transpiled: List[QuantumCircuit]
649
+
645
650
  if routine == "naive":
646
- ghz = generate_ghz_linear(qubit_count)
647
- self.untranspiled_circuits[idx].update({qubit_count: ghz})
651
+ ghz: QuantumCircuit = generate_ghz_linear(qubit_count)
652
+ circuit_group.add_circuit(ghz)
648
653
  ghz_native_transpiled, _ = perform_backend_transpilation(
649
654
  [ghz],
650
655
  self.backend,
@@ -661,7 +666,7 @@ class GHZBenchmark(Benchmark):
661
666
  else:
662
667
  graph = get_edges(self.backend.coupling_map, qubit_layout)
663
668
  ghz, _ = generate_ghz_spanning_tree(graph, qubit_layout, qubit_count)
664
- self.untranspiled_circuits[idx].update({qubit_count: ghz})
669
+ circuit_group.add_circuit(ghz)
665
670
  ghz_native_transpiled, _ = perform_backend_transpilation(
666
671
  [ghz],
667
672
  self.backend,
@@ -685,12 +690,13 @@ class GHZBenchmark(Benchmark):
685
690
  if ghz_native_transpiled[0].depth() == ghz_native_transpiled[1].depth():
686
691
  index_min_2q = np.argmin([c.count_ops()["cz"] for c in ghz_native_transpiled])
687
692
  final_ghz = ghz_native_transpiled[index_min_2q]
688
- self.untranspiled_circuits[idx].update({qubit_count: ghz_log[index_min_2q]})
693
+ circuit_group.add_circuit(ghz_log[index_min_2q])
689
694
  else:
690
695
  index_min_depth = np.argmin([c.depth() for c in ghz_native_transpiled])
691
696
  final_ghz = ghz_native_transpiled[index_min_depth]
692
- self.untranspiled_circuits[idx].update({qubit_count: ghz_log[index_min_depth]})
693
- return final_ghz[0]
697
+ circuit_group.add_circuit([ghz_log[index_min_depth]])
698
+ self.circuits["untranspiled_circuits"].circuit_groups.append(circuit_group)
699
+ return CircuitGroup(name=f"{qubit_layout}_native_ghz", circuits=[final_ghz[0]])
694
700
 
695
701
  def generate_coherence_meas_circuits(self, qubit_layout: List[int], qubit_count: int) -> List[QuantumCircuit]:
696
702
  """
@@ -708,9 +714,9 @@ class GHZBenchmark(Benchmark):
708
714
  """
709
715
 
710
716
  idx = BenchmarkObservationIdentifier(qubit_layout).string_identifier
711
- qc = self.untranspiled_circuits[idx][qubit_count]
712
- qc_list = [qc.copy()]
717
+ qc_list = self.circuits["untranspiled_circuits"][f"{qubit_layout}_native_ghz"].circuits
713
718
 
719
+ qc = qc_list[0].copy()
714
720
  qc.remove_final_measurements()
715
721
  qc_inv = qc.inverse()
716
722
  phases = [np.pi * i / (qubit_count + 1) for i in range(2 * qubit_count + 2)]
@@ -733,10 +739,11 @@ class GHZBenchmark(Benchmark):
733
739
  qiskit_optim_level=self.qiskit_optim_level,
734
740
  optimize_sqg=self.optimize_sqg,
735
741
  )
736
- self.untranspiled_circuits[idx].update({qubit_count: qc_list})
742
+ circuit_group = CircuitGroup(name=idx, circuits=qc_list)
743
+ self.circuits["untranspiled_circuits"].circuit_groups.append(circuit_group)
737
744
  return qc_list_transpiled
738
745
 
739
- def generate_readout_circuit(self, qubit_layout, qubit_count):
746
+ def generate_readout_circuit(self, qubit_layout: List[int], qubit_count: int) -> CircuitGroup:
740
747
  """
741
748
  A wrapper for the creation of different circuits to estimate the fidelity
742
749
 
@@ -752,22 +759,23 @@ class GHZBenchmark(Benchmark):
752
759
  A list of transpiled quantum circuits to be measured
753
760
  """
754
761
  # Generate the list of circuits
755
- idx = BenchmarkObservationIdentifier(qubit_layout).string_identifier
756
- self.untranspiled_circuits[idx] = {}
757
- self.transpiled_circuits[idx] = {}
758
762
 
759
763
  qcvv_logger.info(f"Now generating a {len(qubit_layout)}-qubit GHZ state on qubits {qubit_layout}")
760
- transpiled_ghz = self.generate_native_ghz(qubit_layout, qubit_count, self.state_generation_routine)
761
-
762
- if self.fidelity_routine == "randomized_measurements":
763
- all_circuits_list, _ = append_rms(transpiled_ghz, cast(int, self.num_RMs), self.backend)
764
- elif self.fidelity_routine == "coherences":
765
- all_circuits_list = self.generate_coherence_meas_circuits(qubit_layout, qubit_count)
766
- else:
767
- all_circuits_list = transpiled_ghz
764
+ transpiled_ghz_group: CircuitGroup = self.generate_native_ghz(
765
+ qubit_layout, qubit_count, self.state_generation_routine
766
+ )
768
767
 
769
- self.transpiled_circuits.update({idx: all_circuits_list})
770
- return all_circuits_list
768
+ match self.fidelity_routine:
769
+ case "randomized_measurements":
770
+ all_circuits_list, _ = append_rms(
771
+ transpiled_ghz_group.circuits[0], cast(int, self.num_RMs), self.backend
772
+ )
773
+ transpiled_ghz_group.circuits = all_circuits_list
774
+ case "coherences":
775
+ all_circuits_list = self.generate_coherence_meas_circuits(qubit_layout, qubit_count)
776
+ transpiled_ghz_group.circuits = all_circuits_list
777
+ self.circuits["transpiled_circuits"].circuit_groups.append(transpiled_ghz_group)
778
+ return transpiled_ghz_group
771
779
 
772
780
  def add_configuration_to_dataset(self, dataset: xr.Dataset): # CHECK
773
781
  """
@@ -785,8 +793,7 @@ class GHZBenchmark(Benchmark):
785
793
  else:
786
794
  dataset.attrs[key] = value
787
795
  dataset.attrs[f"backend_name"] = self.backend.name
788
- dataset.attrs[f"untranspiled_circuits"] = self.untranspiled_circuits
789
- dataset.attrs[f"transpiled_circuits"] = self.transpiled_circuits
796
+ dataset.attrs["fidelity_routine"] = self.fidelity_routine
790
797
 
791
798
  def execute(self, backend) -> xr.Dataset:
792
799
  """
@@ -797,13 +804,17 @@ class GHZBenchmark(Benchmark):
797
804
 
798
805
  # Submit all
799
806
  all_jobs: Dict = {}
807
+
808
+ self.circuits = Circuits()
809
+ self.circuits.benchmark_circuits.append(BenchmarkCircuit(name="transpiled_circuits"))
810
+ self.circuits.benchmark_circuits.append(BenchmarkCircuit(name="untranspiled_circuits"))
800
811
  for qubit_layout in aux_custom_qubits_array:
801
812
  Id = BenchmarkObservationIdentifier(qubit_layout)
802
813
  idx = Id.string_identifier
803
814
  # for qubit_count in self.qubit_counts[idx]:
804
815
  qubit_count = len(qubit_layout)
805
- circuits = self.generate_readout_circuit(qubit_layout, qubit_count)
806
- transpiled_circuit_dict = {tuple(qubit_layout): circuits}
816
+ circuit_group: CircuitGroup = self.generate_readout_circuit(qubit_layout, qubit_count)
817
+ transpiled_circuit_dict = {tuple(qubit_layout): circuit_group.circuits}
807
818
  all_jobs[idx], _ = submit_execute(
808
819
  transpiled_circuit_dict,
809
820
  backend,
@@ -811,6 +822,7 @@ class GHZBenchmark(Benchmark):
811
822
  self.calset_id,
812
823
  max_gates_per_batch=self.max_gates_per_batch,
813
824
  )
825
+
814
826
  # Retrieve all
815
827
  qcvv_logger.info(f"Retrieving counts and adding counts to dataset...")
816
828
  for qubit_layout in aux_custom_qubits_array:
@@ -822,8 +834,8 @@ class GHZBenchmark(Benchmark):
822
834
  dataset, _ = add_counts_to_dataset(counts, idx, dataset)
823
835
  if self.rem:
824
836
  qcvv_logger.info(f"Applying readout error mitigation")
825
- circuits = self.transpiled_circuits[idx]
826
- rem_results, _ = apply_readout_error_mitigation(backend, circuits, counts, self.mit_shots)
837
+ circuit_group = self.circuits["transpiled_circuits"][f"{idx}_native_ghz"]
838
+ rem_results, _ = apply_readout_error_mitigation(backend, circuit_group.circuits, counts, self.mit_shots)
827
839
  rem_results_dist = [counts_mit.nearest_probability_distribution() for counts_mit in rem_results]
828
840
  dataset, _ = add_counts_to_dataset(rem_results_dist, f"{idx}_rem", dataset)
829
841
 
@@ -26,12 +26,12 @@ import matplotlib.pyplot as plt
26
26
  from networkx import Graph
27
27
  import networkx as nx
28
28
  import numpy as np
29
- from qiskit import QuantumCircuit
30
29
  from scipy.optimize import basinhopping, minimize
31
30
 
32
31
  from iqm.benchmarks.benchmark import BenchmarkBase, BenchmarkConfigurationBase
33
32
  from iqm.benchmarks.logging_config import qcvv_logger
34
33
  from iqm.benchmarks.utils import perform_backend_transpilation, retrieve_all_counts, submit_execute, timeit
34
+ from iqm.qiskit_iqm import IQMCircuit as QuantumCircuit
35
35
  from iqm.qiskit_iqm.iqm_backend import IQMBackendBase
36
36
 
37
37
 
@@ -25,13 +25,13 @@ import matplotlib as mpl
25
25
  from matplotlib.figure import Figure
26
26
  import matplotlib.pyplot as plt
27
27
  import numpy as np
28
- from qiskit import QuantumCircuit
29
28
  from qiskit.circuit import ParameterVector
30
29
  import xarray as xr
31
30
 
32
31
  from iqm.benchmarks import Benchmark
33
32
  from iqm.benchmarks.benchmark import BenchmarkConfigurationBase
34
33
  from iqm.benchmarks.benchmark_definition import BenchmarkAnalysisResult, BenchmarkRunResult
34
+ from iqm.benchmarks.circuit_containers import BenchmarkCircuit, CircuitGroup, Circuits
35
35
  from iqm.benchmarks.logging_config import qcvv_logger
36
36
  from iqm.benchmarks.utils import (
37
37
  count_2q_layers,
@@ -44,6 +44,7 @@ from iqm.benchmarks.utils import (
44
44
  submit_execute,
45
45
  timeit,
46
46
  )
47
+ from iqm.qiskit_iqm import IQMCircuit as QuantumCircuit
47
48
  from iqm.qiskit_iqm.iqm_backend import IQMBackendBase
48
49
  from iqm.qiskit_iqm.iqm_transpilation import optimize_single_qubit_gates
49
50
 
@@ -251,9 +252,10 @@ def clops_analysis(run: BenchmarkRunResult) -> BenchmarkAnalysisResult:
251
252
  all_times_retrieve = dataset.attrs["all_times_retrieve"]
252
253
 
253
254
  transpiled_qc_list = []
254
- for _, value in dataset.attrs["transpiled_circuits"].items():
255
- for _, transpiled_circuit in value.items():
256
- transpiled_qc_list.extend(transpiled_circuit)
255
+ for group in run.circuits["transpiled_circuits"].circuit_groups:
256
+ transpiled_qc_list.extend(group.circuits)
257
+ # for _, value in dataset.attrs["transpiled_circuits"].items():
258
+ # for _, transpiled_circuit in value.items():
257
259
 
258
260
  # CLOPS_V
259
261
  clops_v: float = num_circuits * num_updates * num_shots * depth / clops_time
@@ -387,26 +389,6 @@ class CLOPSBenchmark(Benchmark):
387
389
  dataset.attrs["u_per_layer"] = self.u_per_layer
388
390
  dataset.attrs["num_parameters"] = self.num_parameters
389
391
 
390
- def add_all_circuits_to_dataset(self, dataset: xr.Dataset):
391
- """Adds all generated circuits during execution to the dataset variable
392
-
393
- Args:
394
- dataset (xr.Dataset): The xarray dataset
395
-
396
- Returns:
397
-
398
- """
399
- qcvv_logger.info(f"Adding all circuits to the dataset")
400
- for key, circuit in zip(
401
- ["transpiled_circuits", "untranspiled_circuits"], [self.transpiled_circuits, self.untranspiled_circuits]
402
- ):
403
- dictionary = {}
404
- for outer_key, outer_value in circuit.items():
405
- dictionary[str(outer_key)] = {
406
- str(inner_key): inner_values for inner_key, inner_values in outer_value.items()
407
- }
408
- dataset.attrs[key] = dictionary
409
-
410
392
  def append_parameterized_unitary(
411
393
  self,
412
394
  qc: QuantumCircuit,
@@ -593,8 +575,6 @@ class CLOPSBenchmark(Benchmark):
593
575
  Dict[str, QuantumCircuit]: a dictionary of quantum circuits with keys being str(qubit layout)
594
576
  """
595
577
  # Generate the list of QV circuits
596
- self.untranspiled_circuits = {}
597
- self.transpiled_circuits = {}
598
578
 
599
579
  qc_list, self.time_circuit_generate = self.generate_circuit_list()
600
580
 
@@ -622,11 +602,9 @@ class CLOPSBenchmark(Benchmark):
622
602
  # Sort circuits according to their final measurement mappings
623
603
  (sorted_transpiled_qc_list, _), self.time_sort_batches = sort_batches_by_final_layout(transpiled_qc_list)
624
604
 
625
- self.untranspiled_circuits.update({str(self.qubits): {str(self.qubits): qc_list}})
626
- self.transpiled_circuits.update(
627
- {str(self.qubits): {str(key): value for key, value in sorted_transpiled_qc_list.items()}}
628
- )
629
- # self.transpiled_circuits[str(self.qubits)].update(sorted_transpiled_qc_list)
605
+ self.untranspiled_circuits.circuit_groups.append(CircuitGroup(name=self.qubits, circuits=qc_list))
606
+ for key in sorted_transpiled_qc_list.keys():
607
+ self.transpiled_circuits.circuit_groups.append(CircuitGroup(name=f"{self.qubits}_{key}", circuits=qc_list))
630
608
 
631
609
  return sorted_transpiled_qc_list
632
610
 
@@ -635,6 +613,9 @@ class CLOPSBenchmark(Benchmark):
635
613
 
636
614
  self.execution_timestamp = strftime("%Y-%m-%d_%H:%M:%S")
637
615
 
616
+ self.circuits = Circuits()
617
+ self.transpiled_circuits = BenchmarkCircuit(name="transpiled_circuits")
618
+ self.untranspiled_circuits = BenchmarkCircuit(name="untranspiled_circuits")
638
619
  dataset = xr.Dataset()
639
620
  self.add_all_meta_to_dataset(dataset)
640
621
 
@@ -691,7 +672,7 @@ class CLOPSBenchmark(Benchmark):
691
672
  }
692
673
  )
693
674
 
694
- self.add_all_circuits_to_dataset(dataset)
675
+ self.circuits = Circuits([self.transpiled_circuits, self.untranspiled_circuits])
695
676
 
696
677
  return dataset
697
678
 
@@ -25,14 +25,10 @@ import matplotlib.pyplot as plt
25
25
  from mthree.classes import QuasiCollection
26
26
  from mthree.utils import expval
27
27
  import numpy as np
28
- from qiskit import QuantumCircuit
29
28
  from qiskit.circuit.library import QuantumVolume
30
29
  from qiskit_aer import Aer
31
30
  import xarray as xr
32
31
 
33
- # import iqm.diqe.executors.dynamical_decoupling.dd_high_level as dd
34
- # from iqm.diqe.executors.dynamical_decoupling.dynamical_decoupling_core import DDStrategy
35
- # from iqm.diqe.mapomatic import evaluate_costs, get_calibration_fidelities, get_circuit, matching_layouts
36
32
  from iqm.benchmarks.benchmark import BenchmarkConfigurationBase
37
33
  from iqm.benchmarks.benchmark_definition import (
38
34
  Benchmark,
@@ -42,6 +38,11 @@ from iqm.benchmarks.benchmark_definition import (
42
38
  BenchmarkRunResult,
43
39
  add_counts_to_dataset,
44
40
  )
41
+
42
+ # import iqm.diqe.executors.dynamical_decoupling.dd_high_level as dd
43
+ # from iqm.diqe.executors.dynamical_decoupling.dynamical_decoupling_core import DDStrategy
44
+ # from iqm.diqe.mapomatic import evaluate_costs, get_calibration_fidelities, get_circuit, matching_layouts
45
+ from iqm.benchmarks.circuit_containers import BenchmarkCircuit, CircuitGroup, Circuits
45
46
  from iqm.benchmarks.logging_config import qcvv_logger
46
47
  from iqm.benchmarks.readout_mitigation import apply_readout_error_mitigation
47
48
  from iqm.benchmarks.utils import ( # execute_with_dd,
@@ -55,6 +56,7 @@ from iqm.benchmarks.utils import ( # execute_with_dd,
55
56
  timeit,
56
57
  xrvariable_to_counts,
57
58
  )
59
+ from iqm.qiskit_iqm import IQMCircuit as QuantumCircuit
58
60
  from iqm.qiskit_iqm.iqm_backend import IQMBackendBase
59
61
 
60
62
 
@@ -322,13 +324,7 @@ def qv_analysis(run: BenchmarkRunResult) -> BenchmarkAnalysisResult:
322
324
  # Retrieve other dataset values
323
325
  dataset_dictionary = dataset.attrs[qubits_idx]
324
326
  sorted_qc_list_indices = dataset_dictionary["sorted_qc_list_indices"]
325
- transpiled_circ_dataset = dataset.attrs["transpiled_circuits"][str(qubits)]
326
- transpiled_qc_list = []
327
- untranspiled_circ_dataset = dataset.attrs["untranspiled_circuits"][str(qubits)]
328
- qc_list = []
329
- for key in transpiled_circ_dataset: # Keys (final layouts) are the same for transp/untransp
330
- transpiled_qc_list.extend(transpiled_circ_dataset[key])
331
- qc_list.extend(untranspiled_circ_dataset[key])
327
+ qc_list = run.circuits["transpiled_circuits"][str(qubits)].circuits
332
328
 
333
329
  qv_results_type[str(qubits)] = dataset_dictionary["qv_results_type"]
334
330
  depth[str(qubits)] = len(qubits)
@@ -738,13 +734,13 @@ class QuantumVolumeBenchmark(Benchmark):
738
734
  sorted_qc_list_indices = {}
739
735
 
740
736
  # Initialize the variable to contain the QV circuits of each layout
741
- self.untranspiled_circuits: Dict[str, Dict[Tuple, List[QuantumCircuit]]] = {}
742
- self.transpiled_circuits: Dict[str, Dict[Tuple, List[QuantumCircuit]]] = {}
737
+ self.circuits = Circuits()
738
+ self.untranspiled_circuits = BenchmarkCircuit(name="untranspiled_circuits")
739
+ self.transpiled_circuits = BenchmarkCircuit(name="transpiled_circuits")
743
740
  all_op_counts = {}
744
741
 
745
742
  for qubits in self.custom_qubits_array: # NB: jobs will be submitted for qubit layouts in the specified order
746
- self.untranspiled_circuits[str(qubits)] = {}
747
- self.transpiled_circuits[str(qubits)] = {}
743
+
748
744
  num_qubits = len(qubits)
749
745
  depth = num_qubits
750
746
  qcvv_logger.info(f"Executing QV on qubits {qubits}")
@@ -781,8 +777,10 @@ class QuantumVolumeBenchmark(Benchmark):
781
777
  else:
782
778
  raise ValueError("physical_layout must either be \"fixed\" or \"batching\"")
783
779
 
784
- self.untranspiled_circuits[str(qubits)].update({tuple(qubits): qc_list})
785
- self.transpiled_circuits[str(qubits)].update(sorted_transpiled_qc_list)
780
+ self.untranspiled_circuits.circuit_groups.append(CircuitGroup(name=str(qubits), circuits=qc_list))
781
+ self.transpiled_circuits.circuit_groups.append(
782
+ CircuitGroup(name=str(qubits), circuits=sorted_transpiled_qc_list[tuple(qubits)])
783
+ )
786
784
 
787
785
  # Count operations
788
786
  all_op_counts[str(qubits)] = count_native_gates(backend, transpiled_qc_list)
@@ -823,14 +821,15 @@ class QuantumVolumeBenchmark(Benchmark):
823
821
  qcvv_logger.info(f"Adding counts of {qubits} run to the dataset")
824
822
  dataset, _ = add_counts_to_dataset(execution_results, str(qubits), dataset)
825
823
 
826
- self.add_all_circuits_to_dataset(dataset)
824
+ self.circuits = Circuits([self.transpiled_circuits, self.untranspiled_circuits])
827
825
 
828
826
  if self.rem:
829
827
  rem_quasidistros = {}
830
828
  for qubits in self.custom_qubits_array:
831
829
  exec_counts = xrvariable_to_counts(dataset, str(qubits), self.num_circuits)
832
830
  rem_quasidistros[f"REM_quasidist_{str(qubits)}"] = self.get_rem_quasidistro(
833
- self.transpiled_circuits[str(qubits)],
831
+ {tuple(qubits): self.transpiled_circuits[str(qubits)].circuits},
832
+ # self.transpiled_circuits[str(qubits)],
834
833
  sorted_qc_list_indices[str(qubits)],
835
834
  exec_counts,
836
835
  self.mit_shots,