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.
- iqm/benchmarks/__init__.py +31 -0
- iqm/benchmarks/benchmark.py +109 -0
- iqm/benchmarks/benchmark_definition.py +264 -0
- iqm/benchmarks/benchmark_experiment.py +163 -0
- iqm/benchmarks/compressive_gst/__init__.py +20 -0
- iqm/benchmarks/compressive_gst/compressive_gst.py +1029 -0
- iqm/benchmarks/entanglement/__init__.py +18 -0
- iqm/benchmarks/entanglement/ghz.py +802 -0
- iqm/benchmarks/logging_config.py +29 -0
- iqm/benchmarks/optimization/__init__.py +18 -0
- iqm/benchmarks/optimization/qscore.py +719 -0
- iqm/benchmarks/quantum_volume/__init__.py +21 -0
- iqm/benchmarks/quantum_volume/clops.py +726 -0
- iqm/benchmarks/quantum_volume/quantum_volume.py +854 -0
- iqm/benchmarks/randomized_benchmarking/__init__.py +18 -0
- iqm/benchmarks/randomized_benchmarking/clifford_1q.pkl +0 -0
- iqm/benchmarks/randomized_benchmarking/clifford_2q.pkl +0 -0
- iqm/benchmarks/randomized_benchmarking/clifford_rb/__init__.py +19 -0
- iqm/benchmarks/randomized_benchmarking/clifford_rb/clifford_rb.py +386 -0
- iqm/benchmarks/randomized_benchmarking/interleaved_rb/__init__.py +19 -0
- iqm/benchmarks/randomized_benchmarking/interleaved_rb/interleaved_rb.py +555 -0
- iqm/benchmarks/randomized_benchmarking/mirror_rb/__init__.py +19 -0
- iqm/benchmarks/randomized_benchmarking/mirror_rb/mirror_rb.py +810 -0
- iqm/benchmarks/randomized_benchmarking/multi_lmfit.py +86 -0
- iqm/benchmarks/randomized_benchmarking/randomized_benchmarking_common.py +892 -0
- iqm/benchmarks/readout_mitigation.py +290 -0
- iqm/benchmarks/utils.py +521 -0
- iqm_benchmarks-1.3.dist-info/LICENSE +205 -0
- iqm_benchmarks-1.3.dist-info/METADATA +190 -0
- iqm_benchmarks-1.3.dist-info/RECORD +42 -0
- iqm_benchmarks-1.3.dist-info/WHEEL +5 -0
- iqm_benchmarks-1.3.dist-info/top_level.txt +2 -0
- mGST/LICENSE +21 -0
- mGST/README.md +54 -0
- mGST/additional_fns.py +962 -0
- mGST/algorithm.py +733 -0
- mGST/compatibility.py +238 -0
- mGST/low_level_jit.py +694 -0
- mGST/optimization.py +349 -0
- mGST/qiskit_interface.py +282 -0
- mGST/reporting/figure_gen.py +334 -0
- mGST/reporting/reporting.py +710 -0
|
@@ -0,0 +1,555 @@
|
|
|
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 Clifford Randomized Benchmarking.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from time import strftime
|
|
20
|
+
from typing import Any, Dict, List, Literal, Optional, Sequence, Type
|
|
21
|
+
|
|
22
|
+
from matplotlib.figure import Figure
|
|
23
|
+
import numpy as np
|
|
24
|
+
from qiskit import QuantumCircuit
|
|
25
|
+
import xarray as xr
|
|
26
|
+
|
|
27
|
+
from iqm.benchmarks import AnalysisResult, Benchmark, RunResult
|
|
28
|
+
from iqm.benchmarks.benchmark import BenchmarkConfigurationBase
|
|
29
|
+
from iqm.benchmarks.benchmark_definition import add_counts_to_dataset
|
|
30
|
+
from iqm.benchmarks.logging_config import qcvv_logger
|
|
31
|
+
from iqm.benchmarks.randomized_benchmarking.randomized_benchmarking_common import (
|
|
32
|
+
exponential_rb,
|
|
33
|
+
fit_decay_lmfit,
|
|
34
|
+
generate_all_rb_circuits,
|
|
35
|
+
generate_fixed_depth_parallel_rb_circuits,
|
|
36
|
+
get_survival_probabilities,
|
|
37
|
+
import_native_gate_cliffords,
|
|
38
|
+
lmfit_minimizer,
|
|
39
|
+
plot_rb_decay,
|
|
40
|
+
submit_parallel_rb_job,
|
|
41
|
+
submit_sequential_rb_jobs,
|
|
42
|
+
survival_probabilities_parallel,
|
|
43
|
+
validate_irb_gate,
|
|
44
|
+
validate_rb_qubits,
|
|
45
|
+
)
|
|
46
|
+
from iqm.benchmarks.utils import retrieve_all_counts, retrieve_all_job_metadata, timeit, xrvariable_to_counts
|
|
47
|
+
from iqm.qiskit_iqm.iqm_backend import IQMBackendBase
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
# pylint: disable=too-many-statements, too-many-branches
|
|
51
|
+
def interleaved_rb_analysis(run: RunResult) -> AnalysisResult:
|
|
52
|
+
"""Analysis function for an Interleaved RB experiment
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
run (RunResult): An interleaved RB experiment run for which analysis result is created
|
|
56
|
+
Returns:
|
|
57
|
+
AnalysisResult corresponding to Interleaved RB
|
|
58
|
+
"""
|
|
59
|
+
dataset = run.dataset
|
|
60
|
+
observations: Dict[int, Any] = {}
|
|
61
|
+
plots: Dict[str, Figure] = {}
|
|
62
|
+
|
|
63
|
+
is_parallel_execution = dataset.attrs["parallel_execution"]
|
|
64
|
+
qubits_array = dataset.attrs["qubits_array"]
|
|
65
|
+
num_circuit_samples = dataset.attrs["num_circuit_samples"]
|
|
66
|
+
sequence_lengths = dataset.attrs["sequence_lengths"]
|
|
67
|
+
|
|
68
|
+
interleaved_gate = dataset.attrs["interleaved_gate"]
|
|
69
|
+
interleaved_gate_parameters = dataset.attrs["interleaved_gate_params"]
|
|
70
|
+
|
|
71
|
+
simultaneous_fit = dataset.attrs["simultaneous_fit"]
|
|
72
|
+
|
|
73
|
+
all_noisy_counts: Dict[str, Dict[str, Dict[int, List[Dict[str, int]]]]] = {}
|
|
74
|
+
fidelities: Dict[str, Dict[str, Dict[int, List[float]]]] = {
|
|
75
|
+
str(q): {rb_type: {} for rb_type in ["clifford", "interleaved"]} for q in qubits_array
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if is_parallel_execution:
|
|
79
|
+
qcvv_logger.info(f"Post-processing parallel Interleaved RB for qubits {qubits_array}")
|
|
80
|
+
all_noisy_counts[str(qubits_array)] = {}
|
|
81
|
+
for rb_type in ["clifford", "interleaved"]:
|
|
82
|
+
all_noisy_counts[str(qubits_array)][rb_type] = {}
|
|
83
|
+
for depth in sequence_lengths:
|
|
84
|
+
identifier = f"{rb_type}_qubits_{str(qubits_array)}_depth_{str(depth)}"
|
|
85
|
+
all_noisy_counts[str(qubits_array)][rb_type][depth] = xrvariable_to_counts(
|
|
86
|
+
dataset, identifier, num_circuit_samples
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
# Retrieve the marginalized survival probabilities
|
|
90
|
+
all_survival_probabilities = survival_probabilities_parallel(
|
|
91
|
+
qubits_array, all_noisy_counts[str(qubits_array)][rb_type][depth]
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
# The marginalized survival probabilities will be arranged by qubit layouts
|
|
95
|
+
for qubits_str in all_survival_probabilities.keys():
|
|
96
|
+
fidelities[qubits_str][rb_type][depth] = all_survival_probabilities[qubits_str]
|
|
97
|
+
# Remaining analysis is the same regardless of whether execution was in parallel or sequential
|
|
98
|
+
qcvv_logger.info(f"Metrics for {rb_type.capitalize()} estimated successfully!")
|
|
99
|
+
else: # sequential
|
|
100
|
+
qcvv_logger.info(f"Post-processing sequential Interleaved RB for qubits {qubits_array}")
|
|
101
|
+
|
|
102
|
+
for q in qubits_array:
|
|
103
|
+
all_noisy_counts[str(q)] = {}
|
|
104
|
+
num_qubits = len(q)
|
|
105
|
+
fidelities[str(q)] = {}
|
|
106
|
+
for rb_type in ["clifford", "interleaved"]:
|
|
107
|
+
all_noisy_counts[str(q)][rb_type] = {}
|
|
108
|
+
fidelities[str(q)][rb_type] = {}
|
|
109
|
+
for depth in sequence_lengths:
|
|
110
|
+
identifier = f"{rb_type}_qubits_{str(q)}_depth_{str(depth)}"
|
|
111
|
+
all_noisy_counts[str(q)][rb_type][depth] = xrvariable_to_counts(
|
|
112
|
+
dataset, identifier, num_circuit_samples
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
qcvv_logger.info(f"Now on {rb_type.capitalize()} RB with qubits {q} and depth {depth}")
|
|
116
|
+
fidelities[str(q)][rb_type][depth] = get_survival_probabilities(
|
|
117
|
+
num_qubits, all_noisy_counts[str(q)][rb_type][depth]
|
|
118
|
+
)
|
|
119
|
+
# Remaining analysis is the same regardless of whether execution was in parallel or sequential
|
|
120
|
+
|
|
121
|
+
# All remaining (fitting & plotting) is done per qubit layout
|
|
122
|
+
for qubits_idx, qubits in enumerate(qubits_array):
|
|
123
|
+
dataset.attrs[str(qubits)] = {}
|
|
124
|
+
# Fit decays simultaneously
|
|
125
|
+
list_of_fidelities_clifford = list(fidelities[str(qubits)]["clifford"].values())
|
|
126
|
+
list_of_fidelities_interleaved = list(fidelities[str(qubits)]["interleaved"].values())
|
|
127
|
+
fit_data, fit_parameters = fit_decay_lmfit(
|
|
128
|
+
exponential_rb,
|
|
129
|
+
qubits,
|
|
130
|
+
[list_of_fidelities_clifford, list_of_fidelities_interleaved],
|
|
131
|
+
"interleaved",
|
|
132
|
+
simultaneous_fit,
|
|
133
|
+
)
|
|
134
|
+
rb_fit_results = lmfit_minimizer(fit_parameters, fit_data, sequence_lengths, exponential_rb)
|
|
135
|
+
|
|
136
|
+
processed_results = {}
|
|
137
|
+
for rb_type in ["interleaved", "clifford"]:
|
|
138
|
+
average_fidelities = {d: np.mean(fidelities[str(qubits)][rb_type][d]) for d in sequence_lengths}
|
|
139
|
+
stddevs_from_mean = {
|
|
140
|
+
d: np.std(fidelities[str(qubits)][rb_type][d]) / np.sqrt(num_circuit_samples) for d in sequence_lengths
|
|
141
|
+
}
|
|
142
|
+
popt = {
|
|
143
|
+
"amplitude": (
|
|
144
|
+
rb_fit_results.params["amplitude_1"]
|
|
145
|
+
if rb_type == "clifford"
|
|
146
|
+
else rb_fit_results.params["amplitude_2"]
|
|
147
|
+
),
|
|
148
|
+
"offset": (
|
|
149
|
+
rb_fit_results.params["offset_1"] if rb_type == "clifford" else rb_fit_results.params["offset_2"]
|
|
150
|
+
),
|
|
151
|
+
"decay_rate": (
|
|
152
|
+
rb_fit_results.params["p_rb"] if rb_type == "clifford" else rb_fit_results.params["p_irb"]
|
|
153
|
+
),
|
|
154
|
+
}
|
|
155
|
+
fidelity = (
|
|
156
|
+
rb_fit_results.params["fidelity_per_clifford"]
|
|
157
|
+
if rb_type == "clifford"
|
|
158
|
+
else rb_fit_results.params["interleaved_fidelity"]
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
processed_results[rb_type] = {
|
|
162
|
+
"avg_gate_fidelity": {"value": fidelity.value, "uncertainty": fidelity.stderr},
|
|
163
|
+
"decay_rate": {"value": popt["decay_rate"].value, "uncertainty": popt["decay_rate"].stderr},
|
|
164
|
+
"fit_amplitude": {"value": popt["amplitude"].value, "uncertainty": popt["amplitude"].stderr},
|
|
165
|
+
"fit_offset": {"value": popt["offset"].value, "uncertainty": popt["offset"].stderr},
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
dataset.attrs[qubits_idx].update(
|
|
169
|
+
{
|
|
170
|
+
rb_type: {
|
|
171
|
+
"fidelities": fidelities[str(qubits)][rb_type],
|
|
172
|
+
"avg_fidelities_nominal_values": average_fidelities,
|
|
173
|
+
"avg_fidelities_stderr": stddevs_from_mean,
|
|
174
|
+
"fitting_method": str(rb_fit_results.method),
|
|
175
|
+
"num_function_evals": int(rb_fit_results.nfev),
|
|
176
|
+
"data_points": int(rb_fit_results.ndata),
|
|
177
|
+
"num_variables": int(rb_fit_results.nvarys),
|
|
178
|
+
"chi_square": float(rb_fit_results.chisqr),
|
|
179
|
+
"reduced_chi_square": float(rb_fit_results.redchi),
|
|
180
|
+
"Akaike_info_crit": float(rb_fit_results.aic),
|
|
181
|
+
"Bayesian_info_crit": float(rb_fit_results.bic),
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
observations.update({qubits_idx: processed_results})
|
|
187
|
+
|
|
188
|
+
# Generate decay plots
|
|
189
|
+
if interleaved_gate_parameters is None:
|
|
190
|
+
interleaved_gate_string = f"{interleaved_gate}"
|
|
191
|
+
else:
|
|
192
|
+
params_string = str(tuple(f"{x:.2f}" for x in interleaved_gate_parameters))
|
|
193
|
+
interleaved_gate_string = f"{interleaved_gate}{params_string}"
|
|
194
|
+
|
|
195
|
+
fig_name, fig = plot_rb_decay(
|
|
196
|
+
"irb",
|
|
197
|
+
[qubits],
|
|
198
|
+
dataset,
|
|
199
|
+
observations,
|
|
200
|
+
interleaved_gate=interleaved_gate_string,
|
|
201
|
+
)
|
|
202
|
+
plots[fig_name] = fig
|
|
203
|
+
|
|
204
|
+
# Rearrange observations
|
|
205
|
+
observations_refactored: Dict[int, Dict[str, Dict[str, float]]] = {}
|
|
206
|
+
for k, o in observations.items():
|
|
207
|
+
observations_refactored[k] = {}
|
|
208
|
+
for rb_type in o.keys():
|
|
209
|
+
observations_refactored[k].update({f"{k}_{rb_type}": v for k, v in o[rb_type].items()})
|
|
210
|
+
|
|
211
|
+
return AnalysisResult(dataset=dataset, observations=observations_refactored, plots=plots)
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
class InterleavedRandomizedBenchmarking(Benchmark):
|
|
215
|
+
"""Interleaved RB estimates the average gate fidelity of a specific Clifford gate"""
|
|
216
|
+
|
|
217
|
+
analysis_function = staticmethod(interleaved_rb_analysis)
|
|
218
|
+
|
|
219
|
+
name: str = "clifford_rb"
|
|
220
|
+
|
|
221
|
+
def __init__(self, backend_arg: IQMBackendBase | str, configuration: "InterleavedRBConfiguration"):
|
|
222
|
+
"""Construct the InterleavedRandomizedBenchmark class
|
|
223
|
+
|
|
224
|
+
Args:
|
|
225
|
+
backend_arg (IQMBackendBase | str): the backend to execute Clifford RB on
|
|
226
|
+
configuration (CliffordRBConfiguration): The Clifford RB configuration
|
|
227
|
+
"""
|
|
228
|
+
super().__init__(backend_arg, configuration)
|
|
229
|
+
|
|
230
|
+
# EXPERIMENT
|
|
231
|
+
self.backend_configuration_name = backend_arg if isinstance(backend_arg, str) else backend_arg.name
|
|
232
|
+
|
|
233
|
+
self.qubits_array = configuration.qubits_array
|
|
234
|
+
self.sequence_lengths = configuration.sequence_lengths
|
|
235
|
+
self.num_circuit_samples = configuration.num_circuit_samples
|
|
236
|
+
|
|
237
|
+
self.parallel_execution = configuration.parallel_execution
|
|
238
|
+
|
|
239
|
+
self.interleaved_gate = configuration.interleaved_gate
|
|
240
|
+
self.interleaved_gate_params = configuration.interleaved_gate_params
|
|
241
|
+
self.simultaneous_fit = configuration.simultaneous_fit
|
|
242
|
+
|
|
243
|
+
self.session_timestamp = strftime("%Y%m%d-%H%M%S")
|
|
244
|
+
self.execution_timestamp = ""
|
|
245
|
+
|
|
246
|
+
def add_all_meta_to_dataset(self, dataset: xr.Dataset):
|
|
247
|
+
"""Adds all configuration metadata and circuits to the dataset variable
|
|
248
|
+
Args:
|
|
249
|
+
dataset (xr.Dataset): The xarray dataset
|
|
250
|
+
"""
|
|
251
|
+
dataset.attrs["session_timestamp"] = self.session_timestamp
|
|
252
|
+
dataset.attrs["execution_timestamp"] = self.execution_timestamp
|
|
253
|
+
dataset.attrs["backend_configuration_name"] = self.backend_configuration_name
|
|
254
|
+
dataset.attrs["backend_name"] = self.backend.name
|
|
255
|
+
|
|
256
|
+
for key, value in self.configuration:
|
|
257
|
+
if key == "benchmark": # Avoid saving the class object
|
|
258
|
+
dataset.attrs[key] = value.name
|
|
259
|
+
else:
|
|
260
|
+
dataset.attrs[key] = value
|
|
261
|
+
# Defined outside configuration - if any
|
|
262
|
+
|
|
263
|
+
@timeit
|
|
264
|
+
def add_all_circuits_to_dataset(self, dataset: xr.Dataset):
|
|
265
|
+
"""Adds all generated circuits during execution to the dataset variable
|
|
266
|
+
|
|
267
|
+
Args:
|
|
268
|
+
dataset (xr.Dataset): The xarray dataset
|
|
269
|
+
|
|
270
|
+
Returns:
|
|
271
|
+
|
|
272
|
+
"""
|
|
273
|
+
qcvv_logger.info("Adding all circuits to the dataset")
|
|
274
|
+
dataset.attrs["untranspiled_circuits"] = self.untranspiled_circuits
|
|
275
|
+
dataset.attrs["transpiled_circuits"] = self.transpiled_circuits
|
|
276
|
+
|
|
277
|
+
# pylint: disable=too-many-statements
|
|
278
|
+
def execute(self, backend: IQMBackendBase) -> xr.Dataset:
|
|
279
|
+
"""Executes the benchmark"""
|
|
280
|
+
|
|
281
|
+
self.execution_timestamp = strftime("%Y%m%d-%H%M%S")
|
|
282
|
+
validate_rb_qubits(self.qubits_array, backend)
|
|
283
|
+
|
|
284
|
+
dataset = xr.Dataset()
|
|
285
|
+
self.add_all_meta_to_dataset(dataset)
|
|
286
|
+
|
|
287
|
+
clifford_1q_dict, clifford_2q_dict = import_native_gate_cliffords()
|
|
288
|
+
|
|
289
|
+
# Submit jobs for all qubit layouts
|
|
290
|
+
all_rb_jobs: Dict[str, List[Dict[str, Any]]] = {} # Label by Clifford or Interleaved
|
|
291
|
+
time_circuit_generation: Dict[str, float] = {}
|
|
292
|
+
|
|
293
|
+
# Initialize the variable to contain the circuits for each layout
|
|
294
|
+
self.untranspiled_circuits: Dict[str, Dict[int, List[QuantumCircuit]]] = {}
|
|
295
|
+
self.transpiled_circuits: Dict[str, Dict[int, List[QuantumCircuit]]] = {}
|
|
296
|
+
|
|
297
|
+
# Validate and get interleaved gate as a QC
|
|
298
|
+
interleaved_gate_qc = validate_irb_gate(
|
|
299
|
+
self.interleaved_gate, backend, gate_params=self.interleaved_gate_params
|
|
300
|
+
)
|
|
301
|
+
|
|
302
|
+
# Auxiliary dict from str(qubits) to indices
|
|
303
|
+
qubit_idx: Dict[str, Any] = {}
|
|
304
|
+
|
|
305
|
+
if self.parallel_execution:
|
|
306
|
+
all_rb_jobs["clifford"] = []
|
|
307
|
+
all_rb_jobs["interleaved"] = []
|
|
308
|
+
# Take the whole qubits_array and do RB in parallel on each qubits_array element
|
|
309
|
+
parallel_untranspiled_rb_circuits = {}
|
|
310
|
+
parallel_transpiled_rb_circuits = {}
|
|
311
|
+
parallel_untranspiled_interleaved_rb_circuits = {}
|
|
312
|
+
parallel_transpiled_interleaved_rb_circuits = {}
|
|
313
|
+
qcvv_logger.info(
|
|
314
|
+
f"Now executing parallel Interleaved RB on qubits {self.qubits_array}."
|
|
315
|
+
f" Will generate and submit all {self.num_circuit_samples} Interleaved and Clifford RB circuits"
|
|
316
|
+
f" for each depth {self.sequence_lengths}."
|
|
317
|
+
)
|
|
318
|
+
|
|
319
|
+
time_circuit_generation[str(self.qubits_array)] = 0
|
|
320
|
+
|
|
321
|
+
# Generate and submit all circuits
|
|
322
|
+
for seq_length in self.sequence_lengths:
|
|
323
|
+
# There are different ways of dealing with submission here:
|
|
324
|
+
# We'll generate Clifford circuits, then Interleaved circuits, for fixed depth
|
|
325
|
+
# Then we'll submit separate jobs but one right after the other, Clifford first
|
|
326
|
+
# Do for all sequence depths
|
|
327
|
+
|
|
328
|
+
qcvv_logger.info(f"Generating Clifford RB circuits of sequence length {seq_length}")
|
|
329
|
+
(
|
|
330
|
+
(parallel_untranspiled_rb_circuits[seq_length], parallel_transpiled_rb_circuits[seq_length]),
|
|
331
|
+
elapsed_time_untranspiled,
|
|
332
|
+
) = generate_fixed_depth_parallel_rb_circuits(
|
|
333
|
+
self.qubits_array,
|
|
334
|
+
clifford_1q_dict,
|
|
335
|
+
clifford_2q_dict,
|
|
336
|
+
seq_length,
|
|
337
|
+
self.num_circuit_samples,
|
|
338
|
+
backend,
|
|
339
|
+
interleaved_gate=None,
|
|
340
|
+
)
|
|
341
|
+
qcvv_logger.info(f"Generating Interleaved RB circuits of sequence length {seq_length}")
|
|
342
|
+
|
|
343
|
+
(
|
|
344
|
+
(
|
|
345
|
+
parallel_untranspiled_interleaved_rb_circuits[seq_length],
|
|
346
|
+
parallel_transpiled_interleaved_rb_circuits[seq_length],
|
|
347
|
+
),
|
|
348
|
+
elapsed_time_transpiled,
|
|
349
|
+
) = generate_fixed_depth_parallel_rb_circuits(
|
|
350
|
+
self.qubits_array,
|
|
351
|
+
clifford_1q_dict,
|
|
352
|
+
clifford_2q_dict,
|
|
353
|
+
seq_length,
|
|
354
|
+
self.num_circuit_samples,
|
|
355
|
+
backend,
|
|
356
|
+
interleaved_gate=interleaved_gate_qc,
|
|
357
|
+
)
|
|
358
|
+
|
|
359
|
+
time_circuit_generation[str(self.qubits_array)] += elapsed_time_untranspiled + elapsed_time_transpiled
|
|
360
|
+
|
|
361
|
+
# Submit all
|
|
362
|
+
flat_qubits_array = [x for y in self.qubits_array for x in y]
|
|
363
|
+
sorted_transpiled_rb_qc_list = {tuple(flat_qubits_array): parallel_transpiled_rb_circuits[seq_length]}
|
|
364
|
+
sorted_transpiled_interleaved_rb_qc_list = {
|
|
365
|
+
tuple(flat_qubits_array): parallel_transpiled_interleaved_rb_circuits[seq_length]
|
|
366
|
+
}
|
|
367
|
+
all_rb_jobs["clifford"].append(
|
|
368
|
+
submit_parallel_rb_job(
|
|
369
|
+
backend,
|
|
370
|
+
self.qubits_array,
|
|
371
|
+
seq_length,
|
|
372
|
+
sorted_transpiled_rb_qc_list,
|
|
373
|
+
self.shots,
|
|
374
|
+
self.calset_id,
|
|
375
|
+
self.max_gates_per_batch,
|
|
376
|
+
)
|
|
377
|
+
)
|
|
378
|
+
all_rb_jobs["interleaved"].append(
|
|
379
|
+
submit_parallel_rb_job(
|
|
380
|
+
backend,
|
|
381
|
+
self.qubits_array,
|
|
382
|
+
seq_length,
|
|
383
|
+
sorted_transpiled_interleaved_rb_qc_list,
|
|
384
|
+
self.shots,
|
|
385
|
+
self.calset_id,
|
|
386
|
+
self.max_gates_per_batch,
|
|
387
|
+
)
|
|
388
|
+
)
|
|
389
|
+
qcvv_logger.info(f"Both jobs for sequence length {seq_length} submitted successfully!")
|
|
390
|
+
|
|
391
|
+
self.untranspiled_circuits[str(self.qubits_array)] = {
|
|
392
|
+
m: parallel_untranspiled_rb_circuits[m] for m in self.sequence_lengths
|
|
393
|
+
}
|
|
394
|
+
self.transpiled_circuits[str(self.qubits_array)] = {
|
|
395
|
+
m: parallel_transpiled_rb_circuits[m] for m in self.sequence_lengths
|
|
396
|
+
}
|
|
397
|
+
self.untranspiled_circuits[str(self.qubits_array) + "_interleaved"] = {
|
|
398
|
+
m: parallel_untranspiled_interleaved_rb_circuits[m] for m in self.sequence_lengths
|
|
399
|
+
}
|
|
400
|
+
self.transpiled_circuits[str(self.qubits_array) + "_interleaved"] = {
|
|
401
|
+
m: parallel_transpiled_interleaved_rb_circuits[m] for m in self.sequence_lengths
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
qubit_idx = {str(self.qubits_array): "parallel_all"}
|
|
405
|
+
dataset.attrs["parallel_all"] = {"qubits": self.qubits_array}
|
|
406
|
+
dataset.attrs.update({q_idx: {"qubits": q} for q_idx, q in enumerate(self.qubits_array)})
|
|
407
|
+
else:
|
|
408
|
+
rb_untranspiled_circuits: Dict[str, Dict[int, List[QuantumCircuit]]] = {}
|
|
409
|
+
rb_transpiled_circuits: Dict[str, Dict[int, List[QuantumCircuit]]] = {}
|
|
410
|
+
rb_untranspiled_interleaved_circuits: Dict[str, Dict[int, List[QuantumCircuit]]] = {}
|
|
411
|
+
rb_transpiled_interleaved_circuits: Dict[str, Dict[int, List[QuantumCircuit]]] = {}
|
|
412
|
+
|
|
413
|
+
all_rb_jobs["clifford"] = []
|
|
414
|
+
all_rb_jobs["interleaved"] = []
|
|
415
|
+
|
|
416
|
+
for qubits_idx, qubits in enumerate(self.qubits_array):
|
|
417
|
+
qubit_idx[str(qubits)] = qubits_idx
|
|
418
|
+
qcvv_logger.info(
|
|
419
|
+
f"Wxecuting sequential Clifford and Interleaved RB circuits on qubits {qubits}."
|
|
420
|
+
f" Will generate and submit all {self.num_circuit_samples} Clifford RB circuits"
|
|
421
|
+
f" for each depth {self.sequence_lengths}"
|
|
422
|
+
)
|
|
423
|
+
num_qubits = len(qubits)
|
|
424
|
+
rb_untranspiled_circuits[str(qubits)] = {}
|
|
425
|
+
rb_transpiled_circuits[str(qubits)] = {}
|
|
426
|
+
rb_untranspiled_interleaved_circuits[str(qubits)] = {}
|
|
427
|
+
rb_transpiled_interleaved_circuits[str(qubits)] = {}
|
|
428
|
+
|
|
429
|
+
if num_qubits == 1:
|
|
430
|
+
clifford_dict = clifford_1q_dict
|
|
431
|
+
else:
|
|
432
|
+
clifford_dict = clifford_2q_dict
|
|
433
|
+
|
|
434
|
+
((rb_untranspiled_circuits[str(qubits)], rb_transpiled_circuits[str(qubits)]), t_clifford) = (
|
|
435
|
+
generate_all_rb_circuits(
|
|
436
|
+
qubits,
|
|
437
|
+
self.sequence_lengths,
|
|
438
|
+
clifford_dict,
|
|
439
|
+
self.num_circuit_samples,
|
|
440
|
+
backend,
|
|
441
|
+
interleaved_gate=None,
|
|
442
|
+
)
|
|
443
|
+
)
|
|
444
|
+
(
|
|
445
|
+
(
|
|
446
|
+
rb_untranspiled_interleaved_circuits[str(qubits)],
|
|
447
|
+
rb_transpiled_interleaved_circuits[str(qubits)],
|
|
448
|
+
),
|
|
449
|
+
t_inter,
|
|
450
|
+
) = generate_all_rb_circuits(
|
|
451
|
+
qubits,
|
|
452
|
+
self.sequence_lengths,
|
|
453
|
+
clifford_dict,
|
|
454
|
+
self.num_circuit_samples,
|
|
455
|
+
backend,
|
|
456
|
+
interleaved_gate=interleaved_gate_qc,
|
|
457
|
+
)
|
|
458
|
+
|
|
459
|
+
time_circuit_generation[str(qubits)] = t_clifford + t_inter
|
|
460
|
+
|
|
461
|
+
# Submit Clifford then Interleaved
|
|
462
|
+
all_rb_jobs["clifford"].extend(
|
|
463
|
+
submit_sequential_rb_jobs(
|
|
464
|
+
qubits,
|
|
465
|
+
rb_transpiled_circuits[str(qubits)],
|
|
466
|
+
self.shots,
|
|
467
|
+
backend,
|
|
468
|
+
self.calset_id,
|
|
469
|
+
max_gates_per_batch=self.max_gates_per_batch,
|
|
470
|
+
)
|
|
471
|
+
)
|
|
472
|
+
all_rb_jobs["interleaved"].extend(
|
|
473
|
+
submit_sequential_rb_jobs(
|
|
474
|
+
qubits,
|
|
475
|
+
rb_transpiled_interleaved_circuits[str(qubits)],
|
|
476
|
+
self.shots,
|
|
477
|
+
backend,
|
|
478
|
+
self.calset_id,
|
|
479
|
+
max_gates_per_batch=self.max_gates_per_batch,
|
|
480
|
+
)
|
|
481
|
+
)
|
|
482
|
+
qcvv_logger.info(
|
|
483
|
+
f"All jobs for qubits {qubits} and sequence lengths {self.sequence_lengths} submitted successfully!"
|
|
484
|
+
)
|
|
485
|
+
|
|
486
|
+
self.untranspiled_circuits[str(qubits)] = rb_untranspiled_circuits[str(qubits)]
|
|
487
|
+
self.transpiled_circuits[str(qubits)] = rb_transpiled_circuits[str(qubits)]
|
|
488
|
+
self.untranspiled_circuits[str(qubits) + "_interleaved"] = rb_untranspiled_interleaved_circuits[
|
|
489
|
+
str(qubits)
|
|
490
|
+
]
|
|
491
|
+
self.transpiled_circuits[str(qubits) + "_interleaved"] = rb_transpiled_interleaved_circuits[str(qubits)]
|
|
492
|
+
|
|
493
|
+
dataset.attrs[qubits_idx] = {"qubits": qubits}
|
|
494
|
+
|
|
495
|
+
# Retrieve counts of jobs for all qubit layouts
|
|
496
|
+
all_job_metadata = {}
|
|
497
|
+
for rb_type in ["clifford", "interleaved"]:
|
|
498
|
+
for job_dict in all_rb_jobs[rb_type]:
|
|
499
|
+
qubits = job_dict["qubits"]
|
|
500
|
+
depth = job_dict["depth"]
|
|
501
|
+
# Retrieve counts
|
|
502
|
+
identifier = f"{rb_type}_qubits_{str(qubits)}_depth_{str(depth)}"
|
|
503
|
+
execution_results, time_retrieve = retrieve_all_counts(job_dict["jobs"], identifier)
|
|
504
|
+
# Retrieve all job meta data
|
|
505
|
+
all_job_metadata = retrieve_all_job_metadata(job_dict["jobs"])
|
|
506
|
+
# Export all to dataset
|
|
507
|
+
dataset.attrs[qubit_idx[str(qubits)]].update(
|
|
508
|
+
{
|
|
509
|
+
rb_type: {
|
|
510
|
+
f"depth_{str(depth)}": {
|
|
511
|
+
"time_circuit_generation": time_circuit_generation[str(qubits)],
|
|
512
|
+
"time_submit": job_dict["time_submit"],
|
|
513
|
+
"time_retrieve": time_retrieve,
|
|
514
|
+
"all_job_metadata": all_job_metadata,
|
|
515
|
+
},
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
)
|
|
519
|
+
|
|
520
|
+
qcvv_logger.info(f"Adding counts of qubits {qubits} and depth {depth} run to the dataset")
|
|
521
|
+
dataset, _ = add_counts_to_dataset(execution_results, identifier, dataset)
|
|
522
|
+
|
|
523
|
+
self.add_all_circuits_to_dataset(dataset)
|
|
524
|
+
|
|
525
|
+
qcvv_logger.info(f"Interleaved RB experiment concluded !")
|
|
526
|
+
|
|
527
|
+
return dataset
|
|
528
|
+
|
|
529
|
+
|
|
530
|
+
class InterleavedRBConfiguration(BenchmarkConfigurationBase):
|
|
531
|
+
"""Interleaved RB configuration.
|
|
532
|
+
Attributes:
|
|
533
|
+
benchmark (Type[Benchmark]): InterleavedRandomizedBenchmarking.
|
|
534
|
+
qubits_array (Sequence[Sequence[int]]): The array of physical qubit labels with which to execute IRB.
|
|
535
|
+
sequence_lengths (Sequence[int]): The length of each random Clifford sequence.
|
|
536
|
+
num_circuit_samples (int): The number of circuit samples to generate.
|
|
537
|
+
shots (int): The number of measurement shots with which to execute each circuit sample.
|
|
538
|
+
parallel_execution(bool): Whether the benchmark is executed on all qubits in parallel or not.
|
|
539
|
+
* Default is False.
|
|
540
|
+
interleaved_gate (str): The name of the gate to interleave.
|
|
541
|
+
* Should be specified as a qiskit circuit library gate name, e.g., "YGate" or "CZGate".
|
|
542
|
+
interleaved_gate_params (Optional[Sequence[float]]): Any optional parameters entering the gate.
|
|
543
|
+
* Default is None.
|
|
544
|
+
simultaneous_fit (Sequence[Literal["amplitude", "offset"]]): Optional parameters to fit simultaneously.
|
|
545
|
+
* Default is ["amplitude", "offset"].
|
|
546
|
+
"""
|
|
547
|
+
|
|
548
|
+
benchmark: Type[Benchmark] = InterleavedRandomizedBenchmarking
|
|
549
|
+
qubits_array: Sequence[Sequence[int]]
|
|
550
|
+
sequence_lengths: Sequence[int]
|
|
551
|
+
num_circuit_samples: int
|
|
552
|
+
parallel_execution: bool = False
|
|
553
|
+
interleaved_gate: str
|
|
554
|
+
interleaved_gate_params: Optional[Sequence[float]] = None
|
|
555
|
+
simultaneous_fit: Sequence[Literal["amplitude", "offset"]] = ["amplitude", "offset"]
|
|
@@ -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
|
+
Mirror RB reflects the fidelity of mirror circuits
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from . import mirror_rb
|