iqm-benchmarks 1.3__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.

Files changed (42) hide show
  1. iqm/benchmarks/__init__.py +31 -0
  2. iqm/benchmarks/benchmark.py +109 -0
  3. iqm/benchmarks/benchmark_definition.py +264 -0
  4. iqm/benchmarks/benchmark_experiment.py +163 -0
  5. iqm/benchmarks/compressive_gst/__init__.py +20 -0
  6. iqm/benchmarks/compressive_gst/compressive_gst.py +1029 -0
  7. iqm/benchmarks/entanglement/__init__.py +18 -0
  8. iqm/benchmarks/entanglement/ghz.py +802 -0
  9. iqm/benchmarks/logging_config.py +29 -0
  10. iqm/benchmarks/optimization/__init__.py +18 -0
  11. iqm/benchmarks/optimization/qscore.py +719 -0
  12. iqm/benchmarks/quantum_volume/__init__.py +21 -0
  13. iqm/benchmarks/quantum_volume/clops.py +726 -0
  14. iqm/benchmarks/quantum_volume/quantum_volume.py +854 -0
  15. iqm/benchmarks/randomized_benchmarking/__init__.py +18 -0
  16. iqm/benchmarks/randomized_benchmarking/clifford_1q.pkl +0 -0
  17. iqm/benchmarks/randomized_benchmarking/clifford_2q.pkl +0 -0
  18. iqm/benchmarks/randomized_benchmarking/clifford_rb/__init__.py +19 -0
  19. iqm/benchmarks/randomized_benchmarking/clifford_rb/clifford_rb.py +386 -0
  20. iqm/benchmarks/randomized_benchmarking/interleaved_rb/__init__.py +19 -0
  21. iqm/benchmarks/randomized_benchmarking/interleaved_rb/interleaved_rb.py +555 -0
  22. iqm/benchmarks/randomized_benchmarking/mirror_rb/__init__.py +19 -0
  23. iqm/benchmarks/randomized_benchmarking/mirror_rb/mirror_rb.py +810 -0
  24. iqm/benchmarks/randomized_benchmarking/multi_lmfit.py +86 -0
  25. iqm/benchmarks/randomized_benchmarking/randomized_benchmarking_common.py +892 -0
  26. iqm/benchmarks/readout_mitigation.py +290 -0
  27. iqm/benchmarks/utils.py +521 -0
  28. iqm_benchmarks-1.3.dist-info/LICENSE +205 -0
  29. iqm_benchmarks-1.3.dist-info/METADATA +190 -0
  30. iqm_benchmarks-1.3.dist-info/RECORD +42 -0
  31. iqm_benchmarks-1.3.dist-info/WHEEL +5 -0
  32. iqm_benchmarks-1.3.dist-info/top_level.txt +2 -0
  33. mGST/LICENSE +21 -0
  34. mGST/README.md +54 -0
  35. mGST/additional_fns.py +962 -0
  36. mGST/algorithm.py +733 -0
  37. mGST/compatibility.py +238 -0
  38. mGST/low_level_jit.py +694 -0
  39. mGST/optimization.py +349 -0
  40. mGST/qiskit_interface.py +282 -0
  41. mGST/reporting/figure_gen.py +334 -0
  42. mGST/reporting/reporting.py +710 -0
@@ -0,0 +1,18 @@
1
+ # Copyright 2024 IQM Benchmarks developers
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ """
15
+ Randomized Benchmarking reflects the fidelity of a gate or operation on a number of qubits
16
+ """
17
+
18
+ from . import randomized_benchmarking_common
@@ -0,0 +1,19 @@
1
+ # Copyright 2024 IQM Benchmarks developers
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """
16
+ Clifford RB reflects the fidelity of Clifford gates
17
+ """
18
+
19
+ from . import clifford_rb
@@ -0,0 +1,386 @@
1
+ # Copyright 2024 IQM Benchmarks developers
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """
16
+ 'Standard' Clifford Randomized Benchmarking.
17
+ """
18
+
19
+ from time import strftime
20
+ from typing import Any, Dict, List, Sequence, Type
21
+
22
+ import numpy as np
23
+ from qiskit import QuantumCircuit
24
+ import xarray as xr
25
+
26
+ from iqm.benchmarks import AnalysisResult, Benchmark, RunResult
27
+ from iqm.benchmarks.benchmark import BenchmarkConfigurationBase
28
+ from iqm.benchmarks.benchmark_definition import add_counts_to_dataset
29
+ from iqm.benchmarks.logging_config import qcvv_logger
30
+ from iqm.benchmarks.randomized_benchmarking.randomized_benchmarking_common import (
31
+ exponential_rb,
32
+ fit_decay_lmfit,
33
+ generate_all_rb_circuits,
34
+ generate_fixed_depth_parallel_rb_circuits,
35
+ get_survival_probabilities,
36
+ import_native_gate_cliffords,
37
+ lmfit_minimizer,
38
+ plot_rb_decay,
39
+ submit_parallel_rb_job,
40
+ submit_sequential_rb_jobs,
41
+ survival_probabilities_parallel,
42
+ validate_rb_qubits,
43
+ )
44
+ from iqm.benchmarks.utils import retrieve_all_counts, retrieve_all_job_metadata, timeit, xrvariable_to_counts
45
+ from iqm.qiskit_iqm.iqm_backend import IQMBackendBase
46
+
47
+
48
+ def clifford_rb_analysis(run: RunResult) -> AnalysisResult:
49
+ """Analysis function for a Clifford RB experiment
50
+
51
+ Args:
52
+ run (RunResult): A Clifford RB experiment run for which analysis result is created
53
+ Returns:
54
+ AnalysisResult corresponding to Clifford RB
55
+ """
56
+ dataset = run.dataset
57
+ observations = {}
58
+ plots = {}
59
+
60
+ is_parallel_execution = dataset.attrs["parallel_execution"]
61
+ qubits_array = dataset.attrs["qubits_array"]
62
+ num_circuit_samples = dataset.attrs["num_circuit_samples"]
63
+ sequence_lengths = dataset.attrs["sequence_lengths"]
64
+
65
+ all_noisy_counts: Dict[str, Dict[int, List[Dict[str, int]]]] = {}
66
+ fidelities: Dict[str, Dict[int, List[float]]] = {str(q): {} for q in qubits_array}
67
+
68
+ if is_parallel_execution:
69
+ qcvv_logger.info(f"Post-processing parallel RB for qubits {qubits_array}")
70
+ all_noisy_counts[str(qubits_array)] = {}
71
+ for depth in sequence_lengths:
72
+ identifier = f"qubits_{str(qubits_array)}_depth_{str(depth)}"
73
+ all_noisy_counts[str(qubits_array)][depth] = xrvariable_to_counts(dataset, identifier, num_circuit_samples)
74
+
75
+ qcvv_logger.info(f"Depth {depth}")
76
+
77
+ # Retrieve the marginalized survival probabilities
78
+ all_survival_probabilities = survival_probabilities_parallel(
79
+ qubits_array, all_noisy_counts[str(qubits_array)][depth]
80
+ )
81
+
82
+ # The marginalized survival probabilities will be arranged by qubit layouts
83
+ for qubits_str in all_survival_probabilities.keys():
84
+ fidelities[qubits_str][depth] = all_survival_probabilities[qubits_str]
85
+ # Remaining analysis is the same regardless of whether execution was in parallel or sequential
86
+ else: # sequential
87
+ qcvv_logger.info(f"Post-processing sequential RB for qubits {qubits_array}")
88
+
89
+ for q in qubits_array:
90
+ all_noisy_counts[str(q)] = {}
91
+ num_qubits = len(q)
92
+ fidelities[str(q)] = {}
93
+ for depth in sequence_lengths:
94
+ identifier = f"qubits_{str(q)}_depth_{str(depth)}"
95
+ all_noisy_counts[str(q)][depth] = xrvariable_to_counts(dataset, identifier, num_circuit_samples)
96
+
97
+ qcvv_logger.info(f"Qubits {q} and depth {depth}")
98
+ fidelities[str(q)][depth] = get_survival_probabilities(num_qubits, all_noisy_counts[str(q)][depth])
99
+ # Remaining analysis is the same regardless of whether execution was in parallel or sequential
100
+
101
+ # All remaining (fitting & plotting) is done per qubit layout
102
+ for qubits_idx, qubits in enumerate(qubits_array):
103
+ # Fit decays
104
+ list_of_fidelities = list(fidelities[str(qubits)].values())
105
+ fit_data, fit_parameters = fit_decay_lmfit(exponential_rb, qubits, list_of_fidelities, "clifford")
106
+ rb_fit_results = lmfit_minimizer(fit_parameters, fit_data, sequence_lengths, exponential_rb)
107
+
108
+ average_fidelities = {d: np.mean(fidelities[str(qubits)][d]) for d in sequence_lengths}
109
+ stddevs_from_mean = {
110
+ d: np.std(fidelities[str(qubits)][d]) / np.sqrt(num_circuit_samples) for d in sequence_lengths
111
+ }
112
+ popt = {
113
+ "amplitude": rb_fit_results.params["amplitude_1"],
114
+ "offset": rb_fit_results.params["offset_1"],
115
+ "decay_rate": rb_fit_results.params["p_rb"],
116
+ }
117
+ fidelity = rb_fit_results.params["fidelity_per_clifford"]
118
+
119
+ processed_results = {
120
+ "avg_gate_fidelity": {"value": fidelity.value, "uncertainty": fidelity.stderr},
121
+ "decay_rate": {"value": popt["decay_rate"].value, "uncertainty": popt["decay_rate"].stderr},
122
+ "fit_amplitude": {"value": popt["amplitude"].value, "uncertainty": popt["amplitude"].stderr},
123
+ "fit_offset": {"value": popt["offset"].value, "uncertainty": popt["offset"].stderr},
124
+ }
125
+
126
+ dataset.attrs[qubits_idx].update(
127
+ {
128
+ "fidelities": fidelities[str(qubits)],
129
+ "avg_fidelities_nominal_values": average_fidelities,
130
+ "avg_fidelities_stderr": stddevs_from_mean,
131
+ "fitting_method": str(rb_fit_results.method),
132
+ "num_function_evals": int(rb_fit_results.nfev),
133
+ "data_points": int(rb_fit_results.ndata),
134
+ "num_variables": int(rb_fit_results.nvarys),
135
+ "chi_square": float(rb_fit_results.chisqr),
136
+ "reduced_chi_square": float(rb_fit_results.redchi),
137
+ "Akaike_info_crit": float(rb_fit_results.aic),
138
+ "Bayesian_info_crit": float(rb_fit_results.bic),
139
+ }
140
+ )
141
+
142
+ observations.update({qubits_idx: processed_results})
143
+
144
+ # Generate individual decay plots
145
+ fig_name, fig = plot_rb_decay("clifford", [qubits], dataset, observations)
146
+ plots[fig_name] = fig
147
+
148
+ return AnalysisResult(dataset=dataset, observations=observations, plots=plots)
149
+
150
+
151
+ class CliffordRandomizedBenchmarking(Benchmark):
152
+ """Clifford RB estimates the average gate fidelity of the n-qubit Clifford group"""
153
+
154
+ analysis_function = staticmethod(clifford_rb_analysis)
155
+
156
+ name: str = "clifford_rb"
157
+
158
+ def __init__(self, backend_arg: IQMBackendBase | str, configuration: "CliffordRBConfiguration"):
159
+ """Construct the CliffordRandomizedBenchmark class
160
+
161
+ Args:
162
+ backend_arg (IQMBackendBase | str): the backend to execute Clifford RB on
163
+ configuration (CliffordRBConfiguration): The Clifford RB configuration
164
+ """
165
+ super().__init__(backend_arg, configuration)
166
+
167
+ # EXPERIMENT
168
+ self.backend_configuration_name = backend_arg if isinstance(backend_arg, str) else backend_arg.name
169
+
170
+ self.qubits_array = configuration.qubits_array
171
+ self.sequence_lengths = configuration.sequence_lengths
172
+ self.num_circuit_samples = configuration.num_circuit_samples
173
+
174
+ self.parallel_execution = configuration.parallel_execution
175
+
176
+ self.session_timestamp = strftime("%Y%m%d-%H%M%S")
177
+ self.execution_timestamp = ""
178
+
179
+ def add_all_meta_to_dataset(self, dataset: xr.Dataset):
180
+ """Adds all configuration metadata and circuits to the dataset variable
181
+ Args:
182
+ dataset (xr.Dataset): The xarray dataset
183
+ """
184
+ dataset.attrs["session_timestamp"] = self.session_timestamp
185
+ dataset.attrs["execution_timestamp"] = self.execution_timestamp
186
+ dataset.attrs["backend_configuration_name"] = self.backend_configuration_name
187
+ dataset.attrs["backend_name"] = self.backend.name
188
+
189
+ for key, value in self.configuration:
190
+ if key == "benchmark": # Avoid saving the class object
191
+ dataset.attrs[key] = value.name
192
+ else:
193
+ dataset.attrs[key] = value
194
+ # Defined outside configuration - if any
195
+
196
+ @timeit
197
+ def add_all_circuits_to_dataset(self, dataset: xr.Dataset):
198
+ """Adds all generated circuits during execution to the dataset variable
199
+
200
+ Args:
201
+ dataset (xr.Dataset): The xarray dataset
202
+
203
+ Returns:
204
+
205
+ """
206
+ qcvv_logger.info(f"Adding all circuits to the dataset")
207
+ dataset.attrs["untranspiled_circuits"] = self.untranspiled_circuits
208
+ dataset.attrs["transpiled_circuits"] = self.transpiled_circuits
209
+
210
+ # pylint: disable=too-many-statements
211
+ def execute(self, backend: IQMBackendBase) -> xr.Dataset:
212
+ """Executes the benchmark"""
213
+
214
+ self.execution_timestamp = strftime("%Y%m%d-%H%M%S")
215
+ validate_rb_qubits(self.qubits_array, backend)
216
+
217
+ dataset = xr.Dataset()
218
+ self.add_all_meta_to_dataset(dataset)
219
+
220
+ clifford_1q_dict, clifford_2q_dict = import_native_gate_cliffords()
221
+
222
+ # Submit jobs for all qubit layouts
223
+ all_rb_jobs: List[Dict[str, Any]] = []
224
+ time_circuit_generation: Dict[str, float] = {}
225
+
226
+ # Initialize the variable to contain the circuits for each layout
227
+ self.untranspiled_circuits: Dict[str, Dict[int, List[QuantumCircuit]]] = {}
228
+ self.transpiled_circuits: Dict[str, Dict[int, List[QuantumCircuit]]] = {}
229
+
230
+ # Auxiliary dict from str(qubits) to indices
231
+ qubit_idx: Dict[str, Any] = {}
232
+
233
+ if self.parallel_execution:
234
+ # Take the whole qubits_array and do RB in parallel on each qubits_array element
235
+ parallel_untranspiled_rb_circuits = {}
236
+ parallel_transpiled_rb_circuits = {}
237
+ qcvv_logger.info(
238
+ f"Executing parallel RB on qubits {self.qubits_array}."
239
+ f" Will generate and submit all {self.num_circuit_samples} Clifford RB circuits"
240
+ f" for each depth {self.sequence_lengths}"
241
+ )
242
+
243
+ time_circuit_generation[str(self.qubits_array)] = 0
244
+ # Generate and submit all circuits
245
+ for seq_length in self.sequence_lengths:
246
+ qcvv_logger.info(f"Sequence length {seq_length}")
247
+ (
248
+ (parallel_untranspiled_rb_circuits[seq_length], parallel_transpiled_rb_circuits[seq_length]),
249
+ elapsed_time,
250
+ ) = generate_fixed_depth_parallel_rb_circuits(
251
+ self.qubits_array,
252
+ clifford_1q_dict,
253
+ clifford_2q_dict,
254
+ seq_length,
255
+ self.num_circuit_samples,
256
+ backend,
257
+ )
258
+ time_circuit_generation[str(self.qubits_array)] += elapsed_time
259
+
260
+ # Submit all
261
+ flat_qubits_array = [x for y in self.qubits_array for x in y]
262
+ sorted_transpiled_qc_list = {tuple(flat_qubits_array): parallel_transpiled_rb_circuits[seq_length]}
263
+ all_rb_jobs.append(
264
+ submit_parallel_rb_job(
265
+ backend,
266
+ self.qubits_array,
267
+ seq_length,
268
+ sorted_transpiled_qc_list,
269
+ self.shots,
270
+ self.calset_id,
271
+ self.max_gates_per_batch,
272
+ )
273
+ )
274
+ qcvv_logger.info(f"Job for sequence length {seq_length} submitted successfully!")
275
+
276
+ self.untranspiled_circuits[str(self.qubits_array)] = {
277
+ m: parallel_untranspiled_rb_circuits[m] for m in self.sequence_lengths
278
+ }
279
+ self.transpiled_circuits[str(self.qubits_array)] = {
280
+ m: parallel_transpiled_rb_circuits[m] for m in self.sequence_lengths
281
+ }
282
+
283
+ qubit_idx = {str(self.qubits_array): "parallel_all"}
284
+ dataset.attrs["parallel_all"] = {"qubits": self.qubits_array}
285
+ dataset.attrs.update({q_idx: {"qubits": q} for q_idx, q in enumerate(self.qubits_array)})
286
+ else:
287
+ rb_untranspiled_circuits: Dict[str, Dict[int, List[QuantumCircuit]]] = {}
288
+ rb_transpiled_circuits: Dict[str, Dict[int, List[QuantumCircuit]]] = {}
289
+ for qubits_idx, qubits in enumerate(self.qubits_array):
290
+ qubit_idx[str(qubits)] = qubits_idx
291
+ qcvv_logger.info(
292
+ f"Executing sequential Clifford RB on qubits {qubits}."
293
+ f" Will generate and submit all {self.num_circuit_samples} Clifford RB circuits"
294
+ f" for each depth {self.sequence_lengths}"
295
+ )
296
+
297
+ num_qubits = len(qubits)
298
+ rb_untranspiled_circuits[str(qubits)] = {}
299
+ rb_transpiled_circuits[str(qubits)] = {}
300
+
301
+ if num_qubits == 1:
302
+ clifford_dict = clifford_1q_dict
303
+ else:
304
+ clifford_dict = clifford_2q_dict
305
+
306
+ (rb_untranspiled_circuits[str(qubits)], rb_transpiled_circuits[str(qubits)]), time_circuit_generation[
307
+ str(qubits)
308
+ ] = generate_all_rb_circuits(
309
+ qubits,
310
+ self.sequence_lengths,
311
+ clifford_dict,
312
+ self.num_circuit_samples,
313
+ backend,
314
+ interleaved_gate=None,
315
+ )
316
+
317
+ # Submit
318
+ all_rb_jobs.extend(
319
+ submit_sequential_rb_jobs(
320
+ qubits,
321
+ rb_transpiled_circuits[str(qubits)],
322
+ self.shots,
323
+ self.backend,
324
+ self.calset_id,
325
+ max_gates_per_batch=self.max_gates_per_batch,
326
+ )
327
+ )
328
+ qcvv_logger.info(
329
+ f"All jobs for qubits {qubits} and sequence lengths {self.sequence_lengths} submitted successfully!"
330
+ )
331
+
332
+ self.untranspiled_circuits[str(qubits)] = rb_untranspiled_circuits[str(qubits)]
333
+ self.transpiled_circuits[str(qubits)] = rb_transpiled_circuits[str(qubits)]
334
+
335
+ dataset.attrs[qubits_idx] = {"qubits": qubits}
336
+
337
+ # Retrieve counts of jobs for all qubit layouts
338
+ all_job_metadata = {}
339
+ for job_dict in all_rb_jobs:
340
+ qubits = job_dict["qubits"]
341
+ depth = job_dict["depth"]
342
+ # Retrieve counts
343
+ identifier = f"qubits_{str(qubits)}_depth_{str(depth)}"
344
+ execution_results, time_retrieve = retrieve_all_counts(job_dict["jobs"], identifier)
345
+ # Retrieve all job meta data
346
+ all_job_metadata = retrieve_all_job_metadata(job_dict["jobs"])
347
+ # Export all to dataset
348
+ dataset.attrs[qubit_idx[str(qubits)]].update(
349
+ {
350
+ f"depth_{str(depth)}": {
351
+ "time_circuit_generation": time_circuit_generation[str(qubits)],
352
+ "time_submit": job_dict["time_submit"],
353
+ "time_retrieve": time_retrieve,
354
+ "all_job_metadata": all_job_metadata,
355
+ },
356
+ }
357
+ )
358
+
359
+ qcvv_logger.info(f"Adding counts of qubits {qubits} and depth {depth} run to the dataset")
360
+ dataset, _ = add_counts_to_dataset(execution_results, identifier, dataset)
361
+
362
+ self.add_all_circuits_to_dataset(dataset)
363
+
364
+ qcvv_logger.info(f"RB experiment concluded !")
365
+
366
+ return dataset
367
+
368
+
369
+ class CliffordRBConfiguration(BenchmarkConfigurationBase):
370
+ """Clifford RB configuration.
371
+
372
+ Attributes:
373
+ benchmark (Type[Benchmark]): CliffordRandomizedBenchmarking
374
+ qubits_array (Sequence[Sequence[int]]): The array of qubits on which to execute the benchmark.
375
+ sequence_lengths (Sequence[int]): The length of Cliffords sequences with which to execute benchmark.
376
+ num_circuit_samples (int): The number of Cliffords circuits per sequence length.
377
+ shots (int): The number of measurement shots per circuit.
378
+ parallel_execution(bool): Whether the benchmark is executed on all qubits in parallel or not.
379
+ * Default is False.
380
+ """
381
+
382
+ benchmark: Type[Benchmark] = CliffordRandomizedBenchmarking
383
+ qubits_array: Sequence[Sequence[int]]
384
+ sequence_lengths: Sequence[int]
385
+ num_circuit_samples: int
386
+ parallel_execution: bool = False
@@ -0,0 +1,19 @@
1
+ # Copyright 2024 IQM Benchmarks developers
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """
16
+ Interleaved RB reflects the fidelity of a given gate
17
+ """
18
+
19
+ from . import interleaved_rb